@constructive-io/graphql-server 3.1.1 → 4.0.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.
Files changed (77) hide show
  1. package/errors/404-message.js +1 -1
  2. package/errors/api-errors.d.ts +200 -0
  3. package/errors/api-errors.js +276 -0
  4. package/esm/errors/404-message.js +1 -1
  5. package/esm/errors/api-errors.js +261 -0
  6. package/esm/index.js +2 -0
  7. package/esm/middleware/api.js +355 -277
  8. package/esm/middleware/auth.js +25 -7
  9. package/esm/middleware/error-handler.js +86 -0
  10. package/esm/middleware/favicon.js +12 -0
  11. package/esm/middleware/graphile.js +149 -64
  12. package/esm/options.js +232 -0
  13. package/esm/schema.js +24 -11
  14. package/esm/server.js +41 -5
  15. package/index.d.ts +1 -0
  16. package/index.js +2 -0
  17. package/middleware/api.d.ts +3 -15
  18. package/middleware/api.js +359 -283
  19. package/middleware/auth.js +25 -7
  20. package/middleware/error-handler.d.ts +4 -0
  21. package/middleware/error-handler.js +94 -0
  22. package/middleware/favicon.d.ts +2 -0
  23. package/middleware/favicon.js +16 -0
  24. package/middleware/graphile.d.ts +14 -0
  25. package/middleware/graphile.js +149 -64
  26. package/options.d.ts +131 -0
  27. package/options.js +244 -0
  28. package/package.json +23 -24
  29. package/schema.d.ts +2 -2
  30. package/schema.js +23 -10
  31. package/server.d.ts +24 -2
  32. package/server.js +39 -3
  33. package/codegen/orm/client.d.ts +0 -55
  34. package/codegen/orm/client.js +0 -75
  35. package/codegen/orm/index.d.ts +0 -36
  36. package/codegen/orm/index.js +0 -59
  37. package/codegen/orm/input-types.d.ts +0 -20140
  38. package/codegen/orm/input-types.js +0 -2
  39. package/codegen/orm/models/api.d.ts +0 -42
  40. package/codegen/orm/models/api.js +0 -76
  41. package/codegen/orm/models/domain.d.ts +0 -42
  42. package/codegen/orm/models/domain.js +0 -76
  43. package/codegen/orm/models/index.d.ts +0 -7
  44. package/codegen/orm/models/index.js +0 -12
  45. package/codegen/orm/mutation/index.d.ts +0 -7
  46. package/codegen/orm/mutation/index.js +0 -7
  47. package/codegen/orm/query/index.d.ts +0 -20
  48. package/codegen/orm/query/index.js +0 -24
  49. package/codegen/orm/query-builder.d.ts +0 -81
  50. package/codegen/orm/query-builder.js +0 -496
  51. package/codegen/orm/select-types.d.ts +0 -83
  52. package/codegen/orm/select-types.js +0 -7
  53. package/codegen/orm/types.d.ts +0 -6
  54. package/codegen/orm/types.js +0 -23
  55. package/esm/codegen/orm/client.js +0 -70
  56. package/esm/codegen/orm/index.js +0 -39
  57. package/esm/codegen/orm/input-types.js +0 -1
  58. package/esm/codegen/orm/models/api.js +0 -72
  59. package/esm/codegen/orm/models/domain.js +0 -72
  60. package/esm/codegen/orm/models/index.js +0 -7
  61. package/esm/codegen/orm/mutation/index.js +0 -4
  62. package/esm/codegen/orm/query/index.js +0 -21
  63. package/esm/codegen/orm/query-builder.js +0 -452
  64. package/esm/codegen/orm/select-types.js +0 -6
  65. package/esm/codegen/orm/types.js +0 -7
  66. package/esm/middleware/gql.js +0 -116
  67. package/esm/plugins/PublicKeySignature.js +0 -114
  68. package/esm/scripts/codegen-schema.js +0 -71
  69. package/esm/scripts/create-bucket.js +0 -40
  70. package/middleware/gql.d.ts +0 -164
  71. package/middleware/gql.js +0 -121
  72. package/plugins/PublicKeySignature.d.ts +0 -11
  73. package/plugins/PublicKeySignature.js +0 -121
  74. package/scripts/codegen-schema.d.ts +0 -1
  75. package/scripts/codegen-schema.js +0 -76
  76. package/scripts/create-bucket.d.ts +0 -1
  77. package/scripts/create-bucket.js +0 -42
package/options.js ADDED
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ /**
3
+ * GraphQL Server Options - Configuration utilities
4
+ *
5
+ * This module provides type-safe configuration utilities for the GraphQL server.
6
+ * It includes type guards for runtime validation and utility functions for
7
+ * configuration normalization.
8
+ *
9
+ * The main configuration type is `ConstructiveOptions` from @constructive-io/graphql-types.
10
+ *
11
+ * @module options
12
+ */
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.serverDefaults = void 0;
18
+ exports.isConstructiveOptions = isConstructiveOptions;
19
+ exports.hasPgConfig = hasPgConfig;
20
+ exports.hasServerConfig = hasServerConfig;
21
+ exports.hasApiConfig = hasApiConfig;
22
+ exports.isLegacyOptions = isLegacyOptions;
23
+ exports.normalizeServerOptions = normalizeServerOptions;
24
+ const deepmerge_1 = __importDefault(require("deepmerge"));
25
+ const graphql_types_1 = require("@constructive-io/graphql-types");
26
+ // ============================================
27
+ // Default Configuration
28
+ // ============================================
29
+ /**
30
+ * Default configuration values for GraphQL server
31
+ *
32
+ * Provides sensible defaults for all currently active fields.
33
+ */
34
+ exports.serverDefaults = {
35
+ pg: {
36
+ host: 'localhost',
37
+ port: 5432,
38
+ user: 'postgres',
39
+ password: 'password',
40
+ database: 'postgres'
41
+ },
42
+ server: {
43
+ host: 'localhost',
44
+ port: 3000,
45
+ trustProxy: false,
46
+ strictAuth: false
47
+ },
48
+ api: graphql_types_1.apiDefaults,
49
+ graphile: graphql_types_1.graphileDefaults,
50
+ features: graphql_types_1.graphileFeatureDefaults
51
+ };
52
+ // ============================================
53
+ // Type Guards
54
+ // ============================================
55
+ /**
56
+ * List of all recognized fields in ConstructiveOptions
57
+ */
58
+ const RECOGNIZED_FIELDS = [
59
+ 'pg',
60
+ 'server',
61
+ 'api',
62
+ 'graphile',
63
+ 'features',
64
+ 'db',
65
+ 'cdn',
66
+ 'deployment',
67
+ 'migrations',
68
+ 'jobs'
69
+ ];
70
+ /**
71
+ * Type guard to validate if an unknown value is a valid ConstructiveOptions object
72
+ *
73
+ * Validates that:
74
+ * 1. The value is a non-null object
75
+ * 2. Contains at least one recognized field from the interface
76
+ * 3. All recognized fields that exist have object values (not primitives)
77
+ *
78
+ * @param opts - Unknown value to validate
79
+ * @returns True if opts is a valid ConstructiveOptions object
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * if (isConstructiveOptions(unknownConfig)) {
84
+ * // TypeScript knows unknownConfig is ConstructiveOptions
85
+ * const { pg, server } = unknownConfig;
86
+ * }
87
+ * ```
88
+ */
89
+ function isConstructiveOptions(opts) {
90
+ if (opts === null || opts === undefined) {
91
+ return false;
92
+ }
93
+ if (typeof opts !== 'object') {
94
+ return false;
95
+ }
96
+ const obj = opts;
97
+ // Check for at least one recognized field from the interface
98
+ const hasRecognizedField = RECOGNIZED_FIELDS.some((field) => field in obj);
99
+ if (!hasRecognizedField) {
100
+ return false;
101
+ }
102
+ // Validate that recognized fields have object values (not primitives)
103
+ for (const field of RECOGNIZED_FIELDS) {
104
+ if (field in obj && obj[field] !== undefined && obj[field] !== null) {
105
+ if (typeof obj[field] !== 'object') {
106
+ return false;
107
+ }
108
+ }
109
+ }
110
+ return true;
111
+ }
112
+ /**
113
+ * Type guard to check if an object has PostgreSQL configuration
114
+ *
115
+ * @param opts - Unknown value to check
116
+ * @returns True if opts has a defined pg property
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * if (hasPgConfig(config)) {
121
+ * console.log(config.pg.host);
122
+ * }
123
+ * ```
124
+ */
125
+ function hasPgConfig(opts) {
126
+ if (opts === null || opts === undefined || typeof opts !== 'object') {
127
+ return false;
128
+ }
129
+ return 'pg' in opts && opts.pg !== undefined;
130
+ }
131
+ /**
132
+ * Type guard to check if an object has HTTP server configuration
133
+ *
134
+ * @param opts - Unknown value to check
135
+ * @returns True if opts has a defined server property
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * if (hasServerConfig(config)) {
140
+ * console.log(config.server.port);
141
+ * }
142
+ * ```
143
+ */
144
+ function hasServerConfig(opts) {
145
+ if (opts === null || opts === undefined || typeof opts !== 'object') {
146
+ return false;
147
+ }
148
+ return 'server' in opts && opts.server !== undefined;
149
+ }
150
+ /**
151
+ * Type guard to check if an object has API configuration
152
+ *
153
+ * @param opts - Unknown value to check
154
+ * @returns True if opts has a defined api property
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * if (hasApiConfig(config)) {
159
+ * console.log(config.api.exposedSchemas);
160
+ * }
161
+ * ```
162
+ */
163
+ function hasApiConfig(opts) {
164
+ if (opts === null || opts === undefined || typeof opts !== 'object') {
165
+ return false;
166
+ }
167
+ return 'api' in opts && opts.api !== undefined;
168
+ }
169
+ // ============================================
170
+ // Internal Utilities
171
+ // ============================================
172
+ /**
173
+ * Array merge strategy that replaces arrays (source wins over target).
174
+ * This ensures that when a user specifies an array value, it replaces
175
+ * the default rather than merging/concatenating.
176
+ *
177
+ * @internal
178
+ */
179
+ const replaceArrays = (_target, source) => source;
180
+ // ============================================
181
+ // Utility Functions
182
+ // ============================================
183
+ /**
184
+ * Legacy field names that indicate old configuration format
185
+ */
186
+ const LEGACY_FIELDS = [
187
+ 'schemas', // Old array-style schema config (should be graphile.schema)
188
+ 'pgConfig', // Old naming (should be pg)
189
+ 'serverPort', // Flat config (should be server.port)
190
+ 'serverHost', // Flat config (should be server.host)
191
+ 'dbConfig', // Old naming (should be db)
192
+ 'postgraphile', // Old Graphile v4 naming (should be graphile)
193
+ 'pgPool', // Direct pool config (deprecated)
194
+ 'jwtSecret', // Flat JWT config (should be in api or auth)
195
+ 'watchPg' // Old PostGraphile v4 option
196
+ ];
197
+ /**
198
+ * Detects if the given options object uses a deprecated/legacy format
199
+ *
200
+ * Checks for presence of legacy field names that indicate the configuration
201
+ * needs to be migrated to ConstructiveOptions format.
202
+ *
203
+ * @param opts - Unknown value to check
204
+ * @returns True if legacy configuration patterns are detected
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * if (isLegacyOptions(config)) {
209
+ * console.warn('Detected legacy configuration format. Please migrate to ConstructiveOptions.');
210
+ * }
211
+ * ```
212
+ */
213
+ function isLegacyOptions(opts) {
214
+ if (opts === null || opts === undefined || typeof opts !== 'object') {
215
+ return false;
216
+ }
217
+ const obj = opts;
218
+ return LEGACY_FIELDS.some((field) => field in obj);
219
+ }
220
+ /**
221
+ * Normalizes input to a ConstructiveOptions object with defaults applied
222
+ *
223
+ * Accepts ConstructiveOptions and returns a fully normalized object
224
+ * with default values applied via deep merge. User-provided values override defaults.
225
+ *
226
+ * @param opts - ConstructiveOptions to normalize
227
+ * @returns ConstructiveOptions with defaults filled in
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * // Partial config - missing fields filled from defaults
232
+ * const normalized = normalizeServerOptions({
233
+ * pg: { database: 'myapp' }
234
+ * });
235
+ *
236
+ * // normalized.pg.host === 'localhost' (from default)
237
+ * // normalized.pg.database === 'myapp' (from user config)
238
+ * // normalized.server.port === 3000 (from default)
239
+ * ```
240
+ */
241
+ function normalizeServerOptions(opts) {
242
+ // Deep merge with defaults - user options override defaults
243
+ return (0, deepmerge_1.default)(exports.serverDefaults, opts, { arrayMerge: replaceArrays });
244
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-server",
3
- "version": "3.1.1",
3
+ "version": "4.0.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Constructive GraphQL Server",
6
6
  "main": "index.js",
@@ -42,38 +42,37 @@
42
42
  "backend"
43
43
  ],
44
44
  "dependencies": {
45
- "@constructive-io/graphql-env": "^2.10.0",
46
- "@constructive-io/graphql-types": "^2.15.0",
45
+ "@constructive-io/graphql-env": "^3.0.0",
46
+ "@constructive-io/graphql-types": "^3.0.0",
47
47
  "@constructive-io/s3-utils": "^2.6.0",
48
48
  "@constructive-io/upload-names": "^2.5.0",
49
49
  "@constructive-io/url-domains": "^2.5.0",
50
- "@graphile-contrib/pg-many-to-many": "^1.0.2",
50
+ "@graphile-contrib/pg-many-to-many": "2.0.0-rc.1",
51
+ "@graphile/simplify-inflection": "8.0.0-rc.3",
51
52
  "@pgpmjs/logger": "^2.1.0",
52
53
  "@pgpmjs/server-utils": "^3.1.0",
53
54
  "@pgpmjs/types": "^2.16.0",
54
55
  "cors": "^2.8.5",
56
+ "deepmerge": "^4.3.1",
55
57
  "express": "^5.2.1",
56
- "gql-ast": "^2.7.0",
57
- "graphile-build": "^4.14.1",
58
- "graphile-cache": "^2.1.0",
59
- "graphile-i18n": "^1.1.1",
60
- "graphile-meta-schema": "^1.1.1",
61
- "graphile-plugin-connection-filter": "^3.1.1",
62
- "graphile-plugin-connection-filter-postgis": "^2.1.1",
63
- "graphile-plugin-fulltext-filter": "^3.1.1",
64
- "graphile-query": "^2.6.0",
65
- "graphile-search-plugin": "^1.1.1",
66
- "graphile-settings": "^3.1.1",
67
- "graphile-simple-inflector": "^1.1.1",
68
- "graphile-utils": "^4.14.1",
69
- "graphql": "15.10.1",
70
- "graphql-tag": "2.12.6",
58
+ "gql-ast": "^3.0.0",
59
+ "grafast": "^1.0.0-rc.4",
60
+ "grafserv": "^1.0.0-rc.4",
61
+ "graphile-build": "^5.0.0-rc.3",
62
+ "graphile-build-pg": "^5.0.0-rc.3",
63
+ "graphile-cache": "^3.0.0",
64
+ "graphile-config": "1.0.0-rc.3",
65
+ "graphile-settings": "^4.0.0",
66
+ "graphql": "^16.9.0",
71
67
  "graphql-upload": "^13.0.0",
72
68
  "lru-cache": "^11.2.4",
73
69
  "pg": "^8.17.1",
74
- "pg-cache": "^2.1.0",
70
+ "pg-cache": "^3.0.0",
71
+ "pg-env": "^1.4.0",
75
72
  "pg-query-context": "^2.5.0",
76
- "postgraphile": "^4.14.1",
73
+ "pg-sql2": "^5.0.0-rc.3",
74
+ "postgraphile": "^5.0.0-rc.4",
75
+ "postgraphile-plugin-connection-filter": "^3.0.0-rc.1",
77
76
  "request-ip": "^3.3.0"
78
77
  },
79
78
  "devDependencies": {
@@ -83,11 +82,11 @@
83
82
  "@types/graphql-upload": "^8.0.12",
84
83
  "@types/pg": "^8.16.0",
85
84
  "@types/request-ip": "^0.0.41",
86
- "graphile-test": "3.1.1",
87
- "makage": "^0.1.12",
85
+ "graphile-test": "4.0.0",
86
+ "makage": "^0.1.10",
88
87
  "nodemon": "^3.1.10",
89
88
  "rimraf": "^6.1.2",
90
89
  "ts-node": "^10.9.2"
91
90
  },
92
- "gitHead": "49049ad3ddd762d35625f657cb42fa0862b829a0"
91
+ "gitHead": "b2daeefe49cdefb3d01ea63cf778fb9b847ab5fe"
93
92
  }
package/schema.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { PostGraphileOptions } from 'postgraphile';
1
+ import type { GraphileConfig } from 'graphile-config';
2
2
  export type BuildSchemaOptions = {
3
3
  database?: string;
4
4
  schemas: string[];
5
- graphile?: Partial<PostGraphileOptions>;
5
+ graphile?: Partial<GraphileConfig.Preset>;
6
6
  };
7
7
  export declare function buildSchemaSDL(opts: BuildSchemaOptions): Promise<string>;
8
8
  export declare function fetchEndpointSchemaSDL(endpoint: string, opts?: {
package/schema.js CHANGED
@@ -37,22 +37,35 @@ exports.buildSchemaSDL = buildSchemaSDL;
37
37
  exports.fetchEndpointSchemaSDL = fetchEndpointSchemaSDL;
38
38
  const graphql_1 = require("graphql");
39
39
  const graphile_settings_1 = require("graphile-settings");
40
+ const graphile_build_1 = require("graphile-build");
40
41
  const pg_cache_1 = require("pg-cache");
41
- const postgraphile_1 = require("postgraphile");
42
42
  const http = __importStar(require("node:http"));
43
43
  const https = __importStar(require("node:https"));
44
- // Build GraphQL Schema SDL directly from Postgres using PostGraphile, without HTTP.
44
+ // Build GraphQL Schema SDL directly from Postgres using PostGraphile v5, without HTTP.
45
45
  async function buildSchemaSDL(opts) {
46
46
  const database = opts.database ?? 'constructive';
47
47
  const schemas = Array.isArray(opts.schemas) ? opts.schemas : [];
48
- const settings = (0, graphile_settings_1.getGraphileSettings)({
49
- graphile: {
50
- schema: schemas,
51
- ...(opts.graphile ?? {})
52
- }
53
- });
54
- const pgPool = (0, pg_cache_1.getPgPool)({ database });
55
- const schema = await (0, postgraphile_1.createPostGraphileSchema)(pgPool, schemas, settings);
48
+ // Get pool config for connection string
49
+ const pool = (0, pg_cache_1.getPgPool)({ database });
50
+ const poolConfig = pool.options || {};
51
+ const connectionString = `postgres://${poolConfig.user || 'postgres'}:${poolConfig.password || ''}@${poolConfig.host || 'localhost'}:${poolConfig.port || 5432}/${database}`;
52
+ // Build v5 preset
53
+ const preset = {
54
+ extends: [
55
+ graphile_settings_1.ConstructivePreset,
56
+ ...(opts.graphile?.extends ?? []),
57
+ ],
58
+ ...(opts.graphile?.disablePlugins && { disablePlugins: opts.graphile.disablePlugins }),
59
+ ...(opts.graphile?.plugins && { plugins: opts.graphile.plugins }),
60
+ ...(opts.graphile?.schema && { schema: opts.graphile.schema }),
61
+ pgServices: [
62
+ (0, graphile_settings_1.makePgService)({
63
+ connectionString,
64
+ schemas,
65
+ }),
66
+ ],
67
+ };
68
+ const { schema } = await (0, graphile_build_1.makeSchema)(preset);
56
69
  return (0, graphql_1.printSchema)(schema);
57
70
  }
58
71
  // Fetch GraphQL Schema SDL from a running GraphQL endpoint via introspection.
package/server.d.ts CHANGED
@@ -1,7 +1,29 @@
1
+ import type { ConstructiveOptions } from '@constructive-io/graphql-types';
1
2
  import { PgpmOptions } from '@pgpmjs/types';
2
3
  import type { Server as HttpServer } from 'http';
3
4
  import { Pool, PoolClient } from 'pg';
4
- export declare const GraphQLServer: (rawOpts?: PgpmOptions) => void;
5
+ /**
6
+ * Creates and starts a GraphQL server instance
7
+ *
8
+ * Accepts ConstructiveOptions or PgpmOptions.
9
+ * Options are normalized using normalizeServerOptions to apply defaults.
10
+ *
11
+ * @param rawOpts - Server configuration options
12
+ * @returns void (server runs until shutdown)
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // Using ConstructiveOptions (recommended)
17
+ * GraphQLServer({
18
+ * pg: { database: 'myapp' },
19
+ * server: { port: 4000 }
20
+ * });
21
+ *
22
+ * // Using PgpmOptions (backward compatible)
23
+ * GraphQLServer(pgpmOptions);
24
+ * ```
25
+ */
26
+ export declare const GraphQLServer: (rawOpts?: ConstructiveOptions | PgpmOptions) => void;
5
27
  declare class Server {
6
28
  private app;
7
29
  private opts;
@@ -10,7 +32,7 @@ declare class Server {
10
32
  private shuttingDown;
11
33
  private closed;
12
34
  private httpServer;
13
- constructor(opts: PgpmOptions);
35
+ constructor(opts: ConstructiveOptions);
14
36
  listen(): HttpServer;
15
37
  flush(databaseId: string): Promise<void>;
16
38
  getPool(): Pool;
package/server.js CHANGED
@@ -18,12 +18,40 @@ const request_ip_1 = __importDefault(require("request-ip"));
18
18
  const api_1 = require("./middleware/api");
19
19
  const auth_1 = require("./middleware/auth");
20
20
  const cors_1 = require("./middleware/cors");
21
+ const error_handler_1 = require("./middleware/error-handler");
22
+ const favicon_1 = require("./middleware/favicon");
21
23
  const flush_1 = require("./middleware/flush");
22
24
  const graphile_1 = require("./middleware/graphile");
25
+ const options_1 = require("./options");
23
26
  const log = new logger_1.Logger('server');
24
27
  const isDev = () => (0, graphql_env_1.getNodeEnv)() === 'development';
28
+ /**
29
+ * Creates and starts a GraphQL server instance
30
+ *
31
+ * Accepts ConstructiveOptions or PgpmOptions.
32
+ * Options are normalized using normalizeServerOptions to apply defaults.
33
+ *
34
+ * @param rawOpts - Server configuration options
35
+ * @returns void (server runs until shutdown)
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * // Using ConstructiveOptions (recommended)
40
+ * GraphQLServer({
41
+ * pg: { database: 'myapp' },
42
+ * server: { port: 4000 }
43
+ * });
44
+ *
45
+ * // Using PgpmOptions (backward compatible)
46
+ * GraphQLServer(pgpmOptions);
47
+ * ```
48
+ */
25
49
  const GraphQLServer = (rawOpts = {}) => {
26
- const envOptions = (0, graphql_env_1.getEnvOptions)(rawOpts);
50
+ // Normalize options to ConstructiveOptions with defaults applied
51
+ const normalizedOpts = (0, options_1.normalizeServerOptions)(rawOpts);
52
+ // Apply environment variable overrides via getEnvOptions
53
+ // Cast to PgpmOptions for backward compatibility with getEnvOptions
54
+ const envOptions = (0, graphql_env_1.getEnvOptions)(normalizedOpts);
27
55
  const app = new Server(envOptions);
28
56
  app.addEventListener();
29
57
  app.listen();
@@ -78,6 +106,7 @@ class Server {
78
106
  roleName: apiOpts.roleName
79
107
  });
80
108
  (0, server_utils_1.healthz)(app);
109
+ app.use(favicon_1.favicon);
81
110
  (0, server_utils_1.trustProxy)(app, effectiveOpts.server.trustProxy);
82
111
  // Warn if a global CORS override is set in production
83
112
  const fallbackOrigin = effectiveOpts.server?.origin?.trim();
@@ -99,6 +128,9 @@ class Server {
99
128
  app.use(authenticate);
100
129
  app.use((0, graphile_1.graphile)(effectiveOpts));
101
130
  app.use(flush_1.flush);
131
+ // Error handling - MUST be LAST
132
+ app.use(error_handler_1.notFoundHandler); // Catches unmatched routes (404)
133
+ app.use(error_handler_1.errorHandler); // Catches all thrown errors
102
134
  this.app = app;
103
135
  }
104
136
  listen() {
@@ -199,9 +231,13 @@ class Server {
199
231
  static async closeCaches(opts = {}) {
200
232
  const { closePools = false } = opts;
201
233
  server_utils_1.svcCache.clear();
202
- graphile_cache_1.graphileCache.clear();
234
+ // Use closeAllCaches to properly await async disposal of PostGraphile instances
235
+ // before closing pg pools - this ensures all connections are released
203
236
  if (closePools) {
204
- await pg_cache_1.pgCache.close();
237
+ await (0, graphile_cache_1.closeAllCaches)();
238
+ }
239
+ else {
240
+ graphile_cache_1.graphileCache.clear();
205
241
  }
206
242
  }
207
243
  log(text) {
@@ -1,55 +0,0 @@
1
- /**
2
- * ORM Client - Runtime GraphQL executor
3
- * @generated by @constructive-io/graphql-codegen
4
- * DO NOT EDIT - changes will be overwritten
5
- */
6
- export interface OrmClientConfig {
7
- endpoint: string;
8
- headers?: Record<string, string>;
9
- }
10
- export interface GraphQLError {
11
- message: string;
12
- locations?: {
13
- line: number;
14
- column: number;
15
- }[];
16
- path?: (string | number)[];
17
- extensions?: Record<string, unknown>;
18
- }
19
- /**
20
- * Error thrown when GraphQL request fails
21
- */
22
- export declare class GraphQLRequestError extends Error {
23
- readonly errors: GraphQLError[];
24
- readonly data: unknown;
25
- constructor(errors: GraphQLError[], data?: unknown);
26
- }
27
- /**
28
- * Discriminated union for query results
29
- * Use .ok to check success, or use .unwrap() to get data or throw
30
- */
31
- export type QueryResult<T> = {
32
- ok: true;
33
- data: T;
34
- errors: undefined;
35
- } | {
36
- ok: false;
37
- data: null;
38
- errors: GraphQLError[];
39
- };
40
- /**
41
- * Legacy QueryResult type for backwards compatibility
42
- * @deprecated Use QueryResult discriminated union instead
43
- */
44
- export interface LegacyQueryResult<T> {
45
- data: T | null;
46
- errors?: GraphQLError[];
47
- }
48
- export declare class OrmClient {
49
- private endpoint;
50
- private headers;
51
- constructor(config: OrmClientConfig);
52
- execute<T>(document: string, variables?: Record<string, unknown>): Promise<QueryResult<T>>;
53
- setHeaders(headers: Record<string, string>): void;
54
- getEndpoint(): string;
55
- }
@@ -1,75 +0,0 @@
1
- "use strict";
2
- /**
3
- * ORM Client - Runtime GraphQL executor
4
- * @generated by @constructive-io/graphql-codegen
5
- * DO NOT EDIT - changes will be overwritten
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.OrmClient = exports.GraphQLRequestError = void 0;
9
- /**
10
- * Error thrown when GraphQL request fails
11
- */
12
- class GraphQLRequestError extends Error {
13
- errors;
14
- data;
15
- constructor(errors, data = null) {
16
- const messages = errors.map((e) => e.message).join('; ');
17
- super(`GraphQL Error: ${messages}`);
18
- this.errors = errors;
19
- this.data = data;
20
- this.name = 'GraphQLRequestError';
21
- }
22
- }
23
- exports.GraphQLRequestError = GraphQLRequestError;
24
- class OrmClient {
25
- endpoint;
26
- headers;
27
- constructor(config) {
28
- this.endpoint = config.endpoint;
29
- this.headers = config.headers ?? {};
30
- }
31
- async execute(document, variables) {
32
- const response = await fetch(this.endpoint, {
33
- method: 'POST',
34
- headers: {
35
- 'Content-Type': 'application/json',
36
- Accept: 'application/json',
37
- ...this.headers,
38
- },
39
- body: JSON.stringify({
40
- query: document,
41
- variables: variables ?? {},
42
- }),
43
- });
44
- if (!response.ok) {
45
- return {
46
- ok: false,
47
- data: null,
48
- errors: [
49
- { message: `HTTP ${response.status}: ${response.statusText}` },
50
- ],
51
- };
52
- }
53
- const json = (await response.json());
54
- // Return discriminated union based on presence of errors
55
- if (json.errors && json.errors.length > 0) {
56
- return {
57
- ok: false,
58
- data: null,
59
- errors: json.errors,
60
- };
61
- }
62
- return {
63
- ok: true,
64
- data: json.data,
65
- errors: undefined,
66
- };
67
- }
68
- setHeaders(headers) {
69
- this.headers = { ...this.headers, ...headers };
70
- }
71
- getEndpoint() {
72
- return this.endpoint;
73
- }
74
- }
75
- exports.OrmClient = OrmClient;
@@ -1,36 +0,0 @@
1
- import type { OrmClientConfig } from './client';
2
- import { ApiModel } from './models/api';
3
- import { DomainModel } from './models/domain';
4
- export type { OrmClientConfig, QueryResult, GraphQLError } from './client';
5
- export { GraphQLRequestError } from './client';
6
- export { QueryBuilder } from './query-builder';
7
- export * from './select-types';
8
- /**
9
- * Create an ORM client instance
10
- *
11
- * @example
12
- * ```typescript
13
- * const db = createClient({
14
- * endpoint: 'https://api.example.com/graphql',
15
- * headers: { Authorization: 'Bearer token' },
16
- * });
17
- *
18
- * // Query apis
19
- * const apis = await db.api.findMany({
20
- * select: { id: true, name: true },
21
- * first: 10,
22
- * }).execute();
23
- * ```
24
- */
25
- export declare function createClient(config: OrmClientConfig): {
26
- api: ApiModel;
27
- domain: DomainModel;
28
- query: {
29
- apiByDatabaseIdAndName: <const S extends import("./input-types").ApiSelect>(args: import("./query").ApiByDatabaseIdAndNameVariables, options?: {
30
- select?: import("./select-types").DeepExact<S, import("./input-types").ApiSelect>;
31
- }) => import("./query-builder").QueryBuilder<{
32
- apiByDatabaseIdAndName: import("./select-types").InferSelectResult<import("./input-types").Api, S>;
33
- }>;
34
- };
35
- mutation: {};
36
- };