@weave-kit/engine 0.7.0 → 0.8.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/CHANGELOG.md +35 -0
- package/README.md +7 -0
- package/dist/adapters/graphql/http.d.ts +24 -0
- package/dist/adapters/graphql/http.d.ts.map +1 -0
- package/dist/adapters/graphql/http.js +147 -0
- package/dist/adapters/graphql/http.js.map +1 -0
- package/dist/adapters/graphql/index.d.ts +33 -0
- package/dist/adapters/graphql/index.d.ts.map +1 -0
- package/dist/adapters/graphql/index.js +24 -0
- package/dist/adapters/graphql/index.js.map +1 -0
- package/dist/adapters/graphql/loader.d.ts +4 -0
- package/dist/adapters/graphql/loader.d.ts.map +1 -0
- package/dist/adapters/graphql/loader.js +135 -0
- package/dist/adapters/graphql/loader.js.map +1 -0
- package/dist/adapters/graphql/resolvers.d.ts +52 -0
- package/dist/adapters/graphql/resolvers.d.ts.map +1 -0
- package/dist/adapters/graphql/resolvers.js +109 -0
- package/dist/adapters/graphql/resolvers.js.map +1 -0
- package/dist/adapters/graphql/scalars.d.ts +8 -0
- package/dist/adapters/graphql/scalars.d.ts.map +1 -0
- package/dist/adapters/graphql/scalars.js +14 -0
- package/dist/adapters/graphql/scalars.js.map +1 -0
- package/dist/adapters/graphql/schema.d.ts +9 -0
- package/dist/adapters/graphql/schema.d.ts.map +1 -0
- package/dist/adapters/graphql/schema.js +297 -0
- package/dist/adapters/graphql/schema.js.map +1 -0
- package/dist/adapters/graphql/security.d.ts +29 -0
- package/dist/adapters/graphql/security.d.ts.map +1 -0
- package/dist/adapters/graphql/security.js +81 -0
- package/dist/adapters/graphql/security.js.map +1 -0
- package/dist/adapters/graphql/types.d.ts +67 -0
- package/dist/adapters/graphql/types.d.ts.map +1 -0
- package/dist/adapters/graphql/types.js +2 -0
- package/dist/adapters/graphql/types.js.map +1 -0
- package/dist/adapters/mcp/generate.js +3 -3
- package/dist/adapters/mcp/generate.js.map +1 -1
- package/dist/adapters/mcp/guardrails.d.ts +1 -1
- package/dist/adapters/mcp/http.d.ts.map +1 -1
- package/dist/adapters/mcp/http.js +28 -15
- package/dist/adapters/mcp/http.js.map +1 -1
- package/dist/adapters/mcp/session.d.ts +11 -3
- package/dist/adapters/mcp/session.d.ts.map +1 -1
- package/dist/adapters/mcp/session.js +12 -0
- package/dist/adapters/mcp/session.js.map +1 -1
- package/dist/adapters/mcp/tools.js +3 -3
- package/dist/adapters/mcp/tools.js.map +1 -1
- package/dist/adapters/openapi/document.d.ts.map +1 -1
- package/dist/adapters/openapi/document.js +9 -2
- package/dist/adapters/openapi/document.js.map +1 -1
- package/dist/adapters/openapi/schema.d.ts +8 -6
- package/dist/adapters/openapi/schema.d.ts.map +1 -1
- package/dist/adapters/openapi/schema.js +41 -9
- package/dist/adapters/openapi/schema.js.map +1 -1
- package/dist/adapters/openapi/types.d.ts +2 -0
- package/dist/adapters/openapi/types.d.ts.map +1 -1
- package/dist/cli/commands/enums.d.ts +14 -0
- package/dist/cli/commands/enums.d.ts.map +1 -0
- package/dist/cli/commands/enums.js +83 -0
- package/dist/cli/commands/enums.js.map +1 -0
- package/dist/cli/commands/field-add.d.ts.map +1 -1
- package/dist/cli/commands/field-add.js +12 -4
- package/dist/cli/commands/field-add.js.map +1 -1
- package/dist/cli/commands/graphql-schema.d.ts +9 -0
- package/dist/cli/commands/graphql-schema.d.ts.map +1 -0
- package/dist/cli/commands/graphql-schema.js +35 -0
- package/dist/cli/commands/graphql-schema.js.map +1 -0
- package/dist/cli/commands/openapi.d.ts.map +1 -1
- package/dist/cli/commands/openapi.js +4 -1
- package/dist/cli/commands/openapi.js.map +1 -1
- package/dist/cli/index.js +23 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/types/commands.d.ts +16 -0
- package/dist/cli/types/commands.d.ts.map +1 -1
- package/dist/cli/types/index.d.ts +1 -1
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/types/values.d.ts +3 -0
- package/dist/cli/types/values.d.ts.map +1 -1
- package/dist/cli/types/values.js +3 -0
- package/dist/cli/types/values.js.map +1 -1
- package/dist/core/api/error.d.ts +3 -2
- package/dist/core/api/error.d.ts.map +1 -1
- package/dist/core/api/error.js +20 -16
- package/dist/core/api/error.js.map +1 -1
- package/dist/core/audit/types.d.ts +2 -2
- package/dist/core/audit/types.d.ts.map +1 -1
- package/dist/core/i18n/ar.d.ts.map +1 -1
- package/dist/core/i18n/ar.js +8 -0
- package/dist/core/i18n/ar.js.map +1 -1
- package/dist/core/i18n/de.d.ts.map +1 -1
- package/dist/core/i18n/de.js +8 -0
- package/dist/core/i18n/de.js.map +1 -1
- package/dist/core/i18n/en.d.ts +8 -0
- package/dist/core/i18n/en.d.ts.map +1 -1
- package/dist/core/i18n/en.js +8 -0
- package/dist/core/i18n/en.js.map +1 -1
- package/dist/core/i18n/es.d.ts.map +1 -1
- package/dist/core/i18n/es.js +8 -0
- package/dist/core/i18n/es.js.map +1 -1
- package/dist/core/i18n/fr.d.ts.map +1 -1
- package/dist/core/i18n/fr.js +8 -0
- package/dist/core/i18n/fr.js.map +1 -1
- package/dist/core/i18n/hi.d.ts.map +1 -1
- package/dist/core/i18n/hi.js +8 -0
- package/dist/core/i18n/hi.js.map +1 -1
- package/dist/core/i18n/id.d.ts.map +1 -1
- package/dist/core/i18n/id.js +8 -0
- package/dist/core/i18n/id.js.map +1 -1
- package/dist/core/i18n/ja.d.ts.map +1 -1
- package/dist/core/i18n/ja.js +8 -0
- package/dist/core/i18n/ja.js.map +1 -1
- package/dist/core/i18n/ko.d.ts.map +1 -1
- package/dist/core/i18n/ko.js +8 -0
- package/dist/core/i18n/ko.js.map +1 -1
- package/dist/core/i18n/pt.d.ts.map +1 -1
- package/dist/core/i18n/pt.js +8 -0
- package/dist/core/i18n/pt.js.map +1 -1
- package/dist/core/i18n/ru.d.ts.map +1 -1
- package/dist/core/i18n/ru.js +8 -0
- package/dist/core/i18n/ru.js.map +1 -1
- package/dist/core/i18n/vi.d.ts.map +1 -1
- package/dist/core/i18n/vi.js +8 -0
- package/dist/core/i18n/vi.js.map +1 -1
- package/dist/core/i18n/zh-hant.d.ts.map +1 -1
- package/dist/core/i18n/zh-hant.js +8 -0
- package/dist/core/i18n/zh-hant.js.map +1 -1
- package/dist/core/i18n/zh.d.ts.map +1 -1
- package/dist/core/i18n/zh.js +8 -0
- package/dist/core/i18n/zh.js.map +1 -1
- package/dist/core/object/describe.d.ts +11 -0
- package/dist/core/object/describe.d.ts.map +1 -1
- package/dist/core/object/describe.js +8 -0
- package/dist/core/object/describe.js.map +1 -1
- package/dist/core/object/enums.d.ts +5 -0
- package/dist/core/object/enums.d.ts.map +1 -0
- package/dist/core/object/enums.js +67 -0
- package/dist/core/object/enums.js.map +1 -0
- package/dist/core/object/gen-types.d.ts +2 -2
- package/dist/core/object/gen-types.d.ts.map +1 -1
- package/dist/core/object/gen-types.js +39 -2
- package/dist/core/object/gen-types.js.map +1 -1
- package/dist/core/object/index.d.ts +1 -0
- package/dist/core/object/index.d.ts.map +1 -1
- package/dist/core/object/index.js +1 -0
- package/dist/core/object/index.js.map +1 -1
- package/dist/core/object/migrations.d.ts.map +1 -1
- package/dist/core/object/migrations.js +11 -0
- package/dist/core/object/migrations.js.map +1 -1
- package/dist/core/object/registry.d.ts +4 -1
- package/dist/core/object/registry.d.ts.map +1 -1
- package/dist/core/object/registry.js +5 -2
- package/dist/core/object/registry.js.map +1 -1
- package/dist/core/object/schema-version.d.ts +1 -1
- package/dist/core/object/schema-version.js +1 -1
- package/dist/core/object/validate/field.d.ts +3 -1
- package/dist/core/object/validate/field.d.ts.map +1 -1
- package/dist/core/object/validate/field.js +63 -29
- package/dist/core/object/validate/field.js.map +1 -1
- package/dist/core/object/validate/object.d.ts +6 -1
- package/dist/core/object/validate/object.d.ts.map +1 -1
- package/dist/core/object/validate/object.js +5 -1
- package/dist/core/object/validate/object.js.map +1 -1
- package/dist/core/tools/types.d.ts +1 -1
- package/dist/core/tools/types.d.ts.map +1 -1
- package/dist/core/types/enum-registry.d.ts +33 -0
- package/dist/core/types/enum-registry.d.ts.map +1 -0
- package/dist/core/types/enum-registry.js +21 -0
- package/dist/core/types/enum-registry.js.map +1 -0
- package/dist/core/types/index.d.ts +2 -0
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/index.js +1 -0
- package/dist/core/types/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime/engine.d.ts +5 -1
- package/dist/runtime/engine.d.ts.map +1 -1
- package/dist/runtime/engine.js +17 -1
- package/dist/runtime/engine.js.map +1 -1
- package/dist/runtime/enums/index.d.ts +3 -0
- package/dist/runtime/enums/index.d.ts.map +1 -0
- package/dist/runtime/enums/index.js +2 -0
- package/dist/runtime/enums/index.js.map +1 -0
- package/dist/runtime/enums/loader.d.ts +27 -0
- package/dist/runtime/enums/loader.d.ts.map +1 -0
- package/dist/runtime/enums/loader.js +61 -0
- package/dist/runtime/enums/loader.js.map +1 -0
- package/dist/runtime/git/autoCommit.d.ts +1 -1
- package/dist/runtime/git/autoCommit.d.ts.map +1 -1
- package/dist/runtime/git/autoCommit.js +20 -1
- package/dist/runtime/git/autoCommit.js.map +1 -1
- package/dist/runtime/git/loader.d.ts +5 -1
- package/dist/runtime/git/loader.d.ts.map +1 -1
- package/dist/runtime/git/loader.js +6 -1
- package/dist/runtime/git/loader.js.map +1 -1
- package/dist/runtime/tools/executor.d.ts +1 -1
- package/dist/runtime/tools/executor.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
2
|
+
import { encodeRecordKey, FIELD_TYPES, primaryFieldsOf, RECORD_META_ID_FIELD, SchemaError, } from '../../core/index.js';
|
|
3
|
+
/** the columns a read projects: every non-details field plus the derived `weave_id` */
|
|
4
|
+
function projectionOf(def) {
|
|
5
|
+
return [...def.fields.filter((f) => f.type !== FIELD_TYPES.DETAILS).map((f) => f.name), RECORD_META_ID_FIELD];
|
|
6
|
+
}
|
|
7
|
+
function dataContext(context) {
|
|
8
|
+
return {
|
|
9
|
+
pool: context.engine.pool,
|
|
10
|
+
registry: context.engine.registry,
|
|
11
|
+
subject: context.subject,
|
|
12
|
+
locale: context.engine.locale,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** map a thrown SchemaError to a GraphQLError carrying its stable code */
|
|
16
|
+
async function guard(fn, locale) {
|
|
17
|
+
try {
|
|
18
|
+
return await fn();
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof SchemaError) {
|
|
22
|
+
throw new GraphQLError(error.localize(locale), {
|
|
23
|
+
extensions: {
|
|
24
|
+
code: error.code,
|
|
25
|
+
...(Object.keys(error.params).length === 0 ? {} : { params: error.params }),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** `<object>` — a page of records, row-scoped by the identity's read RBAC */
|
|
33
|
+
export function listResolver(objectName) {
|
|
34
|
+
return async (_parent, args, context) => {
|
|
35
|
+
const def = context.engine.registry.get(objectName);
|
|
36
|
+
if (def === undefined) {
|
|
37
|
+
throw new GraphQLError(`unknown object "${objectName}"`, { extensions: { code: 'data.objectUnknown' } });
|
|
38
|
+
}
|
|
39
|
+
return guard(() => context.engine.dataAccess.find(objectName, {
|
|
40
|
+
...(args.filter === undefined ? {} : { filter: args.filter }),
|
|
41
|
+
...(args.sort === undefined ? {} : { sort: args.sort }),
|
|
42
|
+
...(args.limit === undefined ? {} : { limit: args.limit }),
|
|
43
|
+
...(args.offset === undefined ? {} : { offset: args.offset }),
|
|
44
|
+
fields: projectionOf(def),
|
|
45
|
+
}, dataContext(context)), context.engine.locale);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** `<object>_by_id` — one record by its `weave_id` (record_key), or null */
|
|
49
|
+
export function singleResolver(objectName) {
|
|
50
|
+
return async (_parent, args, context) => {
|
|
51
|
+
const record = await guard(() => context.engine.dataAccess.findOne(objectName, args.id, dataContext(context)), context.engine.locale);
|
|
52
|
+
return record ?? null;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** `create<Object>(data:)` — create one record (RBAC-checked + audited by data-access) */
|
|
56
|
+
export function createResolver(objectName) {
|
|
57
|
+
return async (_parent, args, context) => {
|
|
58
|
+
return guard(() => context.engine.dataAccess.create(objectName, args.data, dataContext(context)), context.engine.locale);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** `update<Object>(id:, changes:)` — update one record by its `weave_id` */
|
|
62
|
+
export function updateResolver(objectName) {
|
|
63
|
+
return async (_parent, args, context) => {
|
|
64
|
+
return guard(() => context.engine.dataAccess.update(objectName, args.id, args.changes, dataContext(context)), context.engine.locale);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** `delete<Object>(id:)` — delete one record; returns true (throws when absent/denied) */
|
|
68
|
+
export function deleteResolver(objectName) {
|
|
69
|
+
return async (_parent, args, context) => {
|
|
70
|
+
await guard(() => context.engine.dataAccess.delete(objectName, args.id, dataContext(context)), context.engine.locale);
|
|
71
|
+
return true;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** `transition<Object>(id:, action:, payload:)` — run a workflow action */
|
|
75
|
+
export function transitionResolver(objectName) {
|
|
76
|
+
return async (_parent, args, context) => {
|
|
77
|
+
return guard(() => context.engine.dataAccess.transition(objectName, args.id, args.action, dataContext(context), args.payload ?? undefined), context.engine.locale);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** a `relation`/`user`/`department` output field → the target object (batched) */
|
|
81
|
+
export function relationResolver(target, fieldName) {
|
|
82
|
+
return async (parent, _args, context) => {
|
|
83
|
+
const fk = parent[fieldName];
|
|
84
|
+
if (fk === null || fk === undefined)
|
|
85
|
+
return null;
|
|
86
|
+
return context.loader.load(target, encodeRecordKey([String(fk)]));
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** a `multiRelation` output field → the target objects (batched) */
|
|
90
|
+
export function multiRelationResolver(target, targetDef, fieldName) {
|
|
91
|
+
return async (parent, _args, context) => {
|
|
92
|
+
const value = parent[fieldName];
|
|
93
|
+
if (!Array.isArray(value))
|
|
94
|
+
return [];
|
|
95
|
+
const composite = primaryFieldsOf(targetDef).length > 1;
|
|
96
|
+
const records = await Promise.all(value.map((v) => context.loader.load(target, composite ? String(v) : encodeRecordKey([String(v)]))));
|
|
97
|
+
return records.filter((r) => r !== null);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** a `details` output field → the parent's children (batched, ordered by `parent_idx`) */
|
|
101
|
+
export function detailsResolver(childObject) {
|
|
102
|
+
return async (parent, _args, context) => {
|
|
103
|
+
const parentKey = parent[RECORD_META_ID_FIELD];
|
|
104
|
+
if (parentKey === null || parentKey === undefined)
|
|
105
|
+
return [];
|
|
106
|
+
return context.loader.loadChildren(childObject, String(parentKey));
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=resolvers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvers.js","sourceRoot":"","sources":["../../../src/adapters/graphql/resolvers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { GraphQLScalarType } from 'graphql';
|
|
2
|
+
/**
|
|
3
|
+
* The `JSON` scalar — an arbitrary JSON value. Used for `json`/`jsonb` object
|
|
4
|
+
* fields and the free-form `filter` argument (which mirrors the REST/MCP filter
|
|
5
|
+
* contract: exact values, operator objects, and a top-level `$or`).
|
|
6
|
+
*/
|
|
7
|
+
export declare const GraphQLJSON: GraphQLScalarType<unknown, unknown>;
|
|
8
|
+
//# sourceMappingURL=scalars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scalars.d.ts","sourceRoot":"","sources":["../../../src/adapters/graphql/scalars.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA6B,MAAM,SAAS,CAAC;AAEvE;;;;GAIG;AACH,eAAO,MAAM,WAAW,qCAMtB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GraphQLScalarType, Kind, valueFromASTUntyped } from 'graphql';
|
|
2
|
+
/**
|
|
3
|
+
* The `JSON` scalar — an arbitrary JSON value. Used for `json`/`jsonb` object
|
|
4
|
+
* fields and the free-form `filter` argument (which mirrors the REST/MCP filter
|
|
5
|
+
* contract: exact values, operator objects, and a top-level `$or`).
|
|
6
|
+
*/
|
|
7
|
+
export const GraphQLJSON = new GraphQLScalarType({
|
|
8
|
+
name: 'JSON',
|
|
9
|
+
description: 'Arbitrary JSON value (object, array, or scalar).',
|
|
10
|
+
serialize: (value) => value,
|
|
11
|
+
parseValue: (value) => value,
|
|
12
|
+
parseLiteral: (ast) => (ast.kind === Kind.NULL ? null : valueFromASTUntyped(ast)),
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=scalars.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scalars.js","sourceRoot":"","sources":["../../../src/adapters/graphql/scalars.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEvE;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,iBAAiB,CAAC;IAC/C,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,kDAAkD;IAC/D,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;IAC3B,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;IAC5B,YAAY,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;CAClF,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GraphQLSchema } from 'graphql';
|
|
2
|
+
import { type ObjectRegistry } from '../../core/index.js';
|
|
3
|
+
/** compile the registry into a GraphQL schema (only the registry is needed; no data-access) */
|
|
4
|
+
export declare function buildGraphQLSchema(input: {
|
|
5
|
+
registry: ObjectRegistry;
|
|
6
|
+
}): GraphQLSchema;
|
|
7
|
+
/** SDL for the compiled schema (used by `weave graphql:schema` in a later phase). */
|
|
8
|
+
export declare function printGraphQLSchema(schema: GraphQLSchema): string;
|
|
9
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/adapters/graphql/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,aAAa,EAUd,MAAM,SAAS,CAAC;AACjB,OAAO,EASL,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAkO7B,+FAA+F;AAC/F,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,QAAQ,EAAE,cAAc,CAAA;CAAE,GAAG,aAAa,CAmHrF;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAEhE"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { GraphQLBoolean, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, printSchema, } from 'graphql';
|
|
2
|
+
import { FIELD_TYPES, fieldBase, isRelationLike, RECORD_META_ID_FIELD, } from '../../core/index.js';
|
|
3
|
+
import { GraphQLJSON } from './scalars.js';
|
|
4
|
+
import { createResolver, deleteResolver, detailsResolver, listResolver, multiRelationResolver, relationResolver, singleResolver, transitionResolver, updateResolver, } from './resolvers.js';
|
|
5
|
+
/**
|
|
6
|
+
* Compile the object registry into a GraphQL schema.
|
|
7
|
+
*
|
|
8
|
+
* Phase 1: scalar fields + read-only Query. Phase 2: Mutations
|
|
9
|
+
* (`create`/`update`/`delete`, plus `transition` for objects with a workflow).
|
|
10
|
+
* Relations (`relation`/`details`/`multiRelation`) as output fields and nested
|
|
11
|
+
* loaders land in Phase 3.
|
|
12
|
+
*
|
|
13
|
+
* The schema is **identity-agnostic** (built once from the registry): RBAC is
|
|
14
|
+
* enforced at resolve time by the RBAC-decorated data-access layer, so a denied
|
|
15
|
+
* write raises a `rbac.denied.*` GraphQL error and a write is audited exactly as
|
|
16
|
+
* REST/MCP. Build is programmatic so `printSchema` can emit SDL.
|
|
17
|
+
*/
|
|
18
|
+
const SORT_DIR = { ASC: 'asc', DESC: 'desc' };
|
|
19
|
+
/** snake_case → PascalCase (`lead` → `Lead`, `crm_lead` → `CrmLead`) */
|
|
20
|
+
function pascalCase(snake) {
|
|
21
|
+
return snake
|
|
22
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
23
|
+
.filter((part) => part.length > 0)
|
|
24
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
25
|
+
.join('');
|
|
26
|
+
}
|
|
27
|
+
/** engine-managed read-only fields (never writable): system, computed, sequence */
|
|
28
|
+
function isReadonlyField(field) {
|
|
29
|
+
return (field.system === true ||
|
|
30
|
+
field.formula !== undefined ||
|
|
31
|
+
field.type === FIELD_TYPES.SEQ_NO);
|
|
32
|
+
}
|
|
33
|
+
/** a GraphQL-legal, unique enum value name for an arbitrary stored value */
|
|
34
|
+
function enumValueName(raw, used) {
|
|
35
|
+
let name = raw.replace(/[^_0-9A-Za-z]/g, '_');
|
|
36
|
+
if (!/^[_A-Za-z]/.test(name))
|
|
37
|
+
name = `_${name}`;
|
|
38
|
+
if (name.length === 0)
|
|
39
|
+
name = '_';
|
|
40
|
+
let candidate = name;
|
|
41
|
+
let i = 1;
|
|
42
|
+
while (used.has(candidate))
|
|
43
|
+
candidate = `${name}_${i++}`;
|
|
44
|
+
used.add(candidate);
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
/** the GraphQL enum type for a static enum field (data-driven enums are strings) */
|
|
48
|
+
function enumTypeFor(field, objectName, cache) {
|
|
49
|
+
if (!Array.isArray(field.options))
|
|
50
|
+
return GraphQLString;
|
|
51
|
+
const typeName = pascalCase(field.enumType ?? `${objectName}_${field.name}`);
|
|
52
|
+
const cacheKey = `${typeName}::${field.options.join('\u0001')}`;
|
|
53
|
+
let type = cache.get(cacheKey);
|
|
54
|
+
if (type === undefined) {
|
|
55
|
+
const used = new Set();
|
|
56
|
+
const values = {};
|
|
57
|
+
for (const value of field.options)
|
|
58
|
+
values[enumValueName(value, used)] = { value };
|
|
59
|
+
type = new GraphQLEnumType({ name: typeName, values });
|
|
60
|
+
cache.set(cacheKey, type);
|
|
61
|
+
}
|
|
62
|
+
return field.multiple === true ? new GraphQLList(type) : type;
|
|
63
|
+
}
|
|
64
|
+
/** GraphQL output type for one field, or undefined when it is not yet exposed (relations) */
|
|
65
|
+
function fieldType(field, registry, objectName, cache) {
|
|
66
|
+
if (isRelationLike(registry, field.type))
|
|
67
|
+
return undefined; // Phase 3 (output relations)
|
|
68
|
+
switch (fieldBase(registry, field.type)) {
|
|
69
|
+
case FIELD_TYPES.SMALLINT:
|
|
70
|
+
case FIELD_TYPES.INTEGER:
|
|
71
|
+
return GraphQLInt;
|
|
72
|
+
case FIELD_TYPES.BIGINT:
|
|
73
|
+
return GraphQLString; // precision-safe (pg returns int8 as text)
|
|
74
|
+
case FIELD_TYPES.NUMBER:
|
|
75
|
+
case FIELD_TYPES.CURRENCY:
|
|
76
|
+
case FIELD_TYPES.REAL:
|
|
77
|
+
case FIELD_TYPES.DOUBLE:
|
|
78
|
+
return GraphQLFloat;
|
|
79
|
+
case FIELD_TYPES.BOOLEAN:
|
|
80
|
+
return GraphQLBoolean;
|
|
81
|
+
case FIELD_TYPES.JSON:
|
|
82
|
+
case FIELD_TYPES.JSONB:
|
|
83
|
+
return GraphQLJSON;
|
|
84
|
+
case FIELD_TYPES.ENUM:
|
|
85
|
+
return enumTypeFor(field, objectName, cache);
|
|
86
|
+
default:
|
|
87
|
+
return GraphQLString;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** the GraphQL scalar for a relation target's primary key (fallback: String) */
|
|
91
|
+
function pkType(target, registry, objects) {
|
|
92
|
+
const pk = target === undefined ? undefined : objects.get(target)?.fields.find((f) => f.primary === true);
|
|
93
|
+
if (pk === undefined)
|
|
94
|
+
return GraphQLString;
|
|
95
|
+
switch (fieldBase(registry, pk.type)) {
|
|
96
|
+
case FIELD_TYPES.SMALLINT:
|
|
97
|
+
case FIELD_TYPES.INTEGER:
|
|
98
|
+
return GraphQLInt;
|
|
99
|
+
case FIELD_TYPES.NUMBER:
|
|
100
|
+
case FIELD_TYPES.CURRENCY:
|
|
101
|
+
case FIELD_TYPES.REAL:
|
|
102
|
+
case FIELD_TYPES.DOUBLE:
|
|
103
|
+
return GraphQLFloat;
|
|
104
|
+
case FIELD_TYPES.BOOLEAN:
|
|
105
|
+
return GraphQLBoolean;
|
|
106
|
+
default:
|
|
107
|
+
return GraphQLString;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** the GraphQL input type for one writable field, or undefined when it is not writable */
|
|
111
|
+
function inputFieldType(field, registry, objectName, objects, cache) {
|
|
112
|
+
if (field.type === FIELD_TYPES.DETAILS || isReadonlyField(field))
|
|
113
|
+
return undefined;
|
|
114
|
+
if (isRelationLike(registry, field.type)) {
|
|
115
|
+
if (field.type === FIELD_TYPES.MULTI_RELATION)
|
|
116
|
+
return new GraphQLList(GraphQLID); // record keys
|
|
117
|
+
return pkType(field.target, registry, objects);
|
|
118
|
+
}
|
|
119
|
+
return fieldType(field, registry, objectName, cache);
|
|
120
|
+
}
|
|
121
|
+
/** the GraphQL field for a relation-like schema field, or undefined when it cannot be typed */
|
|
122
|
+
function relationField(field, objects, objectTypes) {
|
|
123
|
+
const target = field.target;
|
|
124
|
+
const targetType = target === undefined ? undefined : objectTypes.get(target);
|
|
125
|
+
if (field.type === FIELD_TYPES.DETAILS) {
|
|
126
|
+
if (target === undefined || targetType === undefined)
|
|
127
|
+
return undefined;
|
|
128
|
+
return {
|
|
129
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(targetType))),
|
|
130
|
+
resolve: detailsResolver(target),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (field.type === FIELD_TYPES.MULTI_RELATION) {
|
|
134
|
+
if (target === undefined || targetType === undefined)
|
|
135
|
+
return undefined;
|
|
136
|
+
const targetDef = objects.get(target);
|
|
137
|
+
return {
|
|
138
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(targetType))),
|
|
139
|
+
resolve: multiRelationResolver(target, targetDef, field.name),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// relation / user / department
|
|
143
|
+
if (target !== undefined && targetType !== undefined) {
|
|
144
|
+
return { type: targetType, resolve: relationResolver(target, field.name) };
|
|
145
|
+
}
|
|
146
|
+
// unmodeled target (implicit identity FK) → the raw id as a string
|
|
147
|
+
return { type: GraphQLString, ...(field.description === undefined ? {} : { description: field.description }) };
|
|
148
|
+
}
|
|
149
|
+
/** the fields of one object type (scalars/enums/json + relations) + read-only `weave_id` */
|
|
150
|
+
function objectFields(def, fieldTypes, objects, objectTypes, cache) {
|
|
151
|
+
const fields = {
|
|
152
|
+
[RECORD_META_ID_FIELD]: {
|
|
153
|
+
type: new GraphQLNonNull(GraphQLID),
|
|
154
|
+
description: 'The record id (its `record_key`).',
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
for (const field of def.fields) {
|
|
158
|
+
if (isRelationLike(fieldTypes, field.type)) {
|
|
159
|
+
const rel = relationField(field, objects, objectTypes);
|
|
160
|
+
if (rel !== undefined)
|
|
161
|
+
fields[field.name] = rel;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const type = fieldType(field, fieldTypes, def.name, cache);
|
|
165
|
+
if (type === undefined)
|
|
166
|
+
continue;
|
|
167
|
+
fields[field.name] = { type, ...(field.description === undefined ? {} : { description: field.description }) };
|
|
168
|
+
}
|
|
169
|
+
return fields;
|
|
170
|
+
}
|
|
171
|
+
/** the `create`/`update` input object type for one object; undefined when it has no writable fields */
|
|
172
|
+
function inputType(kind, def, registry, objects, cache) {
|
|
173
|
+
const fields = {};
|
|
174
|
+
for (const field of def.fields) {
|
|
175
|
+
if (kind === 'Update' && field.primary === true)
|
|
176
|
+
continue; // primary keys are immutable
|
|
177
|
+
const type = inputFieldType(field, registry, def.name, objects, cache);
|
|
178
|
+
if (type === undefined)
|
|
179
|
+
continue;
|
|
180
|
+
const required = kind === 'Create' &&
|
|
181
|
+
field.required === true &&
|
|
182
|
+
field.default === undefined;
|
|
183
|
+
fields[field.name] = { type: required ? new GraphQLNonNull(type) : type };
|
|
184
|
+
}
|
|
185
|
+
if (Object.keys(fields).length === 0)
|
|
186
|
+
return undefined; // GraphQL input types need ≥1 field
|
|
187
|
+
return new GraphQLInputObjectType({ name: `${pascalCase(def.name)}${kind}Input`, fields });
|
|
188
|
+
}
|
|
189
|
+
/** compile the registry into a GraphQL schema (only the registry is needed; no data-access) */
|
|
190
|
+
export function buildGraphQLSchema(input) {
|
|
191
|
+
const registry = input.registry;
|
|
192
|
+
const fieldTypes = registry.fieldTypes;
|
|
193
|
+
const enumCache = new Map();
|
|
194
|
+
const objectTypes = new Map();
|
|
195
|
+
for (const def of registry.list()) {
|
|
196
|
+
objectTypes.set(def.name, new GraphQLObjectType({
|
|
197
|
+
name: pascalCase(def.name),
|
|
198
|
+
...(def.description === undefined ? {} : { description: def.description }),
|
|
199
|
+
fields: () => objectFields(def, fieldTypes, registry, objectTypes, enumCache),
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
const sortDir = new GraphQLEnumType({
|
|
203
|
+
name: 'SortDir',
|
|
204
|
+
values: { [SORT_DIR.ASC]: { value: SORT_DIR.ASC }, [SORT_DIR.DESC]: { value: SORT_DIR.DESC } },
|
|
205
|
+
});
|
|
206
|
+
const sortInput = new GraphQLInputObjectType({
|
|
207
|
+
name: 'SortInput',
|
|
208
|
+
fields: {
|
|
209
|
+
field: { type: new GraphQLNonNull(GraphQLString) },
|
|
210
|
+
dir: { type: new GraphQLNonNull(sortDir) },
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
const queryFields = {};
|
|
214
|
+
const mutationFields = {};
|
|
215
|
+
const extraTypes = [sortInput];
|
|
216
|
+
for (const def of registry.list()) {
|
|
217
|
+
const objectType = objectTypes.get(def.name);
|
|
218
|
+
const typeName = pascalCase(def.name);
|
|
219
|
+
queryFields[def.name] = {
|
|
220
|
+
type: new GraphQLNonNull(new GraphQLObjectType({
|
|
221
|
+
name: `${typeName}Page`,
|
|
222
|
+
fields: {
|
|
223
|
+
rows: { type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(objectType))) },
|
|
224
|
+
total: { type: new GraphQLNonNull(GraphQLInt) },
|
|
225
|
+
},
|
|
226
|
+
})),
|
|
227
|
+
description: `List \`${def.name}\` records (row-scoped by RBAC).`,
|
|
228
|
+
args: {
|
|
229
|
+
filter: { type: GraphQLJSON, description: 'filter by exact values / operators; top-level `$or` groups' },
|
|
230
|
+
sort: { type: new GraphQLList(new GraphQLNonNull(sortInput)) },
|
|
231
|
+
limit: { type: GraphQLInt },
|
|
232
|
+
offset: { type: GraphQLInt },
|
|
233
|
+
},
|
|
234
|
+
resolve: listResolver(def.name),
|
|
235
|
+
};
|
|
236
|
+
queryFields[`${def.name}_by_id`] = {
|
|
237
|
+
type: objectType,
|
|
238
|
+
description: `One \`${def.name}\` record by its \`weave_id\` (record_key).`,
|
|
239
|
+
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
|
|
240
|
+
resolve: singleResolver(def.name),
|
|
241
|
+
};
|
|
242
|
+
const createInput = inputType('Create', def, fieldTypes, registry, enumCache);
|
|
243
|
+
if (createInput !== undefined) {
|
|
244
|
+
extraTypes.push(createInput);
|
|
245
|
+
mutationFields[`create${typeName}`] = {
|
|
246
|
+
type: new GraphQLNonNull(objectType),
|
|
247
|
+
description: `Create a \`${def.name}\` record (RBAC-checked and audited).`,
|
|
248
|
+
args: { data: { type: new GraphQLNonNull(createInput) } },
|
|
249
|
+
resolve: createResolver(def.name),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const updateInput = inputType('Update', def, fieldTypes, registry, enumCache);
|
|
253
|
+
if (updateInput !== undefined) {
|
|
254
|
+
extraTypes.push(updateInput);
|
|
255
|
+
mutationFields[`update${typeName}`] = {
|
|
256
|
+
type: new GraphQLNonNull(objectType),
|
|
257
|
+
description: `Update a \`${def.name}\` record by its \`weave_id\`.`,
|
|
258
|
+
args: { id: { type: new GraphQLNonNull(GraphQLID) }, changes: { type: new GraphQLNonNull(updateInput) } },
|
|
259
|
+
resolve: updateResolver(def.name),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
mutationFields[`delete${typeName}`] = {
|
|
263
|
+
type: new GraphQLNonNull(GraphQLBoolean),
|
|
264
|
+
description: `Delete a \`${def.name}\` record by its \`weave_id\`.`,
|
|
265
|
+
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
|
|
266
|
+
resolve: deleteResolver(def.name),
|
|
267
|
+
};
|
|
268
|
+
if (def.workflow !== undefined) {
|
|
269
|
+
mutationFields[`transition${typeName}`] = {
|
|
270
|
+
type: new GraphQLNonNull(objectType),
|
|
271
|
+
description: `Run a workflow action on a \`${def.name}\` record.`,
|
|
272
|
+
args: {
|
|
273
|
+
id: { type: new GraphQLNonNull(GraphQLID) },
|
|
274
|
+
action: { type: new GraphQLNonNull(GraphQLString) },
|
|
275
|
+
payload: { type: GraphQLJSON },
|
|
276
|
+
},
|
|
277
|
+
resolve: transitionResolver(def.name),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
queryFields._objectCount = {
|
|
282
|
+
type: new GraphQLNonNull(GraphQLInt),
|
|
283
|
+
description: 'Number of objects in the schema registry.',
|
|
284
|
+
resolve: () => registry.list().length,
|
|
285
|
+
};
|
|
286
|
+
const hasObjects = registry.list().length > 0;
|
|
287
|
+
return new GraphQLSchema({
|
|
288
|
+
query: new GraphQLObjectType({ name: 'Query', fields: queryFields }),
|
|
289
|
+
...(hasObjects ? { mutation: new GraphQLObjectType({ name: 'Mutation', fields: mutationFields }) } : {}),
|
|
290
|
+
types: extraTypes,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/** SDL for the compiled schema (used by `weave graphql:schema` in a later phase). */
|
|
294
|
+
export function printGraphQLSchema(schema) {
|
|
295
|
+
return printSchema(schema);
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/adapters/graphql/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type DocumentNode, type ValidationRule } from 'graphql';
|
|
2
|
+
import { type Locale } from '../../core/index.js';
|
|
3
|
+
import type { GraphQLSecurityConfig } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Query hardening (depth / complexity / alias / introspection / allow-list).
|
|
6
|
+
* Limits are computed from the parsed document with `visit`; introspection is a
|
|
7
|
+
* validation rule; the allow list is a set of approved operation hashes loaded
|
|
8
|
+
* once at registration (see `weave graphql:allowlist` in a later phase).
|
|
9
|
+
*/
|
|
10
|
+
/** default maximum selection-set depth when the caller doesn't configure one */
|
|
11
|
+
export declare const GRAPHQL_DEFAULT_MAX_DEPTH = 10;
|
|
12
|
+
export interface ResolvedSecurity {
|
|
13
|
+
maxDepth: number;
|
|
14
|
+
maxComplexity?: number;
|
|
15
|
+
maxAliases?: number;
|
|
16
|
+
/** allow `__schema` / `__type` introspection; defaults to true */
|
|
17
|
+
introspection: boolean;
|
|
18
|
+
/** approved operation hashes (enabled → only listed operations run) */
|
|
19
|
+
allowList?: ReadonlySet<string>;
|
|
20
|
+
}
|
|
21
|
+
/** a stable content hash of an operation (the allow-list key) */
|
|
22
|
+
export declare function operationHash(document: DocumentNode): string;
|
|
23
|
+
/** apply defaults to a security config (loads the allow list once) */
|
|
24
|
+
export declare function resolveSecurity(config: GraphQLSecurityConfig | undefined): ResolvedSecurity;
|
|
25
|
+
/** validation rules for this policy (adds the no-introspection rule when disabled) */
|
|
26
|
+
export declare function validationRules(security: ResolvedSecurity): readonly ValidationRule[];
|
|
27
|
+
/** reject a document that is not allow-listed or exceeds the depth / complexity / alias limits */
|
|
28
|
+
export declare function validateQuery(document: DocumentNode, security: ResolvedSecurity, locale: Locale): void;
|
|
29
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../src/adapters/graphql/security.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,YAAY,EACjB,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;GAKG;AAEH,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,aAAa,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjC;AAED,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAE5D;AAeD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,SAAS,GAAG,gBAAgB,CAQ3F;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,cAAc,EAAE,CAErF;AAED,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAoCtG"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { NoSchemaIntrospectionCustomRule, print, specifiedRules, visit, } from 'graphql';
|
|
4
|
+
import { SchemaError } from '../../core/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Query hardening (depth / complexity / alias / introspection / allow-list).
|
|
7
|
+
* Limits are computed from the parsed document with `visit`; introspection is a
|
|
8
|
+
* validation rule; the allow list is a set of approved operation hashes loaded
|
|
9
|
+
* once at registration (see `weave graphql:allowlist` in a later phase).
|
|
10
|
+
*/
|
|
11
|
+
/** default maximum selection-set depth when the caller doesn't configure one */
|
|
12
|
+
export const GRAPHQL_DEFAULT_MAX_DEPTH = 10;
|
|
13
|
+
/** a stable content hash of an operation (the allow-list key) */
|
|
14
|
+
export function operationHash(document) {
|
|
15
|
+
return createHash('sha256').update(print(document)).digest('hex');
|
|
16
|
+
}
|
|
17
|
+
/** load the approved-operation hashes from a Git-versioned JSON file (fail loud on misconfig) */
|
|
18
|
+
function loadAllowList(file) {
|
|
19
|
+
if (file === undefined) {
|
|
20
|
+
throw new Error('graphql.security.allowList.enabled requires "file" (the Git-versioned allow-list path)');
|
|
21
|
+
}
|
|
22
|
+
const raw = JSON.parse(readFileSync(file, 'utf8'));
|
|
23
|
+
const list = Array.isArray(raw) ? raw : raw.operations;
|
|
24
|
+
if (!Array.isArray(list) || !list.every((entry) => typeof entry === 'string')) {
|
|
25
|
+
throw new Error(`graphql allow-list "${file}" must be a JSON string array or { "operations": string[] }`);
|
|
26
|
+
}
|
|
27
|
+
return new Set(list);
|
|
28
|
+
}
|
|
29
|
+
/** apply defaults to a security config (loads the allow list once) */
|
|
30
|
+
export function resolveSecurity(config) {
|
|
31
|
+
return {
|
|
32
|
+
maxDepth: config?.maxDepth ?? GRAPHQL_DEFAULT_MAX_DEPTH,
|
|
33
|
+
introspection: config?.introspection ?? true,
|
|
34
|
+
...(config?.maxComplexity === undefined ? {} : { maxComplexity: config.maxComplexity }),
|
|
35
|
+
...(config?.maxAliases === undefined ? {} : { maxAliases: config.maxAliases }),
|
|
36
|
+
...(config?.allowList?.enabled === true ? { allowList: loadAllowList(config.allowList.file) } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** validation rules for this policy (adds the no-introspection rule when disabled) */
|
|
40
|
+
export function validationRules(security) {
|
|
41
|
+
return security.introspection ? specifiedRules : [...specifiedRules, NoSchemaIntrospectionCustomRule];
|
|
42
|
+
}
|
|
43
|
+
/** reject a document that is not allow-listed or exceeds the depth / complexity / alias limits */
|
|
44
|
+
export function validateQuery(document, security, locale) {
|
|
45
|
+
if (security.allowList !== undefined && !security.allowList.has(operationHash(document))) {
|
|
46
|
+
throw new SchemaError('graphql.allowList.denied', {}, locale);
|
|
47
|
+
}
|
|
48
|
+
let depth = 0;
|
|
49
|
+
let maxDepth = 0;
|
|
50
|
+
let fields = 0;
|
|
51
|
+
let aliases = 0;
|
|
52
|
+
visit(document, {
|
|
53
|
+
SelectionSet: {
|
|
54
|
+
enter: () => {
|
|
55
|
+
depth += 1;
|
|
56
|
+
if (depth > maxDepth)
|
|
57
|
+
maxDepth = depth;
|
|
58
|
+
},
|
|
59
|
+
leave: () => {
|
|
60
|
+
depth -= 1;
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
Field: {
|
|
64
|
+
enter: (node) => {
|
|
65
|
+
fields += 1;
|
|
66
|
+
if (node.alias !== undefined)
|
|
67
|
+
aliases += 1;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
if (security.maxAliases !== undefined && aliases > security.maxAliases) {
|
|
72
|
+
throw new SchemaError('graphql.aliasExceeded', { count: aliases, max: security.maxAliases }, locale);
|
|
73
|
+
}
|
|
74
|
+
if (maxDepth > security.maxDepth) {
|
|
75
|
+
throw new SchemaError('graphql.depthExceeded', { depth: maxDepth, max: security.maxDepth }, locale);
|
|
76
|
+
}
|
|
77
|
+
if (security.maxComplexity !== undefined && fields > security.maxComplexity) {
|
|
78
|
+
throw new SchemaError('graphql.complexityExceeded', { cost: fields, max: security.maxComplexity }, locale);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../../src/adapters/graphql/security.ts"],"names":[],"mappings":"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"}
|