@constructive-io/graphql-server 5.4.2 → 5.7.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/esm/middleware/api.js +7 -6
- package/esm/middleware/routing.js +4 -2
- package/middleware/api.js +7 -6
- package/middleware/routing.js +4 -2
- package/package.json +22 -22
package/esm/middleware/api.js
CHANGED
|
@@ -16,7 +16,10 @@ const defaultRegistry = createDefaultRegistry();
|
|
|
16
16
|
// SQL Queries (API resolution only — module queries now live in loaders)
|
|
17
17
|
// =============================================================================
|
|
18
18
|
// Private-header X-Api-Name lookup against the scoped routing plane.
|
|
19
|
-
//
|
|
19
|
+
// X-Api-Name is a trusted internal selector (only honored when the server
|
|
20
|
+
// runs with isPublic=false): it addresses a database's API surface by name.
|
|
21
|
+
// `is_published` governs cross-scope route visibility, not internal
|
|
22
|
+
// addressability, so it does not filter this lookup.
|
|
20
23
|
const scopedApiNameLookupSql = (routingSchema) => `
|
|
21
24
|
SELECT
|
|
22
25
|
a.id as api_id,
|
|
@@ -31,7 +34,6 @@ const scopedApiNameLookupSql = (routingSchema) => `
|
|
|
31
34
|
LEFT JOIN metaschema_public.schema s ON aps.schema_id = s.id
|
|
32
35
|
WHERE a.database_id = $1
|
|
33
36
|
AND a.name = $2
|
|
34
|
-
AND a.is_published = $3
|
|
35
37
|
GROUP BY a.id, a.database_id, a.dbname, a.role_name, a.anon_role, a.is_published
|
|
36
38
|
LIMIT 1
|
|
37
39
|
`;
|
|
@@ -163,13 +165,13 @@ const validateSchemata = async (pool, schemas) => {
|
|
|
163
165
|
const result = await pool.query(`SELECT schema_name FROM information_schema.schemata WHERE schema_name = ANY($1::text[])`, [schemas]);
|
|
164
166
|
return result.rows.map((row) => row.schema_name);
|
|
165
167
|
};
|
|
166
|
-
const queryByApiName = async (pool, opts, databaseId, name
|
|
168
|
+
const queryByApiName = async (pool, opts, databaseId, name) => {
|
|
167
169
|
const routingSchema = getRoutingSchema(opts);
|
|
168
170
|
if (!isValidSchemaName(routingSchema)) {
|
|
169
171
|
log.warn(`[api-name-lookup] invalid routing schema name: ${routingSchema}`);
|
|
170
172
|
return null;
|
|
171
173
|
}
|
|
172
|
-
const result = await pool.query(scopedApiNameLookupSql(routingSchema), [databaseId, name
|
|
174
|
+
const result = await pool.query(scopedApiNameLookupSql(routingSchema), [databaseId, name]);
|
|
173
175
|
return result.rows[0] ?? null;
|
|
174
176
|
};
|
|
175
177
|
// =============================================================================
|
|
@@ -196,8 +198,7 @@ const resolveApiNameHeader = async (ctx) => {
|
|
|
196
198
|
const { opts, pool, headers } = ctx;
|
|
197
199
|
if (!headers.databaseId)
|
|
198
200
|
return null;
|
|
199
|
-
const
|
|
200
|
-
const row = await queryByApiName(pool, opts, headers.databaseId, headers.apiName, isPublic);
|
|
201
|
+
const row = await queryByApiName(pool, opts, headers.databaseId, headers.apiName);
|
|
201
202
|
if (!row) {
|
|
202
203
|
log.debug(`[api-name-lookup] No API found for databaseId=${headers.databaseId} name=${headers.apiName}`);
|
|
203
204
|
return null;
|
|
@@ -48,12 +48,14 @@ export const routeToApiStructure = (route, opts) => {
|
|
|
48
48
|
return null;
|
|
49
49
|
}
|
|
50
50
|
const config = (route.resolved_config ?? {});
|
|
51
|
-
if (!config.
|
|
52
|
-
log.debug('[resolve-route] api target missing
|
|
51
|
+
if (!config.schemas?.length) {
|
|
52
|
+
log.debug('[resolve-route] api target missing schemas in resolved_config; no match');
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
55
|
return {
|
|
56
56
|
apiId: config.api_id ?? route.target_source_id ?? undefined,
|
|
57
|
+
// Scoped APIs leave dbname NULL when their schemas live in the serving
|
|
58
|
+
// database; fall back to the server's own database in that case.
|
|
57
59
|
dbname: config.dbname || opts.pg?.database || '',
|
|
58
60
|
anonRole: config.anon_role || 'anon',
|
|
59
61
|
roleName: config.role_name || 'authenticated',
|
package/middleware/api.js
CHANGED
|
@@ -22,7 +22,10 @@ const defaultRegistry = (0, express_context_1.createDefaultRegistry)();
|
|
|
22
22
|
// SQL Queries (API resolution only — module queries now live in loaders)
|
|
23
23
|
// =============================================================================
|
|
24
24
|
// Private-header X-Api-Name lookup against the scoped routing plane.
|
|
25
|
-
//
|
|
25
|
+
// X-Api-Name is a trusted internal selector (only honored when the server
|
|
26
|
+
// runs with isPublic=false): it addresses a database's API surface by name.
|
|
27
|
+
// `is_published` governs cross-scope route visibility, not internal
|
|
28
|
+
// addressability, so it does not filter this lookup.
|
|
26
29
|
const scopedApiNameLookupSql = (routingSchema) => `
|
|
27
30
|
SELECT
|
|
28
31
|
a.id as api_id,
|
|
@@ -37,7 +40,6 @@ const scopedApiNameLookupSql = (routingSchema) => `
|
|
|
37
40
|
LEFT JOIN metaschema_public.schema s ON aps.schema_id = s.id
|
|
38
41
|
WHERE a.database_id = $1
|
|
39
42
|
AND a.name = $2
|
|
40
|
-
AND a.is_published = $3
|
|
41
43
|
GROUP BY a.id, a.database_id, a.dbname, a.role_name, a.anon_role, a.is_published
|
|
42
44
|
LIMIT 1
|
|
43
45
|
`;
|
|
@@ -171,13 +173,13 @@ const validateSchemata = async (pool, schemas) => {
|
|
|
171
173
|
const result = await pool.query(`SELECT schema_name FROM information_schema.schemata WHERE schema_name = ANY($1::text[])`, [schemas]);
|
|
172
174
|
return result.rows.map((row) => row.schema_name);
|
|
173
175
|
};
|
|
174
|
-
const queryByApiName = async (pool, opts, databaseId, name
|
|
176
|
+
const queryByApiName = async (pool, opts, databaseId, name) => {
|
|
175
177
|
const routingSchema = (0, routing_1.getRoutingSchema)(opts);
|
|
176
178
|
if (!(0, routing_1.isValidSchemaName)(routingSchema)) {
|
|
177
179
|
log.warn(`[api-name-lookup] invalid routing schema name: ${routingSchema}`);
|
|
178
180
|
return null;
|
|
179
181
|
}
|
|
180
|
-
const result = await pool.query(scopedApiNameLookupSql(routingSchema), [databaseId, name
|
|
182
|
+
const result = await pool.query(scopedApiNameLookupSql(routingSchema), [databaseId, name]);
|
|
181
183
|
return result.rows[0] ?? null;
|
|
182
184
|
};
|
|
183
185
|
// =============================================================================
|
|
@@ -204,8 +206,7 @@ const resolveApiNameHeader = async (ctx) => {
|
|
|
204
206
|
const { opts, pool, headers } = ctx;
|
|
205
207
|
if (!headers.databaseId)
|
|
206
208
|
return null;
|
|
207
|
-
const
|
|
208
|
-
const row = await queryByApiName(pool, opts, headers.databaseId, headers.apiName, isPublic);
|
|
209
|
+
const row = await queryByApiName(pool, opts, headers.databaseId, headers.apiName);
|
|
209
210
|
if (!row) {
|
|
210
211
|
log.debug(`[api-name-lookup] No API found for databaseId=${headers.databaseId} name=${headers.apiName}`);
|
|
211
212
|
return null;
|
package/middleware/routing.js
CHANGED
|
@@ -54,12 +54,14 @@ const routeToApiStructure = (route, opts) => {
|
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
const config = (route.resolved_config ?? {});
|
|
57
|
-
if (!config.
|
|
58
|
-
log.debug('[resolve-route] api target missing
|
|
57
|
+
if (!config.schemas?.length) {
|
|
58
|
+
log.debug('[resolve-route] api target missing schemas in resolved_config; no match');
|
|
59
59
|
return null;
|
|
60
60
|
}
|
|
61
61
|
return {
|
|
62
62
|
apiId: config.api_id ?? route.target_source_id ?? undefined,
|
|
63
|
+
// Scoped APIs leave dbname NULL when their schemas live in the serving
|
|
64
|
+
// database; fall back to the server's own database in that case.
|
|
63
65
|
dbname: config.dbname || opts.pg?.database || '',
|
|
64
66
|
anonRole: config.anon_role || 'anon',
|
|
65
67
|
roleName: config.role_name || 'authenticated',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/graphql-server",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Constructive GraphQL Server",
|
|
6
6
|
"main": "index.js",
|
|
@@ -41,39 +41,39 @@
|
|
|
41
41
|
"backend"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@constructive-io/csrf": "^0.
|
|
45
|
-
"@constructive-io/express-context": "^0.
|
|
46
|
-
"@constructive-io/graphql-env": "^3.
|
|
47
|
-
"@constructive-io/graphql-types": "^3.
|
|
48
|
-
"@constructive-io/query-builder": "^3.
|
|
49
|
-
"@constructive-io/s3-utils": "^2.
|
|
50
|
-
"@constructive-io/url-domains": "^2.
|
|
44
|
+
"@constructive-io/csrf": "^0.21.0",
|
|
45
|
+
"@constructive-io/express-context": "^0.18.0",
|
|
46
|
+
"@constructive-io/graphql-env": "^3.23.0",
|
|
47
|
+
"@constructive-io/graphql-types": "^3.22.0",
|
|
48
|
+
"@constructive-io/query-builder": "^3.4.0",
|
|
49
|
+
"@constructive-io/s3-utils": "^2.24.0",
|
|
50
|
+
"@constructive-io/url-domains": "^2.23.0",
|
|
51
51
|
"@graphile-contrib/pg-many-to-many": "2.0.0-rc.2",
|
|
52
|
-
"@pgpmjs/env": "^2.
|
|
53
|
-
"@pgpmjs/logger": "^2.
|
|
54
|
-
"@pgpmjs/server-utils": "^3.
|
|
55
|
-
"@pgpmjs/types": "^2.
|
|
56
|
-
"agentic-server": "0.
|
|
52
|
+
"@pgpmjs/env": "^2.33.0",
|
|
53
|
+
"@pgpmjs/logger": "^2.18.0",
|
|
54
|
+
"@pgpmjs/server-utils": "^3.19.0",
|
|
55
|
+
"@pgpmjs/types": "^2.40.0",
|
|
56
|
+
"agentic-server": "0.16.0",
|
|
57
57
|
"cors": "^2.8.6",
|
|
58
58
|
"deepmerge": "^4.3.1",
|
|
59
59
|
"express": "^5.2.1",
|
|
60
|
-
"gql-ast": "^3.
|
|
60
|
+
"gql-ast": "^3.17.0",
|
|
61
61
|
"grafast": "1.0.2",
|
|
62
62
|
"grafserv": "1.0.0",
|
|
63
63
|
"graphile-build": "5.0.2",
|
|
64
64
|
"graphile-build-pg": "5.0.2",
|
|
65
|
-
"graphile-cache": "^4.
|
|
65
|
+
"graphile-cache": "^4.4.0",
|
|
66
66
|
"graphile-config": "1.0.1",
|
|
67
|
-
"graphile-function-bindings": "^1.
|
|
68
|
-
"graphile-settings": "^6.
|
|
67
|
+
"graphile-function-bindings": "^1.5.0",
|
|
68
|
+
"graphile-settings": "^6.5.0",
|
|
69
69
|
"graphile-utils": "5.0.1",
|
|
70
70
|
"graphql": "16.13.0",
|
|
71
71
|
"graphql-upload": "^13.0.0",
|
|
72
72
|
"lru-cache": "^11.2.7",
|
|
73
73
|
"pg": "^8.21.0",
|
|
74
|
-
"pg-cache": "^3.
|
|
75
|
-
"pg-env": "^1.
|
|
76
|
-
"pg-query-context": "^2.
|
|
74
|
+
"pg-cache": "^3.19.0",
|
|
75
|
+
"pg-env": "^1.22.0",
|
|
76
|
+
"pg-query-context": "^2.23.0",
|
|
77
77
|
"pg-sql2": "5.0.1",
|
|
78
78
|
"postgraphile": "5.0.3",
|
|
79
79
|
"request-ip": "^3.3.0"
|
|
@@ -87,10 +87,10 @@
|
|
|
87
87
|
"@types/pg": "^8.20.0",
|
|
88
88
|
"@types/request-ip": "^0.0.41",
|
|
89
89
|
"cookie-parser": "^1.4.7",
|
|
90
|
-
"graphile-test": "5.
|
|
90
|
+
"graphile-test": "5.5.0",
|
|
91
91
|
"makage": "^0.3.0",
|
|
92
92
|
"nodemon": "^3.1.14",
|
|
93
93
|
"ts-node": "^10.9.2"
|
|
94
94
|
},
|
|
95
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "73f55ad24d9a92e7ef1e268526b31bfb7bb12b28"
|
|
96
96
|
}
|