@constructive-io/graphql-server 2.11.4 → 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.
@@ -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
- console.error(e);
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
- console.error(result.errors);
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
- console.error(result.errors);
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 message = `No valid schemas found for domain: ${domain}, subdomain: ${subdomain}`;
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;
@@ -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
- console.error(e);
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
- console.error(result.errors);
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
- console.error(result.errors);
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 message = `No valid schemas found for domain: ${domain}, subdomain: ${subdomain}`;
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;
@@ -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.11.4",
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.14",
43
- "@constructive-io/graphql-types": "^2.12.10",
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.45",
56
- "graphile-meta-schema": "^0.3.45",
57
- "graphile-plugin-connection-filter": "^2.4.45",
58
- "graphile-plugin-connection-filter-postgis": "^1.1.46",
59
- "graphile-plugin-fulltext-filter": "^2.1.45",
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.45",
62
- "graphile-settings": "^2.10.4",
63
- "graphile-simple-inflector": "^0.2.45",
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": "acb072b93704ad5218dd2c38306680f3750ead09"
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