@xylex-group/athena 2.7.0 → 2.8.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 (36) hide show
  1. package/README.md +210 -17
  2. package/dist/browser.cjs +1253 -401
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.cts +8 -7
  5. package/dist/browser.d.ts +8 -7
  6. package/dist/browser.js +1247 -402
  7. package/dist/browser.js.map +1 -1
  8. package/dist/cli/index.cjs +1285 -451
  9. package/dist/cli/index.cjs.map +1 -1
  10. package/dist/cli/index.d.cts +3 -3
  11. package/dist/cli/index.d.ts +3 -3
  12. package/dist/cli/index.js +1285 -451
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +1921 -698
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +8 -7
  17. package/dist/index.d.ts +8 -7
  18. package/dist/index.js +1915 -699
  19. package/dist/index.js.map +1 -1
  20. package/dist/{model-form-AKYrgede.d.ts → model-form-DMed05gE.d.cts} +347 -82
  21. package/dist/{model-form-ehfqLuG7.d.cts → model-form-DXPlOnlI.d.ts} +347 -82
  22. package/dist/{pipeline-BUsR9XlO.d.ts → pipeline-CkMnhwPI.d.ts} +1 -1
  23. package/dist/{pipeline-BfCWSRYl.d.cts → pipeline-D4sJRKqN.d.cts} +1 -1
  24. package/dist/{react-email-BQzmXBDE.d.cts → react-email-DZhDDlEl.d.cts} +121 -8
  25. package/dist/{react-email-BrVRp80B.d.ts → react-email-Lrz9A-BW.d.ts} +121 -8
  26. package/dist/react.cjs +1 -1
  27. package/dist/react.cjs.map +1 -1
  28. package/dist/react.d.cts +4 -4
  29. package/dist/react.d.ts +4 -4
  30. package/dist/react.js +1 -1
  31. package/dist/react.js.map +1 -1
  32. package/dist/{types-BSIsyss1.d.cts → types-BzY6fETM.d.ts} +47 -5
  33. package/dist/{types-t_TVqnmp.d.ts → types-CAtTGGoz.d.cts} +47 -5
  34. package/dist/{types-BsyRW49r.d.cts → types-vikz9YIO.d.cts} +23 -1
  35. package/dist/{types-BsyRW49r.d.ts → types-vikz9YIO.d.ts} +23 -1
  36. package/package.json +3 -2
@@ -131,59 +131,6 @@ function escapeStringLiteral(value) {
131
131
  return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
132
132
  }
133
133
 
134
- // src/generator/placeholders.ts
135
- function createStyleTokens(prefix, value) {
136
- return {
137
- [prefix]: value,
138
- [`${prefix}_camel`]: applyNamingStyle(value, "camel"),
139
- [`${prefix}_pascal`]: applyNamingStyle(value, "pascal"),
140
- [`${prefix}_snake`]: applyNamingStyle(value, "snake"),
141
- [`${prefix}_kebab`]: applyNamingStyle(value, "kebab")
142
- };
143
- }
144
- function renderTemplate(template, tokenMap) {
145
- return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_match, token) => {
146
- if (!(token in tokenMap)) {
147
- throw new Error(`Unknown placeholder token "${token}" in template "${template}"`);
148
- }
149
- return tokenMap[token];
150
- });
151
- }
152
- function resolvePlaceholderMap(baseTokens, outputConfig) {
153
- const resolved = {
154
- ...baseTokens
155
- };
156
- const reservedTokenKeys = new Set(Object.keys(baseTokens));
157
- const entries = Object.entries(outputConfig.placeholderMap ?? {});
158
- for (let index = 0; index < entries.length; index += 1) {
159
- const [key, value] = entries[index];
160
- if (reservedTokenKeys.has(key)) {
161
- continue;
162
- }
163
- let current = value;
164
- for (let depth = 0; depth < 8; depth += 1) {
165
- const next = renderTemplate(current, resolved);
166
- if (next === current) {
167
- break;
168
- }
169
- current = next;
170
- }
171
- resolved[key] = current;
172
- }
173
- return resolved;
174
- }
175
- function renderOutputPath(template, context, outputConfig) {
176
- const baseTokens = {
177
- provider: context.provider,
178
- kind: context.kind,
179
- ...createStyleTokens("database", context.database),
180
- ...createStyleTokens("schema", context.schema),
181
- ...createStyleTokens("model", context.model)
182
- };
183
- const tokens = resolvePlaceholderMap(baseTokens, outputConfig);
184
- return renderTemplate(template, tokens);
185
- }
186
-
187
134
  // src/generator/postgres-type-mapping.ts
188
135
  var NUMBER_TYPES = /* @__PURE__ */ new Set([
189
136
  "int2",
@@ -757,6 +704,7 @@ var DEFAULT_TARGETS = {
757
704
  database: "athena/relations.ts",
758
705
  registry: "athena/config.ts"
759
706
  };
707
+ var DEFAULT_OUTPUT_FORMAT = "define-model";
760
708
  var DEFAULT_NAMING = {
761
709
  modelType: "pascal",
762
710
  modelConst: "camel",
@@ -772,6 +720,9 @@ var DEFAULT_EXPERIMENTAL_FLAGS = {
772
720
  postgresGatewayIntrospection: false,
773
721
  scyllaProviderContracts: true
774
722
  };
723
+ var DEFAULT_INTERNAL_CONFIG = {
724
+ schemaVersion: 1
725
+ };
775
726
  var PROJECT_ENV_FILENAMES = [".env", ".env.local"];
776
727
  var DIRECT_CONNECTION_STRING_ENV_KEYS = [
777
728
  "ATHENA_GENERATOR_PG_URL",
@@ -788,6 +739,27 @@ var GATEWAY_API_KEY_ENV_KEYS = [
788
739
  "ATHENA_GATEWAY_API_KEY",
789
740
  "ATHENA_GENERATOR_API_KEY"
790
741
  ];
742
+ var GENERATOR_SCHEMA_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMAS"];
743
+ var OUTPUT_FORMAT_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_FORMAT"];
744
+ var MODEL_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_TARGET"];
745
+ var SCHEMA_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMA_TARGET"];
746
+ var DATABASE_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_DATABASE_TARGET"];
747
+ var REGISTRY_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_REGISTRY_TARGET"];
748
+ var PLACEHOLDER_MAP_ENV_KEYS = ["ATHENA_GENERATOR_PLACEHOLDER_MAP"];
749
+ var MODEL_TYPE_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_TYPE", "ATHENA_GENERATOR_MODEL_STYLE"];
750
+ var MODEL_CONST_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_CONST"];
751
+ var SCHEMA_CONST_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMA_CONST"];
752
+ var DATABASE_CONST_ENV_KEYS = ["ATHENA_GENERATOR_DATABASE_CONST"];
753
+ var REGISTRY_CONST_ENV_KEYS = ["ATHENA_GENERATOR_REGISTRY_CONST"];
754
+ var EMIT_RELATIONS_ENV_KEYS = ["ATHENA_GENERATOR_EMIT_RELATIONS"];
755
+ var EMIT_REGISTRY_ENV_KEYS = ["ATHENA_GENERATOR_EMIT_REGISTRY"];
756
+ var GATEWAY_BACKEND_ENV_KEYS = ["ATHENA_GENERATOR_BACKEND"];
757
+ var GATEWAY_EXPERIMENTAL_ENV_KEYS = ["ATHENA_GENERATOR_GATEWAY_EXPERIMENTAL"];
758
+ var SCYLLA_PROVIDER_CONTRACTS_ENV_KEYS = ["ATHENA_GENERATOR_SCYLLA_PROVIDER_CONTRACTS"];
759
+ var ENV_ONLY_CONFIG_PATH = "[environment defaults]";
760
+ var NAMING_STYLE_VALUES = ["preserve", "camel", "pascal", "snake", "kebab"];
761
+ var OUTPUT_FORMAT_VALUES = ["define-model", "table-builder"];
762
+ var BACKEND_TYPE_VALUES = ["athena", "postgrest", "postgresql", "scylladb"];
791
763
  function normalizeRawEnvValue(rawValue) {
792
764
  if (rawValue.startsWith('"') && rawValue.endsWith('"') && rawValue.length >= 2) {
793
765
  const inner = rawValue.slice(1, -1);
@@ -879,6 +851,50 @@ function resolveFallbackValue(fallbackKeys) {
879
851
  }
880
852
  return void 0;
881
853
  }
854
+ function normalizeOneOfValue(rawValue, allowedValues, envKeys) {
855
+ if (!rawValue) {
856
+ return void 0;
857
+ }
858
+ if (allowedValues.includes(rawValue)) {
859
+ return rawValue;
860
+ }
861
+ throw new Error(
862
+ `Generator config env vars ${envKeys.join(", ")} must resolve to one of: ${allowedValues.join(", ")}. Received: ${rawValue}.`
863
+ );
864
+ }
865
+ function resolveOptionalOneOf(envKeys, allowedValues) {
866
+ return normalizeOneOfValue(resolveFallbackValue(envKeys), allowedValues, envKeys);
867
+ }
868
+ function resolveOptionalBoolean(envKeys) {
869
+ const rawValue = resolveFallbackValue(envKeys);
870
+ return rawValue === void 0 ? void 0 : parseBooleanFlag2(rawValue, false);
871
+ }
872
+ function resolveOptionalJson(envKeys) {
873
+ const rawValue = resolveFallbackValue(envKeys);
874
+ if (rawValue === void 0) {
875
+ return void 0;
876
+ }
877
+ try {
878
+ return JSON.parse(rawValue);
879
+ } catch (error) {
880
+ const message = error instanceof Error ? error.message : String(error);
881
+ throw new Error(
882
+ `Generator config env vars ${envKeys.join(", ")} must contain valid JSON. ${message}`
883
+ );
884
+ }
885
+ }
886
+ function deriveDatabaseNameFromConnectionString(connectionString) {
887
+ try {
888
+ const parsedUrl = new URL(connectionString);
889
+ if (!POSTGRES_PROTOCOLS.has(parsedUrl.protocol)) {
890
+ return void 0;
891
+ }
892
+ const pathname = parsedUrl.pathname.replace(/^\/+/, "").trim();
893
+ return pathname.length > 0 ? decodeURIComponent(pathname) : void 0;
894
+ } catch {
895
+ return void 0;
896
+ }
897
+ }
882
898
  function normalizeOptionalString(value, fallbackKeys) {
883
899
  if (typeof value === "string") {
884
900
  const trimmed = value.trim();
@@ -952,12 +968,13 @@ function normalizeExperimentalFlags(input) {
952
968
  }
953
969
  function normalizeOutputConfig(output) {
954
970
  return {
971
+ format: output?.format ?? DEFAULT_OUTPUT_FORMAT,
955
972
  targets: {
956
973
  ...DEFAULT_TARGETS,
957
- ...output.targets ?? {}
974
+ ...output?.targets ?? {}
958
975
  },
959
976
  placeholderMap: {
960
- ...output.placeholderMap ?? {}
977
+ ...output?.placeholderMap ?? {}
961
978
  }
962
979
  };
963
980
  }
@@ -968,7 +985,7 @@ function normalizeProviderConfig(provider) {
968
985
  "provider.connectionString",
969
986
  DIRECT_CONNECTION_STRING_ENV_KEYS
970
987
  );
971
- const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS);
988
+ const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS) ?? deriveDatabaseNameFromConnectionString(connectionString);
972
989
  return {
973
990
  ...provider,
974
991
  connectionString: applyPostgresPasswordFallback(connectionString),
@@ -987,11 +1004,7 @@ function normalizeProviderConfig(provider) {
987
1004
  "provider.apiKey",
988
1005
  GATEWAY_API_KEY_ENV_KEYS
989
1006
  );
990
- const database = normalizeRequiredString(
991
- provider.database,
992
- "provider.database",
993
- POSTGRES_DATABASE_ENV_KEYS
994
- );
1007
+ const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS) ?? "postgres";
995
1008
  return {
996
1009
  ...provider,
997
1010
  gatewayUrl,
@@ -1000,6 +1013,26 @@ function normalizeProviderConfig(provider) {
1000
1013
  schemas: normalizeSchemaSelection(provider.schemas)
1001
1014
  };
1002
1015
  }
1016
+ if (provider.kind === "scylla" && provider.mode === "direct") {
1017
+ if (!provider.contactPoints?.length) {
1018
+ throw new Error(
1019
+ "Generator config is missing provider.contactPoints for scylla direct mode."
1020
+ );
1021
+ }
1022
+ const keyspace = normalizeOptionalString(provider.keyspace, []);
1023
+ if (!keyspace) {
1024
+ throw new Error(
1025
+ "Generator config is missing provider.keyspace for scylla direct mode."
1026
+ );
1027
+ }
1028
+ return {
1029
+ kind: "scylla",
1030
+ mode: "direct",
1031
+ contactPoints: provider.contactPoints.slice(),
1032
+ keyspace,
1033
+ datacenter: normalizeOptionalString(provider.datacenter, [])
1034
+ };
1035
+ }
1003
1036
  return provider;
1004
1037
  }
1005
1038
  function isAthenaGeneratorConfig(value) {
@@ -1007,7 +1040,7 @@ function isAthenaGeneratorConfig(value) {
1007
1040
  return false;
1008
1041
  }
1009
1042
  const record = value;
1010
- return Boolean(record.provider && typeof record.provider === "object") && Boolean(record.output && typeof record.output === "object");
1043
+ return Boolean(record.provider && typeof record.provider === "object") && (record.output === void 0 || typeof record.output === "object");
1011
1044
  }
1012
1045
  function normalizeGeneratorConfig(input) {
1013
1046
  return {
@@ -1018,7 +1051,10 @@ function normalizeGeneratorConfig(input) {
1018
1051
  ...input.naming ?? {}
1019
1052
  },
1020
1053
  features: normalizeFeatureFlags(input.features),
1021
- experimental: normalizeExperimentalFlags(input.experimental)
1054
+ experimental: normalizeExperimentalFlags(input.experimental),
1055
+ internal: {
1056
+ ...DEFAULT_INTERNAL_CONFIG
1057
+ }
1022
1058
  };
1023
1059
  }
1024
1060
  function findGeneratorConfigPath(cwd = process.cwd()) {
@@ -1072,16 +1108,123 @@ function importConfigModule(moduleSpecifier) {
1072
1108
  );
1073
1109
  return runtimeImport(moduleSpecifier);
1074
1110
  }
1111
+ function buildEnvironmentOutputConfig() {
1112
+ const format = resolveOptionalOneOf(OUTPUT_FORMAT_ENV_KEYS, OUTPUT_FORMAT_VALUES);
1113
+ const modelTarget = resolveFallbackValue(MODEL_TARGET_ENV_KEYS);
1114
+ const schemaTarget = resolveFallbackValue(SCHEMA_TARGET_ENV_KEYS);
1115
+ const databaseTarget = resolveFallbackValue(DATABASE_TARGET_ENV_KEYS);
1116
+ const registryTarget = resolveFallbackValue(REGISTRY_TARGET_ENV_KEYS);
1117
+ const placeholderMap = resolveOptionalJson(PLACEHOLDER_MAP_ENV_KEYS);
1118
+ if (format === void 0 && modelTarget === void 0 && schemaTarget === void 0 && databaseTarget === void 0 && registryTarget === void 0 && placeholderMap === void 0) {
1119
+ return void 0;
1120
+ }
1121
+ return {
1122
+ format,
1123
+ targets: {
1124
+ ...modelTarget ? { model: modelTarget } : {},
1125
+ ...schemaTarget ? { schema: schemaTarget } : {},
1126
+ ...databaseTarget ? { database: databaseTarget } : {},
1127
+ ...registryTarget ? { registry: registryTarget } : {}
1128
+ },
1129
+ placeholderMap
1130
+ };
1131
+ }
1132
+ function buildEnvironmentNamingConfig() {
1133
+ const modelType = resolveOptionalOneOf(MODEL_TYPE_ENV_KEYS, NAMING_STYLE_VALUES);
1134
+ const modelConst = resolveOptionalOneOf(MODEL_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
1135
+ const schemaConst = resolveOptionalOneOf(SCHEMA_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
1136
+ const databaseConst = resolveOptionalOneOf(DATABASE_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
1137
+ const registryConst = resolveOptionalOneOf(REGISTRY_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
1138
+ if (modelType === void 0 && modelConst === void 0 && schemaConst === void 0 && databaseConst === void 0 && registryConst === void 0) {
1139
+ return void 0;
1140
+ }
1141
+ return {
1142
+ ...modelType ? { modelType } : {},
1143
+ ...modelConst ? { modelConst } : {},
1144
+ ...schemaConst ? { schemaConst } : {},
1145
+ ...databaseConst ? { databaseConst } : {},
1146
+ ...registryConst ? { registryConst } : {}
1147
+ };
1148
+ }
1149
+ function buildEnvironmentFeatureFlags() {
1150
+ const emitRelations = resolveOptionalBoolean(EMIT_RELATIONS_ENV_KEYS);
1151
+ const emitRegistry = resolveOptionalBoolean(EMIT_REGISTRY_ENV_KEYS);
1152
+ if (emitRelations === void 0 && emitRegistry === void 0) {
1153
+ return void 0;
1154
+ }
1155
+ return {
1156
+ ...emitRelations !== void 0 ? { emitRelations } : {},
1157
+ ...emitRegistry !== void 0 ? { emitRegistry } : {}
1158
+ };
1159
+ }
1160
+ function buildEnvironmentExperimentalFlags() {
1161
+ const postgresGatewayIntrospection = resolveOptionalBoolean(GATEWAY_EXPERIMENTAL_ENV_KEYS);
1162
+ const scyllaProviderContracts = resolveOptionalBoolean(SCYLLA_PROVIDER_CONTRACTS_ENV_KEYS);
1163
+ if (postgresGatewayIntrospection === void 0 && scyllaProviderContracts === void 0) {
1164
+ return void 0;
1165
+ }
1166
+ return {
1167
+ ...postgresGatewayIntrospection !== void 0 ? { postgresGatewayIntrospection } : {},
1168
+ ...scyllaProviderContracts !== void 0 ? { scyllaProviderContracts } : {}
1169
+ };
1170
+ }
1171
+ function buildEnvironmentProviderConfig() {
1172
+ const directConnectionString = resolveFallbackValue(DIRECT_CONNECTION_STRING_ENV_KEYS);
1173
+ if (directConnectionString) {
1174
+ return {
1175
+ kind: "postgres",
1176
+ mode: "direct",
1177
+ connectionString: directConnectionString,
1178
+ database: normalizeOptionalString(void 0, POSTGRES_DATABASE_ENV_KEYS),
1179
+ schemas: normalizeSchemaSelection(resolveFallbackValue(GENERATOR_SCHEMA_ENV_KEYS))
1180
+ };
1181
+ }
1182
+ const gatewayUrl = resolveFallbackValue(GATEWAY_URL_ENV_KEYS);
1183
+ const apiKey = resolveFallbackValue(GATEWAY_API_KEY_ENV_KEYS);
1184
+ if (gatewayUrl && apiKey) {
1185
+ const backend = resolveOptionalOneOf(GATEWAY_BACKEND_ENV_KEYS, BACKEND_TYPE_VALUES);
1186
+ return {
1187
+ kind: "postgres",
1188
+ mode: "gateway",
1189
+ gatewayUrl,
1190
+ apiKey,
1191
+ database: normalizeOptionalString(void 0, POSTGRES_DATABASE_ENV_KEYS),
1192
+ schemas: normalizeSchemaSelection(resolveFallbackValue(GENERATOR_SCHEMA_ENV_KEYS)),
1193
+ backend
1194
+ };
1195
+ }
1196
+ return void 0;
1197
+ }
1198
+ function createEnvironmentGeneratorConfig() {
1199
+ const provider = buildEnvironmentProviderConfig();
1200
+ if (!provider) {
1201
+ return void 0;
1202
+ }
1203
+ return {
1204
+ provider,
1205
+ output: buildEnvironmentOutputConfig(),
1206
+ naming: buildEnvironmentNamingConfig(),
1207
+ features: buildEnvironmentFeatureFlags(),
1208
+ experimental: buildEnvironmentExperimentalFlags()
1209
+ };
1210
+ }
1075
1211
  async function loadGeneratorConfig(options = {}) {
1076
1212
  const cwd = options.cwd ?? process.cwd();
1077
1213
  const restoreProjectEnv = applyProjectEnv(cwd);
1078
- const resolvedPath = options.configPath ? path.resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
1079
- if (!resolvedPath) {
1080
- throw new Error(
1081
- `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}`
1082
- );
1083
- }
1084
1214
  try {
1215
+ const resolvedPath = options.configPath ? path.resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
1216
+ if (!resolvedPath) {
1217
+ const environmentConfig = createEnvironmentGeneratorConfig();
1218
+ if (environmentConfig) {
1219
+ return {
1220
+ configPath: ENV_ONLY_CONFIG_PATH,
1221
+ config: normalizeGeneratorConfig(environmentConfig)
1222
+ };
1223
+ }
1224
+ throw new Error(
1225
+ `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}. To run without a config file, set DATABASE_URL (direct mode) or ATHENA_URL + ATHENA_API_KEY (gateway mode).`
1226
+ );
1227
+ }
1085
1228
  const moduleUrl = url.pathToFileURL(resolvedPath);
1086
1229
  const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
1087
1230
  const rawConfig = extractConfigExport(module);
@@ -1094,7 +1237,60 @@ async function loadGeneratorConfig(options = {}) {
1094
1237
  }
1095
1238
  }
1096
1239
 
1097
- // src/generator/renderer.ts
1240
+ // src/generator/placeholders.ts
1241
+ function createStyleTokens(prefix, value) {
1242
+ return {
1243
+ [prefix]: value,
1244
+ [`${prefix}_camel`]: applyNamingStyle(value, "camel"),
1245
+ [`${prefix}_pascal`]: applyNamingStyle(value, "pascal"),
1246
+ [`${prefix}_snake`]: applyNamingStyle(value, "snake"),
1247
+ [`${prefix}_kebab`]: applyNamingStyle(value, "kebab")
1248
+ };
1249
+ }
1250
+ function renderTemplate(template, tokenMap) {
1251
+ return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_match, token) => {
1252
+ if (!(token in tokenMap)) {
1253
+ throw new Error(`Unknown placeholder token "${token}" in template "${template}"`);
1254
+ }
1255
+ return tokenMap[token];
1256
+ });
1257
+ }
1258
+ function resolvePlaceholderMap(baseTokens, outputConfig) {
1259
+ const resolved = {
1260
+ ...baseTokens
1261
+ };
1262
+ const reservedTokenKeys = new Set(Object.keys(baseTokens));
1263
+ const entries = Object.entries(outputConfig.placeholderMap ?? {});
1264
+ for (let index = 0; index < entries.length; index += 1) {
1265
+ const [key, value] = entries[index];
1266
+ if (reservedTokenKeys.has(key)) {
1267
+ continue;
1268
+ }
1269
+ let current = value;
1270
+ for (let depth = 0; depth < 8; depth += 1) {
1271
+ const next = renderTemplate(current, resolved);
1272
+ if (next === current) {
1273
+ break;
1274
+ }
1275
+ current = next;
1276
+ }
1277
+ resolved[key] = current;
1278
+ }
1279
+ return resolved;
1280
+ }
1281
+ function renderOutputPath(template, context, outputConfig) {
1282
+ const baseTokens = {
1283
+ provider: context.provider,
1284
+ kind: context.kind,
1285
+ ...createStyleTokens("database", context.database),
1286
+ ...createStyleTokens("schema", context.schema),
1287
+ ...createStyleTokens("model", context.model)
1288
+ };
1289
+ const tokens = resolvePlaceholderMap(baseTokens, outputConfig);
1290
+ return renderTemplate(template, tokens);
1291
+ }
1292
+
1293
+ // src/generator/render-shared.ts
1098
1294
  function normalizePath(pathValue) {
1099
1295
  return pathValue.replace(/\\/g, "/");
1100
1296
  }
@@ -1107,11 +1303,13 @@ function toModuleImportPath(fromFile, targetFile) {
1107
1303
  );
1108
1304
  return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
1109
1305
  }
1306
+ function resolveOutputPath(target, tokens, config) {
1307
+ return normalizePath(renderOutputPath(target, tokens, config.output));
1308
+ }
1110
1309
  function renderObjectKey(key) {
1111
- const escaped = escapeTypePropertyName(key);
1112
- return escaped.startsWith("'") ? escaped : escaped;
1310
+ return escapeTypePropertyName(key);
1113
1311
  }
1114
- function renderRelation(relation) {
1312
+ function renderRelationLiteral(relation) {
1115
1313
  const through = relation.through ? `,
1116
1314
  through: {
1117
1315
  schema: ${escapeStringLiteral(relation.through.schema)},
@@ -1127,54 +1325,12 @@ function renderRelation(relation) {
1127
1325
  targetColumns: [${relation.targetColumns.map((value) => escapeStringLiteral(value)).join(", ")}]${through}
1128
1326
  }`;
1129
1327
  }
1130
- function renderModelArtifact(snapshot, descriptor, config) {
1131
- const columnLines = Object.values(descriptor.table.columns).map((column) => {
1132
- const propertyName = escapeTypePropertyName(column.name);
1133
- const baseType = resolvePostgresColumnType(column);
1134
- const isOptional = column.isNullable;
1135
- const typeWithNullability = column.isNullable ? `${baseType} | null` : baseType;
1136
- return ` ${propertyName}${isOptional ? "?" : ""}: ${typeWithNullability}`;
1137
- }).join("\n");
1138
- const nullableLines = Object.values(descriptor.table.columns).map((column) => ` ${renderObjectKey(column.name)}: ${column.isNullable ? "true" : "false"}`).join(",\n");
1139
- const relationEntries = Object.entries(descriptor.table.relations);
1140
- const relationBlock = config.features.emitRelations && relationEntries.length > 0 ? `,
1141
- relations: {
1142
- ${relationEntries.map(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelation(relationValue)}`).join(",\n")}
1143
- }` : "";
1144
- const content = `import { defineModel } from '@xylex-group/athena'
1145
-
1146
- export interface ${descriptor.rowTypeName} {
1147
- ${columnLines}
1148
- }
1149
-
1150
- export type ${descriptor.insertTypeName} = Partial<${descriptor.rowTypeName}>
1151
- export type ${descriptor.updateTypeName} = Partial<${descriptor.insertTypeName}>
1152
-
1153
- export const ${descriptor.modelConstName} = defineModel<${descriptor.rowTypeName}, ${descriptor.insertTypeName}, ${descriptor.updateTypeName}>({
1154
- meta: {
1155
- database: ${escapeStringLiteral(snapshot.database)},
1156
- schema: ${escapeStringLiteral(descriptor.schemaName)},
1157
- model: ${escapeStringLiteral(descriptor.tableName)},
1158
- tableName: ${escapeStringLiteral(`${descriptor.schemaName}.${descriptor.tableName}`)},
1159
- primaryKey: [${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")}],
1160
- nullable: {
1161
- ${nullableLines}
1162
- }${relationBlock}
1163
- }
1164
- })
1165
- `;
1166
- return {
1167
- kind: "model",
1168
- path: descriptor.filePath,
1169
- content
1170
- };
1171
- }
1172
1328
  function renderSchemaArtifact(descriptor) {
1173
1329
  const importLines = descriptor.models.map((modelDescriptor) => {
1174
1330
  const importPath = toModuleImportPath(descriptor.filePath, modelDescriptor.filePath);
1175
- return `import { ${modelDescriptor.modelConstName} } from '${importPath}'`;
1331
+ return `import { ${modelDescriptor.exportConstName} } from '${importPath}'`;
1176
1332
  }).join("\n");
1177
- const modelEntries = descriptor.models.map((modelDescriptor) => ` ${renderObjectKey(modelDescriptor.tableName)}: ${modelDescriptor.modelConstName}`).join(",\n");
1333
+ const modelEntries = descriptor.models.map((modelDescriptor) => ` ${renderObjectKey(modelDescriptor.tableName)}: ${modelDescriptor.exportConstName}`).join(",\n");
1178
1334
  const content = `import { defineSchema } from '@xylex-group/athena'
1179
1335
  ${importLines ? `
1180
1336
  ${importLines}
@@ -1209,11 +1365,18 @@ ${schemaEntries}
1209
1365
  content
1210
1366
  };
1211
1367
  }
1212
- function renderRegistryArtifact(registryPath, databasePath, databaseConstName, registryConstName, databaseName) {
1368
+ function renderRegistryArtifact(registryPath, databasePath, databaseConstName, registryConstName, databaseName, generatedAt, outputFormat, schemaVersion) {
1213
1369
  const databaseImportPath = toModuleImportPath(registryPath, databasePath);
1214
1370
  const content = `import { defineRegistry } from '@xylex-group/athena'
1215
1371
  import { ${databaseConstName} } from '${databaseImportPath}'
1216
1372
 
1373
+ export const __athena_schema_meta = {
1374
+ schemaVersion: ${schemaVersion},
1375
+ generatedAt: ${escapeStringLiteral(generatedAt)},
1376
+ database: ${escapeStringLiteral(databaseName)},
1377
+ outputFormat: ${escapeStringLiteral(outputFormat)},
1378
+ } as const
1379
+
1217
1380
  export const ${registryConstName} = defineRegistry({
1218
1381
  ${renderObjectKey(databaseName)}: ${databaseConstName}
1219
1382
  })
@@ -1292,123 +1455,332 @@ function scopeDuplicateDescriptorPathsBySchema(descriptors) {
1292
1455
  }
1293
1456
  return nextDescriptors;
1294
1457
  }
1295
- var ArtifactComposer = class {
1296
- constructor(snapshot, config) {
1297
- this.snapshot = snapshot;
1298
- this.config = config;
1299
- }
1300
- compose() {
1301
- const providerName = this.snapshot.backend;
1302
- const databaseName = this.snapshot.database;
1303
- const modelDescriptors = [];
1304
- for (const schemaName of Object.keys(this.snapshot.schemas).sort()) {
1305
- const schema = this.snapshot.schemas[schemaName];
1306
- for (const tableName of Object.keys(schema.tables).sort()) {
1307
- const table = schema.tables[tableName];
1308
- const rowTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Row`;
1309
- const insertTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Insert`;
1310
- const updateTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Update`;
1311
- const modelConstName = `${toSafeIdentifier(`${schemaName} ${tableName} model`, this.config.naming.modelConst, "model")}`;
1312
- const modelPath = normalizePath(
1313
- renderOutputPath(this.config.output.targets.model, {
1458
+ function composeGeneratorArtifacts(input) {
1459
+ const { snapshot, config, createModelDescriptor, renderModelArtifact: renderModelArtifact3 } = input;
1460
+ const providerName = snapshot.backend;
1461
+ const databaseName = snapshot.database;
1462
+ const modelDescriptors = [];
1463
+ for (const schemaName of Object.keys(snapshot.schemas).sort()) {
1464
+ const schema = snapshot.schemas[schemaName];
1465
+ for (const tableName of Object.keys(schema.tables).sort()) {
1466
+ modelDescriptors.push(
1467
+ createModelDescriptor({
1468
+ providerName,
1469
+ databaseName,
1470
+ schemaName,
1471
+ tableName,
1472
+ table: schema.tables[tableName]
1473
+ })
1474
+ );
1475
+ }
1476
+ }
1477
+ const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
1478
+ let schemaDescriptors = Object.keys(snapshot.schemas).sort().map((schemaName) => ({
1479
+ schemaName,
1480
+ filePath: resolveOutputPath(
1481
+ config.output.targets.schema,
1482
+ {
1483
+ provider: providerName,
1484
+ kind: "schema",
1485
+ database: databaseName,
1486
+ schema: schemaName,
1487
+ model: "index"
1488
+ },
1489
+ config
1490
+ ),
1491
+ schemaConstName: toSafeIdentifier(
1492
+ `${schemaName} schema`,
1493
+ config.naming.schemaConst,
1494
+ "schema"
1495
+ ),
1496
+ models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
1497
+ }));
1498
+ schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
1499
+ const databaseDescriptor = {
1500
+ filePath: resolveOutputPath(
1501
+ config.output.targets.database,
1502
+ {
1503
+ provider: providerName,
1504
+ kind: "database",
1505
+ database: databaseName,
1506
+ schema: "index",
1507
+ model: "index"
1508
+ },
1509
+ config
1510
+ ),
1511
+ databaseConstName: toSafeIdentifier(
1512
+ `${databaseName} database`,
1513
+ config.naming.databaseConst,
1514
+ "database"
1515
+ ),
1516
+ schemas: schemaDescriptors
1517
+ };
1518
+ const files = [];
1519
+ for (const modelDescriptor of scopedModelDescriptors) {
1520
+ files.push(renderModelArtifact3(modelDescriptor));
1521
+ }
1522
+ for (const schemaDescriptor of schemaDescriptors) {
1523
+ files.push(renderSchemaArtifact(schemaDescriptor));
1524
+ }
1525
+ files.push(renderDatabaseArtifact(databaseDescriptor));
1526
+ if (config.features.emitRegistry) {
1527
+ const registryPath = resolveOutputPath(
1528
+ config.output.targets.registry,
1529
+ {
1530
+ provider: providerName,
1531
+ kind: "registry",
1532
+ database: databaseName,
1533
+ schema: "index",
1534
+ model: "index"
1535
+ },
1536
+ config
1537
+ );
1538
+ files.push(
1539
+ renderRegistryArtifact(
1540
+ registryPath,
1541
+ databaseDescriptor.filePath,
1542
+ databaseDescriptor.databaseConstName,
1543
+ toSafeIdentifier("registry", config.naming.registryConst, "registry"),
1544
+ databaseName,
1545
+ snapshot.generatedAt,
1546
+ config.output.format,
1547
+ config.internal.schemaVersion
1548
+ )
1549
+ );
1550
+ }
1551
+ assertNoDuplicatePaths(files);
1552
+ return {
1553
+ snapshot,
1554
+ files
1555
+ };
1556
+ }
1557
+
1558
+ // src/generator/table-builder-renderer.ts
1559
+ var SAFE_NUMBER_TYPES = /* @__PURE__ */ new Set([
1560
+ "int2",
1561
+ "int4",
1562
+ "float4",
1563
+ "float8",
1564
+ "smallint",
1565
+ "integer",
1566
+ "real",
1567
+ "double precision"
1568
+ ]);
1569
+ var JSON_TYPES = /* @__PURE__ */ new Set(["json", "jsonb"]);
1570
+ var BOOLEAN_TYPES = /* @__PURE__ */ new Set(["bool", "boolean"]);
1571
+ var STRING_TYPES = /* @__PURE__ */ new Set([
1572
+ "int8",
1573
+ "bigint",
1574
+ "serial8",
1575
+ "bigserial",
1576
+ "numeric",
1577
+ "decimal",
1578
+ "money",
1579
+ "bytea"
1580
+ ]);
1581
+ function normalizeTypeLabel2(column) {
1582
+ const preferred = (column.udtName || column.dataType).toLowerCase().trim();
1583
+ if (column.arrayDimensions > 0 && preferred.startsWith("_")) {
1584
+ return preferred.slice(1);
1585
+ }
1586
+ return preferred;
1587
+ }
1588
+ function renderColumnBuilder(column) {
1589
+ const label = normalizeTypeLabel2(column);
1590
+ let helper;
1591
+ let expression;
1592
+ if (column.typeKind === "enum" && column.enumValues && column.enumValues.length > 0) {
1593
+ helper = "enumeration";
1594
+ expression = `enumeration([${column.enumValues.map((value) => escapeStringLiteral(value)).join(", ")}] as const)`;
1595
+ } else if (column.arrayDimensions > 0 || JSON_TYPES.has(label) || column.typeKind === "composite") {
1596
+ helper = "json";
1597
+ expression = `json<${resolvePostgresColumnType(column)}>()`;
1598
+ } else if (BOOLEAN_TYPES.has(label)) {
1599
+ helper = "boolean";
1600
+ expression = "boolean()";
1601
+ } else if (SAFE_NUMBER_TYPES.has(label)) {
1602
+ helper = "number";
1603
+ expression = "number()";
1604
+ } else if (STRING_TYPES.has(label)) {
1605
+ helper = "string";
1606
+ expression = "string()";
1607
+ } else {
1608
+ helper = "string";
1609
+ expression = "string()";
1610
+ }
1611
+ if (column.isNullable) {
1612
+ expression = `${expression}.optional()`;
1613
+ }
1614
+ if (column.hasDefault) {
1615
+ expression = `${expression}.defaulted()`;
1616
+ }
1617
+ if (column.isGenerated) {
1618
+ expression = `${expression}.generated()`;
1619
+ }
1620
+ return { helper, expression };
1621
+ }
1622
+ function renderModelArtifact(descriptor, config) {
1623
+ const helperImports = /* @__PURE__ */ new Set(["table"]);
1624
+ const columnLines = Object.entries(descriptor.table.columns).map(([columnName, column]) => {
1625
+ const propertyName = escapeTypePropertyName(columnName);
1626
+ const rendered = renderColumnBuilder(column);
1627
+ helperImports.add(rendered.helper);
1628
+ return ` ${propertyName}: ${rendered.expression}`;
1629
+ }).join(",\n");
1630
+ const helperImportLine = Array.from(helperImports).sort().join(", ");
1631
+ const rowSchemaConstName = `${descriptor.tableConstName}_row_schema`;
1632
+ const insertSchemaConstName = `${descriptor.tableConstName}_insert_schema`;
1633
+ const updateSchemaConstName = `${descriptor.tableConstName}_update_schema`;
1634
+ const formSchemaConstName = `${descriptor.tableConstName}_form_schema`;
1635
+ const relationEntries = Object.entries(descriptor.table.relations);
1636
+ const relationsAssignment = config.features.emitRelations && relationEntries.length > 0 ? `
1637
+ Object.assign(${descriptor.tableConstName}.meta, {
1638
+ relations: {
1639
+ ${relationEntries.map(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
1640
+ }
1641
+ })
1642
+ ` : "";
1643
+ const content = `import { ${helperImportLine} } from '@xylex-group/athena'
1644
+ import type { FormValuesOf, InsertOf, RowOf, UpdateOf } from '@xylex-group/athena'
1645
+
1646
+ export const ${descriptor.tableConstName} = table(${escapeStringLiteral(descriptor.tableName)})
1647
+ .schema(${escapeStringLiteral(descriptor.schemaName)})
1648
+ .columns({
1649
+ ${columnLines}
1650
+ })
1651
+ .primaryKey(${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")})
1652
+ ${relationsAssignment ? `${relationsAssignment}` : ""}
1653
+ export type ${descriptor.rowTypeName} = RowOf<typeof ${descriptor.tableConstName}>
1654
+ export type ${descriptor.insertTypeName} = InsertOf<typeof ${descriptor.tableConstName}>
1655
+ export type ${descriptor.updateTypeName} = UpdateOf<typeof ${descriptor.tableConstName}>
1656
+ export type ${descriptor.formValuesTypeName} = FormValuesOf<typeof ${descriptor.tableConstName}>
1657
+
1658
+ export const ${rowSchemaConstName} = ${descriptor.tableConstName}.schemas.row
1659
+ export const ${insertSchemaConstName} = ${descriptor.tableConstName}.schemas.insert
1660
+ export const ${updateSchemaConstName} = ${descriptor.tableConstName}.schemas.update
1661
+ export const ${formSchemaConstName} = ${descriptor.tableConstName}.schemas.form
1662
+ `;
1663
+ return {
1664
+ kind: "model",
1665
+ path: descriptor.filePath,
1666
+ content
1667
+ };
1668
+ }
1669
+ function generateTableBuilderArtifactsFromSnapshot(snapshot, config) {
1670
+ const normalizedConfig = "internal" in config ? config : normalizeGeneratorConfig(config);
1671
+ return composeGeneratorArtifacts({
1672
+ snapshot,
1673
+ config: normalizedConfig,
1674
+ createModelDescriptor({ providerName, databaseName, schemaName, tableName, table }) {
1675
+ const tableConstName = toSafeIdentifier(tableName, "preserve", "table");
1676
+ return {
1677
+ schemaName,
1678
+ tableName,
1679
+ filePath: resolveOutputPath(
1680
+ normalizedConfig.output.targets.model,
1681
+ {
1682
+ provider: providerName,
1683
+ kind: "model",
1684
+ database: databaseName,
1685
+ schema: schemaName,
1686
+ model: tableName
1687
+ },
1688
+ normalizedConfig
1689
+ ),
1690
+ rowTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Row`,
1691
+ insertTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Insert`,
1692
+ updateTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Update`,
1693
+ formValuesTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}FormValues`,
1694
+ tableConstName,
1695
+ exportConstName: tableConstName,
1696
+ table
1697
+ };
1698
+ },
1699
+ renderModelArtifact: (descriptor) => renderModelArtifact(descriptor, normalizedConfig)
1700
+ });
1701
+ }
1702
+
1703
+ // src/generator/renderer.ts
1704
+ function renderModelArtifact2(databaseName, descriptor, config) {
1705
+ const columnLines = Object.values(descriptor.table.columns).map((column) => {
1706
+ const propertyName = escapeTypePropertyName(column.name);
1707
+ const baseType = resolvePostgresColumnType(column);
1708
+ const isOptional = column.isNullable;
1709
+ const typeWithNullability = column.isNullable ? `${baseType} | null` : baseType;
1710
+ return ` ${propertyName}${isOptional ? "?" : ""}: ${typeWithNullability}`;
1711
+ }).join("\n");
1712
+ const nullableLines = Object.values(descriptor.table.columns).map((column) => ` ${renderObjectKey(column.name)}: ${column.isNullable ? "true" : "false"}`).join(",\n");
1713
+ const relationEntries = Object.entries(descriptor.table.relations);
1714
+ const relationBlock = config.features.emitRelations && relationEntries.length > 0 ? `,
1715
+ relations: {
1716
+ ${relationEntries.map(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
1717
+ }` : "";
1718
+ const content = `import { defineModel } from '@xylex-group/athena'
1719
+
1720
+ export interface ${descriptor.rowTypeName} {
1721
+ ${columnLines}
1722
+ }
1723
+
1724
+ export type ${descriptor.insertTypeName} = Partial<${descriptor.rowTypeName}>
1725
+ export type ${descriptor.updateTypeName} = Partial<${descriptor.insertTypeName}>
1726
+
1727
+ export const ${descriptor.modelConstName} = defineModel<${descriptor.rowTypeName}, ${descriptor.insertTypeName}, ${descriptor.updateTypeName}>({
1728
+ meta: {
1729
+ database: ${escapeStringLiteral(databaseName)},
1730
+ schema: ${escapeStringLiteral(descriptor.schemaName)},
1731
+ model: ${escapeStringLiteral(descriptor.tableName)},
1732
+ tableName: ${escapeStringLiteral(`${descriptor.schemaName}.${descriptor.tableName}`)},
1733
+ primaryKey: [${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")}],
1734
+ nullable: {
1735
+ ${nullableLines}
1736
+ }${relationBlock}
1737
+ }
1738
+ })
1739
+ `;
1740
+ return {
1741
+ kind: "model",
1742
+ path: descriptor.filePath,
1743
+ content
1744
+ };
1745
+ }
1746
+ function generateArtifactsFromSnapshot(snapshot, config) {
1747
+ const normalizedConfig = "internal" in config ? config : normalizeGeneratorConfig(config);
1748
+ if (normalizedConfig.output.format === "table-builder") {
1749
+ return generateTableBuilderArtifactsFromSnapshot(snapshot, normalizedConfig);
1750
+ }
1751
+ return composeGeneratorArtifacts({
1752
+ snapshot,
1753
+ config: normalizedConfig,
1754
+ createModelDescriptor({ providerName, databaseName, schemaName, tableName, table }) {
1755
+ const modelConstName = toSafeIdentifier(
1756
+ `${schemaName} ${tableName} model`,
1757
+ normalizedConfig.naming.modelConst,
1758
+ "model"
1759
+ );
1760
+ return {
1761
+ schemaName,
1762
+ tableName,
1763
+ filePath: resolveOutputPath(
1764
+ normalizedConfig.output.targets.model,
1765
+ {
1314
1766
  provider: providerName,
1315
1767
  kind: "model",
1316
1768
  database: databaseName,
1317
1769
  schema: schemaName,
1318
1770
  model: tableName
1319
- }, this.config.output)
1320
- );
1321
- modelDescriptors.push({
1322
- schemaName,
1323
- tableName,
1324
- filePath: modelPath,
1325
- rowTypeName,
1326
- insertTypeName,
1327
- updateTypeName,
1328
- modelConstName,
1329
- table
1330
- });
1331
- }
1332
- }
1333
- const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
1334
- let schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
1335
- const schemaPath = normalizePath(
1336
- renderOutputPath(this.config.output.targets.schema, {
1337
- provider: providerName,
1338
- kind: "schema",
1339
- database: databaseName,
1340
- schema: schemaName,
1341
- model: "index"
1342
- }, this.config.output)
1343
- );
1344
- return {
1345
- schemaName,
1346
- filePath: schemaPath,
1347
- schemaConstName: toSafeIdentifier(
1348
- `${schemaName} schema`,
1349
- this.config.naming.schemaConst,
1350
- "schema"
1771
+ },
1772
+ normalizedConfig
1351
1773
  ),
1352
- models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
1774
+ rowTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Row`,
1775
+ insertTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Insert`,
1776
+ updateTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Update`,
1777
+ modelConstName,
1778
+ exportConstName: modelConstName,
1779
+ table
1353
1780
  };
1354
- });
1355
- schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
1356
- const databasePath = normalizePath(
1357
- renderOutputPath(this.config.output.targets.database, {
1358
- provider: providerName,
1359
- kind: "database",
1360
- database: databaseName,
1361
- schema: "index",
1362
- model: "index"
1363
- }, this.config.output)
1364
- );
1365
- const databaseDescriptor = {
1366
- filePath: databasePath,
1367
- databaseConstName: toSafeIdentifier(
1368
- `${databaseName} database`,
1369
- this.config.naming.databaseConst,
1370
- "database"
1371
- ),
1372
- schemas: schemaDescriptors
1373
- };
1374
- const files = [];
1375
- for (const modelDescriptor of scopedModelDescriptors) {
1376
- files.push(renderModelArtifact(this.snapshot, modelDescriptor, this.config));
1377
- }
1378
- for (const schemaDescriptor of schemaDescriptors) {
1379
- files.push(renderSchemaArtifact(schemaDescriptor));
1380
- }
1381
- files.push(renderDatabaseArtifact(databaseDescriptor));
1382
- if (this.config.features.emitRegistry) {
1383
- const registryPath = normalizePath(
1384
- renderOutputPath(this.config.output.targets.registry, {
1385
- provider: providerName,
1386
- kind: "registry",
1387
- database: databaseName,
1388
- schema: "index",
1389
- model: "index"
1390
- }, this.config.output)
1391
- );
1392
- files.push(
1393
- renderRegistryArtifact(
1394
- registryPath,
1395
- databaseDescriptor.filePath,
1396
- databaseDescriptor.databaseConstName,
1397
- toSafeIdentifier("registry", this.config.naming.registryConst, "registry"),
1398
- databaseName
1399
- )
1400
- );
1401
- }
1402
- assertNoDuplicatePaths(files);
1403
- return {
1404
- snapshot: this.snapshot,
1405
- files
1406
- };
1407
- }
1408
- };
1409
- function generateArtifactsFromSnapshot(snapshot, config) {
1410
- const normalizedConfig = "naming" in config && "features" in config && "experimental" in config ? config : normalizeGeneratorConfig(config);
1411
- return new ArtifactComposer(snapshot, normalizedConfig).compose();
1781
+ },
1782
+ renderModelArtifact: (descriptor) => renderModelArtifact2(snapshot.database, descriptor, normalizedConfig)
1783
+ });
1412
1784
  }
1413
1785
 
1414
1786
  // src/gateway/url.ts
@@ -1513,7 +1885,7 @@ var getSessionCookie = (request, config) => {
1513
1885
 
1514
1886
  // package.json
1515
1887
  var package_default = {
1516
- version: "2.7.0"
1888
+ version: "2.8.0"
1517
1889
  };
1518
1890
 
1519
1891
  // src/sdk-version.ts
@@ -3460,11 +3832,12 @@ function createAuthClient(config = {}) {
3460
3832
  // src/db/module.ts
3461
3833
  function createDbModule(input) {
3462
3834
  const db = {
3463
- from(table, options) {
3464
- return input.from(table, options);
3465
- },
3466
- select(table, columns, options) {
3467
- return input.from(table).select(columns, options);
3835
+ from: input.from,
3836
+ select(table, first, second) {
3837
+ if (first && typeof first === "object" && !Array.isArray(first)) {
3838
+ return input.from(table).select(void 0, first);
3839
+ }
3840
+ return input.from(table).select(first, second);
3468
3841
  },
3469
3842
  insert(table, values, options) {
3470
3843
  return Array.isArray(values) ? input.from(table).insert(values, options) : input.from(table).insert(values, options);
@@ -4131,6 +4504,15 @@ function appendQuery(path, query) {
4131
4504
  function storagePath(path) {
4132
4505
  return path;
4133
4506
  }
4507
+ function resolveStorageEndpointPath(endpoint, runtimeOptions) {
4508
+ if (!runtimeOptions?.stripBasePath) {
4509
+ return endpoint;
4510
+ }
4511
+ const [pathname, queryText] = String(endpoint).split("?", 2);
4512
+ const trimmedPathname = pathname.startsWith("/storage/") ? pathname.slice("/storage".length) : pathname === "/storage" ? "/" : pathname;
4513
+ const resolvedPath = trimmedPathname.startsWith("/") ? trimmedPathname : `/${trimmedPathname}`;
4514
+ return storagePath(queryText ? `${resolvedPath}?${queryText}` : resolvedPath);
4515
+ }
4134
4516
  function withPathParam(path, name, value) {
4135
4517
  return path.replace(`{${name}}`, encodeURIComponent(value));
4136
4518
  }
@@ -4169,8 +4551,8 @@ async function callStorageEndpoint(gateway, endpoint, method, envelope, payload,
4169
4551
  let url;
4170
4552
  let headers;
4171
4553
  try {
4172
- const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : gateway.baseUrl;
4173
- url = buildAthenaGatewayUrl(baseUrl, endpoint);
4554
+ const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : runtimeOptions?.baseUrl ? normalizeAthenaGatewayBaseUrl(runtimeOptions.baseUrl) : gateway.baseUrl;
4555
+ url = buildAthenaGatewayUrl(baseUrl, resolveStorageEndpointPath(endpoint, runtimeOptions));
4174
4556
  headers = gateway.buildHeaders(options);
4175
4557
  } catch (error) {
4176
4558
  return rejectStorageError(
@@ -4294,8 +4676,8 @@ async function callStorageBinaryEndpoint(gateway, endpoint, method, options, run
4294
4676
  let url;
4295
4677
  let headers;
4296
4678
  try {
4297
- const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : gateway.baseUrl;
4298
- url = buildAthenaGatewayUrl(baseUrl, endpoint);
4679
+ const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : runtimeOptions?.baseUrl ? normalizeAthenaGatewayBaseUrl(runtimeOptions.baseUrl) : gateway.baseUrl;
4680
+ url = buildAthenaGatewayUrl(baseUrl, resolveStorageEndpointPath(endpoint, runtimeOptions));
4299
4681
  headers = gateway.buildHeaders(options);
4300
4682
  } catch (error) {
4301
4683
  return rejectStorageError(
@@ -4456,8 +4838,8 @@ async function callStorageUploadBinaryEndpoint(gateway, endpoint, body, options,
4456
4838
  let url;
4457
4839
  let headers;
4458
4840
  try {
4459
- const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : gateway.baseUrl;
4460
- url = buildAthenaGatewayUrl(baseUrl, endpoint);
4841
+ const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : runtimeOptions?.baseUrl ? normalizeAthenaGatewayBaseUrl(runtimeOptions.baseUrl) : gateway.baseUrl;
4842
+ url = buildAthenaGatewayUrl(baseUrl, resolveStorageEndpointPath(endpoint, runtimeOptions));
4461
4843
  headers = gateway.buildHeaders(options);
4462
4844
  } catch (error) {
4463
4845
  return rejectStorageError(
@@ -4581,6 +4963,7 @@ async function callStorageUploadBinaryEndpoint(gateway, endpoint, body, options,
4581
4963
  return parsedBody.parsed.data;
4582
4964
  }
4583
4965
  function createStorageModule(gateway, runtimeOptions) {
4966
+ const resolvedRuntimeOptions = runtimeOptions;
4584
4967
  const callRaw = (path, method, payload, options) => callStorageEndpoint(
4585
4968
  gateway,
4586
4969
  storagePath(path),
@@ -4588,7 +4971,7 @@ function createStorageModule(gateway, runtimeOptions) {
4588
4971
  "raw",
4589
4972
  payload,
4590
4973
  options,
4591
- runtimeOptions
4974
+ resolvedRuntimeOptions
4592
4975
  );
4593
4976
  const callAthena2 = (path, method, payload, options) => callStorageEndpoint(
4594
4977
  gateway,
@@ -4597,7 +4980,7 @@ function createStorageModule(gateway, runtimeOptions) {
4597
4980
  "athena",
4598
4981
  payload,
4599
4982
  options,
4600
- runtimeOptions
4983
+ resolvedRuntimeOptions
4601
4984
  );
4602
4985
  const base = {
4603
4986
  listStorageCatalogs(options) {
@@ -4639,7 +5022,7 @@ function createStorageModule(gateway, runtimeOptions) {
4639
5022
  withPathParam("/storage/files/{file_id}/proxy", "file_id", fileId),
4640
5023
  query
4641
5024
  );
4642
- return callStorageBinaryEndpoint(gateway, storagePath(path), "GET", options, runtimeOptions);
5025
+ return callStorageBinaryEndpoint(gateway, storagePath(path), "GET", options, resolvedRuntimeOptions);
4643
5026
  },
4644
5027
  updateStorageFile(fileId, input, options) {
4645
5028
  return callAthena2(withPathParam("/storage/files/{file_id}", "file_id", fileId), "PATCH", input, options);
@@ -4686,7 +5069,7 @@ function createStorageModule(gateway, runtimeOptions) {
4686
5069
  storagePath(withPathParam("/storage/files/{file_id}/upload", "file_id", fileId)),
4687
5070
  body,
4688
5071
  options,
4689
- runtimeOptions
5072
+ resolvedRuntimeOptions
4690
5073
  );
4691
5074
  },
4692
5075
  search(input, options) {
@@ -4882,6 +5265,13 @@ function createStorageModule(gateway, runtimeOptions) {
4882
5265
  };
4883
5266
  }
4884
5267
 
5268
+ // src/client-builder.ts
5269
+ var DEFAULT_BACKEND = { type: "athena" };
5270
+ function toBackendConfig(value) {
5271
+ if (!value) return DEFAULT_BACKEND;
5272
+ return typeof value === "string" ? { type: value } : value;
5273
+ }
5274
+
4885
5275
  // src/query-ast.ts
4886
5276
  var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
4887
5277
  var FILTER_OPERATORS = /* @__PURE__ */ new Set([
@@ -5504,20 +5894,437 @@ function createSelectTransportPlan(input) {
5504
5894
  };
5505
5895
  }
5506
5896
 
5897
+ // src/query-debug-ast.ts
5898
+ var ATHENA_DEBUG_AST_KEY = "__athenaDebugAst";
5899
+ function cloneConditions(conditions) {
5900
+ return conditions.map((condition) => ({ ...condition }));
5901
+ }
5902
+ function cloneTableBuilderStateAst(state) {
5903
+ return {
5904
+ conditions: cloneConditions(state.conditions),
5905
+ limit: state.limit,
5906
+ offset: state.offset,
5907
+ order: state.order ? { ...state.order } : void 0,
5908
+ currentPage: state.currentPage,
5909
+ pageSize: state.pageSize,
5910
+ totalPages: state.totalPages
5911
+ };
5912
+ }
5913
+ function cloneRpcBuilderStateAst(state) {
5914
+ return {
5915
+ filters: state.filters.map((filter) => ({ ...filter })),
5916
+ limit: state.limit,
5917
+ offset: state.offset,
5918
+ order: state.order ? { ...state.order } : void 0
5919
+ };
5920
+ }
5921
+ function toSelectTransportAst(plan) {
5922
+ if (plan.kind === "query") {
5923
+ return {
5924
+ mode: "typed-query",
5925
+ endpoint: "/gateway/query",
5926
+ payload: plan.payload
5927
+ };
5928
+ }
5929
+ return {
5930
+ mode: plan.payload.select !== void 0 ? "structured-fetch" : "compiled-fetch",
5931
+ endpoint: "/gateway/fetch",
5932
+ payload: plan.payload
5933
+ };
5934
+ }
5935
+ function resolveDebugTableName(tableName) {
5936
+ return tableName ?? "__unknown_table__";
5937
+ }
5938
+ function buildSelectDebugAst(input) {
5939
+ return {
5940
+ version: 1,
5941
+ kind: "select",
5942
+ tableName: input.tableName,
5943
+ input: {
5944
+ columns: input.columns,
5945
+ state: cloneTableBuilderStateAst(input.state)
5946
+ },
5947
+ transport: toSelectTransportAst(input.plan)
5948
+ };
5949
+ }
5950
+ function buildFindManyCompiledDebugAst(input) {
5951
+ return {
5952
+ version: 1,
5953
+ kind: "findMany",
5954
+ tableName: input.tableName,
5955
+ input: {
5956
+ select: input.options.select,
5957
+ where: input.options.where,
5958
+ orderBy: input.options.orderBy,
5959
+ limit: input.options.limit
5960
+ },
5961
+ compiled: {
5962
+ columns: input.compiledColumns,
5963
+ baseState: cloneTableBuilderStateAst(input.baseState),
5964
+ executionState: cloneTableBuilderStateAst(input.executionState)
5965
+ },
5966
+ transport: planToFindManyTransport(input.plan)
5967
+ };
5968
+ }
5969
+ function buildFindManyDirectDebugAst(input) {
5970
+ return {
5971
+ version: 1,
5972
+ kind: "findMany",
5973
+ tableName: input.tableName,
5974
+ input: {
5975
+ select: input.options.select,
5976
+ where: input.options.where,
5977
+ orderBy: input.options.orderBy,
5978
+ limit: input.options.limit
5979
+ },
5980
+ compiled: {
5981
+ columns: input.compiledColumns,
5982
+ baseState: cloneTableBuilderStateAst(input.baseState),
5983
+ executionState: cloneTableBuilderStateAst(input.executionState)
5984
+ },
5985
+ transport: {
5986
+ mode: "direct-ast-fetch",
5987
+ endpoint: "/gateway/fetch",
5988
+ payload: input.payload
5989
+ }
5990
+ };
5991
+ }
5992
+ function planToFindManyTransport(plan) {
5993
+ if (plan.kind === "query") {
5994
+ return {
5995
+ mode: "compiled-query",
5996
+ endpoint: "/gateway/query",
5997
+ payload: plan.payload
5998
+ };
5999
+ }
6000
+ return {
6001
+ mode: plan.payload.select !== void 0 ? "structured-fetch" : "compiled-fetch",
6002
+ endpoint: "/gateway/fetch",
6003
+ payload: plan.payload
6004
+ };
6005
+ }
6006
+ function buildInsertDebugAst(payload) {
6007
+ return {
6008
+ version: 1,
6009
+ kind: "insert",
6010
+ tableName: payload.table_name,
6011
+ input: {
6012
+ values: payload.insert_body,
6013
+ returning: payload.columns,
6014
+ count: payload.count,
6015
+ head: payload.head,
6016
+ defaultToNull: payload.default_to_null
6017
+ },
6018
+ transport: {
6019
+ mode: "insert",
6020
+ endpoint: "/gateway/insert",
6021
+ payload
6022
+ }
6023
+ };
6024
+ }
6025
+ function buildUpsertDebugAst(payload) {
6026
+ return {
6027
+ version: 1,
6028
+ kind: "upsert",
6029
+ tableName: payload.table_name,
6030
+ input: {
6031
+ values: payload.insert_body,
6032
+ updateBody: payload.update_body,
6033
+ onConflict: payload.on_conflict,
6034
+ returning: payload.columns,
6035
+ count: payload.count,
6036
+ head: payload.head,
6037
+ defaultToNull: payload.default_to_null
6038
+ },
6039
+ transport: {
6040
+ mode: "upsert",
6041
+ endpoint: "/gateway/insert",
6042
+ payload
6043
+ }
6044
+ };
6045
+ }
6046
+ function buildUpdateDebugAst(input) {
6047
+ return {
6048
+ version: 1,
6049
+ kind: "update",
6050
+ tableName: resolveDebugTableName(input.payload.table_name),
6051
+ input: {
6052
+ values: input.payload.set,
6053
+ state: cloneTableBuilderStateAst(input.state),
6054
+ returning: input.payload.columns
6055
+ },
6056
+ transport: {
6057
+ mode: "update",
6058
+ endpoint: "/gateway/update",
6059
+ payload: input.payload
6060
+ }
6061
+ };
6062
+ }
6063
+ function buildDeleteDebugAst(input) {
6064
+ return {
6065
+ version: 1,
6066
+ kind: "delete",
6067
+ tableName: input.payload.table_name,
6068
+ input: {
6069
+ resourceId: input.payload.resource_id,
6070
+ state: cloneTableBuilderStateAst(input.state),
6071
+ returning: input.payload.columns
6072
+ },
6073
+ transport: {
6074
+ mode: "delete",
6075
+ endpoint: "/gateway/delete",
6076
+ payload: input.payload
6077
+ }
6078
+ };
6079
+ }
6080
+ function buildRpcDebugAst(input) {
6081
+ return {
6082
+ version: 1,
6083
+ kind: "rpc",
6084
+ functionName: input.functionName,
6085
+ input: {
6086
+ args: input.args,
6087
+ select: input.selectedColumns,
6088
+ state: cloneRpcBuilderStateAst(input.state)
6089
+ },
6090
+ transport: {
6091
+ mode: input.endpoint === "/gateway/rpc" ? "rpc-post" : "rpc-get",
6092
+ endpoint: input.endpoint,
6093
+ payload: input.payload
6094
+ }
6095
+ };
6096
+ }
6097
+ function buildRawQueryDebugAst(query) {
6098
+ return {
6099
+ version: 1,
6100
+ kind: "query",
6101
+ input: {
6102
+ query
6103
+ },
6104
+ transport: {
6105
+ mode: "raw-query",
6106
+ endpoint: "/gateway/query",
6107
+ payload: {
6108
+ query
6109
+ }
6110
+ }
6111
+ };
6112
+ }
6113
+ function attachAthenaDebugAst(target, ast) {
6114
+ if (!ast) {
6115
+ return;
6116
+ }
6117
+ if (!target || typeof target !== "object" && typeof target !== "function") {
6118
+ return;
6119
+ }
6120
+ Object.defineProperty(target, ATHENA_DEBUG_AST_KEY, {
6121
+ value: ast,
6122
+ enumerable: false,
6123
+ configurable: true,
6124
+ writable: false
6125
+ });
6126
+ }
6127
+
6128
+ // src/query-tracing.ts
6129
+ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
6130
+ "src\\client.ts",
6131
+ "src/client.ts",
6132
+ "src\\query-tracing.ts",
6133
+ "src/query-tracing.ts",
6134
+ "dist\\client.",
6135
+ "dist/client.",
6136
+ "dist\\query-tracing.",
6137
+ "dist/query-tracing.",
6138
+ "node_modules\\@xylex-group\\athena",
6139
+ "node_modules/@xylex-group/athena",
6140
+ "node:internal",
6141
+ "internal/process"
6142
+ ];
6143
+ function parseQueryTraceCallsiteFrame(frame) {
6144
+ const trimmed = frame.trim();
6145
+ if (!trimmed) {
6146
+ return null;
6147
+ }
6148
+ let body = trimmed.replace(/^at\s+/, "");
6149
+ if (body.startsWith("async ")) {
6150
+ body = body.slice(6);
6151
+ }
6152
+ let functionName;
6153
+ let location = body;
6154
+ const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
6155
+ if (wrappedMatch) {
6156
+ functionName = wrappedMatch[1].trim() || void 0;
6157
+ location = wrappedMatch[2].trim();
6158
+ }
6159
+ const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
6160
+ if (!locationMatch) {
6161
+ return null;
6162
+ }
6163
+ const filePath = locationMatch[1].replace(/^file:\/\//, "");
6164
+ const line = Number(locationMatch[2]);
6165
+ const column = Number(locationMatch[3]);
6166
+ if (!Number.isFinite(line) || !Number.isFinite(column)) {
6167
+ return null;
6168
+ }
6169
+ const normalizedPath = filePath.replace(/\\/g, "/");
6170
+ const fileName = normalizedPath.split("/").at(-1) ?? filePath;
6171
+ return {
6172
+ filePath,
6173
+ fileName,
6174
+ line,
6175
+ column,
6176
+ frame: trimmed,
6177
+ functionName
6178
+ };
6179
+ }
6180
+ function captureQueryTraceCallsite() {
6181
+ const stack = new Error().stack;
6182
+ if (!stack) return null;
6183
+ const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
6184
+ for (const frame of frames) {
6185
+ if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
6186
+ continue;
6187
+ }
6188
+ const callsite = parseQueryTraceCallsiteFrame(frame);
6189
+ if (callsite) return callsite;
6190
+ }
6191
+ const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
6192
+ return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
6193
+ }
6194
+ function defaultQueryTraceLogger(event) {
6195
+ const target = event.table ?? event.functionName ?? "gateway";
6196
+ const outcomeState = event.outcome?.error ? "error" : "ok";
6197
+ const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
6198
+ console.info(banner, event);
6199
+ }
6200
+ function captureTraceCallsite(tracer) {
6201
+ return tracer?.captureCallsite() ?? null;
6202
+ }
6203
+ function createTraceCallsiteStore(tracer, initialCallsite) {
6204
+ let storedCallsite = initialCallsite ?? void 0;
6205
+ return {
6206
+ resolve(callsite) {
6207
+ if (callsite) {
6208
+ storedCallsite = callsite;
6209
+ return callsite;
6210
+ }
6211
+ if (storedCallsite !== void 0) {
6212
+ return storedCallsite;
6213
+ }
6214
+ const capturedCallsite = captureTraceCallsite(tracer);
6215
+ if (capturedCallsite) {
6216
+ storedCallsite = capturedCallsite;
6217
+ }
6218
+ return capturedCallsite;
6219
+ }
6220
+ };
6221
+ }
6222
+ function createQueryTracer(experimental) {
6223
+ const traceOption = experimental?.traceQueries;
6224
+ if (!traceOption) {
6225
+ return void 0;
6226
+ }
6227
+ const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
6228
+ const emit = (event) => {
6229
+ try {
6230
+ logger(event);
6231
+ } catch (error) {
6232
+ console.warn("[athena-js][trace] logger failed", error);
6233
+ }
6234
+ };
6235
+ return {
6236
+ captureCallsite: captureQueryTraceCallsite,
6237
+ publishSuccess(context, result, durationMs, callsite) {
6238
+ emit({
6239
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6240
+ durationMs,
6241
+ operation: context.operation,
6242
+ endpoint: context.endpoint,
6243
+ table: context.table,
6244
+ functionName: context.functionName,
6245
+ sql: context.sql,
6246
+ payload: context.payload,
6247
+ ast: context.ast,
6248
+ options: context.options,
6249
+ callsite,
6250
+ outcome: {
6251
+ status: result.status,
6252
+ error: result.error,
6253
+ errorDetails: result.errorDetails ?? null,
6254
+ count: result.count ?? null,
6255
+ data: result.data,
6256
+ raw: result.raw
6257
+ }
6258
+ });
6259
+ },
6260
+ publishFailure(context, error, durationMs, callsite) {
6261
+ emit({
6262
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6263
+ durationMs,
6264
+ operation: context.operation,
6265
+ endpoint: context.endpoint,
6266
+ table: context.table,
6267
+ functionName: context.functionName,
6268
+ sql: context.sql,
6269
+ payload: context.payload,
6270
+ ast: context.ast,
6271
+ options: context.options,
6272
+ callsite,
6273
+ thrownError: error
6274
+ });
6275
+ }
6276
+ };
6277
+ }
6278
+ async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
6279
+ const callsite = tracer ? callsiteOverride ?? tracer.captureCallsite() : null;
6280
+ const startedAt = tracer ? Date.now() : 0;
6281
+ try {
6282
+ const result = await runner();
6283
+ attachAthenaDebugAst(result, context.ast);
6284
+ if (tracer) {
6285
+ tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
6286
+ }
6287
+ return result;
6288
+ } catch (error) {
6289
+ attachAthenaDebugAst(error, context.ast);
6290
+ if (tracer) {
6291
+ tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
6292
+ }
6293
+ throw error;
6294
+ }
6295
+ }
6296
+
6297
+ // src/schema/model-target.ts
6298
+ function normalizeOptionalName(value) {
6299
+ const normalized = value?.trim();
6300
+ return normalized ? normalized : void 0;
6301
+ }
6302
+ function isAthenaModelTarget(value) {
6303
+ if (!value || typeof value !== "object") {
6304
+ return false;
6305
+ }
6306
+ const candidate = value;
6307
+ return Boolean(candidate.meta && Array.isArray(candidate.meta.primaryKey));
6308
+ }
6309
+ function resolveAthenaModelTargetTableName(target, options = {}) {
6310
+ const explicitTableName = normalizeOptionalName(target.meta.tableName);
6311
+ if (explicitTableName) {
6312
+ return explicitTableName;
6313
+ }
6314
+ const schemaName = normalizeOptionalName(target.meta.schema ?? options.fallbackSchema);
6315
+ const modelName = normalizeOptionalName(target.meta.model ?? options.fallbackModel);
6316
+ if (!modelName) {
6317
+ throw new Error(
6318
+ "Athena model target is missing meta.model or meta.tableName. Provide one of those before calling from(model)."
6319
+ );
6320
+ }
6321
+ return schemaName ? `${schemaName}.${modelName}` : modelName;
6322
+ }
6323
+
5507
6324
  // src/client.ts
5508
6325
  var DEFAULT_COLUMNS = "*";
5509
6326
  var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
5510
6327
  var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
5511
- var QUERY_TRACE_STACK_SKIP_PATTERNS = [
5512
- "src\\client.ts",
5513
- "src/client.ts",
5514
- "dist\\client.",
5515
- "dist/client.",
5516
- "node_modules\\@xylex-group\\athena",
5517
- "node_modules/@xylex-group/athena",
5518
- "node:internal",
5519
- "internal/process"
5520
- ];
5521
6328
  function formatResult(response) {
5522
6329
  const result = {
5523
6330
  data: response.data ?? null,
@@ -5659,154 +6466,6 @@ function createResultError(response, result, normalized) {
5659
6466
  raw: result.raw
5660
6467
  };
5661
6468
  }
5662
- function parseQueryTraceCallsiteFrame(frame) {
5663
- const trimmed = frame.trim();
5664
- if (!trimmed) {
5665
- return null;
5666
- }
5667
- let body = trimmed.replace(/^at\s+/, "");
5668
- if (body.startsWith("async ")) {
5669
- body = body.slice(6);
5670
- }
5671
- let functionName;
5672
- let location = body;
5673
- const wrappedMatch = body.match(/^(.*?)\s+\((.*)\)$/);
5674
- if (wrappedMatch) {
5675
- functionName = wrappedMatch[1].trim() || void 0;
5676
- location = wrappedMatch[2].trim();
5677
- }
5678
- const locationMatch = location.match(/^(.*):(\d+):(\d+)$/);
5679
- if (!locationMatch) {
5680
- return null;
5681
- }
5682
- const filePath = locationMatch[1].replace(/^file:\/\//, "");
5683
- const line = Number(locationMatch[2]);
5684
- const column = Number(locationMatch[3]);
5685
- if (!Number.isFinite(line) || !Number.isFinite(column)) {
5686
- return null;
5687
- }
5688
- const normalizedPath = filePath.replace(/\\/g, "/");
5689
- const fileName = normalizedPath.split("/").at(-1) ?? filePath;
5690
- return {
5691
- filePath,
5692
- fileName,
5693
- line,
5694
- column,
5695
- frame: trimmed,
5696
- functionName
5697
- };
5698
- }
5699
- function captureQueryTraceCallsite() {
5700
- const stack = new Error().stack;
5701
- if (!stack) return null;
5702
- const frames = stack.split("\n").slice(2).map((frame) => frame.trim()).filter(Boolean);
5703
- for (const frame of frames) {
5704
- if (QUERY_TRACE_STACK_SKIP_PATTERNS.some((pattern) => frame.includes(pattern))) {
5705
- continue;
5706
- }
5707
- const callsite = parseQueryTraceCallsiteFrame(frame);
5708
- if (callsite) return callsite;
5709
- }
5710
- const fallback = frames.find((frame) => !frame.includes("captureQueryTraceCallsite"));
5711
- return fallback ? parseQueryTraceCallsiteFrame(fallback) : null;
5712
- }
5713
- function defaultQueryTraceLogger(event) {
5714
- const target = event.table ?? event.functionName ?? "gateway";
5715
- const outcomeState = event.outcome?.error ? "error" : "ok";
5716
- const banner = `[athena-js][trace] ${event.operation.toUpperCase()} ${event.endpoint} ${target} ${event.durationMs}ms ${outcomeState}`;
5717
- console.info(banner, event);
5718
- }
5719
- function captureTraceCallsite(tracer) {
5720
- return tracer?.captureCallsite() ?? null;
5721
- }
5722
- function createTraceCallsiteStore(tracer, initialCallsite) {
5723
- let storedCallsite = initialCallsite ?? void 0;
5724
- return {
5725
- resolve(callsite) {
5726
- if (callsite) {
5727
- storedCallsite = callsite;
5728
- return callsite;
5729
- }
5730
- if (storedCallsite !== void 0) {
5731
- return storedCallsite;
5732
- }
5733
- const capturedCallsite = captureTraceCallsite(tracer);
5734
- if (capturedCallsite) {
5735
- storedCallsite = capturedCallsite;
5736
- }
5737
- return capturedCallsite;
5738
- }
5739
- };
5740
- }
5741
- function createQueryTracer(experimental) {
5742
- const traceOption = experimental?.traceQueries;
5743
- if (!traceOption) {
5744
- return void 0;
5745
- }
5746
- const logger = typeof traceOption === "object" && traceOption.logger ? traceOption.logger : defaultQueryTraceLogger;
5747
- const emit = (event) => {
5748
- try {
5749
- logger(event);
5750
- } catch (error) {
5751
- console.warn("[athena-js][trace] logger failed", error);
5752
- }
5753
- };
5754
- return {
5755
- captureCallsite: captureQueryTraceCallsite,
5756
- publishSuccess(context, result, durationMs, callsite) {
5757
- emit({
5758
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5759
- durationMs,
5760
- operation: context.operation,
5761
- endpoint: context.endpoint,
5762
- table: context.table,
5763
- functionName: context.functionName,
5764
- sql: context.sql,
5765
- payload: context.payload,
5766
- options: context.options,
5767
- callsite,
5768
- outcome: {
5769
- status: result.status,
5770
- error: result.error,
5771
- errorDetails: result.errorDetails ?? null,
5772
- count: result.count ?? null,
5773
- data: result.data,
5774
- raw: result.raw
5775
- }
5776
- });
5777
- },
5778
- publishFailure(context, error, durationMs, callsite) {
5779
- emit({
5780
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5781
- durationMs,
5782
- operation: context.operation,
5783
- endpoint: context.endpoint,
5784
- table: context.table,
5785
- functionName: context.functionName,
5786
- sql: context.sql,
5787
- payload: context.payload,
5788
- options: context.options,
5789
- callsite,
5790
- thrownError: error
5791
- });
5792
- }
5793
- };
5794
- }
5795
- async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
5796
- if (!tracer) {
5797
- return runner();
5798
- }
5799
- const callsite = callsiteOverride ?? tracer.captureCallsite();
5800
- const startedAt = Date.now();
5801
- try {
5802
- const result = await runner();
5803
- tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
5804
- return result;
5805
- } catch (error) {
5806
- tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
5807
- throw error;
5808
- }
5809
- }
5810
6469
  function toSingleResult(response) {
5811
6470
  const payload = response.data;
5812
6471
  const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
@@ -5834,6 +6493,15 @@ function asAthenaJsonObject(value) {
5834
6493
  function asAthenaJsonObjectArray(values) {
5835
6494
  return values;
5836
6495
  }
6496
+ function normalizeSelectColumnsInput(columns) {
6497
+ if (columns === void 0) {
6498
+ return void 0;
6499
+ }
6500
+ if (typeof columns === "string") {
6501
+ return columns;
6502
+ }
6503
+ return [...columns];
6504
+ }
5837
6505
  function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
5838
6506
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
5839
6507
  let selectedOptions;
@@ -5843,25 +6511,29 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer,
5843
6511
  const payloadColumns = columns ?? selectedColumns;
5844
6512
  const payloadOptions = options ?? selectedOptions;
5845
6513
  if (!promise) {
5846
- promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
6514
+ promise = executor(
6515
+ normalizeSelectColumnsInput(payloadColumns),
6516
+ payloadOptions,
6517
+ callsiteStore.resolve(callsite)
6518
+ );
5847
6519
  }
5848
6520
  return promise;
5849
6521
  };
5850
6522
  const mutationQuery = {
5851
- select(columns = selectedColumns, options) {
6523
+ select(columns, options) {
5852
6524
  selectedColumns = columns;
5853
6525
  selectedOptions = options ?? selectedOptions;
5854
6526
  return run(columns, options, captureTraceCallsite(tracer));
5855
6527
  },
5856
- returning(columns = selectedColumns, options) {
6528
+ returning(columns, options) {
5857
6529
  return mutationQuery.select(columns, options);
5858
6530
  },
5859
- single(columns = selectedColumns, options) {
6531
+ single(columns, options) {
5860
6532
  selectedColumns = columns;
5861
6533
  selectedOptions = options ?? selectedOptions;
5862
6534
  return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
5863
6535
  },
5864
- maybeSingle(columns = selectedColumns, options) {
6536
+ maybeSingle(columns, options) {
5865
6537
  return mutationQuery.single(columns, options);
5866
6538
  },
5867
6539
  then(onfulfilled, onrejected) {
@@ -6418,7 +7090,10 @@ function createFilterMethods(state, addCondition, self) {
6418
7090
  }
6419
7091
  function toRpcSelect(columns) {
6420
7092
  if (!columns) return void 0;
6421
- return Array.isArray(columns) ? columns.join(",") : columns;
7093
+ if (typeof columns === "string") {
7094
+ return columns;
7095
+ }
7096
+ return columns.join(",");
6422
7097
  }
6423
7098
  function createRpcFilterMethods(filters, self) {
6424
7099
  const addFilter = (operator, column, value) => {
@@ -6467,7 +7142,7 @@ function createRpcFilterMethods(filters, self) {
6467
7142
  }
6468
7143
  };
6469
7144
  }
6470
- function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
7145
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite, debugAstEnabled = false) {
6471
7146
  const state = {
6472
7147
  filters: []
6473
7148
  };
@@ -6477,6 +7152,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6477
7152
  const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
6478
7153
  const executeRpc = async (columns, options, callsite) => {
6479
7154
  const mergedOptions = mergeOptions(baseOptions, options);
7155
+ const normalizedSelectedColumns = normalizeSelectColumnsInput(columns);
6480
7156
  const payload = {
6481
7157
  function: functionName,
6482
7158
  args,
@@ -6491,6 +7167,14 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6491
7167
  };
6492
7168
  const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
6493
7169
  const sql = buildRpcDebugSql(payload);
7170
+ const debugAst = debugAstEnabled ? buildRpcDebugAst({
7171
+ functionName,
7172
+ args,
7173
+ selectedColumns: normalizedSelectedColumns,
7174
+ state,
7175
+ payload,
7176
+ endpoint
7177
+ }) : void 0;
6494
7178
  return executeWithQueryTrace(
6495
7179
  tracer,
6496
7180
  {
@@ -6499,6 +7183,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6499
7183
  functionName,
6500
7184
  sql,
6501
7185
  payload,
7186
+ ast: debugAst,
6502
7187
  options: mergedOptions
6503
7188
  },
6504
7189
  async () => {
@@ -6519,7 +7204,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6519
7204
  const builder = {};
6520
7205
  const filterMethods = createRpcFilterMethods(state.filters, builder);
6521
7206
  Object.assign(builder, filterMethods, {
6522
- select(columns = selectedColumns, options) {
7207
+ select(columns, options) {
6523
7208
  selectedColumns = columns;
6524
7209
  selectedOptions = options ?? selectedOptions;
6525
7210
  return run(columns, options, captureTraceCallsite(tracer));
@@ -6564,6 +7249,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6564
7249
  const state = {
6565
7250
  conditions: []
6566
7251
  };
7252
+ const debugAstEnabled = Boolean(experimental?.debugAst);
6567
7253
  const addCondition = (operator, column, value, hints) => {
6568
7254
  const condition = { operator };
6569
7255
  if (column) {
@@ -6607,15 +7293,27 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6607
7293
  addCondition,
6608
7294
  builder
6609
7295
  );
6610
- const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
7296
+ const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite, debugAstFactory) => {
7297
+ const runtimeColumns = normalizeSelectColumnsInput(columns) ?? DEFAULT_COLUMNS;
6611
7298
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
6612
7299
  const plan = createSelectTransportPlan({
6613
7300
  tableName: resolvedTableName,
6614
- columns,
7301
+ columns: runtimeColumns,
6615
7302
  state: executionState,
6616
7303
  options,
6617
7304
  buildTypedSelectQuery
6618
7305
  });
7306
+ const debugAst = debugAstEnabled ? debugAstFactory?.({
7307
+ tableName: resolvedTableName,
7308
+ columns: runtimeColumns,
7309
+ executionState,
7310
+ plan
7311
+ }) ?? buildSelectDebugAst({
7312
+ tableName: resolvedTableName,
7313
+ columns: runtimeColumns,
7314
+ state: executionState,
7315
+ plan
7316
+ }) : void 0;
6619
7317
  if (plan.kind === "query") {
6620
7318
  return executeExperimentalRead(
6621
7319
  experimental,
@@ -6627,6 +7325,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6627
7325
  table: resolvedTableName,
6628
7326
  sql: plan.query,
6629
7327
  payload: plan.payload,
7328
+ ast: debugAst,
6630
7329
  options
6631
7330
  },
6632
7331
  async () => {
@@ -6651,6 +7350,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6651
7350
  table: resolvedTableName,
6652
7351
  sql,
6653
7352
  payload: plan.payload,
7353
+ ast: debugAst,
6654
7354
  options
6655
7355
  },
6656
7356
  async () => {
@@ -6664,7 +7364,11 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6664
7364
  const createSelectChain = (columns, options, initialCallsite) => {
6665
7365
  const chain = {};
6666
7366
  const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
6667
- const filterMethods2 = createFilterMethods(state, addCondition, chain);
7367
+ const filterMethods2 = createFilterMethods(
7368
+ state,
7369
+ addCondition,
7370
+ chain
7371
+ );
6668
7372
  Object.assign(chain, filterMethods2, {
6669
7373
  async single(cols, opts) {
6670
7374
  const r = await runSelect(
@@ -6751,6 +7455,14 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6751
7455
  limit: executionState.limit,
6752
7456
  order: executionState.order
6753
7457
  });
7458
+ const debugAst = debugAstEnabled ? buildFindManyDirectDebugAst({
7459
+ tableName: resolvedTableName,
7460
+ options,
7461
+ compiledColumns: columns,
7462
+ baseState,
7463
+ executionState,
7464
+ payload
7465
+ }) : void 0;
6754
7466
  return executeExperimentalRead(
6755
7467
  experimental,
6756
7468
  () => executeWithQueryTrace(
@@ -6760,7 +7472,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6760
7472
  endpoint: "/gateway/fetch",
6761
7473
  table: resolvedTableName,
6762
7474
  sql,
6763
- payload
7475
+ payload,
7476
+ ast: debugAst
6764
7477
  },
6765
7478
  async () => {
6766
7479
  const response = await client.fetchGateway(
@@ -6776,7 +7489,15 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6776
7489
  columns,
6777
7490
  void 0,
6778
7491
  executionState,
6779
- callsite
7492
+ callsite,
7493
+ debugAstEnabled ? ({ tableName: resolvedTableName, executionState: tracedState, plan }) => buildFindManyCompiledDebugAst({
7494
+ tableName: resolvedTableName,
7495
+ options,
7496
+ compiledColumns: columns,
7497
+ baseState,
7498
+ executionState: tracedState,
7499
+ plan
7500
+ }) : void 0
6780
7501
  );
6781
7502
  },
6782
7503
  insert(values, options) {
@@ -6796,6 +7517,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6796
7517
  payload.default_to_null = mergedOptions.defaultToNull;
6797
7518
  }
6798
7519
  const sql = buildInsertDebugSql(payload);
7520
+ const debugAst = debugAstEnabled ? buildInsertDebugAst(payload) : void 0;
6799
7521
  return executeWithQueryTrace(
6800
7522
  tracer,
6801
7523
  {
@@ -6804,6 +7526,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6804
7526
  table: resolvedTableName,
6805
7527
  sql,
6806
7528
  payload,
7529
+ ast: debugAst,
6807
7530
  options: mergedOptions
6808
7531
  },
6809
7532
  async () => {
@@ -6829,6 +7552,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6829
7552
  payload.default_to_null = mergedOptions.defaultToNull;
6830
7553
  }
6831
7554
  const sql = buildInsertDebugSql(payload);
7555
+ const debugAst = debugAstEnabled ? buildInsertDebugAst(payload) : void 0;
6832
7556
  return executeWithQueryTrace(
6833
7557
  tracer,
6834
7558
  {
@@ -6837,6 +7561,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6837
7561
  table: resolvedTableName,
6838
7562
  sql,
6839
7563
  payload,
7564
+ ast: debugAst,
6840
7565
  options: mergedOptions
6841
7566
  },
6842
7567
  async () => {
@@ -6867,6 +7592,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6867
7592
  payload.default_to_null = mergedOptions.defaultToNull;
6868
7593
  }
6869
7594
  const sql = buildInsertDebugSql(payload);
7595
+ const debugAst = debugAstEnabled ? buildUpsertDebugAst(payload) : void 0;
6870
7596
  return executeWithQueryTrace(
6871
7597
  tracer,
6872
7598
  {
@@ -6875,6 +7601,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6875
7601
  table: resolvedTableName,
6876
7602
  sql,
6877
7603
  payload,
7604
+ ast: debugAst,
6878
7605
  options: mergedOptions
6879
7606
  },
6880
7607
  async () => {
@@ -6902,6 +7629,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6902
7629
  payload.default_to_null = mergedOptions.defaultToNull;
6903
7630
  }
6904
7631
  const sql = buildInsertDebugSql(payload);
7632
+ const debugAst = debugAstEnabled ? buildUpsertDebugAst(payload) : void 0;
6905
7633
  return executeWithQueryTrace(
6906
7634
  tracer,
6907
7635
  {
@@ -6910,6 +7638,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6910
7638
  table: resolvedTableName,
6911
7639
  sql,
6912
7640
  payload,
7641
+ ast: debugAst,
6913
7642
  options: mergedOptions
6914
7643
  },
6915
7644
  async () => {
@@ -6924,7 +7653,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6924
7653
  update(values, options) {
6925
7654
  const mutationCallsite = captureTraceCallsite(tracer);
6926
7655
  const executeUpdate = async (columns, selectOptions, callsite) => {
6927
- const filters = state.conditions.length ? [...state.conditions] : void 0;
7656
+ const executionState = snapshotState();
7657
+ const filters = executionState.conditions.length ? [...executionState.conditions] : void 0;
6928
7658
  const mergedOptions = mergeOptions(options, selectOptions);
6929
7659
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
6930
7660
  const payload = {
@@ -6933,12 +7663,16 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6933
7663
  conditions: filters,
6934
7664
  strip_nulls: mergedOptions?.stripNulls ?? true
6935
7665
  };
6936
- if (state.order) payload.sort_by = state.order;
6937
- if (state.currentPage !== void 0) payload.current_page = state.currentPage;
6938
- if (state.pageSize !== void 0) payload.page_size = state.pageSize;
6939
- if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
7666
+ if (executionState.order) payload.sort_by = executionState.order;
7667
+ if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
7668
+ if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
7669
+ if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
6940
7670
  if (columns) payload.columns = columns;
6941
7671
  const sql = buildUpdateDebugSql(payload);
7672
+ const debugAst = debugAstEnabled ? buildUpdateDebugAst({
7673
+ state: executionState,
7674
+ payload
7675
+ }) : void 0;
6942
7676
  return executeWithQueryTrace(
6943
7677
  tracer,
6944
7678
  {
@@ -6947,6 +7681,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6947
7681
  table: resolvedTableName,
6948
7682
  sql,
6949
7683
  payload,
7684
+ ast: debugAst,
6950
7685
  options: mergedOptions
6951
7686
  },
6952
7687
  async () => {
@@ -6970,6 +7705,11 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6970
7705
  }
6971
7706
  const mutationCallsite = captureTraceCallsite(tracer);
6972
7707
  const executeDelete = async (columns, selectOptions, callsite) => {
7708
+ const executionState = snapshotState();
7709
+ const debugState = {
7710
+ ...executionState,
7711
+ conditions: filters ? filters.map((condition) => ({ ...condition })) : []
7712
+ };
6973
7713
  const mergedOptions = mergeOptions(options, selectOptions);
6974
7714
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
6975
7715
  const payload = {
@@ -6977,12 +7717,16 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6977
7717
  resource_id: resourceId,
6978
7718
  conditions: filters
6979
7719
  };
6980
- if (state.order) payload.sort_by = state.order;
6981
- if (state.currentPage !== void 0) payload.current_page = state.currentPage;
6982
- if (state.pageSize !== void 0) payload.page_size = state.pageSize;
6983
- if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
7720
+ if (executionState.order) payload.sort_by = executionState.order;
7721
+ if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
7722
+ if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
7723
+ if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
6984
7724
  if (columns) payload.columns = columns;
6985
7725
  const sql = buildDeleteDebugSql(payload);
7726
+ const debugAst = debugAstEnabled ? buildDeleteDebugAst({
7727
+ state: debugState,
7728
+ payload
7729
+ }) : void 0;
6986
7730
  return executeWithQueryTrace(
6987
7731
  tracer,
6988
7732
  {
@@ -6991,6 +7735,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6991
7735
  table: resolvedTableName,
6992
7736
  sql,
6993
7737
  payload,
7738
+ ast: debugAst,
6994
7739
  options: mergedOptions
6995
7740
  },
6996
7741
  async () => {
@@ -7018,6 +7763,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
7018
7763
  return builder;
7019
7764
  }
7020
7765
  function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
7766
+ const debugAstEnabled = Boolean(experimental?.debugAst);
7021
7767
  return async function query(query, options) {
7022
7768
  const normalizedQuery = query.trim();
7023
7769
  if (!normalizedQuery) {
@@ -7034,6 +7780,7 @@ function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
7034
7780
  endpoint: "/gateway/query",
7035
7781
  sql: normalizedQuery,
7036
7782
  payload,
7783
+ ast: debugAstEnabled ? buildRawQueryDebugAst(normalizedQuery) : void 0,
7037
7784
  options
7038
7785
  },
7039
7786
  async () => {
@@ -7045,6 +7792,63 @@ function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
7045
7792
  );
7046
7793
  };
7047
7794
  }
7795
+ function resolveClientServiceBaseUrl(value, label) {
7796
+ if (value === void 0 || value === null) {
7797
+ return void 0;
7798
+ }
7799
+ return normalizeAthenaGatewayBaseUrl(value, { label });
7800
+ }
7801
+ function appendServicePath(baseUrl, segment) {
7802
+ const normalizedBaseUrl = normalizeAthenaGatewayBaseUrl(baseUrl, { label: "Athena public base URL" });
7803
+ return `${normalizedBaseUrl}/${segment.replace(/^\/+/, "")}`;
7804
+ }
7805
+ function resolveServiceUrlOverride(value, label) {
7806
+ return resolveClientServiceBaseUrl(value, label);
7807
+ }
7808
+ function resolveServiceUrls(config) {
7809
+ const baseUrl = resolveClientServiceBaseUrl(config.url, "Athena public base URL");
7810
+ return {
7811
+ dbUrl: resolveServiceUrlOverride(config.db?.url, "Athena DB base URL") ?? resolveServiceUrlOverride(config.gateway?.url, "Athena gateway base URL") ?? resolveServiceUrlOverride(config.dbUrl, "Athena DB base URL") ?? resolveServiceUrlOverride(config.gatewayUrl, "Athena gateway base URL") ?? (baseUrl ? appendServicePath(baseUrl, "db") : void 0),
7812
+ authUrl: resolveServiceUrlOverride(config.auth?.url, "Athena auth base URL") ?? resolveServiceUrlOverride(config.auth?.baseUrl, "Athena auth base URL") ?? resolveServiceUrlOverride(config.authUrl, "Athena auth base URL") ?? (baseUrl ? appendServicePath(baseUrl, "auth") : void 0),
7813
+ storageUrl: resolveServiceUrlOverride(config.storage?.url, "Athena storage base URL") ?? resolveServiceUrlOverride(config.storageUrl, "Athena storage base URL") ?? (baseUrl ? appendServicePath(baseUrl, "storage") : void 0)
7814
+ };
7815
+ }
7816
+ function normalizeAuthClientConfig(auth, defaultBaseUrl) {
7817
+ if (!auth && defaultBaseUrl === void 0) {
7818
+ return void 0;
7819
+ }
7820
+ const { url, ...rest } = auth ?? {};
7821
+ const normalized = {
7822
+ ...rest
7823
+ };
7824
+ const resolvedBaseUrl = resolveClientServiceBaseUrl(
7825
+ url ?? rest.baseUrl ?? defaultBaseUrl,
7826
+ "Athena auth base URL"
7827
+ );
7828
+ if (resolvedBaseUrl !== void 0) {
7829
+ normalized.baseUrl = resolvedBaseUrl;
7830
+ }
7831
+ return normalized;
7832
+ }
7833
+ function resolveCreateClientConfig(config) {
7834
+ const resolvedUrls = resolveServiceUrls(config);
7835
+ if (!resolvedUrls.dbUrl) {
7836
+ throw new Error(
7837
+ "Athena DB base URL is required. Pass createClient(url, key) for a unified root, or set db.url / gateway.url / gatewayUrl explicitly."
7838
+ );
7839
+ }
7840
+ return {
7841
+ baseUrl: resolvedUrls.dbUrl,
7842
+ apiKey: config.key,
7843
+ client: config.client,
7844
+ backend: toBackendConfig(config.backend),
7845
+ headers: config.headers,
7846
+ auth: config.auth,
7847
+ authUrl: resolvedUrls.authUrl,
7848
+ storageUrl: resolvedUrls.storageUrl,
7849
+ experimental: config.experimental
7850
+ };
7851
+ }
7048
7852
  function createClientFromConfig(config) {
7049
7853
  const gatewayHeaders = {
7050
7854
  ...config.headers ?? {}
@@ -7059,16 +7863,33 @@ function createClientFromConfig(config) {
7059
7863
  backend: config.backend,
7060
7864
  headers: gatewayHeaders
7061
7865
  });
7062
- const formatGatewayResult = createResultFormatter();
7866
+ const formatGatewayResult = createResultFormatter(config.experimental);
7063
7867
  const queryTracer = createQueryTracer(config.experimental);
7064
- const auth = createAuthClient(config.auth);
7065
- const from = (table, options) => createTableBuilder(
7066
- resolveTableNameForCall(table, options?.schema),
7067
- gateway,
7068
- formatGatewayResult,
7069
- queryTracer,
7070
- config.experimental
7071
- );
7868
+ const auth = createAuthClient(normalizeAuthClientConfig(config.auth, config.authUrl));
7869
+ function from(tableOrModel, options) {
7870
+ if (isAthenaModelTarget(tableOrModel)) {
7871
+ if (options?.schema !== void 0) {
7872
+ throw new Error(
7873
+ "from(model) does not accept a schema override because the model already defines its target."
7874
+ );
7875
+ }
7876
+ return createTableBuilder(
7877
+ resolveAthenaModelTargetTableName(tableOrModel),
7878
+ gateway,
7879
+ formatGatewayResult,
7880
+ queryTracer,
7881
+ config.experimental
7882
+ );
7883
+ }
7884
+ const resolvedTableName = resolveTableNameForCall(tableOrModel, options?.schema);
7885
+ return createTableBuilder(
7886
+ resolvedTableName,
7887
+ gateway,
7888
+ formatGatewayResult,
7889
+ queryTracer,
7890
+ config.experimental
7891
+ );
7892
+ }
7072
7893
  const rpc = (fn, args, options) => {
7073
7894
  const normalizedFn = fn.trim();
7074
7895
  if (!normalizedFn) {
@@ -7081,10 +7902,16 @@ function createClientFromConfig(config) {
7081
7902
  gateway,
7082
7903
  formatGatewayResult,
7083
7904
  queryTracer,
7084
- captureTraceCallsite(queryTracer)
7905
+ captureTraceCallsite(queryTracer),
7906
+ Boolean(config.experimental?.debugAst)
7085
7907
  );
7086
7908
  };
7087
- const query = createQueryBuilder(gateway, formatGatewayResult, config.experimental, queryTracer);
7909
+ const query = createQueryBuilder(
7910
+ gateway,
7911
+ formatGatewayResult,
7912
+ config.experimental,
7913
+ queryTracer
7914
+ );
7088
7915
  const db = createDbModule({ from, rpc, query });
7089
7916
  const sdkClient = {
7090
7917
  from,
@@ -7097,27 +7924,27 @@ function createClientFromConfig(config) {
7097
7924
  if (config.experimental?.athenaStorageBackend) {
7098
7925
  const storageClient = {
7099
7926
  ...sdkClient,
7100
- storage: createStorageModule(gateway, config.experimental.storage)
7927
+ storage: createStorageModule(gateway, {
7928
+ ...config.experimental.storage,
7929
+ ...config.storageUrl ? {
7930
+ baseUrl: config.storageUrl,
7931
+ stripBasePath: true
7932
+ } : {}
7933
+ })
7101
7934
  };
7102
7935
  return storageClient;
7103
7936
  }
7104
7937
  return sdkClient;
7105
7938
  }
7106
- var DEFAULT_BACKEND = { type: "athena" };
7107
- function toBackendConfig(b) {
7108
- if (!b) return DEFAULT_BACKEND;
7109
- return typeof b === "string" ? { type: b } : b;
7110
- }
7111
- function createClient(url, apiKey, options) {
7112
- return createClientFromConfig({
7113
- baseUrl: url,
7114
- apiKey,
7115
- client: options?.client,
7116
- backend: toBackendConfig(options?.backend),
7117
- headers: options?.headers,
7118
- auth: options?.auth,
7119
- experimental: options?.experimental
7120
- });
7939
+ function createClient(configOrUrl, apiKey, options) {
7940
+ if (typeof configOrUrl === "string") {
7941
+ return createClientFromConfig(resolveCreateClientConfig({
7942
+ url: configOrUrl,
7943
+ key: apiKey ?? "",
7944
+ ...options
7945
+ }));
7946
+ }
7947
+ return createClientFromConfig(resolveCreateClientConfig(configOrUrl));
7121
7948
  }
7122
7949
 
7123
7950
  // src/schema/postgres-introspection-core.ts
@@ -7714,6 +8541,7 @@ function rootUsage() {
7714
8541
  "",
7715
8542
  "Examples:",
7716
8543
  " athena-js generate",
8544
+ " DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/app_db athena-js generate --dry-run",
7717
8545
  " athena-js generate --config ./athena.config.ts --dry-run",
7718
8546
  " athena-js generate --help"
7719
8547
  ].join("\n");
@@ -7730,8 +8558,14 @@ function generateUsage() {
7730
8558
  " --dry-run Build generated files in memory without writing them to disk",
7731
8559
  " -h, --help Show help for generate",
7732
8560
  "",
8561
+ "Config resolution:",
8562
+ " - uses athena.config.* discovery first",
8563
+ " - falls back to env-only direct mode when DATABASE_URL/PG_URL is present",
8564
+ " - falls back to env-only gateway mode when ATHENA_URL + ATHENA_API_KEY are present",
8565
+ "",
7733
8566
  "Examples:",
7734
8567
  " athena-js generate",
8568
+ " DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/app_db athena-js generate --dry-run",
7735
8569
  " athena-js generate --config ./athena.config.ts --dry-run"
7736
8570
  ].join("\n");
7737
8571
  }