@powerhousedao/reactor-api 6.2.3-dev.23 → 6.2.3-dev.25
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-Drbaxszc.mjs} +4 -4
- package/dist/{adapter-http-express-D4KBmDcQ.mjs.map → adapter-http-express-Drbaxszc.mjs.map} +1 -1
- package/dist/{adapter-http-fastify-U9j7HxQE.mjs → adapter-http-fastify-DMPW_huG.mjs} +6 -5
- package/dist/{adapter-http-fastify-U9j7HxQE.mjs.map → adapter-http-fastify-DMPW_huG.mjs.map} +1 -1
- package/dist/index.d.mts +595 -461
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +236 -88
- package/dist/index.mjs.map +1 -1
- package/dist/{pieces-eqj2RKgd.mjs → pieces-BOwV3Ql9.mjs} +6 -3
- package/dist/{pieces-eqj2RKgd.mjs.map → pieces-BOwV3Ql9.mjs.map} +1 -1
- 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 +17 -17
- package/dist/types-BXjLvTe3.d.mts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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]="6828688f-9737-5852-b599-51439acc4894")}catch(e){}}();
|
|
3
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
4
|
+
import { C as createAuthorizationService, D as MalformedStoredOperationError, E as ForbiddenError, S as AuthorizedDocumentHandle, T as AuthenticationRequiredError, _ as loadSubgraphs, a as piecesFromCdnList, b as createCanonicalDocumentIdResolver, 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 AuthEvaluationUnsupportedError, x as AuthorizationPolicy, y as CanonicalDocumentIdResolutionError } from "./pieces-BOwV3Ql9.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";
|
|
@@ -19,7 +20,7 @@ import { buildSubgraphSchema } from "@apollo/subgraph";
|
|
|
19
20
|
import { typeDefs } from "@powerhousedao/document-engineering/graphql";
|
|
20
21
|
import { camelCase, kebabCase, pascalCase } from "change-case";
|
|
21
22
|
import { GraphQLJSON, GraphQLJSONObject } from "graphql-type-json";
|
|
22
|
-
import { deserializeSignature, serializeSignature, setName } from "@powerhousedao/shared/document-model";
|
|
23
|
+
import { deserializeSignature, serializeSignature, setName, withSignaturePolicy } from "@powerhousedao/shared/document-model";
|
|
23
24
|
import * as z$1 from "zod";
|
|
24
25
|
import { z } from "zod";
|
|
25
26
|
import { createHandler } from "graphql-sse/lib/use/fetch";
|
|
@@ -47,18 +48,6 @@ 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
|
|
63
52
|
var AnalyticsSubgraph = class extends BaseSubgraph {
|
|
64
53
|
analyticsStore;
|
|
@@ -312,15 +301,15 @@ function createAuthFetchMiddleware(authService) {
|
|
|
312
301
|
async function createGatewayAdapter(type, logger) {
|
|
313
302
|
switch (type) {
|
|
314
303
|
case "apollo": {
|
|
315
|
-
const { ApolloGatewayAdapter } = await import("./adapter-gateway-apollo-
|
|
304
|
+
const { ApolloGatewayAdapter } = await import("./adapter-gateway-apollo-D2DNlPY0.mjs");
|
|
316
305
|
return new ApolloGatewayAdapter(logger);
|
|
317
306
|
}
|
|
318
307
|
case "mercurius": {
|
|
319
|
-
const { MercuriusGatewayAdapter } = await import("./adapter-gateway-mercurius-
|
|
308
|
+
const { MercuriusGatewayAdapter } = await import("./adapter-gateway-mercurius-rbKlwF9m.mjs");
|
|
320
309
|
return new MercuriusGatewayAdapter(logger);
|
|
321
310
|
}
|
|
322
311
|
case "stitching": {
|
|
323
|
-
const { StitchingGatewayAdapter } = await import("./adapter-gateway-stitching-
|
|
312
|
+
const { StitchingGatewayAdapter } = await import("./adapter-gateway-stitching-Dzv10u8D.mjs");
|
|
324
313
|
return new StitchingGatewayAdapter(logger);
|
|
325
314
|
}
|
|
326
315
|
}
|
|
@@ -328,11 +317,11 @@ async function createGatewayAdapter(type, logger) {
|
|
|
328
317
|
async function createHttpAdapter(type) {
|
|
329
318
|
switch (type) {
|
|
330
319
|
case "express": {
|
|
331
|
-
const { createExpressHttpAdapter } = await import("./adapter-http-express-
|
|
320
|
+
const { createExpressHttpAdapter } = await import("./adapter-http-express-Drbaxszc.mjs");
|
|
332
321
|
return createExpressHttpAdapter();
|
|
333
322
|
}
|
|
334
323
|
case "fastify": {
|
|
335
|
-
const { createFastifyHttpAdapter } = await import("./adapter-http-fastify-
|
|
324
|
+
const { createFastifyHttpAdapter } = await import("./adapter-http-fastify-DMPW_huG.mjs");
|
|
336
325
|
return createFastifyHttpAdapter();
|
|
337
326
|
}
|
|
338
327
|
}
|
|
@@ -360,7 +349,7 @@ const WS_AUTH_CLOSE_REASONS = [WS_CLOSE_REASON_AUTHENTICATION_REQUIRED, WS_CLOSE
|
|
|
360
349
|
*/
|
|
361
350
|
const SEGMENT = /^[a-z0-9][-a-z0-9._]*$/i;
|
|
362
351
|
/** Segments that would read as path traversal rather than as a name. */
|
|
363
|
-
const TRAVERSAL = new Set([".", ".."]);
|
|
352
|
+
const TRAVERSAL = /* @__PURE__ */ new Set([".", ".."]);
|
|
364
353
|
var InvalidNamespaceError = class extends Error {};
|
|
365
354
|
/**
|
|
366
355
|
* Turns a package name into the path segments it occupies.
|
|
@@ -846,27 +835,29 @@ var HttpScope = class {
|
|
|
846
835
|
headers: fetchHeaders(req),
|
|
847
836
|
signal: controller.signal
|
|
848
837
|
};
|
|
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 = {
|
|
838
|
+
if (method !== "GET" && method !== "HEAD" && body !== "none") {
|
|
839
|
+
if (body === "stream") init = {
|
|
867
840
|
...init,
|
|
868
|
-
body:
|
|
841
|
+
body: Readable.toWeb(req),
|
|
842
|
+
duplex: "half"
|
|
869
843
|
};
|
|
844
|
+
else {
|
|
845
|
+
try {
|
|
846
|
+
raw = await readBody(req, spec.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES$1);
|
|
847
|
+
} catch (error) {
|
|
848
|
+
if (error instanceof BodyTooLargeError) {
|
|
849
|
+
res.setHeader("connection", "close");
|
|
850
|
+
res.once("finish", () => req.destroy());
|
|
851
|
+
writeError(res, 413, "Payload too large");
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
throw error;
|
|
855
|
+
}
|
|
856
|
+
if (raw.length) init = {
|
|
857
|
+
...init,
|
|
858
|
+
body: new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength)
|
|
859
|
+
};
|
|
860
|
+
}
|
|
870
861
|
}
|
|
871
862
|
await writeResponse(res, await spec.handler(new Request(url, init), {
|
|
872
863
|
...ctx,
|
|
@@ -1043,7 +1034,7 @@ function verifyWebhook(options) {
|
|
|
1043
1034
|
}
|
|
1044
1035
|
/** Headers that would put a credential in a log or run journal. The configured signature
|
|
1045
1036
|
* header joins them: it is an HMAC of the body under a live secret. */
|
|
1046
|
-
const REDACTED_HEADERS = new Set([
|
|
1037
|
+
const REDACTED_HEADERS = /* @__PURE__ */ new Set([
|
|
1047
1038
|
"authorization",
|
|
1048
1039
|
"proxy-authorization",
|
|
1049
1040
|
"cookie",
|
|
@@ -1316,6 +1307,7 @@ function newWebhookToken() {
|
|
|
1316
1307
|
const NAMESPACE = "reactor_webhooks";
|
|
1317
1308
|
/** Relational implementation, over the reactor's own database. */
|
|
1318
1309
|
var RelationalWebhookStore = class {
|
|
1310
|
+
relationalDb;
|
|
1319
1311
|
#db;
|
|
1320
1312
|
constructor(relationalDb) {
|
|
1321
1313
|
this.relationalDb = relationalDb;
|
|
@@ -1461,7 +1453,7 @@ const stripScalarDefinitions = (doc) => {
|
|
|
1461
1453
|
* whole gateway. We dedupe these by name; field/operation/extension nodes are
|
|
1462
1454
|
* left untouched.
|
|
1463
1455
|
*/
|
|
1464
|
-
const TYPE_DEFINITION_KINDS = new Set([
|
|
1456
|
+
const TYPE_DEFINITION_KINDS = /* @__PURE__ */ new Set([
|
|
1465
1457
|
Kind.OBJECT_TYPE_DEFINITION,
|
|
1466
1458
|
Kind.ENUM_TYPE_DEFINITION,
|
|
1467
1459
|
Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
|
@@ -1563,7 +1555,7 @@ const getDocumentModelTypeDefs = (documentModels, typeDefs$1) => {
|
|
|
1563
1555
|
stateJSON: JSONObject
|
|
1564
1556
|
}\n`;
|
|
1565
1557
|
});
|
|
1566
|
-
|
|
1558
|
+
const schema = gql`
|
|
1567
1559
|
scalar JSONObject
|
|
1568
1560
|
scalar AttachmentRef
|
|
1569
1561
|
# Codegen scalars not in the document-engineering set.
|
|
@@ -1639,7 +1631,8 @@ const getDocumentModelTypeDefs = (documentModels, typeDefs$1) => {
|
|
|
1639
1631
|
}
|
|
1640
1632
|
|
|
1641
1633
|
${stripScalarDefinitions(typeDefs$1)}
|
|
1642
|
-
|
|
1634
|
+
`;
|
|
1635
|
+
return dedupeTypeDefinitions(schema);
|
|
1643
1636
|
};
|
|
1644
1637
|
/**
|
|
1645
1638
|
* Extract type names from a GraphQL schema.
|
|
@@ -1735,9 +1728,7 @@ function generateStateInputTypes(stateSchema, excludeTypeNames) {
|
|
|
1735
1728
|
case Kind.OBJECT_TYPE_DEFINITION:
|
|
1736
1729
|
objectNames.add(def.name.value);
|
|
1737
1730
|
break;
|
|
1738
|
-
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
1739
|
-
existingInputNames.add(def.name.value);
|
|
1740
|
-
break;
|
|
1731
|
+
case Kind.INPUT_OBJECT_TYPE_DEFINITION: existingInputNames.add(def.name.value);
|
|
1741
1732
|
}
|
|
1742
1733
|
const inputTypes = [];
|
|
1743
1734
|
for (const def of ast.definitions) {
|
|
@@ -1766,7 +1757,7 @@ function applyGraphQLTypePrefixes(schema, prefix, externalTypeNames = []) {
|
|
|
1766
1757
|
if (!schema || !schema.trim()) return schema;
|
|
1767
1758
|
let processedSchema = schema;
|
|
1768
1759
|
const localTypeNames = extractTypeNames(schema);
|
|
1769
|
-
const allTypeNames = [
|
|
1760
|
+
const allTypeNames = [.../* @__PURE__ */ new Set([...localTypeNames, ...externalTypeNames])];
|
|
1770
1761
|
if (allTypeNames.length === 0) return schema;
|
|
1771
1762
|
allTypeNames.forEach((typeName) => {
|
|
1772
1763
|
const typeRegex = new RegExp(`(?<![_A-Za-z0-9])(${typeName})(?![_A-Za-z0-9])|\\[(${typeName})\\]|\\[(${typeName})!\\]|\\[(${typeName})\\]!|\\[(${typeName})!\\]!`, "g");
|
|
@@ -1794,8 +1785,9 @@ function generateDocumentModelSchema(documentModel, options = {}) {
|
|
|
1794
1785
|
const localStateTypeNames = extractTypeNames(localStateSchema ?? "");
|
|
1795
1786
|
const stateTypeNames = [...globalStateTypeNames, ...localStateTypeNames];
|
|
1796
1787
|
const allOperationTypeNames = specification?.modules.flatMap((module) => module.operations.flatMap((op) => extractTypeNames(op.schema ?? ""))) ?? [];
|
|
1797
|
-
const allTypeNames = [
|
|
1798
|
-
const
|
|
1788
|
+
const allTypeNames = [.../* @__PURE__ */ new Set([...stateTypeNames, ...allOperationTypeNames])];
|
|
1789
|
+
const operationInputTypeNames = new Set(allOperationTypeNames);
|
|
1790
|
+
const prefixedStateInputTypes = applyGraphQLTypePrefixes(extractInputTypeDefinitions(globalStateSchema ?? "", operationInputTypeNames), documentName, allTypeNames);
|
|
1799
1791
|
const hasValidSchema = (schema) => !!(schema && /\b(input|type|enum|union|interface)\s+\w+/.test(schema));
|
|
1800
1792
|
const stateSchemaTypes = globalStateSchema ? applyGraphQLTypePrefixes(globalStateSchema.replaceAll("scalar DateTime", "").replaceAll(/input (.*?) {[\s\S]*?}/g, ""), documentName, allTypeNames) : "";
|
|
1801
1793
|
if (useNewApi) return generateNewApiSchema(documentName, specification, stateSchemaTypes, prefixedStateInputTypes, allTypeNames, hasValidSchema);
|
|
@@ -3020,8 +3012,8 @@ function fromInputMaybe(value) {
|
|
|
3020
3012
|
function toReactorPropagationMode(gqlMode) {
|
|
3021
3013
|
if (gqlMode == null) return;
|
|
3022
3014
|
switch (gqlMode) {
|
|
3023
|
-
case
|
|
3024
|
-
case
|
|
3015
|
+
case "CASCADE": return PropagationMode$1.Cascade;
|
|
3016
|
+
case "ORPHAN": return PropagationMode$1.None;
|
|
3025
3017
|
}
|
|
3026
3018
|
}
|
|
3027
3019
|
/**
|
|
@@ -3031,10 +3023,10 @@ function toReactorPropagationMode(gqlMode) {
|
|
|
3031
3023
|
*/
|
|
3032
3024
|
function toGqlActionEvaluation(evaluation) {
|
|
3033
3025
|
return evaluation.decision === "allow" ? {
|
|
3034
|
-
decision:
|
|
3026
|
+
decision: "ALLOW",
|
|
3035
3027
|
reason: null
|
|
3036
3028
|
} : {
|
|
3037
|
-
decision:
|
|
3029
|
+
decision: "DENY",
|
|
3038
3030
|
reason: evaluation.reason
|
|
3039
3031
|
};
|
|
3040
3032
|
}
|
|
@@ -3617,7 +3609,8 @@ async function createEmptyDocument(reactorClient, args, reactorDriveClient) {
|
|
|
3617
3609
|
if (parentIdentifier) {
|
|
3618
3610
|
const parent = await reactorClient.get(parentIdentifier);
|
|
3619
3611
|
if (isDriveContainerType(parent.header.documentType)) {
|
|
3620
|
-
const
|
|
3612
|
+
const module = await reactorClient.getDocumentModelModule(args.documentType);
|
|
3613
|
+
const document = withSignaturePolicy(module.utils.createDocument(), await reactorClient.getCreateSignaturePolicy());
|
|
3621
3614
|
if (name) document.header.name = name;
|
|
3622
3615
|
result = await pickDriveClient(reactorClient, parent.header.documentType, reactorDriveClient).addFile(parentIdentifier, document);
|
|
3623
3616
|
} else result = await reactorClient.createEmpty(args.documentType, { parentIdentifier });
|
|
@@ -3642,7 +3635,7 @@ async function createDocumentWithInitialState(reactorClient, args, reactorDriveC
|
|
|
3642
3635
|
} catch (error) {
|
|
3643
3636
|
throw new GraphQLError(`Document model not found for type ${args.documentType}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3644
3637
|
}
|
|
3645
|
-
const document = module.utils.createDocument();
|
|
3638
|
+
const document = withSignaturePolicy(module.utils.createDocument(), await reactorClient.getCreateSignaturePolicy());
|
|
3646
3639
|
const allowedScopes = new Set(Object.keys(module.documentModel.global.specifications.at(-1)?.state ?? {}));
|
|
3647
3640
|
const state = document.state;
|
|
3648
3641
|
for (const [scope, scopeState] of Object.entries(args.initialState)) if (allowedScopes.has(scope) && scope in state) state[scope] = {
|
|
@@ -4343,7 +4336,7 @@ const DRIVE_ID_HEADER = "drive-id";
|
|
|
4343
4336
|
* in the ownership set yet); other create-shaped operations that may
|
|
4344
4337
|
* synthesize a drive must be added here too.
|
|
4345
4338
|
*/
|
|
4346
|
-
const CACHE_BYPASS_OPERATIONS = new Set(["createDocument", "createEmptyDocument"]);
|
|
4339
|
+
const CACHE_BYPASS_OPERATIONS = /* @__PURE__ */ new Set(["createDocument", "createEmptyDocument"]);
|
|
4347
4340
|
const driveIdMap = /* @__PURE__ */ new WeakMap();
|
|
4348
4341
|
/** Internal — only `graphql-manager.ts` should call this. */
|
|
4349
4342
|
function getRequestDriveId(request) {
|
|
@@ -4413,6 +4406,7 @@ function wrongShardResponse(driveId) {
|
|
|
4413
4406
|
* 421 response.
|
|
4414
4407
|
*/
|
|
4415
4408
|
var DriveOwnershipCache = class {
|
|
4409
|
+
reactorClient;
|
|
4416
4410
|
drives = /* @__PURE__ */ new Set();
|
|
4417
4411
|
constructor(reactorClient) {
|
|
4418
4412
|
this.reactorClient = reactorClient;
|
|
@@ -4530,6 +4524,22 @@ function createWsAuthHandlers(opts) {
|
|
|
4530
4524
|
};
|
|
4531
4525
|
}
|
|
4532
4526
|
var GraphQLManager = class {
|
|
4527
|
+
path;
|
|
4528
|
+
httpServer;
|
|
4529
|
+
wsServer;
|
|
4530
|
+
reactorClient;
|
|
4531
|
+
relationalDb;
|
|
4532
|
+
analyticsStore;
|
|
4533
|
+
syncManager;
|
|
4534
|
+
logger;
|
|
4535
|
+
httpAdapter;
|
|
4536
|
+
gatewayAdapter;
|
|
4537
|
+
authService;
|
|
4538
|
+
documentPermissionService;
|
|
4539
|
+
featureFlags;
|
|
4540
|
+
port;
|
|
4541
|
+
syncServingGate;
|
|
4542
|
+
httpRoutes;
|
|
4533
4543
|
initialized = false;
|
|
4534
4544
|
coreSubgraphsMap = /* @__PURE__ */ new Map();
|
|
4535
4545
|
contextFields = {};
|
|
@@ -4544,8 +4554,8 @@ var GraphQLManager = class {
|
|
|
4544
4554
|
subgraphHandlerCache = /* @__PURE__ */ new Map();
|
|
4545
4555
|
/** subgraphPath → the http adapter handle of its mounted route. */
|
|
4546
4556
|
subgraphRouteHandles = /* @__PURE__ */ new Map();
|
|
4547
|
-
/**
|
|
4548
|
-
|
|
4557
|
+
/** Mounted SSE routes, keyed by path: the supergraph's and each subgraph's. */
|
|
4558
|
+
sseRouteHandles = /* @__PURE__ */ new Map();
|
|
4549
4559
|
/**
|
|
4550
4560
|
* Package name → the subgraph instances registered from it, keyed by
|
|
4551
4561
|
* subgraph name. Tracks the package association so that removed packages
|
|
@@ -4743,6 +4753,7 @@ var GraphQLManager = class {
|
|
|
4743
4753
|
routeHandle.dispose();
|
|
4744
4754
|
this.subgraphRouteHandles.delete(subgraphPath);
|
|
4745
4755
|
}
|
|
4756
|
+
this.#disposeSSERoute(subgraphPath);
|
|
4746
4757
|
const wsDisposer = this.subgraphWsDisposers.get(subgraphPath);
|
|
4747
4758
|
if (wsDisposer) {
|
|
4748
4759
|
this.subgraphWsDisposers.delete(subgraphPath);
|
|
@@ -5082,10 +5093,7 @@ var GraphQLManager = class {
|
|
|
5082
5093
|
const allSubgraphs = this.#getAllSubgraphs();
|
|
5083
5094
|
const modules = Array.from(allSubgraphs.values()).filter((subgraph) => subgraph.hasSubscriptions).map((subgraph) => this.#buildSubgraphSchemaModule(subgraph));
|
|
5084
5095
|
if (modules.length === 0) {
|
|
5085
|
-
|
|
5086
|
-
this.sseRouteHandle.dispose();
|
|
5087
|
-
this.sseRouteHandle = void 0;
|
|
5088
|
-
}
|
|
5096
|
+
this.#disposeSSERoute(superGraphPath);
|
|
5089
5097
|
return;
|
|
5090
5098
|
}
|
|
5091
5099
|
try {
|
|
@@ -5111,8 +5119,16 @@ var GraphQLManager = class {
|
|
|
5111
5119
|
contextFactory: this.#makeContextFactory()
|
|
5112
5120
|
});
|
|
5113
5121
|
const handler = this.#composeFetchMiddleware(rawHandler);
|
|
5114
|
-
|
|
5115
|
-
this.
|
|
5122
|
+
this.#disposeSSERoute(basePath);
|
|
5123
|
+
this.sseRouteHandles.set(ssePath, this.httpAdapter.mount(ssePath, handler, { exact: true }));
|
|
5124
|
+
}
|
|
5125
|
+
#disposeSSERoute(basePath) {
|
|
5126
|
+
const ssePath = basePath + "/stream";
|
|
5127
|
+
const handle = this.sseRouteHandles.get(ssePath);
|
|
5128
|
+
if (handle !== void 0) {
|
|
5129
|
+
handle.dispose();
|
|
5130
|
+
this.sseRouteHandles.delete(ssePath);
|
|
5131
|
+
}
|
|
5116
5132
|
}
|
|
5117
5133
|
/**
|
|
5118
5134
|
* Compose the request-level fetch middleware chain. Auth runs first
|
|
@@ -5623,7 +5639,7 @@ function createReactorGraphQLClient(url, fetchImpl = fetch, headers) {
|
|
|
5623
5639
|
}
|
|
5624
5640
|
//#endregion
|
|
5625
5641
|
//#region src/graphql/reactor/schema.graphql
|
|
5626
|
-
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 \"\"\"The index of the last operation in the scope the action applies to.\"\"\"\n prevOpIndex: Int\n\n \"\"\"The hash of the state the action applies to.\"\"\"\n prevOpHash: String\n\n \"\"\"Covers replay of an operation that would otherwise be a no-op.\"\"\"\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";
|
|
5642
|
+
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";
|
|
5627
5643
|
//#endregion
|
|
5628
5644
|
//#region src/graphql/reactor/pubsub.ts
|
|
5629
5645
|
const pubSub = new PubSub();
|
|
@@ -5997,6 +6013,13 @@ var ReactorSubgraph = class extends BaseSubgraph {
|
|
|
5997
6013
|
throw error;
|
|
5998
6014
|
}
|
|
5999
6015
|
},
|
|
6016
|
+
/**
|
|
6017
|
+
* Gated on reading the document, the same gate every other read here
|
|
6018
|
+
* carries: a verdict is derived from the document's policy, so a caller
|
|
6019
|
+
* who may not read the document may not preflight against it either.
|
|
6020
|
+
* That gate decides whether the query runs; the answer comes entirely
|
|
6021
|
+
* from the reactor's decision model.
|
|
6022
|
+
*/
|
|
6000
6023
|
evaluateActions: async (_parent, args, ctx) => {
|
|
6001
6024
|
this.logger.debug("evaluateActions(@args)", args);
|
|
6002
6025
|
try {
|
|
@@ -6372,10 +6395,10 @@ const ADMIN_USERS = getAdminUsers();
|
|
|
6372
6395
|
//#endregion
|
|
6373
6396
|
//#region src/graphql/system/version.ts
|
|
6374
6397
|
function getVersion() {
|
|
6375
|
-
return "6.2.3-dev.
|
|
6398
|
+
return "6.2.3-dev.25";
|
|
6376
6399
|
}
|
|
6377
6400
|
function getGitHash() {
|
|
6378
|
-
return "
|
|
6401
|
+
return "e44ced14916428517ebc9e26d9bfb53d1d86cbc0";
|
|
6379
6402
|
}
|
|
6380
6403
|
function getGitUrl() {
|
|
6381
6404
|
return buildTreeUrl(getGitHash());
|
|
@@ -6476,7 +6499,8 @@ var HttpPackageLoader = class {
|
|
|
6476
6499
|
async loadUpgradeManifests(packageSpec) {
|
|
6477
6500
|
const { name: packageName } = this.parsePackageSpec(packageSpec);
|
|
6478
6501
|
if (!this.isValidPackageName(packageName)) throw new Error(`Invalid package name: ${packageName}`);
|
|
6479
|
-
const
|
|
6502
|
+
const module = await import(`${this.registryUrl}-/cdn/${packageSpec}/node/document-models/index.mjs`);
|
|
6503
|
+
const manifests = extractUpgradeManifests(module);
|
|
6480
6504
|
if (manifests.length > 0) this.logger.verbose(`Loaded ${manifests.length} upgrade manifests from ${packageName}`);
|
|
6481
6505
|
return manifests;
|
|
6482
6506
|
}
|
|
@@ -6667,10 +6691,11 @@ var ImportPackageLoader = class {
|
|
|
6667
6691
|
this.reportUnbuilt(identifier, root, listPath);
|
|
6668
6692
|
return [];
|
|
6669
6693
|
}
|
|
6670
|
-
const
|
|
6694
|
+
const module = await import(
|
|
6671
6695
|
/* @vite-ignore */
|
|
6672
6696
|
pathToFileURL(listPath).href
|
|
6673
|
-
)
|
|
6697
|
+
);
|
|
6698
|
+
const pieces = piecesFromListModule(module, {
|
|
6674
6699
|
root,
|
|
6675
6700
|
identifier,
|
|
6676
6701
|
logger: this.logger
|
|
@@ -6720,6 +6745,7 @@ function getUniqueUpgradeManifests(...upgradeManifests) {
|
|
|
6720
6745
|
return Array.from(uniqueManifests.values());
|
|
6721
6746
|
}
|
|
6722
6747
|
var PackageManager = class {
|
|
6748
|
+
options;
|
|
6723
6749
|
logger = childLogger(["reactor-api", "package-manager"]);
|
|
6724
6750
|
loaders;
|
|
6725
6751
|
docModelsMap = /* @__PURE__ */ new Map();
|
|
@@ -7074,20 +7100,41 @@ async function createStartupAttachmentBackend({ db, env = process.env, s3Depende
|
|
|
7074
7100
|
}
|
|
7075
7101
|
//#endregion
|
|
7076
7102
|
//#region src/services/attachment-access.service.ts
|
|
7103
|
+
/** The scope an attachment's bytes belong to: the document's own domain state. */
|
|
7104
|
+
const ATTACHMENT_SCOPE = "global";
|
|
7105
|
+
/** The branch an attachment reference is resolved against. */
|
|
7106
|
+
const ATTACHMENT_BRANCH = "main";
|
|
7077
7107
|
const HASH_PATTERN = /^[a-f0-9]{64}$/;
|
|
7078
7108
|
/**
|
|
7079
7109
|
* Composes document authorization with the projected document/ref
|
|
7080
7110
|
* relationship. Order is fixed: validate ref, resolve the canonical document
|
|
7081
|
-
* id,
|
|
7111
|
+
* id, decide the read, then check the reference index. A denied document
|
|
7082
7112
|
* never reaches the reference reader, and the facade never touches
|
|
7083
7113
|
* attachment metadata, storage backends, or presigners.
|
|
7114
|
+
*
|
|
7115
|
+
* The read is decided by the document's own policy when this composition has a
|
|
7116
|
+
* model to enforce it with, and by the host's permission tables when it does
|
|
7117
|
+
* not. That is not a preference between two equivalent answers: a host running
|
|
7118
|
+
* document policies keeps no rows in the permission tables, so asking them
|
|
7119
|
+
* about such a document returns whatever the host-wide policy says — under
|
|
7120
|
+
* `OPEN`, `true`, for everyone. Serving bytes on that answer hands the file to
|
|
7121
|
+
* anyone who learns its hash, which the document's own state may well have told
|
|
7122
|
+
* them. Both are kept because they are the two halves of one rule: an
|
|
7123
|
+
* attachment is readable by whoever may read the document that references it,
|
|
7124
|
+
* and each composition can only express that in its own terms.
|
|
7084
7125
|
*/
|
|
7085
7126
|
var AttachmentAccessService = class {
|
|
7086
|
-
|
|
7127
|
+
resolveCanonicalId;
|
|
7128
|
+
authorization;
|
|
7129
|
+
references;
|
|
7130
|
+
projection;
|
|
7131
|
+
scopeGate;
|
|
7132
|
+
constructor(resolveCanonicalId, authorization, references, projection, scopeGate) {
|
|
7087
7133
|
this.resolveCanonicalId = resolveCanonicalId;
|
|
7088
7134
|
this.authorization = authorization;
|
|
7089
7135
|
this.references = references;
|
|
7090
7136
|
this.projection = projection;
|
|
7137
|
+
this.scopeGate = scopeGate;
|
|
7091
7138
|
}
|
|
7092
7139
|
async canReadAttachment(request) {
|
|
7093
7140
|
if (this.projection.status !== "available") return { kind: "projection-unavailable" };
|
|
@@ -7099,7 +7146,7 @@ var AttachmentAccessService = class {
|
|
|
7099
7146
|
} catch {
|
|
7100
7147
|
return { kind: "denied" };
|
|
7101
7148
|
}
|
|
7102
|
-
if (!await this.
|
|
7149
|
+
if (!await this.canReadDocument(documentId, request)) return { kind: "denied" };
|
|
7103
7150
|
if (!await this.references.hasReference(documentId, ref)) return { kind: "denied" };
|
|
7104
7151
|
return {
|
|
7105
7152
|
kind: "allowed",
|
|
@@ -7107,6 +7154,21 @@ var AttachmentAccessService = class {
|
|
|
7107
7154
|
ref
|
|
7108
7155
|
};
|
|
7109
7156
|
}
|
|
7157
|
+
/**
|
|
7158
|
+
* Whether the caller may read the state the reference lives in.
|
|
7159
|
+
*
|
|
7160
|
+
* A failure here is rethrown rather than turned into a denial. A read side
|
|
7161
|
+
* that is down must not read as a policy: a denial nobody can distinguish
|
|
7162
|
+
* from a refusal is one nobody investigates, and the route answers 500 for a
|
|
7163
|
+
* reason.
|
|
7164
|
+
*/
|
|
7165
|
+
async canReadDocument(documentId, request) {
|
|
7166
|
+
if (!this.scopeGate) return this.authorization.canRead(documentId, request.userAddress);
|
|
7167
|
+
return (await this.scopeGate.scopePredicateById(documentId, {
|
|
7168
|
+
address: request.userAddress,
|
|
7169
|
+
key: request.appKey
|
|
7170
|
+
}, ATTACHMENT_BRANCH))(ATTACHMENT_SCOPE);
|
|
7171
|
+
}
|
|
7110
7172
|
};
|
|
7111
7173
|
/**
|
|
7112
7174
|
* Parses and canonicalizes a caller-supplied ref through the shared parser.
|
|
@@ -7152,14 +7214,42 @@ function normalizeAttachmentRef(value) {
|
|
|
7152
7214
|
* context has no caller, and is rejected. The server never composes this
|
|
7153
7215
|
* middleware without the auth middleware in the chain (see
|
|
7154
7216
|
* `assertRequireAuthenticatedCallerAllowed` in `server.ts`).
|
|
7217
|
+
*
|
|
7218
|
+
* `exemptPaths` names the mounted paths that stay reachable anonymously — a
|
|
7219
|
+
* deployment whose product has a flow that runs before sign-in, such as
|
|
7220
|
+
* previewing an invitation from its code, needs somewhere to serve it from.
|
|
7221
|
+
* Each entry is a hole in the floor, so the match is deliberately the
|
|
7222
|
+
* narrowest one that works: the request's pathname, compared in full. A
|
|
7223
|
+
* prefix rule would exempt `/graphql/public-admin` along with
|
|
7224
|
+
* `/graphql/public`, and an exempt surface nobody can enumerate by reading
|
|
7225
|
+
* the configuration is not one anybody audits.
|
|
7155
7226
|
*/
|
|
7156
|
-
function createRequireAuthFetchMiddleware() {
|
|
7227
|
+
function createRequireAuthFetchMiddleware(exemptPaths = []) {
|
|
7228
|
+
const exempt = new Set(exemptPaths.map(normalizeExemptPath));
|
|
7157
7229
|
return (next) => async (request) => {
|
|
7158
7230
|
if (request.method === "OPTIONS") return next(request);
|
|
7231
|
+
if (exempt.size > 0 && exempt.has(normalizeExemptPath(new URL(request.url).pathname))) return next(request);
|
|
7159
7232
|
if (getAuthContext(request)?.user === void 0) return new globalThis.Response(JSON.stringify({ error: "Authentication required" }), { status: 401 });
|
|
7160
7233
|
return next(request);
|
|
7161
7234
|
};
|
|
7162
7235
|
}
|
|
7236
|
+
/**
|
|
7237
|
+
* The form both sides of the comparison are reduced to: surrounding whitespace
|
|
7238
|
+
* gone, and one trailing slash gone, so `/graphql/public/` and
|
|
7239
|
+
* `/graphql/public` are the same path. A client that appends a slash is not
|
|
7240
|
+
* asking for a different route, and a configuration that carries one is not
|
|
7241
|
+
* asking for a different rule.
|
|
7242
|
+
*
|
|
7243
|
+
* Deliberately NOT normalized: case, percent-encoding, and a missing leading
|
|
7244
|
+
* slash. The first two would let two spellings of one path diverge from how
|
|
7245
|
+
* the router itself matches; the third is a configuration error, and
|
|
7246
|
+
* `assertRequireAuthenticatedCallerAllowed` refuses to boot on it rather than
|
|
7247
|
+
* leaving an exemption that silently never applies.
|
|
7248
|
+
*/
|
|
7249
|
+
function normalizeExemptPath(path) {
|
|
7250
|
+
const trimmed = path.trim();
|
|
7251
|
+
return trimmed.length > 1 && trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
|
|
7252
|
+
}
|
|
7163
7253
|
//#endregion
|
|
7164
7254
|
//#region src/migrations/001_create_document_permissions.ts
|
|
7165
7255
|
var _001_create_document_permissions_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -7562,6 +7652,7 @@ async function createRenownCredentialVerifier(config = {}) {
|
|
|
7562
7652
|
* - Users can be granted permission to execute specific operations
|
|
7563
7653
|
*/
|
|
7564
7654
|
var DocumentPermissionService = class {
|
|
7655
|
+
db;
|
|
7565
7656
|
config;
|
|
7566
7657
|
constructor(db, config = { defaultProtection: false }) {
|
|
7567
7658
|
this.db = db;
|
|
@@ -8045,10 +8136,36 @@ function assertSkipCredentialVerificationAllowed(resolvesCallerIdentity, skipCre
|
|
|
8045
8136
|
* require-authenticated-caller middleware would reject every caller —
|
|
8046
8137
|
* authenticated ones included. Refuse to boot rather than run broken.
|
|
8047
8138
|
*/
|
|
8048
|
-
function assertRequireAuthenticatedCallerAllowed(requireAuthenticatedCaller, resolvesCallerIdentity) {
|
|
8139
|
+
function assertRequireAuthenticatedCallerAllowed(requireAuthenticatedCaller, resolvesCallerIdentity, exemptPaths = []) {
|
|
8140
|
+
/**
|
|
8141
|
+
* An exemption is only ever a hole in this floor, so configuring one while
|
|
8142
|
+
* the floor is off is not a harmless no-op: it reads, to anyone auditing the
|
|
8143
|
+
* configuration, as a surface that was deliberately opened — and therefore
|
|
8144
|
+
* as a floor that exists. Refuse rather than let the two drift.
|
|
8145
|
+
*/
|
|
8146
|
+
if (!requireAuthenticatedCaller && exemptPaths.length > 0) throw new Error("REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS is set but refused: REQUIRE_AUTHENTICATED_CALLER is off, so nothing is being exempted from anything and the configuration claims a protection the server is not applying. Enable the floor, or drop the exemptions.");
|
|
8147
|
+
/**
|
|
8148
|
+
* A path that cannot match anything is worse than no path: the operator
|
|
8149
|
+
* believes the flow is reachable, and finds out when the first user cannot
|
|
8150
|
+
* claim an invitation. `URL.pathname` is always absolute, so an entry that
|
|
8151
|
+
* does not start with `/` never matches, whatever the router does.
|
|
8152
|
+
*/
|
|
8153
|
+
const relative = exemptPaths.filter((path) => !path.trim().startsWith("/"));
|
|
8154
|
+
if (relative.length > 0) throw new Error(`REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS contains ${relative.map((path) => `"${path}"`).join(", ")}, which cannot match: an exempt path is compared against the request's pathname and must start with '/' (for example '/graphql/public').`);
|
|
8049
8155
|
if (!requireAuthenticatedCaller || resolvesCallerIdentity) return;
|
|
8050
8156
|
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).");
|
|
8051
8157
|
}
|
|
8158
|
+
/**
|
|
8159
|
+
* Deciding an attachment read by the document's policy needs a policy model to
|
|
8160
|
+
* decide with, and that is what auth enforcement supplies. Without one there is
|
|
8161
|
+
* nothing to consult, so the setting would silently leave the permission tables
|
|
8162
|
+
* in charge — configuration that describes a protection the server is not
|
|
8163
|
+
* applying, which is worse than no configuration at all. Refuse instead.
|
|
8164
|
+
*/
|
|
8165
|
+
function assertAttachmentPolicyReadsAllowed(attachmentReadsFollowDocumentPolicy, hasDecisionModel) {
|
|
8166
|
+
if (!attachmentReadsFollowDocumentPolicy || hasDecisionModel) return;
|
|
8167
|
+
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).");
|
|
8168
|
+
}
|
|
8052
8169
|
function createReadinessGate() {
|
|
8053
8170
|
let ready = false;
|
|
8054
8171
|
return {
|
|
@@ -8238,6 +8355,8 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8238
8355
|
let authEnabled = false;
|
|
8239
8356
|
let configuredResolveIdentity;
|
|
8240
8357
|
let configuredRequireAuth;
|
|
8358
|
+
let configuredExemptPaths;
|
|
8359
|
+
let configuredAttachmentPolicyReads;
|
|
8241
8360
|
let configuredRenown;
|
|
8242
8361
|
if (options.configFile) {
|
|
8243
8362
|
const config = getConfig(options.configFile);
|
|
@@ -8249,8 +8368,10 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8249
8368
|
authEnabled = options.auth.enabled;
|
|
8250
8369
|
configuredResolveIdentity = options.auth.resolveIdentity;
|
|
8251
8370
|
configuredRequireAuth = options.auth.requireAuthenticatedCaller;
|
|
8371
|
+
configuredExemptPaths = options.auth.requireAuthenticatedCallerExemptPaths;
|
|
8372
|
+
configuredAttachmentPolicyReads = options.auth.attachmentReadsFollowDocumentPolicy;
|
|
8252
8373
|
}
|
|
8253
|
-
const { AUTH_ENABLED, RESOLVE_CALLER_IDENTITY, REQUIRE_AUTHENTICATED_CALLER, ADMINS, DEFAULT_PROTECTION, DOCUMENT_PERMISSIONS_ENABLED, SKIP_CREDENTIAL_VERIFICATION, CREDENTIAL_VERIFICATION_CACHE_TTL_MS } = process.env;
|
|
8374
|
+
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;
|
|
8254
8375
|
if (AUTH_ENABLED !== void 0) authEnabled = AUTH_ENABLED === "true";
|
|
8255
8376
|
/**
|
|
8256
8377
|
* Whether the auth middleware reads the bearer and populates `ctx.user`,
|
|
@@ -8281,6 +8402,30 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8281
8402
|
*/
|
|
8282
8403
|
let requireAuthenticatedCaller = configuredRequireAuth ?? false;
|
|
8283
8404
|
if (REQUIRE_AUTHENTICATED_CALLER !== void 0) requireAuthenticatedCaller = REQUIRE_AUTHENTICATED_CALLER === "true";
|
|
8405
|
+
/**
|
|
8406
|
+
* The paths the floor above does not apply to. Comma-separated, like
|
|
8407
|
+
* `ADMINS`, because a deployment configures this the same way it configures
|
|
8408
|
+
* everything else: one variable, one line, however many values it has.
|
|
8409
|
+
*
|
|
8410
|
+
* Empty entries are dropped rather than refused, so a trailing comma or a
|
|
8411
|
+
* value split across lines in a manifest is not a boot failure; a value that
|
|
8412
|
+
* cannot ever match is refused, in
|
|
8413
|
+
* {@link assertRequireAuthenticatedCallerAllowed}.
|
|
8414
|
+
*/
|
|
8415
|
+
let requireAuthenticatedCallerExemptPaths = configuredExemptPaths ?? [];
|
|
8416
|
+
if (REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS !== void 0) requireAuthenticatedCallerExemptPaths = REQUIRE_AUTHENTICATED_CALLER_EXEMPT_PATHS.split(",").map((path) => path.trim()).filter((path) => path.length > 0);
|
|
8417
|
+
/**
|
|
8418
|
+
* Whether an attachment read is decided by the referencing document's own
|
|
8419
|
+
* policy rather than by the host's permission tables.
|
|
8420
|
+
*
|
|
8421
|
+
* Off by default, and a deployment's choice rather than something derived
|
|
8422
|
+
* from the flags around it. Which model governs those bytes is configuration
|
|
8423
|
+
* in the same sense the storage backend behind them is: a host that has said
|
|
8424
|
+
* nothing keeps exactly the behaviour it has, and one that wants the change
|
|
8425
|
+
* asks for it and can take it back without disturbing anything else.
|
|
8426
|
+
*/
|
|
8427
|
+
let attachmentReadsFollowDocumentPolicy = configuredAttachmentPolicyReads ?? false;
|
|
8428
|
+
if (ATTACHMENT_READS_FOLLOW_DOCUMENT_POLICY !== void 0) attachmentReadsFollowDocumentPolicy = ATTACHMENT_READS_FOLLOW_DOCUMENT_POLICY === "true";
|
|
8284
8429
|
if (ADMINS !== void 0) admins = ADMINS.split(",").map((a) => a.toLowerCase());
|
|
8285
8430
|
let defaultProtection = false;
|
|
8286
8431
|
if (DEFAULT_PROTECTION !== void 0) defaultProtection = DEFAULT_PROTECTION.toLowerCase() === "true";
|
|
@@ -8295,7 +8440,7 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8295
8440
|
const documentPermissionsRequested = options.documentPermissionService !== void 0 || DOCUMENT_PERMISSIONS_ENABLED === "true";
|
|
8296
8441
|
assertAuthRequiredForDocumentPermissions(authEnabled, documentPermissionsRequested);
|
|
8297
8442
|
assertSkipCredentialVerificationAllowed(resolveCallerIdentity, skipCredentialVerification, process.env);
|
|
8298
|
-
assertRequireAuthenticatedCallerAllowed(requireAuthenticatedCaller, resolveCallerIdentity);
|
|
8443
|
+
assertRequireAuthenticatedCallerAllowed(requireAuthenticatedCaller, resolveCallerIdentity, requireAuthenticatedCallerExemptPaths);
|
|
8299
8444
|
if (authEnabled && skipCredentialVerification) logger.warn("SECURITY: SKIP_CREDENTIAL_VERIFICATION is enabled — Renown credential verification is disabled and a bearer token's claimed address is NOT cryptographically bound to its signing key. Identity is unverifiable; use only in development or test.");
|
|
8300
8445
|
httpAdapter.getRoute("/health", () => new Response("OK", { status: 200 }));
|
|
8301
8446
|
const readiness = createReadinessGate();
|
|
@@ -8331,8 +8476,8 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8331
8476
|
});
|
|
8332
8477
|
authFetchMiddleware = createAuthFetchMiddleware(authService);
|
|
8333
8478
|
if (requireAuthenticatedCaller) {
|
|
8334
|
-
requireAuthFetchMiddleware = createRequireAuthFetchMiddleware();
|
|
8335
|
-
logger.info("Require-authenticated-caller middleware enabled: anonymous callers are rejected with a 401 before any subgraph");
|
|
8479
|
+
requireAuthFetchMiddleware = createRequireAuthFetchMiddleware(requireAuthenticatedCallerExemptPaths);
|
|
8480
|
+
logger.info(requireAuthenticatedCallerExemptPaths.length > 0 ? `Require-authenticated-caller middleware enabled: anonymous callers are rejected with a 401 before any subgraph, except on ${requireAuthenticatedCallerExemptPaths.join(", ")}` : "Require-authenticated-caller middleware enabled: anonymous callers are rejected with a 401 before any subgraph");
|
|
8336
8481
|
} else logger.warn("Anonymous callers are admitted on every transport, including WebSocket subscriptions: REQUIRE_AUTHENTICATED_CALLER is not set. The authorization policy gates the reactor's own documents, but a package-provided subgraph authorizes nothing on its own. Set REQUIRE_AUTHENTICATED_CALLER=true to refuse anonymous callers before any subgraph sees them.");
|
|
8337
8482
|
}
|
|
8338
8483
|
const dbClosers = [];
|
|
@@ -8357,7 +8502,7 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8357
8502
|
await mkdir(attachmentStoragePath, { recursive: true });
|
|
8358
8503
|
const { db: attachmentDb, knex: attachmentKnex, pglite: attachmentPglite } = getDbClient(options.dbPath, options.pgliteFactory);
|
|
8359
8504
|
dbClosers.push(...makeDbClosers(attachmentKnex, attachmentPglite));
|
|
8360
|
-
const ATTACHMENT_SWEEP_INTERVAL_MS =
|
|
8505
|
+
const ATTACHMENT_SWEEP_INTERVAL_MS = 36e5;
|
|
8361
8506
|
const attachmentBackend = await createStartupAttachmentBackend({ db: attachmentDb });
|
|
8362
8507
|
const attachmentBuilder = new AttachmentBuilder(attachmentDb, attachmentStoragePath).withReservationSweepMs(ATTACHMENT_SWEEP_INTERVAL_MS);
|
|
8363
8508
|
if (attachmentBackend) attachmentBuilder.withBackend(attachmentBackend);
|
|
@@ -8402,13 +8547,14 @@ async function _setupCommonInfrastructure(options) {
|
|
|
8402
8547
|
attachmentReferenceIndex,
|
|
8403
8548
|
packages,
|
|
8404
8549
|
dbClosers,
|
|
8405
|
-
readiness
|
|
8550
|
+
readiness,
|
|
8551
|
+
attachmentReadsFollowDocumentPolicy
|
|
8406
8552
|
};
|
|
8407
8553
|
}
|
|
8408
8554
|
/**
|
|
8409
8555
|
* Private helper function containing common setup logic for API initialization
|
|
8410
8556
|
*/
|
|
8411
|
-
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) {
|
|
8557
|
+
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) {
|
|
8412
8558
|
const hostModuleBase = {
|
|
8413
8559
|
...createReactorHostModuleBase({
|
|
8414
8560
|
client: reactorClient,
|
|
@@ -8450,7 +8596,8 @@ async function _setupAPI(reactorClient, syncManager, reactorProcessorManager, ht
|
|
|
8450
8596
|
const { httpServer, wsServer } = await startServer(httpAdapter, port, options.https, logger);
|
|
8451
8597
|
const authorizationService = createAuthorizationService(authorizationConfig, documentPermissionService, createGetParentIdsFn(reactorClient));
|
|
8452
8598
|
logger.info(`Authorization service initialized (policy: ${authorizationConfig.policy})`);
|
|
8453
|
-
|
|
8599
|
+
assertAttachmentPolicyReadsAllowed(attachmentReadsFollowDocumentPolicy, syncServingGate !== void 0);
|
|
8600
|
+
const attachmentAccess = new AttachmentAccessService(createCanonicalDocumentIdResolver(reactorClient), authorizationService, attachmentReferenceIndex.store, attachmentReferenceProjection, attachmentReadsFollowDocumentPolicy ? syncServingGate : void 0);
|
|
8454
8601
|
const coreSubgraphs = DefaultCoreSubgraphs.slice();
|
|
8455
8602
|
coreSubgraphs.push(ReactorSubgraph);
|
|
8456
8603
|
if (documentPermissionService) {
|
|
@@ -8487,6 +8634,7 @@ async function _setupAPI(reactorClient, syncManager, reactorProcessorManager, ht
|
|
|
8487
8634
|
attachmentReferenceIndex,
|
|
8488
8635
|
attachmentAccess,
|
|
8489
8636
|
authService,
|
|
8637
|
+
requireAuthenticatedCaller: requireAuthFetchMiddleware !== void 0,
|
|
8490
8638
|
authorizationService,
|
|
8491
8639
|
relationalDb,
|
|
8492
8640
|
dispose
|
|
@@ -8535,7 +8683,7 @@ function buildApiDispose(args) {
|
|
|
8535
8683
|
};
|
|
8536
8684
|
}
|
|
8537
8685
|
async function initializeAndStartAPI(clientInitializer, options, processorApp) {
|
|
8538
|
-
const { port, httpAdapter, httpRoutes, authFetchMiddleware, requireAuthFetchMiddleware, authService, relationalDb, analyticsStore, documentPermissionService, authorizationConfig, attachments, attachmentReferenceIndex, packages, dbClosers, readiness } = await _setupCommonInfrastructure(options);
|
|
8686
|
+
const { port, httpAdapter, httpRoutes, authFetchMiddleware, requireAuthFetchMiddleware, authService, relationalDb, analyticsStore, documentPermissionService, authorizationConfig, attachments, attachmentReferenceIndex, packages, dbClosers, readiness, attachmentReadsFollowDocumentPolicy } = await _setupCommonInfrastructure(options);
|
|
8539
8687
|
const { documentModels, upgradeManifests, processors, subgraphs } = await packages.init();
|
|
8540
8688
|
const { module: reactorClientModule, reactorDriveClient, attachmentReferenceProjection = {
|
|
8541
8689
|
status: "unavailable",
|
|
@@ -8552,7 +8700,7 @@ async function initializeAndStartAPI(clientInitializer, options, processorApp) {
|
|
|
8552
8700
|
const documentModelRegistry = reactorClientModule.reactorModule?.documentModelRegistry;
|
|
8553
8701
|
if (!documentModelRegistry) throw new Error("DocumentModelRegistry not available from InProcessReactorClientModule");
|
|
8554
8702
|
return {
|
|
8555
|
-
...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),
|
|
8703
|
+
...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),
|
|
8556
8704
|
client: reactorClient,
|
|
8557
8705
|
syncManager,
|
|
8558
8706
|
documentModelRegistry,
|
|
@@ -8685,7 +8833,7 @@ var PackageManagementService = class {
|
|
|
8685
8833
|
}
|
|
8686
8834
|
};
|
|
8687
8835
|
//#endregion
|
|
8688
|
-
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 };
|
|
8836
|
+
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, 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 };
|
|
8689
8837
|
|
|
8690
8838
|
//# sourceMappingURL=index.mjs.map
|
|
8691
|
-
//# debugId=
|
|
8839
|
+
//# debugId=6828688f-9737-5852-b599-51439acc4894
|