@xylex-group/athena 3.1.0 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +17 -1
  2. package/dist/admin.cjs +55 -1
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.d.cts +32 -8
  5. package/dist/admin.d.ts +32 -8
  6. package/dist/admin.js +54 -2
  7. package/dist/admin.js.map +1 -1
  8. package/dist/athena-auth-url-C1FbVmN6.d.cts +200 -0
  9. package/dist/athena-auth-url-C1FbVmN6.d.ts +200 -0
  10. package/dist/{athena-request-headers-C7Jy-c_D.d.ts → athena-request-headers-BnFN2mbd.d.cts} +49 -201
  11. package/dist/{athena-request-headers-DujFFyMU.d.cts → athena-request-headers-Dwdkq2WR.d.ts} +49 -201
  12. package/dist/billing.cjs +1 -1
  13. package/dist/billing.cjs.map +1 -1
  14. package/dist/billing.js +1 -1
  15. package/dist/billing.js.map +1 -1
  16. package/dist/browser.cjs +3735 -248
  17. package/dist/browser.cjs.map +1 -1
  18. package/dist/browser.d.cts +11 -10
  19. package/dist/browser.d.ts +11 -10
  20. package/dist/browser.js +3726 -249
  21. package/dist/browser.js.map +1 -1
  22. package/dist/cli/index.cjs +3232 -190
  23. package/dist/cli/index.cjs.map +1 -1
  24. package/dist/cli/index.d.cts +4 -4
  25. package/dist/cli/index.d.ts +4 -4
  26. package/dist/cli/index.js +3232 -190
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/cloudflare.cjs +12914 -0
  29. package/dist/cloudflare.cjs.map +1 -0
  30. package/dist/cloudflare.d.cts +368 -0
  31. package/dist/cloudflare.d.ts +368 -0
  32. package/dist/cloudflare.js +12885 -0
  33. package/dist/cloudflare.js.map +1 -0
  34. package/dist/cookies.cjs +4 -3
  35. package/dist/cookies.cjs.map +1 -1
  36. package/dist/cookies.js +4 -3
  37. package/dist/cookies.js.map +1 -1
  38. package/dist/env.cjs +130 -0
  39. package/dist/env.cjs.map +1 -0
  40. package/dist/env.d.cts +70 -0
  41. package/dist/env.d.ts +70 -0
  42. package/dist/env.js +122 -0
  43. package/dist/env.js.map +1 -0
  44. package/dist/index.cjs +3749 -241
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.d.cts +11 -10
  47. package/dist/index.d.ts +11 -10
  48. package/dist/index.js +3739 -242
  49. package/dist/index.js.map +1 -1
  50. package/dist/{model-form-BhWWsA-7.d.cts → model-form-D0ykVVOs.d.cts} +26 -4
  51. package/dist/{model-form-BbdzJ9Uh.d.ts → model-form-U8NVtfSA.d.ts} +26 -4
  52. package/dist/{module-xFd7_Igv.d.cts → module-CMWlJ1z3.d.cts} +5 -5
  53. package/dist/{module-DKkJKOuJ.d.ts → module-CZ-wPcf2.d.ts} +5 -5
  54. package/dist/next/client.cjs +3212 -196
  55. package/dist/next/client.cjs.map +1 -1
  56. package/dist/next/client.d.cts +6 -5
  57. package/dist/next/client.d.ts +6 -5
  58. package/dist/next/client.js +3212 -196
  59. package/dist/next/client.js.map +1 -1
  60. package/dist/next/server.cjs +4461 -781
  61. package/dist/next/server.cjs.map +1 -1
  62. package/dist/next/server.d.cts +139 -13
  63. package/dist/next/server.d.ts +139 -13
  64. package/dist/next/server.js +4451 -782
  65. package/dist/next/server.js.map +1 -1
  66. package/dist/{pipeline-DuKzYGia.d.cts → pipeline-BCpb4BX1.d.cts} +1 -1
  67. package/dist/{pipeline-wer2G9xW.d.ts → pipeline-CgmXwMeX.d.ts} +1 -1
  68. package/dist/{proxy-request-headers-m4D2Tduy.d.ts → proxy-request-headers-CttlcuRb.d.ts} +1 -1
  69. package/dist/{proxy-request-headers-DGxdoyA0.d.cts → proxy-request-headers-pIBSn1Fw.d.cts} +1 -1
  70. package/dist/react.cjs +290 -31
  71. package/dist/react.cjs.map +1 -1
  72. package/dist/react.d.cts +62 -12
  73. package/dist/react.d.ts +62 -12
  74. package/dist/react.js +290 -32
  75. package/dist/react.js.map +1 -1
  76. package/dist/schema-handlers-CvWqF-dW.d.ts +138 -0
  77. package/dist/schema-handlers-Dr8h9Jg-.d.cts +138 -0
  78. package/dist/social-providers.cjs +1 -1
  79. package/dist/social-providers.cjs.map +1 -1
  80. package/dist/social-providers.d.cts +1 -1
  81. package/dist/social-providers.d.ts +1 -1
  82. package/dist/social-providers.js +1 -1
  83. package/dist/social-providers.js.map +1 -1
  84. package/dist/{types-Bltx6iL6.d.ts → types-B2RZPivM.d.cts} +8 -1
  85. package/dist/{types-Bltx6iL6.d.cts → types-B2RZPivM.d.ts} +8 -1
  86. package/dist/{types-1ztXDgPa.d.cts → types-BKklrX4J.d.ts} +14 -2
  87. package/dist/{types-AOY-GLu8.d.cts → types-BVKpQmfY.d.cts} +11 -0
  88. package/dist/{types-AOY-GLu8.d.ts → types-BVKpQmfY.d.ts} +11 -0
  89. package/dist/{types-CgCv5o6R.d.cts → types-D5dj1v5Z.d.cts} +1 -1
  90. package/dist/{types-CccOiXPo.d.ts → types-DqBFwfhn.d.cts} +14 -2
  91. package/dist/{types-B75PdABb.d.ts → types-S-bTMPiM.d.ts} +1 -1
  92. package/dist/utils.cjs +30 -0
  93. package/dist/utils.cjs.map +1 -1
  94. package/dist/utils.d.cts +4 -3
  95. package/dist/utils.d.ts +4 -3
  96. package/dist/utils.js +30 -1
  97. package/dist/utils.js.map +1 -1
  98. package/dist/{v3-client-CWfZHcKL.d.cts → v3-client-DP-qg82X.d.cts} +323 -5
  99. package/dist/{v3-client-DZp2NEhK.d.ts → v3-client-OAai_JNs.d.ts} +323 -5
  100. package/package.json +25 -4
package/dist/browser.cjs CHANGED
@@ -1840,6 +1840,8 @@ function buildUpdateDebugSql(payload) {
1840
1840
  sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
1841
1841
  }
1842
1842
  const pagination = resolvePagination({
1843
+ limit: payload.limit,
1844
+ offset: payload.offset,
1843
1845
  currentPage: payload.current_page,
1844
1846
  pageSize: payload.page_size
1845
1847
  });
@@ -1862,6 +1864,8 @@ function buildDeleteDebugSql(payload) {
1862
1864
  sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
1863
1865
  }
1864
1866
  const pagination = resolvePagination({
1867
+ limit: payload.limit,
1868
+ offset: payload.offset,
1865
1869
  currentPage: payload.current_page,
1866
1870
  pageSize: payload.page_size
1867
1871
  });
@@ -2005,7 +2009,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
2005
2009
 
2006
2010
  // package.json
2007
2011
  var package_default = {
2008
- version: "3.1.0"
2012
+ version: "3.5.1"
2009
2013
  };
2010
2014
 
2011
2015
  // src/sdk-version.ts
@@ -2302,13 +2306,14 @@ var LEGACY_COOKIE_PREFIX = "better-auth";
2302
2306
  var DEFAULT_SESSION_MAX_AGE = 7 * 24 * 60 * 60;
2303
2307
  var DEFAULT_CACHE_MAX_AGE = 60 * 5;
2304
2308
  function isProductionRuntime() {
2305
- return typeof process !== "undefined" && process.env?.NODE_ENV === "production";
2309
+ return globalThis.process?.env?.NODE_ENV === "production";
2306
2310
  }
2307
2311
  function getEnvironmentSecret() {
2308
- if (typeof process === "undefined") {
2312
+ const env = globalThis.process?.env;
2313
+ if (!env) {
2309
2314
  return void 0;
2310
2315
  }
2311
- return process.env?.ATHENA_AUTH_SECRET || process.env?.BETTER_AUTH_SECRET || process.env?.AUTH_SECRET;
2316
+ return env.ATHENA_AUTH_SECRET || env.BETTER_AUTH_SECRET || env.AUTH_SECRET;
2312
2317
  }
2313
2318
  function isDynamicBaseURLConfig(baseURL) {
2314
2319
  return typeof baseURL === "object" && baseURL !== null && "allowedHosts" in baseURL && Array.isArray(baseURL.allowedHosts);
@@ -4765,6 +4770,14 @@ function createAuthModule(config = {}, runtimeOptions = {}) {
4765
4770
  changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
4766
4771
  deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
4767
4772
  changePassword: (input, options) => postGeneric("/change-password", input, options),
4773
+ // Better Auth UI flat method aliases (also nested under session/account/social/user).
4774
+ listSessions: (input, options) => getGeneric("/list-sessions", input, options),
4775
+ revokeSession: sessionRevokeBinding,
4776
+ revokeOtherSessions,
4777
+ listAccounts: (input, options) => getGeneric("/list-accounts", input, options),
4778
+ unlinkAccount: (input, options) => postGeneric("/unlink-account", input, options),
4779
+ linkSocial: (input, options) => postGeneric("/link-social", input, options),
4780
+ updateUser: (input, options) => postGeneric("/update-user", input, options),
4768
4781
  user: {
4769
4782
  update: (input, options) => postGeneric("/update-user", input, options),
4770
4783
  delete: (input, options) => postGeneric("/delete-user", input, options),
@@ -5870,9 +5883,9 @@ function readHeadersField(value) {
5870
5883
  const headers = value.headers;
5871
5884
  if (!isRecord8(headers)) return {};
5872
5885
  const result = {};
5873
- for (const [key, headerValue2] of Object.entries(headers)) {
5874
- if (typeof headerValue2 === "string") {
5875
- result[key] = headerValue2;
5886
+ for (const [key, headerValue3] of Object.entries(headers)) {
5887
+ if (typeof headerValue3 === "string") {
5888
+ result[key] = headerValue3;
5876
5889
  }
5877
5890
  }
5878
5891
  return result;
@@ -9550,6 +9563,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, beha
9550
9563
  strip_nulls: mergedOptions?.stripNulls ?? true
9551
9564
  };
9552
9565
  if (executionState.order) payload.sort_by = executionState.order;
9566
+ if (executionState.limit !== void 0) payload.limit = executionState.limit;
9567
+ if (executionState.offset !== void 0) payload.offset = executionState.offset;
9553
9568
  if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
9554
9569
  if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
9555
9570
  if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
@@ -9604,6 +9619,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, beha
9604
9619
  conditions: filters
9605
9620
  };
9606
9621
  if (executionState.order) payload.sort_by = executionState.order;
9622
+ if (executionState.limit !== void 0) payload.limit = executionState.limit;
9623
+ if (executionState.offset !== void 0) payload.offset = executionState.offset;
9607
9624
  if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
9608
9625
  if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
9609
9626
  if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
@@ -9655,7 +9672,11 @@ function createQueryBuilder(client, formatGatewayResult, behavior, tracer) {
9655
9672
  if (!normalizedQuery) {
9656
9673
  throw new Error("query requires a non-empty string");
9657
9674
  }
9658
- const payload = { query: normalizedQuery };
9675
+ const params = options?.params;
9676
+ const payload = {
9677
+ query: normalizedQuery,
9678
+ ...Array.isArray(params) ? { params } : {}
9679
+ };
9659
9680
  const callsite = captureTraceCallsite(tracer);
9660
9681
  return executeRead(
9661
9682
  behavior,
@@ -9704,7 +9725,7 @@ function normalizeAuthClientConfig(auth, defaultBaseUrl) {
9704
9725
  }
9705
9726
  function createInternalClientCore(config) {
9706
9727
  const normalizedAuthConfig = normalizeAuthClientConfig(config.auth, config.authUrl);
9707
- const gatewayTransport = createAthenaGatewayClient({
9728
+ const gatewayTransport = config.gatewayTransport ?? createAthenaGatewayClient({
9708
9729
  baseUrl: config.baseUrl,
9709
9730
  apiKey: config.apiKey,
9710
9731
  client: config.client ?? void 0,
@@ -9859,211 +9880,2849 @@ function createInternalClientView(core, resolveContext) {
9859
9880
  };
9860
9881
  }
9861
9882
 
9862
- // src/billing/module.ts
9863
- var SDK_NAME5 = "xylex-group/athena-billing";
9864
- var SDK_HEADER_VALUE4 = buildSdkHeaderValue(SDK_NAME5);
9865
- var AthenaBillingError = class extends Error {
9866
- status;
9867
- endpoint;
9868
- method;
9869
- body;
9870
- constructor(input) {
9871
- super(input.message);
9872
- this.name = "AthenaBillingError";
9873
- this.status = input.status;
9874
- this.endpoint = input.endpoint;
9875
- this.method = input.method;
9876
- this.body = input.body;
9877
- }
9878
- };
9879
- var billingSdkManifest = {
9880
- namespace: "billing",
9881
- envelopeKind: "athena",
9882
- methods: [
9883
- { name: "getCapabilities", method: "GET", path: "/billing/v1/capabilities" },
9884
- { name: "createCheckout", method: "POST", path: "/billing/v1/checkouts" },
9885
- { name: "listProducts", method: "GET", path: "/billing/v1/products" },
9886
- { name: "listPrices", method: "GET", path: "/billing/v1/prices" },
9887
- { name: "listCustomers", method: "GET", path: "/billing/v1/customers" },
9888
- { name: "createCustomer", method: "POST", path: "/billing/v1/customers" },
9889
- { name: "getCustomer", method: "GET", path: "/billing/v1/customers/{id}" },
9890
- { name: "updateCustomer", method: "PATCH", path: "/billing/v1/customers/{id}" },
9891
- { name: "deleteCustomer", method: "DELETE", path: "/billing/v1/customers/{id}" },
9892
- { name: "listPayments", method: "GET", path: "/billing/v1/payments" },
9893
- { name: "createPayment", method: "POST", path: "/billing/v1/payments" },
9894
- { name: "getPayment", method: "GET", path: "/billing/v1/payments/{id}" },
9895
- { name: "cancelPayment", method: "POST", path: "/billing/v1/payments/{id}/cancel" },
9896
- { name: "listPaymentLinks", method: "GET", path: "/billing/v1/payment-links" },
9897
- { name: "createPaymentLink", method: "POST", path: "/billing/v1/payment-links" },
9898
- { name: "getPaymentLink", method: "GET", path: "/billing/v1/payment-links/{id}" },
9899
- { name: "updatePaymentLink", method: "PATCH", path: "/billing/v1/payment-links/{id}" },
9900
- { name: "deletePaymentLink", method: "DELETE", path: "/billing/v1/payment-links/{id}" },
9901
- { name: "listRefunds", method: "GET", path: "/billing/v1/refunds" },
9902
- { name: "createRefund", method: "POST", path: "/billing/v1/refunds" },
9903
- { name: "getRefund", method: "GET", path: "/billing/v1/refunds/{id}" },
9904
- { name: "cancelRefund", method: "POST", path: "/billing/v1/refunds/{id}/cancel" },
9905
- { name: "listSubscriptions", method: "GET", path: "/billing/v1/subscriptions" },
9906
- { name: "createSubscription", method: "POST", path: "/billing/v1/subscriptions" },
9907
- { name: "getSubscription", method: "GET", path: "/billing/v1/subscriptions/{id}" },
9908
- { name: "updateSubscription", method: "PATCH", path: "/billing/v1/subscriptions/{id}" },
9909
- { name: "cancelSubscription", method: "POST", path: "/billing/v1/subscriptions/{id}/cancel" },
9910
- { name: "listInvoices", method: "GET", path: "/billing/v1/invoices" },
9911
- { name: "getInvoice", method: "GET", path: "/billing/v1/invoices/{id}" },
9912
- { name: "listWebhooks", method: "GET", path: "/billing/v1/webhooks" },
9913
- { name: "createWebhook", method: "POST", path: "/billing/v1/webhooks" },
9914
- { name: "getWebhook", method: "GET", path: "/billing/v1/webhooks/{id}" },
9915
- { name: "updateWebhook", method: "PATCH", path: "/billing/v1/webhooks/{id}" },
9916
- { name: "deleteWebhook", method: "DELETE", path: "/billing/v1/webhooks/{id}" },
9917
- { name: "testWebhook", method: "POST", path: "/billing/v1/webhooks/{id}/test" },
9918
- {
9919
- name: "listConnections",
9920
- method: "GET",
9921
- path: "/admin/billing/clients/{client_name}/connections"
9922
- },
9923
- {
9924
- name: "createConnection",
9925
- method: "POST",
9926
- path: "/admin/billing/clients/{client_name}/connections"
9927
- },
9928
- {
9929
- name: "getConnection",
9930
- method: "GET",
9931
- path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
9932
- },
9933
- {
9934
- name: "updateConnection",
9935
- method: "PATCH",
9936
- path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
9937
- },
9938
- {
9939
- name: "deleteConnection",
9940
- method: "DELETE",
9941
- path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
9942
- },
9943
- {
9944
- name: "reconcileDocument",
9945
- method: "POST",
9946
- path: "/admin/billing/clients/{client_name}/connections/{connection_id}/reconcile"
9947
- },
9948
- {
9949
- name: "listWebhookEvents",
9950
- method: "GET",
9951
- path: "/admin/billing/clients/{client_name}/webhook-events"
9883
+ // src/cloudflare/types.ts
9884
+ var CLOUDFLARE_EDGE_BASE_URL = "https://athena.local/cloudflare-edge";
9885
+ var CLOUDFLARE_EDGE_API_KEY = "cloudflare-edge-local";
9886
+
9887
+ // src/cloudflare/capabilities.ts
9888
+ function createGatewayCapabilities(options) {
9889
+ const storageConfigured = options?.storageConfigured ?? true;
9890
+ return {
9891
+ mode: "gateway",
9892
+ db: {
9893
+ engine: options?.engine ?? "postgresql",
9894
+ local: false,
9895
+ layers: {
9896
+ query: true,
9897
+ flatCrud: true,
9898
+ findManyAst: true,
9899
+ rpc: true,
9900
+ relations: true
9901
+ }
9952
9902
  },
9953
- {
9954
- name: "provisionWebhookSinks",
9955
- method: "POST",
9956
- path: "/admin/billing/clients/{client_name}/webhook-sinks/provision"
9903
+ storage: {
9904
+ local: false,
9905
+ objects: storageConfigured,
9906
+ catalogs: storageConfigured ? options?.storageCatalogs ?? true : false,
9907
+ backups: storageConfigured ? options?.storageBackups ?? true : false
9957
9908
  },
9958
- { name: "listGrants", method: "GET", path: "/admin/billing/grants" },
9959
- { name: "listProviders", method: "GET", path: "/admin/billing/providers" },
9960
- {
9961
- name: "listSinkHelpers",
9962
- method: "GET",
9963
- path: "/admin/webhook-sinks/helpers/billing"
9909
+ auth: {
9910
+ remote: options?.authRemote ?? true
9911
+ }
9912
+ };
9913
+ }
9914
+ function createCloudflareEdgeCapabilities(options) {
9915
+ const hasObjects = options.hasR2 || Boolean(options.hasRemoteStorage);
9916
+ return {
9917
+ mode: "cloudflare-edge",
9918
+ db: {
9919
+ engine: "cloudflare-d1",
9920
+ local: true,
9921
+ layers: {
9922
+ query: true,
9923
+ flatCrud: true,
9924
+ findManyAst: options.findManyAst ?? false,
9925
+ rpc: false,
9926
+ relations: false
9927
+ }
9964
9928
  },
9965
- {
9966
- name: "ingestProviderWebhook",
9967
- method: "POST",
9968
- path: "/billing/providers/{provider}/clients/{client_name}/connections/{connection_id}/webhook"
9929
+ storage: {
9930
+ // Local objects only when an R2 binding is present.
9931
+ local: options.hasR2,
9932
+ // Remote hybrid root can still expose storage.objects via the HTTP API.
9933
+ objects: hasObjects,
9934
+ catalogs: false,
9935
+ backups: false
9969
9936
  },
9970
- { name: "getDebugBilling", method: "GET", path: "/debug/billing" }
9971
- ]
9972
- };
9973
- function withPathParam2(path, name, value) {
9974
- return path.replace(`{${name}}`, encodeURIComponent(value));
9975
- }
9976
- function appendQuery3(path, query) {
9977
- if (!query) return path;
9978
- const params = new URLSearchParams();
9979
- for (const [key, value] of Object.entries(query)) {
9980
- if (value === void 0 || value === null) continue;
9981
- params.set(key, String(value));
9982
- }
9983
- const serialized = params.toString();
9984
- return serialized ? `${path}?${serialized}` : path;
9985
- }
9986
- function connectionQuery(input) {
9987
- const query = {
9988
- connectionId: input.connectionId
9937
+ auth: {
9938
+ remote: options.authRemote
9939
+ }
9989
9940
  };
9990
- if (input.clientName) query.clientName = input.clientName;
9991
- if ("cursor" in input && input.cursor) query.cursor = input.cursor;
9992
- if ("source" in input && input.source) query.source = input.source;
9993
- if ("limit" in input && input.limit !== void 0) query.limit = String(input.limit);
9994
- if ("offset" in input && input.offset !== void 0) query.offset = String(input.offset);
9995
- return query;
9996
9941
  }
9997
- function parseEnvelopeData(body) {
9998
- if (body && typeof body === "object" && "data" in body) {
9999
- return body.data;
9942
+
9943
+ // src/cloudflare/d1/runner.ts
9944
+ function resultColumns(rows) {
9945
+ const first = rows.find((value) => value && typeof value === "object" && !Array.isArray(value));
9946
+ if (!first) return [];
9947
+ return Object.keys(first);
9948
+ }
9949
+ function isIdentChar(ch) {
9950
+ if (!ch) return false;
9951
+ return /[A-Za-z0-9_]/.test(ch);
9952
+ }
9953
+ function scanSqlKeywordsOutsideLiterals(sql, onKeyword) {
9954
+ let inSingle = false;
9955
+ let inDouble = false;
9956
+ let inBacktick = false;
9957
+ let inBracket = false;
9958
+ let inLineComment = false;
9959
+ let inBlockComment = false;
9960
+ for (let i = 0; i < sql.length; i += 1) {
9961
+ const ch = sql[i];
9962
+ const next = sql[i + 1];
9963
+ if (inLineComment) {
9964
+ if (ch === "\n" || ch === "\r") inLineComment = false;
9965
+ continue;
9966
+ }
9967
+ if (inBlockComment) {
9968
+ if (ch === "*" && next === "/") {
9969
+ i += 1;
9970
+ inBlockComment = false;
9971
+ }
9972
+ continue;
9973
+ }
9974
+ if (inSingle) {
9975
+ if (ch === "'" && next === "'") {
9976
+ i += 1;
9977
+ continue;
9978
+ }
9979
+ if (ch === "'") inSingle = false;
9980
+ continue;
9981
+ }
9982
+ if (inDouble) {
9983
+ if (ch === '"' && next === '"') {
9984
+ i += 1;
9985
+ continue;
9986
+ }
9987
+ if (ch === '"') inDouble = false;
9988
+ continue;
9989
+ }
9990
+ if (inBacktick) {
9991
+ if (ch === "`" && next === "`") {
9992
+ i += 1;
9993
+ continue;
9994
+ }
9995
+ if (ch === "`") inBacktick = false;
9996
+ continue;
9997
+ }
9998
+ if (inBracket) {
9999
+ if (ch === "]") inBracket = false;
10000
+ continue;
10001
+ }
10002
+ if (ch === "-" && next === "-") {
10003
+ inLineComment = true;
10004
+ i += 1;
10005
+ continue;
10006
+ }
10007
+ if (ch === "/" && next === "*") {
10008
+ inBlockComment = true;
10009
+ i += 1;
10010
+ continue;
10011
+ }
10012
+ if (ch === "'") {
10013
+ inSingle = true;
10014
+ continue;
10015
+ }
10016
+ if (ch === '"') {
10017
+ inDouble = true;
10018
+ continue;
10019
+ }
10020
+ if (ch === "`") {
10021
+ inBacktick = true;
10022
+ continue;
10023
+ }
10024
+ if (ch === "[") {
10025
+ inBracket = true;
10026
+ continue;
10027
+ }
10028
+ if (!isIdentChar(ch) || isIdentChar(sql[i - 1])) {
10029
+ continue;
10030
+ }
10031
+ let end = i + 1;
10032
+ while (end < sql.length && isIdentChar(sql[end])) {
10033
+ end += 1;
10034
+ }
10035
+ const keyword = sql.slice(i, end);
10036
+ if (onKeyword(keyword, i)) {
10037
+ return;
10038
+ }
10039
+ i = end - 1;
10000
10040
  }
10001
- return body;
10002
10041
  }
10003
- function createBillingModule(config) {
10004
- const baseUrl = normalizeAthenaGatewayBaseUrl(config.baseUrl, {
10005
- label: "Athena billing base URL"
10042
+ function sqlContainsKeywordOutsideLiterals(sql, keyword) {
10043
+ const target = keyword.toUpperCase();
10044
+ let found = false;
10045
+ scanSqlKeywordsOutsideLiterals(sql, (token) => {
10046
+ if (token.toUpperCase() === target) {
10047
+ found = true;
10048
+ return true;
10049
+ }
10050
+ return false;
10006
10051
  });
10007
- const fetchImpl = config.fetchImpl ?? globalThis.fetch.bind(globalThis);
10008
- async function call(method, path, body, options, responseType = "json") {
10009
- const headers = buildAthenaRequestHeaders({
10010
- profile: "gateway",
10011
- sdkHeaderValue: SDK_HEADER_VALUE4,
10012
- apiKey: options?.apiKey ?? config.apiKey,
10013
- client: config.client,
10014
- configHeaders: {
10015
- ...config.headers ?? {}
10016
- },
10017
- callHeaders: options?.headers,
10018
- contentType: "application/json"
10019
- });
10020
- let requestBody;
10021
- if (body !== void 0 && body !== null) {
10022
- if (typeof body === "string" || body instanceof Blob || body instanceof ArrayBuffer || ArrayBuffer.isView(body) || body instanceof FormData || body instanceof URLSearchParams) {
10023
- requestBody = body;
10024
- } else {
10025
- requestBody = JSON.stringify(body);
10026
- if (!hasHeaderIgnoreCase(headers, "Content-Type")) {
10027
- headers["Content-Type"] = "application/json";
10028
- }
10052
+ return found;
10053
+ }
10054
+ function sqlFirstKeywordOutsideLiterals(sql) {
10055
+ let first = null;
10056
+ scanSqlKeywordsOutsideLiterals(sql, (token) => {
10057
+ first = token;
10058
+ return true;
10059
+ });
10060
+ return first;
10061
+ }
10062
+ var ROW_PRODUCING_LEAD_KEYWORDS = /* @__PURE__ */ new Set(["SELECT", "PRAGMA", "EXPLAIN", "VALUES"]);
10063
+ var MUTATION_LEAD_KEYWORDS = /* @__PURE__ */ new Set(["INSERT", "UPDATE", "DELETE", "REPLACE"]);
10064
+ var WITH_TERMINAL_KEYWORDS = /* @__PURE__ */ new Set([
10065
+ "SELECT",
10066
+ "INSERT",
10067
+ "UPDATE",
10068
+ "DELETE",
10069
+ "REPLACE",
10070
+ "VALUES",
10071
+ "PRAGMA",
10072
+ "EXPLAIN"
10073
+ ]);
10074
+ function sqlTerminalKeywordAfterWith(sql) {
10075
+ let inSingle = false;
10076
+ let inDouble = false;
10077
+ let inBacktick = false;
10078
+ let inBracket = false;
10079
+ let inLineComment = false;
10080
+ let inBlockComment = false;
10081
+ let depth = 0;
10082
+ let sawWith = false;
10083
+ for (let i = 0; i < sql.length; i += 1) {
10084
+ const ch = sql[i];
10085
+ const next = sql[i + 1];
10086
+ if (inLineComment) {
10087
+ if (ch === "\n" || ch === "\r") inLineComment = false;
10088
+ continue;
10089
+ }
10090
+ if (inBlockComment) {
10091
+ if (ch === "*" && next === "/") {
10092
+ i += 1;
10093
+ inBlockComment = false;
10029
10094
  }
10095
+ continue;
10030
10096
  }
10031
- const targetUrl = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
10032
- const response = await fetchImpl(targetUrl, {
10033
- method,
10034
- headers,
10035
- body: requestBody,
10036
- signal: options?.signal
10037
- });
10038
- if (responseType === "text") {
10039
- const text = await response.text();
10040
- if (!response.ok) {
10041
- throw new AthenaBillingError({
10042
- message: `Billing request failed (${response.status})`,
10043
- status: response.status,
10044
- endpoint: path,
10045
- method,
10046
- body: text
10047
- });
10097
+ if (inSingle) {
10098
+ if (ch === "'" && next === "'") {
10099
+ i += 1;
10100
+ continue;
10048
10101
  }
10049
- return text;
10102
+ if (ch === "'") inSingle = false;
10103
+ continue;
10050
10104
  }
10051
- const rawText = await response.text();
10052
- let parsed = rawText;
10053
- if (rawText) {
10054
- try {
10055
- parsed = JSON.parse(rawText);
10056
- } catch {
10057
- parsed = rawText;
10105
+ if (inDouble) {
10106
+ if (ch === '"' && next === '"') {
10107
+ i += 1;
10108
+ continue;
10058
10109
  }
10059
- } else {
10060
- parsed = null;
10110
+ if (ch === '"') inDouble = false;
10111
+ continue;
10061
10112
  }
10062
- if (!response.ok) {
10063
- const message = parsed && typeof parsed === "object" && "message" in parsed && typeof parsed.message === "string" ? parsed.message : `Billing request failed (${response.status})`;
10064
- throw new AthenaBillingError({
10065
- message,
10066
- status: response.status,
10113
+ if (inBacktick) {
10114
+ if (ch === "`" && next === "`") {
10115
+ i += 1;
10116
+ continue;
10117
+ }
10118
+ if (ch === "`") inBacktick = false;
10119
+ continue;
10120
+ }
10121
+ if (inBracket) {
10122
+ if (ch === "]") inBracket = false;
10123
+ continue;
10124
+ }
10125
+ if (ch === "-" && next === "-") {
10126
+ inLineComment = true;
10127
+ i += 1;
10128
+ continue;
10129
+ }
10130
+ if (ch === "/" && next === "*") {
10131
+ inBlockComment = true;
10132
+ i += 1;
10133
+ continue;
10134
+ }
10135
+ if (ch === "'") {
10136
+ inSingle = true;
10137
+ continue;
10138
+ }
10139
+ if (ch === '"') {
10140
+ inDouble = true;
10141
+ continue;
10142
+ }
10143
+ if (ch === "`") {
10144
+ inBacktick = true;
10145
+ continue;
10146
+ }
10147
+ if (ch === "[") {
10148
+ inBracket = true;
10149
+ continue;
10150
+ }
10151
+ if (ch === "(") {
10152
+ depth += 1;
10153
+ continue;
10154
+ }
10155
+ if (ch === ")") {
10156
+ if (depth > 0) depth -= 1;
10157
+ continue;
10158
+ }
10159
+ if (depth !== 0 || !isIdentChar(ch) || isIdentChar(sql[i - 1])) {
10160
+ continue;
10161
+ }
10162
+ let end = i + 1;
10163
+ while (end < sql.length && isIdentChar(sql[end])) {
10164
+ end += 1;
10165
+ }
10166
+ const keyword = sql.slice(i, end);
10167
+ const upper = keyword.toUpperCase();
10168
+ if (!sawWith) {
10169
+ if (upper === "WITH") {
10170
+ sawWith = true;
10171
+ }
10172
+ i = end - 1;
10173
+ continue;
10174
+ }
10175
+ if (WITH_TERMINAL_KEYWORDS.has(upper)) {
10176
+ return keyword;
10177
+ }
10178
+ i = end - 1;
10179
+ }
10180
+ return null;
10181
+ }
10182
+ function sqlLeadStatementKeyword(sql) {
10183
+ const first = sqlFirstKeywordOutsideLiterals(sql);
10184
+ if (!first) return null;
10185
+ if (first.toUpperCase() !== "WITH") return first;
10186
+ return sqlTerminalKeywordAfterWith(sql) ?? first;
10187
+ }
10188
+ function statementExpectsResultRows(sql) {
10189
+ const lead = sqlLeadStatementKeyword(sql);
10190
+ if (lead) {
10191
+ const upper = lead.toUpperCase();
10192
+ if (ROW_PRODUCING_LEAD_KEYWORDS.has(upper)) {
10193
+ return true;
10194
+ }
10195
+ if (MUTATION_LEAD_KEYWORDS.has(upper)) {
10196
+ return sqlContainsKeywordOutsideLiterals(sql, "RETURNING");
10197
+ }
10198
+ }
10199
+ return sqlContainsKeywordOutsideLiterals(sql, "RETURNING");
10200
+ }
10201
+ function collectRowsFromBatchResults(results) {
10202
+ const rows = [];
10203
+ for (const item of results) {
10204
+ if (Array.isArray(item.results) && item.results.length > 0) {
10205
+ rows.push(...item.results);
10206
+ }
10207
+ }
10208
+ return rows;
10209
+ }
10210
+ function sumBatchAffectedRows(results, statementCount) {
10211
+ let sum2 = 0;
10212
+ let sawChanges = false;
10213
+ for (const item of results) {
10214
+ const changes = item.meta?.changes;
10215
+ if (typeof changes === "number") {
10216
+ sum2 += changes;
10217
+ sawChanges = true;
10218
+ }
10219
+ }
10220
+ return sawChanges ? sum2 : statementCount;
10221
+ }
10222
+ function matchSqlKeywordAt(query, index, keyword) {
10223
+ const len = keyword.length;
10224
+ if (index + len > query.length) {
10225
+ return null;
10226
+ }
10227
+ const slice = query.slice(index, index + len);
10228
+ if (slice.toLowerCase() !== keyword.toLowerCase()) {
10229
+ return null;
10230
+ }
10231
+ const before = index === 0 ? "" : query[index - 1];
10232
+ const after = index + len >= query.length ? "" : query[index + len];
10233
+ const isIdent = (c) => /[A-Za-z0-9_]/.test(c);
10234
+ if (before && isIdent(before)) {
10235
+ return null;
10236
+ }
10237
+ if (after && isIdent(after)) {
10238
+ return null;
10239
+ }
10240
+ return len;
10241
+ }
10242
+ function splitSqlStatements(query) {
10243
+ const statements = [];
10244
+ let inSingle = false;
10245
+ let inDouble = false;
10246
+ let inBacktick = false;
10247
+ let inBracket = false;
10248
+ let inLineComment = false;
10249
+ let inBlockComment = false;
10250
+ let segmentStart = 0;
10251
+ let segmentHasContent = false;
10252
+ let awaitTriggerBegin = false;
10253
+ let triggerBodyDepth = 0;
10254
+ let caseDepth = 0;
10255
+ const flushSegment = (end) => {
10256
+ if (!segmentHasContent) {
10257
+ segmentStart = end + 1;
10258
+ return;
10259
+ }
10260
+ const sql = query.slice(segmentStart, end).trim();
10261
+ if (sql) {
10262
+ statements.push(sql);
10263
+ }
10264
+ segmentHasContent = false;
10265
+ segmentStart = end + 1;
10266
+ awaitTriggerBegin = false;
10267
+ triggerBodyDepth = 0;
10268
+ caseDepth = 0;
10269
+ };
10270
+ for (let i = 0; i < query.length; i += 1) {
10271
+ const ch = query[i];
10272
+ const next = query[i + 1];
10273
+ if (inLineComment) {
10274
+ if (ch === "\n" || ch === "\r") {
10275
+ inLineComment = false;
10276
+ }
10277
+ continue;
10278
+ }
10279
+ if (inBlockComment) {
10280
+ if (ch === "*" && next === "/") {
10281
+ inBlockComment = false;
10282
+ i += 1;
10283
+ }
10284
+ continue;
10285
+ }
10286
+ if (inSingle) {
10287
+ if (ch === "'" && next === "'") {
10288
+ i += 1;
10289
+ continue;
10290
+ }
10291
+ if (ch === "'") {
10292
+ inSingle = false;
10293
+ }
10294
+ continue;
10295
+ }
10296
+ if (inDouble) {
10297
+ if (ch === '"' && next === '"') {
10298
+ i += 1;
10299
+ continue;
10300
+ }
10301
+ if (ch === '"') {
10302
+ inDouble = false;
10303
+ }
10304
+ continue;
10305
+ }
10306
+ if (inBacktick) {
10307
+ if (ch === "`" && next === "`") {
10308
+ i += 1;
10309
+ continue;
10310
+ }
10311
+ if (ch === "`") {
10312
+ inBacktick = false;
10313
+ }
10314
+ continue;
10315
+ }
10316
+ if (inBracket) {
10317
+ if (ch === "]") {
10318
+ inBracket = false;
10319
+ }
10320
+ continue;
10321
+ }
10322
+ if (ch === "-" && next === "-") {
10323
+ inLineComment = true;
10324
+ i += 1;
10325
+ continue;
10326
+ }
10327
+ if (ch === "/" && next === "*") {
10328
+ inBlockComment = true;
10329
+ i += 1;
10330
+ continue;
10331
+ }
10332
+ if (ch === "'") {
10333
+ inSingle = true;
10334
+ segmentHasContent = true;
10335
+ continue;
10336
+ }
10337
+ if (ch === '"') {
10338
+ inDouble = true;
10339
+ segmentHasContent = true;
10340
+ continue;
10341
+ }
10342
+ if (ch === "`") {
10343
+ inBacktick = true;
10344
+ segmentHasContent = true;
10345
+ continue;
10346
+ }
10347
+ if (ch === "[") {
10348
+ inBracket = true;
10349
+ segmentHasContent = true;
10350
+ continue;
10351
+ }
10352
+ if (/[A-Za-z_]/.test(ch)) {
10353
+ const createLen = matchSqlKeywordAt(query, i, "CREATE");
10354
+ if (createLen != null) {
10355
+ let j2 = i + createLen;
10356
+ const skipWsAndComments = () => {
10357
+ while (j2 < query.length) {
10358
+ const c = query[j2];
10359
+ const n = query[j2 + 1];
10360
+ if (/\s/.test(c)) {
10361
+ j2 += 1;
10362
+ continue;
10363
+ }
10364
+ if (c === "-" && n === "-") {
10365
+ j2 += 2;
10366
+ while (j2 < query.length && query[j2] !== "\n" && query[j2] !== "\r") {
10367
+ j2 += 1;
10368
+ }
10369
+ continue;
10370
+ }
10371
+ if (c === "/" && n === "*") {
10372
+ j2 += 2;
10373
+ while (j2 < query.length) {
10374
+ if (query[j2] === "*" && query[j2 + 1] === "/") {
10375
+ j2 += 2;
10376
+ break;
10377
+ }
10378
+ j2 += 1;
10379
+ }
10380
+ continue;
10381
+ }
10382
+ break;
10383
+ }
10384
+ };
10385
+ skipWsAndComments();
10386
+ const tempLen = matchSqlKeywordAt(query, j2, "TEMPORARY") ?? matchSqlKeywordAt(query, j2, "TEMP");
10387
+ if (tempLen != null) {
10388
+ j2 += tempLen;
10389
+ skipWsAndComments();
10390
+ }
10391
+ const triggerLen = matchSqlKeywordAt(query, j2, "TRIGGER");
10392
+ if (triggerLen != null) {
10393
+ awaitTriggerBegin = true;
10394
+ segmentHasContent = true;
10395
+ i += createLen - 1;
10396
+ continue;
10397
+ }
10398
+ segmentHasContent = true;
10399
+ i += createLen - 1;
10400
+ continue;
10401
+ }
10402
+ const caseLen = matchSqlKeywordAt(query, i, "CASE");
10403
+ if (caseLen != null) {
10404
+ caseDepth += 1;
10405
+ segmentHasContent = true;
10406
+ i += caseLen - 1;
10407
+ continue;
10408
+ }
10409
+ const beginLen = matchSqlKeywordAt(query, i, "BEGIN");
10410
+ if (beginLen != null) {
10411
+ if (awaitTriggerBegin) {
10412
+ triggerBodyDepth += 1;
10413
+ awaitTriggerBegin = false;
10414
+ }
10415
+ segmentHasContent = true;
10416
+ i += beginLen - 1;
10417
+ continue;
10418
+ }
10419
+ const endLen = matchSqlKeywordAt(query, i, "END");
10420
+ if (endLen != null) {
10421
+ if (caseDepth > 0) {
10422
+ caseDepth -= 1;
10423
+ } else if (triggerBodyDepth > 0) {
10424
+ triggerBodyDepth -= 1;
10425
+ }
10426
+ segmentHasContent = true;
10427
+ i += endLen - 1;
10428
+ continue;
10429
+ }
10430
+ let j = i + 1;
10431
+ while (j < query.length && /[A-Za-z0-9_]/.test(query[j])) {
10432
+ j += 1;
10433
+ }
10434
+ segmentHasContent = true;
10435
+ i = j - 1;
10436
+ continue;
10437
+ }
10438
+ if (ch === ";") {
10439
+ if (triggerBodyDepth > 0 || caseDepth > 0) {
10440
+ segmentHasContent = true;
10441
+ continue;
10442
+ }
10443
+ flushSegment(i);
10444
+ continue;
10445
+ }
10446
+ if (!/\s/.test(ch)) {
10447
+ segmentHasContent = true;
10448
+ }
10449
+ }
10450
+ flushSegment(query.length);
10451
+ return statements;
10452
+ }
10453
+ function isMultiStatement(query) {
10454
+ return splitSqlStatements(query).length > 1;
10455
+ }
10456
+ function resolveSessionTarget(db, input) {
10457
+ const sessionValue = input.bookmark?.trim() || input.sessionMode?.trim();
10458
+ if (!sessionValue) {
10459
+ return { target: db, session: null };
10460
+ }
10461
+ if (typeof db.withSession !== "function") {
10462
+ throw new Error("D1 session mode/bookmark requested but withSession is not available");
10463
+ }
10464
+ const session = db.withSession(sessionValue);
10465
+ return { target: session, session };
10466
+ }
10467
+ function normalizeD1BindParams(params) {
10468
+ return params.map((value) => {
10469
+ if (typeof value === "boolean") {
10470
+ return value ? 1 : 0;
10471
+ }
10472
+ return value;
10473
+ });
10474
+ }
10475
+ async function executeD1Query(db, input) {
10476
+ const query = input.query?.trim();
10477
+ if (!query) {
10478
+ return { ok: false, error: "invalid_query", message: "query is required" };
10479
+ }
10480
+ const params = normalizeD1BindParams(Array.isArray(input.params) ? input.params : []);
10481
+ const { target, session } = resolveSessionTarget(db, input);
10482
+ if (isMultiStatement(query)) {
10483
+ if (params.length > 0) {
10484
+ return {
10485
+ ok: false,
10486
+ error: "invalid_query",
10487
+ message: "params are only supported for single prepared statements"
10488
+ };
10489
+ }
10490
+ const resolveBookmark = () => session?.getBookmark() ?? null;
10491
+ const parts = splitSqlStatements(query);
10492
+ if (typeof target.batch === "function") {
10493
+ const prepared = parts.map((part) => target.prepare(part));
10494
+ const results = await target.batch(prepared);
10495
+ const rows2 = collectRowsFromBatchResults(results);
10496
+ return {
10497
+ ok: true,
10498
+ rows: rows2,
10499
+ columns: resultColumns(rows2),
10500
+ // Prefer returned rows; otherwise sum mutation meta.changes (not statement count).
10501
+ count: rows2.length > 0 ? rows2.length : sumBatchAffectedRows(results, parts.length),
10502
+ bookmark: resolveBookmark(),
10503
+ meta: { statementCount: parts.length, results },
10504
+ statementCount: parts.length
10505
+ };
10506
+ }
10507
+ const canExec = typeof target.exec === "function" && !session;
10508
+ if (canExec) {
10509
+ const execResult = await target.exec(query);
10510
+ return {
10511
+ ok: true,
10512
+ rows: [],
10513
+ columns: [],
10514
+ durationMs: execResult.duration,
10515
+ count: execResult.count,
10516
+ bookmark: resolveBookmark(),
10517
+ meta: { statementCount: execResult.count },
10518
+ statementCount: execResult.count
10519
+ };
10520
+ }
10521
+ return {
10522
+ ok: false,
10523
+ error: "invalid_query",
10524
+ message: "multi-statement query requires D1 batch() or exec() support"
10525
+ };
10526
+ }
10527
+ let statement = target.prepare(query);
10528
+ if (params.length > 0) {
10529
+ statement = statement.bind(...params);
10530
+ }
10531
+ const expectsRows = statementExpectsResultRows(query);
10532
+ const result = expectsRows ? await statement.all() : await statement.run();
10533
+ if (result.success === false) {
10534
+ const errorField = result.error;
10535
+ const message = typeof errorField === "string" && errorField.trim() ? errorField : "D1 query failed";
10536
+ return {
10537
+ ok: false,
10538
+ error: "query_failed",
10539
+ message
10540
+ };
10541
+ }
10542
+ const rows = Array.isArray(result.results) ? result.results : [];
10543
+ const bookmark = session?.getBookmark() ?? null;
10544
+ const meta = result.meta ?? {};
10545
+ const changes = typeof meta.changes === "number" ? meta.changes : typeof result.meta?.changes === "number" ? result.meta.changes : void 0;
10546
+ return {
10547
+ ok: true,
10548
+ rows,
10549
+ columns: resultColumns(rows),
10550
+ durationMs: typeof result.meta?.duration === "number" ? result.meta.duration : void 0,
10551
+ count: expectsRows ? rows.length : changes ?? rows.length,
10552
+ bookmark,
10553
+ meta
10554
+ };
10555
+ }
10556
+ async function executeD1Batch(db, input) {
10557
+ const statements = Array.isArray(input.statements) ? input.statements : [];
10558
+ if (statements.length === 0) {
10559
+ return {
10560
+ ok: false,
10561
+ error: "invalid_batch",
10562
+ message: "statements must contain at least one item"
10563
+ };
10564
+ }
10565
+ const { target, session } = resolveSessionTarget(db, input);
10566
+ const prepared = statements.map((item) => {
10567
+ const query = item.query?.trim();
10568
+ if (!query) {
10569
+ throw new Error("statements[].query is required");
10570
+ }
10571
+ const params = normalizeD1BindParams(Array.isArray(item.params) ? item.params : []);
10572
+ let statement = target.prepare(query);
10573
+ if (params.length > 0) {
10574
+ statement = statement.bind(...params);
10575
+ }
10576
+ return statement;
10577
+ });
10578
+ const results = await target.batch(prepared);
10579
+ const bookmark = session?.getBookmark() ?? null;
10580
+ return {
10581
+ ok: true,
10582
+ results,
10583
+ bookmark
10584
+ };
10585
+ }
10586
+
10587
+ // src/cloudflare/d1/sql.ts
10588
+ function asSingle(sql, params) {
10589
+ return { sql, params };
10590
+ }
10591
+ function asBatch(statements) {
10592
+ if (statements.length === 0) {
10593
+ throw new D1SqlCompileError("empty_insert", "batch requires at least one statement");
10594
+ }
10595
+ return {
10596
+ sql: statements[0].sql,
10597
+ params: statements[0].params,
10598
+ statements
10599
+ };
10600
+ }
10601
+ function hasPaginationBounds(payload) {
10602
+ return payload.limit !== void 0 || payload.offset !== void 0 || payload.page_size !== void 0 || payload.current_page !== void 0;
10603
+ }
10604
+ function assertEffectiveMutationBounds(payload) {
10605
+ if (payload.current_page !== void 0 && payload.page_size === void 0 && payload.limit === void 0) {
10606
+ throw new D1SqlCompileError(
10607
+ "page_without_size",
10608
+ "current_page requires page_size (or limit) for bounded update/delete on D1 edge-local"
10609
+ );
10610
+ }
10611
+ const clause = limitOffsetClause(payload);
10612
+ if (!clause.trim()) {
10613
+ throw new D1SqlCompileError(
10614
+ "invalid_pagination_bounds",
10615
+ "Bounded update/delete requires limit, offset, and/or page_size on D1 edge-local"
10616
+ );
10617
+ }
10618
+ }
10619
+ var SQLITE_ROWID_ALIASES = /* @__PURE__ */ new Set(["rowid", "oid", "_rowid_"]);
10620
+ function referencedMutationColumns(payload) {
10621
+ const names = [];
10622
+ for (const condition of payload.conditions ?? []) {
10623
+ const column = (condition.column ?? condition.eq_column ?? "").trim();
10624
+ if (column) names.push(column);
10625
+ }
10626
+ if (payload.sort_by?.field?.trim()) {
10627
+ names.push(payload.sort_by.field.trim());
10628
+ }
10629
+ return names;
10630
+ }
10631
+ function resolveBoundedIdentityColumn(payload, options) {
10632
+ const refs = referencedMutationColumns(payload);
10633
+ const lower = refs.map((name) => name.toLowerCase());
10634
+ if (lower.some((name) => SQLITE_ROWID_ALIASES.has(name))) {
10635
+ throw new D1SqlCompileError(
10636
+ "bounded_mutation_unsafe_identity",
10637
+ "Bounded update/delete cannot use rowid/oid/_rowid_ in filters or order \u2014 those names may be user columns that shadow SQLite row identity. Resolve the table primary key (or a single-column unique index) instead."
10638
+ );
10639
+ }
10640
+ const identity = options?.identityColumn?.trim();
10641
+ if (!identity) {
10642
+ throw new D1SqlCompileError(
10643
+ "bounded_mutation_no_unique_identity",
10644
+ "Bounded update/delete requires a proven unique identity column from the table schema (single-column PRIMARY KEY or UNIQUE index). Cannot assume a column named id."
10645
+ );
10646
+ }
10647
+ if (SQLITE_ROWID_ALIASES.has(identity.toLowerCase())) {
10648
+ throw new D1SqlCompileError(
10649
+ "bounded_mutation_unsafe_identity",
10650
+ `Bounded update/delete cannot use identity column "${identity}" \u2014 it may shadow SQLite row identity.`
10651
+ );
10652
+ }
10653
+ return identity;
10654
+ }
10655
+ function boundedRowidInClause(table2, whereSql, whereParams, payload, options) {
10656
+ assertEffectiveMutationBounds(payload);
10657
+ const identity = resolveBoundedIdentityColumn(payload, options);
10658
+ const identitySql = quoteIdent(identity);
10659
+ const innerWhere = whereSql.replace(/^WHERE\s+/i, "");
10660
+ const parts = [
10661
+ `SELECT ${identitySql} FROM ${quoteIdent(table2)}`,
10662
+ innerWhere ? `WHERE ${innerWhere}` : "",
10663
+ orderClause(payload.sort_by),
10664
+ limitOffsetClause(payload)
10665
+ ].filter(Boolean);
10666
+ return {
10667
+ sql: `${identitySql} IN (${parts.join(" ")})`,
10668
+ params: [...whereParams]
10669
+ };
10670
+ }
10671
+ var D1SqlCompileError = class extends Error {
10672
+ code;
10673
+ constructor(code, message) {
10674
+ super(message);
10675
+ this.name = "D1SqlCompileError";
10676
+ this.code = code;
10677
+ }
10678
+ };
10679
+ var SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
10680
+ function quoteIdent(name) {
10681
+ const trimmed = name.trim();
10682
+ if (!trimmed) {
10683
+ throw new D1SqlCompileError("invalid_identifier", "Identifier is required");
10684
+ }
10685
+ if (trimmed.includes(".")) {
10686
+ throw new D1SqlCompileError(
10687
+ "schema_qualified_name",
10688
+ `Schema-qualified names are unsupported on D1 edge-local: ${trimmed}`
10689
+ );
10690
+ }
10691
+ if (!SAFE_IDENTIFIER.test(trimmed)) {
10692
+ throw new D1SqlCompileError(
10693
+ "invalid_identifier",
10694
+ `Invalid SQL identifier for D1 edge-local: ${trimmed}`
10695
+ );
10696
+ }
10697
+ return quoteQualifiedIdentifier(trimmed);
10698
+ }
10699
+ var RESPONSE_ALIAS_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_]*)$/;
10700
+ var SQL_ALIAS_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
10701
+ function quoteSelectTokenStrict(token) {
10702
+ const trimmed = token.trim();
10703
+ if (!trimmed || trimmed === "*") return trimmed || "*";
10704
+ if (SAFE_IDENTIFIER.test(trimmed)) {
10705
+ return quoteQualifiedIdentifier(trimmed);
10706
+ }
10707
+ const responseAlias = RESPONSE_ALIAS_PATTERN2.exec(trimmed);
10708
+ if (responseAlias) {
10709
+ const [, aliasIdentifier, baseIdentifier] = responseAlias;
10710
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteQualifiedIdentifier(aliasIdentifier)}`;
10711
+ }
10712
+ const sqlAlias = SQL_ALIAS_PATTERN2.exec(trimmed);
10713
+ if (sqlAlias) {
10714
+ const [, baseIdentifier, aliasIdentifier] = sqlAlias;
10715
+ return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteQualifiedIdentifier(aliasIdentifier)}`;
10716
+ }
10717
+ throw new D1SqlCompileError(
10718
+ "unsafe_select",
10719
+ `SELECT/RETURNING expressions are not supported on D1 edge-local; use column names or aliases only: ${token}`
10720
+ );
10721
+ }
10722
+ function selectClause(columns) {
10723
+ if (columns === void 0 || columns === "*" || columns === "") return "*";
10724
+ if (typeof columns === "string") {
10725
+ const trimmed = columns.trim();
10726
+ if (!trimmed || trimmed === "*") return "*";
10727
+ return trimmed.split(",").map((part) => quoteSelectTokenStrict(part)).join(", ");
10728
+ }
10729
+ if (columns.length === 0) return "*";
10730
+ return columns.map((column) => quoteSelectTokenStrict(column)).join(", ");
10731
+ }
10732
+ function wantsReturning(payload) {
10733
+ return Boolean(payload.columns) && payload.head !== true;
10734
+ }
10735
+ function conditionToWhere(condition) {
10736
+ const column = condition.column?.trim() || condition.eq_column?.trim() || "";
10737
+ if (!column) {
10738
+ throw new D1SqlCompileError("invalid_condition", "Condition requires a column");
10739
+ }
10740
+ const col = quoteIdent(column);
10741
+ const operator = (condition.operator || "eq").toLowerCase();
10742
+ const value = condition.value !== void 0 ? condition.value : condition.eq_value;
10743
+ switch (operator) {
10744
+ case "eq": {
10745
+ if (Array.isArray(value)) {
10746
+ if (value.length === 0) {
10747
+ return { sql: "1 = 0", params: [] };
10748
+ }
10749
+ const placeholders = value.map(() => "?").join(", ");
10750
+ return { sql: `${col} IN (${placeholders})`, params: [...value] };
10751
+ }
10752
+ if (value === null) {
10753
+ return { sql: `${col} IS NULL`, params: [] };
10754
+ }
10755
+ return { sql: `${col} = ?`, params: [value ?? null] };
10756
+ }
10757
+ case "neq":
10758
+ if (value === null) {
10759
+ return { sql: `${col} IS NOT NULL`, params: [] };
10760
+ }
10761
+ return { sql: `${col} != ?`, params: [value ?? null] };
10762
+ case "gt":
10763
+ return { sql: `${col} > ?`, params: [value ?? null] };
10764
+ case "gte":
10765
+ return { sql: `${col} >= ?`, params: [value ?? null] };
10766
+ case "lt":
10767
+ return { sql: `${col} < ?`, params: [value ?? null] };
10768
+ case "lte":
10769
+ return { sql: `${col} <= ?`, params: [value ?? null] };
10770
+ case "like":
10771
+ return { sql: `${col} LIKE ?`, params: [value ?? null] };
10772
+ case "ilike":
10773
+ return { sql: `${col} LIKE ? COLLATE NOCASE`, params: [value ?? null] };
10774
+ case "in": {
10775
+ const items = Array.isArray(value) ? value : value === void 0 ? [] : [value];
10776
+ if (items.length === 0) {
10777
+ return { sql: "1 = 0", params: [] };
10778
+ }
10779
+ const placeholders = items.map(() => "?").join(", ");
10780
+ return { sql: `${col} IN (${placeholders})`, params: [...items] };
10781
+ }
10782
+ case "is": {
10783
+ if (value === null || value === "null") {
10784
+ return { sql: `${col} IS NULL`, params: [] };
10785
+ }
10786
+ if (value === true || value === "true") {
10787
+ return { sql: `${col} IS TRUE`, params: [] };
10788
+ }
10789
+ if (value === false || value === "false") {
10790
+ return { sql: `${col} IS FALSE`, params: [] };
10791
+ }
10792
+ return { sql: `${col} IS ?`, params: [value] };
10793
+ }
10794
+ case "not":
10795
+ case "or":
10796
+ case "contains":
10797
+ case "containedby":
10798
+ throw new D1SqlCompileError(
10799
+ "unsupported_operator",
10800
+ `Condition operator "${operator}" is not supported on D1 edge-local L1`
10801
+ );
10802
+ default:
10803
+ throw new D1SqlCompileError(
10804
+ "unsupported_operator",
10805
+ `Unknown condition operator "${operator}"`
10806
+ );
10807
+ }
10808
+ }
10809
+ function buildWhere(conditions) {
10810
+ if (!conditions?.length) {
10811
+ return { sql: "", params: [] };
10812
+ }
10813
+ const parts = [];
10814
+ const params = [];
10815
+ for (const condition of conditions) {
10816
+ if (!condition.operator && condition.eq_column) {
10817
+ const clause2 = conditionToWhere({
10818
+ ...condition,
10819
+ operator: "eq",
10820
+ column: condition.eq_column,
10821
+ value: condition.eq_value
10822
+ });
10823
+ parts.push(clause2.sql);
10824
+ params.push(...clause2.params);
10825
+ continue;
10826
+ }
10827
+ const clause = conditionToWhere(condition);
10828
+ parts.push(clause.sql);
10829
+ params.push(...clause.params);
10830
+ }
10831
+ return {
10832
+ sql: parts.length ? `WHERE ${parts.join(" AND ")}` : "",
10833
+ params
10834
+ };
10835
+ }
10836
+ function orderClause(order) {
10837
+ if (!order?.field?.trim()) return "";
10838
+ const direction = order.direction === "descending" ? "DESC" : "ASC";
10839
+ return `ORDER BY ${quoteIdent(order.field)} ${direction}`;
10840
+ }
10841
+ function limitOffsetClause(payload) {
10842
+ let limit = payload.limit;
10843
+ let offset = payload.offset;
10844
+ if (limit === void 0 && payload.page_size !== void 0) {
10845
+ limit = payload.page_size;
10846
+ }
10847
+ if (payload.current_page !== void 0 && offset === void 0) {
10848
+ const pageSize = payload.page_size ?? payload.limit;
10849
+ if (pageSize !== void 0) {
10850
+ offset = Math.max(0, (payload.current_page - 1) * pageSize);
10851
+ }
10852
+ }
10853
+ const parts = [];
10854
+ if (offset !== void 0 && limit === void 0) {
10855
+ parts.push("LIMIT -1");
10856
+ parts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
10857
+ } else {
10858
+ if (limit !== void 0) {
10859
+ parts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
10860
+ }
10861
+ if (offset !== void 0) {
10862
+ parts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
10863
+ }
10864
+ }
10865
+ return parts.join(" ");
10866
+ }
10867
+ function rejectStructuredRelations(payload) {
10868
+ const select = payload.select;
10869
+ if (select && typeof select === "object" && !Array.isArray(select)) {
10870
+ for (const value of Object.values(select)) {
10871
+ if (value && typeof value === "object") {
10872
+ throw new D1SqlCompileError(
10873
+ "relations_unsupported",
10874
+ "Nested relation selects are unsupported on D1 edge-local"
10875
+ );
10876
+ }
10877
+ }
10878
+ }
10879
+ if (payload.view_name) {
10880
+ throw new D1SqlCompileError(
10881
+ "view_unsupported",
10882
+ "view_name is unsupported on D1 edge-local L1"
10883
+ );
10884
+ }
10885
+ }
10886
+ function jsonValue(value) {
10887
+ if (value === void 0) return null;
10888
+ if (value !== null && typeof value === "object") {
10889
+ return JSON.stringify(value);
10890
+ }
10891
+ return value;
10892
+ }
10893
+ function compileD1Fetch(payload) {
10894
+ rejectStructuredRelations(payload);
10895
+ const table2 = payload.table_name?.trim();
10896
+ if (!table2) {
10897
+ throw new D1SqlCompileError("missing_table", "table_name is required for fetch");
10898
+ }
10899
+ let columns = payload.columns;
10900
+ if (payload.select && typeof payload.select === "object" && !Array.isArray(payload.select)) {
10901
+ const keys = Object.entries(payload.select).filter(([, enabled]) => enabled === true || enabled === 1).map(([key]) => key);
10902
+ if (keys.length > 0) {
10903
+ columns = keys;
10904
+ }
10905
+ } else if (typeof payload.select === "string" && payload.select.trim()) {
10906
+ columns = payload.select;
10907
+ }
10908
+ let where = buildWhere(payload.conditions);
10909
+ if (!where.sql && payload.where && typeof payload.where === "object") {
10910
+ const eqConditions = Object.entries(
10911
+ payload.where
10912
+ ).map(([column, value]) => ({
10913
+ column,
10914
+ operator: "eq",
10915
+ value
10916
+ }));
10917
+ where = buildWhere(eqConditions);
10918
+ }
10919
+ if (payload.head === true) {
10920
+ return compileD1CountFromWhere(table2, where);
10921
+ }
10922
+ const parts = [
10923
+ `SELECT ${selectClause(columns)} FROM ${quoteIdent(table2)}`,
10924
+ where.sql,
10925
+ orderClause(payload.sort_by),
10926
+ limitOffsetClause(payload)
10927
+ ].filter(Boolean);
10928
+ return asSingle(parts.join(" "), where.params);
10929
+ }
10930
+ function compileD1Count(payload) {
10931
+ rejectStructuredRelations(payload);
10932
+ const table2 = payload.table_name?.trim();
10933
+ if (!table2) {
10934
+ throw new D1SqlCompileError("missing_table", "table_name is required for count");
10935
+ }
10936
+ let where = buildWhere(payload.conditions);
10937
+ if (!where.sql && payload.where && typeof payload.where === "object") {
10938
+ const eqConditions = Object.entries(
10939
+ payload.where
10940
+ ).map(([column, value]) => ({
10941
+ column,
10942
+ operator: "eq",
10943
+ value
10944
+ }));
10945
+ where = buildWhere(eqConditions);
10946
+ }
10947
+ return compileD1CountFromWhere(table2, where);
10948
+ }
10949
+ function compileD1CountFromWhere(table2, where) {
10950
+ const parts = [
10951
+ `SELECT COUNT(*) AS __athena_count FROM ${quoteIdent(table2)}`,
10952
+ where.sql
10953
+ ].filter(Boolean);
10954
+ return asSingle(parts.join(" "), where.params);
10955
+ }
10956
+ function extractAthenaCount(rows) {
10957
+ const first = rows[0];
10958
+ const rawCount = first && typeof first === "object" && !Array.isArray(first) ? first.__athena_count : void 0;
10959
+ const count = typeof rawCount === "number" ? rawCount : typeof rawCount === "bigint" ? Number(rawCount) : Number(rawCount ?? 0);
10960
+ return Number.isFinite(count) ? count : 0;
10961
+ }
10962
+ function compileSingleRowInsert(table2, row, payload) {
10963
+ const columns = Object.keys(row);
10964
+ if (columns.length === 0) {
10965
+ if (payload.on_conflict) {
10966
+ throw new D1SqlCompileError(
10967
+ "default_values_upsert_unsupported",
10968
+ "DEFAULT VALUES upsert is unsupported on D1 edge-local; provide insert columns or omit onConflict"
10969
+ );
10970
+ }
10971
+ const parts2 = [`INSERT INTO ${quoteIdent(table2)} DEFAULT VALUES`];
10972
+ if (wantsReturning(payload)) {
10973
+ parts2.push(`RETURNING ${selectClause(payload.columns)}`);
10974
+ }
10975
+ return { sql: parts2.join(" "), params: [] };
10976
+ }
10977
+ const params = columns.map((column) => jsonValue(row[column]));
10978
+ const parts = [
10979
+ `INSERT INTO ${quoteIdent(table2)} (${columns.map(quoteIdent).join(", ")})`,
10980
+ `VALUES (${columns.map(() => "?").join(", ")})`
10981
+ ];
10982
+ appendOnConflict(parts, params, payload, columns);
10983
+ if (wantsReturning(payload)) {
10984
+ parts.push(`RETURNING ${selectClause(payload.columns)}`);
10985
+ }
10986
+ return { sql: parts.join(" "), params };
10987
+ }
10988
+ function parseOnConflictColumns(onConflict) {
10989
+ const raw = Array.isArray(onConflict) ? onConflict : [onConflict];
10990
+ const columns = [];
10991
+ for (const item of raw) {
10992
+ for (const part of String(item).split(",")) {
10993
+ const trimmed = part.trim();
10994
+ if (trimmed) columns.push(trimmed);
10995
+ }
10996
+ }
10997
+ if (columns.length === 0) {
10998
+ throw new D1SqlCompileError(
10999
+ "invalid_on_conflict",
11000
+ "on_conflict requires at least one column"
11001
+ );
11002
+ }
11003
+ return columns;
11004
+ }
11005
+ function appendOnConflict(parts, params, payload, insertColumns) {
11006
+ if (!payload.on_conflict) return;
11007
+ const conflictCols = parseOnConflictColumns(payload.on_conflict);
11008
+ const conflictSql = conflictCols.map(quoteIdent).join(", ");
11009
+ if (payload.update_body !== void 0 && payload.update_body !== null) {
11010
+ const entries = Object.entries(payload.update_body);
11011
+ if (entries.length === 0) {
11012
+ parts.push(`ON CONFLICT (${conflictSql}) DO NOTHING`);
11013
+ return;
11014
+ }
11015
+ const assignments2 = entries.map(([column, value]) => {
11016
+ params.push(jsonValue(value));
11017
+ return `${quoteIdent(column)} = ?`;
11018
+ });
11019
+ parts.push(`ON CONFLICT (${conflictSql}) DO UPDATE SET ${assignments2.join(", ")}`);
11020
+ return;
11021
+ }
11022
+ const conflictSet = new Set(conflictCols);
11023
+ const assignments = insertColumns.filter((column) => !conflictSet.has(column)).map((column) => {
11024
+ const quoted = quoteIdent(column);
11025
+ return `${quoted} = excluded.${quoted}`;
11026
+ });
11027
+ if (assignments.length === 0) {
11028
+ parts.push(`ON CONFLICT (${conflictSql}) DO NOTHING`);
11029
+ } else {
11030
+ parts.push(`ON CONFLICT (${conflictSql}) DO UPDATE SET ${assignments.join(", ")}`);
11031
+ }
11032
+ }
11033
+ function compileD1Insert(payload) {
11034
+ const table2 = payload.table_name?.trim();
11035
+ if (!table2) {
11036
+ throw new D1SqlCompileError("missing_table", "table_name is required for insert");
11037
+ }
11038
+ const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
11039
+ if (rows.length === 0) {
11040
+ throw new D1SqlCompileError("empty_insert", "insert_body must not be empty");
11041
+ }
11042
+ const columns = [];
11043
+ const seen = /* @__PURE__ */ new Set();
11044
+ for (const row of rows) {
11045
+ for (const key of Object.keys(row ?? {})) {
11046
+ if (seen.has(key)) continue;
11047
+ seen.add(key);
11048
+ columns.push(key);
11049
+ }
11050
+ }
11051
+ if (columns.length === 0) {
11052
+ if (rows.length === 1) {
11053
+ const compiled = compileSingleRowInsert(table2, {}, payload);
11054
+ return asSingle(compiled.sql, compiled.params);
11055
+ }
11056
+ throw new D1SqlCompileError(
11057
+ "empty_insert",
11058
+ "Multi-row insert_body cannot be empty objects; use a single {} for DEFAULT VALUES"
11059
+ );
11060
+ }
11061
+ const forceNullForMissing = payload.default_to_null === true;
11062
+ const isSparse = rows.some(
11063
+ (row) => columns.some((column) => !Object.prototype.hasOwnProperty.call(row, column))
11064
+ );
11065
+ if (isSparse && !forceNullForMissing && rows.length > 1) {
11066
+ return asBatch(
11067
+ rows.map((row) => compileSingleRowInsert(table2, row, payload))
11068
+ );
11069
+ }
11070
+ if (isSparse && !forceNullForMissing && rows.length === 1) {
11071
+ const compiled = compileSingleRowInsert(table2, rows[0], payload);
11072
+ return asSingle(compiled.sql, compiled.params);
11073
+ }
11074
+ const params = [];
11075
+ const valueGroups = rows.map((row) => {
11076
+ const placeholders = columns.map((column) => {
11077
+ const has = Object.prototype.hasOwnProperty.call(row, column);
11078
+ if (!has) {
11079
+ params.push(null);
11080
+ return "?";
11081
+ }
11082
+ params.push(jsonValue(row[column]));
11083
+ return "?";
11084
+ });
11085
+ return `(${placeholders.join(", ")})`;
11086
+ });
11087
+ const parts = [
11088
+ `INSERT INTO ${quoteIdent(table2)} (${columns.map(quoteIdent).join(", ")})`,
11089
+ `VALUES ${valueGroups.join(", ")}`
11090
+ ];
11091
+ appendOnConflict(parts, params, payload, columns);
11092
+ if (wantsReturning(payload)) {
11093
+ parts.push(`RETURNING ${selectClause(payload.columns)}`);
11094
+ }
11095
+ return asSingle(parts.join(" "), params);
11096
+ }
11097
+ function compileD1Update(payload, options) {
11098
+ const table2 = payload.table_name?.trim();
11099
+ if (!table2) {
11100
+ throw new D1SqlCompileError("missing_table", "table_name is required for update");
11101
+ }
11102
+ const entries = Object.entries(payload.update_body ?? {});
11103
+ if (entries.length === 0) {
11104
+ throw new D1SqlCompileError("empty_update", "update_body must not be empty");
11105
+ }
11106
+ const params = [];
11107
+ const assignments = entries.map(([column, value]) => {
11108
+ params.push(jsonValue(value));
11109
+ return `${quoteIdent(column)} = ?`;
11110
+ });
11111
+ const where = buildWhere(payload.conditions);
11112
+ if (!where.sql) {
11113
+ throw new D1SqlCompileError(
11114
+ "unfiltered_update",
11115
+ "UPDATE requires at least one condition on D1 edge-local"
11116
+ );
11117
+ }
11118
+ if (hasPaginationBounds(payload) || payload.sort_by) {
11119
+ if (!hasPaginationBounds(payload)) {
11120
+ throw new D1SqlCompileError(
11121
+ "order_without_bounds",
11122
+ "UPDATE with sort_by requires limit/offset or page_size/current_page on D1 edge-local"
11123
+ );
11124
+ }
11125
+ const bounded = boundedRowidInClause(
11126
+ table2,
11127
+ where.sql,
11128
+ where.params,
11129
+ {
11130
+ ...payload,
11131
+ conditions: payload.conditions
11132
+ },
11133
+ options
11134
+ );
11135
+ params.push(...bounded.params);
11136
+ const parts2 = [
11137
+ `UPDATE ${quoteIdent(table2)} SET ${assignments.join(", ")}`,
11138
+ `WHERE ${bounded.sql}`
11139
+ ];
11140
+ if (wantsReturning(payload)) {
11141
+ parts2.push(`RETURNING ${selectClause(payload.columns)}`);
11142
+ }
11143
+ return asSingle(parts2.join(" "), params);
11144
+ }
11145
+ params.push(...where.params);
11146
+ const parts = [
11147
+ `UPDATE ${quoteIdent(table2)} SET ${assignments.join(", ")}`,
11148
+ where.sql
11149
+ ];
11150
+ if (wantsReturning(payload)) {
11151
+ parts.push(`RETURNING ${selectClause(payload.columns)}`);
11152
+ }
11153
+ return asSingle(parts.join(" "), params);
11154
+ }
11155
+ function compileD1Delete(payload, options) {
11156
+ const table2 = payload.table_name?.trim();
11157
+ if (!table2) {
11158
+ throw new D1SqlCompileError("missing_table", "table_name is required for delete");
11159
+ }
11160
+ const conditions = [...payload.conditions ?? []];
11161
+ if (payload.resource_id !== void 0 && payload.resource_id !== null) {
11162
+ const hasResourceIdFilter = conditions.some((condition) => {
11163
+ const column = (condition.column ?? condition.eq_column ?? "").trim();
11164
+ return column === "resource_id";
11165
+ });
11166
+ const hasIdFilter = conditions.some((condition) => {
11167
+ const column = (condition.column ?? condition.eq_column ?? "").trim();
11168
+ return column === "id";
11169
+ });
11170
+ if (!hasResourceIdFilter && !hasIdFilter) {
11171
+ conditions.unshift({
11172
+ column: "id",
11173
+ operator: "eq",
11174
+ value: payload.resource_id
11175
+ });
11176
+ }
11177
+ }
11178
+ const where = buildWhere(conditions);
11179
+ if (!where.sql) {
11180
+ throw new D1SqlCompileError(
11181
+ "unfiltered_delete",
11182
+ "DELETE requires at least one condition or resource_id on D1 edge-local"
11183
+ );
11184
+ }
11185
+ if (hasPaginationBounds(payload) || payload.sort_by) {
11186
+ if (!hasPaginationBounds(payload)) {
11187
+ throw new D1SqlCompileError(
11188
+ "order_without_bounds",
11189
+ "DELETE with sort_by requires limit/offset or page_size/current_page on D1 edge-local"
11190
+ );
11191
+ }
11192
+ const bounded = boundedRowidInClause(
11193
+ table2,
11194
+ where.sql,
11195
+ where.params,
11196
+ {
11197
+ ...payload,
11198
+ conditions
11199
+ },
11200
+ options
11201
+ );
11202
+ const parts2 = [`DELETE FROM ${quoteIdent(table2)}`, `WHERE ${bounded.sql}`];
11203
+ if (wantsReturning(payload)) {
11204
+ parts2.push(`RETURNING ${selectClause(payload.columns)}`);
11205
+ }
11206
+ return asSingle(parts2.join(" "), bounded.params);
11207
+ }
11208
+ const parts = [`DELETE FROM ${quoteIdent(table2)}`, where.sql];
11209
+ if (wantsReturning(payload)) {
11210
+ parts.push(`RETURNING ${selectClause(payload.columns)}`);
11211
+ }
11212
+ return asSingle(parts.join(" "), where.params);
11213
+ }
11214
+
11215
+ // src/cloudflare/d1/sql-rewrite.ts
11216
+ var PG_CAST_TYPES = "text|uuid|citext|varchar|bpchar|char|integer|int4|int8|bigint|smallint|boolean|bool|jsonb|json|numeric|decimal|real|float|double precision|timestamptz|timestamp|date|bytea";
11217
+ function mapSqlOutsideLiterals(sql, transform) {
11218
+ let out = "";
11219
+ let buffer = "";
11220
+ let inSingle = false;
11221
+ let inDouble = false;
11222
+ let inBacktick = false;
11223
+ let inBracket = false;
11224
+ let inLineComment = false;
11225
+ let inBlockComment = false;
11226
+ const flushCode = () => {
11227
+ if (buffer) {
11228
+ out += transform(buffer);
11229
+ buffer = "";
11230
+ }
11231
+ };
11232
+ for (let i = 0; i < sql.length; i += 1) {
11233
+ const ch = sql[i];
11234
+ const next = sql[i + 1];
11235
+ if (inLineComment) {
11236
+ out += ch;
11237
+ if (ch === "\n" || ch === "\r") inLineComment = false;
11238
+ continue;
11239
+ }
11240
+ if (inBlockComment) {
11241
+ out += ch;
11242
+ if (ch === "*" && next === "/") {
11243
+ out += next;
11244
+ i += 1;
11245
+ inBlockComment = false;
11246
+ }
11247
+ continue;
11248
+ }
11249
+ if (inSingle) {
11250
+ out += ch;
11251
+ if (ch === "'" && next === "'") {
11252
+ out += next;
11253
+ i += 1;
11254
+ continue;
11255
+ }
11256
+ if (ch === "'") inSingle = false;
11257
+ continue;
11258
+ }
11259
+ if (inDouble) {
11260
+ out += ch;
11261
+ if (ch === '"' && next === '"') {
11262
+ out += next;
11263
+ i += 1;
11264
+ continue;
11265
+ }
11266
+ if (ch === '"') inDouble = false;
11267
+ continue;
11268
+ }
11269
+ if (inBacktick) {
11270
+ out += ch;
11271
+ if (ch === "`" && next === "`") {
11272
+ out += next;
11273
+ i += 1;
11274
+ continue;
11275
+ }
11276
+ if (ch === "`") inBacktick = false;
11277
+ continue;
11278
+ }
11279
+ if (inBracket) {
11280
+ out += ch;
11281
+ if (ch === "]") inBracket = false;
11282
+ continue;
11283
+ }
11284
+ if (ch === "-" && next === "-") {
11285
+ flushCode();
11286
+ out += ch;
11287
+ out += next;
11288
+ i += 1;
11289
+ inLineComment = true;
11290
+ continue;
11291
+ }
11292
+ if (ch === "/" && next === "*") {
11293
+ flushCode();
11294
+ out += ch;
11295
+ out += next;
11296
+ i += 1;
11297
+ inBlockComment = true;
11298
+ continue;
11299
+ }
11300
+ if (ch === "'") {
11301
+ flushCode();
11302
+ out += ch;
11303
+ inSingle = true;
11304
+ continue;
11305
+ }
11306
+ if (ch === '"') {
11307
+ flushCode();
11308
+ out += ch;
11309
+ inDouble = true;
11310
+ continue;
11311
+ }
11312
+ if (ch === "`") {
11313
+ flushCode();
11314
+ out += ch;
11315
+ inBacktick = true;
11316
+ continue;
11317
+ }
11318
+ if (ch === "[") {
11319
+ flushCode();
11320
+ out += ch;
11321
+ inBracket = true;
11322
+ continue;
11323
+ }
11324
+ buffer += ch;
11325
+ }
11326
+ flushCode();
11327
+ return out;
11328
+ }
11329
+ function isIdentChar2(ch) {
11330
+ if (!ch) return false;
11331
+ return /[A-Za-z0-9_]/.test(ch);
11332
+ }
11333
+ function collectLimitOffsetKeywords(sql) {
11334
+ const hits = [];
11335
+ let depth = 0;
11336
+ let statement = 0;
11337
+ let inSingle = false;
11338
+ let inDouble = false;
11339
+ let inBacktick = false;
11340
+ let inBracket = false;
11341
+ let inLineComment = false;
11342
+ let inBlockComment = false;
11343
+ for (let i = 0; i < sql.length; i += 1) {
11344
+ const ch = sql[i];
11345
+ const next = sql[i + 1];
11346
+ if (inLineComment) {
11347
+ if (ch === "\n" || ch === "\r") inLineComment = false;
11348
+ continue;
11349
+ }
11350
+ if (inBlockComment) {
11351
+ if (ch === "*" && next === "/") {
11352
+ i += 1;
11353
+ inBlockComment = false;
11354
+ }
11355
+ continue;
11356
+ }
11357
+ if (inSingle) {
11358
+ if (ch === "'" && next === "'") {
11359
+ i += 1;
11360
+ continue;
11361
+ }
11362
+ if (ch === "'") inSingle = false;
11363
+ continue;
11364
+ }
11365
+ if (inDouble) {
11366
+ if (ch === '"' && next === '"') {
11367
+ i += 1;
11368
+ continue;
11369
+ }
11370
+ if (ch === '"') inDouble = false;
11371
+ continue;
11372
+ }
11373
+ if (inBacktick) {
11374
+ if (ch === "`" && next === "`") {
11375
+ i += 1;
11376
+ continue;
11377
+ }
11378
+ if (ch === "`") inBacktick = false;
11379
+ continue;
11380
+ }
11381
+ if (inBracket) {
11382
+ if (ch === "]") inBracket = false;
11383
+ continue;
11384
+ }
11385
+ if (ch === "-" && next === "-") {
11386
+ inLineComment = true;
11387
+ i += 1;
11388
+ continue;
11389
+ }
11390
+ if (ch === "/" && next === "*") {
11391
+ inBlockComment = true;
11392
+ i += 1;
11393
+ continue;
11394
+ }
11395
+ if (ch === "'") {
11396
+ inSingle = true;
11397
+ continue;
11398
+ }
11399
+ if (ch === '"') {
11400
+ inDouble = true;
11401
+ continue;
11402
+ }
11403
+ if (ch === "`") {
11404
+ inBacktick = true;
11405
+ continue;
11406
+ }
11407
+ if (ch === "[") {
11408
+ inBracket = true;
11409
+ continue;
11410
+ }
11411
+ if (ch === "(") {
11412
+ depth += 1;
11413
+ continue;
11414
+ }
11415
+ if (ch === ")") {
11416
+ depth = Math.max(0, depth - 1);
11417
+ continue;
11418
+ }
11419
+ if (ch === ";" && depth === 0) {
11420
+ statement += 1;
11421
+ continue;
11422
+ }
11423
+ if (!isIdentChar2(ch) || isIdentChar2(sql[i - 1])) {
11424
+ continue;
11425
+ }
11426
+ const rest = sql.slice(i);
11427
+ if (/^LIMIT\b/i.test(rest)) {
11428
+ hits.push({ kind: "limit", start: i, depth, statement });
11429
+ i += 4;
11430
+ continue;
11431
+ }
11432
+ if (/^OFFSET\b/i.test(rest)) {
11433
+ hits.push({ kind: "offset", start: i, depth, statement });
11434
+ i += 5;
11435
+ }
11436
+ }
11437
+ return hits;
11438
+ }
11439
+ function injectLimitBeforeBareOffsets(sql) {
11440
+ const hits = collectLimitOffsetKeywords(sql);
11441
+ if (hits.length === 0) return sql;
11442
+ const injectAt = [];
11443
+ for (const hit of hits) {
11444
+ if (hit.kind !== "offset") continue;
11445
+ let hasLimit = false;
11446
+ for (let i = hits.length - 1; i >= 0; i -= 1) {
11447
+ const prev = hits[i];
11448
+ if (prev.start >= hit.start) continue;
11449
+ if (prev.statement !== hit.statement) continue;
11450
+ if (prev.depth !== hit.depth) continue;
11451
+ if (prev.kind === "limit") {
11452
+ hasLimit = true;
11453
+ break;
11454
+ }
11455
+ if (prev.kind === "offset") {
11456
+ break;
11457
+ }
11458
+ }
11459
+ if (!hasLimit) {
11460
+ injectAt.push(hit.start);
11461
+ }
11462
+ }
11463
+ if (injectAt.length === 0) return sql;
11464
+ let out = sql;
11465
+ for (let i = injectAt.length - 1; i >= 0; i -= 1) {
11466
+ const at = injectAt[i];
11467
+ out = `${out.slice(0, at)}LIMIT -1 ${out.slice(at)}`;
11468
+ }
11469
+ return out;
11470
+ }
11471
+ function rewritePostgresSqlForSqlite(sql) {
11472
+ const castPattern = new RegExp(`::(?:${PG_CAST_TYPES})\\b`, "gi");
11473
+ const withoutCastsAndIlike = mapSqlOutsideLiterals(sql, (chunk) => {
11474
+ let rewritten = chunk.replace(castPattern, "");
11475
+ rewritten = rewritten.replace(/\bILIKE\b/gi, "LIKE");
11476
+ return rewritten;
11477
+ });
11478
+ return injectLimitBeforeBareOffsets(withoutCastsAndIlike);
11479
+ }
11480
+
11481
+ // src/cloudflare/d1/transport.ts
11482
+ function hasPaginationBounds2(payload) {
11483
+ return payload.limit !== void 0 || payload.offset !== void 0 || payload.page_size !== void 0 || payload.current_page !== void 0;
11484
+ }
11485
+ function normalizeSqliteCollation(name) {
11486
+ const raw = String(name ?? "").trim().replace(/^["'`[]|["'`\]]$/g, "");
11487
+ if (!raw) return "BINARY";
11488
+ return raw.toUpperCase();
11489
+ }
11490
+ function findCreateTableColumnListOpen(createSql) {
11491
+ const m = /\bCREATE\s+(?:(?:TEMP|TEMPORARY|VIRTUAL)\s+)?TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?/i.exec(
11492
+ createSql
11493
+ );
11494
+ if (!m) return -1;
11495
+ let i = m.index + m[0].length;
11496
+ let inSingle = false;
11497
+ let inDouble = false;
11498
+ let inBacktick = false;
11499
+ let inBracket = false;
11500
+ while (i < createSql.length) {
11501
+ const ch = createSql[i];
11502
+ if (inSingle) {
11503
+ if (ch === "'" && createSql[i + 1] === "'") {
11504
+ i += 2;
11505
+ continue;
11506
+ }
11507
+ if (ch === "'") inSingle = false;
11508
+ i++;
11509
+ continue;
11510
+ }
11511
+ if (inDouble) {
11512
+ if (ch === '"') inDouble = false;
11513
+ i++;
11514
+ continue;
11515
+ }
11516
+ if (inBacktick) {
11517
+ if (ch === "`") inBacktick = false;
11518
+ i++;
11519
+ continue;
11520
+ }
11521
+ if (inBracket) {
11522
+ if (ch === "]") inBracket = false;
11523
+ i++;
11524
+ continue;
11525
+ }
11526
+ if (ch === "'") {
11527
+ inSingle = true;
11528
+ i++;
11529
+ continue;
11530
+ }
11531
+ if (ch === '"') {
11532
+ inDouble = true;
11533
+ i++;
11534
+ continue;
11535
+ }
11536
+ if (ch === "`") {
11537
+ inBacktick = true;
11538
+ i++;
11539
+ continue;
11540
+ }
11541
+ if (ch === "[") {
11542
+ inBracket = true;
11543
+ i++;
11544
+ continue;
11545
+ }
11546
+ if (ch === "(") return i;
11547
+ i++;
11548
+ }
11549
+ return -1;
11550
+ }
11551
+ function parseColumnCollationFromCreateSql(createSql, columnName) {
11552
+ if (!createSql || !columnName) return null;
11553
+ const listOpen = findCreateTableColumnListOpen(createSql);
11554
+ if (listOpen < 0) return null;
11555
+ const listStart = listOpen + 1;
11556
+ const escaped = columnName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11557
+ const nameRe = new RegExp(
11558
+ `(?:^|[^\\w])(?:"${escaped}"|\`${escaped}\`|\\[${escaped}\\]|${escaped})\\s+`,
11559
+ "i"
11560
+ );
11561
+ const listSlice = createSql.slice(listStart);
11562
+ let nameMatchAbs = -1;
11563
+ let nameMatchLen = 0;
11564
+ {
11565
+ let i2 = 0;
11566
+ let depth2 = 1;
11567
+ let inSingle2 = false;
11568
+ let inDouble2 = false;
11569
+ let inBacktick2 = false;
11570
+ let inBracket2 = false;
11571
+ let segmentStart = 0;
11572
+ const trySegment = (from, to) => {
11573
+ if (nameMatchAbs >= 0) return;
11574
+ const segment = listSlice.slice(from, to);
11575
+ const m = nameRe.exec(segment);
11576
+ if (!m) return;
11577
+ const leading = segment.slice(0, m.index).trim();
11578
+ if (leading.length > 0) return;
11579
+ nameMatchAbs = listStart + from + m.index;
11580
+ nameMatchLen = m[0].length;
11581
+ };
11582
+ while (i2 < listSlice.length && depth2 > 0) {
11583
+ const ch = listSlice[i2];
11584
+ if (inSingle2) {
11585
+ if (ch === "'" && listSlice[i2 + 1] === "'") {
11586
+ i2 += 2;
11587
+ continue;
11588
+ }
11589
+ if (ch === "'") inSingle2 = false;
11590
+ i2++;
11591
+ continue;
11592
+ }
11593
+ if (inDouble2) {
11594
+ if (ch === '"') inDouble2 = false;
11595
+ i2++;
11596
+ continue;
11597
+ }
11598
+ if (inBacktick2) {
11599
+ if (ch === "`") inBacktick2 = false;
11600
+ i2++;
11601
+ continue;
11602
+ }
11603
+ if (inBracket2) {
11604
+ if (ch === "]") inBracket2 = false;
11605
+ i2++;
11606
+ continue;
11607
+ }
11608
+ if (ch === "'") {
11609
+ inSingle2 = true;
11610
+ i2++;
11611
+ continue;
11612
+ }
11613
+ if (ch === '"') {
11614
+ inDouble2 = true;
11615
+ i2++;
11616
+ continue;
11617
+ }
11618
+ if (ch === "`") {
11619
+ inBacktick2 = true;
11620
+ i2++;
11621
+ continue;
11622
+ }
11623
+ if (ch === "[") {
11624
+ inBracket2 = true;
11625
+ i2++;
11626
+ continue;
11627
+ }
11628
+ if (ch === "(") {
11629
+ depth2++;
11630
+ i2++;
11631
+ continue;
11632
+ }
11633
+ if (ch === ")") {
11634
+ depth2--;
11635
+ if (depth2 === 0) {
11636
+ trySegment(segmentStart, i2);
11637
+ break;
11638
+ }
11639
+ i2++;
11640
+ continue;
11641
+ }
11642
+ if (ch === "," && depth2 === 1) {
11643
+ trySegment(segmentStart, i2);
11644
+ segmentStart = i2 + 1;
11645
+ i2++;
11646
+ continue;
11647
+ }
11648
+ i2++;
11649
+ }
11650
+ }
11651
+ if (nameMatchAbs < 0 || nameMatchLen <= 0) return null;
11652
+ const start = nameMatchAbs + nameMatchLen;
11653
+ let i = start;
11654
+ let depth = 0;
11655
+ let inSingle = false;
11656
+ let inDouble = false;
11657
+ let inBacktick = false;
11658
+ let inBracket = false;
11659
+ while (i < createSql.length) {
11660
+ const ch = createSql[i];
11661
+ if (inSingle) {
11662
+ if (ch === "'" && createSql[i + 1] === "'") {
11663
+ i += 2;
11664
+ continue;
11665
+ }
11666
+ if (ch === "'") inSingle = false;
11667
+ i++;
11668
+ continue;
11669
+ }
11670
+ if (inDouble) {
11671
+ if (ch === '"') inDouble = false;
11672
+ i++;
11673
+ continue;
11674
+ }
11675
+ if (inBacktick) {
11676
+ if (ch === "`") inBacktick = false;
11677
+ i++;
11678
+ continue;
11679
+ }
11680
+ if (inBracket) {
11681
+ if (ch === "]") inBracket = false;
11682
+ i++;
11683
+ continue;
11684
+ }
11685
+ if (ch === "'") {
11686
+ inSingle = true;
11687
+ i++;
11688
+ continue;
11689
+ }
11690
+ if (ch === '"') {
11691
+ inDouble = true;
11692
+ i++;
11693
+ continue;
11694
+ }
11695
+ if (ch === "`") {
11696
+ inBacktick = true;
11697
+ i++;
11698
+ continue;
11699
+ }
11700
+ if (ch === "[") {
11701
+ inBracket = true;
11702
+ i++;
11703
+ continue;
11704
+ }
11705
+ if (ch === "(") {
11706
+ depth++;
11707
+ i++;
11708
+ continue;
11709
+ }
11710
+ if (ch === ")") {
11711
+ if (depth === 0) {
11712
+ break;
11713
+ }
11714
+ depth--;
11715
+ i++;
11716
+ continue;
11717
+ }
11718
+ if (ch === "," && depth === 0) {
11719
+ break;
11720
+ }
11721
+ i++;
11722
+ }
11723
+ const colDef = createSql.slice(start, i);
11724
+ const collRe = /\bCOLLATE\s+("([^"]+)"|'([^']+)'|`([^`]+)`|\[([^\]]+)\]|([A-Za-z_][\w$]*))/i;
11725
+ const match = collRe.exec(colDef);
11726
+ if (!match) return null;
11727
+ return match[2] ?? match[3] ?? match[4] ?? match[5] ?? match[6] ?? match[1] ?? null;
11728
+ }
11729
+ async function indexCollationMatchesColumn(d1, table2, tableSafe, indexSafe, columnName, session) {
11730
+ const xinfo = await executeD1Query(d1, {
11731
+ query: `PRAGMA index_xinfo("${indexSafe}")`,
11732
+ params: [],
11733
+ ...session
11734
+ });
11735
+ if (!xinfo.ok) {
11736
+ return false;
11737
+ }
11738
+ const xRows = xinfo.rows ?? [];
11739
+ const keyRows = xRows.filter((row) => {
11740
+ const isKey = row.key === 1 || row.key === true || Number(row.key) === 1;
11741
+ if (!isKey) return false;
11742
+ return typeof row.name === "string" && row.name === columnName;
11743
+ });
11744
+ if (keyRows.length === 0) {
11745
+ const byName = xRows.find(
11746
+ (row) => typeof row.name === "string" && row.name === columnName
11747
+ );
11748
+ if (!byName) return false;
11749
+ keyRows.push(byName);
11750
+ }
11751
+ const indexColl = normalizeSqliteCollation(keyRows[0]?.coll);
11752
+ const master = await executeD1Query(d1, {
11753
+ query: `SELECT sql AS create_sql FROM sqlite_master WHERE type = 'table' AND name = ?`,
11754
+ params: [table2],
11755
+ ...session
11756
+ });
11757
+ let createSql = "";
11758
+ if (master.ok && Array.isArray(master.rows) && master.rows.length > 0) {
11759
+ createSql = String(
11760
+ master.rows[0]?.create_sql ?? ""
11761
+ );
11762
+ }
11763
+ const columnCollRaw = parseColumnCollationFromCreateSql(createSql, columnName);
11764
+ const columnColl = normalizeSqliteCollation(columnCollRaw);
11765
+ return indexColl === columnColl;
11766
+ }
11767
+ async function resolveD1BoundedIdentityColumn(d1, tableName, session) {
11768
+ const table2 = tableName.trim();
11769
+ if (!table2) {
11770
+ throw new D1SqlCompileError("missing_table", "table_name is required for bounded mutation");
11771
+ }
11772
+ const safe = table2.replace(/"/g, '""');
11773
+ const info = await executeD1Query(d1, {
11774
+ query: `PRAGMA table_info("${safe}")`,
11775
+ params: [],
11776
+ ...session
11777
+ });
11778
+ if (!info.ok) {
11779
+ throw new D1SqlCompileError(
11780
+ "bounded_mutation_no_unique_identity",
11781
+ `Unable to introspect table "${table2}" for bounded mutation identity: ${info.message}`
11782
+ );
11783
+ }
11784
+ const cols = info.rows.filter(
11785
+ (row) => typeof row?.name === "string" && row.name.length > 0
11786
+ );
11787
+ const colByName = new Map(cols.map((col) => [col.name, col]));
11788
+ const isNotNullColumn = (name) => {
11789
+ const col = colByName.get(name);
11790
+ if (!col) return false;
11791
+ return col.notnull === 1 || col.notnull === true || Number(col.notnull) === 1;
11792
+ };
11793
+ const isIntegerPrimaryKeyType = (col) => {
11794
+ if (typeof col.pk !== "number" || col.pk <= 0) return false;
11795
+ const declared = String(col.type ?? "").trim().toUpperCase();
11796
+ return declared === "INTEGER";
11797
+ };
11798
+ const loadIndexList = async () => {
11799
+ const indexList = await executeD1Query(d1, {
11800
+ query: `PRAGMA index_list("${safe}")`,
11801
+ params: [],
11802
+ ...session
11803
+ });
11804
+ if (!indexList.ok) return null;
11805
+ return indexList.rows;
11806
+ };
11807
+ const isDescendingIntegerPrimaryKeyException = async (colName, indexes) => {
11808
+ if (indexes) {
11809
+ const hasPkOrigin = indexes.some(
11810
+ (index) => String(index.origin ?? "").toLowerCase() === "pk"
11811
+ );
11812
+ if (hasPkOrigin) return true;
11813
+ const originReported = indexes.some(
11814
+ (index) => index.origin !== void 0 && index.origin !== null && String(index.origin).length > 0
11815
+ );
11816
+ if (indexes.length === 0 || originReported) {
11817
+ return false;
11818
+ }
11819
+ }
11820
+ const master = await executeD1Query(d1, {
11821
+ query: `SELECT sql AS create_sql FROM sqlite_master WHERE type = 'table' AND name = ?`,
11822
+ params: [table2],
11823
+ ...session
11824
+ });
11825
+ if (!master.ok || !Array.isArray(master.rows) || master.rows.length === 0) {
11826
+ return false;
11827
+ }
11828
+ const createSql = String(
11829
+ master.rows[0]?.create_sql ?? ""
11830
+ );
11831
+ if (!createSql) return false;
11832
+ const escaped = colName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11833
+ const inlineDesc = new RegExp(
11834
+ `(?:^|[^\\w])(?:"${escaped}"|${escaped})\\s+INTEGER\\s+PRIMARY\\s+KEY\\s+DESC\\b`,
11835
+ "i"
11836
+ );
11837
+ const tableDesc = new RegExp(
11838
+ `PRIMARY\\s+KEY\\s*\\(\\s*(?:"${escaped}"|${escaped})\\s+DESC\\b`,
11839
+ "i"
11840
+ );
11841
+ return inlineDesc.test(createSql) || tableDesc.test(createSql);
11842
+ };
11843
+ const pkCols = cols.filter((row) => typeof row.pk === "number" && row.pk > 0).sort((a, b) => (a.pk ?? 0) - (b.pk ?? 0));
11844
+ let indexRows;
11845
+ if (pkCols.length === 1 && pkCols[0]?.name) {
11846
+ if (isIntegerPrimaryKeyType(pkCols[0])) {
11847
+ indexRows = await loadIndexList();
11848
+ const isDescException = await isDescendingIntegerPrimaryKeyException(
11849
+ pkCols[0].name,
11850
+ indexRows
11851
+ );
11852
+ if (!isDescException) {
11853
+ return pkCols[0].name;
11854
+ }
11855
+ } else if (isNotNullColumn(pkCols[0].name)) {
11856
+ indexRows = await loadIndexList();
11857
+ const pkIndex = (indexRows ?? []).find(
11858
+ (index) => String(index.origin ?? "").toLowerCase() === "pk"
11859
+ );
11860
+ if (pkIndex && typeof pkIndex.name === "string" && pkIndex.name) {
11861
+ const indexSafe = pkIndex.name.replace(/"/g, '""');
11862
+ const collMatch = await indexCollationMatchesColumn(
11863
+ d1,
11864
+ table2,
11865
+ safe,
11866
+ indexSafe,
11867
+ pkCols[0].name,
11868
+ session
11869
+ );
11870
+ if (collMatch) {
11871
+ return pkCols[0].name;
11872
+ }
11873
+ }
11874
+ }
11875
+ }
11876
+ if (indexRows === void 0) {
11877
+ indexRows = await loadIndexList();
11878
+ }
11879
+ if (indexRows) {
11880
+ for (const index of indexRows) {
11881
+ const unique = index.unique === 1 || index.unique === true || Number(index.unique) === 1;
11882
+ if (!unique || typeof index.name !== "string" || !index.name) continue;
11883
+ const isPartial = index.partial === 1 || index.partial === true || Number(index.partial) === 1;
11884
+ if (isPartial) {
11885
+ continue;
11886
+ }
11887
+ const indexSafe = index.name.replace(/"/g, '""');
11888
+ const indexInfo = await executeD1Query(d1, {
11889
+ query: `PRAGMA index_info("${indexSafe}")`,
11890
+ params: [],
11891
+ ...session
11892
+ });
11893
+ if (!indexInfo.ok) continue;
11894
+ const rawIndexCols = indexInfo.rows ?? [];
11895
+ const hasExpressionTerm = rawIndexCols.some((row) => {
11896
+ const nameOk = typeof row?.name === "string" && row.name.length > 0;
11897
+ if (!nameOk) return true;
11898
+ if (typeof row.cid === "number" && row.cid < 0) return true;
11899
+ return false;
11900
+ });
11901
+ if (hasExpressionTerm || rawIndexCols.length === 0) {
11902
+ continue;
11903
+ }
11904
+ const indexCols = rawIndexCols.filter(
11905
+ (row) => typeof row?.name === "string" && row.name.length > 0
11906
+ );
11907
+ if (indexCols.length === 1 && indexCols[0]?.name) {
11908
+ const identity = indexCols[0].name;
11909
+ if (!isNotNullColumn(identity)) {
11910
+ continue;
11911
+ }
11912
+ const collMatch = await indexCollationMatchesColumn(
11913
+ d1,
11914
+ table2,
11915
+ safe,
11916
+ indexSafe,
11917
+ identity,
11918
+ session
11919
+ );
11920
+ if (!collMatch) {
11921
+ continue;
11922
+ }
11923
+ return identity;
11924
+ }
11925
+ }
11926
+ }
11927
+ throw new D1SqlCompileError(
11928
+ "bounded_mutation_no_unique_identity",
11929
+ `Bounded update/delete on "${table2}" requires a proven single-column PRIMARY KEY or UNIQUE index`
11930
+ );
11931
+ }
11932
+ async function compileOptionsForBoundedMutation(d1, payload, session) {
11933
+ if (!hasPaginationBounds2(payload) && !payload.sort_by) {
11934
+ return void 0;
11935
+ }
11936
+ if (!hasPaginationBounds2(payload)) {
11937
+ return void 0;
11938
+ }
11939
+ const identityColumn = await resolveD1BoundedIdentityColumn(
11940
+ d1,
11941
+ payload.table_name ?? "",
11942
+ session
11943
+ );
11944
+ return { identityColumn };
11945
+ }
11946
+ function headerValue2(options, name) {
11947
+ const headers = options?.headers;
11948
+ if (!headers) return void 0;
11949
+ const lower = name.toLowerCase();
11950
+ for (const [key, value] of Object.entries(headers)) {
11951
+ if (key.toLowerCase() === lower && value?.trim()) {
11952
+ return value.trim();
11953
+ }
11954
+ }
11955
+ return void 0;
11956
+ }
11957
+ function sessionFromOptions(options, defaults) {
11958
+ return {
11959
+ bookmark: headerValue2(options, "x-athena-d1-bookmark") ?? null,
11960
+ sessionMode: headerValue2(options, "x-athena-d1-session-mode") ?? defaults.defaultSessionMode ?? null
11961
+ };
11962
+ }
11963
+ function resolveStripNulls(payloadStrip, callOptions, defaultValue = true) {
11964
+ if (typeof payloadStrip === "boolean") return payloadStrip;
11965
+ if (typeof callOptions?.stripNulls === "boolean") return callOptions.stripNulls;
11966
+ return defaultValue;
11967
+ }
11968
+ function stripNullPropertiesFromRows(rows) {
11969
+ return rows.map((row) => {
11970
+ if (row == null || typeof row !== "object" || Array.isArray(row)) {
11971
+ return row;
11972
+ }
11973
+ const out = {};
11974
+ for (const [key, value] of Object.entries(row)) {
11975
+ if (value !== null) {
11976
+ out[key] = value;
11977
+ }
11978
+ }
11979
+ return out;
11980
+ });
11981
+ }
11982
+ function maybeStripNullRows(rows, strip) {
11983
+ return strip ? stripNullPropertiesFromRows(rows) : rows;
11984
+ }
11985
+ function successResponse(data, count, raw, bookmark) {
11986
+ const response = {
11987
+ ok: true,
11988
+ status: 200,
11989
+ statusText: "OK",
11990
+ data,
11991
+ count: count ?? null,
11992
+ error: void 0,
11993
+ errorDetails: null,
11994
+ raw
11995
+ };
11996
+ if (bookmark) {
11997
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
11998
+ const rawRecord = raw;
11999
+ rawRecord.bookmark = bookmark;
12000
+ }
12001
+ }
12002
+ return response;
12003
+ }
12004
+ function errorResponse(status, code, message, endpoint, method, hint) {
12005
+ const error = new AthenaGatewayError({
12006
+ code,
12007
+ message,
12008
+ status,
12009
+ endpoint,
12010
+ method,
12011
+ hint
12012
+ });
12013
+ return {
12014
+ ok: false,
12015
+ status,
12016
+ statusText: null,
12017
+ data: null,
12018
+ error: error.message,
12019
+ errorDetails: error.toDetails(),
12020
+ raw: { error: message, code }
12021
+ };
12022
+ }
12023
+ function compileErrorResponse(error, endpoint, method) {
12024
+ if (error instanceof D1SqlCompileError) {
12025
+ return errorResponse(
12026
+ 400,
12027
+ "HTTP_ERROR",
12028
+ error.message,
12029
+ endpoint,
12030
+ method,
12031
+ `D1 SQL compile failed (${error.code})`
12032
+ );
12033
+ }
12034
+ const message = error instanceof Error ? error.message : String(error);
12035
+ return errorResponse(500, "UNKNOWN_ERROR", message, endpoint, method);
12036
+ }
12037
+ function createCloudflareD1GatewayTransport(options) {
12038
+ const { d1 } = options;
12039
+ async function runCompiled(compiled, callOptions, endpoint, method, mapResult, stripNulls = true) {
12040
+ try {
12041
+ const session = sessionFromOptions(callOptions, options);
12042
+ if (compiled.statements && compiled.statements.length > 1) {
12043
+ const batch = await executeD1Batch(d1, {
12044
+ statements: compiled.statements.map((statement) => ({
12045
+ query: statement.sql,
12046
+ params: statement.params
12047
+ })),
12048
+ ...session
12049
+ });
12050
+ if (!batch.ok) {
12051
+ return errorResponse(400, "HTTP_ERROR", batch.message, endpoint, method);
12052
+ }
12053
+ const rows2 = maybeStripNullRows(
12054
+ batch.results.flatMap(
12055
+ (item) => Array.isArray(item.results) ? item.results : []
12056
+ ),
12057
+ stripNulls
12058
+ );
12059
+ const changes = batch.results.reduce((sum2, item) => {
12060
+ const meta = item?.meta;
12061
+ const n = meta && typeof meta === "object" && typeof meta.changes === "number" ? meta.changes : 0;
12062
+ return sum2 + n;
12063
+ }, 0);
12064
+ const count = rows2.length > 0 ? rows2.length : changes;
12065
+ const mapped2 = mapResult?.(rows2, count) ?? {
12066
+ data: rows2,
12067
+ count
12068
+ };
12069
+ return successResponse(mapped2.data, mapped2.count, batch, batch.bookmark);
12070
+ }
12071
+ const result = await executeD1Query(d1, {
12072
+ query: compiled.sql,
12073
+ params: compiled.params,
12074
+ ...session
12075
+ });
12076
+ if (!result.ok) {
12077
+ return errorResponse(400, "HTTP_ERROR", result.message, endpoint, method);
12078
+ }
12079
+ const rows = maybeStripNullRows(result.rows, stripNulls);
12080
+ const mapped = mapResult?.(rows, result.count) ?? {
12081
+ data: rows,
12082
+ count: result.count
12083
+ };
12084
+ return successResponse(mapped.data, mapped.count, result, result.bookmark);
12085
+ } catch (error) {
12086
+ const message = error instanceof Error ? error.message : String(error);
12087
+ return errorResponse(500, "UNKNOWN_ERROR", message, endpoint, method);
12088
+ }
12089
+ }
12090
+ return {
12091
+ baseUrl: CLOUDFLARE_EDGE_BASE_URL,
12092
+ buildHeaders(callOptions) {
12093
+ return { ...callOptions?.headers ?? {} };
12094
+ },
12095
+ async resolveCallOptions(callOptions) {
12096
+ return callOptions;
12097
+ },
12098
+ async verifyConnection(connectionOptions) {
12099
+ const baseUrl = CLOUDFLARE_EDGE_BASE_URL;
12100
+ try {
12101
+ const result = await executeD1Query(d1, { query: "SELECT 1 AS ok" });
12102
+ if (!result.ok) {
12103
+ return {
12104
+ ok: false,
12105
+ reachable: false,
12106
+ status: 500,
12107
+ statusText: null,
12108
+ baseUrl,
12109
+ url: `${baseUrl}/d1`,
12110
+ error: result.message,
12111
+ errorDetails: null,
12112
+ raw: result
12113
+ };
12114
+ }
12115
+ return {
12116
+ ok: true,
12117
+ reachable: true,
12118
+ status: 200,
12119
+ statusText: "OK",
12120
+ baseUrl,
12121
+ url: `${baseUrl}/d1`,
12122
+ error: void 0,
12123
+ errorDetails: null,
12124
+ raw: result
12125
+ };
12126
+ } catch (error) {
12127
+ const message = error instanceof Error ? error.message : String(error);
12128
+ return {
12129
+ ok: false,
12130
+ reachable: false,
12131
+ status: 0,
12132
+ statusText: null,
12133
+ baseUrl,
12134
+ url: `${baseUrl}/d1`,
12135
+ error: message,
12136
+ errorDetails: null,
12137
+ raw: null
12138
+ };
12139
+ }
12140
+ },
12141
+ async fetchGateway(payload, callOptions) {
12142
+ try {
12143
+ if (payload && typeof payload === "object" && "operation" in payload) {
12144
+ return errorResponse(
12145
+ 400,
12146
+ "HTTP_ERROR",
12147
+ "Direct AST operation payloads are unsupported on D1 edge-local",
12148
+ "/gateway/fetch",
12149
+ "POST"
12150
+ );
12151
+ }
12152
+ const compiled = compileD1Fetch(payload);
12153
+ const stripNulls = resolveStripNulls(payload.strip_nulls, callOptions, true);
12154
+ if (payload.head === true) {
12155
+ return runCompiled(
12156
+ compiled,
12157
+ callOptions,
12158
+ "/gateway/fetch",
12159
+ "POST",
12160
+ (rows) => ({ data: [], count: extractAthenaCount(rows) }),
12161
+ // COUNT rows are meta, not user-facing object rows
12162
+ false
12163
+ );
12164
+ }
12165
+ const wantsTotalCount = payload.count === "exact" || payload.count === "planned" || payload.count === "estimated";
12166
+ if (wantsTotalCount) {
12167
+ const session = sessionFromOptions(callOptions, options);
12168
+ const countCompiled = compileD1Count(payload);
12169
+ const batch = await executeD1Batch(d1, {
12170
+ statements: [
12171
+ {
12172
+ query: compiled.sql,
12173
+ params: compiled.params
12174
+ },
12175
+ {
12176
+ query: countCompiled.sql,
12177
+ params: countCompiled.params
12178
+ }
12179
+ ],
12180
+ ...session
12181
+ });
12182
+ if (!batch.ok) {
12183
+ return errorResponse(400, "HTTP_ERROR", batch.message, "/gateway/fetch", "POST");
12184
+ }
12185
+ const dataItem = batch.results[0];
12186
+ const countItem = batch.results[1];
12187
+ if (!dataItem || dataItem.success === false) {
12188
+ const message = dataItem && typeof dataItem.error === "string" && dataItem.error.trim() ? dataItem.error : "D1 page query failed";
12189
+ return errorResponse(400, "HTTP_ERROR", message, "/gateway/fetch", "POST");
12190
+ }
12191
+ if (!countItem || countItem.success === false) {
12192
+ const message = countItem && typeof countItem.error === "string" && countItem.error.trim() ? countItem.error : "D1 count query failed";
12193
+ return errorResponse(400, "HTTP_ERROR", message, "/gateway/fetch", "POST");
12194
+ }
12195
+ const dataRows = Array.isArray(dataItem.results) ? dataItem.results : [];
12196
+ const countRows = Array.isArray(countItem.results) ? countItem.results : [];
12197
+ const total = extractAthenaCount(countRows);
12198
+ const rows = maybeStripNullRows(dataRows, stripNulls);
12199
+ return successResponse(
12200
+ rows,
12201
+ total,
12202
+ { data: dataItem, count: countItem, batch },
12203
+ batch.bookmark
12204
+ );
12205
+ }
12206
+ return runCompiled(compiled, callOptions, "/gateway/fetch", "POST", void 0, stripNulls);
12207
+ } catch (error) {
12208
+ return compileErrorResponse(error, "/gateway/fetch", "POST");
12209
+ }
12210
+ },
12211
+ async insertGateway(payload, callOptions) {
12212
+ try {
12213
+ const compiled = compileD1Insert(payload);
12214
+ const stripNulls = resolveStripNulls(void 0, callOptions, true);
12215
+ return runCompiled(compiled, callOptions, "/gateway/insert", "PUT", void 0, stripNulls);
12216
+ } catch (error) {
12217
+ return compileErrorResponse(error, "/gateway/insert", "PUT");
12218
+ }
12219
+ },
12220
+ async updateGateway(payload, callOptions) {
12221
+ try {
12222
+ const session = sessionFromOptions(callOptions, options);
12223
+ const compileOptions = await compileOptionsForBoundedMutation(d1, payload, session);
12224
+ const compiled = compileD1Update(payload, compileOptions);
12225
+ const stripNulls = resolveStripNulls(payload.strip_nulls, callOptions, true);
12226
+ return runCompiled(compiled, callOptions, "/gateway/update", "POST", void 0, stripNulls);
12227
+ } catch (error) {
12228
+ return compileErrorResponse(error, "/gateway/update", "POST");
12229
+ }
12230
+ },
12231
+ async deleteGateway(payload, callOptions) {
12232
+ try {
12233
+ const session = sessionFromOptions(callOptions, options);
12234
+ const compileOptions = await compileOptionsForBoundedMutation(d1, payload, session);
12235
+ const compiled = compileD1Delete(payload, compileOptions);
12236
+ const stripNulls = resolveStripNulls(void 0, callOptions, true);
12237
+ return runCompiled(compiled, callOptions, "/gateway/delete", "DELETE", void 0, stripNulls);
12238
+ } catch (error) {
12239
+ return compileErrorResponse(error, "/gateway/delete", "DELETE");
12240
+ }
12241
+ },
12242
+ async rpcGateway(payload, callOptions) {
12243
+ return errorResponse(
12244
+ 400,
12245
+ "HTTP_ERROR",
12246
+ "RPC is unsupported on D1 edge-local mode",
12247
+ "/gateway/rpc",
12248
+ "POST",
12249
+ "Use flat CRUD or raw query SQL instead"
12250
+ );
12251
+ },
12252
+ async queryGateway(payload, callOptions) {
12253
+ try {
12254
+ const params = payload.params ?? callOptions?.params;
12255
+ const session = sessionFromOptions(callOptions, options);
12256
+ const query = rewritePostgresSqlForSqlite(payload.query);
12257
+ const result = await executeD1Query(d1, {
12258
+ query,
12259
+ params: Array.isArray(params) ? params : [],
12260
+ ...session
12261
+ });
12262
+ if (!result.ok) {
12263
+ return errorResponse(400, "HTTP_ERROR", result.message, "/gateway/query", "POST");
12264
+ }
12265
+ const stripNulls = resolveStripNulls(void 0, callOptions, true);
12266
+ const rows = maybeStripNullRows(result.rows, stripNulls);
12267
+ return successResponse(
12268
+ rows,
12269
+ result.count,
12270
+ { ...result, query },
12271
+ result.bookmark
12272
+ );
12273
+ } catch (error) {
12274
+ const message = error instanceof Error ? error.message : String(error);
12275
+ return errorResponse(500, "UNKNOWN_ERROR", message, "/gateway/query", "POST");
12276
+ }
12277
+ }
12278
+ };
12279
+ }
12280
+
12281
+ // src/config/errors.ts
12282
+ var AthenaConfigurationError = class extends Error {
12283
+ code;
12284
+ service;
12285
+ constructor(code, message, service) {
12286
+ super(message);
12287
+ this.name = "AthenaConfigurationError";
12288
+ this.code = code;
12289
+ this.service = service;
12290
+ }
12291
+ };
12292
+
12293
+ // src/cloudflare/execution-mode.ts
12294
+ var ATHENA_EXECUTION_MODE_ENV_KEY = "ATHENA_EXECUTION_MODE";
12295
+ var ATHENA_EXECUTION_PREFER_ENV_KEY = "ATHENA_EXECUTION_PREFER";
12296
+ var MODE_ALIASES = {
12297
+ gateway: "gateway",
12298
+ server: "gateway",
12299
+ remote: "gateway",
12300
+ http: "gateway",
12301
+ edge: "edge",
12302
+ cloudflare: "edge",
12303
+ "cloudflare-edge": "edge",
12304
+ d1: "edge",
12305
+ local: "edge",
12306
+ auto: "auto"
12307
+ };
12308
+ function normalizeOptional(value) {
12309
+ const trimmed = value?.trim();
12310
+ return trimmed || void 0;
12311
+ }
12312
+ function normalizeModeString(value) {
12313
+ if (value == null) return void 0;
12314
+ const key = value.trim().toLowerCase();
12315
+ if (!key) return void 0;
12316
+ const mapped = MODE_ALIASES[key];
12317
+ if (!mapped) {
12318
+ throw new AthenaConfigurationError(
12319
+ "ATHENA_NO_SERVICE_CONFIGURED",
12320
+ `Unknown Athena execution mode "${value}". Use gateway | edge | auto (aliases: server, remote, cloudflare, d1).`,
12321
+ "db"
12322
+ );
12323
+ }
12324
+ return mapped;
12325
+ }
12326
+ function isD1Binding(value) {
12327
+ return Boolean(
12328
+ value && typeof value === "object" && typeof value.prepare === "function"
12329
+ );
12330
+ }
12331
+ var GATEWAY_URL_ENV_KEYS = [
12332
+ "ATHENA_URL",
12333
+ "NEXT_PUBLIC_ATHENA_URL",
12334
+ "ATHENA_DB_URL",
12335
+ "ATHENA_GATEWAY_URL",
12336
+ "NEXT_PUBLIC_ATHENA_DB_API_URL"
12337
+ ];
12338
+ function resolveGatewayUrl(url, env) {
12339
+ if (normalizeOptional(url)) {
12340
+ return normalizeOptional(url);
12341
+ }
12342
+ for (const key of GATEWAY_URL_ENV_KEYS) {
12343
+ const value = normalizeOptional(env[key]);
12344
+ if (value) return value;
12345
+ }
12346
+ return void 0;
12347
+ }
12348
+ function resolvePrefer(prefer, env) {
12349
+ const raw = normalizeOptional(typeof prefer === "string" ? prefer : prefer ?? void 0) ?? normalizeOptional(env[ATHENA_EXECUTION_PREFER_ENV_KEY]) ?? "edge";
12350
+ const key = raw.toLowerCase();
12351
+ if (key === "gateway" || key === "server" || key === "remote" || key === "http") {
12352
+ return "gateway";
12353
+ }
12354
+ if (key === "edge" || key === "d1" || key === "cloudflare" || key === "local") {
12355
+ return "edge";
12356
+ }
12357
+ throw new AthenaConfigurationError(
12358
+ "ATHENA_NO_SERVICE_CONFIGURED",
12359
+ `Unknown Athena execution prefer "${raw}". Use edge | gateway.`,
12360
+ "db"
12361
+ );
12362
+ }
12363
+ function resolveAthenaExecutionMode(input = {}) {
12364
+ const env = input.env ?? {};
12365
+ const fromEnv = normalizeModeString(env[ATHENA_EXECUTION_MODE_ENV_KEY]);
12366
+ const requested = normalizeModeString(input.mode) ?? fromEnv ?? "auto";
12367
+ const url = resolveGatewayUrl(input.url, env);
12368
+ const hasD1 = isD1Binding(input.d1);
12369
+ const hasGateway = Boolean(url);
12370
+ if (requested === "gateway") {
12371
+ if (!hasGateway) {
12372
+ throw new AthenaConfigurationError(
12373
+ "ATHENA_NO_SERVICE_CONFIGURED",
12374
+ 'Athena execution mode is "gateway" but no url / ATHENA_URL / ATHENA_DB_URL / ATHENA_GATEWAY_URL was provided.',
12375
+ "db"
12376
+ );
12377
+ }
12378
+ return "gateway";
12379
+ }
12380
+ if (requested === "edge") {
12381
+ if (!hasD1) {
12382
+ throw new AthenaConfigurationError(
12383
+ "ATHENA_NO_SERVICE_CONFIGURED",
12384
+ 'Athena execution mode is "edge" but no D1 binding was provided (db.d1 / config.d1 / env.DB).',
12385
+ "db"
12386
+ );
12387
+ }
12388
+ return "edge";
12389
+ }
12390
+ if (hasD1 && hasGateway) {
12391
+ return resolvePrefer(input.prefer, env);
12392
+ }
12393
+ if (hasD1) return "edge";
12394
+ if (hasGateway) return "gateway";
12395
+ throw new AthenaConfigurationError(
12396
+ "ATHENA_NO_SERVICE_CONFIGURED",
12397
+ 'Cannot resolve Athena execution mode: provide mode "gateway" with url/key, mode "edge" with d1, or mode "auto" with either a D1 binding or a gateway URL (ATHENA_URL / ATHENA_DB_URL / ATHENA_GATEWAY_URL).',
12398
+ "db"
12399
+ );
12400
+ }
12401
+
12402
+ // src/cloudflare/r2/storage.ts
12403
+ function normalizePrefix(prefix) {
12404
+ if (!prefix?.trim()) return "";
12405
+ const normalized = prefix.replace(/^\/+/, "").replace(/\/?$/, "/");
12406
+ if (normalized.includes("\0")) {
12407
+ throw new Error("storage prefix must not contain null bytes");
12408
+ }
12409
+ if (normalized.split("/").some((segment) => segment === "..")) {
12410
+ throw new Error('storage prefix must not contain ".." path segments');
12411
+ }
12412
+ return normalized;
12413
+ }
12414
+ function assertSafeObjectKey(key) {
12415
+ if (typeof key !== "string" || !key.trim()) {
12416
+ throw new Error("Object key is required");
12417
+ }
12418
+ if (key.includes("\0")) {
12419
+ throw new Error("Object key must not contain null bytes");
12420
+ }
12421
+ const cleaned = key.replace(/^\/+/, "");
12422
+ if (!cleaned) {
12423
+ throw new Error("Object key is required");
12424
+ }
12425
+ const segments = cleaned.split("/");
12426
+ if (segments.some((segment) => segment === "..")) {
12427
+ throw new Error('Object key must not contain ".." path segments');
12428
+ }
12429
+ return cleaned;
12430
+ }
12431
+ function joinKey(prefix, key) {
12432
+ return `${prefix}${assertSafeObjectKey(key)}`;
12433
+ }
12434
+ function toLogicalKey(prefix, physicalKey) {
12435
+ if (!prefix) return physicalKey;
12436
+ if (physicalKey.startsWith(prefix)) {
12437
+ return physicalKey.slice(prefix.length);
12438
+ }
12439
+ return physicalKey;
12440
+ }
12441
+ function toPhysicalKey(prefix, key) {
12442
+ return joinKey(prefix, key);
12443
+ }
12444
+ function unsupported(method) {
12445
+ throw new Error(
12446
+ `storage.${method} is not available in Cloudflare edge-local R2 object mode. Only putObject / getObject / deleteObject / listObjects are supported (L3a).`
12447
+ );
12448
+ }
12449
+ function createCloudflareR2StorageModule(options) {
12450
+ const prefix = normalizePrefix(options.prefix);
12451
+ const { r2 } = options;
12452
+ const putObject = async (input) => {
12453
+ const logical = assertSafeObjectKey(input.key);
12454
+ const physical = toPhysicalKey(prefix, logical);
12455
+ await r2.put(physical, input.body, {
12456
+ httpMetadata: input.contentType ? { contentType: input.contentType } : void 0,
12457
+ customMetadata: input.metadata
12458
+ });
12459
+ return { key: logical };
12460
+ };
12461
+ const getObject = async (input) => {
12462
+ const logical = assertSafeObjectKey(input.key);
12463
+ const physical = toPhysicalKey(prefix, logical);
12464
+ const object = await r2.get(physical);
12465
+ if (!object) return null;
12466
+ return {
12467
+ key: toLogicalKey(prefix, object.key),
12468
+ size: object.size,
12469
+ contentType: object.httpMetadata?.contentType,
12470
+ body: object
12471
+ };
12472
+ };
12473
+ const deleteObject = async (input) => {
12474
+ const logicalKeys = (Array.isArray(input.key) ? input.key : [input.key]).map(
12475
+ (key) => assertSafeObjectKey(key)
12476
+ );
12477
+ const physicalKeys = logicalKeys.map((key) => toPhysicalKey(prefix, key));
12478
+ await r2.delete(physicalKeys.length === 1 ? physicalKeys[0] : physicalKeys);
12479
+ return { deleted: logicalKeys };
12480
+ };
12481
+ const listObjects = async (input) => {
12482
+ const relative = input?.prefix?.trim() ? assertSafeObjectKey(input.prefix) : "";
12483
+ const listPrefix = `${prefix}${relative}`;
12484
+ const listed = await r2.list({
12485
+ prefix: listPrefix || void 0,
12486
+ limit: input?.limit,
12487
+ cursor: input?.cursor
12488
+ });
12489
+ return {
12490
+ objects: listed.objects.map((object) => ({
12491
+ key: toLogicalKey(prefix, object.key),
12492
+ size: object.size,
12493
+ etag: object.etag,
12494
+ uploaded: object.uploaded
12495
+ })),
12496
+ truncated: listed.truncated,
12497
+ cursor: listed.cursor
12498
+ };
12499
+ };
12500
+ const base = {
12501
+ putObject,
12502
+ getObject,
12503
+ deleteObject,
12504
+ listObjects
12505
+ };
12506
+ return new Proxy(base, {
12507
+ get(target, property, receiver) {
12508
+ if (property in target) {
12509
+ return Reflect.get(target, property, receiver);
12510
+ }
12511
+ if (typeof property === "string") {
12512
+ return (...args) => {
12513
+ return unsupported(property);
12514
+ };
12515
+ }
12516
+ return void 0;
12517
+ }
12518
+ });
12519
+ }
12520
+
12521
+ // src/billing/module.ts
12522
+ var SDK_NAME5 = "xylex-group/athena-billing";
12523
+ var SDK_HEADER_VALUE4 = buildSdkHeaderValue(SDK_NAME5);
12524
+ var AthenaBillingError = class extends Error {
12525
+ status;
12526
+ endpoint;
12527
+ method;
12528
+ body;
12529
+ constructor(input) {
12530
+ super(input.message);
12531
+ this.name = "AthenaBillingError";
12532
+ this.status = input.status;
12533
+ this.endpoint = input.endpoint;
12534
+ this.method = input.method;
12535
+ this.body = input.body;
12536
+ }
12537
+ };
12538
+ var billingSdkManifest = {
12539
+ namespace: "billing",
12540
+ envelopeKind: "athena",
12541
+ methods: [
12542
+ { name: "getCapabilities", method: "GET", path: "/billing/v1/capabilities" },
12543
+ { name: "createCheckout", method: "POST", path: "/billing/v1/checkouts" },
12544
+ { name: "listProducts", method: "GET", path: "/billing/v1/products" },
12545
+ { name: "listPrices", method: "GET", path: "/billing/v1/prices" },
12546
+ { name: "listCustomers", method: "GET", path: "/billing/v1/customers" },
12547
+ { name: "createCustomer", method: "POST", path: "/billing/v1/customers" },
12548
+ { name: "getCustomer", method: "GET", path: "/billing/v1/customers/{id}" },
12549
+ { name: "updateCustomer", method: "PATCH", path: "/billing/v1/customers/{id}" },
12550
+ { name: "deleteCustomer", method: "DELETE", path: "/billing/v1/customers/{id}" },
12551
+ { name: "listPayments", method: "GET", path: "/billing/v1/payments" },
12552
+ { name: "createPayment", method: "POST", path: "/billing/v1/payments" },
12553
+ { name: "getPayment", method: "GET", path: "/billing/v1/payments/{id}" },
12554
+ { name: "cancelPayment", method: "POST", path: "/billing/v1/payments/{id}/cancel" },
12555
+ { name: "listPaymentLinks", method: "GET", path: "/billing/v1/payment-links" },
12556
+ { name: "createPaymentLink", method: "POST", path: "/billing/v1/payment-links" },
12557
+ { name: "getPaymentLink", method: "GET", path: "/billing/v1/payment-links/{id}" },
12558
+ { name: "updatePaymentLink", method: "PATCH", path: "/billing/v1/payment-links/{id}" },
12559
+ { name: "deletePaymentLink", method: "DELETE", path: "/billing/v1/payment-links/{id}" },
12560
+ { name: "listRefunds", method: "GET", path: "/billing/v1/refunds" },
12561
+ { name: "createRefund", method: "POST", path: "/billing/v1/refunds" },
12562
+ { name: "getRefund", method: "GET", path: "/billing/v1/refunds/{id}" },
12563
+ { name: "cancelRefund", method: "POST", path: "/billing/v1/refunds/{id}/cancel" },
12564
+ { name: "listSubscriptions", method: "GET", path: "/billing/v1/subscriptions" },
12565
+ { name: "createSubscription", method: "POST", path: "/billing/v1/subscriptions" },
12566
+ { name: "getSubscription", method: "GET", path: "/billing/v1/subscriptions/{id}" },
12567
+ { name: "updateSubscription", method: "PATCH", path: "/billing/v1/subscriptions/{id}" },
12568
+ { name: "cancelSubscription", method: "POST", path: "/billing/v1/subscriptions/{id}/cancel" },
12569
+ { name: "listInvoices", method: "GET", path: "/billing/v1/invoices" },
12570
+ { name: "getInvoice", method: "GET", path: "/billing/v1/invoices/{id}" },
12571
+ { name: "listWebhooks", method: "GET", path: "/billing/v1/webhooks" },
12572
+ { name: "createWebhook", method: "POST", path: "/billing/v1/webhooks" },
12573
+ { name: "getWebhook", method: "GET", path: "/billing/v1/webhooks/{id}" },
12574
+ { name: "updateWebhook", method: "PATCH", path: "/billing/v1/webhooks/{id}" },
12575
+ { name: "deleteWebhook", method: "DELETE", path: "/billing/v1/webhooks/{id}" },
12576
+ { name: "testWebhook", method: "POST", path: "/billing/v1/webhooks/{id}/test" },
12577
+ {
12578
+ name: "listConnections",
12579
+ method: "GET",
12580
+ path: "/admin/billing/clients/{client_name}/connections"
12581
+ },
12582
+ {
12583
+ name: "createConnection",
12584
+ method: "POST",
12585
+ path: "/admin/billing/clients/{client_name}/connections"
12586
+ },
12587
+ {
12588
+ name: "getConnection",
12589
+ method: "GET",
12590
+ path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
12591
+ },
12592
+ {
12593
+ name: "updateConnection",
12594
+ method: "PATCH",
12595
+ path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
12596
+ },
12597
+ {
12598
+ name: "deleteConnection",
12599
+ method: "DELETE",
12600
+ path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
12601
+ },
12602
+ {
12603
+ name: "reconcileDocument",
12604
+ method: "POST",
12605
+ path: "/admin/billing/clients/{client_name}/connections/{connection_id}/reconcile"
12606
+ },
12607
+ {
12608
+ name: "listWebhookEvents",
12609
+ method: "GET",
12610
+ path: "/admin/billing/clients/{client_name}/webhook-events"
12611
+ },
12612
+ {
12613
+ name: "provisionWebhookSinks",
12614
+ method: "POST",
12615
+ path: "/admin/billing/clients/{client_name}/webhook-sinks/provision"
12616
+ },
12617
+ { name: "listGrants", method: "GET", path: "/admin/billing/grants" },
12618
+ { name: "listProviders", method: "GET", path: "/admin/billing/providers" },
12619
+ {
12620
+ name: "listSinkHelpers",
12621
+ method: "GET",
12622
+ path: "/admin/webhook-sinks/helpers/billing"
12623
+ },
12624
+ {
12625
+ name: "ingestProviderWebhook",
12626
+ method: "POST",
12627
+ path: "/billing/providers/{provider}/clients/{client_name}/connections/{connection_id}/webhook"
12628
+ },
12629
+ { name: "getDebugBilling", method: "GET", path: "/debug/billing" }
12630
+ ]
12631
+ };
12632
+ function withPathParam2(path, name, value) {
12633
+ return path.replace(`{${name}}`, encodeURIComponent(value));
12634
+ }
12635
+ function appendQuery3(path, query) {
12636
+ if (!query) return path;
12637
+ const params = new URLSearchParams();
12638
+ for (const [key, value] of Object.entries(query)) {
12639
+ if (value === void 0 || value === null) continue;
12640
+ params.set(key, String(value));
12641
+ }
12642
+ const serialized = params.toString();
12643
+ return serialized ? `${path}?${serialized}` : path;
12644
+ }
12645
+ function connectionQuery(input) {
12646
+ const query = {
12647
+ connectionId: input.connectionId
12648
+ };
12649
+ if (input.clientName) query.clientName = input.clientName;
12650
+ if ("cursor" in input && input.cursor) query.cursor = input.cursor;
12651
+ if ("source" in input && input.source) query.source = input.source;
12652
+ if ("limit" in input && input.limit !== void 0) query.limit = String(input.limit);
12653
+ if ("offset" in input && input.offset !== void 0) query.offset = String(input.offset);
12654
+ return query;
12655
+ }
12656
+ function parseEnvelopeData(body) {
12657
+ if (body && typeof body === "object" && "data" in body) {
12658
+ return body.data;
12659
+ }
12660
+ return body;
12661
+ }
12662
+ function createBillingModule(config) {
12663
+ const baseUrl = normalizeAthenaGatewayBaseUrl(config.baseUrl, {
12664
+ label: "Athena billing base URL"
12665
+ });
12666
+ const fetchImpl = config.fetchImpl ?? globalThis.fetch.bind(globalThis);
12667
+ async function call(method, path, body, options, responseType = "json") {
12668
+ const headers = buildAthenaRequestHeaders({
12669
+ profile: "gateway",
12670
+ sdkHeaderValue: SDK_HEADER_VALUE4,
12671
+ apiKey: options?.apiKey ?? config.apiKey,
12672
+ client: config.client,
12673
+ configHeaders: {
12674
+ ...config.headers ?? {}
12675
+ },
12676
+ callHeaders: options?.headers,
12677
+ contentType: "application/json"
12678
+ });
12679
+ let requestBody;
12680
+ if (body !== void 0 && body !== null) {
12681
+ if (typeof body === "string" || body instanceof Blob || body instanceof ArrayBuffer || ArrayBuffer.isView(body) || body instanceof FormData || body instanceof URLSearchParams) {
12682
+ requestBody = body;
12683
+ } else {
12684
+ requestBody = JSON.stringify(body);
12685
+ if (!hasHeaderIgnoreCase(headers, "Content-Type")) {
12686
+ headers["Content-Type"] = "application/json";
12687
+ }
12688
+ }
12689
+ }
12690
+ const targetUrl = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
12691
+ const response = await fetchImpl(targetUrl, {
12692
+ method,
12693
+ headers,
12694
+ body: requestBody,
12695
+ signal: options?.signal
12696
+ });
12697
+ if (responseType === "text") {
12698
+ const text = await response.text();
12699
+ if (!response.ok) {
12700
+ throw new AthenaBillingError({
12701
+ message: `Billing request failed (${response.status})`,
12702
+ status: response.status,
12703
+ endpoint: path,
12704
+ method,
12705
+ body: text
12706
+ });
12707
+ }
12708
+ return text;
12709
+ }
12710
+ const rawText = await response.text();
12711
+ let parsed = rawText;
12712
+ if (rawText) {
12713
+ try {
12714
+ parsed = JSON.parse(rawText);
12715
+ } catch {
12716
+ parsed = rawText;
12717
+ }
12718
+ } else {
12719
+ parsed = null;
12720
+ }
12721
+ if (!response.ok) {
12722
+ const message = parsed && typeof parsed === "object" && "message" in parsed && typeof parsed.message === "string" ? parsed.message : `Billing request failed (${response.status})`;
12723
+ throw new AthenaBillingError({
12724
+ message,
12725
+ status: response.status,
10067
12726
  endpoint: path,
10068
12727
  method,
10069
12728
  body: parsed
@@ -10549,28 +13208,92 @@ function createBillingModule(config) {
10549
13208
  };
10550
13209
  }
10551
13210
 
10552
- // src/config/errors.ts
10553
- var AthenaConfigurationError = class extends Error {
10554
- code;
10555
- service;
10556
- constructor(code, message, service) {
10557
- super(message);
10558
- this.name = "AthenaConfigurationError";
10559
- this.code = code;
10560
- this.service = service;
13211
+ // src/context/merge.ts
13212
+ function mergeAthenaRequestContexts(base, override) {
13213
+ if (!base && !override) return void 0;
13214
+ return {
13215
+ ...base,
13216
+ ...override,
13217
+ headers: base?.headers || override?.headers ? {
13218
+ ...base?.headers ?? {},
13219
+ ...override?.headers ?? {}
13220
+ } : void 0
13221
+ };
13222
+ }
13223
+
13224
+ // src/diagnostics.ts
13225
+ function readProcessEnv2() {
13226
+ try {
13227
+ return globalThis.process?.env ?? {};
13228
+ } catch {
13229
+ return {};
13230
+ }
13231
+ }
13232
+ function isTruthyEnv(value) {
13233
+ if (!value) return false;
13234
+ const normalized = value.trim().toLowerCase();
13235
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
13236
+ }
13237
+ function isQuietAthenaDiagnosticsEnvironment(env = readProcessEnv2()) {
13238
+ const nodeEnv = env.NODE_ENV?.trim().toLowerCase();
13239
+ if (nodeEnv === "production") {
13240
+ return true;
13241
+ }
13242
+ if (isTruthyEnv(env.OPENNEXT_BUILD)) {
13243
+ return true;
13244
+ }
13245
+ const nextPhase = env.NEXT_PHASE?.trim();
13246
+ if (nextPhase === "phase-production-build") {
13247
+ return true;
13248
+ }
13249
+ if (isTruthyEnv(env.CI) && nodeEnv !== "test") {
13250
+ if (nodeEnv === "production" || isTruthyEnv(env.OPENNEXT_BUILD)) {
13251
+ return true;
13252
+ }
13253
+ }
13254
+ return false;
13255
+ }
13256
+ function resolveBooleanFlag(explicit, mode, quiet) {
13257
+ if (typeof explicit === "boolean") {
13258
+ return explicit;
13259
+ }
13260
+ if (mode === true) {
13261
+ return true;
13262
+ }
13263
+ if (mode === false) {
13264
+ return false;
13265
+ }
13266
+ if (mode === "auto") {
13267
+ return false;
13268
+ }
13269
+ return false;
13270
+ }
13271
+ function resolveAthenaClientDiagnostics(input) {
13272
+ const env = input.env ?? readProcessEnv2();
13273
+ const quiet = isQuietAthenaDiagnosticsEnvironment(env);
13274
+ const mode = input.diagnostics;
13275
+ const effectiveMode = mode === "auto" && quiet ? false : mode;
13276
+ const debugAst = resolveBooleanFlag(input.debugAst, effectiveMode);
13277
+ const findManyAst = resolveBooleanFlag(input.findManyAst, effectiveMode);
13278
+ let traceQueries;
13279
+ if (input.traceQueries !== void 0) {
13280
+ if (typeof input.traceQueries === "boolean") {
13281
+ traceQueries = input.traceQueries;
13282
+ } else if (effectiveMode === false || mode === "auto" && quiet) {
13283
+ const enabled = input.traceQueries.enabled;
13284
+ traceQueries = typeof enabled === "boolean" ? enabled ? input.traceQueries : false : false;
13285
+ } else {
13286
+ traceQueries = input.traceQueries;
13287
+ }
13288
+ } else if (effectiveMode === true) {
13289
+ traceQueries = true;
13290
+ } else {
13291
+ traceQueries = false;
10561
13292
  }
10562
- };
10563
-
10564
- // src/context/merge.ts
10565
- function mergeAthenaRequestContexts(base, override) {
10566
- if (!base && !override) return void 0;
10567
13293
  return {
10568
- ...base,
10569
- ...override,
10570
- headers: base?.headers || override?.headers ? {
10571
- ...base?.headers ?? {},
10572
- ...override?.headers ?? {}
10573
- } : void 0
13294
+ debugAst,
13295
+ findManyAst,
13296
+ traceQueries
10574
13297
  };
10575
13298
  }
10576
13299
 
@@ -10582,7 +13305,13 @@ var ENV_CHAT_URL_KEYS = ["ATHENA_CHAT_URL", "NEXT_PUBLIC_ATHENA_CHAT_URL"];
10582
13305
  var ENV_CHAT_WS_URL_KEYS = ["ATHENA_CHAT_WS_URL", "NEXT_PUBLIC_ATHENA_CHAT_WS_URL"];
10583
13306
  var ENV_STORAGE_URL_KEYS = ["ATHENA_STORAGE_URL", "NEXT_PUBLIC_ATHENA_STORAGE_URL"];
10584
13307
  var ENV_KEY_KEYS = ["ATHENA_API_KEY", "NEXT_PUBLIC_ATHENA_API_KEY", "ATHENA_GATEWAY_API_KEY", "X_API_KEY"];
10585
- var ENV_CLIENT_KEYS = ["ATHENA_CLIENT", "NEXT_PUBLIC_ATHENA_CLIENT"];
13308
+ var ENV_CLIENT_KEYS = [
13309
+ "ATHENA_CLIENT",
13310
+ "ATHENA_GATEWAY_CLIENT",
13311
+ "ATHENA_GENERATOR_CLIENT",
13312
+ "NEXT_PUBLIC_ATHENA_CLIENT",
13313
+ "NEXT_PUBLIC_ATHENA_GATEWAY_CLIENT"
13314
+ ];
10586
13315
  var MISSING_DB_SENTINEL = "https://athena.invalid/db";
10587
13316
  function readFirstEnv(env, keys) {
10588
13317
  for (const key of keys) {
@@ -10591,14 +13320,30 @@ function readFirstEnv(env, keys) {
10591
13320
  }
10592
13321
  return void 0;
10593
13322
  }
10594
- function normalizeOptional(value) {
13323
+ function readFirstEnvHttpUrl(env, keys) {
13324
+ for (const key of keys) {
13325
+ const value = env?.[key]?.trim();
13326
+ if (value && isAbsoluteHttpUrl(value)) return value;
13327
+ }
13328
+ return void 0;
13329
+ }
13330
+ function normalizeOptional2(value) {
10595
13331
  const normalized = value?.trim();
10596
13332
  return normalized || void 0;
10597
13333
  }
13334
+ function isAbsoluteHttpUrl(value) {
13335
+ try {
13336
+ const url = new URL(value);
13337
+ return url.protocol === "http:" || url.protocol === "https:";
13338
+ } catch {
13339
+ return false;
13340
+ }
13341
+ }
10598
13342
  function appendPath(baseUrl, path) {
10599
13343
  return `${baseUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
10600
13344
  }
10601
13345
  function toWebSocketUrl(baseUrl) {
13346
+ if (!isAbsoluteHttpUrl(baseUrl)) return void 0;
10602
13347
  const url = new URL(baseUrl);
10603
13348
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
10604
13349
  url.pathname = `${url.pathname.replace(/\/+$/, "")}/wss/gateway`;
@@ -10608,11 +13353,11 @@ function toWebSocketUrl(baseUrl) {
10608
13353
  }
10609
13354
  function resolveCore(config) {
10610
13355
  const env = config.env;
10611
- const explicitRoot = normalizeOptional(config.url);
10612
- const envRoot = readFirstEnv(env, ENV_URL_KEYS);
10613
- const root = explicitRoot ?? envRoot;
10614
- const explicitRootWinsOverEnvServices = explicitRoot !== void 0;
10615
- const resolveService = (explicit, envKeys, path) => normalizeOptional(explicit) ?? (explicitRootWinsOverEnvServices && root ? appendPath(root, path) : void 0) ?? readFirstEnv(env, envKeys) ?? (root ? appendPath(root, path) : void 0);
13356
+ const explicitRoot = normalizeOptional2(config.url);
13357
+ const envRoot = readFirstEnvHttpUrl(env, ENV_URL_KEYS);
13358
+ const root = explicitRoot && isAbsoluteHttpUrl(explicitRoot) ? explicitRoot : explicitRoot ? void 0 : envRoot;
13359
+ const explicitRootWinsOverEnvServices = Boolean(root && explicitRoot && isAbsoluteHttpUrl(explicitRoot));
13360
+ const resolveService = (explicit, envKeys, path) => normalizeOptional2(explicit) ?? (explicitRootWinsOverEnvServices && root ? appendPath(root, path) : void 0) ?? readFirstEnvHttpUrl(env, envKeys) ?? (root ? appendPath(root, path) : void 0);
10616
13361
  const dbUrl = resolveService(config.db?.url, ENV_DB_URL_KEYS, "db");
10617
13362
  const urls = {
10618
13363
  db: dbUrl,
@@ -10620,8 +13365,8 @@ function resolveCore(config) {
10620
13365
  chat: resolveService(config.chat?.url, ENV_CHAT_URL_KEYS, "chat"),
10621
13366
  storage: resolveService(config.storage?.url, ENV_STORAGE_URL_KEYS, "storage"),
10622
13367
  // Billing lives on the main Athena HTTP surface (same host as gateway/db).
10623
- billing: normalizeOptional(config.billing?.url) ?? dbUrl ?? root ?? void 0,
10624
- chatWs: normalizeOptional(config.chat?.wsUrl) ?? (explicitRootWinsOverEnvServices && root ? toWebSocketUrl(root) : void 0) ?? readFirstEnv(env, ENV_CHAT_WS_URL_KEYS) ?? (root ? toWebSocketUrl(root) : void 0)
13368
+ billing: normalizeOptional2(config.billing?.url) ?? dbUrl ?? root ?? void 0,
13369
+ chatWs: normalizeOptional2(config.chat?.wsUrl) ?? (explicitRootWinsOverEnvServices && root ? toWebSocketUrl(root) : void 0) ?? readFirstEnvHttpUrl(env, ENV_CHAT_WS_URL_KEYS) ?? (root ? toWebSocketUrl(root) : void 0)
10625
13370
  };
10626
13371
  if (!urls.db && !urls.auth && !urls.chat && !urls.storage && !urls.billing) {
10627
13372
  throw new AthenaConfigurationError(
@@ -10630,7 +13375,7 @@ function resolveCore(config) {
10630
13375
  "db"
10631
13376
  );
10632
13377
  }
10633
- const key = normalizeOptional(config.key) ?? readFirstEnv(env, ENV_KEY_KEYS);
13378
+ const key = normalizeOptional2(config.key) ?? readFirstEnv(env, ENV_KEY_KEYS);
10634
13379
  if (!key) {
10635
13380
  throw new AthenaConfigurationError(
10636
13381
  "ATHENA_API_KEY_REQUIRED",
@@ -10641,7 +13386,7 @@ function resolveCore(config) {
10641
13386
  config,
10642
13387
  urls,
10643
13388
  key,
10644
- client: normalizeOptional(config.client) ?? readFirstEnv(env, ENV_CLIENT_KEYS)
13389
+ client: normalizeOptional2(config.client) ?? readFirstEnv(env, ENV_CLIENT_KEYS)
10645
13390
  };
10646
13391
  return {
10647
13392
  ...base,
@@ -10656,7 +13401,20 @@ async function resolveConfiguredContext(core, viewContext) {
10656
13401
  function createInternalConfig(core) {
10657
13402
  const { config, urls } = core;
10658
13403
  const { url: _authUrl, ...authOptions } = config.auth ?? {};
10659
- const { url: _storageUrl, directUpload, ...storageOptions } = config.storage ?? {};
13404
+ const {
13405
+ url: _storageUrl,
13406
+ directUpload,
13407
+ r2: _r2,
13408
+ prefix: _r2Prefix,
13409
+ ...storageOptions
13410
+ } = config.storage ?? {};
13411
+ const diagnostics = resolveAthenaClientDiagnostics({
13412
+ diagnostics: config.diagnostics,
13413
+ debugAst: config.debugAst,
13414
+ findManyAst: config.findManyAst,
13415
+ traceQueries: config.traceQueries,
13416
+ env: config.env
13417
+ });
10660
13418
  return {
10661
13419
  baseUrl: urls.db ?? MISSING_DB_SENTINEL,
10662
13420
  apiKey: core.key,
@@ -10673,14 +13431,15 @@ function createInternalConfig(core) {
10673
13431
  models: config.models,
10674
13432
  behavior: {
10675
13433
  retryReads: config.retryReads,
10676
- traceQueries: config.traceQueries,
10677
- debugAst: config.debugAst,
10678
- findManyAst: config.findManyAst
13434
+ traceQueries: diagnostics.traceQueries,
13435
+ debugAst: diagnostics.debugAst,
13436
+ findManyAst: diagnostics.findManyAst
10679
13437
  },
10680
13438
  storage: {
10681
13439
  ...storageOptions,
10682
13440
  ...directUpload ? { directUpload } : {}
10683
- }
13441
+ },
13442
+ gatewayTransport: config.gatewayTransport
10684
13443
  };
10685
13444
  }
10686
13445
  function serviceGuard(urls, service) {
@@ -10703,6 +13462,232 @@ function createUnavailableNamespace(service, urls, path = []) {
10703
13462
  }
10704
13463
  });
10705
13464
  }
13465
+ function isD1Binding2(value) {
13466
+ return Boolean(
13467
+ value && typeof value === "object" && typeof value.prepare === "function"
13468
+ );
13469
+ }
13470
+ function isR2Binding(value) {
13471
+ return Boolean(
13472
+ value && typeof value === "object" && typeof value.put === "function" && typeof value.get === "function"
13473
+ );
13474
+ }
13475
+ function foldBindingAliases(config) {
13476
+ const d1 = config.db?.d1 ?? config.d1;
13477
+ const r2 = config.storage?.r2 ?? config.r2;
13478
+ const sessionMode = config.db?.sessionMode ?? config.sessionMode;
13479
+ const prefix = config.storage?.prefix ?? config.storagePrefix;
13480
+ let next = { ...config };
13481
+ if (d1 !== void 0 || sessionMode !== void 0) {
13482
+ next = {
13483
+ ...next,
13484
+ db: {
13485
+ ...next.db,
13486
+ ...d1 !== void 0 ? { d1 } : {},
13487
+ ...sessionMode !== void 0 ? { sessionMode } : {}
13488
+ }
13489
+ };
13490
+ }
13491
+ if (r2 !== void 0 || prefix !== void 0) {
13492
+ next = {
13493
+ ...next,
13494
+ storage: {
13495
+ ...next.storage,
13496
+ ...r2 !== void 0 ? { r2 } : {},
13497
+ ...prefix !== void 0 ? { prefix } : {}
13498
+ }
13499
+ };
13500
+ }
13501
+ const {
13502
+ d1: _d1,
13503
+ r2: _r2,
13504
+ storagePrefix: _storagePrefix,
13505
+ sessionMode: _sessionMode,
13506
+ ...rest
13507
+ } = next;
13508
+ return rest;
13509
+ }
13510
+ function applyExecutionMode(config) {
13511
+ const d1 = config.db?.d1;
13512
+ const hasD1 = isD1Binding2(d1);
13513
+ const hasUrl = Boolean(
13514
+ normalizeOptional2(config.url) ?? normalizeOptional2(config.db?.url) ?? (config.env ? normalizeOptional2(config.env.ATHENA_URL) ?? normalizeOptional2(config.env.NEXT_PUBLIC_ATHENA_URL) : void 0)
13515
+ );
13516
+ const hasModeHint = config.mode != null || config.prefer != null || Boolean(config.env?.ATHENA_EXECUTION_MODE) || Boolean(config.env?.ATHENA_EXECUTION_PREFER);
13517
+ if (!hasD1 && !hasModeHint) {
13518
+ return config;
13519
+ }
13520
+ if (hasD1 && !hasUrl && !hasModeHint) {
13521
+ return config;
13522
+ }
13523
+ let resolved;
13524
+ try {
13525
+ resolved = resolveAthenaExecutionMode({
13526
+ mode: config.mode,
13527
+ prefer: config.prefer,
13528
+ d1: hasD1 ? d1 : null,
13529
+ url: config.url ?? config.db?.url,
13530
+ env: config.env
13531
+ });
13532
+ } catch (error) {
13533
+ if (!hasModeHint) return config;
13534
+ throw error;
13535
+ }
13536
+ if (resolved === "gateway" && hasD1) {
13537
+ const { d1: _drop, sessionMode: _sm, ...dbRest } = config.db ?? {};
13538
+ return {
13539
+ ...config,
13540
+ db: Object.keys(dbRest).length > 0 ? dbRest : void 0,
13541
+ gatewayTransport: void 0
13542
+ };
13543
+ }
13544
+ return config;
13545
+ }
13546
+ function resolveUnifiedRemoteRoot(config) {
13547
+ return normalizeOptional2(config.url) ?? readFirstEnv(config.env, ENV_URL_KEYS);
13548
+ }
13549
+ function isEdgeLocalSentinelUrl(url) {
13550
+ if (!url) return false;
13551
+ return url === CLOUDFLARE_EDGE_BASE_URL || url.startsWith("https://athena.local/") || url.startsWith("http://athena.local/");
13552
+ }
13553
+ function hasRemoteDbGatewayUrl(config) {
13554
+ const dbUrl = normalizeOptional2(config.db?.url) ?? readFirstEnv(config.env, ENV_DB_URL_KEYS);
13555
+ return Boolean(dbUrl && !isEdgeLocalSentinelUrl(dbUrl));
13556
+ }
13557
+ function hasRemoteHttpServices(config) {
13558
+ return Boolean(
13559
+ resolveUnifiedRemoteRoot(config) || hasRemoteDbGatewayUrl(config) || normalizeOptional2(config.auth?.url) || readFirstEnv(config.env, ENV_AUTH_URL_KEYS) || normalizeOptional2(config.storage?.url) || readFirstEnv(config.env, ENV_STORAGE_URL_KEYS) || normalizeOptional2(config.chat?.url) || readFirstEnv(config.env, ENV_CHAT_URL_KEYS) || normalizeOptional2(config.billing?.url)
13560
+ );
13561
+ }
13562
+ function hasRemoteHttpStorage(config) {
13563
+ return Boolean(
13564
+ normalizeOptional2(config.storage?.url) || readFirstEnv(config.env, ENV_STORAGE_URL_KEYS) || resolveUnifiedRemoteRoot(config)
13565
+ );
13566
+ }
13567
+ function hasRemoteAuthService(config) {
13568
+ return Boolean(
13569
+ normalizeOptional2(config.auth?.url) || readFirstEnv(config.env, ENV_AUTH_URL_KEYS) || resolveUnifiedRemoteRoot(config)
13570
+ );
13571
+ }
13572
+ function materializeEdgeBindings(config) {
13573
+ const d1 = config.db?.d1;
13574
+ const r2 = config.storage?.r2;
13575
+ const hasD1 = isD1Binding2(d1);
13576
+ const hasR2 = isR2Binding(r2);
13577
+ if (!hasD1 && !hasR2) {
13578
+ return config;
13579
+ }
13580
+ if (hasD1 && d1 && typeof d1.prepare !== "function") {
13581
+ throw new AthenaConfigurationError(
13582
+ "ATHENA_NO_SERVICE_CONFIGURED",
13583
+ "db.d1 must be a D1 binding with prepare().",
13584
+ "db"
13585
+ );
13586
+ }
13587
+ const remoteRoot = resolveUnifiedRemoteRoot(config);
13588
+ const remoteServices = hasRemoteHttpServices(config);
13589
+ const remoteStorage = hasRemoteHttpStorage(config);
13590
+ const remoteAuth = hasRemoteAuthService(config);
13591
+ const next = { ...config };
13592
+ if (hasD1 && d1) {
13593
+ if (!config.gatewayTransport) {
13594
+ next.gatewayTransport = createCloudflareD1GatewayTransport({
13595
+ d1,
13596
+ defaultSessionMode: config.db?.sessionMode
13597
+ });
13598
+ }
13599
+ const explicitDbUrl = normalizeOptional2(config.db?.url);
13600
+ const remoteDbGateway = hasRemoteDbGatewayUrl(config);
13601
+ next.db = {
13602
+ ...config.db,
13603
+ d1,
13604
+ url: explicitDbUrl ?? (remoteDbGateway ? void 0 : CLOUDFLARE_EDGE_BASE_URL)
13605
+ };
13606
+ const explicitKey = normalizeOptional2(config.key);
13607
+ if (explicitKey) {
13608
+ next.key = explicitKey;
13609
+ } else if (!remoteServices) {
13610
+ next.key = CLOUDFLARE_EDGE_API_KEY;
13611
+ } else {
13612
+ next.key = void 0;
13613
+ }
13614
+ if (remoteRoot) {
13615
+ next.billing = {
13616
+ ...config.billing ?? {},
13617
+ url: normalizeOptional2(config.billing?.url) ?? remoteRoot
13618
+ };
13619
+ }
13620
+ if (!config.capabilities) {
13621
+ next.capabilities = createCloudflareEdgeCapabilities({
13622
+ hasR2,
13623
+ // Explicit storage.url / env storage URL / unified remote root all count.
13624
+ hasRemoteStorage: remoteStorage,
13625
+ authRemote: remoteAuth,
13626
+ findManyAst: false
13627
+ });
13628
+ }
13629
+ } else if (hasR2 && r2) {
13630
+ if (!remoteRoot && !normalizeOptional2(config.db?.url) && !normalizeOptional2(config.storage?.url) && !readFirstEnv(config.env, ENV_STORAGE_URL_KEYS)) {
13631
+ next.storage = {
13632
+ ...config.storage,
13633
+ r2,
13634
+ // Local sentinel so resolveCore accepts a storage-only binding client.
13635
+ url: CLOUDFLARE_EDGE_BASE_URL
13636
+ };
13637
+ if (!remoteServices) {
13638
+ next.key = normalizeOptional2(config.key) ?? CLOUDFLARE_EDGE_API_KEY;
13639
+ } else if (normalizeOptional2(config.key)) {
13640
+ next.key = normalizeOptional2(config.key);
13641
+ } else {
13642
+ next.key = void 0;
13643
+ }
13644
+ }
13645
+ if (!config.capabilities) {
13646
+ if (remoteRoot || normalizeOptional2(config.db?.url) || readFirstEnv(config.env, ENV_DB_URL_KEYS)) {
13647
+ const base = createGatewayCapabilities({
13648
+ authRemote: remoteAuth,
13649
+ storageConfigured: true
13650
+ });
13651
+ next.capabilities = {
13652
+ ...base,
13653
+ storage: {
13654
+ ...base.storage,
13655
+ local: true,
13656
+ objects: true
13657
+ }
13658
+ };
13659
+ } else {
13660
+ next.capabilities = {
13661
+ mode: "cloudflare-edge",
13662
+ db: {
13663
+ engine: "unknown",
13664
+ local: false,
13665
+ layers: {
13666
+ query: false,
13667
+ flatCrud: false,
13668
+ findManyAst: false,
13669
+ rpc: false,
13670
+ relations: false
13671
+ }
13672
+ },
13673
+ storage: {
13674
+ local: true,
13675
+ objects: true,
13676
+ catalogs: false,
13677
+ backups: false
13678
+ },
13679
+ auth: {
13680
+ remote: remoteAuth
13681
+ }
13682
+ };
13683
+ }
13684
+ }
13685
+ }
13686
+ return next;
13687
+ }
13688
+ function normalizeCreateClientConfig(config) {
13689
+ return materializeEdgeBindings(applyExecutionMode(foldBindingAliases(config)));
13690
+ }
10706
13691
  function createClientView(core, viewContext) {
10707
13692
  const resolved = createInternalClientView(
10708
13693
  core.internalCore,
@@ -10720,12 +13705,23 @@ function createClientView(core, viewContext) {
10720
13705
  },
10721
13706
  ...billingOptions
10722
13707
  }) : createUnavailableNamespace("billing", core.urls);
13708
+ const capabilities = core.config.capabilities ?? createGatewayCapabilities({
13709
+ authRemote: Boolean(core.urls.auth),
13710
+ // Match unavailable storage proxy when no storage URL was resolved.
13711
+ storageConfigured: Boolean(core.urls.storage)
13712
+ });
13713
+ const r2 = core.config.storage?.r2;
13714
+ const storageModule = isR2Binding(r2) ? createCloudflareR2StorageModule({
13715
+ r2,
13716
+ prefix: core.config.storage?.prefix ?? void 0
13717
+ }) : core.urls.storage ? resolved.storage : createUnavailableNamespace("storage", core.urls);
10723
13718
  const client = {
10724
13719
  db: core.urls.db ? resolved.db : createUnavailableNamespace("db", core.urls),
10725
13720
  auth: core.urls.auth ? resolved.auth : createUnavailableNamespace("auth", core.urls),
10726
13721
  chat: core.urls.chat ? resolved.chat : createUnavailableNamespace("chat", core.urls),
10727
- storage: core.urls.storage ? resolved.storage : createUnavailableNamespace("storage", core.urls),
13722
+ storage: storageModule,
10728
13723
  billing: billingModule,
13724
+ capabilities,
10729
13725
  from: ((...args) => {
10730
13726
  requireDb();
10731
13727
  return Reflect.apply(resolved.from, resolved, args);
@@ -10749,13 +13745,34 @@ function createClientView(core, viewContext) {
10749
13745
  return resolved.verifyConnection(options);
10750
13746
  },
10751
13747
  withContext(context) {
13748
+ warnIfEmptyRequestContext(context);
10752
13749
  return createClientView(core, mergeAthenaRequestContexts(viewContext, context));
10753
13750
  }
10754
13751
  };
10755
13752
  return Object.freeze(client);
10756
13753
  }
13754
+ function isEmptyAthenaRequestContext(context) {
13755
+ if (!context) return true;
13756
+ const hasHeaders = context.headers != null && Object.keys(context.headers).length > 0;
13757
+ return context.userId == null && context.organizationId == null && !normalizeOptionalContextString(context.cookie) && !normalizeOptionalContextString(context.bearerToken) && !normalizeOptionalContextString(context.sessionToken) && !context.forceNoCache && !hasHeaders;
13758
+ }
13759
+ function normalizeOptionalContextString(value) {
13760
+ const trimmed = value?.trim();
13761
+ return trimmed || void 0;
13762
+ }
13763
+ function warnIfEmptyRequestContext(context) {
13764
+ if (!isEmptyAthenaRequestContext(context)) return;
13765
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
13766
+ if (nodeEnv === "production") {
13767
+ return;
13768
+ }
13769
+ console.warn(
13770
+ "[athena] withContext({}) has no userId, organizationId, cookie, bearerToken, sessionToken, headers, or forceNoCache. Gateway scope headers will not change. Pass identity fields, or use createAthenaServerClient({ session, scope })."
13771
+ );
13772
+ }
10757
13773
  function createClient(config) {
10758
- return createClientView(resolveCore(config));
13774
+ const normalized = normalizeCreateClientConfig(config);
13775
+ return createClientView(resolveCore(normalized));
10759
13776
  }
10760
13777
 
10761
13778
  // src/gateway/types.ts
@@ -12109,6 +15126,27 @@ function resolveTotalItemsFromPage({
12109
15126
  }
12110
15127
  return clampAthenaReadQueryTotalItems(exactCount, limit);
12111
15128
  }
15129
+ function resolveAthenaReadQueryPageFetch({
15130
+ page,
15131
+ pageSize,
15132
+ limit
15133
+ }) {
15134
+ const safePage = Math.max(1, Math.trunc(page) || 1);
15135
+ const safePageSize = Math.max(1, Math.trunc(pageSize) || 1);
15136
+ if (!limit || limit < 1) {
15137
+ return { page: safePage, pageSize: safePageSize, shouldFetch: true };
15138
+ }
15139
+ const totalCap = Math.trunc(limit);
15140
+ const offset = (safePage - 1) * safePageSize;
15141
+ if (offset >= totalCap) {
15142
+ return { page: safePage, pageSize: safePageSize, shouldFetch: false };
15143
+ }
15144
+ return {
15145
+ page: safePage,
15146
+ pageSize: Math.min(safePageSize, totalCap - offset),
15147
+ shouldFetch: true
15148
+ };
15149
+ }
12112
15150
  async function executeAthenaReadQuery({
12113
15151
  client,
12114
15152
  page,
@@ -12127,15 +15165,29 @@ async function executeAthenaReadQuery({
12127
15165
  count: "exact",
12128
15166
  head: true
12129
15167
  });
15168
+ const pageFetch = resolveAthenaReadQueryPageFetch({
15169
+ limit: query.limit,
15170
+ page,
15171
+ pageSize
15172
+ });
15173
+ if (!pageFetch.shouldFetch) {
15174
+ return {
15175
+ rows: [],
15176
+ totalItems: resolveTotalItemsFromPage({
15177
+ countCandidates: [countResult.count],
15178
+ limit: query.limit,
15179
+ page: pageFetch.page,
15180
+ pageSize,
15181
+ rowCount: 0
15182
+ })
15183
+ };
15184
+ }
12130
15185
  if ((query.mode ?? "findMany") === "select") {
12131
- const selectBuilder = applyAthenaReadQuerySelectLimit(
12132
- applyAthenaReadQuerySelectOrder(
12133
- applyAthenaReadQueryFilters(baseBuilder, query.filters),
12134
- query.orderBy
12135
- ),
12136
- query.limit
15186
+ const selectBuilder = applyAthenaReadQuerySelectOrder(
15187
+ applyAthenaReadQueryFilters(baseBuilder, query.filters),
15188
+ query.orderBy
12137
15189
  );
12138
- const result2 = await selectBuilder.currentPage(page).pageSize(pageSize).select(buildAthenaReadQuerySelectString(query.columns), {
15190
+ const result2 = await selectBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).select(buildAthenaReadQuerySelectString(query.columns), {
12139
15191
  count: "exact"
12140
15192
  });
12141
15193
  const rows2 = flattenAthenaReadQueryRows(
@@ -12149,7 +15201,7 @@ async function executeAthenaReadQuery({
12149
15201
  totalItems: resolveTotalItemsFromPage({
12150
15202
  countCandidates: [countResult.count, result2.count],
12151
15203
  limit: query.limit,
12152
- page,
15204
+ page: pageFetch.page,
12153
15205
  pageSize,
12154
15206
  rowCount: rows2.length
12155
15207
  })
@@ -12157,12 +15209,11 @@ async function executeAthenaReadQuery({
12157
15209
  }
12158
15210
  const findManyOrderBy = buildAthenaReadQueryFindManyOrderBy(query.orderBy);
12159
15211
  const findManyOptions = {
12160
- ...query.limit ? { limit: query.limit } : {},
12161
15212
  ...findManyOrderBy ? { orderBy: findManyOrderBy } : {},
12162
15213
  select: buildAthenaReadQueryFindManySelect(query.columns),
12163
15214
  ...query.filters?.length ? { where: buildAthenaReadQueryFindManyWhere(query.filters) } : {}
12164
15215
  };
12165
- const result = await baseBuilder.currentPage(page).pageSize(pageSize).findMany(findManyOptions);
15216
+ const result = await baseBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).findMany(findManyOptions);
12166
15217
  const rows = flattenAthenaReadQueryRows(
12167
15218
  Array.isArray(result.data) ? result.data : [],
12168
15219
  query.columns,
@@ -12174,7 +15225,7 @@ async function executeAthenaReadQuery({
12174
15225
  totalItems: resolveTotalItemsFromPage({
12175
15226
  countCandidates: [countResult.count, result.count],
12176
15227
  limit: query.limit,
12177
- page,
15228
+ page: pageFetch.page,
12178
15229
  pageSize,
12179
15230
  rowCount: rows.length
12180
15231
  })
@@ -12182,6 +15233,432 @@ async function executeAthenaReadQuery({
12182
15233
  }
12183
15234
  var executeAthenaTableQuery = executeAthenaReadQuery;
12184
15235
 
15236
+ // src/tables/catalog.ts
15237
+ var POSTGRES_CATALOG_SQL = {
15238
+ columns: `
15239
+ SELECT
15240
+ n.nspname AS schema_name,
15241
+ c.relname AS table_name,
15242
+ a.attname AS column_name,
15243
+ format_type(a.atttypid, a.atttypmod) AS data_type,
15244
+ NOT a.attnotnull AS is_nullable
15245
+ FROM pg_attribute a
15246
+ JOIN pg_class c ON c.oid = a.attrelid
15247
+ JOIN pg_namespace n ON n.oid = c.relnamespace
15248
+ WHERE c.relkind IN ('r', 'p')
15249
+ AND a.attnum > 0
15250
+ AND NOT a.attisdropped
15251
+ AND n.nspname = ANY($1::text[])
15252
+ ORDER BY n.nspname, c.relname, a.attnum;
15253
+ `,
15254
+ foreignKeys: `
15255
+ SELECT
15256
+ sn.nspname AS source_schema,
15257
+ sc.relname AS source_table,
15258
+ con.conname AS constraint_name,
15259
+ ARRAY_AGG(sa.attname ORDER BY cols.ordinality) AS source_columns,
15260
+ tn.nspname AS target_schema,
15261
+ tc.relname AS target_table,
15262
+ ARRAY_AGG(ta.attname ORDER BY cols.ordinality) AS target_columns,
15263
+ EXISTS (
15264
+ SELECT 1
15265
+ FROM pg_constraint uq
15266
+ WHERE uq.conrelid = con.conrelid
15267
+ AND uq.contype IN ('p', 'u')
15268
+ AND uq.conkey = con.conkey
15269
+ ) AS source_is_unique
15270
+ FROM pg_constraint con
15271
+ JOIN pg_class sc ON sc.oid = con.conrelid
15272
+ JOIN pg_namespace sn ON sn.oid = sc.relnamespace
15273
+ JOIN pg_class tc ON tc.oid = con.confrelid
15274
+ JOIN pg_namespace tn ON tn.oid = tc.relnamespace
15275
+ JOIN unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(source_attnum, target_attnum, ordinality) ON TRUE
15276
+ JOIN pg_attribute sa ON sa.attrelid = con.conrelid AND sa.attnum = cols.source_attnum
15277
+ JOIN pg_attribute ta ON ta.attrelid = con.confrelid AND ta.attnum = cols.target_attnum
15278
+ WHERE con.contype = 'f'
15279
+ AND sn.nspname = ANY($1::text[])
15280
+ AND tn.nspname = ANY($1::text[])
15281
+ GROUP BY
15282
+ sn.nspname,
15283
+ sc.relname,
15284
+ con.conname,
15285
+ tn.nspname,
15286
+ tc.relname,
15287
+ con.conkey,
15288
+ con.conrelid
15289
+ ORDER BY sn.nspname, sc.relname, con.conname;
15290
+ `,
15291
+ primaryKeys: `
15292
+ SELECT
15293
+ n.nspname AS schema_name,
15294
+ c.relname AS table_name,
15295
+ ARRAY_AGG(a.attname ORDER BY ck.ordinality) AS columns
15296
+ FROM pg_constraint con
15297
+ JOIN pg_class c ON c.oid = con.conrelid
15298
+ JOIN pg_namespace n ON n.oid = c.relnamespace
15299
+ JOIN unnest(con.conkey) WITH ORDINALITY AS ck(attnum, ordinality) ON TRUE
15300
+ JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ck.attnum
15301
+ WHERE con.contype = 'p'
15302
+ AND n.nspname = ANY($1::text[])
15303
+ GROUP BY n.nspname, c.relname
15304
+ ORDER BY n.nspname, c.relname;
15305
+ `
15306
+ };
15307
+ function parseAthenaTableSchemaScope(value) {
15308
+ return value.split(",").map((entry) => entry.trim()).filter(
15309
+ (entry, index, values) => entry.length > 0 && values.indexOf(entry) === index
15310
+ );
15311
+ }
15312
+ function escapeSqlLiteral(value) {
15313
+ return value.replace(/'/g, "''");
15314
+ }
15315
+ function buildSchemaArrayLiteral(schemas) {
15316
+ const literals = schemas.map((schema) => `'${escapeSqlLiteral(schema)}'`).join(", ");
15317
+ return `ARRAY[${literals}]`;
15318
+ }
15319
+ function inlineSchemaLiteral(sql, schemas) {
15320
+ return sql.replace(
15321
+ /\$1::text\[\]/g,
15322
+ `${buildSchemaArrayLiteral(schemas)}::text[]`
15323
+ );
15324
+ }
15325
+ function buildAthenaTableCatalogQueries(schemas) {
15326
+ return {
15327
+ columns: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.columns, schemas),
15328
+ foreignKeys: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.foreignKeys, schemas),
15329
+ primaryKeys: inlineSchemaLiteral(POSTGRES_CATALOG_SQL.primaryKeys, schemas)
15330
+ };
15331
+ }
15332
+ function tableKey(schema, table2) {
15333
+ return `${schema}.${table2}`;
15334
+ }
15335
+ function relationKey(...parts) {
15336
+ const base = parts.join("_").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
15337
+ return base.length > 0 ? base : "relation";
15338
+ }
15339
+ function parsePostgresArrayLiteral(text) {
15340
+ const body = text.slice(1, -1).trim();
15341
+ if (!body) {
15342
+ return [];
15343
+ }
15344
+ const values = [];
15345
+ let current = "";
15346
+ let inQuotes = false;
15347
+ let escaped = false;
15348
+ for (const char of body) {
15349
+ if (escaped) {
15350
+ current += char;
15351
+ escaped = false;
15352
+ continue;
15353
+ }
15354
+ if (char === "\\") {
15355
+ escaped = true;
15356
+ continue;
15357
+ }
15358
+ if (char === '"') {
15359
+ inQuotes = !inQuotes;
15360
+ continue;
15361
+ }
15362
+ if (char === "," && !inQuotes) {
15363
+ values.push(current);
15364
+ current = "";
15365
+ continue;
15366
+ }
15367
+ current += char;
15368
+ }
15369
+ values.push(current);
15370
+ return values.map((value) => value.trim()).filter((value) => value.length > 0);
15371
+ }
15372
+ function coerceStringArray(value) {
15373
+ if (value == null) {
15374
+ return [];
15375
+ }
15376
+ if (Array.isArray(value)) {
15377
+ return value.map((entry) => entry.trim()).filter(Boolean);
15378
+ }
15379
+ if (typeof value !== "string") {
15380
+ return [];
15381
+ }
15382
+ const trimmedValue = value.trim();
15383
+ if (!trimmedValue) {
15384
+ return [];
15385
+ }
15386
+ if (trimmedValue.startsWith("{") && trimmedValue.endsWith("}")) {
15387
+ return parsePostgresArrayLiteral(trimmedValue);
15388
+ }
15389
+ return trimmedValue.split(",").map((entry) => entry.trim()).filter(Boolean);
15390
+ }
15391
+ function createTableCatalog() {
15392
+ const tables = /* @__PURE__ */ new Map();
15393
+ const ensureTable = (schema, name) => {
15394
+ const id = tableKey(schema, name);
15395
+ const existingTable = tables.get(id);
15396
+ if (existingTable) {
15397
+ return existingTable;
15398
+ }
15399
+ const nextTable = {
15400
+ columns: [],
15401
+ id,
15402
+ name,
15403
+ primaryKey: [],
15404
+ relationMap: /* @__PURE__ */ new Map(),
15405
+ schema
15406
+ };
15407
+ tables.set(id, nextTable);
15408
+ return nextTable;
15409
+ };
15410
+ const upsertRelation = (table2, key, relation) => {
15411
+ table2.relationMap.set(key, relation);
15412
+ };
15413
+ return {
15414
+ addColumnRows(columnRows) {
15415
+ for (const row of columnRows) {
15416
+ const table2 = ensureTable(row.schema_name, row.table_name);
15417
+ table2.columns.push({
15418
+ dataType: row.data_type,
15419
+ isNullable: row.is_nullable,
15420
+ isPrimaryKey: false,
15421
+ name: row.column_name
15422
+ });
15423
+ }
15424
+ },
15425
+ addForeignKeyRows(foreignKeyRows) {
15426
+ for (const row of foreignKeyRows) {
15427
+ const sourceTable = ensureTable(row.source_schema, row.source_table);
15428
+ const targetTable = ensureTable(row.target_schema, row.target_table);
15429
+ upsertRelation(
15430
+ sourceTable,
15431
+ relationKey(row.constraint_name, row.target_table),
15432
+ {
15433
+ name: row.constraint_name,
15434
+ targetSchema: row.target_schema,
15435
+ targetTable: row.target_table
15436
+ }
15437
+ );
15438
+ upsertRelation(targetTable, relationKey(row.source_table), {
15439
+ name: relationKey(row.source_table, row.constraint_name),
15440
+ targetSchema: row.source_schema,
15441
+ targetTable: row.source_table
15442
+ });
15443
+ }
15444
+ },
15445
+ addManyToManyRows(foreignKeyRows) {
15446
+ const foreignKeysBySourceTable = /* @__PURE__ */ new Map();
15447
+ for (const foreignKey of foreignKeyRows) {
15448
+ const key = tableKey(foreignKey.source_schema, foreignKey.source_table);
15449
+ const current = foreignKeysBySourceTable.get(key) ?? {
15450
+ foreignKeys: [],
15451
+ schema: foreignKey.source_schema,
15452
+ table: foreignKey.source_table
15453
+ };
15454
+ current.foreignKeys.push(foreignKey);
15455
+ foreignKeysBySourceTable.set(key, current);
15456
+ }
15457
+ for (const candidate of foreignKeysBySourceTable.values()) {
15458
+ const bridgeTable = tables.get(
15459
+ tableKey(candidate.schema, candidate.table)
15460
+ );
15461
+ if (!bridgeTable || candidate.foreignKeys.length !== 2) {
15462
+ continue;
15463
+ }
15464
+ const combinedForeignColumns = Array.from(
15465
+ new Set(
15466
+ candidate.foreignKeys.flatMap(
15467
+ (foreignKey) => coerceStringArray(foreignKey.source_columns)
15468
+ )
15469
+ )
15470
+ );
15471
+ if (bridgeTable.primaryKey.length === 0 || combinedForeignColumns.length !== bridgeTable.primaryKey.length || !bridgeTable.primaryKey.every(
15472
+ (column) => combinedForeignColumns.includes(column)
15473
+ )) {
15474
+ continue;
15475
+ }
15476
+ const [firstForeignKey, secondForeignKey] = candidate.foreignKeys;
15477
+ const firstTarget = tables.get(
15478
+ tableKey(firstForeignKey.target_schema, firstForeignKey.target_table)
15479
+ );
15480
+ const secondTarget = tables.get(
15481
+ tableKey(
15482
+ secondForeignKey.target_schema,
15483
+ secondForeignKey.target_table
15484
+ )
15485
+ );
15486
+ if (!(firstTarget && secondTarget)) {
15487
+ continue;
15488
+ }
15489
+ upsertRelation(
15490
+ firstTarget,
15491
+ relationKey(candidate.table, secondForeignKey.target_table),
15492
+ {
15493
+ name: relationKey(
15494
+ candidate.table,
15495
+ secondForeignKey.constraint_name
15496
+ ),
15497
+ targetSchema: secondForeignKey.target_schema,
15498
+ targetTable: secondForeignKey.target_table
15499
+ }
15500
+ );
15501
+ upsertRelation(
15502
+ secondTarget,
15503
+ relationKey(candidate.table, firstForeignKey.target_table),
15504
+ {
15505
+ name: relationKey(candidate.table, firstForeignKey.constraint_name),
15506
+ targetSchema: firstForeignKey.target_schema,
15507
+ targetTable: firstForeignKey.target_table
15508
+ }
15509
+ );
15510
+ }
15511
+ },
15512
+ addPrimaryKeyRows(primaryKeyRows) {
15513
+ for (const row of primaryKeyRows) {
15514
+ const table2 = ensureTable(row.schema_name, row.table_name);
15515
+ const primaryKey = coerceStringArray(row.columns);
15516
+ table2.primaryKey = primaryKey;
15517
+ for (const columnName of primaryKey) {
15518
+ const column = table2.columns.find(
15519
+ (candidate) => candidate.name === columnName
15520
+ );
15521
+ if (column) {
15522
+ column.isPrimaryKey = true;
15523
+ }
15524
+ }
15525
+ }
15526
+ },
15527
+ toResponse(database) {
15528
+ return {
15529
+ database,
15530
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
15531
+ tables: [...tables.values()].map((table2) => ({
15532
+ columns: [...table2.columns].sort(
15533
+ (left, right) => left.name.localeCompare(right.name)
15534
+ ),
15535
+ id: table2.id,
15536
+ name: table2.name,
15537
+ primaryKey: [...table2.primaryKey],
15538
+ relations: [...table2.relationMap.values()].map((relation) => ({
15539
+ columns: tables.get(
15540
+ tableKey(relation.targetSchema, relation.targetTable)
15541
+ )?.columns ?? [],
15542
+ name: relation.name,
15543
+ targetSchema: relation.targetSchema,
15544
+ targetTable: relation.targetTable
15545
+ })).sort(
15546
+ (left, right) => left.name.localeCompare(right.name)
15547
+ ),
15548
+ schema: table2.schema
15549
+ })).sort(
15550
+ (left, right) => left.id.localeCompare(right.id)
15551
+ )
15552
+ };
15553
+ }
15554
+ };
15555
+ }
15556
+ async function queryRows(client, query) {
15557
+ const result = await client.query(query);
15558
+ if (result.error || result.status < 200 || result.status >= 300) {
15559
+ const errorMessage = typeof result.error === "string" ? result.error : result.error && typeof result.error === "object" && "message" in result.error && typeof result.error.message === "string" ? result.error.message : `Athena gateway query failed with status ${result.status}.`;
15560
+ throw new Error(errorMessage);
15561
+ }
15562
+ return Array.isArray(result.data) ? result.data : [];
15563
+ }
15564
+ function isAthenaTableSchemaConfig(value) {
15565
+ if (typeof value !== "object" || value === null) {
15566
+ return false;
15567
+ }
15568
+ const config = value;
15569
+ return typeof config.gatewayUrl === "string" && typeof config.gatewayKey === "string" && typeof config.gatewayDatabase === "string" && typeof config.schemaScope === "string" && typeof config.clientName === "string";
15570
+ }
15571
+ function hasAthenaTableSchemaCredentials(config) {
15572
+ return config.gatewayUrl.trim().length > 0 && config.gatewayKey.trim().length > 0 && config.gatewayDatabase.trim().length > 0;
15573
+ }
15574
+ async function fetchAthenaTableCatalog(config, options = {}) {
15575
+ const schemas = parseAthenaTableSchemaScope(config.schemaScope);
15576
+ if (schemas.length === 0) {
15577
+ return {
15578
+ database: config.gatewayDatabase,
15579
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
15580
+ tables: []
15581
+ };
15582
+ }
15583
+ const queries = buildAthenaTableCatalogQueries(schemas);
15584
+ const client = options.client ?? createClient({
15585
+ url: config.gatewayUrl.trim(),
15586
+ key: config.gatewayKey.trim(),
15587
+ client: config.clientName.trim() || void 0
15588
+ });
15589
+ const [columnRows, primaryKeyRows, foreignKeyRows] = await Promise.all([
15590
+ queryRows(client, queries.columns),
15591
+ queryRows(client, queries.primaryKeys),
15592
+ queryRows(client, queries.foreignKeys)
15593
+ ]);
15594
+ const catalog = createTableCatalog();
15595
+ catalog.addColumnRows(columnRows);
15596
+ catalog.addPrimaryKeyRows(primaryKeyRows);
15597
+ catalog.addForeignKeyRows(foreignKeyRows);
15598
+ catalog.addManyToManyRows(foreignKeyRows);
15599
+ return catalog.toResponse(config.gatewayDatabase);
15600
+ }
15601
+ var fetchTableCatalog = fetchAthenaTableCatalog;
15602
+
15603
+ // src/tables/schema-handlers.ts
15604
+ var ATHENA_TABLE_SCHEMA_ROUTE = "/api/tables/schema";
15605
+ function json2(body, init) {
15606
+ const headers = new Headers(init?.headers);
15607
+ if (!headers.has("content-type")) {
15608
+ headers.set("content-type", "application/json; charset=utf-8");
15609
+ }
15610
+ return new Response(JSON.stringify(body), {
15611
+ status: init?.status ?? 200,
15612
+ headers
15613
+ });
15614
+ }
15615
+ async function handleAthenaTableSchemaPost(request2, options) {
15616
+ const payload = await request2.json().catch(() => null);
15617
+ let config = isAthenaTableSchemaConfig(
15618
+ payload?.config
15619
+ ) ? payload.config : null;
15620
+ if (config && options?.resolveConfig) {
15621
+ config = await options.resolveConfig(config, request2);
15622
+ }
15623
+ if (!config || !isAthenaTableSchemaConfig(config)) {
15624
+ return json2(
15625
+ {
15626
+ error: "The Athena tables showcase config is invalid."
15627
+ },
15628
+ { status: 400 }
15629
+ );
15630
+ }
15631
+ if (!hasAthenaTableSchemaCredentials(config)) {
15632
+ return json2(
15633
+ {
15634
+ error: "Gateway URL, API key, and database are required for schema introspection."
15635
+ },
15636
+ { status: 400 }
15637
+ );
15638
+ }
15639
+ try {
15640
+ const response = await fetchAthenaTableCatalog(
15641
+ config,
15642
+ {
15643
+ client: options?.client
15644
+ }
15645
+ );
15646
+ return json2(response);
15647
+ } catch (error) {
15648
+ return json2(
15649
+ {
15650
+ error: error instanceof Error ? error.message : "Athena schema introspection failed."
15651
+ },
15652
+ { status: 500 }
15653
+ );
15654
+ }
15655
+ }
15656
+ function createAthenaTableSchemaHandlers(options) {
15657
+ return {
15658
+ POST: (request2) => handleAthenaTableSchemaPost(request2, options)
15659
+ };
15660
+ }
15661
+
12185
15662
  // src/browser.ts
12186
15663
  function throwBrowserUnsupported(apiName) {
12187
15664
  throw new Error(
@@ -12219,6 +15696,7 @@ exports.ATHENA_AUTH_MAX_ADMIN_JSON_BYTES = ATHENA_AUTH_MAX_ADMIN_JSON_BYTES;
12219
15696
  exports.ATHENA_AUTH_MAX_ADMIN_JSON_DEPTH = ATHENA_AUTH_MAX_ADMIN_JSON_DEPTH;
12220
15697
  exports.ATHENA_AUTH_MAX_TEMPLATE_VARIABLES = ATHENA_AUTH_MAX_TEMPLATE_VARIABLES;
12221
15698
  exports.ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH = ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH;
15699
+ exports.ATHENA_TABLE_SCHEMA_ROUTE = ATHENA_TABLE_SCHEMA_ROUTE;
12222
15700
  exports.AthenaBillingError = AthenaBillingError;
12223
15701
  exports.AthenaChatError = AthenaChatError;
12224
15702
  exports.AthenaConfigurationError = AthenaConfigurationError;
@@ -12245,6 +15723,7 @@ exports.buildAthenaReadQueryFindManyOrderBy = buildAthenaReadQueryFindManyOrderB
12245
15723
  exports.buildAthenaReadQueryFindManySelect = buildAthenaReadQueryFindManySelect;
12246
15724
  exports.buildAthenaReadQueryFindManyWhere = buildAthenaReadQueryFindManyWhere;
12247
15725
  exports.buildAthenaReadQuerySelectString = buildAthenaReadQuerySelectString;
15726
+ exports.buildAthenaTableCatalogQueries = buildAthenaTableCatalogQueries;
12248
15727
  exports.buildAthenaTableFindManyOrderBy = buildAthenaTableFindManyOrderBy;
12249
15728
  exports.buildAthenaTableFindManySelect = buildAthenaTableFindManySelect;
12250
15729
  exports.buildAthenaTableFindManyWhere = buildAthenaTableFindManyWhere;
@@ -12254,6 +15733,7 @@ exports.clampAthenaReadQueryTotalItems = clampAthenaReadQueryTotalItems;
12254
15733
  exports.clampAthenaTableTotalItems = clampAthenaTableTotalItems;
12255
15734
  exports.coerceInt = coerceInt;
12256
15735
  exports.createAthenaStorageError = createAthenaStorageError;
15736
+ exports.createAthenaTableSchemaHandlers = createAthenaTableSchemaHandlers;
12257
15737
  exports.createAuthReactEmailInput = createAuthReactEmailInput;
12258
15738
  exports.createBillingModule = createBillingModule;
12259
15739
  exports.createClient = createClient;
@@ -12269,6 +15749,8 @@ exports.defineSchema = defineSchema;
12269
15749
  exports.enumeration = enumeration;
12270
15750
  exports.executeAthenaReadQuery = executeAthenaReadQuery;
12271
15751
  exports.executeAthenaTableQuery = executeAthenaTableQuery;
15752
+ exports.fetchAthenaTableCatalog = fetchAthenaTableCatalog;
15753
+ exports.fetchTableCatalog = fetchTableCatalog;
12272
15754
  exports.filterIntrospectionSnapshot = filterIntrospectionSnapshot;
12273
15755
  exports.findGeneratorConfigPath = findGeneratorConfigPath;
12274
15756
  exports.flattenAthenaReadQueryRows = flattenAthenaReadQueryRows;
@@ -12276,8 +15758,11 @@ exports.flattenAthenaRows = flattenAthenaRows;
12276
15758
  exports.generateArtifactsFromSnapshot = generateArtifactsFromSnapshot;
12277
15759
  exports.generatorEnv = generatorEnv;
12278
15760
  exports.getAthenaDebugAst = getAthenaDebugAst;
15761
+ exports.handleAthenaTableSchemaPost = handleAthenaTableSchemaPost;
15762
+ exports.hasAthenaTableSchemaCredentials = hasAthenaTableSchemaCredentials;
12279
15763
  exports.identifier = identifier;
12280
15764
  exports.isAthenaGatewayError = isAthenaGatewayError;
15765
+ exports.isAthenaTableSchemaConfig = isAthenaTableSchemaConfig;
12281
15766
  exports.isOk = isOk;
12282
15767
  exports.json = json;
12283
15768
  exports.loadGeneratorConfig = loadGeneratorConfig;
@@ -12289,10 +15774,12 @@ exports.normalizeGeneratorConfig = normalizeGeneratorConfig;
12289
15774
  exports.normalizeSchemaSelection = normalizeSchemaSelection;
12290
15775
  exports.normalizeTableSelection = normalizeTableSelection;
12291
15776
  exports.number = number;
15777
+ exports.parseAthenaTableSchemaScope = parseAthenaTableSchemaScope;
12292
15778
  exports.parseBooleanFlag = parseBooleanFlag2;
12293
15779
  exports.renderAthenaReactEmail = renderAthenaReactEmail;
12294
15780
  exports.requireAffected = requireAffected;
12295
15781
  exports.requireSuccess = requireSuccess;
15782
+ exports.resolveAthenaReadQueryPageFetch = resolveAthenaReadQueryPageFetch;
12296
15783
  exports.resolveGeneratorProvider = resolveGeneratorProvider;
12297
15784
  exports.resolvePostgresColumnType = resolvePostgresColumnType;
12298
15785
  exports.resolveProviderSchemas = resolveProviderSchemas;