@xylex-group/athena 1.6.2 → 1.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # athena-js
2
2
 
3
- current version: `1.6.2`
3
+ current version: `1.9.0`
4
4
  `@xylex-group/athena` is a database driver and API gateway SDK that lets you interact with SQL backends over HTTP through a fluent builder API. It ships a typed query builder for Node.js / server environments plus Athena-native React hooks for client-side use.
5
5
 
6
6
  ## Install
@@ -43,6 +43,51 @@ if (error) {
43
43
  }
44
44
  ```
45
45
 
46
+ ### Auth client (Athena Auth server)
47
+
48
+ If your auth backend is now Athena Auth, you can keep core login/session flows in this SDK:
49
+
50
+ ```ts
51
+ import { createAuthClient } from "@xylex-group/athena";
52
+
53
+ const auth = createAuthClient({
54
+ baseUrl: "http://localhost:3001/api/auth",
55
+ // optional: bearer token if you are not using cookie-based sessions
56
+ bearerToken: process.env.AUTH_BEARER_TOKEN,
57
+ });
58
+
59
+ const login = await auth.signIn.email({
60
+ email: "demo@example.com",
61
+ password: "super-secret",
62
+ rememberMe: true,
63
+ });
64
+
65
+ const session = await auth.getSession();
66
+ const sessions = await auth.listSessions();
67
+
68
+ // clear one session
69
+ await auth.revokeSession({ token: "session_token_here" });
70
+ // or clear all sessions
71
+ await auth.revokeSessions();
72
+
73
+ await auth.signOut();
74
+
75
+ // additional core flows
76
+ await auth.forgetPassword({ email: "demo@example.com", redirectTo: "https://app/reset-password" });
77
+ await auth.resetPassword({ newPassword: "new-secret", token: "reset_token" });
78
+ await auth.verifyEmail({ token: "verify_token", callbackURL: "https://app/verified" });
79
+ await auth.changePassword({ currentPassword: "old-secret", newPassword: "new-secret" });
80
+ await auth.updateUser({ name: "Demo User" });
81
+
82
+ // escape hatch for any endpoint on your Athena Auth instance
83
+ await auth.request({
84
+ endpoint: "/ok",
85
+ query: { ping: "pong" },
86
+ });
87
+ ```
88
+
89
+ Auth responses follow the same envelope style: `{ ok, status, data, error, errorDetails, raw }`.
90
+
46
91
  ### Typed schema registry (model-first)
47
92
 
48
93
  You can keep `createClient(...).from<T>(...)` as-is, or opt into a typed registry:
@@ -101,6 +146,7 @@ Generator supports:
101
146
 
102
147
  - PostgreSQL direct introspection (`provider.mode = "direct"`, `provider.connectionString` from your `PG_URL`/`DATABASE_URL`)
103
148
  - PostgreSQL gateway-only introspection (`provider.mode = "gateway"` via Athena `POST /gateway/query`)
149
+ - Multiple schema syncs such as `public` plus `athena`, with schema-safe default output paths
104
150
  - Placeholder-driven output paths
105
151
  - Feature flags (`features.emitRegistry`, `features.emitRelations`)
106
152
 
@@ -344,11 +390,23 @@ const { data: user } = await athena
344
390
  .single();
345
391
  ```
346
392
 
347
- `maybeSingle` behaves identically — both return the first element of the result set.
348
-
349
- ### RPC
350
-
351
- Use `athena.rpc(...)` for Postgres function calls. By default it calls `POST /gateway/rpc`, and with `{ get: true }` it uses the compatibility route `GET /rpc/{function_name}`.
393
+ `maybeSingle` behaves identically — both return the first element of the result set.
394
+
395
+ ### Table schema targeting
396
+
397
+ Use `schema` in table call options to qualify unqualified table names:
398
+
399
+ ```ts
400
+ const { data } = await athena
401
+ .from("users")
402
+ .select("id,email", { schema: "public" });
403
+ ```
404
+
405
+ This resolves the table target to `public.users`.
406
+
407
+ ### RPC
408
+
409
+ Use `athena.rpc(...)` for Postgres function calls. By default it calls `POST /gateway/rpc`, and with `{ get: true }` it uses the compatibility route `GET /rpc/{function_name}`.
352
410
 
353
411
  ```ts
354
412
  const { data, count } = await athena
@@ -382,11 +440,12 @@ RPC options: `schema`, `count` (`"exact" | "planned" | "estimated"`), `head`, `g
382
440
 
383
441
  Pass options as the second argument to `.select()`:
384
442
 
385
- | Option | Type | Description |
386
- | ------------ | ------------------------------------- | -------------------------------------------- |
387
- | `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
388
- | `head` | `boolean` | return response headers only (no rows) |
389
- | `stripNulls` | `boolean` | strip null values from rows (default `true`) |
443
+ | Option | Type | Description |
444
+ | ------------ | ------------------------------------- | -------------------------------------------- |
445
+ | `schema` | `string` | qualify unqualified table names for table calls |
446
+ | `count` | `"exact" \| "planned" \| "estimated"` | request a row count alongside the data |
447
+ | `head` | `boolean` | return response headers only (no rows) |
448
+ | `stripNulls` | `boolean` | strip null values from rows (default `true`) |
390
449
 
391
450
  ```ts
392
451
  const { data } = await athena
package/bin/athena-js.js CHANGED
File without changes
@@ -291,6 +291,37 @@ function resolvePostgresColumnType(column) {
291
291
  }
292
292
  return wrapArrayType(baseType, column.arrayDimensions);
293
293
  }
294
+
295
+ // src/generator/schema-selection.ts
296
+ var DEFAULT_POSTGRES_SCHEMAS = ["public"];
297
+ function collectSchemaNames(input) {
298
+ if (!input) {
299
+ return [];
300
+ }
301
+ const values = typeof input === "string" ? [input] : input;
302
+ return values.flatMap((value) => String(value).split(","));
303
+ }
304
+ function normalizeSchemaSelection(input) {
305
+ const schemas = [];
306
+ const seen = /* @__PURE__ */ new Set();
307
+ for (const value of collectSchemaNames(input)) {
308
+ const schema = value.trim();
309
+ if (!schema || seen.has(schema)) {
310
+ continue;
311
+ }
312
+ seen.add(schema);
313
+ schemas.push(schema);
314
+ }
315
+ return schemas.length > 0 ? schemas : [...DEFAULT_POSTGRES_SCHEMAS];
316
+ }
317
+ function resolveProviderSchemas(providerConfig) {
318
+ if (providerConfig.kind === "postgres") {
319
+ return normalizeSchemaSelection(providerConfig.schemas);
320
+ }
321
+ return [...DEFAULT_POSTGRES_SCHEMAS];
322
+ }
323
+
324
+ // src/generator/config.ts
294
325
  var DEFAULT_CONFIG_CANDIDATES = [
295
326
  "athena.config.ts",
296
327
  "athena.config.js",
@@ -300,8 +331,8 @@ var DEFAULT_CONFIG_CANDIDATES = [
300
331
  ".athena.config.js"
301
332
  ];
302
333
  var DEFAULT_TARGETS = {
303
- model: "athena/models/{model_kebab}.ts",
304
- schema: "athena/schema.ts",
334
+ model: "athena/models/{schema_kebab}/{model_kebab}.ts",
335
+ schema: "athena/schemas/{schema_kebab}.ts",
305
336
  database: "athena/relations.ts",
306
337
  registry: "athena/config.ts"
307
338
  };
@@ -331,6 +362,15 @@ function normalizeOutputConfig(output) {
331
362
  }
332
363
  };
333
364
  }
365
+ function normalizeProviderConfig(provider) {
366
+ if (provider.kind === "postgres") {
367
+ return {
368
+ ...provider,
369
+ schemas: normalizeSchemaSelection(provider.schemas)
370
+ };
371
+ }
372
+ return provider;
373
+ }
334
374
  function isAthenaGeneratorConfig(value) {
335
375
  if (!value || typeof value !== "object") {
336
376
  return false;
@@ -340,7 +380,7 @@ function isAthenaGeneratorConfig(value) {
340
380
  }
341
381
  function normalizeGeneratorConfig(input) {
342
382
  return {
343
- provider: input.provider,
383
+ provider: normalizeProviderConfig(input.provider),
344
384
  output: normalizeOutputConfig(input.output),
345
385
  naming: {
346
386
  ...DEFAULT_NAMING,
@@ -550,12 +590,19 @@ export const ${registryConstName} = defineRegistry({
550
590
  };
551
591
  }
552
592
  function assertNoDuplicatePaths(files) {
553
- const seen = /* @__PURE__ */ new Set();
593
+ const seen = /* @__PURE__ */ new Map();
554
594
  for (const file of files) {
555
- if (seen.has(file.path)) {
556
- throw new Error(`Generator output collision detected for path: ${file.path}`);
595
+ const existing = seen.get(file.path);
596
+ if (existing) {
597
+ throw new Error(
598
+ [
599
+ `Generator output collision detected for path: ${file.path}`,
600
+ `Collision: ${existing.kind} and ${file.kind}.`,
601
+ "When syncing multiple schemas, include a schema placeholder such as {schema} or {schema_kebab} in model/schema output targets."
602
+ ].join(" ")
603
+ );
557
604
  }
558
- seen.add(file.path);
605
+ seen.set(file.path, file);
559
606
  }
560
607
  }
561
608
  var ArtifactComposer = class {
@@ -1184,6 +1231,12 @@ function mergeOptions(...options) {
1184
1231
  return { ...acc, ...next };
1185
1232
  }, void 0);
1186
1233
  }
1234
+ function asAthenaJsonObject(value) {
1235
+ return value;
1236
+ }
1237
+ function asAthenaJsonObjectArray(values) {
1238
+ return values;
1239
+ }
1187
1240
  function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
1188
1241
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
1189
1242
  let selectedOptions;
@@ -1272,6 +1325,22 @@ function buildSelectColumnsClause(columns) {
1272
1325
  }
1273
1326
  return quoteSelectColumnsExpression(columns);
1274
1327
  }
1328
+ function resolveTableNameForCall(tableName, schema) {
1329
+ if (!schema) return tableName;
1330
+ const normalizedSchema = schema.trim();
1331
+ if (!normalizedSchema) {
1332
+ throw new Error("schema option must be a non-empty string");
1333
+ }
1334
+ if (tableName.includes(".")) {
1335
+ if (tableName.startsWith(`${normalizedSchema}.`)) {
1336
+ return tableName;
1337
+ }
1338
+ throw new Error(
1339
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
1340
+ );
1341
+ }
1342
+ return `${normalizedSchema}.${tableName}`;
1343
+ }
1275
1344
  function conditionToSqlClause(condition) {
1276
1345
  if (!condition.column) return null;
1277
1346
  const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
@@ -1351,23 +1420,27 @@ function buildTypedSelectQuery(input) {
1351
1420
  function createFilterMethods(state, addCondition, self) {
1352
1421
  return {
1353
1422
  eq(column, value) {
1354
- if (shouldUseUuidTextComparison(column, value)) {
1355
- addCondition("eq", column, value, { columnCast: "text" });
1423
+ const columnName = String(column);
1424
+ if (shouldUseUuidTextComparison(columnName, value)) {
1425
+ addCondition("eq", columnName, value, { columnCast: "text" });
1356
1426
  } else {
1357
- addCondition("eq", column, value);
1427
+ addCondition("eq", columnName, value);
1358
1428
  }
1359
1429
  return self;
1360
1430
  },
1361
1431
  eqCast(column, value, cast) {
1362
- addCondition("eq", column, value, { valueCast: cast });
1432
+ addCondition("eq", String(column), value, { valueCast: cast });
1363
1433
  return self;
1364
1434
  },
1365
1435
  eqUuid(column, value) {
1366
- addCondition("eq", column, value, { valueCast: "uuid" });
1436
+ addCondition("eq", String(column), value, { valueCast: "uuid" });
1367
1437
  return self;
1368
1438
  },
1369
1439
  match(filters) {
1370
1440
  Object.entries(filters).forEach(([column, value]) => {
1441
+ if (value === void 0) {
1442
+ return;
1443
+ }
1371
1444
  if (shouldUseUuidTextComparison(column, value)) {
1372
1445
  addCondition("eq", column, value, { columnCast: "text" });
1373
1446
  } else {
@@ -1403,60 +1476,61 @@ function createFilterMethods(state, addCondition, self) {
1403
1476
  },
1404
1477
  order(column, options) {
1405
1478
  state.order = {
1406
- field: column,
1479
+ field: String(column),
1407
1480
  direction: options?.ascending === false ? "descending" : "ascending"
1408
1481
  };
1409
1482
  return self;
1410
1483
  },
1411
1484
  gt(column, value) {
1412
- addCondition("gt", column, value);
1485
+ addCondition("gt", String(column), value);
1413
1486
  return self;
1414
1487
  },
1415
1488
  gte(column, value) {
1416
- addCondition("gte", column, value);
1489
+ addCondition("gte", String(column), value);
1417
1490
  return self;
1418
1491
  },
1419
1492
  lt(column, value) {
1420
- addCondition("lt", column, value);
1493
+ addCondition("lt", String(column), value);
1421
1494
  return self;
1422
1495
  },
1423
1496
  lte(column, value) {
1424
- addCondition("lte", column, value);
1497
+ addCondition("lte", String(column), value);
1425
1498
  return self;
1426
1499
  },
1427
1500
  neq(column, value) {
1428
- addCondition("neq", column, value);
1501
+ addCondition("neq", String(column), value);
1429
1502
  return self;
1430
1503
  },
1431
1504
  like(column, value) {
1432
- addCondition("like", column, value);
1505
+ addCondition("like", String(column), value);
1433
1506
  return self;
1434
1507
  },
1435
1508
  ilike(column, value) {
1436
- addCondition("ilike", column, value);
1509
+ addCondition("ilike", String(column), value);
1437
1510
  return self;
1438
1511
  },
1439
1512
  is(column, value) {
1440
- addCondition("is", column, value);
1513
+ addCondition("is", String(column), value);
1441
1514
  return self;
1442
1515
  },
1443
1516
  in(column, values) {
1444
- addCondition("in", column, values);
1517
+ addCondition("in", String(column), values);
1445
1518
  return self;
1446
1519
  },
1447
1520
  contains(column, values) {
1448
- addCondition("contains", column, values);
1521
+ addCondition("contains", String(column), values);
1449
1522
  return self;
1450
1523
  },
1451
1524
  containedBy(column, values) {
1452
- addCondition("containedBy", column, values);
1525
+ addCondition("containedBy", String(column), values);
1453
1526
  return self;
1454
1527
  },
1455
1528
  not(columnOrExpression, operator, value) {
1529
+ const expression = String(columnOrExpression);
1456
1530
  if (operator != null && value !== void 0) {
1457
- addCondition("not", void 0, `${columnOrExpression}.${operator}.${stringifyFilterValue(value)}`);
1531
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
1458
1532
  } else {
1459
- addCondition("not", void 0, columnOrExpression);
1533
+ addCondition("not", void 0, expression);
1460
1534
  }
1461
1535
  return self;
1462
1536
  },
@@ -1626,15 +1700,20 @@ function createTableBuilder(tableName, client) {
1626
1700
  state.conditions.push(condition);
1627
1701
  };
1628
1702
  const builder = {};
1629
- const filterMethods = createFilterMethods(state, addCondition, builder);
1703
+ const filterMethods = createFilterMethods(
1704
+ state,
1705
+ addCondition,
1706
+ builder
1707
+ );
1630
1708
  const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
1709
+ const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
1631
1710
  const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
1632
1711
  const hasTypedEqualityComparison = conditions?.some(
1633
1712
  (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
1634
1713
  ) ?? false;
1635
1714
  if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
1636
1715
  const query = buildTypedSelectQuery({
1637
- tableName,
1716
+ tableName: resolvedTableName,
1638
1717
  columns,
1639
1718
  conditions,
1640
1719
  limit: state.limit,
@@ -1649,7 +1728,7 @@ function createTableBuilder(tableName, client) {
1649
1728
  }
1650
1729
  }
1651
1730
  const payload = {
1652
- table_name: tableName,
1731
+ table_name: resolvedTableName,
1653
1732
  columns,
1654
1733
  conditions,
1655
1734
  limit: state.limit,
@@ -1706,9 +1785,10 @@ function createTableBuilder(tableName, client) {
1706
1785
  if (Array.isArray(values)) {
1707
1786
  const executeInsertMany = async (columns, selectOptions) => {
1708
1787
  const mergedOptions = mergeOptions(options, selectOptions);
1788
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1709
1789
  const payload = {
1710
- table_name: tableName,
1711
- insert_body: values
1790
+ table_name: resolvedTableName,
1791
+ insert_body: asAthenaJsonObjectArray(values)
1712
1792
  };
1713
1793
  if (columns) payload.columns = columns;
1714
1794
  if (mergedOptions?.count) payload.count = mergedOptions.count;
@@ -1723,9 +1803,10 @@ function createTableBuilder(tableName, client) {
1723
1803
  }
1724
1804
  const executeInsertOne = async (columns, selectOptions) => {
1725
1805
  const mergedOptions = mergeOptions(options, selectOptions);
1806
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1726
1807
  const payload = {
1727
- table_name: tableName,
1728
- insert_body: values
1808
+ table_name: resolvedTableName,
1809
+ insert_body: asAthenaJsonObject(values)
1729
1810
  };
1730
1811
  if (columns) payload.columns = columns;
1731
1812
  if (mergedOptions?.count) payload.count = mergedOptions.count;
@@ -1742,10 +1823,11 @@ function createTableBuilder(tableName, client) {
1742
1823
  if (Array.isArray(values)) {
1743
1824
  const executeUpsertMany = async (columns, selectOptions) => {
1744
1825
  const mergedOptions = mergeOptions(options, selectOptions);
1826
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1745
1827
  const payload = {
1746
- table_name: tableName,
1747
- insert_body: values,
1748
- update_body: options?.updateBody ? options.updateBody : void 0
1828
+ table_name: resolvedTableName,
1829
+ insert_body: asAthenaJsonObjectArray(values),
1830
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1749
1831
  };
1750
1832
  if (columns) payload.columns = columns;
1751
1833
  if (options?.onConflict) payload.on_conflict = options.onConflict;
@@ -1761,10 +1843,11 @@ function createTableBuilder(tableName, client) {
1761
1843
  }
1762
1844
  const executeUpsertOne = async (columns, selectOptions) => {
1763
1845
  const mergedOptions = mergeOptions(options, selectOptions);
1846
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1764
1847
  const payload = {
1765
- table_name: tableName,
1766
- insert_body: values,
1767
- update_body: options?.updateBody ? options.updateBody : void 0
1848
+ table_name: resolvedTableName,
1849
+ insert_body: asAthenaJsonObject(values),
1850
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1768
1851
  };
1769
1852
  if (columns) payload.columns = columns;
1770
1853
  if (options?.onConflict) payload.on_conflict = options.onConflict;
@@ -1782,9 +1865,10 @@ function createTableBuilder(tableName, client) {
1782
1865
  const executeUpdate = async (columns, selectOptions) => {
1783
1866
  const filters = state.conditions.length ? [...state.conditions] : void 0;
1784
1867
  const mergedOptions = mergeOptions(options, selectOptions);
1868
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1785
1869
  const payload = {
1786
- table_name: tableName,
1787
- set: values,
1870
+ table_name: resolvedTableName,
1871
+ set: asAthenaJsonObject(values),
1788
1872
  conditions: filters,
1789
1873
  strip_nulls: mergedOptions?.stripNulls ?? true
1790
1874
  };
@@ -1810,8 +1894,9 @@ function createTableBuilder(tableName, client) {
1810
1894
  }
1811
1895
  const executeDelete = async (columns, selectOptions) => {
1812
1896
  const mergedOptions = mergeOptions(options, selectOptions);
1897
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1813
1898
  const payload = {
1814
- table_name: tableName,
1899
+ table_name: resolvedTableName,
1815
1900
  resource_id: resourceId,
1816
1901
  conditions: filters
1817
1902
  };
@@ -2111,8 +2196,21 @@ function coerceStringArray(value) {
2111
2196
  }
2112
2197
  return [];
2113
2198
  }
2199
+ function normalizePostgresCatalogSchemas(schemas) {
2200
+ const normalized = [];
2201
+ const seen = /* @__PURE__ */ new Set();
2202
+ for (const value of schemas ?? []) {
2203
+ const schema = value.trim();
2204
+ if (!schema || seen.has(schema)) {
2205
+ continue;
2206
+ }
2207
+ seen.add(schema);
2208
+ normalized.push(schema);
2209
+ }
2210
+ return normalized.length > 0 ? normalized : ["public"];
2211
+ }
2114
2212
  function buildSchemaArrayLiteral(schemas) {
2115
- const normalized = schemas.length > 0 ? schemas : ["public"];
2213
+ const normalized = normalizePostgresCatalogSchemas(schemas);
2116
2214
  const literals = normalized.map((schema) => `'${escapeSqlLiteral(schema)}'`).join(", ");
2117
2215
  return `ARRAY[${literals}]`;
2118
2216
  }
@@ -2311,12 +2409,14 @@ var PostgresIntrospectionProvider = class {
2311
2409
  backend = "postgresql";
2312
2410
  connectionString;
2313
2411
  database;
2412
+ schemas;
2314
2413
  constructor(options) {
2315
2414
  this.connectionString = options.connectionString;
2316
2415
  this.database = options.database ?? "postgres";
2416
+ this.schemas = normalizePostgresCatalogSchemas(options.schemas);
2317
2417
  }
2318
2418
  async inspect(options) {
2319
- const schemas = options?.schemas && options.schemas.length > 0 ? options.schemas : ["public"];
2419
+ const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
2320
2420
  const pool = new pg.Pool({
2321
2421
  connectionString: this.connectionString
2322
2422
  });
@@ -2388,11 +2488,13 @@ var AthenaGatewayPostgresIntrospectionProvider = class {
2388
2488
  type: this.config.backend ?? "postgresql"
2389
2489
  }
2390
2490
  });
2491
+ this.schemas = normalizeSchemaSelection(this.config.schemas);
2391
2492
  }
2392
2493
  backend = "postgresql";
2393
2494
  client;
2495
+ schemas;
2394
2496
  async inspect(options) {
2395
- const schemas = options?.schemas && options.schemas.length > 0 ? options.schemas : this.config.schemas && this.config.schemas.length > 0 ? this.config.schemas : ["public"];
2497
+ const schemas = options?.schemas && options.schemas.length > 0 ? normalizeSchemaSelection(options.schemas) : this.schemas;
2396
2498
  const catalogClient = new AthenaGatewayCatalogClient(this.client);
2397
2499
  const queries = buildGatewayCatalogQueries(schemas);
2398
2500
  const [columnRows, enumMap, primaryKeyRows, foreignKeyRows] = await Promise.all([
@@ -2428,7 +2530,8 @@ var ScyllaIntrospectionProvider = class {
2428
2530
  function createPostgresProvider(config) {
2429
2531
  return createPostgresIntrospectionProvider({
2430
2532
  connectionString: config.connectionString,
2431
- database: config.database
2533
+ database: config.database,
2534
+ schemas: normalizeSchemaSelection(config.schemas)
2432
2535
  });
2433
2536
  }
2434
2537
  function resolveGeneratorProvider(providerConfig, experimentalFlags) {
@@ -2450,12 +2553,6 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
2450
2553
  }
2451
2554
 
2452
2555
  // src/generator/pipeline.ts
2453
- function extractProviderSchemas(providerConfig) {
2454
- if (!("schemas" in providerConfig) || !providerConfig.schemas || providerConfig.schemas.length === 0) {
2455
- return void 0;
2456
- }
2457
- return providerConfig.schemas;
2458
- }
2459
2556
  async function writeArtifacts(files, cwd) {
2460
2557
  const writtenFiles = [];
2461
2558
  for (const file of files) {
@@ -2475,7 +2572,7 @@ async function runSchemaGenerator(options = {}) {
2475
2572
  const { configPath, config } = await loadGeneratorConfig(configOptions);
2476
2573
  const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
2477
2574
  const snapshot = await provider.inspect({
2478
- schemas: extractProviderSchemas(config.provider)
2575
+ schemas: resolveProviderSchemas(config.provider)
2479
2576
  });
2480
2577
  const generated = generateArtifactsFromSnapshot(snapshot, config);
2481
2578
  const writtenFiles = options.dryRun ? [] : await writeArtifacts(generated.files, cwd);