@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.
- package/README.md +17 -1
- package/dist/admin.cjs +55 -1
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +32 -8
- package/dist/admin.d.ts +32 -8
- package/dist/admin.js +54 -2
- package/dist/admin.js.map +1 -1
- package/dist/athena-auth-url-C1FbVmN6.d.cts +200 -0
- package/dist/athena-auth-url-C1FbVmN6.d.ts +200 -0
- package/dist/{athena-request-headers-C7Jy-c_D.d.ts → athena-request-headers-BnFN2mbd.d.cts} +49 -201
- package/dist/{athena-request-headers-DujFFyMU.d.cts → athena-request-headers-Dwdkq2WR.d.ts} +49 -201
- package/dist/billing.cjs +1 -1
- package/dist/billing.cjs.map +1 -1
- package/dist/billing.js +1 -1
- package/dist/billing.js.map +1 -1
- package/dist/browser.cjs +3735 -248
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +11 -10
- package/dist/browser.d.ts +11 -10
- package/dist/browser.js +3726 -249
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +3232 -190
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +4 -4
- package/dist/cli/index.d.ts +4 -4
- package/dist/cli/index.js +3232 -190
- package/dist/cli/index.js.map +1 -1
- package/dist/cloudflare.cjs +12914 -0
- package/dist/cloudflare.cjs.map +1 -0
- package/dist/cloudflare.d.cts +368 -0
- package/dist/cloudflare.d.ts +368 -0
- package/dist/cloudflare.js +12885 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/cookies.cjs +4 -3
- package/dist/cookies.cjs.map +1 -1
- package/dist/cookies.js +4 -3
- package/dist/cookies.js.map +1 -1
- package/dist/env.cjs +130 -0
- package/dist/env.cjs.map +1 -0
- package/dist/env.d.cts +70 -0
- package/dist/env.d.ts +70 -0
- package/dist/env.js +122 -0
- package/dist/env.js.map +1 -0
- package/dist/index.cjs +3749 -241
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -10
- package/dist/index.d.ts +11 -10
- package/dist/index.js +3739 -242
- package/dist/index.js.map +1 -1
- package/dist/{model-form-BhWWsA-7.d.cts → model-form-D0ykVVOs.d.cts} +26 -4
- package/dist/{model-form-BbdzJ9Uh.d.ts → model-form-U8NVtfSA.d.ts} +26 -4
- package/dist/{module-xFd7_Igv.d.cts → module-CMWlJ1z3.d.cts} +5 -5
- package/dist/{module-DKkJKOuJ.d.ts → module-CZ-wPcf2.d.ts} +5 -5
- package/dist/next/client.cjs +3212 -196
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.d.cts +6 -5
- package/dist/next/client.d.ts +6 -5
- package/dist/next/client.js +3212 -196
- package/dist/next/client.js.map +1 -1
- package/dist/next/server.cjs +4461 -781
- package/dist/next/server.cjs.map +1 -1
- package/dist/next/server.d.cts +139 -13
- package/dist/next/server.d.ts +139 -13
- package/dist/next/server.js +4451 -782
- package/dist/next/server.js.map +1 -1
- package/dist/{pipeline-DuKzYGia.d.cts → pipeline-BCpb4BX1.d.cts} +1 -1
- package/dist/{pipeline-wer2G9xW.d.ts → pipeline-CgmXwMeX.d.ts} +1 -1
- package/dist/{proxy-request-headers-m4D2Tduy.d.ts → proxy-request-headers-CttlcuRb.d.ts} +1 -1
- package/dist/{proxy-request-headers-DGxdoyA0.d.cts → proxy-request-headers-pIBSn1Fw.d.cts} +1 -1
- package/dist/react.cjs +290 -31
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +62 -12
- package/dist/react.d.ts +62 -12
- package/dist/react.js +290 -32
- package/dist/react.js.map +1 -1
- package/dist/schema-handlers-CvWqF-dW.d.ts +138 -0
- package/dist/schema-handlers-Dr8h9Jg-.d.cts +138 -0
- package/dist/social-providers.cjs +1 -1
- package/dist/social-providers.cjs.map +1 -1
- package/dist/social-providers.d.cts +1 -1
- package/dist/social-providers.d.ts +1 -1
- package/dist/social-providers.js +1 -1
- package/dist/social-providers.js.map +1 -1
- package/dist/{types-Bltx6iL6.d.ts → types-B2RZPivM.d.cts} +8 -1
- package/dist/{types-Bltx6iL6.d.cts → types-B2RZPivM.d.ts} +8 -1
- package/dist/{types-1ztXDgPa.d.cts → types-BKklrX4J.d.ts} +14 -2
- package/dist/{types-AOY-GLu8.d.cts → types-BVKpQmfY.d.cts} +11 -0
- package/dist/{types-AOY-GLu8.d.ts → types-BVKpQmfY.d.ts} +11 -0
- package/dist/{types-CgCv5o6R.d.cts → types-D5dj1v5Z.d.cts} +1 -1
- package/dist/{types-CccOiXPo.d.ts → types-DqBFwfhn.d.cts} +14 -2
- package/dist/{types-B75PdABb.d.ts → types-S-bTMPiM.d.ts} +1 -1
- package/dist/utils.cjs +30 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +4 -3
- package/dist/utils.d.ts +4 -3
- package/dist/utils.js +30 -1
- package/dist/utils.js.map +1 -1
- package/dist/{v3-client-CWfZHcKL.d.cts → v3-client-DP-qg82X.d.cts} +323 -5
- package/dist/{v3-client-DZp2NEhK.d.ts → v3-client-OAai_JNs.d.ts} +323 -5
- package/package.json +25 -4
package/dist/index.cjs
CHANGED
|
@@ -1844,6 +1844,8 @@ function buildUpdateDebugSql(payload) {
|
|
|
1844
1844
|
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
1845
1845
|
}
|
|
1846
1846
|
const pagination = resolvePagination({
|
|
1847
|
+
limit: payload.limit,
|
|
1848
|
+
offset: payload.offset,
|
|
1847
1849
|
currentPage: payload.current_page,
|
|
1848
1850
|
pageSize: payload.page_size
|
|
1849
1851
|
});
|
|
@@ -1866,6 +1868,8 @@ function buildDeleteDebugSql(payload) {
|
|
|
1866
1868
|
sqlParts.push(`WHERE ${whereClauses.join(" AND ")}`);
|
|
1867
1869
|
}
|
|
1868
1870
|
const pagination = resolvePagination({
|
|
1871
|
+
limit: payload.limit,
|
|
1872
|
+
offset: payload.offset,
|
|
1869
1873
|
currentPage: payload.current_page,
|
|
1870
1874
|
pageSize: payload.page_size
|
|
1871
1875
|
});
|
|
@@ -2009,7 +2013,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
|
|
|
2009
2013
|
|
|
2010
2014
|
// package.json
|
|
2011
2015
|
var package_default = {
|
|
2012
|
-
version: "3.1
|
|
2016
|
+
version: "3.5.1"
|
|
2013
2017
|
};
|
|
2014
2018
|
|
|
2015
2019
|
// src/sdk-version.ts
|
|
@@ -2306,13 +2310,14 @@ var LEGACY_COOKIE_PREFIX = "better-auth";
|
|
|
2306
2310
|
var DEFAULT_SESSION_MAX_AGE = 7 * 24 * 60 * 60;
|
|
2307
2311
|
var DEFAULT_CACHE_MAX_AGE = 60 * 5;
|
|
2308
2312
|
function isProductionRuntime() {
|
|
2309
|
-
return
|
|
2313
|
+
return globalThis.process?.env?.NODE_ENV === "production";
|
|
2310
2314
|
}
|
|
2311
2315
|
function getEnvironmentSecret() {
|
|
2312
|
-
|
|
2316
|
+
const env = globalThis.process?.env;
|
|
2317
|
+
if (!env) {
|
|
2313
2318
|
return void 0;
|
|
2314
2319
|
}
|
|
2315
|
-
return
|
|
2320
|
+
return env.ATHENA_AUTH_SECRET || env.BETTER_AUTH_SECRET || env.AUTH_SECRET;
|
|
2316
2321
|
}
|
|
2317
2322
|
function isDynamicBaseURLConfig(baseURL) {
|
|
2318
2323
|
return typeof baseURL === "object" && baseURL !== null && "allowedHosts" in baseURL && Array.isArray(baseURL.allowedHosts);
|
|
@@ -4769,6 +4774,14 @@ function createAuthModule(config = {}, runtimeOptions = {}) {
|
|
|
4769
4774
|
changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
|
|
4770
4775
|
deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
|
|
4771
4776
|
changePassword: (input, options) => postGeneric("/change-password", input, options),
|
|
4777
|
+
// Better Auth UI flat method aliases (also nested under session/account/social/user).
|
|
4778
|
+
listSessions: (input, options) => getGeneric("/list-sessions", input, options),
|
|
4779
|
+
revokeSession: sessionRevokeBinding,
|
|
4780
|
+
revokeOtherSessions,
|
|
4781
|
+
listAccounts: (input, options) => getGeneric("/list-accounts", input, options),
|
|
4782
|
+
unlinkAccount: (input, options) => postGeneric("/unlink-account", input, options),
|
|
4783
|
+
linkSocial: (input, options) => postGeneric("/link-social", input, options),
|
|
4784
|
+
updateUser: (input, options) => postGeneric("/update-user", input, options),
|
|
4772
4785
|
user: {
|
|
4773
4786
|
update: (input, options) => postGeneric("/update-user", input, options),
|
|
4774
4787
|
delete: (input, options) => postGeneric("/delete-user", input, options),
|
|
@@ -5874,9 +5887,9 @@ function readHeadersField(value) {
|
|
|
5874
5887
|
const headers = value.headers;
|
|
5875
5888
|
if (!isRecord8(headers)) return {};
|
|
5876
5889
|
const result = {};
|
|
5877
|
-
for (const [key,
|
|
5878
|
-
if (typeof
|
|
5879
|
-
result[key] =
|
|
5890
|
+
for (const [key, headerValue3] of Object.entries(headers)) {
|
|
5891
|
+
if (typeof headerValue3 === "string") {
|
|
5892
|
+
result[key] = headerValue3;
|
|
5880
5893
|
}
|
|
5881
5894
|
}
|
|
5882
5895
|
return result;
|
|
@@ -9554,6 +9567,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, beha
|
|
|
9554
9567
|
strip_nulls: mergedOptions?.stripNulls ?? true
|
|
9555
9568
|
};
|
|
9556
9569
|
if (executionState.order) payload.sort_by = executionState.order;
|
|
9570
|
+
if (executionState.limit !== void 0) payload.limit = executionState.limit;
|
|
9571
|
+
if (executionState.offset !== void 0) payload.offset = executionState.offset;
|
|
9557
9572
|
if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
|
|
9558
9573
|
if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
|
|
9559
9574
|
if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
|
|
@@ -9608,6 +9623,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, beha
|
|
|
9608
9623
|
conditions: filters
|
|
9609
9624
|
};
|
|
9610
9625
|
if (executionState.order) payload.sort_by = executionState.order;
|
|
9626
|
+
if (executionState.limit !== void 0) payload.limit = executionState.limit;
|
|
9627
|
+
if (executionState.offset !== void 0) payload.offset = executionState.offset;
|
|
9611
9628
|
if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
|
|
9612
9629
|
if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
|
|
9613
9630
|
if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
|
|
@@ -9659,7 +9676,11 @@ function createQueryBuilder(client, formatGatewayResult, behavior, tracer) {
|
|
|
9659
9676
|
if (!normalizedQuery) {
|
|
9660
9677
|
throw new Error("query requires a non-empty string");
|
|
9661
9678
|
}
|
|
9662
|
-
const
|
|
9679
|
+
const params = options?.params;
|
|
9680
|
+
const payload = {
|
|
9681
|
+
query: normalizedQuery,
|
|
9682
|
+
...Array.isArray(params) ? { params } : {}
|
|
9683
|
+
};
|
|
9663
9684
|
const callsite = captureTraceCallsite(tracer);
|
|
9664
9685
|
return executeRead(
|
|
9665
9686
|
behavior,
|
|
@@ -9708,7 +9729,7 @@ function normalizeAuthClientConfig(auth, defaultBaseUrl) {
|
|
|
9708
9729
|
}
|
|
9709
9730
|
function createInternalClientCore(config) {
|
|
9710
9731
|
const normalizedAuthConfig = normalizeAuthClientConfig(config.auth, config.authUrl);
|
|
9711
|
-
const gatewayTransport = createAthenaGatewayClient({
|
|
9732
|
+
const gatewayTransport = config.gatewayTransport ?? createAthenaGatewayClient({
|
|
9712
9733
|
baseUrl: config.baseUrl,
|
|
9713
9734
|
apiKey: config.apiKey,
|
|
9714
9735
|
client: config.client ?? void 0,
|
|
@@ -9863,205 +9884,2843 @@ function createInternalClientView(core, resolveContext) {
|
|
|
9863
9884
|
};
|
|
9864
9885
|
}
|
|
9865
9886
|
|
|
9866
|
-
// src/
|
|
9867
|
-
var
|
|
9868
|
-
var
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
envelopeKind: "athena",
|
|
9886
|
-
methods: [
|
|
9887
|
-
{ name: "getCapabilities", method: "GET", path: "/billing/v1/capabilities" },
|
|
9888
|
-
{ name: "createCheckout", method: "POST", path: "/billing/v1/checkouts" },
|
|
9889
|
-
{ name: "listProducts", method: "GET", path: "/billing/v1/products" },
|
|
9890
|
-
{ name: "listPrices", method: "GET", path: "/billing/v1/prices" },
|
|
9891
|
-
{ name: "listCustomers", method: "GET", path: "/billing/v1/customers" },
|
|
9892
|
-
{ name: "createCustomer", method: "POST", path: "/billing/v1/customers" },
|
|
9893
|
-
{ name: "getCustomer", method: "GET", path: "/billing/v1/customers/{id}" },
|
|
9894
|
-
{ name: "updateCustomer", method: "PATCH", path: "/billing/v1/customers/{id}" },
|
|
9895
|
-
{ name: "deleteCustomer", method: "DELETE", path: "/billing/v1/customers/{id}" },
|
|
9896
|
-
{ name: "listPayments", method: "GET", path: "/billing/v1/payments" },
|
|
9897
|
-
{ name: "createPayment", method: "POST", path: "/billing/v1/payments" },
|
|
9898
|
-
{ name: "getPayment", method: "GET", path: "/billing/v1/payments/{id}" },
|
|
9899
|
-
{ name: "cancelPayment", method: "POST", path: "/billing/v1/payments/{id}/cancel" },
|
|
9900
|
-
{ name: "listPaymentLinks", method: "GET", path: "/billing/v1/payment-links" },
|
|
9901
|
-
{ name: "createPaymentLink", method: "POST", path: "/billing/v1/payment-links" },
|
|
9902
|
-
{ name: "getPaymentLink", method: "GET", path: "/billing/v1/payment-links/{id}" },
|
|
9903
|
-
{ name: "updatePaymentLink", method: "PATCH", path: "/billing/v1/payment-links/{id}" },
|
|
9904
|
-
{ name: "deletePaymentLink", method: "DELETE", path: "/billing/v1/payment-links/{id}" },
|
|
9905
|
-
{ name: "listRefunds", method: "GET", path: "/billing/v1/refunds" },
|
|
9906
|
-
{ name: "createRefund", method: "POST", path: "/billing/v1/refunds" },
|
|
9907
|
-
{ name: "getRefund", method: "GET", path: "/billing/v1/refunds/{id}" },
|
|
9908
|
-
{ name: "cancelRefund", method: "POST", path: "/billing/v1/refunds/{id}/cancel" },
|
|
9909
|
-
{ name: "listSubscriptions", method: "GET", path: "/billing/v1/subscriptions" },
|
|
9910
|
-
{ name: "createSubscription", method: "POST", path: "/billing/v1/subscriptions" },
|
|
9911
|
-
{ name: "getSubscription", method: "GET", path: "/billing/v1/subscriptions/{id}" },
|
|
9912
|
-
{ name: "updateSubscription", method: "PATCH", path: "/billing/v1/subscriptions/{id}" },
|
|
9913
|
-
{ name: "cancelSubscription", method: "POST", path: "/billing/v1/subscriptions/{id}/cancel" },
|
|
9914
|
-
{ name: "listInvoices", method: "GET", path: "/billing/v1/invoices" },
|
|
9915
|
-
{ name: "getInvoice", method: "GET", path: "/billing/v1/invoices/{id}" },
|
|
9916
|
-
{ name: "listWebhooks", method: "GET", path: "/billing/v1/webhooks" },
|
|
9917
|
-
{ name: "createWebhook", method: "POST", path: "/billing/v1/webhooks" },
|
|
9918
|
-
{ name: "getWebhook", method: "GET", path: "/billing/v1/webhooks/{id}" },
|
|
9919
|
-
{ name: "updateWebhook", method: "PATCH", path: "/billing/v1/webhooks/{id}" },
|
|
9920
|
-
{ name: "deleteWebhook", method: "DELETE", path: "/billing/v1/webhooks/{id}" },
|
|
9921
|
-
{ name: "testWebhook", method: "POST", path: "/billing/v1/webhooks/{id}/test" },
|
|
9922
|
-
{
|
|
9923
|
-
name: "listConnections",
|
|
9924
|
-
method: "GET",
|
|
9925
|
-
path: "/admin/billing/clients/{client_name}/connections"
|
|
9926
|
-
},
|
|
9927
|
-
{
|
|
9928
|
-
name: "createConnection",
|
|
9929
|
-
method: "POST",
|
|
9930
|
-
path: "/admin/billing/clients/{client_name}/connections"
|
|
9931
|
-
},
|
|
9932
|
-
{
|
|
9933
|
-
name: "getConnection",
|
|
9934
|
-
method: "GET",
|
|
9935
|
-
path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
|
|
9936
|
-
},
|
|
9937
|
-
{
|
|
9938
|
-
name: "updateConnection",
|
|
9939
|
-
method: "PATCH",
|
|
9940
|
-
path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
|
|
9941
|
-
},
|
|
9942
|
-
{
|
|
9943
|
-
name: "deleteConnection",
|
|
9944
|
-
method: "DELETE",
|
|
9945
|
-
path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
|
|
9946
|
-
},
|
|
9947
|
-
{
|
|
9948
|
-
name: "reconcileDocument",
|
|
9949
|
-
method: "POST",
|
|
9950
|
-
path: "/admin/billing/clients/{client_name}/connections/{connection_id}/reconcile"
|
|
9951
|
-
},
|
|
9952
|
-
{
|
|
9953
|
-
name: "listWebhookEvents",
|
|
9954
|
-
method: "GET",
|
|
9955
|
-
path: "/admin/billing/clients/{client_name}/webhook-events"
|
|
9887
|
+
// src/cloudflare/types.ts
|
|
9888
|
+
var CLOUDFLARE_EDGE_BASE_URL = "https://athena.local/cloudflare-edge";
|
|
9889
|
+
var CLOUDFLARE_EDGE_API_KEY = "cloudflare-edge-local";
|
|
9890
|
+
|
|
9891
|
+
// src/cloudflare/capabilities.ts
|
|
9892
|
+
function createGatewayCapabilities(options) {
|
|
9893
|
+
const storageConfigured = options?.storageConfigured ?? true;
|
|
9894
|
+
return {
|
|
9895
|
+
mode: "gateway",
|
|
9896
|
+
db: {
|
|
9897
|
+
engine: options?.engine ?? "postgresql",
|
|
9898
|
+
local: false,
|
|
9899
|
+
layers: {
|
|
9900
|
+
query: true,
|
|
9901
|
+
flatCrud: true,
|
|
9902
|
+
findManyAst: true,
|
|
9903
|
+
rpc: true,
|
|
9904
|
+
relations: true
|
|
9905
|
+
}
|
|
9956
9906
|
},
|
|
9957
|
-
{
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9907
|
+
storage: {
|
|
9908
|
+
local: false,
|
|
9909
|
+
objects: storageConfigured,
|
|
9910
|
+
catalogs: storageConfigured ? options?.storageCatalogs ?? true : false,
|
|
9911
|
+
backups: storageConfigured ? options?.storageBackups ?? true : false
|
|
9961
9912
|
},
|
|
9962
|
-
|
|
9963
|
-
|
|
9964
|
-
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
|
|
9913
|
+
auth: {
|
|
9914
|
+
remote: options?.authRemote ?? true
|
|
9915
|
+
}
|
|
9916
|
+
};
|
|
9917
|
+
}
|
|
9918
|
+
function createCloudflareEdgeCapabilities(options) {
|
|
9919
|
+
const hasObjects = options.hasR2 || Boolean(options.hasRemoteStorage);
|
|
9920
|
+
return {
|
|
9921
|
+
mode: "cloudflare-edge",
|
|
9922
|
+
db: {
|
|
9923
|
+
engine: "cloudflare-d1",
|
|
9924
|
+
local: true,
|
|
9925
|
+
layers: {
|
|
9926
|
+
query: true,
|
|
9927
|
+
flatCrud: true,
|
|
9928
|
+
findManyAst: options.findManyAst ?? false,
|
|
9929
|
+
rpc: false,
|
|
9930
|
+
relations: false
|
|
9931
|
+
}
|
|
9968
9932
|
},
|
|
9969
|
-
{
|
|
9970
|
-
|
|
9971
|
-
|
|
9972
|
-
|
|
9933
|
+
storage: {
|
|
9934
|
+
// Local objects only when an R2 binding is present.
|
|
9935
|
+
local: options.hasR2,
|
|
9936
|
+
// Remote hybrid root can still expose storage.objects via the HTTP API.
|
|
9937
|
+
objects: hasObjects,
|
|
9938
|
+
catalogs: false,
|
|
9939
|
+
backups: false
|
|
9973
9940
|
},
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
}
|
|
9977
|
-
|
|
9978
|
-
return path.replace(`{${name}}`, encodeURIComponent(value));
|
|
9941
|
+
auth: {
|
|
9942
|
+
remote: options.authRemote
|
|
9943
|
+
}
|
|
9944
|
+
};
|
|
9979
9945
|
}
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
9984
|
-
|
|
9985
|
-
|
|
9986
|
-
}
|
|
9987
|
-
const serialized = params.toString();
|
|
9988
|
-
return serialized ? `${path}?${serialized}` : path;
|
|
9946
|
+
|
|
9947
|
+
// src/cloudflare/d1/runner.ts
|
|
9948
|
+
function resultColumns(rows) {
|
|
9949
|
+
const first = rows.find((value) => value && typeof value === "object" && !Array.isArray(value));
|
|
9950
|
+
if (!first) return [];
|
|
9951
|
+
return Object.keys(first);
|
|
9989
9952
|
}
|
|
9990
|
-
function
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
};
|
|
9994
|
-
if (input.clientName) query.clientName = input.clientName;
|
|
9995
|
-
if ("cursor" in input && input.cursor) query.cursor = input.cursor;
|
|
9996
|
-
if ("source" in input && input.source) query.source = input.source;
|
|
9997
|
-
if ("limit" in input && input.limit !== void 0) query.limit = String(input.limit);
|
|
9998
|
-
if ("offset" in input && input.offset !== void 0) query.offset = String(input.offset);
|
|
9999
|
-
return query;
|
|
9953
|
+
function isIdentChar(ch) {
|
|
9954
|
+
if (!ch) return false;
|
|
9955
|
+
return /[A-Za-z0-9_]/.test(ch);
|
|
10000
9956
|
}
|
|
10001
|
-
function
|
|
10002
|
-
|
|
10003
|
-
|
|
9957
|
+
function scanSqlKeywordsOutsideLiterals(sql, onKeyword) {
|
|
9958
|
+
let inSingle = false;
|
|
9959
|
+
let inDouble = false;
|
|
9960
|
+
let inBacktick = false;
|
|
9961
|
+
let inBracket = false;
|
|
9962
|
+
let inLineComment = false;
|
|
9963
|
+
let inBlockComment = false;
|
|
9964
|
+
for (let i = 0; i < sql.length; i += 1) {
|
|
9965
|
+
const ch = sql[i];
|
|
9966
|
+
const next = sql[i + 1];
|
|
9967
|
+
if (inLineComment) {
|
|
9968
|
+
if (ch === "\n" || ch === "\r") inLineComment = false;
|
|
9969
|
+
continue;
|
|
9970
|
+
}
|
|
9971
|
+
if (inBlockComment) {
|
|
9972
|
+
if (ch === "*" && next === "/") {
|
|
9973
|
+
i += 1;
|
|
9974
|
+
inBlockComment = false;
|
|
9975
|
+
}
|
|
9976
|
+
continue;
|
|
9977
|
+
}
|
|
9978
|
+
if (inSingle) {
|
|
9979
|
+
if (ch === "'" && next === "'") {
|
|
9980
|
+
i += 1;
|
|
9981
|
+
continue;
|
|
9982
|
+
}
|
|
9983
|
+
if (ch === "'") inSingle = false;
|
|
9984
|
+
continue;
|
|
9985
|
+
}
|
|
9986
|
+
if (inDouble) {
|
|
9987
|
+
if (ch === '"' && next === '"') {
|
|
9988
|
+
i += 1;
|
|
9989
|
+
continue;
|
|
9990
|
+
}
|
|
9991
|
+
if (ch === '"') inDouble = false;
|
|
9992
|
+
continue;
|
|
9993
|
+
}
|
|
9994
|
+
if (inBacktick) {
|
|
9995
|
+
if (ch === "`" && next === "`") {
|
|
9996
|
+
i += 1;
|
|
9997
|
+
continue;
|
|
9998
|
+
}
|
|
9999
|
+
if (ch === "`") inBacktick = false;
|
|
10000
|
+
continue;
|
|
10001
|
+
}
|
|
10002
|
+
if (inBracket) {
|
|
10003
|
+
if (ch === "]") inBracket = false;
|
|
10004
|
+
continue;
|
|
10005
|
+
}
|
|
10006
|
+
if (ch === "-" && next === "-") {
|
|
10007
|
+
inLineComment = true;
|
|
10008
|
+
i += 1;
|
|
10009
|
+
continue;
|
|
10010
|
+
}
|
|
10011
|
+
if (ch === "/" && next === "*") {
|
|
10012
|
+
inBlockComment = true;
|
|
10013
|
+
i += 1;
|
|
10014
|
+
continue;
|
|
10015
|
+
}
|
|
10016
|
+
if (ch === "'") {
|
|
10017
|
+
inSingle = true;
|
|
10018
|
+
continue;
|
|
10019
|
+
}
|
|
10020
|
+
if (ch === '"') {
|
|
10021
|
+
inDouble = true;
|
|
10022
|
+
continue;
|
|
10023
|
+
}
|
|
10024
|
+
if (ch === "`") {
|
|
10025
|
+
inBacktick = true;
|
|
10026
|
+
continue;
|
|
10027
|
+
}
|
|
10028
|
+
if (ch === "[") {
|
|
10029
|
+
inBracket = true;
|
|
10030
|
+
continue;
|
|
10031
|
+
}
|
|
10032
|
+
if (!isIdentChar(ch) || isIdentChar(sql[i - 1])) {
|
|
10033
|
+
continue;
|
|
10034
|
+
}
|
|
10035
|
+
let end = i + 1;
|
|
10036
|
+
while (end < sql.length && isIdentChar(sql[end])) {
|
|
10037
|
+
end += 1;
|
|
10038
|
+
}
|
|
10039
|
+
const keyword = sql.slice(i, end);
|
|
10040
|
+
if (onKeyword(keyword, i)) {
|
|
10041
|
+
return;
|
|
10042
|
+
}
|
|
10043
|
+
i = end - 1;
|
|
10004
10044
|
}
|
|
10005
|
-
return body;
|
|
10006
10045
|
}
|
|
10007
|
-
function
|
|
10008
|
-
const
|
|
10009
|
-
|
|
10046
|
+
function sqlContainsKeywordOutsideLiterals(sql, keyword) {
|
|
10047
|
+
const target = keyword.toUpperCase();
|
|
10048
|
+
let found = false;
|
|
10049
|
+
scanSqlKeywordsOutsideLiterals(sql, (token) => {
|
|
10050
|
+
if (token.toUpperCase() === target) {
|
|
10051
|
+
found = true;
|
|
10052
|
+
return true;
|
|
10053
|
+
}
|
|
10054
|
+
return false;
|
|
10010
10055
|
});
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
|
|
10019
|
-
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10056
|
+
return found;
|
|
10057
|
+
}
|
|
10058
|
+
function sqlFirstKeywordOutsideLiterals(sql) {
|
|
10059
|
+
let first = null;
|
|
10060
|
+
scanSqlKeywordsOutsideLiterals(sql, (token) => {
|
|
10061
|
+
first = token;
|
|
10062
|
+
return true;
|
|
10063
|
+
});
|
|
10064
|
+
return first;
|
|
10065
|
+
}
|
|
10066
|
+
var ROW_PRODUCING_LEAD_KEYWORDS = /* @__PURE__ */ new Set(["SELECT", "PRAGMA", "EXPLAIN", "VALUES"]);
|
|
10067
|
+
var MUTATION_LEAD_KEYWORDS = /* @__PURE__ */ new Set(["INSERT", "UPDATE", "DELETE", "REPLACE"]);
|
|
10068
|
+
var WITH_TERMINAL_KEYWORDS = /* @__PURE__ */ new Set([
|
|
10069
|
+
"SELECT",
|
|
10070
|
+
"INSERT",
|
|
10071
|
+
"UPDATE",
|
|
10072
|
+
"DELETE",
|
|
10073
|
+
"REPLACE",
|
|
10074
|
+
"VALUES",
|
|
10075
|
+
"PRAGMA",
|
|
10076
|
+
"EXPLAIN"
|
|
10077
|
+
]);
|
|
10078
|
+
function sqlTerminalKeywordAfterWith(sql) {
|
|
10079
|
+
let inSingle = false;
|
|
10080
|
+
let inDouble = false;
|
|
10081
|
+
let inBacktick = false;
|
|
10082
|
+
let inBracket = false;
|
|
10083
|
+
let inLineComment = false;
|
|
10084
|
+
let inBlockComment = false;
|
|
10085
|
+
let depth = 0;
|
|
10086
|
+
let sawWith = false;
|
|
10087
|
+
for (let i = 0; i < sql.length; i += 1) {
|
|
10088
|
+
const ch = sql[i];
|
|
10089
|
+
const next = sql[i + 1];
|
|
10090
|
+
if (inLineComment) {
|
|
10091
|
+
if (ch === "\n" || ch === "\r") inLineComment = false;
|
|
10092
|
+
continue;
|
|
10093
|
+
}
|
|
10094
|
+
if (inBlockComment) {
|
|
10095
|
+
if (ch === "*" && next === "/") {
|
|
10096
|
+
i += 1;
|
|
10097
|
+
inBlockComment = false;
|
|
10033
10098
|
}
|
|
10099
|
+
continue;
|
|
10034
10100
|
}
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
body: requestBody,
|
|
10040
|
-
signal: options?.signal
|
|
10041
|
-
});
|
|
10042
|
-
if (responseType === "text") {
|
|
10043
|
-
const text = await response.text();
|
|
10044
|
-
if (!response.ok) {
|
|
10045
|
-
throw new AthenaBillingError({
|
|
10046
|
-
message: `Billing request failed (${response.status})`,
|
|
10047
|
-
status: response.status,
|
|
10048
|
-
endpoint: path,
|
|
10049
|
-
method,
|
|
10050
|
-
body: text
|
|
10051
|
-
});
|
|
10101
|
+
if (inSingle) {
|
|
10102
|
+
if (ch === "'" && next === "'") {
|
|
10103
|
+
i += 1;
|
|
10104
|
+
continue;
|
|
10052
10105
|
}
|
|
10053
|
-
|
|
10106
|
+
if (ch === "'") inSingle = false;
|
|
10107
|
+
continue;
|
|
10054
10108
|
}
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
parsed = JSON.parse(rawText);
|
|
10060
|
-
} catch {
|
|
10061
|
-
parsed = rawText;
|
|
10109
|
+
if (inDouble) {
|
|
10110
|
+
if (ch === '"' && next === '"') {
|
|
10111
|
+
i += 1;
|
|
10112
|
+
continue;
|
|
10062
10113
|
}
|
|
10063
|
-
|
|
10064
|
-
|
|
10114
|
+
if (ch === '"') inDouble = false;
|
|
10115
|
+
continue;
|
|
10116
|
+
}
|
|
10117
|
+
if (inBacktick) {
|
|
10118
|
+
if (ch === "`" && next === "`") {
|
|
10119
|
+
i += 1;
|
|
10120
|
+
continue;
|
|
10121
|
+
}
|
|
10122
|
+
if (ch === "`") inBacktick = false;
|
|
10123
|
+
continue;
|
|
10124
|
+
}
|
|
10125
|
+
if (inBracket) {
|
|
10126
|
+
if (ch === "]") inBracket = false;
|
|
10127
|
+
continue;
|
|
10128
|
+
}
|
|
10129
|
+
if (ch === "-" && next === "-") {
|
|
10130
|
+
inLineComment = true;
|
|
10131
|
+
i += 1;
|
|
10132
|
+
continue;
|
|
10133
|
+
}
|
|
10134
|
+
if (ch === "/" && next === "*") {
|
|
10135
|
+
inBlockComment = true;
|
|
10136
|
+
i += 1;
|
|
10137
|
+
continue;
|
|
10138
|
+
}
|
|
10139
|
+
if (ch === "'") {
|
|
10140
|
+
inSingle = true;
|
|
10141
|
+
continue;
|
|
10142
|
+
}
|
|
10143
|
+
if (ch === '"') {
|
|
10144
|
+
inDouble = true;
|
|
10145
|
+
continue;
|
|
10146
|
+
}
|
|
10147
|
+
if (ch === "`") {
|
|
10148
|
+
inBacktick = true;
|
|
10149
|
+
continue;
|
|
10150
|
+
}
|
|
10151
|
+
if (ch === "[") {
|
|
10152
|
+
inBracket = true;
|
|
10153
|
+
continue;
|
|
10154
|
+
}
|
|
10155
|
+
if (ch === "(") {
|
|
10156
|
+
depth += 1;
|
|
10157
|
+
continue;
|
|
10158
|
+
}
|
|
10159
|
+
if (ch === ")") {
|
|
10160
|
+
if (depth > 0) depth -= 1;
|
|
10161
|
+
continue;
|
|
10162
|
+
}
|
|
10163
|
+
if (depth !== 0 || !isIdentChar(ch) || isIdentChar(sql[i - 1])) {
|
|
10164
|
+
continue;
|
|
10165
|
+
}
|
|
10166
|
+
let end = i + 1;
|
|
10167
|
+
while (end < sql.length && isIdentChar(sql[end])) {
|
|
10168
|
+
end += 1;
|
|
10169
|
+
}
|
|
10170
|
+
const keyword = sql.slice(i, end);
|
|
10171
|
+
const upper = keyword.toUpperCase();
|
|
10172
|
+
if (!sawWith) {
|
|
10173
|
+
if (upper === "WITH") {
|
|
10174
|
+
sawWith = true;
|
|
10175
|
+
}
|
|
10176
|
+
i = end - 1;
|
|
10177
|
+
continue;
|
|
10178
|
+
}
|
|
10179
|
+
if (WITH_TERMINAL_KEYWORDS.has(upper)) {
|
|
10180
|
+
return keyword;
|
|
10181
|
+
}
|
|
10182
|
+
i = end - 1;
|
|
10183
|
+
}
|
|
10184
|
+
return null;
|
|
10185
|
+
}
|
|
10186
|
+
function sqlLeadStatementKeyword(sql) {
|
|
10187
|
+
const first = sqlFirstKeywordOutsideLiterals(sql);
|
|
10188
|
+
if (!first) return null;
|
|
10189
|
+
if (first.toUpperCase() !== "WITH") return first;
|
|
10190
|
+
return sqlTerminalKeywordAfterWith(sql) ?? first;
|
|
10191
|
+
}
|
|
10192
|
+
function statementExpectsResultRows(sql) {
|
|
10193
|
+
const lead = sqlLeadStatementKeyword(sql);
|
|
10194
|
+
if (lead) {
|
|
10195
|
+
const upper = lead.toUpperCase();
|
|
10196
|
+
if (ROW_PRODUCING_LEAD_KEYWORDS.has(upper)) {
|
|
10197
|
+
return true;
|
|
10198
|
+
}
|
|
10199
|
+
if (MUTATION_LEAD_KEYWORDS.has(upper)) {
|
|
10200
|
+
return sqlContainsKeywordOutsideLiterals(sql, "RETURNING");
|
|
10201
|
+
}
|
|
10202
|
+
}
|
|
10203
|
+
return sqlContainsKeywordOutsideLiterals(sql, "RETURNING");
|
|
10204
|
+
}
|
|
10205
|
+
function collectRowsFromBatchResults(results) {
|
|
10206
|
+
const rows = [];
|
|
10207
|
+
for (const item of results) {
|
|
10208
|
+
if (Array.isArray(item.results) && item.results.length > 0) {
|
|
10209
|
+
rows.push(...item.results);
|
|
10210
|
+
}
|
|
10211
|
+
}
|
|
10212
|
+
return rows;
|
|
10213
|
+
}
|
|
10214
|
+
function sumBatchAffectedRows(results, statementCount) {
|
|
10215
|
+
let sum2 = 0;
|
|
10216
|
+
let sawChanges = false;
|
|
10217
|
+
for (const item of results) {
|
|
10218
|
+
const changes = item.meta?.changes;
|
|
10219
|
+
if (typeof changes === "number") {
|
|
10220
|
+
sum2 += changes;
|
|
10221
|
+
sawChanges = true;
|
|
10222
|
+
}
|
|
10223
|
+
}
|
|
10224
|
+
return sawChanges ? sum2 : statementCount;
|
|
10225
|
+
}
|
|
10226
|
+
function matchSqlKeywordAt(query, index, keyword) {
|
|
10227
|
+
const len = keyword.length;
|
|
10228
|
+
if (index + len > query.length) {
|
|
10229
|
+
return null;
|
|
10230
|
+
}
|
|
10231
|
+
const slice = query.slice(index, index + len);
|
|
10232
|
+
if (slice.toLowerCase() !== keyword.toLowerCase()) {
|
|
10233
|
+
return null;
|
|
10234
|
+
}
|
|
10235
|
+
const before = index === 0 ? "" : query[index - 1];
|
|
10236
|
+
const after = index + len >= query.length ? "" : query[index + len];
|
|
10237
|
+
const isIdent = (c) => /[A-Za-z0-9_]/.test(c);
|
|
10238
|
+
if (before && isIdent(before)) {
|
|
10239
|
+
return null;
|
|
10240
|
+
}
|
|
10241
|
+
if (after && isIdent(after)) {
|
|
10242
|
+
return null;
|
|
10243
|
+
}
|
|
10244
|
+
return len;
|
|
10245
|
+
}
|
|
10246
|
+
function splitSqlStatements(query) {
|
|
10247
|
+
const statements = [];
|
|
10248
|
+
let inSingle = false;
|
|
10249
|
+
let inDouble = false;
|
|
10250
|
+
let inBacktick = false;
|
|
10251
|
+
let inBracket = false;
|
|
10252
|
+
let inLineComment = false;
|
|
10253
|
+
let inBlockComment = false;
|
|
10254
|
+
let segmentStart = 0;
|
|
10255
|
+
let segmentHasContent = false;
|
|
10256
|
+
let awaitTriggerBegin = false;
|
|
10257
|
+
let triggerBodyDepth = 0;
|
|
10258
|
+
let caseDepth = 0;
|
|
10259
|
+
const flushSegment = (end) => {
|
|
10260
|
+
if (!segmentHasContent) {
|
|
10261
|
+
segmentStart = end + 1;
|
|
10262
|
+
return;
|
|
10263
|
+
}
|
|
10264
|
+
const sql = query.slice(segmentStart, end).trim();
|
|
10265
|
+
if (sql) {
|
|
10266
|
+
statements.push(sql);
|
|
10267
|
+
}
|
|
10268
|
+
segmentHasContent = false;
|
|
10269
|
+
segmentStart = end + 1;
|
|
10270
|
+
awaitTriggerBegin = false;
|
|
10271
|
+
triggerBodyDepth = 0;
|
|
10272
|
+
caseDepth = 0;
|
|
10273
|
+
};
|
|
10274
|
+
for (let i = 0; i < query.length; i += 1) {
|
|
10275
|
+
const ch = query[i];
|
|
10276
|
+
const next = query[i + 1];
|
|
10277
|
+
if (inLineComment) {
|
|
10278
|
+
if (ch === "\n" || ch === "\r") {
|
|
10279
|
+
inLineComment = false;
|
|
10280
|
+
}
|
|
10281
|
+
continue;
|
|
10282
|
+
}
|
|
10283
|
+
if (inBlockComment) {
|
|
10284
|
+
if (ch === "*" && next === "/") {
|
|
10285
|
+
inBlockComment = false;
|
|
10286
|
+
i += 1;
|
|
10287
|
+
}
|
|
10288
|
+
continue;
|
|
10289
|
+
}
|
|
10290
|
+
if (inSingle) {
|
|
10291
|
+
if (ch === "'" && next === "'") {
|
|
10292
|
+
i += 1;
|
|
10293
|
+
continue;
|
|
10294
|
+
}
|
|
10295
|
+
if (ch === "'") {
|
|
10296
|
+
inSingle = false;
|
|
10297
|
+
}
|
|
10298
|
+
continue;
|
|
10299
|
+
}
|
|
10300
|
+
if (inDouble) {
|
|
10301
|
+
if (ch === '"' && next === '"') {
|
|
10302
|
+
i += 1;
|
|
10303
|
+
continue;
|
|
10304
|
+
}
|
|
10305
|
+
if (ch === '"') {
|
|
10306
|
+
inDouble = false;
|
|
10307
|
+
}
|
|
10308
|
+
continue;
|
|
10309
|
+
}
|
|
10310
|
+
if (inBacktick) {
|
|
10311
|
+
if (ch === "`" && next === "`") {
|
|
10312
|
+
i += 1;
|
|
10313
|
+
continue;
|
|
10314
|
+
}
|
|
10315
|
+
if (ch === "`") {
|
|
10316
|
+
inBacktick = false;
|
|
10317
|
+
}
|
|
10318
|
+
continue;
|
|
10319
|
+
}
|
|
10320
|
+
if (inBracket) {
|
|
10321
|
+
if (ch === "]") {
|
|
10322
|
+
inBracket = false;
|
|
10323
|
+
}
|
|
10324
|
+
continue;
|
|
10325
|
+
}
|
|
10326
|
+
if (ch === "-" && next === "-") {
|
|
10327
|
+
inLineComment = true;
|
|
10328
|
+
i += 1;
|
|
10329
|
+
continue;
|
|
10330
|
+
}
|
|
10331
|
+
if (ch === "/" && next === "*") {
|
|
10332
|
+
inBlockComment = true;
|
|
10333
|
+
i += 1;
|
|
10334
|
+
continue;
|
|
10335
|
+
}
|
|
10336
|
+
if (ch === "'") {
|
|
10337
|
+
inSingle = true;
|
|
10338
|
+
segmentHasContent = true;
|
|
10339
|
+
continue;
|
|
10340
|
+
}
|
|
10341
|
+
if (ch === '"') {
|
|
10342
|
+
inDouble = true;
|
|
10343
|
+
segmentHasContent = true;
|
|
10344
|
+
continue;
|
|
10345
|
+
}
|
|
10346
|
+
if (ch === "`") {
|
|
10347
|
+
inBacktick = true;
|
|
10348
|
+
segmentHasContent = true;
|
|
10349
|
+
continue;
|
|
10350
|
+
}
|
|
10351
|
+
if (ch === "[") {
|
|
10352
|
+
inBracket = true;
|
|
10353
|
+
segmentHasContent = true;
|
|
10354
|
+
continue;
|
|
10355
|
+
}
|
|
10356
|
+
if (/[A-Za-z_]/.test(ch)) {
|
|
10357
|
+
const createLen = matchSqlKeywordAt(query, i, "CREATE");
|
|
10358
|
+
if (createLen != null) {
|
|
10359
|
+
let j2 = i + createLen;
|
|
10360
|
+
const skipWsAndComments = () => {
|
|
10361
|
+
while (j2 < query.length) {
|
|
10362
|
+
const c = query[j2];
|
|
10363
|
+
const n = query[j2 + 1];
|
|
10364
|
+
if (/\s/.test(c)) {
|
|
10365
|
+
j2 += 1;
|
|
10366
|
+
continue;
|
|
10367
|
+
}
|
|
10368
|
+
if (c === "-" && n === "-") {
|
|
10369
|
+
j2 += 2;
|
|
10370
|
+
while (j2 < query.length && query[j2] !== "\n" && query[j2] !== "\r") {
|
|
10371
|
+
j2 += 1;
|
|
10372
|
+
}
|
|
10373
|
+
continue;
|
|
10374
|
+
}
|
|
10375
|
+
if (c === "/" && n === "*") {
|
|
10376
|
+
j2 += 2;
|
|
10377
|
+
while (j2 < query.length) {
|
|
10378
|
+
if (query[j2] === "*" && query[j2 + 1] === "/") {
|
|
10379
|
+
j2 += 2;
|
|
10380
|
+
break;
|
|
10381
|
+
}
|
|
10382
|
+
j2 += 1;
|
|
10383
|
+
}
|
|
10384
|
+
continue;
|
|
10385
|
+
}
|
|
10386
|
+
break;
|
|
10387
|
+
}
|
|
10388
|
+
};
|
|
10389
|
+
skipWsAndComments();
|
|
10390
|
+
const tempLen = matchSqlKeywordAt(query, j2, "TEMPORARY") ?? matchSqlKeywordAt(query, j2, "TEMP");
|
|
10391
|
+
if (tempLen != null) {
|
|
10392
|
+
j2 += tempLen;
|
|
10393
|
+
skipWsAndComments();
|
|
10394
|
+
}
|
|
10395
|
+
const triggerLen = matchSqlKeywordAt(query, j2, "TRIGGER");
|
|
10396
|
+
if (triggerLen != null) {
|
|
10397
|
+
awaitTriggerBegin = true;
|
|
10398
|
+
segmentHasContent = true;
|
|
10399
|
+
i += createLen - 1;
|
|
10400
|
+
continue;
|
|
10401
|
+
}
|
|
10402
|
+
segmentHasContent = true;
|
|
10403
|
+
i += createLen - 1;
|
|
10404
|
+
continue;
|
|
10405
|
+
}
|
|
10406
|
+
const caseLen = matchSqlKeywordAt(query, i, "CASE");
|
|
10407
|
+
if (caseLen != null) {
|
|
10408
|
+
caseDepth += 1;
|
|
10409
|
+
segmentHasContent = true;
|
|
10410
|
+
i += caseLen - 1;
|
|
10411
|
+
continue;
|
|
10412
|
+
}
|
|
10413
|
+
const beginLen = matchSqlKeywordAt(query, i, "BEGIN");
|
|
10414
|
+
if (beginLen != null) {
|
|
10415
|
+
if (awaitTriggerBegin) {
|
|
10416
|
+
triggerBodyDepth += 1;
|
|
10417
|
+
awaitTriggerBegin = false;
|
|
10418
|
+
}
|
|
10419
|
+
segmentHasContent = true;
|
|
10420
|
+
i += beginLen - 1;
|
|
10421
|
+
continue;
|
|
10422
|
+
}
|
|
10423
|
+
const endLen = matchSqlKeywordAt(query, i, "END");
|
|
10424
|
+
if (endLen != null) {
|
|
10425
|
+
if (caseDepth > 0) {
|
|
10426
|
+
caseDepth -= 1;
|
|
10427
|
+
} else if (triggerBodyDepth > 0) {
|
|
10428
|
+
triggerBodyDepth -= 1;
|
|
10429
|
+
}
|
|
10430
|
+
segmentHasContent = true;
|
|
10431
|
+
i += endLen - 1;
|
|
10432
|
+
continue;
|
|
10433
|
+
}
|
|
10434
|
+
let j = i + 1;
|
|
10435
|
+
while (j < query.length && /[A-Za-z0-9_]/.test(query[j])) {
|
|
10436
|
+
j += 1;
|
|
10437
|
+
}
|
|
10438
|
+
segmentHasContent = true;
|
|
10439
|
+
i = j - 1;
|
|
10440
|
+
continue;
|
|
10441
|
+
}
|
|
10442
|
+
if (ch === ";") {
|
|
10443
|
+
if (triggerBodyDepth > 0 || caseDepth > 0) {
|
|
10444
|
+
segmentHasContent = true;
|
|
10445
|
+
continue;
|
|
10446
|
+
}
|
|
10447
|
+
flushSegment(i);
|
|
10448
|
+
continue;
|
|
10449
|
+
}
|
|
10450
|
+
if (!/\s/.test(ch)) {
|
|
10451
|
+
segmentHasContent = true;
|
|
10452
|
+
}
|
|
10453
|
+
}
|
|
10454
|
+
flushSegment(query.length);
|
|
10455
|
+
return statements;
|
|
10456
|
+
}
|
|
10457
|
+
function isMultiStatement(query) {
|
|
10458
|
+
return splitSqlStatements(query).length > 1;
|
|
10459
|
+
}
|
|
10460
|
+
function resolveSessionTarget(db, input) {
|
|
10461
|
+
const sessionValue = input.bookmark?.trim() || input.sessionMode?.trim();
|
|
10462
|
+
if (!sessionValue) {
|
|
10463
|
+
return { target: db, session: null };
|
|
10464
|
+
}
|
|
10465
|
+
if (typeof db.withSession !== "function") {
|
|
10466
|
+
throw new Error("D1 session mode/bookmark requested but withSession is not available");
|
|
10467
|
+
}
|
|
10468
|
+
const session = db.withSession(sessionValue);
|
|
10469
|
+
return { target: session, session };
|
|
10470
|
+
}
|
|
10471
|
+
function normalizeD1BindParams(params) {
|
|
10472
|
+
return params.map((value) => {
|
|
10473
|
+
if (typeof value === "boolean") {
|
|
10474
|
+
return value ? 1 : 0;
|
|
10475
|
+
}
|
|
10476
|
+
return value;
|
|
10477
|
+
});
|
|
10478
|
+
}
|
|
10479
|
+
async function executeD1Query(db, input) {
|
|
10480
|
+
const query = input.query?.trim();
|
|
10481
|
+
if (!query) {
|
|
10482
|
+
return { ok: false, error: "invalid_query", message: "query is required" };
|
|
10483
|
+
}
|
|
10484
|
+
const params = normalizeD1BindParams(Array.isArray(input.params) ? input.params : []);
|
|
10485
|
+
const { target, session } = resolveSessionTarget(db, input);
|
|
10486
|
+
if (isMultiStatement(query)) {
|
|
10487
|
+
if (params.length > 0) {
|
|
10488
|
+
return {
|
|
10489
|
+
ok: false,
|
|
10490
|
+
error: "invalid_query",
|
|
10491
|
+
message: "params are only supported for single prepared statements"
|
|
10492
|
+
};
|
|
10493
|
+
}
|
|
10494
|
+
const resolveBookmark = () => session?.getBookmark() ?? null;
|
|
10495
|
+
const parts = splitSqlStatements(query);
|
|
10496
|
+
if (typeof target.batch === "function") {
|
|
10497
|
+
const prepared = parts.map((part) => target.prepare(part));
|
|
10498
|
+
const results = await target.batch(prepared);
|
|
10499
|
+
const rows2 = collectRowsFromBatchResults(results);
|
|
10500
|
+
return {
|
|
10501
|
+
ok: true,
|
|
10502
|
+
rows: rows2,
|
|
10503
|
+
columns: resultColumns(rows2),
|
|
10504
|
+
// Prefer returned rows; otherwise sum mutation meta.changes (not statement count).
|
|
10505
|
+
count: rows2.length > 0 ? rows2.length : sumBatchAffectedRows(results, parts.length),
|
|
10506
|
+
bookmark: resolveBookmark(),
|
|
10507
|
+
meta: { statementCount: parts.length, results },
|
|
10508
|
+
statementCount: parts.length
|
|
10509
|
+
};
|
|
10510
|
+
}
|
|
10511
|
+
const canExec = typeof target.exec === "function" && !session;
|
|
10512
|
+
if (canExec) {
|
|
10513
|
+
const execResult = await target.exec(query);
|
|
10514
|
+
return {
|
|
10515
|
+
ok: true,
|
|
10516
|
+
rows: [],
|
|
10517
|
+
columns: [],
|
|
10518
|
+
durationMs: execResult.duration,
|
|
10519
|
+
count: execResult.count,
|
|
10520
|
+
bookmark: resolveBookmark(),
|
|
10521
|
+
meta: { statementCount: execResult.count },
|
|
10522
|
+
statementCount: execResult.count
|
|
10523
|
+
};
|
|
10524
|
+
}
|
|
10525
|
+
return {
|
|
10526
|
+
ok: false,
|
|
10527
|
+
error: "invalid_query",
|
|
10528
|
+
message: "multi-statement query requires D1 batch() or exec() support"
|
|
10529
|
+
};
|
|
10530
|
+
}
|
|
10531
|
+
let statement = target.prepare(query);
|
|
10532
|
+
if (params.length > 0) {
|
|
10533
|
+
statement = statement.bind(...params);
|
|
10534
|
+
}
|
|
10535
|
+
const expectsRows = statementExpectsResultRows(query);
|
|
10536
|
+
const result = expectsRows ? await statement.all() : await statement.run();
|
|
10537
|
+
if (result.success === false) {
|
|
10538
|
+
const errorField = result.error;
|
|
10539
|
+
const message = typeof errorField === "string" && errorField.trim() ? errorField : "D1 query failed";
|
|
10540
|
+
return {
|
|
10541
|
+
ok: false,
|
|
10542
|
+
error: "query_failed",
|
|
10543
|
+
message
|
|
10544
|
+
};
|
|
10545
|
+
}
|
|
10546
|
+
const rows = Array.isArray(result.results) ? result.results : [];
|
|
10547
|
+
const bookmark = session?.getBookmark() ?? null;
|
|
10548
|
+
const meta = result.meta ?? {};
|
|
10549
|
+
const changes = typeof meta.changes === "number" ? meta.changes : typeof result.meta?.changes === "number" ? result.meta.changes : void 0;
|
|
10550
|
+
return {
|
|
10551
|
+
ok: true,
|
|
10552
|
+
rows,
|
|
10553
|
+
columns: resultColumns(rows),
|
|
10554
|
+
durationMs: typeof result.meta?.duration === "number" ? result.meta.duration : void 0,
|
|
10555
|
+
count: expectsRows ? rows.length : changes ?? rows.length,
|
|
10556
|
+
bookmark,
|
|
10557
|
+
meta
|
|
10558
|
+
};
|
|
10559
|
+
}
|
|
10560
|
+
async function executeD1Batch(db, input) {
|
|
10561
|
+
const statements = Array.isArray(input.statements) ? input.statements : [];
|
|
10562
|
+
if (statements.length === 0) {
|
|
10563
|
+
return {
|
|
10564
|
+
ok: false,
|
|
10565
|
+
error: "invalid_batch",
|
|
10566
|
+
message: "statements must contain at least one item"
|
|
10567
|
+
};
|
|
10568
|
+
}
|
|
10569
|
+
const { target, session } = resolveSessionTarget(db, input);
|
|
10570
|
+
const prepared = statements.map((item) => {
|
|
10571
|
+
const query = item.query?.trim();
|
|
10572
|
+
if (!query) {
|
|
10573
|
+
throw new Error("statements[].query is required");
|
|
10574
|
+
}
|
|
10575
|
+
const params = normalizeD1BindParams(Array.isArray(item.params) ? item.params : []);
|
|
10576
|
+
let statement = target.prepare(query);
|
|
10577
|
+
if (params.length > 0) {
|
|
10578
|
+
statement = statement.bind(...params);
|
|
10579
|
+
}
|
|
10580
|
+
return statement;
|
|
10581
|
+
});
|
|
10582
|
+
const results = await target.batch(prepared);
|
|
10583
|
+
const bookmark = session?.getBookmark() ?? null;
|
|
10584
|
+
return {
|
|
10585
|
+
ok: true,
|
|
10586
|
+
results,
|
|
10587
|
+
bookmark
|
|
10588
|
+
};
|
|
10589
|
+
}
|
|
10590
|
+
|
|
10591
|
+
// src/cloudflare/d1/sql.ts
|
|
10592
|
+
function asSingle(sql, params) {
|
|
10593
|
+
return { sql, params };
|
|
10594
|
+
}
|
|
10595
|
+
function asBatch(statements) {
|
|
10596
|
+
if (statements.length === 0) {
|
|
10597
|
+
throw new D1SqlCompileError("empty_insert", "batch requires at least one statement");
|
|
10598
|
+
}
|
|
10599
|
+
return {
|
|
10600
|
+
sql: statements[0].sql,
|
|
10601
|
+
params: statements[0].params,
|
|
10602
|
+
statements
|
|
10603
|
+
};
|
|
10604
|
+
}
|
|
10605
|
+
function hasPaginationBounds(payload) {
|
|
10606
|
+
return payload.limit !== void 0 || payload.offset !== void 0 || payload.page_size !== void 0 || payload.current_page !== void 0;
|
|
10607
|
+
}
|
|
10608
|
+
function assertEffectiveMutationBounds(payload) {
|
|
10609
|
+
if (payload.current_page !== void 0 && payload.page_size === void 0 && payload.limit === void 0) {
|
|
10610
|
+
throw new D1SqlCompileError(
|
|
10611
|
+
"page_without_size",
|
|
10612
|
+
"current_page requires page_size (or limit) for bounded update/delete on D1 edge-local"
|
|
10613
|
+
);
|
|
10614
|
+
}
|
|
10615
|
+
const clause = limitOffsetClause(payload);
|
|
10616
|
+
if (!clause.trim()) {
|
|
10617
|
+
throw new D1SqlCompileError(
|
|
10618
|
+
"invalid_pagination_bounds",
|
|
10619
|
+
"Bounded update/delete requires limit, offset, and/or page_size on D1 edge-local"
|
|
10620
|
+
);
|
|
10621
|
+
}
|
|
10622
|
+
}
|
|
10623
|
+
var SQLITE_ROWID_ALIASES = /* @__PURE__ */ new Set(["rowid", "oid", "_rowid_"]);
|
|
10624
|
+
function referencedMutationColumns(payload) {
|
|
10625
|
+
const names = [];
|
|
10626
|
+
for (const condition of payload.conditions ?? []) {
|
|
10627
|
+
const column = (condition.column ?? condition.eq_column ?? "").trim();
|
|
10628
|
+
if (column) names.push(column);
|
|
10629
|
+
}
|
|
10630
|
+
if (payload.sort_by?.field?.trim()) {
|
|
10631
|
+
names.push(payload.sort_by.field.trim());
|
|
10632
|
+
}
|
|
10633
|
+
return names;
|
|
10634
|
+
}
|
|
10635
|
+
function resolveBoundedIdentityColumn(payload, options) {
|
|
10636
|
+
const refs = referencedMutationColumns(payload);
|
|
10637
|
+
const lower = refs.map((name) => name.toLowerCase());
|
|
10638
|
+
if (lower.some((name) => SQLITE_ROWID_ALIASES.has(name))) {
|
|
10639
|
+
throw new D1SqlCompileError(
|
|
10640
|
+
"bounded_mutation_unsafe_identity",
|
|
10641
|
+
"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."
|
|
10642
|
+
);
|
|
10643
|
+
}
|
|
10644
|
+
const identity = options?.identityColumn?.trim();
|
|
10645
|
+
if (!identity) {
|
|
10646
|
+
throw new D1SqlCompileError(
|
|
10647
|
+
"bounded_mutation_no_unique_identity",
|
|
10648
|
+
"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."
|
|
10649
|
+
);
|
|
10650
|
+
}
|
|
10651
|
+
if (SQLITE_ROWID_ALIASES.has(identity.toLowerCase())) {
|
|
10652
|
+
throw new D1SqlCompileError(
|
|
10653
|
+
"bounded_mutation_unsafe_identity",
|
|
10654
|
+
`Bounded update/delete cannot use identity column "${identity}" \u2014 it may shadow SQLite row identity.`
|
|
10655
|
+
);
|
|
10656
|
+
}
|
|
10657
|
+
return identity;
|
|
10658
|
+
}
|
|
10659
|
+
function boundedRowidInClause(table2, whereSql, whereParams, payload, options) {
|
|
10660
|
+
assertEffectiveMutationBounds(payload);
|
|
10661
|
+
const identity = resolveBoundedIdentityColumn(payload, options);
|
|
10662
|
+
const identitySql = quoteIdent(identity);
|
|
10663
|
+
const innerWhere = whereSql.replace(/^WHERE\s+/i, "");
|
|
10664
|
+
const parts = [
|
|
10665
|
+
`SELECT ${identitySql} FROM ${quoteIdent(table2)}`,
|
|
10666
|
+
innerWhere ? `WHERE ${innerWhere}` : "",
|
|
10667
|
+
orderClause(payload.sort_by),
|
|
10668
|
+
limitOffsetClause(payload)
|
|
10669
|
+
].filter(Boolean);
|
|
10670
|
+
return {
|
|
10671
|
+
sql: `${identitySql} IN (${parts.join(" ")})`,
|
|
10672
|
+
params: [...whereParams]
|
|
10673
|
+
};
|
|
10674
|
+
}
|
|
10675
|
+
var D1SqlCompileError = class extends Error {
|
|
10676
|
+
code;
|
|
10677
|
+
constructor(code, message) {
|
|
10678
|
+
super(message);
|
|
10679
|
+
this.name = "D1SqlCompileError";
|
|
10680
|
+
this.code = code;
|
|
10681
|
+
}
|
|
10682
|
+
};
|
|
10683
|
+
var SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
10684
|
+
function quoteIdent(name) {
|
|
10685
|
+
const trimmed = name.trim();
|
|
10686
|
+
if (!trimmed) {
|
|
10687
|
+
throw new D1SqlCompileError("invalid_identifier", "Identifier is required");
|
|
10688
|
+
}
|
|
10689
|
+
if (trimmed.includes(".")) {
|
|
10690
|
+
throw new D1SqlCompileError(
|
|
10691
|
+
"schema_qualified_name",
|
|
10692
|
+
`Schema-qualified names are unsupported on D1 edge-local: ${trimmed}`
|
|
10693
|
+
);
|
|
10694
|
+
}
|
|
10695
|
+
if (!SAFE_IDENTIFIER.test(trimmed)) {
|
|
10696
|
+
throw new D1SqlCompileError(
|
|
10697
|
+
"invalid_identifier",
|
|
10698
|
+
`Invalid SQL identifier for D1 edge-local: ${trimmed}`
|
|
10699
|
+
);
|
|
10700
|
+
}
|
|
10701
|
+
return quoteQualifiedIdentifier(trimmed);
|
|
10702
|
+
}
|
|
10703
|
+
var RESPONSE_ALIAS_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_]*)$/;
|
|
10704
|
+
var SQL_ALIAS_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)\s+(?:as\s+)?([A-Za-z_][A-Za-z0-9_]*)$/i;
|
|
10705
|
+
function quoteSelectTokenStrict(token) {
|
|
10706
|
+
const trimmed = token.trim();
|
|
10707
|
+
if (!trimmed || trimmed === "*") return trimmed || "*";
|
|
10708
|
+
if (SAFE_IDENTIFIER.test(trimmed)) {
|
|
10709
|
+
return quoteQualifiedIdentifier(trimmed);
|
|
10710
|
+
}
|
|
10711
|
+
const responseAlias = RESPONSE_ALIAS_PATTERN2.exec(trimmed);
|
|
10712
|
+
if (responseAlias) {
|
|
10713
|
+
const [, aliasIdentifier, baseIdentifier] = responseAlias;
|
|
10714
|
+
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteQualifiedIdentifier(aliasIdentifier)}`;
|
|
10715
|
+
}
|
|
10716
|
+
const sqlAlias = SQL_ALIAS_PATTERN2.exec(trimmed);
|
|
10717
|
+
if (sqlAlias) {
|
|
10718
|
+
const [, baseIdentifier, aliasIdentifier] = sqlAlias;
|
|
10719
|
+
return `${quoteQualifiedIdentifier(baseIdentifier)} AS ${quoteQualifiedIdentifier(aliasIdentifier)}`;
|
|
10720
|
+
}
|
|
10721
|
+
throw new D1SqlCompileError(
|
|
10722
|
+
"unsafe_select",
|
|
10723
|
+
`SELECT/RETURNING expressions are not supported on D1 edge-local; use column names or aliases only: ${token}`
|
|
10724
|
+
);
|
|
10725
|
+
}
|
|
10726
|
+
function selectClause(columns) {
|
|
10727
|
+
if (columns === void 0 || columns === "*" || columns === "") return "*";
|
|
10728
|
+
if (typeof columns === "string") {
|
|
10729
|
+
const trimmed = columns.trim();
|
|
10730
|
+
if (!trimmed || trimmed === "*") return "*";
|
|
10731
|
+
return trimmed.split(",").map((part) => quoteSelectTokenStrict(part)).join(", ");
|
|
10732
|
+
}
|
|
10733
|
+
if (columns.length === 0) return "*";
|
|
10734
|
+
return columns.map((column) => quoteSelectTokenStrict(column)).join(", ");
|
|
10735
|
+
}
|
|
10736
|
+
function wantsReturning(payload) {
|
|
10737
|
+
return Boolean(payload.columns) && payload.head !== true;
|
|
10738
|
+
}
|
|
10739
|
+
function conditionToWhere(condition) {
|
|
10740
|
+
const column = condition.column?.trim() || condition.eq_column?.trim() || "";
|
|
10741
|
+
if (!column) {
|
|
10742
|
+
throw new D1SqlCompileError("invalid_condition", "Condition requires a column");
|
|
10743
|
+
}
|
|
10744
|
+
const col = quoteIdent(column);
|
|
10745
|
+
const operator = (condition.operator || "eq").toLowerCase();
|
|
10746
|
+
const value = condition.value !== void 0 ? condition.value : condition.eq_value;
|
|
10747
|
+
switch (operator) {
|
|
10748
|
+
case "eq": {
|
|
10749
|
+
if (Array.isArray(value)) {
|
|
10750
|
+
if (value.length === 0) {
|
|
10751
|
+
return { sql: "1 = 0", params: [] };
|
|
10752
|
+
}
|
|
10753
|
+
const placeholders = value.map(() => "?").join(", ");
|
|
10754
|
+
return { sql: `${col} IN (${placeholders})`, params: [...value] };
|
|
10755
|
+
}
|
|
10756
|
+
if (value === null) {
|
|
10757
|
+
return { sql: `${col} IS NULL`, params: [] };
|
|
10758
|
+
}
|
|
10759
|
+
return { sql: `${col} = ?`, params: [value ?? null] };
|
|
10760
|
+
}
|
|
10761
|
+
case "neq":
|
|
10762
|
+
if (value === null) {
|
|
10763
|
+
return { sql: `${col} IS NOT NULL`, params: [] };
|
|
10764
|
+
}
|
|
10765
|
+
return { sql: `${col} != ?`, params: [value ?? null] };
|
|
10766
|
+
case "gt":
|
|
10767
|
+
return { sql: `${col} > ?`, params: [value ?? null] };
|
|
10768
|
+
case "gte":
|
|
10769
|
+
return { sql: `${col} >= ?`, params: [value ?? null] };
|
|
10770
|
+
case "lt":
|
|
10771
|
+
return { sql: `${col} < ?`, params: [value ?? null] };
|
|
10772
|
+
case "lte":
|
|
10773
|
+
return { sql: `${col} <= ?`, params: [value ?? null] };
|
|
10774
|
+
case "like":
|
|
10775
|
+
return { sql: `${col} LIKE ?`, params: [value ?? null] };
|
|
10776
|
+
case "ilike":
|
|
10777
|
+
return { sql: `${col} LIKE ? COLLATE NOCASE`, params: [value ?? null] };
|
|
10778
|
+
case "in": {
|
|
10779
|
+
const items = Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
10780
|
+
if (items.length === 0) {
|
|
10781
|
+
return { sql: "1 = 0", params: [] };
|
|
10782
|
+
}
|
|
10783
|
+
const placeholders = items.map(() => "?").join(", ");
|
|
10784
|
+
return { sql: `${col} IN (${placeholders})`, params: [...items] };
|
|
10785
|
+
}
|
|
10786
|
+
case "is": {
|
|
10787
|
+
if (value === null || value === "null") {
|
|
10788
|
+
return { sql: `${col} IS NULL`, params: [] };
|
|
10789
|
+
}
|
|
10790
|
+
if (value === true || value === "true") {
|
|
10791
|
+
return { sql: `${col} IS TRUE`, params: [] };
|
|
10792
|
+
}
|
|
10793
|
+
if (value === false || value === "false") {
|
|
10794
|
+
return { sql: `${col} IS FALSE`, params: [] };
|
|
10795
|
+
}
|
|
10796
|
+
return { sql: `${col} IS ?`, params: [value] };
|
|
10797
|
+
}
|
|
10798
|
+
case "not":
|
|
10799
|
+
case "or":
|
|
10800
|
+
case "contains":
|
|
10801
|
+
case "containedby":
|
|
10802
|
+
throw new D1SqlCompileError(
|
|
10803
|
+
"unsupported_operator",
|
|
10804
|
+
`Condition operator "${operator}" is not supported on D1 edge-local L1`
|
|
10805
|
+
);
|
|
10806
|
+
default:
|
|
10807
|
+
throw new D1SqlCompileError(
|
|
10808
|
+
"unsupported_operator",
|
|
10809
|
+
`Unknown condition operator "${operator}"`
|
|
10810
|
+
);
|
|
10811
|
+
}
|
|
10812
|
+
}
|
|
10813
|
+
function buildWhere(conditions) {
|
|
10814
|
+
if (!conditions?.length) {
|
|
10815
|
+
return { sql: "", params: [] };
|
|
10816
|
+
}
|
|
10817
|
+
const parts = [];
|
|
10818
|
+
const params = [];
|
|
10819
|
+
for (const condition of conditions) {
|
|
10820
|
+
if (!condition.operator && condition.eq_column) {
|
|
10821
|
+
const clause2 = conditionToWhere({
|
|
10822
|
+
...condition,
|
|
10823
|
+
operator: "eq",
|
|
10824
|
+
column: condition.eq_column,
|
|
10825
|
+
value: condition.eq_value
|
|
10826
|
+
});
|
|
10827
|
+
parts.push(clause2.sql);
|
|
10828
|
+
params.push(...clause2.params);
|
|
10829
|
+
continue;
|
|
10830
|
+
}
|
|
10831
|
+
const clause = conditionToWhere(condition);
|
|
10832
|
+
parts.push(clause.sql);
|
|
10833
|
+
params.push(...clause.params);
|
|
10834
|
+
}
|
|
10835
|
+
return {
|
|
10836
|
+
sql: parts.length ? `WHERE ${parts.join(" AND ")}` : "",
|
|
10837
|
+
params
|
|
10838
|
+
};
|
|
10839
|
+
}
|
|
10840
|
+
function orderClause(order) {
|
|
10841
|
+
if (!order?.field?.trim()) return "";
|
|
10842
|
+
const direction = order.direction === "descending" ? "DESC" : "ASC";
|
|
10843
|
+
return `ORDER BY ${quoteIdent(order.field)} ${direction}`;
|
|
10844
|
+
}
|
|
10845
|
+
function limitOffsetClause(payload) {
|
|
10846
|
+
let limit = payload.limit;
|
|
10847
|
+
let offset = payload.offset;
|
|
10848
|
+
if (limit === void 0 && payload.page_size !== void 0) {
|
|
10849
|
+
limit = payload.page_size;
|
|
10850
|
+
}
|
|
10851
|
+
if (payload.current_page !== void 0 && offset === void 0) {
|
|
10852
|
+
const pageSize = payload.page_size ?? payload.limit;
|
|
10853
|
+
if (pageSize !== void 0) {
|
|
10854
|
+
offset = Math.max(0, (payload.current_page - 1) * pageSize);
|
|
10855
|
+
}
|
|
10856
|
+
}
|
|
10857
|
+
const parts = [];
|
|
10858
|
+
if (offset !== void 0 && limit === void 0) {
|
|
10859
|
+
parts.push("LIMIT -1");
|
|
10860
|
+
parts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
10861
|
+
} else {
|
|
10862
|
+
if (limit !== void 0) {
|
|
10863
|
+
parts.push(`LIMIT ${Math.max(0, Math.trunc(limit))}`);
|
|
10864
|
+
}
|
|
10865
|
+
if (offset !== void 0) {
|
|
10866
|
+
parts.push(`OFFSET ${Math.max(0, Math.trunc(offset))}`);
|
|
10867
|
+
}
|
|
10868
|
+
}
|
|
10869
|
+
return parts.join(" ");
|
|
10870
|
+
}
|
|
10871
|
+
function rejectStructuredRelations(payload) {
|
|
10872
|
+
const select = payload.select;
|
|
10873
|
+
if (select && typeof select === "object" && !Array.isArray(select)) {
|
|
10874
|
+
for (const value of Object.values(select)) {
|
|
10875
|
+
if (value && typeof value === "object") {
|
|
10876
|
+
throw new D1SqlCompileError(
|
|
10877
|
+
"relations_unsupported",
|
|
10878
|
+
"Nested relation selects are unsupported on D1 edge-local"
|
|
10879
|
+
);
|
|
10880
|
+
}
|
|
10881
|
+
}
|
|
10882
|
+
}
|
|
10883
|
+
if (payload.view_name) {
|
|
10884
|
+
throw new D1SqlCompileError(
|
|
10885
|
+
"view_unsupported",
|
|
10886
|
+
"view_name is unsupported on D1 edge-local L1"
|
|
10887
|
+
);
|
|
10888
|
+
}
|
|
10889
|
+
}
|
|
10890
|
+
function jsonValue(value) {
|
|
10891
|
+
if (value === void 0) return null;
|
|
10892
|
+
if (value !== null && typeof value === "object") {
|
|
10893
|
+
return JSON.stringify(value);
|
|
10894
|
+
}
|
|
10895
|
+
return value;
|
|
10896
|
+
}
|
|
10897
|
+
function compileD1Fetch(payload) {
|
|
10898
|
+
rejectStructuredRelations(payload);
|
|
10899
|
+
const table2 = payload.table_name?.trim();
|
|
10900
|
+
if (!table2) {
|
|
10901
|
+
throw new D1SqlCompileError("missing_table", "table_name is required for fetch");
|
|
10902
|
+
}
|
|
10903
|
+
let columns = payload.columns;
|
|
10904
|
+
if (payload.select && typeof payload.select === "object" && !Array.isArray(payload.select)) {
|
|
10905
|
+
const keys = Object.entries(payload.select).filter(([, enabled]) => enabled === true || enabled === 1).map(([key]) => key);
|
|
10906
|
+
if (keys.length > 0) {
|
|
10907
|
+
columns = keys;
|
|
10908
|
+
}
|
|
10909
|
+
} else if (typeof payload.select === "string" && payload.select.trim()) {
|
|
10910
|
+
columns = payload.select;
|
|
10911
|
+
}
|
|
10912
|
+
let where = buildWhere(payload.conditions);
|
|
10913
|
+
if (!where.sql && payload.where && typeof payload.where === "object") {
|
|
10914
|
+
const eqConditions = Object.entries(
|
|
10915
|
+
payload.where
|
|
10916
|
+
).map(([column, value]) => ({
|
|
10917
|
+
column,
|
|
10918
|
+
operator: "eq",
|
|
10919
|
+
value
|
|
10920
|
+
}));
|
|
10921
|
+
where = buildWhere(eqConditions);
|
|
10922
|
+
}
|
|
10923
|
+
if (payload.head === true) {
|
|
10924
|
+
return compileD1CountFromWhere(table2, where);
|
|
10925
|
+
}
|
|
10926
|
+
const parts = [
|
|
10927
|
+
`SELECT ${selectClause(columns)} FROM ${quoteIdent(table2)}`,
|
|
10928
|
+
where.sql,
|
|
10929
|
+
orderClause(payload.sort_by),
|
|
10930
|
+
limitOffsetClause(payload)
|
|
10931
|
+
].filter(Boolean);
|
|
10932
|
+
return asSingle(parts.join(" "), where.params);
|
|
10933
|
+
}
|
|
10934
|
+
function compileD1Count(payload) {
|
|
10935
|
+
rejectStructuredRelations(payload);
|
|
10936
|
+
const table2 = payload.table_name?.trim();
|
|
10937
|
+
if (!table2) {
|
|
10938
|
+
throw new D1SqlCompileError("missing_table", "table_name is required for count");
|
|
10939
|
+
}
|
|
10940
|
+
let where = buildWhere(payload.conditions);
|
|
10941
|
+
if (!where.sql && payload.where && typeof payload.where === "object") {
|
|
10942
|
+
const eqConditions = Object.entries(
|
|
10943
|
+
payload.where
|
|
10944
|
+
).map(([column, value]) => ({
|
|
10945
|
+
column,
|
|
10946
|
+
operator: "eq",
|
|
10947
|
+
value
|
|
10948
|
+
}));
|
|
10949
|
+
where = buildWhere(eqConditions);
|
|
10950
|
+
}
|
|
10951
|
+
return compileD1CountFromWhere(table2, where);
|
|
10952
|
+
}
|
|
10953
|
+
function compileD1CountFromWhere(table2, where) {
|
|
10954
|
+
const parts = [
|
|
10955
|
+
`SELECT COUNT(*) AS __athena_count FROM ${quoteIdent(table2)}`,
|
|
10956
|
+
where.sql
|
|
10957
|
+
].filter(Boolean);
|
|
10958
|
+
return asSingle(parts.join(" "), where.params);
|
|
10959
|
+
}
|
|
10960
|
+
function extractAthenaCount(rows) {
|
|
10961
|
+
const first = rows[0];
|
|
10962
|
+
const rawCount = first && typeof first === "object" && !Array.isArray(first) ? first.__athena_count : void 0;
|
|
10963
|
+
const count = typeof rawCount === "number" ? rawCount : typeof rawCount === "bigint" ? Number(rawCount) : Number(rawCount ?? 0);
|
|
10964
|
+
return Number.isFinite(count) ? count : 0;
|
|
10965
|
+
}
|
|
10966
|
+
function compileSingleRowInsert(table2, row, payload) {
|
|
10967
|
+
const columns = Object.keys(row);
|
|
10968
|
+
if (columns.length === 0) {
|
|
10969
|
+
if (payload.on_conflict) {
|
|
10970
|
+
throw new D1SqlCompileError(
|
|
10971
|
+
"default_values_upsert_unsupported",
|
|
10972
|
+
"DEFAULT VALUES upsert is unsupported on D1 edge-local; provide insert columns or omit onConflict"
|
|
10973
|
+
);
|
|
10974
|
+
}
|
|
10975
|
+
const parts2 = [`INSERT INTO ${quoteIdent(table2)} DEFAULT VALUES`];
|
|
10976
|
+
if (wantsReturning(payload)) {
|
|
10977
|
+
parts2.push(`RETURNING ${selectClause(payload.columns)}`);
|
|
10978
|
+
}
|
|
10979
|
+
return { sql: parts2.join(" "), params: [] };
|
|
10980
|
+
}
|
|
10981
|
+
const params = columns.map((column) => jsonValue(row[column]));
|
|
10982
|
+
const parts = [
|
|
10983
|
+
`INSERT INTO ${quoteIdent(table2)} (${columns.map(quoteIdent).join(", ")})`,
|
|
10984
|
+
`VALUES (${columns.map(() => "?").join(", ")})`
|
|
10985
|
+
];
|
|
10986
|
+
appendOnConflict(parts, params, payload, columns);
|
|
10987
|
+
if (wantsReturning(payload)) {
|
|
10988
|
+
parts.push(`RETURNING ${selectClause(payload.columns)}`);
|
|
10989
|
+
}
|
|
10990
|
+
return { sql: parts.join(" "), params };
|
|
10991
|
+
}
|
|
10992
|
+
function parseOnConflictColumns(onConflict) {
|
|
10993
|
+
const raw = Array.isArray(onConflict) ? onConflict : [onConflict];
|
|
10994
|
+
const columns = [];
|
|
10995
|
+
for (const item of raw) {
|
|
10996
|
+
for (const part of String(item).split(",")) {
|
|
10997
|
+
const trimmed = part.trim();
|
|
10998
|
+
if (trimmed) columns.push(trimmed);
|
|
10999
|
+
}
|
|
11000
|
+
}
|
|
11001
|
+
if (columns.length === 0) {
|
|
11002
|
+
throw new D1SqlCompileError(
|
|
11003
|
+
"invalid_on_conflict",
|
|
11004
|
+
"on_conflict requires at least one column"
|
|
11005
|
+
);
|
|
11006
|
+
}
|
|
11007
|
+
return columns;
|
|
11008
|
+
}
|
|
11009
|
+
function appendOnConflict(parts, params, payload, insertColumns) {
|
|
11010
|
+
if (!payload.on_conflict) return;
|
|
11011
|
+
const conflictCols = parseOnConflictColumns(payload.on_conflict);
|
|
11012
|
+
const conflictSql = conflictCols.map(quoteIdent).join(", ");
|
|
11013
|
+
if (payload.update_body !== void 0 && payload.update_body !== null) {
|
|
11014
|
+
const entries = Object.entries(payload.update_body);
|
|
11015
|
+
if (entries.length === 0) {
|
|
11016
|
+
parts.push(`ON CONFLICT (${conflictSql}) DO NOTHING`);
|
|
11017
|
+
return;
|
|
11018
|
+
}
|
|
11019
|
+
const assignments2 = entries.map(([column, value]) => {
|
|
11020
|
+
params.push(jsonValue(value));
|
|
11021
|
+
return `${quoteIdent(column)} = ?`;
|
|
11022
|
+
});
|
|
11023
|
+
parts.push(`ON CONFLICT (${conflictSql}) DO UPDATE SET ${assignments2.join(", ")}`);
|
|
11024
|
+
return;
|
|
11025
|
+
}
|
|
11026
|
+
const conflictSet = new Set(conflictCols);
|
|
11027
|
+
const assignments = insertColumns.filter((column) => !conflictSet.has(column)).map((column) => {
|
|
11028
|
+
const quoted = quoteIdent(column);
|
|
11029
|
+
return `${quoted} = excluded.${quoted}`;
|
|
11030
|
+
});
|
|
11031
|
+
if (assignments.length === 0) {
|
|
11032
|
+
parts.push(`ON CONFLICT (${conflictSql}) DO NOTHING`);
|
|
11033
|
+
} else {
|
|
11034
|
+
parts.push(`ON CONFLICT (${conflictSql}) DO UPDATE SET ${assignments.join(", ")}`);
|
|
11035
|
+
}
|
|
11036
|
+
}
|
|
11037
|
+
function compileD1Insert(payload) {
|
|
11038
|
+
const table2 = payload.table_name?.trim();
|
|
11039
|
+
if (!table2) {
|
|
11040
|
+
throw new D1SqlCompileError("missing_table", "table_name is required for insert");
|
|
11041
|
+
}
|
|
11042
|
+
const rows = Array.isArray(payload.insert_body) ? payload.insert_body : [payload.insert_body];
|
|
11043
|
+
if (rows.length === 0) {
|
|
11044
|
+
throw new D1SqlCompileError("empty_insert", "insert_body must not be empty");
|
|
11045
|
+
}
|
|
11046
|
+
const columns = [];
|
|
11047
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11048
|
+
for (const row of rows) {
|
|
11049
|
+
for (const key of Object.keys(row ?? {})) {
|
|
11050
|
+
if (seen.has(key)) continue;
|
|
11051
|
+
seen.add(key);
|
|
11052
|
+
columns.push(key);
|
|
11053
|
+
}
|
|
11054
|
+
}
|
|
11055
|
+
if (columns.length === 0) {
|
|
11056
|
+
if (rows.length === 1) {
|
|
11057
|
+
const compiled = compileSingleRowInsert(table2, {}, payload);
|
|
11058
|
+
return asSingle(compiled.sql, compiled.params);
|
|
11059
|
+
}
|
|
11060
|
+
throw new D1SqlCompileError(
|
|
11061
|
+
"empty_insert",
|
|
11062
|
+
"Multi-row insert_body cannot be empty objects; use a single {} for DEFAULT VALUES"
|
|
11063
|
+
);
|
|
11064
|
+
}
|
|
11065
|
+
const forceNullForMissing = payload.default_to_null === true;
|
|
11066
|
+
const isSparse = rows.some(
|
|
11067
|
+
(row) => columns.some((column) => !Object.prototype.hasOwnProperty.call(row, column))
|
|
11068
|
+
);
|
|
11069
|
+
if (isSparse && !forceNullForMissing && rows.length > 1) {
|
|
11070
|
+
return asBatch(
|
|
11071
|
+
rows.map((row) => compileSingleRowInsert(table2, row, payload))
|
|
11072
|
+
);
|
|
11073
|
+
}
|
|
11074
|
+
if (isSparse && !forceNullForMissing && rows.length === 1) {
|
|
11075
|
+
const compiled = compileSingleRowInsert(table2, rows[0], payload);
|
|
11076
|
+
return asSingle(compiled.sql, compiled.params);
|
|
11077
|
+
}
|
|
11078
|
+
const params = [];
|
|
11079
|
+
const valueGroups = rows.map((row) => {
|
|
11080
|
+
const placeholders = columns.map((column) => {
|
|
11081
|
+
const has = Object.prototype.hasOwnProperty.call(row, column);
|
|
11082
|
+
if (!has) {
|
|
11083
|
+
params.push(null);
|
|
11084
|
+
return "?";
|
|
11085
|
+
}
|
|
11086
|
+
params.push(jsonValue(row[column]));
|
|
11087
|
+
return "?";
|
|
11088
|
+
});
|
|
11089
|
+
return `(${placeholders.join(", ")})`;
|
|
11090
|
+
});
|
|
11091
|
+
const parts = [
|
|
11092
|
+
`INSERT INTO ${quoteIdent(table2)} (${columns.map(quoteIdent).join(", ")})`,
|
|
11093
|
+
`VALUES ${valueGroups.join(", ")}`
|
|
11094
|
+
];
|
|
11095
|
+
appendOnConflict(parts, params, payload, columns);
|
|
11096
|
+
if (wantsReturning(payload)) {
|
|
11097
|
+
parts.push(`RETURNING ${selectClause(payload.columns)}`);
|
|
11098
|
+
}
|
|
11099
|
+
return asSingle(parts.join(" "), params);
|
|
11100
|
+
}
|
|
11101
|
+
function compileD1Update(payload, options) {
|
|
11102
|
+
const table2 = payload.table_name?.trim();
|
|
11103
|
+
if (!table2) {
|
|
11104
|
+
throw new D1SqlCompileError("missing_table", "table_name is required for update");
|
|
11105
|
+
}
|
|
11106
|
+
const entries = Object.entries(payload.update_body ?? {});
|
|
11107
|
+
if (entries.length === 0) {
|
|
11108
|
+
throw new D1SqlCompileError("empty_update", "update_body must not be empty");
|
|
11109
|
+
}
|
|
11110
|
+
const params = [];
|
|
11111
|
+
const assignments = entries.map(([column, value]) => {
|
|
11112
|
+
params.push(jsonValue(value));
|
|
11113
|
+
return `${quoteIdent(column)} = ?`;
|
|
11114
|
+
});
|
|
11115
|
+
const where = buildWhere(payload.conditions);
|
|
11116
|
+
if (!where.sql) {
|
|
11117
|
+
throw new D1SqlCompileError(
|
|
11118
|
+
"unfiltered_update",
|
|
11119
|
+
"UPDATE requires at least one condition on D1 edge-local"
|
|
11120
|
+
);
|
|
11121
|
+
}
|
|
11122
|
+
if (hasPaginationBounds(payload) || payload.sort_by) {
|
|
11123
|
+
if (!hasPaginationBounds(payload)) {
|
|
11124
|
+
throw new D1SqlCompileError(
|
|
11125
|
+
"order_without_bounds",
|
|
11126
|
+
"UPDATE with sort_by requires limit/offset or page_size/current_page on D1 edge-local"
|
|
11127
|
+
);
|
|
11128
|
+
}
|
|
11129
|
+
const bounded = boundedRowidInClause(
|
|
11130
|
+
table2,
|
|
11131
|
+
where.sql,
|
|
11132
|
+
where.params,
|
|
11133
|
+
{
|
|
11134
|
+
...payload,
|
|
11135
|
+
conditions: payload.conditions
|
|
11136
|
+
},
|
|
11137
|
+
options
|
|
11138
|
+
);
|
|
11139
|
+
params.push(...bounded.params);
|
|
11140
|
+
const parts2 = [
|
|
11141
|
+
`UPDATE ${quoteIdent(table2)} SET ${assignments.join(", ")}`,
|
|
11142
|
+
`WHERE ${bounded.sql}`
|
|
11143
|
+
];
|
|
11144
|
+
if (wantsReturning(payload)) {
|
|
11145
|
+
parts2.push(`RETURNING ${selectClause(payload.columns)}`);
|
|
11146
|
+
}
|
|
11147
|
+
return asSingle(parts2.join(" "), params);
|
|
11148
|
+
}
|
|
11149
|
+
params.push(...where.params);
|
|
11150
|
+
const parts = [
|
|
11151
|
+
`UPDATE ${quoteIdent(table2)} SET ${assignments.join(", ")}`,
|
|
11152
|
+
where.sql
|
|
11153
|
+
];
|
|
11154
|
+
if (wantsReturning(payload)) {
|
|
11155
|
+
parts.push(`RETURNING ${selectClause(payload.columns)}`);
|
|
11156
|
+
}
|
|
11157
|
+
return asSingle(parts.join(" "), params);
|
|
11158
|
+
}
|
|
11159
|
+
function compileD1Delete(payload, options) {
|
|
11160
|
+
const table2 = payload.table_name?.trim();
|
|
11161
|
+
if (!table2) {
|
|
11162
|
+
throw new D1SqlCompileError("missing_table", "table_name is required for delete");
|
|
11163
|
+
}
|
|
11164
|
+
const conditions = [...payload.conditions ?? []];
|
|
11165
|
+
if (payload.resource_id !== void 0 && payload.resource_id !== null) {
|
|
11166
|
+
const hasResourceIdFilter = conditions.some((condition) => {
|
|
11167
|
+
const column = (condition.column ?? condition.eq_column ?? "").trim();
|
|
11168
|
+
return column === "resource_id";
|
|
11169
|
+
});
|
|
11170
|
+
const hasIdFilter = conditions.some((condition) => {
|
|
11171
|
+
const column = (condition.column ?? condition.eq_column ?? "").trim();
|
|
11172
|
+
return column === "id";
|
|
11173
|
+
});
|
|
11174
|
+
if (!hasResourceIdFilter && !hasIdFilter) {
|
|
11175
|
+
conditions.unshift({
|
|
11176
|
+
column: "id",
|
|
11177
|
+
operator: "eq",
|
|
11178
|
+
value: payload.resource_id
|
|
11179
|
+
});
|
|
11180
|
+
}
|
|
11181
|
+
}
|
|
11182
|
+
const where = buildWhere(conditions);
|
|
11183
|
+
if (!where.sql) {
|
|
11184
|
+
throw new D1SqlCompileError(
|
|
11185
|
+
"unfiltered_delete",
|
|
11186
|
+
"DELETE requires at least one condition or resource_id on D1 edge-local"
|
|
11187
|
+
);
|
|
11188
|
+
}
|
|
11189
|
+
if (hasPaginationBounds(payload) || payload.sort_by) {
|
|
11190
|
+
if (!hasPaginationBounds(payload)) {
|
|
11191
|
+
throw new D1SqlCompileError(
|
|
11192
|
+
"order_without_bounds",
|
|
11193
|
+
"DELETE with sort_by requires limit/offset or page_size/current_page on D1 edge-local"
|
|
11194
|
+
);
|
|
11195
|
+
}
|
|
11196
|
+
const bounded = boundedRowidInClause(
|
|
11197
|
+
table2,
|
|
11198
|
+
where.sql,
|
|
11199
|
+
where.params,
|
|
11200
|
+
{
|
|
11201
|
+
...payload,
|
|
11202
|
+
conditions
|
|
11203
|
+
},
|
|
11204
|
+
options
|
|
11205
|
+
);
|
|
11206
|
+
const parts2 = [`DELETE FROM ${quoteIdent(table2)}`, `WHERE ${bounded.sql}`];
|
|
11207
|
+
if (wantsReturning(payload)) {
|
|
11208
|
+
parts2.push(`RETURNING ${selectClause(payload.columns)}`);
|
|
11209
|
+
}
|
|
11210
|
+
return asSingle(parts2.join(" "), bounded.params);
|
|
11211
|
+
}
|
|
11212
|
+
const parts = [`DELETE FROM ${quoteIdent(table2)}`, where.sql];
|
|
11213
|
+
if (wantsReturning(payload)) {
|
|
11214
|
+
parts.push(`RETURNING ${selectClause(payload.columns)}`);
|
|
11215
|
+
}
|
|
11216
|
+
return asSingle(parts.join(" "), where.params);
|
|
11217
|
+
}
|
|
11218
|
+
|
|
11219
|
+
// src/cloudflare/d1/sql-rewrite.ts
|
|
11220
|
+
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";
|
|
11221
|
+
function mapSqlOutsideLiterals(sql, transform) {
|
|
11222
|
+
let out = "";
|
|
11223
|
+
let buffer = "";
|
|
11224
|
+
let inSingle = false;
|
|
11225
|
+
let inDouble = false;
|
|
11226
|
+
let inBacktick = false;
|
|
11227
|
+
let inBracket = false;
|
|
11228
|
+
let inLineComment = false;
|
|
11229
|
+
let inBlockComment = false;
|
|
11230
|
+
const flushCode = () => {
|
|
11231
|
+
if (buffer) {
|
|
11232
|
+
out += transform(buffer);
|
|
11233
|
+
buffer = "";
|
|
11234
|
+
}
|
|
11235
|
+
};
|
|
11236
|
+
for (let i = 0; i < sql.length; i += 1) {
|
|
11237
|
+
const ch = sql[i];
|
|
11238
|
+
const next = sql[i + 1];
|
|
11239
|
+
if (inLineComment) {
|
|
11240
|
+
out += ch;
|
|
11241
|
+
if (ch === "\n" || ch === "\r") inLineComment = false;
|
|
11242
|
+
continue;
|
|
11243
|
+
}
|
|
11244
|
+
if (inBlockComment) {
|
|
11245
|
+
out += ch;
|
|
11246
|
+
if (ch === "*" && next === "/") {
|
|
11247
|
+
out += next;
|
|
11248
|
+
i += 1;
|
|
11249
|
+
inBlockComment = false;
|
|
11250
|
+
}
|
|
11251
|
+
continue;
|
|
11252
|
+
}
|
|
11253
|
+
if (inSingle) {
|
|
11254
|
+
out += ch;
|
|
11255
|
+
if (ch === "'" && next === "'") {
|
|
11256
|
+
out += next;
|
|
11257
|
+
i += 1;
|
|
11258
|
+
continue;
|
|
11259
|
+
}
|
|
11260
|
+
if (ch === "'") inSingle = false;
|
|
11261
|
+
continue;
|
|
11262
|
+
}
|
|
11263
|
+
if (inDouble) {
|
|
11264
|
+
out += ch;
|
|
11265
|
+
if (ch === '"' && next === '"') {
|
|
11266
|
+
out += next;
|
|
11267
|
+
i += 1;
|
|
11268
|
+
continue;
|
|
11269
|
+
}
|
|
11270
|
+
if (ch === '"') inDouble = false;
|
|
11271
|
+
continue;
|
|
11272
|
+
}
|
|
11273
|
+
if (inBacktick) {
|
|
11274
|
+
out += ch;
|
|
11275
|
+
if (ch === "`" && next === "`") {
|
|
11276
|
+
out += next;
|
|
11277
|
+
i += 1;
|
|
11278
|
+
continue;
|
|
11279
|
+
}
|
|
11280
|
+
if (ch === "`") inBacktick = false;
|
|
11281
|
+
continue;
|
|
11282
|
+
}
|
|
11283
|
+
if (inBracket) {
|
|
11284
|
+
out += ch;
|
|
11285
|
+
if (ch === "]") inBracket = false;
|
|
11286
|
+
continue;
|
|
11287
|
+
}
|
|
11288
|
+
if (ch === "-" && next === "-") {
|
|
11289
|
+
flushCode();
|
|
11290
|
+
out += ch;
|
|
11291
|
+
out += next;
|
|
11292
|
+
i += 1;
|
|
11293
|
+
inLineComment = true;
|
|
11294
|
+
continue;
|
|
11295
|
+
}
|
|
11296
|
+
if (ch === "/" && next === "*") {
|
|
11297
|
+
flushCode();
|
|
11298
|
+
out += ch;
|
|
11299
|
+
out += next;
|
|
11300
|
+
i += 1;
|
|
11301
|
+
inBlockComment = true;
|
|
11302
|
+
continue;
|
|
11303
|
+
}
|
|
11304
|
+
if (ch === "'") {
|
|
11305
|
+
flushCode();
|
|
11306
|
+
out += ch;
|
|
11307
|
+
inSingle = true;
|
|
11308
|
+
continue;
|
|
11309
|
+
}
|
|
11310
|
+
if (ch === '"') {
|
|
11311
|
+
flushCode();
|
|
11312
|
+
out += ch;
|
|
11313
|
+
inDouble = true;
|
|
11314
|
+
continue;
|
|
11315
|
+
}
|
|
11316
|
+
if (ch === "`") {
|
|
11317
|
+
flushCode();
|
|
11318
|
+
out += ch;
|
|
11319
|
+
inBacktick = true;
|
|
11320
|
+
continue;
|
|
11321
|
+
}
|
|
11322
|
+
if (ch === "[") {
|
|
11323
|
+
flushCode();
|
|
11324
|
+
out += ch;
|
|
11325
|
+
inBracket = true;
|
|
11326
|
+
continue;
|
|
11327
|
+
}
|
|
11328
|
+
buffer += ch;
|
|
11329
|
+
}
|
|
11330
|
+
flushCode();
|
|
11331
|
+
return out;
|
|
11332
|
+
}
|
|
11333
|
+
function isIdentChar2(ch) {
|
|
11334
|
+
if (!ch) return false;
|
|
11335
|
+
return /[A-Za-z0-9_]/.test(ch);
|
|
11336
|
+
}
|
|
11337
|
+
function collectLimitOffsetKeywords(sql) {
|
|
11338
|
+
const hits = [];
|
|
11339
|
+
let depth = 0;
|
|
11340
|
+
let statement = 0;
|
|
11341
|
+
let inSingle = false;
|
|
11342
|
+
let inDouble = false;
|
|
11343
|
+
let inBacktick = false;
|
|
11344
|
+
let inBracket = false;
|
|
11345
|
+
let inLineComment = false;
|
|
11346
|
+
let inBlockComment = false;
|
|
11347
|
+
for (let i = 0; i < sql.length; i += 1) {
|
|
11348
|
+
const ch = sql[i];
|
|
11349
|
+
const next = sql[i + 1];
|
|
11350
|
+
if (inLineComment) {
|
|
11351
|
+
if (ch === "\n" || ch === "\r") inLineComment = false;
|
|
11352
|
+
continue;
|
|
11353
|
+
}
|
|
11354
|
+
if (inBlockComment) {
|
|
11355
|
+
if (ch === "*" && next === "/") {
|
|
11356
|
+
i += 1;
|
|
11357
|
+
inBlockComment = false;
|
|
11358
|
+
}
|
|
11359
|
+
continue;
|
|
11360
|
+
}
|
|
11361
|
+
if (inSingle) {
|
|
11362
|
+
if (ch === "'" && next === "'") {
|
|
11363
|
+
i += 1;
|
|
11364
|
+
continue;
|
|
11365
|
+
}
|
|
11366
|
+
if (ch === "'") inSingle = false;
|
|
11367
|
+
continue;
|
|
11368
|
+
}
|
|
11369
|
+
if (inDouble) {
|
|
11370
|
+
if (ch === '"' && next === '"') {
|
|
11371
|
+
i += 1;
|
|
11372
|
+
continue;
|
|
11373
|
+
}
|
|
11374
|
+
if (ch === '"') inDouble = false;
|
|
11375
|
+
continue;
|
|
11376
|
+
}
|
|
11377
|
+
if (inBacktick) {
|
|
11378
|
+
if (ch === "`" && next === "`") {
|
|
11379
|
+
i += 1;
|
|
11380
|
+
continue;
|
|
11381
|
+
}
|
|
11382
|
+
if (ch === "`") inBacktick = false;
|
|
11383
|
+
continue;
|
|
11384
|
+
}
|
|
11385
|
+
if (inBracket) {
|
|
11386
|
+
if (ch === "]") inBracket = false;
|
|
11387
|
+
continue;
|
|
11388
|
+
}
|
|
11389
|
+
if (ch === "-" && next === "-") {
|
|
11390
|
+
inLineComment = true;
|
|
11391
|
+
i += 1;
|
|
11392
|
+
continue;
|
|
11393
|
+
}
|
|
11394
|
+
if (ch === "/" && next === "*") {
|
|
11395
|
+
inBlockComment = true;
|
|
11396
|
+
i += 1;
|
|
11397
|
+
continue;
|
|
11398
|
+
}
|
|
11399
|
+
if (ch === "'") {
|
|
11400
|
+
inSingle = true;
|
|
11401
|
+
continue;
|
|
11402
|
+
}
|
|
11403
|
+
if (ch === '"') {
|
|
11404
|
+
inDouble = true;
|
|
11405
|
+
continue;
|
|
11406
|
+
}
|
|
11407
|
+
if (ch === "`") {
|
|
11408
|
+
inBacktick = true;
|
|
11409
|
+
continue;
|
|
11410
|
+
}
|
|
11411
|
+
if (ch === "[") {
|
|
11412
|
+
inBracket = true;
|
|
11413
|
+
continue;
|
|
11414
|
+
}
|
|
11415
|
+
if (ch === "(") {
|
|
11416
|
+
depth += 1;
|
|
11417
|
+
continue;
|
|
11418
|
+
}
|
|
11419
|
+
if (ch === ")") {
|
|
11420
|
+
depth = Math.max(0, depth - 1);
|
|
11421
|
+
continue;
|
|
11422
|
+
}
|
|
11423
|
+
if (ch === ";" && depth === 0) {
|
|
11424
|
+
statement += 1;
|
|
11425
|
+
continue;
|
|
11426
|
+
}
|
|
11427
|
+
if (!isIdentChar2(ch) || isIdentChar2(sql[i - 1])) {
|
|
11428
|
+
continue;
|
|
11429
|
+
}
|
|
11430
|
+
const rest = sql.slice(i);
|
|
11431
|
+
if (/^LIMIT\b/i.test(rest)) {
|
|
11432
|
+
hits.push({ kind: "limit", start: i, depth, statement });
|
|
11433
|
+
i += 4;
|
|
11434
|
+
continue;
|
|
11435
|
+
}
|
|
11436
|
+
if (/^OFFSET\b/i.test(rest)) {
|
|
11437
|
+
hits.push({ kind: "offset", start: i, depth, statement });
|
|
11438
|
+
i += 5;
|
|
11439
|
+
}
|
|
11440
|
+
}
|
|
11441
|
+
return hits;
|
|
11442
|
+
}
|
|
11443
|
+
function injectLimitBeforeBareOffsets(sql) {
|
|
11444
|
+
const hits = collectLimitOffsetKeywords(sql);
|
|
11445
|
+
if (hits.length === 0) return sql;
|
|
11446
|
+
const injectAt = [];
|
|
11447
|
+
for (const hit of hits) {
|
|
11448
|
+
if (hit.kind !== "offset") continue;
|
|
11449
|
+
let hasLimit = false;
|
|
11450
|
+
for (let i = hits.length - 1; i >= 0; i -= 1) {
|
|
11451
|
+
const prev = hits[i];
|
|
11452
|
+
if (prev.start >= hit.start) continue;
|
|
11453
|
+
if (prev.statement !== hit.statement) continue;
|
|
11454
|
+
if (prev.depth !== hit.depth) continue;
|
|
11455
|
+
if (prev.kind === "limit") {
|
|
11456
|
+
hasLimit = true;
|
|
11457
|
+
break;
|
|
11458
|
+
}
|
|
11459
|
+
if (prev.kind === "offset") {
|
|
11460
|
+
break;
|
|
11461
|
+
}
|
|
11462
|
+
}
|
|
11463
|
+
if (!hasLimit) {
|
|
11464
|
+
injectAt.push(hit.start);
|
|
11465
|
+
}
|
|
11466
|
+
}
|
|
11467
|
+
if (injectAt.length === 0) return sql;
|
|
11468
|
+
let out = sql;
|
|
11469
|
+
for (let i = injectAt.length - 1; i >= 0; i -= 1) {
|
|
11470
|
+
const at = injectAt[i];
|
|
11471
|
+
out = `${out.slice(0, at)}LIMIT -1 ${out.slice(at)}`;
|
|
11472
|
+
}
|
|
11473
|
+
return out;
|
|
11474
|
+
}
|
|
11475
|
+
function rewritePostgresSqlForSqlite(sql) {
|
|
11476
|
+
const castPattern = new RegExp(`::(?:${PG_CAST_TYPES})\\b`, "gi");
|
|
11477
|
+
const withoutCastsAndIlike = mapSqlOutsideLiterals(sql, (chunk) => {
|
|
11478
|
+
let rewritten = chunk.replace(castPattern, "");
|
|
11479
|
+
rewritten = rewritten.replace(/\bILIKE\b/gi, "LIKE");
|
|
11480
|
+
return rewritten;
|
|
11481
|
+
});
|
|
11482
|
+
return injectLimitBeforeBareOffsets(withoutCastsAndIlike);
|
|
11483
|
+
}
|
|
11484
|
+
|
|
11485
|
+
// src/cloudflare/d1/transport.ts
|
|
11486
|
+
function hasPaginationBounds2(payload) {
|
|
11487
|
+
return payload.limit !== void 0 || payload.offset !== void 0 || payload.page_size !== void 0 || payload.current_page !== void 0;
|
|
11488
|
+
}
|
|
11489
|
+
function normalizeSqliteCollation(name) {
|
|
11490
|
+
const raw = String(name ?? "").trim().replace(/^["'`[]|["'`\]]$/g, "");
|
|
11491
|
+
if (!raw) return "BINARY";
|
|
11492
|
+
return raw.toUpperCase();
|
|
11493
|
+
}
|
|
11494
|
+
function findCreateTableColumnListOpen(createSql) {
|
|
11495
|
+
const m = /\bCREATE\s+(?:(?:TEMP|TEMPORARY|VIRTUAL)\s+)?TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?/i.exec(
|
|
11496
|
+
createSql
|
|
11497
|
+
);
|
|
11498
|
+
if (!m) return -1;
|
|
11499
|
+
let i = m.index + m[0].length;
|
|
11500
|
+
let inSingle = false;
|
|
11501
|
+
let inDouble = false;
|
|
11502
|
+
let inBacktick = false;
|
|
11503
|
+
let inBracket = false;
|
|
11504
|
+
while (i < createSql.length) {
|
|
11505
|
+
const ch = createSql[i];
|
|
11506
|
+
if (inSingle) {
|
|
11507
|
+
if (ch === "'" && createSql[i + 1] === "'") {
|
|
11508
|
+
i += 2;
|
|
11509
|
+
continue;
|
|
11510
|
+
}
|
|
11511
|
+
if (ch === "'") inSingle = false;
|
|
11512
|
+
i++;
|
|
11513
|
+
continue;
|
|
11514
|
+
}
|
|
11515
|
+
if (inDouble) {
|
|
11516
|
+
if (ch === '"') inDouble = false;
|
|
11517
|
+
i++;
|
|
11518
|
+
continue;
|
|
11519
|
+
}
|
|
11520
|
+
if (inBacktick) {
|
|
11521
|
+
if (ch === "`") inBacktick = false;
|
|
11522
|
+
i++;
|
|
11523
|
+
continue;
|
|
11524
|
+
}
|
|
11525
|
+
if (inBracket) {
|
|
11526
|
+
if (ch === "]") inBracket = false;
|
|
11527
|
+
i++;
|
|
11528
|
+
continue;
|
|
11529
|
+
}
|
|
11530
|
+
if (ch === "'") {
|
|
11531
|
+
inSingle = true;
|
|
11532
|
+
i++;
|
|
11533
|
+
continue;
|
|
11534
|
+
}
|
|
11535
|
+
if (ch === '"') {
|
|
11536
|
+
inDouble = true;
|
|
11537
|
+
i++;
|
|
11538
|
+
continue;
|
|
11539
|
+
}
|
|
11540
|
+
if (ch === "`") {
|
|
11541
|
+
inBacktick = true;
|
|
11542
|
+
i++;
|
|
11543
|
+
continue;
|
|
11544
|
+
}
|
|
11545
|
+
if (ch === "[") {
|
|
11546
|
+
inBracket = true;
|
|
11547
|
+
i++;
|
|
11548
|
+
continue;
|
|
11549
|
+
}
|
|
11550
|
+
if (ch === "(") return i;
|
|
11551
|
+
i++;
|
|
11552
|
+
}
|
|
11553
|
+
return -1;
|
|
11554
|
+
}
|
|
11555
|
+
function parseColumnCollationFromCreateSql(createSql, columnName) {
|
|
11556
|
+
if (!createSql || !columnName) return null;
|
|
11557
|
+
const listOpen = findCreateTableColumnListOpen(createSql);
|
|
11558
|
+
if (listOpen < 0) return null;
|
|
11559
|
+
const listStart = listOpen + 1;
|
|
11560
|
+
const escaped = columnName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11561
|
+
const nameRe = new RegExp(
|
|
11562
|
+
`(?:^|[^\\w])(?:"${escaped}"|\`${escaped}\`|\\[${escaped}\\]|${escaped})\\s+`,
|
|
11563
|
+
"i"
|
|
11564
|
+
);
|
|
11565
|
+
const listSlice = createSql.slice(listStart);
|
|
11566
|
+
let nameMatchAbs = -1;
|
|
11567
|
+
let nameMatchLen = 0;
|
|
11568
|
+
{
|
|
11569
|
+
let i2 = 0;
|
|
11570
|
+
let depth2 = 1;
|
|
11571
|
+
let inSingle2 = false;
|
|
11572
|
+
let inDouble2 = false;
|
|
11573
|
+
let inBacktick2 = false;
|
|
11574
|
+
let inBracket2 = false;
|
|
11575
|
+
let segmentStart = 0;
|
|
11576
|
+
const trySegment = (from, to) => {
|
|
11577
|
+
if (nameMatchAbs >= 0) return;
|
|
11578
|
+
const segment = listSlice.slice(from, to);
|
|
11579
|
+
const m = nameRe.exec(segment);
|
|
11580
|
+
if (!m) return;
|
|
11581
|
+
const leading = segment.slice(0, m.index).trim();
|
|
11582
|
+
if (leading.length > 0) return;
|
|
11583
|
+
nameMatchAbs = listStart + from + m.index;
|
|
11584
|
+
nameMatchLen = m[0].length;
|
|
11585
|
+
};
|
|
11586
|
+
while (i2 < listSlice.length && depth2 > 0) {
|
|
11587
|
+
const ch = listSlice[i2];
|
|
11588
|
+
if (inSingle2) {
|
|
11589
|
+
if (ch === "'" && listSlice[i2 + 1] === "'") {
|
|
11590
|
+
i2 += 2;
|
|
11591
|
+
continue;
|
|
11592
|
+
}
|
|
11593
|
+
if (ch === "'") inSingle2 = false;
|
|
11594
|
+
i2++;
|
|
11595
|
+
continue;
|
|
11596
|
+
}
|
|
11597
|
+
if (inDouble2) {
|
|
11598
|
+
if (ch === '"') inDouble2 = false;
|
|
11599
|
+
i2++;
|
|
11600
|
+
continue;
|
|
11601
|
+
}
|
|
11602
|
+
if (inBacktick2) {
|
|
11603
|
+
if (ch === "`") inBacktick2 = false;
|
|
11604
|
+
i2++;
|
|
11605
|
+
continue;
|
|
11606
|
+
}
|
|
11607
|
+
if (inBracket2) {
|
|
11608
|
+
if (ch === "]") inBracket2 = false;
|
|
11609
|
+
i2++;
|
|
11610
|
+
continue;
|
|
11611
|
+
}
|
|
11612
|
+
if (ch === "'") {
|
|
11613
|
+
inSingle2 = true;
|
|
11614
|
+
i2++;
|
|
11615
|
+
continue;
|
|
11616
|
+
}
|
|
11617
|
+
if (ch === '"') {
|
|
11618
|
+
inDouble2 = true;
|
|
11619
|
+
i2++;
|
|
11620
|
+
continue;
|
|
11621
|
+
}
|
|
11622
|
+
if (ch === "`") {
|
|
11623
|
+
inBacktick2 = true;
|
|
11624
|
+
i2++;
|
|
11625
|
+
continue;
|
|
11626
|
+
}
|
|
11627
|
+
if (ch === "[") {
|
|
11628
|
+
inBracket2 = true;
|
|
11629
|
+
i2++;
|
|
11630
|
+
continue;
|
|
11631
|
+
}
|
|
11632
|
+
if (ch === "(") {
|
|
11633
|
+
depth2++;
|
|
11634
|
+
i2++;
|
|
11635
|
+
continue;
|
|
11636
|
+
}
|
|
11637
|
+
if (ch === ")") {
|
|
11638
|
+
depth2--;
|
|
11639
|
+
if (depth2 === 0) {
|
|
11640
|
+
trySegment(segmentStart, i2);
|
|
11641
|
+
break;
|
|
11642
|
+
}
|
|
11643
|
+
i2++;
|
|
11644
|
+
continue;
|
|
11645
|
+
}
|
|
11646
|
+
if (ch === "," && depth2 === 1) {
|
|
11647
|
+
trySegment(segmentStart, i2);
|
|
11648
|
+
segmentStart = i2 + 1;
|
|
11649
|
+
i2++;
|
|
11650
|
+
continue;
|
|
11651
|
+
}
|
|
11652
|
+
i2++;
|
|
11653
|
+
}
|
|
11654
|
+
}
|
|
11655
|
+
if (nameMatchAbs < 0 || nameMatchLen <= 0) return null;
|
|
11656
|
+
const start = nameMatchAbs + nameMatchLen;
|
|
11657
|
+
let i = start;
|
|
11658
|
+
let depth = 0;
|
|
11659
|
+
let inSingle = false;
|
|
11660
|
+
let inDouble = false;
|
|
11661
|
+
let inBacktick = false;
|
|
11662
|
+
let inBracket = false;
|
|
11663
|
+
while (i < createSql.length) {
|
|
11664
|
+
const ch = createSql[i];
|
|
11665
|
+
if (inSingle) {
|
|
11666
|
+
if (ch === "'" && createSql[i + 1] === "'") {
|
|
11667
|
+
i += 2;
|
|
11668
|
+
continue;
|
|
11669
|
+
}
|
|
11670
|
+
if (ch === "'") inSingle = false;
|
|
11671
|
+
i++;
|
|
11672
|
+
continue;
|
|
11673
|
+
}
|
|
11674
|
+
if (inDouble) {
|
|
11675
|
+
if (ch === '"') inDouble = false;
|
|
11676
|
+
i++;
|
|
11677
|
+
continue;
|
|
11678
|
+
}
|
|
11679
|
+
if (inBacktick) {
|
|
11680
|
+
if (ch === "`") inBacktick = false;
|
|
11681
|
+
i++;
|
|
11682
|
+
continue;
|
|
11683
|
+
}
|
|
11684
|
+
if (inBracket) {
|
|
11685
|
+
if (ch === "]") inBracket = false;
|
|
11686
|
+
i++;
|
|
11687
|
+
continue;
|
|
11688
|
+
}
|
|
11689
|
+
if (ch === "'") {
|
|
11690
|
+
inSingle = true;
|
|
11691
|
+
i++;
|
|
11692
|
+
continue;
|
|
11693
|
+
}
|
|
11694
|
+
if (ch === '"') {
|
|
11695
|
+
inDouble = true;
|
|
11696
|
+
i++;
|
|
11697
|
+
continue;
|
|
11698
|
+
}
|
|
11699
|
+
if (ch === "`") {
|
|
11700
|
+
inBacktick = true;
|
|
11701
|
+
i++;
|
|
11702
|
+
continue;
|
|
11703
|
+
}
|
|
11704
|
+
if (ch === "[") {
|
|
11705
|
+
inBracket = true;
|
|
11706
|
+
i++;
|
|
11707
|
+
continue;
|
|
11708
|
+
}
|
|
11709
|
+
if (ch === "(") {
|
|
11710
|
+
depth++;
|
|
11711
|
+
i++;
|
|
11712
|
+
continue;
|
|
11713
|
+
}
|
|
11714
|
+
if (ch === ")") {
|
|
11715
|
+
if (depth === 0) {
|
|
11716
|
+
break;
|
|
11717
|
+
}
|
|
11718
|
+
depth--;
|
|
11719
|
+
i++;
|
|
11720
|
+
continue;
|
|
11721
|
+
}
|
|
11722
|
+
if (ch === "," && depth === 0) {
|
|
11723
|
+
break;
|
|
11724
|
+
}
|
|
11725
|
+
i++;
|
|
11726
|
+
}
|
|
11727
|
+
const colDef = createSql.slice(start, i);
|
|
11728
|
+
const collRe = /\bCOLLATE\s+("([^"]+)"|'([^']+)'|`([^`]+)`|\[([^\]]+)\]|([A-Za-z_][\w$]*))/i;
|
|
11729
|
+
const match = collRe.exec(colDef);
|
|
11730
|
+
if (!match) return null;
|
|
11731
|
+
return match[2] ?? match[3] ?? match[4] ?? match[5] ?? match[6] ?? match[1] ?? null;
|
|
11732
|
+
}
|
|
11733
|
+
async function indexCollationMatchesColumn(d1, table2, tableSafe, indexSafe, columnName, session) {
|
|
11734
|
+
const xinfo = await executeD1Query(d1, {
|
|
11735
|
+
query: `PRAGMA index_xinfo("${indexSafe}")`,
|
|
11736
|
+
params: [],
|
|
11737
|
+
...session
|
|
11738
|
+
});
|
|
11739
|
+
if (!xinfo.ok) {
|
|
11740
|
+
return false;
|
|
11741
|
+
}
|
|
11742
|
+
const xRows = xinfo.rows ?? [];
|
|
11743
|
+
const keyRows = xRows.filter((row) => {
|
|
11744
|
+
const isKey = row.key === 1 || row.key === true || Number(row.key) === 1;
|
|
11745
|
+
if (!isKey) return false;
|
|
11746
|
+
return typeof row.name === "string" && row.name === columnName;
|
|
11747
|
+
});
|
|
11748
|
+
if (keyRows.length === 0) {
|
|
11749
|
+
const byName = xRows.find(
|
|
11750
|
+
(row) => typeof row.name === "string" && row.name === columnName
|
|
11751
|
+
);
|
|
11752
|
+
if (!byName) return false;
|
|
11753
|
+
keyRows.push(byName);
|
|
11754
|
+
}
|
|
11755
|
+
const indexColl = normalizeSqliteCollation(keyRows[0]?.coll);
|
|
11756
|
+
const master = await executeD1Query(d1, {
|
|
11757
|
+
query: `SELECT sql AS create_sql FROM sqlite_master WHERE type = 'table' AND name = ?`,
|
|
11758
|
+
params: [table2],
|
|
11759
|
+
...session
|
|
11760
|
+
});
|
|
11761
|
+
let createSql = "";
|
|
11762
|
+
if (master.ok && Array.isArray(master.rows) && master.rows.length > 0) {
|
|
11763
|
+
createSql = String(
|
|
11764
|
+
master.rows[0]?.create_sql ?? ""
|
|
11765
|
+
);
|
|
11766
|
+
}
|
|
11767
|
+
const columnCollRaw = parseColumnCollationFromCreateSql(createSql, columnName);
|
|
11768
|
+
const columnColl = normalizeSqliteCollation(columnCollRaw);
|
|
11769
|
+
return indexColl === columnColl;
|
|
11770
|
+
}
|
|
11771
|
+
async function resolveD1BoundedIdentityColumn(d1, tableName, session) {
|
|
11772
|
+
const table2 = tableName.trim();
|
|
11773
|
+
if (!table2) {
|
|
11774
|
+
throw new D1SqlCompileError("missing_table", "table_name is required for bounded mutation");
|
|
11775
|
+
}
|
|
11776
|
+
const safe = table2.replace(/"/g, '""');
|
|
11777
|
+
const info = await executeD1Query(d1, {
|
|
11778
|
+
query: `PRAGMA table_info("${safe}")`,
|
|
11779
|
+
params: [],
|
|
11780
|
+
...session
|
|
11781
|
+
});
|
|
11782
|
+
if (!info.ok) {
|
|
11783
|
+
throw new D1SqlCompileError(
|
|
11784
|
+
"bounded_mutation_no_unique_identity",
|
|
11785
|
+
`Unable to introspect table "${table2}" for bounded mutation identity: ${info.message}`
|
|
11786
|
+
);
|
|
11787
|
+
}
|
|
11788
|
+
const cols = info.rows.filter(
|
|
11789
|
+
(row) => typeof row?.name === "string" && row.name.length > 0
|
|
11790
|
+
);
|
|
11791
|
+
const colByName = new Map(cols.map((col) => [col.name, col]));
|
|
11792
|
+
const isNotNullColumn = (name) => {
|
|
11793
|
+
const col = colByName.get(name);
|
|
11794
|
+
if (!col) return false;
|
|
11795
|
+
return col.notnull === 1 || col.notnull === true || Number(col.notnull) === 1;
|
|
11796
|
+
};
|
|
11797
|
+
const isIntegerPrimaryKeyType = (col) => {
|
|
11798
|
+
if (typeof col.pk !== "number" || col.pk <= 0) return false;
|
|
11799
|
+
const declared = String(col.type ?? "").trim().toUpperCase();
|
|
11800
|
+
return declared === "INTEGER";
|
|
11801
|
+
};
|
|
11802
|
+
const loadIndexList = async () => {
|
|
11803
|
+
const indexList = await executeD1Query(d1, {
|
|
11804
|
+
query: `PRAGMA index_list("${safe}")`,
|
|
11805
|
+
params: [],
|
|
11806
|
+
...session
|
|
11807
|
+
});
|
|
11808
|
+
if (!indexList.ok) return null;
|
|
11809
|
+
return indexList.rows;
|
|
11810
|
+
};
|
|
11811
|
+
const isDescendingIntegerPrimaryKeyException = async (colName, indexes) => {
|
|
11812
|
+
if (indexes) {
|
|
11813
|
+
const hasPkOrigin = indexes.some(
|
|
11814
|
+
(index) => String(index.origin ?? "").toLowerCase() === "pk"
|
|
11815
|
+
);
|
|
11816
|
+
if (hasPkOrigin) return true;
|
|
11817
|
+
const originReported = indexes.some(
|
|
11818
|
+
(index) => index.origin !== void 0 && index.origin !== null && String(index.origin).length > 0
|
|
11819
|
+
);
|
|
11820
|
+
if (indexes.length === 0 || originReported) {
|
|
11821
|
+
return false;
|
|
11822
|
+
}
|
|
11823
|
+
}
|
|
11824
|
+
const master = await executeD1Query(d1, {
|
|
11825
|
+
query: `SELECT sql AS create_sql FROM sqlite_master WHERE type = 'table' AND name = ?`,
|
|
11826
|
+
params: [table2],
|
|
11827
|
+
...session
|
|
11828
|
+
});
|
|
11829
|
+
if (!master.ok || !Array.isArray(master.rows) || master.rows.length === 0) {
|
|
11830
|
+
return false;
|
|
11831
|
+
}
|
|
11832
|
+
const createSql = String(
|
|
11833
|
+
master.rows[0]?.create_sql ?? ""
|
|
11834
|
+
);
|
|
11835
|
+
if (!createSql) return false;
|
|
11836
|
+
const escaped = colName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11837
|
+
const inlineDesc = new RegExp(
|
|
11838
|
+
`(?:^|[^\\w])(?:"${escaped}"|${escaped})\\s+INTEGER\\s+PRIMARY\\s+KEY\\s+DESC\\b`,
|
|
11839
|
+
"i"
|
|
11840
|
+
);
|
|
11841
|
+
const tableDesc = new RegExp(
|
|
11842
|
+
`PRIMARY\\s+KEY\\s*\\(\\s*(?:"${escaped}"|${escaped})\\s+DESC\\b`,
|
|
11843
|
+
"i"
|
|
11844
|
+
);
|
|
11845
|
+
return inlineDesc.test(createSql) || tableDesc.test(createSql);
|
|
11846
|
+
};
|
|
11847
|
+
const pkCols = cols.filter((row) => typeof row.pk === "number" && row.pk > 0).sort((a, b) => (a.pk ?? 0) - (b.pk ?? 0));
|
|
11848
|
+
let indexRows;
|
|
11849
|
+
if (pkCols.length === 1 && pkCols[0]?.name) {
|
|
11850
|
+
if (isIntegerPrimaryKeyType(pkCols[0])) {
|
|
11851
|
+
indexRows = await loadIndexList();
|
|
11852
|
+
const isDescException = await isDescendingIntegerPrimaryKeyException(
|
|
11853
|
+
pkCols[0].name,
|
|
11854
|
+
indexRows
|
|
11855
|
+
);
|
|
11856
|
+
if (!isDescException) {
|
|
11857
|
+
return pkCols[0].name;
|
|
11858
|
+
}
|
|
11859
|
+
} else if (isNotNullColumn(pkCols[0].name)) {
|
|
11860
|
+
indexRows = await loadIndexList();
|
|
11861
|
+
const pkIndex = (indexRows ?? []).find(
|
|
11862
|
+
(index) => String(index.origin ?? "").toLowerCase() === "pk"
|
|
11863
|
+
);
|
|
11864
|
+
if (pkIndex && typeof pkIndex.name === "string" && pkIndex.name) {
|
|
11865
|
+
const indexSafe = pkIndex.name.replace(/"/g, '""');
|
|
11866
|
+
const collMatch = await indexCollationMatchesColumn(
|
|
11867
|
+
d1,
|
|
11868
|
+
table2,
|
|
11869
|
+
safe,
|
|
11870
|
+
indexSafe,
|
|
11871
|
+
pkCols[0].name,
|
|
11872
|
+
session
|
|
11873
|
+
);
|
|
11874
|
+
if (collMatch) {
|
|
11875
|
+
return pkCols[0].name;
|
|
11876
|
+
}
|
|
11877
|
+
}
|
|
11878
|
+
}
|
|
11879
|
+
}
|
|
11880
|
+
if (indexRows === void 0) {
|
|
11881
|
+
indexRows = await loadIndexList();
|
|
11882
|
+
}
|
|
11883
|
+
if (indexRows) {
|
|
11884
|
+
for (const index of indexRows) {
|
|
11885
|
+
const unique = index.unique === 1 || index.unique === true || Number(index.unique) === 1;
|
|
11886
|
+
if (!unique || typeof index.name !== "string" || !index.name) continue;
|
|
11887
|
+
const isPartial = index.partial === 1 || index.partial === true || Number(index.partial) === 1;
|
|
11888
|
+
if (isPartial) {
|
|
11889
|
+
continue;
|
|
11890
|
+
}
|
|
11891
|
+
const indexSafe = index.name.replace(/"/g, '""');
|
|
11892
|
+
const indexInfo = await executeD1Query(d1, {
|
|
11893
|
+
query: `PRAGMA index_info("${indexSafe}")`,
|
|
11894
|
+
params: [],
|
|
11895
|
+
...session
|
|
11896
|
+
});
|
|
11897
|
+
if (!indexInfo.ok) continue;
|
|
11898
|
+
const rawIndexCols = indexInfo.rows ?? [];
|
|
11899
|
+
const hasExpressionTerm = rawIndexCols.some((row) => {
|
|
11900
|
+
const nameOk = typeof row?.name === "string" && row.name.length > 0;
|
|
11901
|
+
if (!nameOk) return true;
|
|
11902
|
+
if (typeof row.cid === "number" && row.cid < 0) return true;
|
|
11903
|
+
return false;
|
|
11904
|
+
});
|
|
11905
|
+
if (hasExpressionTerm || rawIndexCols.length === 0) {
|
|
11906
|
+
continue;
|
|
11907
|
+
}
|
|
11908
|
+
const indexCols = rawIndexCols.filter(
|
|
11909
|
+
(row) => typeof row?.name === "string" && row.name.length > 0
|
|
11910
|
+
);
|
|
11911
|
+
if (indexCols.length === 1 && indexCols[0]?.name) {
|
|
11912
|
+
const identity = indexCols[0].name;
|
|
11913
|
+
if (!isNotNullColumn(identity)) {
|
|
11914
|
+
continue;
|
|
11915
|
+
}
|
|
11916
|
+
const collMatch = await indexCollationMatchesColumn(
|
|
11917
|
+
d1,
|
|
11918
|
+
table2,
|
|
11919
|
+
safe,
|
|
11920
|
+
indexSafe,
|
|
11921
|
+
identity,
|
|
11922
|
+
session
|
|
11923
|
+
);
|
|
11924
|
+
if (!collMatch) {
|
|
11925
|
+
continue;
|
|
11926
|
+
}
|
|
11927
|
+
return identity;
|
|
11928
|
+
}
|
|
11929
|
+
}
|
|
11930
|
+
}
|
|
11931
|
+
throw new D1SqlCompileError(
|
|
11932
|
+
"bounded_mutation_no_unique_identity",
|
|
11933
|
+
`Bounded update/delete on "${table2}" requires a proven single-column PRIMARY KEY or UNIQUE index`
|
|
11934
|
+
);
|
|
11935
|
+
}
|
|
11936
|
+
async function compileOptionsForBoundedMutation(d1, payload, session) {
|
|
11937
|
+
if (!hasPaginationBounds2(payload) && !payload.sort_by) {
|
|
11938
|
+
return void 0;
|
|
11939
|
+
}
|
|
11940
|
+
if (!hasPaginationBounds2(payload)) {
|
|
11941
|
+
return void 0;
|
|
11942
|
+
}
|
|
11943
|
+
const identityColumn = await resolveD1BoundedIdentityColumn(
|
|
11944
|
+
d1,
|
|
11945
|
+
payload.table_name ?? "",
|
|
11946
|
+
session
|
|
11947
|
+
);
|
|
11948
|
+
return { identityColumn };
|
|
11949
|
+
}
|
|
11950
|
+
function headerValue2(options, name) {
|
|
11951
|
+
const headers = options?.headers;
|
|
11952
|
+
if (!headers) return void 0;
|
|
11953
|
+
const lower = name.toLowerCase();
|
|
11954
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
11955
|
+
if (key.toLowerCase() === lower && value?.trim()) {
|
|
11956
|
+
return value.trim();
|
|
11957
|
+
}
|
|
11958
|
+
}
|
|
11959
|
+
return void 0;
|
|
11960
|
+
}
|
|
11961
|
+
function sessionFromOptions(options, defaults) {
|
|
11962
|
+
return {
|
|
11963
|
+
bookmark: headerValue2(options, "x-athena-d1-bookmark") ?? null,
|
|
11964
|
+
sessionMode: headerValue2(options, "x-athena-d1-session-mode") ?? defaults.defaultSessionMode ?? null
|
|
11965
|
+
};
|
|
11966
|
+
}
|
|
11967
|
+
function resolveStripNulls(payloadStrip, callOptions, defaultValue = true) {
|
|
11968
|
+
if (typeof payloadStrip === "boolean") return payloadStrip;
|
|
11969
|
+
if (typeof callOptions?.stripNulls === "boolean") return callOptions.stripNulls;
|
|
11970
|
+
return defaultValue;
|
|
11971
|
+
}
|
|
11972
|
+
function stripNullPropertiesFromRows(rows) {
|
|
11973
|
+
return rows.map((row) => {
|
|
11974
|
+
if (row == null || typeof row !== "object" || Array.isArray(row)) {
|
|
11975
|
+
return row;
|
|
11976
|
+
}
|
|
11977
|
+
const out = {};
|
|
11978
|
+
for (const [key, value] of Object.entries(row)) {
|
|
11979
|
+
if (value !== null) {
|
|
11980
|
+
out[key] = value;
|
|
11981
|
+
}
|
|
11982
|
+
}
|
|
11983
|
+
return out;
|
|
11984
|
+
});
|
|
11985
|
+
}
|
|
11986
|
+
function maybeStripNullRows(rows, strip) {
|
|
11987
|
+
return strip ? stripNullPropertiesFromRows(rows) : rows;
|
|
11988
|
+
}
|
|
11989
|
+
function successResponse(data, count, raw, bookmark) {
|
|
11990
|
+
const response = {
|
|
11991
|
+
ok: true,
|
|
11992
|
+
status: 200,
|
|
11993
|
+
statusText: "OK",
|
|
11994
|
+
data,
|
|
11995
|
+
count: count ?? null,
|
|
11996
|
+
error: void 0,
|
|
11997
|
+
errorDetails: null,
|
|
11998
|
+
raw
|
|
11999
|
+
};
|
|
12000
|
+
if (bookmark) {
|
|
12001
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
12002
|
+
const rawRecord = raw;
|
|
12003
|
+
rawRecord.bookmark = bookmark;
|
|
12004
|
+
}
|
|
12005
|
+
}
|
|
12006
|
+
return response;
|
|
12007
|
+
}
|
|
12008
|
+
function errorResponse(status, code, message, endpoint, method, hint) {
|
|
12009
|
+
const error = new AthenaGatewayError({
|
|
12010
|
+
code,
|
|
12011
|
+
message,
|
|
12012
|
+
status,
|
|
12013
|
+
endpoint,
|
|
12014
|
+
method,
|
|
12015
|
+
hint
|
|
12016
|
+
});
|
|
12017
|
+
return {
|
|
12018
|
+
ok: false,
|
|
12019
|
+
status,
|
|
12020
|
+
statusText: null,
|
|
12021
|
+
data: null,
|
|
12022
|
+
error: error.message,
|
|
12023
|
+
errorDetails: error.toDetails(),
|
|
12024
|
+
raw: { error: message, code }
|
|
12025
|
+
};
|
|
12026
|
+
}
|
|
12027
|
+
function compileErrorResponse(error, endpoint, method) {
|
|
12028
|
+
if (error instanceof D1SqlCompileError) {
|
|
12029
|
+
return errorResponse(
|
|
12030
|
+
400,
|
|
12031
|
+
"HTTP_ERROR",
|
|
12032
|
+
error.message,
|
|
12033
|
+
endpoint,
|
|
12034
|
+
method,
|
|
12035
|
+
`D1 SQL compile failed (${error.code})`
|
|
12036
|
+
);
|
|
12037
|
+
}
|
|
12038
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12039
|
+
return errorResponse(500, "UNKNOWN_ERROR", message, endpoint, method);
|
|
12040
|
+
}
|
|
12041
|
+
function createCloudflareD1GatewayTransport(options) {
|
|
12042
|
+
const { d1 } = options;
|
|
12043
|
+
async function runCompiled(compiled, callOptions, endpoint, method, mapResult, stripNulls = true) {
|
|
12044
|
+
try {
|
|
12045
|
+
const session = sessionFromOptions(callOptions, options);
|
|
12046
|
+
if (compiled.statements && compiled.statements.length > 1) {
|
|
12047
|
+
const batch = await executeD1Batch(d1, {
|
|
12048
|
+
statements: compiled.statements.map((statement) => ({
|
|
12049
|
+
query: statement.sql,
|
|
12050
|
+
params: statement.params
|
|
12051
|
+
})),
|
|
12052
|
+
...session
|
|
12053
|
+
});
|
|
12054
|
+
if (!batch.ok) {
|
|
12055
|
+
return errorResponse(400, "HTTP_ERROR", batch.message, endpoint, method);
|
|
12056
|
+
}
|
|
12057
|
+
const rows2 = maybeStripNullRows(
|
|
12058
|
+
batch.results.flatMap(
|
|
12059
|
+
(item) => Array.isArray(item.results) ? item.results : []
|
|
12060
|
+
),
|
|
12061
|
+
stripNulls
|
|
12062
|
+
);
|
|
12063
|
+
const changes = batch.results.reduce((sum2, item) => {
|
|
12064
|
+
const meta = item?.meta;
|
|
12065
|
+
const n = meta && typeof meta === "object" && typeof meta.changes === "number" ? meta.changes : 0;
|
|
12066
|
+
return sum2 + n;
|
|
12067
|
+
}, 0);
|
|
12068
|
+
const count = rows2.length > 0 ? rows2.length : changes;
|
|
12069
|
+
const mapped2 = mapResult?.(rows2, count) ?? {
|
|
12070
|
+
data: rows2,
|
|
12071
|
+
count
|
|
12072
|
+
};
|
|
12073
|
+
return successResponse(mapped2.data, mapped2.count, batch, batch.bookmark);
|
|
12074
|
+
}
|
|
12075
|
+
const result = await executeD1Query(d1, {
|
|
12076
|
+
query: compiled.sql,
|
|
12077
|
+
params: compiled.params,
|
|
12078
|
+
...session
|
|
12079
|
+
});
|
|
12080
|
+
if (!result.ok) {
|
|
12081
|
+
return errorResponse(400, "HTTP_ERROR", result.message, endpoint, method);
|
|
12082
|
+
}
|
|
12083
|
+
const rows = maybeStripNullRows(result.rows, stripNulls);
|
|
12084
|
+
const mapped = mapResult?.(rows, result.count) ?? {
|
|
12085
|
+
data: rows,
|
|
12086
|
+
count: result.count
|
|
12087
|
+
};
|
|
12088
|
+
return successResponse(mapped.data, mapped.count, result, result.bookmark);
|
|
12089
|
+
} catch (error) {
|
|
12090
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12091
|
+
return errorResponse(500, "UNKNOWN_ERROR", message, endpoint, method);
|
|
12092
|
+
}
|
|
12093
|
+
}
|
|
12094
|
+
return {
|
|
12095
|
+
baseUrl: CLOUDFLARE_EDGE_BASE_URL,
|
|
12096
|
+
buildHeaders(callOptions) {
|
|
12097
|
+
return { ...callOptions?.headers ?? {} };
|
|
12098
|
+
},
|
|
12099
|
+
async resolveCallOptions(callOptions) {
|
|
12100
|
+
return callOptions;
|
|
12101
|
+
},
|
|
12102
|
+
async verifyConnection(connectionOptions) {
|
|
12103
|
+
const baseUrl = CLOUDFLARE_EDGE_BASE_URL;
|
|
12104
|
+
try {
|
|
12105
|
+
const result = await executeD1Query(d1, { query: "SELECT 1 AS ok" });
|
|
12106
|
+
if (!result.ok) {
|
|
12107
|
+
return {
|
|
12108
|
+
ok: false,
|
|
12109
|
+
reachable: false,
|
|
12110
|
+
status: 500,
|
|
12111
|
+
statusText: null,
|
|
12112
|
+
baseUrl,
|
|
12113
|
+
url: `${baseUrl}/d1`,
|
|
12114
|
+
error: result.message,
|
|
12115
|
+
errorDetails: null,
|
|
12116
|
+
raw: result
|
|
12117
|
+
};
|
|
12118
|
+
}
|
|
12119
|
+
return {
|
|
12120
|
+
ok: true,
|
|
12121
|
+
reachable: true,
|
|
12122
|
+
status: 200,
|
|
12123
|
+
statusText: "OK",
|
|
12124
|
+
baseUrl,
|
|
12125
|
+
url: `${baseUrl}/d1`,
|
|
12126
|
+
error: void 0,
|
|
12127
|
+
errorDetails: null,
|
|
12128
|
+
raw: result
|
|
12129
|
+
};
|
|
12130
|
+
} catch (error) {
|
|
12131
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12132
|
+
return {
|
|
12133
|
+
ok: false,
|
|
12134
|
+
reachable: false,
|
|
12135
|
+
status: 0,
|
|
12136
|
+
statusText: null,
|
|
12137
|
+
baseUrl,
|
|
12138
|
+
url: `${baseUrl}/d1`,
|
|
12139
|
+
error: message,
|
|
12140
|
+
errorDetails: null,
|
|
12141
|
+
raw: null
|
|
12142
|
+
};
|
|
12143
|
+
}
|
|
12144
|
+
},
|
|
12145
|
+
async fetchGateway(payload, callOptions) {
|
|
12146
|
+
try {
|
|
12147
|
+
if (payload && typeof payload === "object" && "operation" in payload) {
|
|
12148
|
+
return errorResponse(
|
|
12149
|
+
400,
|
|
12150
|
+
"HTTP_ERROR",
|
|
12151
|
+
"Direct AST operation payloads are unsupported on D1 edge-local",
|
|
12152
|
+
"/gateway/fetch",
|
|
12153
|
+
"POST"
|
|
12154
|
+
);
|
|
12155
|
+
}
|
|
12156
|
+
const compiled = compileD1Fetch(payload);
|
|
12157
|
+
const stripNulls = resolveStripNulls(payload.strip_nulls, callOptions, true);
|
|
12158
|
+
if (payload.head === true) {
|
|
12159
|
+
return runCompiled(
|
|
12160
|
+
compiled,
|
|
12161
|
+
callOptions,
|
|
12162
|
+
"/gateway/fetch",
|
|
12163
|
+
"POST",
|
|
12164
|
+
(rows) => ({ data: [], count: extractAthenaCount(rows) }),
|
|
12165
|
+
// COUNT rows are meta, not user-facing object rows
|
|
12166
|
+
false
|
|
12167
|
+
);
|
|
12168
|
+
}
|
|
12169
|
+
const wantsTotalCount = payload.count === "exact" || payload.count === "planned" || payload.count === "estimated";
|
|
12170
|
+
if (wantsTotalCount) {
|
|
12171
|
+
const session = sessionFromOptions(callOptions, options);
|
|
12172
|
+
const countCompiled = compileD1Count(payload);
|
|
12173
|
+
const batch = await executeD1Batch(d1, {
|
|
12174
|
+
statements: [
|
|
12175
|
+
{
|
|
12176
|
+
query: compiled.sql,
|
|
12177
|
+
params: compiled.params
|
|
12178
|
+
},
|
|
12179
|
+
{
|
|
12180
|
+
query: countCompiled.sql,
|
|
12181
|
+
params: countCompiled.params
|
|
12182
|
+
}
|
|
12183
|
+
],
|
|
12184
|
+
...session
|
|
12185
|
+
});
|
|
12186
|
+
if (!batch.ok) {
|
|
12187
|
+
return errorResponse(400, "HTTP_ERROR", batch.message, "/gateway/fetch", "POST");
|
|
12188
|
+
}
|
|
12189
|
+
const dataItem = batch.results[0];
|
|
12190
|
+
const countItem = batch.results[1];
|
|
12191
|
+
if (!dataItem || dataItem.success === false) {
|
|
12192
|
+
const message = dataItem && typeof dataItem.error === "string" && dataItem.error.trim() ? dataItem.error : "D1 page query failed";
|
|
12193
|
+
return errorResponse(400, "HTTP_ERROR", message, "/gateway/fetch", "POST");
|
|
12194
|
+
}
|
|
12195
|
+
if (!countItem || countItem.success === false) {
|
|
12196
|
+
const message = countItem && typeof countItem.error === "string" && countItem.error.trim() ? countItem.error : "D1 count query failed";
|
|
12197
|
+
return errorResponse(400, "HTTP_ERROR", message, "/gateway/fetch", "POST");
|
|
12198
|
+
}
|
|
12199
|
+
const dataRows = Array.isArray(dataItem.results) ? dataItem.results : [];
|
|
12200
|
+
const countRows = Array.isArray(countItem.results) ? countItem.results : [];
|
|
12201
|
+
const total = extractAthenaCount(countRows);
|
|
12202
|
+
const rows = maybeStripNullRows(dataRows, stripNulls);
|
|
12203
|
+
return successResponse(
|
|
12204
|
+
rows,
|
|
12205
|
+
total,
|
|
12206
|
+
{ data: dataItem, count: countItem, batch },
|
|
12207
|
+
batch.bookmark
|
|
12208
|
+
);
|
|
12209
|
+
}
|
|
12210
|
+
return runCompiled(compiled, callOptions, "/gateway/fetch", "POST", void 0, stripNulls);
|
|
12211
|
+
} catch (error) {
|
|
12212
|
+
return compileErrorResponse(error, "/gateway/fetch", "POST");
|
|
12213
|
+
}
|
|
12214
|
+
},
|
|
12215
|
+
async insertGateway(payload, callOptions) {
|
|
12216
|
+
try {
|
|
12217
|
+
const compiled = compileD1Insert(payload);
|
|
12218
|
+
const stripNulls = resolveStripNulls(void 0, callOptions, true);
|
|
12219
|
+
return runCompiled(compiled, callOptions, "/gateway/insert", "PUT", void 0, stripNulls);
|
|
12220
|
+
} catch (error) {
|
|
12221
|
+
return compileErrorResponse(error, "/gateway/insert", "PUT");
|
|
12222
|
+
}
|
|
12223
|
+
},
|
|
12224
|
+
async updateGateway(payload, callOptions) {
|
|
12225
|
+
try {
|
|
12226
|
+
const session = sessionFromOptions(callOptions, options);
|
|
12227
|
+
const compileOptions = await compileOptionsForBoundedMutation(d1, payload, session);
|
|
12228
|
+
const compiled = compileD1Update(payload, compileOptions);
|
|
12229
|
+
const stripNulls = resolveStripNulls(payload.strip_nulls, callOptions, true);
|
|
12230
|
+
return runCompiled(compiled, callOptions, "/gateway/update", "POST", void 0, stripNulls);
|
|
12231
|
+
} catch (error) {
|
|
12232
|
+
return compileErrorResponse(error, "/gateway/update", "POST");
|
|
12233
|
+
}
|
|
12234
|
+
},
|
|
12235
|
+
async deleteGateway(payload, callOptions) {
|
|
12236
|
+
try {
|
|
12237
|
+
const session = sessionFromOptions(callOptions, options);
|
|
12238
|
+
const compileOptions = await compileOptionsForBoundedMutation(d1, payload, session);
|
|
12239
|
+
const compiled = compileD1Delete(payload, compileOptions);
|
|
12240
|
+
const stripNulls = resolveStripNulls(void 0, callOptions, true);
|
|
12241
|
+
return runCompiled(compiled, callOptions, "/gateway/delete", "DELETE", void 0, stripNulls);
|
|
12242
|
+
} catch (error) {
|
|
12243
|
+
return compileErrorResponse(error, "/gateway/delete", "DELETE");
|
|
12244
|
+
}
|
|
12245
|
+
},
|
|
12246
|
+
async rpcGateway(payload, callOptions) {
|
|
12247
|
+
return errorResponse(
|
|
12248
|
+
400,
|
|
12249
|
+
"HTTP_ERROR",
|
|
12250
|
+
"RPC is unsupported on D1 edge-local mode",
|
|
12251
|
+
"/gateway/rpc",
|
|
12252
|
+
"POST",
|
|
12253
|
+
"Use flat CRUD or raw query SQL instead"
|
|
12254
|
+
);
|
|
12255
|
+
},
|
|
12256
|
+
async queryGateway(payload, callOptions) {
|
|
12257
|
+
try {
|
|
12258
|
+
const params = payload.params ?? callOptions?.params;
|
|
12259
|
+
const session = sessionFromOptions(callOptions, options);
|
|
12260
|
+
const query = rewritePostgresSqlForSqlite(payload.query);
|
|
12261
|
+
const result = await executeD1Query(d1, {
|
|
12262
|
+
query,
|
|
12263
|
+
params: Array.isArray(params) ? params : [],
|
|
12264
|
+
...session
|
|
12265
|
+
});
|
|
12266
|
+
if (!result.ok) {
|
|
12267
|
+
return errorResponse(400, "HTTP_ERROR", result.message, "/gateway/query", "POST");
|
|
12268
|
+
}
|
|
12269
|
+
const stripNulls = resolveStripNulls(void 0, callOptions, true);
|
|
12270
|
+
const rows = maybeStripNullRows(result.rows, stripNulls);
|
|
12271
|
+
return successResponse(
|
|
12272
|
+
rows,
|
|
12273
|
+
result.count,
|
|
12274
|
+
{ ...result, query },
|
|
12275
|
+
result.bookmark
|
|
12276
|
+
);
|
|
12277
|
+
} catch (error) {
|
|
12278
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12279
|
+
return errorResponse(500, "UNKNOWN_ERROR", message, "/gateway/query", "POST");
|
|
12280
|
+
}
|
|
12281
|
+
}
|
|
12282
|
+
};
|
|
12283
|
+
}
|
|
12284
|
+
|
|
12285
|
+
// src/config/errors.ts
|
|
12286
|
+
var AthenaConfigurationError = class extends Error {
|
|
12287
|
+
code;
|
|
12288
|
+
service;
|
|
12289
|
+
constructor(code, message, service) {
|
|
12290
|
+
super(message);
|
|
12291
|
+
this.name = "AthenaConfigurationError";
|
|
12292
|
+
this.code = code;
|
|
12293
|
+
this.service = service;
|
|
12294
|
+
}
|
|
12295
|
+
};
|
|
12296
|
+
|
|
12297
|
+
// src/cloudflare/execution-mode.ts
|
|
12298
|
+
var ATHENA_EXECUTION_MODE_ENV_KEY = "ATHENA_EXECUTION_MODE";
|
|
12299
|
+
var ATHENA_EXECUTION_PREFER_ENV_KEY = "ATHENA_EXECUTION_PREFER";
|
|
12300
|
+
var MODE_ALIASES = {
|
|
12301
|
+
gateway: "gateway",
|
|
12302
|
+
server: "gateway",
|
|
12303
|
+
remote: "gateway",
|
|
12304
|
+
http: "gateway",
|
|
12305
|
+
edge: "edge",
|
|
12306
|
+
cloudflare: "edge",
|
|
12307
|
+
"cloudflare-edge": "edge",
|
|
12308
|
+
d1: "edge",
|
|
12309
|
+
local: "edge",
|
|
12310
|
+
auto: "auto"
|
|
12311
|
+
};
|
|
12312
|
+
function normalizeOptional(value) {
|
|
12313
|
+
const trimmed = value?.trim();
|
|
12314
|
+
return trimmed || void 0;
|
|
12315
|
+
}
|
|
12316
|
+
function normalizeModeString(value) {
|
|
12317
|
+
if (value == null) return void 0;
|
|
12318
|
+
const key = value.trim().toLowerCase();
|
|
12319
|
+
if (!key) return void 0;
|
|
12320
|
+
const mapped = MODE_ALIASES[key];
|
|
12321
|
+
if (!mapped) {
|
|
12322
|
+
throw new AthenaConfigurationError(
|
|
12323
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
12324
|
+
`Unknown Athena execution mode "${value}". Use gateway | edge | auto (aliases: server, remote, cloudflare, d1).`,
|
|
12325
|
+
"db"
|
|
12326
|
+
);
|
|
12327
|
+
}
|
|
12328
|
+
return mapped;
|
|
12329
|
+
}
|
|
12330
|
+
function isD1Binding(value) {
|
|
12331
|
+
return Boolean(
|
|
12332
|
+
value && typeof value === "object" && typeof value.prepare === "function"
|
|
12333
|
+
);
|
|
12334
|
+
}
|
|
12335
|
+
var GATEWAY_URL_ENV_KEYS = [
|
|
12336
|
+
"ATHENA_URL",
|
|
12337
|
+
"NEXT_PUBLIC_ATHENA_URL",
|
|
12338
|
+
"ATHENA_DB_URL",
|
|
12339
|
+
"ATHENA_GATEWAY_URL",
|
|
12340
|
+
"NEXT_PUBLIC_ATHENA_DB_API_URL"
|
|
12341
|
+
];
|
|
12342
|
+
function resolveGatewayUrl(url, env) {
|
|
12343
|
+
if (normalizeOptional(url)) {
|
|
12344
|
+
return normalizeOptional(url);
|
|
12345
|
+
}
|
|
12346
|
+
for (const key of GATEWAY_URL_ENV_KEYS) {
|
|
12347
|
+
const value = normalizeOptional(env[key]);
|
|
12348
|
+
if (value) return value;
|
|
12349
|
+
}
|
|
12350
|
+
return void 0;
|
|
12351
|
+
}
|
|
12352
|
+
function resolvePrefer(prefer, env) {
|
|
12353
|
+
const raw = normalizeOptional(typeof prefer === "string" ? prefer : prefer ?? void 0) ?? normalizeOptional(env[ATHENA_EXECUTION_PREFER_ENV_KEY]) ?? "edge";
|
|
12354
|
+
const key = raw.toLowerCase();
|
|
12355
|
+
if (key === "gateway" || key === "server" || key === "remote" || key === "http") {
|
|
12356
|
+
return "gateway";
|
|
12357
|
+
}
|
|
12358
|
+
if (key === "edge" || key === "d1" || key === "cloudflare" || key === "local") {
|
|
12359
|
+
return "edge";
|
|
12360
|
+
}
|
|
12361
|
+
throw new AthenaConfigurationError(
|
|
12362
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
12363
|
+
`Unknown Athena execution prefer "${raw}". Use edge | gateway.`,
|
|
12364
|
+
"db"
|
|
12365
|
+
);
|
|
12366
|
+
}
|
|
12367
|
+
function resolveAthenaExecutionMode(input = {}) {
|
|
12368
|
+
const env = input.env ?? {};
|
|
12369
|
+
const fromEnv = normalizeModeString(env[ATHENA_EXECUTION_MODE_ENV_KEY]);
|
|
12370
|
+
const requested = normalizeModeString(input.mode) ?? fromEnv ?? "auto";
|
|
12371
|
+
const url = resolveGatewayUrl(input.url, env);
|
|
12372
|
+
const hasD1 = isD1Binding(input.d1);
|
|
12373
|
+
const hasGateway = Boolean(url);
|
|
12374
|
+
if (requested === "gateway") {
|
|
12375
|
+
if (!hasGateway) {
|
|
12376
|
+
throw new AthenaConfigurationError(
|
|
12377
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
12378
|
+
'Athena execution mode is "gateway" but no url / ATHENA_URL / ATHENA_DB_URL / ATHENA_GATEWAY_URL was provided.',
|
|
12379
|
+
"db"
|
|
12380
|
+
);
|
|
12381
|
+
}
|
|
12382
|
+
return "gateway";
|
|
12383
|
+
}
|
|
12384
|
+
if (requested === "edge") {
|
|
12385
|
+
if (!hasD1) {
|
|
12386
|
+
throw new AthenaConfigurationError(
|
|
12387
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
12388
|
+
'Athena execution mode is "edge" but no D1 binding was provided (db.d1 / config.d1 / env.DB).',
|
|
12389
|
+
"db"
|
|
12390
|
+
);
|
|
12391
|
+
}
|
|
12392
|
+
return "edge";
|
|
12393
|
+
}
|
|
12394
|
+
if (hasD1 && hasGateway) {
|
|
12395
|
+
return resolvePrefer(input.prefer, env);
|
|
12396
|
+
}
|
|
12397
|
+
if (hasD1) return "edge";
|
|
12398
|
+
if (hasGateway) return "gateway";
|
|
12399
|
+
throw new AthenaConfigurationError(
|
|
12400
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
12401
|
+
'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).',
|
|
12402
|
+
"db"
|
|
12403
|
+
);
|
|
12404
|
+
}
|
|
12405
|
+
|
|
12406
|
+
// src/cloudflare/r2/storage.ts
|
|
12407
|
+
function normalizePrefix(prefix) {
|
|
12408
|
+
if (!prefix?.trim()) return "";
|
|
12409
|
+
const normalized = prefix.replace(/^\/+/, "").replace(/\/?$/, "/");
|
|
12410
|
+
if (normalized.includes("\0")) {
|
|
12411
|
+
throw new Error("storage prefix must not contain null bytes");
|
|
12412
|
+
}
|
|
12413
|
+
if (normalized.split("/").some((segment) => segment === "..")) {
|
|
12414
|
+
throw new Error('storage prefix must not contain ".." path segments');
|
|
12415
|
+
}
|
|
12416
|
+
return normalized;
|
|
12417
|
+
}
|
|
12418
|
+
function assertSafeObjectKey(key) {
|
|
12419
|
+
if (typeof key !== "string" || !key.trim()) {
|
|
12420
|
+
throw new Error("Object key is required");
|
|
12421
|
+
}
|
|
12422
|
+
if (key.includes("\0")) {
|
|
12423
|
+
throw new Error("Object key must not contain null bytes");
|
|
12424
|
+
}
|
|
12425
|
+
const cleaned = key.replace(/^\/+/, "");
|
|
12426
|
+
if (!cleaned) {
|
|
12427
|
+
throw new Error("Object key is required");
|
|
12428
|
+
}
|
|
12429
|
+
const segments = cleaned.split("/");
|
|
12430
|
+
if (segments.some((segment) => segment === "..")) {
|
|
12431
|
+
throw new Error('Object key must not contain ".." path segments');
|
|
12432
|
+
}
|
|
12433
|
+
return cleaned;
|
|
12434
|
+
}
|
|
12435
|
+
function joinKey(prefix, key) {
|
|
12436
|
+
return `${prefix}${assertSafeObjectKey(key)}`;
|
|
12437
|
+
}
|
|
12438
|
+
function toLogicalKey(prefix, physicalKey) {
|
|
12439
|
+
if (!prefix) return physicalKey;
|
|
12440
|
+
if (physicalKey.startsWith(prefix)) {
|
|
12441
|
+
return physicalKey.slice(prefix.length);
|
|
12442
|
+
}
|
|
12443
|
+
return physicalKey;
|
|
12444
|
+
}
|
|
12445
|
+
function toPhysicalKey(prefix, key) {
|
|
12446
|
+
return joinKey(prefix, key);
|
|
12447
|
+
}
|
|
12448
|
+
function unsupported(method) {
|
|
12449
|
+
throw new Error(
|
|
12450
|
+
`storage.${method} is not available in Cloudflare edge-local R2 object mode. Only putObject / getObject / deleteObject / listObjects are supported (L3a).`
|
|
12451
|
+
);
|
|
12452
|
+
}
|
|
12453
|
+
function createCloudflareR2StorageModule(options) {
|
|
12454
|
+
const prefix = normalizePrefix(options.prefix);
|
|
12455
|
+
const { r2 } = options;
|
|
12456
|
+
const putObject = async (input) => {
|
|
12457
|
+
const logical = assertSafeObjectKey(input.key);
|
|
12458
|
+
const physical = toPhysicalKey(prefix, logical);
|
|
12459
|
+
await r2.put(physical, input.body, {
|
|
12460
|
+
httpMetadata: input.contentType ? { contentType: input.contentType } : void 0,
|
|
12461
|
+
customMetadata: input.metadata
|
|
12462
|
+
});
|
|
12463
|
+
return { key: logical };
|
|
12464
|
+
};
|
|
12465
|
+
const getObject = async (input) => {
|
|
12466
|
+
const logical = assertSafeObjectKey(input.key);
|
|
12467
|
+
const physical = toPhysicalKey(prefix, logical);
|
|
12468
|
+
const object = await r2.get(physical);
|
|
12469
|
+
if (!object) return null;
|
|
12470
|
+
return {
|
|
12471
|
+
key: toLogicalKey(prefix, object.key),
|
|
12472
|
+
size: object.size,
|
|
12473
|
+
contentType: object.httpMetadata?.contentType,
|
|
12474
|
+
body: object
|
|
12475
|
+
};
|
|
12476
|
+
};
|
|
12477
|
+
const deleteObject = async (input) => {
|
|
12478
|
+
const logicalKeys = (Array.isArray(input.key) ? input.key : [input.key]).map(
|
|
12479
|
+
(key) => assertSafeObjectKey(key)
|
|
12480
|
+
);
|
|
12481
|
+
const physicalKeys = logicalKeys.map((key) => toPhysicalKey(prefix, key));
|
|
12482
|
+
await r2.delete(physicalKeys.length === 1 ? physicalKeys[0] : physicalKeys);
|
|
12483
|
+
return { deleted: logicalKeys };
|
|
12484
|
+
};
|
|
12485
|
+
const listObjects = async (input) => {
|
|
12486
|
+
const relative = input?.prefix?.trim() ? assertSafeObjectKey(input.prefix) : "";
|
|
12487
|
+
const listPrefix = `${prefix}${relative}`;
|
|
12488
|
+
const listed = await r2.list({
|
|
12489
|
+
prefix: listPrefix || void 0,
|
|
12490
|
+
limit: input?.limit,
|
|
12491
|
+
cursor: input?.cursor
|
|
12492
|
+
});
|
|
12493
|
+
return {
|
|
12494
|
+
objects: listed.objects.map((object) => ({
|
|
12495
|
+
key: toLogicalKey(prefix, object.key),
|
|
12496
|
+
size: object.size,
|
|
12497
|
+
etag: object.etag,
|
|
12498
|
+
uploaded: object.uploaded
|
|
12499
|
+
})),
|
|
12500
|
+
truncated: listed.truncated,
|
|
12501
|
+
cursor: listed.cursor
|
|
12502
|
+
};
|
|
12503
|
+
};
|
|
12504
|
+
const base = {
|
|
12505
|
+
putObject,
|
|
12506
|
+
getObject,
|
|
12507
|
+
deleteObject,
|
|
12508
|
+
listObjects
|
|
12509
|
+
};
|
|
12510
|
+
return new Proxy(base, {
|
|
12511
|
+
get(target, property, receiver) {
|
|
12512
|
+
if (property in target) {
|
|
12513
|
+
return Reflect.get(target, property, receiver);
|
|
12514
|
+
}
|
|
12515
|
+
if (typeof property === "string") {
|
|
12516
|
+
return (...args) => {
|
|
12517
|
+
return unsupported(property);
|
|
12518
|
+
};
|
|
12519
|
+
}
|
|
12520
|
+
return void 0;
|
|
12521
|
+
}
|
|
12522
|
+
});
|
|
12523
|
+
}
|
|
12524
|
+
|
|
12525
|
+
// src/billing/module.ts
|
|
12526
|
+
var SDK_NAME5 = "xylex-group/athena-billing";
|
|
12527
|
+
var SDK_HEADER_VALUE4 = buildSdkHeaderValue(SDK_NAME5);
|
|
12528
|
+
var AthenaBillingError = class extends Error {
|
|
12529
|
+
status;
|
|
12530
|
+
endpoint;
|
|
12531
|
+
method;
|
|
12532
|
+
body;
|
|
12533
|
+
constructor(input) {
|
|
12534
|
+
super(input.message);
|
|
12535
|
+
this.name = "AthenaBillingError";
|
|
12536
|
+
this.status = input.status;
|
|
12537
|
+
this.endpoint = input.endpoint;
|
|
12538
|
+
this.method = input.method;
|
|
12539
|
+
this.body = input.body;
|
|
12540
|
+
}
|
|
12541
|
+
};
|
|
12542
|
+
var billingSdkManifest = {
|
|
12543
|
+
namespace: "billing",
|
|
12544
|
+
envelopeKind: "athena",
|
|
12545
|
+
methods: [
|
|
12546
|
+
{ name: "getCapabilities", method: "GET", path: "/billing/v1/capabilities" },
|
|
12547
|
+
{ name: "createCheckout", method: "POST", path: "/billing/v1/checkouts" },
|
|
12548
|
+
{ name: "listProducts", method: "GET", path: "/billing/v1/products" },
|
|
12549
|
+
{ name: "listPrices", method: "GET", path: "/billing/v1/prices" },
|
|
12550
|
+
{ name: "listCustomers", method: "GET", path: "/billing/v1/customers" },
|
|
12551
|
+
{ name: "createCustomer", method: "POST", path: "/billing/v1/customers" },
|
|
12552
|
+
{ name: "getCustomer", method: "GET", path: "/billing/v1/customers/{id}" },
|
|
12553
|
+
{ name: "updateCustomer", method: "PATCH", path: "/billing/v1/customers/{id}" },
|
|
12554
|
+
{ name: "deleteCustomer", method: "DELETE", path: "/billing/v1/customers/{id}" },
|
|
12555
|
+
{ name: "listPayments", method: "GET", path: "/billing/v1/payments" },
|
|
12556
|
+
{ name: "createPayment", method: "POST", path: "/billing/v1/payments" },
|
|
12557
|
+
{ name: "getPayment", method: "GET", path: "/billing/v1/payments/{id}" },
|
|
12558
|
+
{ name: "cancelPayment", method: "POST", path: "/billing/v1/payments/{id}/cancel" },
|
|
12559
|
+
{ name: "listPaymentLinks", method: "GET", path: "/billing/v1/payment-links" },
|
|
12560
|
+
{ name: "createPaymentLink", method: "POST", path: "/billing/v1/payment-links" },
|
|
12561
|
+
{ name: "getPaymentLink", method: "GET", path: "/billing/v1/payment-links/{id}" },
|
|
12562
|
+
{ name: "updatePaymentLink", method: "PATCH", path: "/billing/v1/payment-links/{id}" },
|
|
12563
|
+
{ name: "deletePaymentLink", method: "DELETE", path: "/billing/v1/payment-links/{id}" },
|
|
12564
|
+
{ name: "listRefunds", method: "GET", path: "/billing/v1/refunds" },
|
|
12565
|
+
{ name: "createRefund", method: "POST", path: "/billing/v1/refunds" },
|
|
12566
|
+
{ name: "getRefund", method: "GET", path: "/billing/v1/refunds/{id}" },
|
|
12567
|
+
{ name: "cancelRefund", method: "POST", path: "/billing/v1/refunds/{id}/cancel" },
|
|
12568
|
+
{ name: "listSubscriptions", method: "GET", path: "/billing/v1/subscriptions" },
|
|
12569
|
+
{ name: "createSubscription", method: "POST", path: "/billing/v1/subscriptions" },
|
|
12570
|
+
{ name: "getSubscription", method: "GET", path: "/billing/v1/subscriptions/{id}" },
|
|
12571
|
+
{ name: "updateSubscription", method: "PATCH", path: "/billing/v1/subscriptions/{id}" },
|
|
12572
|
+
{ name: "cancelSubscription", method: "POST", path: "/billing/v1/subscriptions/{id}/cancel" },
|
|
12573
|
+
{ name: "listInvoices", method: "GET", path: "/billing/v1/invoices" },
|
|
12574
|
+
{ name: "getInvoice", method: "GET", path: "/billing/v1/invoices/{id}" },
|
|
12575
|
+
{ name: "listWebhooks", method: "GET", path: "/billing/v1/webhooks" },
|
|
12576
|
+
{ name: "createWebhook", method: "POST", path: "/billing/v1/webhooks" },
|
|
12577
|
+
{ name: "getWebhook", method: "GET", path: "/billing/v1/webhooks/{id}" },
|
|
12578
|
+
{ name: "updateWebhook", method: "PATCH", path: "/billing/v1/webhooks/{id}" },
|
|
12579
|
+
{ name: "deleteWebhook", method: "DELETE", path: "/billing/v1/webhooks/{id}" },
|
|
12580
|
+
{ name: "testWebhook", method: "POST", path: "/billing/v1/webhooks/{id}/test" },
|
|
12581
|
+
{
|
|
12582
|
+
name: "listConnections",
|
|
12583
|
+
method: "GET",
|
|
12584
|
+
path: "/admin/billing/clients/{client_name}/connections"
|
|
12585
|
+
},
|
|
12586
|
+
{
|
|
12587
|
+
name: "createConnection",
|
|
12588
|
+
method: "POST",
|
|
12589
|
+
path: "/admin/billing/clients/{client_name}/connections"
|
|
12590
|
+
},
|
|
12591
|
+
{
|
|
12592
|
+
name: "getConnection",
|
|
12593
|
+
method: "GET",
|
|
12594
|
+
path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
|
|
12595
|
+
},
|
|
12596
|
+
{
|
|
12597
|
+
name: "updateConnection",
|
|
12598
|
+
method: "PATCH",
|
|
12599
|
+
path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
|
|
12600
|
+
},
|
|
12601
|
+
{
|
|
12602
|
+
name: "deleteConnection",
|
|
12603
|
+
method: "DELETE",
|
|
12604
|
+
path: "/admin/billing/clients/{client_name}/connections/{connection_id}"
|
|
12605
|
+
},
|
|
12606
|
+
{
|
|
12607
|
+
name: "reconcileDocument",
|
|
12608
|
+
method: "POST",
|
|
12609
|
+
path: "/admin/billing/clients/{client_name}/connections/{connection_id}/reconcile"
|
|
12610
|
+
},
|
|
12611
|
+
{
|
|
12612
|
+
name: "listWebhookEvents",
|
|
12613
|
+
method: "GET",
|
|
12614
|
+
path: "/admin/billing/clients/{client_name}/webhook-events"
|
|
12615
|
+
},
|
|
12616
|
+
{
|
|
12617
|
+
name: "provisionWebhookSinks",
|
|
12618
|
+
method: "POST",
|
|
12619
|
+
path: "/admin/billing/clients/{client_name}/webhook-sinks/provision"
|
|
12620
|
+
},
|
|
12621
|
+
{ name: "listGrants", method: "GET", path: "/admin/billing/grants" },
|
|
12622
|
+
{ name: "listProviders", method: "GET", path: "/admin/billing/providers" },
|
|
12623
|
+
{
|
|
12624
|
+
name: "listSinkHelpers",
|
|
12625
|
+
method: "GET",
|
|
12626
|
+
path: "/admin/webhook-sinks/helpers/billing"
|
|
12627
|
+
},
|
|
12628
|
+
{
|
|
12629
|
+
name: "ingestProviderWebhook",
|
|
12630
|
+
method: "POST",
|
|
12631
|
+
path: "/billing/providers/{provider}/clients/{client_name}/connections/{connection_id}/webhook"
|
|
12632
|
+
},
|
|
12633
|
+
{ name: "getDebugBilling", method: "GET", path: "/debug/billing" }
|
|
12634
|
+
]
|
|
12635
|
+
};
|
|
12636
|
+
function withPathParam2(path, name, value) {
|
|
12637
|
+
return path.replace(`{${name}}`, encodeURIComponent(value));
|
|
12638
|
+
}
|
|
12639
|
+
function appendQuery3(path, query) {
|
|
12640
|
+
if (!query) return path;
|
|
12641
|
+
const params = new URLSearchParams();
|
|
12642
|
+
for (const [key, value] of Object.entries(query)) {
|
|
12643
|
+
if (value === void 0 || value === null) continue;
|
|
12644
|
+
params.set(key, String(value));
|
|
12645
|
+
}
|
|
12646
|
+
const serialized = params.toString();
|
|
12647
|
+
return serialized ? `${path}?${serialized}` : path;
|
|
12648
|
+
}
|
|
12649
|
+
function connectionQuery(input) {
|
|
12650
|
+
const query = {
|
|
12651
|
+
connectionId: input.connectionId
|
|
12652
|
+
};
|
|
12653
|
+
if (input.clientName) query.clientName = input.clientName;
|
|
12654
|
+
if ("cursor" in input && input.cursor) query.cursor = input.cursor;
|
|
12655
|
+
if ("source" in input && input.source) query.source = input.source;
|
|
12656
|
+
if ("limit" in input && input.limit !== void 0) query.limit = String(input.limit);
|
|
12657
|
+
if ("offset" in input && input.offset !== void 0) query.offset = String(input.offset);
|
|
12658
|
+
return query;
|
|
12659
|
+
}
|
|
12660
|
+
function parseEnvelopeData(body) {
|
|
12661
|
+
if (body && typeof body === "object" && "data" in body) {
|
|
12662
|
+
return body.data;
|
|
12663
|
+
}
|
|
12664
|
+
return body;
|
|
12665
|
+
}
|
|
12666
|
+
function createBillingModule(config) {
|
|
12667
|
+
const baseUrl = normalizeAthenaGatewayBaseUrl(config.baseUrl, {
|
|
12668
|
+
label: "Athena billing base URL"
|
|
12669
|
+
});
|
|
12670
|
+
const fetchImpl = config.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
12671
|
+
async function call(method, path, body, options, responseType = "json") {
|
|
12672
|
+
const headers = buildAthenaRequestHeaders({
|
|
12673
|
+
profile: "gateway",
|
|
12674
|
+
sdkHeaderValue: SDK_HEADER_VALUE4,
|
|
12675
|
+
apiKey: options?.apiKey ?? config.apiKey,
|
|
12676
|
+
client: config.client,
|
|
12677
|
+
configHeaders: {
|
|
12678
|
+
...config.headers ?? {}
|
|
12679
|
+
},
|
|
12680
|
+
callHeaders: options?.headers,
|
|
12681
|
+
contentType: "application/json"
|
|
12682
|
+
});
|
|
12683
|
+
let requestBody;
|
|
12684
|
+
if (body !== void 0 && body !== null) {
|
|
12685
|
+
if (typeof body === "string" || body instanceof Blob || body instanceof ArrayBuffer || ArrayBuffer.isView(body) || body instanceof FormData || body instanceof URLSearchParams) {
|
|
12686
|
+
requestBody = body;
|
|
12687
|
+
} else {
|
|
12688
|
+
requestBody = JSON.stringify(body);
|
|
12689
|
+
if (!hasHeaderIgnoreCase(headers, "Content-Type")) {
|
|
12690
|
+
headers["Content-Type"] = "application/json";
|
|
12691
|
+
}
|
|
12692
|
+
}
|
|
12693
|
+
}
|
|
12694
|
+
const targetUrl = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
12695
|
+
const response = await fetchImpl(targetUrl, {
|
|
12696
|
+
method,
|
|
12697
|
+
headers,
|
|
12698
|
+
body: requestBody,
|
|
12699
|
+
signal: options?.signal
|
|
12700
|
+
});
|
|
12701
|
+
if (responseType === "text") {
|
|
12702
|
+
const text = await response.text();
|
|
12703
|
+
if (!response.ok) {
|
|
12704
|
+
throw new AthenaBillingError({
|
|
12705
|
+
message: `Billing request failed (${response.status})`,
|
|
12706
|
+
status: response.status,
|
|
12707
|
+
endpoint: path,
|
|
12708
|
+
method,
|
|
12709
|
+
body: text
|
|
12710
|
+
});
|
|
12711
|
+
}
|
|
12712
|
+
return text;
|
|
12713
|
+
}
|
|
12714
|
+
const rawText = await response.text();
|
|
12715
|
+
let parsed = rawText;
|
|
12716
|
+
if (rawText) {
|
|
12717
|
+
try {
|
|
12718
|
+
parsed = JSON.parse(rawText);
|
|
12719
|
+
} catch {
|
|
12720
|
+
parsed = rawText;
|
|
12721
|
+
}
|
|
12722
|
+
} else {
|
|
12723
|
+
parsed = null;
|
|
10065
12724
|
}
|
|
10066
12725
|
if (!response.ok) {
|
|
10067
12726
|
const message = parsed && typeof parsed === "object" && "message" in parsed && typeof parsed.message === "string" ? parsed.message : `Billing request failed (${response.status})`;
|
|
@@ -10553,18 +13212,6 @@ function createBillingModule(config) {
|
|
|
10553
13212
|
};
|
|
10554
13213
|
}
|
|
10555
13214
|
|
|
10556
|
-
// src/config/errors.ts
|
|
10557
|
-
var AthenaConfigurationError = class extends Error {
|
|
10558
|
-
code;
|
|
10559
|
-
service;
|
|
10560
|
-
constructor(code, message, service) {
|
|
10561
|
-
super(message);
|
|
10562
|
-
this.name = "AthenaConfigurationError";
|
|
10563
|
-
this.code = code;
|
|
10564
|
-
this.service = service;
|
|
10565
|
-
}
|
|
10566
|
-
};
|
|
10567
|
-
|
|
10568
13215
|
// src/context/merge.ts
|
|
10569
13216
|
function mergeAthenaRequestContexts(base, override) {
|
|
10570
13217
|
if (!base && !override) return void 0;
|
|
@@ -10578,6 +13225,82 @@ function mergeAthenaRequestContexts(base, override) {
|
|
|
10578
13225
|
};
|
|
10579
13226
|
}
|
|
10580
13227
|
|
|
13228
|
+
// src/diagnostics.ts
|
|
13229
|
+
function readProcessEnv2() {
|
|
13230
|
+
try {
|
|
13231
|
+
return globalThis.process?.env ?? {};
|
|
13232
|
+
} catch {
|
|
13233
|
+
return {};
|
|
13234
|
+
}
|
|
13235
|
+
}
|
|
13236
|
+
function isTruthyEnv(value) {
|
|
13237
|
+
if (!value) return false;
|
|
13238
|
+
const normalized = value.trim().toLowerCase();
|
|
13239
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
13240
|
+
}
|
|
13241
|
+
function isQuietAthenaDiagnosticsEnvironment(env = readProcessEnv2()) {
|
|
13242
|
+
const nodeEnv = env.NODE_ENV?.trim().toLowerCase();
|
|
13243
|
+
if (nodeEnv === "production") {
|
|
13244
|
+
return true;
|
|
13245
|
+
}
|
|
13246
|
+
if (isTruthyEnv(env.OPENNEXT_BUILD)) {
|
|
13247
|
+
return true;
|
|
13248
|
+
}
|
|
13249
|
+
const nextPhase = env.NEXT_PHASE?.trim();
|
|
13250
|
+
if (nextPhase === "phase-production-build") {
|
|
13251
|
+
return true;
|
|
13252
|
+
}
|
|
13253
|
+
if (isTruthyEnv(env.CI) && nodeEnv !== "test") {
|
|
13254
|
+
if (nodeEnv === "production" || isTruthyEnv(env.OPENNEXT_BUILD)) {
|
|
13255
|
+
return true;
|
|
13256
|
+
}
|
|
13257
|
+
}
|
|
13258
|
+
return false;
|
|
13259
|
+
}
|
|
13260
|
+
function resolveBooleanFlag(explicit, mode, quiet) {
|
|
13261
|
+
if (typeof explicit === "boolean") {
|
|
13262
|
+
return explicit;
|
|
13263
|
+
}
|
|
13264
|
+
if (mode === true) {
|
|
13265
|
+
return true;
|
|
13266
|
+
}
|
|
13267
|
+
if (mode === false) {
|
|
13268
|
+
return false;
|
|
13269
|
+
}
|
|
13270
|
+
if (mode === "auto") {
|
|
13271
|
+
return false;
|
|
13272
|
+
}
|
|
13273
|
+
return false;
|
|
13274
|
+
}
|
|
13275
|
+
function resolveAthenaClientDiagnostics(input) {
|
|
13276
|
+
const env = input.env ?? readProcessEnv2();
|
|
13277
|
+
const quiet = isQuietAthenaDiagnosticsEnvironment(env);
|
|
13278
|
+
const mode = input.diagnostics;
|
|
13279
|
+
const effectiveMode = mode === "auto" && quiet ? false : mode;
|
|
13280
|
+
const debugAst = resolveBooleanFlag(input.debugAst, effectiveMode);
|
|
13281
|
+
const findManyAst = resolveBooleanFlag(input.findManyAst, effectiveMode);
|
|
13282
|
+
let traceQueries;
|
|
13283
|
+
if (input.traceQueries !== void 0) {
|
|
13284
|
+
if (typeof input.traceQueries === "boolean") {
|
|
13285
|
+
traceQueries = input.traceQueries;
|
|
13286
|
+
} else if (effectiveMode === false || mode === "auto" && quiet) {
|
|
13287
|
+
const enabled = input.traceQueries.enabled;
|
|
13288
|
+
traceQueries = typeof enabled === "boolean" ? enabled ? input.traceQueries : false : false;
|
|
13289
|
+
} else {
|
|
13290
|
+
traceQueries = input.traceQueries;
|
|
13291
|
+
}
|
|
13292
|
+
} else if (effectiveMode === true) {
|
|
13293
|
+
traceQueries = true;
|
|
13294
|
+
} else {
|
|
13295
|
+
traceQueries = false;
|
|
13296
|
+
}
|
|
13297
|
+
return {
|
|
13298
|
+
debugAst,
|
|
13299
|
+
findManyAst,
|
|
13300
|
+
traceQueries
|
|
13301
|
+
};
|
|
13302
|
+
}
|
|
13303
|
+
|
|
10581
13304
|
// src/v3-client.ts
|
|
10582
13305
|
var ENV_URL_KEYS = ["ATHENA_URL", "NEXT_PUBLIC_ATHENA_URL"];
|
|
10583
13306
|
var ENV_DB_URL_KEYS = ["ATHENA_DB_URL", "ATHENA_GATEWAY_URL", "NEXT_PUBLIC_ATHENA_DB_API_URL"];
|
|
@@ -10586,7 +13309,13 @@ var ENV_CHAT_URL_KEYS = ["ATHENA_CHAT_URL", "NEXT_PUBLIC_ATHENA_CHAT_URL"];
|
|
|
10586
13309
|
var ENV_CHAT_WS_URL_KEYS = ["ATHENA_CHAT_WS_URL", "NEXT_PUBLIC_ATHENA_CHAT_WS_URL"];
|
|
10587
13310
|
var ENV_STORAGE_URL_KEYS = ["ATHENA_STORAGE_URL", "NEXT_PUBLIC_ATHENA_STORAGE_URL"];
|
|
10588
13311
|
var ENV_KEY_KEYS = ["ATHENA_API_KEY", "NEXT_PUBLIC_ATHENA_API_KEY", "ATHENA_GATEWAY_API_KEY", "X_API_KEY"];
|
|
10589
|
-
var ENV_CLIENT_KEYS = [
|
|
13312
|
+
var ENV_CLIENT_KEYS = [
|
|
13313
|
+
"ATHENA_CLIENT",
|
|
13314
|
+
"ATHENA_GATEWAY_CLIENT",
|
|
13315
|
+
"ATHENA_GENERATOR_CLIENT",
|
|
13316
|
+
"NEXT_PUBLIC_ATHENA_CLIENT",
|
|
13317
|
+
"NEXT_PUBLIC_ATHENA_GATEWAY_CLIENT"
|
|
13318
|
+
];
|
|
10590
13319
|
var MISSING_DB_SENTINEL = "https://athena.invalid/db";
|
|
10591
13320
|
function readFirstEnv(env, keys) {
|
|
10592
13321
|
for (const key of keys) {
|
|
@@ -10595,14 +13324,30 @@ function readFirstEnv(env, keys) {
|
|
|
10595
13324
|
}
|
|
10596
13325
|
return void 0;
|
|
10597
13326
|
}
|
|
10598
|
-
function
|
|
13327
|
+
function readFirstEnvHttpUrl(env, keys) {
|
|
13328
|
+
for (const key of keys) {
|
|
13329
|
+
const value = env?.[key]?.trim();
|
|
13330
|
+
if (value && isAbsoluteHttpUrl(value)) return value;
|
|
13331
|
+
}
|
|
13332
|
+
return void 0;
|
|
13333
|
+
}
|
|
13334
|
+
function normalizeOptional2(value) {
|
|
10599
13335
|
const normalized = value?.trim();
|
|
10600
13336
|
return normalized || void 0;
|
|
10601
13337
|
}
|
|
13338
|
+
function isAbsoluteHttpUrl(value) {
|
|
13339
|
+
try {
|
|
13340
|
+
const url = new URL(value);
|
|
13341
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
13342
|
+
} catch {
|
|
13343
|
+
return false;
|
|
13344
|
+
}
|
|
13345
|
+
}
|
|
10602
13346
|
function appendPath(baseUrl, path) {
|
|
10603
13347
|
return `${baseUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
10604
13348
|
}
|
|
10605
13349
|
function toWebSocketUrl(baseUrl) {
|
|
13350
|
+
if (!isAbsoluteHttpUrl(baseUrl)) return void 0;
|
|
10606
13351
|
const url = new URL(baseUrl);
|
|
10607
13352
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
10608
13353
|
url.pathname = `${url.pathname.replace(/\/+$/, "")}/wss/gateway`;
|
|
@@ -10612,11 +13357,11 @@ function toWebSocketUrl(baseUrl) {
|
|
|
10612
13357
|
}
|
|
10613
13358
|
function resolveCore(config) {
|
|
10614
13359
|
const env = config.env;
|
|
10615
|
-
const explicitRoot =
|
|
10616
|
-
const envRoot =
|
|
10617
|
-
const root = explicitRoot
|
|
10618
|
-
const explicitRootWinsOverEnvServices = explicitRoot
|
|
10619
|
-
const resolveService = (explicit, envKeys, path) =>
|
|
13360
|
+
const explicitRoot = normalizeOptional2(config.url);
|
|
13361
|
+
const envRoot = readFirstEnvHttpUrl(env, ENV_URL_KEYS);
|
|
13362
|
+
const root = explicitRoot && isAbsoluteHttpUrl(explicitRoot) ? explicitRoot : explicitRoot ? void 0 : envRoot;
|
|
13363
|
+
const explicitRootWinsOverEnvServices = Boolean(root && explicitRoot && isAbsoluteHttpUrl(explicitRoot));
|
|
13364
|
+
const resolveService = (explicit, envKeys, path) => normalizeOptional2(explicit) ?? (explicitRootWinsOverEnvServices && root ? appendPath(root, path) : void 0) ?? readFirstEnvHttpUrl(env, envKeys) ?? (root ? appendPath(root, path) : void 0);
|
|
10620
13365
|
const dbUrl = resolveService(config.db?.url, ENV_DB_URL_KEYS, "db");
|
|
10621
13366
|
const urls = {
|
|
10622
13367
|
db: dbUrl,
|
|
@@ -10624,8 +13369,8 @@ function resolveCore(config) {
|
|
|
10624
13369
|
chat: resolveService(config.chat?.url, ENV_CHAT_URL_KEYS, "chat"),
|
|
10625
13370
|
storage: resolveService(config.storage?.url, ENV_STORAGE_URL_KEYS, "storage"),
|
|
10626
13371
|
// Billing lives on the main Athena HTTP surface (same host as gateway/db).
|
|
10627
|
-
billing:
|
|
10628
|
-
chatWs:
|
|
13372
|
+
billing: normalizeOptional2(config.billing?.url) ?? dbUrl ?? root ?? void 0,
|
|
13373
|
+
chatWs: normalizeOptional2(config.chat?.wsUrl) ?? (explicitRootWinsOverEnvServices && root ? toWebSocketUrl(root) : void 0) ?? readFirstEnvHttpUrl(env, ENV_CHAT_WS_URL_KEYS) ?? (root ? toWebSocketUrl(root) : void 0)
|
|
10629
13374
|
};
|
|
10630
13375
|
if (!urls.db && !urls.auth && !urls.chat && !urls.storage && !urls.billing) {
|
|
10631
13376
|
throw new AthenaConfigurationError(
|
|
@@ -10634,7 +13379,7 @@ function resolveCore(config) {
|
|
|
10634
13379
|
"db"
|
|
10635
13380
|
);
|
|
10636
13381
|
}
|
|
10637
|
-
const key =
|
|
13382
|
+
const key = normalizeOptional2(config.key) ?? readFirstEnv(env, ENV_KEY_KEYS);
|
|
10638
13383
|
if (!key) {
|
|
10639
13384
|
throw new AthenaConfigurationError(
|
|
10640
13385
|
"ATHENA_API_KEY_REQUIRED",
|
|
@@ -10645,7 +13390,7 @@ function resolveCore(config) {
|
|
|
10645
13390
|
config,
|
|
10646
13391
|
urls,
|
|
10647
13392
|
key,
|
|
10648
|
-
client:
|
|
13393
|
+
client: normalizeOptional2(config.client) ?? readFirstEnv(env, ENV_CLIENT_KEYS)
|
|
10649
13394
|
};
|
|
10650
13395
|
return {
|
|
10651
13396
|
...base,
|
|
@@ -10660,7 +13405,20 @@ async function resolveConfiguredContext(core, viewContext) {
|
|
|
10660
13405
|
function createInternalConfig(core) {
|
|
10661
13406
|
const { config, urls } = core;
|
|
10662
13407
|
const { url: _authUrl, ...authOptions } = config.auth ?? {};
|
|
10663
|
-
const {
|
|
13408
|
+
const {
|
|
13409
|
+
url: _storageUrl,
|
|
13410
|
+
directUpload,
|
|
13411
|
+
r2: _r2,
|
|
13412
|
+
prefix: _r2Prefix,
|
|
13413
|
+
...storageOptions
|
|
13414
|
+
} = config.storage ?? {};
|
|
13415
|
+
const diagnostics = resolveAthenaClientDiagnostics({
|
|
13416
|
+
diagnostics: config.diagnostics,
|
|
13417
|
+
debugAst: config.debugAst,
|
|
13418
|
+
findManyAst: config.findManyAst,
|
|
13419
|
+
traceQueries: config.traceQueries,
|
|
13420
|
+
env: config.env
|
|
13421
|
+
});
|
|
10664
13422
|
return {
|
|
10665
13423
|
baseUrl: urls.db ?? MISSING_DB_SENTINEL,
|
|
10666
13424
|
apiKey: core.key,
|
|
@@ -10677,14 +13435,15 @@ function createInternalConfig(core) {
|
|
|
10677
13435
|
models: config.models,
|
|
10678
13436
|
behavior: {
|
|
10679
13437
|
retryReads: config.retryReads,
|
|
10680
|
-
traceQueries:
|
|
10681
|
-
debugAst:
|
|
10682
|
-
findManyAst:
|
|
13438
|
+
traceQueries: diagnostics.traceQueries,
|
|
13439
|
+
debugAst: diagnostics.debugAst,
|
|
13440
|
+
findManyAst: diagnostics.findManyAst
|
|
10683
13441
|
},
|
|
10684
13442
|
storage: {
|
|
10685
13443
|
...storageOptions,
|
|
10686
13444
|
...directUpload ? { directUpload } : {}
|
|
10687
|
-
}
|
|
13445
|
+
},
|
|
13446
|
+
gatewayTransport: config.gatewayTransport
|
|
10688
13447
|
};
|
|
10689
13448
|
}
|
|
10690
13449
|
function serviceGuard(urls, service) {
|
|
@@ -10705,7 +13464,233 @@ function createUnavailableNamespace(service, urls, path = []) {
|
|
|
10705
13464
|
serviceGuard(urls, service);
|
|
10706
13465
|
throw new TypeError(`Athena service property ${path.map(String).join(".")} is not callable.`);
|
|
10707
13466
|
}
|
|
10708
|
-
});
|
|
13467
|
+
});
|
|
13468
|
+
}
|
|
13469
|
+
function isD1Binding2(value) {
|
|
13470
|
+
return Boolean(
|
|
13471
|
+
value && typeof value === "object" && typeof value.prepare === "function"
|
|
13472
|
+
);
|
|
13473
|
+
}
|
|
13474
|
+
function isR2Binding(value) {
|
|
13475
|
+
return Boolean(
|
|
13476
|
+
value && typeof value === "object" && typeof value.put === "function" && typeof value.get === "function"
|
|
13477
|
+
);
|
|
13478
|
+
}
|
|
13479
|
+
function foldBindingAliases(config) {
|
|
13480
|
+
const d1 = config.db?.d1 ?? config.d1;
|
|
13481
|
+
const r2 = config.storage?.r2 ?? config.r2;
|
|
13482
|
+
const sessionMode = config.db?.sessionMode ?? config.sessionMode;
|
|
13483
|
+
const prefix = config.storage?.prefix ?? config.storagePrefix;
|
|
13484
|
+
let next = { ...config };
|
|
13485
|
+
if (d1 !== void 0 || sessionMode !== void 0) {
|
|
13486
|
+
next = {
|
|
13487
|
+
...next,
|
|
13488
|
+
db: {
|
|
13489
|
+
...next.db,
|
|
13490
|
+
...d1 !== void 0 ? { d1 } : {},
|
|
13491
|
+
...sessionMode !== void 0 ? { sessionMode } : {}
|
|
13492
|
+
}
|
|
13493
|
+
};
|
|
13494
|
+
}
|
|
13495
|
+
if (r2 !== void 0 || prefix !== void 0) {
|
|
13496
|
+
next = {
|
|
13497
|
+
...next,
|
|
13498
|
+
storage: {
|
|
13499
|
+
...next.storage,
|
|
13500
|
+
...r2 !== void 0 ? { r2 } : {},
|
|
13501
|
+
...prefix !== void 0 ? { prefix } : {}
|
|
13502
|
+
}
|
|
13503
|
+
};
|
|
13504
|
+
}
|
|
13505
|
+
const {
|
|
13506
|
+
d1: _d1,
|
|
13507
|
+
r2: _r2,
|
|
13508
|
+
storagePrefix: _storagePrefix,
|
|
13509
|
+
sessionMode: _sessionMode,
|
|
13510
|
+
...rest
|
|
13511
|
+
} = next;
|
|
13512
|
+
return rest;
|
|
13513
|
+
}
|
|
13514
|
+
function applyExecutionMode(config) {
|
|
13515
|
+
const d1 = config.db?.d1;
|
|
13516
|
+
const hasD1 = isD1Binding2(d1);
|
|
13517
|
+
const hasUrl = Boolean(
|
|
13518
|
+
normalizeOptional2(config.url) ?? normalizeOptional2(config.db?.url) ?? (config.env ? normalizeOptional2(config.env.ATHENA_URL) ?? normalizeOptional2(config.env.NEXT_PUBLIC_ATHENA_URL) : void 0)
|
|
13519
|
+
);
|
|
13520
|
+
const hasModeHint = config.mode != null || config.prefer != null || Boolean(config.env?.ATHENA_EXECUTION_MODE) || Boolean(config.env?.ATHENA_EXECUTION_PREFER);
|
|
13521
|
+
if (!hasD1 && !hasModeHint) {
|
|
13522
|
+
return config;
|
|
13523
|
+
}
|
|
13524
|
+
if (hasD1 && !hasUrl && !hasModeHint) {
|
|
13525
|
+
return config;
|
|
13526
|
+
}
|
|
13527
|
+
let resolved;
|
|
13528
|
+
try {
|
|
13529
|
+
resolved = resolveAthenaExecutionMode({
|
|
13530
|
+
mode: config.mode,
|
|
13531
|
+
prefer: config.prefer,
|
|
13532
|
+
d1: hasD1 ? d1 : null,
|
|
13533
|
+
url: config.url ?? config.db?.url,
|
|
13534
|
+
env: config.env
|
|
13535
|
+
});
|
|
13536
|
+
} catch (error) {
|
|
13537
|
+
if (!hasModeHint) return config;
|
|
13538
|
+
throw error;
|
|
13539
|
+
}
|
|
13540
|
+
if (resolved === "gateway" && hasD1) {
|
|
13541
|
+
const { d1: _drop, sessionMode: _sm, ...dbRest } = config.db ?? {};
|
|
13542
|
+
return {
|
|
13543
|
+
...config,
|
|
13544
|
+
db: Object.keys(dbRest).length > 0 ? dbRest : void 0,
|
|
13545
|
+
gatewayTransport: void 0
|
|
13546
|
+
};
|
|
13547
|
+
}
|
|
13548
|
+
return config;
|
|
13549
|
+
}
|
|
13550
|
+
function resolveUnifiedRemoteRoot(config) {
|
|
13551
|
+
return normalizeOptional2(config.url) ?? readFirstEnv(config.env, ENV_URL_KEYS);
|
|
13552
|
+
}
|
|
13553
|
+
function isEdgeLocalSentinelUrl(url) {
|
|
13554
|
+
if (!url) return false;
|
|
13555
|
+
return url === CLOUDFLARE_EDGE_BASE_URL || url.startsWith("https://athena.local/") || url.startsWith("http://athena.local/");
|
|
13556
|
+
}
|
|
13557
|
+
function hasRemoteDbGatewayUrl(config) {
|
|
13558
|
+
const dbUrl = normalizeOptional2(config.db?.url) ?? readFirstEnv(config.env, ENV_DB_URL_KEYS);
|
|
13559
|
+
return Boolean(dbUrl && !isEdgeLocalSentinelUrl(dbUrl));
|
|
13560
|
+
}
|
|
13561
|
+
function hasRemoteHttpServices(config) {
|
|
13562
|
+
return Boolean(
|
|
13563
|
+
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)
|
|
13564
|
+
);
|
|
13565
|
+
}
|
|
13566
|
+
function hasRemoteHttpStorage(config) {
|
|
13567
|
+
return Boolean(
|
|
13568
|
+
normalizeOptional2(config.storage?.url) || readFirstEnv(config.env, ENV_STORAGE_URL_KEYS) || resolveUnifiedRemoteRoot(config)
|
|
13569
|
+
);
|
|
13570
|
+
}
|
|
13571
|
+
function hasRemoteAuthService(config) {
|
|
13572
|
+
return Boolean(
|
|
13573
|
+
normalizeOptional2(config.auth?.url) || readFirstEnv(config.env, ENV_AUTH_URL_KEYS) || resolveUnifiedRemoteRoot(config)
|
|
13574
|
+
);
|
|
13575
|
+
}
|
|
13576
|
+
function materializeEdgeBindings(config) {
|
|
13577
|
+
const d1 = config.db?.d1;
|
|
13578
|
+
const r2 = config.storage?.r2;
|
|
13579
|
+
const hasD1 = isD1Binding2(d1);
|
|
13580
|
+
const hasR2 = isR2Binding(r2);
|
|
13581
|
+
if (!hasD1 && !hasR2) {
|
|
13582
|
+
return config;
|
|
13583
|
+
}
|
|
13584
|
+
if (hasD1 && d1 && typeof d1.prepare !== "function") {
|
|
13585
|
+
throw new AthenaConfigurationError(
|
|
13586
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
13587
|
+
"db.d1 must be a D1 binding with prepare().",
|
|
13588
|
+
"db"
|
|
13589
|
+
);
|
|
13590
|
+
}
|
|
13591
|
+
const remoteRoot = resolveUnifiedRemoteRoot(config);
|
|
13592
|
+
const remoteServices = hasRemoteHttpServices(config);
|
|
13593
|
+
const remoteStorage = hasRemoteHttpStorage(config);
|
|
13594
|
+
const remoteAuth = hasRemoteAuthService(config);
|
|
13595
|
+
const next = { ...config };
|
|
13596
|
+
if (hasD1 && d1) {
|
|
13597
|
+
if (!config.gatewayTransport) {
|
|
13598
|
+
next.gatewayTransport = createCloudflareD1GatewayTransport({
|
|
13599
|
+
d1,
|
|
13600
|
+
defaultSessionMode: config.db?.sessionMode
|
|
13601
|
+
});
|
|
13602
|
+
}
|
|
13603
|
+
const explicitDbUrl = normalizeOptional2(config.db?.url);
|
|
13604
|
+
const remoteDbGateway = hasRemoteDbGatewayUrl(config);
|
|
13605
|
+
next.db = {
|
|
13606
|
+
...config.db,
|
|
13607
|
+
d1,
|
|
13608
|
+
url: explicitDbUrl ?? (remoteDbGateway ? void 0 : CLOUDFLARE_EDGE_BASE_URL)
|
|
13609
|
+
};
|
|
13610
|
+
const explicitKey = normalizeOptional2(config.key);
|
|
13611
|
+
if (explicitKey) {
|
|
13612
|
+
next.key = explicitKey;
|
|
13613
|
+
} else if (!remoteServices) {
|
|
13614
|
+
next.key = CLOUDFLARE_EDGE_API_KEY;
|
|
13615
|
+
} else {
|
|
13616
|
+
next.key = void 0;
|
|
13617
|
+
}
|
|
13618
|
+
if (remoteRoot) {
|
|
13619
|
+
next.billing = {
|
|
13620
|
+
...config.billing ?? {},
|
|
13621
|
+
url: normalizeOptional2(config.billing?.url) ?? remoteRoot
|
|
13622
|
+
};
|
|
13623
|
+
}
|
|
13624
|
+
if (!config.capabilities) {
|
|
13625
|
+
next.capabilities = createCloudflareEdgeCapabilities({
|
|
13626
|
+
hasR2,
|
|
13627
|
+
// Explicit storage.url / env storage URL / unified remote root all count.
|
|
13628
|
+
hasRemoteStorage: remoteStorage,
|
|
13629
|
+
authRemote: remoteAuth,
|
|
13630
|
+
findManyAst: false
|
|
13631
|
+
});
|
|
13632
|
+
}
|
|
13633
|
+
} else if (hasR2 && r2) {
|
|
13634
|
+
if (!remoteRoot && !normalizeOptional2(config.db?.url) && !normalizeOptional2(config.storage?.url) && !readFirstEnv(config.env, ENV_STORAGE_URL_KEYS)) {
|
|
13635
|
+
next.storage = {
|
|
13636
|
+
...config.storage,
|
|
13637
|
+
r2,
|
|
13638
|
+
// Local sentinel so resolveCore accepts a storage-only binding client.
|
|
13639
|
+
url: CLOUDFLARE_EDGE_BASE_URL
|
|
13640
|
+
};
|
|
13641
|
+
if (!remoteServices) {
|
|
13642
|
+
next.key = normalizeOptional2(config.key) ?? CLOUDFLARE_EDGE_API_KEY;
|
|
13643
|
+
} else if (normalizeOptional2(config.key)) {
|
|
13644
|
+
next.key = normalizeOptional2(config.key);
|
|
13645
|
+
} else {
|
|
13646
|
+
next.key = void 0;
|
|
13647
|
+
}
|
|
13648
|
+
}
|
|
13649
|
+
if (!config.capabilities) {
|
|
13650
|
+
if (remoteRoot || normalizeOptional2(config.db?.url) || readFirstEnv(config.env, ENV_DB_URL_KEYS)) {
|
|
13651
|
+
const base = createGatewayCapabilities({
|
|
13652
|
+
authRemote: remoteAuth,
|
|
13653
|
+
storageConfigured: true
|
|
13654
|
+
});
|
|
13655
|
+
next.capabilities = {
|
|
13656
|
+
...base,
|
|
13657
|
+
storage: {
|
|
13658
|
+
...base.storage,
|
|
13659
|
+
local: true,
|
|
13660
|
+
objects: true
|
|
13661
|
+
}
|
|
13662
|
+
};
|
|
13663
|
+
} else {
|
|
13664
|
+
next.capabilities = {
|
|
13665
|
+
mode: "cloudflare-edge",
|
|
13666
|
+
db: {
|
|
13667
|
+
engine: "unknown",
|
|
13668
|
+
local: false,
|
|
13669
|
+
layers: {
|
|
13670
|
+
query: false,
|
|
13671
|
+
flatCrud: false,
|
|
13672
|
+
findManyAst: false,
|
|
13673
|
+
rpc: false,
|
|
13674
|
+
relations: false
|
|
13675
|
+
}
|
|
13676
|
+
},
|
|
13677
|
+
storage: {
|
|
13678
|
+
local: true,
|
|
13679
|
+
objects: true,
|
|
13680
|
+
catalogs: false,
|
|
13681
|
+
backups: false
|
|
13682
|
+
},
|
|
13683
|
+
auth: {
|
|
13684
|
+
remote: remoteAuth
|
|
13685
|
+
}
|
|
13686
|
+
};
|
|
13687
|
+
}
|
|
13688
|
+
}
|
|
13689
|
+
}
|
|
13690
|
+
return next;
|
|
13691
|
+
}
|
|
13692
|
+
function normalizeCreateClientConfig(config) {
|
|
13693
|
+
return materializeEdgeBindings(applyExecutionMode(foldBindingAliases(config)));
|
|
10709
13694
|
}
|
|
10710
13695
|
function createClientView(core, viewContext) {
|
|
10711
13696
|
const resolved = createInternalClientView(
|
|
@@ -10724,12 +13709,23 @@ function createClientView(core, viewContext) {
|
|
|
10724
13709
|
},
|
|
10725
13710
|
...billingOptions
|
|
10726
13711
|
}) : createUnavailableNamespace("billing", core.urls);
|
|
13712
|
+
const capabilities = core.config.capabilities ?? createGatewayCapabilities({
|
|
13713
|
+
authRemote: Boolean(core.urls.auth),
|
|
13714
|
+
// Match unavailable storage proxy when no storage URL was resolved.
|
|
13715
|
+
storageConfigured: Boolean(core.urls.storage)
|
|
13716
|
+
});
|
|
13717
|
+
const r2 = core.config.storage?.r2;
|
|
13718
|
+
const storageModule = isR2Binding(r2) ? createCloudflareR2StorageModule({
|
|
13719
|
+
r2,
|
|
13720
|
+
prefix: core.config.storage?.prefix ?? void 0
|
|
13721
|
+
}) : core.urls.storage ? resolved.storage : createUnavailableNamespace("storage", core.urls);
|
|
10727
13722
|
const client = {
|
|
10728
13723
|
db: core.urls.db ? resolved.db : createUnavailableNamespace("db", core.urls),
|
|
10729
13724
|
auth: core.urls.auth ? resolved.auth : createUnavailableNamespace("auth", core.urls),
|
|
10730
13725
|
chat: core.urls.chat ? resolved.chat : createUnavailableNamespace("chat", core.urls),
|
|
10731
|
-
storage:
|
|
13726
|
+
storage: storageModule,
|
|
10732
13727
|
billing: billingModule,
|
|
13728
|
+
capabilities,
|
|
10733
13729
|
from: ((...args) => {
|
|
10734
13730
|
requireDb();
|
|
10735
13731
|
return Reflect.apply(resolved.from, resolved, args);
|
|
@@ -10753,13 +13749,34 @@ function createClientView(core, viewContext) {
|
|
|
10753
13749
|
return resolved.verifyConnection(options);
|
|
10754
13750
|
},
|
|
10755
13751
|
withContext(context) {
|
|
13752
|
+
warnIfEmptyRequestContext(context);
|
|
10756
13753
|
return createClientView(core, mergeAthenaRequestContexts(viewContext, context));
|
|
10757
13754
|
}
|
|
10758
13755
|
};
|
|
10759
13756
|
return Object.freeze(client);
|
|
10760
13757
|
}
|
|
13758
|
+
function isEmptyAthenaRequestContext(context) {
|
|
13759
|
+
if (!context) return true;
|
|
13760
|
+
const hasHeaders = context.headers != null && Object.keys(context.headers).length > 0;
|
|
13761
|
+
return context.userId == null && context.organizationId == null && !normalizeOptionalContextString(context.cookie) && !normalizeOptionalContextString(context.bearerToken) && !normalizeOptionalContextString(context.sessionToken) && !context.forceNoCache && !hasHeaders;
|
|
13762
|
+
}
|
|
13763
|
+
function normalizeOptionalContextString(value) {
|
|
13764
|
+
const trimmed = value?.trim();
|
|
13765
|
+
return trimmed || void 0;
|
|
13766
|
+
}
|
|
13767
|
+
function warnIfEmptyRequestContext(context) {
|
|
13768
|
+
if (!isEmptyAthenaRequestContext(context)) return;
|
|
13769
|
+
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
13770
|
+
if (nodeEnv === "production") {
|
|
13771
|
+
return;
|
|
13772
|
+
}
|
|
13773
|
+
console.warn(
|
|
13774
|
+
"[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 })."
|
|
13775
|
+
);
|
|
13776
|
+
}
|
|
10761
13777
|
function createClient(config) {
|
|
10762
|
-
|
|
13778
|
+
const normalized = normalizeCreateClientConfig(config);
|
|
13779
|
+
return createClientView(resolveCore(normalized));
|
|
10763
13780
|
}
|
|
10764
13781
|
|
|
10765
13782
|
// src/gateway/types.ts
|
|
@@ -10996,6 +14013,27 @@ function resolveTotalItemsFromPage({
|
|
|
10996
14013
|
}
|
|
10997
14014
|
return clampAthenaReadQueryTotalItems(exactCount, limit);
|
|
10998
14015
|
}
|
|
14016
|
+
function resolveAthenaReadQueryPageFetch({
|
|
14017
|
+
page,
|
|
14018
|
+
pageSize,
|
|
14019
|
+
limit
|
|
14020
|
+
}) {
|
|
14021
|
+
const safePage = Math.max(1, Math.trunc(page) || 1);
|
|
14022
|
+
const safePageSize = Math.max(1, Math.trunc(pageSize) || 1);
|
|
14023
|
+
if (!limit || limit < 1) {
|
|
14024
|
+
return { page: safePage, pageSize: safePageSize, shouldFetch: true };
|
|
14025
|
+
}
|
|
14026
|
+
const totalCap = Math.trunc(limit);
|
|
14027
|
+
const offset = (safePage - 1) * safePageSize;
|
|
14028
|
+
if (offset >= totalCap) {
|
|
14029
|
+
return { page: safePage, pageSize: safePageSize, shouldFetch: false };
|
|
14030
|
+
}
|
|
14031
|
+
return {
|
|
14032
|
+
page: safePage,
|
|
14033
|
+
pageSize: Math.min(safePageSize, totalCap - offset),
|
|
14034
|
+
shouldFetch: true
|
|
14035
|
+
};
|
|
14036
|
+
}
|
|
10999
14037
|
async function executeAthenaReadQuery({
|
|
11000
14038
|
client,
|
|
11001
14039
|
page,
|
|
@@ -11014,15 +14052,29 @@ async function executeAthenaReadQuery({
|
|
|
11014
14052
|
count: "exact",
|
|
11015
14053
|
head: true
|
|
11016
14054
|
});
|
|
14055
|
+
const pageFetch = resolveAthenaReadQueryPageFetch({
|
|
14056
|
+
limit: query.limit,
|
|
14057
|
+
page,
|
|
14058
|
+
pageSize
|
|
14059
|
+
});
|
|
14060
|
+
if (!pageFetch.shouldFetch) {
|
|
14061
|
+
return {
|
|
14062
|
+
rows: [],
|
|
14063
|
+
totalItems: resolveTotalItemsFromPage({
|
|
14064
|
+
countCandidates: [countResult.count],
|
|
14065
|
+
limit: query.limit,
|
|
14066
|
+
page: pageFetch.page,
|
|
14067
|
+
pageSize,
|
|
14068
|
+
rowCount: 0
|
|
14069
|
+
})
|
|
14070
|
+
};
|
|
14071
|
+
}
|
|
11017
14072
|
if ((query.mode ?? "findMany") === "select") {
|
|
11018
|
-
const selectBuilder =
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
query.orderBy
|
|
11022
|
-
),
|
|
11023
|
-
query.limit
|
|
14073
|
+
const selectBuilder = applyAthenaReadQuerySelectOrder(
|
|
14074
|
+
applyAthenaReadQueryFilters(baseBuilder, query.filters),
|
|
14075
|
+
query.orderBy
|
|
11024
14076
|
);
|
|
11025
|
-
const result2 = await selectBuilder.currentPage(page).pageSize(pageSize).select(buildAthenaReadQuerySelectString(query.columns), {
|
|
14077
|
+
const result2 = await selectBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).select(buildAthenaReadQuerySelectString(query.columns), {
|
|
11026
14078
|
count: "exact"
|
|
11027
14079
|
});
|
|
11028
14080
|
const rows2 = flattenAthenaReadQueryRows(
|
|
@@ -11036,7 +14088,7 @@ async function executeAthenaReadQuery({
|
|
|
11036
14088
|
totalItems: resolveTotalItemsFromPage({
|
|
11037
14089
|
countCandidates: [countResult.count, result2.count],
|
|
11038
14090
|
limit: query.limit,
|
|
11039
|
-
page,
|
|
14091
|
+
page: pageFetch.page,
|
|
11040
14092
|
pageSize,
|
|
11041
14093
|
rowCount: rows2.length
|
|
11042
14094
|
})
|
|
@@ -11044,12 +14096,11 @@ async function executeAthenaReadQuery({
|
|
|
11044
14096
|
}
|
|
11045
14097
|
const findManyOrderBy = buildAthenaReadQueryFindManyOrderBy(query.orderBy);
|
|
11046
14098
|
const findManyOptions = {
|
|
11047
|
-
...query.limit ? { limit: query.limit } : {},
|
|
11048
14099
|
...findManyOrderBy ? { orderBy: findManyOrderBy } : {},
|
|
11049
14100
|
select: buildAthenaReadQueryFindManySelect(query.columns),
|
|
11050
14101
|
...query.filters?.length ? { where: buildAthenaReadQueryFindManyWhere(query.filters) } : {}
|
|
11051
14102
|
};
|
|
11052
|
-
const result = await baseBuilder.currentPage(page).pageSize(pageSize).findMany(findManyOptions);
|
|
14103
|
+
const result = await baseBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).findMany(findManyOptions);
|
|
11053
14104
|
const rows = flattenAthenaReadQueryRows(
|
|
11054
14105
|
Array.isArray(result.data) ? result.data : [],
|
|
11055
14106
|
query.columns,
|
|
@@ -11061,7 +14112,7 @@ async function executeAthenaReadQuery({
|
|
|
11061
14112
|
totalItems: resolveTotalItemsFromPage({
|
|
11062
14113
|
countCandidates: [countResult.count, result.count],
|
|
11063
14114
|
limit: query.limit,
|
|
11064
|
-
page,
|
|
14115
|
+
page: pageFetch.page,
|
|
11065
14116
|
pageSize,
|
|
11066
14117
|
rowCount: rows.length
|
|
11067
14118
|
})
|
|
@@ -12056,12 +15107,19 @@ var DIRECT_CONNECTION_STRING_ENV_KEYS = [
|
|
|
12056
15107
|
];
|
|
12057
15108
|
var POSTGRES_DATABASE_ENV_KEYS = ["ATHENA_GENERATOR_DB", "ATHENA_DATABASE", "PGDATABASE"];
|
|
12058
15109
|
var POSTGRES_PASSWORD_ENV_KEYS = ["ATHENA_GENERATOR_PG_PASSWORD", "PGPASSWORD"];
|
|
12059
|
-
var
|
|
15110
|
+
var GATEWAY_URL_ENV_KEYS2 = ["ATHENA_URL", "ATHENA_GATEWAY_URL", "ATHENA_GENERATOR_URL"];
|
|
12060
15111
|
var GATEWAY_API_KEY_ENV_KEYS = [
|
|
12061
15112
|
"ATHENA_API_KEY",
|
|
12062
15113
|
"ATHENA_GATEWAY_API_KEY",
|
|
12063
15114
|
"ATHENA_GENERATOR_API_KEY"
|
|
12064
15115
|
];
|
|
15116
|
+
var GATEWAY_CLIENT_ENV_KEYS = [
|
|
15117
|
+
"ATHENA_CLIENT",
|
|
15118
|
+
"ATHENA_GATEWAY_CLIENT",
|
|
15119
|
+
"ATHENA_GENERATOR_CLIENT",
|
|
15120
|
+
"NEXT_PUBLIC_ATHENA_CLIENT",
|
|
15121
|
+
"NEXT_PUBLIC_ATHENA_GATEWAY_CLIENT"
|
|
15122
|
+
];
|
|
12065
15123
|
var GENERATOR_SCHEMA_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMAS"];
|
|
12066
15124
|
var OUTPUT_FORMAT_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_FORMAT"];
|
|
12067
15125
|
var OUTPUT_PRESET_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_PRESET"];
|
|
@@ -12354,7 +15412,7 @@ function normalizeProviderConfig(provider) {
|
|
|
12354
15412
|
const gatewayUrl = normalizeRequiredString(
|
|
12355
15413
|
provider.gatewayUrl,
|
|
12356
15414
|
"provider.gatewayUrl",
|
|
12357
|
-
|
|
15415
|
+
GATEWAY_URL_ENV_KEYS2
|
|
12358
15416
|
);
|
|
12359
15417
|
const apiKey = normalizeRequiredString(
|
|
12360
15418
|
provider.apiKey,
|
|
@@ -12362,11 +15420,13 @@ function normalizeProviderConfig(provider) {
|
|
|
12362
15420
|
GATEWAY_API_KEY_ENV_KEYS
|
|
12363
15421
|
);
|
|
12364
15422
|
const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS) ?? "postgres";
|
|
15423
|
+
const client = normalizeOptionalString(provider.client, GATEWAY_CLIENT_ENV_KEYS);
|
|
12365
15424
|
return {
|
|
12366
15425
|
...provider,
|
|
12367
15426
|
gatewayUrl,
|
|
12368
15427
|
apiKey,
|
|
12369
15428
|
database,
|
|
15429
|
+
...client ? { client } : {},
|
|
12370
15430
|
schemas: normalizeSchemaSelection(provider.schemas)
|
|
12371
15431
|
};
|
|
12372
15432
|
}
|
|
@@ -12556,10 +15616,11 @@ function buildEnvironmentProviderConfig() {
|
|
|
12556
15616
|
schemas: normalizeSchemaSelection(resolveFallbackValue(GENERATOR_SCHEMA_ENV_KEYS))
|
|
12557
15617
|
};
|
|
12558
15618
|
}
|
|
12559
|
-
const gatewayUrl = resolveFallbackValue(
|
|
15619
|
+
const gatewayUrl = resolveFallbackValue(GATEWAY_URL_ENV_KEYS2);
|
|
12560
15620
|
const apiKey = resolveFallbackValue(GATEWAY_API_KEY_ENV_KEYS);
|
|
12561
15621
|
if (gatewayUrl && apiKey) {
|
|
12562
15622
|
const backend = resolveOptionalOneOf(GATEWAY_BACKEND_ENV_KEYS, BACKEND_TYPE_VALUES);
|
|
15623
|
+
const client = resolveFallbackValue(GATEWAY_CLIENT_ENV_KEYS);
|
|
12563
15624
|
return {
|
|
12564
15625
|
kind: "postgres",
|
|
12565
15626
|
mode: "gateway",
|
|
@@ -12567,7 +15628,8 @@ function buildEnvironmentProviderConfig() {
|
|
|
12567
15628
|
apiKey,
|
|
12568
15629
|
database: normalizeOptionalString(void 0, POSTGRES_DATABASE_ENV_KEYS),
|
|
12569
15630
|
schemas: normalizeSchemaSelection(resolveFallbackValue(GENERATOR_SCHEMA_ENV_KEYS)),
|
|
12570
|
-
backend
|
|
15631
|
+
backend,
|
|
15632
|
+
...client ? { client } : {}
|
|
12571
15633
|
};
|
|
12572
15634
|
}
|
|
12573
15635
|
return void 0;
|
|
@@ -12711,6 +15773,8 @@ async function discoverGatewaySchemas(config) {
|
|
|
12711
15773
|
const client = createClient({
|
|
12712
15774
|
db: { url: config.gatewayUrl },
|
|
12713
15775
|
key: config.apiKey,
|
|
15776
|
+
client: config.client,
|
|
15777
|
+
env: typeof process !== "undefined" ? process.env : void 0,
|
|
12714
15778
|
backend: {
|
|
12715
15779
|
type: config.backend ?? "postgresql"
|
|
12716
15780
|
}
|
|
@@ -12797,6 +15861,7 @@ function buildGatewayProviderBlock(schemas) {
|
|
|
12797
15861
|
mode: "gateway",
|
|
12798
15862
|
gatewayUrl: generatorEnv("ATHENA_URL"),
|
|
12799
15863
|
apiKey: generatorEnv("ATHENA_API_KEY"),
|
|
15864
|
+
client: generatorEnv("ATHENA_CLIENT", { optional: true }),
|
|
12800
15865
|
database: generatorEnv("ATHENA_GENERATOR_DB", { default: "postgres" }),
|
|
12801
15866
|
schemas: ${formatStringArray(schemas, " ")},
|
|
12802
15867
|
}`;
|
|
@@ -13820,7 +16885,7 @@ function renderModelArtifact(descriptor, config) {
|
|
|
13820
16885
|
const relationsAssignment = config.features.emitRelations && relationEntries.length > 0 ? `
|
|
13821
16886
|
Object.assign(${descriptor.tableConstName}.meta, {
|
|
13822
16887
|
relations: {
|
|
13823
|
-
${relationEntries.map(([
|
|
16888
|
+
${relationEntries.map(([relationKey3, relationValue]) => ` ${renderObjectKey(relationKey3)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
|
|
13824
16889
|
}
|
|
13825
16890
|
})
|
|
13826
16891
|
` : "";
|
|
@@ -13897,7 +16962,7 @@ function renderModelArtifact2(databaseName, descriptor, config) {
|
|
|
13897
16962
|
const relationEntries = Object.entries(descriptor.table.relations);
|
|
13898
16963
|
const relationBlock = config.features.emitRelations && relationEntries.length > 0 ? `,
|
|
13899
16964
|
relations: {
|
|
13900
|
-
${relationEntries.map(([
|
|
16965
|
+
${relationEntries.map(([relationKey3, relationValue]) => ` ${renderObjectKey(relationKey3)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
|
|
13901
16966
|
}` : "";
|
|
13902
16967
|
const content = `import { defineModel } from '@xylex-group/athena'
|
|
13903
16968
|
|
|
@@ -14004,8 +17069,14 @@ var AthenaGatewayPostgresIntrospectionProvider = class {
|
|
|
14004
17069
|
constructor(config) {
|
|
14005
17070
|
this.config = config;
|
|
14006
17071
|
this.client = createClient({
|
|
17072
|
+
url: this.config.gatewayUrl,
|
|
14007
17073
|
db: { url: this.config.gatewayUrl },
|
|
14008
17074
|
key: this.config.apiKey,
|
|
17075
|
+
// Multi-tenant gateways reject DEFAULT_CLIENT; prefer explicit config.
|
|
17076
|
+
// Also pass process.env so ATHENA_CLIENT / ATHENA_GATEWAY_CLIENT still resolve
|
|
17077
|
+
// when the field was not normalized into provider config.
|
|
17078
|
+
client: this.config.client,
|
|
17079
|
+
env: typeof process !== "undefined" ? process.env : void 0,
|
|
14009
17080
|
backend: {
|
|
14010
17081
|
type: this.config.backend ?? "postgresql"
|
|
14011
17082
|
}
|
|
@@ -15486,12 +18557,439 @@ async function ensureActiveOrganization(options) {
|
|
|
15486
18557
|
}
|
|
15487
18558
|
}
|
|
15488
18559
|
|
|
18560
|
+
// src/tables/catalog.ts
|
|
18561
|
+
var POSTGRES_CATALOG_SQL2 = {
|
|
18562
|
+
columns: `
|
|
18563
|
+
SELECT
|
|
18564
|
+
n.nspname AS schema_name,
|
|
18565
|
+
c.relname AS table_name,
|
|
18566
|
+
a.attname AS column_name,
|
|
18567
|
+
format_type(a.atttypid, a.atttypmod) AS data_type,
|
|
18568
|
+
NOT a.attnotnull AS is_nullable
|
|
18569
|
+
FROM pg_attribute a
|
|
18570
|
+
JOIN pg_class c ON c.oid = a.attrelid
|
|
18571
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
18572
|
+
WHERE c.relkind IN ('r', 'p')
|
|
18573
|
+
AND a.attnum > 0
|
|
18574
|
+
AND NOT a.attisdropped
|
|
18575
|
+
AND n.nspname = ANY($1::text[])
|
|
18576
|
+
ORDER BY n.nspname, c.relname, a.attnum;
|
|
18577
|
+
`,
|
|
18578
|
+
foreignKeys: `
|
|
18579
|
+
SELECT
|
|
18580
|
+
sn.nspname AS source_schema,
|
|
18581
|
+
sc.relname AS source_table,
|
|
18582
|
+
con.conname AS constraint_name,
|
|
18583
|
+
ARRAY_AGG(sa.attname ORDER BY cols.ordinality) AS source_columns,
|
|
18584
|
+
tn.nspname AS target_schema,
|
|
18585
|
+
tc.relname AS target_table,
|
|
18586
|
+
ARRAY_AGG(ta.attname ORDER BY cols.ordinality) AS target_columns,
|
|
18587
|
+
EXISTS (
|
|
18588
|
+
SELECT 1
|
|
18589
|
+
FROM pg_constraint uq
|
|
18590
|
+
WHERE uq.conrelid = con.conrelid
|
|
18591
|
+
AND uq.contype IN ('p', 'u')
|
|
18592
|
+
AND uq.conkey = con.conkey
|
|
18593
|
+
) AS source_is_unique
|
|
18594
|
+
FROM pg_constraint con
|
|
18595
|
+
JOIN pg_class sc ON sc.oid = con.conrelid
|
|
18596
|
+
JOIN pg_namespace sn ON sn.oid = sc.relnamespace
|
|
18597
|
+
JOIN pg_class tc ON tc.oid = con.confrelid
|
|
18598
|
+
JOIN pg_namespace tn ON tn.oid = tc.relnamespace
|
|
18599
|
+
JOIN unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(source_attnum, target_attnum, ordinality) ON TRUE
|
|
18600
|
+
JOIN pg_attribute sa ON sa.attrelid = con.conrelid AND sa.attnum = cols.source_attnum
|
|
18601
|
+
JOIN pg_attribute ta ON ta.attrelid = con.confrelid AND ta.attnum = cols.target_attnum
|
|
18602
|
+
WHERE con.contype = 'f'
|
|
18603
|
+
AND sn.nspname = ANY($1::text[])
|
|
18604
|
+
AND tn.nspname = ANY($1::text[])
|
|
18605
|
+
GROUP BY
|
|
18606
|
+
sn.nspname,
|
|
18607
|
+
sc.relname,
|
|
18608
|
+
con.conname,
|
|
18609
|
+
tn.nspname,
|
|
18610
|
+
tc.relname,
|
|
18611
|
+
con.conkey,
|
|
18612
|
+
con.conrelid
|
|
18613
|
+
ORDER BY sn.nspname, sc.relname, con.conname;
|
|
18614
|
+
`,
|
|
18615
|
+
primaryKeys: `
|
|
18616
|
+
SELECT
|
|
18617
|
+
n.nspname AS schema_name,
|
|
18618
|
+
c.relname AS table_name,
|
|
18619
|
+
ARRAY_AGG(a.attname ORDER BY ck.ordinality) AS columns
|
|
18620
|
+
FROM pg_constraint con
|
|
18621
|
+
JOIN pg_class c ON c.oid = con.conrelid
|
|
18622
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
18623
|
+
JOIN unnest(con.conkey) WITH ORDINALITY AS ck(attnum, ordinality) ON TRUE
|
|
18624
|
+
JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ck.attnum
|
|
18625
|
+
WHERE con.contype = 'p'
|
|
18626
|
+
AND n.nspname = ANY($1::text[])
|
|
18627
|
+
GROUP BY n.nspname, c.relname
|
|
18628
|
+
ORDER BY n.nspname, c.relname;
|
|
18629
|
+
`
|
|
18630
|
+
};
|
|
18631
|
+
function parseAthenaTableSchemaScope(value) {
|
|
18632
|
+
return value.split(",").map((entry) => entry.trim()).filter(
|
|
18633
|
+
(entry, index, values) => entry.length > 0 && values.indexOf(entry) === index
|
|
18634
|
+
);
|
|
18635
|
+
}
|
|
18636
|
+
function escapeSqlLiteral2(value) {
|
|
18637
|
+
return value.replace(/'/g, "''");
|
|
18638
|
+
}
|
|
18639
|
+
function buildSchemaArrayLiteral2(schemas) {
|
|
18640
|
+
const literals = schemas.map((schema) => `'${escapeSqlLiteral2(schema)}'`).join(", ");
|
|
18641
|
+
return `ARRAY[${literals}]`;
|
|
18642
|
+
}
|
|
18643
|
+
function inlineSchemaLiteral2(sql, schemas) {
|
|
18644
|
+
return sql.replace(
|
|
18645
|
+
/\$1::text\[\]/g,
|
|
18646
|
+
`${buildSchemaArrayLiteral2(schemas)}::text[]`
|
|
18647
|
+
);
|
|
18648
|
+
}
|
|
18649
|
+
function buildAthenaTableCatalogQueries(schemas) {
|
|
18650
|
+
return {
|
|
18651
|
+
columns: inlineSchemaLiteral2(POSTGRES_CATALOG_SQL2.columns, schemas),
|
|
18652
|
+
foreignKeys: inlineSchemaLiteral2(POSTGRES_CATALOG_SQL2.foreignKeys, schemas),
|
|
18653
|
+
primaryKeys: inlineSchemaLiteral2(POSTGRES_CATALOG_SQL2.primaryKeys, schemas)
|
|
18654
|
+
};
|
|
18655
|
+
}
|
|
18656
|
+
function tableKey2(schema, table2) {
|
|
18657
|
+
return `${schema}.${table2}`;
|
|
18658
|
+
}
|
|
18659
|
+
function relationKey2(...parts) {
|
|
18660
|
+
const base = parts.join("_").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
|
|
18661
|
+
return base.length > 0 ? base : "relation";
|
|
18662
|
+
}
|
|
18663
|
+
function parsePostgresArrayLiteral2(text) {
|
|
18664
|
+
const body = text.slice(1, -1).trim();
|
|
18665
|
+
if (!body) {
|
|
18666
|
+
return [];
|
|
18667
|
+
}
|
|
18668
|
+
const values = [];
|
|
18669
|
+
let current = "";
|
|
18670
|
+
let inQuotes = false;
|
|
18671
|
+
let escaped = false;
|
|
18672
|
+
for (const char of body) {
|
|
18673
|
+
if (escaped) {
|
|
18674
|
+
current += char;
|
|
18675
|
+
escaped = false;
|
|
18676
|
+
continue;
|
|
18677
|
+
}
|
|
18678
|
+
if (char === "\\") {
|
|
18679
|
+
escaped = true;
|
|
18680
|
+
continue;
|
|
18681
|
+
}
|
|
18682
|
+
if (char === '"') {
|
|
18683
|
+
inQuotes = !inQuotes;
|
|
18684
|
+
continue;
|
|
18685
|
+
}
|
|
18686
|
+
if (char === "," && !inQuotes) {
|
|
18687
|
+
values.push(current);
|
|
18688
|
+
current = "";
|
|
18689
|
+
continue;
|
|
18690
|
+
}
|
|
18691
|
+
current += char;
|
|
18692
|
+
}
|
|
18693
|
+
values.push(current);
|
|
18694
|
+
return values.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
18695
|
+
}
|
|
18696
|
+
function coerceStringArray2(value) {
|
|
18697
|
+
if (value == null) {
|
|
18698
|
+
return [];
|
|
18699
|
+
}
|
|
18700
|
+
if (Array.isArray(value)) {
|
|
18701
|
+
return value.map((entry) => entry.trim()).filter(Boolean);
|
|
18702
|
+
}
|
|
18703
|
+
if (typeof value !== "string") {
|
|
18704
|
+
return [];
|
|
18705
|
+
}
|
|
18706
|
+
const trimmedValue = value.trim();
|
|
18707
|
+
if (!trimmedValue) {
|
|
18708
|
+
return [];
|
|
18709
|
+
}
|
|
18710
|
+
if (trimmedValue.startsWith("{") && trimmedValue.endsWith("}")) {
|
|
18711
|
+
return parsePostgresArrayLiteral2(trimmedValue);
|
|
18712
|
+
}
|
|
18713
|
+
return trimmedValue.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
18714
|
+
}
|
|
18715
|
+
function createTableCatalog() {
|
|
18716
|
+
const tables = /* @__PURE__ */ new Map();
|
|
18717
|
+
const ensureTable = (schema, name) => {
|
|
18718
|
+
const id = tableKey2(schema, name);
|
|
18719
|
+
const existingTable = tables.get(id);
|
|
18720
|
+
if (existingTable) {
|
|
18721
|
+
return existingTable;
|
|
18722
|
+
}
|
|
18723
|
+
const nextTable = {
|
|
18724
|
+
columns: [],
|
|
18725
|
+
id,
|
|
18726
|
+
name,
|
|
18727
|
+
primaryKey: [],
|
|
18728
|
+
relationMap: /* @__PURE__ */ new Map(),
|
|
18729
|
+
schema
|
|
18730
|
+
};
|
|
18731
|
+
tables.set(id, nextTable);
|
|
18732
|
+
return nextTable;
|
|
18733
|
+
};
|
|
18734
|
+
const upsertRelation = (table2, key, relation) => {
|
|
18735
|
+
table2.relationMap.set(key, relation);
|
|
18736
|
+
};
|
|
18737
|
+
return {
|
|
18738
|
+
addColumnRows(columnRows) {
|
|
18739
|
+
for (const row of columnRows) {
|
|
18740
|
+
const table2 = ensureTable(row.schema_name, row.table_name);
|
|
18741
|
+
table2.columns.push({
|
|
18742
|
+
dataType: row.data_type,
|
|
18743
|
+
isNullable: row.is_nullable,
|
|
18744
|
+
isPrimaryKey: false,
|
|
18745
|
+
name: row.column_name
|
|
18746
|
+
});
|
|
18747
|
+
}
|
|
18748
|
+
},
|
|
18749
|
+
addForeignKeyRows(foreignKeyRows) {
|
|
18750
|
+
for (const row of foreignKeyRows) {
|
|
18751
|
+
const sourceTable = ensureTable(row.source_schema, row.source_table);
|
|
18752
|
+
const targetTable = ensureTable(row.target_schema, row.target_table);
|
|
18753
|
+
upsertRelation(
|
|
18754
|
+
sourceTable,
|
|
18755
|
+
relationKey2(row.constraint_name, row.target_table),
|
|
18756
|
+
{
|
|
18757
|
+
name: row.constraint_name,
|
|
18758
|
+
targetSchema: row.target_schema,
|
|
18759
|
+
targetTable: row.target_table
|
|
18760
|
+
}
|
|
18761
|
+
);
|
|
18762
|
+
upsertRelation(targetTable, relationKey2(row.source_table), {
|
|
18763
|
+
name: relationKey2(row.source_table, row.constraint_name),
|
|
18764
|
+
targetSchema: row.source_schema,
|
|
18765
|
+
targetTable: row.source_table
|
|
18766
|
+
});
|
|
18767
|
+
}
|
|
18768
|
+
},
|
|
18769
|
+
addManyToManyRows(foreignKeyRows) {
|
|
18770
|
+
const foreignKeysBySourceTable = /* @__PURE__ */ new Map();
|
|
18771
|
+
for (const foreignKey of foreignKeyRows) {
|
|
18772
|
+
const key = tableKey2(foreignKey.source_schema, foreignKey.source_table);
|
|
18773
|
+
const current = foreignKeysBySourceTable.get(key) ?? {
|
|
18774
|
+
foreignKeys: [],
|
|
18775
|
+
schema: foreignKey.source_schema,
|
|
18776
|
+
table: foreignKey.source_table
|
|
18777
|
+
};
|
|
18778
|
+
current.foreignKeys.push(foreignKey);
|
|
18779
|
+
foreignKeysBySourceTable.set(key, current);
|
|
18780
|
+
}
|
|
18781
|
+
for (const candidate of foreignKeysBySourceTable.values()) {
|
|
18782
|
+
const bridgeTable = tables.get(
|
|
18783
|
+
tableKey2(candidate.schema, candidate.table)
|
|
18784
|
+
);
|
|
18785
|
+
if (!bridgeTable || candidate.foreignKeys.length !== 2) {
|
|
18786
|
+
continue;
|
|
18787
|
+
}
|
|
18788
|
+
const combinedForeignColumns = Array.from(
|
|
18789
|
+
new Set(
|
|
18790
|
+
candidate.foreignKeys.flatMap(
|
|
18791
|
+
(foreignKey) => coerceStringArray2(foreignKey.source_columns)
|
|
18792
|
+
)
|
|
18793
|
+
)
|
|
18794
|
+
);
|
|
18795
|
+
if (bridgeTable.primaryKey.length === 0 || combinedForeignColumns.length !== bridgeTable.primaryKey.length || !bridgeTable.primaryKey.every(
|
|
18796
|
+
(column) => combinedForeignColumns.includes(column)
|
|
18797
|
+
)) {
|
|
18798
|
+
continue;
|
|
18799
|
+
}
|
|
18800
|
+
const [firstForeignKey, secondForeignKey] = candidate.foreignKeys;
|
|
18801
|
+
const firstTarget = tables.get(
|
|
18802
|
+
tableKey2(firstForeignKey.target_schema, firstForeignKey.target_table)
|
|
18803
|
+
);
|
|
18804
|
+
const secondTarget = tables.get(
|
|
18805
|
+
tableKey2(
|
|
18806
|
+
secondForeignKey.target_schema,
|
|
18807
|
+
secondForeignKey.target_table
|
|
18808
|
+
)
|
|
18809
|
+
);
|
|
18810
|
+
if (!(firstTarget && secondTarget)) {
|
|
18811
|
+
continue;
|
|
18812
|
+
}
|
|
18813
|
+
upsertRelation(
|
|
18814
|
+
firstTarget,
|
|
18815
|
+
relationKey2(candidate.table, secondForeignKey.target_table),
|
|
18816
|
+
{
|
|
18817
|
+
name: relationKey2(
|
|
18818
|
+
candidate.table,
|
|
18819
|
+
secondForeignKey.constraint_name
|
|
18820
|
+
),
|
|
18821
|
+
targetSchema: secondForeignKey.target_schema,
|
|
18822
|
+
targetTable: secondForeignKey.target_table
|
|
18823
|
+
}
|
|
18824
|
+
);
|
|
18825
|
+
upsertRelation(
|
|
18826
|
+
secondTarget,
|
|
18827
|
+
relationKey2(candidate.table, firstForeignKey.target_table),
|
|
18828
|
+
{
|
|
18829
|
+
name: relationKey2(candidate.table, firstForeignKey.constraint_name),
|
|
18830
|
+
targetSchema: firstForeignKey.target_schema,
|
|
18831
|
+
targetTable: firstForeignKey.target_table
|
|
18832
|
+
}
|
|
18833
|
+
);
|
|
18834
|
+
}
|
|
18835
|
+
},
|
|
18836
|
+
addPrimaryKeyRows(primaryKeyRows) {
|
|
18837
|
+
for (const row of primaryKeyRows) {
|
|
18838
|
+
const table2 = ensureTable(row.schema_name, row.table_name);
|
|
18839
|
+
const primaryKey = coerceStringArray2(row.columns);
|
|
18840
|
+
table2.primaryKey = primaryKey;
|
|
18841
|
+
for (const columnName of primaryKey) {
|
|
18842
|
+
const column = table2.columns.find(
|
|
18843
|
+
(candidate) => candidate.name === columnName
|
|
18844
|
+
);
|
|
18845
|
+
if (column) {
|
|
18846
|
+
column.isPrimaryKey = true;
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
}
|
|
18850
|
+
},
|
|
18851
|
+
toResponse(database) {
|
|
18852
|
+
return {
|
|
18853
|
+
database,
|
|
18854
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18855
|
+
tables: [...tables.values()].map((table2) => ({
|
|
18856
|
+
columns: [...table2.columns].sort(
|
|
18857
|
+
(left, right) => left.name.localeCompare(right.name)
|
|
18858
|
+
),
|
|
18859
|
+
id: table2.id,
|
|
18860
|
+
name: table2.name,
|
|
18861
|
+
primaryKey: [...table2.primaryKey],
|
|
18862
|
+
relations: [...table2.relationMap.values()].map((relation) => ({
|
|
18863
|
+
columns: tables.get(
|
|
18864
|
+
tableKey2(relation.targetSchema, relation.targetTable)
|
|
18865
|
+
)?.columns ?? [],
|
|
18866
|
+
name: relation.name,
|
|
18867
|
+
targetSchema: relation.targetSchema,
|
|
18868
|
+
targetTable: relation.targetTable
|
|
18869
|
+
})).sort(
|
|
18870
|
+
(left, right) => left.name.localeCompare(right.name)
|
|
18871
|
+
),
|
|
18872
|
+
schema: table2.schema
|
|
18873
|
+
})).sort(
|
|
18874
|
+
(left, right) => left.id.localeCompare(right.id)
|
|
18875
|
+
)
|
|
18876
|
+
};
|
|
18877
|
+
}
|
|
18878
|
+
};
|
|
18879
|
+
}
|
|
18880
|
+
async function queryRows(client, query) {
|
|
18881
|
+
const result = await client.query(query);
|
|
18882
|
+
if (result.error || result.status < 200 || result.status >= 300) {
|
|
18883
|
+
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}.`;
|
|
18884
|
+
throw new Error(errorMessage);
|
|
18885
|
+
}
|
|
18886
|
+
return Array.isArray(result.data) ? result.data : [];
|
|
18887
|
+
}
|
|
18888
|
+
function isAthenaTableSchemaConfig(value) {
|
|
18889
|
+
if (typeof value !== "object" || value === null) {
|
|
18890
|
+
return false;
|
|
18891
|
+
}
|
|
18892
|
+
const config = value;
|
|
18893
|
+
return typeof config.gatewayUrl === "string" && typeof config.gatewayKey === "string" && typeof config.gatewayDatabase === "string" && typeof config.schemaScope === "string" && typeof config.clientName === "string";
|
|
18894
|
+
}
|
|
18895
|
+
function hasAthenaTableSchemaCredentials(config) {
|
|
18896
|
+
return config.gatewayUrl.trim().length > 0 && config.gatewayKey.trim().length > 0 && config.gatewayDatabase.trim().length > 0;
|
|
18897
|
+
}
|
|
18898
|
+
async function fetchAthenaTableCatalog(config, options = {}) {
|
|
18899
|
+
const schemas = parseAthenaTableSchemaScope(config.schemaScope);
|
|
18900
|
+
if (schemas.length === 0) {
|
|
18901
|
+
return {
|
|
18902
|
+
database: config.gatewayDatabase,
|
|
18903
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18904
|
+
tables: []
|
|
18905
|
+
};
|
|
18906
|
+
}
|
|
18907
|
+
const queries = buildAthenaTableCatalogQueries(schemas);
|
|
18908
|
+
const client = options.client ?? createClient({
|
|
18909
|
+
url: config.gatewayUrl.trim(),
|
|
18910
|
+
key: config.gatewayKey.trim(),
|
|
18911
|
+
client: config.clientName.trim() || void 0
|
|
18912
|
+
});
|
|
18913
|
+
const [columnRows, primaryKeyRows, foreignKeyRows] = await Promise.all([
|
|
18914
|
+
queryRows(client, queries.columns),
|
|
18915
|
+
queryRows(client, queries.primaryKeys),
|
|
18916
|
+
queryRows(client, queries.foreignKeys)
|
|
18917
|
+
]);
|
|
18918
|
+
const catalog = createTableCatalog();
|
|
18919
|
+
catalog.addColumnRows(columnRows);
|
|
18920
|
+
catalog.addPrimaryKeyRows(primaryKeyRows);
|
|
18921
|
+
catalog.addForeignKeyRows(foreignKeyRows);
|
|
18922
|
+
catalog.addManyToManyRows(foreignKeyRows);
|
|
18923
|
+
return catalog.toResponse(config.gatewayDatabase);
|
|
18924
|
+
}
|
|
18925
|
+
var fetchTableCatalog = fetchAthenaTableCatalog;
|
|
18926
|
+
|
|
18927
|
+
// src/tables/schema-handlers.ts
|
|
18928
|
+
var ATHENA_TABLE_SCHEMA_ROUTE = "/api/tables/schema";
|
|
18929
|
+
function json2(body, init) {
|
|
18930
|
+
const headers = new Headers(init?.headers);
|
|
18931
|
+
if (!headers.has("content-type")) {
|
|
18932
|
+
headers.set("content-type", "application/json; charset=utf-8");
|
|
18933
|
+
}
|
|
18934
|
+
return new Response(JSON.stringify(body), {
|
|
18935
|
+
status: init?.status ?? 200,
|
|
18936
|
+
headers
|
|
18937
|
+
});
|
|
18938
|
+
}
|
|
18939
|
+
async function handleAthenaTableSchemaPost(request2, options) {
|
|
18940
|
+
const payload = await request2.json().catch(() => null);
|
|
18941
|
+
let config = isAthenaTableSchemaConfig(
|
|
18942
|
+
payload?.config
|
|
18943
|
+
) ? payload.config : null;
|
|
18944
|
+
if (config && options?.resolveConfig) {
|
|
18945
|
+
config = await options.resolveConfig(config, request2);
|
|
18946
|
+
}
|
|
18947
|
+
if (!config || !isAthenaTableSchemaConfig(config)) {
|
|
18948
|
+
return json2(
|
|
18949
|
+
{
|
|
18950
|
+
error: "The Athena tables showcase config is invalid."
|
|
18951
|
+
},
|
|
18952
|
+
{ status: 400 }
|
|
18953
|
+
);
|
|
18954
|
+
}
|
|
18955
|
+
if (!hasAthenaTableSchemaCredentials(config)) {
|
|
18956
|
+
return json2(
|
|
18957
|
+
{
|
|
18958
|
+
error: "Gateway URL, API key, and database are required for schema introspection."
|
|
18959
|
+
},
|
|
18960
|
+
{ status: 400 }
|
|
18961
|
+
);
|
|
18962
|
+
}
|
|
18963
|
+
try {
|
|
18964
|
+
const response = await fetchAthenaTableCatalog(
|
|
18965
|
+
config,
|
|
18966
|
+
{
|
|
18967
|
+
client: options?.client
|
|
18968
|
+
}
|
|
18969
|
+
);
|
|
18970
|
+
return json2(response);
|
|
18971
|
+
} catch (error) {
|
|
18972
|
+
return json2(
|
|
18973
|
+
{
|
|
18974
|
+
error: error instanceof Error ? error.message : "Athena schema introspection failed."
|
|
18975
|
+
},
|
|
18976
|
+
{ status: 500 }
|
|
18977
|
+
);
|
|
18978
|
+
}
|
|
18979
|
+
}
|
|
18980
|
+
function createAthenaTableSchemaHandlers(options) {
|
|
18981
|
+
return {
|
|
18982
|
+
POST: (request2) => handleAthenaTableSchemaPost(request2, options)
|
|
18983
|
+
};
|
|
18984
|
+
}
|
|
18985
|
+
|
|
15489
18986
|
exports.ATHENA_AUTH_ADMIN_LIMITS = ATHENA_AUTH_ADMIN_LIMITS;
|
|
15490
18987
|
exports.ATHENA_AUTH_BASE_ERROR_CODES = ATHENA_AUTH_BASE_ERROR_CODES;
|
|
15491
18988
|
exports.ATHENA_AUTH_MAX_ADMIN_JSON_BYTES = ATHENA_AUTH_MAX_ADMIN_JSON_BYTES;
|
|
15492
18989
|
exports.ATHENA_AUTH_MAX_ADMIN_JSON_DEPTH = ATHENA_AUTH_MAX_ADMIN_JSON_DEPTH;
|
|
15493
18990
|
exports.ATHENA_AUTH_MAX_TEMPLATE_VARIABLES = ATHENA_AUTH_MAX_TEMPLATE_VARIABLES;
|
|
15494
18991
|
exports.ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH = ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH;
|
|
18992
|
+
exports.ATHENA_TABLE_SCHEMA_ROUTE = ATHENA_TABLE_SCHEMA_ROUTE;
|
|
15495
18993
|
exports.AthenaBillingError = AthenaBillingError;
|
|
15496
18994
|
exports.AthenaChatError = AthenaChatError;
|
|
15497
18995
|
exports.AthenaConfigurationError = AthenaConfigurationError;
|
|
@@ -15520,6 +19018,7 @@ exports.buildAthenaReadQueryFindManyOrderBy = buildAthenaReadQueryFindManyOrderB
|
|
|
15520
19018
|
exports.buildAthenaReadQueryFindManySelect = buildAthenaReadQueryFindManySelect;
|
|
15521
19019
|
exports.buildAthenaReadQueryFindManyWhere = buildAthenaReadQueryFindManyWhere;
|
|
15522
19020
|
exports.buildAthenaReadQuerySelectString = buildAthenaReadQuerySelectString;
|
|
19021
|
+
exports.buildAthenaTableCatalogQueries = buildAthenaTableCatalogQueries;
|
|
15523
19022
|
exports.buildAthenaTableFindManyOrderBy = buildAthenaTableFindManyOrderBy;
|
|
15524
19023
|
exports.buildAthenaTableFindManySelect = buildAthenaTableFindManySelect;
|
|
15525
19024
|
exports.buildAthenaTableFindManyWhere = buildAthenaTableFindManyWhere;
|
|
@@ -15529,6 +19028,7 @@ exports.clampAthenaReadQueryTotalItems = clampAthenaReadQueryTotalItems;
|
|
|
15529
19028
|
exports.clampAthenaTableTotalItems = clampAthenaTableTotalItems;
|
|
15530
19029
|
exports.coerceInt = coerceInt;
|
|
15531
19030
|
exports.createAthenaStorageError = createAthenaStorageError;
|
|
19031
|
+
exports.createAthenaTableSchemaHandlers = createAthenaTableSchemaHandlers;
|
|
15532
19032
|
exports.createAuthReactEmailInput = createAuthReactEmailInput;
|
|
15533
19033
|
exports.createBillingModule = createBillingModule;
|
|
15534
19034
|
exports.createClient = createClient;
|
|
@@ -15549,6 +19049,8 @@ exports.ensureGeneratorConfigFile = ensureGeneratorConfigFile;
|
|
|
15549
19049
|
exports.enumeration = enumeration;
|
|
15550
19050
|
exports.executeAthenaReadQuery = executeAthenaReadQuery;
|
|
15551
19051
|
exports.executeAthenaTableQuery = executeAthenaTableQuery;
|
|
19052
|
+
exports.fetchAthenaTableCatalog = fetchAthenaTableCatalog;
|
|
19053
|
+
exports.fetchTableCatalog = fetchTableCatalog;
|
|
15552
19054
|
exports.filterIntrospectionSnapshot = filterIntrospectionSnapshot;
|
|
15553
19055
|
exports.findGeneratorConfigPath = findGeneratorConfigPath;
|
|
15554
19056
|
exports.flattenAthenaReadQueryRows = flattenAthenaReadQueryRows;
|
|
@@ -15556,8 +19058,11 @@ exports.flattenAthenaRows = flattenAthenaRows;
|
|
|
15556
19058
|
exports.generateArtifactsFromSnapshot = generateArtifactsFromSnapshot;
|
|
15557
19059
|
exports.generatorEnv = generatorEnv;
|
|
15558
19060
|
exports.getAthenaDebugAst = getAthenaDebugAst;
|
|
19061
|
+
exports.handleAthenaTableSchemaPost = handleAthenaTableSchemaPost;
|
|
19062
|
+
exports.hasAthenaTableSchemaCredentials = hasAthenaTableSchemaCredentials;
|
|
15559
19063
|
exports.identifier = identifier;
|
|
15560
19064
|
exports.isAthenaGatewayError = isAthenaGatewayError;
|
|
19065
|
+
exports.isAthenaTableSchemaConfig = isAthenaTableSchemaConfig;
|
|
15561
19066
|
exports.isOk = isOk;
|
|
15562
19067
|
exports.json = json;
|
|
15563
19068
|
exports.loadGeneratorConfig = loadGeneratorConfig;
|
|
@@ -15571,12 +19076,15 @@ exports.normalizeGeneratorConfig = normalizeGeneratorConfig;
|
|
|
15571
19076
|
exports.normalizeSchemaSelection = normalizeSchemaSelection;
|
|
15572
19077
|
exports.normalizeTableSelection = normalizeTableSelection;
|
|
15573
19078
|
exports.number = number;
|
|
19079
|
+
exports.parseAthenaTableSchemaScope = parseAthenaTableSchemaScope;
|
|
15574
19080
|
exports.parseBooleanFlag = parseBooleanFlag2;
|
|
15575
19081
|
exports.patchSchemasInConfigSource = patchSchemasInConfigSource;
|
|
15576
19082
|
exports.renderAthenaReactEmail = renderAthenaReactEmail;
|
|
15577
19083
|
exports.renderGeneratorConfigFile = renderGeneratorConfigFile;
|
|
15578
19084
|
exports.requireAffected = requireAffected;
|
|
15579
19085
|
exports.requireSuccess = requireSuccess;
|
|
19086
|
+
exports.resolveAthenaExecutionMode = resolveAthenaExecutionMode;
|
|
19087
|
+
exports.resolveAthenaReadQueryPageFetch = resolveAthenaReadQueryPageFetch;
|
|
15580
19088
|
exports.resolveGeneratorProvider = resolveGeneratorProvider;
|
|
15581
19089
|
exports.resolvePostgresColumnType = resolvePostgresColumnType;
|
|
15582
19090
|
exports.resolveProviderSchemas = resolveProviderSchemas;
|