@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.
Files changed (86) hide show
  1. package/README.md +1 -1
  2. package/dist/admin.cjs +55 -1
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.d.cts +32 -8
  5. package/dist/admin.d.ts +32 -8
  6. package/dist/admin.js +54 -2
  7. package/dist/admin.js.map +1 -1
  8. package/dist/athena-auth-url-C1FbVmN6.d.cts +200 -0
  9. package/dist/athena-auth-url-C1FbVmN6.d.ts +200 -0
  10. package/dist/{athena-request-headers-C7Jy-c_D.d.ts → athena-request-headers-DzimbvOA.d.ts} +48 -200
  11. package/dist/{athena-request-headers-DujFFyMU.d.cts → athena-request-headers-Lr_m8xCV.d.cts} +48 -200
  12. package/dist/billing.cjs +1 -1
  13. package/dist/billing.cjs.map +1 -1
  14. package/dist/billing.js +1 -1
  15. package/dist/billing.js.map +1 -1
  16. package/dist/browser.cjs +912 -5
  17. package/dist/browser.cjs.map +1 -1
  18. package/dist/browser.d.cts +8 -7
  19. package/dist/browser.d.ts +8 -7
  20. package/dist/browser.js +881 -6
  21. package/dist/browser.js.map +1 -1
  22. package/dist/cli/index.cjs +7909 -7061
  23. package/dist/cli/index.cjs.map +1 -1
  24. package/dist/cli/index.d.cts +17 -10
  25. package/dist/cli/index.d.ts +17 -10
  26. package/dist/cli/index.js +7911 -7063
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/env.cjs +130 -0
  29. package/dist/env.cjs.map +1 -0
  30. package/dist/env.d.cts +70 -0
  31. package/dist/env.d.ts +70 -0
  32. package/dist/env.js +122 -0
  33. package/dist/env.js.map +1 -0
  34. package/dist/index.cjs +1570 -98
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +31 -8
  37. package/dist/index.d.ts +31 -8
  38. package/dist/index.js +1532 -100
  39. package/dist/index.js.map +1 -1
  40. package/dist/model-form-3Gr8rkdT.d.cts +281 -0
  41. package/dist/model-form-CotpEL7z.d.ts +281 -0
  42. package/dist/{module-CPG3ULxQ.d.cts → module-CQmOaDzP.d.cts} +4 -4
  43. package/dist/{module-BruTcxe0.d.ts → module-CWkUTcUc.d.ts} +4 -4
  44. package/dist/next/client.cjs +123 -7
  45. package/dist/next/client.cjs.map +1 -1
  46. package/dist/next/client.d.cts +4 -3
  47. package/dist/next/client.d.ts +4 -3
  48. package/dist/next/client.js +123 -7
  49. package/dist/next/client.js.map +1 -1
  50. package/dist/next/server.cjs +1130 -364
  51. package/dist/next/server.cjs.map +1 -1
  52. package/dist/next/server.d.cts +121 -8
  53. package/dist/next/server.d.ts +121 -8
  54. package/dist/next/server.js +1120 -365
  55. package/dist/next/server.js.map +1 -1
  56. package/dist/pipeline-BnRKO_Pd.d.cts +93 -0
  57. package/dist/pipeline-sWCmlFqu.d.ts +93 -0
  58. package/dist/{proxy-request-headers-m4D2Tduy.d.ts → proxy-request-headers-CttlcuRb.d.ts} +1 -1
  59. package/dist/{proxy-request-headers-DGxdoyA0.d.cts → proxy-request-headers-pIBSn1Fw.d.cts} +1 -1
  60. package/dist/react.cjs +672 -16
  61. package/dist/react.cjs.map +1 -1
  62. package/dist/react.d.cts +123 -8
  63. package/dist/react.d.ts +123 -8
  64. package/dist/react.js +671 -17
  65. package/dist/react.js.map +1 -1
  66. package/dist/schema-handlers-BtT_IQFi.d.cts +138 -0
  67. package/dist/schema-handlers-VjFDhIMw.d.ts +138 -0
  68. package/dist/social-providers.d.cts +1 -1
  69. package/dist/social-providers.d.ts +1 -1
  70. package/dist/{types-D6tZ9aoq.d.ts → types-BDX8zS7w.d.ts} +40 -1
  71. package/dist/{types-AOY-GLu8.d.cts → types-BVKpQmfY.d.cts} +11 -0
  72. package/dist/{types-AOY-GLu8.d.ts → types-BVKpQmfY.d.ts} +11 -0
  73. package/dist/{types-DFr2cL1N.d.cts → types-D-Am7YSd.d.cts} +40 -1
  74. package/dist/utils.cjs +30 -0
  75. package/dist/utils.cjs.map +1 -1
  76. package/dist/utils.d.cts +3 -2
  77. package/dist/utils.d.ts +3 -2
  78. package/dist/utils.js +30 -1
  79. package/dist/utils.js.map +1 -1
  80. package/dist/{v3-client-CWfZHcKL.d.cts → v3-client-G1SLeHRa.d.cts} +23 -1
  81. package/dist/{v3-client-DZp2NEhK.d.ts → v3-client-ao8BWQ8v.d.ts} +23 -1
  82. package/package.json +16 -2
  83. package/dist/model-form-Dh0sisdL.d.ts +0 -97
  84. package/dist/model-form-oOAJUVd4.d.cts +0 -97
  85. package/dist/pipeline-CIzV9f7b.d.cts +0 -8
  86. 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, stat, readFile } from 'fs/promises';
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((resolve3) => {
575
- setTimeout(resolve3, ms);
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.3"
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((resolve3, reject) => {
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
- resolve3(new Response(xhr.response, {
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((resolve3, reject) => {
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
- resolve3(new Response(xhr.response, {
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 = ["ATHENA_CLIENT", "NEXT_PUBLIC_ATHENA_CLIENT"];
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: config.traceQueries,
10679
- debugAst: config.debugAst,
10680
- findManyAst: config.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 isRecord12(value) {
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 (!isRecord12(source)) {
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/env.ts
12318
- function readEnvStringValue2(key) {
12319
- if (typeof process === "undefined" || !process.env) {
12320
- return void 0;
12321
- }
12322
- const value = process.env[key];
12323
- if (typeof value !== "string") {
12324
- return void 0;
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
- const trimmed = value.trim();
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 resolveEnvValue(key, options, resolver) {
12335
- const rawValue = readEnvStringValue2(key);
12336
- if (rawValue === void 0) {
12337
- if (options?.default !== void 0) {
12338
- return options.default;
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
- if (options?.optional) {
12341
- return void 0;
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
- return throwMissingEnvVar(key);
12826
+ seen.add(schema);
12827
+ result.push(schema);
12344
12828
  }
12345
- return resolver(rawValue);
12829
+ return result.length > 0 ? result : ["public"];
12346
12830
  }
12347
- function resolveStringEnv(key, options) {
12348
- return resolveEnvValue(key, options, (value) => value);
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 resolveBooleanEnv(key, options) {
12351
- return resolveEnvValue(key, options, (value) => parseBooleanFlag2(value, false));
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 resolveListEnv(key, options) {
12354
- return resolveEnvValue(key, options, (value) => {
12355
- const separator = options?.separator ?? ",";
12356
- return value.split(separator).map((entry) => entry.trim()).filter((entry, index, entries) => entry.length > 0 && entries.indexOf(entry) === index);
12357
- })?.slice();
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 resolveJsonEnv(key, options) {
12360
- return resolveEnvValue(key, options, (value) => {
12361
- try {
12362
- return JSON.parse(value);
12363
- } catch (error) {
12364
- const message = error instanceof Error ? error.message : String(error);
12365
- throw new Error(`Generator config env var ${key} must contain valid JSON. ${message}`);
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 resolveOneOfEnv(key, allowedValues, options) {
12370
- return resolveEnvValue(key, options, (value) => {
12371
- if (allowedValues.includes(value)) {
12372
- return value;
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
- `Generator config env var ${key} must be one of: ${allowedValues.join(", ")}. Received: ${value}.`
12882
+ result.error?.message ?? `Gateway schema discovery failed with status ${result.status}`
12376
12883
  );
12377
- });
12378
- }
12379
- function generatorEnvString(key, options) {
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
- var generatorEnv = Object.assign(generatorEnvString, {
12395
- boolean: generatorEnvBoolean,
12396
- list: generatorEnvList,
12397
- json: generatorEnvJson,
12398
- oneOf: generatorEnvOneOf
12399
- });
12400
-
12401
- // src/utils/slugify.ts
12402
- function slugify(input) {
12403
- return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
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(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
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(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
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 { configPath, config } = await loadGeneratorConfig(configOptions);
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: resolveProviderSchemas(config.provider)
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
- options.dryRun === true
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 isRecord13(value) {
15227
+ function isRecord14(value) {
14222
15228
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
14223
15229
  }
14224
15230
  function resolveSessionCandidate(value) {
14225
- if (!isRecord13(value)) {
15231
+ if (!isRecord14(value)) {
14226
15232
  return null;
14227
15233
  }
14228
- const session = isRecord13(value.session) ? value.session : void 0;
14229
- const user = isRecord13(value.user) ? value.user : void 0;
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) ?? (isRecord13(returned) ? resolveSessionCandidate(returned.data) : null) ?? (isRecord13(returned) ? resolveSessionCandidate(returned.session) : null);
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
- 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, AthenaBillingError, AthenaChatError, AthenaConfigurationError, AthenaError, AthenaErrorCategory, AthenaErrorCode, AthenaErrorKind, AthenaGatewayError, AthenaStorageError, AthenaStorageErrorCode, Backend, DEFAULT_MULTIPART_PART_SIZE_BYTES, DEFAULT_MULTIPART_THRESHOLD_BYTES, DEFAULT_POSTGRES_SCHEMAS, assertInt, athenaAuth, billingSdkManifest, boolean, chatSdkManifest, coerceInt, createAthenaStorageError, createAuthReactEmailInput, createBillingModule, createClient, createModelFormAdapter, createPostgresIntrospectionProvider, createStorageFileModule, defineAthenaAuthConfig, defineAuthEmailTemplate, defineDatabase, defineGeneratorConfig, defineModel, defineRegistry, defineSchema, ensureActiveOrganization, enumeration, filterIntrospectionSnapshot, findGeneratorConfigPath, generateArtifactsFromSnapshot, generatorEnv, getAthenaDebugAst, identifier, isAthenaGatewayError, isOk, json, loadGeneratorConfig, normalizeAthenaError, normalizeAthenaGatewayBaseUrl, normalizeGeneratorConfig, normalizeSchemaSelection, normalizeTableSelection, number, parseBooleanFlag2 as parseBooleanFlag, renderAthenaReactEmail, requireAffected, requireSuccess, resolveGeneratorProvider, resolvePostgresColumnType, resolveProviderSchemas, resolveStoragePath, runSchemaGenerator, storageSdkManifest, string, table, toModelFormDefaults, toModelPayload, unwrap, unwrapChatMessage, unwrapChatRoom, unwrapOne, unwrapRows, verifyAthenaGatewayUrl, withRetry };
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