@xylex-group/athena 2.8.2 → 2.9.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 (52) hide show
  1. package/README.md +154 -64
  2. package/dist/browser.cjs +636 -21
  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 +630 -22
  7. package/dist/browser.js.map +1 -1
  8. package/dist/cli/index.cjs +591 -29
  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 +591 -29
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/{model-form-Cx3wtvi8.d.ts → client-CfAE_QOj.d.cts} +101 -97
  15. package/dist/{model-form-_ugfOXao.d.cts → client-D6EIJdQS.d.ts} +101 -97
  16. package/dist/index.cjs +714 -41
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +8 -7
  19. package/dist/index.d.ts +8 -7
  20. package/dist/index.js +708 -42
  21. package/dist/index.js.map +1 -1
  22. package/dist/model-form-ByvyyvxB.d.ts +96 -0
  23. package/dist/model-form-DACdBLYG.d.cts +96 -0
  24. package/dist/next/client.cjs +7875 -0
  25. package/dist/next/client.cjs.map +1 -0
  26. package/dist/next/client.d.cts +25 -0
  27. package/dist/next/client.d.ts +25 -0
  28. package/dist/next/client.js +7873 -0
  29. package/dist/next/client.js.map +1 -0
  30. package/dist/next/server.cjs +7993 -0
  31. package/dist/next/server.cjs.map +1 -0
  32. package/dist/next/server.d.cts +52 -0
  33. package/dist/next/server.d.ts +52 -0
  34. package/dist/next/server.js +7990 -0
  35. package/dist/next/server.js.map +1 -0
  36. package/dist/{pipeline-BtD-Uo5X.d.cts → pipeline-CmUZsXsi.d.cts} +1 -1
  37. package/dist/{pipeline-yCIZNJHE.d.ts → pipeline-DZMsPxUg.d.ts} +1 -1
  38. package/dist/{react-email-CiiSVa9F.d.cts → react-email-BvJ3fj_F.d.cts} +35 -5
  39. package/dist/{react-email-WN8UU3AL.d.ts → react-email-PLAJuZuO.d.ts} +35 -5
  40. package/dist/react.cjs +30 -1
  41. package/dist/react.cjs.map +1 -1
  42. package/dist/react.d.cts +39 -10
  43. package/dist/react.d.ts +39 -10
  44. package/dist/react.js +30 -2
  45. package/dist/react.js.map +1 -1
  46. package/dist/shared-BW6hoLBY.d.cts +33 -0
  47. package/dist/shared-BiJvoURI.d.ts +33 -0
  48. package/dist/{types-g8G6J0xE.d.cts → types-BeZIHduP.d.cts} +2 -1
  49. package/dist/{types-g8G6J0xE.d.ts → types-BeZIHduP.d.ts} +2 -1
  50. package/dist/{types-C2kiTt6-.d.ts → types-C-YvfgYh.d.cts} +26 -2
  51. package/dist/{types-89EfjLjV.d.cts → types-CRjDwmtJ.d.ts} +26 -2
  52. package/package.json +32 -14
@@ -688,6 +688,77 @@ function resolveProviderSchemas(providerConfig) {
688
688
  return [...DEFAULT_POSTGRES_SCHEMAS];
689
689
  }
690
690
 
691
+ // src/generator/table-selection.ts
692
+ function normalizeTableSelector(value) {
693
+ const trimmed = value.trim();
694
+ return trimmed.length > 0 ? trimmed : void 0;
695
+ }
696
+ function normalizeTableSelection(value) {
697
+ if (typeof value === "string") {
698
+ return Array.from(
699
+ new Set(
700
+ value.split(",").map(normalizeTableSelector).filter((entry) => Boolean(entry))
701
+ )
702
+ );
703
+ }
704
+ if (Array.isArray(value)) {
705
+ return Array.from(
706
+ new Set(
707
+ value.map((entry) => typeof entry === "string" ? normalizeTableSelector(entry) : void 0).filter((entry) => Boolean(entry))
708
+ )
709
+ );
710
+ }
711
+ return [];
712
+ }
713
+ function matchesTableSelector(schemaName, tableName, selector) {
714
+ const separatorIndex = selector.indexOf(".");
715
+ if (separatorIndex < 0) {
716
+ return tableName === selector;
717
+ }
718
+ const selectorSchema = selector.slice(0, separatorIndex).trim();
719
+ const selectorTable = selector.slice(separatorIndex + 1).trim();
720
+ return selectorSchema === schemaName && selectorTable === tableName;
721
+ }
722
+ function shouldKeepTable(schemaName, tableName, filter) {
723
+ const included = filter.includeTables.length === 0 || filter.includeTables.some((selector) => matchesTableSelector(schemaName, tableName, selector));
724
+ if (!included) {
725
+ return false;
726
+ }
727
+ return !filter.excludeTables.some((selector) => matchesTableSelector(schemaName, tableName, selector));
728
+ }
729
+ function hasTableFilters(filter) {
730
+ return filter.includeTables.length > 0 || filter.excludeTables.length > 0;
731
+ }
732
+ function filterIntrospectionSnapshot(snapshot, filter) {
733
+ if (!hasTableFilters(filter)) {
734
+ return snapshot;
735
+ }
736
+ const schemas = {};
737
+ for (const [schemaName, schema] of Object.entries(snapshot.schemas)) {
738
+ const tables = Object.fromEntries(
739
+ Object.entries(schema.tables).filter(([tableName]) => shouldKeepTable(schemaName, tableName, filter))
740
+ );
741
+ if (Object.keys(tables).length === 0) {
742
+ continue;
743
+ }
744
+ schemas[schemaName] = {
745
+ ...schema,
746
+ tables
747
+ };
748
+ }
749
+ if (Object.keys(schemas).length === 0) {
750
+ const includeLabel = filter.includeTables.length > 0 ? ` includeTables=${filter.includeTables.join(", ")}` : "";
751
+ const excludeLabel = filter.excludeTables.length > 0 ? ` excludeTables=${filter.excludeTables.join(", ")}` : "";
752
+ throw new Error(
753
+ `Generator table filters matched no tables after schema selection.${includeLabel}${excludeLabel}`
754
+ );
755
+ }
756
+ return {
757
+ ...snapshot,
758
+ schemas
759
+ };
760
+ }
761
+
691
762
  // src/generator/config.ts
692
763
  var POSTGRES_PROTOCOLS = /* @__PURE__ */ new Set(["postgres:", "postgresql:"]);
693
764
  var DEFAULT_CONFIG_CANDIDATES = [
@@ -698,13 +769,20 @@ var DEFAULT_CONFIG_CANDIDATES = [
698
769
  ".athena.config.ts",
699
770
  ".athena.config.js"
700
771
  ];
701
- var DEFAULT_TARGETS = {
772
+ var LEGACY_DEFAULT_TARGETS = {
702
773
  model: "athena/models/{schema_kebab}/{model_kebab}.ts",
703
774
  schema: "athena/schemas/{schema_kebab}.ts",
704
775
  database: "athena/relations.ts",
705
776
  registry: "athena/config.ts"
706
777
  };
707
- var DEFAULT_OUTPUT_FORMAT = "define-model";
778
+ var ATHENA_DIRECT_TARGETS = {
779
+ model: "athena/models/{schema_kebab}/{model_kebab}.ts",
780
+ schema: "athena/schemas/{schema_kebab}.ts",
781
+ database: "athena/relations.ts",
782
+ registry: "athena/registry.generated.ts"
783
+ };
784
+ var DEFAULT_OUTPUT_FORMAT = "table-builder";
785
+ var DEFAULT_OUTPUT_PRESET = "athena-direct";
708
786
  var DEFAULT_NAMING = {
709
787
  modelType: "pascal",
710
788
  modelConst: "camel",
@@ -723,6 +801,10 @@ var DEFAULT_EXPERIMENTAL_FLAGS = {
723
801
  var DEFAULT_INTERNAL_CONFIG = {
724
802
  schemaVersion: 1
725
803
  };
804
+ var DEFAULT_FILTER_CONFIG = {
805
+ includeTables: [],
806
+ excludeTables: []
807
+ };
726
808
  var PROJECT_ENV_FILENAMES = [".env", ".env.local"];
727
809
  var DIRECT_CONNECTION_STRING_ENV_KEYS = [
728
810
  "ATHENA_GENERATOR_PG_URL",
@@ -741,10 +823,13 @@ var GATEWAY_API_KEY_ENV_KEYS = [
741
823
  ];
742
824
  var GENERATOR_SCHEMA_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMAS"];
743
825
  var OUTPUT_FORMAT_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_FORMAT"];
826
+ var OUTPUT_PRESET_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_PRESET"];
744
827
  var MODEL_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_TARGET"];
745
828
  var SCHEMA_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMA_TARGET"];
746
829
  var DATABASE_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_DATABASE_TARGET"];
747
830
  var REGISTRY_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_REGISTRY_TARGET"];
831
+ var TABLES_ENV_KEYS = ["ATHENA_GENERATOR_TABLES"];
832
+ var EXCLUDE_TABLES_ENV_KEYS = ["ATHENA_GENERATOR_EXCLUDE_TABLES"];
748
833
  var PLACEHOLDER_MAP_ENV_KEYS = ["ATHENA_GENERATOR_PLACEHOLDER_MAP"];
749
834
  var MODEL_TYPE_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_TYPE", "ATHENA_GENERATOR_MODEL_STYLE"];
750
835
  var MODEL_CONST_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_CONST"];
@@ -759,7 +844,12 @@ var SCYLLA_PROVIDER_CONTRACTS_ENV_KEYS = ["ATHENA_GENERATOR_SCYLLA_PROVIDER_CONT
759
844
  var ENV_ONLY_CONFIG_PATH = "[environment defaults]";
760
845
  var NAMING_STYLE_VALUES = ["preserve", "camel", "pascal", "snake", "kebab"];
761
846
  var OUTPUT_FORMAT_VALUES = ["define-model", "table-builder"];
847
+ var OUTPUT_PRESET_VALUES = ["legacy", "athena-direct"];
762
848
  var BACKEND_TYPE_VALUES = ["athena", "postgrest", "postgresql", "scylladb"];
849
+ var OUTPUT_PRESET_TARGETS = {
850
+ legacy: LEGACY_DEFAULT_TARGETS,
851
+ "athena-direct": ATHENA_DIRECT_TARGETS
852
+ };
763
853
  function normalizeRawEnvValue(rawValue) {
764
854
  if (rawValue.startsWith('"') && rawValue.endsWith('"') && rawValue.length >= 2) {
765
855
  const inner = rawValue.slice(1, -1);
@@ -966,11 +1056,19 @@ function normalizeExperimentalFlags(input) {
966
1056
  )
967
1057
  };
968
1058
  }
1059
+ function normalizeFilterConfig(input) {
1060
+ return {
1061
+ includeTables: normalizeTableSelection(input?.includeTables),
1062
+ excludeTables: normalizeTableSelection(input?.excludeTables)
1063
+ };
1064
+ }
969
1065
  function normalizeOutputConfig(output) {
1066
+ const preset = output?.preset ?? DEFAULT_OUTPUT_PRESET;
970
1067
  return {
971
1068
  format: output?.format ?? DEFAULT_OUTPUT_FORMAT,
1069
+ preset,
972
1070
  targets: {
973
- ...DEFAULT_TARGETS,
1071
+ ...OUTPUT_PRESET_TARGETS[preset],
974
1072
  ...output?.targets ?? {}
975
1073
  },
976
1074
  placeholderMap: {
@@ -1050,6 +1148,10 @@ function normalizeGeneratorConfig(input) {
1050
1148
  ...DEFAULT_NAMING,
1051
1149
  ...input.naming ?? {}
1052
1150
  },
1151
+ filter: {
1152
+ ...DEFAULT_FILTER_CONFIG,
1153
+ ...normalizeFilterConfig(input.filter)
1154
+ },
1053
1155
  features: normalizeFeatureFlags(input.features),
1054
1156
  experimental: normalizeExperimentalFlags(input.experimental),
1055
1157
  internal: {
@@ -1110,16 +1212,18 @@ function importConfigModule(moduleSpecifier) {
1110
1212
  }
1111
1213
  function buildEnvironmentOutputConfig() {
1112
1214
  const format = resolveOptionalOneOf(OUTPUT_FORMAT_ENV_KEYS, OUTPUT_FORMAT_VALUES);
1215
+ const preset = resolveOptionalOneOf(OUTPUT_PRESET_ENV_KEYS, OUTPUT_PRESET_VALUES);
1113
1216
  const modelTarget = resolveFallbackValue(MODEL_TARGET_ENV_KEYS);
1114
1217
  const schemaTarget = resolveFallbackValue(SCHEMA_TARGET_ENV_KEYS);
1115
1218
  const databaseTarget = resolveFallbackValue(DATABASE_TARGET_ENV_KEYS);
1116
1219
  const registryTarget = resolveFallbackValue(REGISTRY_TARGET_ENV_KEYS);
1117
1220
  const placeholderMap = resolveOptionalJson(PLACEHOLDER_MAP_ENV_KEYS);
1118
- if (format === void 0 && modelTarget === void 0 && schemaTarget === void 0 && databaseTarget === void 0 && registryTarget === void 0 && placeholderMap === void 0) {
1221
+ if (format === void 0 && preset === void 0 && modelTarget === void 0 && schemaTarget === void 0 && databaseTarget === void 0 && registryTarget === void 0 && placeholderMap === void 0) {
1119
1222
  return void 0;
1120
1223
  }
1121
1224
  return {
1122
1225
  format,
1226
+ preset,
1123
1227
  targets: {
1124
1228
  ...modelTarget ? { model: modelTarget } : {},
1125
1229
  ...schemaTarget ? { schema: schemaTarget } : {},
@@ -1129,6 +1233,17 @@ function buildEnvironmentOutputConfig() {
1129
1233
  placeholderMap
1130
1234
  };
1131
1235
  }
1236
+ function buildEnvironmentFilterConfig() {
1237
+ const includeTables = resolveFallbackValue(TABLES_ENV_KEYS);
1238
+ const excludeTables = resolveFallbackValue(EXCLUDE_TABLES_ENV_KEYS);
1239
+ if (includeTables === void 0 && excludeTables === void 0) {
1240
+ return void 0;
1241
+ }
1242
+ return {
1243
+ ...includeTables !== void 0 ? { includeTables } : {},
1244
+ ...excludeTables !== void 0 ? { excludeTables } : {}
1245
+ };
1246
+ }
1132
1247
  function buildEnvironmentNamingConfig() {
1133
1248
  const modelType = resolveOptionalOneOf(MODEL_TYPE_ENV_KEYS, NAMING_STYLE_VALUES);
1134
1249
  const modelConst = resolveOptionalOneOf(MODEL_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
@@ -1204,6 +1319,7 @@ function createEnvironmentGeneratorConfig() {
1204
1319
  provider,
1205
1320
  output: buildEnvironmentOutputConfig(),
1206
1321
  naming: buildEnvironmentNamingConfig(),
1322
+ filter: buildEnvironmentFilterConfig(),
1207
1323
  features: buildEnvironmentFeatureFlags(),
1208
1324
  experimental: buildEnvironmentExperimentalFlags()
1209
1325
  };
@@ -1365,7 +1481,7 @@ ${schemaEntries}
1365
1481
  content
1366
1482
  };
1367
1483
  }
1368
- function renderRegistryArtifact(registryPath, databasePath, databaseConstName, registryConstName, databaseName, generatedAt, outputFormat, schemaVersion) {
1484
+ function renderRegistryArtifact(registryPath, databasePath, databaseConstName, registryConstName, databaseName, generatedAt, outputPreset, outputFormat, schemaVersion) {
1369
1485
  const databaseImportPath = toModuleImportPath(registryPath, databasePath);
1370
1486
  const content = `import { defineRegistry } from '@xylex-group/athena'
1371
1487
  import { ${databaseConstName} } from '${databaseImportPath}'
@@ -1374,6 +1490,7 @@ export const __athena_schema_meta = {
1374
1490
  schemaVersion: ${schemaVersion},
1375
1491
  generatedAt: ${escapeStringLiteral(generatedAt)},
1376
1492
  database: ${escapeStringLiteral(databaseName)},
1493
+ outputPreset: ${escapeStringLiteral(outputPreset)},
1377
1494
  outputFormat: ${escapeStringLiteral(outputFormat)},
1378
1495
  } as const
1379
1496
 
@@ -1543,6 +1660,7 @@ function composeGeneratorArtifacts(input) {
1543
1660
  toSafeIdentifier("registry", config.naming.registryConst, "registry"),
1544
1661
  databaseName,
1545
1662
  snapshot.generatedAt,
1663
+ config.output.preset,
1546
1664
  config.output.format,
1547
1665
  config.internal.schemaVersion
1548
1666
  )
@@ -1648,7 +1766,7 @@ export const ${descriptor.tableConstName} = table(${escapeStringLiteral(descript
1648
1766
  .columns({
1649
1767
  ${columnLines}
1650
1768
  })
1651
- .primaryKey(${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")})
1769
+ ${descriptor.table.primaryKey.length > 0 ? `.primaryKey(${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")})` : ".withoutPrimaryKey()"}
1652
1770
  ${relationsAssignment ? `${relationsAssignment}` : ""}
1653
1771
  export type ${descriptor.rowTypeName} = RowOf<typeof ${descriptor.tableConstName}>
1654
1772
  export type ${descriptor.insertTypeName} = InsertOf<typeof ${descriptor.tableConstName}>
@@ -1745,11 +1863,12 @@ ${nullableLines}
1745
1863
  }
1746
1864
  function generateArtifactsFromSnapshot(snapshot, config) {
1747
1865
  const normalizedConfig = "internal" in config ? config : normalizeGeneratorConfig(config);
1866
+ const filteredSnapshot = filterIntrospectionSnapshot(snapshot, normalizedConfig.filter);
1748
1867
  if (normalizedConfig.output.format === "table-builder") {
1749
- return generateTableBuilderArtifactsFromSnapshot(snapshot, normalizedConfig);
1868
+ return generateTableBuilderArtifactsFromSnapshot(filteredSnapshot, normalizedConfig);
1750
1869
  }
1751
1870
  return composeGeneratorArtifacts({
1752
- snapshot,
1871
+ snapshot: filteredSnapshot,
1753
1872
  config: normalizedConfig,
1754
1873
  createModelDescriptor({ providerName, databaseName, schemaName, tableName, table }) {
1755
1874
  const modelConstName = toSafeIdentifier(
@@ -1779,7 +1898,7 @@ function generateArtifactsFromSnapshot(snapshot, config) {
1779
1898
  table
1780
1899
  };
1781
1900
  },
1782
- renderModelArtifact: (descriptor) => renderModelArtifact2(snapshot.database, descriptor, normalizedConfig)
1901
+ renderModelArtifact: (descriptor) => renderModelArtifact2(filteredSnapshot.database, descriptor, normalizedConfig)
1783
1902
  });
1784
1903
  }
1785
1904
 
@@ -1885,7 +2004,7 @@ var getSessionCookie = (request, config) => {
1885
2004
 
1886
2005
  // package.json
1887
2006
  var package_default = {
1888
- version: "2.8.2"
2007
+ version: "2.9.0"
1889
2008
  };
1890
2009
 
1891
2010
  // src/sdk-version.ts
@@ -1898,6 +2017,7 @@ function buildSdkHeaderValue(sdkName) {
1898
2017
  var DEFAULT_CLIENT = "railway_direct";
1899
2018
  var SDK_NAME = "xylex-group/athena";
1900
2019
  var SDK_HEADER_VALUE = buildSdkHeaderValue(SDK_NAME);
2020
+ var NO_CACHE_HEADER_VALUE = "no-cache";
1901
2021
  function parseResponseBody(rawText, contentType) {
1902
2022
  if (!rawText) {
1903
2023
  return { parsed: null, parseFailed: false };
@@ -1916,6 +2036,9 @@ function parseResponseBody(rawText, contentType) {
1916
2036
  function normalizeHeaderValue(value) {
1917
2037
  return value ? value : void 0;
1918
2038
  }
2039
+ function isCacheControlHeaderName(name) {
2040
+ return name.toLowerCase() === "cache-control";
2041
+ }
1919
2042
  function resolveHeaderValue(headers, candidates) {
1920
2043
  for (const candidate of candidates) {
1921
2044
  const direct = normalizeHeaderValue(headers[candidate]);
@@ -2074,6 +2197,7 @@ function buildRpcGetEndpoint(payload) {
2074
2197
  }
2075
2198
  function buildHeaders(config, options) {
2076
2199
  const mergedStripNulls = options?.stripNulls ?? true;
2200
+ const forceNoCache = Boolean(config.forceNoCache || options?.forceNoCache);
2077
2201
  const extraHeaders = {
2078
2202
  ...config.headers ?? {},
2079
2203
  ...options?.headers ?? {}
@@ -2127,11 +2251,15 @@ function buildHeaders(config, options) {
2127
2251
  const athenaClientKeys = ["x-athena-client", "X-Athena-Client"];
2128
2252
  Object.entries(extraHeaders).forEach(([key, value]) => {
2129
2253
  if (athenaClientKeys.includes(key)) return;
2254
+ if (forceNoCache && isCacheControlHeaderName(key)) return;
2130
2255
  const normalized = normalizeHeaderValue(value);
2131
2256
  if (normalized) {
2132
2257
  headers[key] = normalized;
2133
2258
  }
2134
2259
  });
2260
+ if (forceNoCache) {
2261
+ headers["Cache-Control"] = NO_CACHE_HEADER_VALUE;
2262
+ }
2135
2263
  return headers;
2136
2264
  }
2137
2265
  function toInvalidUrlResponse(error, endpoint, method) {
@@ -2571,6 +2699,35 @@ function quoteSelectColumnsExpression(columns) {
2571
2699
  }
2572
2700
  return tokens.map(quoteSelectToken).join(", ");
2573
2701
  }
2702
+ var ATHENA_AUTH_MAX_TEMPLATE_VARIABLES = 64;
2703
+ var ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH = 128;
2704
+ function describeTemplateVariableTarget(target) {
2705
+ const normalized = target?.trim();
2706
+ return normalized && normalized.length > 0 ? normalized : "Athena auth admin email template variables";
2707
+ }
2708
+ function assertAthenaAuthTemplateVariables(variables, target) {
2709
+ const label = describeTemplateVariableTarget(target);
2710
+ if (!Array.isArray(variables)) {
2711
+ throw new Error(`${label} must be an array of strings.`);
2712
+ }
2713
+ if (variables.length > ATHENA_AUTH_MAX_TEMPLATE_VARIABLES) {
2714
+ throw new Error(
2715
+ `${label} cannot contain more than ${ATHENA_AUTH_MAX_TEMPLATE_VARIABLES} entries.`
2716
+ );
2717
+ }
2718
+ variables.forEach((variable, index) => {
2719
+ if (typeof variable !== "string") {
2720
+ throw new Error(
2721
+ `${label} must contain only strings. Received ${typeof variable} at index ${index}.`
2722
+ );
2723
+ }
2724
+ if (variable.length > ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH) {
2725
+ throw new Error(
2726
+ `${label} cannot contain entries longer than ${ATHENA_AUTH_MAX_TEMPLATE_VARIABLE_LENGTH} characters. Received ${variable.length} characters at index ${index}.`
2727
+ );
2728
+ }
2729
+ });
2730
+ }
2574
2731
 
2575
2732
  // src/auth/react-email.ts
2576
2733
  var reactEmailRenderModulePromise;
@@ -2760,6 +2917,7 @@ async function resolveReactEmailPayloadFields(input, fields, options) {
2760
2917
  var DEFAULT_AUTH_BASE_URL = "http://localhost:3001/api/auth";
2761
2918
  var SDK_NAME2 = "xylex-group/athena-auth";
2762
2919
  var SDK_HEADER_VALUE2 = buildSdkHeaderValue(SDK_NAME2);
2920
+ var NO_CACHE_HEADER_VALUE2 = "no-cache";
2763
2921
  function normalizeBaseUrl(baseUrl) {
2764
2922
  return (baseUrl ?? DEFAULT_AUTH_BASE_URL).replace(/\/$/, "");
2765
2923
  }
@@ -2769,6 +2927,9 @@ function isRecord4(value) {
2769
2927
  function normalizeHeaderValue2(value) {
2770
2928
  return value ? value : void 0;
2771
2929
  }
2930
+ function isCacheControlHeaderName2(name) {
2931
+ return name.toLowerCase() === "cache-control";
2932
+ }
2772
2933
  function parseResponseBody2(rawText, contentType) {
2773
2934
  if (!rawText) {
2774
2935
  return { parsed: null, parseFailed: false };
@@ -2824,6 +2985,54 @@ function mergeCallOptions(base, override) {
2824
2985
  }
2825
2986
  };
2826
2987
  }
2988
+ function toSessionGuardFailure(sessionResult) {
2989
+ if (sessionResult.status === 401 || sessionResult.data == null) {
2990
+ return {
2991
+ ok: false,
2992
+ reason: "unauthorized",
2993
+ status: 401,
2994
+ error: sessionResult.error ?? "Unauthorized",
2995
+ sessionResult
2996
+ };
2997
+ }
2998
+ return {
2999
+ ok: false,
3000
+ reason: "upstream_error",
3001
+ status: sessionResult.status,
3002
+ error: sessionResult.error ?? "Failed to resolve current session",
3003
+ sessionResult
3004
+ };
3005
+ }
3006
+ function toPermissionGuardFailure(permissionResult, sessionResult) {
3007
+ if (permissionResult.status === 401) {
3008
+ return {
3009
+ ok: false,
3010
+ reason: "unauthorized",
3011
+ status: 401,
3012
+ error: permissionResult.error ?? "Unauthorized",
3013
+ sessionResult,
3014
+ permissionResult
3015
+ };
3016
+ }
3017
+ if (permissionResult.status === 403) {
3018
+ return {
3019
+ ok: false,
3020
+ reason: "forbidden",
3021
+ status: 403,
3022
+ error: permissionResult.error ?? "Forbidden",
3023
+ sessionResult,
3024
+ permissionResult
3025
+ };
3026
+ }
3027
+ return {
3028
+ ok: false,
3029
+ reason: "upstream_error",
3030
+ status: permissionResult.status,
3031
+ error: permissionResult.error ?? "Failed to resolve permission check",
3032
+ sessionResult,
3033
+ permissionResult
3034
+ };
3035
+ }
2827
3036
  function extractFetchOptions(input) {
2828
3037
  if (!input) {
2829
3038
  return {
@@ -2839,6 +3048,7 @@ function extractFetchOptions(input) {
2839
3048
  };
2840
3049
  }
2841
3050
  function buildHeaders2(config, options) {
3051
+ const forceNoCache = Boolean(config.forceNoCache || options?.forceNoCache);
2842
3052
  const headers = {
2843
3053
  "Content-Type": "application/json",
2844
3054
  "X-Athena-Sdk": SDK_HEADER_VALUE2
@@ -2852,16 +3062,30 @@ function buildHeaders2(config, options) {
2852
3062
  if (bearerToken) {
2853
3063
  headers.Authorization = `Bearer ${bearerToken}`;
2854
3064
  }
3065
+ const cookie = options?.cookie ?? config.cookie;
3066
+ if (cookie) {
3067
+ headers.Cookie = cookie;
3068
+ }
3069
+ const sessionToken = options?.sessionToken ?? config.sessionToken;
3070
+ if (sessionToken) {
3071
+ headers["X-Athena-Auth-Session-Token"] = sessionToken;
3072
+ }
2855
3073
  const mergedExtraHeaders = {
2856
3074
  ...config.headers ?? {},
2857
3075
  ...options?.headers ?? {}
2858
3076
  };
2859
3077
  Object.entries(mergedExtraHeaders).forEach(([key, value]) => {
3078
+ if (forceNoCache && isCacheControlHeaderName2(key)) {
3079
+ return;
3080
+ }
2860
3081
  const normalized = normalizeHeaderValue2(value);
2861
3082
  if (normalized) {
2862
3083
  headers[key] = normalized;
2863
3084
  }
2864
3085
  });
3086
+ if (forceNoCache) {
3087
+ headers["Cache-Control"] = NO_CACHE_HEADER_VALUE2;
3088
+ }
2865
3089
  return headers;
2866
3090
  }
2867
3091
  function appendQueryParam(searchParams, key, value) {
@@ -3126,7 +3350,91 @@ function createAuthClient(config = {}) {
3126
3350
  htmlField: "htmlTemplate",
3127
3351
  textField: "textTemplate",
3128
3352
  variablesField: "variables"
3129
- }, withReactEmailRoute(route));
3353
+ }, withReactEmailRoute(route)).then((payload) => {
3354
+ if ("variables" in payload && payload.variables !== void 0 && payload.variables !== null) {
3355
+ assertAthenaAuthTemplateVariables(
3356
+ payload.variables,
3357
+ `${route} variables`
3358
+ );
3359
+ }
3360
+ return payload;
3361
+ });
3362
+ const requireSession = async (input, options) => {
3363
+ const sessionInput = input?.fetchOptions ? { fetchOptions: input.fetchOptions } : void 0;
3364
+ const sessionResult = await getGeneric(
3365
+ "/get-session",
3366
+ sessionInput,
3367
+ options
3368
+ );
3369
+ if (!sessionResult.ok || sessionResult.data == null) {
3370
+ return toSessionGuardFailure(sessionResult);
3371
+ }
3372
+ return {
3373
+ ok: true,
3374
+ session: sessionResult.data
3375
+ };
3376
+ };
3377
+ const getUser = async (input, options) => {
3378
+ const sessionResult = await getGeneric(
3379
+ "/get-session",
3380
+ input,
3381
+ options
3382
+ );
3383
+ if (!sessionResult.ok) {
3384
+ return {
3385
+ ...sessionResult,
3386
+ data: null
3387
+ };
3388
+ }
3389
+ return {
3390
+ ...sessionResult,
3391
+ data: {
3392
+ user: sessionResult.data?.user ?? null
3393
+ }
3394
+ };
3395
+ };
3396
+ const requirePermission = async (endpoint, input, options) => {
3397
+ const sessionGuard = await requireSession(
3398
+ input?.fetchOptions ? { fetchOptions: input.fetchOptions } : void 0,
3399
+ options
3400
+ );
3401
+ if (!sessionGuard.ok) {
3402
+ return sessionGuard;
3403
+ }
3404
+ const permissionResult = await postGeneric(
3405
+ endpoint,
3406
+ input,
3407
+ options
3408
+ );
3409
+ if (!permissionResult.ok) {
3410
+ return toPermissionGuardFailure(permissionResult, {
3411
+ ok: true,
3412
+ status: 200,
3413
+ data: sessionGuard.session,
3414
+ error: null,
3415
+ errorDetails: null,
3416
+ raw: sessionGuard.session
3417
+ });
3418
+ }
3419
+ if (!permissionResult.data?.success) {
3420
+ return {
3421
+ ok: false,
3422
+ reason: "forbidden",
3423
+ status: 403,
3424
+ error: permissionResult.data?.error ?? "Forbidden",
3425
+ sessionResult: {
3426
+ ok: true,
3427
+ status: 200,
3428
+ data: sessionGuard.session,
3429
+ error: null,
3430
+ errorDetails: null,
3431
+ raw: sessionGuard.session
3432
+ },
3433
+ permissionResult
3434
+ };
3435
+ }
3436
+ return sessionGuard;
3437
+ };
3130
3438
  const listUserEmailsWithFallback = async (input, options) => {
3131
3439
  const primary = await getWithQuery(
3132
3440
  "/email/list",
@@ -3288,6 +3596,7 @@ function createAuthClient(config = {}) {
3288
3596
  input,
3289
3597
  options
3290
3598
  ),
3599
+ requirePermission: (input, options) => requirePermission("/organization/has-permission", input, options),
3291
3600
  invitation: {
3292
3601
  cancel: (input, options) => executePostWithCompatibleInput(
3293
3602
  resolvedConfig,
@@ -3483,6 +3792,8 @@ function createAuthClient(config = {}) {
3483
3792
  };
3484
3793
  const auth = {
3485
3794
  getSession: (input, options) => getGeneric("/get-session", input, options),
3795
+ getUser,
3796
+ requireSession,
3486
3797
  signOut,
3487
3798
  forgetPassword: (input, options) => postGeneric("/forget-password", input, options),
3488
3799
  resetPassword: authResetPassword,
@@ -3577,6 +3888,7 @@ function createAuthClient(config = {}) {
3577
3888
  }
3578
3889
  },
3579
3890
  hasPermission: (input, options) => postGeneric("/admin/has-permission", input, options),
3891
+ requirePermission: (input, options) => requirePermission("/admin/has-permission", input, options),
3580
3892
  apiKey: {
3581
3893
  create: (input, options) => postGeneric("/admin/api-key/create", input, options)
3582
3894
  },
@@ -3728,6 +4040,8 @@ function createAuthClient(config = {}) {
3728
4040
  input,
3729
4041
  options
3730
4042
  ),
4043
+ getUser,
4044
+ requireSession,
3731
4045
  listSessions: (input, options) => executeGetWithCompatibleInput(
3732
4046
  resolvedConfig,
3733
4047
  { endpoint: "/list-sessions", method: "GET" },
@@ -8405,6 +8719,59 @@ function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
8405
8719
  );
8406
8720
  };
8407
8721
  }
8722
+ function normalizeOptionalString2(value) {
8723
+ if (typeof value !== "string") {
8724
+ return void 0;
8725
+ }
8726
+ const normalizedValue = value.trim();
8727
+ return normalizedValue ? normalizedValue : void 0;
8728
+ }
8729
+ function readHeaderBagValue(headers, targetKey) {
8730
+ if (!headers) {
8731
+ return void 0;
8732
+ }
8733
+ if (typeof headers.get === "function") {
8734
+ return normalizeOptionalString2(headers.get(targetKey));
8735
+ }
8736
+ const normalizedTargetKey = targetKey.toLowerCase();
8737
+ for (const [key, value] of Object.entries(headers)) {
8738
+ if (key.toLowerCase() !== normalizedTargetKey) {
8739
+ continue;
8740
+ }
8741
+ if (typeof value === "string") {
8742
+ return normalizeOptionalString2(value);
8743
+ }
8744
+ return void 0;
8745
+ }
8746
+ return void 0;
8747
+ }
8748
+ function resolveSessionContextOptions(session, options) {
8749
+ const sessionToken = normalizeOptionalString2(session?.session?.token);
8750
+ const requestCookie = readHeaderBagValue(options?.requestHeaders, "cookie") ?? readHeaderBagValue(options?.headers, "cookie");
8751
+ const authInput = options?.auth;
8752
+ const resolvedUserId = options?.userId !== void 0 ? options.userId : session?.user?.id;
8753
+ const resolvedOrganizationId = options?.organizationId !== void 0 ? options.organizationId : session?.session?.activeOrganizationId;
8754
+ const resolvedBearerToken = authInput?.bearerToken !== void 0 ? authInput.bearerToken : sessionToken;
8755
+ const resolvedSessionToken = authInput?.sessionToken !== void 0 ? authInput.sessionToken : sessionToken;
8756
+ const resolvedCookie = authInput?.cookie !== void 0 ? authInput.cookie : requestCookie;
8757
+ const auth = authInput !== void 0 || resolvedBearerToken !== void 0 || resolvedSessionToken !== void 0 || resolvedCookie !== void 0 ? {
8758
+ ...authInput ?? {},
8759
+ ...resolvedBearerToken !== void 0 ? { bearerToken: resolvedBearerToken } : {},
8760
+ ...resolvedSessionToken !== void 0 ? { sessionToken: resolvedSessionToken } : {},
8761
+ ...resolvedCookie !== void 0 ? { cookie: resolvedCookie } : {},
8762
+ headers: authInput?.headers ? { ...authInput.headers } : void 0
8763
+ } : void 0;
8764
+ if (resolvedUserId === void 0 && resolvedOrganizationId === void 0 && options?.forceNoCache === void 0 && !options?.headers && !auth) {
8765
+ return void 0;
8766
+ }
8767
+ return {
8768
+ userId: resolvedUserId,
8769
+ organizationId: resolvedOrganizationId,
8770
+ forceNoCache: options?.forceNoCache,
8771
+ headers: options?.headers ? { ...options.headers } : void 0,
8772
+ auth
8773
+ };
8774
+ }
8408
8775
  function resolveClientServiceBaseUrl(value, label) {
8409
8776
  if (value === void 0 || value === null) {
8410
8777
  return void 0;
@@ -8447,6 +8814,87 @@ function resolveRequiredClientApiKey(value) {
8447
8814
  }
8448
8815
  return normalizedValue;
8449
8816
  }
8817
+ function hasHeaderIgnoreCase(headers, targetKey) {
8818
+ const normalizedTargetKey = targetKey.toLowerCase();
8819
+ return Object.keys(headers).some((key) => key.toLowerCase() === normalizedTargetKey);
8820
+ }
8821
+ function mergeClientHeaders(current, next) {
8822
+ if (!current && !next) {
8823
+ return void 0;
8824
+ }
8825
+ return {
8826
+ ...current ?? {},
8827
+ ...next ?? {}
8828
+ };
8829
+ }
8830
+ function mergeDefinedObject(current, next) {
8831
+ if (!current && !next) {
8832
+ return void 0;
8833
+ }
8834
+ const merged = {
8835
+ ...current ?? {}
8836
+ };
8837
+ const mutableMerged = merged;
8838
+ for (const [key, value] of Object.entries(next ?? {})) {
8839
+ if (value !== void 0) {
8840
+ mutableMerged[key] = value;
8841
+ }
8842
+ }
8843
+ return merged;
8844
+ }
8845
+ function mergeAuthClientOptions(current, next) {
8846
+ const merged = mergeDefinedObject(current, next);
8847
+ if (!merged) {
8848
+ return void 0;
8849
+ }
8850
+ const mergedHeaders = mergeClientHeaders(current?.headers, next?.headers);
8851
+ if (mergedHeaders) {
8852
+ merged.headers = mergedHeaders;
8853
+ }
8854
+ return merged;
8855
+ }
8856
+ function mergeServiceUrlOverrides(current, next) {
8857
+ return mergeDefinedObject(current, next);
8858
+ }
8859
+ function toClientContextOverrides(context) {
8860
+ if (!context) {
8861
+ return void 0;
8862
+ }
8863
+ return {
8864
+ userId: context.userId,
8865
+ organizationId: context.organizationId,
8866
+ forceNoCache: context.forceNoCache,
8867
+ headers: context.headers,
8868
+ auth: context.auth ? {
8869
+ ...context.auth,
8870
+ headers: context.auth.headers ? { ...context.auth.headers } : void 0
8871
+ } : void 0
8872
+ };
8873
+ }
8874
+ function mergeClientOverrideOptions(base, overrides) {
8875
+ if (!overrides) {
8876
+ return {
8877
+ ...base,
8878
+ headers: base.headers ? { ...base.headers } : void 0,
8879
+ auth: base.auth ? {
8880
+ ...base.auth,
8881
+ headers: base.auth.headers ? { ...base.auth.headers } : void 0
8882
+ } : void 0,
8883
+ db: base.db ? { ...base.db } : void 0,
8884
+ gateway: base.gateway ? { ...base.gateway } : void 0,
8885
+ storage: base.storage ? { ...base.storage } : void 0
8886
+ };
8887
+ }
8888
+ const merged = mergeDefinedObject(base, overrides) ?? { ...base };
8889
+ return {
8890
+ ...merged,
8891
+ headers: mergeClientHeaders(base.headers, overrides.headers),
8892
+ auth: mergeAuthClientOptions(base.auth, overrides.auth),
8893
+ db: mergeServiceUrlOverrides(base.db, overrides.db),
8894
+ gateway: mergeServiceUrlOverrides(base.gateway, overrides.gateway),
8895
+ storage: mergeServiceUrlOverrides(base.storage, overrides.storage)
8896
+ };
8897
+ }
8450
8898
  function normalizeAuthClientConfig(auth, defaultBaseUrl) {
8451
8899
  if (!auth && defaultBaseUrl === void 0) {
8452
8900
  return void 0;
@@ -8456,6 +8904,8 @@ function normalizeAuthClientConfig(auth, defaultBaseUrl) {
8456
8904
  baseUrl,
8457
8905
  apiKey,
8458
8906
  bearerToken,
8907
+ cookie,
8908
+ sessionToken,
8459
8909
  ...rest
8460
8910
  } = auth ?? {};
8461
8911
  const normalized = {
@@ -8474,6 +8924,12 @@ function normalizeAuthClientConfig(auth, defaultBaseUrl) {
8474
8924
  if (typeof bearerToken === "string") {
8475
8925
  normalized.bearerToken = bearerToken;
8476
8926
  }
8927
+ if (typeof cookie === "string") {
8928
+ normalized.cookie = cookie;
8929
+ }
8930
+ if (typeof sessionToken === "string") {
8931
+ normalized.sessionToken = sessionToken;
8932
+ }
8477
8933
  return normalized;
8478
8934
  }
8479
8935
  function resolveCreateClientConfig(config) {
@@ -8487,6 +8943,9 @@ function resolveCreateClientConfig(config) {
8487
8943
  baseUrl: resolvedUrls.dbUrl,
8488
8944
  apiKey: resolveRequiredClientApiKey(config.key),
8489
8945
  client: resolveOptionalClientName(config.client),
8946
+ userId: config.userId,
8947
+ organizationId: config.organizationId,
8948
+ forceNoCache: config.forceNoCache,
8490
8949
  backend: toBackendConfig(config.backend),
8491
8950
  headers: config.headers,
8492
8951
  auth: config.auth,
@@ -8495,23 +8954,39 @@ function resolveCreateClientConfig(config) {
8495
8954
  experimental: config.experimental
8496
8955
  };
8497
8956
  }
8498
- function createClientFromConfig(config) {
8957
+ function createClientFromInput(sourceConfig) {
8958
+ return createClientFromConfig(resolveCreateClientConfig(sourceConfig), sourceConfig);
8959
+ }
8960
+ function createClientFromConfig(config, sourceConfig) {
8961
+ const normalizedAuthConfig = normalizeAuthClientConfig(config.auth, config.authUrl);
8499
8962
  const gatewayHeaders = {
8500
8963
  ...config.headers ?? {}
8501
8964
  };
8502
- if (config.auth?.bearerToken && gatewayHeaders["X-Athena-Auth-Bearer-Token"] === void 0 && gatewayHeaders["x-athena-auth-bearer-token"] === void 0) {
8503
- gatewayHeaders["X-Athena-Auth-Bearer-Token"] = config.auth.bearerToken;
8965
+ if (normalizedAuthConfig?.bearerToken && !hasHeaderIgnoreCase(gatewayHeaders, "X-Athena-Auth-Bearer-Token")) {
8966
+ gatewayHeaders["X-Athena-Auth-Bearer-Token"] = normalizedAuthConfig.bearerToken;
8967
+ }
8968
+ if (normalizedAuthConfig?.cookie && !hasHeaderIgnoreCase(gatewayHeaders, "Cookie")) {
8969
+ gatewayHeaders.Cookie = normalizedAuthConfig.cookie;
8970
+ }
8971
+ if (normalizedAuthConfig?.sessionToken && !hasHeaderIgnoreCase(gatewayHeaders, "X-Athena-Auth-Session-Token")) {
8972
+ gatewayHeaders["X-Athena-Auth-Session-Token"] = normalizedAuthConfig.sessionToken;
8504
8973
  }
8505
8974
  const gateway = createAthenaGatewayClient({
8506
8975
  baseUrl: config.baseUrl,
8507
8976
  apiKey: config.apiKey,
8508
8977
  client: config.client,
8978
+ userId: config.userId,
8979
+ organizationId: config.organizationId,
8980
+ forceNoCache: config.forceNoCache,
8509
8981
  backend: config.backend,
8510
8982
  headers: gatewayHeaders
8511
8983
  });
8512
8984
  const formatGatewayResult = createResultFormatter(config.experimental);
8513
8985
  const queryTracer = createQueryTracer(config.experimental);
8514
- const auth = createAuthClient(normalizeAuthClientConfig(config.auth, config.authUrl));
8986
+ const auth = createAuthClient({
8987
+ ...normalizedAuthConfig ?? {},
8988
+ ...config.forceNoCache ? { forceNoCache: true } : {}
8989
+ });
8515
8990
  function from(tableOrModel, options) {
8516
8991
  if (isAthenaModelTarget(tableOrModel)) {
8517
8992
  if (options?.schema !== void 0) {
@@ -8559,17 +9034,45 @@ function createClientFromConfig(config) {
8559
9034
  queryTracer
8560
9035
  );
8561
9036
  const db = createDbModule({ from, rpc, query });
9037
+ const withContext = (context) => createClientFromInput(
9038
+ mergeClientOverrideOptions(sourceConfig, toClientContextOverrides(context))
9039
+ );
9040
+ const withSession = (session, options) => createClientFromInput(
9041
+ mergeClientOverrideOptions(
9042
+ sourceConfig,
9043
+ toClientContextOverrides(resolveSessionContextOptions(session, options))
9044
+ )
9045
+ );
9046
+ const authWithOptions = (options) => createClientFromInput(mergeClientOverrideOptions(sourceConfig, options));
8562
9047
  const sdkClient = {
8563
9048
  from,
8564
9049
  db,
8565
9050
  rpc,
8566
9051
  query,
8567
9052
  verifyConnection: gateway.verifyConnection,
8568
- auth: auth.auth
9053
+ auth: auth.auth,
9054
+ withContext,
9055
+ withSession,
9056
+ withOptions: authWithOptions
8569
9057
  };
8570
9058
  if (config.experimental?.athenaStorageBackend) {
9059
+ const storageWithContext = (context) => createClientFromInput(
9060
+ mergeClientOverrideOptions(sourceConfig, toClientContextOverrides(context))
9061
+ );
9062
+ const storageWithSession = (session, options) => createClientFromInput(
9063
+ mergeClientOverrideOptions(
9064
+ sourceConfig,
9065
+ toClientContextOverrides(resolveSessionContextOptions(session, options))
9066
+ )
9067
+ );
9068
+ const storageWithOptions = (options) => createClientFromInput(
9069
+ mergeClientOverrideOptions(sourceConfig, options)
9070
+ );
8571
9071
  const storageClient = {
8572
9072
  ...sdkClient,
9073
+ withContext: storageWithContext,
9074
+ withSession: storageWithSession,
9075
+ withOptions: storageWithOptions,
8573
9076
  storage: createStorageModule(gateway, {
8574
9077
  ...config.experimental.storage,
8575
9078
  ...config.storageUrl ? {
@@ -8584,13 +9087,13 @@ function createClientFromConfig(config) {
8584
9087
  }
8585
9088
  function createClient(configOrUrl, apiKey, options) {
8586
9089
  if (typeof configOrUrl === "string" || configOrUrl === null || configOrUrl === void 0) {
8587
- return createClientFromConfig(resolveCreateClientConfig({
9090
+ return createClientFromInput({
8588
9091
  url: configOrUrl,
8589
9092
  key: apiKey ?? "",
8590
9093
  ...options
8591
- }));
9094
+ });
8592
9095
  }
8593
- return createClientFromConfig(resolveCreateClientConfig(configOrUrl));
9096
+ return createClientFromInput(configOrUrl);
8594
9097
  }
8595
9098
 
8596
9099
  // src/schema/postgres-introspection-core.ts
@@ -9146,16 +9649,25 @@ async function fileExists(path) {
9146
9649
  }
9147
9650
  async function writeArtifacts(files, cwd) {
9148
9651
  const writtenFiles = [];
9652
+ const skippedFiles = [];
9149
9653
  for (const file of files) {
9150
9654
  const absolutePath = path.resolve(cwd, file.path);
9151
9655
  if (!canOverwriteArtifact(file) && await fileExists(absolutePath)) {
9656
+ skippedFiles.push({
9657
+ kind: file.kind,
9658
+ path: file.path,
9659
+ reason: "protected-existing-file"
9660
+ });
9152
9661
  continue;
9153
9662
  }
9154
9663
  await promises.mkdir(path.dirname(absolutePath), { recursive: true });
9155
9664
  await promises.writeFile(absolutePath, file.content, "utf8");
9156
9665
  writtenFiles.push(file.path);
9157
9666
  }
9158
- return writtenFiles;
9667
+ return {
9668
+ writtenFiles,
9669
+ skippedFiles
9670
+ };
9159
9671
  }
9160
9672
  async function runSchemaGenerator(options = {}) {
9161
9673
  const cwd = options.cwd ?? process.cwd();
@@ -9169,12 +9681,13 @@ async function runSchemaGenerator(options = {}) {
9169
9681
  schemas: resolveProviderSchemas(config.provider)
9170
9682
  });
9171
9683
  const generated = generateArtifactsFromSnapshot(snapshot, config);
9172
- const writtenFiles = options.dryRun ? [] : await writeArtifacts(generated.files, cwd);
9684
+ const writeResult = options.dryRun ? { writtenFiles: [], skippedFiles: [] } : await writeArtifacts(generated.files, cwd);
9173
9685
  return {
9174
9686
  ...generated,
9175
9687
  configPath,
9176
9688
  config,
9177
- writtenFiles
9689
+ writtenFiles: writeResult.writtenFiles,
9690
+ skippedFiles: writeResult.skippedFiles
9178
9691
  };
9179
9692
  }
9180
9693
 
@@ -9216,24 +9729,64 @@ function generateUsage() {
9216
9729
  " athena-js generate --config ./athena.config.ts --dry-run"
9217
9730
  ].join("\n");
9218
9731
  }
9219
- function usesSchemaScopedModelTarget(target) {
9220
- return /\{schema(?:_[a-z]+)?\}/.test(target);
9732
+ function normalizePath2(pathValue) {
9733
+ return pathValue.replace(/\\/g, "/");
9734
+ }
9735
+ function isLegacyConfigRegistryTarget(target) {
9736
+ return normalizePath2(target) === "athena/config.ts";
9737
+ }
9738
+ function isFlatSchemaTarget(target) {
9739
+ return normalizePath2(target) === "athena/schema.ts";
9740
+ }
9741
+ function formatProviderLine(result) {
9742
+ const { provider } = result.config;
9743
+ if (provider.kind === "postgres") {
9744
+ const schemaList = Array.isArray(provider.schemas) ? provider.schemas.join(",") : typeof provider.schemas === "string" ? provider.schemas : "public";
9745
+ const database = provider.database ? ` database=${provider.database}` : "";
9746
+ const backend = provider.mode === "gateway" && provider.backend ? ` backend=${provider.backend}` : "";
9747
+ return `[provider] kind=${provider.kind} mode=${provider.mode}${database}${backend} schemas=${schemaList}`;
9748
+ }
9749
+ const datacenter = provider.datacenter ? ` datacenter=${provider.datacenter}` : "";
9750
+ return `[provider] kind=${provider.kind} mode=${provider.mode} keyspace=${provider.keyspace} contactPoints=${provider.contactPoints.join(",")}${datacenter}`;
9751
+ }
9752
+ function formatFilterLine(result) {
9753
+ const { includeTables, excludeTables } = result.config.filter;
9754
+ if (includeTables.length === 0 && excludeTables.length === 0) {
9755
+ return void 0;
9756
+ }
9757
+ return `[filter] include=${includeTables.length > 0 ? includeTables.join(",") : "-"} exclude=${excludeTables.length > 0 ? excludeTables.join(",") : "-"}`;
9221
9758
  }
9222
9759
  function formatGeneratorModeLines(result) {
9223
9760
  const lines = [
9224
- `[mode] format=${result.config.output.format} modelTarget=${result.config.output.targets.model}`
9761
+ `[mode] preset=${result.config.output.preset} format=${result.config.output.format} modelTarget=${result.config.output.targets.model}`,
9762
+ formatProviderLine(result),
9763
+ `[targets] schema=${result.config.output.targets.schema} database=${result.config.output.targets.database} registry=${result.config.output.targets.registry}`
9225
9764
  ];
9765
+ const filterLine = formatFilterLine(result);
9766
+ if (filterLine) {
9767
+ lines.push(filterLine);
9768
+ }
9226
9769
  if (result.config.output.format === "define-model") {
9227
9770
  lines.push(
9228
- '[note] Zero-style table-builder files are not active. Set output.format="table-builder" or ATHENA_GENERATOR_OUTPUT_FORMAT=table-builder to emit table(...).schema(...).columns(...).primaryKey(...).'
9771
+ '[note] Legacy define-model compatibility output is active. Set output.format="table-builder" or ATHENA_GENERATOR_OUTPUT_FORMAT=table-builder to emit table(...).schema(...).columns(...).primaryKey(...).'
9772
+ );
9773
+ }
9774
+ if (result.config.output.preset === "legacy") {
9775
+ lines.push(
9776
+ '[note] Legacy preset is active. It keeps registry output on athena/config.ts for compatibility; prefer output.preset="athena-direct" for the default safe direct layout.'
9229
9777
  );
9230
9778
  }
9231
9779
  lines.push(
9232
- "[note] Table-builder generation is stable. experimental.findManyAst only affects runtime findMany(...) transport and does not enable generator table output."
9780
+ "[note] Default generator mode is preset=athena-direct + format=table-builder. experimental.findManyAst only affects runtime findMany(...) transport and does not enable generator table output."
9233
9781
  );
9234
- if (usesSchemaScopedModelTarget(result.config.output.targets.model)) {
9782
+ if (isLegacyConfigRegistryTarget(result.config.output.targets.registry)) {
9235
9783
  lines.push(
9236
- '[note] Flat athena/models/*.ts output is opt-in. Set output.targets.model="athena/models/{model_kebab}.ts" or ATHENA_GENERATOR_MODEL_TARGET=athena/models/{model_kebab}.ts; multi-schema collisions are still auto-scoped by schema when needed.'
9784
+ '[warn] Registry target points at athena/config.ts. That file is often a handwritten runtime seam; prefer output.preset="athena-direct" or output.targets.registry="athena/registry.generated.ts" unless you intentionally need legacy compatibility.'
9785
+ );
9786
+ }
9787
+ if (isFlatSchemaTarget(result.config.output.targets.schema)) {
9788
+ lines.push(
9789
+ "[warn] Schema target points at athena/schema.ts. Prefer schema-scoped output such as athena/schemas/{schema_kebab}.ts."
9237
9790
  );
9238
9791
  }
9239
9792
  return lines;
@@ -9320,6 +9873,12 @@ function formatGeneratorError(error, configPath) {
9320
9873
  }
9321
9874
  return new Error(normalizeErrorMessage(error));
9322
9875
  }
9876
+ function formatSkippedArtifactLine(artifact) {
9877
+ if (artifact.reason === "protected-existing-file") {
9878
+ return ` [skip] ${artifact.path} (existing ${artifact.kind} artifacts are protected from overwrite; delete or retarget the file to regenerate it)`;
9879
+ }
9880
+ return ` [skip] ${artifact.path}`;
9881
+ }
9323
9882
  async function runCLI(argv, runtime = {}) {
9324
9883
  const log = runtime.log ?? console.log;
9325
9884
  const runGenerator = runtime.runGenerator ?? runSchemaGenerator;
@@ -9354,6 +9913,9 @@ async function runCLI(argv, runtime = {}) {
9354
9913
  for (const filePath of result.writtenFiles) {
9355
9914
  log(` - ${filePath}`);
9356
9915
  }
9916
+ for (const artifact of result.skippedFiles) {
9917
+ log(formatSkippedArtifactLine(artifact));
9918
+ }
9357
9919
  }
9358
9920
 
9359
9921
  exports.parseCommand = parseCommand;