@powerhousedao/reactor-api 6.2.3-dev.24 → 6.2.3-dev.26
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/{adapter-gateway-apollo-CxJNBVyD.mjs → adapter-gateway-apollo-B54G_cXT.mjs} +15 -13
- package/dist/{adapter-gateway-apollo-CxJNBVyD.mjs.map → adapter-gateway-apollo-B54G_cXT.mjs.map} +1 -1
- package/dist/{adapter-gateway-apollo-DowrX6E_.mjs → adapter-gateway-apollo-D2DNlPY0.mjs} +3 -3
- package/dist/{adapter-gateway-mercurius-CZVy88Za.mjs → adapter-gateway-mercurius-rbKlwF9m.mjs} +4 -4
- package/dist/{adapter-gateway-mercurius-CZVy88Za.mjs.map → adapter-gateway-mercurius-rbKlwF9m.mjs.map} +1 -1
- package/dist/{adapter-gateway-stitching-CaZjvRzx.mjs → adapter-gateway-stitching-Dzv10u8D.mjs} +15 -10
- package/dist/{adapter-gateway-stitching-CaZjvRzx.mjs.map → adapter-gateway-stitching-Dzv10u8D.mjs.map} +1 -1
- package/dist/{adapter-http-express-D4KBmDcQ.mjs → adapter-http-express-CWqziB1p.mjs} +6 -6
- package/dist/adapter-http-express-CWqziB1p.mjs.map +1 -0
- package/dist/{adapter-http-fastify-U9j7HxQE.mjs → adapter-http-fastify-CYZQ6FFv.mjs} +8 -7
- package/dist/adapter-http-fastify-CYZQ6FFv.mjs.map +1 -0
- package/dist/index.d.mts +609 -489
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +467 -235
- package/dist/index.mjs.map +1 -1
- package/dist/{pieces-eqj2RKgd.mjs → pieces-DMQotfIR.mjs} +27 -8
- package/dist/pieces-DMQotfIR.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +15 -0
- package/dist/{run-node-handler-Bqn0X6bT.mjs → run-node-handler-CQjyjOuN.mjs} +3 -3
- package/dist/{run-node-handler-Bqn0X6bT.mjs.map → run-node-handler-CQjyjOuN.mjs.map} +1 -1
- package/dist/src/packages/https-hooks.d.mts +4 -4
- package/dist/src/packages/https-hooks.d.mts.map +1 -1
- package/dist/src/packages/https-hooks.mjs +2 -2
- package/dist/src/packages/https-hooks.mjs.map +1 -1
- package/dist/src/packages/vite-loader.d.mts +5 -6
- package/dist/src/packages/vite-loader.d.mts.map +1 -1
- package/dist/src/packages/vite-loader.mjs +9 -6
- package/dist/src/packages/vite-loader.mjs.map +1 -1
- package/dist/{types-BXjLvTe3.d.mts → types-D4Qnqo_D.d.mts} +2 -2
- package/dist/types-D4Qnqo_D.d.mts.map +1 -0
- package/dist/{websocket-DncAB9XK.mjs → websocket-_SH5aBcy.mjs} +3 -3
- package/dist/{websocket-DncAB9XK.mjs.map → websocket-_SH5aBcy.mjs.map} +1 -1
- package/package.json +16 -16
- package/dist/adapter-http-express-D4KBmDcQ.mjs.map +0 -1
- package/dist/adapter-http-fastify-U9j7HxQE.mjs.map +0 -1
- package/dist/pieces-eqj2RKgd.mjs.map +0 -1
- package/dist/types-BXjLvTe3.d.mts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
-
import {
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8ab62893-8127-51eb-9d6f-a5900b1823de")}catch(e){}}();
|
|
3
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
4
|
+
import { C as AuthorizedDocumentHandle, D as ForbiddenError, E as AuthenticationRequiredError, O as MalformedStoredOperationError, S as AuthorizationPolicy, T as AuthEvaluationUnsupportedError, _ as loadSubgraphs, a as piecesFromCdnList, b as CanonicalDocumentIdResolutionError, c as buildGraphQlDriveDocument, d as isSubgraphClass, f as debounce, g as loadProcessors, h as loadDocumentModels, i as pieceListLocation, l as buildGraphqlOperation, o as piecesFromListModule, p as extractUpgradeManifests, r as PIECE_SOURCE_LIST, s as buildGraphQlDocument, u as buildGraphqlOperations, v as BaseSubgraph, w as createAuthorizationService, x as createCanonicalDocumentIdResolver, y as callerSubject } from "./pieces-DMQotfIR.mjs";
|
|
4
5
|
import { AnalyticsQueryEngine } from "@powerhousedao/analytics-engine-core";
|
|
5
6
|
import { AnalyticsModel, AnalyticsResolvers, typedefs } from "@powerhousedao/analytics-engine-graphql";
|
|
6
7
|
import { gql } from "graphql-tag";
|
|
7
8
|
import { GraphQLError, Kind, parse, print } from "graphql";
|
|
8
|
-
import { AuthEnforcementDisabledError, DEFAULT_DRIVE_CONTAINER_TYPES, DriveCollectionId, ModelReadGate, PropagationMode as PropagationMode$1, SyncScopeGate, consolidateSyncOperations, createReactorHostModuleBase, driveIdFromUrl, envelopesToSyncOperations, parseDriveUrl, readDecisionModel, syncOperationErrorType } from "@powerhousedao/reactor";
|
|
9
|
+
import { AuthEnforcementDisabledError, BareReadGate, DEFAULT_DRIVE_CONTAINER_TYPES, DriveCollectionId, JobStatus, ModelReadGate, PropagationMode as PropagationMode$1, SyncScopeGate, consolidateSyncOperations, createReactorHostModuleBase, driveIdFromUrl, envelopesToSyncOperations, parseDriveUrl, readDecisionModel, syncOperationErrorType } from "@powerhousedao/reactor";
|
|
9
10
|
import { ConsoleLogger, childLogger, documentModelDocumentModelModule } from "document-model";
|
|
10
11
|
import path, { isAbsolute, join } from "node:path";
|
|
11
12
|
import { match } from "path-to-regexp";
|
|
@@ -47,19 +48,8 @@ import { AtomicNodeFs } from "@powerhousedao/pglite-fs";
|
|
|
47
48
|
import knex from "knex";
|
|
48
49
|
import ClientPgLite from "knex-pglite";
|
|
49
50
|
import { KyselyKnexDialect, PGColdDialect } from "kysely-knex";
|
|
50
|
-
//#region \0rolldown/runtime.js
|
|
51
|
-
var __defProp = Object.defineProperty;
|
|
52
|
-
var __exportAll = (all, no_symbols) => {
|
|
53
|
-
let target = {};
|
|
54
|
-
for (var name in all) __defProp(target, name, {
|
|
55
|
-
get: all[name],
|
|
56
|
-
enumerable: true
|
|
57
|
-
});
|
|
58
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
59
|
-
return target;
|
|
60
|
-
};
|
|
61
|
-
//#endregion
|
|
62
51
|
//#region src/graphql/analytics-subgraph.ts
|
|
52
|
+
const analyticsResolvers = AnalyticsResolvers;
|
|
63
53
|
var AnalyticsSubgraph = class extends BaseSubgraph {
|
|
64
54
|
analyticsStore;
|
|
65
55
|
analyticsModel;
|
|
@@ -67,13 +57,33 @@ var AnalyticsSubgraph = class extends BaseSubgraph {
|
|
|
67
57
|
typeDefs = gql`
|
|
68
58
|
${typedefs}
|
|
69
59
|
`;
|
|
70
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Every analytics field hangs off `Query.analytics`, so gating it gates them
|
|
62
|
+
* all. Series are aggregates a processor built from many documents and carry
|
|
63
|
+
* no document to decide on, so only a caller with policy-wide read (anyone
|
|
64
|
+
* under OPEN, an admin otherwise) may read them.
|
|
65
|
+
*/
|
|
66
|
+
resolvers = {
|
|
67
|
+
...analyticsResolvers,
|
|
68
|
+
Query: {
|
|
69
|
+
...analyticsResolvers.Query,
|
|
70
|
+
analytics: (parent, args, ctx) => {
|
|
71
|
+
this.#assertCanReadAnalytics(ctx);
|
|
72
|
+
return analyticsResolvers.Query.analytics(parent, args, ctx);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
71
76
|
constructor(args) {
|
|
72
77
|
super(args);
|
|
73
78
|
this.analyticsStore = args.analyticsStore;
|
|
74
79
|
this.analyticsModel = new AnalyticsModel(new AnalyticsQueryEngine(this.analyticsStore));
|
|
75
80
|
args.graphqlManager.setAdditionalContextFields({ dataSources: { db: { Analytics: this.analyticsModel } } });
|
|
76
81
|
}
|
|
82
|
+
#assertCanReadAnalytics(ctx) {
|
|
83
|
+
if (this.authorizationService.isSupremeAdmin(ctx.user?.address)) return;
|
|
84
|
+
if (ctx.user?.address) throw new ForbiddenError("to read analytics");
|
|
85
|
+
throw new AuthenticationRequiredError("to read analytics");
|
|
86
|
+
}
|
|
77
87
|
};
|
|
78
88
|
//#endregion
|
|
79
89
|
//#region src/graphql/auth/schema.graphql
|
|
@@ -312,15 +322,15 @@ function createAuthFetchMiddleware(authService) {
|
|
|
312
322
|
async function createGatewayAdapter(type, logger) {
|
|
313
323
|
switch (type) {
|
|
314
324
|
case "apollo": {
|
|
315
|
-
const { ApolloGatewayAdapter } = await import("./adapter-gateway-apollo-
|
|
325
|
+
const { ApolloGatewayAdapter } = await import("./adapter-gateway-apollo-D2DNlPY0.mjs");
|
|
316
326
|
return new ApolloGatewayAdapter(logger);
|
|
317
327
|
}
|
|
318
328
|
case "mercurius": {
|
|
319
|
-
const { MercuriusGatewayAdapter } = await import("./adapter-gateway-mercurius-
|
|
329
|
+
const { MercuriusGatewayAdapter } = await import("./adapter-gateway-mercurius-rbKlwF9m.mjs");
|
|
320
330
|
return new MercuriusGatewayAdapter(logger);
|
|
321
331
|
}
|
|
322
332
|
case "stitching": {
|
|
323
|
-
const { StitchingGatewayAdapter } = await import("./adapter-gateway-stitching-
|
|
333
|
+
const { StitchingGatewayAdapter } = await import("./adapter-gateway-stitching-Dzv10u8D.mjs");
|
|
324
334
|
return new StitchingGatewayAdapter(logger);
|
|
325
335
|
}
|
|
326
336
|
}
|
|
@@ -328,11 +338,11 @@ async function createGatewayAdapter(type, logger) {
|
|
|
328
338
|
async function createHttpAdapter(type) {
|
|
329
339
|
switch (type) {
|
|
330
340
|
case "express": {
|
|
331
|
-
const { createExpressHttpAdapter } = await import("./adapter-http-express-
|
|
341
|
+
const { createExpressHttpAdapter } = await import("./adapter-http-express-CWqziB1p.mjs");
|
|
332
342
|
return createExpressHttpAdapter();
|
|
333
343
|
}
|
|
334
344
|
case "fastify": {
|
|
335
|
-
const { createFastifyHttpAdapter } = await import("./adapter-http-fastify-
|
|
345
|
+
const { createFastifyHttpAdapter } = await import("./adapter-http-fastify-CYZQ6FFv.mjs");
|
|
336
346
|
return createFastifyHttpAdapter();
|
|
337
347
|
}
|
|
338
348
|
}
|
|
@@ -360,7 +370,7 @@ const WS_AUTH_CLOSE_REASONS = [WS_CLOSE_REASON_AUTHENTICATION_REQUIRED, WS_CLOSE
|
|
|
360
370
|
*/
|
|
361
371
|
const SEGMENT = /^[a-z0-9][-a-z0-9._]*$/i;
|
|
362
372
|
/** Segments that would read as path traversal rather than as a name. */
|
|
363
|
-
const TRAVERSAL = new Set([".", ".."]);
|
|
373
|
+
const TRAVERSAL = /* @__PURE__ */ new Set([".", ".."]);
|
|
364
374
|
var InvalidNamespaceError = class extends Error {};
|
|
365
375
|
/**
|
|
366
376
|
* Turns a package name into the path segments it occupies.
|
|
@@ -846,27 +856,29 @@ var HttpScope = class {
|
|
|
846
856
|
headers: fetchHeaders(req),
|
|
847
857
|
signal: controller.signal
|
|
848
858
|
};
|
|
849
|
-
if (method !== "GET" && method !== "HEAD" && body !== "none")
|
|
850
|
-
|
|
851
|
-
body: Readable.toWeb(req),
|
|
852
|
-
duplex: "half"
|
|
853
|
-
};
|
|
854
|
-
else {
|
|
855
|
-
try {
|
|
856
|
-
raw = await readBody(req, spec.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES$1);
|
|
857
|
-
} catch (error) {
|
|
858
|
-
if (error instanceof BodyTooLargeError) {
|
|
859
|
-
res.setHeader("connection", "close");
|
|
860
|
-
res.once("finish", () => req.destroy());
|
|
861
|
-
writeError(res, 413, "Payload too large");
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
throw error;
|
|
865
|
-
}
|
|
866
|
-
if (raw.length) init = {
|
|
859
|
+
if (method !== "GET" && method !== "HEAD" && body !== "none") {
|
|
860
|
+
if (body === "stream") init = {
|
|
867
861
|
...init,
|
|
868
|
-
body:
|
|
862
|
+
body: Readable.toWeb(req),
|
|
863
|
+
duplex: "half"
|
|
869
864
|
};
|
|
865
|
+
else {
|
|
866
|
+
try {
|
|
867
|
+
raw = await readBody(req, spec.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES$1);
|
|
868
|
+
} catch (error) {
|
|
869
|
+
if (error instanceof BodyTooLargeError) {
|
|
870
|
+
res.setHeader("connection", "close");
|
|
871
|
+
res.once("finish", () => req.destroy());
|
|
872
|
+
writeError(res, 413, "Payload too large");
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
throw error;
|
|
876
|
+
}
|
|
877
|
+
if (raw.length) init = {
|
|
878
|
+
...init,
|
|
879
|
+
body: new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength)
|
|
880
|
+
};
|
|
881
|
+
}
|
|
870
882
|
}
|
|
871
883
|
await writeResponse(res, await spec.handler(new Request(url, init), {
|
|
872
884
|
...ctx,
|
|
@@ -1043,7 +1055,7 @@ function verifyWebhook(options) {
|
|
|
1043
1055
|
}
|
|
1044
1056
|
/** Headers that would put a credential in a log or run journal. The configured signature
|
|
1045
1057
|
* header joins them: it is an HMAC of the body under a live secret. */
|
|
1046
|
-
const REDACTED_HEADERS = new Set([
|
|
1058
|
+
const REDACTED_HEADERS = /* @__PURE__ */ new Set([
|
|
1047
1059
|
"authorization",
|
|
1048
1060
|
"proxy-authorization",
|
|
1049
1061
|
"cookie",
|
|
@@ -1316,6 +1328,7 @@ function newWebhookToken() {
|
|
|
1316
1328
|
const NAMESPACE = "reactor_webhooks";
|
|
1317
1329
|
/** Relational implementation, over the reactor's own database. */
|
|
1318
1330
|
var RelationalWebhookStore = class {
|
|
1331
|
+
relationalDb;
|
|
1319
1332
|
#db;
|
|
1320
1333
|
constructor(relationalDb) {
|
|
1321
1334
|
this.relationalDb = relationalDb;
|
|
@@ -1461,7 +1474,7 @@ const stripScalarDefinitions = (doc) => {
|
|
|
1461
1474
|
* whole gateway. We dedupe these by name; field/operation/extension nodes are
|
|
1462
1475
|
* left untouched.
|
|
1463
1476
|
*/
|
|
1464
|
-
const TYPE_DEFINITION_KINDS = new Set([
|
|
1477
|
+
const TYPE_DEFINITION_KINDS = /* @__PURE__ */ new Set([
|
|
1465
1478
|
Kind.OBJECT_TYPE_DEFINITION,
|
|
1466
1479
|
Kind.ENUM_TYPE_DEFINITION,
|
|
1467
1480
|
Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
|
@@ -1563,7 +1576,7 @@ const getDocumentModelTypeDefs = (documentModels, typeDefs$1) => {
|
|
|
1563
1576
|
stateJSON: JSONObject
|
|
1564
1577
|
}\n`;
|
|
1565
1578
|
});
|
|
1566
|
-
|
|
1579
|
+
const schema = gql`
|
|
1567
1580
|
scalar JSONObject
|
|
1568
1581
|
scalar AttachmentRef
|
|
1569
1582
|
# Codegen scalars not in the document-engineering set.
|
|
@@ -1639,7 +1652,8 @@ const getDocumentModelTypeDefs = (documentModels, typeDefs$1) => {
|
|
|
1639
1652
|
}
|
|
1640
1653
|
|
|
1641
1654
|
${stripScalarDefinitions(typeDefs$1)}
|
|
1642
|
-
|
|
1655
|
+
`;
|
|
1656
|
+
return dedupeTypeDefinitions(schema);
|
|
1643
1657
|
};
|
|
1644
1658
|
/**
|
|
1645
1659
|
* Extract type names from a GraphQL schema.
|
|
@@ -1735,9 +1749,7 @@ function generateStateInputTypes(stateSchema, excludeTypeNames) {
|
|
|
1735
1749
|
case Kind.OBJECT_TYPE_DEFINITION:
|
|
1736
1750
|
objectNames.add(def.name.value);
|
|
1737
1751
|
break;
|
|
1738
|
-
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
1739
|
-
existingInputNames.add(def.name.value);
|
|
1740
|
-
break;
|
|
1752
|
+
case Kind.INPUT_OBJECT_TYPE_DEFINITION: existingInputNames.add(def.name.value);
|
|
1741
1753
|
}
|
|
1742
1754
|
const inputTypes = [];
|
|
1743
1755
|
for (const def of ast.definitions) {
|
|
@@ -1766,7 +1778,7 @@ function applyGraphQLTypePrefixes(schema, prefix, externalTypeNames = []) {
|
|
|
1766
1778
|
if (!schema || !schema.trim()) return schema;
|
|
1767
1779
|
let processedSchema = schema;
|
|
1768
1780
|
const localTypeNames = extractTypeNames(schema);
|
|
1769
|
-
const allTypeNames = [
|
|
1781
|
+
const allTypeNames = [.../* @__PURE__ */ new Set([...localTypeNames, ...externalTypeNames])];
|
|
1770
1782
|
if (allTypeNames.length === 0) return schema;
|
|
1771
1783
|
allTypeNames.forEach((typeName) => {
|
|
1772
1784
|
const typeRegex = new RegExp(`(?<![_A-Za-z0-9])(${typeName})(?![_A-Za-z0-9])|\\[(${typeName})\\]|\\[(${typeName})!\\]|\\[(${typeName})\\]!|\\[(${typeName})!\\]!`, "g");
|
|
@@ -1794,8 +1806,9 @@ function generateDocumentModelSchema(documentModel, options = {}) {
|
|
|
1794
1806
|
const localStateTypeNames = extractTypeNames(localStateSchema ?? "");
|
|
1795
1807
|
const stateTypeNames = [...globalStateTypeNames, ...localStateTypeNames];
|
|
1796
1808
|
const allOperationTypeNames = specification?.modules.flatMap((module) => module.operations.flatMap((op) => extractTypeNames(op.schema ?? ""))) ?? [];
|
|
1797
|
-
const allTypeNames = [
|
|
1798
|
-
const
|
|
1809
|
+
const allTypeNames = [.../* @__PURE__ */ new Set([...stateTypeNames, ...allOperationTypeNames])];
|
|
1810
|
+
const operationInputTypeNames = new Set(allOperationTypeNames);
|
|
1811
|
+
const prefixedStateInputTypes = applyGraphQLTypePrefixes(extractInputTypeDefinitions(globalStateSchema ?? "", operationInputTypeNames), documentName, allTypeNames);
|
|
1799
1812
|
const hasValidSchema = (schema) => !!(schema && /\b(input|type|enum|union|interface)\s+\w+/.test(schema));
|
|
1800
1813
|
const stateSchemaTypes = globalStateSchema ? applyGraphQLTypePrefixes(globalStateSchema.replaceAll("scalar DateTime", "").replaceAll(/input (.*?) {[\s\S]*?}/g, ""), documentName, allTypeNames) : "";
|
|
1801
1814
|
if (useNewApi) return generateNewApiSchema(documentName, specification, stateSchemaTypes, prefixedStateInputTypes, allTypeNames, hasValidSchema);
|
|
@@ -1925,7 +1938,6 @@ function generateNewApiSchema(documentName, specification, _stateSchemaTypes, pr
|
|
|
1925
1938
|
"""
|
|
1926
1939
|
type ${documentName}_DocumentResultPage {
|
|
1927
1940
|
items: [${documentName}MutationResult!]!
|
|
1928
|
-
totalCount: Int!
|
|
1929
1941
|
hasNextPage: Boolean!
|
|
1930
1942
|
hasPreviousPage: Boolean!
|
|
1931
1943
|
cursor: String
|
|
@@ -2251,7 +2263,6 @@ const GetDocumentModelsDocument = gql`
|
|
|
2251
2263
|
version
|
|
2252
2264
|
specification
|
|
2253
2265
|
}
|
|
2254
|
-
totalCount
|
|
2255
2266
|
hasNextPage
|
|
2256
2267
|
hasPreviousPage
|
|
2257
2268
|
cursor
|
|
@@ -2310,7 +2321,6 @@ const GetDocumentWithOperationsDocument = gql`
|
|
|
2310
2321
|
}
|
|
2311
2322
|
}
|
|
2312
2323
|
}
|
|
2313
|
-
totalCount
|
|
2314
2324
|
hasNextPage
|
|
2315
2325
|
hasPreviousPage
|
|
2316
2326
|
cursor
|
|
@@ -2337,7 +2347,6 @@ const GetDocumentOutgoingRelationshipsDocument = gql`
|
|
|
2337
2347
|
items {
|
|
2338
2348
|
...PHDocumentFields
|
|
2339
2349
|
}
|
|
2340
|
-
totalCount
|
|
2341
2350
|
hasNextPage
|
|
2342
2351
|
hasPreviousPage
|
|
2343
2352
|
cursor
|
|
@@ -2361,7 +2370,6 @@ const GetDocumentIncomingRelationshipsDocument = gql`
|
|
|
2361
2370
|
items {
|
|
2362
2371
|
...PHDocumentFields
|
|
2363
2372
|
}
|
|
2364
|
-
totalCount
|
|
2365
2373
|
hasNextPage
|
|
2366
2374
|
hasPreviousPage
|
|
2367
2375
|
cursor
|
|
@@ -2385,7 +2393,6 @@ const GetDocumentOutgoingRelationshipEdgesDocument = gql`
|
|
|
2385
2393
|
items {
|
|
2386
2394
|
...DocumentRelationshipFields
|
|
2387
2395
|
}
|
|
2388
|
-
totalCount
|
|
2389
2396
|
hasNextPage
|
|
2390
2397
|
hasPreviousPage
|
|
2391
2398
|
cursor
|
|
@@ -2409,7 +2416,6 @@ const GetDocumentIncomingRelationshipEdgesDocument = gql`
|
|
|
2409
2416
|
items {
|
|
2410
2417
|
...DocumentRelationshipFields
|
|
2411
2418
|
}
|
|
2412
|
-
totalCount
|
|
2413
2419
|
hasNextPage
|
|
2414
2420
|
hasPreviousPage
|
|
2415
2421
|
cursor
|
|
@@ -2427,7 +2433,6 @@ const FindDocumentsDocument = gql`
|
|
|
2427
2433
|
items {
|
|
2428
2434
|
...PHDocumentFields
|
|
2429
2435
|
}
|
|
2430
|
-
totalCount
|
|
2431
2436
|
hasNextPage
|
|
2432
2437
|
hasPreviousPage
|
|
2433
2438
|
cursor
|
|
@@ -2471,7 +2476,6 @@ const GetDocumentOperationsDocument = gql`
|
|
|
2471
2476
|
}
|
|
2472
2477
|
}
|
|
2473
2478
|
}
|
|
2474
|
-
totalCount
|
|
2475
2479
|
hasNextPage
|
|
2476
2480
|
hasPreviousPage
|
|
2477
2481
|
cursor
|
|
@@ -2910,8 +2914,7 @@ function toDocumentModelResultPage(result) {
|
|
|
2910
2914
|
cursor: result.nextCursor ?? null,
|
|
2911
2915
|
hasNextPage: !!result.nextCursor,
|
|
2912
2916
|
hasPreviousPage: !!result.options.cursor,
|
|
2913
|
-
items: models.map(toGqlDocumentModelState)
|
|
2914
|
-
totalCount: result.results.length
|
|
2917
|
+
items: models.map(toGqlDocumentModelState)
|
|
2915
2918
|
};
|
|
2916
2919
|
}
|
|
2917
2920
|
/**
|
|
@@ -2943,8 +2946,7 @@ function toPhDocumentResultPage(result) {
|
|
|
2943
2946
|
cursor: result.nextCursor ?? null,
|
|
2944
2947
|
hasNextPage: !!result.nextCursor,
|
|
2945
2948
|
hasPreviousPage: !!result.options.cursor,
|
|
2946
|
-
items: result.results.map(toGqlPhDocument)
|
|
2947
|
-
totalCount: result.totalCount ?? result.results.length
|
|
2949
|
+
items: result.results.map(toGqlPhDocument)
|
|
2948
2950
|
};
|
|
2949
2951
|
}
|
|
2950
2952
|
/**
|
|
@@ -2969,8 +2971,7 @@ function toDocumentRelationshipResultPage(result) {
|
|
|
2969
2971
|
cursor: result.nextCursor ?? null,
|
|
2970
2972
|
hasNextPage: !!result.nextCursor,
|
|
2971
2973
|
hasPreviousPage: !!result.options.cursor,
|
|
2972
|
-
items: result.results.map(toGqlDocumentRelationship)
|
|
2973
|
-
totalCount: result.totalCount ?? result.results.length
|
|
2974
|
+
items: result.results.map(toGqlDocumentRelationship)
|
|
2974
2975
|
};
|
|
2975
2976
|
}
|
|
2976
2977
|
/**
|
|
@@ -3020,8 +3021,8 @@ function fromInputMaybe(value) {
|
|
|
3020
3021
|
function toReactorPropagationMode(gqlMode) {
|
|
3021
3022
|
if (gqlMode == null) return;
|
|
3022
3023
|
switch (gqlMode) {
|
|
3023
|
-
case
|
|
3024
|
-
case
|
|
3024
|
+
case "CASCADE": return PropagationMode$1.Cascade;
|
|
3025
|
+
case "ORPHAN": return PropagationMode$1.None;
|
|
3025
3026
|
}
|
|
3026
3027
|
}
|
|
3027
3028
|
/**
|
|
@@ -3031,10 +3032,10 @@ function toReactorPropagationMode(gqlMode) {
|
|
|
3031
3032
|
*/
|
|
3032
3033
|
function toGqlActionEvaluation(evaluation) {
|
|
3033
3034
|
return evaluation.decision === "allow" ? {
|
|
3034
|
-
decision:
|
|
3035
|
+
decision: "ALLOW",
|
|
3035
3036
|
reason: null
|
|
3036
3037
|
} : {
|
|
3037
|
-
decision:
|
|
3038
|
+
decision: "DENY",
|
|
3038
3039
|
reason: evaluation.reason
|
|
3039
3040
|
};
|
|
3040
3041
|
}
|
|
@@ -3239,8 +3240,7 @@ function toOperationResultPage(result) {
|
|
|
3239
3240
|
cursor: result.nextCursor ?? null,
|
|
3240
3241
|
hasNextPage: !!result.nextCursor,
|
|
3241
3242
|
hasPreviousPage: !!result.options.cursor && result.options.cursor !== "0",
|
|
3242
|
-
items: result.results.map(serializeOperationForGraphQL)
|
|
3243
|
-
totalCount: result.results.length
|
|
3243
|
+
items: result.results.map(serializeOperationForGraphQL)
|
|
3244
3244
|
};
|
|
3245
3245
|
}
|
|
3246
3246
|
function toGqlDocumentChangeEvent(event) {
|
|
@@ -3312,6 +3312,21 @@ function pickDriveClient(reactorClient, driveContainerType, reactorDriveClient)
|
|
|
3312
3312
|
}
|
|
3313
3313
|
return reactorClient.drives;
|
|
3314
3314
|
}
|
|
3315
|
+
/**
|
|
3316
|
+
* A mutation's document re-read as the caller, since the client reads it back
|
|
3317
|
+
* as its signer. A caller who may write but not read gets it stripped.
|
|
3318
|
+
*/
|
|
3319
|
+
async function readAsCaller(reactorClient, document, subject, branch) {
|
|
3320
|
+
if (!subject) return document;
|
|
3321
|
+
try {
|
|
3322
|
+
return await reactorClient.get(document.header.id, {
|
|
3323
|
+
subject,
|
|
3324
|
+
branch
|
|
3325
|
+
});
|
|
3326
|
+
} catch (error) {
|
|
3327
|
+
throw new GraphQLError(`Failed to read the document back: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3315
3330
|
async function documentModels(reactorClient, args) {
|
|
3316
3331
|
const namespace = fromInputMaybe(args.namespace);
|
|
3317
3332
|
let paging;
|
|
@@ -3499,13 +3514,42 @@ async function findDocuments(reactorClient, args, subject) {
|
|
|
3499
3514
|
throw new GraphQLError(`Failed to convert documents to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3500
3515
|
}
|
|
3501
3516
|
}
|
|
3502
|
-
|
|
3517
|
+
/**
|
|
3518
|
+
* The answer for a job the caller may not see, shaped as the reactor answers
|
|
3519
|
+
* an unknown one so that the two cannot be told apart.
|
|
3520
|
+
*/
|
|
3521
|
+
function unknownJob(jobId) {
|
|
3522
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3523
|
+
return {
|
|
3524
|
+
id: jobId,
|
|
3525
|
+
documentId: "",
|
|
3526
|
+
status: JobStatus.FAILED,
|
|
3527
|
+
createdAtUtcIso: now,
|
|
3528
|
+
completedAtUtcIso: now,
|
|
3529
|
+
error: {
|
|
3530
|
+
name: "Error",
|
|
3531
|
+
message: "Job not found",
|
|
3532
|
+
stack: ""
|
|
3533
|
+
},
|
|
3534
|
+
consistencyToken: {
|
|
3535
|
+
version: 1,
|
|
3536
|
+
createdAtUtcIso: now,
|
|
3537
|
+
coordinates: []
|
|
3538
|
+
},
|
|
3539
|
+
meta: {
|
|
3540
|
+
batchId: jobId,
|
|
3541
|
+
batchJobIds: [jobId]
|
|
3542
|
+
}
|
|
3543
|
+
};
|
|
3544
|
+
}
|
|
3545
|
+
async function jobStatus(reactorClient, args, serves) {
|
|
3503
3546
|
let result;
|
|
3504
3547
|
try {
|
|
3505
3548
|
result = await reactorClient.getJobStatus(args.jobId);
|
|
3506
3549
|
} catch (error) {
|
|
3507
3550
|
throw new GraphQLError(`Failed to fetch job status: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3508
3551
|
}
|
|
3552
|
+
if (!await serves(result.documentId)) result = unknownJob(args.jobId);
|
|
3509
3553
|
try {
|
|
3510
3554
|
return toGqlJobInfo(result);
|
|
3511
3555
|
} catch (error) {
|
|
@@ -3588,7 +3632,7 @@ async function evaluateActions(reactorClient, args, subject) {
|
|
|
3588
3632
|
anyDenied: result.anyDenied
|
|
3589
3633
|
};
|
|
3590
3634
|
}
|
|
3591
|
-
async function createDocument(reactorClient, args, reactorDriveClient) {
|
|
3635
|
+
async function createDocument(reactorClient, args, reactorDriveClient, subject) {
|
|
3592
3636
|
if (!args.document || typeof args.document !== "object") throw new GraphQLError("Invalid document: must be an object");
|
|
3593
3637
|
const document = args.document;
|
|
3594
3638
|
if (!document.header || typeof document.header !== "object") throw new GraphQLError("Invalid document: missing or invalid header");
|
|
@@ -3596,28 +3640,30 @@ async function createDocument(reactorClient, args, reactorDriveClient) {
|
|
|
3596
3640
|
let result;
|
|
3597
3641
|
try {
|
|
3598
3642
|
if (parentIdentifier) {
|
|
3599
|
-
const parent = await reactorClient.get(parentIdentifier);
|
|
3643
|
+
const parent = await reactorClient.get(parentIdentifier, subject && { subject });
|
|
3600
3644
|
if (isDriveContainerType(parent.header.documentType)) result = await pickDriveClient(reactorClient, parent.header.documentType, reactorDriveClient).addFile(parentIdentifier, document);
|
|
3601
3645
|
else result = await reactorClient.create(document, parentIdentifier);
|
|
3602
3646
|
} else result = await reactorClient.create(document);
|
|
3603
3647
|
} catch (error) {
|
|
3604
3648
|
throw new GraphQLError(`Failed to create document: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3605
3649
|
}
|
|
3650
|
+
result = await readAsCaller(reactorClient, result, subject);
|
|
3606
3651
|
try {
|
|
3607
3652
|
return toGqlPhDocument(result);
|
|
3608
3653
|
} catch (error) {
|
|
3609
3654
|
throw new GraphQLError(`Failed to convert created document to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3610
3655
|
}
|
|
3611
3656
|
}
|
|
3612
|
-
async function createEmptyDocument(reactorClient, args, reactorDriveClient) {
|
|
3657
|
+
async function createEmptyDocument(reactorClient, args, reactorDriveClient, subject) {
|
|
3613
3658
|
const parentIdentifier = fromInputMaybe(args.parentIdentifier);
|
|
3614
3659
|
const name = fromInputMaybe(args.name);
|
|
3615
3660
|
let result;
|
|
3616
3661
|
try {
|
|
3617
3662
|
if (parentIdentifier) {
|
|
3618
|
-
const parent = await reactorClient.get(parentIdentifier);
|
|
3663
|
+
const parent = await reactorClient.get(parentIdentifier, subject && { subject });
|
|
3619
3664
|
if (isDriveContainerType(parent.header.documentType)) {
|
|
3620
|
-
const
|
|
3665
|
+
const module = await reactorClient.getDocumentModelModule(args.documentType);
|
|
3666
|
+
const document = withSignaturePolicy(module.utils.createDocument(), await reactorClient.getCreateSignaturePolicy());
|
|
3621
3667
|
if (name) document.header.name = name;
|
|
3622
3668
|
result = await pickDriveClient(reactorClient, parent.header.documentType, reactorDriveClient).addFile(parentIdentifier, document);
|
|
3623
3669
|
} else result = await reactorClient.createEmpty(args.documentType, { parentIdentifier });
|
|
@@ -3625,13 +3671,14 @@ async function createEmptyDocument(reactorClient, args, reactorDriveClient) {
|
|
|
3625
3671
|
} catch (error) {
|
|
3626
3672
|
throw new GraphQLError(`Failed to create empty document: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3627
3673
|
}
|
|
3674
|
+
result = await readAsCaller(reactorClient, result, subject);
|
|
3628
3675
|
try {
|
|
3629
3676
|
return toGqlPhDocument(result);
|
|
3630
3677
|
} catch (error) {
|
|
3631
3678
|
throw new GraphQLError(`Failed to convert created document to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3632
3679
|
}
|
|
3633
3680
|
}
|
|
3634
|
-
async function createDocumentWithInitialState(reactorClient, args, reactorDriveClient) {
|
|
3681
|
+
async function createDocumentWithInitialState(reactorClient, args, reactorDriveClient, subject) {
|
|
3635
3682
|
const parentIdentifier = fromInputMaybe(args.parentIdentifier);
|
|
3636
3683
|
const name = fromInputMaybe(args.name);
|
|
3637
3684
|
const slug = fromInputMaybe(args.slug);
|
|
@@ -3659,7 +3706,7 @@ async function createDocumentWithInitialState(reactorClient, args, reactorDriveC
|
|
|
3659
3706
|
if (parentIdentifier) {
|
|
3660
3707
|
let parent;
|
|
3661
3708
|
try {
|
|
3662
|
-
parent = await reactorClient.get(parentIdentifier);
|
|
3709
|
+
parent = await reactorClient.get(parentIdentifier, subject && { subject });
|
|
3663
3710
|
} catch (error) {
|
|
3664
3711
|
throw new GraphQLError(`Parent document not found: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3665
3712
|
}
|
|
@@ -3680,6 +3727,7 @@ async function createDocumentWithInitialState(reactorClient, args, reactorDriveC
|
|
|
3680
3727
|
} catch (error) {
|
|
3681
3728
|
throw new GraphQLError(`Failed to create document: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3682
3729
|
}
|
|
3730
|
+
result = await readAsCaller(reactorClient, result, subject);
|
|
3683
3731
|
try {
|
|
3684
3732
|
return toGqlPhDocument(result);
|
|
3685
3733
|
} catch (error) {
|
|
@@ -3696,12 +3744,12 @@ const DEFAULT_BRANCH = "main";
|
|
|
3696
3744
|
* the schema cannot express: a signature travels as one string, and verification
|
|
3697
3745
|
* reads it as the tuple it was.
|
|
3698
3746
|
*/
|
|
3699
|
-
async function execute(reactorClient, args) {
|
|
3747
|
+
async function execute(reactorClient, args, subject) {
|
|
3700
3748
|
const actions = toSubmittableActions(args.actions);
|
|
3701
3749
|
const branch = fromInputMaybe(args.branch) ?? DEFAULT_BRANCH;
|
|
3702
3750
|
let result;
|
|
3703
3751
|
try {
|
|
3704
|
-
result = await reactorClient.execute(args.documentIdentifier, branch, actions);
|
|
3752
|
+
result = await reactorClient.execute(args.documentIdentifier, branch, actions, void 0, subject);
|
|
3705
3753
|
} catch (error) {
|
|
3706
3754
|
throw new GraphQLError(`Failed to execute actions: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3707
3755
|
}
|
|
@@ -3729,7 +3777,7 @@ async function executeAsync(reactorClient, args) {
|
|
|
3729
3777
|
}
|
|
3730
3778
|
return toGqlJobInfo(job);
|
|
3731
3779
|
}
|
|
3732
|
-
async function mutateDocument(reactorClient, args) {
|
|
3780
|
+
async function mutateDocument(reactorClient, args, subject) {
|
|
3733
3781
|
let validatedActions;
|
|
3734
3782
|
try {
|
|
3735
3783
|
validatedActions = validateActions(args.actions);
|
|
@@ -3740,7 +3788,7 @@ async function mutateDocument(reactorClient, args) {
|
|
|
3740
3788
|
const branch = args.view?.branch ?? "main";
|
|
3741
3789
|
let result;
|
|
3742
3790
|
try {
|
|
3743
|
-
result = await reactorClient.execute(args.documentIdentifier, branch, validatedActions);
|
|
3791
|
+
result = await reactorClient.execute(args.documentIdentifier, branch, validatedActions, void 0, subject);
|
|
3744
3792
|
} catch (error) {
|
|
3745
3793
|
throw new GraphQLError(`Failed to mutate document: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3746
3794
|
}
|
|
@@ -3767,7 +3815,7 @@ async function mutateDocumentAsync(reactorClient, args) {
|
|
|
3767
3815
|
}
|
|
3768
3816
|
return result.id;
|
|
3769
3817
|
}
|
|
3770
|
-
async function renameDocument(reactorClient, args, signal) {
|
|
3818
|
+
async function renameDocument(reactorClient, args, signal, subject) {
|
|
3771
3819
|
const branch = fromInputMaybe(args.branch);
|
|
3772
3820
|
let result;
|
|
3773
3821
|
try {
|
|
@@ -3775,13 +3823,14 @@ async function renameDocument(reactorClient, args, signal) {
|
|
|
3775
3823
|
} catch (error) {
|
|
3776
3824
|
throw new GraphQLError(`Failed to rename document: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3777
3825
|
}
|
|
3826
|
+
result = await readAsCaller(reactorClient, result, subject, branch);
|
|
3778
3827
|
try {
|
|
3779
3828
|
return toGqlPhDocument(result);
|
|
3780
3829
|
} catch (error) {
|
|
3781
3830
|
throw new GraphQLError(`Failed to convert renamed document to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3782
3831
|
}
|
|
3783
3832
|
}
|
|
3784
|
-
async function setPreferredEditor(reactorClient, args, signal) {
|
|
3833
|
+
async function setPreferredEditor(reactorClient, args, signal, subject) {
|
|
3785
3834
|
const branch = fromInputMaybe(args.branch);
|
|
3786
3835
|
const preferredEditor = fromInputMaybe(args.preferredEditor) ?? null;
|
|
3787
3836
|
let result;
|
|
@@ -3790,13 +3839,14 @@ async function setPreferredEditor(reactorClient, args, signal) {
|
|
|
3790
3839
|
} catch (error) {
|
|
3791
3840
|
throw new GraphQLError(`Failed to set preferred editor: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3792
3841
|
}
|
|
3842
|
+
result = await readAsCaller(reactorClient, result, subject, branch);
|
|
3793
3843
|
try {
|
|
3794
3844
|
return toGqlPhDocument(result);
|
|
3795
3845
|
} catch (error) {
|
|
3796
3846
|
throw new GraphQLError(`Failed to convert updated document to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3797
3847
|
}
|
|
3798
3848
|
}
|
|
3799
|
-
async function addRelationship(reactorClient, args) {
|
|
3849
|
+
async function addRelationship(reactorClient, args, subject) {
|
|
3800
3850
|
const branch = fromInputMaybe(args.branch);
|
|
3801
3851
|
const metadata = fromInputMaybe(args.metadata);
|
|
3802
3852
|
let result;
|
|
@@ -3805,13 +3855,14 @@ async function addRelationship(reactorClient, args) {
|
|
|
3805
3855
|
} catch (error) {
|
|
3806
3856
|
throw new GraphQLError(`Failed to add relationship: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3807
3857
|
}
|
|
3858
|
+
result = await readAsCaller(reactorClient, result, subject, branch);
|
|
3808
3859
|
try {
|
|
3809
3860
|
return toGqlPhDocument(result);
|
|
3810
3861
|
} catch (error) {
|
|
3811
3862
|
throw new GraphQLError(`Failed to convert document to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3812
3863
|
}
|
|
3813
3864
|
}
|
|
3814
|
-
async function updateRelationship(reactorClient, args) {
|
|
3865
|
+
async function updateRelationship(reactorClient, args, subject) {
|
|
3815
3866
|
const branch = fromInputMaybe(args.branch);
|
|
3816
3867
|
const metadata = fromInputMaybe(args.metadata) ?? null;
|
|
3817
3868
|
let result;
|
|
@@ -3820,13 +3871,14 @@ async function updateRelationship(reactorClient, args) {
|
|
|
3820
3871
|
} catch (error) {
|
|
3821
3872
|
throw new GraphQLError(`Failed to update relationship: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3822
3873
|
}
|
|
3874
|
+
result = await readAsCaller(reactorClient, result, subject, branch);
|
|
3823
3875
|
try {
|
|
3824
3876
|
return toGqlPhDocument(result);
|
|
3825
3877
|
} catch (error) {
|
|
3826
3878
|
throw new GraphQLError(`Failed to convert document to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3827
3879
|
}
|
|
3828
3880
|
}
|
|
3829
|
-
async function removeRelationship(reactorClient, args) {
|
|
3881
|
+
async function removeRelationship(reactorClient, args, subject) {
|
|
3830
3882
|
const branch = fromInputMaybe(args.branch);
|
|
3831
3883
|
let result;
|
|
3832
3884
|
try {
|
|
@@ -3834,13 +3886,14 @@ async function removeRelationship(reactorClient, args) {
|
|
|
3834
3886
|
} catch (error) {
|
|
3835
3887
|
throw new GraphQLError(`Failed to remove relationship: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3836
3888
|
}
|
|
3889
|
+
result = await readAsCaller(reactorClient, result, subject, branch);
|
|
3837
3890
|
try {
|
|
3838
3891
|
return toGqlPhDocument(result);
|
|
3839
3892
|
} catch (error) {
|
|
3840
3893
|
throw new GraphQLError(`Failed to convert document to GraphQL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3841
3894
|
}
|
|
3842
3895
|
}
|
|
3843
|
-
async function moveRelationship(reactorClient, args) {
|
|
3896
|
+
async function moveRelationship(reactorClient, args, subject) {
|
|
3844
3897
|
const branch = fromInputMaybe(args.branch);
|
|
3845
3898
|
let result;
|
|
3846
3899
|
try {
|
|
@@ -3848,6 +3901,10 @@ async function moveRelationship(reactorClient, args) {
|
|
|
3848
3901
|
} catch (error) {
|
|
3849
3902
|
throw new GraphQLError(`Failed to move relationship: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3850
3903
|
}
|
|
3904
|
+
result = {
|
|
3905
|
+
source: await readAsCaller(reactorClient, result.source, subject, branch),
|
|
3906
|
+
target: await readAsCaller(reactorClient, result.target, subject, branch)
|
|
3907
|
+
};
|
|
3851
3908
|
try {
|
|
3852
3909
|
return {
|
|
3853
3910
|
source: toGqlPhDocument(result.source),
|
|
@@ -4137,6 +4194,16 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4137
4194
|
const documentName = getDocumentModelSchemaName(this.documentModel.documentModel.global);
|
|
4138
4195
|
return this.resolvers[`${documentName}Mutations`];
|
|
4139
4196
|
}
|
|
4197
|
+
/** Drops the items the host's own ACL refuses the caller. */
|
|
4198
|
+
async #readableItems(page, ctx) {
|
|
4199
|
+
if (this.authorizationService.isSupremeAdmin(ctx.user?.address)) return page;
|
|
4200
|
+
const items = [];
|
|
4201
|
+
for (const item of page.items) if (await this.canReadDocument(item.id, ctx)) items.push(item);
|
|
4202
|
+
return {
|
|
4203
|
+
...page,
|
|
4204
|
+
items
|
|
4205
|
+
};
|
|
4206
|
+
}
|
|
4140
4207
|
/**
|
|
4141
4208
|
* Generate __resolveType functions for union types found in the document model schema.
|
|
4142
4209
|
* Parses the state schema to find union definitions and their member types,
|
|
@@ -4197,7 +4264,7 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4197
4264
|
const result = await document(this.reactorClient, {
|
|
4198
4265
|
identifier,
|
|
4199
4266
|
view
|
|
4200
|
-
});
|
|
4267
|
+
}, this.viewSubject(ctx));
|
|
4201
4268
|
if (result.document.documentType !== documentType) throw new GraphQLError(`Document with id ${identifier} is not of type ${documentType}`);
|
|
4202
4269
|
await this.assertCanReadCanonical(result.document.id, ctx);
|
|
4203
4270
|
return result;
|
|
@@ -4207,17 +4274,8 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4207
4274
|
const result = await findDocuments(this.reactorClient, {
|
|
4208
4275
|
search: { type: documentType },
|
|
4209
4276
|
paging
|
|
4210
|
-
});
|
|
4211
|
-
|
|
4212
|
-
const filteredItems = [];
|
|
4213
|
-
for (const item of result.items) if (await this.canReadDocument(item.id, ctx)) filteredItems.push(item);
|
|
4214
|
-
return {
|
|
4215
|
-
...result,
|
|
4216
|
-
items: filteredItems,
|
|
4217
|
-
totalCount: filteredItems.length
|
|
4218
|
-
};
|
|
4219
|
-
}
|
|
4220
|
-
return result;
|
|
4277
|
+
}, this.viewSubject(ctx));
|
|
4278
|
+
return this.#readableItems(result, ctx);
|
|
4221
4279
|
},
|
|
4222
4280
|
findDocuments: async (_, args, ctx) => {
|
|
4223
4281
|
const { search, view, paging } = args;
|
|
@@ -4228,17 +4286,8 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4228
4286
|
},
|
|
4229
4287
|
view,
|
|
4230
4288
|
paging
|
|
4231
|
-
});
|
|
4232
|
-
|
|
4233
|
-
const filteredItems = [];
|
|
4234
|
-
for (const item of result.items) if (await this.canReadDocument(item.id, ctx)) filteredItems.push(item);
|
|
4235
|
-
return {
|
|
4236
|
-
...result,
|
|
4237
|
-
items: filteredItems,
|
|
4238
|
-
totalCount: filteredItems.length
|
|
4239
|
-
};
|
|
4240
|
-
}
|
|
4241
|
-
return result;
|
|
4289
|
+
}, this.viewSubject(ctx));
|
|
4290
|
+
return this.#readableItems(result, ctx);
|
|
4242
4291
|
},
|
|
4243
4292
|
documentOutgoingRelationships: async (_, args, ctx) => {
|
|
4244
4293
|
const { relationshipType, view, paging } = args;
|
|
@@ -4248,23 +4297,24 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4248
4297
|
relationshipType,
|
|
4249
4298
|
view,
|
|
4250
4299
|
paging
|
|
4251
|
-
});
|
|
4252
|
-
const
|
|
4300
|
+
}, this.viewSubject(ctx));
|
|
4301
|
+
const readable = await this.#readableItems(result, ctx);
|
|
4302
|
+
const filteredItems = readable.items.filter((item) => item.documentType === documentType);
|
|
4253
4303
|
return {
|
|
4254
|
-
...
|
|
4255
|
-
items: filteredItems
|
|
4256
|
-
totalCount: filteredItems.length
|
|
4304
|
+
...readable,
|
|
4305
|
+
items: filteredItems
|
|
4257
4306
|
};
|
|
4258
4307
|
},
|
|
4259
4308
|
documentIncomingRelationships: async (_, args, ctx) => {
|
|
4260
4309
|
const { relationshipType, view, paging } = args;
|
|
4261
4310
|
const handle = await this.assertCanRead(args.targetIdentifier, ctx);
|
|
4262
|
-
|
|
4311
|
+
const result = await documentIncomingRelationships(this.reactorClient, {
|
|
4263
4312
|
targetIdentifier: handle.fetchIdentifier,
|
|
4264
4313
|
relationshipType,
|
|
4265
4314
|
view,
|
|
4266
4315
|
paging
|
|
4267
|
-
});
|
|
4316
|
+
}, this.viewSubject(ctx));
|
|
4317
|
+
return this.#readableItems(result, ctx);
|
|
4268
4318
|
}
|
|
4269
4319
|
},
|
|
4270
4320
|
Mutation: { [documentName]: () => ({}) },
|
|
@@ -4282,14 +4332,14 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4282
4332
|
slug,
|
|
4283
4333
|
preferredEditor,
|
|
4284
4334
|
initialState: initialState ?? {}
|
|
4285
|
-
}, this.graphqlManager.reactorDriveClient);
|
|
4335
|
+
}, this.graphqlManager.reactorDriveClient, this.viewSubject(ctx));
|
|
4286
4336
|
else createdDoc = await createEmptyDocument(this.reactorClient, {
|
|
4287
4337
|
documentType,
|
|
4288
4338
|
parentIdentifier,
|
|
4289
4339
|
name
|
|
4290
|
-
}, this.graphqlManager.reactorDriveClient);
|
|
4340
|
+
}, this.graphqlManager.reactorDriveClient, this.viewSubject(ctx));
|
|
4291
4341
|
if (ctx.user?.address && createdDoc?.id) await this.documentPermissionService?.initializeDocumentProtection(createdDoc.id, ctx.user.address, this.authorizationService.config.defaultProtection);
|
|
4292
|
-
if (!initialState && !preferredEditor && name && createdDoc.name !== name) return toGqlPhDocument(await this.reactorClient.execute(createdDoc.id, "main", [setName(name)]));
|
|
4342
|
+
if (!initialState && !preferredEditor && name && createdDoc.name !== name) return toGqlPhDocument(await this.reactorClient.execute(createdDoc.id, "main", [setName(name)], void 0, this.viewSubject(ctx)));
|
|
4293
4343
|
return createdDoc;
|
|
4294
4344
|
},
|
|
4295
4345
|
createEmptyDocument: async (_, args, ctx) => {
|
|
@@ -4299,7 +4349,7 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4299
4349
|
const result = await createEmptyDocument(this.reactorClient, {
|
|
4300
4350
|
documentType,
|
|
4301
4351
|
parentIdentifier
|
|
4302
|
-
}, this.graphqlManager.reactorDriveClient);
|
|
4352
|
+
}, this.graphqlManager.reactorDriveClient, this.viewSubject(ctx));
|
|
4303
4353
|
if (ctx.user?.address && result?.id) await this.documentPermissionService?.initializeDocumentProtection(result.id, ctx.user.address, this.authorizationService.config.defaultProtection);
|
|
4304
4354
|
return result;
|
|
4305
4355
|
},
|
|
@@ -4307,11 +4357,11 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4307
4357
|
mutations[camelCase(op.name)] = async (_, args, ctx) => {
|
|
4308
4358
|
const { docId, input } = args;
|
|
4309
4359
|
const effectiveDocId = (await this.assertCanExecuteOperation(docId, op.name, ctx)).fetchIdentifier;
|
|
4310
|
-
if ((await this.reactorClient.get(effectiveDocId)).header.documentType !== documentType) throw new GraphQLError(`Document with id ${docId} is not of type ${documentType}`);
|
|
4360
|
+
if ((await this.reactorClient.get(effectiveDocId, { subject: this.viewSubject(ctx) })).header.documentType !== documentType) throw new GraphQLError(`Document with id ${docId} is not of type ${documentType}`);
|
|
4311
4361
|
const action = this.documentModel.actions[camelCase(op.name)];
|
|
4312
4362
|
if (!action) throw new GraphQLError(`Action ${op.name} not found`);
|
|
4313
4363
|
try {
|
|
4314
|
-
return toGqlPhDocument(await this.reactorClient.execute(effectiveDocId, "main", [action(input)]));
|
|
4364
|
+
return toGqlPhDocument(await this.reactorClient.execute(effectiveDocId, "main", [action(input)], void 0, this.viewSubject(ctx)));
|
|
4315
4365
|
} catch (error) {
|
|
4316
4366
|
throw new GraphQLError(error instanceof Error ? error.message : `Failed to ${op.name}`);
|
|
4317
4367
|
}
|
|
@@ -4319,7 +4369,7 @@ var DocumentModelSubgraph = class extends BaseSubgraph {
|
|
|
4319
4369
|
mutations[`${camelCase(op.name)}Async`] = async (_, args, ctx) => {
|
|
4320
4370
|
const { docId, input } = args;
|
|
4321
4371
|
const effectiveDocId = (await this.assertCanExecuteOperation(docId, op.name, ctx)).fetchIdentifier;
|
|
4322
|
-
if ((await this.reactorClient.get(effectiveDocId)).header.documentType !== documentType) throw new GraphQLError(`Document with id ${docId} is not of type ${documentType}`);
|
|
4372
|
+
if ((await this.reactorClient.get(effectiveDocId, { subject: this.viewSubject(ctx) })).header.documentType !== documentType) throw new GraphQLError(`Document with id ${docId} is not of type ${documentType}`);
|
|
4323
4373
|
const action = this.documentModel.actions[camelCase(op.name)];
|
|
4324
4374
|
if (!action) throw new GraphQLError(`Action ${op.name} not found`);
|
|
4325
4375
|
try {
|
|
@@ -4343,7 +4393,7 @@ const DRIVE_ID_HEADER = "drive-id";
|
|
|
4343
4393
|
* in the ownership set yet); other create-shaped operations that may
|
|
4344
4394
|
* synthesize a drive must be added here too.
|
|
4345
4395
|
*/
|
|
4346
|
-
const CACHE_BYPASS_OPERATIONS = new Set(["createDocument", "createEmptyDocument"]);
|
|
4396
|
+
const CACHE_BYPASS_OPERATIONS = /* @__PURE__ */ new Set(["createDocument", "createEmptyDocument"]);
|
|
4347
4397
|
const driveIdMap = /* @__PURE__ */ new WeakMap();
|
|
4348
4398
|
/** Internal — only `graphql-manager.ts` should call this. */
|
|
4349
4399
|
function getRequestDriveId(request) {
|
|
@@ -4413,6 +4463,7 @@ function wrongShardResponse(driveId) {
|
|
|
4413
4463
|
* 421 response.
|
|
4414
4464
|
*/
|
|
4415
4465
|
var DriveOwnershipCache = class {
|
|
4466
|
+
reactorClient;
|
|
4416
4467
|
drives = /* @__PURE__ */ new Set();
|
|
4417
4468
|
constructor(reactorClient) {
|
|
4418
4469
|
this.reactorClient = reactorClient;
|
|
@@ -4530,6 +4581,22 @@ function createWsAuthHandlers(opts) {
|
|
|
4530
4581
|
};
|
|
4531
4582
|
}
|
|
4532
4583
|
var GraphQLManager = class {
|
|
4584
|
+
path;
|
|
4585
|
+
httpServer;
|
|
4586
|
+
wsServer;
|
|
4587
|
+
reactorClient;
|
|
4588
|
+
relationalDb;
|
|
4589
|
+
analyticsStore;
|
|
4590
|
+
syncManager;
|
|
4591
|
+
logger;
|
|
4592
|
+
httpAdapter;
|
|
4593
|
+
gatewayAdapter;
|
|
4594
|
+
authService;
|
|
4595
|
+
documentPermissionService;
|
|
4596
|
+
featureFlags;
|
|
4597
|
+
port;
|
|
4598
|
+
syncServingGate;
|
|
4599
|
+
httpRoutes;
|
|
4533
4600
|
initialized = false;
|
|
4534
4601
|
coreSubgraphsMap = /* @__PURE__ */ new Map();
|
|
4535
4602
|
contextFields = {};
|
|
@@ -4606,19 +4673,21 @@ var GraphQLManager = class {
|
|
|
4606
4673
|
const matched = driveMatcher(url.pathname);
|
|
4607
4674
|
const driveIdOrSlug = matched ? matched.params.drive : void 0;
|
|
4608
4675
|
if (!driveIdOrSlug) return Response.json({ error: "Drive ID or slug is required" }, { status: 400 });
|
|
4676
|
+
const user = getAuthContext(request)?.user;
|
|
4609
4677
|
try {
|
|
4610
|
-
const driveDoc = await this.reactorClient.get(driveIdOrSlug);
|
|
4611
|
-
if (!await this.authorizationService.canRead(driveDoc.header.id,
|
|
4678
|
+
const driveDoc = await this.reactorClient.get(driveIdOrSlug, { subject: callerSubject(user) });
|
|
4679
|
+
if (!await this.authorizationService.canRead(driveDoc.header.id, user?.address)) {
|
|
4612
4680
|
this.logger.debug(`Drive read refused: ${driveIdOrSlug}`);
|
|
4613
4681
|
return Response.json({ error: "Drive not found" }, { status: 404 });
|
|
4614
4682
|
}
|
|
4615
4683
|
const graphqlEndpoint = `${(request.headers.get("x-forwarded-proto")?.split(",")[0].trim() ?? url.protocol.replace(":", "")) + ":"}//${request.headers.get("x-forwarded-host")?.split(",")[0].trim() ?? request.headers.get("host") ?? ""}${(request.headers.get("x-forwarded-prefix")?.split(",")[0].trim().replace(/\/$/, "") ?? "") + (this.path === "/" ? "" : this.path)}/graphql/r`;
|
|
4684
|
+
const global = driveDoc.state.global;
|
|
4616
4685
|
return Response.json({
|
|
4617
4686
|
id: driveDoc.header.id,
|
|
4618
4687
|
slug: driveDoc.header.slug,
|
|
4619
4688
|
meta: driveDoc.header.meta,
|
|
4620
|
-
name:
|
|
4621
|
-
icon:
|
|
4689
|
+
name: global?.name || driveDoc.header.name,
|
|
4690
|
+
icon: global?.icon ?? void 0,
|
|
4622
4691
|
...graphqlEndpoint && { graphqlEndpoint }
|
|
4623
4692
|
});
|
|
4624
4693
|
} catch (error) {
|
|
@@ -5402,7 +5471,6 @@ const DocumentModelStateDTO = z.object({
|
|
|
5402
5471
|
}).strip();
|
|
5403
5472
|
const DocumentModelResultPageDTO = z.object({
|
|
5404
5473
|
items: z.array(DocumentModelStateDTO),
|
|
5405
|
-
totalCount: z.number().int(),
|
|
5406
5474
|
hasNextPage: z.boolean(),
|
|
5407
5475
|
hasPreviousPage: z.boolean(),
|
|
5408
5476
|
cursor: z.string().nullable().optional()
|
|
@@ -5423,7 +5491,6 @@ const PHDocumentDTO = z.object({
|
|
|
5423
5491
|
}).strip();
|
|
5424
5492
|
const PHDocumentResultPageDTO = z.object({
|
|
5425
5493
|
items: z.array(PHDocumentDTO),
|
|
5426
|
-
totalCount: z.number().int(),
|
|
5427
5494
|
hasNextPage: z.boolean(),
|
|
5428
5495
|
hasPreviousPage: z.boolean(),
|
|
5429
5496
|
cursor: z.string().nullable().optional()
|
|
@@ -5438,7 +5505,6 @@ const DocumentRelationshipDTO = z.object({
|
|
|
5438
5505
|
}).strip();
|
|
5439
5506
|
const DocumentRelationshipResultPageDTO = z.object({
|
|
5440
5507
|
items: z.array(DocumentRelationshipDTO),
|
|
5441
|
-
totalCount: z.number().int(),
|
|
5442
5508
|
hasNextPage: z.boolean(),
|
|
5443
5509
|
hasPreviousPage: z.boolean(),
|
|
5444
5510
|
cursor: z.string().nullable().optional()
|
|
@@ -5493,7 +5559,6 @@ const OperationDTO = z.object({
|
|
|
5493
5559
|
}).strip();
|
|
5494
5560
|
const OperationResultPageDTO = z.object({
|
|
5495
5561
|
items: z.array(OperationDTO),
|
|
5496
|
-
totalCount: z.number().int(),
|
|
5497
5562
|
hasNextPage: z.boolean(),
|
|
5498
5563
|
hasPreviousPage: z.boolean(),
|
|
5499
5564
|
cursor: z.string().nullable().optional()
|
|
@@ -5629,7 +5694,7 @@ function createReactorGraphQLClient(url, fetchImpl = fetch, headers) {
|
|
|
5629
5694
|
}
|
|
5630
5695
|
//#endregion
|
|
5631
5696
|
//#region src/graphql/reactor/schema.graphql
|
|
5632
|
-
var schema_default = "# Scalar types (for codegen - also defined in create-schema.ts)\nscalar JSONObject\nscalar DateTime\n\n# Input types\ninput PagingInput {\n limit: Int\n offset: Int\n cursor: String\n}\n\ninput ViewFilterInput {\n branch: String\n scopes: [String!]\n}\n\ninput SearchFilterInput {\n type: String\n parentId: String\n identifiers: [String!]\n}\n\ninput OperationsFilterInput {\n documentId: String!\n branch: String\n scopes: [String!]\n actionTypes: [String!]\n sinceRevision: Int\n timestampFrom: String\n timestampTo: String\n}\n\ninput DocumentOperationsFilterInput {\n branch: String\n scopes: [String!]\n actionTypes: [String!]\n sinceRevision: Int\n timestampFrom: String\n timestampTo: String\n}\n\n# Enums\nenum PropagationMode {\n CASCADE\n ORPHAN\n}\n\nenum DocumentChangeType {\n CREATED\n DELETED\n UPDATED\n PARENT_ADDED\n PARENT_REMOVED\n CHILD_ADDED\n CHILD_REMOVED\n}\n\n# Object types\ntype DocumentModelGlobalState {\n id: String!\n name: String!\n namespace: String\n version: String\n specification: JSONObject!\n}\n\ntype DocumentModelResultPage {\n items: [DocumentModelGlobalState!]!\n totalCount: Int!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\ntype Revision {\n scope: String!\n revision: Int!\n}\n\ntype PHDocument {\n id: String!\n slug: String\n preferredEditor: String\n name: String!\n documentType: String!\n state: JSONObject!\n revisionsList: [Revision!]!\n createdAtUtcIso: DateTime!\n lastModifiedAtUtcIso: DateTime!\n operations(\n filter: DocumentOperationsFilterInput\n paging: PagingInput\n ): ReactorOperationResultPage\n}\n\ntype PHDocumentResultPage {\n items: [PHDocument!]!\n totalCount: Int!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\n# A directed edge between two documents, with the metadata recorded against it.\ntype DocumentRelationship {\n sourceId: String!\n targetId: String!\n relationshipType: String!\n metadata: JSONObject\n createdAt: DateTime!\n updatedAt: DateTime!\n}\n\ntype DocumentRelationshipResultPage {\n items: [DocumentRelationship!]!\n totalCount: Int!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\ntype ReactorOperationResultPage {\n items: [ReactorOperation!]!\n totalCount: Int!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\ntype DeadLetterInfo {\n documentId: String!\n error: String!\n \"\"\"\n How the origin classified the failure. A peer needs this to mirror the origin's\n quarantine decision; without it a held auth operation would freeze the document\n on the peer side while the origin kept syncing.\n \"\"\"\n errorType: String\n jobId: String!\n branch: String!\n scopes: [String!]!\n operationCount: Int!\n}\n\ntype PollSyncEnvelopesResult {\n envelopes: [SyncEnvelope!]!\n ackOrdinal: Int!\n deadLetters: [DeadLetterInfo!]!\n hasMore: Boolean!\n}\n\ntype DocumentWithChildren {\n document: PHDocument!\n childIds: [String!]!\n}\n\ntype MoveRelationshipResult {\n source: PHDocument!\n target: PHDocument!\n}\n\ntype JobInfo {\n id: String!\n status: String!\n\n \"\"\"\n What the job produced, once it has produced anything. Null until then, which\n is the state every job is in when it is handed back from a submission.\n \"\"\"\n result: JSONObject\n\n error: String\n createdAt: DateTime!\n completedAt: DateTime\n}\n\ntype DocumentChangeEvent {\n type: DocumentChangeType!\n documents: [PHDocument!]!\n context: DocumentChangeContext\n}\n\ntype DocumentChangeContext {\n parentId: String\n childId: String\n}\n\ntype JobChangeEvent {\n jobId: String!\n status: String!\n\n \"\"\"\n What the job produced, once it has produced anything. Nullable for the same\n reason as `JobInfo.result`: a job that has not written yet has produced\n nothing, and an empty object would claim otherwise.\n \"\"\"\n result: JSONObject\n\n error: String\n}\n\ntype ReactorSignerUser {\n address: String!\n networkId: String!\n chainId: Int!\n}\n\ntype ReactorSignerApp {\n name: String!\n key: String!\n}\n\ntype ReactorSigner {\n user: ReactorSignerUser\n app: ReactorSignerApp\n signatures: [String!]!\n}\n\ntype ActionContext {\n signer: ReactorSigner\n}\n\ntype Action {\n id: String!\n type: String!\n timestampUtcMs: String!\n input: JSONObject!\n scope: String!\n context: ActionContext\n}\n\n\"\"\"\nOne operation an authorization preflight predicts a verdict for.\n\n`input` is what a conditional grant reads, so a candidate standing for a\nfilled-in form carries that form's input. Omitting it predicts the verdict an\nempty input earns, not the verdict the filled-in form will get.\n\"\"\"\ninput ActionCandidateInput {\n scope: String!\n type: String!\n input: JSONObject\n}\n\nenum AuthDecision {\n ALLOW\n DENY\n}\n\n\"\"\"\nOne candidate's predicted verdict. `reason` carries the refusal a DENY is\nrecorded with, and is null on an ALLOW.\n\"\"\"\ntype ActionEvaluation {\n decision: AuthDecision!\n reason: String\n}\n\n\"\"\"\nThe predicted verdicts for a set of candidates, in the order they were given,\nwith the aggregates a caller branches on.\n\nThe aggregates are redundant -- a verdict is binary -- and all four are returned\nso a caller reads the one its question is phrased in rather than negating\nanother. Over no candidates every aggregate is false: nothing is allowed and\nnothing is denied.\n\"\"\"\ntype ActionEvaluations {\n evaluations: [ActionEvaluation!]!\n allAllowed: Boolean!\n anyAllowed: Boolean!\n allDenied: Boolean!\n anyDenied: Boolean!\n}\n\n# Input types for sync operations\n\"\"\"\nAn action's context, as a caller submits it.\n\nDeclares every field `ActionContext` carries, because an input object rejects a\nfield it does not declare: an action stamped with the head it applies to - which\nis what a signing client sends - is refused outright if these are missing, and\nthat refusal is a whole-request one, not a per-field one.\n\n`prevOpHash` and `prevOpIndex` are the scope head the action was composed\nagainst. They are recorded rather than enforced; a signature is verified from\nthe params carried in its own tuple, which do not include them.\n\"\"\"\ninput ActionContextInput {\n \"\"\"\n The index of the last operation in the scope the action applies to.\n \"\"\"\n prevOpIndex: Int\n\n \"\"\"\n The hash of the state the action applies to.\n \"\"\"\n prevOpHash: String\n\n \"\"\"\n Covers replay of an operation that would otherwise be a no-op.\n \"\"\"\n nonce: String\n\n signer: ReactorSignerInput\n}\n\ninput ReactorSignerInput {\n user: ReactorSignerUserInput\n app: ReactorSignerAppInput\n signatures: [String!]!\n}\n\ninput ReactorSignerUserInput {\n address: String!\n networkId: String!\n chainId: Int!\n}\n\ninput ReactorSignerAppInput {\n name: String!\n key: String!\n}\n\ninput ActionInput {\n id: String!\n type: String!\n timestampUtcMs: String!\n input: JSONObject!\n scope: String!\n context: ActionContextInput\n}\n\n# Synchronization types\ntype ReactorOperation {\n index: Int!\n timestampUtcMs: String!\n hash: String!\n skip: Int!\n error: String\n deniedReason: String\n id: String\n action: Action!\n}\n\ninput OperationInput {\n index: Int!\n timestampUtcMs: String!\n hash: String!\n skip: Int!\n error: String\n deniedReason: String\n id: String\n action: ActionInput!\n}\n\ntype OperationContext {\n documentId: String!\n documentType: String!\n scope: String!\n branch: String!\n ordinal: Int!\n}\n\ninput OperationContextInput {\n documentId: String!\n documentType: String!\n scope: String!\n branch: String!\n ordinal: Int!\n}\n\ntype OperationWithContext {\n operation: ReactorOperation!\n context: OperationContext!\n}\n\ninput OperationWithContextInput {\n operation: OperationInput!\n context: OperationContextInput!\n}\n\ntype ChannelMeta {\n id: String!\n}\n\ninput ChannelMetaInput {\n id: String!\n}\n\ntype RemoteCursor {\n remoteName: String!\n cursorOrdinal: Int!\n lastSyncedAtUtcMs: String\n}\n\ninput RemoteCursorInput {\n remoteName: String!\n cursorOrdinal: Int!\n lastSyncedAtUtcMs: String\n}\n\nenum SyncEnvelopeType {\n OPERATIONS\n ACK\n}\n\ntype SyncEnvelope {\n type: SyncEnvelopeType!\n channelMeta: ChannelMeta!\n operations: [OperationWithContext!]\n cursor: RemoteCursor\n key: String\n dependsOn: [String!]\n}\n\ninput SyncEnvelopeInput {\n type: SyncEnvelopeType!\n channelMeta: ChannelMetaInput!\n operations: [OperationWithContextInput!]\n cursor: RemoteCursorInput\n key: String\n dependsOn: [String!]\n}\n\ninput RemoteFilterInput {\n documentId: [String!]!\n scope: [String!]!\n branch: String!\n}\n\ninput TouchChannelInput {\n id: String!\n name: String!\n collectionId: String!\n filter: RemoteFilterInput!\n sinceTimestampUtcMs: String!\n}\n\ntype TouchChannelResult {\n success: Boolean!\n ackOrdinal: Int!\n}\n\ntype Query {\n # Get document models for a namespace\n documentModels(\n namespace: String\n paging: PagingInput\n ): DocumentModelResultPage!\n\n # Get a specific document by ID or slug\n document(identifier: String!, view: ViewFilterInput): DocumentWithChildren\n\n # Get outgoing relationships of a given type from a source document\n documentOutgoingRelationships(\n sourceIdentifier: String!\n relationshipType: String!\n view: ViewFilterInput\n paging: PagingInput\n ): PHDocumentResultPage!\n\n # Get incoming relationships of a given type to a target document\n documentIncomingRelationships(\n targetIdentifier: String!\n relationshipType: String!\n view: ViewFilterInput\n paging: PagingInput\n ): PHDocumentResultPage!\n\n # Get the outgoing relationship edges of a source document. Unlike\n # documentOutgoingRelationships, which returns the documents at the far end,\n # this returns the edges themselves, carrying their metadata and timestamps.\n # Omit relationshipType to return edges of every type.\n documentOutgoingRelationshipEdges(\n sourceIdentifier: String!\n relationshipType: String\n view: ViewFilterInput\n paging: PagingInput\n ): DocumentRelationshipResultPage!\n\n # Get the incoming relationship edges of a target document. Unlike\n # documentIncomingRelationships, which returns the documents at the far end,\n # this returns the edges themselves, carrying their metadata and timestamps.\n # Omit relationshipType to return edges of every type.\n documentIncomingRelationshipEdges(\n targetIdentifier: String!\n relationshipType: String\n view: ViewFilterInput\n paging: PagingInput\n ): DocumentRelationshipResultPage!\n\n # Find documents by search criteria\n findDocuments(\n search: SearchFilterInput\n view: ViewFilterInput\n paging: PagingInput\n ): PHDocumentResultPage!\n\n # Get job status\n jobStatus(jobId: String!): JobInfo\n\n # Get operations for a document with filtering and pagination\n documentOperations(\n filter: OperationsFilterInput!\n paging: PagingInput\n ): ReactorOperationResultPage!\n\n \"\"\"\n Predicts whether the calling subject would be admitted to execute each of a\n set of candidate operations, without submitting any of them. A UI asks this to\n disable a control rather than offer an action that fails on submit.\n\n The answer is a prediction, not a promise:\n\n - Real admission compiles an append condition over everything it read and the\n store enforces it at write time. A preflight reads no future, so a policy\n change landing between this answer and the submit changes the verdict. The\n submit path stays the only authority.\n - The verdict is evaluated at the stream heads, so it is correct for a\n candidate about to be submitted. A backdated submission is out of contract;\n the reactor decides that one by position.\n - A candidate whose verdict depends on its input has to carry that input, since\n a conditional grant reads it.\n\n The subject is the authenticated caller and cannot be named in the request:\n answering for an arbitrary subject would disclose what a policy grants\n somebody else. It carries both the caller's address and the did:key of the app\n instance whose token authenticated the request, so a policy naming either\n matches the same principal the write path presents.\n\n Requires the reactor's authEnforcement feature flag. Without it the reactor\n holds no decision model, so this fails with extensions.code\n AUTH_EVALUATION_UNSUPPORTED rather than guessing.\n \"\"\"\n evaluateActions(\n documentIdentifier: String!\n branch: String\n candidates: [ActionCandidateInput!]!\n ): ActionEvaluations!\n\n \"\"\"\n Polls for sync envelopes from a channel.\n\n An operation stored before the API required an action id cannot be\n represented by this schema, and rather than serving a partial response beside\n a bare non-null violation, this fails with extensions.code\n MALFORMED_STORED_OPERATION naming the operation. That code means the failure\n is worth polling through: the document holding the operation needs repairing,\n but the channel serves every other document, and a peer that stopped polling\n would stop receiving those too.\n \"\"\"\n pollSyncEnvelopes(\n channelId: String!\n outboxAck: Int!\n outboxLatest: Int!\n ): PollSyncEnvelopesResult!\n}\n\ntype Mutation {\n # Create a new document\n createDocument(document: JSONObject!, parentIdentifier: String): PHDocument!\n\n # Create an empty document of specified type\n createEmptyDocument(\n documentType: String!\n parentIdentifier: String\n ): PHDocument!\n\n \"\"\"\n Applies actions to a document and waits for the result.\n\n Each action is coerced against `ActionInput`, so one missing a field the wire\n declares is refused before any work starts. The id in particular: it is hashed\n into the operation id and replay dedupes by it, so an action without one is\n stored under an operation id shared by every id-less operation on the same\n document, scope and branch.\n\n Named for `IReactorClient.execute`, which this is the wire form of. `branch`\n defaults to `main`.\n \"\"\"\n execute(\n documentIdentifier: String!\n actions: [ActionInput!]!\n branch: String\n ): PHDocument!\n\n \"\"\"\n Submits actions to a document and returns the job that will apply them.\n\n Coerced exactly as `execute` is, so a malformed action is refused here rather\n than surfacing later as a failed job. Returns the job rather than only its id,\n so a caller has the status and the creation time it would otherwise have to\n ask for; `result` is null until the job produces one.\n \"\"\"\n executeAsync(\n documentIdentifier: String!\n actions: [ActionInput!]!\n branch: String\n ): JobInfo!\n\n # Apply actions to a document (synchronous)\n mutateDocument(\n documentIdentifier: String!\n actions: [JSONObject!]!\n view: ViewFilterInput\n ): PHDocument!\n @deprecated(\n reason: \"Use execute. Actions here are untyped, so a malformed one is refused by a hand-written check rather than by the schema, and `view.scopes` is accepted but ignored.\"\n )\n\n # Submit actions to a document (asynchronous)\n mutateDocumentAsync(\n documentIdentifier: String!\n actions: [JSONObject!]!\n view: ViewFilterInput\n ): String!\n @deprecated(\n reason: \"Use executeAsync, which is typed and returns the job rather than only its id.\"\n )\n\n # Rename a document\n renameDocument(\n documentIdentifier: String!\n name: String!\n branch: String\n ): PHDocument!\n\n # Update the preferred editor recorded in the document header meta.\n # Pass null/omit to clear it.\n setPreferredEditor(\n documentIdentifier: String!\n preferredEditor: String\n branch: String\n ): PHDocument!\n\n # Add a relationship between two documents. Adding one that already exists is\n # a no-op, metadata included -- use updateRelationship to change an edge.\n addRelationship(\n sourceIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n metadata: JSONObject\n branch: String\n ): PHDocument!\n\n # Replace the metadata of an existing relationship, preserving its createdAt.\n # Omitting metadata, or passing null, clears it.\n updateRelationship(\n sourceIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n metadata: JSONObject\n branch: String\n ): PHDocument!\n\n # Remove a relationship between two documents\n removeRelationship(\n sourceIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n branch: String\n ): PHDocument!\n\n # Move a relationship from one source to another\n moveRelationship(\n sourceParentIdentifier: String!\n targetParentIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n branch: String\n ): MoveRelationshipResult!\n\n # Delete a single document\n deleteDocument(identifier: String!, propagate: PropagationMode): Boolean!\n\n # Delete multiple documents\n deleteDocuments(identifiers: [String!]!, propagate: PropagationMode): Boolean!\n\n # Touch (create or update) a channel for sync\n touchChannel(input: TouchChannelInput!): TouchChannelResult!\n\n # Push sync envelopes to a channel\n pushSyncEnvelopes(envelopes: [SyncEnvelopeInput!]!): Boolean!\n}\n\ntype Subscription {\n # Subscribe to document changes\n documentChanges(\n search: SearchFilterInput\n view: ViewFilterInput\n ): DocumentChangeEvent!\n\n # Subscribe to job changes\n jobChanges(jobId: String!): JobChangeEvent!\n}\n";
|
|
5697
|
+
var schema_default = "# Scalar types (for codegen - also defined in create-schema.ts)\nscalar JSONObject\nscalar DateTime\n\n# Input types\ninput PagingInput {\n limit: Int\n offset: Int\n cursor: String\n}\n\ninput ViewFilterInput {\n branch: String\n scopes: [String!]\n}\n\ninput SearchFilterInput {\n type: String\n parentId: String\n identifiers: [String!]\n}\n\ninput OperationsFilterInput {\n documentId: String!\n branch: String\n scopes: [String!]\n actionTypes: [String!]\n sinceRevision: Int\n timestampFrom: String\n timestampTo: String\n}\n\ninput DocumentOperationsFilterInput {\n branch: String\n scopes: [String!]\n actionTypes: [String!]\n sinceRevision: Int\n timestampFrom: String\n timestampTo: String\n}\n\n# Enums\nenum PropagationMode {\n CASCADE\n ORPHAN\n}\n\nenum DocumentChangeType {\n CREATED\n DELETED\n UPDATED\n PARENT_ADDED\n PARENT_REMOVED\n CHILD_ADDED\n CHILD_REMOVED\n}\n\n# Object types\ntype DocumentModelGlobalState {\n id: String!\n name: String!\n namespace: String\n version: String\n specification: JSONObject!\n}\n\ntype DocumentModelResultPage {\n items: [DocumentModelGlobalState!]!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\ntype Revision {\n scope: String!\n revision: Int!\n}\n\ntype PHDocument {\n id: String!\n slug: String\n preferredEditor: String\n name: String!\n documentType: String!\n state: JSONObject!\n revisionsList: [Revision!]!\n createdAtUtcIso: DateTime!\n lastModifiedAtUtcIso: DateTime!\n operations(\n filter: DocumentOperationsFilterInput\n paging: PagingInput\n ): ReactorOperationResultPage\n}\n\ntype PHDocumentResultPage {\n items: [PHDocument!]!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\n# A directed edge between two documents, with the metadata recorded against it.\ntype DocumentRelationship {\n sourceId: String!\n targetId: String!\n relationshipType: String!\n metadata: JSONObject\n createdAt: DateTime!\n updatedAt: DateTime!\n}\n\ntype DocumentRelationshipResultPage {\n items: [DocumentRelationship!]!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\ntype ReactorOperationResultPage {\n items: [ReactorOperation!]!\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n cursor: String\n}\n\ntype DeadLetterInfo {\n documentId: String!\n error: String!\n \"\"\"\n How the origin classified the failure. A peer needs this to mirror the origin's\n quarantine decision; without it a held auth operation would freeze the document\n on the peer side while the origin kept syncing.\n \"\"\"\n errorType: String\n jobId: String!\n branch: String!\n scopes: [String!]!\n operationCount: Int!\n}\n\ntype PollSyncEnvelopesResult {\n envelopes: [SyncEnvelope!]!\n ackOrdinal: Int!\n deadLetters: [DeadLetterInfo!]!\n hasMore: Boolean!\n}\n\ntype DocumentWithChildren {\n document: PHDocument!\n childIds: [String!]!\n}\n\ntype MoveRelationshipResult {\n source: PHDocument!\n target: PHDocument!\n}\n\ntype JobInfo {\n id: String!\n status: String!\n\n \"\"\"\n What the job produced, once it has produced anything. Null until then, which\n is the state every job is in when it is handed back from a submission.\n \"\"\"\n result: JSONObject\n\n error: String\n createdAt: DateTime!\n completedAt: DateTime\n}\n\ntype DocumentChangeEvent {\n type: DocumentChangeType!\n documents: [PHDocument!]!\n context: DocumentChangeContext\n}\n\ntype DocumentChangeContext {\n parentId: String\n childId: String\n}\n\ntype JobChangeEvent {\n jobId: String!\n status: String!\n\n \"\"\"\n What the job produced, once it has produced anything. Nullable for the same\n reason as `JobInfo.result`: a job that has not written yet has produced\n nothing, and an empty object would claim otherwise.\n \"\"\"\n result: JSONObject\n\n error: String\n}\n\ntype ReactorSignerUser {\n address: String!\n networkId: String!\n chainId: Int!\n}\n\ntype ReactorSignerApp {\n name: String!\n key: String!\n}\n\ntype ReactorSigner {\n user: ReactorSignerUser\n app: ReactorSignerApp\n signatures: [String!]!\n}\n\ntype ActionContext {\n signer: ReactorSigner\n}\n\ntype Action {\n id: String!\n type: String!\n timestampUtcMs: String!\n input: JSONObject!\n scope: String!\n context: ActionContext\n}\n\n\"\"\"\nOne operation an authorization preflight predicts a verdict for.\n\n`input` is what a conditional grant reads, so a candidate standing for a\nfilled-in form carries that form's input. Omitting it predicts the verdict an\nempty input earns, not the verdict the filled-in form will get.\n\"\"\"\ninput ActionCandidateInput {\n scope: String!\n type: String!\n input: JSONObject\n}\n\nenum AuthDecision {\n ALLOW\n DENY\n}\n\n\"\"\"\nOne candidate's predicted verdict. `reason` carries the refusal a DENY is\nrecorded with, and is null on an ALLOW.\n\"\"\"\ntype ActionEvaluation {\n decision: AuthDecision!\n reason: String\n}\n\n\"\"\"\nThe predicted verdicts for a set of candidates, in the order they were given,\nwith the aggregates a caller branches on.\n\nThe aggregates are redundant -- a verdict is binary -- and all four are returned\nso a caller reads the one its question is phrased in rather than negating\nanother. Over no candidates every aggregate is false: nothing is allowed and\nnothing is denied.\n\"\"\"\ntype ActionEvaluations {\n evaluations: [ActionEvaluation!]!\n allAllowed: Boolean!\n anyAllowed: Boolean!\n allDenied: Boolean!\n anyDenied: Boolean!\n}\n\n# Input types for sync operations\n\"\"\"\nAn action's context, as a caller submits it.\n\nDeclares every field `ActionContext` carries, because an input object rejects a\nfield it does not declare: an action stamped with the head it applies to - which\nis what a signing client sends - is refused outright if these are missing, and\nthat refusal is a whole-request one, not a per-field one.\n\n`prevOpHash` and `prevOpIndex` are the scope head the action was composed\nagainst. They are recorded rather than enforced; a signature is verified from\nthe params carried in its own tuple, which do not include them.\n\"\"\"\ninput ActionContextInput {\n \"\"\"\n The index of the last operation in the scope the action applies to.\n \"\"\"\n prevOpIndex: Int\n\n \"\"\"\n The hash of the state the action applies to.\n \"\"\"\n prevOpHash: String\n\n \"\"\"\n Covers replay of an operation that would otherwise be a no-op.\n \"\"\"\n nonce: String\n\n signer: ReactorSignerInput\n}\n\ninput ReactorSignerInput {\n user: ReactorSignerUserInput\n app: ReactorSignerAppInput\n signatures: [String!]!\n}\n\ninput ReactorSignerUserInput {\n address: String!\n networkId: String!\n chainId: Int!\n}\n\ninput ReactorSignerAppInput {\n name: String!\n key: String!\n}\n\ninput ActionInput {\n id: String!\n type: String!\n timestampUtcMs: String!\n input: JSONObject!\n scope: String!\n context: ActionContextInput\n}\n\n# Synchronization types\ntype ReactorOperation {\n index: Int!\n timestampUtcMs: String!\n hash: String!\n skip: Int!\n error: String\n deniedReason: String\n id: String\n action: Action!\n}\n\ninput OperationInput {\n index: Int!\n timestampUtcMs: String!\n hash: String!\n skip: Int!\n error: String\n deniedReason: String\n id: String\n action: ActionInput!\n}\n\ntype OperationContext {\n documentId: String!\n documentType: String!\n scope: String!\n branch: String!\n ordinal: Int!\n}\n\ninput OperationContextInput {\n documentId: String!\n documentType: String!\n scope: String!\n branch: String!\n ordinal: Int!\n}\n\ntype OperationWithContext {\n operation: ReactorOperation!\n context: OperationContext!\n}\n\ninput OperationWithContextInput {\n operation: OperationInput!\n context: OperationContextInput!\n}\n\ntype ChannelMeta {\n id: String!\n}\n\ninput ChannelMetaInput {\n id: String!\n}\n\ntype RemoteCursor {\n remoteName: String!\n cursorOrdinal: Int!\n lastSyncedAtUtcMs: String\n}\n\ninput RemoteCursorInput {\n remoteName: String!\n cursorOrdinal: Int!\n lastSyncedAtUtcMs: String\n}\n\nenum SyncEnvelopeType {\n OPERATIONS\n ACK\n}\n\ntype SyncEnvelope {\n type: SyncEnvelopeType!\n channelMeta: ChannelMeta!\n operations: [OperationWithContext!]\n cursor: RemoteCursor\n key: String\n dependsOn: [String!]\n}\n\ninput SyncEnvelopeInput {\n type: SyncEnvelopeType!\n channelMeta: ChannelMetaInput!\n operations: [OperationWithContextInput!]\n cursor: RemoteCursorInput\n key: String\n dependsOn: [String!]\n}\n\ninput RemoteFilterInput {\n documentId: [String!]!\n scope: [String!]!\n branch: String!\n}\n\ninput TouchChannelInput {\n id: String!\n name: String!\n collectionId: String!\n filter: RemoteFilterInput!\n sinceTimestampUtcMs: String!\n}\n\ntype TouchChannelResult {\n success: Boolean!\n ackOrdinal: Int!\n}\n\ntype Query {\n # Get document models for a namespace\n documentModels(\n namespace: String\n paging: PagingInput\n ): DocumentModelResultPage!\n\n # Get a specific document by ID or slug\n document(identifier: String!, view: ViewFilterInput): DocumentWithChildren\n\n # Get outgoing relationships of a given type from a source document\n documentOutgoingRelationships(\n sourceIdentifier: String!\n relationshipType: String!\n view: ViewFilterInput\n paging: PagingInput\n ): PHDocumentResultPage!\n\n # Get incoming relationships of a given type to a target document\n documentIncomingRelationships(\n targetIdentifier: String!\n relationshipType: String!\n view: ViewFilterInput\n paging: PagingInput\n ): PHDocumentResultPage!\n\n # Get the outgoing relationship edges of a source document. Unlike\n # documentOutgoingRelationships, which returns the documents at the far end,\n # this returns the edges themselves, carrying their metadata and timestamps.\n # Omit relationshipType to return edges of every type.\n documentOutgoingRelationshipEdges(\n sourceIdentifier: String!\n relationshipType: String\n view: ViewFilterInput\n paging: PagingInput\n ): DocumentRelationshipResultPage!\n\n # Get the incoming relationship edges of a target document. Unlike\n # documentIncomingRelationships, which returns the documents at the far end,\n # this returns the edges themselves, carrying their metadata and timestamps.\n # Omit relationshipType to return edges of every type.\n documentIncomingRelationshipEdges(\n targetIdentifier: String!\n relationshipType: String\n view: ViewFilterInput\n paging: PagingInput\n ): DocumentRelationshipResultPage!\n\n # Find documents by search criteria\n findDocuments(\n search: SearchFilterInput\n view: ViewFilterInput\n paging: PagingInput\n ): PHDocumentResultPage!\n\n # Get job status\n jobStatus(jobId: String!): JobInfo\n\n # Get operations for a document with filtering and pagination\n documentOperations(\n filter: OperationsFilterInput!\n paging: PagingInput\n ): ReactorOperationResultPage!\n\n \"\"\"\n Predicts whether the calling subject would be admitted to execute each of a\n set of candidate operations, without submitting any of them. A UI asks this to\n disable a control rather than offer an action that fails on submit.\n\n The answer is a prediction, not a promise:\n\n - Real admission compiles an append condition over everything it read and the\n store enforces it at write time. A preflight reads no future, so a policy\n change landing between this answer and the submit changes the verdict. The\n submit path stays the only authority.\n - The verdict is evaluated at the stream heads, so it is correct for a\n candidate about to be submitted. A backdated submission is out of contract;\n the reactor decides that one by position.\n - A candidate whose verdict depends on its input has to carry that input, since\n a conditional grant reads it.\n\n The subject is the authenticated caller and cannot be named in the request:\n answering for an arbitrary subject would disclose what a policy grants\n somebody else. It carries both the caller's address and the did:key of the app\n instance whose token authenticated the request, so a policy naming either\n matches the same principal the write path presents.\n\n Requires the reactor's authEnforcement feature flag. Without it the reactor\n holds no decision model, so this fails with extensions.code\n AUTH_EVALUATION_UNSUPPORTED rather than guessing.\n \"\"\"\n evaluateActions(\n documentIdentifier: String!\n branch: String\n candidates: [ActionCandidateInput!]!\n ): ActionEvaluations!\n\n \"\"\"\n Polls for sync envelopes from a channel.\n\n An operation stored before the API required an action id cannot be\n represented by this schema, and rather than serving a partial response beside\n a bare non-null violation, this fails with extensions.code\n MALFORMED_STORED_OPERATION naming the operation. That code means the failure\n is worth polling through: the document holding the operation needs repairing,\n but the channel serves every other document, and a peer that stopped polling\n would stop receiving those too.\n \"\"\"\n pollSyncEnvelopes(\n channelId: String!\n outboxAck: Int!\n outboxLatest: Int!\n ): PollSyncEnvelopesResult!\n}\n\ntype Mutation {\n # Create a new document\n createDocument(document: JSONObject!, parentIdentifier: String): PHDocument!\n\n # Create an empty document of specified type\n createEmptyDocument(\n documentType: String!\n parentIdentifier: String\n ): PHDocument!\n\n \"\"\"\n Applies actions to a document and waits for the result.\n\n Each action is coerced against `ActionInput`, so one missing a field the wire\n declares is refused before any work starts. The id in particular: it is hashed\n into the operation id and replay dedupes by it, so an action without one is\n stored under an operation id shared by every id-less operation on the same\n document, scope and branch.\n\n Named for `IReactorClient.execute`, which this is the wire form of. `branch`\n defaults to `main`.\n \"\"\"\n execute(\n documentIdentifier: String!\n actions: [ActionInput!]!\n branch: String\n ): PHDocument!\n\n \"\"\"\n Submits actions to a document and returns the job that will apply them.\n\n Coerced exactly as `execute` is, so a malformed action is refused here rather\n than surfacing later as a failed job. Returns the job rather than only its id,\n so a caller has the status and the creation time it would otherwise have to\n ask for; `result` is null until the job produces one.\n \"\"\"\n executeAsync(\n documentIdentifier: String!\n actions: [ActionInput!]!\n branch: String\n ): JobInfo!\n\n # Apply actions to a document (synchronous)\n mutateDocument(\n documentIdentifier: String!\n actions: [JSONObject!]!\n view: ViewFilterInput\n ): PHDocument!\n @deprecated(\n reason: \"Use execute. Actions here are untyped, so a malformed one is refused by a hand-written check rather than by the schema, and `view.scopes` is accepted but ignored.\"\n )\n\n # Submit actions to a document (asynchronous)\n mutateDocumentAsync(\n documentIdentifier: String!\n actions: [JSONObject!]!\n view: ViewFilterInput\n ): String!\n @deprecated(\n reason: \"Use executeAsync, which is typed and returns the job rather than only its id.\"\n )\n\n # Rename a document\n renameDocument(\n documentIdentifier: String!\n name: String!\n branch: String\n ): PHDocument!\n\n # Update the preferred editor recorded in the document header meta.\n # Pass null/omit to clear it.\n setPreferredEditor(\n documentIdentifier: String!\n preferredEditor: String\n branch: String\n ): PHDocument!\n\n # Add a relationship between two documents. Adding one that already exists is\n # a no-op, metadata included -- use updateRelationship to change an edge.\n addRelationship(\n sourceIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n metadata: JSONObject\n branch: String\n ): PHDocument!\n\n # Replace the metadata of an existing relationship, preserving its createdAt.\n # Omitting metadata, or passing null, clears it.\n updateRelationship(\n sourceIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n metadata: JSONObject\n branch: String\n ): PHDocument!\n\n # Remove a relationship between two documents\n removeRelationship(\n sourceIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n branch: String\n ): PHDocument!\n\n # Move a relationship from one source to another\n moveRelationship(\n sourceParentIdentifier: String!\n targetParentIdentifier: String!\n targetIdentifier: String!\n relationshipType: String!\n branch: String\n ): MoveRelationshipResult!\n\n # Delete a single document\n deleteDocument(identifier: String!, propagate: PropagationMode): Boolean!\n\n # Delete multiple documents\n deleteDocuments(identifiers: [String!]!, propagate: PropagationMode): Boolean!\n\n # Touch (create or update) a channel for sync\n touchChannel(input: TouchChannelInput!): TouchChannelResult!\n\n # Push sync envelopes to a channel\n pushSyncEnvelopes(envelopes: [SyncEnvelopeInput!]!): Boolean!\n}\n\ntype Subscription {\n # Subscribe to document changes\n documentChanges(\n search: SearchFilterInput\n view: ViewFilterInput\n ): DocumentChangeEvent!\n\n # Subscribe to job changes\n jobChanges(jobId: String!): JobChangeEvent!\n}\n";
|
|
5633
5698
|
//#endregion
|
|
5634
5699
|
//#region src/graphql/reactor/pubsub.ts
|
|
5635
5700
|
const pubSub = new PubSub();
|
|
@@ -5640,26 +5705,79 @@ const SUBSCRIPTION_TRIGGERS = {
|
|
|
5640
5705
|
DOCUMENT_CHANGES: "DOCUMENT_CHANGES",
|
|
5641
5706
|
JOB_CHANGES: "JOB_CHANGES"
|
|
5642
5707
|
};
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5708
|
+
function subjectKey(subject) {
|
|
5709
|
+
return `${subject.address ?? ""}|${subject.key ?? ""}`;
|
|
5710
|
+
}
|
|
5711
|
+
/**
|
|
5712
|
+
* The reactor's change feed, read once per distinct subject and shared by that
|
|
5713
|
+
* subject's GraphQL subscriptions. Each feed is read as its subject, so the
|
|
5714
|
+
* client withholds what that subject may not read; one feed read with no view
|
|
5715
|
+
* would gate every subscriber as the host.
|
|
5716
|
+
*/
|
|
5717
|
+
var DocumentChangeFeed = class {
|
|
5718
|
+
reactorClient;
|
|
5719
|
+
#pubSub = new PubSub();
|
|
5720
|
+
#feeds = /* @__PURE__ */ new Map();
|
|
5721
|
+
constructor(reactorClient) {
|
|
5722
|
+
this.reactorClient = reactorClient;
|
|
5723
|
+
}
|
|
5724
|
+
subscribe(subject) {
|
|
5725
|
+
const key = subjectKey(subject);
|
|
5726
|
+
const topic = `${SUBSCRIPTION_TRIGGERS.DOCUMENT_CHANGES}:${key}`;
|
|
5727
|
+
const iterator = this.#pubSub.asyncIterableIterator(topic);
|
|
5728
|
+
this.#acquire(key, topic, subject);
|
|
5729
|
+
let released = false;
|
|
5730
|
+
const release = () => {
|
|
5731
|
+
if (!released) {
|
|
5732
|
+
released = true;
|
|
5733
|
+
this.#release(key);
|
|
5734
|
+
}
|
|
5651
5735
|
};
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5736
|
+
return {
|
|
5737
|
+
next: () => iterator.next(),
|
|
5738
|
+
return: () => {
|
|
5739
|
+
release();
|
|
5740
|
+
return iterator.return();
|
|
5741
|
+
},
|
|
5742
|
+
throw: (error) => {
|
|
5743
|
+
release();
|
|
5744
|
+
return iterator.throw(error);
|
|
5745
|
+
},
|
|
5746
|
+
[Symbol.asyncIterator]() {
|
|
5747
|
+
return this;
|
|
5748
|
+
}
|
|
5749
|
+
};
|
|
5750
|
+
}
|
|
5751
|
+
#acquire(key, topic, subject) {
|
|
5752
|
+
const feed = this.#feeds.get(key);
|
|
5753
|
+
if (feed) {
|
|
5754
|
+
feed.subscribers++;
|
|
5755
|
+
return;
|
|
5660
5756
|
}
|
|
5661
|
-
|
|
5662
|
-
}
|
|
5757
|
+
const view = { subject };
|
|
5758
|
+
const unsubscribe = this.reactorClient.subscribe({}, (event) => {
|
|
5759
|
+
const payload = {
|
|
5760
|
+
documentChanges: event,
|
|
5761
|
+
search: {},
|
|
5762
|
+
view
|
|
5763
|
+
};
|
|
5764
|
+
this.#pubSub.publish(topic, payload);
|
|
5765
|
+
}, view);
|
|
5766
|
+
this.#feeds.set(key, {
|
|
5767
|
+
unsubscribe,
|
|
5768
|
+
subscribers: 1
|
|
5769
|
+
});
|
|
5770
|
+
}
|
|
5771
|
+
#release(key) {
|
|
5772
|
+
const feed = this.#feeds.get(key);
|
|
5773
|
+
if (!feed) return;
|
|
5774
|
+
feed.subscribers--;
|
|
5775
|
+
if (feed.subscribers === 0) {
|
|
5776
|
+
this.#feeds.delete(key);
|
|
5777
|
+
feed.unsubscribe();
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5780
|
+
};
|
|
5663
5781
|
const activeJobSubscriptions = /* @__PURE__ */ new Map();
|
|
5664
5782
|
function ensureJobSubscription(reactorClient, jobId) {
|
|
5665
5783
|
let subscription = activeJobSubscriptions.get(jobId);
|
|
@@ -5724,6 +5842,11 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5724
5842
|
}
|
|
5725
5843
|
name = "r";
|
|
5726
5844
|
hasSubscriptions = true;
|
|
5845
|
+
#documentChanges;
|
|
5846
|
+
get documentChanges() {
|
|
5847
|
+
this.#documentChanges ??= new DocumentChangeFeed(this.reactorClient);
|
|
5848
|
+
return this.#documentChanges;
|
|
5849
|
+
}
|
|
5727
5850
|
/**
|
|
5728
5851
|
* Check operation-level permissions for an array of actions.
|
|
5729
5852
|
* Delegates to base assertCanExecuteOperation for each action.
|
|
@@ -5762,10 +5885,10 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5762
5885
|
* or they become a way to enumerate around that check. Supreme admins read
|
|
5763
5886
|
* everything, so the per-edge check is skipped for them.
|
|
5764
5887
|
*
|
|
5765
|
-
* The
|
|
5766
|
-
*
|
|
5767
|
-
*
|
|
5768
|
-
*
|
|
5888
|
+
* The cursor describes where to resume in the underlying unfiltered stream,
|
|
5889
|
+
* so it is left as it came. A filtered page is therefore often shorter than
|
|
5890
|
+
* the requested limit, and that is the stream continuing rather than a sign
|
|
5891
|
+
* it ended.
|
|
5769
5892
|
*/
|
|
5770
5893
|
async filterRelationshipEdges(page, farEnd, ctx) {
|
|
5771
5894
|
if (this.authorizationService.isSupremeAdmin(ctx.user?.address)) return page;
|
|
@@ -5780,19 +5903,9 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5780
5903
|
}
|
|
5781
5904
|
if (canRead) items.push(edge);
|
|
5782
5905
|
}
|
|
5783
|
-
return this.servedPage(page, items);
|
|
5784
|
-
}
|
|
5785
|
-
/**
|
|
5786
|
-
* Restates a page's totalCount over the items that survived a read filter, so
|
|
5787
|
-
* that the difference between the two cannot be read off as a count of what
|
|
5788
|
-
* the caller was not allowed to see.
|
|
5789
|
-
*/
|
|
5790
|
-
servedPage(page, items) {
|
|
5791
|
-
const withheld = page.items.length - items.length;
|
|
5792
5906
|
return {
|
|
5793
5907
|
...page,
|
|
5794
|
-
items
|
|
5795
|
-
totalCount: Math.max(0, page.totalCount - withheld)
|
|
5908
|
+
items
|
|
5796
5909
|
};
|
|
5797
5910
|
}
|
|
5798
5911
|
/**
|
|
@@ -5828,9 +5941,9 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5828
5941
|
* reports the liveness that keeps it from being reclaimed -- but they never
|
|
5829
5942
|
* adopt, since the push path has no drive check to clear the claimant.
|
|
5830
5943
|
*
|
|
5831
|
-
* Nothing is enforced or adopted without a serving gate
|
|
5832
|
-
*
|
|
5833
|
-
* belong to
|
|
5944
|
+
* Nothing is enforced or adopted without a serving gate: with no gate the
|
|
5945
|
+
* channel serves every subject alike, so there is no subject for it to
|
|
5946
|
+
* belong to.
|
|
5834
5947
|
*/
|
|
5835
5948
|
async #bindOrRefuseChannel(channelId, ctx, options = {}) {
|
|
5836
5949
|
if (!this.syncServingGate) return;
|
|
@@ -5924,7 +6037,10 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5924
6037
|
if (!this.authorizationService.isSupremeAdmin(ctx.user?.address)) {
|
|
5925
6038
|
const filteredItems = [];
|
|
5926
6039
|
for (const item of result.items) if (await this.canReadDocument(item.id, ctx)) filteredItems.push(item);
|
|
5927
|
-
return
|
|
6040
|
+
return {
|
|
6041
|
+
...result,
|
|
6042
|
+
items: filteredItems
|
|
6043
|
+
};
|
|
5928
6044
|
}
|
|
5929
6045
|
return result;
|
|
5930
6046
|
} catch (error) {
|
|
@@ -5970,7 +6086,10 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5970
6086
|
if (!this.authorizationService.isSupremeAdmin(ctx.user?.address)) {
|
|
5971
6087
|
const filteredItems = [];
|
|
5972
6088
|
for (const item of result.items) if (await this.canReadDocument(item.id, ctx)) filteredItems.push(item);
|
|
5973
|
-
return
|
|
6089
|
+
return {
|
|
6090
|
+
...result,
|
|
6091
|
+
items: filteredItems
|
|
6092
|
+
};
|
|
5974
6093
|
}
|
|
5975
6094
|
return result;
|
|
5976
6095
|
} catch (error) {
|
|
@@ -5978,10 +6097,10 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5978
6097
|
throw error;
|
|
5979
6098
|
}
|
|
5980
6099
|
},
|
|
5981
|
-
jobStatus: async (_parent, args) => {
|
|
6100
|
+
jobStatus: async (_parent, args, ctx) => {
|
|
5982
6101
|
this.logger.debug("jobStatus(@args)", args);
|
|
5983
6102
|
try {
|
|
5984
|
-
return await jobStatus(this.reactorClient, args);
|
|
6103
|
+
return await jobStatus(this.reactorClient, args, (id) => this.servesDocument(id, ctx));
|
|
5985
6104
|
} catch (error) {
|
|
5986
6105
|
this.logger.error("Error in jobStatus: @Error", error);
|
|
5987
6106
|
throw error;
|
|
@@ -6003,6 +6122,13 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6003
6122
|
throw error;
|
|
6004
6123
|
}
|
|
6005
6124
|
},
|
|
6125
|
+
/**
|
|
6126
|
+
* Gated on reading the document, the same gate every other read here
|
|
6127
|
+
* carries: a verdict is derived from the document's policy, so a caller
|
|
6128
|
+
* who may not read the document may not preflight against it either.
|
|
6129
|
+
* That gate decides whether the query runs; the answer comes entirely
|
|
6130
|
+
* from the reactor's decision model.
|
|
6131
|
+
*/
|
|
6006
6132
|
evaluateActions: async (_parent, args, ctx) => {
|
|
6007
6133
|
this.logger.debug("evaluateActions(@args)", args);
|
|
6008
6134
|
try {
|
|
@@ -6058,7 +6184,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6058
6184
|
const parent = await document(this.reactorClient, { identifier: args.parentIdentifier });
|
|
6059
6185
|
await this.assertCanWriteCanonical(parent.document.id, ctx);
|
|
6060
6186
|
} else this.assertCanCreate(ctx);
|
|
6061
|
-
const result = await createDocument(this.reactorClient, args, this.graphqlManager.reactorDriveClient);
|
|
6187
|
+
const result = await createDocument(this.reactorClient, args, this.graphqlManager.reactorDriveClient, this.viewSubject(ctx));
|
|
6062
6188
|
if (result?.id && isDriveContainerType(result.documentType)) this.graphqlManager.driveOwnershipCache.add(result.id);
|
|
6063
6189
|
if (ctx.user?.address && result?.id) await this.documentPermissionService?.initializeDocumentProtection(result.id, ctx.user.address, this.authorizationService.config.defaultProtection);
|
|
6064
6190
|
return result;
|
|
@@ -6074,7 +6200,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6074
6200
|
const parent = await document(this.reactorClient, { identifier: args.parentIdentifier });
|
|
6075
6201
|
await this.assertCanWriteCanonical(parent.document.id, ctx);
|
|
6076
6202
|
} else this.assertCanCreate(ctx);
|
|
6077
|
-
const result = await createEmptyDocument(this.reactorClient, args, this.graphqlManager.reactorDriveClient);
|
|
6203
|
+
const result = await createEmptyDocument(this.reactorClient, args, this.graphqlManager.reactorDriveClient, this.viewSubject(ctx));
|
|
6078
6204
|
if (result?.id && isDriveContainerType(result.documentType)) this.graphqlManager.driveOwnershipCache.add(result.id);
|
|
6079
6205
|
if (ctx.user?.address && result?.id) await this.documentPermissionService?.initializeDocumentProtection(result.id, ctx.user.address, this.authorizationService.config.defaultProtection);
|
|
6080
6206
|
return result;
|
|
@@ -6090,7 +6216,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6090
6216
|
return await execute(this.reactorClient, {
|
|
6091
6217
|
...args,
|
|
6092
6218
|
documentIdentifier: handle.fetchIdentifier
|
|
6093
|
-
});
|
|
6219
|
+
}, this.viewSubject(ctx));
|
|
6094
6220
|
} catch (error) {
|
|
6095
6221
|
this.logger.error("Error in execute(@args): @Error", args, error);
|
|
6096
6222
|
throw error;
|
|
@@ -6116,7 +6242,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6116
6242
|
return await mutateDocument(this.reactorClient, {
|
|
6117
6243
|
...args,
|
|
6118
6244
|
documentIdentifier: handle.fetchIdentifier
|
|
6119
|
-
});
|
|
6245
|
+
}, this.viewSubject(ctx));
|
|
6120
6246
|
} catch (error) {
|
|
6121
6247
|
this.logger.error("Error in mutateDocument(@args): @Error", args, error);
|
|
6122
6248
|
throw error;
|
|
@@ -6142,7 +6268,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6142
6268
|
return await renameDocument(this.reactorClient, {
|
|
6143
6269
|
...args,
|
|
6144
6270
|
documentIdentifier: handle.fetchIdentifier
|
|
6145
|
-
});
|
|
6271
|
+
}, void 0, this.viewSubject(ctx));
|
|
6146
6272
|
} catch (error) {
|
|
6147
6273
|
this.logger.error("Error in renameDocument(@args): @Error", args, error);
|
|
6148
6274
|
throw error;
|
|
@@ -6155,7 +6281,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6155
6281
|
return await setPreferredEditor(this.reactorClient, {
|
|
6156
6282
|
...args,
|
|
6157
6283
|
documentIdentifier: handle.fetchIdentifier
|
|
6158
|
-
});
|
|
6284
|
+
}, void 0, this.viewSubject(ctx));
|
|
6159
6285
|
} catch (error) {
|
|
6160
6286
|
this.logger.error("Error in setPreferredEditor(@args): @Error", args, error);
|
|
6161
6287
|
throw error;
|
|
@@ -6168,7 +6294,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6168
6294
|
return await addRelationship(this.reactorClient, {
|
|
6169
6295
|
...args,
|
|
6170
6296
|
sourceIdentifier: handle.fetchIdentifier
|
|
6171
|
-
});
|
|
6297
|
+
}, this.viewSubject(ctx));
|
|
6172
6298
|
} catch (error) {
|
|
6173
6299
|
this.logger.error("Error in addRelationship(@args): @Error", args, error);
|
|
6174
6300
|
throw error;
|
|
@@ -6181,7 +6307,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6181
6307
|
return await updateRelationship(this.reactorClient, {
|
|
6182
6308
|
...args,
|
|
6183
6309
|
sourceIdentifier: handle.fetchIdentifier
|
|
6184
|
-
});
|
|
6310
|
+
}, this.viewSubject(ctx));
|
|
6185
6311
|
} catch (error) {
|
|
6186
6312
|
this.logger.error("Error in updateRelationship(@args): @Error", args, error);
|
|
6187
6313
|
throw error;
|
|
@@ -6194,7 +6320,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6194
6320
|
return await removeRelationship(this.reactorClient, {
|
|
6195
6321
|
...args,
|
|
6196
6322
|
sourceIdentifier: handle.fetchIdentifier
|
|
6197
|
-
});
|
|
6323
|
+
}, this.viewSubject(ctx));
|
|
6198
6324
|
} catch (error) {
|
|
6199
6325
|
this.logger.error("Error in removeRelationship(@args): @Error", args, error);
|
|
6200
6326
|
throw error;
|
|
@@ -6209,7 +6335,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6209
6335
|
...args,
|
|
6210
6336
|
sourceParentIdentifier: sourceHandle.fetchIdentifier,
|
|
6211
6337
|
targetParentIdentifier: targetHandle.fetchIdentifier
|
|
6212
|
-
});
|
|
6338
|
+
}, this.viewSubject(ctx));
|
|
6213
6339
|
} catch (error) {
|
|
6214
6340
|
this.logger.error("Error in moveRelationship(@args): @Error @args", error, args);
|
|
6215
6341
|
throw error;
|
|
@@ -6320,10 +6446,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6320
6446
|
documentChanges: {
|
|
6321
6447
|
subscribe: (rootValue, args, ctx, info) => {
|
|
6322
6448
|
this.logger.debug("documentChanges subscription started");
|
|
6323
|
-
return withFilter(() => {
|
|
6324
|
-
ensureGlobalDocumentSubscription(this.reactorClient);
|
|
6325
|
-
return getPubSub().asyncIterableIterator(SUBSCRIPTION_TRIGGERS.DOCUMENT_CHANGES);
|
|
6326
|
-
}, async (payload, filterArgs, filterCtx) => {
|
|
6449
|
+
return withFilter(() => this.documentChanges.subscribe(this.viewSubject(ctx)), async (payload, filterArgs, filterCtx) => {
|
|
6327
6450
|
if (!payload) return false;
|
|
6328
6451
|
const search = {
|
|
6329
6452
|
type: filterArgs?.search?.type ?? void 0,
|
|
@@ -6350,6 +6473,7 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
6350
6473
|
}, async (payload, filterArgs, filterCtx) => {
|
|
6351
6474
|
if (!payload || !filterArgs) return false;
|
|
6352
6475
|
if (!matchesJobFilter(payload, filterArgs)) return false;
|
|
6476
|
+
if (!await this.servesDocument(payload.documentId, filterCtx)) return false;
|
|
6353
6477
|
if (this.authorizationService.isSupremeAdmin(filterCtx?.user?.address)) return true;
|
|
6354
6478
|
if (!payload.documentId) return false;
|
|
6355
6479
|
return this.canReadDocument(payload.documentId, filterCtx);
|
|
@@ -6378,10 +6502,10 @@ const ADMIN_USERS = getAdminUsers();
|
|
|
6378
6502
|
//#endregion
|
|
6379
6503
|
//#region src/graphql/system/version.ts
|
|
6380
6504
|
function getVersion() {
|
|
6381
|
-
return "6.2.3-dev.
|
|
6505
|
+
return "6.2.3-dev.26";
|
|
6382
6506
|
}
|
|
6383
6507
|
function getGitHash() {
|
|
6384
|
-
return "
|
|
6508
|
+
return "25dd1c83d3dd25a0a08cc0e858e91a55da97043e";
|
|
6385
6509
|
}
|
|
6386
6510
|
function getGitUrl() {
|
|
6387
6511
|
return buildTreeUrl(getGitHash());
|
|
@@ -6482,7 +6606,8 @@ var HttpPackageLoader = class {
|
|
|
6482
6606
|
async loadUpgradeManifests(packageSpec) {
|
|
6483
6607
|
const { name: packageName } = this.parsePackageSpec(packageSpec);
|
|
6484
6608
|
if (!this.isValidPackageName(packageName)) throw new Error(`Invalid package name: ${packageName}`);
|
|
6485
|
-
const
|
|
6609
|
+
const module = await import(`${this.registryUrl}-/cdn/${packageSpec}/node/document-models/index.mjs`);
|
|
6610
|
+
const manifests = extractUpgradeManifests(module);
|
|
6486
6611
|
if (manifests.length > 0) this.logger.verbose(`Loaded ${manifests.length} upgrade manifests from ${packageName}`);
|
|
6487
6612
|
return manifests;
|
|
6488
6613
|
}
|
|
@@ -6673,10 +6798,11 @@ var ImportPackageLoader = class {
|
|
|
6673
6798
|
this.reportUnbuilt(identifier, root, listPath);
|
|
6674
6799
|
return [];
|
|
6675
6800
|
}
|
|
6676
|
-
const
|
|
6801
|
+
const module = await import(
|
|
6677
6802
|
/* @vite-ignore */
|
|
6678
6803
|
pathToFileURL(listPath).href
|
|
6679
|
-
)
|
|
6804
|
+
);
|
|
6805
|
+
const pieces = piecesFromListModule(module, {
|
|
6680
6806
|
root,
|
|
6681
6807
|
identifier,
|
|
6682
6808
|
logger: this.logger
|
|
@@ -6726,6 +6852,7 @@ function getUniqueUpgradeManifests(...upgradeManifests) {
|
|
|
6726
6852
|
return Array.from(uniqueManifests.values());
|
|
6727
6853
|
}
|
|
6728
6854
|
var PackageManager = class {
|
|
6855
|
+
options;
|
|
6729
6856
|
logger = childLogger(["reactor-api", "package-manager"]);
|
|
6730
6857
|
loaders;
|
|
6731
6858
|
docModelsMap = /* @__PURE__ */ new Map();
|
|
@@ -7080,20 +7207,48 @@ async function createStartupAttachmentBackend({ db, env = process.env, s3Depende
|
|
|
7080
7207
|
}
|
|
7081
7208
|
//#endregion
|
|
7082
7209
|
//#region src/services/attachment-access.service.ts
|
|
7210
|
+
/** The scope an attachment's bytes belong to: the document's own domain state. */
|
|
7211
|
+
const ATTACHMENT_SCOPE = "global";
|
|
7212
|
+
/** The branch an attachment reference is resolved against. */
|
|
7213
|
+
const ATTACHMENT_BRANCH = "main";
|
|
7083
7214
|
const HASH_PATTERN = /^[a-f0-9]{64}$/;
|
|
7084
7215
|
/**
|
|
7085
7216
|
* Composes document authorization with the projected document/ref
|
|
7086
7217
|
* relationship. Order is fixed: validate ref, resolve the canonical document
|
|
7087
|
-
* id,
|
|
7088
|
-
*
|
|
7089
|
-
* attachment
|
|
7218
|
+
* id, decide the read, check the reactor's read gate serves the document, then
|
|
7219
|
+
* check the reference index and that the subject may read a scope whose
|
|
7220
|
+
* operations reference the attachment. A denied document never reaches the
|
|
7221
|
+
* reference reader, and the facade never touches attachment metadata, storage
|
|
7222
|
+
* backends, or presigners.
|
|
7223
|
+
*
|
|
7224
|
+
* The named document decides alone: an attachment several documents reference
|
|
7225
|
+
* is readable through each of them on that document's own terms.
|
|
7226
|
+
*
|
|
7227
|
+
* The read is decided by the document's own policy when this composition has a
|
|
7228
|
+
* model to enforce it with, and by the host's permission tables when it does
|
|
7229
|
+
* not. That is not a preference between two equivalent answers: a host running
|
|
7230
|
+
* document policies keeps no rows in the permission tables, so asking them
|
|
7231
|
+
* about such a document returns whatever the host-wide policy says — under
|
|
7232
|
+
* `OPEN`, `true`, for everyone. Serving bytes on that answer hands the file to
|
|
7233
|
+
* anyone who learns its hash, which the document's own state may well have told
|
|
7234
|
+
* them. Both are kept because they are the two halves of one rule: an
|
|
7235
|
+
* attachment is readable by whoever may read the document that references it,
|
|
7236
|
+
* and each composition can only express that in its own terms.
|
|
7090
7237
|
*/
|
|
7091
7238
|
var AttachmentAccessService = class {
|
|
7092
|
-
|
|
7239
|
+
resolveCanonicalId;
|
|
7240
|
+
authorization;
|
|
7241
|
+
references;
|
|
7242
|
+
projection;
|
|
7243
|
+
readGate;
|
|
7244
|
+
scopeGate;
|
|
7245
|
+
constructor(resolveCanonicalId, authorization, references, projection, readGate, scopeGate) {
|
|
7093
7246
|
this.resolveCanonicalId = resolveCanonicalId;
|
|
7094
7247
|
this.authorization = authorization;
|
|
7095
7248
|
this.references = references;
|
|
7096
7249
|
this.projection = projection;
|
|
7250
|
+
this.readGate = readGate;
|
|
7251
|
+
this.scopeGate = scopeGate;
|
|
7097
7252
|
}
|
|
7098
7253
|
async canReadAttachment(request) {
|
|
7099
7254
|
if (this.projection.status !== "available") return { kind: "projection-unavailable" };
|
|
@@ -7105,14 +7260,51 @@ var AttachmentAccessService = class {
|
|
|
7105
7260
|
} catch {
|
|
7106
7261
|
return { kind: "denied" };
|
|
7107
7262
|
}
|
|
7108
|
-
if (!await this.
|
|
7109
|
-
|
|
7263
|
+
if (!await this.canReadDocument(documentId, request)) return { kind: "denied" };
|
|
7264
|
+
const subject = {
|
|
7265
|
+
address: request.userAddress,
|
|
7266
|
+
key: request.appKey
|
|
7267
|
+
};
|
|
7268
|
+
let served;
|
|
7269
|
+
try {
|
|
7270
|
+
served = await this.readGate.isServed(documentId, { subject });
|
|
7271
|
+
} catch {
|
|
7272
|
+
return { kind: "denied" };
|
|
7273
|
+
}
|
|
7274
|
+
if (!served) return { kind: "denied" };
|
|
7275
|
+
const scopes = await this.references.referencingScopes(documentId, ref);
|
|
7276
|
+
if (scopes.length === 0) return { kind: "denied" };
|
|
7277
|
+
let held;
|
|
7278
|
+
try {
|
|
7279
|
+
held = (await this.readGate.get(documentId, {
|
|
7280
|
+
subject,
|
|
7281
|
+
scopes
|
|
7282
|
+
})).state;
|
|
7283
|
+
} catch {
|
|
7284
|
+
return { kind: "denied" };
|
|
7285
|
+
}
|
|
7286
|
+
if (!scopes.some((scope) => scope in held)) return { kind: "denied" };
|
|
7110
7287
|
return {
|
|
7111
7288
|
kind: "allowed",
|
|
7112
7289
|
documentId,
|
|
7113
7290
|
ref
|
|
7114
7291
|
};
|
|
7115
7292
|
}
|
|
7293
|
+
/**
|
|
7294
|
+
* Whether the caller may read the state the reference lives in.
|
|
7295
|
+
*
|
|
7296
|
+
* A failure here is rethrown rather than turned into a denial. A read side
|
|
7297
|
+
* that is down must not read as a policy: a denial nobody can distinguish
|
|
7298
|
+
* from a refusal is one nobody investigates, and the route answers 500 for a
|
|
7299
|
+
* reason.
|
|
7300
|
+
*/
|
|
7301
|
+
async canReadDocument(documentId, request) {
|
|
7302
|
+
if (!this.scopeGate) return this.authorization.canRead(documentId, request.userAddress);
|
|
7303
|
+
return (await this.scopeGate.scopePredicateById(documentId, {
|
|
7304
|
+
address: request.userAddress,
|
|
7305
|
+
key: request.appKey
|
|
7306
|
+
}, ATTACHMENT_BRANCH))(ATTACHMENT_SCOPE);
|
|
7307
|
+
}
|
|
7116
7308
|
};
|
|
7117
7309
|
/**
|
|
7118
7310
|
* Parses and canonicalizes a caller-supplied ref through the shared parser.
|
|
@@ -7596,6 +7788,7 @@ async function createRenownCredentialVerifier(config = {}) {
|
|
|
7596
7788
|
* - Users can be granted permission to execute specific operations
|
|
7597
7789
|
*/
|
|
7598
7790
|
var DocumentPermissionService = class {
|
|
7791
|
+
db;
|
|
7599
7792
|
config;
|
|
7600
7793
|
constructor(db, config = { defaultProtection: false }) {
|
|
7601
7794
|
this.db = db;
|
|
@@ -7866,12 +8059,16 @@ function createGetParentIdsFn(reactorClient) {
|
|
|
7866
8059
|
* Authorization gate for the /mcp endpoint (AUTH_REVIEW S-C1). MCP tools have
|
|
7867
8060
|
* unrestricted reactor access, so access is limited to supreme admins when
|
|
7868
8061
|
* auth is enabled. OPEN policy is public; any other policy without an
|
|
7869
|
-
* AuthService fails closed.
|
|
8062
|
+
* AuthService fails closed. The tools read as the caller: anonymous under OPEN,
|
|
8063
|
+
* else the admin's address and the app key its token carries.
|
|
7870
8064
|
*/
|
|
7871
8065
|
function createMcpRequestAuthorizer(authService, authorizationService) {
|
|
7872
8066
|
return async (req) => {
|
|
7873
8067
|
if (!authService) {
|
|
7874
|
-
if (authorizationService.config.policy === AuthorizationPolicy.OPEN) return {
|
|
8068
|
+
if (authorizationService.config.policy === AuthorizationPolicy.OPEN) return {
|
|
8069
|
+
authorized: true,
|
|
8070
|
+
subject: {}
|
|
8071
|
+
};
|
|
7875
8072
|
return {
|
|
7876
8073
|
authorized: false,
|
|
7877
8074
|
status: 401,
|
|
@@ -7894,10 +8091,39 @@ function createMcpRequestAuthorizer(authService, authorizationService) {
|
|
|
7894
8091
|
status: 403,
|
|
7895
8092
|
message: "Forbidden: MCP access requires an administrator"
|
|
7896
8093
|
};
|
|
7897
|
-
return {
|
|
8094
|
+
return {
|
|
8095
|
+
authorized: true,
|
|
8096
|
+
subject: {
|
|
8097
|
+
address: context.user.address,
|
|
8098
|
+
key: context.user.appKey
|
|
8099
|
+
}
|
|
8100
|
+
};
|
|
7898
8101
|
};
|
|
7899
8102
|
}
|
|
7900
8103
|
//#endregion
|
|
8104
|
+
//#region src/services/sync-serving-gate.ts
|
|
8105
|
+
/**
|
|
8106
|
+
* The gate sync serving evaluates a document's own policy through, deciding
|
|
8107
|
+
* what the reactor client's read gate decides at the same flag level.
|
|
8108
|
+
*
|
|
8109
|
+
* Under `authEnforcement` it is built here rather than taken off the client
|
|
8110
|
+
* because it also carries the host's closes-by-default setting, which withholds
|
|
8111
|
+
* the domain scopes of a document nobody has policied yet. That answer belongs
|
|
8112
|
+
* to serving alone -- replay must keep reading an uninitialized document in
|
|
8113
|
+
* full -- so the two gates are separate objects over the same model.
|
|
8114
|
+
*
|
|
8115
|
+
* Below it the registered model ignores the auth scope, so the client reads
|
|
8116
|
+
* through the policy alone, and so does serving: a policy written below the
|
|
8117
|
+
* flag still withholds, where serving ungated would sync to a peer what `get`
|
|
8118
|
+
* refuses it.
|
|
8119
|
+
*/
|
|
8120
|
+
function buildSyncServingGate(reactorModule, authorizationConfig, logger) {
|
|
8121
|
+
if (!reactorModule) return;
|
|
8122
|
+
const model = readDecisionModel(reactorModule.featureFlags, reactorModule.documentModelRegistry);
|
|
8123
|
+
if (!model) return new SyncScopeGate(new BareReadGate(), reactorModule.documentView, logger);
|
|
8124
|
+
return new SyncScopeGate(new ModelReadGate(model, reactorModule.documentView, reactorModule.featureFlags.authGroups, reactorModule.operationIndex, logger, { withholdUninitialized: authorizationConfig.defaultProtection }), reactorModule.documentView, logger);
|
|
8125
|
+
}
|
|
8126
|
+
//#endregion
|
|
7901
8127
|
//#region src/services/renown-config.ts
|
|
7902
8128
|
/** Reading credentials from this reactor's own read model needs a host-supplied
|
|
7903
8129
|
* verifier: core has no idea which subgraph serves that read model. */
|
|
@@ -8098,6 +8324,17 @@ function assertRequireAuthenticatedCallerAllowed(requireAuthenticatedCaller, res
|
|
|
8098
8324
|
if (!requireAuthenticatedCaller || resolvesCallerIdentity) return;
|
|
8099
8325
|
throw new Error("REQUIRE_AUTHENTICATED_CALLER is set but refused: it rejects every request without a resolved caller, and with neither AUTH_ENABLED nor RESOLVE_CALLER_IDENTITY the server never reads a bearer, so it would reject every caller, including authenticated ones. Enable identity resolution first (RESOLVE_CALLER_IDENTITY=true or AUTH_ENABLED=true).");
|
|
8100
8326
|
}
|
|
8327
|
+
/**
|
|
8328
|
+
* Deciding an attachment read by the document's policy needs a policy model to
|
|
8329
|
+
* decide with, and that is what auth enforcement supplies. Without one there is
|
|
8330
|
+
* nothing to consult, so the setting would silently leave the permission tables
|
|
8331
|
+
* in charge — configuration that describes a protection the server is not
|
|
8332
|
+
* applying, which is worse than no configuration at all. Refuse instead.
|
|
8333
|
+
*/
|
|
8334
|
+
function assertAttachmentPolicyReadsAllowed(attachmentReadsFollowDocumentPolicy, hasDecisionModel) {
|
|
8335
|
+
if (!attachmentReadsFollowDocumentPolicy || hasDecisionModel) return;
|
|
8336
|
+
throw new Error("ATTACHMENT_READS_FOLLOW_DOCUMENT_POLICY is set but refused: deciding an attachment read by the referencing document's policy requires a policy model to evaluate, and this composition has none, so the host permission tables would keep deciding while the configuration says otherwise. Enable auth enforcement first (REACTOR_AUTH_ENFORCEMENT=true).");
|
|
8337
|
+
}
|
|
8101
8338
|
function createReadinessGate() {
|
|
8102
8339
|
let ready = false;
|
|
8103
8340
|
return {
|
|
@@ -8152,27 +8389,6 @@ function makeDbClosers(knexInstance, pglite) {
|
|
|
8152
8389
|
return closers;
|
|
8153
8390
|
}
|
|
8154
8391
|
/**
|
|
8155
|
-
* The gate sync serving evaluates a document's own policy through, or undefined
|
|
8156
|
-
* when there is none to evaluate.
|
|
8157
|
-
*
|
|
8158
|
-
* It is built here rather than taken off the reactor client because it is not
|
|
8159
|
-
* the same gate reads use: it carries the host's closes-by-default setting,
|
|
8160
|
-
* which withholds the domain scopes of a document nobody has policied yet. That
|
|
8161
|
-
* answer belongs to serving alone -- replay must keep reading an uninitialized
|
|
8162
|
-
* document in full -- so the two gates are deliberately separate objects over
|
|
8163
|
-
* the same model.
|
|
8164
|
-
*
|
|
8165
|
-
* Undefined below `authEnforcement`, where the registered model ignores the auth
|
|
8166
|
-
* scope: gating through it would serve every domain scope of a policied document
|
|
8167
|
-
* to anyone, which is worse than not gating at all.
|
|
8168
|
-
*/
|
|
8169
|
-
function buildSyncServingGate(reactorModule, authorizationConfig, logger) {
|
|
8170
|
-
if (!reactorModule) return;
|
|
8171
|
-
const model = readDecisionModel(reactorModule.featureFlags, reactorModule.documentModelRegistry);
|
|
8172
|
-
if (!model) return;
|
|
8173
|
-
return new SyncScopeGate(new ModelReadGate(model, reactorModule.documentView, reactorModule.featureFlags.authGroups, reactorModule.operationIndex, logger, { withholdUninitialized: authorizationConfig.defaultProtection }), reactorModule.documentView, logger);
|
|
8174
|
-
}
|
|
8175
|
-
/**
|
|
8176
8392
|
* Resolves the gateway adapter type from the `GATEWAY_ADAPTER` env var.
|
|
8177
8393
|
* Defaults to "apollo" (the federation gateway, production behavior).
|
|
8178
8394
|
* "stitching" selects the in-process graphql-tools merge gateway (#1565
|
|
@@ -8288,6 +8504,7 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8288
8504
|
let configuredResolveIdentity;
|
|
8289
8505
|
let configuredRequireAuth;
|
|
8290
8506
|
let configuredExemptPaths;
|
|
8507
|
+
let configuredAttachmentPolicyReads;
|
|
8291
8508
|
let configuredRenown;
|
|
8292
8509
|
if (options.configFile) {
|
|
8293
8510
|
const config = getConfig(options.configFile);
|
|
@@ -8300,8 +8517,9 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8300
8517
|
configuredResolveIdentity = options.auth.resolveIdentity;
|
|
8301
8518
|
configuredRequireAuth = options.auth.requireAuthenticatedCaller;
|
|
8302
8519
|
configuredExemptPaths = options.auth.requireAuthenticatedCallerExemptPaths;
|
|
8520
|
+
configuredAttachmentPolicyReads = options.auth.attachmentReadsFollowDocumentPolicy;
|
|
8303
8521
|
}
|
|
8304
|
-
const { AUTH_ENABLED, RESOLVE_CALLER_IDENTITY, REQUIRE_AUTHENTICATED_CALLER, REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS, ADMINS, DEFAULT_PROTECTION, DOCUMENT_PERMISSIONS_ENABLED, SKIP_CREDENTIAL_VERIFICATION, CREDENTIAL_VERIFICATION_CACHE_TTL_MS } = process.env;
|
|
8522
|
+
const { AUTH_ENABLED, RESOLVE_CALLER_IDENTITY, REQUIRE_AUTHENTICATED_CALLER, REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS, ATTACHMENT_READS_FOLLOW_DOCUMENT_POLICY, ADMINS, DEFAULT_PROTECTION, DOCUMENT_PERMISSIONS_ENABLED, SKIP_CREDENTIAL_VERIFICATION, CREDENTIAL_VERIFICATION_CACHE_TTL_MS } = process.env;
|
|
8305
8523
|
if (AUTH_ENABLED !== void 0) authEnabled = AUTH_ENABLED === "true";
|
|
8306
8524
|
/**
|
|
8307
8525
|
* Whether the auth middleware reads the bearer and populates `ctx.user`,
|
|
@@ -8344,6 +8562,18 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8344
8562
|
*/
|
|
8345
8563
|
let requireAuthenticatedCallerExemptPaths = configuredExemptPaths ?? [];
|
|
8346
8564
|
if (REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS !== void 0) requireAuthenticatedCallerExemptPaths = REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS.split(",").map((path) => path.trim()).filter((path) => path.length > 0);
|
|
8565
|
+
/**
|
|
8566
|
+
* Whether an attachment read is decided by the referencing document's own
|
|
8567
|
+
* policy rather than by the host's permission tables.
|
|
8568
|
+
*
|
|
8569
|
+
* Off by default, and a deployment's choice rather than something derived
|
|
8570
|
+
* from the flags around it. Which model governs those bytes is configuration
|
|
8571
|
+
* in the same sense the storage backend behind them is: a host that has said
|
|
8572
|
+
* nothing keeps exactly the behaviour it has, and one that wants the change
|
|
8573
|
+
* asks for it and can take it back without disturbing anything else.
|
|
8574
|
+
*/
|
|
8575
|
+
let attachmentReadsFollowDocumentPolicy = configuredAttachmentPolicyReads ?? false;
|
|
8576
|
+
if (ATTACHMENT_READS_FOLLOW_DOCUMENT_POLICY !== void 0) attachmentReadsFollowDocumentPolicy = ATTACHMENT_READS_FOLLOW_DOCUMENT_POLICY === "true";
|
|
8347
8577
|
if (ADMINS !== void 0) admins = ADMINS.split(",").map((a) => a.toLowerCase());
|
|
8348
8578
|
let defaultProtection = false;
|
|
8349
8579
|
if (DEFAULT_PROTECTION !== void 0) defaultProtection = DEFAULT_PROTECTION.toLowerCase() === "true";
|
|
@@ -8420,7 +8650,7 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8420
8650
|
await mkdir(attachmentStoragePath, { recursive: true });
|
|
8421
8651
|
const { db: attachmentDb, knex: attachmentKnex, pglite: attachmentPglite } = getDbClient(options.dbPath, options.pgliteFactory);
|
|
8422
8652
|
dbClosers.push(...makeDbClosers(attachmentKnex, attachmentPglite));
|
|
8423
|
-
const ATTACHMENT_SWEEP_INTERVAL_MS =
|
|
8653
|
+
const ATTACHMENT_SWEEP_INTERVAL_MS = 36e5;
|
|
8424
8654
|
const attachmentBackend = await createStartupAttachmentBackend({ db: attachmentDb });
|
|
8425
8655
|
const attachmentBuilder = new AttachmentBuilder(attachmentDb, attachmentStoragePath).withReservationSweepMs(ATTACHMENT_SWEEP_INTERVAL_MS);
|
|
8426
8656
|
if (attachmentBackend) attachmentBuilder.withBackend(attachmentBackend);
|
|
@@ -8465,13 +8695,14 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8465
8695
|
attachmentReferenceIndex,
|
|
8466
8696
|
packages,
|
|
8467
8697
|
dbClosers,
|
|
8468
|
-
readiness
|
|
8698
|
+
readiness,
|
|
8699
|
+
attachmentReadsFollowDocumentPolicy
|
|
8469
8700
|
};
|
|
8470
8701
|
}
|
|
8471
8702
|
/**
|
|
8472
8703
|
* Private helper function containing common setup logic for API initialization
|
|
8473
8704
|
*/
|
|
8474
|
-
async function _setupAPI(reactorClient, syncManager, reactorProcessorManager, httpAdapter, authFetchMiddleware, requireAuthFetchMiddleware, authService, port, packages, relationalDb, analyticsStore, documentPermissionService, processors, subgraphs, options, processorApp, readModels, attachments, attachmentReferenceIndex, attachmentReferenceProjection, authorizationConfig, documentModelRegistry, dbClosers = [], reactorDriveClient, syncServingGate, httpRoutes) {
|
|
8705
|
+
async function _setupAPI(reactorClient, syncManager, reactorProcessorManager, httpAdapter, authFetchMiddleware, requireAuthFetchMiddleware, authService, port, packages, relationalDb, analyticsStore, documentPermissionService, processors, subgraphs, options, processorApp, readModels, attachments, attachmentReferenceIndex, attachmentReferenceProjection, authorizationConfig, documentModelRegistry, dbClosers = [], reactorDriveClient, syncServingGate, httpRoutes, attachmentReadsFollowDocumentPolicy = false) {
|
|
8475
8706
|
const hostModuleBase = {
|
|
8476
8707
|
...createReactorHostModuleBase({
|
|
8477
8708
|
client: reactorClient,
|
|
@@ -8513,7 +8744,8 @@ async function _setupAPI(reactorClient, syncManager, reactorProcessorManager, ht
|
|
|
8513
8744
|
const { httpServer, wsServer } = await startServer(httpAdapter, port, options.https, logger);
|
|
8514
8745
|
const authorizationService = createAuthorizationService(authorizationConfig, documentPermissionService, createGetParentIdsFn(reactorClient));
|
|
8515
8746
|
logger.info(`Authorization service initialized (policy: ${authorizationConfig.policy})`);
|
|
8516
|
-
|
|
8747
|
+
assertAttachmentPolicyReadsAllowed(attachmentReadsFollowDocumentPolicy, syncServingGate !== void 0);
|
|
8748
|
+
const attachmentAccess = new AttachmentAccessService(createCanonicalDocumentIdResolver(reactorClient), authorizationService, attachmentReferenceIndex.store, attachmentReferenceProjection, reactorClient, attachmentReadsFollowDocumentPolicy ? syncServingGate : void 0);
|
|
8517
8749
|
const coreSubgraphs = DefaultCoreSubgraphs.slice();
|
|
8518
8750
|
coreSubgraphs.push(ReactorSubgraph);
|
|
8519
8751
|
if (documentPermissionService) {
|
|
@@ -8599,7 +8831,7 @@ function buildApiDispose(args) {
|
|
|
8599
8831
|
};
|
|
8600
8832
|
}
|
|
8601
8833
|
async function initializeAndStartAPI(clientInitializer, options, processorApp) {
|
|
8602
|
-
const { port, httpAdapter, httpRoutes, authFetchMiddleware, requireAuthFetchMiddleware, authService, relationalDb, analyticsStore, documentPermissionService, authorizationConfig, attachments, attachmentReferenceIndex, packages, dbClosers, readiness } = await _setupCommonInfrastructure(options);
|
|
8834
|
+
const { port, httpAdapter, httpRoutes, authFetchMiddleware, requireAuthFetchMiddleware, authService, relationalDb, analyticsStore, documentPermissionService, authorizationConfig, attachments, attachmentReferenceIndex, packages, dbClosers, readiness, attachmentReadsFollowDocumentPolicy } = await _setupCommonInfrastructure(options);
|
|
8603
8835
|
const { documentModels, upgradeManifests, processors, subgraphs } = await packages.init();
|
|
8604
8836
|
const { module: reactorClientModule, reactorDriveClient, attachmentReferenceProjection = {
|
|
8605
8837
|
status: "unavailable",
|
|
@@ -8616,7 +8848,7 @@ async function initializeAndStartAPI(clientInitializer, options, processorApp) {
|
|
|
8616
8848
|
const documentModelRegistry = reactorClientModule.reactorModule?.documentModelRegistry;
|
|
8617
8849
|
if (!documentModelRegistry) throw new Error("DocumentModelRegistry not available from InProcessReactorClientModule");
|
|
8618
8850
|
return {
|
|
8619
|
-
...await _setupAPI(reactorClient, syncManager, reactorProcessorManager, httpAdapter, authFetchMiddleware, requireAuthFetchMiddleware, authService, port, packages, relationalDb, analyticsStore, documentPermissionService, processors, subgraphs, options, processorApp, (reactorClientModule.reactorModule?.readModelCoordinator)?.readModels ?? [], attachments, attachmentReferenceIndex, attachmentReferenceProjection, authorizationConfig, documentModelRegistry, dbClosers, reactorDriveClient, buildSyncServingGate(reactorClientModule.reactorModule, authorizationConfig, options.logger ?? defaultLogger), httpRoutes),
|
|
8851
|
+
...await _setupAPI(reactorClient, syncManager, reactorProcessorManager, httpAdapter, authFetchMiddleware, requireAuthFetchMiddleware, authService, port, packages, relationalDb, analyticsStore, documentPermissionService, processors, subgraphs, options, processorApp, (reactorClientModule.reactorModule?.readModelCoordinator)?.readModels ?? [], attachments, attachmentReferenceIndex, attachmentReferenceProjection, authorizationConfig, documentModelRegistry, dbClosers, reactorDriveClient, buildSyncServingGate(reactorClientModule.reactorModule, authorizationConfig, options.logger ?? defaultLogger), httpRoutes, attachmentReadsFollowDocumentPolicy),
|
|
8620
8852
|
client: reactorClient,
|
|
8621
8853
|
syncManager,
|
|
8622
8854
|
documentModelRegistry,
|
|
@@ -8749,7 +8981,7 @@ var PackageManagementService = class {
|
|
|
8749
8981
|
}
|
|
8750
8982
|
};
|
|
8751
8983
|
//#endregion
|
|
8752
|
-
export { ADMIN_USERS, ActionCandidateInputSchema, ActionContextInputSchema, ActionInputSchema, AddRelationshipDocument, AnalyticsSubgraph, AttachmentAccessService, AuthDecision, AuthDecisionSchema, AuthEvaluationUnsupportedError, AuthService, AuthSubgraph, AuthenticationRequiredError, AuthorizationPolicy, AuthorizedDocumentHandle, BaseSubgraph, CORE_PACKAGE_NAME, CanonicalDocumentIdResolutionError, ChannelMetaInputSchema, CreateDocumentDocument, CreateEmptyDocumentDocument, DeleteDocumentDocument, DeleteDocumentsDocument, DocumentChangeType, DocumentChangeTypeSchema, DocumentChangesDocument, DocumentOperationsFilterInputSchema, DocumentPermissionService, DocumentRelationshipFieldsFragmentDoc, EvaluateActionsDocument, FindDocumentsDocument, ForbiddenError, GetDocumentDocument, GetDocumentIncomingRelationshipEdgesDocument, GetDocumentIncomingRelationshipsDocument, GetDocumentModelsDocument, GetDocumentOperationsDocument, GetDocumentOutgoingRelationshipEdgesDocument, GetDocumentOutgoingRelationshipsDocument, GetDocumentWithOperationsDocument, GetJobStatusDocument, GraphQLManager, HttpDocumentModelLoader, HttpPackageLoader, HttpRouteService, ImportPackageLoader, InMemoryPackageStorage, InvalidNamespaceError, JobChangesDocument, MalformedStoredOperationError, MemoryWebhookStore, MoveRelationshipDocument, MutateDocumentAsyncDocument, MutateDocumentDocument, OperationContextInputSchema, OperationInputSchema, OperationWithContextInputSchema, OperationsFilterInputSchema, PACKAGE_ROUTE_SEGMENT, PGLITE_UTC_PARSERS, PackageManagementService, PackageManager, PackagesSubgraph, PagingInputSchema, PhDocumentFieldsFragmentDoc, PollSyncEnvelopesDocument, PropagationMode, PropagationModeSchema, PushSyncEnvelopesDocument, ReactorSignerAppInputSchema, ReactorSignerInputSchema, ReactorSignerUserInputSchema, ReactorSubgraph, RelationalWebhookStore, RemoteCursorInputSchema, RemoteFilterInputSchema, RemoveRelationshipDocument, RenameDocumentDocument, SearchFilterInputSchema, SetPreferredEditorDocument, SyncEnvelopeInputSchema, SyncEnvelopeType, SyncEnvelopeTypeSchema, SystemSubgraph, TouchChannelDocument, TouchChannelInputSchema, UpdateRelationshipDocument, ViewFilterInputSchema, WEBHOOK_SEGMENT, WS_AUTH_CLOSE_REASONS, WS_CLOSE_REASON_AUTHENTICATION_REQUIRED, WS_CLOSE_REASON_BEARER_REJECTED, WebhookService, assertAuthRequiredForDocumentPermissions, assertCredentialVerifierForSource, assertHostMountPath, assertRequireAuthenticatedCallerAllowed, assertSkipCredentialVerificationAllowed, buildGraphQlDocument, buildGraphQlDriveDocument, buildGraphqlOperation, buildGraphqlOperations, buildSubgraphSchemaModule, createAuthFetchMiddleware, createCanonicalDocumentIdResolver, createGatewayAdapter, createHttpAdapter, createMergedSchema, createReactorGraphQLClient, createRenownCredentialVerifier, createSchema, createWsAuthHandlers, decodeExplorerUrlState, definedNonNullAnySchema, driveIdFromUrl, extractSubgraphsFromModule, generateDocumentModelSchema, getAuthContext, getDbClient, getDocumentModelSchemaName, getDocumentModelTypeDefs, getExplorerPrefix, getGitHash, getGitUrl, getSdk, getUniqueDocumentModels, getUniqueUpgradeManifests, getVersion, initAnalyticsStoreSql, initializeAndStartAPI, isDefinedNonNullAny, isExpectedLoaderMiss, isSubgraphClass, namespacePath, namespaceSegments, newWebhookToken, parseDriveUrl, parseWebhookBody, redactHeaders, renderGraphqlPlayground, resolvePackageName, resolveRenownConfig, verifyWebhook };
|
|
8984
|
+
export { ADMIN_USERS, ActionCandidateInputSchema, ActionContextInputSchema, ActionInputSchema, AddRelationshipDocument, AnalyticsSubgraph, AttachmentAccessService, AuthDecision, AuthDecisionSchema, AuthEvaluationUnsupportedError, AuthService, AuthSubgraph, AuthenticationRequiredError, AuthorizationPolicy, AuthorizedDocumentHandle, BaseSubgraph, CORE_PACKAGE_NAME, CanonicalDocumentIdResolutionError, ChannelMetaInputSchema, CreateDocumentDocument, CreateEmptyDocumentDocument, DeleteDocumentDocument, DeleteDocumentsDocument, DocumentChangeType, DocumentChangeTypeSchema, DocumentChangesDocument, DocumentOperationsFilterInputSchema, DocumentPermissionService, DocumentRelationshipFieldsFragmentDoc, EvaluateActionsDocument, FindDocumentsDocument, ForbiddenError, GetDocumentDocument, GetDocumentIncomingRelationshipEdgesDocument, GetDocumentIncomingRelationshipsDocument, GetDocumentModelsDocument, GetDocumentOperationsDocument, GetDocumentOutgoingRelationshipEdgesDocument, GetDocumentOutgoingRelationshipsDocument, GetDocumentWithOperationsDocument, GetJobStatusDocument, GraphQLManager, HttpDocumentModelLoader, HttpPackageLoader, HttpRouteService, ImportPackageLoader, InMemoryPackageStorage, InvalidNamespaceError, JobChangesDocument, MalformedStoredOperationError, MemoryWebhookStore, MoveRelationshipDocument, MutateDocumentAsyncDocument, MutateDocumentDocument, OperationContextInputSchema, OperationInputSchema, OperationWithContextInputSchema, OperationsFilterInputSchema, PACKAGE_ROUTE_SEGMENT, PGLITE_UTC_PARSERS, PackageManagementService, PackageManager, PackagesSubgraph, PagingInputSchema, PhDocumentFieldsFragmentDoc, PollSyncEnvelopesDocument, PropagationMode, PropagationModeSchema, PushSyncEnvelopesDocument, ReactorSignerAppInputSchema, ReactorSignerInputSchema, ReactorSignerUserInputSchema, ReactorSubgraph, RelationalWebhookStore, RemoteCursorInputSchema, RemoteFilterInputSchema, RemoveRelationshipDocument, RenameDocumentDocument, SearchFilterInputSchema, SetPreferredEditorDocument, SyncEnvelopeInputSchema, SyncEnvelopeType, SyncEnvelopeTypeSchema, SystemSubgraph, TouchChannelDocument, TouchChannelInputSchema, UpdateRelationshipDocument, ViewFilterInputSchema, WEBHOOK_SEGMENT, WS_AUTH_CLOSE_REASONS, WS_CLOSE_REASON_AUTHENTICATION_REQUIRED, WS_CLOSE_REASON_BEARER_REJECTED, WebhookService, assertAttachmentPolicyReadsAllowed, assertAuthRequiredForDocumentPermissions, assertCredentialVerifierForSource, assertHostMountPath, assertRequireAuthenticatedCallerAllowed, assertSkipCredentialVerificationAllowed, buildGraphQlDocument, buildGraphQlDriveDocument, buildGraphqlOperation, buildGraphqlOperations, buildSubgraphSchemaModule, callerSubject, createAuthFetchMiddleware, createCanonicalDocumentIdResolver, createGatewayAdapter, createHttpAdapter, createMergedSchema, createReactorGraphQLClient, createRenownCredentialVerifier, createSchema, createWsAuthHandlers, decodeExplorerUrlState, definedNonNullAnySchema, driveIdFromUrl, extractSubgraphsFromModule, generateDocumentModelSchema, getAuthContext, getDbClient, getDocumentModelSchemaName, getDocumentModelTypeDefs, getExplorerPrefix, getGitHash, getGitUrl, getSdk, getUniqueDocumentModels, getUniqueUpgradeManifests, getVersion, initAnalyticsStoreSql, initializeAndStartAPI, isDefinedNonNullAny, isExpectedLoaderMiss, isSubgraphClass, namespacePath, namespaceSegments, newWebhookToken, parseDriveUrl, parseWebhookBody, redactHeaders, renderGraphqlPlayground, resolvePackageName, resolveRenownConfig, verifyWebhook };
|
|
8753
8985
|
|
|
8754
8986
|
//# sourceMappingURL=index.mjs.map
|
|
8755
|
-
//# debugId=
|
|
8987
|
+
//# debugId=8ab62893-8127-51eb-9d6f-a5900b1823de
|