@xylex-group/athena 3.0.3 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -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-DzimbvOA.d.ts} +48 -200
- package/dist/{athena-request-headers-DujFFyMU.d.cts → athena-request-headers-Lr_m8xCV.d.cts} +48 -200
- 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 +912 -5
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +8 -7
- package/dist/browser.d.ts +8 -7
- package/dist/browser.js +881 -6
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +7909 -7061
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +17 -10
- package/dist/cli/index.d.ts +17 -10
- package/dist/cli/index.js +7911 -7063
- package/dist/cli/index.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 +1570 -98
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -8
- package/dist/index.d.ts +31 -8
- package/dist/index.js +1532 -100
- package/dist/index.js.map +1 -1
- package/dist/model-form-3Gr8rkdT.d.cts +281 -0
- package/dist/model-form-CotpEL7z.d.ts +281 -0
- package/dist/{module-CPG3ULxQ.d.cts → module-CQmOaDzP.d.cts} +4 -4
- package/dist/{module-BruTcxe0.d.ts → module-CWkUTcUc.d.ts} +4 -4
- package/dist/next/client.cjs +123 -7
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.d.cts +4 -3
- package/dist/next/client.d.ts +4 -3
- package/dist/next/client.js +123 -7
- package/dist/next/client.js.map +1 -1
- package/dist/next/server.cjs +1130 -364
- package/dist/next/server.cjs.map +1 -1
- package/dist/next/server.d.cts +121 -8
- package/dist/next/server.d.ts +121 -8
- package/dist/next/server.js +1120 -365
- package/dist/next/server.js.map +1 -1
- package/dist/pipeline-BnRKO_Pd.d.cts +93 -0
- package/dist/pipeline-sWCmlFqu.d.ts +93 -0
- 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 +672 -16
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +123 -8
- package/dist/react.d.ts +123 -8
- package/dist/react.js +671 -17
- package/dist/react.js.map +1 -1
- package/dist/schema-handlers-BtT_IQFi.d.cts +138 -0
- package/dist/schema-handlers-VjFDhIMw.d.ts +138 -0
- package/dist/social-providers.d.cts +1 -1
- package/dist/social-providers.d.ts +1 -1
- package/dist/{types-D6tZ9aoq.d.ts → types-BDX8zS7w.d.ts} +40 -1
- 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-DFr2cL1N.d.cts → types-D-Am7YSd.d.cts} +40 -1
- package/dist/utils.cjs +30 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +3 -2
- package/dist/utils.d.ts +3 -2
- package/dist/utils.js +30 -1
- package/dist/utils.js.map +1 -1
- package/dist/{v3-client-CWfZHcKL.d.cts → v3-client-G1SLeHRa.d.cts} +23 -1
- package/dist/{v3-client-DZp2NEhK.d.ts → v3-client-ao8BWQ8v.d.ts} +23 -1
- package/package.json +16 -2
- package/dist/model-form-Dh0sisdL.d.ts +0 -97
- package/dist/model-form-oOAJUVd4.d.cts +0 -97
- package/dist/pipeline-CIzV9f7b.d.cts +0 -8
- package/dist/pipeline-DNlc8Ayn.d.ts +0 -8
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { existsSync, readFileSync } from 'fs';
|
|
3
3
|
import { resolve, dirname, posix } from 'path';
|
|
4
4
|
import { pathToFileURL } from 'url';
|
|
5
|
-
import { mkdir, writeFile,
|
|
5
|
+
import { mkdir, writeFile, readFile, stat } from 'fs/promises';
|
|
6
6
|
|
|
7
7
|
// src/gateway/errors.ts
|
|
8
8
|
var AthenaGatewayError = class _AthenaGatewayError extends Error {
|
|
@@ -571,8 +571,8 @@ function computeDelayMs(attempt, error, config) {
|
|
|
571
571
|
}
|
|
572
572
|
function sleep(ms) {
|
|
573
573
|
if (ms <= 0) return Promise.resolve();
|
|
574
|
-
return new Promise((
|
|
575
|
-
setTimeout(
|
|
574
|
+
return new Promise((resolve4) => {
|
|
575
|
+
setTimeout(resolve4, ms);
|
|
576
576
|
});
|
|
577
577
|
}
|
|
578
578
|
async function withRetry(config, fn) {
|
|
@@ -2007,7 +2007,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
|
|
|
2007
2007
|
|
|
2008
2008
|
// package.json
|
|
2009
2009
|
var package_default = {
|
|
2010
|
-
version: "3.0
|
|
2010
|
+
version: "3.3.0"
|
|
2011
2011
|
};
|
|
2012
2012
|
|
|
2013
2013
|
// src/sdk-version.ts
|
|
@@ -4767,6 +4767,14 @@ function createAuthModule(config = {}, runtimeOptions = {}) {
|
|
|
4767
4767
|
changeEmailVerify: (input, options) => getWithQuery("/change-email/verify", input, options),
|
|
4768
4768
|
deleteUserVerify: (input, options) => getWithQuery("/delete-user/verify", input, options),
|
|
4769
4769
|
changePassword: (input, options) => postGeneric("/change-password", input, options),
|
|
4770
|
+
// Better Auth UI flat method aliases (also nested under session/account/social/user).
|
|
4771
|
+
listSessions: (input, options) => getGeneric("/list-sessions", input, options),
|
|
4772
|
+
revokeSession: sessionRevokeBinding,
|
|
4773
|
+
revokeOtherSessions,
|
|
4774
|
+
listAccounts: (input, options) => getGeneric("/list-accounts", input, options),
|
|
4775
|
+
unlinkAccount: (input, options) => postGeneric("/unlink-account", input, options),
|
|
4776
|
+
linkSocial: (input, options) => postGeneric("/link-social", input, options),
|
|
4777
|
+
updateUser: (input, options) => postGeneric("/update-user", input, options),
|
|
4770
4778
|
user: {
|
|
4771
4779
|
update: (input, options) => postGeneric("/update-user", input, options),
|
|
4772
4780
|
delete: (input, options) => postGeneric("/delete-user", input, options),
|
|
@@ -5226,7 +5234,7 @@ async function putWithXhr(url, signed, body, signal, onProgress) {
|
|
|
5226
5234
|
if (Xhr === void 0) {
|
|
5227
5235
|
return Promise.reject(new Error("athena.storage.file.upload direct mode requires XMLHttpRequest in this runtime"));
|
|
5228
5236
|
}
|
|
5229
|
-
return new Promise((
|
|
5237
|
+
return new Promise((resolve4, reject) => {
|
|
5230
5238
|
const xhr = new Xhr();
|
|
5231
5239
|
const abort = () => xhr.abort();
|
|
5232
5240
|
xhr.open("PUT", url);
|
|
@@ -5239,7 +5247,7 @@ async function putWithXhr(url, signed, body, signal, onProgress) {
|
|
|
5239
5247
|
return;
|
|
5240
5248
|
}
|
|
5241
5249
|
onProgress({ loaded: bodySize(body) });
|
|
5242
|
-
|
|
5250
|
+
resolve4(new Response(xhr.response, {
|
|
5243
5251
|
status: xhr.status,
|
|
5244
5252
|
statusText: xhr.statusText,
|
|
5245
5253
|
headers: parseXhrHeaders(xhr.getAllResponseHeaders())
|
|
@@ -5692,7 +5700,7 @@ function putUploadBodyWithXhr(url, source, headers, options, onProgress) {
|
|
|
5692
5700
|
if (Xhr === void 0) {
|
|
5693
5701
|
return Promise.reject(new Error("athena.storage.file.upload requires XMLHttpRequest in this runtime"));
|
|
5694
5702
|
}
|
|
5695
|
-
return new Promise((
|
|
5703
|
+
return new Promise((resolve4, reject) => {
|
|
5696
5704
|
const xhr = new Xhr();
|
|
5697
5705
|
const abort = () => xhr.abort();
|
|
5698
5706
|
xhr.open("PUT", url);
|
|
@@ -5709,7 +5717,7 @@ function putUploadBodyWithXhr(url, source, headers, options, onProgress) {
|
|
|
5709
5717
|
return;
|
|
5710
5718
|
}
|
|
5711
5719
|
onProgress({ loaded: source.sizeBytes });
|
|
5712
|
-
|
|
5720
|
+
resolve4(new Response(xhr.response, {
|
|
5713
5721
|
status: xhr.status,
|
|
5714
5722
|
statusText: xhr.statusText,
|
|
5715
5723
|
headers: parseXhrHeaders2(xhr.getAllResponseHeaders())
|
|
@@ -10576,6 +10584,82 @@ function mergeAthenaRequestContexts(base, override) {
|
|
|
10576
10584
|
};
|
|
10577
10585
|
}
|
|
10578
10586
|
|
|
10587
|
+
// src/diagnostics.ts
|
|
10588
|
+
function readProcessEnv2() {
|
|
10589
|
+
try {
|
|
10590
|
+
return globalThis.process?.env ?? {};
|
|
10591
|
+
} catch {
|
|
10592
|
+
return {};
|
|
10593
|
+
}
|
|
10594
|
+
}
|
|
10595
|
+
function isTruthyEnv(value) {
|
|
10596
|
+
if (!value) return false;
|
|
10597
|
+
const normalized = value.trim().toLowerCase();
|
|
10598
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
10599
|
+
}
|
|
10600
|
+
function isQuietAthenaDiagnosticsEnvironment(env = readProcessEnv2()) {
|
|
10601
|
+
const nodeEnv = env.NODE_ENV?.trim().toLowerCase();
|
|
10602
|
+
if (nodeEnv === "production") {
|
|
10603
|
+
return true;
|
|
10604
|
+
}
|
|
10605
|
+
if (isTruthyEnv(env.OPENNEXT_BUILD)) {
|
|
10606
|
+
return true;
|
|
10607
|
+
}
|
|
10608
|
+
const nextPhase = env.NEXT_PHASE?.trim();
|
|
10609
|
+
if (nextPhase === "phase-production-build") {
|
|
10610
|
+
return true;
|
|
10611
|
+
}
|
|
10612
|
+
if (isTruthyEnv(env.CI) && nodeEnv !== "test") {
|
|
10613
|
+
if (nodeEnv === "production" || isTruthyEnv(env.OPENNEXT_BUILD)) {
|
|
10614
|
+
return true;
|
|
10615
|
+
}
|
|
10616
|
+
}
|
|
10617
|
+
return false;
|
|
10618
|
+
}
|
|
10619
|
+
function resolveBooleanFlag(explicit, mode, quiet) {
|
|
10620
|
+
if (typeof explicit === "boolean") {
|
|
10621
|
+
return explicit;
|
|
10622
|
+
}
|
|
10623
|
+
if (mode === true) {
|
|
10624
|
+
return true;
|
|
10625
|
+
}
|
|
10626
|
+
if (mode === false) {
|
|
10627
|
+
return false;
|
|
10628
|
+
}
|
|
10629
|
+
if (mode === "auto") {
|
|
10630
|
+
return false;
|
|
10631
|
+
}
|
|
10632
|
+
return false;
|
|
10633
|
+
}
|
|
10634
|
+
function resolveAthenaClientDiagnostics(input) {
|
|
10635
|
+
const env = input.env ?? readProcessEnv2();
|
|
10636
|
+
const quiet = isQuietAthenaDiagnosticsEnvironment(env);
|
|
10637
|
+
const mode = input.diagnostics;
|
|
10638
|
+
const effectiveMode = mode === "auto" && quiet ? false : mode;
|
|
10639
|
+
const debugAst = resolveBooleanFlag(input.debugAst, effectiveMode);
|
|
10640
|
+
const findManyAst = resolveBooleanFlag(input.findManyAst, effectiveMode);
|
|
10641
|
+
let traceQueries;
|
|
10642
|
+
if (input.traceQueries !== void 0) {
|
|
10643
|
+
if (typeof input.traceQueries === "boolean") {
|
|
10644
|
+
traceQueries = input.traceQueries;
|
|
10645
|
+
} else if (effectiveMode === false || mode === "auto" && quiet) {
|
|
10646
|
+
const enabled = input.traceQueries.enabled;
|
|
10647
|
+
traceQueries = typeof enabled === "boolean" ? enabled ? input.traceQueries : false : false;
|
|
10648
|
+
} else {
|
|
10649
|
+
traceQueries = input.traceQueries;
|
|
10650
|
+
}
|
|
10651
|
+
} else if (effectiveMode === true) {
|
|
10652
|
+
traceQueries = true;
|
|
10653
|
+
} else {
|
|
10654
|
+
traceQueries = false;
|
|
10655
|
+
}
|
|
10656
|
+
return {
|
|
10657
|
+
debugAst,
|
|
10658
|
+
findManyAst,
|
|
10659
|
+
traceQueries
|
|
10660
|
+
};
|
|
10661
|
+
}
|
|
10662
|
+
|
|
10579
10663
|
// src/v3-client.ts
|
|
10580
10664
|
var ENV_URL_KEYS = ["ATHENA_URL", "NEXT_PUBLIC_ATHENA_URL"];
|
|
10581
10665
|
var ENV_DB_URL_KEYS = ["ATHENA_DB_URL", "ATHENA_GATEWAY_URL", "NEXT_PUBLIC_ATHENA_DB_API_URL"];
|
|
@@ -10584,7 +10668,13 @@ var ENV_CHAT_URL_KEYS = ["ATHENA_CHAT_URL", "NEXT_PUBLIC_ATHENA_CHAT_URL"];
|
|
|
10584
10668
|
var ENV_CHAT_WS_URL_KEYS = ["ATHENA_CHAT_WS_URL", "NEXT_PUBLIC_ATHENA_CHAT_WS_URL"];
|
|
10585
10669
|
var ENV_STORAGE_URL_KEYS = ["ATHENA_STORAGE_URL", "NEXT_PUBLIC_ATHENA_STORAGE_URL"];
|
|
10586
10670
|
var ENV_KEY_KEYS = ["ATHENA_API_KEY", "NEXT_PUBLIC_ATHENA_API_KEY", "ATHENA_GATEWAY_API_KEY", "X_API_KEY"];
|
|
10587
|
-
var ENV_CLIENT_KEYS = [
|
|
10671
|
+
var ENV_CLIENT_KEYS = [
|
|
10672
|
+
"ATHENA_CLIENT",
|
|
10673
|
+
"ATHENA_GATEWAY_CLIENT",
|
|
10674
|
+
"ATHENA_GENERATOR_CLIENT",
|
|
10675
|
+
"NEXT_PUBLIC_ATHENA_CLIENT",
|
|
10676
|
+
"NEXT_PUBLIC_ATHENA_GATEWAY_CLIENT"
|
|
10677
|
+
];
|
|
10588
10678
|
var MISSING_DB_SENTINEL = "https://athena.invalid/db";
|
|
10589
10679
|
function readFirstEnv(env, keys) {
|
|
10590
10680
|
for (const key of keys) {
|
|
@@ -10659,6 +10749,13 @@ function createInternalConfig(core) {
|
|
|
10659
10749
|
const { config, urls } = core;
|
|
10660
10750
|
const { url: _authUrl, ...authOptions } = config.auth ?? {};
|
|
10661
10751
|
const { url: _storageUrl, directUpload, ...storageOptions } = config.storage ?? {};
|
|
10752
|
+
const diagnostics = resolveAthenaClientDiagnostics({
|
|
10753
|
+
diagnostics: config.diagnostics,
|
|
10754
|
+
debugAst: config.debugAst,
|
|
10755
|
+
findManyAst: config.findManyAst,
|
|
10756
|
+
traceQueries: config.traceQueries,
|
|
10757
|
+
env: config.env
|
|
10758
|
+
});
|
|
10662
10759
|
return {
|
|
10663
10760
|
baseUrl: urls.db ?? MISSING_DB_SENTINEL,
|
|
10664
10761
|
apiKey: core.key,
|
|
@@ -10675,9 +10772,9 @@ function createInternalConfig(core) {
|
|
|
10675
10772
|
models: config.models,
|
|
10676
10773
|
behavior: {
|
|
10677
10774
|
retryReads: config.retryReads,
|
|
10678
|
-
traceQueries:
|
|
10679
|
-
debugAst:
|
|
10680
|
-
findManyAst:
|
|
10775
|
+
traceQueries: diagnostics.traceQueries,
|
|
10776
|
+
debugAst: diagnostics.debugAst,
|
|
10777
|
+
findManyAst: diagnostics.findManyAst
|
|
10681
10778
|
},
|
|
10682
10779
|
storage: {
|
|
10683
10780
|
...storageOptions,
|
|
@@ -10751,11 +10848,30 @@ function createClientView(core, viewContext) {
|
|
|
10751
10848
|
return resolved.verifyConnection(options);
|
|
10752
10849
|
},
|
|
10753
10850
|
withContext(context) {
|
|
10851
|
+
warnIfEmptyRequestContext(context);
|
|
10754
10852
|
return createClientView(core, mergeAthenaRequestContexts(viewContext, context));
|
|
10755
10853
|
}
|
|
10756
10854
|
};
|
|
10757
10855
|
return Object.freeze(client);
|
|
10758
10856
|
}
|
|
10857
|
+
function isEmptyAthenaRequestContext(context) {
|
|
10858
|
+
if (!context) return true;
|
|
10859
|
+
const hasHeaders = context.headers != null && Object.keys(context.headers).length > 0;
|
|
10860
|
+
return context.userId == null && context.organizationId == null && !normalizeOptionalContextString(context.cookie) && !normalizeOptionalContextString(context.bearerToken) && !normalizeOptionalContextString(context.sessionToken) && !context.forceNoCache && !hasHeaders;
|
|
10861
|
+
}
|
|
10862
|
+
function normalizeOptionalContextString(value) {
|
|
10863
|
+
const trimmed = value?.trim();
|
|
10864
|
+
return trimmed || void 0;
|
|
10865
|
+
}
|
|
10866
|
+
function warnIfEmptyRequestContext(context) {
|
|
10867
|
+
if (!isEmptyAthenaRequestContext(context)) return;
|
|
10868
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
10869
|
+
return;
|
|
10870
|
+
}
|
|
10871
|
+
console.warn(
|
|
10872
|
+
"[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 })."
|
|
10873
|
+
);
|
|
10874
|
+
}
|
|
10759
10875
|
function createClient(config) {
|
|
10760
10876
|
return createClientView(resolveCore(config));
|
|
10761
10877
|
}
|
|
@@ -10768,6 +10884,339 @@ var Backend = {
|
|
|
10768
10884
|
ScyllaDB: { type: "scylladb" }
|
|
10769
10885
|
};
|
|
10770
10886
|
|
|
10887
|
+
// src/query/read-query.ts
|
|
10888
|
+
function normalizeAthenaReadQueryOrderBy(orderBy) {
|
|
10889
|
+
if (!orderBy) {
|
|
10890
|
+
return [];
|
|
10891
|
+
}
|
|
10892
|
+
const list = Array.isArray(orderBy) ? orderBy : [orderBy];
|
|
10893
|
+
return list.filter(
|
|
10894
|
+
(entry) => entry && typeof entry.column === "string" && entry.column.trim().length > 0
|
|
10895
|
+
);
|
|
10896
|
+
}
|
|
10897
|
+
function isRecord12(value) {
|
|
10898
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10899
|
+
}
|
|
10900
|
+
function flattenAthenaRowValue(row, column) {
|
|
10901
|
+
if (!column.relation) {
|
|
10902
|
+
return row[column.column];
|
|
10903
|
+
}
|
|
10904
|
+
const relationValue = row[column.relation.name];
|
|
10905
|
+
if (Array.isArray(relationValue)) {
|
|
10906
|
+
return relationValue.map((entry) => isRecord12(entry) ? entry[column.column] : void 0).filter((entry) => entry !== void 0);
|
|
10907
|
+
}
|
|
10908
|
+
if (isRecord12(relationValue)) {
|
|
10909
|
+
return relationValue[column.column];
|
|
10910
|
+
}
|
|
10911
|
+
return void 0;
|
|
10912
|
+
}
|
|
10913
|
+
function resolveFlatRowKey(row, index, preferredKey) {
|
|
10914
|
+
const preferredValue = preferredKey && preferredKey in row ? row[preferredKey] : void 0;
|
|
10915
|
+
if (preferredValue !== void 0 && preferredValue !== null && `${preferredValue}`.trim().length > 0) {
|
|
10916
|
+
return String(preferredValue);
|
|
10917
|
+
}
|
|
10918
|
+
for (const [key, value] of Object.entries(row)) {
|
|
10919
|
+
if (key === "__rowKey") {
|
|
10920
|
+
continue;
|
|
10921
|
+
}
|
|
10922
|
+
if (value === void 0 || value === null) {
|
|
10923
|
+
continue;
|
|
10924
|
+
}
|
|
10925
|
+
if (Array.isArray(value)) {
|
|
10926
|
+
if (value.length > 0) {
|
|
10927
|
+
return `${key}-${value.join("-")}`;
|
|
10928
|
+
}
|
|
10929
|
+
continue;
|
|
10930
|
+
}
|
|
10931
|
+
const nextValue = String(value).trim();
|
|
10932
|
+
if (nextValue.length > 0) {
|
|
10933
|
+
return nextValue;
|
|
10934
|
+
}
|
|
10935
|
+
}
|
|
10936
|
+
return `row-${index + 1}`;
|
|
10937
|
+
}
|
|
10938
|
+
function flattenAthenaReadQueryRows(rows, columns, preferredKey) {
|
|
10939
|
+
return rows.map((entry, index) => {
|
|
10940
|
+
const sourceRow = isRecord12(entry) ? entry : {};
|
|
10941
|
+
const flatRow = columns.reduce(
|
|
10942
|
+
(currentRow, column) => {
|
|
10943
|
+
currentRow[column.key] = flattenAthenaRowValue(sourceRow, column);
|
|
10944
|
+
return currentRow;
|
|
10945
|
+
},
|
|
10946
|
+
{ __rowKey: "" }
|
|
10947
|
+
);
|
|
10948
|
+
flatRow.__rowKey = resolveFlatRowKey(flatRow, index, preferredKey);
|
|
10949
|
+
return flatRow;
|
|
10950
|
+
});
|
|
10951
|
+
}
|
|
10952
|
+
var flattenAthenaRows = flattenAthenaReadQueryRows;
|
|
10953
|
+
function buildAthenaReadQuerySelectString(columns) {
|
|
10954
|
+
const baseColumns = columns.filter((column) => !column.relation).map((column) => column.column);
|
|
10955
|
+
const relationGroups = /* @__PURE__ */ new Map();
|
|
10956
|
+
for (const column of columns) {
|
|
10957
|
+
if (!column.relation) {
|
|
10958
|
+
continue;
|
|
10959
|
+
}
|
|
10960
|
+
const groupKey = [
|
|
10961
|
+
column.relation.name,
|
|
10962
|
+
column.relation.schema ?? "",
|
|
10963
|
+
column.relation.table
|
|
10964
|
+
].join(":");
|
|
10965
|
+
const existingGroup = relationGroups.get(groupKey);
|
|
10966
|
+
if (existingGroup) {
|
|
10967
|
+
if (!existingGroup.columns.includes(column.column)) {
|
|
10968
|
+
existingGroup.columns.push(column.column);
|
|
10969
|
+
}
|
|
10970
|
+
continue;
|
|
10971
|
+
}
|
|
10972
|
+
relationGroups.set(groupKey, {
|
|
10973
|
+
columns: [column.column],
|
|
10974
|
+
relation: column.relation
|
|
10975
|
+
});
|
|
10976
|
+
}
|
|
10977
|
+
const relationColumns = [...relationGroups.values()].map(
|
|
10978
|
+
({ columns: relationColumns2, relation }) => {
|
|
10979
|
+
const relationTarget = relation.schema ? `${relation.schema}.${relation.table}` : relation.table;
|
|
10980
|
+
return `${relation.name}:${relationTarget}(${relationColumns2.join(",")})`;
|
|
10981
|
+
}
|
|
10982
|
+
);
|
|
10983
|
+
return [...baseColumns, ...relationColumns].join(",");
|
|
10984
|
+
}
|
|
10985
|
+
var buildAthenaTableSelectString = buildAthenaReadQuerySelectString;
|
|
10986
|
+
function buildAthenaReadQueryFindManySelect(columns) {
|
|
10987
|
+
const select = {};
|
|
10988
|
+
for (const column of columns) {
|
|
10989
|
+
if (!column.relation) {
|
|
10990
|
+
select[column.column] = true;
|
|
10991
|
+
continue;
|
|
10992
|
+
}
|
|
10993
|
+
const existingRelation = select[column.relation.name];
|
|
10994
|
+
if (existingRelation && existingRelation !== true && isRecord12(existingRelation.select)) {
|
|
10995
|
+
existingRelation.select[column.column] = true;
|
|
10996
|
+
continue;
|
|
10997
|
+
}
|
|
10998
|
+
select[column.relation.name] = {
|
|
10999
|
+
...column.relation.schema ? { schema: column.relation.schema } : {},
|
|
11000
|
+
select: {
|
|
11001
|
+
[column.column]: true
|
|
11002
|
+
}
|
|
11003
|
+
};
|
|
11004
|
+
}
|
|
11005
|
+
return select;
|
|
11006
|
+
}
|
|
11007
|
+
var buildAthenaTableFindManySelect = buildAthenaReadQueryFindManySelect;
|
|
11008
|
+
function buildAthenaReadQueryFindManyWhere(filters) {
|
|
11009
|
+
if (!filters?.length) {
|
|
11010
|
+
return;
|
|
11011
|
+
}
|
|
11012
|
+
return filters.reduce(
|
|
11013
|
+
(where, filter) => {
|
|
11014
|
+
const operator = filter.operator ?? "eq";
|
|
11015
|
+
where[filter.column] = operator === "eq" ? filter.value : { [operator]: filter.value };
|
|
11016
|
+
return where;
|
|
11017
|
+
},
|
|
11018
|
+
{}
|
|
11019
|
+
);
|
|
11020
|
+
}
|
|
11021
|
+
var buildAthenaTableFindManyWhere = buildAthenaReadQueryFindManyWhere;
|
|
11022
|
+
function buildAthenaReadQueryFindManyOrderBy(orderBy) {
|
|
11023
|
+
const normalized = normalizeAthenaReadQueryOrderBy(orderBy);
|
|
11024
|
+
if (normalized.length === 0) {
|
|
11025
|
+
return;
|
|
11026
|
+
}
|
|
11027
|
+
if (normalized.length === 1) {
|
|
11028
|
+
const primary = normalized[0];
|
|
11029
|
+
if (!primary) {
|
|
11030
|
+
return;
|
|
11031
|
+
}
|
|
11032
|
+
return {
|
|
11033
|
+
ascending: primary.direction !== "desc",
|
|
11034
|
+
column: primary.column
|
|
11035
|
+
};
|
|
11036
|
+
}
|
|
11037
|
+
return Object.fromEntries(
|
|
11038
|
+
normalized.map((entry) => [
|
|
11039
|
+
entry.column,
|
|
11040
|
+
entry.direction === "desc" ? "desc" : "asc"
|
|
11041
|
+
])
|
|
11042
|
+
);
|
|
11043
|
+
}
|
|
11044
|
+
var buildAthenaTableFindManyOrderBy = buildAthenaReadQueryFindManyOrderBy;
|
|
11045
|
+
var normalizeAthenaTableOrderBy = normalizeAthenaReadQueryOrderBy;
|
|
11046
|
+
function applyAthenaReadQueryFilters(queryBuilder, filters) {
|
|
11047
|
+
if (!filters?.length) {
|
|
11048
|
+
return queryBuilder;
|
|
11049
|
+
}
|
|
11050
|
+
return filters.reduce((currentBuilder, filter) => {
|
|
11051
|
+
const operator = filter.operator ?? "eq";
|
|
11052
|
+
const builderMethod = currentBuilder[operator];
|
|
11053
|
+
if (typeof builderMethod !== "function") {
|
|
11054
|
+
return currentBuilder;
|
|
11055
|
+
}
|
|
11056
|
+
return builderMethod.call(currentBuilder, filter.column, filter.value);
|
|
11057
|
+
}, queryBuilder);
|
|
11058
|
+
}
|
|
11059
|
+
var applyAthenaTableFilters = applyAthenaReadQueryFilters;
|
|
11060
|
+
function applyAthenaReadQuerySelectOrder(queryBuilder, orderBy) {
|
|
11061
|
+
const normalized = normalizeAthenaReadQueryOrderBy(orderBy);
|
|
11062
|
+
if (normalized.length === 0) {
|
|
11063
|
+
return queryBuilder;
|
|
11064
|
+
}
|
|
11065
|
+
return normalized.reduce(
|
|
11066
|
+
(builder, entry) => builder.order(entry.column, {
|
|
11067
|
+
ascending: entry.direction !== "desc"
|
|
11068
|
+
}),
|
|
11069
|
+
queryBuilder
|
|
11070
|
+
);
|
|
11071
|
+
}
|
|
11072
|
+
var applyAthenaTableSelectOrder = applyAthenaReadQuerySelectOrder;
|
|
11073
|
+
function applyAthenaReadQuerySelectLimit(queryBuilder, limit) {
|
|
11074
|
+
if (!limit || limit < 1) {
|
|
11075
|
+
return queryBuilder;
|
|
11076
|
+
}
|
|
11077
|
+
return queryBuilder.limit(limit);
|
|
11078
|
+
}
|
|
11079
|
+
var applyAthenaTableSelectLimit = applyAthenaReadQuerySelectLimit;
|
|
11080
|
+
function clampAthenaReadQueryTotalItems(totalItems, limit) {
|
|
11081
|
+
if (!limit || limit < 1) {
|
|
11082
|
+
return totalItems;
|
|
11083
|
+
}
|
|
11084
|
+
return Math.min(totalItems, limit);
|
|
11085
|
+
}
|
|
11086
|
+
var clampAthenaTableTotalItems = clampAthenaReadQueryTotalItems;
|
|
11087
|
+
function resolveCountValue(...candidates) {
|
|
11088
|
+
for (const candidate of candidates) {
|
|
11089
|
+
if (typeof candidate === "number" && Number.isFinite(candidate)) {
|
|
11090
|
+
return Math.max(0, Math.trunc(candidate));
|
|
11091
|
+
}
|
|
11092
|
+
}
|
|
11093
|
+
return 0;
|
|
11094
|
+
}
|
|
11095
|
+
function resolveTotalItemsFromPage({
|
|
11096
|
+
countCandidates,
|
|
11097
|
+
limit,
|
|
11098
|
+
page,
|
|
11099
|
+
pageSize,
|
|
11100
|
+
rowCount
|
|
11101
|
+
}) {
|
|
11102
|
+
const exactCount = resolveCountValue(...countCandidates);
|
|
11103
|
+
if (exactCount > 0) {
|
|
11104
|
+
return clampAthenaReadQueryTotalItems(exactCount, limit);
|
|
11105
|
+
}
|
|
11106
|
+
if (rowCount > 0) {
|
|
11107
|
+
const base = (page - 1) * pageSize + rowCount;
|
|
11108
|
+
const synthetic = rowCount >= pageSize ? base + 1 : base;
|
|
11109
|
+
return clampAthenaReadQueryTotalItems(synthetic, limit);
|
|
11110
|
+
}
|
|
11111
|
+
return clampAthenaReadQueryTotalItems(exactCount, limit);
|
|
11112
|
+
}
|
|
11113
|
+
function resolveAthenaReadQueryPageFetch({
|
|
11114
|
+
page,
|
|
11115
|
+
pageSize,
|
|
11116
|
+
limit
|
|
11117
|
+
}) {
|
|
11118
|
+
const safePage = Math.max(1, Math.trunc(page) || 1);
|
|
11119
|
+
const safePageSize = Math.max(1, Math.trunc(pageSize) || 1);
|
|
11120
|
+
if (!limit || limit < 1) {
|
|
11121
|
+
return { page: safePage, pageSize: safePageSize, shouldFetch: true };
|
|
11122
|
+
}
|
|
11123
|
+
const totalCap = Math.trunc(limit);
|
|
11124
|
+
const offset = (safePage - 1) * safePageSize;
|
|
11125
|
+
if (offset >= totalCap) {
|
|
11126
|
+
return { page: safePage, pageSize: safePageSize, shouldFetch: false };
|
|
11127
|
+
}
|
|
11128
|
+
return {
|
|
11129
|
+
page: safePage,
|
|
11130
|
+
pageSize: Math.min(safePageSize, totalCap - offset),
|
|
11131
|
+
shouldFetch: true
|
|
11132
|
+
};
|
|
11133
|
+
}
|
|
11134
|
+
async function executeAthenaReadQuery({
|
|
11135
|
+
client,
|
|
11136
|
+
page,
|
|
11137
|
+
pageSize,
|
|
11138
|
+
query
|
|
11139
|
+
}) {
|
|
11140
|
+
const db = client.db;
|
|
11141
|
+
const baseBuilder = db.from(query.table, {
|
|
11142
|
+
schema: query.schema
|
|
11143
|
+
});
|
|
11144
|
+
const countBuilder = applyAthenaReadQueryFilters(
|
|
11145
|
+
db.from(query.table, { schema: query.schema }),
|
|
11146
|
+
query.filters
|
|
11147
|
+
);
|
|
11148
|
+
const countResult = await countBuilder.select(query.countColumn, {
|
|
11149
|
+
count: "exact",
|
|
11150
|
+
head: true
|
|
11151
|
+
});
|
|
11152
|
+
const pageFetch = resolveAthenaReadQueryPageFetch({
|
|
11153
|
+
limit: query.limit,
|
|
11154
|
+
page,
|
|
11155
|
+
pageSize
|
|
11156
|
+
});
|
|
11157
|
+
if (!pageFetch.shouldFetch) {
|
|
11158
|
+
return {
|
|
11159
|
+
rows: [],
|
|
11160
|
+
totalItems: resolveTotalItemsFromPage({
|
|
11161
|
+
countCandidates: [countResult.count],
|
|
11162
|
+
limit: query.limit,
|
|
11163
|
+
page: pageFetch.page,
|
|
11164
|
+
pageSize,
|
|
11165
|
+
rowCount: 0
|
|
11166
|
+
})
|
|
11167
|
+
};
|
|
11168
|
+
}
|
|
11169
|
+
if ((query.mode ?? "findMany") === "select") {
|
|
11170
|
+
const selectBuilder = applyAthenaReadQuerySelectOrder(
|
|
11171
|
+
applyAthenaReadQueryFilters(baseBuilder, query.filters),
|
|
11172
|
+
query.orderBy
|
|
11173
|
+
);
|
|
11174
|
+
const result2 = await selectBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).select(buildAthenaReadQuerySelectString(query.columns), {
|
|
11175
|
+
count: "exact"
|
|
11176
|
+
});
|
|
11177
|
+
const rows2 = flattenAthenaReadQueryRows(
|
|
11178
|
+
Array.isArray(result2.data) ? result2.data : [],
|
|
11179
|
+
query.columns,
|
|
11180
|
+
query.rowKey
|
|
11181
|
+
);
|
|
11182
|
+
return {
|
|
11183
|
+
debugAst: getAthenaDebugAst(result2) ?? void 0,
|
|
11184
|
+
rows: rows2,
|
|
11185
|
+
totalItems: resolveTotalItemsFromPage({
|
|
11186
|
+
countCandidates: [countResult.count, result2.count],
|
|
11187
|
+
limit: query.limit,
|
|
11188
|
+
page: pageFetch.page,
|
|
11189
|
+
pageSize,
|
|
11190
|
+
rowCount: rows2.length
|
|
11191
|
+
})
|
|
11192
|
+
};
|
|
11193
|
+
}
|
|
11194
|
+
const findManyOrderBy = buildAthenaReadQueryFindManyOrderBy(query.orderBy);
|
|
11195
|
+
const findManyOptions = {
|
|
11196
|
+
...findManyOrderBy ? { orderBy: findManyOrderBy } : {},
|
|
11197
|
+
select: buildAthenaReadQueryFindManySelect(query.columns),
|
|
11198
|
+
...query.filters?.length ? { where: buildAthenaReadQueryFindManyWhere(query.filters) } : {}
|
|
11199
|
+
};
|
|
11200
|
+
const result = await baseBuilder.currentPage(pageFetch.page).pageSize(pageFetch.pageSize).findMany(findManyOptions);
|
|
11201
|
+
const rows = flattenAthenaReadQueryRows(
|
|
11202
|
+
Array.isArray(result.data) ? result.data : [],
|
|
11203
|
+
query.columns,
|
|
11204
|
+
query.rowKey
|
|
11205
|
+
);
|
|
11206
|
+
return {
|
|
11207
|
+
debugAst: getAthenaDebugAst(result) ?? void 0,
|
|
11208
|
+
rows,
|
|
11209
|
+
totalItems: resolveTotalItemsFromPage({
|
|
11210
|
+
countCandidates: [countResult.count, result.count],
|
|
11211
|
+
limit: query.limit,
|
|
11212
|
+
page: pageFetch.page,
|
|
11213
|
+
pageSize,
|
|
11214
|
+
rowCount: rows.length
|
|
11215
|
+
})
|
|
11216
|
+
};
|
|
11217
|
+
}
|
|
11218
|
+
var executeAthenaTableQuery = executeAthenaReadQuery;
|
|
11219
|
+
|
|
10771
11220
|
// src/schema/definitions.ts
|
|
10772
11221
|
function defineModel(input) {
|
|
10773
11222
|
return input;
|
|
@@ -10788,7 +11237,7 @@ function resolveNullishValue(mode) {
|
|
|
10788
11237
|
if (mode === "null") return null;
|
|
10789
11238
|
return "";
|
|
10790
11239
|
}
|
|
10791
|
-
function
|
|
11240
|
+
function isRecord13(value) {
|
|
10792
11241
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
10793
11242
|
}
|
|
10794
11243
|
function isNullableColumn(model, key) {
|
|
@@ -10797,7 +11246,7 @@ function isNullableColumn(model, key) {
|
|
|
10797
11246
|
}
|
|
10798
11247
|
function toModelFormDefaults(model, values, options) {
|
|
10799
11248
|
const source = values;
|
|
10800
|
-
if (!
|
|
11249
|
+
if (!isRecord13(source)) {
|
|
10801
11250
|
return {};
|
|
10802
11251
|
}
|
|
10803
11252
|
const mode = options?.nullishMode ?? "empty-string";
|
|
@@ -11761,6 +12210,13 @@ var GATEWAY_API_KEY_ENV_KEYS = [
|
|
|
11761
12210
|
"ATHENA_GATEWAY_API_KEY",
|
|
11762
12211
|
"ATHENA_GENERATOR_API_KEY"
|
|
11763
12212
|
];
|
|
12213
|
+
var GATEWAY_CLIENT_ENV_KEYS = [
|
|
12214
|
+
"ATHENA_CLIENT",
|
|
12215
|
+
"ATHENA_GATEWAY_CLIENT",
|
|
12216
|
+
"ATHENA_GENERATOR_CLIENT",
|
|
12217
|
+
"NEXT_PUBLIC_ATHENA_CLIENT",
|
|
12218
|
+
"NEXT_PUBLIC_ATHENA_GATEWAY_CLIENT"
|
|
12219
|
+
];
|
|
11764
12220
|
var GENERATOR_SCHEMA_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMAS"];
|
|
11765
12221
|
var OUTPUT_FORMAT_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_FORMAT"];
|
|
11766
12222
|
var OUTPUT_PRESET_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_PRESET"];
|
|
@@ -12061,11 +12517,13 @@ function normalizeProviderConfig(provider) {
|
|
|
12061
12517
|
GATEWAY_API_KEY_ENV_KEYS
|
|
12062
12518
|
);
|
|
12063
12519
|
const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS) ?? "postgres";
|
|
12520
|
+
const client = normalizeOptionalString(provider.client, GATEWAY_CLIENT_ENV_KEYS);
|
|
12064
12521
|
return {
|
|
12065
12522
|
...provider,
|
|
12066
12523
|
gatewayUrl,
|
|
12067
12524
|
apiKey,
|
|
12068
12525
|
database,
|
|
12526
|
+
...client ? { client } : {},
|
|
12069
12527
|
schemas: normalizeSchemaSelection(provider.schemas)
|
|
12070
12528
|
};
|
|
12071
12529
|
}
|
|
@@ -12259,6 +12717,7 @@ function buildEnvironmentProviderConfig() {
|
|
|
12259
12717
|
const apiKey = resolveFallbackValue(GATEWAY_API_KEY_ENV_KEYS);
|
|
12260
12718
|
if (gatewayUrl && apiKey) {
|
|
12261
12719
|
const backend = resolveOptionalOneOf(GATEWAY_BACKEND_ENV_KEYS, BACKEND_TYPE_VALUES);
|
|
12720
|
+
const client = resolveFallbackValue(GATEWAY_CLIENT_ENV_KEYS);
|
|
12262
12721
|
return {
|
|
12263
12722
|
kind: "postgres",
|
|
12264
12723
|
mode: "gateway",
|
|
@@ -12266,7 +12725,8 @@ function buildEnvironmentProviderConfig() {
|
|
|
12266
12725
|
apiKey,
|
|
12267
12726
|
database: normalizeOptionalString(void 0, POSTGRES_DATABASE_ENV_KEYS),
|
|
12268
12727
|
schemas: normalizeSchemaSelection(resolveFallbackValue(GENERATOR_SCHEMA_ENV_KEYS)),
|
|
12269
|
-
backend
|
|
12728
|
+
backend,
|
|
12729
|
+
...client ? { client } : {}
|
|
12270
12730
|
};
|
|
12271
12731
|
}
|
|
12272
12732
|
return void 0;
|
|
@@ -12314,93 +12774,576 @@ async function loadGeneratorConfig(options = {}) {
|
|
|
12314
12774
|
}
|
|
12315
12775
|
}
|
|
12316
12776
|
|
|
12317
|
-
// src/generator/
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12777
|
+
// src/generator/schema-discovery.ts
|
|
12778
|
+
var DISCOVER_POSTGRES_SCHEMAS_SQL = `
|
|
12779
|
+
SELECT DISTINCT n.nspname AS schema_name
|
|
12780
|
+
FROM pg_namespace n
|
|
12781
|
+
JOIN pg_class c ON c.relnamespace = n.oid
|
|
12782
|
+
WHERE c.relkind IN ('r', 'p')
|
|
12783
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
12784
|
+
AND n.nspname NOT LIKE 'pg_toast%'
|
|
12785
|
+
AND n.nspname NOT LIKE 'pg_temp_%'
|
|
12786
|
+
AND n.nspname NOT LIKE 'pg_toast_temp_%'
|
|
12787
|
+
ORDER BY n.nspname;
|
|
12788
|
+
`.trim();
|
|
12789
|
+
var SYSTEM_SCHEMA_PREFIXES = ["pg_"];
|
|
12790
|
+
var SYSTEM_SCHEMAS = /* @__PURE__ */ new Set(["pg_catalog", "information_schema"]);
|
|
12791
|
+
function normalizeDiscoveredSchemas(input) {
|
|
12792
|
+
const schemas = [];
|
|
12793
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12794
|
+
for (const value of input) {
|
|
12795
|
+
const schema = value.trim();
|
|
12796
|
+
if (!schema || seen.has(schema)) {
|
|
12797
|
+
continue;
|
|
12798
|
+
}
|
|
12799
|
+
if (SYSTEM_SCHEMAS.has(schema)) {
|
|
12800
|
+
continue;
|
|
12801
|
+
}
|
|
12802
|
+
if (SYSTEM_SCHEMA_PREFIXES.some((prefix) => schema.startsWith(prefix))) {
|
|
12803
|
+
continue;
|
|
12804
|
+
}
|
|
12805
|
+
seen.add(schema);
|
|
12806
|
+
schemas.push(schema);
|
|
12325
12807
|
}
|
|
12326
|
-
|
|
12327
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
12328
|
-
}
|
|
12329
|
-
function throwMissingEnvVar(key) {
|
|
12330
|
-
throw new Error(
|
|
12331
|
-
`Generator config env var ${key} is missing or empty. Set ${key} or provide a default value.`
|
|
12332
|
-
);
|
|
12808
|
+
return schemas;
|
|
12333
12809
|
}
|
|
12334
|
-
function
|
|
12335
|
-
const
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12810
|
+
function mergeSchemaSelections(configured, discovered) {
|
|
12811
|
+
const result = [];
|
|
12812
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12813
|
+
for (const value of configured ?? []) {
|
|
12814
|
+
const schema = value.trim();
|
|
12815
|
+
if (!schema || seen.has(schema)) {
|
|
12816
|
+
continue;
|
|
12339
12817
|
}
|
|
12340
|
-
|
|
12341
|
-
|
|
12818
|
+
seen.add(schema);
|
|
12819
|
+
result.push(schema);
|
|
12820
|
+
}
|
|
12821
|
+
for (const value of discovered) {
|
|
12822
|
+
const schema = value.trim();
|
|
12823
|
+
if (!schema || seen.has(schema)) {
|
|
12824
|
+
continue;
|
|
12342
12825
|
}
|
|
12343
|
-
|
|
12826
|
+
seen.add(schema);
|
|
12827
|
+
result.push(schema);
|
|
12344
12828
|
}
|
|
12345
|
-
return
|
|
12829
|
+
return result.length > 0 ? result : ["public"];
|
|
12346
12830
|
}
|
|
12347
|
-
function
|
|
12348
|
-
|
|
12831
|
+
function schemasEqual(left, right) {
|
|
12832
|
+
const a = normalizeDiscoveredSchemas(left ?? []);
|
|
12833
|
+
const b = normalizeDiscoveredSchemas(right ?? []);
|
|
12834
|
+
if (a.length !== b.length) {
|
|
12835
|
+
return false;
|
|
12836
|
+
}
|
|
12837
|
+
const set = new Set(a);
|
|
12838
|
+
return b.every((schema) => set.has(schema));
|
|
12349
12839
|
}
|
|
12350
|
-
function
|
|
12351
|
-
|
|
12840
|
+
function coerceSchemaName(row) {
|
|
12841
|
+
const raw = row.schema_name ?? row.schemaName ?? row.nspname;
|
|
12842
|
+
if (typeof raw !== "string") {
|
|
12843
|
+
return void 0;
|
|
12844
|
+
}
|
|
12845
|
+
const trimmed = raw.trim();
|
|
12846
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
12352
12847
|
}
|
|
12353
|
-
function
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12848
|
+
async function loadPgPoolConstructor2() {
|
|
12849
|
+
const module = await import('pg');
|
|
12850
|
+
const poolConstructor = module.Pool ?? module.default?.Pool;
|
|
12851
|
+
if (!poolConstructor) {
|
|
12852
|
+
throw new Error(
|
|
12853
|
+
'@xylex-group/athena: Unable to load the PostgreSQL driver for schema discovery. Ensure "pg" is installed and this API runs in a Node.js server runtime.'
|
|
12854
|
+
);
|
|
12855
|
+
}
|
|
12856
|
+
return poolConstructor;
|
|
12358
12857
|
}
|
|
12359
|
-
function
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12858
|
+
async function discoverDirectSchemas(config) {
|
|
12859
|
+
const PoolConstructor = await loadPgPoolConstructor2();
|
|
12860
|
+
const pool = new PoolConstructor({ connectionString: config.connectionString });
|
|
12861
|
+
try {
|
|
12862
|
+
const result = await pool.query(DISCOVER_POSTGRES_SCHEMAS_SQL);
|
|
12863
|
+
const names = result.rows.map(coerceSchemaName).filter((value) => Boolean(value));
|
|
12864
|
+
return normalizeDiscoveredSchemas(names);
|
|
12865
|
+
} finally {
|
|
12866
|
+
await pool.end();
|
|
12867
|
+
}
|
|
12368
12868
|
}
|
|
12369
|
-
function
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12869
|
+
async function discoverGatewaySchemas(config) {
|
|
12870
|
+
const client = createClient({
|
|
12871
|
+
db: { url: config.gatewayUrl },
|
|
12872
|
+
key: config.apiKey,
|
|
12873
|
+
client: config.client,
|
|
12874
|
+
env: typeof process !== "undefined" ? process.env : void 0,
|
|
12875
|
+
backend: {
|
|
12876
|
+
type: config.backend ?? "postgresql"
|
|
12373
12877
|
}
|
|
12878
|
+
});
|
|
12879
|
+
const result = await client.query(DISCOVER_POSTGRES_SCHEMAS_SQL);
|
|
12880
|
+
if (result.error || result.status < 200 || result.status >= 300) {
|
|
12374
12881
|
throw new Error(
|
|
12375
|
-
|
|
12882
|
+
result.error?.message ?? `Gateway schema discovery failed with status ${result.status}`
|
|
12376
12883
|
);
|
|
12377
|
-
}
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
return resolveStringEnv(key, options);
|
|
12381
|
-
}
|
|
12382
|
-
function generatorEnvBoolean(key, options) {
|
|
12383
|
-
return resolveBooleanEnv(key, options);
|
|
12384
|
-
}
|
|
12385
|
-
function generatorEnvList(key, options) {
|
|
12386
|
-
return resolveListEnv(key, options);
|
|
12387
|
-
}
|
|
12388
|
-
function generatorEnvJson(key, options) {
|
|
12389
|
-
return resolveJsonEnv(key, options);
|
|
12390
|
-
}
|
|
12391
|
-
function generatorEnvOneOf(key, allowedValues, options) {
|
|
12392
|
-
return resolveOneOfEnv(key, allowedValues, options);
|
|
12884
|
+
}
|
|
12885
|
+
const names = (result.data ?? []).map(coerceSchemaName).filter((value) => Boolean(value));
|
|
12886
|
+
return normalizeDiscoveredSchemas(names);
|
|
12393
12887
|
}
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12402
|
-
|
|
12403
|
-
|
|
12888
|
+
async function discoverPostgresSchemas(provider) {
|
|
12889
|
+
if (provider.kind === "postgres" && provider.mode === "direct") {
|
|
12890
|
+
return discoverDirectSchemas(provider);
|
|
12891
|
+
}
|
|
12892
|
+
if (provider.kind === "postgres" && provider.mode === "gateway") {
|
|
12893
|
+
return discoverGatewaySchemas(provider);
|
|
12894
|
+
}
|
|
12895
|
+
throw new Error(
|
|
12896
|
+
`Schema discovery is only implemented for postgres direct/gateway providers (received ${provider.kind}/${"mode" in provider ? provider.mode : "unknown"}).`
|
|
12897
|
+
);
|
|
12898
|
+
}
|
|
12899
|
+
|
|
12900
|
+
// src/generator/config-file.ts
|
|
12901
|
+
function hasEnv(keys) {
|
|
12902
|
+
for (const key of keys) {
|
|
12903
|
+
const value = process.env[key];
|
|
12904
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
12905
|
+
return true;
|
|
12906
|
+
}
|
|
12907
|
+
}
|
|
12908
|
+
return false;
|
|
12909
|
+
}
|
|
12910
|
+
var DIRECT_CONNECTION_KEYS = [
|
|
12911
|
+
"ATHENA_GENERATOR_PG_URL",
|
|
12912
|
+
"DATABASE_URL",
|
|
12913
|
+
"PG_URL",
|
|
12914
|
+
"POSTGRES_URL",
|
|
12915
|
+
"POSTGRESQL_URL"
|
|
12916
|
+
];
|
|
12917
|
+
var GATEWAY_URL_KEYS = ["ATHENA_URL", "ATHENA_GATEWAY_URL", "ATHENA_GENERATOR_URL"];
|
|
12918
|
+
var GATEWAY_KEY_KEYS = [
|
|
12919
|
+
"ATHENA_API_KEY",
|
|
12920
|
+
"ATHENA_GATEWAY_API_KEY",
|
|
12921
|
+
"ATHENA_GENERATOR_API_KEY"
|
|
12922
|
+
];
|
|
12923
|
+
function detectGeneratorProviderMode(preferred = "auto") {
|
|
12924
|
+
if (preferred === "direct" || preferred === "gateway") {
|
|
12925
|
+
return preferred;
|
|
12926
|
+
}
|
|
12927
|
+
const hasDirect = hasEnv(DIRECT_CONNECTION_KEYS);
|
|
12928
|
+
const hasGateway = hasEnv(GATEWAY_URL_KEYS) && hasEnv(GATEWAY_KEY_KEYS);
|
|
12929
|
+
if (hasDirect) {
|
|
12930
|
+
return "direct";
|
|
12931
|
+
}
|
|
12932
|
+
if (hasGateway) {
|
|
12933
|
+
return "gateway";
|
|
12934
|
+
}
|
|
12935
|
+
return "direct";
|
|
12936
|
+
}
|
|
12937
|
+
function formatStringArray(values, indent) {
|
|
12938
|
+
if (values.length === 0) {
|
|
12939
|
+
return "[]";
|
|
12940
|
+
}
|
|
12941
|
+
const inner = values.map((value) => `${indent} ${JSON.stringify(value)}`).join(",\n");
|
|
12942
|
+
return `[
|
|
12943
|
+
${inner},
|
|
12944
|
+
${indent}]`;
|
|
12945
|
+
}
|
|
12946
|
+
function buildDirectProviderBlock(schemas) {
|
|
12947
|
+
return ` provider: {
|
|
12948
|
+
kind: "postgres",
|
|
12949
|
+
mode: "direct",
|
|
12950
|
+
connectionString: generatorEnv("DATABASE_URL"),
|
|
12951
|
+
database: generatorEnv("ATHENA_GENERATOR_DB", { optional: true }),
|
|
12952
|
+
schemas: ${formatStringArray(schemas, " ")},
|
|
12953
|
+
}`;
|
|
12954
|
+
}
|
|
12955
|
+
function buildGatewayProviderBlock(schemas) {
|
|
12956
|
+
return ` provider: {
|
|
12957
|
+
kind: "postgres",
|
|
12958
|
+
mode: "gateway",
|
|
12959
|
+
gatewayUrl: generatorEnv("ATHENA_URL"),
|
|
12960
|
+
apiKey: generatorEnv("ATHENA_API_KEY"),
|
|
12961
|
+
client: generatorEnv("ATHENA_CLIENT", { optional: true }),
|
|
12962
|
+
database: generatorEnv("ATHENA_GENERATOR_DB", { default: "postgres" }),
|
|
12963
|
+
schemas: ${formatStringArray(schemas, " ")},
|
|
12964
|
+
}`;
|
|
12965
|
+
}
|
|
12966
|
+
function renderGeneratorConfigFile(options) {
|
|
12967
|
+
const schemas = options.schemas && options.schemas.length > 0 ? [...options.schemas] : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
12968
|
+
const providerBlock = options.mode === "gateway" ? buildGatewayProviderBlock(schemas) : buildDirectProviderBlock(schemas);
|
|
12969
|
+
return `import { defineGeneratorConfig, generatorEnv } from "@xylex-group/athena";
|
|
12970
|
+
|
|
12971
|
+
export default defineGeneratorConfig({
|
|
12972
|
+
${providerBlock},
|
|
12973
|
+
output: {
|
|
12974
|
+
format: "table-builder",
|
|
12975
|
+
preset: "athena-direct",
|
|
12976
|
+
targets: {
|
|
12977
|
+
model: "athena/models/{schema_kebab}/{model_kebab}.ts",
|
|
12978
|
+
schema: "athena/schemas/{schema_kebab}.ts",
|
|
12979
|
+
database: "athena/relations.ts",
|
|
12980
|
+
registry: "athena/registry.generated.ts",
|
|
12981
|
+
},
|
|
12982
|
+
placeholderMap: {
|
|
12983
|
+
namespace: "athena",
|
|
12984
|
+
},
|
|
12985
|
+
},
|
|
12986
|
+
naming: {
|
|
12987
|
+
modelType: "pascal",
|
|
12988
|
+
modelConst: "camel",
|
|
12989
|
+
schemaConst: "camel",
|
|
12990
|
+
databaseConst: "camel",
|
|
12991
|
+
registryConst: "camel",
|
|
12992
|
+
},
|
|
12993
|
+
features: {
|
|
12994
|
+
emitRelations: true,
|
|
12995
|
+
emitRegistry: true,
|
|
12996
|
+
},
|
|
12997
|
+
experimental: {
|
|
12998
|
+
postgresGatewayIntrospection: false,
|
|
12999
|
+
scyllaProviderContracts: true,
|
|
13000
|
+
},
|
|
13001
|
+
});
|
|
13002
|
+
`;
|
|
13003
|
+
}
|
|
13004
|
+
function resolveConfigPath(cwd, configPath) {
|
|
13005
|
+
if (configPath) {
|
|
13006
|
+
const absolutePath2 = resolve(cwd, configPath);
|
|
13007
|
+
return {
|
|
13008
|
+
absolutePath: absolutePath2,
|
|
13009
|
+
relativePath: configPath.replace(/\\/g, "/"),
|
|
13010
|
+
exists: existsSync(absolutePath2)
|
|
13011
|
+
};
|
|
13012
|
+
}
|
|
13013
|
+
const discovered = findGeneratorConfigPath(cwd);
|
|
13014
|
+
if (discovered) {
|
|
13015
|
+
const relativePath = discovered.startsWith(cwd) ? discovered.slice(cwd.length).replace(/^[/\\]/, "").replace(/\\/g, "/") : "athena.config.ts";
|
|
13016
|
+
return {
|
|
13017
|
+
absolutePath: discovered,
|
|
13018
|
+
relativePath,
|
|
13019
|
+
exists: true
|
|
13020
|
+
};
|
|
13021
|
+
}
|
|
13022
|
+
const absolutePath = resolve(cwd, "athena.config.ts");
|
|
13023
|
+
return {
|
|
13024
|
+
absolutePath,
|
|
13025
|
+
relativePath: "athena.config.ts",
|
|
13026
|
+
exists: false
|
|
13027
|
+
};
|
|
13028
|
+
}
|
|
13029
|
+
function providerModeFromConfig(provider, preferred) {
|
|
13030
|
+
if (provider && provider.kind === "postgres") {
|
|
13031
|
+
if (provider.mode === "gateway") {
|
|
13032
|
+
return "gateway";
|
|
13033
|
+
}
|
|
13034
|
+
if (provider.mode === "direct") {
|
|
13035
|
+
return "direct";
|
|
13036
|
+
}
|
|
13037
|
+
}
|
|
13038
|
+
return detectGeneratorProviderMode(preferred);
|
|
13039
|
+
}
|
|
13040
|
+
function schemasFromNormalized(config) {
|
|
13041
|
+
if (config.provider.kind !== "postgres") {
|
|
13042
|
+
return [...DEFAULT_POSTGRES_SCHEMAS];
|
|
13043
|
+
}
|
|
13044
|
+
return normalizeSchemaSelection(config.provider.schemas);
|
|
13045
|
+
}
|
|
13046
|
+
function patchSchemasInConfigSource(source, schemas) {
|
|
13047
|
+
const formattedInline = `[${schemas.map((value) => JSON.stringify(value)).join(", ")}]`;
|
|
13048
|
+
const formattedMultiline = formatStringArray(schemas, " ");
|
|
13049
|
+
const listDefaultPattern = /(schemas\s*:\s*generatorEnv\.list\s*\(\s*['"][^'"]+['"]\s*,\s*\{[\s\S]*?default\s*:\s*)(\[[^\]]*\])/m;
|
|
13050
|
+
if (listDefaultPattern.test(source)) {
|
|
13051
|
+
return source.replace(listDefaultPattern, `$1${formattedInline}`);
|
|
13052
|
+
}
|
|
13053
|
+
const literalPattern = /(schemas\s*:\s*)(\[[^\]]*\])/m;
|
|
13054
|
+
if (literalPattern.test(source)) {
|
|
13055
|
+
const usesMultiline = /schemas\s*:\s*\[\s*\n/.test(source);
|
|
13056
|
+
return source.replace(
|
|
13057
|
+
literalPattern,
|
|
13058
|
+
`$1${usesMultiline ? formattedMultiline : formattedInline}`
|
|
13059
|
+
);
|
|
13060
|
+
}
|
|
13061
|
+
const modeLine = /(mode\s*:\s*["'](?:direct|gateway)["']\s*,)/m;
|
|
13062
|
+
if (modeLine.test(source)) {
|
|
13063
|
+
return source.replace(
|
|
13064
|
+
modeLine,
|
|
13065
|
+
`$1
|
|
13066
|
+
schemas: ${formattedInline},`
|
|
13067
|
+
);
|
|
13068
|
+
}
|
|
13069
|
+
return void 0;
|
|
13070
|
+
}
|
|
13071
|
+
function extractLiteralSchemas(source) {
|
|
13072
|
+
const listDefaultMatch = source.match(
|
|
13073
|
+
/schemas\s*:\s*generatorEnv\.list\s*\(\s*['"][^'"]+['"]\s*,\s*\{[\s\S]*?default\s*:\s*(\[[^\]]*\])/m
|
|
13074
|
+
);
|
|
13075
|
+
const literalMatch = listDefaultMatch ?? source.match(/schemas\s*:\s*(\[[^\]]*\])/m);
|
|
13076
|
+
if (!literalMatch) {
|
|
13077
|
+
return void 0;
|
|
13078
|
+
}
|
|
13079
|
+
try {
|
|
13080
|
+
const parsed = JSON.parse(literalMatch[1].replace(/'/g, '"'));
|
|
13081
|
+
if (!Array.isArray(parsed)) {
|
|
13082
|
+
return void 0;
|
|
13083
|
+
}
|
|
13084
|
+
return parsed.map((value) => typeof value === "string" ? value.trim() : "").filter((value) => value.length > 0);
|
|
13085
|
+
} catch {
|
|
13086
|
+
return void 0;
|
|
13087
|
+
}
|
|
13088
|
+
}
|
|
13089
|
+
async function resolveDiscoveredSchemas(options) {
|
|
13090
|
+
if (options.explicit && options.explicit.length > 0) {
|
|
13091
|
+
return {
|
|
13092
|
+
schemas: normalizeSchemaSelection(options.explicit),
|
|
13093
|
+
discovered: false
|
|
13094
|
+
};
|
|
13095
|
+
}
|
|
13096
|
+
if (!options.discoverSchemas) {
|
|
13097
|
+
if (options.loaded) {
|
|
13098
|
+
return {
|
|
13099
|
+
schemas: schemasFromNormalized(options.loaded.config),
|
|
13100
|
+
discovered: false
|
|
13101
|
+
};
|
|
13102
|
+
}
|
|
13103
|
+
return {
|
|
13104
|
+
schemas: [...DEFAULT_POSTGRES_SCHEMAS],
|
|
13105
|
+
discovered: false
|
|
13106
|
+
};
|
|
13107
|
+
}
|
|
13108
|
+
try {
|
|
13109
|
+
let provider = options.provider;
|
|
13110
|
+
if (!provider && options.loaded) {
|
|
13111
|
+
provider = options.loaded.config.provider;
|
|
13112
|
+
}
|
|
13113
|
+
if (!provider) {
|
|
13114
|
+
const probeConfig = {
|
|
13115
|
+
provider: options.mode === "gateway" ? { kind: "postgres", mode: "gateway" } : { kind: "postgres", mode: "direct" }
|
|
13116
|
+
};
|
|
13117
|
+
const normalized = normalizeGeneratorConfig(probeConfig);
|
|
13118
|
+
provider = normalized.provider;
|
|
13119
|
+
}
|
|
13120
|
+
const discovered = await discoverPostgresSchemas(provider);
|
|
13121
|
+
if (discovered.length === 0) {
|
|
13122
|
+
const fallback = options.loaded ? schemasFromNormalized(options.loaded.config) : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
13123
|
+
return { schemas: fallback, discovered: true };
|
|
13124
|
+
}
|
|
13125
|
+
if (options.loaded) {
|
|
13126
|
+
return {
|
|
13127
|
+
schemas: mergeSchemaSelections(schemasFromNormalized(options.loaded.config), discovered),
|
|
13128
|
+
discovered: true
|
|
13129
|
+
};
|
|
13130
|
+
}
|
|
13131
|
+
return { schemas: discovered, discovered: true };
|
|
13132
|
+
} catch (error) {
|
|
13133
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13134
|
+
const fallback = options.loaded ? schemasFromNormalized(options.loaded.config) : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
13135
|
+
return {
|
|
13136
|
+
schemas: fallback,
|
|
13137
|
+
discovered: false,
|
|
13138
|
+
discoveryError: message
|
|
13139
|
+
};
|
|
13140
|
+
}
|
|
13141
|
+
}
|
|
13142
|
+
async function ensureGeneratorConfigFile(options = {}) {
|
|
13143
|
+
const cwd = options.cwd ?? process.cwd();
|
|
13144
|
+
const dryRun = options.dryRun === true;
|
|
13145
|
+
const discoverSchemas = options.discoverSchemas !== false;
|
|
13146
|
+
const force = options.force === true;
|
|
13147
|
+
const preferredMode = options.mode ?? "auto";
|
|
13148
|
+
const pathInfo = resolveConfigPath(cwd, options.configPath);
|
|
13149
|
+
const changes = [];
|
|
13150
|
+
let loaded = options.loaded;
|
|
13151
|
+
if (!loaded && pathInfo.exists && !force) {
|
|
13152
|
+
try {
|
|
13153
|
+
loaded = await loadGeneratorConfig({
|
|
13154
|
+
cwd,
|
|
13155
|
+
configPath: pathInfo.absolutePath
|
|
13156
|
+
});
|
|
13157
|
+
} catch {
|
|
13158
|
+
}
|
|
13159
|
+
}
|
|
13160
|
+
const mode = providerModeFromConfig(loaded?.config.provider ?? options.provider, preferredMode);
|
|
13161
|
+
const schemaResolution = await resolveDiscoveredSchemas({
|
|
13162
|
+
discoverSchemas,
|
|
13163
|
+
provider: options.provider ?? loaded?.config.provider,
|
|
13164
|
+
loaded,
|
|
13165
|
+
explicit: options.schemas,
|
|
13166
|
+
mode
|
|
13167
|
+
});
|
|
13168
|
+
if (schemaResolution.discoveryError) {
|
|
13169
|
+
changes.push(`schema-discovery-failed: ${schemaResolution.discoveryError}`);
|
|
13170
|
+
} else if (schemaResolution.discovered) {
|
|
13171
|
+
changes.push(`schemas-discovered: ${schemaResolution.schemas.join(",")}`);
|
|
13172
|
+
}
|
|
13173
|
+
if (!pathInfo.exists || force) {
|
|
13174
|
+
const content = renderGeneratorConfigFile({
|
|
13175
|
+
mode,
|
|
13176
|
+
schemas: schemaResolution.schemas
|
|
13177
|
+
});
|
|
13178
|
+
if (!pathInfo.exists) {
|
|
13179
|
+
changes.push("created-modern-config");
|
|
13180
|
+
} else {
|
|
13181
|
+
changes.push("force-rewrote-config");
|
|
13182
|
+
}
|
|
13183
|
+
if (!dryRun) {
|
|
13184
|
+
await mkdir(dirname(pathInfo.absolutePath), { recursive: true });
|
|
13185
|
+
await writeFile(pathInfo.absolutePath, content, "utf8");
|
|
13186
|
+
}
|
|
13187
|
+
return {
|
|
13188
|
+
action: pathInfo.exists ? "updated" : "created",
|
|
13189
|
+
path: pathInfo.relativePath,
|
|
13190
|
+
absolutePath: pathInfo.absolutePath,
|
|
13191
|
+
content,
|
|
13192
|
+
schemas: schemaResolution.schemas,
|
|
13193
|
+
changes,
|
|
13194
|
+
mode,
|
|
13195
|
+
reason: pathInfo.exists ? "force rewrite" : "config file missing"
|
|
13196
|
+
};
|
|
13197
|
+
}
|
|
13198
|
+
const existingSource = await readFile(pathInfo.absolutePath, "utf8");
|
|
13199
|
+
const existingLiteralSchemas = extractLiteralSchemas(existingSource);
|
|
13200
|
+
const existingSchemas = existingLiteralSchemas ?? (loaded ? schemasFromNormalized(loaded.config) : [...DEFAULT_POSTGRES_SCHEMAS]);
|
|
13201
|
+
if (schemasEqual(existingSchemas, schemaResolution.schemas)) {
|
|
13202
|
+
return {
|
|
13203
|
+
action: "unchanged",
|
|
13204
|
+
path: pathInfo.relativePath,
|
|
13205
|
+
absolutePath: pathInfo.absolutePath,
|
|
13206
|
+
content: existingSource,
|
|
13207
|
+
schemas: existingSchemas,
|
|
13208
|
+
changes: changes.length > 0 ? changes : ["schemas-already-current"],
|
|
13209
|
+
mode,
|
|
13210
|
+
reason: "schemas already match discovered/configured set"
|
|
13211
|
+
};
|
|
13212
|
+
}
|
|
13213
|
+
const patched = patchSchemasInConfigSource(existingSource, schemaResolution.schemas);
|
|
13214
|
+
if (!patched) {
|
|
13215
|
+
return {
|
|
13216
|
+
action: "skipped",
|
|
13217
|
+
path: pathInfo.relativePath,
|
|
13218
|
+
absolutePath: pathInfo.absolutePath,
|
|
13219
|
+
content: existingSource,
|
|
13220
|
+
schemas: existingSchemas,
|
|
13221
|
+
changes: [
|
|
13222
|
+
...changes,
|
|
13223
|
+
"could-not-patch-schemas-surgically",
|
|
13224
|
+
"re-run with force=true to rewrite full template"
|
|
13225
|
+
],
|
|
13226
|
+
mode,
|
|
13227
|
+
reason: "existing config schemas could not be updated surgically without risking a destructive rewrite"
|
|
13228
|
+
};
|
|
13229
|
+
}
|
|
13230
|
+
if (patched === existingSource) {
|
|
13231
|
+
return {
|
|
13232
|
+
action: "unchanged",
|
|
13233
|
+
path: pathInfo.relativePath,
|
|
13234
|
+
absolutePath: pathInfo.absolutePath,
|
|
13235
|
+
content: existingSource,
|
|
13236
|
+
schemas: existingSchemas,
|
|
13237
|
+
changes: [...changes, "patch-noop"],
|
|
13238
|
+
mode,
|
|
13239
|
+
reason: "patch produced identical content"
|
|
13240
|
+
};
|
|
13241
|
+
}
|
|
13242
|
+
changes.push(
|
|
13243
|
+
`schemas-updated: ${existingSchemas.join(",")} -> ${schemaResolution.schemas.join(",")}`
|
|
13244
|
+
);
|
|
13245
|
+
if (!dryRun) {
|
|
13246
|
+
await writeFile(pathInfo.absolutePath, patched, "utf8");
|
|
13247
|
+
}
|
|
13248
|
+
return {
|
|
13249
|
+
action: "updated",
|
|
13250
|
+
path: pathInfo.relativePath,
|
|
13251
|
+
absolutePath: pathInfo.absolutePath,
|
|
13252
|
+
content: patched,
|
|
13253
|
+
schemas: schemaResolution.schemas,
|
|
13254
|
+
changes,
|
|
13255
|
+
mode,
|
|
13256
|
+
reason: "auto-filled provider.schemas"
|
|
13257
|
+
};
|
|
13258
|
+
}
|
|
13259
|
+
|
|
13260
|
+
// src/generator/env.ts
|
|
13261
|
+
function readEnvStringValue2(key) {
|
|
13262
|
+
if (typeof process === "undefined" || !process.env) {
|
|
13263
|
+
return void 0;
|
|
13264
|
+
}
|
|
13265
|
+
const value = process.env[key];
|
|
13266
|
+
if (typeof value !== "string") {
|
|
13267
|
+
return void 0;
|
|
13268
|
+
}
|
|
13269
|
+
const trimmed = value.trim();
|
|
13270
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
13271
|
+
}
|
|
13272
|
+
function throwMissingEnvVar(key) {
|
|
13273
|
+
throw new Error(
|
|
13274
|
+
`Generator config env var ${key} is missing or empty. Set ${key} or provide a default value.`
|
|
13275
|
+
);
|
|
13276
|
+
}
|
|
13277
|
+
function resolveEnvValue(key, options, resolver) {
|
|
13278
|
+
const rawValue = readEnvStringValue2(key);
|
|
13279
|
+
if (rawValue === void 0) {
|
|
13280
|
+
if (options?.default !== void 0) {
|
|
13281
|
+
return options.default;
|
|
13282
|
+
}
|
|
13283
|
+
if (options?.optional) {
|
|
13284
|
+
return void 0;
|
|
13285
|
+
}
|
|
13286
|
+
return throwMissingEnvVar(key);
|
|
13287
|
+
}
|
|
13288
|
+
return resolver(rawValue);
|
|
13289
|
+
}
|
|
13290
|
+
function resolveStringEnv(key, options) {
|
|
13291
|
+
return resolveEnvValue(key, options, (value) => value);
|
|
13292
|
+
}
|
|
13293
|
+
function resolveBooleanEnv(key, options) {
|
|
13294
|
+
return resolveEnvValue(key, options, (value) => parseBooleanFlag2(value, false));
|
|
13295
|
+
}
|
|
13296
|
+
function resolveListEnv(key, options) {
|
|
13297
|
+
return resolveEnvValue(key, options, (value) => {
|
|
13298
|
+
const separator = options?.separator ?? ",";
|
|
13299
|
+
return value.split(separator).map((entry) => entry.trim()).filter((entry, index, entries) => entry.length > 0 && entries.indexOf(entry) === index);
|
|
13300
|
+
})?.slice();
|
|
13301
|
+
}
|
|
13302
|
+
function resolveJsonEnv(key, options) {
|
|
13303
|
+
return resolveEnvValue(key, options, (value) => {
|
|
13304
|
+
try {
|
|
13305
|
+
return JSON.parse(value);
|
|
13306
|
+
} catch (error) {
|
|
13307
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13308
|
+
throw new Error(`Generator config env var ${key} must contain valid JSON. ${message}`);
|
|
13309
|
+
}
|
|
13310
|
+
});
|
|
13311
|
+
}
|
|
13312
|
+
function resolveOneOfEnv(key, allowedValues, options) {
|
|
13313
|
+
return resolveEnvValue(key, options, (value) => {
|
|
13314
|
+
if (allowedValues.includes(value)) {
|
|
13315
|
+
return value;
|
|
13316
|
+
}
|
|
13317
|
+
throw new Error(
|
|
13318
|
+
`Generator config env var ${key} must be one of: ${allowedValues.join(", ")}. Received: ${value}.`
|
|
13319
|
+
);
|
|
13320
|
+
});
|
|
13321
|
+
}
|
|
13322
|
+
function generatorEnvString(key, options) {
|
|
13323
|
+
return resolveStringEnv(key, options);
|
|
13324
|
+
}
|
|
13325
|
+
function generatorEnvBoolean(key, options) {
|
|
13326
|
+
return resolveBooleanEnv(key, options);
|
|
13327
|
+
}
|
|
13328
|
+
function generatorEnvList(key, options) {
|
|
13329
|
+
return resolveListEnv(key, options);
|
|
13330
|
+
}
|
|
13331
|
+
function generatorEnvJson(key, options) {
|
|
13332
|
+
return resolveJsonEnv(key, options);
|
|
13333
|
+
}
|
|
13334
|
+
function generatorEnvOneOf(key, allowedValues, options) {
|
|
13335
|
+
return resolveOneOfEnv(key, allowedValues, options);
|
|
13336
|
+
}
|
|
13337
|
+
var generatorEnv = Object.assign(generatorEnvString, {
|
|
13338
|
+
boolean: generatorEnvBoolean,
|
|
13339
|
+
list: generatorEnvList,
|
|
13340
|
+
json: generatorEnvJson,
|
|
13341
|
+
oneOf: generatorEnvOneOf
|
|
13342
|
+
});
|
|
13343
|
+
|
|
13344
|
+
// src/utils/slugify.ts
|
|
13345
|
+
function slugify(input) {
|
|
13346
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
12404
13347
|
}
|
|
12405
13348
|
|
|
12406
13349
|
// src/generator/naming.ts
|
|
@@ -13039,7 +13982,7 @@ function renderModelArtifact(descriptor, config) {
|
|
|
13039
13982
|
const relationsAssignment = config.features.emitRelations && relationEntries.length > 0 ? `
|
|
13040
13983
|
Object.assign(${descriptor.tableConstName}.meta, {
|
|
13041
13984
|
relations: {
|
|
13042
|
-
${relationEntries.map(([
|
|
13985
|
+
${relationEntries.map(([relationKey3, relationValue]) => ` ${renderObjectKey(relationKey3)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
|
|
13043
13986
|
}
|
|
13044
13987
|
})
|
|
13045
13988
|
` : "";
|
|
@@ -13116,7 +14059,7 @@ function renderModelArtifact2(databaseName, descriptor, config) {
|
|
|
13116
14059
|
const relationEntries = Object.entries(descriptor.table.relations);
|
|
13117
14060
|
const relationBlock = config.features.emitRelations && relationEntries.length > 0 ? `,
|
|
13118
14061
|
relations: {
|
|
13119
|
-
${relationEntries.map(([
|
|
14062
|
+
${relationEntries.map(([relationKey3, relationValue]) => ` ${renderObjectKey(relationKey3)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
|
|
13120
14063
|
}` : "";
|
|
13121
14064
|
const content = `import { defineModel } from '@xylex-group/athena'
|
|
13122
14065
|
|
|
@@ -13225,6 +14168,11 @@ var AthenaGatewayPostgresIntrospectionProvider = class {
|
|
|
13225
14168
|
this.client = createClient({
|
|
13226
14169
|
db: { url: this.config.gatewayUrl },
|
|
13227
14170
|
key: this.config.apiKey,
|
|
14171
|
+
// Multi-tenant gateways reject DEFAULT_CLIENT; prefer explicit config.
|
|
14172
|
+
// Also pass process.env so ATHENA_CLIENT / ATHENA_GATEWAY_CLIENT still resolve
|
|
14173
|
+
// when the field was not normalized into provider config.
|
|
14174
|
+
client: this.config.client,
|
|
14175
|
+
env: typeof process !== "undefined" ? process.env : void 0,
|
|
13228
14176
|
backend: {
|
|
13229
14177
|
type: this.config.backend ?? "postgresql"
|
|
13230
14178
|
}
|
|
@@ -14125,23 +15073,80 @@ async function writeArtifacts(files, cwd, config, dryRun) {
|
|
|
14125
15073
|
skippedFiles
|
|
14126
15074
|
};
|
|
14127
15075
|
}
|
|
15076
|
+
function withPostgresSchemas(config, schemas) {
|
|
15077
|
+
if (config.provider.kind !== "postgres") {
|
|
15078
|
+
return config;
|
|
15079
|
+
}
|
|
15080
|
+
return {
|
|
15081
|
+
...config,
|
|
15082
|
+
provider: {
|
|
15083
|
+
...config.provider,
|
|
15084
|
+
schemas
|
|
15085
|
+
}
|
|
15086
|
+
};
|
|
15087
|
+
}
|
|
14128
15088
|
async function runSchemaGenerator(options = {}) {
|
|
14129
15089
|
const cwd = options.cwd ?? process.cwd();
|
|
15090
|
+
const dryRun = options.dryRun === true;
|
|
15091
|
+
const writeConfig = options.writeConfig !== false;
|
|
15092
|
+
const discoverSchemas = options.discoverSchemas !== false;
|
|
14130
15093
|
const configOptions = {
|
|
14131
15094
|
cwd,
|
|
14132
15095
|
configPath: options.configPath
|
|
14133
15096
|
};
|
|
14134
|
-
const
|
|
15097
|
+
const loaded = await loadGeneratorConfig(configOptions);
|
|
15098
|
+
let { configPath, config } = loaded;
|
|
15099
|
+
let configEnsure;
|
|
15100
|
+
let effectiveSchemas = resolveProviderSchemas(config.provider);
|
|
15101
|
+
const canDiscoverLive = discoverSchemas && config.provider.kind === "postgres" && !options.provider;
|
|
15102
|
+
if (canDiscoverLive) {
|
|
15103
|
+
try {
|
|
15104
|
+
const discovered = await discoverPostgresSchemas(config.provider);
|
|
15105
|
+
if (discovered.length > 0) {
|
|
15106
|
+
effectiveSchemas = mergeSchemaSelections(effectiveSchemas, discovered);
|
|
15107
|
+
}
|
|
15108
|
+
} catch {
|
|
15109
|
+
}
|
|
15110
|
+
}
|
|
15111
|
+
config = withPostgresSchemas(config, effectiveSchemas);
|
|
15112
|
+
const shouldEnsureConfig = writeConfig && config.provider.kind === "postgres" && !options.provider;
|
|
15113
|
+
if (shouldEnsureConfig) {
|
|
15114
|
+
const ensureResult = await ensureGeneratorConfigFile({
|
|
15115
|
+
cwd,
|
|
15116
|
+
configPath: options.configPath,
|
|
15117
|
+
dryRun,
|
|
15118
|
+
// Schemas already resolved above — avoid a second discovery round-trip.
|
|
15119
|
+
discoverSchemas: false,
|
|
15120
|
+
provider: config.provider,
|
|
15121
|
+
loaded: { configPath, config },
|
|
15122
|
+
schemas: effectiveSchemas,
|
|
15123
|
+
mode: config.provider.mode
|
|
15124
|
+
});
|
|
15125
|
+
configEnsure = {
|
|
15126
|
+
action: ensureResult.action,
|
|
15127
|
+
path: ensureResult.path,
|
|
15128
|
+
schemas: ensureResult.schemas,
|
|
15129
|
+
changes: ensureResult.changes,
|
|
15130
|
+
reason: ensureResult.reason
|
|
15131
|
+
};
|
|
15132
|
+
if (ensureResult.action === "created" || ensureResult.action === "updated" || ensureResult.action === "unchanged" && configPath === "[environment defaults]") {
|
|
15133
|
+
configPath = ensureResult.absolutePath;
|
|
15134
|
+
if (ensureResult.schemas.length > 0) {
|
|
15135
|
+
effectiveSchemas = ensureResult.schemas;
|
|
15136
|
+
config = withPostgresSchemas(config, effectiveSchemas);
|
|
15137
|
+
}
|
|
15138
|
+
}
|
|
15139
|
+
}
|
|
14135
15140
|
const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
|
|
14136
15141
|
const snapshot = await provider.inspect({
|
|
14137
|
-
schemas:
|
|
15142
|
+
schemas: effectiveSchemas
|
|
14138
15143
|
});
|
|
14139
15144
|
const generated = generateArtifactsFromSnapshot(snapshot, config);
|
|
14140
15145
|
const writeResult = await writeArtifacts(
|
|
14141
15146
|
generated.files,
|
|
14142
15147
|
cwd,
|
|
14143
15148
|
config,
|
|
14144
|
-
|
|
15149
|
+
dryRun
|
|
14145
15150
|
);
|
|
14146
15151
|
return {
|
|
14147
15152
|
...generated,
|
|
@@ -14149,7 +15154,8 @@ async function runSchemaGenerator(options = {}) {
|
|
|
14149
15154
|
config,
|
|
14150
15155
|
writtenFiles: writeResult.writtenFiles,
|
|
14151
15156
|
writtenDetails: writeResult.writtenDetails,
|
|
14152
|
-
skippedFiles: writeResult.skippedFiles
|
|
15157
|
+
skippedFiles: writeResult.skippedFiles,
|
|
15158
|
+
configEnsure
|
|
14153
15159
|
};
|
|
14154
15160
|
}
|
|
14155
15161
|
|
|
@@ -14218,15 +15224,15 @@ function readCookieFromHeaders(headers, name) {
|
|
|
14218
15224
|
}
|
|
14219
15225
|
return parseCookies(cookieHeader).get(name);
|
|
14220
15226
|
}
|
|
14221
|
-
function
|
|
15227
|
+
function isRecord14(value) {
|
|
14222
15228
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
14223
15229
|
}
|
|
14224
15230
|
function resolveSessionCandidate(value) {
|
|
14225
|
-
if (!
|
|
15231
|
+
if (!isRecord14(value)) {
|
|
14226
15232
|
return null;
|
|
14227
15233
|
}
|
|
14228
|
-
const session =
|
|
14229
|
-
const user =
|
|
15234
|
+
const session = isRecord14(value.session) ? value.session : void 0;
|
|
15235
|
+
const user = isRecord14(value.user) ? value.user : void 0;
|
|
14230
15236
|
if (session && typeof session.token === "string" && session.token.length > 0 && user) {
|
|
14231
15237
|
return {
|
|
14232
15238
|
session,
|
|
@@ -14236,7 +15242,7 @@ function resolveSessionCandidate(value) {
|
|
|
14236
15242
|
return null;
|
|
14237
15243
|
}
|
|
14238
15244
|
function inferSessionPair(returned) {
|
|
14239
|
-
return resolveSessionCandidate(returned) ?? (
|
|
15245
|
+
return resolveSessionCandidate(returned) ?? (isRecord14(returned) ? resolveSessionCandidate(returned.data) : null) ?? (isRecord14(returned) ? resolveSessionCandidate(returned.session) : null);
|
|
14240
15246
|
}
|
|
14241
15247
|
function resolveResponseHeaders(ctx) {
|
|
14242
15248
|
if (ctx.context.responseHeaders instanceof Headers) {
|
|
@@ -14647,6 +15653,432 @@ async function ensureActiveOrganization(options) {
|
|
|
14647
15653
|
}
|
|
14648
15654
|
}
|
|
14649
15655
|
|
|
14650
|
-
|
|
15656
|
+
// src/tables/catalog.ts
|
|
15657
|
+
var POSTGRES_CATALOG_SQL2 = {
|
|
15658
|
+
columns: `
|
|
15659
|
+
SELECT
|
|
15660
|
+
n.nspname AS schema_name,
|
|
15661
|
+
c.relname AS table_name,
|
|
15662
|
+
a.attname AS column_name,
|
|
15663
|
+
format_type(a.atttypid, a.atttypmod) AS data_type,
|
|
15664
|
+
NOT a.attnotnull AS is_nullable
|
|
15665
|
+
FROM pg_attribute a
|
|
15666
|
+
JOIN pg_class c ON c.oid = a.attrelid
|
|
15667
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
15668
|
+
WHERE c.relkind IN ('r', 'p')
|
|
15669
|
+
AND a.attnum > 0
|
|
15670
|
+
AND NOT a.attisdropped
|
|
15671
|
+
AND n.nspname = ANY($1::text[])
|
|
15672
|
+
ORDER BY n.nspname, c.relname, a.attnum;
|
|
15673
|
+
`,
|
|
15674
|
+
foreignKeys: `
|
|
15675
|
+
SELECT
|
|
15676
|
+
sn.nspname AS source_schema,
|
|
15677
|
+
sc.relname AS source_table,
|
|
15678
|
+
con.conname AS constraint_name,
|
|
15679
|
+
ARRAY_AGG(sa.attname ORDER BY cols.ordinality) AS source_columns,
|
|
15680
|
+
tn.nspname AS target_schema,
|
|
15681
|
+
tc.relname AS target_table,
|
|
15682
|
+
ARRAY_AGG(ta.attname ORDER BY cols.ordinality) AS target_columns,
|
|
15683
|
+
EXISTS (
|
|
15684
|
+
SELECT 1
|
|
15685
|
+
FROM pg_constraint uq
|
|
15686
|
+
WHERE uq.conrelid = con.conrelid
|
|
15687
|
+
AND uq.contype IN ('p', 'u')
|
|
15688
|
+
AND uq.conkey = con.conkey
|
|
15689
|
+
) AS source_is_unique
|
|
15690
|
+
FROM pg_constraint con
|
|
15691
|
+
JOIN pg_class sc ON sc.oid = con.conrelid
|
|
15692
|
+
JOIN pg_namespace sn ON sn.oid = sc.relnamespace
|
|
15693
|
+
JOIN pg_class tc ON tc.oid = con.confrelid
|
|
15694
|
+
JOIN pg_namespace tn ON tn.oid = tc.relnamespace
|
|
15695
|
+
JOIN unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(source_attnum, target_attnum, ordinality) ON TRUE
|
|
15696
|
+
JOIN pg_attribute sa ON sa.attrelid = con.conrelid AND sa.attnum = cols.source_attnum
|
|
15697
|
+
JOIN pg_attribute ta ON ta.attrelid = con.confrelid AND ta.attnum = cols.target_attnum
|
|
15698
|
+
WHERE con.contype = 'f'
|
|
15699
|
+
AND sn.nspname = ANY($1::text[])
|
|
15700
|
+
AND tn.nspname = ANY($1::text[])
|
|
15701
|
+
GROUP BY
|
|
15702
|
+
sn.nspname,
|
|
15703
|
+
sc.relname,
|
|
15704
|
+
con.conname,
|
|
15705
|
+
tn.nspname,
|
|
15706
|
+
tc.relname,
|
|
15707
|
+
con.conkey,
|
|
15708
|
+
con.conrelid
|
|
15709
|
+
ORDER BY sn.nspname, sc.relname, con.conname;
|
|
15710
|
+
`,
|
|
15711
|
+
primaryKeys: `
|
|
15712
|
+
SELECT
|
|
15713
|
+
n.nspname AS schema_name,
|
|
15714
|
+
c.relname AS table_name,
|
|
15715
|
+
ARRAY_AGG(a.attname ORDER BY ck.ordinality) AS columns
|
|
15716
|
+
FROM pg_constraint con
|
|
15717
|
+
JOIN pg_class c ON c.oid = con.conrelid
|
|
15718
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
15719
|
+
JOIN unnest(con.conkey) WITH ORDINALITY AS ck(attnum, ordinality) ON TRUE
|
|
15720
|
+
JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ck.attnum
|
|
15721
|
+
WHERE con.contype = 'p'
|
|
15722
|
+
AND n.nspname = ANY($1::text[])
|
|
15723
|
+
GROUP BY n.nspname, c.relname
|
|
15724
|
+
ORDER BY n.nspname, c.relname;
|
|
15725
|
+
`
|
|
15726
|
+
};
|
|
15727
|
+
function parseAthenaTableSchemaScope(value) {
|
|
15728
|
+
return value.split(",").map((entry) => entry.trim()).filter(
|
|
15729
|
+
(entry, index, values) => entry.length > 0 && values.indexOf(entry) === index
|
|
15730
|
+
);
|
|
15731
|
+
}
|
|
15732
|
+
function escapeSqlLiteral2(value) {
|
|
15733
|
+
return value.replace(/'/g, "''");
|
|
15734
|
+
}
|
|
15735
|
+
function buildSchemaArrayLiteral2(schemas) {
|
|
15736
|
+
const literals = schemas.map((schema) => `'${escapeSqlLiteral2(schema)}'`).join(", ");
|
|
15737
|
+
return `ARRAY[${literals}]`;
|
|
15738
|
+
}
|
|
15739
|
+
function inlineSchemaLiteral2(sql, schemas) {
|
|
15740
|
+
return sql.replace(
|
|
15741
|
+
/\$1::text\[\]/g,
|
|
15742
|
+
`${buildSchemaArrayLiteral2(schemas)}::text[]`
|
|
15743
|
+
);
|
|
15744
|
+
}
|
|
15745
|
+
function buildAthenaTableCatalogQueries(schemas) {
|
|
15746
|
+
return {
|
|
15747
|
+
columns: inlineSchemaLiteral2(POSTGRES_CATALOG_SQL2.columns, schemas),
|
|
15748
|
+
foreignKeys: inlineSchemaLiteral2(POSTGRES_CATALOG_SQL2.foreignKeys, schemas),
|
|
15749
|
+
primaryKeys: inlineSchemaLiteral2(POSTGRES_CATALOG_SQL2.primaryKeys, schemas)
|
|
15750
|
+
};
|
|
15751
|
+
}
|
|
15752
|
+
function tableKey2(schema, table2) {
|
|
15753
|
+
return `${schema}.${table2}`;
|
|
15754
|
+
}
|
|
15755
|
+
function relationKey2(...parts) {
|
|
15756
|
+
const base = parts.join("_").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
|
|
15757
|
+
return base.length > 0 ? base : "relation";
|
|
15758
|
+
}
|
|
15759
|
+
function parsePostgresArrayLiteral2(text) {
|
|
15760
|
+
const body = text.slice(1, -1).trim();
|
|
15761
|
+
if (!body) {
|
|
15762
|
+
return [];
|
|
15763
|
+
}
|
|
15764
|
+
const values = [];
|
|
15765
|
+
let current = "";
|
|
15766
|
+
let inQuotes = false;
|
|
15767
|
+
let escaped = false;
|
|
15768
|
+
for (const char of body) {
|
|
15769
|
+
if (escaped) {
|
|
15770
|
+
current += char;
|
|
15771
|
+
escaped = false;
|
|
15772
|
+
continue;
|
|
15773
|
+
}
|
|
15774
|
+
if (char === "\\") {
|
|
15775
|
+
escaped = true;
|
|
15776
|
+
continue;
|
|
15777
|
+
}
|
|
15778
|
+
if (char === '"') {
|
|
15779
|
+
inQuotes = !inQuotes;
|
|
15780
|
+
continue;
|
|
15781
|
+
}
|
|
15782
|
+
if (char === "," && !inQuotes) {
|
|
15783
|
+
values.push(current);
|
|
15784
|
+
current = "";
|
|
15785
|
+
continue;
|
|
15786
|
+
}
|
|
15787
|
+
current += char;
|
|
15788
|
+
}
|
|
15789
|
+
values.push(current);
|
|
15790
|
+
return values.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
15791
|
+
}
|
|
15792
|
+
function coerceStringArray2(value) {
|
|
15793
|
+
if (value == null) {
|
|
15794
|
+
return [];
|
|
15795
|
+
}
|
|
15796
|
+
if (Array.isArray(value)) {
|
|
15797
|
+
return value.map((entry) => entry.trim()).filter(Boolean);
|
|
15798
|
+
}
|
|
15799
|
+
if (typeof value !== "string") {
|
|
15800
|
+
return [];
|
|
15801
|
+
}
|
|
15802
|
+
const trimmedValue = value.trim();
|
|
15803
|
+
if (!trimmedValue) {
|
|
15804
|
+
return [];
|
|
15805
|
+
}
|
|
15806
|
+
if (trimmedValue.startsWith("{") && trimmedValue.endsWith("}")) {
|
|
15807
|
+
return parsePostgresArrayLiteral2(trimmedValue);
|
|
15808
|
+
}
|
|
15809
|
+
return trimmedValue.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
15810
|
+
}
|
|
15811
|
+
function createTableCatalog() {
|
|
15812
|
+
const tables = /* @__PURE__ */ new Map();
|
|
15813
|
+
const ensureTable = (schema, name) => {
|
|
15814
|
+
const id = tableKey2(schema, name);
|
|
15815
|
+
const existingTable = tables.get(id);
|
|
15816
|
+
if (existingTable) {
|
|
15817
|
+
return existingTable;
|
|
15818
|
+
}
|
|
15819
|
+
const nextTable = {
|
|
15820
|
+
columns: [],
|
|
15821
|
+
id,
|
|
15822
|
+
name,
|
|
15823
|
+
primaryKey: [],
|
|
15824
|
+
relationMap: /* @__PURE__ */ new Map(),
|
|
15825
|
+
schema
|
|
15826
|
+
};
|
|
15827
|
+
tables.set(id, nextTable);
|
|
15828
|
+
return nextTable;
|
|
15829
|
+
};
|
|
15830
|
+
const upsertRelation = (table2, key, relation) => {
|
|
15831
|
+
table2.relationMap.set(key, relation);
|
|
15832
|
+
};
|
|
15833
|
+
return {
|
|
15834
|
+
addColumnRows(columnRows) {
|
|
15835
|
+
for (const row of columnRows) {
|
|
15836
|
+
const table2 = ensureTable(row.schema_name, row.table_name);
|
|
15837
|
+
table2.columns.push({
|
|
15838
|
+
dataType: row.data_type,
|
|
15839
|
+
isNullable: row.is_nullable,
|
|
15840
|
+
isPrimaryKey: false,
|
|
15841
|
+
name: row.column_name
|
|
15842
|
+
});
|
|
15843
|
+
}
|
|
15844
|
+
},
|
|
15845
|
+
addForeignKeyRows(foreignKeyRows) {
|
|
15846
|
+
for (const row of foreignKeyRows) {
|
|
15847
|
+
const sourceTable = ensureTable(row.source_schema, row.source_table);
|
|
15848
|
+
const targetTable = ensureTable(row.target_schema, row.target_table);
|
|
15849
|
+
upsertRelation(
|
|
15850
|
+
sourceTable,
|
|
15851
|
+
relationKey2(row.constraint_name, row.target_table),
|
|
15852
|
+
{
|
|
15853
|
+
name: row.constraint_name,
|
|
15854
|
+
targetSchema: row.target_schema,
|
|
15855
|
+
targetTable: row.target_table
|
|
15856
|
+
}
|
|
15857
|
+
);
|
|
15858
|
+
upsertRelation(targetTable, relationKey2(row.source_table), {
|
|
15859
|
+
name: relationKey2(row.source_table, row.constraint_name),
|
|
15860
|
+
targetSchema: row.source_schema,
|
|
15861
|
+
targetTable: row.source_table
|
|
15862
|
+
});
|
|
15863
|
+
}
|
|
15864
|
+
},
|
|
15865
|
+
addManyToManyRows(foreignKeyRows) {
|
|
15866
|
+
const foreignKeysBySourceTable = /* @__PURE__ */ new Map();
|
|
15867
|
+
for (const foreignKey of foreignKeyRows) {
|
|
15868
|
+
const key = tableKey2(foreignKey.source_schema, foreignKey.source_table);
|
|
15869
|
+
const current = foreignKeysBySourceTable.get(key) ?? {
|
|
15870
|
+
foreignKeys: [],
|
|
15871
|
+
schema: foreignKey.source_schema,
|
|
15872
|
+
table: foreignKey.source_table
|
|
15873
|
+
};
|
|
15874
|
+
current.foreignKeys.push(foreignKey);
|
|
15875
|
+
foreignKeysBySourceTable.set(key, current);
|
|
15876
|
+
}
|
|
15877
|
+
for (const candidate of foreignKeysBySourceTable.values()) {
|
|
15878
|
+
const bridgeTable = tables.get(
|
|
15879
|
+
tableKey2(candidate.schema, candidate.table)
|
|
15880
|
+
);
|
|
15881
|
+
if (!bridgeTable || candidate.foreignKeys.length !== 2) {
|
|
15882
|
+
continue;
|
|
15883
|
+
}
|
|
15884
|
+
const combinedForeignColumns = Array.from(
|
|
15885
|
+
new Set(
|
|
15886
|
+
candidate.foreignKeys.flatMap(
|
|
15887
|
+
(foreignKey) => coerceStringArray2(foreignKey.source_columns)
|
|
15888
|
+
)
|
|
15889
|
+
)
|
|
15890
|
+
);
|
|
15891
|
+
if (bridgeTable.primaryKey.length === 0 || combinedForeignColumns.length !== bridgeTable.primaryKey.length || !bridgeTable.primaryKey.every(
|
|
15892
|
+
(column) => combinedForeignColumns.includes(column)
|
|
15893
|
+
)) {
|
|
15894
|
+
continue;
|
|
15895
|
+
}
|
|
15896
|
+
const [firstForeignKey, secondForeignKey] = candidate.foreignKeys;
|
|
15897
|
+
const firstTarget = tables.get(
|
|
15898
|
+
tableKey2(firstForeignKey.target_schema, firstForeignKey.target_table)
|
|
15899
|
+
);
|
|
15900
|
+
const secondTarget = tables.get(
|
|
15901
|
+
tableKey2(
|
|
15902
|
+
secondForeignKey.target_schema,
|
|
15903
|
+
secondForeignKey.target_table
|
|
15904
|
+
)
|
|
15905
|
+
);
|
|
15906
|
+
if (!(firstTarget && secondTarget)) {
|
|
15907
|
+
continue;
|
|
15908
|
+
}
|
|
15909
|
+
upsertRelation(
|
|
15910
|
+
firstTarget,
|
|
15911
|
+
relationKey2(candidate.table, secondForeignKey.target_table),
|
|
15912
|
+
{
|
|
15913
|
+
name: relationKey2(
|
|
15914
|
+
candidate.table,
|
|
15915
|
+
secondForeignKey.constraint_name
|
|
15916
|
+
),
|
|
15917
|
+
targetSchema: secondForeignKey.target_schema,
|
|
15918
|
+
targetTable: secondForeignKey.target_table
|
|
15919
|
+
}
|
|
15920
|
+
);
|
|
15921
|
+
upsertRelation(
|
|
15922
|
+
secondTarget,
|
|
15923
|
+
relationKey2(candidate.table, firstForeignKey.target_table),
|
|
15924
|
+
{
|
|
15925
|
+
name: relationKey2(candidate.table, firstForeignKey.constraint_name),
|
|
15926
|
+
targetSchema: firstForeignKey.target_schema,
|
|
15927
|
+
targetTable: firstForeignKey.target_table
|
|
15928
|
+
}
|
|
15929
|
+
);
|
|
15930
|
+
}
|
|
15931
|
+
},
|
|
15932
|
+
addPrimaryKeyRows(primaryKeyRows) {
|
|
15933
|
+
for (const row of primaryKeyRows) {
|
|
15934
|
+
const table2 = ensureTable(row.schema_name, row.table_name);
|
|
15935
|
+
const primaryKey = coerceStringArray2(row.columns);
|
|
15936
|
+
table2.primaryKey = primaryKey;
|
|
15937
|
+
for (const columnName of primaryKey) {
|
|
15938
|
+
const column = table2.columns.find(
|
|
15939
|
+
(candidate) => candidate.name === columnName
|
|
15940
|
+
);
|
|
15941
|
+
if (column) {
|
|
15942
|
+
column.isPrimaryKey = true;
|
|
15943
|
+
}
|
|
15944
|
+
}
|
|
15945
|
+
}
|
|
15946
|
+
},
|
|
15947
|
+
toResponse(database) {
|
|
15948
|
+
return {
|
|
15949
|
+
database,
|
|
15950
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15951
|
+
tables: [...tables.values()].map((table2) => ({
|
|
15952
|
+
columns: [...table2.columns].sort(
|
|
15953
|
+
(left, right) => left.name.localeCompare(right.name)
|
|
15954
|
+
),
|
|
15955
|
+
id: table2.id,
|
|
15956
|
+
name: table2.name,
|
|
15957
|
+
primaryKey: [...table2.primaryKey],
|
|
15958
|
+
relations: [...table2.relationMap.values()].map((relation) => ({
|
|
15959
|
+
columns: tables.get(
|
|
15960
|
+
tableKey2(relation.targetSchema, relation.targetTable)
|
|
15961
|
+
)?.columns ?? [],
|
|
15962
|
+
name: relation.name,
|
|
15963
|
+
targetSchema: relation.targetSchema,
|
|
15964
|
+
targetTable: relation.targetTable
|
|
15965
|
+
})).sort(
|
|
15966
|
+
(left, right) => left.name.localeCompare(right.name)
|
|
15967
|
+
),
|
|
15968
|
+
schema: table2.schema
|
|
15969
|
+
})).sort(
|
|
15970
|
+
(left, right) => left.id.localeCompare(right.id)
|
|
15971
|
+
)
|
|
15972
|
+
};
|
|
15973
|
+
}
|
|
15974
|
+
};
|
|
15975
|
+
}
|
|
15976
|
+
async function queryRows(client, query) {
|
|
15977
|
+
const result = await client.query(query);
|
|
15978
|
+
if (result.error || result.status < 200 || result.status >= 300) {
|
|
15979
|
+
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}.`;
|
|
15980
|
+
throw new Error(errorMessage);
|
|
15981
|
+
}
|
|
15982
|
+
return Array.isArray(result.data) ? result.data : [];
|
|
15983
|
+
}
|
|
15984
|
+
function isAthenaTableSchemaConfig(value) {
|
|
15985
|
+
if (typeof value !== "object" || value === null) {
|
|
15986
|
+
return false;
|
|
15987
|
+
}
|
|
15988
|
+
const config = value;
|
|
15989
|
+
return typeof config.gatewayUrl === "string" && typeof config.gatewayKey === "string" && typeof config.gatewayDatabase === "string" && typeof config.schemaScope === "string" && typeof config.clientName === "string";
|
|
15990
|
+
}
|
|
15991
|
+
function hasAthenaTableSchemaCredentials(config) {
|
|
15992
|
+
return config.gatewayUrl.trim().length > 0 && config.gatewayKey.trim().length > 0 && config.gatewayDatabase.trim().length > 0;
|
|
15993
|
+
}
|
|
15994
|
+
async function fetchAthenaTableCatalog(config, options = {}) {
|
|
15995
|
+
const schemas = parseAthenaTableSchemaScope(config.schemaScope);
|
|
15996
|
+
if (schemas.length === 0) {
|
|
15997
|
+
return {
|
|
15998
|
+
database: config.gatewayDatabase,
|
|
15999
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16000
|
+
tables: []
|
|
16001
|
+
};
|
|
16002
|
+
}
|
|
16003
|
+
const queries = buildAthenaTableCatalogQueries(schemas);
|
|
16004
|
+
const client = options.client ?? createClient({
|
|
16005
|
+
url: config.gatewayUrl.trim(),
|
|
16006
|
+
key: config.gatewayKey.trim(),
|
|
16007
|
+
client: config.clientName.trim() || void 0
|
|
16008
|
+
});
|
|
16009
|
+
const [columnRows, primaryKeyRows, foreignKeyRows] = await Promise.all([
|
|
16010
|
+
queryRows(client, queries.columns),
|
|
16011
|
+
queryRows(client, queries.primaryKeys),
|
|
16012
|
+
queryRows(client, queries.foreignKeys)
|
|
16013
|
+
]);
|
|
16014
|
+
const catalog = createTableCatalog();
|
|
16015
|
+
catalog.addColumnRows(columnRows);
|
|
16016
|
+
catalog.addPrimaryKeyRows(primaryKeyRows);
|
|
16017
|
+
catalog.addForeignKeyRows(foreignKeyRows);
|
|
16018
|
+
catalog.addManyToManyRows(foreignKeyRows);
|
|
16019
|
+
return catalog.toResponse(config.gatewayDatabase);
|
|
16020
|
+
}
|
|
16021
|
+
var fetchTableCatalog = fetchAthenaTableCatalog;
|
|
16022
|
+
|
|
16023
|
+
// src/tables/schema-handlers.ts
|
|
16024
|
+
var ATHENA_TABLE_SCHEMA_ROUTE = "/api/tables/schema";
|
|
16025
|
+
function json2(body, init) {
|
|
16026
|
+
const headers = new Headers(init?.headers);
|
|
16027
|
+
if (!headers.has("content-type")) {
|
|
16028
|
+
headers.set("content-type", "application/json; charset=utf-8");
|
|
16029
|
+
}
|
|
16030
|
+
return new Response(JSON.stringify(body), {
|
|
16031
|
+
status: init?.status ?? 200,
|
|
16032
|
+
headers
|
|
16033
|
+
});
|
|
16034
|
+
}
|
|
16035
|
+
async function handleAthenaTableSchemaPost(request2, options) {
|
|
16036
|
+
const payload = await request2.json().catch(() => null);
|
|
16037
|
+
let config = isAthenaTableSchemaConfig(
|
|
16038
|
+
payload?.config
|
|
16039
|
+
) ? payload.config : null;
|
|
16040
|
+
if (config && options?.resolveConfig) {
|
|
16041
|
+
config = await options.resolveConfig(config, request2);
|
|
16042
|
+
}
|
|
16043
|
+
if (!config || !isAthenaTableSchemaConfig(config)) {
|
|
16044
|
+
return json2(
|
|
16045
|
+
{
|
|
16046
|
+
error: "The Athena tables showcase config is invalid."
|
|
16047
|
+
},
|
|
16048
|
+
{ status: 400 }
|
|
16049
|
+
);
|
|
16050
|
+
}
|
|
16051
|
+
if (!hasAthenaTableSchemaCredentials(config)) {
|
|
16052
|
+
return json2(
|
|
16053
|
+
{
|
|
16054
|
+
error: "Gateway URL, API key, and database are required for schema introspection."
|
|
16055
|
+
},
|
|
16056
|
+
{ status: 400 }
|
|
16057
|
+
);
|
|
16058
|
+
}
|
|
16059
|
+
try {
|
|
16060
|
+
const response = await fetchAthenaTableCatalog(
|
|
16061
|
+
config,
|
|
16062
|
+
{
|
|
16063
|
+
client: options?.client
|
|
16064
|
+
}
|
|
16065
|
+
);
|
|
16066
|
+
return json2(response);
|
|
16067
|
+
} catch (error) {
|
|
16068
|
+
return json2(
|
|
16069
|
+
{
|
|
16070
|
+
error: error instanceof Error ? error.message : "Athena schema introspection failed."
|
|
16071
|
+
},
|
|
16072
|
+
{ status: 500 }
|
|
16073
|
+
);
|
|
16074
|
+
}
|
|
16075
|
+
}
|
|
16076
|
+
function createAthenaTableSchemaHandlers(options) {
|
|
16077
|
+
return {
|
|
16078
|
+
POST: (request2) => handleAthenaTableSchemaPost(request2, options)
|
|
16079
|
+
};
|
|
16080
|
+
}
|
|
16081
|
+
|
|
16082
|
+
export { ATHENA_AUTH_ADMIN_LIMITS, ATHENA_AUTH_BASE_ERROR_CODES, ATHENA_AUTH_MAX_ADMIN_JSON_BYTES, ATHENA_AUTH_MAX_ADMIN_JSON_DEPTH, ATHENA_AUTH_MAX_TEMPLATE_VARIABLES, ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH, ATHENA_TABLE_SCHEMA_ROUTE, AthenaBillingError, AthenaChatError, AthenaConfigurationError, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, AthenaStorageError, AthenaStorageErrorCode, Backend, DEFAULT_MULTIPART_PART_SIZE_BYTES, DEFAULT_MULTIPART_THRESHOLD_BYTES, DEFAULT_POSTGRES_SCHEMAS, applyAthenaReadQueryFilters, applyAthenaReadQuerySelectLimit, applyAthenaReadQuerySelectOrder, applyAthenaTableFilters, applyAthenaTableSelectLimit, applyAthenaTableSelectOrder, assertInt, athenaAuth, billingSdkManifest, boolean, buildAthenaReadQueryFindManyOrderBy, buildAthenaReadQueryFindManySelect, buildAthenaReadQueryFindManyWhere, buildAthenaReadQuerySelectString, buildAthenaTableCatalogQueries, buildAthenaTableFindManyOrderBy, buildAthenaTableFindManySelect, buildAthenaTableFindManyWhere, buildAthenaTableSelectString, chatSdkManifest, clampAthenaReadQueryTotalItems, clampAthenaTableTotalItems, coerceInt, createAthenaStorageError, createAthenaTableSchemaHandlers, createAuthReactEmailInput, createBillingModule, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createStorageFileModule, defineAthenaAuthConfig, defineAuthEmailTemplate, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, detectGeneratorProviderMode, discoverPostgresSchemas, ensureActiveOrganization, ensureGeneratorConfigFile, enumeration, executeAthenaReadQuery, executeAthenaTableQuery, fetchAthenaTableCatalog, fetchTableCatalog, filterIntrospectionSnapshot, findGeneratorConfigPath, flattenAthenaReadQueryRows, flattenAthenaRows, generateArtifactsFromSnapshot, generatorEnv, getAthenaDebugAst, handleAthenaTableSchemaPost, hasAthenaTableSchemaCredentials, identifier, isAthenaGatewayError, isAthenaTableSchemaConfig, isOk, json, loadGeneratorConfig, mergeSchemaSelections, normalizeAthenaError, normalizeAthenaGatewayBaseUrl, normalizeAthenaReadQueryOrderBy, normalizeAthenaTableOrderBy, normalizeDiscoveredSchemas, normalizeGeneratorConfig, normalizeSchemaSelection, normalizeTableSelection, number, parseAthenaTableSchemaScope, parseBooleanFlag2 as parseBooleanFlag, patchSchemasInConfigSource, renderAthenaReactEmail, renderGeneratorConfigFile, requireAffected, requireSuccess, resolveAthenaReadQueryPageFetch, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, resolveStoragePath, runSchemaGenerator, schemasEqual, storageSdkManifest, string, table, toModelFormDefaults, toModelPayload, unwrap, unwrapChatMessage, unwrapChatRoom, unwrapOne, unwrapRows, verifyAthenaGatewayUrl, withRetry };
|
|
14651
16083
|
//# sourceMappingURL=index.js.map
|
|
14652
16084
|
//# sourceMappingURL=index.js.map
|