@messagebird/sdk 0.3.0 → 0.4.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/dist/index.mjs ADDED
@@ -0,0 +1,3030 @@
1
+ import { Webhook } from "standardwebhooks";
2
+ //#region src/generated/core/bodySerializer.gen.ts
3
+ const jsonBodySerializer = { bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value) };
4
+ //#endregion
5
+ //#region src/generated/core/serverSentEvents.gen.ts
6
+ function createSseClient({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) {
7
+ let lastEventId;
8
+ const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
9
+ const createStream = async function* () {
10
+ let retryDelay = sseDefaultRetryDelay ?? 3e3;
11
+ let attempt = 0;
12
+ const signal = options.signal ?? new AbortController().signal;
13
+ while (true) {
14
+ if (signal.aborted) break;
15
+ attempt++;
16
+ const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
17
+ if (lastEventId !== void 0) headers.set("Last-Event-ID", lastEventId);
18
+ try {
19
+ const requestInit = {
20
+ redirect: "follow",
21
+ ...options,
22
+ body: options.serializedBody,
23
+ headers,
24
+ signal
25
+ };
26
+ let request = new Request(url, requestInit);
27
+ if (onRequest) request = await onRequest(url, requestInit);
28
+ const response = await (options.fetch ?? globalThis.fetch)(request);
29
+ if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
30
+ if (!response.body) throw new Error("No body in SSE response");
31
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
32
+ let buffer = "";
33
+ const abortHandler = () => {
34
+ try {
35
+ reader.cancel();
36
+ } catch {}
37
+ };
38
+ signal.addEventListener("abort", abortHandler);
39
+ try {
40
+ while (true) {
41
+ const { done, value } = await reader.read();
42
+ if (done) break;
43
+ buffer += value;
44
+ buffer = buffer.replace(/\r\n?/g, "\n");
45
+ const chunks = buffer.split("\n\n");
46
+ buffer = chunks.pop() ?? "";
47
+ for (const chunk of chunks) {
48
+ const lines = chunk.split("\n");
49
+ const dataLines = [];
50
+ let eventName;
51
+ for (const line of lines) if (line.startsWith("data:")) dataLines.push(line.replace(/^data:\s*/, ""));
52
+ else if (line.startsWith("event:")) eventName = line.replace(/^event:\s*/, "");
53
+ else if (line.startsWith("id:")) lastEventId = line.replace(/^id:\s*/, "");
54
+ else if (line.startsWith("retry:")) {
55
+ const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
56
+ if (!Number.isNaN(parsed)) retryDelay = parsed;
57
+ }
58
+ let data;
59
+ let parsedJson = false;
60
+ if (dataLines.length) {
61
+ const rawData = dataLines.join("\n");
62
+ try {
63
+ data = JSON.parse(rawData);
64
+ parsedJson = true;
65
+ } catch {
66
+ data = rawData;
67
+ }
68
+ }
69
+ if (parsedJson) {
70
+ if (responseValidator) await responseValidator(data);
71
+ if (responseTransformer) data = await responseTransformer(data);
72
+ }
73
+ onSseEvent?.({
74
+ data,
75
+ event: eventName,
76
+ id: lastEventId,
77
+ retry: retryDelay
78
+ });
79
+ if (dataLines.length) yield data;
80
+ }
81
+ }
82
+ } finally {
83
+ signal.removeEventListener("abort", abortHandler);
84
+ reader.releaseLock();
85
+ }
86
+ break;
87
+ } catch (error) {
88
+ onSseError?.(error);
89
+ if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) break;
90
+ const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
91
+ await sleep(backoff);
92
+ }
93
+ }
94
+ };
95
+ return { stream: createStream() };
96
+ }
97
+ //#endregion
98
+ //#region src/generated/core/pathSerializer.gen.ts
99
+ const separatorArrayExplode = (style) => {
100
+ switch (style) {
101
+ case "label": return ".";
102
+ case "matrix": return ";";
103
+ case "simple": return ",";
104
+ default: return "&";
105
+ }
106
+ };
107
+ const separatorArrayNoExplode = (style) => {
108
+ switch (style) {
109
+ case "form": return ",";
110
+ case "pipeDelimited": return "|";
111
+ case "spaceDelimited": return "%20";
112
+ default: return ",";
113
+ }
114
+ };
115
+ const separatorObjectExplode = (style) => {
116
+ switch (style) {
117
+ case "label": return ".";
118
+ case "matrix": return ";";
119
+ case "simple": return ",";
120
+ default: return "&";
121
+ }
122
+ };
123
+ const serializeArrayParam = ({ allowReserved, explode, name, style, value }) => {
124
+ if (!explode) {
125
+ const joinedValues = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
126
+ switch (style) {
127
+ case "label": return `.${joinedValues}`;
128
+ case "matrix": return `;${name}=${joinedValues}`;
129
+ case "simple": return joinedValues;
130
+ default: return `${name}=${joinedValues}`;
131
+ }
132
+ }
133
+ const separator = separatorArrayExplode(style);
134
+ const joinedValues = value.map((v) => {
135
+ if (style === "label" || style === "simple") return allowReserved ? v : encodeURIComponent(v);
136
+ return serializePrimitiveParam({
137
+ allowReserved,
138
+ name,
139
+ value: v
140
+ });
141
+ }).join(separator);
142
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
143
+ };
144
+ const serializePrimitiveParam = ({ allowReserved, name, value }) => {
145
+ if (value === void 0 || value === null) return "";
146
+ if (typeof value === "object") throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
147
+ return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
148
+ };
149
+ const serializeObjectParam = ({ allowReserved, explode, name, style, value, valueOnly }) => {
150
+ if (value instanceof Date) return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
151
+ if (style !== "deepObject" && !explode) {
152
+ let values = [];
153
+ Object.entries(value).forEach(([key, v]) => {
154
+ values = [
155
+ ...values,
156
+ key,
157
+ allowReserved ? v : encodeURIComponent(v)
158
+ ];
159
+ });
160
+ const joinedValues = values.join(",");
161
+ switch (style) {
162
+ case "form": return `${name}=${joinedValues}`;
163
+ case "label": return `.${joinedValues}`;
164
+ case "matrix": return `;${name}=${joinedValues}`;
165
+ default: return joinedValues;
166
+ }
167
+ }
168
+ const separator = separatorObjectExplode(style);
169
+ const joinedValues = Object.entries(value).map(([key, v]) => serializePrimitiveParam({
170
+ allowReserved,
171
+ name: style === "deepObject" ? `${name}[${key}]` : key,
172
+ value: v
173
+ })).join(separator);
174
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
175
+ };
176
+ //#endregion
177
+ //#region src/generated/core/utils.gen.ts
178
+ const PATH_PARAM_RE = /\{[^{}]+\}/g;
179
+ const defaultPathSerializer = ({ path, url: _url }) => {
180
+ let url = _url;
181
+ const matches = _url.match(PATH_PARAM_RE);
182
+ if (matches) for (const match of matches) {
183
+ let explode = false;
184
+ let name = match.substring(1, match.length - 1);
185
+ let style = "simple";
186
+ if (name.endsWith("*")) {
187
+ explode = true;
188
+ name = name.substring(0, name.length - 1);
189
+ }
190
+ if (name.startsWith(".")) {
191
+ name = name.substring(1);
192
+ style = "label";
193
+ } else if (name.startsWith(";")) {
194
+ name = name.substring(1);
195
+ style = "matrix";
196
+ }
197
+ const value = path[name];
198
+ if (value === void 0 || value === null) continue;
199
+ if (Array.isArray(value)) {
200
+ url = url.replace(match, serializeArrayParam({
201
+ explode,
202
+ name,
203
+ style,
204
+ value
205
+ }));
206
+ continue;
207
+ }
208
+ if (typeof value === "object") {
209
+ url = url.replace(match, serializeObjectParam({
210
+ explode,
211
+ name,
212
+ style,
213
+ value,
214
+ valueOnly: true
215
+ }));
216
+ continue;
217
+ }
218
+ if (style === "matrix") {
219
+ url = url.replace(match, `;${serializePrimitiveParam({
220
+ name,
221
+ value
222
+ })}`);
223
+ continue;
224
+ }
225
+ const replaceValue = encodeURIComponent(style === "label" ? `.${value}` : value);
226
+ url = url.replace(match, replaceValue);
227
+ }
228
+ return url;
229
+ };
230
+ const getUrl = ({ baseUrl, path, query, querySerializer, url: _url }) => {
231
+ const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
232
+ let url = (baseUrl ?? "") + pathUrl;
233
+ if (path) url = defaultPathSerializer({
234
+ path,
235
+ url
236
+ });
237
+ let search = query ? querySerializer(query) : "";
238
+ if (search.startsWith("?")) search = search.substring(1);
239
+ if (search) url += `?${search}`;
240
+ return url;
241
+ };
242
+ function getValidRequestBody(options) {
243
+ const hasBody = options.body !== void 0;
244
+ if (hasBody && options.bodySerializer) {
245
+ if ("serializedBody" in options) return options.serializedBody !== void 0 && options.serializedBody !== "" ? options.serializedBody : null;
246
+ return options.body !== "" ? options.body : null;
247
+ }
248
+ if (hasBody) return options.body;
249
+ }
250
+ //#endregion
251
+ //#region src/generated/core/auth.gen.ts
252
+ const getAuthToken = async (auth, callback) => {
253
+ const token = typeof callback === "function" ? await callback(auth) : callback;
254
+ if (!token) return;
255
+ if (auth.scheme === "bearer") return `Bearer ${token}`;
256
+ if (auth.scheme === "basic") return `Basic ${btoa(token)}`;
257
+ return token;
258
+ };
259
+ //#endregion
260
+ //#region src/generated/client/utils.gen.ts
261
+ const createQuerySerializer = ({ parameters = {}, ...args } = {}) => {
262
+ const querySerializer = (queryParams) => {
263
+ const search = [];
264
+ if (queryParams && typeof queryParams === "object") for (const name in queryParams) {
265
+ const value = queryParams[name];
266
+ if (value === void 0 || value === null) continue;
267
+ const options = parameters[name] || args;
268
+ if (Array.isArray(value)) {
269
+ const serializedArray = serializeArrayParam({
270
+ allowReserved: options.allowReserved,
271
+ explode: true,
272
+ name,
273
+ style: "form",
274
+ value,
275
+ ...options.array
276
+ });
277
+ if (serializedArray) search.push(serializedArray);
278
+ } else if (typeof value === "object") {
279
+ const serializedObject = serializeObjectParam({
280
+ allowReserved: options.allowReserved,
281
+ explode: true,
282
+ name,
283
+ style: "deepObject",
284
+ value,
285
+ ...options.object
286
+ });
287
+ if (serializedObject) search.push(serializedObject);
288
+ } else {
289
+ const serializedPrimitive = serializePrimitiveParam({
290
+ allowReserved: options.allowReserved,
291
+ name,
292
+ value
293
+ });
294
+ if (serializedPrimitive) search.push(serializedPrimitive);
295
+ }
296
+ }
297
+ return search.join("&");
298
+ };
299
+ return querySerializer;
300
+ };
301
+ /**
302
+ * Infers parseAs value from provided Content-Type header.
303
+ */
304
+ const getParseAs = (contentType) => {
305
+ if (!contentType) return "stream";
306
+ const cleanContent = contentType.split(";")[0]?.trim();
307
+ if (!cleanContent) return;
308
+ if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) return "json";
309
+ if (cleanContent === "multipart/form-data") return "formData";
310
+ if ([
311
+ "application/",
312
+ "audio/",
313
+ "image/",
314
+ "video/"
315
+ ].some((type) => cleanContent.startsWith(type))) return "blob";
316
+ if (cleanContent.startsWith("text/")) return "text";
317
+ };
318
+ const checkForExistence = (options, name) => {
319
+ if (!name) return false;
320
+ if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) return true;
321
+ return false;
322
+ };
323
+ async function setAuthParams(options) {
324
+ for (const auth of options.security ?? []) {
325
+ if (checkForExistence(options, auth.name)) continue;
326
+ const token = await getAuthToken(auth, options.auth);
327
+ if (!token) continue;
328
+ const name = auth.name ?? "Authorization";
329
+ switch (auth.in) {
330
+ case "query":
331
+ if (!options.query) options.query = {};
332
+ options.query[name] = token;
333
+ break;
334
+ case "cookie":
335
+ options.headers.append("Cookie", `${name}=${token}`);
336
+ break;
337
+ default:
338
+ options.headers.set(name, token);
339
+ break;
340
+ }
341
+ }
342
+ }
343
+ const buildUrl = (options) => getUrl({
344
+ baseUrl: options.baseUrl,
345
+ path: options.path,
346
+ query: options.query,
347
+ querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
348
+ url: options.url
349
+ });
350
+ const mergeConfigs = (a, b) => {
351
+ const config = {
352
+ ...a,
353
+ ...b
354
+ };
355
+ if (config.baseUrl?.endsWith("/")) config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
356
+ config.headers = mergeHeaders$1(a.headers, b.headers);
357
+ return config;
358
+ };
359
+ const headersEntries = (headers) => {
360
+ const entries = [];
361
+ headers.forEach((value, key) => {
362
+ entries.push([key, value]);
363
+ });
364
+ return entries;
365
+ };
366
+ const mergeHeaders$1 = (...headers) => {
367
+ const mergedHeaders = new Headers();
368
+ for (const header of headers) {
369
+ if (!header) continue;
370
+ const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
371
+ for (const [key, value] of iterator) if (value === null) mergedHeaders.delete(key);
372
+ else if (Array.isArray(value)) for (const v of value) mergedHeaders.append(key, v);
373
+ else if (value !== void 0) mergedHeaders.set(key, typeof value === "object" ? JSON.stringify(value) : value);
374
+ }
375
+ return mergedHeaders;
376
+ };
377
+ var Interceptors = class {
378
+ fns = [];
379
+ clear() {
380
+ this.fns = [];
381
+ }
382
+ eject(id) {
383
+ const index = this.getInterceptorIndex(id);
384
+ if (this.fns[index]) this.fns[index] = null;
385
+ }
386
+ exists(id) {
387
+ const index = this.getInterceptorIndex(id);
388
+ return Boolean(this.fns[index]);
389
+ }
390
+ getInterceptorIndex(id) {
391
+ if (typeof id === "number") return this.fns[id] ? id : -1;
392
+ return this.fns.indexOf(id);
393
+ }
394
+ update(id, fn) {
395
+ const index = this.getInterceptorIndex(id);
396
+ if (this.fns[index]) {
397
+ this.fns[index] = fn;
398
+ return id;
399
+ }
400
+ return false;
401
+ }
402
+ use(fn) {
403
+ this.fns.push(fn);
404
+ return this.fns.length - 1;
405
+ }
406
+ };
407
+ const createInterceptors = () => ({
408
+ error: new Interceptors(),
409
+ request: new Interceptors(),
410
+ response: new Interceptors()
411
+ });
412
+ const defaultQuerySerializer = createQuerySerializer({
413
+ allowReserved: false,
414
+ array: {
415
+ explode: true,
416
+ style: "form"
417
+ },
418
+ object: {
419
+ explode: true,
420
+ style: "deepObject"
421
+ }
422
+ });
423
+ const defaultHeaders = { "Content-Type": "application/json" };
424
+ const createConfig = (override = {}) => ({
425
+ ...jsonBodySerializer,
426
+ headers: defaultHeaders,
427
+ parseAs: "auto",
428
+ querySerializer: defaultQuerySerializer,
429
+ ...override
430
+ });
431
+ //#endregion
432
+ //#region src/generated/client/client.gen.ts
433
+ const createClient = (config = {}) => {
434
+ let _config = mergeConfigs(createConfig(), config);
435
+ const getConfig = () => ({ ..._config });
436
+ const setConfig = (config) => {
437
+ _config = mergeConfigs(_config, config);
438
+ return getConfig();
439
+ };
440
+ const interceptors = createInterceptors();
441
+ const beforeRequest = async (options) => {
442
+ const opts = {
443
+ ..._config,
444
+ ...options,
445
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
446
+ headers: mergeHeaders$1(_config.headers, options.headers),
447
+ serializedBody: void 0
448
+ };
449
+ if (opts.security) await setAuthParams(opts);
450
+ if (opts.requestValidator) await opts.requestValidator(opts);
451
+ if (opts.body !== void 0 && opts.bodySerializer) opts.serializedBody = opts.bodySerializer(opts.body);
452
+ if (opts.body === void 0 || opts.serializedBody === "") opts.headers.delete("Content-Type");
453
+ const resolvedOpts = opts;
454
+ return {
455
+ opts: resolvedOpts,
456
+ url: buildUrl(resolvedOpts)
457
+ };
458
+ };
459
+ const request = async (options) => {
460
+ const throwOnError = options.throwOnError ?? _config.throwOnError;
461
+ const responseStyle = options.responseStyle ?? _config.responseStyle;
462
+ let request;
463
+ let response;
464
+ try {
465
+ const { opts, url } = await beforeRequest(options);
466
+ const requestInit = {
467
+ redirect: "follow",
468
+ ...opts,
469
+ body: getValidRequestBody(opts)
470
+ };
471
+ request = new Request(url, requestInit);
472
+ for (const fn of interceptors.request.fns) if (fn) request = await fn(request, opts);
473
+ const _fetch = opts.fetch;
474
+ response = await _fetch(request);
475
+ for (const fn of interceptors.response.fns) if (fn) response = await fn(response, request, opts);
476
+ const result = {
477
+ request,
478
+ response
479
+ };
480
+ if (response.ok) {
481
+ const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
482
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
483
+ let emptyData;
484
+ switch (parseAs) {
485
+ case "arrayBuffer":
486
+ case "blob":
487
+ case "text":
488
+ emptyData = await response[parseAs]();
489
+ break;
490
+ case "formData":
491
+ emptyData = new FormData();
492
+ break;
493
+ case "stream":
494
+ emptyData = response.body;
495
+ break;
496
+ default:
497
+ emptyData = {};
498
+ break;
499
+ }
500
+ return opts.responseStyle === "data" ? emptyData : {
501
+ data: emptyData,
502
+ ...result
503
+ };
504
+ }
505
+ let data;
506
+ switch (parseAs) {
507
+ case "arrayBuffer":
508
+ case "blob":
509
+ case "formData":
510
+ case "text":
511
+ data = await response[parseAs]();
512
+ break;
513
+ case "json": {
514
+ const text = await response.text();
515
+ data = text ? JSON.parse(text) : {};
516
+ break;
517
+ }
518
+ case "stream": return opts.responseStyle === "data" ? response.body : {
519
+ data: response.body,
520
+ ...result
521
+ };
522
+ }
523
+ if (parseAs === "json") {
524
+ if (opts.responseValidator) await opts.responseValidator(data);
525
+ if (opts.responseTransformer) data = await opts.responseTransformer(data);
526
+ }
527
+ return opts.responseStyle === "data" ? data : {
528
+ data,
529
+ ...result
530
+ };
531
+ }
532
+ const textError = await response.text();
533
+ let jsonError;
534
+ try {
535
+ jsonError = JSON.parse(textError);
536
+ } catch {}
537
+ throw jsonError ?? textError;
538
+ } catch (error) {
539
+ let finalError = error;
540
+ for (const fn of interceptors.error.fns) if (fn) finalError = await fn(finalError, response, request, options);
541
+ finalError = finalError || {};
542
+ if (throwOnError) throw finalError;
543
+ return responseStyle === "data" ? void 0 : {
544
+ error: finalError,
545
+ request,
546
+ response
547
+ };
548
+ }
549
+ };
550
+ const makeMethodFn = (method) => (options) => request({
551
+ ...options,
552
+ method
553
+ });
554
+ const makeSseFn = (method) => async (options) => {
555
+ const { opts, url } = await beforeRequest(options);
556
+ return createSseClient({
557
+ ...opts,
558
+ body: opts.body,
559
+ method,
560
+ onRequest: async (url, init) => {
561
+ let request = new Request(url, init);
562
+ for (const fn of interceptors.request.fns) if (fn) request = await fn(request, opts);
563
+ return request;
564
+ },
565
+ serializedBody: getValidRequestBody(opts),
566
+ url
567
+ });
568
+ };
569
+ const _buildUrl = (options) => buildUrl({
570
+ ..._config,
571
+ ...options
572
+ });
573
+ return {
574
+ buildUrl: _buildUrl,
575
+ connect: makeMethodFn("CONNECT"),
576
+ delete: makeMethodFn("DELETE"),
577
+ get: makeMethodFn("GET"),
578
+ getConfig,
579
+ head: makeMethodFn("HEAD"),
580
+ interceptors,
581
+ options: makeMethodFn("OPTIONS"),
582
+ patch: makeMethodFn("PATCH"),
583
+ post: makeMethodFn("POST"),
584
+ put: makeMethodFn("PUT"),
585
+ request,
586
+ setConfig,
587
+ sse: {
588
+ connect: makeSseFn("CONNECT"),
589
+ delete: makeSseFn("DELETE"),
590
+ get: makeSseFn("GET"),
591
+ head: makeSseFn("HEAD"),
592
+ options: makeSseFn("OPTIONS"),
593
+ patch: makeSseFn("PATCH"),
594
+ post: makeSseFn("POST"),
595
+ put: makeSseFn("PUT"),
596
+ trace: makeSseFn("TRACE")
597
+ },
598
+ trace: makeMethodFn("TRACE")
599
+ };
600
+ };
601
+ //#endregion
602
+ //#region src/region.ts
603
+ const REGION_PATTERN = /^[a-z]{2}[0-9]+$/;
604
+ /** Extracts the region code from a `bk_{region}_{token}` key, or undefined. */
605
+ function regionFromApiKey(apiKey) {
606
+ const [prefix, region, token] = apiKey.split("_");
607
+ if (prefix !== "bk" || !region || !token) return void 0;
608
+ return REGION_PATTERN.test(region) ? region : void 0;
609
+ }
610
+ function baseUrlForRegion(region) {
611
+ return `https://${region}.platform.bird.com`;
612
+ }
613
+ //#endregion
614
+ //#region src/caller-rules.gen.ts
615
+ const callerRules = [
616
+ {
617
+ env: "CLAUDECODE",
618
+ name: "claude-code"
619
+ },
620
+ {
621
+ env: "CODEX_CI",
622
+ name: "codex"
623
+ },
624
+ {
625
+ env: "GEMINI_CLI",
626
+ name: "gemini"
627
+ },
628
+ {
629
+ env: "QWEN_CODE",
630
+ name: "qwen"
631
+ },
632
+ {
633
+ env: "PI_CODING_AGENT",
634
+ name: "pi"
635
+ },
636
+ {
637
+ env: "OPENCODE",
638
+ name: "opencode"
639
+ },
640
+ {
641
+ env: "CLINE_ACTIVE",
642
+ name: "cline"
643
+ },
644
+ {
645
+ env: "ROO_ACTIVE",
646
+ name: "roo"
647
+ },
648
+ {
649
+ env: "CURSOR_TRACE_ID",
650
+ name: "cursor"
651
+ },
652
+ {
653
+ env: "CURSOR_AGENT",
654
+ name: "cursor"
655
+ },
656
+ {
657
+ env: "ANTIGRAVITY_AGENT",
658
+ name: "antigravity"
659
+ },
660
+ {
661
+ env: "AUGMENT_AGENT",
662
+ name: "augment"
663
+ },
664
+ {
665
+ env: "AGENT",
666
+ passthrough: true
667
+ },
668
+ {
669
+ env: "AI_AGENT",
670
+ passthrough: true
671
+ },
672
+ {
673
+ env: "REPL_ID",
674
+ name: "replit"
675
+ },
676
+ {
677
+ env: "CI",
678
+ name: "ci"
679
+ },
680
+ {
681
+ env: "GITHUB_ACTIONS",
682
+ name: "ci"
683
+ },
684
+ {
685
+ env: "TERM_PROGRAM",
686
+ equals: "zed",
687
+ name: "zed"
688
+ },
689
+ {
690
+ env: "ZED_TERM",
691
+ name: "zed"
692
+ },
693
+ {
694
+ env: "TERM_PROGRAM",
695
+ equals: "kiro",
696
+ name: "kiro"
697
+ },
698
+ {
699
+ env: "TERM_PROGRAM",
700
+ equals: "WarpTerminal",
701
+ name: "warp"
702
+ },
703
+ {
704
+ env: "TERMINAL_EMULATOR",
705
+ equals: "JetBrains-JediTerm",
706
+ name: "jetbrains"
707
+ },
708
+ {
709
+ env: "__CFBundleIdentifier",
710
+ equals: "com.exafunction.windsurf",
711
+ name: "windsurf"
712
+ },
713
+ {
714
+ env: "TERM_PROGRAM",
715
+ equals: "vscode",
716
+ name: "vscode"
717
+ }
718
+ ];
719
+ const callerBooleanishSkip = /* @__PURE__ */ new Set([
720
+ "1",
721
+ "0",
722
+ "true",
723
+ "false",
724
+ "yes",
725
+ "no",
726
+ "on",
727
+ "off"
728
+ ]);
729
+ const callerDefault = "shell";
730
+ //#endregion
731
+ //#region src/detect-caller.ts
732
+ /**
733
+ * Infers the environment driving the SDK for the `Bird-Caller` usage-telemetry
734
+ * label by walking the generated rules in order (single source of truth:
735
+ * `clients/caller-detection.yaml`, shared with the CLI and the other SDKs).
736
+ * Best-effort and non-authoritative — it only labels traffic, never gates
737
+ * behavior.
738
+ *
739
+ * Edge-safe: `process` is read only through a `typeof`-style `globalThis` guard,
740
+ * so on a browser (no `process.env`) it returns `""` and the client sends no
741
+ * `Bird-Caller` header. `env` is injected in tests.
742
+ */
743
+ function detectCaller(env) {
744
+ let source = env;
745
+ if (source === void 0) {
746
+ const proc = globalThis.process;
747
+ if (proc?.versions?.node === void 0) return "";
748
+ source = proc.env ?? {};
749
+ }
750
+ for (const rule of callerRules) {
751
+ const value = source[rule.env];
752
+ if (value === void 0 || value === "" || rule.equals !== void 0 && value !== rule.equals) continue;
753
+ if (!rule.passthrough) return rule.name;
754
+ const sanitized = sanitizeCaller(value);
755
+ if (sanitized) return sanitized;
756
+ }
757
+ return callerDefault;
758
+ }
759
+ function sanitizeCaller(value) {
760
+ const s = value.trim().toLowerCase();
761
+ if (s === "" || s.length > 32 || callerBooleanishSkip.has(s)) return "";
762
+ return /^[a-z0-9._-]+$/.test(s) ? s : "";
763
+ }
764
+ //#endregion
765
+ //#region src/errors.ts
766
+ /** Root of the hierarchy. Catch this to catch anything the SDK throws. */
767
+ var BirdError = class extends Error {
768
+ constructor(message) {
769
+ super(message);
770
+ this.name = "BirdError";
771
+ Object.setPrototypeOf(this, new.target.prototype);
772
+ }
773
+ };
774
+ /** Network-level failure with no HTTP response (DNS, refused, socket hangup). */
775
+ var BirdConnectionError = class extends BirdError {
776
+ constructor(message) {
777
+ super(message);
778
+ this.name = "BirdConnectionError";
779
+ Object.setPrototypeOf(this, new.target.prototype);
780
+ }
781
+ };
782
+ /** A single attempt exceeded its timeout. Retryable. */
783
+ var BirdTimeoutError = class extends BirdError {
784
+ timeoutMs;
785
+ constructor(message, timeoutMs) {
786
+ super(message);
787
+ this.name = "BirdTimeoutError";
788
+ this.timeoutMs = timeoutMs;
789
+ Object.setPrototypeOf(this, new.target.prototype);
790
+ }
791
+ };
792
+ /** A webhook payload failed signature verification (bad signature, stale timestamp, malformed headers). */
793
+ var BirdWebhookVerificationError = class extends BirdError {
794
+ constructor(message) {
795
+ super(message);
796
+ this.name = "BirdWebhookVerificationError";
797
+ Object.setPrototypeOf(this, new.target.prototype);
798
+ }
799
+ };
800
+ /** The server returned an error body. Base for every `type`-specific class. */
801
+ var BirdAPIError = class extends BirdError {
802
+ statusCode;
803
+ code;
804
+ type;
805
+ errorName;
806
+ docUrl;
807
+ requestId;
808
+ param;
809
+ vendorCode;
810
+ remediation;
811
+ next;
812
+ constructor(fields) {
813
+ super(fields.message);
814
+ this.name = "BirdAPIError";
815
+ this.statusCode = fields.statusCode;
816
+ this.code = fields.code;
817
+ this.type = fields.type;
818
+ this.errorName = fields.errorName;
819
+ this.docUrl = fields.docUrl;
820
+ this.requestId = fields.requestId;
821
+ this.param = fields.param;
822
+ this.vendorCode = fields.vendorCode;
823
+ this.remediation = fields.remediation;
824
+ this.next = fields.next;
825
+ Object.setPrototypeOf(this, new.target.prototype);
826
+ }
827
+ };
828
+ /** 401 — authentication failed or missing. */
829
+ var BirdAuthError = class extends BirdAPIError {
830
+ constructor(fields) {
831
+ super(fields);
832
+ this.name = "BirdAuthError";
833
+ Object.setPrototypeOf(this, new.target.prototype);
834
+ }
835
+ };
836
+ /** 403 — authenticated but not allowed. */
837
+ var BirdPermissionError = class extends BirdAPIError {
838
+ constructor(fields) {
839
+ super(fields);
840
+ this.name = "BirdPermissionError";
841
+ Object.setPrototypeOf(this, new.target.prototype);
842
+ }
843
+ };
844
+ /** 404 — resource does not exist. */
845
+ var BirdNotFoundError = class extends BirdAPIError {
846
+ constructor(fields) {
847
+ super(fields);
848
+ this.name = "BirdNotFoundError";
849
+ Object.setPrototypeOf(this, new.target.prototype);
850
+ }
851
+ };
852
+ /** 409 — semantic conflict (e.g. a unique value already taken). */
853
+ var BirdConflictError = class extends BirdAPIError {
854
+ constructor(fields) {
855
+ super(fields);
856
+ this.name = "BirdConflictError";
857
+ Object.setPrototypeOf(this, new.target.prototype);
858
+ }
859
+ };
860
+ /** 400 — malformed request. */
861
+ var BirdBadRequestError = class extends BirdAPIError {
862
+ constructor(fields) {
863
+ super(fields);
864
+ this.name = "BirdBadRequestError";
865
+ Object.setPrototypeOf(this, new.target.prototype);
866
+ }
867
+ };
868
+ /** 402 — billing/balance problem. */
869
+ var BirdBillingError = class extends BirdAPIError {
870
+ constructor(fields) {
871
+ super(fields);
872
+ this.name = "BirdBillingError";
873
+ Object.setPrototypeOf(this, new.target.prototype);
874
+ }
875
+ };
876
+ /** 412/428 — a precondition was not met. */
877
+ var BirdPreconditionError = class extends BirdAPIError {
878
+ constructor(fields) {
879
+ super(fields);
880
+ this.name = "BirdPreconditionError";
881
+ Object.setPrototypeOf(this, new.target.prototype);
882
+ }
883
+ };
884
+ /** 413 — request body too large. */
885
+ var BirdPayloadTooLargeError = class extends BirdAPIError {
886
+ constructor(fields) {
887
+ super(fields);
888
+ this.name = "BirdPayloadTooLargeError";
889
+ Object.setPrototypeOf(this, new.target.prototype);
890
+ }
891
+ };
892
+ /** 500 — unexpected server error. */
893
+ var BirdInternalError = class extends BirdAPIError {
894
+ constructor(fields) {
895
+ super(fields);
896
+ this.name = "BirdInternalError";
897
+ Object.setPrototypeOf(this, new.target.prototype);
898
+ }
899
+ };
900
+ /** 501 — endpoint not implemented. */
901
+ var BirdNotImplementedError = class extends BirdAPIError {
902
+ constructor(fields) {
903
+ super(fields);
904
+ this.name = "BirdNotImplementedError";
905
+ Object.setPrototypeOf(this, new.target.prototype);
906
+ }
907
+ };
908
+ /** 421 — request reached the wrong region (ADR-0036). */
909
+ var BirdMisdirectedError = class extends BirdAPIError {
910
+ constructor(fields) {
911
+ super(fields);
912
+ this.name = "BirdMisdirectedError";
913
+ Object.setPrototypeOf(this, new.target.prototype);
914
+ }
915
+ };
916
+ /** 503 — service temporarily unavailable. */
917
+ var BirdServiceUnavailableError = class extends BirdAPIError {
918
+ constructor(fields) {
919
+ super(fields);
920
+ this.name = "BirdServiceUnavailableError";
921
+ Object.setPrototypeOf(this, new.target.prototype);
922
+ }
923
+ };
924
+ /** 422 — field validation failed; `details` carries the per-field errors. */
925
+ var BirdValidationError = class extends BirdAPIError {
926
+ details;
927
+ constructor(fields) {
928
+ super(fields);
929
+ this.name = "BirdValidationError";
930
+ this.details = fields.details;
931
+ Object.setPrototypeOf(this, new.target.prototype);
932
+ }
933
+ };
934
+ /** 429 — rate limited; `retryAfter` is the server-advised wait in seconds. */
935
+ var BirdRateLimitError = class extends BirdAPIError {
936
+ retryAfter;
937
+ constructor(fields) {
938
+ super(fields);
939
+ this.name = "BirdRateLimitError";
940
+ this.retryAfter = fields.retryAfter;
941
+ Object.setPrototypeOf(this, new.target.prototype);
942
+ }
943
+ };
944
+ /**
945
+ * Parse `Retry-After` (delta-seconds or HTTP-date) into whole seconds. A
946
+ * negative or unparseable value yields `undefined` — a negative wait is
947
+ * meaningless, so both the user-facing `retryAfter` and the retry loop treat it
948
+ * as "no server advice". The single Retry-After parser; `retryDelay` builds on it.
949
+ */
950
+ function parseRetryAfter(headers) {
951
+ const header = headers?.get("Retry-After");
952
+ if (!header) return void 0;
953
+ const seconds = Number(header);
954
+ const value = Number.isFinite(seconds) ? seconds : (Date.parse(header) - Date.now()) / 1e3;
955
+ return Number.isFinite(value) && value >= 0 ? Math.round(value) : void 0;
956
+ }
957
+ function inferType(status) {
958
+ switch (status) {
959
+ case 400: return "bad_request_error";
960
+ case 401: return "auth_error";
961
+ case 402: return "billing_error";
962
+ case 403: return "permission_error";
963
+ case 404: return "not_found_error";
964
+ case 409: return "conflict_error";
965
+ case 412:
966
+ case 428: return "precondition_error";
967
+ case 413: return "payload_too_large_error";
968
+ case 421: return "misdirected_error";
969
+ case 422: return "validation_error";
970
+ case 429: return "rate_limit_error";
971
+ case 501: return "not_implemented_error";
972
+ case 503: return "service_unavailable_error";
973
+ default: return status >= 500 ? "internal_error" : "bad_request_error";
974
+ }
975
+ }
976
+ /**
977
+ * Map a non-2xx response to the right `BirdAPIError` subclass. The single place
978
+ * the SDK turns a wire error into a thrown error.
979
+ */
980
+ function mapResponseToError(status, body, headers) {
981
+ const raw = body ?? {};
982
+ const b = raw.error ?? raw ?? {};
983
+ const fields = {
984
+ statusCode: status,
985
+ code: b.code ?? "unknown",
986
+ type: b.type ?? inferType(status),
987
+ errorName: b.name ?? "",
988
+ message: b.message ?? `Request failed with status ${status}`,
989
+ docUrl: b.doc_url ?? "",
990
+ requestId: b.request_id ?? headers?.get("X-Request-Id") ?? "",
991
+ param: b.param,
992
+ vendorCode: b.vendor_code,
993
+ remediation: b.remediation,
994
+ next: b.next ?? []
995
+ };
996
+ switch (fields.type) {
997
+ case "auth_error": return new BirdAuthError(fields);
998
+ case "permission_error": return new BirdPermissionError(fields);
999
+ case "not_found_error": return new BirdNotFoundError(fields);
1000
+ case "conflict_error": return new BirdConflictError(fields);
1001
+ case "bad_request_error": return new BirdBadRequestError(fields);
1002
+ case "billing_error": return new BirdBillingError(fields);
1003
+ case "precondition_error": return new BirdPreconditionError(fields);
1004
+ case "payload_too_large_error": return new BirdPayloadTooLargeError(fields);
1005
+ case "internal_error": return new BirdInternalError(fields);
1006
+ case "not_implemented_error": return new BirdNotImplementedError(fields);
1007
+ case "misdirected_error": return new BirdMisdirectedError(fields);
1008
+ case "service_unavailable_error": return new BirdServiceUnavailableError(fields);
1009
+ case "rate_limit_error": return new BirdRateLimitError({
1010
+ ...fields,
1011
+ retryAfter: parseRetryAfter(headers)
1012
+ });
1013
+ case "validation_error": return new BirdValidationError({
1014
+ ...fields,
1015
+ details: b.details ?? []
1016
+ });
1017
+ default: return new BirdAPIError(fields);
1018
+ }
1019
+ }
1020
+ //#endregion
1021
+ //#region src/core/http.ts
1022
+ const BACKOFF_BASE_MS = 500;
1023
+ const BACKOFF_CAP_MS = 8e3;
1024
+ const RETRY_AFTER_CAP_MS = 6e4;
1025
+ var BirdHTTPClient = class {
1026
+ defaults;
1027
+ constructor(defaults) {
1028
+ this.defaults = defaults;
1029
+ }
1030
+ /**
1031
+ * Run a generated hey-api SDK call through the request lifecycle.
1032
+ *
1033
+ * @param call Invokes the SDK function; receives the per-attempt signal and
1034
+ * the idempotency key to set as a header.
1035
+ * @returns the parsed body plus transport metadata.
1036
+ * @throws a `BirdError` subclass on terminal failure; the native
1037
+ * `AbortError` if the caller's signal aborts.
1038
+ */
1039
+ async request(call, options) {
1040
+ const maxRetries = options.maxRetries ?? this.defaults.maxRetries;
1041
+ const timeout = options.timeout ?? this.defaults.timeout;
1042
+ const idempotencyKey = options.idempotencyKey ?? (isMutation(options.method) ? crypto.randomUUID() : void 0);
1043
+ for (let attempt = 0;; attempt++) {
1044
+ throwIfAborted(options.signal);
1045
+ const retryOrThrow = async (terminal) => {
1046
+ if (attempt >= maxRetries) throw terminal();
1047
+ await sleep(backoffDelay(attempt), options.signal);
1048
+ };
1049
+ const timeoutSignal = AbortSignal.timeout(timeout);
1050
+ const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
1051
+ let outcome;
1052
+ try {
1053
+ outcome = await call({
1054
+ signal,
1055
+ idempotencyKey
1056
+ });
1057
+ } catch (err) {
1058
+ throwIfAborted(options.signal);
1059
+ await retryOrThrow(() => timeoutSignal.aborted ? new BirdTimeoutError(`Request timed out after ${timeout}ms`, timeout) : new BirdConnectionError(errorMessage(err)));
1060
+ continue;
1061
+ }
1062
+ const res = outcome.response;
1063
+ if (!res) {
1064
+ await retryOrThrow(() => new BirdConnectionError("No response received from the server"));
1065
+ continue;
1066
+ }
1067
+ if (res.ok) return {
1068
+ data: outcome.data,
1069
+ response: toBirdResponse(res)
1070
+ };
1071
+ if (!isRetryableStatus(res.status) || attempt >= maxRetries) throw mapResponseToError(res.status, outcome.error, res.headers);
1072
+ await sleep(retryDelay(attempt, res.headers), options.signal);
1073
+ }
1074
+ }
1075
+ };
1076
+ function isMutation(method) {
1077
+ return [
1078
+ "POST",
1079
+ "PATCH",
1080
+ "DELETE"
1081
+ ].includes(method.toUpperCase());
1082
+ }
1083
+ function isRetryableStatus(status) {
1084
+ return [
1085
+ 408,
1086
+ 429,
1087
+ 500,
1088
+ 502,
1089
+ 503,
1090
+ 504
1091
+ ].includes(status);
1092
+ }
1093
+ /** Full-jitter exponential backoff: random in [0, min(cap, base·2^attempt)). */
1094
+ function backoffDelay(attempt) {
1095
+ const ceiling = Math.min(BACKOFF_CAP_MS, BACKOFF_BASE_MS * 2 ** attempt);
1096
+ return Math.random() * ceiling;
1097
+ }
1098
+ /** Honor Retry-After on a retryable response, else fall back to backoff. */
1099
+ function retryDelay(attempt, headers) {
1100
+ const seconds = parseRetryAfter(headers);
1101
+ return seconds === void 0 ? backoffDelay(attempt) : Math.min(seconds * 1e3, RETRY_AFTER_CAP_MS);
1102
+ }
1103
+ function toBirdResponse(res) {
1104
+ return {
1105
+ status: res.status,
1106
+ headers: res.headers,
1107
+ requestId: res.headers.get("X-Request-Id") ?? ""
1108
+ };
1109
+ }
1110
+ function abortReason(signal) {
1111
+ return signal?.reason ?? new DOMException("Aborted", "AbortError");
1112
+ }
1113
+ function throwIfAborted(signal) {
1114
+ if (signal?.aborted) throw abortReason(signal);
1115
+ }
1116
+ /** Sleep, rejecting immediately if the caller's signal aborts. */
1117
+ function sleep(ms, signal) {
1118
+ return new Promise((resolve, reject) => {
1119
+ if (signal?.aborted) {
1120
+ reject(abortReason(signal));
1121
+ return;
1122
+ }
1123
+ const timer = setTimeout(() => {
1124
+ signal?.removeEventListener("abort", onAbort);
1125
+ resolve();
1126
+ }, ms);
1127
+ const onAbort = () => {
1128
+ clearTimeout(timer);
1129
+ reject(abortReason(signal));
1130
+ };
1131
+ signal?.addEventListener("abort", onAbort, { once: true });
1132
+ });
1133
+ }
1134
+ function errorMessage(err) {
1135
+ if (err instanceof Error) return err.message;
1136
+ return String(err);
1137
+ }
1138
+ //#endregion
1139
+ //#region src/core/result.ts
1140
+ function basePromise(inner) {
1141
+ const promise = inner.then((r) => r.data);
1142
+ promise.catch(() => {});
1143
+ promise.withResponse = () => inner;
1144
+ promise.safe = () => toSafe(inner);
1145
+ return promise;
1146
+ }
1147
+ function apiPromise(inner) {
1148
+ return basePromise(inner);
1149
+ }
1150
+ function paginate(fetchPage) {
1151
+ const first = fetchPage();
1152
+ const promise = basePromise(first);
1153
+ promise[Symbol.asyncIterator] = async function* () {
1154
+ let result = await first;
1155
+ for (;;) {
1156
+ for (const item of result.data.data) yield item;
1157
+ if (result.data.next_cursor == null) return;
1158
+ result = await fetchPage(result.data.next_cursor);
1159
+ }
1160
+ };
1161
+ return promise;
1162
+ }
1163
+ function toSafe(inner) {
1164
+ return inner.then(({ data, response }) => ({
1165
+ data,
1166
+ error: null,
1167
+ response
1168
+ }), (error) => {
1169
+ if (error instanceof BirdError) return {
1170
+ data: null,
1171
+ error,
1172
+ response: null
1173
+ };
1174
+ throw error;
1175
+ });
1176
+ }
1177
+ //#endregion
1178
+ //#region src/generated/client.gen.ts
1179
+ const client = createClient(createConfig());
1180
+ //#endregion
1181
+ //#region src/generated/sdk.gen.ts
1182
+ /**
1183
+ * List messages
1184
+ *
1185
+ * Returns a paginated list of email messages in the workspace, newest first.
1186
+ */
1187
+ const listEmailMessages = (options) => (options?.client ?? client).get({
1188
+ security: [{
1189
+ scheme: "bearer",
1190
+ type: "http"
1191
+ }, {
1192
+ in: "cookie",
1193
+ name: "bird_session",
1194
+ type: "apiKey"
1195
+ }],
1196
+ url: "/v1/email/messages",
1197
+ ...options
1198
+ });
1199
+ /**
1200
+ * Send a message
1201
+ *
1202
+ * Sends an email to the recipients you list explicitly in `to`/`cc`/`bcc`. Use this for transactional sends (receipts, password resets, alerts) and for marketing sends where you have the recipient addresses on hand. For sends targeting a stored audience by reference, use POST /v1/email/broadcasts. The `category` field controls suppression policy independently — set it to `marketing` when sending marketing content from this endpoint. The 202 response is returned only after the message is safely accepted for delivery. If the sender domain is not verified, or all recipients are suppressed, the request fails immediately with a 422 — it is never accepted and then silently dropped. Other field-level validation failures also return 422.
1203
+ * Recipient addresses on reserved testing domains are rejected with a 422 RecipientDomainNotAllowed error. This covers @example.com, @example.net, @example.org, @example.edu, @test.com, and any address under the reserved .test, .example, .invalid, or .localhost top-level domains. These placeholder domains cannot receive mail, and the resulting bounces would hurt your sender reputation — use a real recipient address instead.
1204
+ * During onboarding, you can send without verifying a domain: use any sender address on the shared onboarding domain (for example onboarding@messagebird.dev). Such sends skip the sender-domain verification check, can only go to verified members of your workspace (other recipients are rejected with a 422 OnboardingRecipientNotAllowed error), and are subject to a daily recipient limit per organization (429 OnboardingSendLimitExceeded once exhausted).
1205
+ *
1206
+ */
1207
+ const createEmailMessage = (options) => (options.client ?? client).post({
1208
+ security: [{
1209
+ scheme: "bearer",
1210
+ type: "http"
1211
+ }, {
1212
+ in: "cookie",
1213
+ name: "bird_session",
1214
+ type: "apiKey"
1215
+ }],
1216
+ url: "/v1/email/messages",
1217
+ ...options,
1218
+ headers: {
1219
+ "Content-Type": "application/json",
1220
+ ...options.headers
1221
+ }
1222
+ });
1223
+ /**
1224
+ * Send a batch of messages
1225
+ *
1226
+ * Accepts up to 100 independent email messages and queues them for delivery. All items are validated before any are queued — if one fails validation, the entire batch is rejected. Field-level validation failures and business-rule failures (such as domain_not_verified or all_recipients_suppressed) both return 422. Attachments are allowed per message. Each message must stay within the 20 MB estimated generated message-size cap. The serialized JSON request body for the batch has a hard 20 MB cap.
1227
+ *
1228
+ */
1229
+ const createEmailMessageBatch = (options) => (options.client ?? client).post({
1230
+ security: [{
1231
+ scheme: "bearer",
1232
+ type: "http"
1233
+ }, {
1234
+ in: "cookie",
1235
+ name: "bird_session",
1236
+ type: "apiKey"
1237
+ }],
1238
+ url: "/v1/email/batches",
1239
+ ...options,
1240
+ headers: {
1241
+ "Content-Type": "application/json",
1242
+ ...options.headers
1243
+ }
1244
+ });
1245
+ /**
1246
+ * Get a message
1247
+ *
1248
+ * Returns a single email message object with aggregate delivery status and counts. Message body (html, text) is not returned — it is not stored after delivery.
1249
+ *
1250
+ */
1251
+ const getEmailMessage = (options) => (options.client ?? client).get({
1252
+ security: [{
1253
+ scheme: "bearer",
1254
+ type: "http"
1255
+ }, {
1256
+ in: "cookie",
1257
+ name: "bird_session",
1258
+ type: "apiKey"
1259
+ }],
1260
+ url: "/v1/email/messages/{message_id}",
1261
+ ...options
1262
+ });
1263
+ /**
1264
+ * List contacts
1265
+ *
1266
+ * Returns a paginated list of contacts in the workspace, newest first. Look up a single contact by its exact `email` or `external_id`, or search by email substring with `search`.
1267
+ *
1268
+ */
1269
+ const listContacts = (options) => (options?.client ?? client).get({
1270
+ security: [{
1271
+ scheme: "bearer",
1272
+ type: "http"
1273
+ }, {
1274
+ in: "cookie",
1275
+ name: "bird_session",
1276
+ type: "apiKey"
1277
+ }],
1278
+ url: "/v1/contacts",
1279
+ ...options
1280
+ });
1281
+ /**
1282
+ * Create a contact
1283
+ *
1284
+ * Creates a contact in the workspace. Contacts are unique by email address; creating a second contact with the same email returns a conflict error. The same applies to `external_id` — a value already used by another contact returns a conflict error. Custom values in `data` must use property keys you created via the contact properties API, with values matching each property's declared type.
1285
+ *
1286
+ */
1287
+ const createContact = (options) => (options.client ?? client).post({
1288
+ security: [{
1289
+ scheme: "bearer",
1290
+ type: "http"
1291
+ }, {
1292
+ in: "cookie",
1293
+ name: "bird_session",
1294
+ type: "apiKey"
1295
+ }],
1296
+ url: "/v1/contacts",
1297
+ ...options,
1298
+ headers: {
1299
+ "Content-Type": "application/json",
1300
+ ...options.headers
1301
+ }
1302
+ });
1303
+ /**
1304
+ * Create or update contacts in bulk
1305
+ *
1306
+ * Creates or updates up to 1,000 contacts in one request, matched by email address (trimmed and lowercased before matching). Existing contacts are updated with the supplied fields; new ones are created. Optionally adds every contact in the request to one or more audiences. Results are returned per contact, in submission order — a failed entry does not abort the rest of the request.
1307
+ *
1308
+ */
1309
+ const createContactBatch = (options) => (options.client ?? client).post({
1310
+ security: [{
1311
+ scheme: "bearer",
1312
+ type: "http"
1313
+ }, {
1314
+ in: "cookie",
1315
+ name: "bird_session",
1316
+ type: "apiKey"
1317
+ }],
1318
+ url: "/v1/contacts/batch",
1319
+ ...options,
1320
+ headers: {
1321
+ "Content-Type": "application/json",
1322
+ ...options.headers
1323
+ }
1324
+ });
1325
+ /**
1326
+ * Delete a contact
1327
+ *
1328
+ * Deletes a contact and removes it from every audience it belongs to. Suppression records for the address are not affected — an unsubscribed or bounced address stays suppressed even after the contact is deleted.
1329
+ *
1330
+ */
1331
+ const deleteContact = (options) => (options.client ?? client).delete({
1332
+ security: [{
1333
+ scheme: "bearer",
1334
+ type: "http"
1335
+ }, {
1336
+ in: "cookie",
1337
+ name: "bird_session",
1338
+ type: "apiKey"
1339
+ }],
1340
+ url: "/v1/contacts/{contact_id}",
1341
+ ...options
1342
+ });
1343
+ /**
1344
+ * Get a contact
1345
+ *
1346
+ * Returns a single contact by ID.
1347
+ */
1348
+ const getContact = (options) => (options.client ?? client).get({
1349
+ security: [{
1350
+ scheme: "bearer",
1351
+ type: "http"
1352
+ }, {
1353
+ in: "cookie",
1354
+ name: "bird_session",
1355
+ type: "apiKey"
1356
+ }],
1357
+ url: "/v1/contacts/{contact_id}",
1358
+ ...options
1359
+ });
1360
+ /**
1361
+ * Update a contact
1362
+ *
1363
+ * Updates a contact. Supplied fields are changed; omitted fields are left unchanged. Custom values in `data` are merged — keys you supply are set, keys set to null are removed, and keys you omit are unchanged. Changing the email address or `external_id` to a value already used by another contact returns a conflict error.
1364
+ *
1365
+ */
1366
+ const updateContact = (options) => (options.client ?? client).patch({
1367
+ security: [{
1368
+ scheme: "bearer",
1369
+ type: "http"
1370
+ }, {
1371
+ in: "cookie",
1372
+ name: "bird_session",
1373
+ type: "apiKey"
1374
+ }],
1375
+ url: "/v1/contacts/{contact_id}",
1376
+ ...options,
1377
+ headers: {
1378
+ "Content-Type": "application/json",
1379
+ ...options.headers
1380
+ }
1381
+ });
1382
+ /**
1383
+ * List contact properties
1384
+ *
1385
+ * Returns a paginated list of the workspace's contact properties.
1386
+ */
1387
+ const listContactProperties = (options) => (options?.client ?? client).get({
1388
+ security: [{
1389
+ scheme: "bearer",
1390
+ type: "http"
1391
+ }, {
1392
+ in: "cookie",
1393
+ name: "bird_session",
1394
+ type: "apiKey"
1395
+ }],
1396
+ url: "/v1/contact-properties",
1397
+ ...options
1398
+ });
1399
+ /**
1400
+ * Create a contact property
1401
+ *
1402
+ * Defines a custom property that contacts in the workspace can carry. The key becomes available in contact `data` and as a template variable in broadcasts. Keys are unique within the workspace; the key and type cannot be changed after creation.
1403
+ *
1404
+ */
1405
+ const createContactProperty = (options) => (options.client ?? client).post({
1406
+ security: [{
1407
+ scheme: "bearer",
1408
+ type: "http"
1409
+ }, {
1410
+ in: "cookie",
1411
+ name: "bird_session",
1412
+ type: "apiKey"
1413
+ }],
1414
+ url: "/v1/contact-properties",
1415
+ ...options,
1416
+ headers: {
1417
+ "Content-Type": "application/json",
1418
+ ...options.headers
1419
+ }
1420
+ });
1421
+ /**
1422
+ * Get a contact property
1423
+ *
1424
+ * Returns a single contact property by ID.
1425
+ */
1426
+ const getContactProperty = (options) => (options.client ?? client).get({
1427
+ security: [{
1428
+ scheme: "bearer",
1429
+ type: "http"
1430
+ }, {
1431
+ in: "cookie",
1432
+ name: "bird_session",
1433
+ type: "apiKey"
1434
+ }],
1435
+ url: "/v1/contact-properties/{property_id}",
1436
+ ...options
1437
+ });
1438
+ /**
1439
+ * Update a contact property
1440
+ *
1441
+ * Updates a contact property's fallback value. The key and type cannot be changed after creation — create a new property instead.
1442
+ *
1443
+ */
1444
+ const updateContactProperty = (options) => (options.client ?? client).patch({
1445
+ security: [{
1446
+ scheme: "bearer",
1447
+ type: "http"
1448
+ }, {
1449
+ in: "cookie",
1450
+ name: "bird_session",
1451
+ type: "apiKey"
1452
+ }],
1453
+ url: "/v1/contact-properties/{property_id}",
1454
+ ...options,
1455
+ headers: {
1456
+ "Content-Type": "application/json",
1457
+ ...options.headers
1458
+ }
1459
+ });
1460
+ /**
1461
+ * Archive a contact property
1462
+ *
1463
+ * Archives a contact property. The key stops being accepted in new contact writes and stops rendering in templates, but every value already stored on your contacts is preserved and still returned when you read a contact. The key stays reserved, so it cannot be re-created with a different type. Returns 409 if the property is already archived. Reverse it with unarchive.
1464
+ *
1465
+ */
1466
+ const archiveContactProperty = (options) => (options.client ?? client).post({
1467
+ security: [{
1468
+ scheme: "bearer",
1469
+ type: "http"
1470
+ }, {
1471
+ in: "cookie",
1472
+ name: "bird_session",
1473
+ type: "apiKey"
1474
+ }],
1475
+ url: "/v1/contact-properties/{property_id}/archive",
1476
+ ...options
1477
+ });
1478
+ /**
1479
+ * Unarchive a contact property
1480
+ *
1481
+ * Reactivates an archived contact property. The key is accepted in contact writes and renders in templates again; stored values were never removed, so they are unchanged. Returns 409 if the property is not archived.
1482
+ *
1483
+ */
1484
+ const unarchiveContactProperty = (options) => (options.client ?? client).post({
1485
+ security: [{
1486
+ scheme: "bearer",
1487
+ type: "http"
1488
+ }, {
1489
+ in: "cookie",
1490
+ name: "bird_session",
1491
+ type: "apiKey"
1492
+ }],
1493
+ url: "/v1/contact-properties/{property_id}/unarchive",
1494
+ ...options
1495
+ });
1496
+ /**
1497
+ * List audiences
1498
+ *
1499
+ * Returns a paginated list of audiences in the workspace, newest first.
1500
+ */
1501
+ const listAudiences = (options) => (options?.client ?? client).get({
1502
+ security: [{
1503
+ scheme: "bearer",
1504
+ type: "http"
1505
+ }, {
1506
+ in: "cookie",
1507
+ name: "bird_session",
1508
+ type: "apiKey"
1509
+ }],
1510
+ url: "/v1/audiences",
1511
+ ...options
1512
+ });
1513
+ /**
1514
+ * Create an audience
1515
+ *
1516
+ * Creates an audience in the workspace. Static audiences start empty — add contacts via the audience contacts endpoint or the bulk contact upsert.
1517
+ *
1518
+ */
1519
+ const createAudience = (options) => (options.client ?? client).post({
1520
+ security: [{
1521
+ scheme: "bearer",
1522
+ type: "http"
1523
+ }, {
1524
+ in: "cookie",
1525
+ name: "bird_session",
1526
+ type: "apiKey"
1527
+ }],
1528
+ url: "/v1/audiences",
1529
+ ...options,
1530
+ headers: {
1531
+ "Content-Type": "application/json",
1532
+ ...options.headers
1533
+ }
1534
+ });
1535
+ /**
1536
+ * Delete an audience
1537
+ *
1538
+ * Deletes an audience and its memberships. Contacts themselves are not deleted. An audience cannot be deleted while a broadcast targeting it is scheduled, accepted, sending, or canceling — cancel that broadcast first.
1539
+ *
1540
+ */
1541
+ const deleteAudience = (options) => (options.client ?? client).delete({
1542
+ security: [{
1543
+ scheme: "bearer",
1544
+ type: "http"
1545
+ }, {
1546
+ in: "cookie",
1547
+ name: "bird_session",
1548
+ type: "apiKey"
1549
+ }],
1550
+ url: "/v1/audiences/{audience_id}",
1551
+ ...options
1552
+ });
1553
+ /**
1554
+ * Get an audience
1555
+ *
1556
+ * Returns a single audience by ID.
1557
+ */
1558
+ const getAudience = (options) => (options.client ?? client).get({
1559
+ security: [{
1560
+ scheme: "bearer",
1561
+ type: "http"
1562
+ }, {
1563
+ in: "cookie",
1564
+ name: "bird_session",
1565
+ type: "apiKey"
1566
+ }],
1567
+ url: "/v1/audiences/{audience_id}",
1568
+ ...options
1569
+ });
1570
+ /**
1571
+ * Update an audience
1572
+ *
1573
+ * Updates an audience's name or description.
1574
+ */
1575
+ const updateAudience = (options) => (options.client ?? client).patch({
1576
+ security: [{
1577
+ scheme: "bearer",
1578
+ type: "http"
1579
+ }, {
1580
+ in: "cookie",
1581
+ name: "bird_session",
1582
+ type: "apiKey"
1583
+ }],
1584
+ url: "/v1/audiences/{audience_id}",
1585
+ ...options,
1586
+ headers: {
1587
+ "Content-Type": "application/json",
1588
+ ...options.headers
1589
+ }
1590
+ });
1591
+ /**
1592
+ * List an audience's contacts
1593
+ *
1594
+ * Lists the contacts in a static audience as a cursor page, ordered by the time each contact joined the audience, most recent first. Each entry is the contact together with the time it joined.
1595
+ *
1596
+ */
1597
+ const listAudienceContacts = (options) => (options.client ?? client).get({
1598
+ security: [{
1599
+ scheme: "bearer",
1600
+ type: "http"
1601
+ }, {
1602
+ in: "cookie",
1603
+ name: "bird_session",
1604
+ type: "apiKey"
1605
+ }],
1606
+ url: "/v1/audiences/{audience_id}/contacts",
1607
+ ...options
1608
+ });
1609
+ /**
1610
+ * Add contacts to an audience
1611
+ *
1612
+ * Adds up to 1,000 contacts to a static audience. Contacts that are already members are left in place. If any contact ID does not exist, the whole request fails and no contacts are added.
1613
+ *
1614
+ */
1615
+ const assignAudienceContacts = (options) => (options.client ?? client).post({
1616
+ security: [{
1617
+ scheme: "bearer",
1618
+ type: "http"
1619
+ }, {
1620
+ in: "cookie",
1621
+ name: "bird_session",
1622
+ type: "apiKey"
1623
+ }],
1624
+ url: "/v1/audiences/{audience_id}/contacts",
1625
+ ...options,
1626
+ headers: {
1627
+ "Content-Type": "application/json",
1628
+ ...options.headers
1629
+ }
1630
+ });
1631
+ /**
1632
+ * Remove contacts from an audience
1633
+ *
1634
+ * Removes up to 1,000 contacts from a static audience. Contacts that are not members are skipped. If any contact ID does not exist, the whole request fails and no contacts are removed. The contacts themselves are not deleted and remain members of any other audiences.
1635
+ *
1636
+ */
1637
+ const unassignAudienceContacts = (options) => (options.client ?? client).post({
1638
+ security: [{
1639
+ scheme: "bearer",
1640
+ type: "http"
1641
+ }, {
1642
+ in: "cookie",
1643
+ name: "bird_session",
1644
+ type: "apiKey"
1645
+ }],
1646
+ url: "/v1/audiences/{audience_id}/contacts/remove",
1647
+ ...options,
1648
+ headers: {
1649
+ "Content-Type": "application/json",
1650
+ ...options.headers
1651
+ }
1652
+ });
1653
+ /**
1654
+ * Remove a contact from an audience
1655
+ *
1656
+ * Removes a contact's membership in an audience. The contact itself is not deleted and remains a member of any other audiences. Removing a contact that is not a member of the audience succeeds with no effect (204); an unknown audience or contact returns a not-found error.
1657
+ *
1658
+ */
1659
+ const unassignAudienceContact = (options) => (options.client ?? client).delete({
1660
+ security: [{
1661
+ scheme: "bearer",
1662
+ type: "http"
1663
+ }, {
1664
+ in: "cookie",
1665
+ name: "bird_session",
1666
+ type: "apiKey"
1667
+ }],
1668
+ url: "/v1/audiences/{audience_id}/contacts/{contact_id}",
1669
+ ...options
1670
+ });
1671
+ /**
1672
+ * List SMS messages
1673
+ *
1674
+ * Returns a paginated list of SMS messages in the workspace, newest first.
1675
+ */
1676
+ const listSmsMessages = (options) => (options?.client ?? client).get({
1677
+ security: [{
1678
+ scheme: "bearer",
1679
+ type: "http"
1680
+ }, {
1681
+ in: "cookie",
1682
+ name: "bird_session",
1683
+ type: "apiKey"
1684
+ }],
1685
+ url: "/v1/sms/messages",
1686
+ ...options
1687
+ });
1688
+ /**
1689
+ * Send an SMS message
1690
+ *
1691
+ * Sends a single SMS message to one recipient. The 202 response is returned only after the message is durably accepted for delivery; actual delivery happens asynchronously, and you track it with the get-message and list-events endpoints or with webhooks. `category` is required and controls opt-out (STOP) policy, quiet hours, and per-country compliance. A body exceeding the 12-segment cap is rejected with a 422, as are field-level validation failures and sends that cannot be afforded by the workspace balance.
1692
+ *
1693
+ */
1694
+ const createSmsMessage = (options) => (options.client ?? client).post({
1695
+ security: [{
1696
+ scheme: "bearer",
1697
+ type: "http"
1698
+ }, {
1699
+ in: "cookie",
1700
+ name: "bird_session",
1701
+ type: "apiKey"
1702
+ }],
1703
+ url: "/v1/sms/messages",
1704
+ ...options,
1705
+ headers: {
1706
+ "Content-Type": "application/json",
1707
+ ...options.headers
1708
+ }
1709
+ });
1710
+ /**
1711
+ * Send a batch of SMS messages
1712
+ *
1713
+ * Accepts up to 100 independent SMS messages and queues them for delivery. Each message is an independent send with its own ID, status, and cost. All items are validated before any are queued — if one fails validation, the entire batch is rejected. Field-level validation failures, the 12-segment body cap, and insufficient workspace balance all return 422 (or 402 for balance).
1714
+ *
1715
+ */
1716
+ const createSmsMessageBatch = (options) => (options.client ?? client).post({
1717
+ security: [{
1718
+ scheme: "bearer",
1719
+ type: "http"
1720
+ }, {
1721
+ in: "cookie",
1722
+ name: "bird_session",
1723
+ type: "apiKey"
1724
+ }],
1725
+ url: "/v1/sms/batches",
1726
+ ...options,
1727
+ headers: {
1728
+ "Content-Type": "application/json",
1729
+ ...options.headers
1730
+ }
1731
+ });
1732
+ /**
1733
+ * Get an SMS message
1734
+ *
1735
+ * Returns a single SMS message with its current status, segment breakdown, cost, and failure detail if it failed.
1736
+ */
1737
+ const getSmsMessage = (options) => (options.client ?? client).get({
1738
+ security: [{
1739
+ scheme: "bearer",
1740
+ type: "http"
1741
+ }, {
1742
+ in: "cookie",
1743
+ name: "bird_session",
1744
+ type: "apiKey"
1745
+ }],
1746
+ url: "/v1/sms/messages/{message_id}",
1747
+ ...options
1748
+ });
1749
+ /**
1750
+ * List SMS templates
1751
+ *
1752
+ * Returns the SMS templates available to your workspace, including Bird's built-in templates. Filter by scope, category, or language.
1753
+ *
1754
+ */
1755
+ const listSmsTemplates = (options) => (options?.client ?? client).get({
1756
+ security: [{
1757
+ scheme: "bearer",
1758
+ type: "http"
1759
+ }, {
1760
+ in: "cookie",
1761
+ name: "bird_session",
1762
+ type: "apiKey"
1763
+ }],
1764
+ url: "/v1/sms/templates",
1765
+ ...options
1766
+ });
1767
+ /**
1768
+ * Get an SMS template
1769
+ *
1770
+ * Returns a single SMS template by its name or id.
1771
+ */
1772
+ const getSmsTemplate = (options) => (options.client ?? client).get({
1773
+ security: [{
1774
+ scheme: "bearer",
1775
+ type: "http"
1776
+ }, {
1777
+ in: "cookie",
1778
+ name: "bird_session",
1779
+ type: "apiKey"
1780
+ }],
1781
+ url: "/v1/sms/templates/{template_ref}",
1782
+ ...options
1783
+ });
1784
+ /**
1785
+ * List email templates
1786
+ *
1787
+ * Returns a paginated list of the workspace's email templates, newest first. Filter by category, source, or a case-insensitive search that matches the template's name or description.
1788
+ *
1789
+ */
1790
+ const listEmailTemplates = (options) => (options?.client ?? client).get({
1791
+ security: [{
1792
+ scheme: "bearer",
1793
+ type: "http"
1794
+ }, {
1795
+ in: "cookie",
1796
+ name: "bird_session",
1797
+ type: "apiKey"
1798
+ }],
1799
+ url: "/v1/email/templates",
1800
+ ...options
1801
+ });
1802
+ /**
1803
+ * Create an email template
1804
+ *
1805
+ * Creates a template and its initial editable draft. The body carries the template's name, category, authoring format (`source`), and the draft's content (`subject`, `html`, `text`). A name already used in the workspace returns a conflict.
1806
+ *
1807
+ */
1808
+ const createEmailTemplate = (options) => (options.client ?? client).post({
1809
+ security: [{
1810
+ scheme: "bearer",
1811
+ type: "http"
1812
+ }, {
1813
+ in: "cookie",
1814
+ name: "bird_session",
1815
+ type: "apiKey"
1816
+ }],
1817
+ url: "/v1/email/templates",
1818
+ ...options,
1819
+ headers: {
1820
+ "Content-Type": "application/json",
1821
+ ...options.headers
1822
+ }
1823
+ });
1824
+ /**
1825
+ * Delete an email template
1826
+ *
1827
+ * Deletes the template and all its versions. The name becomes available for reuse within the workspace.
1828
+ *
1829
+ */
1830
+ const deleteEmailTemplate = (options) => (options.client ?? client).delete({
1831
+ security: [{
1832
+ scheme: "bearer",
1833
+ type: "http"
1834
+ }, {
1835
+ in: "cookie",
1836
+ name: "bird_session",
1837
+ type: "apiKey"
1838
+ }],
1839
+ url: "/v1/email/templates/{template_id}",
1840
+ ...options
1841
+ });
1842
+ /**
1843
+ * Get an email template
1844
+ *
1845
+ * Returns a single email template with its current draft content (subject, HTML, and plain text), the draft revision, and its draft and published version ids.
1846
+ *
1847
+ */
1848
+ const getEmailTemplate = (options) => (options.client ?? client).get({
1849
+ security: [{
1850
+ scheme: "bearer",
1851
+ type: "http"
1852
+ }, {
1853
+ in: "cookie",
1854
+ name: "bird_session",
1855
+ type: "apiKey"
1856
+ }],
1857
+ url: "/v1/email/templates/{template_id}",
1858
+ ...options
1859
+ });
1860
+ /**
1861
+ * Update an email template
1862
+ *
1863
+ * Updates a template's metadata and its draft content. Only the fields you send are changed. Send the draft `revision` you last read; if it is stale (someone else edited the draft first) the request returns a conflict so you can reload and retry.
1864
+ *
1865
+ */
1866
+ const updateEmailTemplate = (options) => (options.client ?? client).patch({
1867
+ security: [{
1868
+ scheme: "bearer",
1869
+ type: "http"
1870
+ }, {
1871
+ in: "cookie",
1872
+ name: "bird_session",
1873
+ type: "apiKey"
1874
+ }],
1875
+ url: "/v1/email/templates/{template_id}",
1876
+ ...options,
1877
+ headers: {
1878
+ "Content-Type": "application/json",
1879
+ ...options.headers
1880
+ }
1881
+ });
1882
+ /**
1883
+ * List email template versions
1884
+ *
1885
+ * Returns every version of the template — the current draft plus all published versions — newest first.
1886
+ *
1887
+ */
1888
+ const listEmailTemplateVersions = (options) => (options.client ?? client).get({
1889
+ security: [{
1890
+ scheme: "bearer",
1891
+ type: "http"
1892
+ }, {
1893
+ in: "cookie",
1894
+ name: "bird_session",
1895
+ type: "apiKey"
1896
+ }],
1897
+ url: "/v1/email/templates/{template_id}/versions",
1898
+ ...options
1899
+ });
1900
+ /**
1901
+ * Get an email template version
1902
+ *
1903
+ * Returns a single version of an email template.
1904
+ */
1905
+ const getEmailTemplateVersion = (options) => (options.client ?? client).get({
1906
+ security: [{
1907
+ scheme: "bearer",
1908
+ type: "http"
1909
+ }, {
1910
+ in: "cookie",
1911
+ name: "bird_session",
1912
+ type: "apiKey"
1913
+ }],
1914
+ url: "/v1/email/templates/{template_id}/versions/{version_id}",
1915
+ ...options
1916
+ });
1917
+ /**
1918
+ * Publish an email template
1919
+ *
1920
+ * Publishes the template's current draft as a new immutable, numbered version and makes it the live version used by sends. The draft remains editable for future changes. The draft must have a subject and a body; an empty draft is rejected.
1921
+ *
1922
+ */
1923
+ const publishEmailTemplate = (options) => (options.client ?? client).post({
1924
+ security: [{
1925
+ scheme: "bearer",
1926
+ type: "http"
1927
+ }, {
1928
+ in: "cookie",
1929
+ name: "bird_session",
1930
+ type: "apiKey"
1931
+ }],
1932
+ url: "/v1/email/templates/{template_id}/publish",
1933
+ ...options
1934
+ });
1935
+ //#endregion
1936
+ //#region src/resources/base.ts
1937
+ var Resource = class {
1938
+ core;
1939
+ client;
1940
+ constructor(core, client) {
1941
+ this.core = core;
1942
+ this.client = client;
1943
+ }
1944
+ /** Run a single typed call through the lifecycle. */
1945
+ call(method, options, invoke) {
1946
+ return apiPromise(this.core.request((ctx) => invoke(callContext(ctx, options)), lifecycle(method, options)));
1947
+ }
1948
+ /** Run a cursor-paginated list through the lifecycle (each page retried independently). */
1949
+ paginated(method, options, invoke) {
1950
+ return paginate((cursor) => this.core.request((ctx) => invoke(callContext(ctx, options), cursor), lifecycle(method, options)));
1951
+ }
1952
+ };
1953
+ function callContext(ctx, options) {
1954
+ return {
1955
+ signal: ctx.signal,
1956
+ headers: mergeHeaders(ctx.idempotencyKey, options?.headers)
1957
+ };
1958
+ }
1959
+ function lifecycle(method, options) {
1960
+ return {
1961
+ method,
1962
+ idempotencyKey: options?.idempotencyKey,
1963
+ signal: options?.signal,
1964
+ timeout: options?.timeout,
1965
+ maxRetries: options?.maxRetries
1966
+ };
1967
+ }
1968
+ function mergeHeaders(idempotencyKey, extra) {
1969
+ return {
1970
+ ...extra,
1971
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
1972
+ };
1973
+ }
1974
+ //#endregion
1975
+ //#region src/resources/email.ts
1976
+ var EmailResource = class extends Resource {
1977
+ #defaults;
1978
+ constructor(core, client, defaults) {
1979
+ super(core, client);
1980
+ this.#defaults = defaults;
1981
+ }
1982
+ /**
1983
+ * Send an email message. Resolves once the message is accepted for delivery
1984
+ * (the API's 202). Throws on failure — a 422 (unverified sender, all
1985
+ * recipients suppressed, validation) is a `BirdValidationError`. Fields set as
1986
+ * channel defaults may be omitted (per-send value wins).
1987
+ *
1988
+ * @example Send a message
1989
+ * const msg = await bird.email.send({
1990
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
1991
+ * to: ["delivered@messagebird.dev"],
1992
+ * subject: "Hello from Bird",
1993
+ * html: "<p>My first Bird email.</p>",
1994
+ * });
1995
+ * console.log(msg.id, msg.status); // "em_…", "accepted"
1996
+ *
1997
+ * @example A richer send — cc/bcc, reply-to, tags, metadata, click-tracking off, and an idempotency key (safe to retry; the server dedupes)
1998
+ * await bird.email.send(
1999
+ * {
2000
+ * from: "hello@acme.com",
2001
+ * to: ["a@example.com", "b@example.com"],
2002
+ * cc: ["manager@example.com"],
2003
+ * reply_to: ["support@acme.com"],
2004
+ * subject: "Your March invoice",
2005
+ * html: "<p>Attached.</p>",
2006
+ * tags: [{ name: "category", value: "billing" }],
2007
+ * metadata: { invoice_id: "inv_123" },
2008
+ * track_clicks: false,
2009
+ * },
2010
+ * { idempotencyKey: "invoice-march/cust_1" },
2011
+ * );
2012
+ *
2013
+ * @example Branch on the typed error hierarchy
2014
+ * import { BirdRateLimitError, BirdValidationError, BirdAPIError } from "@messagebird/sdk";
2015
+ *
2016
+ * try {
2017
+ * await bird.email.send({
2018
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
2019
+ * to: ["delivered@messagebird.dev"],
2020
+ * subject: "Hello from Bird",
2021
+ * html: "<p>My first Bird email.</p>",
2022
+ * });
2023
+ * } catch (err) {
2024
+ * if (err instanceof BirdRateLimitError) console.log(`rate limited — retry in ${err.retryAfter}s`);
2025
+ * else if (err instanceof BirdValidationError) console.error(err.details);
2026
+ * else if (err instanceof BirdAPIError) console.error(err.code, err.requestId);
2027
+ * else throw err;
2028
+ * }
2029
+ *
2030
+ * @example Errors as values with `.safe()`
2031
+ * const { data, error } = await bird.email
2032
+ * .send({
2033
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
2034
+ * to: ["delivered@messagebird.dev"],
2035
+ * subject: "Hello from Bird",
2036
+ * html: "<p>My first Bird email.</p>",
2037
+ * })
2038
+ * .safe();
2039
+ * if (error) console.error(error.message);
2040
+ * else console.log(data.id);
2041
+ */
2042
+ send(params, options) {
2043
+ const body = {
2044
+ ...this.#defaults,
2045
+ ...params
2046
+ };
2047
+ return this.call("POST", options, ({ signal, headers }) => createEmailMessage({
2048
+ client: this.client,
2049
+ body,
2050
+ headers,
2051
+ signal
2052
+ }));
2053
+ }
2054
+ /**
2055
+ * Send a batch of up to 100 independent email messages in one request. The
2056
+ * batch is validated as a unit — if any item fails validation (unverified
2057
+ * sender, all recipients suppressed, field-level errors) the whole batch is
2058
+ * rejected with a `BirdValidationError` and nothing is queued. Resolves with
2059
+ * one accepted item per submitted message, in submission order, once the batch
2060
+ * is accepted (the API's 202). Channel defaults are applied per item.
2061
+ *
2062
+ * @example Send a batch of messages
2063
+ * const batch = await bird.email.sendBatch([
2064
+ * {
2065
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
2066
+ * to: ["alice@example.com"],
2067
+ * subject: "Your receipt",
2068
+ * html: "<p>Thanks, Alice.</p>",
2069
+ * },
2070
+ * {
2071
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
2072
+ * to: ["bob@example.com"],
2073
+ * subject: "Your receipt",
2074
+ * html: "<p>Thanks, Bob.</p>",
2075
+ * },
2076
+ * ]);
2077
+ * for (const item of batch.data) console.log(item.id, item.status);
2078
+ */
2079
+ sendBatch(params, options) {
2080
+ const body = params.map((item) => ({
2081
+ ...this.#defaults,
2082
+ ...item
2083
+ }));
2084
+ return this.call("POST", options, ({ signal, headers }) => createEmailMessageBatch({
2085
+ client: this.client,
2086
+ body,
2087
+ headers,
2088
+ signal
2089
+ }));
2090
+ }
2091
+ /**
2092
+ * Fetch a message with aggregate delivery status.
2093
+ *
2094
+ * @example
2095
+ * const msg = await bird.email.get("em_abc123");
2096
+ * msg.status; // "accepted" | "processed" | "delivered" | "bounced" | …
2097
+ * msg.delivered_count;
2098
+ * msg.bounced_count;
2099
+ */
2100
+ get(messageId, options) {
2101
+ return this.call("GET", options, ({ signal, headers }) => getEmailMessage({
2102
+ client: this.client,
2103
+ path: { message_id: messageId },
2104
+ headers,
2105
+ signal
2106
+ }));
2107
+ }
2108
+ /**
2109
+ * List messages, newest first. `await` resolves the first page; `for await`
2110
+ * walks every message across all pages.
2111
+ *
2112
+ * @example Iterate every message, or take one page
2113
+ * for await (const message of bird.email.list({ status: "bounced" })) {
2114
+ * console.log(message.id);
2115
+ * }
2116
+ * const page = await bird.email.list({ limit: 50 }); // page.data, page.next_cursor
2117
+ */
2118
+ list(query, options) {
2119
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listEmailMessages({
2120
+ client: this.client,
2121
+ query: {
2122
+ ...query,
2123
+ starting_after: cursor ?? query?.starting_after
2124
+ },
2125
+ headers,
2126
+ signal
2127
+ }));
2128
+ }
2129
+ };
2130
+ //#endregion
2131
+ //#region src/resources/audiences.ts
2132
+ var AudiencesResource = class extends Resource {
2133
+ /**
2134
+ * Create an audience.
2135
+ *
2136
+ * @example Create an audience
2137
+ * const audience = await bird.audiences.create({ name: "Newsletter subscribers" });
2138
+ * console.log(audience.id); // "aud_…"
2139
+ */
2140
+ create(params, options) {
2141
+ return this.call("POST", options, ({ signal, headers }) => createAudience({
2142
+ client: this.client,
2143
+ body: params,
2144
+ headers,
2145
+ signal
2146
+ }));
2147
+ }
2148
+ /**
2149
+ * List the workspace's audiences, newest first. `await` resolves the first
2150
+ * page; `for await` walks every audience across pages.
2151
+ *
2152
+ * @example
2153
+ * for await (const audience of bird.audiences.list()) {
2154
+ * console.log(audience.id, audience.name);
2155
+ * }
2156
+ */
2157
+ list(query, options) {
2158
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listAudiences({
2159
+ client: this.client,
2160
+ query: {
2161
+ ...query,
2162
+ starting_after: cursor ?? query?.starting_after
2163
+ },
2164
+ headers,
2165
+ signal
2166
+ }));
2167
+ }
2168
+ /**
2169
+ * Fetch a single audience by id.
2170
+ *
2171
+ * @example
2172
+ * const audience = await bird.audiences.get("aud_01krdgeqcxet5s7t44vh8rt9mg");
2173
+ */
2174
+ get(audienceId, options) {
2175
+ return this.call("GET", options, ({ signal, headers }) => getAudience({
2176
+ client: this.client,
2177
+ path: { audience_id: audienceId },
2178
+ headers,
2179
+ signal
2180
+ }));
2181
+ }
2182
+ /**
2183
+ * Update an audience. Only the fields you send change.
2184
+ *
2185
+ * @example
2186
+ * await bird.audiences.update("aud_01krdgeqcxet5s7t44vh8rt9mg", { name: "Renamed" });
2187
+ */
2188
+ update(audienceId, params, options) {
2189
+ return this.call("PATCH", options, ({ signal, headers }) => updateAudience({
2190
+ client: this.client,
2191
+ path: { audience_id: audienceId },
2192
+ body: params,
2193
+ headers,
2194
+ signal
2195
+ }));
2196
+ }
2197
+ /**
2198
+ * Delete an audience. Its contacts are unaffected.
2199
+ *
2200
+ * @example
2201
+ * await bird.audiences.delete("aud_01krdgeqcxet5s7t44vh8rt9mg");
2202
+ */
2203
+ delete(audienceId, options) {
2204
+ return this.call("DELETE", options, ({ signal, headers }) => deleteAudience({
2205
+ client: this.client,
2206
+ path: { audience_id: audienceId },
2207
+ headers,
2208
+ signal
2209
+ }));
2210
+ }
2211
+ /**
2212
+ * List the contacts in an audience, newest first. `await` resolves the first
2213
+ * page; `for await` walks every member across pages.
2214
+ *
2215
+ * @example
2216
+ * for await (const member of bird.audiences.listContacts("aud_01krdgeqcxet5s7t44vh8rt9mg")) {
2217
+ * console.log(member.contact.id, member.joined_at);
2218
+ * }
2219
+ */
2220
+ listContacts(audienceId, query, options) {
2221
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listAudienceContacts({
2222
+ client: this.client,
2223
+ path: { audience_id: audienceId },
2224
+ query: {
2225
+ ...query,
2226
+ starting_after: cursor ?? query?.starting_after
2227
+ },
2228
+ headers,
2229
+ signal
2230
+ }));
2231
+ }
2232
+ /**
2233
+ * Add contacts to an audience by id.
2234
+ *
2235
+ * @example
2236
+ * await bird.audiences.addContacts("aud_01krdgeqcxet5s7t44vh8rt9mg", {
2237
+ * contact_ids: ["con_1", "con_2"],
2238
+ * });
2239
+ */
2240
+ addContacts(audienceId, params, options) {
2241
+ return this.call("POST", options, ({ signal, headers }) => assignAudienceContacts({
2242
+ client: this.client,
2243
+ path: { audience_id: audienceId },
2244
+ body: params,
2245
+ headers,
2246
+ signal
2247
+ }));
2248
+ }
2249
+ /**
2250
+ * Remove a set of contacts from an audience.
2251
+ *
2252
+ * @example
2253
+ * await bird.audiences.removeContacts("aud_01krdgeqcxet5s7t44vh8rt9mg", {
2254
+ * contact_ids: ["con_1", "con_2"],
2255
+ * });
2256
+ */
2257
+ removeContacts(audienceId, params, options) {
2258
+ return this.call("POST", options, ({ signal, headers }) => unassignAudienceContacts({
2259
+ client: this.client,
2260
+ path: { audience_id: audienceId },
2261
+ body: params,
2262
+ headers,
2263
+ signal
2264
+ }));
2265
+ }
2266
+ /**
2267
+ * Remove a single contact from an audience.
2268
+ *
2269
+ * @example
2270
+ * await bird.audiences.removeContact("aud_01krdgeqcxet5s7t44vh8rt9mg", "con_1");
2271
+ */
2272
+ removeContact(audienceId, contactId, options) {
2273
+ return this.call("DELETE", options, ({ signal, headers }) => unassignAudienceContact({
2274
+ client: this.client,
2275
+ path: {
2276
+ audience_id: audienceId,
2277
+ contact_id: contactId
2278
+ },
2279
+ headers,
2280
+ signal
2281
+ }));
2282
+ }
2283
+ };
2284
+ //#endregion
2285
+ //#region src/resources/contactProperties.ts
2286
+ var ContactPropertiesResource = class extends Resource {
2287
+ /**
2288
+ * Define a contact property. The `key` must be unique in the workspace and is
2289
+ * how contacts reference the field in their `data`.
2290
+ *
2291
+ * @example
2292
+ * const prop = await bird.contactProperties.create({ key: "plan", type: "string" });
2293
+ * console.log(prop.id); // "cp_…"
2294
+ */
2295
+ create(params, options) {
2296
+ return this.call("POST", options, ({ signal, headers }) => createContactProperty({
2297
+ client: this.client,
2298
+ body: params,
2299
+ headers,
2300
+ signal
2301
+ }));
2302
+ }
2303
+ /**
2304
+ * List the workspace's contact properties. `await` resolves the first page;
2305
+ * `for await` walks every property across pages.
2306
+ *
2307
+ * @example
2308
+ * for await (const prop of bird.contactProperties.list()) {
2309
+ * console.log(prop.key, prop.type);
2310
+ * }
2311
+ */
2312
+ list(query, options) {
2313
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listContactProperties({
2314
+ client: this.client,
2315
+ query: {
2316
+ ...query,
2317
+ starting_after: cursor ?? query?.starting_after
2318
+ },
2319
+ headers,
2320
+ signal
2321
+ }));
2322
+ }
2323
+ /**
2324
+ * Fetch a single contact property by id.
2325
+ *
2326
+ * @example
2327
+ * const prop = await bird.contactProperties.get("cp_01krdgeqcxet5s7t44vh8rt9mg");
2328
+ */
2329
+ get(propertyId, options) {
2330
+ return this.call("GET", options, ({ signal, headers }) => getContactProperty({
2331
+ client: this.client,
2332
+ path: { property_id: propertyId },
2333
+ headers,
2334
+ signal
2335
+ }));
2336
+ }
2337
+ /**
2338
+ * Update a contact property. Only the fields you send change.
2339
+ *
2340
+ * @example
2341
+ * await bird.contactProperties.update("cp_01krdgeqcxet5s7t44vh8rt9mg", { fallback_value: "free" });
2342
+ */
2343
+ update(propertyId, params, options) {
2344
+ return this.call("PATCH", options, ({ signal, headers }) => updateContactProperty({
2345
+ client: this.client,
2346
+ path: { property_id: propertyId },
2347
+ body: params,
2348
+ headers,
2349
+ signal
2350
+ }));
2351
+ }
2352
+ /**
2353
+ * Archive a contact property, retiring the field without deleting its data.
2354
+ *
2355
+ * @example
2356
+ * await bird.contactProperties.archive("cp_01krdgeqcxet5s7t44vh8rt9mg");
2357
+ */
2358
+ archive(propertyId, options) {
2359
+ return this.call("POST", options, ({ signal, headers }) => archiveContactProperty({
2360
+ client: this.client,
2361
+ path: { property_id: propertyId },
2362
+ headers,
2363
+ signal
2364
+ }));
2365
+ }
2366
+ /**
2367
+ * Restore an archived contact property.
2368
+ *
2369
+ * @example
2370
+ * await bird.contactProperties.unarchive("cp_01krdgeqcxet5s7t44vh8rt9mg");
2371
+ */
2372
+ unarchive(propertyId, options) {
2373
+ return this.call("POST", options, ({ signal, headers }) => unarchiveContactProperty({
2374
+ client: this.client,
2375
+ path: { property_id: propertyId },
2376
+ headers,
2377
+ signal
2378
+ }));
2379
+ }
2380
+ };
2381
+ //#endregion
2382
+ //#region src/resources/contacts.ts
2383
+ var ContactsResource = class extends Resource {
2384
+ /**
2385
+ * Create a contact. `email` is required and unique within the workspace; set
2386
+ * custom fields via `data` (each key a property defined in contact properties).
2387
+ *
2388
+ * @example Create a contact
2389
+ * const contact = await bird.contacts.create({
2390
+ * email: "jane@acme.com",
2391
+ * first_name: "Jane",
2392
+ * });
2393
+ * console.log(contact.id); // "con_…"
2394
+ */
2395
+ create(params, options) {
2396
+ return this.call("POST", options, ({ signal, headers }) => createContact({
2397
+ client: this.client,
2398
+ body: params,
2399
+ headers,
2400
+ signal
2401
+ }));
2402
+ }
2403
+ /**
2404
+ * List the workspace's contacts, newest first. `await` resolves the first page;
2405
+ * `for await` walks every contact across pages. Filter by `email`,
2406
+ * `external_id`, or a `search` term.
2407
+ *
2408
+ * @example Iterate every contact, or take one page
2409
+ * for await (const contact of bird.contacts.list({ search: "acme.com" })) {
2410
+ * console.log(contact.id, contact.email);
2411
+ * }
2412
+ * const page = await bird.contacts.list({ limit: 50 }); // page.data, page.next_cursor
2413
+ */
2414
+ list(query, options) {
2415
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listContacts({
2416
+ client: this.client,
2417
+ query: {
2418
+ ...query,
2419
+ starting_after: cursor ?? query?.starting_after
2420
+ },
2421
+ headers,
2422
+ signal
2423
+ }));
2424
+ }
2425
+ /**
2426
+ * Fetch a single contact by id.
2427
+ *
2428
+ * @example
2429
+ * const contact = await bird.contacts.get("con_01krdgeqcxet5s7t44vh8rt9mg");
2430
+ * contact.email;
2431
+ */
2432
+ get(contactId, options) {
2433
+ return this.call("GET", options, ({ signal, headers }) => getContact({
2434
+ client: this.client,
2435
+ path: { contact_id: contactId },
2436
+ headers,
2437
+ signal
2438
+ }));
2439
+ }
2440
+ /**
2441
+ * Update a contact. Only the fields you send change.
2442
+ *
2443
+ * @example
2444
+ * const contact = await bird.contacts.update("con_01krdgeqcxet5s7t44vh8rt9mg", {
2445
+ * first_name: "Jane",
2446
+ * });
2447
+ */
2448
+ update(contactId, params, options) {
2449
+ return this.call("PATCH", options, ({ signal, headers }) => updateContact({
2450
+ client: this.client,
2451
+ path: { contact_id: contactId },
2452
+ body: params,
2453
+ headers,
2454
+ signal
2455
+ }));
2456
+ }
2457
+ /**
2458
+ * Delete a contact by id.
2459
+ *
2460
+ * @example
2461
+ * await bird.contacts.delete("con_01krdgeqcxet5s7t44vh8rt9mg");
2462
+ */
2463
+ delete(contactId, options) {
2464
+ return this.call("DELETE", options, ({ signal, headers }) => deleteContact({
2465
+ client: this.client,
2466
+ path: { contact_id: contactId },
2467
+ headers,
2468
+ signal
2469
+ }));
2470
+ }
2471
+ /**
2472
+ * Create or update many contacts in one call, matched by email. Returns a
2473
+ * per-contact result.
2474
+ *
2475
+ * @example
2476
+ * const result = await bird.contacts.batch({
2477
+ * contacts: [{ email: "jane@acme.com", first_name: "Jane" }],
2478
+ * });
2479
+ */
2480
+ batch(params, options) {
2481
+ return this.call("POST", options, ({ signal, headers }) => createContactBatch({
2482
+ client: this.client,
2483
+ body: params,
2484
+ headers,
2485
+ signal
2486
+ }));
2487
+ }
2488
+ };
2489
+ //#endregion
2490
+ //#region src/resources/emailTemplates.ts
2491
+ var EmailTemplatesResource = class extends Resource {
2492
+ /**
2493
+ * Create a template and its initial editable draft. Pick the authoring format
2494
+ * with `source` (`liquid`, `handlebars`, or `html`); the name must be unique
2495
+ * in the workspace or the call throws a `BirdConflictError`.
2496
+ *
2497
+ * @example Create a template
2498
+ * const tpl = await bird.emailTemplates.create({
2499
+ * name: "welcome-email",
2500
+ * description: "Welcome",
2501
+ * category: "transactional",
2502
+ * source: "handlebars",
2503
+ * subject: "Welcome, {{ first_name }}!",
2504
+ * html: "<h1>Hi {{ first_name }}</h1>",
2505
+ * });
2506
+ * console.log(tpl.id, tpl.revision); // "emt_…", 0
2507
+ */
2508
+ create(params, options) {
2509
+ return this.call("POST", options, ({ signal, headers }) => createEmailTemplate({
2510
+ client: this.client,
2511
+ body: params,
2512
+ headers,
2513
+ signal
2514
+ }));
2515
+ }
2516
+ /**
2517
+ * List the workspace's templates, newest first. `await` resolves the first
2518
+ * page; `for await` walks every template across all pages. Filter by
2519
+ * `category`, `source`, or a case-insensitive `name` prefix.
2520
+ *
2521
+ * @example Iterate every template, or take one page
2522
+ * for await (const tpl of bird.emailTemplates.list({ category: "transactional" })) {
2523
+ * console.log(tpl.id, tpl.name);
2524
+ * }
2525
+ * const page = await bird.emailTemplates.list({ limit: 50 }); // page.data, page.next_cursor
2526
+ */
2527
+ list(query, options) {
2528
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listEmailTemplates({
2529
+ client: this.client,
2530
+ query: {
2531
+ ...query,
2532
+ starting_after: cursor ?? query?.starting_after
2533
+ },
2534
+ headers,
2535
+ signal
2536
+ }));
2537
+ }
2538
+ /**
2539
+ * Fetch a template with its current draft content (subject, HTML, text), the
2540
+ * draft `revision`, and its draft/published version ids.
2541
+ *
2542
+ * @example
2543
+ * const tpl = await bird.emailTemplates.get("emt_abc123");
2544
+ * tpl.subject;
2545
+ * tpl.published_version_id; // null until first publish
2546
+ */
2547
+ get(templateId, options) {
2548
+ return this.call("GET", options, ({ signal, headers }) => getEmailTemplate({
2549
+ client: this.client,
2550
+ path: { template_id: templateId },
2551
+ headers,
2552
+ signal
2553
+ }));
2554
+ }
2555
+ /**
2556
+ * Update a template's metadata and draft content. Only the fields you send
2557
+ * change. Pass the draft `revision` you last read; if another edit landed
2558
+ * first the call throws a `BirdConflictError` — reload and retry.
2559
+ *
2560
+ * @example Edit the draft, guarded by the revision you read
2561
+ * const tpl = await bird.emailTemplates.get("emt_abc123");
2562
+ * const updated = await bird.emailTemplates.update("emt_abc123", {
2563
+ * revision: tpl.revision,
2564
+ * subject: "Welcome aboard, {{ first_name }}!",
2565
+ * });
2566
+ */
2567
+ update(templateId, params, options) {
2568
+ return this.call("PATCH", options, ({ signal, headers }) => updateEmailTemplate({
2569
+ client: this.client,
2570
+ path: { template_id: templateId },
2571
+ body: params,
2572
+ headers,
2573
+ signal
2574
+ }));
2575
+ }
2576
+ /**
2577
+ * Delete a template and all its versions. The name becomes available for
2578
+ * reuse in the workspace.
2579
+ *
2580
+ * @example
2581
+ * await bird.emailTemplates.delete("emt_abc123");
2582
+ */
2583
+ delete(templateId, options) {
2584
+ return this.call("DELETE", options, ({ signal, headers }) => deleteEmailTemplate({
2585
+ client: this.client,
2586
+ path: { template_id: templateId },
2587
+ headers,
2588
+ signal
2589
+ }));
2590
+ }
2591
+ /**
2592
+ * Publish the current draft as a new immutable, numbered version and make it
2593
+ * the live version used by sends. The draft stays editable. The draft must
2594
+ * have a subject and a body, or the call throws.
2595
+ *
2596
+ * @example Publish, then send by template
2597
+ * const version = await bird.emailTemplates.publish("emt_abc123");
2598
+ * console.log(version.version_number); // 1, 2, 3…
2599
+ * await bird.email.send({
2600
+ * from: "hello@acme.com",
2601
+ * to: ["alice@example.com"],
2602
+ * template: { id: "emt_abc123", parameters: { first_name: "Alice" } },
2603
+ * });
2604
+ */
2605
+ publish(templateId, options) {
2606
+ return this.call("POST", options, ({ signal, headers }) => publishEmailTemplate({
2607
+ client: this.client,
2608
+ path: { template_id: templateId },
2609
+ headers,
2610
+ signal
2611
+ }));
2612
+ }
2613
+ /**
2614
+ * List every version of a template — the current draft plus all published
2615
+ * versions — newest first. Returns the full set in one response (`.data`);
2616
+ * this list is not paginated.
2617
+ *
2618
+ * @example
2619
+ * const { data } = await bird.emailTemplates.listVersions("emt_abc123");
2620
+ * for (const v of data) console.log(v.version_number, v.status);
2621
+ */
2622
+ listVersions(templateId, options) {
2623
+ return this.call("GET", options, ({ signal, headers }) => listEmailTemplateVersions({
2624
+ client: this.client,
2625
+ path: { template_id: templateId },
2626
+ headers,
2627
+ signal
2628
+ }));
2629
+ }
2630
+ /**
2631
+ * Fetch a single version of a template.
2632
+ *
2633
+ * @example
2634
+ * const version = await bird.emailTemplates.getVersion("emt_abc123", "emv_def456");
2635
+ * version.status; // "draft" | "published"
2636
+ */
2637
+ getVersion(templateId, versionId, options) {
2638
+ return this.call("GET", options, ({ signal, headers }) => getEmailTemplateVersion({
2639
+ client: this.client,
2640
+ path: {
2641
+ template_id: templateId,
2642
+ version_id: versionId
2643
+ },
2644
+ headers,
2645
+ signal
2646
+ }));
2647
+ }
2648
+ };
2649
+ //#endregion
2650
+ //#region src/resources/sms.ts
2651
+ var SmsResource = class extends Resource {
2652
+ /**
2653
+ * Send one SMS to a single recipient. Supply either `text` (with a `category`)
2654
+ * or a stored `template` (by `id` or `name`, with its `parameters`). The
2655
+ * result is `accepted`, not yet delivered — read it back with `get` to confirm.
2656
+ *
2657
+ * @example Send free text
2658
+ * const msg = await bird.sms.send({
2659
+ * to: "+15551234567",
2660
+ * text: "Your verification code is 123456.",
2661
+ * category: "authentication",
2662
+ * });
2663
+ * console.log(msg.id, msg.status);
2664
+ *
2665
+ * @example Send by template
2666
+ * await bird.sms.send({
2667
+ * to: "+15551234567",
2668
+ * template: { name: "bird_otp_verification", parameters: { code: "123456" } },
2669
+ * });
2670
+ */
2671
+ send(params, options) {
2672
+ return this.call("POST", options, ({ signal, headers }) => createSmsMessage({
2673
+ client: this.client,
2674
+ body: params,
2675
+ headers,
2676
+ signal
2677
+ }));
2678
+ }
2679
+ /**
2680
+ * Send up to 100 independent SMS messages in one call. Each item is a full send
2681
+ * (free text or template); all items are validated before any are queued.
2682
+ *
2683
+ * @example
2684
+ * const result = await bird.sms.sendBatch([
2685
+ * { to: "+15551111111", text: "Hi Alice!", category: "marketing" },
2686
+ * { to: "+15552222222", text: "Hi Bob!", category: "marketing" },
2687
+ * ]);
2688
+ */
2689
+ sendBatch(params, options) {
2690
+ return this.call("POST", options, ({ signal, headers }) => createSmsMessageBatch({
2691
+ client: this.client,
2692
+ body: params,
2693
+ headers,
2694
+ signal
2695
+ }));
2696
+ }
2697
+ /**
2698
+ * Fetch a single SMS message: its current delivery status, segment breakdown,
2699
+ * cost, and failure detail if it failed.
2700
+ *
2701
+ * @example
2702
+ * const msg = await bird.sms.get("sms_abc123");
2703
+ * msg.status; // "accepted" | "delivered" | …
2704
+ */
2705
+ get(messageId, options) {
2706
+ return this.call("GET", options, ({ signal, headers }) => getSmsMessage({
2707
+ client: this.client,
2708
+ path: { message_id: messageId },
2709
+ headers,
2710
+ signal
2711
+ }));
2712
+ }
2713
+ /**
2714
+ * List SMS messages, newest first. `await` resolves the first page; `for await`
2715
+ * walks every message across all pages. Filter by direction, status, category,
2716
+ * recipient, sender, or tag.
2717
+ *
2718
+ * @example
2719
+ * for await (const msg of bird.sms.list({ direction: "outbound" })) {
2720
+ * console.log(msg.id, msg.status);
2721
+ * }
2722
+ */
2723
+ list(query, options) {
2724
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listSmsMessages({
2725
+ client: this.client,
2726
+ query: {
2727
+ ...query,
2728
+ starting_after: cursor ?? query?.starting_after
2729
+ },
2730
+ headers,
2731
+ signal
2732
+ }));
2733
+ }
2734
+ };
2735
+ //#endregion
2736
+ //#region src/resources/smsTemplates.ts
2737
+ var SmsTemplatesResource = class extends Resource {
2738
+ /**
2739
+ * List the SMS templates available to the workspace — Bird's built-in
2740
+ * templates plus any the workspace authored. The catalogue is small and
2741
+ * returned in full (`.data`); this list is not paginated. Filter by `scope`,
2742
+ * `category`, or `language` (a BCP-47 language tag).
2743
+ *
2744
+ * @example List the built-in templates
2745
+ * const { data } = await bird.smsTemplates.list({ scope: "system" });
2746
+ * for (const tpl of data) console.log(tpl.id, tpl.name);
2747
+ */
2748
+ list(query, options) {
2749
+ return this.call("GET", options, ({ signal, headers }) => listSmsTemplates({
2750
+ client: this.client,
2751
+ query,
2752
+ headers,
2753
+ signal
2754
+ }));
2755
+ }
2756
+ /**
2757
+ * Fetch a single SMS template by its name or id, including its body and the
2758
+ * variables it expects.
2759
+ *
2760
+ * @example
2761
+ * const tpl = await bird.smsTemplates.get("bird_otp_verification");
2762
+ * console.log(tpl.body, tpl.variables);
2763
+ */
2764
+ get(templateRef, options) {
2765
+ return this.call("GET", options, ({ signal, headers }) => getSmsTemplate({
2766
+ client: this.client,
2767
+ path: { template_ref: templateRef },
2768
+ headers,
2769
+ signal
2770
+ }));
2771
+ }
2772
+ };
2773
+ //#endregion
2774
+ //#region src/resources/webhooks.ts
2775
+ var WebhooksResource = class {
2776
+ #secret;
2777
+ constructor(config) {
2778
+ this.#secret = config?.secret;
2779
+ }
2780
+ /**
2781
+ * Verify a webhook delivery and return the typed event.
2782
+ *
2783
+ * **Pass the raw request body**, exactly as received — do NOT parse it first.
2784
+ * The Standard Webhooks signature is computed over the raw bytes, so parsing
2785
+ * and re-serializing before verifying is the classic webhook bug.
2786
+ *
2787
+ * The secret comes from `webhooks.secret` on the client; pass `{ secret }` to
2788
+ * override per call. Throws {@link BirdWebhookVerificationError} on a bad
2789
+ * signature, a stale timestamp, or missing/malformed headers. Unknown event
2790
+ * types are returned as-is (handle them in a `default` case) so a newer server
2791
+ * event can't break an older SDK.
2792
+ *
2793
+ * @example One call verifies the signature and returns the typed event
2794
+ * // Pass the RAW request body; set the secret via new BirdClient({ webhooks: { secret } }).
2795
+ * const event = bird.webhooks.unwrap(rawBody, headers);
2796
+ * console.log(event.type); // discriminated union — narrow on event.type
2797
+ *
2798
+ * @example Verify and dispatch — pass the raw request body, never the parsed JSON
2799
+ * // new BirdClient({ apiKey, webhooks: { secret } })
2800
+ * try {
2801
+ * const event = bird.webhooks.unwrap(rawBody, req.headers);
2802
+ * switch (event.type) {
2803
+ * case "email.delivered":
2804
+ * markDelivered(event.email_id, event.recipient); // narrowed; fields are flat
2805
+ * break;
2806
+ * case "email.bounced":
2807
+ * case "email.complained":
2808
+ * suppress(event.recipient);
2809
+ * break;
2810
+ * default: // unknown future event types — an older SDK won't break on a new one
2811
+ * }
2812
+ * } catch (err) {
2813
+ * if (err instanceof BirdWebhookVerificationError) {
2814
+ * // reject with 400 — bad signature, stale timestamp, or missing/malformed headers
2815
+ * } else throw err;
2816
+ * }
2817
+ */
2818
+ unwrap(payload, headers, options) {
2819
+ const secret = options?.secret ?? this.#secret;
2820
+ if (!secret) throw new Error("No webhook secret. Set `webhooks: { secret }` on the client, or pass `{ secret }` to unwrap.");
2821
+ const wh = new Webhook(secret);
2822
+ let verified;
2823
+ try {
2824
+ verified = wh.verify(payload, toHeaderRecord(headers));
2825
+ } catch (err) {
2826
+ throw new BirdWebhookVerificationError(err instanceof Error ? err.message : "Webhook signature verification failed");
2827
+ }
2828
+ return verified;
2829
+ }
2830
+ };
2831
+ function toHeaderRecord(headers) {
2832
+ return headers instanceof Headers ? Object.fromEntries(headers) : headers;
2833
+ }
2834
+ //#endregion
2835
+ //#region src/client.ts
2836
+ const DEFAULT_TIMEOUT_MS = 6e4;
2837
+ const DEFAULT_MAX_RETRIES = 2;
2838
+ function resolveBaseUrl(options) {
2839
+ if (options.baseUrl) return options.baseUrl;
2840
+ const region = options.region ?? regionFromApiKey(options.apiKey);
2841
+ if (!region) throw new Error("Unable to determine region: API key is not in the expected bk_{region}_{token} format. Pass an explicit `region` or `baseUrl`.");
2842
+ return baseUrlForRegion(region);
2843
+ }
2844
+ function resolveRawRequestUrl(baseUrl, path) {
2845
+ if (!path.startsWith("/") || path.startsWith("//")) throw new TypeError("bird.request path must be an absolute path starting with a single `/`");
2846
+ const base = new URL(baseUrl);
2847
+ const url = new URL(baseUrl + path);
2848
+ if (url.origin !== base.origin) throw new TypeError("bird.request path must stay on the configured Bird API origin");
2849
+ return url;
2850
+ }
2851
+ /**
2852
+ * The Bird API client. Construct it with an API key; the region is taken from
2853
+ * the key's prefix (`bk_{region}_…`) — pass `baseUrl` or `region` to override.
2854
+ *
2855
+ * @example Construct and send
2856
+ * const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
2857
+ * const msg = await bird.email.send({
2858
+ * from: "hello@acme.com",
2859
+ * to: ["customer@example.com"],
2860
+ * subject: "Welcome aboard",
2861
+ * html: "<h1>Hi there 👋</h1>",
2862
+ * });
2863
+ * console.log(msg.id);
2864
+ *
2865
+ * @example Channel defaults — set common send fields once; a per-send value always wins
2866
+ * const bird = new BirdClient({
2867
+ * apiKey: process.env.BIRD_API_KEY!,
2868
+ * email: { from: "hello@acme.com", category: "transactional" },
2869
+ * });
2870
+ * // `from` and `category` are filled from the defaults; both stay optional in `send`.
2871
+ * await bird.email.send({ to: ["customer@example.com"], subject: "Hi", html: "<p>hi</p>" });
2872
+ *
2873
+ * @example All client options
2874
+ * const bird = new BirdClient({
2875
+ * apiKey: process.env.BIRD_API_KEY!,
2876
+ * region: "eu1", // optional — override the region from the key prefix
2877
+ * baseUrl: "http://localhost:8080", // optional — overrides region entirely (local/self-hosted)
2878
+ * timeout: 60_000, // per-attempt timeout in ms (default 60_000)
2879
+ * maxRetries: 2, // retry budget for transient failures (default 2)
2880
+ * });
2881
+ */
2882
+ var BirdClient = class {
2883
+ core;
2884
+ #client;
2885
+ #baseUrl;
2886
+ #fetch;
2887
+ #headers;
2888
+ /** The email channel — `bird.email.send(...)`, `.get(...)`, `.list(...)`. */
2889
+ email;
2890
+ /** Email templates — `bird.emailTemplates.create(...)`, `.list(...)`, `.publish(...)`, … */
2891
+ emailTemplates;
2892
+ /** The SMS channel — `bird.sms.send(...)`, `.get(...)`, `.list(...)`. */
2893
+ sms;
2894
+ /** SMS templates — `bird.smsTemplates.list(...)`, `.get(...)`. */
2895
+ smsTemplates;
2896
+ /** Contacts — `bird.contacts.create(...)`, `.list(...)`, `.get(...)`, `.batch(...)`, … */
2897
+ contacts;
2898
+ /** Audiences — `bird.audiences.create(...)`, `.list(...)`, `.addContacts(...)`, … */
2899
+ audiences;
2900
+ /** Contact properties — `bird.contactProperties.create(...)`, `.list(...)`, `.archive(...)`, … */
2901
+ contactProperties;
2902
+ /** Webhooks — `bird.webhooks.unwrap(payload, headers)` verifies an inbound delivery. */
2903
+ webhooks;
2904
+ constructor(options) {
2905
+ const opts = options;
2906
+ this.#baseUrl = resolveBaseUrl(opts);
2907
+ this.#fetch = opts.fetch ?? fetch;
2908
+ this.#headers = {
2909
+ ...opts.defaultHeaders,
2910
+ Authorization: `Bearer ${opts.apiKey}`,
2911
+ "User-Agent": `bird-sdk-js/0.4.2`,
2912
+ "Bird-Surface": "sdk-js",
2913
+ "Bird-Version": "0.4.2"
2914
+ };
2915
+ const caller = detectCaller();
2916
+ if (caller) this.#headers["Bird-Caller"] = caller;
2917
+ this.#client = createClient(createConfig({
2918
+ baseUrl: this.#baseUrl,
2919
+ fetch: this.#fetch,
2920
+ headers: this.#headers
2921
+ }));
2922
+ this.core = new BirdHTTPClient({
2923
+ timeout: opts.timeout ?? DEFAULT_TIMEOUT_MS,
2924
+ maxRetries: opts.maxRetries ?? DEFAULT_MAX_RETRIES
2925
+ });
2926
+ this.email = new EmailResource(this.core, this.#client, opts.email);
2927
+ this.emailTemplates = new EmailTemplatesResource(this.core, this.#client);
2928
+ this.sms = new SmsResource(this.core, this.#client);
2929
+ this.smsTemplates = new SmsTemplatesResource(this.core, this.#client);
2930
+ this.contacts = new ContactsResource(this.core, this.#client);
2931
+ this.audiences = new AudiencesResource(this.core, this.#client);
2932
+ this.contactProperties = new ContactPropertiesResource(this.core, this.#client);
2933
+ this.webhooks = new WebhooksResource(opts.webhooks);
2934
+ }
2935
+ /**
2936
+ * Escape hatch for endpoints the typed resources don't cover. Runs the full
2937
+ * lifecycle (auth, retries, idempotency, error mapping); you supply the
2938
+ * response type. Prefer a typed resource method where one exists.
2939
+ *
2940
+ * @throws {TypeError} if `req.path` does not start with exactly one `/` or
2941
+ * resolves to a different origin than the configured Bird API base URL.
2942
+ *
2943
+ * @example Reach an endpoint outside the curated surface — you supply the response type
2944
+ * type Suppressions = { data: Array<{ recipient: string }> };
2945
+ * const suppressions = await bird.request<Suppressions>({ method: "GET", path: "/v1/email/suppressions" });
2946
+ * console.log(suppressions.data.length);
2947
+ */
2948
+ request(req, options) {
2949
+ const url = resolveRawRequestUrl(this.#baseUrl, req.path);
2950
+ return apiPromise(this.core.request((ctx) => this.#raw(url, req, ctx, options?.headers), {
2951
+ method: req.method,
2952
+ idempotencyKey: options?.idempotencyKey,
2953
+ signal: options?.signal,
2954
+ timeout: options?.timeout,
2955
+ maxRetries: options?.maxRetries
2956
+ }));
2957
+ }
2958
+ async #raw(url, req, ctx, extraHeaders) {
2959
+ url = new URL(url);
2960
+ if (req.query) {
2961
+ for (const [key, value] of Object.entries(req.query)) if (value !== void 0) url.searchParams.set(key, String(value));
2962
+ }
2963
+ const headers = {
2964
+ ...extraHeaders,
2965
+ ...this.#headers
2966
+ };
2967
+ if (ctx.idempotencyKey) headers["Idempotency-Key"] = ctx.idempotencyKey;
2968
+ if (req.body !== void 0) headers["Content-Type"] = "application/json";
2969
+ const response = await this.#fetch(url, {
2970
+ method: req.method,
2971
+ headers,
2972
+ body: req.body !== void 0 ? JSON.stringify(req.body) : void 0,
2973
+ signal: ctx.signal
2974
+ });
2975
+ if (response.ok) return {
2976
+ data: response.status === 204 ? void 0 : await response.json().catch(() => void 0),
2977
+ response
2978
+ };
2979
+ return {
2980
+ error: await response.clone().json().catch(() => void 0),
2981
+ response
2982
+ };
2983
+ }
2984
+ };
2985
+ //#endregion
2986
+ //#region src/event-types.gen.ts
2987
+ /**
2988
+ * Webhook event types known at this SDK version. The wire value is an open
2989
+ * string: a value added by a newer server is returned by `unwrap` unchanged,
2990
+ * so switch on these with a `default` branch.
2991
+ */
2992
+ const WebhookEventType = {
2993
+ DomainFailed: "domain.failed",
2994
+ DomainVerified: "domain.verified",
2995
+ EmailAccepted: "email.accepted",
2996
+ EmailBounced: "email.bounced",
2997
+ EmailCanceled: "email.canceled",
2998
+ EmailClicked: "email.clicked",
2999
+ EmailComplained: "email.complained",
3000
+ EmailDeferred: "email.deferred",
3001
+ EmailDelivered: "email.delivered",
3002
+ EmailListUnsubscribed: "email.list_unsubscribed",
3003
+ EmailMailboxMessageDelivered: "email_mailbox.message_delivered",
3004
+ EmailMailboxMessageFailed: "email_mailbox.message_failed",
3005
+ EmailMailboxMessageReceived: "email_mailbox.message_received",
3006
+ EmailMailboxMessageReceivedBlocked: "email_mailbox.message_received_blocked",
3007
+ EmailMailboxMessageReceivedUnauthenticated: "email_mailbox.message_received_unauthenticated",
3008
+ EmailMailboxMessageSent: "email_mailbox.message_sent",
3009
+ EmailMailboxSuspended: "email_mailbox.suspended",
3010
+ EmailMailboxThreadCreated: "email_mailbox.thread_created",
3011
+ EmailOpened: "email.opened",
3012
+ EmailOutOfBandBounce: "email.out_of_band_bounce",
3013
+ EmailProcessed: "email.processed",
3014
+ EmailReceived: "email.received",
3015
+ EmailRejected: "email.rejected",
3016
+ EmailScheduled: "email.scheduled",
3017
+ EmailSuppressionCreated: "email_suppression.created",
3018
+ EmailUnsubscribed: "email.unsubscribed",
3019
+ SmsAccepted: "sms.accepted",
3020
+ SmsDelivered: "sms.delivered",
3021
+ SmsExpired: "sms.expired",
3022
+ SmsFailed: "sms.failed",
3023
+ SmsRejected: "sms.rejected",
3024
+ SmsSent: "sms.sent",
3025
+ SmsUndelivered: "sms.undelivered"
3026
+ };
3027
+ //#endregion
3028
+ export { BirdAPIError, BirdAuthError, BirdBadRequestError, BirdBillingError, BirdClient, BirdConflictError, BirdConnectionError, BirdError, BirdInternalError, BirdMisdirectedError, BirdNotFoundError, BirdNotImplementedError, BirdPayloadTooLargeError, BirdPermissionError, BirdPreconditionError, BirdRateLimitError, BirdServiceUnavailableError, BirdTimeoutError, BirdValidationError, BirdWebhookVerificationError, WebhookEventType, baseUrlForRegion, regionFromApiKey };
3029
+
3030
+ //# sourceMappingURL=index.mjs.map