whisp-js 0.0.0-stage → 0.3.0

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +739 -2
  3. package/dist/cjs/client.d.ts +213 -0
  4. package/dist/cjs/client.js +570 -0
  5. package/dist/cjs/constants.d.ts +43 -0
  6. package/dist/cjs/constants.js +60 -0
  7. package/dist/cjs/errors.d.ts +96 -0
  8. package/dist/cjs/errors.js +115 -0
  9. package/dist/cjs/index.d.ts +19 -0
  10. package/dist/cjs/index.js +39 -0
  11. package/dist/cjs/listener.d.ts +93 -0
  12. package/dist/cjs/listener.js +457 -0
  13. package/dist/cjs/media.d.ts +40 -0
  14. package/dist/cjs/media.js +181 -0
  15. package/dist/cjs/package.json +3 -0
  16. package/dist/cjs/refs.d.ts +4 -0
  17. package/dist/cjs/refs.js +38 -0
  18. package/dist/cjs/runtime.d.ts +24 -0
  19. package/dist/cjs/runtime.js +93 -0
  20. package/dist/cjs/sse.d.ts +32 -0
  21. package/dist/cjs/sse.js +105 -0
  22. package/dist/cjs/transport.d.ts +61 -0
  23. package/dist/cjs/transport.js +181 -0
  24. package/dist/cjs/types.d.ts +583 -0
  25. package/dist/cjs/types.js +14 -0
  26. package/dist/cjs/version.d.ts +2 -0
  27. package/dist/cjs/version.js +5 -0
  28. package/dist/cjs/webhook.d.ts +27 -0
  29. package/dist/cjs/webhook.js +128 -0
  30. package/dist/esm/client.d.ts +213 -0
  31. package/dist/esm/client.js +566 -0
  32. package/dist/esm/constants.d.ts +43 -0
  33. package/dist/esm/constants.js +57 -0
  34. package/dist/esm/errors.d.ts +96 -0
  35. package/dist/esm/errors.js +107 -0
  36. package/dist/esm/index.d.ts +19 -0
  37. package/dist/esm/index.js +16 -0
  38. package/dist/esm/listener.d.ts +93 -0
  39. package/dist/esm/listener.js +452 -0
  40. package/dist/esm/media.d.ts +40 -0
  41. package/dist/esm/media.js +175 -0
  42. package/dist/esm/refs.d.ts +4 -0
  43. package/dist/esm/refs.js +33 -0
  44. package/dist/esm/runtime.d.ts +24 -0
  45. package/dist/esm/runtime.js +84 -0
  46. package/dist/esm/sse.d.ts +32 -0
  47. package/dist/esm/sse.js +100 -0
  48. package/dist/esm/transport.d.ts +61 -0
  49. package/dist/esm/transport.js +172 -0
  50. package/dist/esm/types.d.ts +583 -0
  51. package/dist/esm/types.js +13 -0
  52. package/dist/esm/version.d.ts +2 -0
  53. package/dist/esm/version.js +2 -0
  54. package/dist/esm/webhook.d.ts +27 -0
  55. package/dist/esm/webhook.js +123 -0
  56. package/package.json +37 -5
@@ -0,0 +1,213 @@
1
+ import { type EventHandlers } from './listener.js';
2
+ import { type MediaSource } from './media.js';
3
+ import { type Timers } from './runtime.js';
4
+ import type { Chat, ChatListQuery, ChatMessagesQuery, MarkReadResult, Message, PhoneCheck, ProjectInfo, PublicEventType, SendMessageBody, SendStrategy, TypingOptions, TypingResult, WebhookEvent, WhatsAppNumber } from './types.js';
5
+ import { type VerifyWebhookInput } from './webhook.js';
6
+ export declare const DEFAULT_TIMEOUT_MS = 30000;
7
+ export declare const DEFAULT_MAX_RETRIES = 2;
8
+ /** `downloadMedia` waits for a file being prepared at most this long. */
9
+ export declare const MEDIA_WAIT_MAX_MS = 60000;
10
+ export interface WhispOptions {
11
+ /** The project token (`wsp_live_…`). Default: WHISP_API_TOKEN, read on each call until set. */
12
+ token?: string;
13
+ /** Phones (`972501234567`, `+972 50-123-4567`) or number ids (`num_7Hq2kD3x`); none = the whole project. */
14
+ phone?: string | readonly string[];
15
+ /**
16
+ * How a pool picks its sender: 'healthiest' (the server's default), 'random' or 'round-robin'. Only used
17
+ * with several numbers or none.
18
+ */
19
+ strategy?: SendStrategy;
20
+ /** Keep a recipient on the number that last talked to them. Default true. */
21
+ sticky?: boolean;
22
+ /**
23
+ * Send from a number only while it has sent fewer than this many messages in the last 24 hours (1 to
24
+ * 10,000), on every send of this instance. A number's own daily cap still applies: the lower one wins. The
25
+ * server counts and enforces it; a pool skips numbers at their cap, a single number answers
26
+ * DAILY_CAP_REACHED.
27
+ */
28
+ dailyCap?: number;
29
+ /** Default: WHISP_API_URL, else https://api.whisp.lue.my. */
30
+ baseUrl?: string;
31
+ /** Per attempt. Default 30,000 ms. */
32
+ timeoutMs?: number;
33
+ /** Attempts after the first, for network errors, timeouts, 429 and 5xx. Default 2. */
34
+ maxRetries?: number;
35
+ /** Resume the event stream after this cursor (a saved `whisp.cursor`). */
36
+ cursor?: string;
37
+ /** Any WHATWG fetch. Default: the global one, looked up on each call. */
38
+ fetch?: typeof fetch;
39
+ /**
40
+ * The SDK refuses to run in a browser, where every visitor could copy the
41
+ * token. Even with this set, the API answers 403 TOKEN_IN_BROWSER.
42
+ */
43
+ dangerouslyAllowBrowser?: boolean;
44
+ }
45
+ /** Test hooks; not part of the published options. */
46
+ export interface InternalWhispOptions extends WhispOptions {
47
+ timers?: Timers;
48
+ /** Where errors go when nobody listens to `'error'`. Default console.error. */
49
+ report?: (error: Error) => void;
50
+ }
51
+ export interface SendOptions {
52
+ /** A `msg_` id or a WhatsApp id of a message in the same chat. */
53
+ replyTo?: string;
54
+ /** Your own id for this send (1-128 characters), echoed on the message and its events. */
55
+ reference?: string;
56
+ /** Wait for the outcome: true is 15 s, or a number of ms from 1,000 to 20,000. */
57
+ wait?: boolean | number;
58
+ /** This send's daily cap (1 to 10,000), in place of the instance's `dailyCap`. */
59
+ dailyCap?: number;
60
+ /** Makes retries safe across your own restarts too. Default: a random UUID per call, kept across its retries. */
61
+ idempotencyKey?: string;
62
+ /**
63
+ * Phones or `<digits>@lid` JIDs to mention (0.3.0), each written `@<digits>` in the text or caption. Groups
64
+ * only; at most 50.
65
+ */
66
+ mentions?: string[];
67
+ }
68
+ export interface SendFileOptions extends SendOptions {
69
+ caption?: string;
70
+ }
71
+ /** A voice note has no text to carry `@<digits>`, so it takes no `mentions`. */
72
+ export type SendVoiceOptions = Omit<SendOptions, 'mentions'>;
73
+ export interface EditOptions {
74
+ /**
75
+ * Replaces the message's mentions (phones or `<digits>@lid` JIDs, each written `@<digits>` in `text`). Left
76
+ * out, the mentions still named in the new text are kept.
77
+ */
78
+ mentions?: string[];
79
+ }
80
+ export interface MessagesQuery {
81
+ reference: string;
82
+ }
83
+ export interface DownloadOptions {
84
+ variant?: 'original' | 'thumb';
85
+ }
86
+ /** One page of a list, and the cursor of the next one (null on the last). */
87
+ export interface Page<T> {
88
+ items: T[];
89
+ nextCursor: string | null;
90
+ }
91
+ /** Await it for the first page, or `for await` it for every item across pages. */
92
+ export type PageResult<T> = Promise<Page<T>> & AsyncIterable<T>;
93
+ export interface VerifyResult extends ProjectInfo {
94
+ numbers: WhatsAppNumber[];
95
+ }
96
+ export declare class Whisp {
97
+ #private;
98
+ constructor(options?: WhispOptions);
99
+ /**
100
+ * The cursor after the last event delivered to handlers (6.5): save it and
101
+ * pass it as `cursor` to resume after a restart. Not an event's `evt_` id,
102
+ * which is `event.event.id` in a handler. Before the first event it is
103
+ * where the stream started (its `ready`), so a save then resumes from
104
+ * there; null until the stream first opens, unless `cursor` was given
105
+ * (sdk-reconnect-without-cursor-loses-events).
106
+ */
107
+ get cursor(): string | null;
108
+ /** A copy that sends from, reads and listens on this one number (a phone or a `num_` id). */
109
+ number(phoneOrId: string): Whisp;
110
+ /**
111
+ * Checks the token and the instance's numbers (GET /project, then GET
112
+ * /numbers): throws NUMBER_NOT_IN_PROJECT listing every phone or id that
113
+ * isn't the token's project's. Optional: the first send or listen reports
114
+ * the same.
115
+ */
116
+ verify(): Promise<VerifyResult>;
117
+ /** Sends text (`POST /messages`) from the instance's number, pool or project. Resolves the message (`pending`, or its status after `wait`). */
118
+ send(to: string, text: string, options?: SendOptions): Promise<Message>;
119
+ sendImage(to: string, media: MediaSource, options?: SendFileOptions): Promise<Message>;
120
+ sendVideo(to: string, media: MediaSource, options?: SendFileOptions): Promise<Message>;
121
+ sendDocument(to: string, media: MediaSource, options?: SendFileOptions): Promise<Message>;
122
+ sendVoice(to: string, media: MediaSource, options?: SendVoiceOptions): Promise<Message>;
123
+ /**
124
+ * `POST /messages` with a body you build (5.6). The instance's `from`,
125
+ * `strategy`, `sticky` and `dailyCap` fill in what the body leaves out.
126
+ */
127
+ sendMessage(body: SendMessageBody, options?: Pick<SendOptions, 'idempotencyKey'>): Promise<Message>;
128
+ /**
129
+ * Sets this number's reaction to a message (one emoji), replacing its earlier one. Resolves once the server
130
+ * queued it for the number's connection; a `message.reaction` event with `fromMe: true` follows.
131
+ */
132
+ react(message: Message | string, emoji: string): Promise<void>;
133
+ /** Removes this number's reaction to a message. */
134
+ unreact(message: Message | string): Promise<void>;
135
+ /**
136
+ * Edits the text or caption of a message this number sent, within WhatsApp's 15 minutes
137
+ * (EDIT_WINDOW_PASSED after). Refused on a paused number (NUMBER_PAUSED). Resolves the edited message; the
138
+ * same text without `mentions` resolves it unchanged.
139
+ */
140
+ edit(message: Message | string, text: string, options?: EditOptions): Promise<Message>;
141
+ /**
142
+ * Deletes a message this number sent for everyone, within 2 days (REVOKE_WINDOW_PASSED after). Resolves the
143
+ * message with `deletedAt` set, also when it was deleted already.
144
+ */
145
+ revoke(message: Message | string): Promise<Message>;
146
+ /**
147
+ * Marks a chat of this instance's number read (a phone, a `cht_` id or a group JID). Unread is one count per
148
+ * chat, so this clears it for the panel's members too. `readReceipts` says what happened to the blue ticks:
149
+ * `queued` (handed to the server, not proof WhatsApp got them), `off` (the number's setting) or `none`
150
+ * (nothing was unread).
151
+ */
152
+ markRead(chat: string): Promise<MarkReadResult>;
153
+ /**
154
+ * Shows "typing..." (or "recording audio..." with `state: 'recording'`) in a chat of this instance's number (a
155
+ * phone, a `cht_` id or a group JID). The server keeps it up until a message of the number goes out in that chat
156
+ * (no need to stop before sending), stopTyping(), or 2 minutes from the latest start (call it again to keep
157
+ * going). Refused on a paused number (NUMBER_PAUSED), in a group the number left (NOT_IN_GROUP) and on a number
158
+ * that isn't connected or connecting (NUMBER_NOT_CONNECTED).
159
+ */
160
+ startTyping(chat: string, options?: TypingOptions): Promise<TypingResult>;
161
+ /** Stops this number's typing in a chat at once ("paused"). Safe to call when nothing is typing. */
162
+ stopTyping(chat: string): Promise<void>;
163
+ /** Every number of the project, any status. */
164
+ numbers(): Promise<WhatsAppNumber[]>;
165
+ /** One message of the project's numbers; 404 MESSAGE_NOT_FOUND otherwise. */
166
+ message(messageId: string): Promise<Message>;
167
+ /** What earlier sends with this `reference` made, newest first, at most 50. */
168
+ messages(query: MessagesQuery): Promise<Message[]>;
169
+ /** Is this phone on WhatsApp, asked through the instance's number. */
170
+ check(phone: string): Promise<PhoneCheck>;
171
+ /** The number's chats, newest activity first. */
172
+ chats(query?: ChatListQuery): PageResult<Chat>;
173
+ /** One chat: a phone, a `cht_` id or a group JID (a merged-away id resolves to the chat it joined). */
174
+ chat(chat: string): Promise<Chat>;
175
+ /**
176
+ * A chat's messages, newest first, history included. Each next page is
177
+ * older (`nextCursor` goes in `before`); after an `after` request, each next
178
+ * page is newer (`nextCursor` goes in `after`).
179
+ */
180
+ chatMessages(chat: string, query?: ChatMessagesQuery): PageResult<Message>;
181
+ /**
182
+ * A message's file as a fetch `Response` (12.3). Asks the API for a
183
+ * 5-minute link with the token, then fetches the link with no token and no
184
+ * redirects. A file still being prepared (409 MEDIA_NOT_READY with
185
+ * Retry-After) is waited for, up to 60 s.
186
+ */
187
+ downloadMedia(message: Message | string, options?: DownloadOptions): Promise<Response>;
188
+ /**
189
+ * Calls `handler` for each event of this name (12.4): any of the public
190
+ * types, `'message'` (= `message.received`), `'*'`, or the stream's own
191
+ * `'open'`, `'close'`, `'gap'` and `'error'`. The first event handler
192
+ * opens the stream. Returns `off()`.
193
+ */
194
+ on(event: '*', handler: EventHandlers['*']): () => void;
195
+ on(event: 'message', handler: EventHandlers['message']): () => void;
196
+ on(event: 'open', handler: EventHandlers['open']): () => void;
197
+ on(event: 'close', handler: EventHandlers['close']): () => void;
198
+ on(event: 'gap', handler: EventHandlers['gap']): () => void;
199
+ on(event: 'error', handler: EventHandlers['error']): () => void;
200
+ on<T extends PublicEventType>(event: T, handler: EventHandlers[T]): () => void;
201
+ /** Removes a handler; the stream closes with the last event handler. */
202
+ off(event: '*', handler: EventHandlers['*']): void;
203
+ off(event: 'message', handler: EventHandlers['message']): void;
204
+ off(event: 'open', handler: EventHandlers['open']): void;
205
+ off(event: 'close', handler: EventHandlers['close']): void;
206
+ off(event: 'gap', handler: EventHandlers['gap']): void;
207
+ off(event: 'error', handler: EventHandlers['error']): void;
208
+ off<T extends PublicEventType>(event: T, handler: EventHandlers[T]): void;
209
+ /** Ends the stream, forgets every handler, and stops retries still waiting for their turn. */
210
+ close(): void;
211
+ /** The standalone `verifyWebhook`, for convenience. */
212
+ verifyWebhook(input: VerifyWebhookInput): Promise<WebhookEvent>;
213
+ }