morok-bot-sdk 1.0.1
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/LICENSE +201 -0
- package/README.md +602 -0
- package/README.ru.md +602 -0
- package/dist/bot.d.ts +232 -0
- package/dist/bot.d.ts.map +1 -0
- package/dist/bot.js +558 -0
- package/dist/bot.js.map +1 -0
- package/dist/crypto/channel-cipher.d.ts +32 -0
- package/dist/crypto/channel-cipher.d.ts.map +1 -0
- package/dist/crypto/channel-cipher.js +77 -0
- package/dist/crypto/channel-cipher.js.map +1 -0
- package/dist/crypto/channel-key-store.d.ts +37 -0
- package/dist/crypto/channel-key-store.d.ts.map +1 -0
- package/dist/crypto/channel-key-store.js +149 -0
- package/dist/crypto/channel-key-store.js.map +1 -0
- package/dist/crypto/cross-signing.d.ts +57 -0
- package/dist/crypto/cross-signing.d.ts.map +1 -0
- package/dist/crypto/cross-signing.js +111 -0
- package/dist/crypto/cross-signing.js.map +1 -0
- package/dist/crypto/file-cipher.d.ts +36 -0
- package/dist/crypto/file-cipher.d.ts.map +1 -0
- package/dist/crypto/file-cipher.js +61 -0
- package/dist/crypto/file-cipher.js.map +1 -0
- package/dist/crypto/group-secret-cipher.d.ts +49 -0
- package/dist/crypto/group-secret-cipher.d.ts.map +1 -0
- package/dist/crypto/group-secret-cipher.js +69 -0
- package/dist/crypto/group-secret-cipher.js.map +1 -0
- package/dist/crypto/group-secret-store.d.ts +35 -0
- package/dist/crypto/group-secret-store.d.ts.map +1 -0
- package/dist/crypto/group-secret-store.js +149 -0
- package/dist/crypto/group-secret-store.js.map +1 -0
- package/dist/crypto/signal.d.ts +81 -0
- package/dist/crypto/signal.d.ts.map +1 -0
- package/dist/crypto/signal.js +125 -0
- package/dist/crypto/signal.js.map +1 -0
- package/dist/crypto/stores.d.ts +130 -0
- package/dist/crypto/stores.d.ts.map +1 -0
- package/dist/crypto/stores.js +314 -0
- package/dist/crypto/stores.js.map +1 -0
- package/dist/flow/attachments.d.ts +110 -0
- package/dist/flow/attachments.d.ts.map +1 -0
- package/dist/flow/attachments.js +409 -0
- package/dist/flow/attachments.js.map +1 -0
- package/dist/flow/conv-cache.d.ts +36 -0
- package/dist/flow/conv-cache.d.ts.map +1 -0
- package/dist/flow/conv-cache.js +84 -0
- package/dist/flow/conv-cache.js.map +1 -0
- package/dist/flow/direct.d.ts +109 -0
- package/dist/flow/direct.d.ts.map +1 -0
- package/dist/flow/direct.js +346 -0
- package/dist/flow/direct.js.map +1 -0
- package/dist/flow/groups.d.ts +146 -0
- package/dist/flow/groups.d.ts.map +1 -0
- package/dist/flow/groups.js +768 -0
- package/dist/flow/groups.js.map +1 -0
- package/dist/flow/prekeys.d.ts +45 -0
- package/dist/flow/prekeys.d.ts.map +1 -0
- package/dist/flow/prekeys.js +111 -0
- package/dist/flow/prekeys.js.map +1 -0
- package/dist/flow/receive.d.ts +125 -0
- package/dist/flow/receive.d.ts.map +1 -0
- package/dist/flow/receive.js +773 -0
- package/dist/flow/receive.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/morokbot-file.d.ts +14 -0
- package/dist/morokbot-file.d.ts.map +1 -0
- package/dist/morokbot-file.js +88 -0
- package/dist/morokbot-file.js.map +1 -0
- package/dist/ratelimit.d.ts +40 -0
- package/dist/ratelimit.d.ts.map +1 -0
- package/dist/ratelimit.js +76 -0
- package/dist/ratelimit.js.map +1 -0
- package/dist/sessions.d.ts +34 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +69 -0
- package/dist/sessions.js.map +1 -0
- package/dist/state-lock.d.ts +17 -0
- package/dist/state-lock.d.ts.map +1 -0
- package/dist/state-lock.js +66 -0
- package/dist/state-lock.js.map +1 -0
- package/dist/transport/http.d.ts +48 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +112 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/ws.d.ts +65 -0
- package/dist/transport/ws.d.ts.map +1 -0
- package/dist/transport/ws.js +219 -0
- package/dist/transport/ws.js.map +1 -0
- package/dist/types.d.ts +254 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
package/dist/bot.d.ts
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public orchestrator. Use MorokBot.fromFile(...) to construct
|
|
3
|
+
* The ctor is private because .morokbot parsing and state-dir setup need IO
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle:
|
|
6
|
+
* fromFile: parse .morokbot, build modules (no network IO)
|
|
7
|
+
* start(): import keys, fsck state, /auth/bot-session, WS handshake, prekey replenish + background loop
|
|
8
|
+
* stop(): prekey loop -> ws -> pending sends -> done
|
|
9
|
+
*
|
|
10
|
+
* `error` fires on recoverable failures (decrypt errors, exceptions thrown by developer handlers)
|
|
11
|
+
* start() itself throws on fatal init errors (bad .morokbot, 401, etc.)
|
|
12
|
+
*/
|
|
13
|
+
import { EventEmitter } from 'node:events';
|
|
14
|
+
import type { BotConfig, IncomingMessage, CommandInvocation, BotStartEvent, BotStopEvent, ReactionEvent, ControlEvent, BotControl, ConversationAddedEvent, ConversationKickedEvent, DisconnectInfo, AttachmentInput } from './types.js';
|
|
15
|
+
import { type SendResult } from './flow/direct.js';
|
|
16
|
+
export interface SendArgs {
|
|
17
|
+
/**
|
|
18
|
+
* DM target, numeric userId or username (the SDK resolves a username via `GET /users/:username`)
|
|
19
|
+
* Mutually exclusive with `conversation`
|
|
20
|
+
*/
|
|
21
|
+
peer?: number | string;
|
|
22
|
+
/**
|
|
23
|
+
* Group-chat / channel target, numeric conversationId. Mutually exclusive with `peer`
|
|
24
|
+
* The bot must already be a member, obtain `conversationId` from a `conversation_added` event,
|
|
25
|
+
* or from an incoming `IncomingMessage.conversationId` when responding to one
|
|
26
|
+
*/
|
|
27
|
+
conversation?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Message text. Required when `attachment` is absent
|
|
30
|
+
* Sent alongside a `'file'` attachment, it becomes the caption
|
|
31
|
+
* Ignored (with a debug log) for `'voice'` and `'video_note'` attachments,
|
|
32
|
+
* the FE renderer has no caption slot for those
|
|
33
|
+
*/
|
|
34
|
+
text?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Single attachment (file / voice / video_note). Mutually exclusive with `attachments`
|
|
37
|
+
*/
|
|
38
|
+
attachment?: AttachmentInput;
|
|
39
|
+
/**
|
|
40
|
+
* Gallery of 2-10 file attachments shipped in one message, the bubble renders as a grid on the FE
|
|
41
|
+
* voice and video_note are not allowed in a gallery
|
|
42
|
+
* (server caps and FE renderer both expect `kind: 'file'` per item). Mutually exclusive with `attachment`
|
|
43
|
+
*/
|
|
44
|
+
attachments?: AttachmentInput[];
|
|
45
|
+
replyToId?: number;
|
|
46
|
+
replyToClientMsgId?: string;
|
|
47
|
+
threadRootId?: number;
|
|
48
|
+
/** Disappearing-message TTL in seconds. Server-validated */
|
|
49
|
+
expiresInSeconds?: number;
|
|
50
|
+
}
|
|
51
|
+
export interface ReplyArgs {
|
|
52
|
+
text?: string;
|
|
53
|
+
attachment?: AttachmentInput;
|
|
54
|
+
attachments?: AttachmentInput[];
|
|
55
|
+
expiresInSeconds?: number;
|
|
56
|
+
}
|
|
57
|
+
interface MorokBotEvents {
|
|
58
|
+
message: (msg: IncomingMessage) => void | Promise<void>;
|
|
59
|
+
command: (cmd: CommandInvocation) => void | Promise<void>;
|
|
60
|
+
start: (e: BotStartEvent) => void | Promise<void>;
|
|
61
|
+
stop: (e: BotStopEvent) => void | Promise<void>;
|
|
62
|
+
reaction: (e: ReactionEvent) => void | Promise<void>;
|
|
63
|
+
control: (e: ControlEvent) => void | Promise<void>;
|
|
64
|
+
conversation_added: (e: ConversationAddedEvent) => void | Promise<void>;
|
|
65
|
+
conversation_kicked: (e: ConversationKickedEvent) => void | Promise<void>;
|
|
66
|
+
disconnect: (info: DisconnectInfo) => void | Promise<void>;
|
|
67
|
+
error: (err: Error) => void | Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
export declare class MorokBot extends EventEmitter {
|
|
70
|
+
private readonly file;
|
|
71
|
+
private readonly stateDir;
|
|
72
|
+
private readonly apiBaseUrl;
|
|
73
|
+
private readonly wsUrlVal;
|
|
74
|
+
private readonly logger?;
|
|
75
|
+
private readonly bgIntervalMs;
|
|
76
|
+
private readonly replenishThreshold;
|
|
77
|
+
private readonly replenishTarget;
|
|
78
|
+
private readonly autoBackfillOnJoin;
|
|
79
|
+
private readonly serveBackfillRequests;
|
|
80
|
+
private signal?;
|
|
81
|
+
private http?;
|
|
82
|
+
private ws?;
|
|
83
|
+
private direct?;
|
|
84
|
+
private receive?;
|
|
85
|
+
private groups?;
|
|
86
|
+
private chanStore?;
|
|
87
|
+
private gsStore?;
|
|
88
|
+
private convCache?;
|
|
89
|
+
private stateLock?;
|
|
90
|
+
private prekey?;
|
|
91
|
+
private botUserId?;
|
|
92
|
+
private running;
|
|
93
|
+
/** Set true synchronously when start() enters, before any await, so a second concurrent start() returns
|
|
94
|
+
* without opening a second WS. Separate from `running` so isConnected stays accurate during boot */
|
|
95
|
+
private starting;
|
|
96
|
+
/** Flipped by stop() while start() is mid-flight. start() checks it at every checkpoint,
|
|
97
|
+
* and throws into its own catch so teardown runs and nothing is left open */
|
|
98
|
+
private stopRequested;
|
|
99
|
+
private constructor();
|
|
100
|
+
/** Read + validate the .morokbot file and build the bot. No network IO, call start() to connect */
|
|
101
|
+
static fromFile(config: BotConfig & {
|
|
102
|
+
tokenFile: string;
|
|
103
|
+
}): Promise<MorokBot>;
|
|
104
|
+
/** Connect. Resolves after WS auth + boot prekey replenish. Throws on fatal init errors. Idempotent */
|
|
105
|
+
start(): Promise<void>;
|
|
106
|
+
private assertResolvedUserId;
|
|
107
|
+
/**
|
|
108
|
+
* One-shot device-certificate publish (D cross-signing). Signs a certificate over this device's identity key
|
|
109
|
+
* under the .morokbot account signing key (XSK) and commits it via POST /crypto/cross-signing,
|
|
110
|
+
* so peers verify the bot's device against its account key and render a cross-signed safety number
|
|
111
|
+
* (routes/developer.ts:556 documents this obligation)
|
|
112
|
+
*
|
|
113
|
+
* Best-effort and idempotent: re-submitting the same (XSK, cert) on every start succeeds server-side
|
|
114
|
+
* Any failure (network, 409 XSK_ALREADY_SET / IDENTITY_ROTATED, missing XSK) is logged and non-fatal,
|
|
115
|
+
* the bot keeps running uncertified while peers fall back to TOFU
|
|
116
|
+
* One device per bot, so the FE's multi-device XSK propagation races don't apply here
|
|
117
|
+
*
|
|
118
|
+
* Skipped silently when the .morokbot predates cross-signing (no accountSigningKey), matching the FE
|
|
119
|
+
*/
|
|
120
|
+
private ensureCrossSigning;
|
|
121
|
+
/** Clean shutdown. Stops background loops, closes the socket, rejects pending sends,
|
|
122
|
+
* releases the state lock. Idempotent. If start() is mid-flight, stopRequested makes it abort
|
|
123
|
+
* at the next checkpoint into its catch path */
|
|
124
|
+
stop(): Promise<void>;
|
|
125
|
+
get isConnected(): boolean;
|
|
126
|
+
/** Bot's own userId. Available after start() resolves */
|
|
127
|
+
get userId(): number;
|
|
128
|
+
send(args: SendArgs): Promise<SendResult>;
|
|
129
|
+
private sendDirect;
|
|
130
|
+
private sendGroup;
|
|
131
|
+
/** Rotate the channel-key. Mints a fresh 32-byte secret, wraps it to every other member device,
|
|
132
|
+
* POSTs to /channel-key/rotate. The server allows any member,
|
|
133
|
+
* so the bot's call is functionally identical to a human admin's */
|
|
134
|
+
rotateChannelKey(conversationId: number): Promise<{
|
|
135
|
+
epoch: number;
|
|
136
|
+
}>;
|
|
137
|
+
/** Share locally-known channel-key epochs with another member's devices
|
|
138
|
+
* Useful when the bot is the only online member at the moment a new joiner needs history
|
|
139
|
+
*
|
|
140
|
+
* target.deviceIds optional, absent = fetch via /prekeys/:userId/devices
|
|
141
|
+
* opts.epochs optional, absent = all local epochs. Server filters pre-join epochs by joined_secret_version */
|
|
142
|
+
backfillChannelKeys(conversationId: number, target: {
|
|
143
|
+
userId: number;
|
|
144
|
+
deviceIds?: number[];
|
|
145
|
+
}, opts?: {
|
|
146
|
+
epochs?: number[];
|
|
147
|
+
}): Promise<{
|
|
148
|
+
accepted: number;
|
|
149
|
+
}>;
|
|
150
|
+
/**
|
|
151
|
+
* Rotate group_secret and channel-key in one server transaction
|
|
152
|
+
* Run after kicking a leaker so a stale ex-member can't unseal future bundles with the old group_secret
|
|
153
|
+
*
|
|
154
|
+
* Server constraints (POST /groups/:id/group-secret/rotate):
|
|
155
|
+
* - conv type must be GROUP
|
|
156
|
+
* - conv must be private or the caller must be owner
|
|
157
|
+
* - bot must hold the current group_secret (auto-fetched)
|
|
158
|
+
*
|
|
159
|
+
* Error codes (axios error.response.data.code):
|
|
160
|
+
* SECRET_VERSION_STALE : someone else rotated, retry
|
|
161
|
+
* NOT_PRIVATE : bot lacks permission
|
|
162
|
+
* DIST_MISMATCH : membership shifted mid-rotate
|
|
163
|
+
* NO_READY_DEVICES : no recipient had an SPK
|
|
164
|
+
*
|
|
165
|
+
* Also re-seals every locally-known historical epoch under the new group_secret (server's resealHistorical field)
|
|
166
|
+
* After a rotate, no epoch is unsealable with the old secret
|
|
167
|
+
* If the bot is missing some historical epochs it reseals what it has, the rest can be patched on a later rotate
|
|
168
|
+
*/
|
|
169
|
+
rotateGroupSecret(conversationId: number): Promise<{
|
|
170
|
+
epoch: number;
|
|
171
|
+
version: number;
|
|
172
|
+
}>;
|
|
173
|
+
/**
|
|
174
|
+
* Replace the bot's slash-command catalogue (the /-autocomplete the composer offers users)
|
|
175
|
+
* Call after start(). Defining handlers does not advertise commands, the catalogue is separate
|
|
176
|
+
* Server bounds: up to 32 entries, name /^[a-z][a-z0-9_]{0,31}$/, description trimmed to 256 chars
|
|
177
|
+
* An empty array clears it. Idempotent, safe to call on every start
|
|
178
|
+
*/
|
|
179
|
+
setMyCommands(commands: ReadonlyArray<{
|
|
180
|
+
command: string;
|
|
181
|
+
description: string;
|
|
182
|
+
sortOrder?: number;
|
|
183
|
+
}>): Promise<{
|
|
184
|
+
count: number;
|
|
185
|
+
}>;
|
|
186
|
+
setMyControls(controls: ReadonlyArray<BotControl>): Promise<{
|
|
187
|
+
count: number;
|
|
188
|
+
}>;
|
|
189
|
+
/**
|
|
190
|
+
* Set the control buttons for ONE user's chat without touching the global menu others see
|
|
191
|
+
* Use it to drive a stateful flow, for example search results as buttons or a step-by-step wizard
|
|
192
|
+
* Pass the user id from an incoming message or control event (sender.userId)
|
|
193
|
+
* The override is short-lived on the server and survives that user's reload
|
|
194
|
+
* An empty array shows no buttons, call clearControlsFor to revert to the global menu
|
|
195
|
+
* Bounds match setMyControls, up to 16 top-level and 64 total nodes and depth 4
|
|
196
|
+
*/
|
|
197
|
+
setControlsFor(peerUserId: number, controls: ReadonlyArray<BotControl>): Promise<{
|
|
198
|
+
count: number;
|
|
199
|
+
}>;
|
|
200
|
+
/**
|
|
201
|
+
* Drop a user's per-chat control override and revert them to the global menu set by setMyControls
|
|
202
|
+
* Call this when the flow ends
|
|
203
|
+
*/
|
|
204
|
+
clearControlsFor(peerUserId: number): Promise<void>;
|
|
205
|
+
/** Reply to an incoming message. Threads replyToId/clientMsgId,
|
|
206
|
+
* routes DM vs group/channel by msg.conversationType */
|
|
207
|
+
reply(msg: IncomingMessage, args: ReplyArgs): Promise<SendResult>;
|
|
208
|
+
/**
|
|
209
|
+
* React to a message with a unicode symbol (any character, emoji included)
|
|
210
|
+
* DM reactions are encrypted per peer device (Signal), group-chat/channel reactions under the shared channel-key
|
|
211
|
+
* The reactor (this bot) is never echoed its own reaction back,
|
|
212
|
+
* so this resolves as soon as the frame is queued, there is no own-echo to await
|
|
213
|
+
* Re-reacting with a different symbol replaces the bot's previous one server-side
|
|
214
|
+
*
|
|
215
|
+
* `msg` is an incoming message or command. It carries messageId, conversationId,
|
|
216
|
+
* conversationType and sender. In a DM the reaction is encrypted to msg.sender (the peer)
|
|
217
|
+
*/
|
|
218
|
+
react(msg: IncomingMessage, unicode: string): Promise<void>;
|
|
219
|
+
/**
|
|
220
|
+
* Remove this bot's reaction from a message. The server keys deletion off (messageId, reactorUserId),
|
|
221
|
+
* so no ciphertext is needed. One frame clears every distribution shape the bot wrote
|
|
222
|
+
*/
|
|
223
|
+
unreact(msg: IncomingMessage): Promise<void>;
|
|
224
|
+
/** Resolve userId or username to a userId. Usernames hit GET /users/:username every time
|
|
225
|
+
* (bots usually pass userId from an incoming message, so the miss is rare) */
|
|
226
|
+
private resolvePeerUserId;
|
|
227
|
+
on<K extends keyof MorokBotEvents>(event: K, listener: MorokBotEvents[K]): this;
|
|
228
|
+
off<K extends keyof MorokBotEvents>(event: K, listener: MorokBotEvents[K]): this;
|
|
229
|
+
emit<K extends keyof MorokBotEvents>(event: K, ...args: Parameters<MorokBotEvents[K]>): boolean;
|
|
230
|
+
}
|
|
231
|
+
export {};
|
|
232
|
+
//# sourceMappingURL=bot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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"}
|