@powerhousedao/reactor-api 6.0.0-dev.6 → 6.0.0-dev.61
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/dist/codegen.js +1 -1
- package/dist/codegen.js.map +1 -1
- package/dist/src/config.d.ts +1 -2
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +1 -5
- package/dist/src/config.js.map +1 -1
- package/dist/src/graphql/auth/resolvers.d.ts +17 -0
- package/dist/src/graphql/auth/resolvers.d.ts.map +1 -1
- package/dist/src/graphql/auth/resolvers.js +54 -0
- package/dist/src/graphql/auth/resolvers.js.map +1 -1
- package/dist/src/graphql/auth/schema.graphql +27 -5
- package/dist/src/graphql/auth/subgraph.d.ts +25 -0
- package/dist/src/graphql/auth/subgraph.d.ts.map +1 -1
- package/dist/src/graphql/auth/subgraph.js +45 -1
- package/dist/src/graphql/auth/subgraph.js.map +1 -1
- package/dist/src/graphql/base-subgraph.d.ts +12 -3
- package/dist/src/graphql/base-subgraph.d.ts.map +1 -1
- package/dist/src/graphql/base-subgraph.js +94 -0
- package/dist/src/graphql/base-subgraph.js.map +1 -1
- package/dist/src/graphql/document-model-subgraph.d.ts +28 -43
- package/dist/src/graphql/document-model-subgraph.d.ts.map +1 -1
- package/dist/src/graphql/document-model-subgraph.js +425 -83
- package/dist/src/graphql/document-model-subgraph.js.map +1 -1
- package/dist/src/graphql/drive-subgraph.d.ts.map +1 -1
- package/dist/src/graphql/drive-subgraph.js +47 -35
- package/dist/src/graphql/drive-subgraph.js.map +1 -1
- package/dist/src/graphql/graphql-manager.d.ts +13 -5
- package/dist/src/graphql/graphql-manager.d.ts.map +1 -1
- package/dist/src/graphql/graphql-manager.js +206 -137
- package/dist/src/graphql/graphql-manager.js.map +1 -1
- package/dist/src/graphql/index.d.ts +1 -0
- package/dist/src/graphql/index.d.ts.map +1 -1
- package/dist/src/graphql/index.js +1 -0
- package/dist/src/graphql/index.js.map +1 -1
- package/dist/src/graphql/reactor/adapters.d.ts +10 -2
- package/dist/src/graphql/reactor/adapters.d.ts.map +1 -1
- package/dist/src/graphql/reactor/adapters.js +35 -1
- package/dist/src/graphql/reactor/adapters.js.map +1 -1
- package/dist/src/graphql/reactor/factory.d.ts +12 -1
- package/dist/src/graphql/reactor/factory.d.ts.map +1 -1
- package/dist/src/graphql/reactor/factory.js +1 -1
- package/dist/src/graphql/reactor/factory.js.map +1 -1
- package/dist/src/graphql/reactor/gen/graphql.d.ts +221 -76
- package/dist/src/graphql/reactor/gen/graphql.d.ts.map +1 -1
- package/dist/src/graphql/reactor/gen/graphql.js +129 -10
- package/dist/src/graphql/reactor/gen/graphql.js.map +1 -1
- package/dist/src/graphql/reactor/index.d.ts +1 -1
- package/dist/src/graphql/reactor/index.d.ts.map +1 -1
- package/dist/src/graphql/reactor/index.js +1 -1
- package/dist/src/graphql/reactor/index.js.map +1 -1
- package/dist/src/graphql/reactor/operations.graphql +84 -1
- package/dist/src/graphql/reactor/requester.with-zod.d.ts.map +1 -1
- package/dist/src/graphql/reactor/requester.with-zod.js +104 -38
- package/dist/src/graphql/reactor/requester.with-zod.js.map +1 -1
- package/dist/src/graphql/reactor/resolvers.d.ts +77 -25
- package/dist/src/graphql/reactor/resolvers.d.ts.map +1 -1
- package/dist/src/graphql/reactor/resolvers.js +164 -70
- package/dist/src/graphql/reactor/resolvers.js.map +1 -1
- package/dist/src/graphql/reactor/schema.graphql +70 -30
- package/dist/src/graphql/reactor/subgraph.d.ts +2 -31
- package/dist/src/graphql/reactor/subgraph.d.ts.map +1 -1
- package/dist/src/graphql/reactor/subgraph.js +132 -209
- package/dist/src/graphql/reactor/subgraph.js.map +1 -1
- package/dist/src/graphql/reactor/validation.d.ts +23 -5
- package/dist/src/graphql/reactor/validation.d.ts.map +1 -1
- package/dist/src/graphql/reactor/validation.js +15 -1
- package/dist/src/graphql/reactor/validation.js.map +1 -1
- package/dist/src/graphql/system/index.d.ts +0 -1
- package/dist/src/graphql/system/index.d.ts.map +1 -1
- package/dist/src/graphql/system/index.js +0 -1
- package/dist/src/graphql/system/index.js.map +1 -1
- package/dist/src/graphql/types.d.ts +6 -5
- package/dist/src/graphql/types.d.ts.map +1 -1
- package/dist/src/graphql/utils.d.ts.map +1 -1
- package/dist/src/graphql/utils.js +7 -3
- package/dist/src/graphql/utils.js.map +1 -1
- package/dist/src/migrations/002_add_document_protection.d.ts +4 -0
- package/dist/src/migrations/002_add_document_protection.d.ts.map +1 -0
- package/dist/src/migrations/002_add_document_protection.js +18 -0
- package/dist/src/migrations/002_add_document_protection.js.map +1 -0
- package/dist/src/migrations/index.d.ts.map +1 -1
- package/dist/src/migrations/index.js +2 -0
- package/dist/src/migrations/index.js.map +1 -1
- package/dist/src/packages/import-loader.d.ts +5 -3
- package/dist/src/packages/import-loader.d.ts.map +1 -1
- package/dist/src/packages/import-loader.js +19 -10
- package/dist/src/packages/import-loader.js.map +1 -1
- package/dist/src/packages/package-manager.d.ts +2 -2
- package/dist/src/packages/package-manager.d.ts.map +1 -1
- package/dist/src/packages/package-manager.js.map +1 -1
- package/dist/src/packages/types.d.ts +9 -4
- package/dist/src/packages/types.d.ts.map +1 -1
- package/dist/src/packages/util.d.ts +3 -2
- package/dist/src/packages/util.d.ts.map +1 -1
- package/dist/src/packages/util.js +1 -1
- package/dist/src/packages/util.js.map +1 -1
- package/dist/src/packages/vite-loader.d.ts +10 -8
- package/dist/src/packages/vite-loader.d.ts.map +1 -1
- package/dist/src/packages/vite-loader.js +33 -10
- package/dist/src/packages/vite-loader.js.map +1 -1
- package/dist/src/server.d.ts +18 -11
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +147 -90
- package/dist/src/server.js.map +1 -1
- package/dist/src/services/auth.service.d.ts +0 -12
- package/dist/src/services/auth.service.d.ts.map +1 -1
- package/dist/src/services/auth.service.js +13 -40
- package/dist/src/services/auth.service.js.map +1 -1
- package/dist/src/services/authorization.service.d.ts +70 -0
- package/dist/src/services/authorization.service.d.ts.map +1 -0
- package/dist/src/services/authorization.service.js +155 -0
- package/dist/src/services/authorization.service.js.map +1 -0
- package/dist/src/services/document-permission.service.d.ts +47 -7
- package/dist/src/services/document-permission.service.d.ts.map +1 -1
- package/dist/src/services/document-permission.service.js +162 -7
- package/dist/src/services/document-permission.service.js.map +1 -1
- package/dist/src/tracing.js +3 -1
- package/dist/src/tracing.js.map +1 -1
- package/dist/src/types.d.ts +5 -5
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/auth.d.ts +1 -1
- package/dist/src/utils/auth.d.ts.map +1 -1
- package/dist/src/utils/auth.js +5 -12
- package/dist/src/utils/auth.js.map +1 -1
- package/dist/src/utils/create-schema.d.ts +21 -1
- package/dist/src/utils/create-schema.d.ts.map +1 -1
- package/dist/src/utils/create-schema.js +289 -16
- package/dist/src/utils/create-schema.js.map +1 -1
- package/dist/src/utils/db.d.ts +8 -0
- package/dist/src/utils/db.d.ts.map +1 -1
- package/dist/src/utils/db.js.map +1 -1
- package/dist/src/utils/drive-url.d.ts +2 -0
- package/dist/src/utils/drive-url.d.ts.map +1 -0
- package/dist/src/utils/drive-url.js +3 -0
- package/dist/src/utils/drive-url.js.map +1 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +1 -0
- package/dist/src/utils/index.js.map +1 -1
- package/dist/test/authorization.service.test.d.ts +2 -0
- package/dist/test/authorization.service.test.d.ts.map +1 -0
- package/dist/test/authorization.service.test.js +252 -0
- package/dist/test/authorization.service.test.js.map +1 -0
- package/dist/test/connect-switchboard-reshuffle-convergence.test.d.ts +2 -0
- package/dist/test/connect-switchboard-reshuffle-convergence.test.d.ts.map +1 -0
- package/dist/test/connect-switchboard-reshuffle-convergence.test.js +203 -0
- package/dist/test/connect-switchboard-reshuffle-convergence.test.js.map +1 -0
- package/dist/test/connect-switchboard-sync.test.d.ts +2 -0
- package/dist/test/connect-switchboard-sync.test.d.ts.map +1 -0
- package/dist/test/connect-switchboard-sync.test.js +581 -0
- package/dist/test/connect-switchboard-sync.test.js.map +1 -0
- package/dist/test/document-drive-subgraph.test.d.ts +2 -0
- package/dist/test/document-drive-subgraph.test.d.ts.map +1 -0
- package/dist/test/document-drive-subgraph.test.js +186 -0
- package/dist/test/document-drive-subgraph.test.js.map +1 -0
- package/dist/test/document-model-subgraph-legacy-permissions.test.d.ts +2 -0
- package/dist/test/document-model-subgraph-legacy-permissions.test.d.ts.map +1 -0
- package/dist/test/document-model-subgraph-legacy-permissions.test.js +460 -0
- package/dist/test/document-model-subgraph-legacy-permissions.test.js.map +1 -0
- package/dist/test/document-model-subgraph-permissions.test.d.ts +2 -0
- package/dist/test/document-model-subgraph-permissions.test.d.ts.map +1 -0
- package/dist/test/document-model-subgraph-permissions.test.js +573 -0
- package/dist/test/document-model-subgraph-permissions.test.js.map +1 -0
- package/dist/test/document-model-subgraph.test.d.ts +2 -0
- package/dist/test/document-model-subgraph.test.d.ts.map +1 -0
- package/dist/test/document-model-subgraph.test.js +439 -0
- package/dist/test/document-model-subgraph.test.js.map +1 -0
- package/dist/test/drive-handlers.js +1 -1
- package/dist/test/drive-handlers.js.map +1 -1
- package/dist/test/drive-info-endpoint.test.d.ts +2 -0
- package/dist/test/drive-info-endpoint.test.d.ts.map +1 -0
- package/dist/test/drive-info-endpoint.test.js +123 -0
- package/dist/test/drive-info-endpoint.test.js.map +1 -0
- package/dist/test/drive-subgraph-permissions.test.js +1 -30
- package/dist/test/drive-subgraph-permissions.test.js.map +1 -1
- package/dist/test/permissions-integration.test.js +5 -19
- package/dist/test/permissions-integration.test.js.map +1 -1
- package/dist/test/push-backfill.test.d.ts +2 -0
- package/dist/test/push-backfill.test.d.ts.map +1 -0
- package/dist/test/push-backfill.test.js +298 -0
- package/dist/test/push-backfill.test.js.map +1 -0
- package/dist/test/reactor-client.test.js +4 -4
- package/dist/test/reactor-client.test.js.map +1 -1
- package/dist/test/reactor-resolvers.test.js +8 -11
- package/dist/test/reactor-resolvers.test.js.map +1 -1
- package/dist/test/reactor-subgraph-permissions.test.js +6 -35
- package/dist/test/reactor-subgraph-permissions.test.js.map +1 -1
- package/dist/test/subscriptions.test.js +2 -0
- package/dist/test/subscriptions.test.js.map +1 -1
- package/dist/test/utils/gql-resolver-bridge.d.ts +4 -1
- package/dist/test/utils/gql-resolver-bridge.d.ts.map +1 -1
- package/dist/test/utils/gql-resolver-bridge.js +36 -7
- package/dist/test/utils/gql-resolver-bridge.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +44 -55
- package/dist/src/graphql/system/system-subgraph.d.ts +0 -49
- package/dist/src/graphql/system/system-subgraph.d.ts.map +0 -1
- package/dist/src/graphql/system/system-subgraph.js +0 -130
- package/dist/src/graphql/system/system-subgraph.js.map +0 -1
- package/dist/test/system.test.d.ts +0 -2
- package/dist/test/system.test.d.ts.map +0 -1
- package/dist/test/system.test.js +0 -211
- package/dist/test/system.test.js.map +0 -1
- package/dist/test/three-reactor-gql-sync.test.d.ts +0 -2
- package/dist/test/three-reactor-gql-sync.test.d.ts.map +0 -1
- package/dist/test/three-reactor-gql-sync.test.js +0 -368
- package/dist/test/three-reactor-gql-sync.test.js.map +0 -1
- package/dist/test/two-reactor-gql-sync.test.d.ts +0 -2
- package/dist/test/two-reactor-gql-sync.test.d.ts.map +0 -1
- package/dist/test/two-reactor-gql-sync.test.js +0 -348
- package/dist/test/two-reactor-gql-sync.test.js.map +0 -1
|
@@ -1,51 +1,36 @@
|
|
|
1
|
-
import { type IDocumentDriveServer } from "document-drive";
|
|
2
1
|
import { type DocumentModelModule } from "document-model";
|
|
3
2
|
import { BaseSubgraph } from "./base-subgraph.js";
|
|
4
3
|
import type { SubgraphArgs } from "./types.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
id: string;
|
|
30
|
-
name: string;
|
|
31
|
-
documentType: string;
|
|
32
|
-
revision: number;
|
|
33
|
-
createdAtUtcIso: string;
|
|
34
|
-
lastModifiedAtUtcIso: string;
|
|
35
|
-
operations: import("./types.js").GqlOperation[];
|
|
36
|
-
stateJSON: JSON;
|
|
37
|
-
state: unknown;
|
|
38
|
-
initialState: unknown;
|
|
39
|
-
driveId: string;
|
|
40
|
-
}[]>;
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
Mutation: {
|
|
44
|
-
[x: string]: any;
|
|
45
|
-
};
|
|
46
|
-
};
|
|
4
|
+
/**
|
|
5
|
+
* New document model subgraph that uses reactorClient instead of legacy reactor.
|
|
6
|
+
* This class auto-generates GraphQL queries and mutations for a document model.
|
|
7
|
+
*/
|
|
8
|
+
export declare class DocumentModelSubgraph extends BaseSubgraph {
|
|
9
|
+
private documentModel;
|
|
10
|
+
constructor(documentModel: DocumentModelModule, args: SubgraphArgs);
|
|
11
|
+
/**
|
|
12
|
+
* Generate __resolveType functions for union types found in the document model schema.
|
|
13
|
+
* Parses the state schema to find union definitions and their member types,
|
|
14
|
+
* then uses unique field presence to discriminate between member types at runtime.
|
|
15
|
+
*/
|
|
16
|
+
private generateUnionResolvers;
|
|
17
|
+
/**
|
|
18
|
+
* Generate resolvers for this document model using reactorClient
|
|
19
|
+
* Uses flat queries (not nested) consistent with ReactorSubgraph patterns
|
|
20
|
+
*/
|
|
21
|
+
private generateResolvers;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Use `DocumentModelSubgraph` instead. This class uses the legacy `reactor` (IDocumentDriveServer)
|
|
25
|
+
* interface. The new `DocumentModelSubgraph` class uses `reactorClient` (IReactorClient) which provides
|
|
26
|
+
* better patterns and more capabilities. Enable via `useNewDocumentModelSubgraph: true` in GraphQLManager.
|
|
27
|
+
*/
|
|
47
28
|
export declare class DocumentModelSubgraphLegacy extends BaseSubgraph {
|
|
48
29
|
private documentModel;
|
|
49
30
|
constructor(documentModel: DocumentModelModule, args: SubgraphArgs);
|
|
31
|
+
/**
|
|
32
|
+
* Generate resolvers for this document model with permission checks
|
|
33
|
+
*/
|
|
34
|
+
private generateResolvers;
|
|
50
35
|
}
|
|
51
36
|
//# sourceMappingURL=document-model-subgraph.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-model-subgraph.d.ts","sourceRoot":"","sources":["../../../src/graphql/document-model-subgraph.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"document-model-subgraph.d.ts","sourceRoot":"","sources":["../../../src/graphql/document-model-subgraph.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAMnE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AASlD,OAAO,KAAK,EAAW,YAAY,EAAE,MAAM,YAAY,CAAC;AAGxD;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,YAAY;IACrD,OAAO,CAAC,aAAa,CAAsB;gBAE/B,aAAa,EAAE,mBAAmB,EAAE,IAAI,EAAE,YAAY;IAWlE;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAuE9B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CA0V1B;AAED;;;;GAIG;AACH,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D,OAAO,CAAC,aAAa,CAAsB;gBAE/B,aAAa,EAAE,mBAAmB,EAAE,IAAI,EAAE,YAAY;IAUlE;;OAEG;IACH,OAAO,CAAC,iBAAiB;CA2L1B"}
|
|
@@ -1,104 +1,446 @@
|
|
|
1
1
|
import { camelCase, kebabCase } from "change-case";
|
|
2
2
|
import { addFile } from "document-drive";
|
|
3
3
|
import { setName } from "document-model";
|
|
4
|
-
import {
|
|
4
|
+
import { GraphQLError, Kind, parse } from "graphql";
|
|
5
|
+
import { generateDocumentModelSchema, getDocumentModelSchemaName, } from "../utils/create-schema.js";
|
|
5
6
|
import { BaseSubgraph } from "./base-subgraph.js";
|
|
7
|
+
import { toGqlPhDocument } from "./reactor/adapters.js";
|
|
8
|
+
import { createEmptyDocument as createEmptyDocumentResolver, documentChildren as documentChildrenResolver, documentParents as documentParentsResolver, document as documentResolver, findDocuments as findDocumentsResolver, } from "./reactor/resolvers.js";
|
|
6
9
|
import { buildGraphQlDocument } from "./utils.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
10
|
+
/**
|
|
11
|
+
* New document model subgraph that uses reactorClient instead of legacy reactor.
|
|
12
|
+
* This class auto-generates GraphQL queries and mutations for a document model.
|
|
13
|
+
*/
|
|
14
|
+
export class DocumentModelSubgraph extends BaseSubgraph {
|
|
15
|
+
documentModel;
|
|
16
|
+
constructor(documentModel, args) {
|
|
17
|
+
super(args);
|
|
18
|
+
this.documentModel = documentModel;
|
|
19
|
+
this.name = kebabCase(documentModel.documentModel.global.name);
|
|
20
|
+
this.typeDefs = generateDocumentModelSchema(this.documentModel.documentModel.global, { useNewApi: true });
|
|
21
|
+
this.resolvers = this.generateResolvers();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate __resolveType functions for union types found in the document model schema.
|
|
25
|
+
* Parses the state schema to find union definitions and their member types,
|
|
26
|
+
* then uses unique field presence to discriminate between member types at runtime.
|
|
27
|
+
*/
|
|
28
|
+
generateUnionResolvers() {
|
|
29
|
+
const documentName = getDocumentModelSchemaName(this.documentModel.documentModel.global);
|
|
30
|
+
const specification = this.documentModel.documentModel.global.specifications.at(-1);
|
|
31
|
+
if (!specification)
|
|
32
|
+
return {};
|
|
33
|
+
const globalSchema = specification.state.global.schema ?? "";
|
|
34
|
+
const localSchema = specification.state.local.schema ?? "";
|
|
35
|
+
const fullSchema = `${globalSchema}\n${localSchema}`;
|
|
36
|
+
if (!fullSchema.trim())
|
|
37
|
+
return {};
|
|
38
|
+
let ast;
|
|
39
|
+
try {
|
|
40
|
+
ast = parse(fullSchema);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
// Build map: object type name -> field names
|
|
46
|
+
const objectFieldsMap = new Map();
|
|
47
|
+
for (const def of ast.definitions) {
|
|
48
|
+
if (def.kind === Kind.OBJECT_TYPE_DEFINITION) {
|
|
49
|
+
objectFieldsMap.set(def.name.value, def.fields?.map((f) => f.name.value) ?? []);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const resolvers = {};
|
|
53
|
+
for (const def of ast.definitions) {
|
|
54
|
+
if (def.kind !== Kind.UNION_TYPE_DEFINITION)
|
|
55
|
+
continue;
|
|
56
|
+
const unionName = def.name.value;
|
|
57
|
+
const memberTypes = def.types?.map((t) => t.name.value) ?? [];
|
|
58
|
+
if (memberTypes.length === 0)
|
|
59
|
+
continue;
|
|
60
|
+
// Compute unique fields per member type
|
|
61
|
+
const uniqueFields = {};
|
|
62
|
+
for (const memberType of memberTypes) {
|
|
63
|
+
const ownFields = objectFieldsMap.get(memberType) ?? [];
|
|
64
|
+
const otherFields = new Set(memberTypes
|
|
65
|
+
.filter((t) => t !== memberType)
|
|
66
|
+
.flatMap((t) => objectFieldsMap.get(t) ?? []));
|
|
67
|
+
uniqueFields[memberType] = ownFields.filter((f) => !otherFields.has(f));
|
|
68
|
+
}
|
|
69
|
+
const prefixedUnionName = `${documentName}_${unionName}`;
|
|
70
|
+
resolvers[prefixedUnionName] = {
|
|
71
|
+
__resolveType: (obj) => {
|
|
72
|
+
for (const memberType of memberTypes) {
|
|
73
|
+
const fields = uniqueFields[memberType] ?? [];
|
|
74
|
+
if (fields.length > 0 && fields.some((f) => f in obj)) {
|
|
75
|
+
return `${documentName}_${memberType}`;
|
|
27
76
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
77
|
+
}
|
|
78
|
+
return `${documentName}_${memberTypes[0]}`;
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return resolvers;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Generate resolvers for this document model using reactorClient
|
|
86
|
+
* Uses flat queries (not nested) consistent with ReactorSubgraph patterns
|
|
87
|
+
*/
|
|
88
|
+
generateResolvers() {
|
|
89
|
+
const documentType = this.documentModel.documentModel.global.id;
|
|
90
|
+
const documentName = getDocumentModelSchemaName(this.documentModel.documentModel.global);
|
|
91
|
+
const operations = this.documentModel.documentModel.global.specifications
|
|
92
|
+
.at(-1)
|
|
93
|
+
?.modules.flatMap((module) => module.operations.filter((op) => op.name)) ?? [];
|
|
94
|
+
return {
|
|
95
|
+
...this.generateUnionResolvers(),
|
|
96
|
+
Query: {
|
|
97
|
+
// Flat query: Get a specific document by identifier
|
|
98
|
+
// Uses shared documentResolver from reactor/resolvers.ts
|
|
99
|
+
[`${documentName}_document`]: async (_, args, ctx) => {
|
|
100
|
+
const { identifier, view } = args;
|
|
101
|
+
if (!identifier) {
|
|
102
|
+
throw new GraphQLError("Document identifier is required");
|
|
103
|
+
}
|
|
104
|
+
// Use shared resolver function
|
|
105
|
+
const result = await documentResolver(this.reactorClient, {
|
|
106
|
+
identifier,
|
|
107
|
+
view,
|
|
108
|
+
});
|
|
109
|
+
// Validate document type
|
|
110
|
+
if (result.document.documentType !== documentType) {
|
|
111
|
+
throw new GraphQLError(`Document with id ${identifier} is not of type ${documentType}`);
|
|
112
|
+
}
|
|
113
|
+
// Check permissions
|
|
114
|
+
await this.assertCanRead(result.document.id, ctx);
|
|
115
|
+
// Return shared resolver result directly (matches PHDocument format)
|
|
116
|
+
return result;
|
|
117
|
+
},
|
|
118
|
+
// Flat query: Find documents by search criteria (type is built-in)
|
|
119
|
+
// Uses shared findDocumentsResolver from reactor/resolvers.ts
|
|
120
|
+
[`${documentName}_findDocuments`]: async (_, args, ctx) => {
|
|
121
|
+
const { search, view, paging } = args;
|
|
122
|
+
// Use shared resolver function with built-in type filter
|
|
123
|
+
const result = await findDocumentsResolver(this.reactorClient, {
|
|
124
|
+
search: {
|
|
125
|
+
type: documentType, // Type is built-in for this document model subgraph
|
|
126
|
+
parentId: search.parentId,
|
|
127
|
+
},
|
|
128
|
+
view,
|
|
129
|
+
paging,
|
|
130
|
+
});
|
|
131
|
+
// Filter by permission if needed
|
|
132
|
+
if (!this.hasGlobalAdminAccess(ctx) &&
|
|
133
|
+
this.documentPermissionService) {
|
|
134
|
+
const filteredItems = [];
|
|
135
|
+
for (const item of result.items) {
|
|
136
|
+
const canRead = await this.canReadDocument(item.id, ctx);
|
|
137
|
+
if (canRead) {
|
|
138
|
+
filteredItems.push(item);
|
|
139
|
+
}
|
|
31
140
|
}
|
|
32
141
|
return {
|
|
33
|
-
|
|
34
|
-
|
|
142
|
+
...result,
|
|
143
|
+
items: filteredItems,
|
|
144
|
+
totalCount: filteredItems.length,
|
|
35
145
|
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
146
|
+
}
|
|
147
|
+
// Return shared resolver result directly (matches PHDocument format)
|
|
148
|
+
return result;
|
|
149
|
+
},
|
|
150
|
+
// Flat query: Get children of a document (filtered by this document type)
|
|
151
|
+
// Uses shared documentChildrenResolver from reactor/resolvers.ts
|
|
152
|
+
[`${documentName}_documentChildren`]: async (_, args, ctx) => {
|
|
153
|
+
const { parentIdentifier, view, paging } = args;
|
|
154
|
+
await this.assertCanRead(parentIdentifier, ctx);
|
|
155
|
+
// Use shared resolver function
|
|
156
|
+
const result = await documentChildrenResolver(this.reactorClient, {
|
|
157
|
+
parentIdentifier,
|
|
158
|
+
view,
|
|
159
|
+
paging,
|
|
160
|
+
});
|
|
161
|
+
// Filter children by this document type
|
|
162
|
+
const filteredItems = result.items.filter((item) => item.documentType === documentType);
|
|
163
|
+
return {
|
|
164
|
+
...result,
|
|
165
|
+
items: filteredItems,
|
|
166
|
+
totalCount: filteredItems.length,
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
// Flat query: Get parents of a document
|
|
170
|
+
// Uses shared documentParentsResolver from reactor/resolvers.ts
|
|
171
|
+
[`${documentName}_documentParents`]: async (_, args, ctx) => {
|
|
172
|
+
const { childIdentifier, view, paging } = args;
|
|
173
|
+
await this.assertCanRead(childIdentifier, ctx);
|
|
174
|
+
// Use shared resolver function - return directly
|
|
175
|
+
return documentParentsResolver(this.reactorClient, {
|
|
176
|
+
childIdentifier,
|
|
177
|
+
view,
|
|
178
|
+
paging,
|
|
179
|
+
});
|
|
180
|
+
},
|
|
50
181
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
182
|
+
Mutation: {
|
|
183
|
+
// Uses shared createEmptyDocumentResolver from reactor/resolvers.ts
|
|
184
|
+
[`${documentName}_createDocument`]: async (_, args, ctx) => {
|
|
185
|
+
const { parentIdentifier, name } = args;
|
|
186
|
+
if (parentIdentifier) {
|
|
187
|
+
await this.assertCanWrite(parentIdentifier, ctx);
|
|
188
|
+
}
|
|
189
|
+
else if (this.authorizationService) {
|
|
190
|
+
if (!ctx.user?.address) {
|
|
191
|
+
throw new GraphQLError("Forbidden: authentication required to create documents");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else if (!this.hasGlobalAdminAccess(ctx)) {
|
|
195
|
+
throw new GraphQLError("Forbidden: insufficient permissions to create documents");
|
|
196
|
+
}
|
|
197
|
+
// Use shared resolver function - returns PHDocument format
|
|
198
|
+
const createdDoc = await createEmptyDocumentResolver(this.reactorClient, {
|
|
199
|
+
documentType,
|
|
200
|
+
parentIdentifier,
|
|
201
|
+
});
|
|
202
|
+
// Auto-ownership: set creator as document owner
|
|
203
|
+
if (this.authorizationService &&
|
|
204
|
+
ctx.user?.address &&
|
|
205
|
+
createdDoc?.id) {
|
|
206
|
+
await this.documentPermissionService?.initializeDocumentProtection(createdDoc.id, ctx.user.address, this.authorizationService.config.defaultProtection);
|
|
207
|
+
}
|
|
208
|
+
if (name) {
|
|
209
|
+
const updatedDoc = await this.reactorClient.execute(createdDoc.id, "main", [setName(name)]);
|
|
210
|
+
// Use toGqlPhDocument for PHDocument format with revisionsList
|
|
211
|
+
return toGqlPhDocument(updatedDoc);
|
|
212
|
+
}
|
|
213
|
+
// Return directly - already in PHDocument format
|
|
214
|
+
return createdDoc;
|
|
215
|
+
},
|
|
216
|
+
// Uses shared createEmptyDocumentResolver from reactor/resolvers.ts
|
|
217
|
+
[`${documentName}_createEmptyDocument`]: async (_, args, ctx) => {
|
|
218
|
+
const { parentIdentifier } = args;
|
|
219
|
+
if (parentIdentifier) {
|
|
220
|
+
await this.assertCanWrite(parentIdentifier, ctx);
|
|
221
|
+
}
|
|
222
|
+
else if (this.authorizationService) {
|
|
223
|
+
if (!ctx.user?.address) {
|
|
224
|
+
throw new GraphQLError("Forbidden: authentication required to create documents");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (!this.hasGlobalAdminAccess(ctx)) {
|
|
228
|
+
throw new GraphQLError("Forbidden: insufficient permissions to create documents");
|
|
229
|
+
}
|
|
230
|
+
// Use shared resolver function - returns PHDocument format directly
|
|
231
|
+
const result = await createEmptyDocumentResolver(this.reactorClient, {
|
|
232
|
+
documentType,
|
|
233
|
+
parentIdentifier,
|
|
234
|
+
});
|
|
235
|
+
// Auto-ownership: set creator as document owner
|
|
236
|
+
if (this.authorizationService && ctx.user?.address && result?.id) {
|
|
237
|
+
await this.documentPermissionService?.initializeDocumentProtection(result.id, ctx.user.address, this.authorizationService.config.defaultProtection);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
},
|
|
241
|
+
// Generate sync and async mutations for each operation
|
|
242
|
+
...operations.reduce((mutations, op) => {
|
|
243
|
+
// Sync mutation
|
|
244
|
+
mutations[`${documentName}_${camelCase(op.name)}`] = async (_, args, ctx) => {
|
|
245
|
+
const { docId, input } = args;
|
|
246
|
+
// assertCanExecuteOperation uses canMutate (write + operation) when
|
|
247
|
+
// authorizationService is available. Legacy fallback needs separate write check.
|
|
248
|
+
if (!this.authorizationService) {
|
|
249
|
+
await this.assertCanWrite(docId, ctx);
|
|
250
|
+
}
|
|
251
|
+
await this.assertCanExecuteOperation(docId, op.name, ctx);
|
|
252
|
+
const doc = await this.reactorClient.get(docId);
|
|
253
|
+
if (doc.header.documentType !== documentType) {
|
|
254
|
+
throw new GraphQLError(`Document with id ${docId} is not of type ${documentType}`);
|
|
255
|
+
}
|
|
256
|
+
const action = this.documentModel.actions[camelCase(op.name)];
|
|
257
|
+
if (!action) {
|
|
258
|
+
throw new GraphQLError(`Action ${op.name} not found`);
|
|
259
|
+
}
|
|
260
|
+
try {
|
|
261
|
+
const updatedDoc = await this.reactorClient.execute(docId, "main", [action(input)]);
|
|
262
|
+
// Use toGqlPhDocument for PHDocument format with revisionsList
|
|
263
|
+
return toGqlPhDocument(updatedDoc);
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
throw new GraphQLError(error instanceof Error
|
|
267
|
+
? error.message
|
|
268
|
+
: `Failed to ${op.name}`);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
// Async mutation - returns job ID
|
|
272
|
+
mutations[`${documentName}_${camelCase(op.name)}Async`] = async (_, args, ctx) => {
|
|
273
|
+
const { docId, input } = args;
|
|
274
|
+
if (!this.authorizationService) {
|
|
275
|
+
await this.assertCanWrite(docId, ctx);
|
|
276
|
+
}
|
|
277
|
+
await this.assertCanExecuteOperation(docId, op.name, ctx);
|
|
278
|
+
const doc = await this.reactorClient.get(docId);
|
|
279
|
+
if (doc.header.documentType !== documentType) {
|
|
280
|
+
throw new GraphQLError(`Document with id ${docId} is not of type ${documentType}`);
|
|
281
|
+
}
|
|
282
|
+
const action = this.documentModel.actions[camelCase(op.name)];
|
|
283
|
+
if (!action) {
|
|
284
|
+
throw new GraphQLError(`Action ${op.name} not found`);
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
const jobInfo = await this.reactorClient.executeAsync(docId, "main", [action(input)]);
|
|
288
|
+
return jobInfo.id;
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
throw new GraphQLError(error instanceof Error
|
|
292
|
+
? error.message
|
|
293
|
+
: `Failed to ${op.name}`);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
return mutations;
|
|
297
|
+
}, {}),
|
|
67
298
|
},
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const { docId, input } = args;
|
|
71
|
-
const doc = await reactor.getDocument(docId);
|
|
72
|
-
if (!doc) {
|
|
73
|
-
throw new Error("Document not found");
|
|
74
|
-
}
|
|
75
|
-
const action = documentModel.actions[camelCase(op.name)];
|
|
76
|
-
if (!action) {
|
|
77
|
-
throw new Error(`Action ${op.name} not found`);
|
|
78
|
-
}
|
|
79
|
-
const result = await reactor.addAction(docId, action(input));
|
|
80
|
-
if (result.status !== "SUCCESS") {
|
|
81
|
-
throw new Error(result.error?.message ?? `Failed to ${op.name}`);
|
|
82
|
-
}
|
|
83
|
-
const errorOp = result.operations.find((op) => op.error);
|
|
84
|
-
if (errorOp) {
|
|
85
|
-
throw new Error(errorOp.error);
|
|
86
|
-
}
|
|
87
|
-
return result.operations.at(-1)?.index ?? -1;
|
|
88
|
-
};
|
|
89
|
-
return mutations;
|
|
90
|
-
}, {}),
|
|
91
|
-
},
|
|
92
|
-
};
|
|
299
|
+
};
|
|
300
|
+
}
|
|
93
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* @deprecated Use `DocumentModelSubgraph` instead. This class uses the legacy `reactor` (IDocumentDriveServer)
|
|
304
|
+
* interface. The new `DocumentModelSubgraph` class uses `reactorClient` (IReactorClient) which provides
|
|
305
|
+
* better patterns and more capabilities. Enable via `useNewDocumentModelSubgraph: true` in GraphQLManager.
|
|
306
|
+
*/
|
|
94
307
|
export class DocumentModelSubgraphLegacy extends BaseSubgraph {
|
|
95
308
|
documentModel;
|
|
96
309
|
constructor(documentModel, args) {
|
|
97
310
|
super(args);
|
|
98
311
|
this.documentModel = documentModel;
|
|
99
312
|
this.name = kebabCase(documentModel.documentModel.global.name);
|
|
100
|
-
this.typeDefs =
|
|
101
|
-
this.resolvers =
|
|
313
|
+
this.typeDefs = generateDocumentModelSchema(this.documentModel.documentModel.global);
|
|
314
|
+
this.resolvers = this.generateResolvers();
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Generate resolvers for this document model with permission checks
|
|
318
|
+
*/
|
|
319
|
+
generateResolvers() {
|
|
320
|
+
const documentType = this.documentModel.documentModel.global.id;
|
|
321
|
+
const documentName = getDocumentModelSchemaName(this.documentModel.documentModel.global);
|
|
322
|
+
const operations = this.documentModel.documentModel.global.specifications
|
|
323
|
+
.at(-1)
|
|
324
|
+
?.modules.flatMap((module) => module.operations.filter((op) => op.name)) ?? [];
|
|
325
|
+
return {
|
|
326
|
+
Query: {
|
|
327
|
+
[documentName]: (_, __, ctx) => {
|
|
328
|
+
return {
|
|
329
|
+
getDocument: async (args) => {
|
|
330
|
+
const { docId, driveId } = args;
|
|
331
|
+
if (!docId) {
|
|
332
|
+
throw new Error("Document id is required");
|
|
333
|
+
}
|
|
334
|
+
// Check read permission before accessing document
|
|
335
|
+
await this.assertCanRead(docId, ctx);
|
|
336
|
+
if (driveId) {
|
|
337
|
+
const docIds = await this.reactor.getDocuments(driveId);
|
|
338
|
+
if (!docIds.includes(docId)) {
|
|
339
|
+
throw new Error(`Document with id ${docId} is not part of ${driveId}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const doc = await this.reactor.getDocument(docId);
|
|
343
|
+
if (doc.header.documentType !== documentType) {
|
|
344
|
+
throw new Error(`Document with id ${docId} is not of type ${documentType}`);
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
driveId: driveId,
|
|
348
|
+
...buildGraphQlDocument(doc),
|
|
349
|
+
};
|
|
350
|
+
},
|
|
351
|
+
getDocuments: async (args) => {
|
|
352
|
+
const { driveId } = args;
|
|
353
|
+
// Check read permission on drive before listing documents
|
|
354
|
+
await this.assertCanRead(driveId, ctx);
|
|
355
|
+
const docsIds = await this.reactor.getDocuments(driveId);
|
|
356
|
+
const docs = await Promise.all(docsIds.map(async (docId) => {
|
|
357
|
+
const doc = await this.reactor.getDocument(docId);
|
|
358
|
+
return {
|
|
359
|
+
driveId: driveId,
|
|
360
|
+
...buildGraphQlDocument(doc),
|
|
361
|
+
};
|
|
362
|
+
}));
|
|
363
|
+
const filteredByType = docs.filter((doc) => doc.documentType === documentType);
|
|
364
|
+
// If user doesn't have global read access, filter by document-level permissions
|
|
365
|
+
if (!this.hasGlobalAdminAccess(ctx) &&
|
|
366
|
+
this.documentPermissionService) {
|
|
367
|
+
const filteredDocs = [];
|
|
368
|
+
for (const doc of filteredByType) {
|
|
369
|
+
const canRead = await this.canReadDocument(doc.id, ctx);
|
|
370
|
+
if (canRead) {
|
|
371
|
+
filteredDocs.push(doc);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return filteredDocs;
|
|
375
|
+
}
|
|
376
|
+
return filteredByType;
|
|
377
|
+
},
|
|
378
|
+
};
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
Mutation: {
|
|
382
|
+
[`${documentName}_createDocument`]: async (_, args, ctx) => {
|
|
383
|
+
const { driveId, name } = args;
|
|
384
|
+
// If creating under a drive, check write permission on drive
|
|
385
|
+
if (driveId) {
|
|
386
|
+
await this.assertCanWrite(driveId, ctx);
|
|
387
|
+
}
|
|
388
|
+
else if (this.authorizationService) {
|
|
389
|
+
if (!ctx.user?.address) {
|
|
390
|
+
throw new GraphQLError("Forbidden: authentication required to create documents");
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
else if (!this.hasGlobalAdminAccess(ctx)) {
|
|
394
|
+
throw new GraphQLError("Forbidden: insufficient permissions to create documents");
|
|
395
|
+
}
|
|
396
|
+
const document = await this.reactor.addDocument(documentType);
|
|
397
|
+
if (driveId) {
|
|
398
|
+
await this.reactor.addAction(driveId, addFile({
|
|
399
|
+
name,
|
|
400
|
+
id: document.header.id,
|
|
401
|
+
documentType: documentType,
|
|
402
|
+
}));
|
|
403
|
+
}
|
|
404
|
+
if (name) {
|
|
405
|
+
await this.reactor.addAction(document.header.id, setName(name));
|
|
406
|
+
}
|
|
407
|
+
// Auto-ownership: set creator as document owner
|
|
408
|
+
if (this.authorizationService && ctx.user?.address) {
|
|
409
|
+
await this.documentPermissionService?.initializeDocumentProtection(document.header.id, ctx.user.address, this.authorizationService.config.defaultProtection);
|
|
410
|
+
}
|
|
411
|
+
return document.header.id;
|
|
412
|
+
},
|
|
413
|
+
...operations.reduce((mutations, op) => {
|
|
414
|
+
mutations[`${documentName}_${camelCase(op.name)}`] = async (_, args, ctx) => {
|
|
415
|
+
const { docId, input } = args;
|
|
416
|
+
// assertCanExecuteOperation uses canMutate (write + operation) when
|
|
417
|
+
// authorizationService is available. Legacy fallback needs separate write check.
|
|
418
|
+
if (!this.authorizationService) {
|
|
419
|
+
await this.assertCanWrite(docId, ctx);
|
|
420
|
+
}
|
|
421
|
+
await this.assertCanExecuteOperation(docId, op.name, ctx);
|
|
422
|
+
const doc = await this.reactor.getDocument(docId);
|
|
423
|
+
if (!doc) {
|
|
424
|
+
throw new Error("Document not found");
|
|
425
|
+
}
|
|
426
|
+
const action = this.documentModel.actions[camelCase(op.name)];
|
|
427
|
+
if (!action) {
|
|
428
|
+
throw new Error(`Action ${op.name} not found`);
|
|
429
|
+
}
|
|
430
|
+
const result = await this.reactor.addAction(docId, action(input));
|
|
431
|
+
if (result.status !== "SUCCESS") {
|
|
432
|
+
throw new Error(result.error?.message ?? `Failed to ${op.name}`);
|
|
433
|
+
}
|
|
434
|
+
const errorOp = result.operations.find((op) => op.error);
|
|
435
|
+
if (errorOp) {
|
|
436
|
+
throw new Error(errorOp.error);
|
|
437
|
+
}
|
|
438
|
+
return result.operations.at(-1)?.index ?? -1;
|
|
439
|
+
};
|
|
440
|
+
return mutations;
|
|
441
|
+
}, {}),
|
|
442
|
+
},
|
|
443
|
+
};
|
|
102
444
|
}
|
|
103
445
|
}
|
|
104
446
|
//# sourceMappingURL=document-model-subgraph.js.map
|