@open-apime/sdk 0.2.2
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 +22 -0
- package/README.md +44 -0
- package/dist/chunk-2BUPSB7O.js +0 -0
- package/dist/chunk-HS2RZ6SJ.js +93 -0
- package/dist/events-BV5UVoFu.d.cts +90 -0
- package/dist/events-BV5UVoFu.d.ts +90 -0
- package/dist/index-37ITjlwO.d.cts +83 -0
- package/dist/index-TqYrYke0.d.ts +83 -0
- package/dist/index.cjs +816 -0
- package/dist/index.d.cts +512 -0
- package/dist/index.d.ts +512 -0
- package/dist/index.js +719 -0
- package/dist/types/index.cjs +18 -0
- package/dist/types/index.d.cts +46 -0
- package/dist/types/index.d.ts +46 -0
- package/dist/types/index.js +1 -0
- package/dist/webhook/index.cjs +78 -0
- package/dist/webhook/index.d.cts +2 -0
- package/dist/webhook/index.d.ts +2 -0
- package/dist/webhook/index.js +12 -0
- package/package.json +73 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
import "./chunk-2BUPSB7O.js";
|
|
2
|
+
import {
|
|
3
|
+
ApiError,
|
|
4
|
+
ApimeError,
|
|
5
|
+
AuthenticationError,
|
|
6
|
+
ConfigurationError,
|
|
7
|
+
ConflictError,
|
|
8
|
+
ConnectionError,
|
|
9
|
+
InvalidRequestError,
|
|
10
|
+
InvalidSignatureError,
|
|
11
|
+
NotFoundError,
|
|
12
|
+
PermissionError,
|
|
13
|
+
RateLimitError,
|
|
14
|
+
SessionUnavailableError,
|
|
15
|
+
TimeoutError,
|
|
16
|
+
UnprocessableError,
|
|
17
|
+
constructEvent,
|
|
18
|
+
verifyWebhookSignature
|
|
19
|
+
} from "./chunk-HS2RZ6SJ.js";
|
|
20
|
+
|
|
21
|
+
// src/observability/sentry.ts
|
|
22
|
+
function findScope() {
|
|
23
|
+
const carrier = globalThis.__SENTRY__;
|
|
24
|
+
if (!carrier?.version) return void 0;
|
|
25
|
+
const versioned = carrier[carrier.version];
|
|
26
|
+
const scope = versioned?.globalScope;
|
|
27
|
+
return typeof scope?.captureException === "function" ? scope : void 0;
|
|
28
|
+
}
|
|
29
|
+
function hasSentry() {
|
|
30
|
+
return findScope() !== void 0;
|
|
31
|
+
}
|
|
32
|
+
function reportToSentry(info) {
|
|
33
|
+
const scope = findScope();
|
|
34
|
+
if (!scope) return;
|
|
35
|
+
scope.captureException(info.error, {
|
|
36
|
+
captureContext: {
|
|
37
|
+
tags: {
|
|
38
|
+
sdk: "open-apime",
|
|
39
|
+
route: info.route,
|
|
40
|
+
method: info.method,
|
|
41
|
+
...info.status !== void 0 ? { status: String(info.status) } : {}
|
|
42
|
+
},
|
|
43
|
+
extra: {
|
|
44
|
+
// Nao mandamos `path`: ele carrega o jid do contato, ou seja o telefone
|
|
45
|
+
// de quem conversa. `route` ja identifica o endpoint sem isso.
|
|
46
|
+
instanceId: info.instanceId,
|
|
47
|
+
attempt: info.attempt,
|
|
48
|
+
durationMs: info.durationMs,
|
|
49
|
+
idempotencyKey: info.idempotencyKey
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/observability/index.ts
|
|
56
|
+
function safeNotify(fn) {
|
|
57
|
+
if (!fn) return;
|
|
58
|
+
try {
|
|
59
|
+
fn();
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function toRoute(path) {
|
|
64
|
+
return path.replace(/\/instances\/[^/]+/, "/instances/{id}").replace(/\/(profile|business)\/[^/]+\/picture/, "/$1/{jid}/picture").replace(/\/(profile|business|contacts|userinfo|newsletters)\/[^/]+/, "/$1/{jid}").replace(/\/chat-settings\/[^/]+/, "/chat-settings/{chat}").replace(/\/groups\/(?!join$|resolve-invite$)[^/]+/, "/groups/{group}").replace(/\/tokens\/[^/]+$/, "/tokens/{tokenId}").replace(/\/users\/[^/]+(?=\/|$)/, "/users/{id}");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/http/errors.ts
|
|
68
|
+
function messageFrom(body, status) {
|
|
69
|
+
if (body && typeof body === "object" && "error" in body) {
|
|
70
|
+
const raw = body.error;
|
|
71
|
+
if (typeof raw === "string" && raw.length > 0) return raw;
|
|
72
|
+
}
|
|
73
|
+
return `HTTP ${status}`;
|
|
74
|
+
}
|
|
75
|
+
function retryAfterMs(headers) {
|
|
76
|
+
const raw = headers.get("retry-after");
|
|
77
|
+
if (!raw) return void 0;
|
|
78
|
+
const seconds = Number(raw);
|
|
79
|
+
if (Number.isFinite(seconds)) return seconds * 1e3;
|
|
80
|
+
const date = Date.parse(raw);
|
|
81
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
82
|
+
}
|
|
83
|
+
function errorFromResponse(status, body, headers) {
|
|
84
|
+
const message = messageFrom(body, status);
|
|
85
|
+
const requestId = headers.get("x-request-id") ?? void 0;
|
|
86
|
+
const base = { status, body, ...requestId !== void 0 ? { requestId } : {} };
|
|
87
|
+
switch (status) {
|
|
88
|
+
case 401:
|
|
89
|
+
return new AuthenticationError(message, base);
|
|
90
|
+
case 403:
|
|
91
|
+
return new PermissionError(message, base);
|
|
92
|
+
case 404:
|
|
93
|
+
return new NotFoundError(message, base);
|
|
94
|
+
case 409:
|
|
95
|
+
return new ConflictError(message, base);
|
|
96
|
+
case 422:
|
|
97
|
+
return new UnprocessableError(message, base);
|
|
98
|
+
case 429: {
|
|
99
|
+
const after = retryAfterMs(headers);
|
|
100
|
+
return new RateLimitError(message, { ...base, ...after !== void 0 ? { retryAfterMs: after } : {} });
|
|
101
|
+
}
|
|
102
|
+
case 503:
|
|
103
|
+
return new SessionUnavailableError(message, base);
|
|
104
|
+
default:
|
|
105
|
+
if (status >= 500) return new ApiError(message, base);
|
|
106
|
+
return new InvalidRequestError(message, base);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/http/url.ts
|
|
111
|
+
var BLOCKED_HOSTS = /* @__PURE__ */ new Set(["169.254.169.254", "metadata.google.internal"]);
|
|
112
|
+
function assertUsableBaseUrl(raw) {
|
|
113
|
+
let parsed;
|
|
114
|
+
try {
|
|
115
|
+
parsed = new URL(raw);
|
|
116
|
+
} catch {
|
|
117
|
+
throw new ConfigurationError(`baseUrl inv\xE1lida: ${raw}`);
|
|
118
|
+
}
|
|
119
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
120
|
+
throw new ConfigurationError(`baseUrl deve usar http ou https, veio ${parsed.protocol}`);
|
|
121
|
+
}
|
|
122
|
+
if (BLOCKED_HOSTS.has(parsed.hostname)) {
|
|
123
|
+
throw new ConfigurationError("baseUrl aponta para endpoint de metadados da nuvem");
|
|
124
|
+
}
|
|
125
|
+
if (isPrivateIPv4(parsed.hostname)) {
|
|
126
|
+
throw new ConfigurationError("baseUrl aponta para IP privado ou loopback");
|
|
127
|
+
}
|
|
128
|
+
return parsed;
|
|
129
|
+
}
|
|
130
|
+
function isPrivateIPv4(host) {
|
|
131
|
+
const parts = host.split(".");
|
|
132
|
+
if (parts.length !== 4) return false;
|
|
133
|
+
const nums = parts.map(Number);
|
|
134
|
+
if (nums.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return false;
|
|
135
|
+
const [a = 0, b = 0] = nums;
|
|
136
|
+
return a === 10 || a === 127 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 169 && b === 254;
|
|
137
|
+
}
|
|
138
|
+
function pathSegment(value) {
|
|
139
|
+
return encodeURIComponent(value);
|
|
140
|
+
}
|
|
141
|
+
function buildUrl(base, path, query) {
|
|
142
|
+
const prefix = base.pathname.replace(/\/+$/, "");
|
|
143
|
+
const url = new URL(`${prefix}/api${path}`, base);
|
|
144
|
+
if (query) {
|
|
145
|
+
for (const [key, value] of Object.entries(query)) {
|
|
146
|
+
if (value !== void 0) url.searchParams.set(key, String(value));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return url.toString();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/http/client.ts
|
|
153
|
+
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
154
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
155
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
156
|
+
var HttpClient = class {
|
|
157
|
+
baseUrl;
|
|
158
|
+
auth;
|
|
159
|
+
timeoutMs;
|
|
160
|
+
maxRetries;
|
|
161
|
+
fetchImpl;
|
|
162
|
+
userAgent;
|
|
163
|
+
observer;
|
|
164
|
+
autoReport;
|
|
165
|
+
instanceId;
|
|
166
|
+
constructor(options) {
|
|
167
|
+
this.baseUrl = assertUsableBaseUrl(options.baseUrl);
|
|
168
|
+
this.auth = options.auth;
|
|
169
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
170
|
+
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
171
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
172
|
+
this.userAgent = options.appName ? `open-apime-sdk (${options.appName})` : "open-apime-sdk";
|
|
173
|
+
this.observer = options.observer;
|
|
174
|
+
this.autoReport = options.autoReport ?? true;
|
|
175
|
+
this.instanceId = options.auth.type === "instanceToken" ? options.auth.instanceId : void 0;
|
|
176
|
+
}
|
|
177
|
+
info(args, attempt) {
|
|
178
|
+
return {
|
|
179
|
+
method: args.method,
|
|
180
|
+
route: toRoute(args.path),
|
|
181
|
+
path: args.path,
|
|
182
|
+
instanceId: this.instanceId,
|
|
183
|
+
attempt: attempt + 1,
|
|
184
|
+
idempotencyKey: args.options?.idempotencyKey
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
async request(args) {
|
|
188
|
+
const attempts = (args.options?.maxRetries ?? this.maxRetries) + 1;
|
|
189
|
+
let lastError;
|
|
190
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
191
|
+
const info = this.info(args, attempt);
|
|
192
|
+
const startedAt = Date.now();
|
|
193
|
+
safeNotify(this.observer?.onRequest && (() => this.observer?.onRequest?.(info)));
|
|
194
|
+
try {
|
|
195
|
+
const result = await this.attempt(args);
|
|
196
|
+
const durationMs = Date.now() - startedAt;
|
|
197
|
+
safeNotify(this.observer?.onSuccess && (() => this.observer?.onSuccess?.({ ...info, status: 200, durationMs })));
|
|
198
|
+
return result;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
lastError = error;
|
|
201
|
+
const isLast = attempt === attempts - 1;
|
|
202
|
+
const retryable = !isLast && this.mayRetry(args, error);
|
|
203
|
+
const failure = {
|
|
204
|
+
...info,
|
|
205
|
+
status: error instanceof ApimeError ? error.status : void 0,
|
|
206
|
+
durationMs: Date.now() - startedAt,
|
|
207
|
+
error,
|
|
208
|
+
willRetry: retryable
|
|
209
|
+
};
|
|
210
|
+
if (this.observer?.onError) {
|
|
211
|
+
safeNotify(() => this.observer?.onError?.(failure));
|
|
212
|
+
} else if (this.autoReport && !retryable) {
|
|
213
|
+
safeNotify(() => reportToSentry(failure));
|
|
214
|
+
}
|
|
215
|
+
if (isLast || !retryable) break;
|
|
216
|
+
const delayMs = backoffMs(attempt, error);
|
|
217
|
+
safeNotify(this.observer?.onRetry && (() => this.observer?.onRetry?.({ ...failure, delayMs })));
|
|
218
|
+
await sleep(delayMs, args.options?.signal);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
throw lastError;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* A write is only retried when the caller passed an idempotency key: without
|
|
225
|
+
* it a retried send can deliver the same WhatsApp message twice. The one
|
|
226
|
+
* exception is 503, which the apime returns before touching WhatsApp.
|
|
227
|
+
*/
|
|
228
|
+
mayRetry(args, error) {
|
|
229
|
+
if (!(error instanceof ApimeError)) return false;
|
|
230
|
+
if (error instanceof TimeoutError) return this.writeIsSafe(args, error);
|
|
231
|
+
if (error instanceof ConnectionError) return this.writeIsSafe(args, error);
|
|
232
|
+
if (error.status === void 0) return false;
|
|
233
|
+
if (!RETRYABLE_STATUS.has(error.status)) return false;
|
|
234
|
+
return this.writeIsSafe(args, error);
|
|
235
|
+
}
|
|
236
|
+
writeIsSafe(args, error) {
|
|
237
|
+
if (args.method === "GET") return true;
|
|
238
|
+
if (args.options?.idempotencyKey) return true;
|
|
239
|
+
return error instanceof ApimeError && error.status === 503;
|
|
240
|
+
}
|
|
241
|
+
async attempt(args) {
|
|
242
|
+
const url = buildUrl(this.baseUrl, args.path, args.query);
|
|
243
|
+
const timeoutMs = args.options?.timeoutMs ?? this.timeoutMs;
|
|
244
|
+
const controller = new AbortController();
|
|
245
|
+
const onAbort = () => controller.abort();
|
|
246
|
+
args.options?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
247
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
248
|
+
const headers = {
|
|
249
|
+
authorization: `Bearer ${this.auth.token}`,
|
|
250
|
+
accept: "application/json",
|
|
251
|
+
"user-agent": this.userAgent,
|
|
252
|
+
...args.options?.headers
|
|
253
|
+
};
|
|
254
|
+
if (args.options?.idempotencyKey) headers["idempotency-key"] = args.options.idempotencyKey;
|
|
255
|
+
let init = { method: args.method, headers, signal: controller.signal };
|
|
256
|
+
if (args.body instanceof FormData) {
|
|
257
|
+
init = { ...init, body: args.body };
|
|
258
|
+
} else if (args.body !== void 0) {
|
|
259
|
+
headers["content-type"] = "application/json";
|
|
260
|
+
init = { ...init, body: JSON.stringify(args.body) };
|
|
261
|
+
}
|
|
262
|
+
let response;
|
|
263
|
+
try {
|
|
264
|
+
response = await this.fetchImpl(url, init);
|
|
265
|
+
} catch (cause) {
|
|
266
|
+
if (controller.signal.aborted && args.options?.signal?.aborted !== true) {
|
|
267
|
+
throw new TimeoutError(`a requisi\xE7\xE3o passou de ${timeoutMs}ms`, { cause });
|
|
268
|
+
}
|
|
269
|
+
throw new ConnectionError("falha de rede ao falar com o apime", { cause });
|
|
270
|
+
} finally {
|
|
271
|
+
clearTimeout(timer);
|
|
272
|
+
args.options?.signal?.removeEventListener("abort", onAbort);
|
|
273
|
+
}
|
|
274
|
+
const payload = await readBody(response);
|
|
275
|
+
if (!response.ok) throw errorFromResponse(response.status, payload, response.headers);
|
|
276
|
+
return unwrap(payload);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
function unwrap(body) {
|
|
280
|
+
if (body && typeof body === "object" && "data" in body) {
|
|
281
|
+
return body.data;
|
|
282
|
+
}
|
|
283
|
+
return body;
|
|
284
|
+
}
|
|
285
|
+
async function readBody(response) {
|
|
286
|
+
const text = await response.text();
|
|
287
|
+
if (text.length === 0) return void 0;
|
|
288
|
+
try {
|
|
289
|
+
return JSON.parse(text);
|
|
290
|
+
} catch {
|
|
291
|
+
return text;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function backoffMs(attempt, error) {
|
|
295
|
+
if (error instanceof RateLimitError && error.retryAfterMs !== void 0) {
|
|
296
|
+
return error.retryAfterMs;
|
|
297
|
+
}
|
|
298
|
+
const ceiling = Math.min(1e3 * 2 ** attempt, 8e3);
|
|
299
|
+
return Math.random() * ceiling;
|
|
300
|
+
}
|
|
301
|
+
function sleep(ms, signal) {
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
303
|
+
if (signal?.aborted) return reject(new ConnectionError("requisi\xE7\xE3o cancelada"));
|
|
304
|
+
const timer = setTimeout(resolve, ms);
|
|
305
|
+
signal?.addEventListener("abort", () => {
|
|
306
|
+
clearTimeout(timer);
|
|
307
|
+
reject(new ConnectionError("requisi\xE7\xE3o cancelada"));
|
|
308
|
+
}, { once: true });
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// src/resources/instances/index.ts
|
|
313
|
+
var InstancesResource = class {
|
|
314
|
+
constructor(http) {
|
|
315
|
+
this.http = http;
|
|
316
|
+
}
|
|
317
|
+
http;
|
|
318
|
+
list(options) {
|
|
319
|
+
return this.http.request({ method: "GET", path: "/instances", ...options ? { options } : {} });
|
|
320
|
+
}
|
|
321
|
+
create(input, options) {
|
|
322
|
+
return this.http.request({ method: "POST", path: "/instances", body: input, ...options ? { options } : {} });
|
|
323
|
+
}
|
|
324
|
+
get(instanceId, options) {
|
|
325
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(instanceId)}`, ...options ? { options } : {} });
|
|
326
|
+
}
|
|
327
|
+
update(instanceId, input, options) {
|
|
328
|
+
return this.http.request({ method: "PUT", path: `/instances/${pathSegment(instanceId)}`, body: input, ...options ? { options } : {} });
|
|
329
|
+
}
|
|
330
|
+
delete(instanceId, options) {
|
|
331
|
+
return this.http.request({ method: "DELETE", path: `/instances/${pathSegment(instanceId)}`, ...options ? { options } : {} });
|
|
332
|
+
}
|
|
333
|
+
rotateToken(instanceId, options) {
|
|
334
|
+
return this.http.request({ method: "POST", path: `/instances/${pathSegment(instanceId)}/token/rotate`, ...options ? { options } : {} });
|
|
335
|
+
}
|
|
336
|
+
getQrCode(instanceId, options) {
|
|
337
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(instanceId)}/qr`, ...options ? { options } : {} });
|
|
338
|
+
}
|
|
339
|
+
disconnect(instanceId, options) {
|
|
340
|
+
return this.http.request({ method: "POST", path: `/instances/${pathSegment(instanceId)}/disconnect`, ...options ? { options } : {} });
|
|
341
|
+
}
|
|
342
|
+
listEvents(instanceId, query, options) {
|
|
343
|
+
return this.http.request({
|
|
344
|
+
method: "GET",
|
|
345
|
+
path: `/instances/${pathSegment(instanceId)}/events`,
|
|
346
|
+
...query ? { query } : {},
|
|
347
|
+
...options ? { options } : {}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
var ScopedInstanceResource = class {
|
|
352
|
+
constructor(http, instanceId) {
|
|
353
|
+
this.http = http;
|
|
354
|
+
this.instanceId = instanceId;
|
|
355
|
+
}
|
|
356
|
+
http;
|
|
357
|
+
instanceId;
|
|
358
|
+
get(options) {
|
|
359
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(this.instanceId)}`, ...options ? { options } : {} });
|
|
360
|
+
}
|
|
361
|
+
/** Only reachable with an instance token; a user token gets a 403. */
|
|
362
|
+
info(options) {
|
|
363
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(this.instanceId)}/info`, ...options ? { options } : {} });
|
|
364
|
+
}
|
|
365
|
+
getQrCode(options) {
|
|
366
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(this.instanceId)}/qr`, ...options ? { options } : {} });
|
|
367
|
+
}
|
|
368
|
+
disconnect(options) {
|
|
369
|
+
return this.http.request({ method: "POST", path: `/instances/${pathSegment(this.instanceId)}/disconnect`, ...options ? { options } : {} });
|
|
370
|
+
}
|
|
371
|
+
listEvents(query, options) {
|
|
372
|
+
return this.http.request({
|
|
373
|
+
method: "GET",
|
|
374
|
+
path: `/instances/${pathSegment(this.instanceId)}/events`,
|
|
375
|
+
...query ? { query } : {},
|
|
376
|
+
...options ? { options } : {}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
getProfile(jid, options) {
|
|
380
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(this.instanceId)}/profile/${pathSegment(jid)}`, ...options ? { options } : {} });
|
|
381
|
+
}
|
|
382
|
+
getBusinessProfile(jid, options) {
|
|
383
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(this.instanceId)}/business/${pathSegment(jid)}`, ...options ? { options } : {} });
|
|
384
|
+
}
|
|
385
|
+
getProfilePicture(jid, options) {
|
|
386
|
+
return this.http.request({ method: "GET", path: `/instances/${pathSegment(this.instanceId)}/profile/${pathSegment(jid)}/picture`, ...options ? { options } : {} });
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// src/resources/messages/index.ts
|
|
391
|
+
var MessagesResource = class {
|
|
392
|
+
constructor(http, instanceId) {
|
|
393
|
+
this.http = http;
|
|
394
|
+
this.instanceId = instanceId;
|
|
395
|
+
}
|
|
396
|
+
http;
|
|
397
|
+
instanceId;
|
|
398
|
+
get base() {
|
|
399
|
+
return `/instances/${pathSegment(this.instanceId)}/messages`;
|
|
400
|
+
}
|
|
401
|
+
sendText(input, options) {
|
|
402
|
+
return this.http.request({ method: "POST", path: `${this.base}/text`, body: input, ...options ? { options } : {} });
|
|
403
|
+
}
|
|
404
|
+
sendMedia(input, options) {
|
|
405
|
+
const form = toForm(input, ["file", "filename"]);
|
|
406
|
+
form.set("file", input.file, input.filename ?? fileName(input.file, "media"));
|
|
407
|
+
return this.http.request({ method: "POST", path: `${this.base}/media`, body: form, ...options ? { options } : {} });
|
|
408
|
+
}
|
|
409
|
+
sendAudio(input, options) {
|
|
410
|
+
const form = toForm(input, ["file", "filename"]);
|
|
411
|
+
form.set("file", input.file, input.filename ?? fileName(input.file, "audio.ogg"));
|
|
412
|
+
return this.http.request({ method: "POST", path: `${this.base}/audio`, body: form, ...options ? { options } : {} });
|
|
413
|
+
}
|
|
414
|
+
sendDocument(input, options) {
|
|
415
|
+
const form = toForm(input, ["file"]);
|
|
416
|
+
form.set("file", input.file, input.filename ?? fileName(input.file, "document"));
|
|
417
|
+
return this.http.request({ method: "POST", path: `${this.base}/document`, body: form, ...options ? { options } : {} });
|
|
418
|
+
}
|
|
419
|
+
sendContact(input, options) {
|
|
420
|
+
return this.http.request({ method: "POST", path: `${this.base}/contact`, body: input, ...options ? { options } : {} });
|
|
421
|
+
}
|
|
422
|
+
sendLocation(input, options) {
|
|
423
|
+
return this.http.request({ method: "POST", path: `${this.base}/location`, body: input, ...options ? { options } : {} });
|
|
424
|
+
}
|
|
425
|
+
/** Generic enqueue, for a type the SDK does not model yet. */
|
|
426
|
+
enqueue(input, options) {
|
|
427
|
+
return this.http.request({ method: "POST", path: this.base, body: input, ...options ? { options } : {} });
|
|
428
|
+
}
|
|
429
|
+
list(options) {
|
|
430
|
+
return this.http.request({ method: "GET", path: this.base, ...options ? { options } : {} });
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
function toForm(input, skip) {
|
|
434
|
+
const form = new FormData();
|
|
435
|
+
for (const [key, value] of Object.entries(input)) {
|
|
436
|
+
if (skip.includes(key) || value === void 0 || value === null) continue;
|
|
437
|
+
form.set(key, typeof value === "string" ? value : String(value));
|
|
438
|
+
}
|
|
439
|
+
return form;
|
|
440
|
+
}
|
|
441
|
+
function fileName(file, fallback) {
|
|
442
|
+
return "name" in file && typeof file.name === "string" && file.name.length > 0 ? file.name : fallback;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// src/resources/tokens/index.ts
|
|
446
|
+
var TokensResource = class {
|
|
447
|
+
constructor(http) {
|
|
448
|
+
this.http = http;
|
|
449
|
+
}
|
|
450
|
+
http;
|
|
451
|
+
list(options) {
|
|
452
|
+
return this.http.request({ method: "GET", path: "/tokens", ...options ? { options } : {} });
|
|
453
|
+
}
|
|
454
|
+
create(input, options) {
|
|
455
|
+
return this.http.request({ method: "POST", path: "/tokens", body: input, ...options ? { options } : {} });
|
|
456
|
+
}
|
|
457
|
+
delete(tokenId, options) {
|
|
458
|
+
return this.http.request({ method: "DELETE", path: `/tokens/${pathSegment(tokenId)}`, ...options ? { options } : {} });
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
// src/resources/users/index.ts
|
|
463
|
+
var UsersResource = class {
|
|
464
|
+
constructor(http) {
|
|
465
|
+
this.http = http;
|
|
466
|
+
}
|
|
467
|
+
http;
|
|
468
|
+
list(options) {
|
|
469
|
+
return this.http.request({ method: "GET", path: "/users", ...options ? { options } : {} });
|
|
470
|
+
}
|
|
471
|
+
create(input, options) {
|
|
472
|
+
return this.http.request({ method: "POST", path: "/users", body: input, ...options ? { options } : {} });
|
|
473
|
+
}
|
|
474
|
+
updatePassword(userId, password, options) {
|
|
475
|
+
return this.http.request({ method: "PATCH", path: `/users/${pathSegment(userId)}/password`, body: { password }, ...options ? { options } : {} });
|
|
476
|
+
}
|
|
477
|
+
rotateApiToken(userId, options) {
|
|
478
|
+
return this.http.request({ method: "POST", path: `/users/${pathSegment(userId)}/token`, ...options ? { options } : {} });
|
|
479
|
+
}
|
|
480
|
+
delete(userId, options) {
|
|
481
|
+
return this.http.request({ method: "DELETE", path: `/users/${pathSegment(userId)}`, ...options ? { options } : {} });
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// src/resources/whatsapp/index.ts
|
|
486
|
+
var WhatsAppResource = class {
|
|
487
|
+
constructor(http, instanceId) {
|
|
488
|
+
this.http = http;
|
|
489
|
+
this.instanceId = instanceId;
|
|
490
|
+
this.groups = new GroupsResource(http, instanceId);
|
|
491
|
+
this.newsletters = new NewslettersResource(http, instanceId);
|
|
492
|
+
}
|
|
493
|
+
http;
|
|
494
|
+
instanceId;
|
|
495
|
+
groups;
|
|
496
|
+
newsletters;
|
|
497
|
+
get base() {
|
|
498
|
+
return `/instances/${pathSegment(this.instanceId)}/whatsapp`;
|
|
499
|
+
}
|
|
500
|
+
checkNumber(phone, options) {
|
|
501
|
+
return this.http.request({ method: "POST", path: `${this.base}/check`, body: { phone }, ...options ? { options } : {} });
|
|
502
|
+
}
|
|
503
|
+
/** `to` is optional: without it the presence is global, not per chat. */
|
|
504
|
+
setPresence(input, options) {
|
|
505
|
+
return this.http.request({ method: "POST", path: `${this.base}/presence`, body: input, ...options ? { options } : {} });
|
|
506
|
+
}
|
|
507
|
+
listContacts(options) {
|
|
508
|
+
return this.http.request({ method: "GET", path: `${this.base}/contacts`, ...options ? { options } : {} });
|
|
509
|
+
}
|
|
510
|
+
getContact(jid, options) {
|
|
511
|
+
return this.http.request({ method: "GET", path: `${this.base}/contacts/${pathSegment(jid)}`, ...options ? { options } : {} });
|
|
512
|
+
}
|
|
513
|
+
getUserInfo(jid, options) {
|
|
514
|
+
return this.http.request({ method: "GET", path: `${this.base}/userinfo/${pathSegment(jid)}`, ...options ? { options } : {} });
|
|
515
|
+
}
|
|
516
|
+
/** `sender` is required in groups, to identify whose message it is. */
|
|
517
|
+
markRead(input, options) {
|
|
518
|
+
return this.http.request({ method: "POST", path: `${this.base}/messages/read`, body: input, ...options ? { options } : {} });
|
|
519
|
+
}
|
|
520
|
+
deleteMessage(input, options) {
|
|
521
|
+
return this.http.request({ method: "POST", path: `${this.base}/messages/delete`, body: input, ...options ? { options } : {} });
|
|
522
|
+
}
|
|
523
|
+
editMessage(input, options) {
|
|
524
|
+
return this.http.request({ method: "POST", path: `${this.base}/messages/edit`, body: input, ...options ? { options } : {} });
|
|
525
|
+
}
|
|
526
|
+
/** An empty `emoji` removes the reaction. */
|
|
527
|
+
react(input, options) {
|
|
528
|
+
return this.http.request({ method: "POST", path: `${this.base}/messages/react`, body: input, ...options ? { options } : {} });
|
|
529
|
+
}
|
|
530
|
+
getPrivacySettings(options) {
|
|
531
|
+
return this.http.request({ method: "GET", path: `${this.base}/privacy`, ...options ? { options } : {} });
|
|
532
|
+
}
|
|
533
|
+
setPrivacySetting(input, options) {
|
|
534
|
+
return this.http.request({ method: "POST", path: `${this.base}/privacy`, body: input, ...options ? { options } : {} });
|
|
535
|
+
}
|
|
536
|
+
getStatusPrivacy(options) {
|
|
537
|
+
return this.http.request({ method: "GET", path: `${this.base}/status-privacy`, ...options ? { options } : {} });
|
|
538
|
+
}
|
|
539
|
+
getChatSettings(chat, options) {
|
|
540
|
+
return this.http.request({ method: "GET", path: `${this.base}/chat-settings/${pathSegment(chat)}`, ...options ? { options } : {} });
|
|
541
|
+
}
|
|
542
|
+
/** `muted_until` as null unmutes. */
|
|
543
|
+
setChatSettings(chat, input, options) {
|
|
544
|
+
return this.http.request({ method: "POST", path: `${this.base}/chat-settings/${pathSegment(chat)}`, body: input, ...options ? { options } : {} });
|
|
545
|
+
}
|
|
546
|
+
setStatusMessage(message, options) {
|
|
547
|
+
return this.http.request({ method: "POST", path: `${this.base}/status`, body: { message }, ...options ? { options } : {} });
|
|
548
|
+
}
|
|
549
|
+
/** `seconds` as 0 turns disappearing messages off. */
|
|
550
|
+
setDefaultDisappearingTimer(seconds, options) {
|
|
551
|
+
return this.http.request({ method: "POST", path: `${this.base}/disappearing-timer`, body: { seconds }, ...options ? { options } : {} });
|
|
552
|
+
}
|
|
553
|
+
uploadMedia(input, options) {
|
|
554
|
+
return this.http.request({ method: "POST", path: `${this.base}/upload`, body: input, ...options ? { options } : {} });
|
|
555
|
+
}
|
|
556
|
+
/** `revoke` invalidates the previous link and issues another. */
|
|
557
|
+
getContactQrLink(query, options) {
|
|
558
|
+
return this.http.request({
|
|
559
|
+
method: "GET",
|
|
560
|
+
path: `${this.base}/qr/contact`,
|
|
561
|
+
...query?.revoke !== void 0 ? { query: { revoke: String(query.revoke) } } : {},
|
|
562
|
+
...options ? { options } : {}
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
resolveContactQrLink(code, options) {
|
|
566
|
+
return this.http.request({ method: "POST", path: `${this.base}/qr/contact/resolve`, body: { code }, ...options ? { options } : {} });
|
|
567
|
+
}
|
|
568
|
+
resolveBusinessMessageLink(code, options) {
|
|
569
|
+
return this.http.request({ method: "POST", path: `${this.base}/qr/business-message/resolve`, body: { code }, ...options ? { options } : {} });
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
var GroupsResource = class {
|
|
573
|
+
constructor(http, instanceId) {
|
|
574
|
+
this.http = http;
|
|
575
|
+
this.instanceId = instanceId;
|
|
576
|
+
}
|
|
577
|
+
http;
|
|
578
|
+
instanceId;
|
|
579
|
+
get base() {
|
|
580
|
+
return `/instances/${pathSegment(this.instanceId)}/whatsapp/groups`;
|
|
581
|
+
}
|
|
582
|
+
list(options) {
|
|
583
|
+
return this.http.request({ method: "GET", path: this.base, ...options ? { options } : {} });
|
|
584
|
+
}
|
|
585
|
+
create(input, options) {
|
|
586
|
+
return this.http.request({ method: "POST", path: this.base, body: input, ...options ? { options } : {} });
|
|
587
|
+
}
|
|
588
|
+
get(group, options) {
|
|
589
|
+
return this.http.request({ method: "GET", path: `${this.base}/${pathSegment(group)}`, ...options ? { options } : {} });
|
|
590
|
+
}
|
|
591
|
+
getInviteLink(group, options) {
|
|
592
|
+
return this.http.request({ method: "GET", path: `${this.base}/${pathSegment(group)}/invite-link`, ...options ? { options } : {} });
|
|
593
|
+
}
|
|
594
|
+
resolveInvite(link, options) {
|
|
595
|
+
return this.http.request({ method: "POST", path: `${this.base}/resolve-invite`, body: { link }, ...options ? { options } : {} });
|
|
596
|
+
}
|
|
597
|
+
join(link, options) {
|
|
598
|
+
return this.http.request({ method: "POST", path: `${this.base}/join`, body: { link }, ...options ? { options } : {} });
|
|
599
|
+
}
|
|
600
|
+
leave(group, options) {
|
|
601
|
+
return this.http.request({ method: "POST", path: `${this.base}/${pathSegment(group)}/leave`, ...options ? { options } : {} });
|
|
602
|
+
}
|
|
603
|
+
updateParticipants(group, input, options) {
|
|
604
|
+
return this.http.request({ method: "POST", path: `${this.base}/${pathSegment(group)}/participants`, body: input, ...options ? { options } : {} });
|
|
605
|
+
}
|
|
606
|
+
listJoinRequests(group, options) {
|
|
607
|
+
return this.http.request({ method: "GET", path: `${this.base}/${pathSegment(group)}/requests`, ...options ? { options } : {} });
|
|
608
|
+
}
|
|
609
|
+
updateJoinRequests(group, input, options) {
|
|
610
|
+
return this.http.request({ method: "POST", path: `${this.base}/${pathSegment(group)}/requests`, body: input, ...options ? { options } : {} });
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
var NewslettersResource = class {
|
|
614
|
+
constructor(http, instanceId) {
|
|
615
|
+
this.http = http;
|
|
616
|
+
this.instanceId = instanceId;
|
|
617
|
+
}
|
|
618
|
+
http;
|
|
619
|
+
instanceId;
|
|
620
|
+
base(jid) {
|
|
621
|
+
return `/instances/${pathSegment(this.instanceId)}/whatsapp/newsletters/${pathSegment(jid)}`;
|
|
622
|
+
}
|
|
623
|
+
subscribeLiveUpdates(jid, options) {
|
|
624
|
+
return this.http.request({ method: "POST", path: `${this.base(jid)}/live-updates`, ...options ? { options } : {} });
|
|
625
|
+
}
|
|
626
|
+
markViewed(jid, serverIds, options) {
|
|
627
|
+
return this.http.request({ method: "POST", path: `${this.base(jid)}/mark-viewed`, body: { server_ids: serverIds }, ...options ? { options } : {} });
|
|
628
|
+
}
|
|
629
|
+
react(jid, input, options) {
|
|
630
|
+
return this.http.request({ method: "POST", path: `${this.base(jid)}/reaction`, body: input, ...options ? { options } : {} });
|
|
631
|
+
}
|
|
632
|
+
getMessageUpdates(jid, options) {
|
|
633
|
+
return this.http.request({ method: "POST", path: `${this.base(jid)}/message-updates`, ...options ? { options } : {} });
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
// src/client.ts
|
|
638
|
+
var ApimeUserClient = class {
|
|
639
|
+
instances;
|
|
640
|
+
/** Requires the user to have role admin; other users get a 403. */
|
|
641
|
+
users;
|
|
642
|
+
tokens;
|
|
643
|
+
http;
|
|
644
|
+
constructor(auth, options) {
|
|
645
|
+
this.http = new HttpClient(toHttpOptions(auth, options));
|
|
646
|
+
this.instances = new InstancesResource(this.http);
|
|
647
|
+
this.users = new UsersResource(this.http);
|
|
648
|
+
this.tokens = new TokensResource(this.http);
|
|
649
|
+
}
|
|
650
|
+
/** Escape hatch for a route the SDK does not cover yet. */
|
|
651
|
+
request(args) {
|
|
652
|
+
return this.http.request(args);
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
var ApimeInstanceClient = class {
|
|
656
|
+
instanceId;
|
|
657
|
+
instance;
|
|
658
|
+
messages;
|
|
659
|
+
whatsapp;
|
|
660
|
+
http;
|
|
661
|
+
constructor(auth, options) {
|
|
662
|
+
this.http = new HttpClient(toHttpOptions(auth, options));
|
|
663
|
+
this.instanceId = auth.instanceId;
|
|
664
|
+
this.instance = new ScopedInstanceResource(this.http, auth.instanceId);
|
|
665
|
+
this.messages = new MessagesResource(this.http, auth.instanceId);
|
|
666
|
+
this.whatsapp = new WhatsAppResource(this.http, auth.instanceId);
|
|
667
|
+
}
|
|
668
|
+
request(args) {
|
|
669
|
+
return this.http.request(args);
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
function toHttpOptions(auth, options) {
|
|
673
|
+
return {
|
|
674
|
+
baseUrl: options.baseUrl,
|
|
675
|
+
auth,
|
|
676
|
+
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
|
|
677
|
+
...options.maxRetries !== void 0 ? { maxRetries: options.maxRetries } : {},
|
|
678
|
+
...options.fetch !== void 0 ? { fetch: options.fetch } : {},
|
|
679
|
+
...options.appName !== void 0 ? { appName: options.appName } : {},
|
|
680
|
+
...options.observer !== void 0 ? { observer: options.observer } : {},
|
|
681
|
+
...options.autoReport !== void 0 ? { autoReport: options.autoReport } : {}
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
var Apime = {
|
|
685
|
+
withUserJwt(token, options) {
|
|
686
|
+
return new ApimeUserClient({ type: "userJwt", token }, options);
|
|
687
|
+
},
|
|
688
|
+
withApiToken(token, options) {
|
|
689
|
+
return new ApimeUserClient({ type: "apiToken", token }, options);
|
|
690
|
+
},
|
|
691
|
+
withInstanceToken(credentials, options) {
|
|
692
|
+
return new ApimeInstanceClient(
|
|
693
|
+
{ type: "instanceToken", token: credentials.token, instanceId: credentials.instanceId },
|
|
694
|
+
options
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
export {
|
|
699
|
+
ApiError,
|
|
700
|
+
Apime,
|
|
701
|
+
ApimeError,
|
|
702
|
+
ApimeInstanceClient,
|
|
703
|
+
ApimeUserClient,
|
|
704
|
+
AuthenticationError,
|
|
705
|
+
ConfigurationError,
|
|
706
|
+
ConflictError,
|
|
707
|
+
ConnectionError,
|
|
708
|
+
InvalidRequestError,
|
|
709
|
+
InvalidSignatureError,
|
|
710
|
+
NotFoundError,
|
|
711
|
+
PermissionError,
|
|
712
|
+
RateLimitError,
|
|
713
|
+
SessionUnavailableError,
|
|
714
|
+
TimeoutError,
|
|
715
|
+
UnprocessableError,
|
|
716
|
+
constructEvent,
|
|
717
|
+
hasSentry,
|
|
718
|
+
verifyWebhookSignature
|
|
719
|
+
};
|