sauruspro-bail 5.0.1 → 5.0.2-alpha.spr.test

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  ![node](https://img.shields.io/badge/Node.js-20%2B-22c55e?style=for-the-badge)
12
12
  ![license](https://img.shields.io/badge/License-MIT-3b82f6?style=for-the-badge)
13
13
 
14
- **Owner: Saurus / Dinonic** · **Version: 5.0.1**
14
+ **Owner: Saurus / Dinonic** · **Version: 5.0.2-alpha.spr.test**
15
15
 
16
16
  </div>
17
17
 
@@ -22,7 +22,7 @@
22
22
  | | |
23
23
  |---|---|
24
24
  | Package | `sauruspro-bail` |
25
- | Version | `5.0.1` |
25
+ | Version | `5.0.2-alpha.spr.test` |
26
26
  | Owner | Saurus / Dinonic |
27
27
  | Module type | ESM (`"type": "module"`) |
28
28
  | Runtime | Node.js >= 20 |
@@ -100,9 +100,13 @@ Dokumentasi lengkap: **[docs/NEWSLETTER-STATUS.md](docs/NEWSLETTER-STATUS.md)**
100
100
  ```js
101
101
  await sock.sPR(jid, { conversation: 'Halo!' })
102
102
  // alias: sock.relayMessageSelective(jid, message, options)
103
+
104
+ // pesan privat per orang + foto profil
105
+ await sock.sPRPrivate(groupJid, targetJid, { publicText: 'Ada pesan', privateText: 'rahasia' })
106
+ await sock.sPRBroadcast(groupJid, { template: 'Halo {name}!' })
103
107
  ```
104
108
 
105
- Dokumentasi lengkap: **[docs/SPR.md](docs/SPR.md)** · SPR dibuat oleh **Nixel** (watermark di `dinonic-spr.js` tidak boleh dihapus).
109
+ Dokumentasi lengkap: **[docs/SPR.md](docs/SPR.md)**
106
110
 
107
111
  ## 📚 Dokumentasi
108
112
 
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.0.2-alpha.spr.test
4
+ ### Changed
5
+ - `lib/Utils/dinonic-spr.js` ditulis ulang dari nol (engine baru, sender key sekali pakai). API `sPR` / `selectiveRelay` tetap kompatibel.
6
+
7
+ ### Added (diadaptasi dari plugin zapo-js, MIT)
8
+ - Opsi `personal` pada `sPR`: pesan khusus per orang.
9
+ - `sPRPrivate`, `sPRBroadcast` (`{name}` + mention + foto profil), `getSPRTargets`, `loadSPRAvatars`.
10
+ - Batas target 100 + hitung overflow, cache foto, budget/timeout, konkurensi.
11
+ - Reporting token memakai util resmi, tctoken memakai pengecekan expired.
12
+
3
13
  ## 5.0.1
4
14
  **Owner: Saurus / Dinonic**
5
15
 
package/docs/SPR.md CHANGED
@@ -1,51 +1,88 @@
1
- # 🎯 SPR (Selective Relay)
1
+ # 🎯 SPR (Selective & Private Relay)
2
2
 
3
- Kirim pesan dengan kontrol **device/JID mana yang menerima kunci asli**, sisanya menerima kunci palsu sehingga tidak bisa membuka pesan.
3
+ Kirim pesan dengan kontrol **siapa membaca apa**. Tiap device penerima masuk salah satu peran:
4
4
 
5
- > Modul SPR dibuat oleh **Nixel**. Watermark di `lib/Utils/dinonic-spr.js` wajib dipertahankan. Lisensi aslinya melarang reupload/resell sebagai produk mandiri dan mengaku sebagai karya sendiri.
5
+ | Peran | Yang diterima |
6
+ |---|---|
7
+ | `public` | pesan umum (menerima sender key sekali pakai) |
8
+ | `personal` | pesan khusus miliknya (enkripsi 1-lawan-1), tanpa pesan umum |
9
+ | `hidden` | tidak menerima apa-apa |
10
+
11
+ Sender key dibuat baru untuk setiap pesan dan tidak disimpan, jadi device yang tidak diberi kunci tidak bisa membuka pesan meski pernah menerima pesan lain dari bot.
12
+
13
+ ## API
6
14
 
7
15
  ```js
8
- await sock.sPR(jid, message, options)
9
- // alias
10
- await sock.relayMessageSelective(jid, message, options)
16
+ await sock.sPR(jid, message, options) // alias: sock.relayMessageSelective
17
+ await sock.sPRPrivate(groupJid, targetJid, { publicText, privateText })
18
+ await sock.sPRBroadcast(groupJid, { template })
19
+ await sock.getSPRTargets(groupJid, { limit })
11
20
  ```
12
21
 
13
- Juga bisa di-import: `import { sPR, selectiveRelay } from 'sauruspro-bail'`
14
- (`sPR(conn, jid, message, options)`, parameter pertama adalah socket).
22
+ Bisa juga di-import: `import { sPR, sPRPrivate, sPRBroadcast } from 'sauruspro-bail'` (parameter pertama adalah socket).
15
23
 
16
- ## Options
24
+ ## sPR options
17
25
 
18
26
  | Option | Default | Keterangan |
19
27
  |---|---|---|
20
- | `mode` | `"exclude"` | `exclude`: target **tidak** menerima. `include`: **hanya** target yang menerima |
21
- | `target` | `[]` | Daftar JID (PN atau LID) |
28
+ | `mode` | `"exclude"` | `exclude`: target **tidak** menerima pesan publik. `include`: **hanya** target |
29
+ | `target` | `[]` | Daftar JID (PN atau LID, alias dicocokkan otomatis) |
30
+ | `personal` | - | Pesan khusus per orang: `{ jid: message }`, `Map`, atau `({jid,user}) => message` |
22
31
  | `targetMe` | - | `true/false` memaksa device milik sendiri menerima/tidak |
23
- | `deviceMode` | `"all"` | `all` / `primary` (device 0) / `secondary` (device lain) |
32
+ | `deviceMode` | `"all"` | `all` / `primary` (device 0) / `secondary` |
24
33
  | `hideDecryptFail` | `true` | Sembunyikan placeholder gagal-dekripsi |
25
34
  | `messageId` | auto | ID pesan kustom |
26
35
  | `additionalAttributes` / `additionalNodes` | - | Atribut/node tambahan pada stanza |
27
36
  | `useUserDevicesCache` / `useCachedGroupMetadata` | - | Pakai cache |
28
37
  | `statusJidList` | - | Untuk status broadcast |
29
38
 
39
+ `message` boleh `null` bila semua penerima punya pesan `personal`.
40
+
30
41
  ## Contoh
31
42
 
32
43
  ```js
33
- // Kirim ke grup, tapi sembunyikan dari 1 orang
44
+ // Sembunyikan dari 1 orang
34
45
  await sock.sPR(groupJid, { conversation: 'rahasia' }, {
35
- mode: 'exclude',
36
- target: ['6281234567890@s.whatsapp.net']
46
+ mode: 'exclude', target: ['6281234567890@s.whatsapp.net']
47
+ })
48
+
49
+ // Pesan umum untuk semua, pesan lain khusus untuk A
50
+ await sock.sPR(groupJid, { conversation: 'info umum' }, {
51
+ personal: { '6281234567890@s.whatsapp.net': { conversation: 'info khusus kamu' } }
52
+ })
53
+ ```
54
+
55
+ ## sPRPrivate (setara `!spr publik | privat`)
56
+
57
+ Anggota lain melihat `publicText`, `targetJid` melihat `privateText` dengan foto profilnya sendiri.
58
+
59
+ ```js
60
+ await sock.sPRPrivate(groupJid, targetJid, {
61
+ publicText: 'Pesan ini memiliki isi khusus untuk beberapa penerima.',
62
+ privateText: 'rahasia buat kamu',
63
+ avatar: true
37
64
  })
65
+ // -> { id, avatar }
66
+ ```
38
67
 
39
- // Hanya kirim ke 1 orang di grup
40
- await sock.sPR(groupJid, { conversation: 'khusus kamu' }, {
41
- mode: 'include',
42
- target: ['6281234567890@s.whatsapp.net']
68
+ ## sPRBroadcast (setara `!sbpr` / `!sbrp`)
69
+
70
+ Tiap anggota menerima pesan sendiri: `{name}` menjadi @mention orang itu, plus foto profilnya.
71
+ Anggota di luar `limit` (default 100) melihat `publicText`. Bot tidak dihitung, admin didahulukan.
72
+
73
+ ```js
74
+ await sock.sPRBroadcast(groupJid, {
75
+ template: 'Halo {name}, ada pesan untukmu.',
76
+ limit: 100,
77
+ avatar: true
43
78
  })
79
+ // -> { id, targets, total, overflow, withAvatar }
44
80
  ```
45
81
 
46
- ## Perubahan v5.0.0
82
+ Foto profil diambil konkuren (10 sekaligus) dengan budget 10 dtk dan batas keras 14 dtk; gagal/lambat otomatis jatuh ke pesan teks. Hasil di-cache (200 entri).
83
+
84
+ ## Catatan
47
85
 
48
- - `lib/Utils/dinonic-spr.js` diganti dengan port ESM langsung dari SPR referensi. Logika **identik**; yang berubah hanya sintaks modul (CJS → ESM).
49
- - Termasuk fallback `me.id` / `me.lid` ke `conn.user` (tidak crash saat `authState.creds.me` kosong).
50
- - `sPR` & `selectiveRelay` diexport dari entry utama.
51
- - `encodeSignedDeviceIdentity` diimpor dari `validate-connection.js` (sebelumnya salah dari `generics.js` sehingga paket gagal load).
86
+ - Penerima `personal` hanya melihat pesan personalnya; pesan umum tidak dikirim ke mereka.
87
+ - Fitur privat/broadcast diadaptasi dari plugin zapo-js (MIT).
88
+ - Perubahan v5.0.2-alpha.spr.test: engine ditulis ulang (kode baru), tambah `personal`, `sPRPrivate`, `sPRBroadcast`, `getSPRTargets`, `loadSPRAvatars`. API `sPR`/`selectiveRelay` lama tetap kompatibel.
@@ -5,7 +5,7 @@ import { makeInteropSocket } from './interop.js'
5
5
  import { makePrivacySocket } from './privacy.js'
6
6
  import { makeGraphQLSocket } from './graphql.js'
7
7
  import { makeMessageBuilderSocket } from './message-builder.js'
8
- import { sPR } from '../Utils/dinonic-spr.js'
8
+ import { sPR, sPRPrivate, sPRBroadcast, getSPRTargets } from '../Utils/dinonic-spr.js'
9
9
  import * as DinonicBuilder from '../Utils/MessageBuilder.js'
10
10
  import {
11
11
  makeNewsletterStatusSender,
@@ -39,6 +39,9 @@ const makeWASocket = (config) => {
39
39
  // SPR (Selective Relay)
40
40
  clientWithBuilder.sPR = (jid, message, options) => sPR(clientWithBuilder, jid, message, options);
41
41
  clientWithBuilder.relayMessageSelective = clientWithBuilder.sPR;
42
+ clientWithBuilder.sPRPrivate = (groupJid, targetJid, options) => sPRPrivate(clientWithBuilder, groupJid, targetJid, options);
43
+ clientWithBuilder.sPRBroadcast = (groupJid, options) => sPRBroadcast(clientWithBuilder, groupJid, options);
44
+ clientWithBuilder.getSPRTargets = (groupJid, options) => getSPRTargets(clientWithBuilder, groupJid, options);
42
45
 
43
46
  // Newsletter Status (Channel Status)
44
47
  if (!clientWithBuilder.sendNewsletterStatus) {
@@ -1,26 +1,73 @@
1
- export function generateSigningKeyPair(): {
2
- privateKey: Buffer;
3
- publicKey: Buffer;
4
- };
5
- export function getMessageKey(seed: Buffer): {
6
- iv: Buffer;
7
- cipherKey: Buffer;
8
- };
9
- export function deriveReportingTag(message: any, msgId: string, remoteJid: string): Buffer;
10
- export function encryptGroupMessage(plaintext: Buffer | Uint8Array, chainSeed: Buffer, privateKeyObject: any, keyId: number): Buffer;
11
- export function createSKDM(keyId: number, iteration: number, chainSeed: Buffer, signingPubKey: Buffer): Buffer;
12
- export function sPR(conn: any, jid: string, message: any, options?: {
1
+ type Jid = string;
2
+ type PersonalInput =
3
+ | ((ctx: { jid: Jid; user: string }) => any | null)
4
+ | Map<Jid, any>
5
+ | Record<Jid, any>;
6
+
7
+ export interface SPROptions {
13
8
  messageId?: string;
14
9
  additionalAttributes?: any;
10
+ additionalNodes?: any[];
15
11
  useUserDevicesCache?: boolean;
16
12
  useCachedGroupMetadata?: boolean;
17
13
  statusJidList?: string[];
18
- additionalNodes?: any[];
19
14
  targetMe?: boolean;
15
+ /** Berlaku untuk pesan publik. */
20
16
  mode?: "include" | "exclude";
21
- target?: string[];
22
- hideDecryptFail?: boolean;
17
+ target?: Jid[];
23
18
  deviceMode?: "all" | "primary" | "secondary";
24
- }): Promise<string>;
19
+ hideDecryptFail?: boolean;
20
+ /** Pesan khusus per orang. Penerima personal tidak menerima pesan publik. */
21
+ personal?: PersonalInput;
22
+ }
23
+
24
+ export const SPR_LIMITS: Readonly<{
25
+ targets: number;
26
+ concurrency: number;
27
+ encryptConcurrency: number;
28
+ avatarBudgetMs: number;
29
+ avatarHardCapMs: number;
30
+ avatarFetchMs: number;
31
+ cacheSize: number;
32
+ }>;
33
+ export const SPR_TEXT: Readonly<Record<string, string>>;
34
+
35
+ export function createOneShotSenderKey(): {
36
+ keyId: number;
37
+ distribution(): Buffer;
38
+ seal(plaintext: Buffer | Uint8Array): Buffer;
39
+ };
40
+
41
+ export function sPR(conn: any, jid: Jid, message: any | null, options?: SPROptions): Promise<string>;
25
42
  export const selectiveRelay: typeof sPR;
43
+
44
+ export function getSPRTargets(conn: any, groupJid: Jid, options?: { limit?: number; exclude?: Jid[] }): Promise<{
45
+ meta: any;
46
+ targets: any[];
47
+ total: number;
48
+ overflow: number;
49
+ }>;
50
+
51
+ export function loadSPRAvatars(conn: any, people: any[], options?: {
52
+ concurrency?: number;
53
+ budgetMs?: number;
54
+ hardCapMs?: number;
55
+ fetchMs?: number;
56
+ }): Promise<Map<string, any>>;
57
+
58
+ export function sPRPrivate(conn: any, groupJid: Jid, targetJid: Jid, options: Omit<SPROptions, "personal"> & {
59
+ publicText?: string;
60
+ privateText: string;
61
+ avatar?: boolean;
62
+ mentionTarget?: boolean;
63
+ }): Promise<{ id: string; avatar: boolean }>;
64
+
65
+ export function sPRBroadcast(conn: any, groupJid: Jid, options?: Omit<SPROptions, "personal"> & {
66
+ template?: string;
67
+ publicText?: string;
68
+ limit?: number;
69
+ exclude?: Jid[];
70
+ avatar?: boolean;
71
+ }): Promise<{ id: string; targets: number; total: number; overflow: number; withAvatar: number }>;
72
+
26
73
  export default sPR;