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