@constructive-io/graphql-server 2.11.5 → 2.12.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 +16 -4
- package/esm/middleware/auth.js +11 -1
- package/esm/server.js +7 -1
- package/middleware/api.js +16 -4
- package/middleware/auth.js +11 -1
- package/package.json +12 -12
- package/server.js +6 -0
package/esm/middleware/api.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getNodeEnv } from '@constructive-io/graphql-env';
|
|
2
|
+
import { Logger } from '@pgpmjs/logger';
|
|
2
3
|
import { svcCache } from '@pgpmjs/server-utils';
|
|
3
4
|
import { getSchema, GraphileQuery } from 'graphile-query';
|
|
4
5
|
import { getGraphileSettings } from 'graphile-settings';
|
|
@@ -7,6 +8,8 @@ import errorPage50x from '../errors/50x';
|
|
|
7
8
|
import errorPage404Message from '../errors/404-message';
|
|
8
9
|
import { ApiByNameQuery, ApiQuery, ListOfAllDomainsOfDb } from './gql';
|
|
9
10
|
import './types'; // for Request type
|
|
11
|
+
const log = new Logger('api');
|
|
12
|
+
const isDev = () => getNodeEnv() === 'development';
|
|
10
13
|
const transformServiceToApi = (svc) => {
|
|
11
14
|
const api = svc.data.api;
|
|
12
15
|
const schemaNames = api.schemaNamesFromExt?.nodes?.map((n) => n.schemaName) || [];
|
|
@@ -92,6 +95,8 @@ export const createApiMiddleware = (opts) => {
|
|
|
92
95
|
const api = transformServiceToApi(svc);
|
|
93
96
|
req.api = api;
|
|
94
97
|
req.databaseId = api.databaseId;
|
|
98
|
+
if (isDev())
|
|
99
|
+
log.debug(`Resolved API: db=${api.dbname}, schemas=[${api.schema?.join(', ')}]`);
|
|
95
100
|
next();
|
|
96
101
|
}
|
|
97
102
|
catch (e) {
|
|
@@ -104,7 +109,7 @@ export const createApiMiddleware = (opts) => {
|
|
|
104
109
|
.send(errorPage404Message("The resource you're looking for does not exist."));
|
|
105
110
|
}
|
|
106
111
|
else {
|
|
107
|
-
|
|
112
|
+
log.error('API middleware error:', e);
|
|
108
113
|
res.status(500).send(errorPage50x);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
@@ -162,7 +167,7 @@ const queryServiceByDomainAndSubdomain = async ({ opts, key, client, domain, sub
|
|
|
162
167
|
variables: { domain, subdomain },
|
|
163
168
|
});
|
|
164
169
|
if (result.errors?.length) {
|
|
165
|
-
|
|
170
|
+
log.error('GraphQL query errors:', result.errors);
|
|
166
171
|
return null;
|
|
167
172
|
}
|
|
168
173
|
const nodes = result?.data?.domains?.nodes;
|
|
@@ -184,7 +189,7 @@ const queryServiceByApiName = async ({ opts, key, client, databaseId, name, }) =
|
|
|
184
189
|
variables: { databaseId, name },
|
|
185
190
|
});
|
|
186
191
|
if (result.errors?.length) {
|
|
187
|
-
|
|
192
|
+
log.error('GraphQL query errors:', result.errors);
|
|
188
193
|
return null;
|
|
189
194
|
}
|
|
190
195
|
const data = result?.data;
|
|
@@ -229,14 +234,21 @@ export const getApiConfig = async (opts, req) => {
|
|
|
229
234
|
req.svc_key = key;
|
|
230
235
|
let svc;
|
|
231
236
|
if (svcCache.has(key)) {
|
|
237
|
+
if (isDev())
|
|
238
|
+
log.debug(`Cache HIT for key=${key}`);
|
|
232
239
|
svc = svcCache.get(key);
|
|
233
240
|
}
|
|
234
241
|
else {
|
|
242
|
+
if (isDev())
|
|
243
|
+
log.debug(`Cache MISS for key=${key}, looking up API`);
|
|
235
244
|
const apiOpts = opts.api || {};
|
|
236
245
|
const allSchemata = apiOpts.metaSchemas || [];
|
|
237
246
|
const validatedSchemata = await validateSchemata(rootPgPool, allSchemata);
|
|
238
247
|
if (validatedSchemata.length === 0) {
|
|
239
|
-
const
|
|
248
|
+
const apiOpts2 = opts.api || {};
|
|
249
|
+
const message = `No valid schemas found. Configured metaSchemas: [${(apiOpts2.metaSchemas || []).join(', ')}]`;
|
|
250
|
+
if (isDev())
|
|
251
|
+
log.debug(message);
|
|
240
252
|
const error = new Error(message);
|
|
241
253
|
error.code = 'NO_VALID_SCHEMAS';
|
|
242
254
|
throw error;
|
package/esm/middleware/auth.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { getNodeEnv } from '@constructive-io/graphql-env';
|
|
2
|
+
import { Logger } from '@pgpmjs/logger';
|
|
1
3
|
import { getPgPool } from 'pg-cache';
|
|
2
4
|
import pgQueryContext from 'pg-query-context';
|
|
3
5
|
import './types'; // for Request type
|
|
6
|
+
const log = new Logger('auth');
|
|
7
|
+
const isDev = () => getNodeEnv() === 'development';
|
|
4
8
|
export const createAuthenticateMiddleware = (opts) => {
|
|
5
9
|
return async (req, res, next) => {
|
|
6
10
|
const api = req.api;
|
|
@@ -13,8 +17,11 @@ export const createAuthenticateMiddleware = (opts) => {
|
|
|
13
17
|
database: api.dbname,
|
|
14
18
|
});
|
|
15
19
|
const rlsModule = api.rlsModule;
|
|
16
|
-
if (!rlsModule)
|
|
20
|
+
if (!rlsModule) {
|
|
21
|
+
if (isDev())
|
|
22
|
+
log.debug('No RLS module configured, skipping auth');
|
|
17
23
|
return next();
|
|
24
|
+
}
|
|
18
25
|
const authFn = opts.server.strictAuth
|
|
19
26
|
? rlsModule.authenticateStrict
|
|
20
27
|
: rlsModule.authenticate;
|
|
@@ -46,8 +53,11 @@ export const createAuthenticateMiddleware = (opts) => {
|
|
|
46
53
|
return;
|
|
47
54
|
}
|
|
48
55
|
token = result.rows[0];
|
|
56
|
+
if (isDev())
|
|
57
|
+
log.debug(`Auth success: role=${token.role}`);
|
|
49
58
|
}
|
|
50
59
|
catch (e) {
|
|
60
|
+
log.error('Auth error:', e.message);
|
|
51
61
|
res.status(200).json({
|
|
52
62
|
errors: [
|
|
53
63
|
{
|
package/esm/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getEnvOptions } from '@constructive-io/graphql-env';
|
|
1
|
+
import { getEnvOptions, getNodeEnv } from '@constructive-io/graphql-env';
|
|
2
2
|
import { Logger } from '@pgpmjs/logger';
|
|
3
3
|
import { healthz, poweredBy, trustProxy } from '@pgpmjs/server-utils';
|
|
4
4
|
import { middleware as parseDomains } from '@constructive-io/url-domains';
|
|
@@ -13,6 +13,7 @@ import { cors } from './middleware/cors';
|
|
|
13
13
|
import { flush, flushService } from './middleware/flush';
|
|
14
14
|
import { graphile } from './middleware/graphile';
|
|
15
15
|
const log = new Logger('server');
|
|
16
|
+
const isDev = () => getNodeEnv() === 'development';
|
|
16
17
|
export const GraphQLServer = (rawOpts = {}) => {
|
|
17
18
|
const envOptions = getEnvOptions(rawOpts);
|
|
18
19
|
const app = new Server(envOptions);
|
|
@@ -27,6 +28,11 @@ class Server {
|
|
|
27
28
|
const app = express();
|
|
28
29
|
const api = createApiMiddleware(opts);
|
|
29
30
|
const authenticate = createAuthenticateMiddleware(opts);
|
|
31
|
+
// Log startup config in dev mode
|
|
32
|
+
if (isDev()) {
|
|
33
|
+
log.debug(`Database: ${opts.pg?.database}@${opts.pg?.host}:${opts.pg?.port}`);
|
|
34
|
+
log.debug(`Meta schemas: ${opts.api?.metaSchemas?.join(', ') || 'default'}`);
|
|
35
|
+
}
|
|
30
36
|
healthz(app);
|
|
31
37
|
trustProxy(app, opts.server.trustProxy);
|
|
32
38
|
// Warn if a global CORS override is set in production
|
package/middleware/api.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getApiConfig = exports.createApiMiddleware = exports.getSubdomain = void 0;
|
|
7
7
|
const graphql_env_1 = require("@constructive-io/graphql-env");
|
|
8
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
8
9
|
const server_utils_1 = require("@pgpmjs/server-utils");
|
|
9
10
|
const graphile_query_1 = require("graphile-query");
|
|
10
11
|
const graphile_settings_1 = require("graphile-settings");
|
|
@@ -13,6 +14,8 @@ const _50x_1 = __importDefault(require("../errors/50x"));
|
|
|
13
14
|
const _404_message_1 = __importDefault(require("../errors/404-message"));
|
|
14
15
|
const gql_1 = require("./gql");
|
|
15
16
|
require("./types"); // for Request type
|
|
17
|
+
const log = new logger_1.Logger('api');
|
|
18
|
+
const isDev = () => (0, graphql_env_1.getNodeEnv)() === 'development';
|
|
16
19
|
const transformServiceToApi = (svc) => {
|
|
17
20
|
const api = svc.data.api;
|
|
18
21
|
const schemaNames = api.schemaNamesFromExt?.nodes?.map((n) => n.schemaName) || [];
|
|
@@ -99,6 +102,8 @@ const createApiMiddleware = (opts) => {
|
|
|
99
102
|
const api = transformServiceToApi(svc);
|
|
100
103
|
req.api = api;
|
|
101
104
|
req.databaseId = api.databaseId;
|
|
105
|
+
if (isDev())
|
|
106
|
+
log.debug(`Resolved API: db=${api.dbname}, schemas=[${api.schema?.join(', ')}]`);
|
|
102
107
|
next();
|
|
103
108
|
}
|
|
104
109
|
catch (e) {
|
|
@@ -111,7 +116,7 @@ const createApiMiddleware = (opts) => {
|
|
|
111
116
|
.send((0, _404_message_1.default)("The resource you're looking for does not exist."));
|
|
112
117
|
}
|
|
113
118
|
else {
|
|
114
|
-
|
|
119
|
+
log.error('API middleware error:', e);
|
|
115
120
|
res.status(500).send(_50x_1.default);
|
|
116
121
|
}
|
|
117
122
|
}
|
|
@@ -170,7 +175,7 @@ const queryServiceByDomainAndSubdomain = async ({ opts, key, client, domain, sub
|
|
|
170
175
|
variables: { domain, subdomain },
|
|
171
176
|
});
|
|
172
177
|
if (result.errors?.length) {
|
|
173
|
-
|
|
178
|
+
log.error('GraphQL query errors:', result.errors);
|
|
174
179
|
return null;
|
|
175
180
|
}
|
|
176
181
|
const nodes = result?.data?.domains?.nodes;
|
|
@@ -192,7 +197,7 @@ const queryServiceByApiName = async ({ opts, key, client, databaseId, name, }) =
|
|
|
192
197
|
variables: { databaseId, name },
|
|
193
198
|
});
|
|
194
199
|
if (result.errors?.length) {
|
|
195
|
-
|
|
200
|
+
log.error('GraphQL query errors:', result.errors);
|
|
196
201
|
return null;
|
|
197
202
|
}
|
|
198
203
|
const data = result?.data;
|
|
@@ -237,14 +242,21 @@ const getApiConfig = async (opts, req) => {
|
|
|
237
242
|
req.svc_key = key;
|
|
238
243
|
let svc;
|
|
239
244
|
if (server_utils_1.svcCache.has(key)) {
|
|
245
|
+
if (isDev())
|
|
246
|
+
log.debug(`Cache HIT for key=${key}`);
|
|
240
247
|
svc = server_utils_1.svcCache.get(key);
|
|
241
248
|
}
|
|
242
249
|
else {
|
|
250
|
+
if (isDev())
|
|
251
|
+
log.debug(`Cache MISS for key=${key}, looking up API`);
|
|
243
252
|
const apiOpts = opts.api || {};
|
|
244
253
|
const allSchemata = apiOpts.metaSchemas || [];
|
|
245
254
|
const validatedSchemata = await validateSchemata(rootPgPool, allSchemata);
|
|
246
255
|
if (validatedSchemata.length === 0) {
|
|
247
|
-
const
|
|
256
|
+
const apiOpts2 = opts.api || {};
|
|
257
|
+
const message = `No valid schemas found. Configured metaSchemas: [${(apiOpts2.metaSchemas || []).join(', ')}]`;
|
|
258
|
+
if (isDev())
|
|
259
|
+
log.debug(message);
|
|
248
260
|
const error = new Error(message);
|
|
249
261
|
error.code = 'NO_VALID_SCHEMAS';
|
|
250
262
|
throw error;
|
package/middleware/auth.js
CHANGED
|
@@ -4,9 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createAuthenticateMiddleware = void 0;
|
|
7
|
+
const graphql_env_1 = require("@constructive-io/graphql-env");
|
|
8
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
7
9
|
const pg_cache_1 = require("pg-cache");
|
|
8
10
|
const pg_query_context_1 = __importDefault(require("pg-query-context"));
|
|
9
11
|
require("./types"); // for Request type
|
|
12
|
+
const log = new logger_1.Logger('auth');
|
|
13
|
+
const isDev = () => (0, graphql_env_1.getNodeEnv)() === 'development';
|
|
10
14
|
const createAuthenticateMiddleware = (opts) => {
|
|
11
15
|
return async (req, res, next) => {
|
|
12
16
|
const api = req.api;
|
|
@@ -19,8 +23,11 @@ const createAuthenticateMiddleware = (opts) => {
|
|
|
19
23
|
database: api.dbname,
|
|
20
24
|
});
|
|
21
25
|
const rlsModule = api.rlsModule;
|
|
22
|
-
if (!rlsModule)
|
|
26
|
+
if (!rlsModule) {
|
|
27
|
+
if (isDev())
|
|
28
|
+
log.debug('No RLS module configured, skipping auth');
|
|
23
29
|
return next();
|
|
30
|
+
}
|
|
24
31
|
const authFn = opts.server.strictAuth
|
|
25
32
|
? rlsModule.authenticateStrict
|
|
26
33
|
: rlsModule.authenticate;
|
|
@@ -52,8 +59,11 @@ const createAuthenticateMiddleware = (opts) => {
|
|
|
52
59
|
return;
|
|
53
60
|
}
|
|
54
61
|
token = result.rows[0];
|
|
62
|
+
if (isDev())
|
|
63
|
+
log.debug(`Auth success: role=${token.role}`);
|
|
55
64
|
}
|
|
56
65
|
catch (e) {
|
|
66
|
+
log.error('Auth error:', e.message);
|
|
57
67
|
res.status(200).json({
|
|
58
68
|
errors: [
|
|
59
69
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/graphql-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Constructive GraphQL Server",
|
|
6
6
|
"main": "index.js",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"backend"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@constructive-io/graphql-env": "^2.8.
|
|
43
|
-
"@constructive-io/graphql-types": "^2.12.
|
|
42
|
+
"@constructive-io/graphql-env": "^2.8.15",
|
|
43
|
+
"@constructive-io/graphql-types": "^2.12.11",
|
|
44
44
|
"@constructive-io/s3-utils": "^2.4.1",
|
|
45
45
|
"@constructive-io/upload-names": "^2.3.6",
|
|
46
46
|
"@constructive-io/url-domains": "^2.3.7",
|
|
@@ -52,15 +52,15 @@
|
|
|
52
52
|
"express": "^5.2.1",
|
|
53
53
|
"graphile-build": "^4.14.1",
|
|
54
54
|
"graphile-cache": "^1.6.14",
|
|
55
|
-
"graphile-i18n": "^0.2.
|
|
56
|
-
"graphile-meta-schema": "^0.3.
|
|
57
|
-
"graphile-plugin-connection-filter": "^2.4.
|
|
58
|
-
"graphile-plugin-connection-filter-postgis": "^1.1.
|
|
59
|
-
"graphile-plugin-fulltext-filter": "^2.1.
|
|
55
|
+
"graphile-i18n": "^0.2.47",
|
|
56
|
+
"graphile-meta-schema": "^0.3.47",
|
|
57
|
+
"graphile-plugin-connection-filter": "^2.4.47",
|
|
58
|
+
"graphile-plugin-connection-filter-postgis": "^1.1.48",
|
|
59
|
+
"graphile-plugin-fulltext-filter": "^2.1.47",
|
|
60
60
|
"graphile-query": "^2.4.7",
|
|
61
|
-
"graphile-search-plugin": "^0.2.
|
|
62
|
-
"graphile-settings": "^2.10.
|
|
63
|
-
"graphile-simple-inflector": "^0.2.
|
|
61
|
+
"graphile-search-plugin": "^0.2.47",
|
|
62
|
+
"graphile-settings": "^2.10.6",
|
|
63
|
+
"graphile-simple-inflector": "^0.2.47",
|
|
64
64
|
"graphile-utils": "^4.14.1",
|
|
65
65
|
"graphql": "15.10.1",
|
|
66
66
|
"graphql-tag": "2.12.6",
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"nodemon": "^3.1.10",
|
|
84
84
|
"ts-node": "^10.9.2"
|
|
85
85
|
},
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "127c05d5673647cf04111771701a1e4bc7b47ba8"
|
|
87
87
|
}
|
package/server.js
CHANGED
|
@@ -19,6 +19,7 @@ const cors_1 = require("./middleware/cors");
|
|
|
19
19
|
const flush_1 = require("./middleware/flush");
|
|
20
20
|
const graphile_1 = require("./middleware/graphile");
|
|
21
21
|
const log = new logger_1.Logger('server');
|
|
22
|
+
const isDev = () => (0, graphql_env_1.getNodeEnv)() === 'development';
|
|
22
23
|
const GraphQLServer = (rawOpts = {}) => {
|
|
23
24
|
const envOptions = (0, graphql_env_1.getEnvOptions)(rawOpts);
|
|
24
25
|
const app = new Server(envOptions);
|
|
@@ -34,6 +35,11 @@ class Server {
|
|
|
34
35
|
const app = (0, express_1.default)();
|
|
35
36
|
const api = (0, api_1.createApiMiddleware)(opts);
|
|
36
37
|
const authenticate = (0, auth_1.createAuthenticateMiddleware)(opts);
|
|
38
|
+
// Log startup config in dev mode
|
|
39
|
+
if (isDev()) {
|
|
40
|
+
log.debug(`Database: ${opts.pg?.database}@${opts.pg?.host}:${opts.pg?.port}`);
|
|
41
|
+
log.debug(`Meta schemas: ${opts.api?.metaSchemas?.join(', ') || 'default'}`);
|
|
42
|
+
}
|
|
37
43
|
(0, server_utils_1.healthz)(app);
|
|
38
44
|
(0, server_utils_1.trustProxy)(app, opts.server.trustProxy);
|
|
39
45
|
// Warn if a global CORS override is set in production
|