@constructive-io/graphql-server 5.33.4 → 5.33.5

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.
@@ -6,7 +6,7 @@ import { svcCache } from '@pgpmjs/server-utils';
6
6
  import { getPgPool } from 'pg-cache';
7
7
  import errorPage50x from '../errors/50x';
8
8
  import errorPage404Message from '../errors/404-message';
9
- import { requireApiRole, resolveRouteAcrossPlanes, routeToApiStructure } from './routing';
9
+ import { requireApiRole, resolveRouteAcrossPlanes, routeToApiStructure, servedDatabasePool } from './routing';
10
10
  const log = new Logger('api');
11
11
  // =============================================================================
12
12
  // Module Loader Registry (replaces inline SQL queries for per-db config)
@@ -23,7 +23,7 @@ const defaultRegistry = createDefaultRegistry();
23
23
  // `is_published` governs cross-scope route visibility, not internal
24
24
  // addressability, so it does not filter this lookup.
25
25
  const API_BY_NAME_SQL = `
26
- SELECT api_id, api_database_id AS database_id, dbname, role_name, anon_role, is_public, schemas
26
+ SELECT api_id, api_database_id AS database_id, role_name, anon_role, is_public, schemas
27
27
  FROM function_resolution.api_by_name($1, $2)
28
28
  LIMIT 1
29
29
  `;
@@ -31,18 +31,12 @@ const API_BY_NAME_SQL = `
31
31
  * Build a LoaderContext from the API row and options.
32
32
  * This is used to resolve per-database module settings via the loader registry.
33
33
  */
34
- const buildLoaderContext = (routingPool, opts, row) => {
35
- // Scoped APIs leave dbname NULL when their schemas live in the serving
36
- // database (pooled tenants); fall back to the server's own database.
37
- const dbname = row.dbname || opts.pg?.database || '';
38
- return {
39
- routingPool,
40
- tenantPool: getPgPool({ ...opts.pg, database: dbname }),
41
- databaseId: row.database_id,
42
- apiId: row.api_id,
43
- dbname
44
- };
45
- };
34
+ const buildLoaderContext = (routingPool, opts, row) => ({
35
+ routingPool,
36
+ tenantPool: servedDatabasePool(opts),
37
+ databaseId: row.database_id,
38
+ apiId: row.api_id
39
+ });
46
40
  /**
47
41
  * Resolve all per-database module settings in parallel via the loader registry.
48
42
  * Each loader independently caches by databaseId — repeated calls are cheap.
@@ -129,7 +123,7 @@ export const getSvcKey = (opts, req) => {
129
123
  };
130
124
  const toApiStructure = (row, opts, settings = {}) => ({
131
125
  apiId: row.api_id,
132
- dbname: row.dbname || opts.pg?.database || '',
126
+ tenantPool: servedDatabasePool(opts),
133
127
  anonRole: requireApiRole('anon_role', row.anon_role, row.api_id),
134
128
  roleName: requireApiRole('role_name', row.role_name, row.api_id),
135
129
  schema: row.schemas || [],
@@ -144,7 +138,7 @@ const toApiStructure = (row, opts, settings = {}) => ({
144
138
  webauthnSettings: settings.webauthnSettings
145
139
  });
146
140
  const createAdminStructure = (opts, schemas, databaseId) => ({
147
- dbname: opts.pg?.database ?? '',
141
+ tenantPool: servedDatabasePool(opts),
148
142
  anonRole: 'anonymous',
149
143
  roleName: 'authenticated',
150
144
  schema: schemas,
@@ -221,13 +215,12 @@ const resolveScopedRoute = async (ctx) => {
221
215
  error.code = 'CROSS_DATABASE_ROUTE';
222
216
  throw error;
223
217
  }
224
- log.debug(`[scoped-routing] resolved host=${host} → api=${structure.apiId} db=${structure.dbname}`);
218
+ log.debug(`[scoped-routing] resolved host=${host} → api=${structure.apiId} databaseId=${structure.databaseId}`);
225
219
  if (!structure.databaseId || !structure.apiId)
226
220
  return structure;
227
221
  const loaderCtx = buildLoaderContext(pool, opts, {
228
222
  api_id: structure.apiId,
229
223
  database_id: structure.databaseId,
230
- dbname: structure.dbname,
231
224
  role_name: structure.roleName,
232
225
  anon_role: structure.anonRole,
233
226
  is_public: structure.isPublic ?? false,
@@ -324,7 +317,7 @@ export const createApiMiddleware = (opts) => {
324
317
  }
325
318
  req.api = apiConfig;
326
319
  req.databaseId = apiConfig.databaseId;
327
- log.debug(`Resolved API: db=${apiConfig.dbname}, schemas=[${apiConfig.schema?.join(', ')}]`);
320
+ log.debug(`Resolved API: databaseId=${apiConfig.databaseId}, schemas=[${apiConfig.schema?.join(', ')}]`);
328
321
  next();
329
322
  }
330
323
  catch (error) {
@@ -2,7 +2,6 @@ import './types'; // for Request type
2
2
  import { errors } from '@constructive-io/errors';
3
3
  import { getNodeEnv } from '@pgpmjs/env';
4
4
  import { Logger } from '@pgpmjs/logger';
5
- import { getPgPool } from 'pg-cache';
6
5
  import pgQueryContext from 'pg-query-context';
7
6
  import { respondWithGraphQLError } from '../errors/graphql-response';
8
7
  const log = new Logger('auth');
@@ -38,10 +37,7 @@ export const createAuthenticateMiddleware = (opts) => {
38
37
  res.status(500).send('Missing API info');
39
38
  return;
40
39
  }
41
- const pool = getPgPool({
42
- ...opts.pg,
43
- database: api.dbname,
44
- });
40
+ const pool = api.tenantPool;
45
41
  const rlsModule = api.rlsModule;
46
42
  log.info(`[auth] rlsModule=${rlsModule ? 'present' : 'missing'}, ` +
47
43
  `authenticate=${rlsModule?.authenticate ?? 'none'}, ` +
@@ -5,8 +5,6 @@ import { Logger } from '@pgpmjs/logger';
5
5
  import { cacheGraphileInstance, createGraphileInstance, graphileCache } from 'graphile-cache';
6
6
  import { createFunctionBindingsPlugin } from 'graphile-function-bindings';
7
7
  import { createConstructivePreset, createGrafastCacheLimitsPreset } from 'graphile-settings';
8
- import { getPgPool } from 'pg-cache';
9
- import { getPgEnvOptions } from 'pg-env';
10
8
  import { isGraphqlObservabilityEnabled } from '../diagnostics/observability';
11
9
  import { HandlerCreationError } from '../errors/api-errors';
12
10
  import { respondWithGraphQLError } from '../errors/graphql-response';
@@ -261,17 +259,18 @@ export const graphile = (opts) => {
261
259
  respondWithGraphQLError(res, errors.INTERNAL_FAILURE({ details: 'Missing service cache key' }));
262
260
  return;
263
261
  }
264
- const { dbname, anonRole, roleName, schema } = api;
262
+ const { anonRole, roleName, schema } = api;
263
+ const databaseLabel = api.databaseId ?? 'none';
265
264
  const schemaLabel = schema?.join(',') || 'unknown';
266
265
  // =========================================================================
267
266
  // Phase A: Cache Check (fast path)
268
267
  // =========================================================================
269
268
  const cached = graphileCache.get(key);
270
269
  if (cached) {
271
- log.debug(`${label} PostGraphile cache hit key=${key} db=${dbname} schemas=${schemaLabel}`);
270
+ log.debug(`${label} PostGraphile cache hit key=${key} databaseId=${databaseLabel} schemas=${schemaLabel}`);
272
271
  return cached.handler(req, res, next);
273
272
  }
274
- log.debug(`${label} PostGraphile cache miss key=${key} db=${dbname} schemas=${schemaLabel}`);
273
+ log.debug(`${label} PostGraphile cache miss key=${key} databaseId=${databaseLabel} schemas=${schemaLabel}`);
275
274
  // =========================================================================
276
275
  // Phase B: In-Flight Check (single-flight coalescing)
277
276
  // =========================================================================
@@ -303,14 +302,8 @@ export const graphile = (opts) => {
303
302
  const retryInstance = await retryInFlight;
304
303
  return retryInstance.handler(req, res, next);
305
304
  }
306
- log.info(`${label} Building PostGraphile v5 handler key=${key} db=${dbname} schemas=${schemaLabel} role=${roleName} anon=${anonRole}`);
307
- const pgConfig = getPgEnvOptions({
308
- ...opts.pg,
309
- database: dbname
310
- });
311
- // Route through pg-cache so the pool is tracked and can be cleaned up
312
- // properly, preventing leaked connections during database teardown.
313
- const pool = getPgPool(pgConfig);
305
+ log.info(`${label} Building PostGraphile v5 handler key=${key} databaseId=${databaseLabel} schemas=${schemaLabel} role=${roleName} anon=${anonRole}`);
306
+ const pool = api.tenantPool;
314
307
  // Register the creation promise before any asynchronous preset work so
315
308
  // concurrent requests coalesce while optional plugin modules load.
316
309
  const creationPromise = (async () => {
@@ -333,7 +326,7 @@ export const graphile = (opts) => {
333
326
  creating.set(key, creationPromise);
334
327
  try {
335
328
  const instance = await creationPromise;
336
- log.info(`${label} Cached PostGraphile v5 handler key=${key} db=${dbname}`);
329
+ log.info(`${label} Cached PostGraphile v5 handler key=${key} databaseId=${databaseLabel}`);
337
330
  return instance.handler(req, res, next);
338
331
  }
339
332
  catch (error) {
@@ -18,7 +18,7 @@ export const createRequestLogger = ({ observabilityEnabled }) => {
18
18
  finished = true;
19
19
  const durationMs = Number(process.hrtime.bigint() - start) / 1e6;
20
20
  const apiInfo = req.api
21
- ? `db=${req.api.dbname} schemas=${req.api.schema?.join(',') || 'none'}`
21
+ ? `databaseId=${req.api.databaseId ?? 'none'} schemas=${req.api.schema?.join(',') || 'none'}`
22
22
  : 'api=unresolved';
23
23
  const authInfo = req.token ? 'auth=token' : 'auth=anon';
24
24
  const svcInfo = req.svc_key ? `svc=${req.svc_key}` : 'svc=unset';
@@ -31,7 +31,7 @@ export const createRequestLogger = ({ observabilityEnabled }) => {
31
31
  }
32
32
  const durationMs = Number(process.hrtime.bigint() - start) / 1e6;
33
33
  const apiInfo = req.api
34
- ? `db=${req.api.dbname} schemas=${req.api.schema?.join(',') || 'none'}`
34
+ ? `databaseId=${req.api.databaseId ?? 'none'} schemas=${req.api.schema?.join(',') || 'none'}`
35
35
  : 'api=unresolved';
36
36
  log.warn(`[${reqId}] connection closed before response completed ` +
37
37
  `${req.method} ${req.originalUrl} (${durationMs.toFixed(1)} ms) ${apiInfo}`);
@@ -1,5 +1,6 @@
1
1
  import { Logger } from '@pgpmjs/logger';
2
2
  import { QuoteUtils } from '@pgsql/quotes';
3
+ import { getPgPool } from 'pg-cache';
3
4
  const log = new Logger('routing');
4
5
  // =============================================================================
5
6
  // Scoped routing plane (resolve_route contract)
@@ -141,6 +142,8 @@ export const resolveRouteAcrossPlanes = async (pool, host) => {
141
142
  * rest of the middleware chain. Returns null when the route target is not an
142
143
  * api surface or its resolved_config lacks the api essentials (→ 404).
143
144
  */
145
+ /** The server always serves its own configured database. */
146
+ export const servedDatabasePool = (opts) => getPgPool({ ...opts.pg });
144
147
  export const routeToApiStructure = (route, opts) => {
145
148
  if (route.target_module !== 'apis' && route.target_module !== 'api') {
146
149
  return null;
@@ -153,9 +156,7 @@ export const routeToApiStructure = (route, opts) => {
153
156
  const apiId = config.api_id ?? route.target_source_id ?? undefined;
154
157
  return {
155
158
  apiId,
156
- // Scoped APIs leave dbname NULL when their schemas live in the serving
157
- // database; fall back to the server's own database in that case.
158
- dbname: config.dbname || opts.pg?.database || '',
159
+ tenantPool: servedDatabasePool(opts),
159
160
  anonRole: requireApiRole('anon_role', config.anon_role, apiId),
160
161
  roleName: requireApiRole('role_name', config.role_name, apiId),
161
162
  schema: config.schemas,
package/middleware/api.js CHANGED
@@ -29,7 +29,7 @@ const defaultRegistry = (0, express_context_1.createDefaultRegistry)();
29
29
  // `is_published` governs cross-scope route visibility, not internal
30
30
  // addressability, so it does not filter this lookup.
31
31
  const API_BY_NAME_SQL = `
32
- SELECT api_id, api_database_id AS database_id, dbname, role_name, anon_role, is_public, schemas
32
+ SELECT api_id, api_database_id AS database_id, role_name, anon_role, is_public, schemas
33
33
  FROM function_resolution.api_by_name($1, $2)
34
34
  LIMIT 1
35
35
  `;
@@ -37,18 +37,12 @@ const API_BY_NAME_SQL = `
37
37
  * Build a LoaderContext from the API row and options.
38
38
  * This is used to resolve per-database module settings via the loader registry.
39
39
  */
40
- const buildLoaderContext = (routingPool, opts, row) => {
41
- // Scoped APIs leave dbname NULL when their schemas live in the serving
42
- // database (pooled tenants); fall back to the server's own database.
43
- const dbname = row.dbname || opts.pg?.database || '';
44
- return {
45
- routingPool,
46
- tenantPool: (0, pg_cache_1.getPgPool)({ ...opts.pg, database: dbname }),
47
- databaseId: row.database_id,
48
- apiId: row.api_id,
49
- dbname
50
- };
51
- };
40
+ const buildLoaderContext = (routingPool, opts, row) => ({
41
+ routingPool,
42
+ tenantPool: (0, routing_1.servedDatabasePool)(opts),
43
+ databaseId: row.database_id,
44
+ apiId: row.api_id
45
+ });
52
46
  /**
53
47
  * Resolve all per-database module settings in parallel via the loader registry.
54
48
  * Each loader independently caches by databaseId — repeated calls are cheap.
@@ -137,7 +131,7 @@ const getSvcKey = (opts, req) => {
137
131
  exports.getSvcKey = getSvcKey;
138
132
  const toApiStructure = (row, opts, settings = {}) => ({
139
133
  apiId: row.api_id,
140
- dbname: row.dbname || opts.pg?.database || '',
134
+ tenantPool: (0, routing_1.servedDatabasePool)(opts),
141
135
  anonRole: (0, routing_1.requireApiRole)('anon_role', row.anon_role, row.api_id),
142
136
  roleName: (0, routing_1.requireApiRole)('role_name', row.role_name, row.api_id),
143
137
  schema: row.schemas || [],
@@ -152,7 +146,7 @@ const toApiStructure = (row, opts, settings = {}) => ({
152
146
  webauthnSettings: settings.webauthnSettings
153
147
  });
154
148
  const createAdminStructure = (opts, schemas, databaseId) => ({
155
- dbname: opts.pg?.database ?? '',
149
+ tenantPool: (0, routing_1.servedDatabasePool)(opts),
156
150
  anonRole: 'anonymous',
157
151
  roleName: 'authenticated',
158
152
  schema: schemas,
@@ -229,13 +223,12 @@ const resolveScopedRoute = async (ctx) => {
229
223
  error.code = 'CROSS_DATABASE_ROUTE';
230
224
  throw error;
231
225
  }
232
- log.debug(`[scoped-routing] resolved host=${host} → api=${structure.apiId} db=${structure.dbname}`);
226
+ log.debug(`[scoped-routing] resolved host=${host} → api=${structure.apiId} databaseId=${structure.databaseId}`);
233
227
  if (!structure.databaseId || !structure.apiId)
234
228
  return structure;
235
229
  const loaderCtx = buildLoaderContext(pool, opts, {
236
230
  api_id: structure.apiId,
237
231
  database_id: structure.databaseId,
238
- dbname: structure.dbname,
239
232
  role_name: structure.roleName,
240
233
  anon_role: structure.anonRole,
241
234
  is_public: structure.isPublic ?? false,
@@ -333,7 +326,7 @@ const createApiMiddleware = (opts) => {
333
326
  }
334
327
  req.api = apiConfig;
335
328
  req.databaseId = apiConfig.databaseId;
336
- log.debug(`Resolved API: db=${apiConfig.dbname}, schemas=[${apiConfig.schema?.join(', ')}]`);
329
+ log.debug(`Resolved API: databaseId=${apiConfig.databaseId}, schemas=[${apiConfig.schema?.join(', ')}]`);
337
330
  next();
338
331
  }
339
332
  catch (error) {
@@ -8,7 +8,6 @@ require("./types"); // for Request type
8
8
  const errors_1 = require("@constructive-io/errors");
9
9
  const env_1 = require("@pgpmjs/env");
10
10
  const logger_1 = require("@pgpmjs/logger");
11
- const pg_cache_1 = require("pg-cache");
12
11
  const pg_query_context_1 = __importDefault(require("pg-query-context"));
13
12
  const graphql_response_1 = require("../errors/graphql-response");
14
13
  const log = new logger_1.Logger('auth');
@@ -45,10 +44,7 @@ const createAuthenticateMiddleware = (opts) => {
45
44
  res.status(500).send('Missing API info');
46
45
  return;
47
46
  }
48
- const pool = (0, pg_cache_1.getPgPool)({
49
- ...opts.pg,
50
- database: api.dbname,
51
- });
47
+ const pool = api.tenantPool;
52
48
  const rlsModule = api.rlsModule;
53
49
  log.info(`[auth] rlsModule=${rlsModule ? 'present' : 'missing'}, ` +
54
50
  `authenticate=${rlsModule?.authenticate ?? 'none'}, ` +
@@ -11,8 +11,6 @@ const logger_1 = require("@pgpmjs/logger");
11
11
  const graphile_cache_1 = require("graphile-cache");
12
12
  const graphile_function_bindings_1 = require("graphile-function-bindings");
13
13
  const graphile_settings_1 = require("graphile-settings");
14
- const pg_cache_1 = require("pg-cache");
15
- const pg_env_1 = require("pg-env");
16
14
  const observability_1 = require("../diagnostics/observability");
17
15
  const api_errors_1 = require("../errors/api-errors");
18
16
  const graphql_response_1 = require("../errors/graphql-response");
@@ -267,17 +265,18 @@ const graphile = (opts) => {
267
265
  (0, graphql_response_1.respondWithGraphQLError)(res, errors_1.errors.INTERNAL_FAILURE({ details: 'Missing service cache key' }));
268
266
  return;
269
267
  }
270
- const { dbname, anonRole, roleName, schema } = api;
268
+ const { anonRole, roleName, schema } = api;
269
+ const databaseLabel = api.databaseId ?? 'none';
271
270
  const schemaLabel = schema?.join(',') || 'unknown';
272
271
  // =========================================================================
273
272
  // Phase A: Cache Check (fast path)
274
273
  // =========================================================================
275
274
  const cached = graphile_cache_1.graphileCache.get(key);
276
275
  if (cached) {
277
- log.debug(`${label} PostGraphile cache hit key=${key} db=${dbname} schemas=${schemaLabel}`);
276
+ log.debug(`${label} PostGraphile cache hit key=${key} databaseId=${databaseLabel} schemas=${schemaLabel}`);
278
277
  return cached.handler(req, res, next);
279
278
  }
280
- log.debug(`${label} PostGraphile cache miss key=${key} db=${dbname} schemas=${schemaLabel}`);
279
+ log.debug(`${label} PostGraphile cache miss key=${key} databaseId=${databaseLabel} schemas=${schemaLabel}`);
281
280
  // =========================================================================
282
281
  // Phase B: In-Flight Check (single-flight coalescing)
283
282
  // =========================================================================
@@ -309,14 +308,8 @@ const graphile = (opts) => {
309
308
  const retryInstance = await retryInFlight;
310
309
  return retryInstance.handler(req, res, next);
311
310
  }
312
- log.info(`${label} Building PostGraphile v5 handler key=${key} db=${dbname} schemas=${schemaLabel} role=${roleName} anon=${anonRole}`);
313
- const pgConfig = (0, pg_env_1.getPgEnvOptions)({
314
- ...opts.pg,
315
- database: dbname
316
- });
317
- // Route through pg-cache so the pool is tracked and can be cleaned up
318
- // properly, preventing leaked connections during database teardown.
319
- const pool = (0, pg_cache_1.getPgPool)(pgConfig);
311
+ log.info(`${label} Building PostGraphile v5 handler key=${key} databaseId=${databaseLabel} schemas=${schemaLabel} role=${roleName} anon=${anonRole}`);
312
+ const pool = api.tenantPool;
320
313
  // Register the creation promise before any asynchronous preset work so
321
314
  // concurrent requests coalesce while optional plugin modules load.
322
315
  const creationPromise = (async () => {
@@ -339,7 +332,7 @@ const graphile = (opts) => {
339
332
  creating.set(key, creationPromise);
340
333
  try {
341
334
  const instance = await creationPromise;
342
- log.info(`${label} Cached PostGraphile v5 handler key=${key} db=${dbname}`);
335
+ log.info(`${label} Cached PostGraphile v5 handler key=${key} databaseId=${databaseLabel}`);
343
336
  return instance.handler(req, res, next);
344
337
  }
345
338
  catch (error) {
@@ -21,7 +21,7 @@ const createRequestLogger = ({ observabilityEnabled }) => {
21
21
  finished = true;
22
22
  const durationMs = Number(process.hrtime.bigint() - start) / 1e6;
23
23
  const apiInfo = req.api
24
- ? `db=${req.api.dbname} schemas=${req.api.schema?.join(',') || 'none'}`
24
+ ? `databaseId=${req.api.databaseId ?? 'none'} schemas=${req.api.schema?.join(',') || 'none'}`
25
25
  : 'api=unresolved';
26
26
  const authInfo = req.token ? 'auth=token' : 'auth=anon';
27
27
  const svcInfo = req.svc_key ? `svc=${req.svc_key}` : 'svc=unset';
@@ -34,7 +34,7 @@ const createRequestLogger = ({ observabilityEnabled }) => {
34
34
  }
35
35
  const durationMs = Number(process.hrtime.bigint() - start) / 1e6;
36
36
  const apiInfo = req.api
37
- ? `db=${req.api.dbname} schemas=${req.api.schema?.join(',') || 'none'}`
37
+ ? `databaseId=${req.api.databaseId ?? 'none'} schemas=${req.api.schema?.join(',') || 'none'}`
38
38
  : 'api=unresolved';
39
39
  log.warn(`[${reqId}] connection closed before response completed ` +
40
40
  `${req.method} ${req.originalUrl} (${durationMs.toFixed(1)} ms) ${apiInfo}`);
@@ -75,4 +75,6 @@ export declare const resolveRouteAcrossPlanes: (pool: Pool, host: string) => Pro
75
75
  * rest of the middleware chain. Returns null when the route target is not an
76
76
  * api surface or its resolved_config lacks the api essentials (→ 404).
77
77
  */
78
+ /** The server always serves its own configured database. */
79
+ export declare const servedDatabasePool: (opts: ApiOptions) => Pool;
78
80
  export declare const routeToApiStructure: (route: ResolvedRoute, opts: ApiOptions) => ApiStructure | null;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.routeToApiStructure = exports.resolveRouteAcrossPlanes = exports.loadRoutingPlanes = exports.resolveRoute = exports.isValidSchemaName = exports.ROUTING_SCHEMA = exports.requireApiRole = void 0;
3
+ exports.routeToApiStructure = exports.servedDatabasePool = exports.resolveRouteAcrossPlanes = exports.loadRoutingPlanes = exports.resolveRoute = exports.isValidSchemaName = exports.ROUTING_SCHEMA = exports.requireApiRole = void 0;
4
4
  const logger_1 = require("@pgpmjs/logger");
5
5
  const quotes_1 = require("@pgsql/quotes");
6
+ const pg_cache_1 = require("pg-cache");
6
7
  const log = new logger_1.Logger('routing');
7
8
  // =============================================================================
8
9
  // Scoped routing plane (resolve_route contract)
@@ -149,6 +150,9 @@ exports.resolveRouteAcrossPlanes = resolveRouteAcrossPlanes;
149
150
  * rest of the middleware chain. Returns null when the route target is not an
150
151
  * api surface or its resolved_config lacks the api essentials (→ 404).
151
152
  */
153
+ /** The server always serves its own configured database. */
154
+ const servedDatabasePool = (opts) => (0, pg_cache_1.getPgPool)({ ...opts.pg });
155
+ exports.servedDatabasePool = servedDatabasePool;
152
156
  const routeToApiStructure = (route, opts) => {
153
157
  if (route.target_module !== 'apis' && route.target_module !== 'api') {
154
158
  return null;
@@ -161,9 +165,7 @@ const routeToApiStructure = (route, opts) => {
161
165
  const apiId = config.api_id ?? route.target_source_id ?? undefined;
162
166
  return {
163
167
  apiId,
164
- // Scoped APIs leave dbname NULL when their schemas live in the serving
165
- // database; fall back to the server's own database in that case.
166
- dbname: config.dbname || opts.pg?.database || '',
168
+ tenantPool: (0, exports.servedDatabasePool)(opts),
167
169
  anonRole: (0, exports.requireApiRole)('anon_role', config.anon_role, apiId),
168
170
  roleName: (0, exports.requireApiRole)('role_name', config.role_name, apiId),
169
171
  schema: config.schemas,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-server",
3
- "version": "5.33.4",
3
+ "version": "5.33.5",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Constructive GraphQL Server",
6
6
  "main": "index.js",
@@ -43,7 +43,7 @@
43
43
  "@agentic-kit/ollama": "2.16.0",
44
44
  "@constructive-io/csrf": "^0.31.0",
45
45
  "@constructive-io/errors": "^0.25.0",
46
- "@constructive-io/express-context": "^0.35.3",
46
+ "@constructive-io/express-context": "^0.35.4",
47
47
  "@constructive-io/graphql-env": "^3.37.2",
48
48
  "@constructive-io/graphql-types": "^3.36.1",
49
49
  "@constructive-io/llm-env": "^0.16.0",
@@ -72,7 +72,7 @@
72
72
  "graphile-plugin-utils": "^1.14.1",
73
73
  "graphile-presigned-url-plugin": "^1.23.4",
74
74
  "graphile-scoped-introspection": "^0.6.0",
75
- "graphile-settings": "^6.28.3",
75
+ "graphile-settings": "^6.28.4",
76
76
  "graphile-utils": "5.0.3",
77
77
  "graphql": "16.13.0",
78
78
  "graphql-upload": "^13.0.0",
@@ -98,5 +98,5 @@
98
98
  "supertest": "^7.2.2",
99
99
  "ts-node": "^10.9.2"
100
100
  },
101
- "gitHead": "7ce27b6ff591192fe5eb87e26bb3fb1e538d6505"
101
+ "gitHead": "ed0726630bf8211ff3f58934e0e0b70a180284db"
102
102
  }