@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/esm/schema.js CHANGED
@@ -1,21 +1,34 @@
1
1
  import { printSchema, getIntrospectionQuery, buildClientSchema } from 'graphql';
2
- import { getGraphileSettings } from 'graphile-settings';
2
+ import { ConstructivePreset, makePgService } from 'graphile-settings';
3
+ import { makeSchema } from 'graphile-build';
3
4
  import { getPgPool } from 'pg-cache';
4
- import { createPostGraphileSchema } from 'postgraphile';
5
5
  import * as http from 'node:http';
6
6
  import * as https from 'node:https';
7
- // Build GraphQL Schema SDL directly from Postgres using PostGraphile, without HTTP.
7
+ // Build GraphQL Schema SDL directly from Postgres using PostGraphile v5, without HTTP.
8
8
  export async function buildSchemaSDL(opts) {
9
9
  const database = opts.database ?? 'constructive';
10
10
  const schemas = Array.isArray(opts.schemas) ? opts.schemas : [];
11
- const settings = getGraphileSettings({
12
- graphile: {
13
- schema: schemas,
14
- ...(opts.graphile ?? {})
15
- }
16
- });
17
- const pgPool = getPgPool({ database });
18
- const schema = await createPostGraphileSchema(pgPool, schemas, settings);
11
+ // Get pool config for connection string
12
+ const pool = getPgPool({ database });
13
+ const poolConfig = pool.options || {};
14
+ const connectionString = `postgres://${poolConfig.user || 'postgres'}:${poolConfig.password || ''}@${poolConfig.host || 'localhost'}:${poolConfig.port || 5432}/${database}`;
15
+ // Build v5 preset
16
+ const preset = {
17
+ extends: [
18
+ ConstructivePreset,
19
+ ...(opts.graphile?.extends ?? []),
20
+ ],
21
+ ...(opts.graphile?.disablePlugins && { disablePlugins: opts.graphile.disablePlugins }),
22
+ ...(opts.graphile?.plugins && { plugins: opts.graphile.plugins }),
23
+ ...(opts.graphile?.schema && { schema: opts.graphile.schema }),
24
+ pgServices: [
25
+ makePgService({
26
+ connectionString,
27
+ schemas,
28
+ }),
29
+ ],
30
+ };
31
+ const { schema } = await makeSchema(preset);
19
32
  return printSchema(schema);
20
33
  }
21
34
  // Fetch GraphQL Schema SDL from a running GraphQL endpoint via introspection.
package/esm/server.js CHANGED
@@ -6,18 +6,46 @@ import { randomUUID } from 'crypto';
6
6
  import express from 'express';
7
7
  // @ts-ignore
8
8
  import graphqlUpload from 'graphql-upload';
9
- import { graphileCache } from 'graphile-cache';
10
- import { getPgPool, pgCache } from 'pg-cache';
9
+ import { graphileCache, closeAllCaches } from 'graphile-cache';
10
+ import { getPgPool } from 'pg-cache';
11
11
  import requestIp from 'request-ip';
12
12
  import { createApiMiddleware } from './middleware/api';
13
13
  import { createAuthenticateMiddleware } from './middleware/auth';
14
14
  import { cors } from './middleware/cors';
15
+ import { errorHandler, notFoundHandler } from './middleware/error-handler';
16
+ import { favicon } from './middleware/favicon';
15
17
  import { flush, flushService } from './middleware/flush';
16
18
  import { graphile } from './middleware/graphile';
19
+ import { normalizeServerOptions } from './options';
17
20
  const log = new Logger('server');
18
21
  const isDev = () => getNodeEnv() === 'development';
22
+ /**
23
+ * Creates and starts a GraphQL server instance
24
+ *
25
+ * Accepts ConstructiveOptions or PgpmOptions.
26
+ * Options are normalized using normalizeServerOptions to apply defaults.
27
+ *
28
+ * @param rawOpts - Server configuration options
29
+ * @returns void (server runs until shutdown)
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // Using ConstructiveOptions (recommended)
34
+ * GraphQLServer({
35
+ * pg: { database: 'myapp' },
36
+ * server: { port: 4000 }
37
+ * });
38
+ *
39
+ * // Using PgpmOptions (backward compatible)
40
+ * GraphQLServer(pgpmOptions);
41
+ * ```
42
+ */
19
43
  export const GraphQLServer = (rawOpts = {}) => {
20
- const envOptions = getEnvOptions(rawOpts);
44
+ // Normalize options to ConstructiveOptions with defaults applied
45
+ const normalizedOpts = normalizeServerOptions(rawOpts);
46
+ // Apply environment variable overrides via getEnvOptions
47
+ // Cast to PgpmOptions for backward compatibility with getEnvOptions
48
+ const envOptions = getEnvOptions(normalizedOpts);
21
49
  const app = new Server(envOptions);
22
50
  app.addEventListener();
23
51
  app.listen();
@@ -71,6 +99,7 @@ class Server {
71
99
  roleName: apiOpts.roleName
72
100
  });
73
101
  healthz(app);
102
+ app.use(favicon);
74
103
  trustProxy(app, effectiveOpts.server.trustProxy);
75
104
  // Warn if a global CORS override is set in production
76
105
  const fallbackOrigin = effectiveOpts.server?.origin?.trim();
@@ -92,6 +121,9 @@ class Server {
92
121
  app.use(authenticate);
93
122
  app.use(graphile(effectiveOpts));
94
123
  app.use(flush);
124
+ // Error handling - MUST be LAST
125
+ app.use(notFoundHandler); // Catches unmatched routes (404)
126
+ app.use(errorHandler); // Catches all thrown errors
95
127
  this.app = app;
96
128
  }
97
129
  listen() {
@@ -192,9 +224,13 @@ class Server {
192
224
  static async closeCaches(opts = {}) {
193
225
  const { closePools = false } = opts;
194
226
  svcCache.clear();
195
- graphileCache.clear();
227
+ // Use closeAllCaches to properly await async disposal of PostGraphile instances
228
+ // before closing pg pools - this ensures all connections are released
196
229
  if (closePools) {
197
- await pgCache.close();
230
+ await closeAllCaches();
231
+ }
232
+ else {
233
+ graphileCache.clear();
198
234
  }
199
235
  }
200
236
  log(text) {
package/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './server';
2
2
  export * from './schema';
3
+ export * from './options';
3
4
  export { createApiMiddleware, getSubdomain, getApiConfig } from './middleware/api';
4
5
  export { createAuthenticateMiddleware } from './middleware/auth';
5
6
  export { cors } from './middleware/cors';
package/index.js CHANGED
@@ -17,6 +17,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.flushService = exports.flush = exports.graphile = exports.cors = exports.createAuthenticateMiddleware = exports.getApiConfig = exports.getSubdomain = exports.createApiMiddleware = void 0;
18
18
  __exportStar(require("./server"), exports);
19
19
  __exportStar(require("./schema"), exports);
20
+ // Export options module - types, defaults, type guards, and utility functions
21
+ __exportStar(require("./options"), exports);
20
22
  // Export middleware for use in testing packages
21
23
  var api_1 = require("./middleware/api");
22
24
  Object.defineProperty(exports, "createApiMiddleware", { enumerable: true, get: function () { return api_1.createApiMiddleware; } });
@@ -1,19 +1,7 @@
1
1
  import { NextFunction, Request, Response } from 'express';
2
- /**
3
- * Normalizes API records into ApiStructure
4
- */
5
- import { type ApiQueryOps } from './gql';
6
- import { ApiConfigResult, ApiOptions, ApiStructure } from '../types';
2
+ import { ApiConfigResult, ApiOptions } from '../types';
7
3
  import './types';
8
- export { normalizeApiRecord } from './gql';
9
- export declare const getSubdomain: (reqDomains: string[]) => string | null;
10
- export declare const createApiMiddleware: (opts: ApiOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
11
- export declare const queryServiceByApiName: ({ opts, key, queryOps, databaseId, name, }: {
12
- opts: ApiOptions;
13
- key: string;
14
- queryOps: ApiQueryOps;
15
- databaseId?: string;
16
- name: string;
17
- }) => Promise<ApiStructure | null>;
4
+ export declare const getSubdomain: (subdomains: string[]) => string | null;
18
5
  export declare const getSvcKey: (opts: ApiOptions, req: Request) => string;
19
6
  export declare const getApiConfig: (opts: ApiOptions, req: Request) => Promise<ApiConfigResult>;
7
+ export declare const createApiMiddleware: (opts: ApiOptions) => (req: Request, res: Response, next: NextFunction) => Promise<void>;