@gigadrive/sdk 0.8.5 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ __export(src_exports, {
38
38
  AiGatewayVideosResource: () => AiGatewayVideosResource,
39
39
  ApiError: () => ApiError,
40
40
  ApiKeysResource: () => ApiKeysResource,
41
+ ApplicationDomainsResource: () => ApplicationDomainsResource,
41
42
  ApplicationEnvVarsResource: () => ApplicationEnvVarsResource,
42
43
  ApplicationRequestsResource: () => ApplicationRequestsResource,
43
44
  ApplicationStorageResource: () => ApplicationStorageResource,
@@ -45,14 +46,25 @@ __export(src_exports, {
45
46
  AuthenticationError: () => AuthenticationError,
46
47
  ConfigurationError: () => ConfigurationError,
47
48
  DeploymentsResource: () => DeploymentsResource,
49
+ DomainNotActiveError: () => DomainNotActiveError,
48
50
  GigadriveClient: () => GigadriveClient,
49
51
  GigadriveError: () => GigadriveError,
50
52
  ImageOptimizationResource: () => ImageOptimizationResource,
53
+ NonRetryableError: () => NonRetryableError,
51
54
  OrganizationAiGatewayResource: () => OrganizationAiGatewayResource,
55
+ OrganizationDomainsResource: () => OrganizationDomainsResource,
52
56
  OrganizationEnvVarsResource: () => OrganizationEnvVarsResource,
53
57
  OrganizationMembersResource: () => OrganizationMembersResource,
54
58
  OrganizationProductsResource: () => OrganizationProductsResource,
55
59
  OrganizationsResource: () => OrganizationsResource,
60
+ QUEUE_DELIVERY_HEADERS: () => QUEUE_DELIVERY_HEADERS,
61
+ QUEUE_RESPONSE_HEADERS: () => QUEUE_RESPONSE_HEADERS,
62
+ QUEUE_SIGNATURE_HEADER: () => QUEUE_SIGNATURE_HEADER,
63
+ QUEUE_SIGNATURE_TOLERANCE_MS: () => QUEUE_SIGNATURE_TOLERANCE_MS,
64
+ QUEUE_SIGNING_SECRET_ENV: () => QUEUE_SIGNING_SECRET_ENV,
65
+ Queue: () => Queue,
66
+ QueuesResource: () => QueuesResource,
67
+ RetryLaterError: () => RetryLaterError,
56
68
  StickySessionsResource: () => StickySessionsResource,
57
69
  StorageBucketsResource: () => StorageBucketsResource,
58
70
  StorageObjectsResource: () => StorageObjectsResource,
@@ -60,9 +72,17 @@ __export(src_exports, {
60
72
  StorageUploadSessionsResource: () => StorageUploadSessionsResource,
61
73
  UploadError: () => UploadError,
62
74
  UploadSessionExpiredError: () => UploadSessionExpiredError,
75
+ WORKFLOW_CONSUMER_PATH: () => WORKFLOW_CONSUMER_PATH,
76
+ WORKFLOW_QUEUE_NAME_HEADER: () => WORKFLOW_QUEUE_NAME_HEADER,
63
77
  createManagedImageUrl: () => createManagedImageUrl,
78
+ createWorkflowQueue: () => createWorkflowQueue,
79
+ defaultQueueCodec: () => defaultQueueCodec,
80
+ durationToSeconds: () => durationToSeconds,
64
81
  paginate: () => paginate,
65
- parseSSEStream: () => parseSSEStream
82
+ parseSSEStream: () => parseSSEStream,
83
+ queue: () => queue,
84
+ signQueueDelivery: () => signQueueDelivery,
85
+ verifyQueueSignature: () => verifyQueueSignature
66
86
  });
67
87
  module.exports = __toCommonJS(src_exports);
68
88
 
@@ -90,11 +110,17 @@ var ApiError = class extends GigadriveError {
90
110
  status;
91
111
  /** An optional machine-readable error code from the API response body. */
92
112
  code;
93
- constructor(message, status, code) {
113
+ /**
114
+ * An optional finer-grained reason next to {@link code}, for example `daily_add_limit` with
115
+ * `quota_exceeded`, or `other_organization` with `domain_in_use`.
116
+ */
117
+ reason;
118
+ constructor(message, status, code, reason) {
94
119
  super(message);
95
120
  this.name = "ApiError";
96
121
  this.status = status;
97
122
  this.code = code;
123
+ this.reason = reason;
98
124
  }
99
125
  };
100
126
  var UploadError = class extends GigadriveError {
@@ -582,10 +608,13 @@ var HttpClient = class {
582
608
  async toApiError(response) {
583
609
  let message;
584
610
  let code;
611
+ let reason;
585
612
  try {
586
613
  const body = await response.json();
587
614
  if (typeof body.error === "string") {
588
615
  message = body.error;
616
+ if (typeof body.code === "string") code = body.code;
617
+ if (typeof body.reason === "string") reason = body.reason;
589
618
  } else if (body.error && typeof body.error === "object") {
590
619
  message = body.error.message ?? response.statusText;
591
620
  code = body.error.code;
@@ -595,7 +624,7 @@ var HttpClient = class {
595
624
  } catch {
596
625
  message = response.statusText;
597
626
  }
598
- return new ApiError(message, response.status, code);
627
+ return new ApiError(message, response.status, code, reason);
599
628
  }
600
629
  buildUrl(path, query) {
601
630
  const url = `${this.baseUrl}${path}`;
@@ -955,6 +984,7 @@ var ApplicationRequestsResource = class extends BaseResource {
955
984
  };
956
985
 
957
986
  // src/upload/checksum.ts
987
+ var EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
958
988
  var toHex = (buffer) => {
959
989
  const bytes = new Uint8Array(buffer);
960
990
  let hex = "";
@@ -1073,6 +1103,8 @@ var inferContentType = (nameOrKey) => {
1073
1103
  };
1074
1104
 
1075
1105
  // src/upload/source.ts
1106
+ var noop = () => {
1107
+ };
1076
1108
  var isNode = () => typeof process !== "undefined" && !!process.versions?.node;
1077
1109
  var toBytes = async (data) => {
1078
1110
  if (typeof Blob !== "undefined" && data instanceof Blob) return new Uint8Array(await data.arrayBuffer());
@@ -1119,7 +1151,8 @@ var resolveUploadSource = async (input, options = {}) => {
1119
1151
  size,
1120
1152
  contentType,
1121
1153
  checksums: buildChecksums(input, sha256),
1122
- requiresFiniteChunkSize: false
1154
+ requiresFiniteChunkSize: false,
1155
+ release: noop
1123
1156
  };
1124
1157
  }
1125
1158
  if (input.path !== void 0) {
@@ -1127,22 +1160,34 @@ var resolveUploadSource = async (input, options = {}) => {
1127
1160
  const fs = await import("fs");
1128
1161
  const size = input.contentLength ?? fs.statSync(input.path).size;
1129
1162
  const sha256 = input.checksumSha256 ?? (hash ? (await hashNodeFile(input.path)).sha256 : "");
1130
- const tusFile = fs.createReadStream(input.path);
1131
- return { tusFile, size, contentType, checksums: buildChecksums(input, sha256), requiresFiniteChunkSize: true };
1163
+ const stream = fs.createReadStream(input.path);
1164
+ return {
1165
+ tusFile: stream,
1166
+ size,
1167
+ contentType,
1168
+ checksums: buildChecksums(input, sha256),
1169
+ requiresFiniteChunkSize: true,
1170
+ release: () => {
1171
+ stream.on("error", noop);
1172
+ stream.destroy();
1173
+ }
1174
+ };
1132
1175
  }
1133
1176
  if (input.stream !== void 0) {
1134
1177
  if (input.contentLength === void 0) {
1135
1178
  throw new Error("Uploading from a stream requires contentLength to be provided.");
1136
1179
  }
1137
- if (hash && !input.checksumSha256) {
1180
+ const sha256 = input.checksumSha256 ?? (input.contentLength === 0 ? EMPTY_SHA256 : void 0);
1181
+ if (hash && !sha256) {
1138
1182
  throw new Error("Uploading from a stream requires checksumSha256 to be provided.");
1139
1183
  }
1140
1184
  return {
1141
1185
  tusFile: input.stream,
1142
1186
  size: input.contentLength,
1143
1187
  contentType,
1144
- checksums: buildChecksums(input, input.checksumSha256 ?? ""),
1145
- requiresFiniteChunkSize: true
1188
+ checksums: buildChecksums(input, sha256 ?? ""),
1189
+ requiresFiniteChunkSize: true,
1190
+ release: noop
1146
1191
  };
1147
1192
  }
1148
1193
  throw new Error("No upload source provided. Pass one of: data, path, or stream.");
@@ -1515,7 +1560,7 @@ var StorageUploadSessionsResource = class extends BaseResource {
1515
1560
  async uploadToUrl(url, source, options) {
1516
1561
  const resolved = await resolveUploadSource({ key: "", ...source }, { hash: false });
1517
1562
  const headers = { "Tus-Resumable": "1.0.0", ...options?.headers };
1518
- await runResolvedUpload(this.transport, url, resolved, options, headers).catch(toUploadError);
1563
+ await runResolvedUpload(this.transport, url, resolved, options, headers).catch(toUploadError).finally(resolved.release);
1519
1564
  }
1520
1565
  /**
1521
1566
  * Resume an interrupted upload to a previously issued signed upload URL. The
@@ -1532,6 +1577,7 @@ var StorageUploadSessionsResource = class extends BaseResource {
1532
1577
 
1533
1578
  // src/resources/application-storage.ts
1534
1579
  var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1580
+ var buildStorageObjectUrl = (cdnHostname, key) => `https://${cdnHostname}/${encodeURIComponent(key).replace(/%2F/g, "/")}`;
1535
1581
  var ApplicationStorageResource = class {
1536
1582
  constructor(httpClient, transport = tusUploadTransport, defaultApplicationId) {
1537
1583
  this.defaultApplicationId = defaultApplicationId;
@@ -1561,6 +1607,10 @@ var ApplicationStorageResource = class {
1561
1607
  * Node filesystem `path`, or a Node readable `stream` (with `contentLength`
1562
1608
  * and `checksumSha256`). The content type is inferred from `key` when omitted.
1563
1609
  *
1610
+ * Empty (zero-byte) files are supported for every input kind. The API stores
1611
+ * them during session creation, so no bytes are transferred, `onProgress` is
1612
+ * not called, `waitForCompletion` does not poll, and `object` is always set.
1613
+ *
1564
1614
  * @param input - What and where to upload, plus optional transfer options.
1565
1615
  * @returns The upload session and public object URL (and the finalized object when `waitForCompletion` is set).
1566
1616
  * @throws {@link UploadError} if the byte upload fails.
@@ -1591,19 +1641,42 @@ var ApplicationStorageResource = class {
1591
1641
  checksumSha1: input.checksumSha1,
1592
1642
  checksumMd5: input.checksumMd5
1593
1643
  });
1594
- const { session, upload } = await this.uploadSessions.create(
1595
- applicationId,
1596
- bucketRef,
1597
- {
1598
- key: input.key,
1599
- contentLength: resolved.size,
1600
- checksumSha256: resolved.checksums.sha256,
1601
- contentType: resolved.contentType,
1602
- checksumSha1: resolved.checksums.sha1,
1603
- checksumMd5: resolved.checksums.md5
1604
- },
1605
- { environment }
1606
- );
1644
+ if (input.signal?.aborted) {
1645
+ resolved.release();
1646
+ throw createAbortError();
1647
+ }
1648
+ let created;
1649
+ try {
1650
+ created = await this.uploadSessions.create(
1651
+ applicationId,
1652
+ bucketRef,
1653
+ {
1654
+ key: input.key,
1655
+ contentLength: resolved.size,
1656
+ checksumSha256: resolved.checksums.sha256,
1657
+ contentType: resolved.contentType,
1658
+ checksumSha1: resolved.checksums.sha1,
1659
+ checksumMd5: resolved.checksums.md5
1660
+ },
1661
+ { environment }
1662
+ );
1663
+ } catch (error) {
1664
+ resolved.release();
1665
+ throw error;
1666
+ }
1667
+ const { session, upload } = created;
1668
+ if (upload === null) {
1669
+ resolved.release();
1670
+ const object = created.object;
1671
+ if (!object) {
1672
+ throw new UploadError("The upload session completed without returning the stored object.");
1673
+ }
1674
+ const url = created.publicObjectUrl ?? buildStorageObjectUrl(
1675
+ (await this.buckets.get(applicationId, bucketRef, { environment })).cdnHostname,
1676
+ object.key
1677
+ );
1678
+ return { session, url, object };
1679
+ }
1607
1680
  await runResolvedUpload(
1608
1681
  this.transport,
1609
1682
  upload.url,
@@ -1618,7 +1691,7 @@ var ApplicationStorageResource = class {
1618
1691
  },
1619
1692
  // Forward any required headers the API issued with the session.
1620
1693
  { "Tus-Resumable": "1.0.0", ...upload.headers }
1621
- ).catch(toUploadError);
1694
+ ).catch(toUploadError).finally(resolved.release);
1622
1695
  if (input.waitForCompletion) {
1623
1696
  const options = completionOptions ?? {};
1624
1697
  const completed = await this.waitForCompletion(applicationId, bucketRef, session.id, {
@@ -1697,6 +1770,201 @@ var ApplicationStorageResource = class {
1697
1770
  }
1698
1771
  };
1699
1772
 
1773
+ // src/resources/domains.ts
1774
+ var DomainNotActiveError = class extends GigadriveError {
1775
+ /** The domain as of the last successful check. */
1776
+ domain;
1777
+ /** `timeout` when the wait ran out, `removing` when the domain was removed, otherwise the state that ended it. */
1778
+ reason;
1779
+ constructor(domain, reason) {
1780
+ const detail = domain.error ? `: ${domain.error.message}` : "";
1781
+ super(
1782
+ reason === "timeout" ? `${domain.unicodeHostname} is not active yet (state: ${domain.state})${detail}` : `${domain.unicodeHostname} is ${reason}${detail}`
1783
+ );
1784
+ this.name = "DomainNotActiveError";
1785
+ this.domain = domain;
1786
+ this.reason = reason;
1787
+ }
1788
+ };
1789
+ var SERVING_STATES = /* @__PURE__ */ new Set(["active", "degraded"]);
1790
+ var isTransient = (error) => error instanceof ApiError ? error.status === 429 || error.status >= 500 : error instanceof TypeError;
1791
+ var pollSignal = (ms, signal) => {
1792
+ const controller = new AbortController();
1793
+ const timer = setTimeout(() => controller.abort(new DOMException("The operation timed out.", "TimeoutError")), ms);
1794
+ const onAbort = () => controller.abort(signal?.reason);
1795
+ if (signal?.aborted) onAbort();
1796
+ else signal?.addEventListener("abort", onAbort, { once: true });
1797
+ return {
1798
+ signal: controller.signal,
1799
+ dispose: () => {
1800
+ clearTimeout(timer);
1801
+ signal?.removeEventListener("abort", onAbort);
1802
+ }
1803
+ };
1804
+ };
1805
+ var sleep = (ms, signal) => new Promise((resolve, reject) => {
1806
+ if (signal?.aborted) {
1807
+ reject(signal.reason instanceof Error ? signal.reason : new GigadriveError("Aborted"));
1808
+ return;
1809
+ }
1810
+ const timer = setTimeout(() => {
1811
+ signal?.removeEventListener("abort", onAbort);
1812
+ resolve();
1813
+ }, ms);
1814
+ const onAbort = () => {
1815
+ clearTimeout(timer);
1816
+ reject(signal?.reason instanceof Error ? signal.reason : new GigadriveError("Aborted"));
1817
+ };
1818
+ signal?.addEventListener("abort", onAbort, { once: true });
1819
+ });
1820
+ var ApplicationDomainsResource = class extends BaseResource {
1821
+ /**
1822
+ * List the custom domains of an application.
1823
+ *
1824
+ * @example
1825
+ * ```ts
1826
+ * const { items } = await client.applications.domains.list('app-id');
1827
+ * for (const domain of items) console.log(domain.hostname, domain.state);
1828
+ * ```
1829
+ */
1830
+ async list(applicationId, query) {
1831
+ return this.httpClient.get(`/applications/${applicationId}/domains`, {
1832
+ query
1833
+ });
1834
+ }
1835
+ /**
1836
+ * Attach a hostname to an application.
1837
+ *
1838
+ * @returns The new domain, including the `requiredRecords` to publish at your DNS provider.
1839
+ *
1840
+ * @example
1841
+ * ```ts
1842
+ * const domain = await client.applications.domains.add('app-id', { hostname: 'shop.example.com' });
1843
+ * for (const record of domain.requiredRecords) console.log(record.type, record.host, record.value);
1844
+ * ```
1845
+ */
1846
+ async add(applicationId, data) {
1847
+ return this.httpClient.post(`/applications/${applicationId}/domains`, data);
1848
+ }
1849
+ /** Get one custom domain with its current state. */
1850
+ async get(applicationId, domainId, options) {
1851
+ const path = `/applications/${applicationId}/domains/${domainId}`;
1852
+ return options?.signal ? this.httpClient.get(path, { signal: options.signal }) : this.httpClient.get(path);
1853
+ }
1854
+ /**
1855
+ * Change what a domain serves, or make it the primary domain.
1856
+ *
1857
+ * @example
1858
+ * ```ts
1859
+ * await client.applications.domains.update('app-id', 'domain-id', {
1860
+ * target: { type: 'redirect', to: 'www.example.com' },
1861
+ * });
1862
+ * ```
1863
+ */
1864
+ async update(applicationId, domainId, data) {
1865
+ return this.httpClient.patch(`/applications/${applicationId}/domains/${domainId}`, data);
1866
+ }
1867
+ /** Check the domain now instead of waiting for the next scheduled check. Rate limited. */
1868
+ async refresh(applicationId, domainId) {
1869
+ return this.httpClient.post(`/applications/${applicationId}/domains/${domainId}/refresh`);
1870
+ }
1871
+ /** Stop serving the domain and remove it. */
1872
+ async remove(applicationId, domainId) {
1873
+ return this.httpClient.delete(`/applications/${applicationId}/domains/${domainId}`);
1874
+ }
1875
+ /**
1876
+ * Move a hostname another organization attached to this application. Verify the domain for your
1877
+ * organization first and keep its TXT record published: the claim checks the record again.
1878
+ */
1879
+ async claim(applicationId, hostname) {
1880
+ return this.httpClient.post(`/applications/${applicationId}/domains/claim`, { hostname });
1881
+ }
1882
+ /**
1883
+ * Poll a domain until it serves traffic.
1884
+ *
1885
+ * Rate limits, server errors and network failures do not end the wait; the next poll retries until
1886
+ * the timeout. Aborting the signal or reaching the timeout also cancels a request in flight.
1887
+ *
1888
+ * @returns The domain once it is `active` (or `degraded`, which also serves).
1889
+ * @throws {DomainNotActiveError} When it fails, is suspended or removed, or the timeout runs out.
1890
+ *
1891
+ * @example
1892
+ * ```ts
1893
+ * const domain = await client.applications.domains.add('app-id', { hostname: 'shop.example.com' });
1894
+ * await client.applications.domains.waitUntilActive('app-id', domain.id, {
1895
+ * onState: (current) => console.log(current.state),
1896
+ * });
1897
+ * ```
1898
+ */
1899
+ async waitUntilActive(applicationId, domainId, options = {}) {
1900
+ const { timeoutMs = 10 * 6e4, intervalMs = 5e3, signal, onState } = options;
1901
+ const deadline = Date.now() + timeoutMs;
1902
+ let last;
1903
+ for (; ; ) {
1904
+ const poll = pollSignal(Math.max(deadline - Date.now(), 1), signal);
1905
+ let domain;
1906
+ try {
1907
+ domain = await this.get(applicationId, domainId, { signal: poll.signal });
1908
+ } catch (error) {
1909
+ if (signal?.aborted) throw error;
1910
+ if (last && error instanceof ApiError && error.status === 404) throw new DomainNotActiveError(last, "removing");
1911
+ if (!poll.signal.aborted && !isTransient(error)) throw error;
1912
+ if (Date.now() >= deadline && !last) throw error;
1913
+ } finally {
1914
+ poll.dispose();
1915
+ }
1916
+ if (domain) {
1917
+ if (domain.state !== last?.state) onState?.(domain);
1918
+ last = domain;
1919
+ if (SERVING_STATES.has(domain.state)) return domain;
1920
+ if (domain.state === "failed" || domain.state === "suspended" || domain.state === "removing") {
1921
+ throw new DomainNotActiveError(domain, domain.state);
1922
+ }
1923
+ }
1924
+ const untilDeadline = deadline - Date.now();
1925
+ if (untilDeadline <= 0) {
1926
+ if (last) throw new DomainNotActiveError(last, "timeout");
1927
+ throw new GigadriveError("Timed out before the domain could be read");
1928
+ }
1929
+ await sleep(Math.min(intervalMs, untilDeadline), signal);
1930
+ }
1931
+ }
1932
+ };
1933
+ var OrganizationDomainsResource = class extends BaseResource {
1934
+ /** List the organization's claimed and verified domains. */
1935
+ async list(organizationId, query) {
1936
+ return this.httpClient.get(`/organizations/${organizationId}/domains`, {
1937
+ query
1938
+ });
1939
+ }
1940
+ /**
1941
+ * Claim a domain for verification.
1942
+ *
1943
+ * @returns The claim, including the TXT `record` to publish.
1944
+ *
1945
+ * @example
1946
+ * ```ts
1947
+ * const claim = await client.organizations.domains.add('org-id', 'example.com');
1948
+ * console.log(claim.record.host, claim.record.value);
1949
+ * ```
1950
+ */
1951
+ async add(organizationId, name) {
1952
+ return this.httpClient.post(`/organizations/${organizationId}/domains`, { name });
1953
+ }
1954
+ /** Get one claimed or verified domain. */
1955
+ async get(organizationId, domainId) {
1956
+ return this.httpClient.get(`/organizations/${organizationId}/domains/${domainId}`);
1957
+ }
1958
+ /** Check the TXT record now. Rate limited. */
1959
+ async verify(organizationId, domainId) {
1960
+ return this.httpClient.post(`/organizations/${organizationId}/domains/${domainId}/verify`);
1961
+ }
1962
+ /** Remove a domain. Refused while custom domains still rely on it. */
1963
+ async remove(organizationId, domainId) {
1964
+ return this.httpClient.delete(`/organizations/${organizationId}/domains/${domainId}`);
1965
+ }
1966
+ };
1967
+
1700
1968
  // src/resources/applications.ts
1701
1969
  var ApplicationsResource = class extends BaseResource {
1702
1970
  /**
@@ -1738,11 +2006,22 @@ var ApplicationsResource = class extends BaseResource {
1738
2006
  * ```
1739
2007
  */
1740
2008
  requests;
2009
+ /**
2010
+ * Custom domains attached to the application.
2011
+ *
2012
+ * @example
2013
+ * ```ts
2014
+ * const domain = await client.applications.domains.add('app-id', { hostname: 'shop.example.com' });
2015
+ * await client.applications.domains.waitUntilActive('app-id', domain.id);
2016
+ * ```
2017
+ */
2018
+ domains;
1741
2019
  constructor(httpClient, defaultApplicationId) {
1742
2020
  super(httpClient);
1743
2021
  this.envVars = new ApplicationEnvVarsResource(this.httpClient);
1744
2022
  this.storage = new ApplicationStorageResource(this.httpClient, void 0, defaultApplicationId);
1745
2023
  this.requests = new ApplicationRequestsResource(this.httpClient);
2024
+ this.domains = new ApplicationDomainsResource(this.httpClient);
1746
2025
  }
1747
2026
  /**
1748
2027
  * List applications the authenticated actor has access to.
@@ -2368,12 +2647,23 @@ var OrganizationsResource = class extends BaseResource {
2368
2647
  * ```
2369
2648
  */
2370
2649
  products;
2650
+ /**
2651
+ * Domains the organization verified. A verified domain lets every application attach hostnames
2652
+ * below it without another TXT record.
2653
+ *
2654
+ * @example
2655
+ * ```ts
2656
+ * const claim = await client.organizations.domains.add('org-id', 'example.com');
2657
+ * ```
2658
+ */
2659
+ domains;
2371
2660
  constructor(...args) {
2372
2661
  super(...args);
2373
2662
  this.envVars = new OrganizationEnvVarsResource(this.httpClient);
2374
2663
  this.aiGateway = new OrganizationAiGatewayResource(this.httpClient);
2375
2664
  this.members = new OrganizationMembersResource(this.httpClient);
2376
2665
  this.products = new OrganizationProductsResource(this.httpClient);
2666
+ this.domains = new OrganizationDomainsResource(this.httpClient);
2377
2667
  }
2378
2668
  /**
2379
2669
  * List organizations the authenticated actor has access to.
@@ -2427,6 +2717,783 @@ var OrganizationsResource = class extends BaseResource {
2427
2717
  }
2428
2718
  };
2429
2719
 
2720
+ // src/queues/encoding.ts
2721
+ var DURATION_PATTERN = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/;
2722
+ var UNIT_SECONDS = { ms: 1e-3, s: 1, m: 60, h: 3600, d: 86400 };
2723
+ var durationToSeconds = (value) => {
2724
+ let seconds;
2725
+ if (typeof value === "number") {
2726
+ seconds = value;
2727
+ } else {
2728
+ const match = DURATION_PATTERN.exec(value.trim());
2729
+ if (!match) throw new Error(`Invalid duration "${value}". Use seconds or a string such as 30s, 10m, 12h or 7d.`);
2730
+ seconds = Number(match[1]) * UNIT_SECONDS[match[2]];
2731
+ }
2732
+ if (!Number.isFinite(seconds) || seconds < 0) throw new Error(`Invalid duration "${String(value)}"`);
2733
+ return Math.ceil(seconds);
2734
+ };
2735
+ var textEncoder = new TextEncoder();
2736
+ var textDecoder = new TextDecoder();
2737
+ var utf8Encode = (value) => textEncoder.encode(value);
2738
+ var utf8Decode = (bytes) => textDecoder.decode(bytes);
2739
+ var bytesToBase64 = (bytes) => {
2740
+ let binary = "";
2741
+ for (let index = 0; index < bytes.length; index += 32768) {
2742
+ binary += String.fromCharCode(...bytes.subarray(index, index + 32768));
2743
+ }
2744
+ return btoa(binary);
2745
+ };
2746
+ var base64ToBytes = (value) => {
2747
+ const binary = atob(value);
2748
+ const bytes = new Uint8Array(binary.length);
2749
+ for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
2750
+ return bytes;
2751
+ };
2752
+ var toHex2 = (buffer) => Array.from(new Uint8Array(buffer), (byte) => byte.toString(16).padStart(2, "0")).join("");
2753
+ var toArrayBuffer = (bytes) => {
2754
+ const copy = new ArrayBuffer(bytes.byteLength);
2755
+ new Uint8Array(copy).set(bytes);
2756
+ return copy;
2757
+ };
2758
+
2759
+ // src/queues/errors.ts
2760
+ var RetryLaterError = class extends GigadriveError {
2761
+ /** Seconds until the next delivery. */
2762
+ delaySeconds;
2763
+ constructor(delay2, message = "Message deferred") {
2764
+ super(message);
2765
+ this.name = "RetryLaterError";
2766
+ this.delaySeconds = durationToSeconds(delay2);
2767
+ }
2768
+ };
2769
+ var NonRetryableError = class extends GigadriveError {
2770
+ constructor(message) {
2771
+ super(message);
2772
+ this.name = "NonRetryableError";
2773
+ }
2774
+ };
2775
+
2776
+ // src/queues/signature.ts
2777
+ var QUEUE_SIGNATURE_HEADER = "x-gigadrive-queue-signature";
2778
+ var QUEUE_SIGNATURE_TOLERANCE_MS = 5 * 6e4;
2779
+ var QUEUE_SIGNING_SECRET_ENV = "GIGADRIVE_QUEUE_SIGNING_SECRET";
2780
+ var hmacSha256Hex = async (secret, payload) => {
2781
+ const key = await crypto.subtle.importKey(
2782
+ "raw",
2783
+ toArrayBuffer(utf8Encode(secret)),
2784
+ { name: "HMAC", hash: "SHA-256" },
2785
+ false,
2786
+ ["sign"]
2787
+ );
2788
+ return toHex2(await crypto.subtle.sign("HMAC", key, toArrayBuffer(utf8Encode(payload))));
2789
+ };
2790
+ var signedPayload = async (input, timestamp) => {
2791
+ const body = typeof input.body === "string" ? utf8Encode(input.body) : input.body;
2792
+ const bodyHash = toHex2(await crypto.subtle.digest("SHA-256", toArrayBuffer(body)));
2793
+ return `${String(timestamp)}.${input.queue}.${input.messageId}.${String(input.attempt)}.${bodyHash}`;
2794
+ };
2795
+ var safeEqual = (left, right) => {
2796
+ if (left.length !== right.length) return false;
2797
+ let difference = 0;
2798
+ for (let index = 0; index < left.length; index++) difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
2799
+ return difference === 0;
2800
+ };
2801
+ async function signQueueDelivery(input, timestamp = Date.now()) {
2802
+ return `t=${String(timestamp)},v1=${await hmacSha256Hex(input.secret, await signedPayload(input, timestamp))}`;
2803
+ }
2804
+ async function verifyQueueSignature(header, input, now = Date.now()) {
2805
+ if (!header || !input.secret) return false;
2806
+ const fields = /* @__PURE__ */ new Map();
2807
+ for (const part of header.split(",")) {
2808
+ const separator = part.indexOf("=");
2809
+ if (separator > 0) fields.set(part.slice(0, separator).trim(), part.slice(separator + 1).trim());
2810
+ }
2811
+ const timestamp = Number(fields.get("t"));
2812
+ const signature = fields.get("v1");
2813
+ if (!Number.isSafeInteger(timestamp) || !signature || Math.abs(now - timestamp) > QUEUE_SIGNATURE_TOLERANCE_MS) {
2814
+ return false;
2815
+ }
2816
+ const expected = await hmacSha256Hex(input.secret, await signedPayload(input, timestamp));
2817
+ return safeEqual(signature.toLowerCase(), expected);
2818
+ }
2819
+
2820
+ // src/queues/queue.ts
2821
+ var QUEUE_DELIVERY_HEADERS = {
2822
+ name: "x-gigadrive-queue-name",
2823
+ messageId: "x-gigadrive-queue-message-id",
2824
+ attempt: "x-gigadrive-queue-attempt",
2825
+ createdAt: "x-gigadrive-queue-created-at",
2826
+ expiresAt: "x-gigadrive-queue-expires-at",
2827
+ deadline: "x-gigadrive-queue-deadline",
2828
+ groupKey: "x-gigadrive-queue-group-key",
2829
+ deduplicationKey: "x-gigadrive-queue-deduplication-key",
2830
+ deploymentId: "x-gigadrive-queue-deployment-id",
2831
+ deploymentFallback: "x-gigadrive-queue-deployment-fallback",
2832
+ signature: QUEUE_SIGNATURE_HEADER
2833
+ };
2834
+ var QUEUE_RESPONSE_HEADERS = {
2835
+ /** On a 2xx: deliver again after this many seconds without spending an attempt. */
2836
+ retryAfter: "x-gigadrive-queue-retry-after",
2837
+ /** `dead-letter`: stop retrying now, whatever the status. */
2838
+ action: "x-gigadrive-queue-action",
2839
+ /**
2840
+ * Reason recorded on the message. Read only together with `action:
2841
+ * dead-letter`; for any other failure the platform records `HTTP <status>`
2842
+ * and the first 512 bytes of the response body.
2843
+ */
2844
+ error: "x-gigadrive-queue-error"
2845
+ };
2846
+ var isJsonContentType = (contentType) => /^application\/(?:[\w.+-]+\+)?json\b/i.test(contentType);
2847
+ var defaultQueueCodec = {
2848
+ encode(payload) {
2849
+ if (payload instanceof Uint8Array || payload instanceof ArrayBuffer) {
2850
+ const bytes = payload instanceof Uint8Array ? payload : new Uint8Array(payload);
2851
+ return { body: bytesToBase64(bytes), encoding: "base64", contentType: "application/octet-stream" };
2852
+ }
2853
+ const json = JSON.stringify(payload);
2854
+ if (json === void 0) throw new TypeError("Queue payloads must be JSON-serializable or binary");
2855
+ return { body: json, encoding: "utf8", contentType: "application/json" };
2856
+ },
2857
+ decode(body, contentType) {
2858
+ if (isJsonContentType(contentType)) return body.length === 0 ? null : JSON.parse(utf8Decode(body));
2859
+ if (/^text\//i.test(contentType)) return utf8Decode(body);
2860
+ return body;
2861
+ }
2862
+ };
2863
+ var errorText = (error) => (error instanceof Error ? error.message : String(error)).slice(0, 2e3);
2864
+ var headerText = (text) => text.replace(/[^\x20-\x7e]/g, " ").trim().slice(0, 500);
2865
+ var toDate = (value) => {
2866
+ if (!value) return null;
2867
+ const date = new Date(/^\d+$/.test(value) ? Number(value) : value);
2868
+ return Number.isNaN(date.getTime()) ? null : date;
2869
+ };
2870
+ var BATCH_LIMIT = 100;
2871
+ var ACK_FLUSH_MS = 25;
2872
+ var ACK_RETRY_DELAYS_MS = [200, 1e3];
2873
+ var EMPTY_POLL_MIN_MS = 1e3;
2874
+ var EMPTY_POLL_MAX_MS = 5e3;
2875
+ var sleep2 = (ms, signal) => new Promise((resolve) => {
2876
+ if (signal?.aborted) return resolve();
2877
+ const timer = setTimeout(done, ms);
2878
+ function done() {
2879
+ clearTimeout(timer);
2880
+ signal?.removeEventListener("abort", done);
2881
+ resolve();
2882
+ }
2883
+ signal?.addEventListener("abort", done, { once: true });
2884
+ });
2885
+ var Queue = class {
2886
+ constructor(name, resource, options = {}) {
2887
+ this.name = name;
2888
+ this.resource = resource;
2889
+ this.options = options;
2890
+ this.codec = options.codec ?? defaultQueueCodec;
2891
+ }
2892
+ name;
2893
+ resource;
2894
+ options;
2895
+ codec;
2896
+ get scope() {
2897
+ return { applicationId: this.options.applicationId, environment: this.options.environment };
2898
+ }
2899
+ toMessage(payload, options = {}) {
2900
+ const encoded = this.codec.encode(payload);
2901
+ const at = options.at === void 0 ? void 0 : new Date(options.at);
2902
+ if (at && Number.isNaN(at.getTime())) throw new ConfigurationError("Invalid `at` time for a queue message");
2903
+ return {
2904
+ body: encoded.body,
2905
+ encoding: encoded.encoding,
2906
+ contentType: encoded.contentType,
2907
+ ...options.headers ? { headers: options.headers } : {},
2908
+ ...at ? { deliverAt: at.toISOString() } : {},
2909
+ ...options.delay !== void 0 && !at ? { delaySeconds: durationToSeconds(options.delay) } : {},
2910
+ ...options.groupKey ? { groupKey: options.groupKey } : {},
2911
+ ...options.deduplicationKey ? { deduplicationKey: options.deduplicationKey } : {},
2912
+ ...options.deploymentId ? { deploymentId: options.deploymentId } : {}
2913
+ };
2914
+ }
2915
+ decode(body, contentType) {
2916
+ const decoded = this.codec.decode(body, contentType);
2917
+ return this.options.validate ? this.options.validate(decoded) : decoded;
2918
+ }
2919
+ /**
2920
+ * Sends one message.
2921
+ *
2922
+ * @example
2923
+ * ```ts
2924
+ * await emails.send({ to: 'jane@example.com' });
2925
+ * await emails.send({ to: 'jane@example.com' }, { delay: '10m' });
2926
+ * await emails.send(reminder, { at: new Date('2027-01-01T09:00:00Z'), deduplicationKey: `reminder:${id}` });
2927
+ * ```
2928
+ *
2929
+ * @throws {@link ApiError} when the message is refused, for example with
2930
+ * `code: 'backlog_full'` when your organization's queued storage is full.
2931
+ * Its `status` is 429 when sending again later may succeed and 400 when it
2932
+ * will not, so retry logic that keys on the status stays correct.
2933
+ */
2934
+ async send(payload, options) {
2935
+ const result = await this.resource().send(this.name, this.toMessage(payload, options), {
2936
+ ...this.scope,
2937
+ autoCreate: this.options.autoCreate
2938
+ });
2939
+ if (result.messageId === null) throw new ApiError(result.error, result.retryable ? 429 : 400, result.code);
2940
+ return { messageId: result.messageId, deduplicated: result.deduplicated, deliverAt: new Date(result.deliverAt) };
2941
+ }
2942
+ /**
2943
+ * Sends many messages, 100 per request. Results come back in input order;
2944
+ * a refused message does not fail the rest; its error carries status 429
2945
+ * when it may be sent again later and 400 when it may not. Chunks are split by count only:
2946
+ * a request whose message bodies exceed 4 MiB in total is refused whole.
2947
+ */
2948
+ async sendBatch(messages) {
2949
+ const results = [];
2950
+ for (let index = 0; index < messages.length; index += BATCH_LIMIT) {
2951
+ const chunk = messages.slice(index, index + BATCH_LIMIT);
2952
+ const sent = await this.resource().sendBatch(
2953
+ this.name,
2954
+ chunk.map(({ payload, ...options }) => this.toMessage(payload, options)),
2955
+ { ...this.scope, autoCreate: this.options.autoCreate }
2956
+ );
2957
+ for (const result of sent) {
2958
+ results.push(
2959
+ result.messageId === null ? { messageId: null, error: new ApiError(result.error, result.retryable ? 429 : 400, result.code) } : { messageId: result.messageId, deduplicated: result.deduplicated, deliverAt: new Date(result.deliverAt) }
2960
+ );
2961
+ }
2962
+ }
2963
+ return results;
2964
+ }
2965
+ /** Deletes a message that has not been processed yet, such as a scheduled send. */
2966
+ async cancel(messageId) {
2967
+ await this.resource().deleteMessage(this.name, messageId, this.scope);
2968
+ }
2969
+ /**
2970
+ * Leases messages from a pull queue. Waits up to `wait` (at most 20
2971
+ * seconds) for the first message, then returns what is available.
2972
+ */
2973
+ async receive(options = {}) {
2974
+ const records = await this.resource().receive(
2975
+ this.name,
2976
+ {
2977
+ maxMessages: options.maxMessages ?? 1,
2978
+ ...options.wait === void 0 ? {} : { waitSeconds: Math.min(durationToSeconds(options.wait), 20) },
2979
+ ...options.visibilityTimeout === void 0 ? {} : { visibilityTimeoutSeconds: durationToSeconds(options.visibilityTimeout) }
2980
+ },
2981
+ { ...this.scope, signal: options.signal }
2982
+ );
2983
+ return records.map((record) => this.toReceived(record));
2984
+ }
2985
+ toReceived(record) {
2986
+ const resource = this.resource();
2987
+ const receipt = record.receipt ?? "";
2988
+ const bytes = record.encoding === "base64" ? base64ToBytes(record.body) : utf8Encode(record.body);
2989
+ const nack = (request) => resource.nack(this.name, record.id, { receipt, ...request }, this.scope).then(() => void 0);
2990
+ let payload;
2991
+ let decodeError;
2992
+ try {
2993
+ payload = this.decode(bytes, record.contentType);
2994
+ } catch (error) {
2995
+ decodeError = error;
2996
+ }
2997
+ return {
2998
+ messageId: record.id,
2999
+ queue: this.name,
3000
+ attempt: record.attempts,
3001
+ createdAt: toDate(record.createdAt),
3002
+ groupKey: record.groupKey,
3003
+ deduplicationKey: record.deduplicationKey,
3004
+ deploymentId: record.deploymentId,
3005
+ headers: record.headers,
3006
+ receipt,
3007
+ leaseExpiresAt: toDate(record.leaseExpiresAt),
3008
+ get payload() {
3009
+ if (decodeError !== void 0) throw new NonRetryableError(`Undecodable payload: ${errorText(decodeError)}`);
3010
+ return payload;
3011
+ },
3012
+ ack: () => resource.ack(this.name, record.id, receipt, this.scope).then(() => void 0),
3013
+ retry: (options = {}) => nack({
3014
+ ...options.delay === void 0 ? {} : { delaySeconds: durationToSeconds(options.delay) },
3015
+ ...options.error ? { error: options.error } : {}
3016
+ }),
3017
+ defer: (delay2) => nack({ delaySeconds: durationToSeconds(delay2), countAttempt: false }),
3018
+ deadLetter: (reason) => nack({ deadLetter: true, ...reason ? { error: reason } : {} }),
3019
+ extendLease: (duration) => resource.extend(this.name, record.id, receipt, durationToSeconds(duration), this.scope).then(() => void 0)
3020
+ };
3021
+ }
3022
+ /**
3023
+ * Receives and processes messages until `signal` aborts, or until the queue
3024
+ * is empty with `stopWhenEmpty`. A handler that returns acknowledges the
3025
+ * message; {@link RetryLaterError} defers it, {@link NonRetryableError}
3026
+ * dead-letters it, and any other error retries it with backoff.
3027
+ *
3028
+ * @example
3029
+ * ```ts
3030
+ * const controller = new AbortController();
3031
+ * await jobs.consume(async (job) => processJob(job), { maxMessages: 10, signal: controller.signal });
3032
+ * ```
3033
+ */
3034
+ async consume(handler, options = {}) {
3035
+ const wait = options.wait ?? (options.stopWhenEmpty ? 0 : 20);
3036
+ const waitMs = Math.min(durationToSeconds(wait), 20) * 1e3;
3037
+ const pending = [];
3038
+ let timer;
3039
+ const sendAcks = async (batch) => {
3040
+ const resource = this.resource();
3041
+ for (let attempt = 0; ; attempt += 1) {
3042
+ try {
3043
+ const { results } = await resource.ackBatch(
3044
+ this.name,
3045
+ batch.map((message) => ({ messageId: message.messageId, receipt: message.receipt })),
3046
+ this.scope
3047
+ );
3048
+ return batch.map((_message, index) => {
3049
+ const result = results[index];
3050
+ if (result?.acknowledged || attempt > 0 && result?.code === "message_not_found") return void 0;
3051
+ const code = result?.code ?? "no_result";
3052
+ return new ApiError(
3053
+ `Acknowledging message failed: ${code}`,
3054
+ code === "message_not_found" ? 404 : 409,
3055
+ code
3056
+ );
3057
+ });
3058
+ } catch (error) {
3059
+ if (error instanceof ApiError && error.status === 404 && error.code !== "queue_not_found") {
3060
+ const settled = await Promise.allSettled(
3061
+ batch.map((message) => resource.ack(this.name, message.messageId, message.receipt, this.scope))
3062
+ );
3063
+ return settled.map(
3064
+ (outcome) => outcome.status === "fulfilled" ? void 0 : outcome.reason instanceof Error ? outcome.reason : new Error(errorText(outcome.reason))
3065
+ );
3066
+ }
3067
+ const retryable = !(error instanceof ApiError) || error.status >= 500 || error.status === 429;
3068
+ const delay2 = ACK_RETRY_DELAYS_MS[attempt];
3069
+ if (!retryable || delay2 === void 0) throw error;
3070
+ await sleep2(delay2, void 0);
3071
+ }
3072
+ }
3073
+ };
3074
+ const flush = () => {
3075
+ clearTimeout(timer);
3076
+ timer = void 0;
3077
+ const batch = pending.splice(0, BATCH_LIMIT);
3078
+ if (pending.length > 0) timer = setTimeout(flush, 0);
3079
+ if (batch.length === 0) return;
3080
+ sendAcks(batch.map(({ message }) => message)).then((errors) => batch.forEach(({ settled }, index) => settled(errors[index]))).catch((error) => batch.forEach(({ settled }) => settled(error)));
3081
+ };
3082
+ const acknowledge = (message) => new Promise((resolve, reject) => {
3083
+ pending.push({
3084
+ message,
3085
+ settled: (error) => {
3086
+ if (error === void 0) resolve();
3087
+ else reject(error instanceof Error ? error : new Error(errorText(error)));
3088
+ }
3089
+ });
3090
+ if (pending.length >= BATCH_LIMIT) flush();
3091
+ else timer ??= setTimeout(flush, ACK_FLUSH_MS);
3092
+ });
3093
+ while (!options.signal?.aborted) {
3094
+ let messages;
3095
+ const started = Date.now();
3096
+ try {
3097
+ messages = await this.receive({
3098
+ maxMessages: options.maxMessages ?? 10,
3099
+ wait,
3100
+ visibilityTimeout: options.visibilityTimeout,
3101
+ signal: options.signal
3102
+ });
3103
+ } catch (error) {
3104
+ if (options.signal?.aborted) return;
3105
+ throw error;
3106
+ }
3107
+ if (messages.length === 0) {
3108
+ if (options.stopWhenEmpty) return;
3109
+ const remaining = Math.max(waitMs, EMPTY_POLL_MIN_MS) - (Date.now() - started);
3110
+ if (remaining > 0) await sleep2(Math.min(remaining, EMPTY_POLL_MAX_MS), options.signal);
3111
+ continue;
3112
+ }
3113
+ await Promise.all(
3114
+ messages.map(async (message) => {
3115
+ let outcome;
3116
+ try {
3117
+ await handler(message.payload, message);
3118
+ outcome = acknowledge(message);
3119
+ } catch (error) {
3120
+ outcome = error instanceof RetryLaterError ? message.defer(error.delaySeconds) : error instanceof NonRetryableError ? message.deadLetter(error.message) : message.retry({ error: errorText(error) });
3121
+ }
3122
+ try {
3123
+ await outcome;
3124
+ } catch (settleError) {
3125
+ options.onError?.(settleError);
3126
+ }
3127
+ })
3128
+ );
3129
+ }
3130
+ }
3131
+ /**
3132
+ * Builds a push consumer: a `(request: Request) => Promise<Response>`
3133
+ * function for the queue's consumer path, such as a Next.js route handler.
3134
+ *
3135
+ * It verifies the delivery signature, decodes the payload and calls
3136
+ * `handler`. Returning acknowledges the message. Throw
3137
+ * {@link RetryLaterError} to defer it without spending an attempt,
3138
+ * {@link NonRetryableError} to dead-letter it, or anything else to retry
3139
+ * with backoff.
3140
+ *
3141
+ * @example
3142
+ * ```ts
3143
+ * // app/api/queues/emails/route.ts
3144
+ * export const POST = emails.handler(async (email, { attempt }) => {
3145
+ * await sendEmail(email);
3146
+ * });
3147
+ * ```
3148
+ */
3149
+ handler(handler) {
3150
+ return async (request) => {
3151
+ const header = (name) => request.headers.get(name);
3152
+ const messageId = header(QUEUE_DELIVERY_HEADERS.messageId);
3153
+ const queueName = header(QUEUE_DELIVERY_HEADERS.name);
3154
+ const attempt = Number(header(QUEUE_DELIVERY_HEADERS.attempt) ?? "1");
3155
+ if (!messageId || !queueName) {
3156
+ return Response.json({ error: "Not a queue delivery" }, { status: 400 });
3157
+ }
3158
+ if (queueName !== this.name) {
3159
+ console.error(`[gigadrive] Rejected a delivery for queue "${queueName}" at the handler of "${this.name}"`);
3160
+ return Response.json({ error: `This endpoint consumes queue "${this.name}"` }, { status: 400 });
3161
+ }
3162
+ const body = new Uint8Array(await request.arrayBuffer());
3163
+ if (!this.options.allowUnsigned) {
3164
+ const secret = this.options.signingSecret ?? readSigningSecret();
3165
+ if (!secret) {
3166
+ console.error(
3167
+ `[gigadrive] Rejected a queue delivery: ${QUEUE_SIGNING_SECRET_ENV} is not set. Deployments receive it automatically; set allowUnsigned for local development.`
3168
+ );
3169
+ return Response.json({ error: "Queue signing secret is not configured" }, { status: 500 });
3170
+ }
3171
+ const valid = await verifyQueueSignature(header(QUEUE_SIGNATURE_HEADER), {
3172
+ secret,
3173
+ queue: queueName,
3174
+ messageId,
3175
+ attempt,
3176
+ body
3177
+ });
3178
+ if (!valid) return Response.json({ error: "Invalid queue signature" }, { status: 401 });
3179
+ }
3180
+ const meta = {
3181
+ messageId,
3182
+ queue: queueName,
3183
+ attempt,
3184
+ createdAt: toDate(header(QUEUE_DELIVERY_HEADERS.createdAt)),
3185
+ groupKey: header(QUEUE_DELIVERY_HEADERS.groupKey),
3186
+ deduplicationKey: header(QUEUE_DELIVERY_HEADERS.deduplicationKey),
3187
+ deploymentId: header(QUEUE_DELIVERY_HEADERS.deploymentId),
3188
+ headers: Object.fromEntries(
3189
+ [...request.headers.entries()].filter(([name]) => !name.startsWith("x-gigadrive-queue-"))
3190
+ )
3191
+ };
3192
+ let payload;
3193
+ try {
3194
+ payload = this.decode(body, header("content-type") ?? "application/octet-stream");
3195
+ } catch (error) {
3196
+ return deadLetterResponse(`Undecodable payload: ${errorText(error)}`);
3197
+ }
3198
+ try {
3199
+ await handler(payload, meta);
3200
+ return Response.json({ ok: true });
3201
+ } catch (error) {
3202
+ if (error instanceof RetryLaterError) {
3203
+ return Response.json(
3204
+ { ok: true, retryAfter: error.delaySeconds },
3205
+ { headers: { [QUEUE_RESPONSE_HEADERS.retryAfter]: String(error.delaySeconds) } }
3206
+ );
3207
+ }
3208
+ if (error instanceof NonRetryableError) return deadLetterResponse(error.message);
3209
+ console.error(`[gigadrive] Queue handler for "${queueName}" failed (attempt ${String(attempt)})`, error);
3210
+ return Response.json({ error: errorText(error) }, { status: 500 });
3211
+ }
3212
+ };
3213
+ }
3214
+ /** Creates the queue, or applies `settings` to it. Use it to make a push queue from code. */
3215
+ async ensure(settings = {}) {
3216
+ return this.resource().ensure(this.name, settings, this.scope);
3217
+ }
3218
+ /** The queue's settings and live depth. */
3219
+ async info() {
3220
+ return this.resource().get(this.name, this.scope);
3221
+ }
3222
+ /** Stops deliveries until {@link resume}. Sends are still accepted. */
3223
+ async pause() {
3224
+ await this.resource().pause(this.name, this.scope);
3225
+ }
3226
+ async resume() {
3227
+ await this.resource().resume(this.name, this.scope);
3228
+ }
3229
+ /** Deletes every message, or only the dead letters. */
3230
+ async purge(scope = "all") {
3231
+ return (await this.resource().purge(this.name, scope, this.scope)).purgedMessages;
3232
+ }
3233
+ /** Moves dead letters back for another round of attempts. */
3234
+ async redrive(messageIds) {
3235
+ return (await this.resource().redrive(this.name, messageIds, this.scope)).redrivenMessages;
3236
+ }
3237
+ /**
3238
+ * Creates or updates a cron schedule that sends `payload` into this queue.
3239
+ *
3240
+ * @example
3241
+ * ```ts
3242
+ * await digests.schedule('weekday-digest', { cron: '0 8 * * MON-FRI', timezone: 'Europe/Berlin', payload: { kind: 'digest' } });
3243
+ * ```
3244
+ */
3245
+ async schedule(name, schedule) {
3246
+ const encoded = schedule.payload === void 0 ? void 0 : this.codec.encode(schedule.payload);
3247
+ if (encoded?.encoding === "base64") throw new ConfigurationError("Scheduled payloads must be text or JSON");
3248
+ const input = {
3249
+ cron: schedule.cron,
3250
+ ...schedule.timezone ? { timezone: schedule.timezone } : {},
3251
+ ...encoded ? { body: encoded.body, contentType: encoded.contentType } : {},
3252
+ ...schedule.headers ? { headers: schedule.headers } : {},
3253
+ ...schedule.enabled === void 0 ? {} : { enabled: schedule.enabled }
3254
+ };
3255
+ try {
3256
+ return await this.resource().createSchedule(this.name, name, input, this.scope);
3257
+ } catch (error) {
3258
+ if (error instanceof ApiError && error.code === "schedule_exists") {
3259
+ return this.resource().updateSchedule(this.name, name, input, this.scope);
3260
+ }
3261
+ throw error;
3262
+ }
3263
+ }
3264
+ /** Deletes a schedule. */
3265
+ async unschedule(name) {
3266
+ await this.resource().deleteSchedule(this.name, name, this.scope);
3267
+ }
3268
+ };
3269
+ var deadLetterResponse = (reason) => Response.json(
3270
+ { error: reason },
3271
+ {
3272
+ status: 422,
3273
+ headers: { [QUEUE_RESPONSE_HEADERS.action]: "dead-letter", [QUEUE_RESPONSE_HEADERS.error]: headerText(reason) }
3274
+ }
3275
+ );
3276
+ var readSigningSecret = () => {
3277
+ const env = globalThis.process?.env;
3278
+ return env?.[QUEUE_SIGNING_SECRET_ENV] || void 0;
3279
+ };
3280
+
3281
+ // src/resources/queues.ts
3282
+ var QueuesResource = class extends BaseResource {
3283
+ constructor(httpClient, defaultApplicationId) {
3284
+ super(httpClient);
3285
+ this.defaultApplicationId = defaultApplicationId;
3286
+ }
3287
+ defaultApplicationId;
3288
+ /**
3289
+ * Returns a typed handle for one queue. Nothing is sent until you call a
3290
+ * method on it, and the queue does not need to exist: the first send
3291
+ * creates a pull queue with default settings.
3292
+ *
3293
+ * @typeParam T - The payload type sent and received through this queue.
3294
+ * @param name - Queue name, unique in the environment and case-sensitive.
3295
+ * @param options - Scope, codec and default send options.
3296
+ */
3297
+ queue(name, options = {}) {
3298
+ return new Queue(name, () => this, options);
3299
+ }
3300
+ base(options) {
3301
+ return `/applications/${encodeURIComponent(
3302
+ resolveStorageApplicationId(this.defaultApplicationId, options?.applicationId)
3303
+ )}/queues`;
3304
+ }
3305
+ path(name, options, suffix = "") {
3306
+ return `${this.base(options)}/${encodeURIComponent(name)}${suffix}`;
3307
+ }
3308
+ /** Lists the environment's queues with their live depth. */
3309
+ async list(options) {
3310
+ return this.httpClient.get(this.base(options), { query: { environment: options?.environment } });
3311
+ }
3312
+ /** Fetches one queue with its live depth. */
3313
+ async get(name, options) {
3314
+ return this.httpClient.get(this.path(name, options), { query: { environment: options?.environment } });
3315
+ }
3316
+ /**
3317
+ * Creates a queue. Fails with `queue_exists` when the name is taken; use
3318
+ * {@link ensure} for create-or-update.
3319
+ */
3320
+ async create(name, settings = {}, options) {
3321
+ return this.httpClient.post(this.base(options), { name, environment: options?.environment, ...settings });
3322
+ }
3323
+ /** Creates the queue, or applies `settings` to the existing one. */
3324
+ async ensure(name, settings = {}, options) {
3325
+ return this.httpClient.put(this.path(name, options), { environment: options?.environment, ...settings });
3326
+ }
3327
+ /** Changes a queue's settings. Messages already queued keep flowing. */
3328
+ async update(name, settings, options) {
3329
+ return this.httpClient.patch(this.path(name, options), { environment: options?.environment, ...settings });
3330
+ }
3331
+ /** Deletes a queue, its messages and its schedules. */
3332
+ async delete(name, options) {
3333
+ return this.httpClient.delete(this.path(name, options), { query: { environment: options?.environment } });
3334
+ }
3335
+ /** Stops deliveries. Sends are still accepted and wait until you resume. */
3336
+ async pause(name, options) {
3337
+ return this.httpClient.post(this.path(name, options, "/pause"), { environment: options?.environment });
3338
+ }
3339
+ /** Restarts deliveries after {@link pause}. */
3340
+ async resume(name, options) {
3341
+ return this.httpClient.post(this.path(name, options, "/resume"), { environment: options?.environment });
3342
+ }
3343
+ /** Deletes every message, or only the dead letters. */
3344
+ async purge(name, scope = "all", options) {
3345
+ return this.httpClient.post(this.path(name, options, "/purge"), { environment: options?.environment, scope });
3346
+ }
3347
+ /** Moves dead letters back to the queue with fresh attempts: all of them, or the given ids. */
3348
+ async redrive(name, messageIds, options) {
3349
+ return this.httpClient.post(this.path(name, options, "/redrive"), {
3350
+ environment: options?.environment,
3351
+ ...messageIds ? { messageIds } : {}
3352
+ });
3353
+ }
3354
+ /**
3355
+ * Sends one message.
3356
+ *
3357
+ * @param autoCreate - Create a pull queue with default settings when the name is new. Default `true`.
3358
+ */
3359
+ async send(name, message, options) {
3360
+ return this.httpClient.post(this.path(name, options, "/messages"), {
3361
+ environment: options?.environment,
3362
+ autoCreate: options?.autoCreate,
3363
+ ...message
3364
+ });
3365
+ }
3366
+ /**
3367
+ * Sends up to 100 messages in one request. Results come back in input
3368
+ * order; one rejected message does not fail the others.
3369
+ */
3370
+ async sendBatch(name, messages, options) {
3371
+ const { results } = await this.httpClient.post(
3372
+ this.path(name, options, "/messages"),
3373
+ { environment: options?.environment, autoCreate: options?.autoCreate, messages }
3374
+ );
3375
+ return results;
3376
+ }
3377
+ /** Lists messages in one state without leasing them. Bodies are cut to a preview. */
3378
+ async listMessages(name, query = {}, options) {
3379
+ return this.httpClient.get(this.path(name, options, "/messages"), {
3380
+ query: { environment: options?.environment, ...query }
3381
+ });
3382
+ }
3383
+ /** Fetches one message without leasing it. */
3384
+ async getMessage(name, messageId, options) {
3385
+ return this.httpClient.get(this.path(name, options, `/messages/${encodeURIComponent(messageId)}`), {
3386
+ query: { environment: options?.environment }
3387
+ });
3388
+ }
3389
+ /**
3390
+ * Cancels a message that has not been delivered yet, such as a scheduled
3391
+ * send you no longer want. A message being delivered or dead-lettered
3392
+ * answers 400 `invalid_request`; settle it from its consumer, or purge or
3393
+ * redrive dead letters.
3394
+ */
3395
+ async deleteMessage(name, messageId, options) {
3396
+ return this.httpClient.delete(this.path(name, options, `/messages/${encodeURIComponent(messageId)}`), {
3397
+ query: { environment: options?.environment }
3398
+ });
3399
+ }
3400
+ /**
3401
+ * Leases up to `maxMessages` messages from a pull queue, waiting up to
3402
+ * `waitSeconds` (at most 20) for the first one. Each must be acknowledged
3403
+ * with its receipt before the lease ends, or it is delivered again.
3404
+ */
3405
+ async receive(name, request = {}, options) {
3406
+ const { messages } = await this.httpClient.post(
3407
+ this.path(name, options, "/messages/receive"),
3408
+ { environment: options?.environment, ...request },
3409
+ { signal: options?.signal }
3410
+ );
3411
+ return messages;
3412
+ }
3413
+ /** Acknowledges a received message, deleting it. */
3414
+ async ack(name, messageId, receipt, options) {
3415
+ return this.httpClient.post(this.path(name, options, `/messages/${encodeURIComponent(messageId)}/ack`), {
3416
+ environment: options?.environment,
3417
+ receipt
3418
+ });
3419
+ }
3420
+ /**
3421
+ * Acknowledges up to 100 received messages in one request. Each settles on
3422
+ * its own: `results` reports, in order, which were acknowledged and why any
3423
+ * were not (`message_not_found`, `receipt_mismatch`). A batch counts one
3424
+ * operation per started ten acknowledged messages.
3425
+ */
3426
+ async ackBatch(name, messages, options) {
3427
+ return this.httpClient.post(this.path(name, options, "/messages/ack"), {
3428
+ environment: options?.environment,
3429
+ messages
3430
+ });
3431
+ }
3432
+ /**
3433
+ * Releases a received message: retry with backoff (or after `delaySeconds`),
3434
+ * or dead-letter it now with `deadLetter: true`. `countAttempt: false`
3435
+ * reschedules without spending an attempt.
3436
+ */
3437
+ async nack(name, messageId, request, options) {
3438
+ return this.httpClient.post(this.path(name, options, `/messages/${encodeURIComponent(messageId)}/nack`), {
3439
+ environment: options?.environment,
3440
+ ...request
3441
+ });
3442
+ }
3443
+ /** Extends a received message's lease to `visibilityTimeoutSeconds` from now. */
3444
+ async extend(name, messageId, receipt, visibilityTimeoutSeconds, options) {
3445
+ return this.httpClient.post(this.path(name, options, `/messages/${encodeURIComponent(messageId)}/extend`), {
3446
+ environment: options?.environment,
3447
+ receipt,
3448
+ visibilityTimeoutSeconds
3449
+ });
3450
+ }
3451
+ /** Lists a queue's schedules. */
3452
+ async listSchedules(name, options) {
3453
+ return this.httpClient.get(this.path(name, options, "/schedules"), {
3454
+ query: { environment: options?.environment }
3455
+ });
3456
+ }
3457
+ /**
3458
+ * Creates a schedule that sends a message into the queue on a cron.
3459
+ *
3460
+ * @example
3461
+ * ```ts
3462
+ * await client.queues.createSchedule('emails', 'daily-digest', {
3463
+ * cron: '0 8 * * MON-FRI',
3464
+ * timezone: 'Europe/Berlin',
3465
+ * json: { kind: 'digest' },
3466
+ * });
3467
+ * ```
3468
+ */
3469
+ async createSchedule(name, schedule, input, options) {
3470
+ return this.httpClient.post(this.path(name, options, "/schedules"), {
3471
+ environment: options?.environment,
3472
+ name: schedule,
3473
+ ...input
3474
+ });
3475
+ }
3476
+ /** Changes a schedule. Its next run is recomputed when the cron or time zone changes. */
3477
+ async updateSchedule(name, schedule, input, options) {
3478
+ return this.httpClient.patch(this.path(name, options, `/schedules/${encodeURIComponent(schedule)}`), {
3479
+ environment: options?.environment,
3480
+ ...input
3481
+ });
3482
+ }
3483
+ /** Deletes a schedule. Messages it already sent stay queued. */
3484
+ async deleteSchedule(name, schedule, options) {
3485
+ return this.httpClient.delete(this.path(name, options, `/schedules/${encodeURIComponent(schedule)}`), {
3486
+ query: { environment: options?.environment }
3487
+ });
3488
+ }
3489
+ /** Sends the schedule's message now, outside its cron. */
3490
+ async triggerSchedule(name, schedule, options) {
3491
+ return this.httpClient.post(this.path(name, options, `/schedules/${encodeURIComponent(schedule)}/trigger`), {
3492
+ environment: options?.environment
3493
+ });
3494
+ }
3495
+ };
3496
+
2430
3497
  // src/resources/sticky-sessions.ts
2431
3498
  var StickySessionsResource = class extends BaseResource {
2432
3499
  /**
@@ -2470,6 +3537,12 @@ var GigadriveClient = class {
2470
3537
  stickySessions;
2471
3538
  /** Managed image optimization inspection and cache purge operations. */
2472
3539
  imageOptimization;
3540
+ /**
3541
+ * Network Queues: manage queues and schedules, send, receive and
3542
+ * acknowledge messages. `client.queues.queue<T>(name)` returns a typed
3543
+ * handle bound to one queue.
3544
+ */
3545
+ queues;
2473
3546
  constructor(config = {}) {
2474
3547
  const baseUrl = config.baseUrl ?? readEnv("GIGADRIVE_API_BASE_URL") ?? DEFAULT_BASE_URL2;
2475
3548
  const applicationId = config.applicationId ?? readEnv("GIGADRIVE_APPLICATION_ID");
@@ -2485,6 +3558,7 @@ var GigadriveClient = class {
2485
3558
  this.apiKeys = new ApiKeysResource(httpClient);
2486
3559
  this.stickySessions = new StickySessionsResource(httpClient);
2487
3560
  this.imageOptimization = new ImageOptimizationResource(httpClient);
3561
+ this.queues = new QueuesResource(httpClient, applicationId);
2488
3562
  }
2489
3563
  };
2490
3564
 
@@ -2499,6 +3573,161 @@ async function* paginate(fetchPage) {
2499
3573
  cursor = page.nextCursor;
2500
3574
  } while (cursor);
2501
3575
  }
3576
+
3577
+ // src/queues/default-client.ts
3578
+ var defaultClient;
3579
+ var defaultQueuesResource = () => {
3580
+ defaultClient ??= new GigadriveClient();
3581
+ return defaultClient.queues;
3582
+ };
3583
+ function queue(name, options = {}) {
3584
+ const { client, ...queueOptions } = options;
3585
+ return new Queue(name, () => client?.queues ?? defaultQueuesResource(), queueOptions);
3586
+ }
3587
+
3588
+ // src/queues/workflow.ts
3589
+ var WORKFLOW_CONSUMER_PATH = "/.well-known/workflow/v1/flow";
3590
+ var WORKFLOW_QUEUE_NAME_HEADER = "x-workflow-queue-name";
3591
+ var WORKFLOW_PREFIX = /^__(?:[a-z][a-z0-9]*_)?wkf_workflow_/;
3592
+ var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3593
+ var RESERVED_HEADER = /^(host|content-length|content-type|connection|transfer-encoding|te|upgrade|keep-alive|proxy-.*|authorization|cookie|x-gigadrive-.*|x-nebula-.*|x-substrate-.*|x-vercel-.*|x-forwarded-.*|x-bunny-.*|x-real-ip|true-client-ip|forwarded)$/i;
3594
+ var encodeWorkflowMessage = (message) => JSON.stringify(
3595
+ message,
3596
+ (_key, value) => value instanceof Uint8Array ? { __type: "Uint8Array", data: bytesToBase64(value) } : value
3597
+ );
3598
+ var decodeWorkflowMessage = (text) => JSON.parse(text, (_key, value) => {
3599
+ if (typeof value === "object" && value !== null && value.__type === "Uint8Array" && typeof value.data === "string") {
3600
+ return base64ToBytes(value.data);
3601
+ }
3602
+ return value;
3603
+ });
3604
+ var readEnv2 = (name) => globalThis.process?.env?.[name] || void 0;
3605
+ var deduplicationKeyFor = async (idempotencyKey) => idempotencyKey.length <= 256 ? idempotencyKey : `wkf:sha256:${toHex2(await crypto.subtle.digest("SHA-256", toArrayBuffer(utf8Encode(idempotencyKey))))}`;
3606
+ function createWorkflowQueue(options = {}) {
3607
+ const resource = () => options.client?.queues ?? defaultQueuesResource();
3608
+ const scope = { applicationId: options.applicationId, environment: options.environment };
3609
+ const ensured = /* @__PURE__ */ new Map();
3610
+ const physicalQueue = async (queueName) => {
3611
+ const prefix = WORKFLOW_PREFIX.exec(queueName)?.[0];
3612
+ if (!prefix) throw new Error(`"${queueName}" is not a Workflow SDK queue name`);
3613
+ let ready = ensured.get(prefix);
3614
+ if (!ready) {
3615
+ const consumerPath = options.consumerPath ?? WORKFLOW_CONSUMER_PATH;
3616
+ ready = options.queueSettings ? resource().ensure(prefix, { ...options.queueSettings, consumerPath }, scope) : (
3617
+ // Create-only: a queue that exists keeps the settings someone gave it in the console.
3618
+ resource().create(prefix, { maxAttempts: 100, visibilityTimeoutSeconds: 900, deadLetter: true, consumerPath }, scope).catch((error) => {
3619
+ if (error instanceof ApiError && error.code === "queue_exists") return void 0;
3620
+ throw error;
3621
+ })
3622
+ );
3623
+ ensured.set(prefix, ready);
3624
+ ready.catch(() => ensured.delete(prefix));
3625
+ }
3626
+ await ready;
3627
+ return prefix;
3628
+ };
3629
+ const toMessage = async (queueName, message, opts = {}) => {
3630
+ const headers = Object.fromEntries(
3631
+ Object.entries(opts.headers ?? {}).filter(([name]) => !RESERVED_HEADER.test(name))
3632
+ );
3633
+ headers[WORKFLOW_QUEUE_NAME_HEADER] = queueName;
3634
+ const pin = opts.deploymentId ?? options.deploymentId ?? readEnv2("GIGADRIVE_DEPLOYMENT_ID");
3635
+ return {
3636
+ body: encodeWorkflowMessage(message),
3637
+ contentType: "application/json",
3638
+ headers,
3639
+ ...opts.delaySeconds && opts.delaySeconds > 0 ? { delaySeconds: Math.ceil(opts.delaySeconds) } : {},
3640
+ ...opts.idempotencyKey ? { deduplicationKey: await deduplicationKeyFor(opts.idempotencyKey) } : {},
3641
+ ...pin && UUID.test(pin) ? { deploymentId: pin } : {}
3642
+ };
3643
+ };
3644
+ return {
3645
+ getDeploymentId: () => Promise.resolve(options.deploymentId ?? readEnv2("GIGADRIVE_DEPLOYMENT_ID") ?? "local"),
3646
+ async queue(queueName, message, opts) {
3647
+ const physical = await physicalQueue(queueName);
3648
+ const result = await resource().send(physical, await toMessage(queueName, message, opts), {
3649
+ ...scope,
3650
+ autoCreate: false
3651
+ });
3652
+ if (result.messageId === null) throw new Error(`Workflow message was refused: ${result.error}`);
3653
+ return { messageId: result.messageId };
3654
+ },
3655
+ async queueBatch(queueName, messages) {
3656
+ const physical = await physicalQueue(queueName);
3657
+ const results = [];
3658
+ for (let index = 0; index < messages.length; index += 100) {
3659
+ const chunk = messages.slice(index, index + 100);
3660
+ const sent = await resource().sendBatch(
3661
+ physical,
3662
+ await Promise.all(chunk.map(({ message, opts }) => toMessage(queueName, message, opts))),
3663
+ { ...scope, autoCreate: false }
3664
+ );
3665
+ for (const result of sent) {
3666
+ results.push(
3667
+ result.messageId === null ? { messageId: null, error: result.error, retryable: result.retryable } : { messageId: result.messageId }
3668
+ );
3669
+ }
3670
+ }
3671
+ return results;
3672
+ },
3673
+ createQueueHandler(queueNamePrefix, handler) {
3674
+ return async (request) => {
3675
+ const messageId = request.headers.get(QUEUE_DELIVERY_HEADERS.messageId);
3676
+ const physicalName = request.headers.get(QUEUE_DELIVERY_HEADERS.name);
3677
+ const attempt = Number(request.headers.get(QUEUE_DELIVERY_HEADERS.attempt) ?? "1");
3678
+ const queueName = request.headers.get(WORKFLOW_QUEUE_NAME_HEADER);
3679
+ if (!messageId || !physicalName || !queueName) {
3680
+ return Response.json({ error: "Missing required headers" }, { status: 400 });
3681
+ }
3682
+ const body = new Uint8Array(await request.arrayBuffer());
3683
+ if (!options.allowUnsigned) {
3684
+ const secret = options.signingSecret ?? readSigningSecret();
3685
+ const valid = secret !== void 0 && await verifyQueueSignature(request.headers.get(QUEUE_SIGNATURE_HEADER), {
3686
+ secret,
3687
+ queue: physicalName,
3688
+ messageId,
3689
+ attempt,
3690
+ body
3691
+ });
3692
+ if (!valid) return Response.json({ error: "Invalid queue signature" }, { status: 401 });
3693
+ }
3694
+ if (physicalName !== queueNamePrefix || !queueName.startsWith(queueNamePrefix)) {
3695
+ return Response.json({ error: "Unhandled queue" }, { status: 400 });
3696
+ }
3697
+ let message;
3698
+ try {
3699
+ message = decodeWorkflowMessage(utf8Decode(body));
3700
+ } catch {
3701
+ return Response.json(
3702
+ { error: "Malformed workflow message" },
3703
+ { status: 422, headers: { [QUEUE_RESPONSE_HEADERS.action]: "dead-letter" } }
3704
+ );
3705
+ }
3706
+ try {
3707
+ const result = await handler(message, {
3708
+ attempt,
3709
+ queueName,
3710
+ messageId,
3711
+ requestId: request.headers.get("x-request-id") ?? void 0
3712
+ });
3713
+ if (typeof message === "object" && message !== null && message.invoke === true) {
3714
+ return Response.json({ result });
3715
+ }
3716
+ const timeoutSeconds = typeof result === "object" && result !== null ? result.timeoutSeconds : void 0;
3717
+ if (typeof timeoutSeconds === "number" && Number.isFinite(timeoutSeconds) && timeoutSeconds >= 0) {
3718
+ return Response.json(
3719
+ { timeoutSeconds },
3720
+ { headers: { [QUEUE_RESPONSE_HEADERS.retryAfter]: String(Math.ceil(timeoutSeconds)) } }
3721
+ );
3722
+ }
3723
+ return Response.json({ ok: true });
3724
+ } catch (error) {
3725
+ return Response.json(String(error), { status: 500 });
3726
+ }
3727
+ };
3728
+ }
3729
+ };
3730
+ }
2502
3731
  // Annotate the CommonJS export names for ESM import in node:
2503
3732
  0 && (module.exports = {
2504
3733
  AiGatewayAudioResource,
@@ -2509,6 +3738,7 @@ async function* paginate(fetchPage) {
2509
3738
  AiGatewayVideosResource,
2510
3739
  ApiError,
2511
3740
  ApiKeysResource,
3741
+ ApplicationDomainsResource,
2512
3742
  ApplicationEnvVarsResource,
2513
3743
  ApplicationRequestsResource,
2514
3744
  ApplicationStorageResource,
@@ -2516,14 +3746,25 @@ async function* paginate(fetchPage) {
2516
3746
  AuthenticationError,
2517
3747
  ConfigurationError,
2518
3748
  DeploymentsResource,
3749
+ DomainNotActiveError,
2519
3750
  GigadriveClient,
2520
3751
  GigadriveError,
2521
3752
  ImageOptimizationResource,
3753
+ NonRetryableError,
2522
3754
  OrganizationAiGatewayResource,
3755
+ OrganizationDomainsResource,
2523
3756
  OrganizationEnvVarsResource,
2524
3757
  OrganizationMembersResource,
2525
3758
  OrganizationProductsResource,
2526
3759
  OrganizationsResource,
3760
+ QUEUE_DELIVERY_HEADERS,
3761
+ QUEUE_RESPONSE_HEADERS,
3762
+ QUEUE_SIGNATURE_HEADER,
3763
+ QUEUE_SIGNATURE_TOLERANCE_MS,
3764
+ QUEUE_SIGNING_SECRET_ENV,
3765
+ Queue,
3766
+ QueuesResource,
3767
+ RetryLaterError,
2527
3768
  StickySessionsResource,
2528
3769
  StorageBucketsResource,
2529
3770
  StorageObjectsResource,
@@ -2531,8 +3772,16 @@ async function* paginate(fetchPage) {
2531
3772
  StorageUploadSessionsResource,
2532
3773
  UploadError,
2533
3774
  UploadSessionExpiredError,
3775
+ WORKFLOW_CONSUMER_PATH,
3776
+ WORKFLOW_QUEUE_NAME_HEADER,
2534
3777
  createManagedImageUrl,
3778
+ createWorkflowQueue,
3779
+ defaultQueueCodec,
3780
+ durationToSeconds,
2535
3781
  paginate,
2536
- parseSSEStream
3782
+ parseSSEStream,
3783
+ queue,
3784
+ signQueueDelivery,
3785
+ verifyQueueSignature
2537
3786
  });
2538
3787
  //# sourceMappingURL=index.js.map