@constructive-io/graphql-server 5.23.0 → 5.24.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.
@@ -5,7 +5,6 @@ import { escapeIdentifier } from 'pg';
5
5
  import { withPgClient } from 'pg-query-context';
6
6
  import { normalizeError } from '../middleware/mask-error';
7
7
  const log = new Logger('error-events');
8
- export const GRAPHQL_ERROR_EVENT = 'graphql.error';
9
8
  const getExpressRequest = (requestContext) => requestContext?.expressv4?.req;
10
9
  /**
11
10
  * The first structured, public-classified registry code among the errors.
@@ -20,23 +19,31 @@ const refusalCode = (errors) => {
20
19
  }
21
20
  return undefined;
22
21
  };
23
- export const recordEventSql = (events) => `SELECT ${escapeIdentifier(events.privateSchemaName)}.${escapeIdentifier(events.recordEvent)}($1, $2::uuid, $3::jsonb)`;
22
+ export const recordErrorSql = (events) => {
23
+ if (!events.recordError) {
24
+ throw new Error(`events module ${events.privateSchemaName} has no record_error function`);
25
+ }
26
+ return `SELECT ${escapeIdentifier(events.privateSchemaName)}.${escapeIdentifier(events.recordError)}($1, $2::uuid, $3::jsonb)`;
27
+ };
24
28
  /**
25
- * Records `graphql.error` when an authenticated mutation is refused with a
26
- * structured registry code. The refusal rolled back the mutation's own
27
- * transaction, so the event is written afterwards in a fresh transaction under
28
- * the same request claims, via the tenant's events module `record_event`.
29
+ * Records a refused authenticated mutation as an event named after the error
30
+ * code raised by `errors.raise_error`. The refusal rolled back the mutation's
31
+ * own transaction, so the event is written afterwards in a fresh transaction
32
+ * under the same request claims, via the tenant's events module
33
+ * `record_error`, which classifies the code as an error that earns no ladder
34
+ * progress.
29
35
  *
30
- * The server carries no policy about what a code means: the database reads
31
- * `payload->>'code'` (e.g. PRINCIPAL_CHILD_WIDENS demoting a principal on the
32
- * trust ladder). Endpoints without an events module record nothing.
33
- * Unauthenticated requests are never recorded, so anonymous traffic cannot
34
- * drive writes. The client response is never altered.
36
+ * The server carries no policy: the code is the event, and the database decides
37
+ * what it means a ladder's `revoked_by` names the code directly (e.g.
38
+ * PRINCIPAL_CHILD_WIDENS demoting a principal on the trust ladder). Endpoints
39
+ * without an events module record nothing. Unauthenticated requests are never
40
+ * recorded, so anonymous traffic cannot drive writes. The client response is
41
+ * never altered.
35
42
  */
36
43
  export const createErrorEventsPlugin = (pool) => ({
37
44
  name: 'ErrorEventsPlugin',
38
45
  version: '0.0.0',
39
- description: 'Records graphql.error through the tenant events module when an authenticated mutation is refused.',
46
+ description: 'Records a refused authenticated mutation as its error code through the tenant events module.',
40
47
  grafast: {
41
48
  middleware: {
42
49
  async execute(next, event) {
@@ -60,14 +67,10 @@ export const createErrorEventsPlugin = (pool) => ({
60
67
  if (!events || !pgSettings)
61
68
  return result;
62
69
  const operation = args.operationName ?? getOperationAST(args.document)?.name?.value ?? null;
63
- await withPgClient(pool, pgSettings, (client) => client.query(recordEventSql(events), [
64
- GRAPHQL_ERROR_EVENT,
65
- actorId,
66
- JSON.stringify({ code, operation })
67
- ]));
70
+ await withPgClient(pool, pgSettings, (client) => client.query(recordErrorSql(events), [code, actorId, JSON.stringify({ operation })]));
68
71
  }
69
72
  catch (err) {
70
- log.error(`${label} failed to record ${GRAPHQL_ERROR_EVENT} (${code}) for ${actorId}: ${err instanceof Error ? err.message : String(err)}`);
73
+ log.error(`${label} failed to record refusal ${code} for ${actorId}: ${err instanceof Error ? err.message : String(err)}`);
71
74
  }
72
75
  return result;
73
76
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-server",
3
- "version": "5.23.0",
3
+ "version": "5.24.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Constructive GraphQL Server",
6
6
  "main": "index.js",
@@ -44,7 +44,7 @@
44
44
  "@agentic-kit/ollama": "2.14.0",
45
45
  "@constructive-io/csrf": "^0.29.1",
46
46
  "@constructive-io/errors": "^0.13.0",
47
- "@constructive-io/express-context": "^0.29.0",
47
+ "@constructive-io/express-context": "^0.30.0",
48
48
  "@constructive-io/graphql-env": "^3.32.0",
49
49
  "@constructive-io/graphql-types": "^3.31.0",
50
50
  "@constructive-io/llm-env": "^0.14.1",
@@ -67,7 +67,7 @@
67
67
  "graphile-cache": "^4.12.4",
68
68
  "graphile-config": "1.1.0",
69
69
  "graphile-function-bindings": "^1.14.5",
70
- "graphile-settings": "^6.21.6",
70
+ "graphile-settings": "^6.21.7",
71
71
  "graphile-utils": "5.0.3",
72
72
  "graphql": "16.13.0",
73
73
  "graphql-upload": "^13.0.0",
@@ -96,5 +96,5 @@
96
96
  "supertest": "^7.2.2",
97
97
  "ts-node": "^10.9.2"
98
98
  },
99
- "gitHead": "86896399e80595be179738d459106cfbfbada659"
99
+ "gitHead": "10d3a11478d17a20c80da5a827f8e8da4facfc80"
100
100
  }
@@ -2,18 +2,20 @@ import '../middleware/types';
2
2
  import type { EventsConfig } from '@constructive-io/express-context';
3
3
  import type { GraphileConfig } from 'graphile-config';
4
4
  import { type Pool } from 'pg';
5
- export declare const GRAPHQL_ERROR_EVENT = "graphql.error";
6
- export declare const recordEventSql: (events: EventsConfig) => string;
5
+ export declare const recordErrorSql: (events: EventsConfig) => string;
7
6
  /**
8
- * Records `graphql.error` when an authenticated mutation is refused with a
9
- * structured registry code. The refusal rolled back the mutation's own
10
- * transaction, so the event is written afterwards in a fresh transaction under
11
- * the same request claims, via the tenant's events module `record_event`.
7
+ * Records a refused authenticated mutation as an event named after the error
8
+ * code raised by `errors.raise_error`. The refusal rolled back the mutation's
9
+ * own transaction, so the event is written afterwards in a fresh transaction
10
+ * under the same request claims, via the tenant's events module
11
+ * `record_error`, which classifies the code as an error that earns no ladder
12
+ * progress.
12
13
  *
13
- * The server carries no policy about what a code means: the database reads
14
- * `payload->>'code'` (e.g. PRINCIPAL_CHILD_WIDENS demoting a principal on the
15
- * trust ladder). Endpoints without an events module record nothing.
16
- * Unauthenticated requests are never recorded, so anonymous traffic cannot
17
- * drive writes. The client response is never altered.
14
+ * The server carries no policy: the code is the event, and the database decides
15
+ * what it means a ladder's `revoked_by` names the code directly (e.g.
16
+ * PRINCIPAL_CHILD_WIDENS demoting a principal on the trust ladder). Endpoints
17
+ * without an events module record nothing. Unauthenticated requests are never
18
+ * recorded, so anonymous traffic cannot drive writes. The client response is
19
+ * never altered.
18
20
  */
19
21
  export declare const createErrorEventsPlugin: (pool: Pool) => GraphileConfig.Plugin;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createErrorEventsPlugin = exports.recordEventSql = exports.GRAPHQL_ERROR_EVENT = void 0;
3
+ exports.createErrorEventsPlugin = exports.recordErrorSql = void 0;
4
4
  require("../middleware/types"); // for Request type
5
5
  const logger_1 = require("@pgpmjs/logger");
6
6
  const graphql_1 = require("graphql");
@@ -8,7 +8,6 @@ const pg_1 = require("pg");
8
8
  const pg_query_context_1 = require("pg-query-context");
9
9
  const mask_error_1 = require("../middleware/mask-error");
10
10
  const log = new logger_1.Logger('error-events');
11
- exports.GRAPHQL_ERROR_EVENT = 'graphql.error';
12
11
  const getExpressRequest = (requestContext) => requestContext?.expressv4?.req;
13
12
  /**
14
13
  * The first structured, public-classified registry code among the errors.
@@ -23,24 +22,32 @@ const refusalCode = (errors) => {
23
22
  }
24
23
  return undefined;
25
24
  };
26
- const recordEventSql = (events) => `SELECT ${(0, pg_1.escapeIdentifier)(events.privateSchemaName)}.${(0, pg_1.escapeIdentifier)(events.recordEvent)}($1, $2::uuid, $3::jsonb)`;
27
- exports.recordEventSql = recordEventSql;
25
+ const recordErrorSql = (events) => {
26
+ if (!events.recordError) {
27
+ throw new Error(`events module ${events.privateSchemaName} has no record_error function`);
28
+ }
29
+ return `SELECT ${(0, pg_1.escapeIdentifier)(events.privateSchemaName)}.${(0, pg_1.escapeIdentifier)(events.recordError)}($1, $2::uuid, $3::jsonb)`;
30
+ };
31
+ exports.recordErrorSql = recordErrorSql;
28
32
  /**
29
- * Records `graphql.error` when an authenticated mutation is refused with a
30
- * structured registry code. The refusal rolled back the mutation's own
31
- * transaction, so the event is written afterwards in a fresh transaction under
32
- * the same request claims, via the tenant's events module `record_event`.
33
+ * Records a refused authenticated mutation as an event named after the error
34
+ * code raised by `errors.raise_error`. The refusal rolled back the mutation's
35
+ * own transaction, so the event is written afterwards in a fresh transaction
36
+ * under the same request claims, via the tenant's events module
37
+ * `record_error`, which classifies the code as an error that earns no ladder
38
+ * progress.
33
39
  *
34
- * The server carries no policy about what a code means: the database reads
35
- * `payload->>'code'` (e.g. PRINCIPAL_CHILD_WIDENS demoting a principal on the
36
- * trust ladder). Endpoints without an events module record nothing.
37
- * Unauthenticated requests are never recorded, so anonymous traffic cannot
38
- * drive writes. The client response is never altered.
40
+ * The server carries no policy: the code is the event, and the database decides
41
+ * what it means a ladder's `revoked_by` names the code directly (e.g.
42
+ * PRINCIPAL_CHILD_WIDENS demoting a principal on the trust ladder). Endpoints
43
+ * without an events module record nothing. Unauthenticated requests are never
44
+ * recorded, so anonymous traffic cannot drive writes. The client response is
45
+ * never altered.
39
46
  */
40
47
  const createErrorEventsPlugin = (pool) => ({
41
48
  name: 'ErrorEventsPlugin',
42
49
  version: '0.0.0',
43
- description: 'Records graphql.error through the tenant events module when an authenticated mutation is refused.',
50
+ description: 'Records a refused authenticated mutation as its error code through the tenant events module.',
44
51
  grafast: {
45
52
  middleware: {
46
53
  async execute(next, event) {
@@ -64,14 +71,10 @@ const createErrorEventsPlugin = (pool) => ({
64
71
  if (!events || !pgSettings)
65
72
  return result;
66
73
  const operation = args.operationName ?? (0, graphql_1.getOperationAST)(args.document)?.name?.value ?? null;
67
- await (0, pg_query_context_1.withPgClient)(pool, pgSettings, (client) => client.query((0, exports.recordEventSql)(events), [
68
- exports.GRAPHQL_ERROR_EVENT,
69
- actorId,
70
- JSON.stringify({ code, operation })
71
- ]));
74
+ await (0, pg_query_context_1.withPgClient)(pool, pgSettings, (client) => client.query((0, exports.recordErrorSql)(events), [code, actorId, JSON.stringify({ operation })]));
72
75
  }
73
76
  catch (err) {
74
- log.error(`${label} failed to record ${exports.GRAPHQL_ERROR_EVENT} (${code}) for ${actorId}: ${err instanceof Error ? err.message : String(err)}`);
77
+ log.error(`${label} failed to record refusal ${code} for ${actorId}: ${err instanceof Error ? err.message : String(err)}`);
75
78
  }
76
79
  return result;
77
80
  }