@messagebird/sdk 0.2.2 → 0.4.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/dist/index.js DELETED
@@ -1,1699 +0,0 @@
1
- import { Webhook } from 'standardwebhooks';
2
-
3
- // src/generated/core/bodySerializer.gen.ts
4
- var jsonBodySerializer = {
5
- bodySerializer: (body) => JSON.stringify(
6
- body,
7
- (_key, value) => typeof value === "bigint" ? value.toString() : value
8
- )
9
- };
10
-
11
- // src/generated/core/serverSentEvents.gen.ts
12
- function createSseClient({
13
- onRequest,
14
- onSseError,
15
- onSseEvent,
16
- responseTransformer,
17
- responseValidator,
18
- sseDefaultRetryDelay,
19
- sseMaxRetryAttempts,
20
- sseMaxRetryDelay,
21
- sseSleepFn,
22
- url,
23
- ...options
24
- }) {
25
- let lastEventId;
26
- const sleep2 = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
27
- const createStream = async function* () {
28
- let retryDelay2 = sseDefaultRetryDelay ?? 3e3;
29
- let attempt = 0;
30
- const signal = options.signal ?? new AbortController().signal;
31
- while (true) {
32
- if (signal.aborted) break;
33
- attempt++;
34
- const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
35
- if (lastEventId !== void 0) {
36
- headers.set("Last-Event-ID", lastEventId);
37
- }
38
- try {
39
- const requestInit = {
40
- redirect: "follow",
41
- ...options,
42
- body: options.serializedBody,
43
- headers,
44
- signal
45
- };
46
- let request = new Request(url, requestInit);
47
- if (onRequest) {
48
- request = await onRequest(url, requestInit);
49
- }
50
- const _fetch = options.fetch ?? globalThis.fetch;
51
- const response = await _fetch(request);
52
- if (!response.ok)
53
- throw new Error(
54
- `SSE failed: ${response.status} ${response.statusText}`
55
- );
56
- if (!response.body) throw new Error("No body in SSE response");
57
- const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
58
- let buffer = "";
59
- const abortHandler = () => {
60
- try {
61
- reader.cancel();
62
- } catch {
63
- }
64
- };
65
- signal.addEventListener("abort", abortHandler);
66
- try {
67
- while (true) {
68
- const { done, value } = await reader.read();
69
- if (done) break;
70
- buffer += value;
71
- buffer = buffer.replace(/\r\n?/g, "\n");
72
- const chunks = buffer.split("\n\n");
73
- buffer = chunks.pop() ?? "";
74
- for (const chunk of chunks) {
75
- const lines = chunk.split("\n");
76
- const dataLines = [];
77
- let eventName;
78
- for (const line of lines) {
79
- if (line.startsWith("data:")) {
80
- dataLines.push(line.replace(/^data:\s*/, ""));
81
- } else if (line.startsWith("event:")) {
82
- eventName = line.replace(/^event:\s*/, "");
83
- } else if (line.startsWith("id:")) {
84
- lastEventId = line.replace(/^id:\s*/, "");
85
- } else if (line.startsWith("retry:")) {
86
- const parsed = Number.parseInt(
87
- line.replace(/^retry:\s*/, ""),
88
- 10
89
- );
90
- if (!Number.isNaN(parsed)) {
91
- retryDelay2 = parsed;
92
- }
93
- }
94
- }
95
- let data;
96
- let parsedJson = false;
97
- if (dataLines.length) {
98
- const rawData = dataLines.join("\n");
99
- try {
100
- data = JSON.parse(rawData);
101
- parsedJson = true;
102
- } catch {
103
- data = rawData;
104
- }
105
- }
106
- if (parsedJson) {
107
- if (responseValidator) {
108
- await responseValidator(data);
109
- }
110
- if (responseTransformer) {
111
- data = await responseTransformer(data);
112
- }
113
- }
114
- onSseEvent?.({
115
- data,
116
- event: eventName,
117
- id: lastEventId,
118
- retry: retryDelay2
119
- });
120
- if (dataLines.length) {
121
- yield data;
122
- }
123
- }
124
- }
125
- } finally {
126
- signal.removeEventListener("abort", abortHandler);
127
- reader.releaseLock();
128
- }
129
- break;
130
- } catch (error) {
131
- onSseError?.(error);
132
- if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
133
- break;
134
- }
135
- const backoff = Math.min(
136
- retryDelay2 * 2 ** (attempt - 1),
137
- sseMaxRetryDelay ?? 3e4
138
- );
139
- await sleep2(backoff);
140
- }
141
- }
142
- };
143
- const stream = createStream();
144
- return { stream };
145
- }
146
-
147
- // src/generated/core/pathSerializer.gen.ts
148
- var separatorArrayExplode = (style) => {
149
- switch (style) {
150
- case "label":
151
- return ".";
152
- case "matrix":
153
- return ";";
154
- case "simple":
155
- return ",";
156
- default:
157
- return "&";
158
- }
159
- };
160
- var separatorArrayNoExplode = (style) => {
161
- switch (style) {
162
- case "form":
163
- return ",";
164
- case "pipeDelimited":
165
- return "|";
166
- case "spaceDelimited":
167
- return "%20";
168
- default:
169
- return ",";
170
- }
171
- };
172
- var separatorObjectExplode = (style) => {
173
- switch (style) {
174
- case "label":
175
- return ".";
176
- case "matrix":
177
- return ";";
178
- case "simple":
179
- return ",";
180
- default:
181
- return "&";
182
- }
183
- };
184
- var serializeArrayParam = ({
185
- allowReserved,
186
- explode,
187
- name,
188
- style,
189
- value
190
- }) => {
191
- if (!explode) {
192
- const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
193
- switch (style) {
194
- case "label":
195
- return `.${joinedValues2}`;
196
- case "matrix":
197
- return `;${name}=${joinedValues2}`;
198
- case "simple":
199
- return joinedValues2;
200
- default:
201
- return `${name}=${joinedValues2}`;
202
- }
203
- }
204
- const separator = separatorArrayExplode(style);
205
- const joinedValues = value.map((v) => {
206
- if (style === "label" || style === "simple") {
207
- return allowReserved ? v : encodeURIComponent(v);
208
- }
209
- return serializePrimitiveParam({
210
- allowReserved,
211
- name,
212
- value: v
213
- });
214
- }).join(separator);
215
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
216
- };
217
- var serializePrimitiveParam = ({
218
- allowReserved,
219
- name,
220
- value
221
- }) => {
222
- if (value === void 0 || value === null) {
223
- return "";
224
- }
225
- if (typeof value === "object") {
226
- throw new Error(
227
- "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
228
- );
229
- }
230
- return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
231
- };
232
- var serializeObjectParam = ({
233
- allowReserved,
234
- explode,
235
- name,
236
- style,
237
- value,
238
- valueOnly
239
- }) => {
240
- if (value instanceof Date) {
241
- return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
242
- }
243
- if (style !== "deepObject" && !explode) {
244
- let values = [];
245
- Object.entries(value).forEach(([key, v]) => {
246
- values = [
247
- ...values,
248
- key,
249
- allowReserved ? v : encodeURIComponent(v)
250
- ];
251
- });
252
- const joinedValues2 = values.join(",");
253
- switch (style) {
254
- case "form":
255
- return `${name}=${joinedValues2}`;
256
- case "label":
257
- return `.${joinedValues2}`;
258
- case "matrix":
259
- return `;${name}=${joinedValues2}`;
260
- default:
261
- return joinedValues2;
262
- }
263
- }
264
- const separator = separatorObjectExplode(style);
265
- const joinedValues = Object.entries(value).map(
266
- ([key, v]) => serializePrimitiveParam({
267
- allowReserved,
268
- name: style === "deepObject" ? `${name}[${key}]` : key,
269
- value: v
270
- })
271
- ).join(separator);
272
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
273
- };
274
-
275
- // src/generated/core/utils.gen.ts
276
- var PATH_PARAM_RE = /\{[^{}]+\}/g;
277
- var defaultPathSerializer = ({ path, url: _url }) => {
278
- let url = _url;
279
- const matches = _url.match(PATH_PARAM_RE);
280
- if (matches) {
281
- for (const match of matches) {
282
- let explode = false;
283
- let name = match.substring(1, match.length - 1);
284
- let style = "simple";
285
- if (name.endsWith("*")) {
286
- explode = true;
287
- name = name.substring(0, name.length - 1);
288
- }
289
- if (name.startsWith(".")) {
290
- name = name.substring(1);
291
- style = "label";
292
- } else if (name.startsWith(";")) {
293
- name = name.substring(1);
294
- style = "matrix";
295
- }
296
- const value = path[name];
297
- if (value === void 0 || value === null) {
298
- continue;
299
- }
300
- if (Array.isArray(value)) {
301
- url = url.replace(
302
- match,
303
- serializeArrayParam({ explode, name, style, value })
304
- );
305
- continue;
306
- }
307
- if (typeof value === "object") {
308
- url = url.replace(
309
- match,
310
- serializeObjectParam({
311
- explode,
312
- name,
313
- style,
314
- value,
315
- valueOnly: true
316
- })
317
- );
318
- continue;
319
- }
320
- if (style === "matrix") {
321
- url = url.replace(
322
- match,
323
- `;${serializePrimitiveParam({
324
- name,
325
- value
326
- })}`
327
- );
328
- continue;
329
- }
330
- const replaceValue = encodeURIComponent(
331
- style === "label" ? `.${value}` : value
332
- );
333
- url = url.replace(match, replaceValue);
334
- }
335
- }
336
- return url;
337
- };
338
- var getUrl = ({
339
- baseUrl,
340
- path,
341
- query,
342
- querySerializer,
343
- url: _url
344
- }) => {
345
- const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
346
- let url = (baseUrl ?? "") + pathUrl;
347
- if (path) {
348
- url = defaultPathSerializer({ path, url });
349
- }
350
- let search = query ? querySerializer(query) : "";
351
- if (search.startsWith("?")) {
352
- search = search.substring(1);
353
- }
354
- if (search) {
355
- url += `?${search}`;
356
- }
357
- return url;
358
- };
359
- function getValidRequestBody(options) {
360
- const hasBody = options.body !== void 0;
361
- const isSerializedBody = hasBody && options.bodySerializer;
362
- if (isSerializedBody) {
363
- if ("serializedBody" in options) {
364
- const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
365
- return hasSerializedBody ? options.serializedBody : null;
366
- }
367
- return options.body !== "" ? options.body : null;
368
- }
369
- if (hasBody) {
370
- return options.body;
371
- }
372
- return void 0;
373
- }
374
-
375
- // src/generated/core/auth.gen.ts
376
- var getAuthToken = async (auth, callback) => {
377
- const token = typeof callback === "function" ? await callback(auth) : callback;
378
- if (!token) {
379
- return;
380
- }
381
- if (auth.scheme === "bearer") {
382
- return `Bearer ${token}`;
383
- }
384
- if (auth.scheme === "basic") {
385
- return `Basic ${btoa(token)}`;
386
- }
387
- return token;
388
- };
389
-
390
- // src/generated/client/utils.gen.ts
391
- var createQuerySerializer = ({
392
- parameters = {},
393
- ...args
394
- } = {}) => {
395
- const querySerializer = (queryParams) => {
396
- const search = [];
397
- if (queryParams && typeof queryParams === "object") {
398
- for (const name in queryParams) {
399
- const value = queryParams[name];
400
- if (value === void 0 || value === null) {
401
- continue;
402
- }
403
- const options = parameters[name] || args;
404
- if (Array.isArray(value)) {
405
- const serializedArray = serializeArrayParam({
406
- allowReserved: options.allowReserved,
407
- explode: true,
408
- name,
409
- style: "form",
410
- value,
411
- ...options.array
412
- });
413
- if (serializedArray) search.push(serializedArray);
414
- } else if (typeof value === "object") {
415
- const serializedObject = serializeObjectParam({
416
- allowReserved: options.allowReserved,
417
- explode: true,
418
- name,
419
- style: "deepObject",
420
- value,
421
- ...options.object
422
- });
423
- if (serializedObject) search.push(serializedObject);
424
- } else {
425
- const serializedPrimitive = serializePrimitiveParam({
426
- allowReserved: options.allowReserved,
427
- name,
428
- value
429
- });
430
- if (serializedPrimitive) search.push(serializedPrimitive);
431
- }
432
- }
433
- }
434
- return search.join("&");
435
- };
436
- return querySerializer;
437
- };
438
- var getParseAs = (contentType) => {
439
- if (!contentType) {
440
- return "stream";
441
- }
442
- const cleanContent = contentType.split(";")[0]?.trim();
443
- if (!cleanContent) {
444
- return;
445
- }
446
- if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
447
- return "json";
448
- }
449
- if (cleanContent === "multipart/form-data") {
450
- return "formData";
451
- }
452
- if (["application/", "audio/", "image/", "video/"].some(
453
- (type) => cleanContent.startsWith(type)
454
- )) {
455
- return "blob";
456
- }
457
- if (cleanContent.startsWith("text/")) {
458
- return "text";
459
- }
460
- return;
461
- };
462
- var checkForExistence = (options, name) => {
463
- if (!name) {
464
- return false;
465
- }
466
- if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
467
- return true;
468
- }
469
- return false;
470
- };
471
- var setAuthParams = async ({
472
- security,
473
- ...options
474
- }) => {
475
- for (const auth of security) {
476
- if (checkForExistence(options, auth.name)) {
477
- continue;
478
- }
479
- const token = await getAuthToken(auth, options.auth);
480
- if (!token) {
481
- continue;
482
- }
483
- const name = auth.name ?? "Authorization";
484
- switch (auth.in) {
485
- case "query":
486
- if (!options.query) {
487
- options.query = {};
488
- }
489
- options.query[name] = token;
490
- break;
491
- case "cookie":
492
- options.headers.append("Cookie", `${name}=${token}`);
493
- break;
494
- case "header":
495
- default:
496
- options.headers.set(name, token);
497
- break;
498
- }
499
- }
500
- };
501
- var buildUrl = (options) => getUrl({
502
- baseUrl: options.baseUrl,
503
- path: options.path,
504
- query: options.query,
505
- querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
506
- url: options.url
507
- });
508
- var mergeConfigs = (a, b) => {
509
- const config = { ...a, ...b };
510
- if (config.baseUrl?.endsWith("/")) {
511
- config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
512
- }
513
- config.headers = mergeHeaders(a.headers, b.headers);
514
- return config;
515
- };
516
- var headersEntries = (headers) => {
517
- const entries = [];
518
- headers.forEach((value, key) => {
519
- entries.push([key, value]);
520
- });
521
- return entries;
522
- };
523
- var mergeHeaders = (...headers) => {
524
- const mergedHeaders = new Headers();
525
- for (const header of headers) {
526
- if (!header) {
527
- continue;
528
- }
529
- const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
530
- for (const [key, value] of iterator) {
531
- if (value === null) {
532
- mergedHeaders.delete(key);
533
- } else if (Array.isArray(value)) {
534
- for (const v of value) {
535
- mergedHeaders.append(key, v);
536
- }
537
- } else if (value !== void 0) {
538
- mergedHeaders.set(
539
- key,
540
- typeof value === "object" ? JSON.stringify(value) : value
541
- );
542
- }
543
- }
544
- }
545
- return mergedHeaders;
546
- };
547
- var Interceptors = class {
548
- fns = [];
549
- clear() {
550
- this.fns = [];
551
- }
552
- eject(id) {
553
- const index = this.getInterceptorIndex(id);
554
- if (this.fns[index]) {
555
- this.fns[index] = null;
556
- }
557
- }
558
- exists(id) {
559
- const index = this.getInterceptorIndex(id);
560
- return Boolean(this.fns[index]);
561
- }
562
- getInterceptorIndex(id) {
563
- if (typeof id === "number") {
564
- return this.fns[id] ? id : -1;
565
- }
566
- return this.fns.indexOf(id);
567
- }
568
- update(id, fn) {
569
- const index = this.getInterceptorIndex(id);
570
- if (this.fns[index]) {
571
- this.fns[index] = fn;
572
- return id;
573
- }
574
- return false;
575
- }
576
- use(fn) {
577
- this.fns.push(fn);
578
- return this.fns.length - 1;
579
- }
580
- };
581
- var createInterceptors = () => ({
582
- error: new Interceptors(),
583
- request: new Interceptors(),
584
- response: new Interceptors()
585
- });
586
- var defaultQuerySerializer = createQuerySerializer({
587
- allowReserved: false,
588
- array: {
589
- explode: true,
590
- style: "form"
591
- },
592
- object: {
593
- explode: true,
594
- style: "deepObject"
595
- }
596
- });
597
- var defaultHeaders = {
598
- "Content-Type": "application/json"
599
- };
600
- var createConfig = (override = {}) => ({
601
- ...jsonBodySerializer,
602
- headers: defaultHeaders,
603
- parseAs: "auto",
604
- querySerializer: defaultQuerySerializer,
605
- ...override
606
- });
607
-
608
- // src/generated/client/client.gen.ts
609
- var createClient = (config = {}) => {
610
- let _config = mergeConfigs(createConfig(), config);
611
- const getConfig = () => ({ ..._config });
612
- const setConfig = (config2) => {
613
- _config = mergeConfigs(_config, config2);
614
- return getConfig();
615
- };
616
- const interceptors = createInterceptors();
617
- const beforeRequest = async (options) => {
618
- const opts = {
619
- ..._config,
620
- ...options,
621
- fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
622
- headers: mergeHeaders(_config.headers, options.headers),
623
- serializedBody: void 0
624
- };
625
- if (opts.security) {
626
- await setAuthParams({
627
- ...opts,
628
- security: opts.security
629
- });
630
- }
631
- if (opts.requestValidator) {
632
- await opts.requestValidator(opts);
633
- }
634
- if (opts.body !== void 0 && opts.bodySerializer) {
635
- opts.serializedBody = opts.bodySerializer(opts.body);
636
- }
637
- if (opts.body === void 0 || opts.serializedBody === "") {
638
- opts.headers.delete("Content-Type");
639
- }
640
- const resolvedOpts = opts;
641
- const url = buildUrl(resolvedOpts);
642
- return { opts: resolvedOpts, url };
643
- };
644
- const request = async (options) => {
645
- const throwOnError = options.throwOnError ?? _config.throwOnError;
646
- const responseStyle = options.responseStyle ?? _config.responseStyle;
647
- let request2;
648
- let response;
649
- try {
650
- const { opts, url } = await beforeRequest(options);
651
- const requestInit = {
652
- redirect: "follow",
653
- ...opts,
654
- body: getValidRequestBody(opts)
655
- };
656
- request2 = new Request(url, requestInit);
657
- for (const fn of interceptors.request.fns) {
658
- if (fn) {
659
- request2 = await fn(request2, opts);
660
- }
661
- }
662
- const _fetch = opts.fetch;
663
- response = await _fetch(request2);
664
- for (const fn of interceptors.response.fns) {
665
- if (fn) {
666
- response = await fn(response, request2, opts);
667
- }
668
- }
669
- const result = {
670
- request: request2,
671
- response
672
- };
673
- if (response.ok) {
674
- const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
675
- if (response.status === 204 || response.headers.get("Content-Length") === "0") {
676
- let emptyData;
677
- switch (parseAs) {
678
- case "arrayBuffer":
679
- case "blob":
680
- case "text":
681
- emptyData = await response[parseAs]();
682
- break;
683
- case "formData":
684
- emptyData = new FormData();
685
- break;
686
- case "stream":
687
- emptyData = response.body;
688
- break;
689
- case "json":
690
- default:
691
- emptyData = {};
692
- break;
693
- }
694
- return opts.responseStyle === "data" ? emptyData : {
695
- data: emptyData,
696
- ...result
697
- };
698
- }
699
- let data;
700
- switch (parseAs) {
701
- case "arrayBuffer":
702
- case "blob":
703
- case "formData":
704
- case "text":
705
- data = await response[parseAs]();
706
- break;
707
- case "json": {
708
- const text = await response.text();
709
- data = text ? JSON.parse(text) : {};
710
- break;
711
- }
712
- case "stream":
713
- return opts.responseStyle === "data" ? response.body : {
714
- data: response.body,
715
- ...result
716
- };
717
- }
718
- if (parseAs === "json") {
719
- if (opts.responseValidator) {
720
- await opts.responseValidator(data);
721
- }
722
- if (opts.responseTransformer) {
723
- data = await opts.responseTransformer(data);
724
- }
725
- }
726
- return opts.responseStyle === "data" ? data : {
727
- data,
728
- ...result
729
- };
730
- }
731
- const textError = await response.text();
732
- let jsonError;
733
- try {
734
- jsonError = JSON.parse(textError);
735
- } catch {
736
- }
737
- throw jsonError ?? textError;
738
- } catch (error) {
739
- let finalError = error;
740
- for (const fn of interceptors.error.fns) {
741
- if (fn) {
742
- finalError = await fn(
743
- finalError,
744
- response,
745
- request2,
746
- options
747
- );
748
- }
749
- }
750
- finalError = finalError || {};
751
- if (throwOnError) {
752
- throw finalError;
753
- }
754
- return responseStyle === "data" ? void 0 : {
755
- error: finalError,
756
- request: request2,
757
- response
758
- };
759
- }
760
- };
761
- const makeMethodFn = (method) => (options) => request({ ...options, method });
762
- const makeSseFn = (method) => async (options) => {
763
- const { opts, url } = await beforeRequest(options);
764
- return createSseClient({
765
- ...opts,
766
- body: opts.body,
767
- method,
768
- onRequest: async (url2, init) => {
769
- let request2 = new Request(url2, init);
770
- for (const fn of interceptors.request.fns) {
771
- if (fn) {
772
- request2 = await fn(request2, opts);
773
- }
774
- }
775
- return request2;
776
- },
777
- serializedBody: getValidRequestBody(opts),
778
- url
779
- });
780
- };
781
- const _buildUrl = (options) => buildUrl({ ..._config, ...options });
782
- return {
783
- buildUrl: _buildUrl,
784
- connect: makeMethodFn("CONNECT"),
785
- delete: makeMethodFn("DELETE"),
786
- get: makeMethodFn("GET"),
787
- getConfig,
788
- head: makeMethodFn("HEAD"),
789
- interceptors,
790
- options: makeMethodFn("OPTIONS"),
791
- patch: makeMethodFn("PATCH"),
792
- post: makeMethodFn("POST"),
793
- put: makeMethodFn("PUT"),
794
- request,
795
- setConfig,
796
- sse: {
797
- connect: makeSseFn("CONNECT"),
798
- delete: makeSseFn("DELETE"),
799
- get: makeSseFn("GET"),
800
- head: makeSseFn("HEAD"),
801
- options: makeSseFn("OPTIONS"),
802
- patch: makeSseFn("PATCH"),
803
- post: makeSseFn("POST"),
804
- put: makeSseFn("PUT"),
805
- trace: makeSseFn("TRACE")
806
- },
807
- trace: makeMethodFn("TRACE")
808
- };
809
- };
810
-
811
- // src/region.ts
812
- var REGION_PATTERN = /^[a-z]{2}[0-9]+$/;
813
- function regionFromApiKey(apiKey) {
814
- const [prefix, region, token] = apiKey.split("_");
815
- if (prefix !== "bk" || !region || !token) return void 0;
816
- return REGION_PATTERN.test(region) ? region : void 0;
817
- }
818
- function baseUrlForRegion(region) {
819
- return `https://${region}.platform.bird.com`;
820
- }
821
-
822
- // src/errors.ts
823
- var BirdError = class extends Error {
824
- constructor(message) {
825
- super(message);
826
- this.name = "BirdError";
827
- Object.setPrototypeOf(this, new.target.prototype);
828
- }
829
- };
830
- var BirdConnectionError = class extends BirdError {
831
- constructor(message) {
832
- super(message);
833
- this.name = "BirdConnectionError";
834
- Object.setPrototypeOf(this, new.target.prototype);
835
- }
836
- };
837
- var BirdTimeoutError = class extends BirdError {
838
- timeoutMs;
839
- constructor(message, timeoutMs) {
840
- super(message);
841
- this.name = "BirdTimeoutError";
842
- this.timeoutMs = timeoutMs;
843
- Object.setPrototypeOf(this, new.target.prototype);
844
- }
845
- };
846
- var BirdWebhookVerificationError = class extends BirdError {
847
- constructor(message) {
848
- super(message);
849
- this.name = "BirdWebhookVerificationError";
850
- Object.setPrototypeOf(this, new.target.prototype);
851
- }
852
- };
853
- var BirdAPIError = class extends BirdError {
854
- statusCode;
855
- code;
856
- type;
857
- errorName;
858
- docUrl;
859
- requestId;
860
- param;
861
- vendorCode;
862
- remediation;
863
- next;
864
- constructor(fields) {
865
- super(fields.message);
866
- this.name = "BirdAPIError";
867
- this.statusCode = fields.statusCode;
868
- this.code = fields.code;
869
- this.type = fields.type;
870
- this.errorName = fields.errorName;
871
- this.docUrl = fields.docUrl;
872
- this.requestId = fields.requestId;
873
- this.param = fields.param;
874
- this.vendorCode = fields.vendorCode;
875
- this.remediation = fields.remediation;
876
- this.next = fields.next;
877
- Object.setPrototypeOf(this, new.target.prototype);
878
- }
879
- };
880
- var BirdAuthError = class extends BirdAPIError {
881
- constructor(fields) {
882
- super(fields);
883
- this.name = "BirdAuthError";
884
- Object.setPrototypeOf(this, new.target.prototype);
885
- }
886
- };
887
- var BirdPermissionError = class extends BirdAPIError {
888
- constructor(fields) {
889
- super(fields);
890
- this.name = "BirdPermissionError";
891
- Object.setPrototypeOf(this, new.target.prototype);
892
- }
893
- };
894
- var BirdNotFoundError = class extends BirdAPIError {
895
- constructor(fields) {
896
- super(fields);
897
- this.name = "BirdNotFoundError";
898
- Object.setPrototypeOf(this, new.target.prototype);
899
- }
900
- };
901
- var BirdConflictError = class extends BirdAPIError {
902
- constructor(fields) {
903
- super(fields);
904
- this.name = "BirdConflictError";
905
- Object.setPrototypeOf(this, new.target.prototype);
906
- }
907
- };
908
- var BirdBadRequestError = class extends BirdAPIError {
909
- constructor(fields) {
910
- super(fields);
911
- this.name = "BirdBadRequestError";
912
- Object.setPrototypeOf(this, new.target.prototype);
913
- }
914
- };
915
- var BirdBillingError = class extends BirdAPIError {
916
- constructor(fields) {
917
- super(fields);
918
- this.name = "BirdBillingError";
919
- Object.setPrototypeOf(this, new.target.prototype);
920
- }
921
- };
922
- var BirdPreconditionError = class extends BirdAPIError {
923
- constructor(fields) {
924
- super(fields);
925
- this.name = "BirdPreconditionError";
926
- Object.setPrototypeOf(this, new.target.prototype);
927
- }
928
- };
929
- var BirdPayloadTooLargeError = class extends BirdAPIError {
930
- constructor(fields) {
931
- super(fields);
932
- this.name = "BirdPayloadTooLargeError";
933
- Object.setPrototypeOf(this, new.target.prototype);
934
- }
935
- };
936
- var BirdInternalError = class extends BirdAPIError {
937
- constructor(fields) {
938
- super(fields);
939
- this.name = "BirdInternalError";
940
- Object.setPrototypeOf(this, new.target.prototype);
941
- }
942
- };
943
- var BirdNotImplementedError = class extends BirdAPIError {
944
- constructor(fields) {
945
- super(fields);
946
- this.name = "BirdNotImplementedError";
947
- Object.setPrototypeOf(this, new.target.prototype);
948
- }
949
- };
950
- var BirdMisdirectedError = class extends BirdAPIError {
951
- constructor(fields) {
952
- super(fields);
953
- this.name = "BirdMisdirectedError";
954
- Object.setPrototypeOf(this, new.target.prototype);
955
- }
956
- };
957
- var BirdServiceUnavailableError = class extends BirdAPIError {
958
- constructor(fields) {
959
- super(fields);
960
- this.name = "BirdServiceUnavailableError";
961
- Object.setPrototypeOf(this, new.target.prototype);
962
- }
963
- };
964
- var BirdValidationError = class extends BirdAPIError {
965
- details;
966
- constructor(fields) {
967
- super(fields);
968
- this.name = "BirdValidationError";
969
- this.details = fields.details;
970
- Object.setPrototypeOf(this, new.target.prototype);
971
- }
972
- };
973
- var BirdRateLimitError = class extends BirdAPIError {
974
- retryAfter;
975
- constructor(fields) {
976
- super(fields);
977
- this.name = "BirdRateLimitError";
978
- this.retryAfter = fields.retryAfter;
979
- Object.setPrototypeOf(this, new.target.prototype);
980
- }
981
- };
982
- function parseRetryAfter(headers) {
983
- const header = headers?.get("Retry-After");
984
- if (!header) return void 0;
985
- const seconds = Number(header);
986
- const value = Number.isFinite(seconds) ? seconds : (Date.parse(header) - Date.now()) / 1e3;
987
- return Number.isFinite(value) && value >= 0 ? Math.round(value) : void 0;
988
- }
989
- function inferType(status) {
990
- switch (status) {
991
- case 400:
992
- return "bad_request_error";
993
- case 401:
994
- return "auth_error";
995
- case 402:
996
- return "billing_error";
997
- case 403:
998
- return "permission_error";
999
- case 404:
1000
- return "not_found_error";
1001
- case 409:
1002
- return "conflict_error";
1003
- case 412:
1004
- case 428:
1005
- return "precondition_error";
1006
- case 413:
1007
- return "payload_too_large_error";
1008
- case 421:
1009
- return "misdirected_error";
1010
- case 422:
1011
- return "validation_error";
1012
- case 429:
1013
- return "rate_limit_error";
1014
- case 501:
1015
- return "not_implemented_error";
1016
- case 503:
1017
- return "service_unavailable_error";
1018
- default:
1019
- return status >= 500 ? "internal_error" : "bad_request_error";
1020
- }
1021
- }
1022
- function mapResponseToError(status, body, headers) {
1023
- const raw = body ?? {};
1024
- const b = raw.error ?? raw ?? {};
1025
- const fields = {
1026
- statusCode: status,
1027
- code: b.code ?? "unknown",
1028
- type: b.type ?? inferType(status),
1029
- errorName: b.name ?? "",
1030
- message: b.message ?? `Request failed with status ${status}`,
1031
- docUrl: b.doc_url ?? "",
1032
- requestId: b.request_id ?? headers?.get("X-Request-Id") ?? "",
1033
- param: b.param,
1034
- vendorCode: b.vendor_code,
1035
- remediation: b.remediation,
1036
- next: b.next ?? []
1037
- // normalize a null/absent wire `next` to [] so callers can always iterate
1038
- };
1039
- switch (fields.type) {
1040
- case "auth_error":
1041
- return new BirdAuthError(fields);
1042
- case "permission_error":
1043
- return new BirdPermissionError(fields);
1044
- case "not_found_error":
1045
- return new BirdNotFoundError(fields);
1046
- case "conflict_error":
1047
- return new BirdConflictError(fields);
1048
- case "bad_request_error":
1049
- return new BirdBadRequestError(fields);
1050
- case "billing_error":
1051
- return new BirdBillingError(fields);
1052
- case "precondition_error":
1053
- return new BirdPreconditionError(fields);
1054
- case "payload_too_large_error":
1055
- return new BirdPayloadTooLargeError(fields);
1056
- case "internal_error":
1057
- return new BirdInternalError(fields);
1058
- case "not_implemented_error":
1059
- return new BirdNotImplementedError(fields);
1060
- case "misdirected_error":
1061
- return new BirdMisdirectedError(fields);
1062
- case "service_unavailable_error":
1063
- return new BirdServiceUnavailableError(fields);
1064
- case "rate_limit_error":
1065
- return new BirdRateLimitError({
1066
- ...fields,
1067
- retryAfter: parseRetryAfter(headers)
1068
- });
1069
- case "validation_error":
1070
- return new BirdValidationError({ ...fields, details: b.details ?? [] });
1071
- default:
1072
- return new BirdAPIError(fields);
1073
- }
1074
- }
1075
-
1076
- // src/core/http.ts
1077
- var BACKOFF_BASE_MS = 500;
1078
- var BACKOFF_CAP_MS = 8e3;
1079
- var RETRY_AFTER_CAP_MS = 6e4;
1080
- var BirdHTTPClient = class {
1081
- constructor(defaults) {
1082
- this.defaults = defaults;
1083
- }
1084
- defaults;
1085
- /**
1086
- * Run a generated hey-api SDK call through the request lifecycle.
1087
- *
1088
- * @param call Invokes the SDK function; receives the per-attempt signal and
1089
- * the idempotency key to set as a header.
1090
- * @returns the parsed body plus transport metadata.
1091
- * @throws a `BirdError` subclass on terminal failure; the native
1092
- * `AbortError` if the caller's signal aborts.
1093
- */
1094
- async request(call, options) {
1095
- const maxRetries = options.maxRetries ?? this.defaults.maxRetries;
1096
- const timeout = options.timeout ?? this.defaults.timeout;
1097
- const idempotencyKey = options.idempotencyKey ?? (isMutation(options.method) ? crypto.randomUUID() : void 0);
1098
- for (let attempt = 0; ; attempt++) {
1099
- throwIfAborted(options.signal);
1100
- const retryOrThrow = async (terminal) => {
1101
- if (attempt >= maxRetries) throw terminal();
1102
- await sleep(backoffDelay(attempt), options.signal);
1103
- };
1104
- const timeoutSignal = AbortSignal.timeout(timeout);
1105
- const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
1106
- let outcome;
1107
- try {
1108
- outcome = await call({ signal, idempotencyKey });
1109
- } catch (err) {
1110
- throwIfAborted(options.signal);
1111
- await retryOrThrow(
1112
- () => timeoutSignal.aborted ? new BirdTimeoutError(`Request timed out after ${timeout}ms`, timeout) : new BirdConnectionError(errorMessage(err))
1113
- );
1114
- continue;
1115
- }
1116
- const res = outcome.response;
1117
- if (!res) {
1118
- await retryOrThrow(() => new BirdConnectionError("No response received from the server"));
1119
- continue;
1120
- }
1121
- if (res.ok) {
1122
- return { data: outcome.data, response: toBirdResponse(res) };
1123
- }
1124
- if (!isRetryableStatus(res.status) || attempt >= maxRetries) {
1125
- throw mapResponseToError(res.status, outcome.error, res.headers);
1126
- }
1127
- await sleep(retryDelay(attempt, res.headers), options.signal);
1128
- }
1129
- }
1130
- };
1131
- function isMutation(method) {
1132
- return ["POST", "PATCH", "DELETE"].includes(method.toUpperCase());
1133
- }
1134
- function isRetryableStatus(status) {
1135
- return [408, 429, 500, 502, 503, 504].includes(status);
1136
- }
1137
- function backoffDelay(attempt) {
1138
- const ceiling = Math.min(BACKOFF_CAP_MS, BACKOFF_BASE_MS * 2 ** attempt);
1139
- return Math.random() * ceiling;
1140
- }
1141
- function retryDelay(attempt, headers) {
1142
- const seconds = parseRetryAfter(headers);
1143
- return seconds === void 0 ? backoffDelay(attempt) : Math.min(seconds * 1e3, RETRY_AFTER_CAP_MS);
1144
- }
1145
- function toBirdResponse(res) {
1146
- return {
1147
- status: res.status,
1148
- headers: res.headers,
1149
- requestId: res.headers.get("X-Request-Id") ?? ""
1150
- };
1151
- }
1152
- function abortReason(signal) {
1153
- return signal?.reason ?? new DOMException("Aborted", "AbortError");
1154
- }
1155
- function throwIfAborted(signal) {
1156
- if (signal?.aborted) throw abortReason(signal);
1157
- }
1158
- function sleep(ms, signal) {
1159
- return new Promise((resolve, reject) => {
1160
- if (signal?.aborted) {
1161
- reject(abortReason(signal));
1162
- return;
1163
- }
1164
- const timer = setTimeout(() => {
1165
- signal?.removeEventListener("abort", onAbort);
1166
- resolve();
1167
- }, ms);
1168
- const onAbort = () => {
1169
- clearTimeout(timer);
1170
- reject(abortReason(signal));
1171
- };
1172
- signal?.addEventListener("abort", onAbort, { once: true });
1173
- });
1174
- }
1175
- function errorMessage(err) {
1176
- if (err instanceof Error) return err.message;
1177
- return String(err);
1178
- }
1179
-
1180
- // src/core/result.ts
1181
- function basePromise(inner) {
1182
- const promise = inner.then((r) => r.data);
1183
- void promise.catch(() => {
1184
- });
1185
- promise.withResponse = () => inner;
1186
- promise.safe = () => toSafe(inner);
1187
- return promise;
1188
- }
1189
- function apiPromise(inner) {
1190
- return basePromise(inner);
1191
- }
1192
- function paginate(fetchPage) {
1193
- const first = fetchPage();
1194
- const promise = basePromise(first);
1195
- promise[Symbol.asyncIterator] = async function* () {
1196
- let result = await first;
1197
- for (; ; ) {
1198
- for (const item of result.data.data) yield item;
1199
- if (result.data.next_cursor == null) return;
1200
- result = await fetchPage(result.data.next_cursor);
1201
- }
1202
- };
1203
- return promise;
1204
- }
1205
- function toSafe(inner) {
1206
- return inner.then(
1207
- ({ data, response }) => ({ data, error: null, response }),
1208
- (error) => {
1209
- if (error instanceof BirdError) return { data: null, error, response: null };
1210
- throw error;
1211
- }
1212
- );
1213
- }
1214
-
1215
- // src/generated/client.gen.ts
1216
- var client = createClient(createConfig());
1217
-
1218
- // src/generated/sdk.gen.ts
1219
- var listEmailMessages = (options) => (options?.client ?? client).get({
1220
- security: [
1221
- { scheme: "bearer", type: "http" },
1222
- {
1223
- in: "cookie",
1224
- name: "bird_session",
1225
- type: "apiKey"
1226
- }
1227
- ],
1228
- url: "/v1/email/messages",
1229
- ...options
1230
- });
1231
- var createEmailMessage = (options) => (options.client ?? client).post({
1232
- security: [
1233
- { scheme: "bearer", type: "http" },
1234
- {
1235
- in: "cookie",
1236
- name: "bird_session",
1237
- type: "apiKey"
1238
- }
1239
- ],
1240
- url: "/v1/email/messages",
1241
- ...options,
1242
- headers: {
1243
- "Content-Type": "application/json",
1244
- ...options.headers
1245
- }
1246
- });
1247
- var createEmailMessageBatch = (options) => (options.client ?? client).post({
1248
- security: [
1249
- { scheme: "bearer", type: "http" },
1250
- {
1251
- in: "cookie",
1252
- name: "bird_session",
1253
- type: "apiKey"
1254
- }
1255
- ],
1256
- url: "/v1/email/batches",
1257
- ...options,
1258
- headers: {
1259
- "Content-Type": "application/json",
1260
- ...options.headers
1261
- }
1262
- });
1263
- var getEmailMessage = (options) => (options.client ?? client).get({
1264
- security: [
1265
- { scheme: "bearer", type: "http" },
1266
- {
1267
- in: "cookie",
1268
- name: "bird_session",
1269
- type: "apiKey"
1270
- }
1271
- ],
1272
- url: "/v1/email/messages/{message_id}",
1273
- ...options
1274
- });
1275
-
1276
- // src/resources/base.ts
1277
- var Resource = class {
1278
- constructor(core, client2) {
1279
- this.core = core;
1280
- this.client = client2;
1281
- }
1282
- core;
1283
- client;
1284
- /** Run a single typed call through the lifecycle. */
1285
- call(method, options, invoke) {
1286
- return apiPromise(
1287
- this.core.request((ctx) => invoke(callContext(ctx, options)), lifecycle(method, options))
1288
- );
1289
- }
1290
- /** Run a cursor-paginated list through the lifecycle (each page retried independently). */
1291
- paginated(method, options, invoke) {
1292
- return paginate(
1293
- (cursor) => this.core.request(
1294
- (ctx) => invoke(callContext(ctx, options), cursor),
1295
- lifecycle(method, options)
1296
- )
1297
- );
1298
- }
1299
- };
1300
- function callContext(ctx, options) {
1301
- return { signal: ctx.signal, headers: mergeHeaders2(ctx.idempotencyKey, options?.headers) };
1302
- }
1303
- function lifecycle(method, options) {
1304
- return {
1305
- method,
1306
- idempotencyKey: options?.idempotencyKey,
1307
- signal: options?.signal,
1308
- timeout: options?.timeout,
1309
- maxRetries: options?.maxRetries
1310
- };
1311
- }
1312
- function mergeHeaders2(idempotencyKey, extra) {
1313
- return {
1314
- ...extra,
1315
- ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
1316
- };
1317
- }
1318
-
1319
- // src/resources/email.ts
1320
- var EmailResource = class extends Resource {
1321
- #defaults;
1322
- constructor(core, client2, defaults) {
1323
- super(core, client2);
1324
- this.#defaults = defaults;
1325
- }
1326
- /**
1327
- * Send an email message. Resolves once the message is accepted for delivery
1328
- * (the API's 202). Throws on failure — a 422 (unverified sender, all
1329
- * recipients suppressed, validation) is a `BirdValidationError`. Fields set as
1330
- * channel defaults may be omitted (per-send value wins).
1331
- *
1332
- * @example Send a message
1333
- * const msg = await bird.email.send({
1334
- * from: { email: "onboarding@messagebird.dev", name: "Bird" },
1335
- * to: ["delivered@messagebird.dev"],
1336
- * subject: "Hello from Bird",
1337
- * html: "<p>My first Bird email.</p>",
1338
- * });
1339
- * console.log(msg.id, msg.status); // "em_…", "accepted"
1340
- *
1341
- * @example A richer send — cc/bcc, reply-to, tags, metadata, click-tracking off, and an idempotency key (safe to retry; the server dedupes)
1342
- * await bird.email.send(
1343
- * {
1344
- * from: "hello@acme.com",
1345
- * to: ["a@example.com", "b@example.com"],
1346
- * cc: ["manager@example.com"],
1347
- * reply_to: ["support@acme.com"],
1348
- * subject: "Your March invoice",
1349
- * html: "<p>Attached.</p>",
1350
- * tags: [{ name: "category", value: "billing" }],
1351
- * metadata: { invoice_id: "inv_123" },
1352
- * track_clicks: false,
1353
- * },
1354
- * { idempotencyKey: "invoice-march/cust_1" },
1355
- * );
1356
- *
1357
- * @example Branch on the typed error hierarchy
1358
- * import { BirdRateLimitError, BirdValidationError, BirdAPIError } from "@messagebird/sdk";
1359
- *
1360
- * try {
1361
- * await bird.email.send({
1362
- * from: { email: "onboarding@messagebird.dev", name: "Bird" },
1363
- * to: ["delivered@messagebird.dev"],
1364
- * subject: "Hello from Bird",
1365
- * html: "<p>My first Bird email.</p>",
1366
- * });
1367
- * } catch (err) {
1368
- * if (err instanceof BirdRateLimitError) console.log(`rate limited — retry in ${err.retryAfter}s`);
1369
- * else if (err instanceof BirdValidationError) console.error(err.details);
1370
- * else if (err instanceof BirdAPIError) console.error(err.code, err.requestId);
1371
- * else throw err;
1372
- * }
1373
- *
1374
- * @example Errors as values with `.safe()`
1375
- * const { data, error } = await bird.email
1376
- * .send({
1377
- * from: { email: "onboarding@messagebird.dev", name: "Bird" },
1378
- * to: ["delivered@messagebird.dev"],
1379
- * subject: "Hello from Bird",
1380
- * html: "<p>My first Bird email.</p>",
1381
- * })
1382
- * .safe();
1383
- * if (error) console.error(error.message);
1384
- * else console.log(data.id);
1385
- */
1386
- send(params, options) {
1387
- const body = { ...this.#defaults, ...params };
1388
- return this.call(
1389
- "POST",
1390
- options,
1391
- ({ signal, headers }) => createEmailMessage({ client: this.client, body, headers, signal })
1392
- );
1393
- }
1394
- /**
1395
- * Send a batch of up to 100 independent email messages in one request. The
1396
- * batch is validated as a unit — if any item fails validation (unverified
1397
- * sender, all recipients suppressed, field-level errors) the whole batch is
1398
- * rejected with a `BirdValidationError` and nothing is queued. Resolves with
1399
- * one accepted item per submitted message, in submission order, once the batch
1400
- * is accepted (the API's 202). Channel defaults are applied per item.
1401
- *
1402
- * @example Send a batch of messages
1403
- * const batch = await bird.email.sendBatch([
1404
- * {
1405
- * from: { email: "onboarding@messagebird.dev", name: "Bird" },
1406
- * to: ["alice@example.com"],
1407
- * subject: "Your receipt",
1408
- * html: "<p>Thanks, Alice.</p>",
1409
- * },
1410
- * {
1411
- * from: { email: "onboarding@messagebird.dev", name: "Bird" },
1412
- * to: ["bob@example.com"],
1413
- * subject: "Your receipt",
1414
- * html: "<p>Thanks, Bob.</p>",
1415
- * },
1416
- * ]);
1417
- * for (const item of batch.data) console.log(item.id, item.status);
1418
- */
1419
- sendBatch(params, options) {
1420
- const body = params.map((item) => ({
1421
- ...this.#defaults,
1422
- ...item
1423
- }));
1424
- return this.call(
1425
- "POST",
1426
- options,
1427
- ({ signal, headers }) => createEmailMessageBatch({ client: this.client, body, headers, signal })
1428
- );
1429
- }
1430
- /**
1431
- * Fetch a message with aggregate delivery status.
1432
- *
1433
- * @example
1434
- * const msg = await bird.email.get("em_abc123");
1435
- * msg.status; // "accepted" | "processed" | "delivered" | "bounced" | …
1436
- * msg.delivered_count;
1437
- * msg.bounced_count;
1438
- */
1439
- get(messageId, options) {
1440
- return this.call(
1441
- "GET",
1442
- options,
1443
- ({ signal, headers }) => getEmailMessage({
1444
- client: this.client,
1445
- path: { message_id: messageId },
1446
- headers,
1447
- signal
1448
- })
1449
- );
1450
- }
1451
- /**
1452
- * List messages, newest first. `await` resolves the first page; `for await`
1453
- * walks every message across all pages.
1454
- *
1455
- * @example Iterate every message, or take one page
1456
- * for await (const message of bird.email.list({ status: "bounced" })) {
1457
- * console.log(message.id);
1458
- * }
1459
- * const page = await bird.email.list({ limit: 50 }); // page.data, page.next_cursor
1460
- */
1461
- list(query, options) {
1462
- return this.paginated(
1463
- "GET",
1464
- options,
1465
- ({ signal, headers }, cursor) => listEmailMessages({
1466
- client: this.client,
1467
- query: { ...query, starting_after: cursor ?? query?.starting_after },
1468
- headers,
1469
- signal
1470
- })
1471
- );
1472
- }
1473
- };
1474
- var WebhooksResource = class {
1475
- #secret;
1476
- constructor(config) {
1477
- this.#secret = config?.secret;
1478
- }
1479
- /**
1480
- * Verify a webhook delivery and return the typed event.
1481
- *
1482
- * **Pass the raw request body**, exactly as received — do NOT parse it first.
1483
- * The Standard Webhooks signature is computed over the raw bytes, so parsing
1484
- * and re-serializing before verifying is the classic webhook bug.
1485
- *
1486
- * The secret comes from `webhooks.secret` on the client; pass `{ secret }` to
1487
- * override per call. Throws {@link BirdWebhookVerificationError} on a bad
1488
- * signature, a stale timestamp, or missing/malformed headers. Unknown event
1489
- * types are returned as-is (handle them in a `default` case) so a newer server
1490
- * event can't break an older SDK.
1491
- *
1492
- * @example One call verifies the signature and returns the typed event
1493
- * // Pass the RAW request body; set the secret via new BirdClient({ webhooks: { secret } }).
1494
- * const event = bird.webhooks.unwrap(rawBody, headers);
1495
- * console.log(event.type); // discriminated union — narrow on event.type
1496
- *
1497
- * @example Verify and dispatch — pass the raw request body, never the parsed JSON
1498
- * // new BirdClient({ apiKey, webhooks: { secret } })
1499
- * try {
1500
- * const event = bird.webhooks.unwrap(rawBody, req.headers);
1501
- * switch (event.type) {
1502
- * case "email.delivered":
1503
- * markDelivered(event.email_id, event.recipient); // narrowed; fields are flat
1504
- * break;
1505
- * case "email.bounced":
1506
- * case "email.complained":
1507
- * suppress(event.recipient);
1508
- * break;
1509
- * default: // unknown future event types — an older SDK won't break on a new one
1510
- * }
1511
- * } catch (err) {
1512
- * if (err instanceof BirdWebhookVerificationError) {
1513
- * // reject with 400 — bad signature, stale timestamp, or missing/malformed headers
1514
- * } else throw err;
1515
- * }
1516
- */
1517
- unwrap(payload, headers, options) {
1518
- const secret = options?.secret ?? this.#secret;
1519
- if (!secret) {
1520
- throw new Error(
1521
- "No webhook secret. Set `webhooks: { secret }` on the client, or pass `{ secret }` to unwrap."
1522
- );
1523
- }
1524
- const wh = new Webhook(secret);
1525
- let verified;
1526
- try {
1527
- verified = wh.verify(payload, toHeaderRecord(headers));
1528
- } catch (err) {
1529
- throw new BirdWebhookVerificationError(
1530
- err instanceof Error ? err.message : "Webhook signature verification failed"
1531
- );
1532
- }
1533
- return verified;
1534
- }
1535
- };
1536
- function toHeaderRecord(headers) {
1537
- return headers instanceof Headers ? Object.fromEntries(headers) : headers;
1538
- }
1539
-
1540
- // src/client.ts
1541
- var DEFAULT_TIMEOUT_MS = 6e4;
1542
- var DEFAULT_MAX_RETRIES = 2;
1543
- function resolveBaseUrl(options) {
1544
- if (options.baseUrl) return options.baseUrl;
1545
- const region = options.region ?? regionFromApiKey(options.apiKey);
1546
- if (!region) {
1547
- throw new Error(
1548
- "Unable to determine region: API key is not in the expected bk_{region}_{token} format. Pass an explicit `region` or `baseUrl`."
1549
- );
1550
- }
1551
- return baseUrlForRegion(region);
1552
- }
1553
- function resolveRawRequestUrl(baseUrl, path) {
1554
- if (!path.startsWith("/") || path.startsWith("//")) {
1555
- throw new TypeError(
1556
- "bird.request path must be an absolute path starting with a single `/`"
1557
- );
1558
- }
1559
- const base = new URL(baseUrl);
1560
- const url = new URL(baseUrl + path);
1561
- if (url.origin !== base.origin) {
1562
- throw new TypeError(
1563
- "bird.request path must stay on the configured Bird API origin"
1564
- );
1565
- }
1566
- return url;
1567
- }
1568
- var BirdClient = class {
1569
- core;
1570
- // The generated hey-api client, configured with this instance's base URL,
1571
- // auth, and fetch. Resources call the generated SDK functions through it.
1572
- #client;
1573
- #baseUrl;
1574
- #fetch;
1575
- #headers;
1576
- /** The email channel — `bird.email.send(...)`, `.get(...)`, `.list(...)`. */
1577
- email;
1578
- /** Webhooks — `bird.webhooks.unwrap(payload, headers)` verifies an inbound delivery. */
1579
- webhooks;
1580
- constructor(options) {
1581
- const opts = options;
1582
- this.#baseUrl = resolveBaseUrl(opts);
1583
- this.#fetch = opts.fetch ?? fetch;
1584
- this.#headers = {
1585
- ...opts.defaultHeaders,
1586
- Authorization: `Bearer ${opts.apiKey}`,
1587
- "User-Agent": `bird-sdk-js/${"0.2.2"}`,
1588
- // Bird-* client-identity headers (ADR-0074): the API attributes the SDK
1589
- // surface from these, not the User-Agent. Edge-safe, so no os/arch/runtime
1590
- // (those need Node globals this SDK must not touch); surface + version only.
1591
- "Bird-Surface": "sdk-js",
1592
- "Bird-Version": "0.2.2"
1593
- };
1594
- this.#client = createClient(
1595
- createConfig({
1596
- baseUrl: this.#baseUrl,
1597
- fetch: this.#fetch,
1598
- headers: this.#headers
1599
- })
1600
- );
1601
- this.core = new BirdHTTPClient({
1602
- timeout: opts.timeout ?? DEFAULT_TIMEOUT_MS,
1603
- maxRetries: opts.maxRetries ?? DEFAULT_MAX_RETRIES
1604
- });
1605
- this.email = new EmailResource(
1606
- this.core,
1607
- this.#client,
1608
- opts.email
1609
- );
1610
- this.webhooks = new WebhooksResource(opts.webhooks);
1611
- }
1612
- /**
1613
- * Escape hatch for endpoints the typed resources don't cover. Runs the full
1614
- * lifecycle (auth, retries, idempotency, error mapping); you supply the
1615
- * response type. Prefer a typed resource method where one exists.
1616
- *
1617
- * @throws {TypeError} if `req.path` does not start with exactly one `/` or
1618
- * resolves to a different origin than the configured Bird API base URL.
1619
- *
1620
- * @example Reach an endpoint outside the curated surface — you supply the response type
1621
- * type Suppressions = { data: Array<{ recipient: string }> };
1622
- * const suppressions = await bird.request<Suppressions>({ method: "GET", path: "/v1/email/suppressions" });
1623
- * console.log(suppressions.data.length);
1624
- */
1625
- request(req, options) {
1626
- const url = resolveRawRequestUrl(this.#baseUrl, req.path);
1627
- return apiPromise(
1628
- this.core.request(
1629
- (ctx) => this.#raw(url, req, ctx, options?.headers),
1630
- {
1631
- method: req.method,
1632
- idempotencyKey: options?.idempotencyKey,
1633
- signal: options?.signal,
1634
- timeout: options?.timeout,
1635
- maxRetries: options?.maxRetries
1636
- }
1637
- )
1638
- );
1639
- }
1640
- async #raw(url, req, ctx, extraHeaders) {
1641
- url = new URL(url);
1642
- if (req.query) {
1643
- for (const [key, value] of Object.entries(req.query)) {
1644
- if (value !== void 0) url.searchParams.set(key, String(value));
1645
- }
1646
- }
1647
- const headers = {
1648
- ...extraHeaders,
1649
- ...this.#headers
1650
- };
1651
- if (ctx.idempotencyKey) headers["Idempotency-Key"] = ctx.idempotencyKey;
1652
- if (req.body !== void 0) headers["Content-Type"] = "application/json";
1653
- const response = await this.#fetch(url, {
1654
- method: req.method,
1655
- headers,
1656
- body: req.body !== void 0 ? JSON.stringify(req.body) : void 0,
1657
- signal: ctx.signal
1658
- });
1659
- if (response.ok) {
1660
- const data = response.status === 204 ? void 0 : await response.json().catch(() => void 0);
1661
- return { data, response };
1662
- }
1663
- const error = await response.clone().json().catch(() => void 0);
1664
- return { error, response };
1665
- }
1666
- };
1667
-
1668
- // src/event-types.gen.ts
1669
- var WebhookEventType = {
1670
- DomainFailed: "domain.failed",
1671
- DomainVerified: "domain.verified",
1672
- EmailAccepted: "email.accepted",
1673
- EmailBounced: "email.bounced",
1674
- EmailCanceled: "email.canceled",
1675
- EmailClicked: "email.clicked",
1676
- EmailComplained: "email.complained",
1677
- EmailDeferred: "email.deferred",
1678
- EmailDelivered: "email.delivered",
1679
- EmailListUnsubscribed: "email.list_unsubscribed",
1680
- EmailOpened: "email.opened",
1681
- EmailOutOfBandBounce: "email.out_of_band_bounce",
1682
- EmailProcessed: "email.processed",
1683
- EmailReceived: "email.received",
1684
- EmailRejected: "email.rejected",
1685
- EmailScheduled: "email.scheduled",
1686
- EmailSuppressionCreated: "email_suppression.created",
1687
- EmailUnsubscribed: "email.unsubscribed",
1688
- SmsAccepted: "sms.accepted",
1689
- SmsDelivered: "sms.delivered",
1690
- SmsExpired: "sms.expired",
1691
- SmsFailed: "sms.failed",
1692
- SmsRejected: "sms.rejected",
1693
- SmsSent: "sms.sent",
1694
- SmsUndelivered: "sms.undelivered"
1695
- };
1696
-
1697
- export { BirdAPIError, BirdAuthError, BirdBadRequestError, BirdBillingError, BirdClient, BirdConflictError, BirdConnectionError, BirdError, BirdInternalError, BirdMisdirectedError, BirdNotFoundError, BirdNotImplementedError, BirdPayloadTooLargeError, BirdPermissionError, BirdPreconditionError, BirdRateLimitError, BirdServiceUnavailableError, BirdTimeoutError, BirdValidationError, BirdWebhookVerificationError, WebhookEventType, baseUrlForRegion, regionFromApiKey };
1698
- //# sourceMappingURL=index.js.map
1699
- //# sourceMappingURL=index.js.map