@powerhousedao/powerhouse-vetra-packages 6.2.3-dev.2 → 6.2.3-dev.4
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/browser/{connect-BqgnsniX.js → connect-BtHSAuSc.js} +10 -4
- package/dist/browser/{connect-BqgnsniX.js.map → connect-BtHSAuSc.js.map} +1 -1
- package/dist/browser/{dist-C-xkNfyD.js → dist-D69hfRZN.js} +8 -8
- package/dist/browser/dist-D69hfRZN.js.map +1 -0
- package/dist/browser/{document-drive-ZQzPQfEL.js → document-drive-BEXJ-rHp.js} +61 -21
- package/dist/browser/{document-drive-ZQzPQfEL.js.map → document-drive-BEXJ-rHp.js.map} +1 -1
- package/dist/browser/document-models/index.js +1 -1
- package/dist/browser/{editor-DZP1WlYy.js → editor-Cbl_EDjI.js} +5 -5
- package/dist/browser/{editor-DZP1WlYy.js.map → editor-Cbl_EDjI.js.map} +1 -1
- package/dist/browser/{editor-BNgF9-uX.js → editor-mNThkZOv.js} +6 -6
- package/dist/browser/{editor-BNgF9-uX.js.map → editor-mNThkZOv.js.map} +1 -1
- package/dist/browser/editors/document-model-editor/module.js +1 -1
- package/dist/browser/editors/generic-drive-explorer/index.js +4 -4
- package/dist/browser/editors/generic-drive-explorer/module.js +1 -1
- package/dist/browser/{folder-view-tx0A96ZI.js → folder-view-D8AkN1Oj.js} +3 -3
- package/dist/browser/{folder-view-tx0A96ZI.js.map → folder-view-D8AkN1Oj.js.map} +1 -1
- package/dist/browser/{graphql-editor-Cbkb5KRZ.js → graphql-editor-BcL3-Zha.js} +3 -3
- package/dist/browser/{graphql-editor-Cbkb5KRZ.js.map → graphql-editor-BcL3-Zha.js.map} +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/{json-editor-CN6kPtl1.js → json-editor-DHXQRIN5.js} +3 -3
- package/dist/browser/{json-editor-CN6kPtl1.js.map → json-editor-DHXQRIN5.js.map} +1 -1
- package/dist/browser/lib-ewnRj2dJ.js.map +1 -1
- package/dist/browser/{state-schemas-CKh98ehP.js → state-schemas-C4F8lReN.js} +3 -3
- package/dist/browser/{state-schemas-CKh98ehP.js.map → state-schemas-C4F8lReN.js.map} +1 -1
- package/dist/node/{connect-CeLh6yfj.mjs → connect-B6IQsY6u.mjs} +10 -4
- package/dist/node/{connect-CeLh6yfj.mjs.map → connect-B6IQsY6u.mjs.map} +1 -1
- package/dist/node/{dist-CUFTZwfc.mjs → dist-hd-KLWy7.mjs} +8 -8
- package/dist/node/dist-hd-KLWy7.mjs.map +1 -0
- package/dist/node/{document-drive-D1NMjQQc.mjs → document-drive-CkV9NvD7.mjs} +61 -21
- package/dist/node/{document-drive-D1NMjQQc.mjs.map → document-drive-CkV9NvD7.mjs.map} +1 -1
- package/dist/node/document-models/index.mjs +1 -1
- package/dist/node/{editor-CXQOsbup.mjs → editor-C93fdI28.mjs} +6 -6
- package/dist/node/{editor-CXQOsbup.mjs.map → editor-C93fdI28.mjs.map} +1 -1
- package/dist/node/{editor-Dg2OZEJu.mjs → editor-DG1q4Y55.mjs} +5 -5
- package/dist/node/{editor-Dg2OZEJu.mjs.map → editor-DG1q4Y55.mjs.map} +1 -1
- package/dist/node/editors/document-model-editor/module.mjs +1 -1
- package/dist/node/editors/generic-drive-explorer/index.mjs +4 -4
- package/dist/node/editors/generic-drive-explorer/module.mjs +1 -1
- package/dist/node/{folder-view-DZ0o2-Ef.mjs → folder-view-BGabHV7H.mjs} +3 -3
- package/dist/node/{folder-view-DZ0o2-Ef.mjs.map → folder-view-BGabHV7H.mjs.map} +1 -1
- package/dist/node/{graphql-editor-DNxebuTn.mjs → graphql-editor-B-XIb6az.mjs} +3 -3
- package/dist/node/{graphql-editor-DNxebuTn.mjs.map → graphql-editor-B-XIb6az.mjs.map} +1 -1
- package/dist/node/index.mjs +1 -1
- package/dist/node/{json-editor-BpnEn9AS.mjs → json-editor-DB0vi6tV.mjs} +3 -3
- package/dist/node/{json-editor-BpnEn9AS.mjs.map → json-editor-DB0vi6tV.mjs.map} +1 -1
- package/dist/node/main-B1tRsYOp.mjs.map +1 -1
- package/dist/node/{state-schemas-CuSHxrn6.mjs → state-schemas-BGsgtEG1.mjs} +3 -3
- package/dist/node/{state-schemas-CuSHxrn6.mjs.map → state-schemas-BGsgtEG1.mjs.map} +1 -1
- package/package.json +7 -7
- package/dist/browser/dist-C-xkNfyD.js.map +0 -1
- package/dist/node/dist-CUFTZwfc.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-B1tRsYOp.mjs","names":["exports"],"sources":["../../../reactor/dist/drive-container-types-yZrksiJR.js","../../../reactor/dist/index.js","../../../../node_modules/.pnpm/tslib@2.8.1/node_modules/tslib/tslib.es6.mjs","../../../../node_modules/.pnpm/graphql-tag@2.12.6_graphql@16.12.0/node_modules/graphql-tag/lib/graphql-tag.umd.js","../../../../node_modules/.pnpm/graphql-tag@2.12.6_graphql@16.12.0/node_modules/graphql-tag/main.js"],"sourcesContent":["import { n as ReactorEventTypes, t as EventBusAggregateError } from \"./types-DMKLa0Ok.js\";\nimport { AUTH_ACTION_TYPES, AUTH_DENIED_BY_GRANT_REASON, AUTH_NO_GRANT_REASON, AUTH_VERSION_UNSUPPORTED_REASON, DOCUMENT_DELETED_REASON, DowngradeNotSupportedError as DowngradeNotSupportedError$1, appendWithoutApplying, applyAuthAction, applyDeleteDocumentAction, applyDeleteDocumentAction as applyDeleteDocumentAction$1, applyUpgradeDocumentAction, applyUpgradeDocumentAction as applyUpgradeDocumentAction$1, baseReducerVersion, createPresignedHeader, decide, defaultBaseState, deriveOperationId, evaluate, garbageCollect, groupDocumentType, groupMembershipActionTypes, hashDocumentStateForScope, isDenied, isUndoRedo, mentionedGroupIds, normalizeDocumentModelVersion, referencedGroupIds, sortOperations } from \"@powerhousedao/shared/document-model\";\nimport { v4 } from \"uuid\";\nimport { Migrator, sql } from \"kysely\";\n//#region \\0rolldown/runtime.js\nvar __defProp = Object.defineProperty;\nvar __exportAll = (all, no_symbols) => {\n\tlet target = {};\n\tfor (var name in all) __defProp(target, name, {\n\t\tget: all[name],\n\t\tenumerable: true\n\t});\n\tif (!no_symbols) __defProp(target, Symbol.toStringTag, { value: \"Module\" });\n\treturn target;\n};\n//#endregion\n//#region src/shared/utils.ts\nfunction matchesScope(view = {}, scope) {\n\tif (view.scopes) return view.scopes.includes(scope);\n\treturn true;\n}\nfunction yieldToMain() {\n\tconst s = globalThis.scheduler;\n\tif (s?.yield) return s.yield();\n\treturn new Promise((resolve) => setTimeout(resolve, 0));\n}\nconst defaultAbortError = () => /* @__PURE__ */ new Error(\"Operation aborted\");\nfunction throwIfAborted(signal, makeError = defaultAbortError) {\n\tif (signal?.aborted) throw makeError();\n}\n/**\n* Validates PagingOptions and returns a normalized offset and limit.\n* Throws if the cursor is not empty and not a non-negative integer, or if\n* limit is less than 1. When `paging` is undefined, returns offset 0 and\n* the caller-supplied `defaultLimit`.\n*/\nfunction parsePagingOptions(paging, defaultLimit) {\n\tif (paging === void 0) return {\n\t\toffset: 0,\n\t\tlimit: defaultLimit\n\t};\n\tif (!Number.isInteger(paging.limit) || paging.limit < 1) throw new Error(`Invalid paging limit: ${String(paging.limit)} (must be an integer >= 1)`);\n\tif (paging.cursor === \"\") return {\n\t\toffset: 0,\n\t\tlimit: paging.limit\n\t};\n\tconst parsed = Number(paging.cursor);\n\tif (!Number.isInteger(parsed) || parsed < 0) throw new Error(`Invalid paging cursor: ${JSON.stringify(paging.cursor)} (must be empty or a non-negative integer)`);\n\treturn {\n\t\toffset: parsed,\n\t\tlimit: paging.limit\n\t};\n}\n//#endregion\n//#region src/shared/errors.ts\n/**\n* Error thrown when attempting to access a deleted document.\n*/\nvar DocumentDeletedError = class DocumentDeletedError extends Error {\n\tdocumentId;\n\tdeletedAtUtcIso;\n\tconstructor(documentId, deletedAtUtcIso = null) {\n\t\tconst message = deletedAtUtcIso ? `Document ${documentId} was deleted at ${deletedAtUtcIso}` : `Document ${documentId} has been deleted`;\n\t\tsuper(message);\n\t\tthis.name = \"DocumentDeletedError\";\n\t\tthis.documentId = documentId;\n\t\tthis.deletedAtUtcIso = deletedAtUtcIso;\n\t\tError.captureStackTrace(this, DocumentDeletedError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DocumentDeletedError\";\n\t}\n};\n/**\n* Error thrown when the auth policy denies an action at the executor gate.\n*/\nvar AuthorizationDeniedError = class AuthorizationDeniedError extends Error {\n\tdocumentId;\n\tscope;\n\toperation;\n\tsubject;\n\tconstructor(documentId, scope, operation, subject) {\n\t\tsuper(`Authorization denied: ${subject ?? \"anonymous\"} may not execute ${operation} in scope \"${scope}\" of document ${documentId}`);\n\t\tthis.name = \"AuthorizationDeniedError\";\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.operation = operation;\n\t\tthis.subject = subject;\n\t\tError.captureStackTrace(this, AuthorizationDeniedError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AuthorizationDeniedError\";\n\t}\n};\n/**\n* An auth operation did not strictly exceed the newest timestamp in its stream.\n*\n* Terminal and asymmetric by design: no ordering rule can reconcile two replicas\n* that each accepted an auth operation offline, because either order hands one\n* authority the other never granted, so the replica ahead holds the arrival.\n*/\nvar AuthTimestampNotMonotonicError = class AuthTimestampNotMonotonicError extends Error {\n\tdocumentId;\n\tbranch;\n\ttimestampUtcMs;\n\tnewestTimestampUtcMs;\n\tconstructor(documentId, branch, timestampUtcMs, newestTimestampUtcMs) {\n\t\tsuper(`Auth timestamp not monotonic: ${timestampUtcMs} does not exceed ${newestTimestampUtcMs} in the auth stream of document ${documentId} on branch ${branch}`);\n\t\tthis.name = \"AuthTimestampNotMonotonicError\";\n\t\tthis.documentId = documentId;\n\t\tthis.branch = branch;\n\t\tthis.timestampUtcMs = timestampUtcMs;\n\t\tthis.newestTimestampUtcMs = newestTimestampUtcMs;\n\t\tError.captureStackTrace(this, AuthTimestampNotMonotonicError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AuthTimestampNotMonotonicError\";\n\t}\n};\n/**\n* An operation or action carried a timestamp that is not an ISO-8601 UTC\n* instant.\n*\n* Terminal rather than retryable: the value does not change between attempts,\n* so a retry re-runs the whole job to fail identically. Quarantining, unlike a\n* held auth operation — this is malformed data rather than two replicas\n* disagreeing, and nothing further from that source should be trusted until it\n* is looked at.\n*/\nvar InvalidOperationTimestampError = class InvalidOperationTimestampError extends Error {\n\tdocumentId;\n\tscope;\n\ttimestampUtcMs;\n\tconstructor(documentId, scope, timestampUtcMs, context) {\n\t\tsuper(`Invalid timestamp \"${timestampUtcMs}\" on ${context} in scope \"${scope}\" of document ${documentId}`);\n\t\tthis.name = \"InvalidOperationTimestampError\";\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.timestampUtcMs = timestampUtcMs;\n\t\tError.captureStackTrace(this, InvalidOperationTimestampError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"InvalidOperationTimestampError\";\n\t}\n};\n/**\n* A load would move more operations than the bound allows, indicating a real\n* divergence between local and incoming history. Counts only first-time moves,\n* so a re-evaluation pass's re-appends do not make busy documents\n* revocation-proof. Terminal: the condition is deterministic.\n*/\nvar ExcessiveReshuffleError = class ExcessiveReshuffleError extends Error {\n\tdocumentId;\n\tscope;\n\tcount;\n\tthreshold;\n\tconstructor(documentId, scope, count, threshold) {\n\t\tsuper(`Excessive reshuffle detected: ${count} operations in scope \"${scope}\" of document ${documentId} exceeds the threshold of ${threshold}. This indicates a significant divergence between local and incoming operations.`);\n\t\tthis.name = \"ExcessiveReshuffleError\";\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.count = count;\n\t\tthis.threshold = threshold;\n\t\tError.captureStackTrace(this, ExcessiveReshuffleError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"ExcessiveReshuffleError\";\n\t}\n};\n/**\n* Error thrown when an operation has an invalid signature.\n*/\nvar InvalidSignatureError = class InvalidSignatureError extends Error {\n\tdocumentId;\n\treason;\n\tconstructor(documentId, reason) {\n\t\tsuper(`Invalid signature in document ${documentId}: ${reason}`);\n\t\tthis.name = \"InvalidSignatureError\";\n\t\tthis.documentId = documentId;\n\t\tthis.reason = reason;\n\t\tError.captureStackTrace(this, InvalidSignatureError);\n\t}\n};\n/**\n* An UPGRADE_DOCUMENT action's preconditions (fromVersion and the per-scope\n* revision snapshot) did not match the document state the executor loaded.\n*\n* Terminal rather than retryable: the action carries the client's snapshot,\n* which stays stale no matter how often the job re-runs. The client is\n* expected to re-read the document and submit a fresh action instead.\n*/\nvar UpgradePreconditionFailedError = class UpgradePreconditionFailedError extends Error {\n\tdocumentId;\n\tdetail;\n\tconstructor(documentId, detail) {\n\t\tsuper(`Upgrade precondition failed for document ${documentId}: ${detail}`);\n\t\tthis.name = \"UpgradePreconditionFailedError\";\n\t\tthis.documentId = documentId;\n\t\tthis.detail = detail;\n\t\tError.captureStackTrace(this, UpgradePreconditionFailedError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"UpgradePreconditionFailedError\";\n\t}\n};\n/**\n* Error thrown when a document is not found (no operations exist for the document ID).\n*/\nvar DocumentNotFoundError = class DocumentNotFoundError extends Error {\n\tdocumentId;\n\t/**\n\t* @param message Overrides the default text. A handler that knows which of\n\t* several documents an action reads - a relationship's source, say - says so\n\t* here rather than rewrapping in a bare Error, which would strip the name the\n\t* executor classifies by.\n\t*/\n\tconstructor(documentId, message) {\n\t\tsuper(message ?? `Document ${documentId} not found`);\n\t\tthis.name = \"DocumentNotFoundError\";\n\t\tthis.documentId = documentId;\n\t\tError.captureStackTrace(this, DocumentNotFoundError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DocumentNotFoundError\";\n\t}\n};\n/**\n* An authorization preflight was asked for while the reactor's decision model\n* is off, so there is no model to answer from.\n*\n* Thrown rather than answered from the legacy host-side permission tables. The\n* two systems do not compose: the tables record which addresses a host lets\n* near a drive, the policy records what a document's own grants permit, and an\n* answer stitched from both would report an admission verdict neither system\n* would reach. A caller that cannot get a prediction disables nothing, which\n* leaves the submit path -- and its real gate -- as the only authority.\n*\n* Detection is by `name`, not `instanceof`: the SharedWorker RPC boundary\n* rebuilds a thrown error from `{ name, message, stack, cause }` alone\n* (`reactor-browser/src/rpc/error-info.ts`), so the class identity and any\n* custom field are lost in transit. This error therefore carries no fields.\n*/\nvar AuthEnforcementDisabledError = class AuthEnforcementDisabledError extends Error {\n\tconstructor() {\n\t\tsuper(\"Authorization evaluation requires the authEnforcement feature flag; this reactor holds no decision model, and the legacy host-table permission system cannot answer for one\");\n\t\tthis.name = \"AuthEnforcementDisabledError\";\n\t\tError.captureStackTrace(this, AuthEnforcementDisabledError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AuthEnforcementDisabledError\";\n\t}\n};\n//#endregion\n//#region src/storage/interfaces.ts\n/**\n* Thrown when an operation with the same identity already exists in the store.\n*/\nvar DuplicateOperationError = class extends Error {\n\tconstructor(description) {\n\t\tsuper(`Duplicate operation: ${description}`);\n\t\tthis.name = \"DuplicateOperationError\";\n\t}\n};\n/**\n* Thrown when a concurrent write conflict is detected during an atomic apply.\n*/\nvar OptimisticLockError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message);\n\t\tthis.name = \"OptimisticLockError\";\n\t}\n};\n/**\n* Thrown when the caller-provided revision does not match the current\n* stored revision, indicating a stale read.\n*/\nvar RevisionMismatchError = class extends Error {\n\tconstructor(expected, actual) {\n\t\tsuper(`Revision mismatch: expected ${expected}, got ${actual}`);\n\t\tthis.name = \"RevisionMismatchError\";\n\t}\n};\n/**\n* A create based on an empty stream that already has operations: the id is\n* taken, and no retry can resolve it. Matched by `name`, all the RPC boundary keeps.\n*/\nvar DocumentAlreadyExistsError = class extends Error {\n\tdocumentId;\n\tconstructor(documentId, scope, headRevision) {\n\t\tsuper(`Document ${documentId} already exists: create requested revision 0 but the \"${scope}\" stream is at revision ${headRevision}`);\n\t\tthis.name = \"DocumentAlreadyExistsError\";\n\t\tthis.documentId = documentId;\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DocumentAlreadyExistsError\";\n\t}\n};\n/** Error history keeps messages, not classes, so failures match by prefix. */\nconst APPEND_CONDITION_FAILED_PREFIX = \"Append condition failed: \";\n/**\n* A read-set stream grew before the append committed. A concurrency\n* conflict, not a fault: the caller retries against the new stream heads.\n*/\nvar AppendConditionFailedError = class extends Error {\n\tconstructor(condition) {\n\t\tconst streams = condition.streams.map((s) => `${s.documentId}:${s.scope}:${s.branch}@${s.revision}`).join(\", \");\n\t\tsuper(`${APPEND_CONDITION_FAILED_PREFIX}a read-set stream advanced [${streams}]`);\n\t\tthis.condition = condition;\n\t\tthis.name = \"AppendConditionFailedError\";\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AppendConditionFailedError\";\n\t}\n\t/** True when a recorded error message is an append-condition failure. */\n\tstatic isFailureMessage(message) {\n\t\treturn message.startsWith(APPEND_CONDITION_FAILED_PREFIX);\n\t}\n};\n/**\n* Which sense of \"exists\" a caller of {@link IDocumentView.exists} means.\n*/\nlet DocumentExistence = /* @__PURE__ */ function(DocumentExistence) {\n\t/**\n\t* A document that is present and not deleted. This is the question a read\n\t* asks: a deleted document is not readable, so it does not exist.\n\t*/\n\tDocumentExistence[\"LiveOnly\"] = \"LiveOnly\";\n\t/**\n\t* Whether the id is taken, deleted or not. This is the question a write\n\t* asks: a deleted document keeps its operation stream, so its id can never\n\t* be reused, and answering from snapshots alone would say otherwise whenever\n\t* a snapshot row is missing while the stream is intact.\n\t*/\n\tDocumentExistence[\"IncludingDeleted\"] = \"IncludingDeleted\";\n\treturn DocumentExistence;\n}({});\n//#endregion\n//#region src/decision/build-decision-model.ts\n/**\n* Reads each projection's stream through the supplied reader, recording the\n* revision observed. Static projections resolve first; derived projections\n* see only those and contribute a map from document id to state. Each\n* distinct stream is read once and yields one append condition entry.\n*/\nasync function buildDecisionModel(reader, definition, target, signal) {\n\tconst decisionModel = definition(target);\n\tconst projections = Object.entries(decisionModel.projections);\n\tconst reads = /* @__PURE__ */ new Map();\n\tconst model = {};\n\tfor (const [key, projection] of projections) {\n\t\tif (typeof projection.query === \"function\") continue;\n\t\tmodel[key] = (await readStream(reader, projection.query, reads, signal)).state;\n\t}\n\tconst staticModel = { ...model };\n\tfor (const [key, projection] of projections) {\n\t\tif (typeof projection.query !== \"function\") continue;\n\t\tconst queries = projection.query(staticModel);\n\t\tconst value = {};\n\t\tfor (const query of queries) {\n\t\t\tlet read;\n\t\t\ttry {\n\t\t\t\tread = await readStream(reader, query, reads, signal);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof DocumentNotFoundError) {\n\t\t\t\t\trecordEmptyStream(query, reads);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tvalue[query.documentId] = read.state;\n\t\t}\n\t\tmodel[key] = value;\n\t}\n\treturn {\n\t\tmodel,\n\t\tappendCondition: { streams: [...reads.values()].map((read) => read.stream) }\n\t};\n}\n/** Guards a stream that holds nothing yet: any operation appearing is growth. */\nfunction recordEmptyStream(query, reads) {\n\tconst key = `${query.documentId}:${query.scope}:${query.branch}`;\n\tif (reads.has(key)) return;\n\treads.set(key, {\n\t\tstate: void 0,\n\t\tstream: {\n\t\t\tdocumentId: query.documentId,\n\t\t\tscope: query.scope,\n\t\t\tbranch: query.branch,\n\t\t\trevision: -1\n\t\t}\n\t});\n}\nasync function readStream(reader, query, reads, signal) {\n\tconst key = `${query.documentId}:${query.scope}:${query.branch}`;\n\tconst existing = reads.get(key);\n\tif (existing) return existing;\n\tconst document = await reader.getState(query.documentId, query.scope, query.branch, void 0, signal);\n\tconst read = {\n\t\tstate: document.state[query.scope],\n\t\tstream: {\n\t\t\tdocumentId: query.documentId,\n\t\t\tscope: query.scope,\n\t\t\tbranch: query.branch,\n\t\t\trevision: observedRevision(document, query.scope)\n\t\t}\n\t};\n\treads.set(key, read);\n\treturn read;\n}\n/**\n* The highest operation index the document reflects for the scope, or -1 if\n* empty. `header.revision` is authoritative, not the rebuilt operation list.\n*/\nfunction observedRevision(document, scope) {\n\tif (scope in document.header.revision) return document.header.revision[scope] - 1;\n\tif (scope in document.operations) {\n\t\tconst operations = document.operations[scope];\n\t\tif (operations.length > 0) return operations[operations.length - 1].index;\n\t}\n\tif (!(scope in document.header.revision)) return -1;\n\treturn document.header.revision[scope] - 1;\n}\n/**\n* The projections whose queries depend on folded state. A positional walk\n* resolves their streams through `queryOverHistory`; a projection without one\n* contributes no streams to a walk.\n*/\nfunction derivedReadSet(definition) {\n\tconst projections = [];\n\tfor (const [name, projection] of Object.entries(definition.projections)) {\n\t\tif (typeof projection.query !== \"function\") continue;\n\t\tprojections.push({\n\t\t\tname,\n\t\t\tdecidingActions: projection.decidingActions,\n\t\t\tapply: projection.apply,\n\t\t\tqueryOverHistory: projection.queryOverHistory\n\t\t});\n\t}\n\treturn projections;\n}\n/**\n* The streams a model reads whose queries are known before it is built. A\n* derived query needs the statically-queried projections first, so it is not\n* included here.\n*/\nfunction staticReadSet(definition) {\n\tconst streams = [];\n\tfor (const [name, projection] of Object.entries(definition.projections)) {\n\t\tif (typeof projection.query === \"function\") continue;\n\t\tstreams.push({\n\t\t\tname,\n\t\t\tquery: projection.query,\n\t\t\tdecidingActions: projection.decidingActions,\n\t\t\tapply: projection.apply\n\t\t});\n\t}\n\treturn streams;\n}\n//#endregion\n//#region src/decision/auth-decision-model.ts\nfunction refusalReason(refusal) {\n\tswitch (refusal) {\n\t\tcase \"version-unsupported\": return AUTH_VERSION_UNSUPPORTED_REASON;\n\t\tcase \"denied-by-grant\": return AUTH_DENIED_BY_GRANT_REASON;\n\t\tcase \"no-applicable-grant\": return AUTH_NO_GRANT_REASON;\n\t}\n}\nfunction decideAuthModel(model, subject, request, groups, conditions) {\n\tif (request.verb === \"execute\" && model.document.isDeleted) return {\n\t\tdecision: \"deny\",\n\t\treason: DOCUMENT_DELETED_REASON\n\t};\n\tconst evaluation = evaluate(model.auth, subject, request, groups, conditions);\n\tif (evaluation.decision === \"allow\") return { decision: \"allow\" };\n\treturn {\n\t\tdecision: \"deny\",\n\t\treason: refusalReason(evaluation.refusal)\n\t};\n}\nfunction documentProjection(target) {\n\treturn {\n\t\tdecidingActions: [\"DELETE_DOCUMENT\"],\n\t\tapply: (document, operation) => operation.action.type === \"DELETE_DOCUMENT\" ? applyDeleteDocumentAction({\n\t\t\t...document,\n\t\t\tstate: { ...document.state }\n\t\t}, operation.action) : document,\n\t\tquery: {\n\t\t\tdocumentId: target.documentId,\n\t\t\tbranch: target.branch,\n\t\t\tscope: \"document\"\n\t\t}\n\t};\n}\nfunction authProjection(target) {\n\treturn {\n\t\tdecidingActions: [...AUTH_ACTION_TYPES],\n\t\tapply: (document, operation) => applyAuthAction(document, operation.action),\n\t\tquery: {\n\t\t\tdocumentId: target.documentId,\n\t\t\tbranch: target.branch,\n\t\t\tscope: \"auth\"\n\t\t}\n\t};\n}\n/** This decision model uses both the document and the auth streams. */\nfunction authDecisionModel(target) {\n\treturn {\n\t\tprojections: {\n\t\t\tdocument: documentProjection(target),\n\t\t\tauth: authProjection(target)\n\t\t},\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request) {\n\t\t\treturn decideAuthModel(model, subject, request);\n\t\t}\n\t};\n}\n/**\n* Folds one group-stream operation with the registered group model's reducer.\n* A reactor without the module registered folds nothing, so the member list\n* stays as read and a missing reducer never widens access.\n*/\nfunction applyGroupOperation(registry, document, operation) {\n\tlet reducer;\n\ttry {\n\t\treducer = registry.getModule(groupDocumentType).reducer;\n\t} catch {\n\t\treturn document;\n\t}\n\treturn reducer(document, operation.action);\n}\n/**\n* Folds one evaluated-scope operation with the reducer registered for the\n* document's own type, at the document's stamped version. A reactor without\n* that module folds nothing, so conditions read the base state and an\n* unresolvable reducer never widens access.\n*/\nfunction applyModelOperation(registry, document, operation) {\n\tlet reducer;\n\ttry {\n\t\tconst version = normalizeDocumentModelVersion(document.state.document?.version);\n\t\treducer = registry.getModule(document.header.documentType, version).reducer;\n\t} catch {\n\t\treturn document;\n\t}\n\treturn reducer(document, operation.action);\n}\n/**\n* The auth model extended with a derived groups projection: the streams it\n* reads are the group documents the folded grant list names, so adding a\n* grant that names a new group pulls that group's stream into the read-set.\n* Group queries pin the main branch, because a group's member list lives on\n* its main branch no matter which branch the referencing document is on.\n*/\nfunction groupsProjection(registry) {\n\treturn {\n\t\tdecidingActions: [...groupMembershipActionTypes],\n\t\tapply: (document, operation) => applyGroupOperation(registry, document, operation),\n\t\tquery: (model) => referencedGroupIds(model.auth?.grants ?? []).map((id) => ({\n\t\t\tdocumentId: id,\n\t\t\tbranch: \"main\",\n\t\t\tscope: \"global\"\n\t\t})),\n\t\tqueryOverHistory: (reads) => {\n\t\t\tconst ids = [];\n\t\t\tfor (const read of reads) {\n\t\t\t\tif (read.name !== \"auth\") continue;\n\t\t\t\tfor (const operation of read.operations) for (const id of mentionedGroupIds(operation.action)) if (!ids.includes(id)) ids.push(id);\n\t\t\t}\n\t\t\treturn ids.map((id) => ({\n\t\t\t\tdocumentId: id,\n\t\t\t\tbranch: \"main\",\n\t\t\t\tscope: \"global\"\n\t\t\t}));\n\t\t}\n\t};\n}\nfunction authGroupsDecisionModel(registry) {\n\treturn (target) => ({\n\t\tprojections: {\n\t\t\tdocument: documentProjection(target),\n\t\t\tauth: authProjection(target),\n\t\t\tgroups: groupsProjection(registry)\n\t\t},\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request) {\n\t\t\treturn decideAuthModel(model, subject, request, model.groups);\n\t\t}\n\t});\n}\n/**\n* The groups model with conditions live: decide hands the executing scope's\n* state and the action input through to the evaluator, so `where` clauses\n* and { match } principals apply. The model folds the evaluated scope during\n* a positional walk, so a condition reads the state as it stood at each\n* operation's position.\n*/\nfunction authConditionsDecisionModel(registry) {\n\treturn (target) => ({\n\t\tprojections: {\n\t\t\tdocument: documentProjection(target),\n\t\t\tauth: authProjection(target),\n\t\t\tgroups: groupsProjection(registry)\n\t\t},\n\t\tfoldEvaluatedScope: (document, operation) => applyModelOperation(registry, document, operation),\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request, ctx) {\n\t\t\treturn decideAuthModel(model, subject, request, model.groups, {\n\t\t\t\tscopeState: ctx.scopeState,\n\t\t\t\tactionInput: ctx.actionInput\n\t\t\t});\n\t\t}\n\t});\n}\n//#endregion\n//#region src/decision/document-decision-model.ts\n/**\n* The simplest decision model: one projection over the document scope, which\n* rejects on a deleted document.\n*/\nfunction documentDecisionModel(target) {\n\treturn {\n\t\tprojections: { document: {\n\t\t\tdecidingActions: [\"DELETE_DOCUMENT\"],\n\t\t\tapply: (document, operation) => operation.action.type === \"DELETE_DOCUMENT\" ? applyDeleteDocumentAction({\n\t\t\t\t...document,\n\t\t\t\tstate: { ...document.state }\n\t\t\t}, operation.action) : document,\n\t\t\tquery: {\n\t\t\t\tdocumentId: target.documentId,\n\t\t\t\tbranch: target.branch,\n\t\t\t\tscope: \"document\"\n\t\t\t}\n\t\t} },\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request) {\n\t\t\treturn request.verb === \"execute\" && model.document.isDeleted ? {\n\t\t\t\tdecision: \"deny\",\n\t\t\t\treason: DOCUMENT_DELETED_REASON\n\t\t\t} : { decision: \"allow\" };\n\t\t}\n\t};\n}\n//#endregion\n//#region src/decision/registered-model.ts\n/**\n* Builds the model at the stream heads and decides one request against it. The\n* append condition it returns is the read-set the store enforces at write time.\n*\n* With `conditions` supplied, the executing scope's state is read at the head\n* for `doc.<scope>.*` paths, or taken from the run's carried document when the\n* caller has already reduced earlier writes into it. That read carries no\n* append-condition entry of its own: the written stream's expected-revision\n* check already refuses a write whose scope grew between the read and the\n* append.\n*/\nasync function decideAtHead(model, cache, target, subject, request, signal, conditions) {\n\tconst built = await buildDecisionModel(cache, model, target, signal);\n\tlet scopeState;\n\tif (conditions !== void 0) scopeState = (conditions.carriedDocument ?? await cache.getState(target.documentId, request.scope, target.branch, void 0, signal)).state[request.scope];\n\treturn {\n\t\tevaluation: model(target).decide(built.model, subject, request, {\n\t\t\tscopeState,\n\t\t\tactionInput: conditions?.actionInput\n\t\t}),\n\t\tappendCondition: built.appendCondition,\n\t\tdocumentVersion: built.model.document.version,\n\t\tdeletedAtUtcIso: built.model.document.deletedAtUtcIso ?? null\n\t};\n}\n/**\n* The model this reactor enforces. With `authEnforcement` off the auth scope is\n* absent from every append condition and no load walks it; with `authGroups`\n* on, the group documents the grant list names join the read-set and the\n* registry supplies the reducer that folds them.\n*/\nfunction selectDecisionModel(flags, registry) {\n\tif (flags.authConditions) return authConditionsDecisionModel(registry);\n\tif (flags.authGroups) return authGroupsDecisionModel(registry);\n\treturn flags.authEnforcement ? authDecisionModel : documentDecisionModel;\n}\n//#endregion\n//#region src/executor/util.ts\n/** Actions the reactor reduces itself, onto the document scope. */\nconst DOCUMENT_SCOPE_ACTIONS = new Set([\n\t\"CREATE_DOCUMENT\",\n\t\"DELETE_DOCUMENT\",\n\t\"UPGRADE_DOCUMENT\",\n\t\"ADD_RELATIONSHIP\",\n\t\"REMOVE_RELATIONSHIP\",\n\t\"UPDATE_RELATIONSHIP\"\n]);\n/**\n* `CREATE_DOCUMENT` is exempt by necessity: it runs before the document exists,\n* so building a decision model would throw and defer the job forever.\n*/\nconst GATED_DOCUMENT_ACTIONS = new Set([...DOCUMENT_SCOPE_ACTIONS].filter((type) => type !== \"CREATE_DOCUMENT\"));\n/**\n* The document a document-scope action writes to, which is not always the job's\n* own document: delete and upgrade name it in `input.documentId`, and the\n* relationship actions in `input.sourceId`. `execute` only checks that a batch\n* shares one scope, so a caller can submit an action whose target is a document\n* other than the one the job is keyed by. The policy gate has to follow the\n* action rather than the job, or it decides against a policy the caller may\n* control instead of the one guarding the write.\n*/\nfunction targetDocumentId(action, fallback) {\n\tconst input = action.input;\n\tif (action.type === \"ADD_RELATIONSHIP\" || action.type === \"REMOVE_RELATIONSHIP\" || action.type === \"UPDATE_RELATIONSHIP\") return typeof input?.sourceId === \"string\" && input.sourceId.length > 0 ? input.sourceId : fallback;\n\treturn typeof input?.documentId === \"string\" && input.documentId.length > 0 ? input.documentId : fallback;\n}\n/**\n* Creates a PHDocument from a CREATE_DOCUMENT action input.\n* Reconstructs the document header and initializes the base state.\n*\n* @param action - The CREATE_DOCUMENT action containing the document parameters\n* @returns A newly constructed PHDocument with initialized header and base state\n*/\nfunction createDocumentFromAction(action) {\n\tconst input = action.input;\n\tconst header = createPresignedHeader();\n\theader.id = input.documentId;\n\theader.documentType = input.model;\n\tif (input.signing) {\n\t\theader.createdAtUtcIso = input.signing.createdAtUtcIso;\n\t\theader.lastModifiedAtUtcIso = input.signing.createdAtUtcIso;\n\t\theader.sig = {\n\t\t\tpublicKey: input.signing.publicKey,\n\t\t\tnonce: input.signing.nonce\n\t\t};\n\t}\n\tif (input.slug !== void 0) header.slug = input.slug;\n\tif (!header.slug) header.slug = input.documentId;\n\tif (input.name !== void 0) header.name = input.name;\n\tif (input.branch !== void 0) header.branch = input.branch;\n\tif (input.meta !== void 0) header.meta = input.meta;\n\tif (input.protocolVersions !== void 0) header.protocolVersions = input.protocolVersions;\n\tconst baseState = defaultBaseState();\n\treturn {\n\t\theader,\n\t\toperations: {},\n\t\tstate: baseState,\n\t\tinitialState: baseState,\n\t\tclipboard: []\n\t};\n}\n/**\n* Calculate the next operation index for a specific scope.\n* Each scope maintains its own independent index sequence.\n*\n* Per-scope indexing means:\n* - Each scope (document, global, local, etc.) has independent indexes\n* - Indexes start at 0 for each scope\n* - Different scopes can have operations with the same index value\n*\n* This function uses header.revision which is populated by the cache/storage layer\n* and contains the next available index for each scope. This design avoids requiring\n* the full operation history to be loaded, which is crucial for snapshot-based caching.\n*\n* @param document - The document whose header.revision to inspect\n* @param scope - The scope to calculate the next index for\n* @returns The next available index in the specified scope\n*/\nconst getNextIndexForScope = (document, scope) => {\n\treturn document.header.revision[scope] || 0;\n};\n/**\n* Creates an empty consistency token with no coordinates.\n* Used when a job is registered or fails without writing operations.\n*\n* @returns A consistency token with an empty coordinates array\n*/\nfunction createEmptyConsistencyToken() {\n\treturn {\n\t\tversion: 1,\n\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tcoordinates: []\n\t};\n}\n/**\n* Creates a consistency token from operations written during job execution.\n* Maps each operation to a consistency coordinate tracking (documentId, scope, branch, operationIndex).\n* If no operations are provided, returns an empty token.\n*\n* @param operationsWithContext - Array of operations with their execution context\n* @returns A consistency token representing all operations written\n*/\nfunction createConsistencyToken(operationsWithContext) {\n\tif (operationsWithContext.length === 0) return createEmptyConsistencyToken();\n\tconst coordinates = [];\n\tfor (let i = 0; i < operationsWithContext.length; i++) {\n\t\tconst opWithContext = operationsWithContext[i];\n\t\tcoordinates.push({\n\t\t\tdocumentId: opWithContext.context.documentId,\n\t\t\tscope: opWithContext.context.scope,\n\t\t\tbranch: opWithContext.context.branch,\n\t\t\toperationIndex: opWithContext.operation.index\n\t\t});\n\t}\n\treturn {\n\t\tversion: 1,\n\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tcoordinates\n\t};\n}\nfunction createOperation(action, index, skip, context) {\n\treturn {\n\t\tid: deriveOperationId(context.documentId, context.scope, context.branch, action.id),\n\t\tindex,\n\t\ttimestampUtcMs: action.timestampUtcMs || (/* @__PURE__ */ new Date()).toISOString(),\n\t\thash: \"\",\n\t\tskip,\n\t\taction\n\t};\n}\nfunction updateDocumentRevision(document, scope, operationIndex) {\n\tdocument.header.revision = {\n\t\t...document.header.revision,\n\t\t[scope]: operationIndex + 1\n\t};\n}\nfunction buildSuccessResult(job, operation, documentId, documentType, resultingState, startTime) {\n\treturn {\n\t\tjob,\n\t\tsuccess: true,\n\t\toperations: [operation],\n\t\toperationsWithContext: [{\n\t\t\toperation,\n\t\t\tcontext: {\n\t\t\t\tdocumentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch,\n\t\t\t\tdocumentType,\n\t\t\t\tresultingState,\n\t\t\t\tordinal: 0\n\t\t\t}\n\t\t}],\n\t\tduration: Date.now() - startTime\n\t};\n}\nfunction buildErrorResult(job, error, startTime) {\n\treturn {\n\t\tjob,\n\t\tsuccess: false,\n\t\terror,\n\t\tduration: Date.now() - startTime\n\t};\n}\n/**\n* The error a refusal surfaces as. Both classes are already terminal in the job\n* result handler, so a refusal never burns a retry.\n*/\nfunction refusalError(reason, documentId, deletedAtUtcIso, action) {\n\tif (reason === DOCUMENT_DELETED_REASON) return new DocumentDeletedError(documentId, deletedAtUtcIso);\n\treturn new AuthorizationDeniedError(documentId, action.scope, action.type, action.context?.signer?.user.address);\n}\n/**\n* Whether this operation is part of the document's creation. The create and the\n* upgrade from version zero hold the first two indexes for the life of the\n* document, so a reshuffle has to leave them where they are.\n*/\nfunction isGenesisOperation(operation) {\n\tif (operation.action.type === \"CREATE_DOCUMENT\") return true;\n\tif (operation.action.type !== \"UPGRADE_DOCUMENT\") return false;\n\treturn operation.action.input.fromVersion === 0;\n}\n/**\n* The distinct streams a job wrote, collected so a rollback knows what to evict.\n*\n* A write records its stream on every apply, and a long run applies the same\n* stream hundreds of times, so this keeps one entry per stream rather than one\n* per write: the eviction only cares which streams were touched, and the\n* successful jobs that never read this back pay for a lookup instead of an\n* allocation.\n*/\nvar TouchedStreams = class {\n\tstreams = /* @__PURE__ */ new Map();\n\tadd(documentId, scope, branch) {\n\t\tconst key = `${documentId}\\u0000${scope}\\u0000${branch}`;\n\t\tif (this.streams.has(key)) return;\n\t\tthis.streams.set(key, {\n\t\t\tdocumentId,\n\t\t\tscope,\n\t\t\tbranch\n\t\t});\n\t}\n\t[Symbol.iterator]() {\n\t\treturn this.streams.values();\n\t}\n};\n//#endregion\n//#region src/registry/errors.ts\n/**\n* Error thrown when a document model module is not found in the registry.\n*/\nvar ModuleNotFoundError = class extends Error {\n\tdocumentType;\n\trequestedVersion;\n\tconstructor(documentType, version) {\n\t\tconst versionSuffix = version !== void 0 ? ` version ${version}` : \"\";\n\t\tsuper(`Document model module not found for type: ${documentType}${versionSuffix}`);\n\t\tthis.name = \"ModuleNotFoundError\";\n\t\tthis.documentType = documentType;\n\t\tthis.requestedVersion = version;\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"ModuleNotFoundError\";\n\t}\n};\n/**\n* Error thrown when attempting to register a module that already exists.\n*/\nvar DuplicateModuleError = class extends Error {\n\tconstructor(documentType, version) {\n\t\tconst versionSuffix = version !== void 0 ? ` (version ${version})` : \"\";\n\t\tsuper(`Document model module already registered for type: ${documentType}${versionSuffix}`);\n\t\tthis.name = \"DuplicateModuleError\";\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DuplicateModuleError\";\n\t}\n};\n/**\n* Error thrown when a module is invalid or malformed.\n*/\nvar InvalidModuleError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(`Invalid document model module: ${message}`);\n\t\tthis.name = \"InvalidModuleError\";\n\t}\n};\n/**\n* Error thrown when attempting to register an upgrade manifest that already exists.\n*/\nvar DuplicateManifestError = class extends Error {\n\tconstructor(documentType) {\n\t\tsuper(`Upgrade manifest already registered for type: ${documentType}`);\n\t\tthis.name = \"DuplicateManifestError\";\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DuplicateManifestError\";\n\t}\n};\n/**\n* Error thrown when an upgrade manifest is not found.\n*/\nvar ManifestNotFoundError = class extends Error {\n\tconstructor(documentType) {\n\t\tsuper(`Upgrade manifest not found for type: ${documentType}`);\n\t\tthis.name = \"ManifestNotFoundError\";\n\t}\n};\n/**\n* Error thrown when a required upgrade transition is missing from the manifest.\n*/\nvar MissingUpgradeTransitionError = class extends Error {\n\tconstructor(documentType, fromVersion, toVersion) {\n\t\tsuper(`Missing upgrade transition for ${documentType}: v${fromVersion} to v${toVersion}`);\n\t\tthis.name = \"MissingUpgradeTransitionError\";\n\t}\n};\n/**\n* Error thrown when getUpgradeReducer is called with a non-single-step version increment.\n*/\nvar InvalidUpgradeStepError = class extends Error {\n\tconstructor(documentType, fromVersion, toVersion) {\n\t\tsuper(`Invalid upgrade step for ${documentType}: must be single version increment, got v${fromVersion} to v${toVersion}`);\n\t\tthis.name = \"InvalidUpgradeStepError\";\n\t}\n};\n//#endregion\n//#region src/executor/types.ts\n/** How long a deferred job waits for its document before it fails. */\nconst DEFAULT_DEFERRED_JOB_TTL_MS = 3e4;\n/**\n* Event types for the job executor\n*/\nconst JobExecutorEventTypes = {\n\tJOB_STARTED: 2e4,\n\tJOB_COMPLETED: 20001,\n\tJOB_FAILED: 20002,\n\tEXECUTOR_STARTED: 20003,\n\tEXECUTOR_STOPPED: 20004\n};\n//#endregion\n//#region src/cache/collection-membership-cache.ts\nvar CollectionMembershipCache = class CollectionMembershipCache {\n\tcache = /* @__PURE__ */ new Map();\n\tconstructor(operationIndex) {\n\t\tthis.operationIndex = operationIndex;\n\t}\n\twithScopedIndex(operationIndex) {\n\t\tconst scoped = new CollectionMembershipCache(operationIndex);\n\t\tscoped.cache = this.cache;\n\t\treturn scoped;\n\t}\n\tasync getCollectionsForDocuments(documentIds) {\n\t\tconst result = {};\n\t\tconst missing = [];\n\t\tfor (const docId of documentIds) {\n\t\t\tconst cached = this.cache.get(docId);\n\t\t\tif (cached !== void 0) result[docId] = cached;\n\t\t\telse missing.push(docId);\n\t\t}\n\t\tif (missing.length > 0) {\n\t\t\tconst fromDb = await this.operationIndex.getCollectionsForDocuments(missing);\n\t\t\tfor (const docId of missing) {\n\t\t\t\tconst collections = fromDb[docId] ?? [];\n\t\t\t\tresult[docId] = collections;\n\t\t\t\tthis.cache.set(docId, collections);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\tinvalidate(documentId) {\n\t\tthis.cache.delete(documentId);\n\t}\n};\n//#endregion\n//#region src/cache/lru/lru-tracker.ts\nvar LRUNode = class {\n\tkey;\n\tprev;\n\tnext;\n\tconstructor(key) {\n\t\tthis.key = key;\n\t\tthis.prev = void 0;\n\t\tthis.next = void 0;\n\t}\n};\nvar LRUTracker = class {\n\tmap;\n\thead;\n\ttail;\n\tconstructor() {\n\t\tthis.map = /* @__PURE__ */ new Map();\n\t\tthis.head = void 0;\n\t\tthis.tail = void 0;\n\t}\n\tget size() {\n\t\treturn this.map.size;\n\t}\n\ttouch(key) {\n\t\tconst node = this.map.get(key);\n\t\tif (node) this.moveToFront(node);\n\t\telse this.addToFront(key);\n\t}\n\tevict() {\n\t\tif (!this.tail) return;\n\t\tconst key = this.tail.key;\n\t\tthis.remove(key);\n\t\treturn key;\n\t}\n\tremove(key) {\n\t\tconst node = this.map.get(key);\n\t\tif (!node) return;\n\t\tthis.removeNode(node);\n\t\tthis.map.delete(key);\n\t}\n\tclear() {\n\t\tthis.map.clear();\n\t\tthis.head = void 0;\n\t\tthis.tail = void 0;\n\t}\n\taddToFront(key) {\n\t\tconst node = new LRUNode(key);\n\t\tthis.map.set(key, node);\n\t\tif (!this.head) {\n\t\t\tthis.head = node;\n\t\t\tthis.tail = node;\n\t\t} else {\n\t\t\tnode.next = this.head;\n\t\t\tthis.head.prev = node;\n\t\t\tthis.head = node;\n\t\t}\n\t}\n\tmoveToFront(node) {\n\t\tif (node === this.head) return;\n\t\tthis.removeNode(node);\n\t\tnode.prev = void 0;\n\t\tnode.next = this.head;\n\t\tif (this.head) this.head.prev = node;\n\t\tthis.head = node;\n\t\tif (!this.tail) this.tail = node;\n\t}\n\tremoveNode(node) {\n\t\tif (node.prev) node.prev.next = node.next;\n\t\telse this.head = node.next;\n\t\tif (node.next) node.next.prev = node.prev;\n\t\telse this.tail = node.prev;\n\t}\n};\n//#endregion\n//#region src/cache/document-meta-cache.ts\n/**\n* In-memory document metadata cache with LRU eviction.\n*\n* Caches PHDocumentState per (documentId, branch) key. On cache miss,\n* rebuilds from document scope operations. Provides an explicit cross-scope\n* contract for accessing document scope metadata.\n*\n* **Thread Safety:**\n* Not thread-safe. Designed for single-threaded job executor environment.\n*/\nvar DocumentMetaCache = class DocumentMetaCache {\n\tcache;\n\tlruTracker;\n\toperationStore;\n\tconfig;\n\tconstructor(operationStore, config) {\n\t\tthis.operationStore = operationStore;\n\t\tthis.config = { maxDocuments: config.maxDocuments };\n\t\tthis.cache = /* @__PURE__ */ new Map();\n\t\tthis.lruTracker = new LRUTracker();\n\t}\n\twithScopedStore(operationStore) {\n\t\tconst scoped = new DocumentMetaCache(operationStore, this.config);\n\t\tscoped.cache = this.cache;\n\t\tscoped.lruTracker = this.lruTracker;\n\t\treturn scoped;\n\t}\n\tasync startup() {\n\t\treturn Promise.resolve();\n\t}\n\tasync shutdown() {\n\t\treturn Promise.resolve();\n\t}\n\tasync getDocumentMeta(documentId, branch, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst key = this.makeKey(documentId, branch);\n\t\tconst cached = this.cache.get(key);\n\t\tif (cached) {\n\t\t\tthis.lruTracker.touch(key);\n\t\t\treturn cached;\n\t\t}\n\t\tconst meta = await this.rebuildLatest(documentId, branch, signal);\n\t\tthis.putDocumentMeta(documentId, branch, meta);\n\t\treturn meta;\n\t}\n\tasync rebuildAtRevision(documentId, branch, targetRevision, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn this.rebuildFromOperations(documentId, branch, targetRevision, signal);\n\t}\n\tputDocumentMeta(documentId, branch, meta) {\n\t\tconst key = this.makeKey(documentId, branch);\n\t\tif (!this.cache.has(key) && this.cache.size >= this.config.maxDocuments) {\n\t\t\tconst evictKey = this.lruTracker.evict();\n\t\t\tif (evictKey) this.cache.delete(evictKey);\n\t\t}\n\t\tthis.cache.set(key, structuredClone(meta));\n\t\tthis.lruTracker.touch(key);\n\t}\n\tinvalidate(documentId, branch) {\n\t\tlet evicted = 0;\n\t\tif (branch === void 0) {\n\t\t\tfor (const key of this.cache.keys()) if (key.startsWith(`${documentId}:`)) {\n\t\t\t\tthis.cache.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted++;\n\t\t\t}\n\t\t} else {\n\t\t\tconst key = this.makeKey(documentId, branch);\n\t\t\tif (this.cache.has(key)) {\n\t\t\t\tthis.cache.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted = 1;\n\t\t\t}\n\t\t}\n\t\treturn evicted;\n\t}\n\tclear() {\n\t\tthis.cache.clear();\n\t\tthis.lruTracker.clear();\n\t}\n\tmakeKey(documentId, branch) {\n\t\treturn `${documentId}:${branch}`;\n\t}\n\tasync rebuildLatest(documentId, branch, signal) {\n\t\treturn this.rebuildFromOperations(documentId, branch, void 0, signal);\n\t}\n\tasync rebuildFromOperations(documentId, branch, targetRevision, signal) {\n\t\tconst docScopeOps = await this.operationStore.getSince(documentId, \"document\", branch, -1, void 0, void 0, signal);\n\t\tif (docScopeOps.results.length === 0) throw new DocumentNotFoundError(documentId);\n\t\tconst createOp = docScopeOps.results[0];\n\t\tif (createOp.action.type !== \"CREATE_DOCUMENT\") throw new Error(`Invalid document: first operation must be CREATE_DOCUMENT, found ${createOp.action.type}`);\n\t\tconst createAction = createOp.action;\n\t\tconst documentType = createAction.input.model;\n\t\tlet document = createDocumentFromAction(createAction);\n\t\tlet documentScopeRevision = 0;\n\t\tfor (const op of docScopeOps.results) {\n\t\t\tif (targetRevision !== void 0 && op.index > targetRevision) break;\n\t\t\tdocumentScopeRevision = op.index;\n\t\t\tif (op.action.type === \"UPGRADE_DOCUMENT\") {\n\t\t\t\tconst upgradeAction = op.action;\n\t\t\t\tdocument = applyUpgradeDocumentAction$1(document, upgradeAction);\n\t\t\t} else if (op.action.type === \"DELETE_DOCUMENT\") document = applyDeleteDocumentAction$1(document, op.action);\n\t\t}\n\t\treturn {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType,\n\t\t\tdocumentScopeRevision: documentScopeRevision + 1\n\t\t};\n\t}\n};\nvar KyselyOperationIndexTxn = class {\n\tcollections = [];\n\tcollectionMemberships = [];\n\tcollectionRemovals = [];\n\tgroupReferences = [];\n\toperations = [];\n\tmembershipInvalidations = /* @__PURE__ */ new Set();\n\t/** Called by the commit as it writes each document_collections row. */\n\trecordMembershipInvalidation(documentId) {\n\t\tthis.membershipInvalidations.add(documentId);\n\t}\n\tgetMembershipInvalidations() {\n\t\treturn [...this.membershipInvalidations];\n\t}\n\tcreateCollection(collectionId) {\n\t\tthis.collections.push(collectionId);\n\t}\n\taddToCollection(collectionId, documentId) {\n\t\tconst lastOpIndex = this.operations.length - 1;\n\t\tif (lastOpIndex < 0) throw new Error(\"addToCollection must be called after write() - no operations in transaction\");\n\t\tthis.collectionMemberships.push({\n\t\t\tcollectionId,\n\t\t\tdocumentId,\n\t\t\toperationIndex: lastOpIndex\n\t\t});\n\t}\n\tremoveFromCollection(collectionId, documentId) {\n\t\tconst lastOpIndex = this.operations.length - 1;\n\t\tif (lastOpIndex < 0) throw new Error(\"removeFromCollection must be called after write() - no operations in transaction\");\n\t\tthis.collectionRemovals.push({\n\t\t\tcollectionId,\n\t\t\tdocumentId,\n\t\t\toperationIndex: lastOpIndex\n\t\t});\n\t}\n\trecordGroupReferences(documentId, groupIds) {\n\t\tconst lastOpIndex = this.operations.length - 1;\n\t\tif (lastOpIndex < 0) throw new Error(\"recordGroupReferences must be called after write() - no operations in transaction\");\n\t\tif (groupIds.length === 0) return;\n\t\tthis.groupReferences.push({\n\t\t\tdocumentId,\n\t\t\tgroupIds,\n\t\t\toperationIndex: lastOpIndex\n\t\t});\n\t}\n\twrite(operations) {\n\t\tthis.operations.push(...operations);\n\t}\n\tgetCollections() {\n\t\treturn this.collections;\n\t}\n\tgetGroupReferenceRecords() {\n\t\treturn this.groupReferences;\n\t}\n\tgetCollectionMembershipRecords() {\n\t\treturn this.collectionMemberships;\n\t}\n\tgetCollectionRemovals() {\n\t\treturn this.collectionRemovals;\n\t}\n\tgetOperations() {\n\t\treturn this.operations;\n\t}\n};\nvar KyselyOperationIndex = class KyselyOperationIndex {\n\ttrx;\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tget queryExecutor() {\n\t\treturn this.trx ?? this.db;\n\t}\n\twithTransaction(trx) {\n\t\tconst instance = new KyselyOperationIndex(this.db);\n\t\tinstance.trx = trx;\n\t\treturn instance;\n\t}\n\tstart() {\n\t\treturn new KyselyOperationIndexTxn();\n\t}\n\tasync commit(txn, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst kyselyTxn = txn;\n\t\tif (this.trx) return this.executeCommit(this.trx, kyselyTxn);\n\t\tlet resultOrdinals = [];\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tresultOrdinals = await this.executeCommit(trx, kyselyTxn);\n\t\t});\n\t\treturn resultOrdinals;\n\t}\n\t/**\n\t* A policy-driven join: keeps the earliest join so a rediscovered reference\n\t* never shrinks a backfill window remotes already rely on, and reopens a\n\t* closed membership because a policy reference is not a removable one.\n\t*/\n\tasync joinKeepingEarliest(trx, kyselyTxn, documentId, collectionId, ordinal) {\n\t\tkyselyTxn.recordMembershipInvalidation(documentId);\n\t\tawait trx.insertInto(\"document_collections\").values({\n\t\t\tdocumentId,\n\t\t\tcollectionId,\n\t\t\tjoinedOrdinal: ordinal,\n\t\t\tleftOrdinal: null\n\t\t}).onConflict((oc) => oc.columns([\"documentId\", \"collectionId\"]).doUpdateSet({\n\t\t\tjoinedOrdinal: sql`LEAST(\"document_collections\".\"joinedOrdinal\", EXCLUDED.\"joinedOrdinal\")`,\n\t\t\tleftOrdinal: null\n\t\t})).execute();\n\t}\n\tasync executeCommit(trx, kyselyTxn) {\n\t\tconst collections = kyselyTxn.getCollections();\n\t\tconst memberships = kyselyTxn.getCollectionMembershipRecords();\n\t\tconst removals = kyselyTxn.getCollectionRemovals();\n\t\tconst groupReferences = kyselyTxn.getGroupReferenceRecords();\n\t\tconst operations = kyselyTxn.getOperations();\n\t\tif (collections.length > 0) {\n\t\t\tconst collectionRows = collections.map((collectionId) => ({\n\t\t\t\tdocumentId: collectionId,\n\t\t\t\tcollectionId,\n\t\t\t\tjoinedOrdinal: BigInt(0),\n\t\t\t\tleftOrdinal: null\n\t\t\t}));\n\t\t\tfor (const collectionId of collections) kyselyTxn.recordMembershipInvalidation(collectionId);\n\t\t\tawait trx.insertInto(\"document_collections\").values(collectionRows).onConflict((oc) => oc.doNothing()).execute();\n\t\t}\n\t\tlet operationOrdinals = [];\n\t\tif (operations.length > 0) {\n\t\t\tconst operationRows = operations.map((op) => ({\n\t\t\t\topId: op.id || \"\",\n\t\t\t\tdocumentId: op.documentId,\n\t\t\t\tdocumentType: op.documentType,\n\t\t\t\tscope: op.scope,\n\t\t\t\tbranch: op.branch,\n\t\t\t\ttimestampUtcMs: op.timestampUtcMs,\n\t\t\t\tindex: op.index,\n\t\t\t\tskip: op.skip,\n\t\t\t\thash: op.hash,\n\t\t\t\taction: op.action,\n\t\t\t\tdeniedReason: op.deniedReason ?? null,\n\t\t\t\tsourceRemote: op.sourceRemote\n\t\t\t}));\n\t\t\toperationOrdinals = (await trx.insertInto(\"operation_index_operations\").values(operationRows).returning(\"ordinal\").execute()).map((row) => row.ordinal);\n\t\t}\n\t\tif (memberships.length > 0) for (const m of memberships) {\n\t\t\tconst ordinal = operationOrdinals[m.operationIndex];\n\t\t\tkyselyTxn.recordMembershipInvalidation(m.documentId);\n\t\t\tawait trx.insertInto(\"document_collections\").values({\n\t\t\t\tdocumentId: m.documentId,\n\t\t\t\tcollectionId: m.collectionId,\n\t\t\t\tjoinedOrdinal: BigInt(ordinal),\n\t\t\t\tleftOrdinal: null\n\t\t\t}).onConflict((oc) => oc.columns([\"documentId\", \"collectionId\"]).doUpdateSet({\n\t\t\t\tjoinedOrdinal: BigInt(ordinal),\n\t\t\t\tleftOrdinal: null\n\t\t\t})).execute();\n\t\t\tconst references = await trx.selectFrom(\"group_references\").select(\"groupId\").where(\"documentId\", \"=\", m.documentId).execute();\n\t\t\tfor (const { groupId } of references) await this.joinKeepingEarliest(trx, kyselyTxn, groupId, m.collectionId, BigInt(ordinal));\n\t\t}\n\t\tif (removals.length > 0) for (const r of removals) {\n\t\t\tconst ordinal = operationOrdinals[r.operationIndex];\n\t\t\tkyselyTxn.recordMembershipInvalidation(r.documentId);\n\t\t\tawait trx.updateTable(\"document_collections\").set({ leftOrdinal: BigInt(ordinal) }).where(\"collectionId\", \"=\", r.collectionId).where(\"documentId\", \"=\", r.documentId).where(\"leftOrdinal\", \"is\", null).execute();\n\t\t}\n\t\tif (groupReferences.length > 0) for (const record of groupReferences) {\n\t\t\tconst ordinal = operationOrdinals[record.operationIndex];\n\t\t\tawait trx.insertInto(\"group_references\").values(record.groupIds.map((groupId) => ({\n\t\t\t\tdocumentId: record.documentId,\n\t\t\t\tgroupId\n\t\t\t}))).onConflict((oc) => oc.doNothing()).execute();\n\t\t\tconst rows = await trx.selectFrom(\"document_collections\").select(\"collectionId\").where(\"documentId\", \"=\", record.documentId).execute();\n\t\t\tfor (const groupId of record.groupIds) for (const { collectionId } of rows) await this.joinKeepingEarliest(trx, kyselyTxn, groupId, collectionId, BigInt(ordinal));\n\t\t}\n\t\treturn operationOrdinals;\n\t}\n\tasync getGroupReferencers(groupId, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn (await this.queryExecutor.selectFrom(\"group_references\").select(\"documentId\").where(\"groupId\", \"=\", groupId).orderBy(\"documentId\").execute()).map((row) => row.documentId);\n\t}\n\tasync find(collectionId, cursor, view, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst outerCursor = cursor ?? -1;\n\t\tconst limit = paging?.limit ?? 500;\n\t\tconst pagingCursorOrdinal = paging?.cursor !== void 0 ? Number.parseInt(paging.cursor, 10) : -1;\n\t\tconst buildBranch = (kind) => {\n\t\t\tlet qb = this.queryExecutor.selectFrom(\"operation_index_operations as oi\").innerJoin(\"document_collections as dc\", \"oi.documentId\", \"dc.documentId\").selectAll(\"oi\").select([\"dc.documentId\", \"dc.collectionId\"]).where(\"dc.collectionId\", \"=\", collectionId).where(sql`(dc.\"leftOrdinal\" IS NULL OR oi.ordinal < dc.\"leftOrdinal\")`);\n\t\t\tif (kind === \"joiner\") qb = qb.where(\"dc.joinedOrdinal\", \">\", BigInt(outerCursor)).where(\"oi.ordinal\", \"<=\", outerCursor);\n\t\t\telse qb = qb.where(\"oi.ordinal\", \">\", outerCursor);\n\t\t\tqb = qb.where(\"oi.ordinal\", \">\", pagingCursorOrdinal);\n\t\t\tif (view?.branch) qb = qb.where(\"oi.branch\", \"=\", view.branch);\n\t\t\tif (view?.scopes && view.scopes.length > 0) qb = qb.where(\"oi.scope\", \"in\", view.scopes);\n\t\t\tif (view?.excludeSourceRemote) qb = qb.where(\"oi.sourceRemote\", \"!=\", view.excludeSourceRemote);\n\t\t\treturn qb;\n\t\t};\n\t\tconst rows = await buildBranch(\"joiner\").unionAll(buildBranch(\"newOps\")).orderBy(\"ordinal\", \"asc\").limit(limit + 1).execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore && items.length > 0 ? items[items.length - 1].ordinal.toString() : void 0;\n\t\tconst cursorValue = paging?.cursor || \"0\";\n\t\treturn {\n\t\t\tresults: items.map((row) => this.rowToOperationIndexEntry(row)),\n\t\t\toptions: {\n\t\t\t\tcursor: cursorValue,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.find(collectionId, cursor, view, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t};\n\t}\n\tasync get(documentId, view, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst limit = paging?.limit ?? 500;\n\t\tlet query = this.queryExecutor.selectFrom(\"operation_index_operations\").selectAll().where(\"documentId\", \"=\", documentId).orderBy(\"ordinal\", \"asc\");\n\t\tif (view?.branch) query = query.where(\"branch\", \"=\", view.branch);\n\t\tif (view?.scopes && view.scopes.length > 0) query = query.where(\"scope\", \"in\", view.scopes);\n\t\tif (paging?.cursor) {\n\t\t\tconst cursorOrdinal = Number.parseInt(paging.cursor, 10);\n\t\t\tquery = query.where(\"ordinal\", \">\", cursorOrdinal);\n\t\t}\n\t\tquery = query.limit(limit + 1);\n\t\tconst rows = await query.execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore && items.length > 0 ? items[items.length - 1].ordinal.toString() : void 0;\n\t\tconst cursorValue = paging?.cursor || \"0\";\n\t\treturn {\n\t\t\tresults: items.map((row) => this.rowToOperationIndexEntry(row)),\n\t\t\toptions: {\n\t\t\t\tcursor: cursorValue,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.get(documentId, view, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t};\n\t}\n\tasync getSinceOrdinal(ordinal, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst limit = paging?.limit ?? 500;\n\t\tlet query = this.queryExecutor.selectFrom(\"operation_index_operations\").selectAll().where(\"ordinal\", \">\", ordinal).orderBy(\"ordinal\", \"asc\");\n\t\tif (paging?.cursor) {\n\t\t\tconst cursorOrdinal = Number.parseInt(paging.cursor, 10);\n\t\t\tquery = query.where(\"ordinal\", \">\", cursorOrdinal);\n\t\t}\n\t\tquery = query.limit(limit + 1);\n\t\tconst rows = await query.execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore && items.length > 0 ? items[items.length - 1].ordinal.toString() : void 0;\n\t\tconst cursorValue = paging?.cursor || \"0\";\n\t\treturn {\n\t\t\tresults: items.map((row) => this.rowToOperationWithContext(row)),\n\t\t\toptions: {\n\t\t\t\tcursor: cursorValue,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.getSinceOrdinal(ordinal, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t};\n\t}\n\trowToOperationWithContext(row) {\n\t\treturn {\n\t\t\toperation: {\n\t\t\t\tindex: row.index,\n\t\t\t\ttimestampUtcMs: row.timestampUtcMs,\n\t\t\t\thash: row.hash,\n\t\t\t\tskip: row.skip,\n\t\t\t\taction: row.action,\n\t\t\t\tdeniedReason: row.deniedReason ?? void 0,\n\t\t\t\tid: row.opId\n\t\t\t},\n\t\t\tcontext: {\n\t\t\t\tdocumentId: row.documentId,\n\t\t\t\tdocumentType: row.documentType,\n\t\t\t\tscope: row.scope,\n\t\t\t\tbranch: row.branch,\n\t\t\t\tordinal: row.ordinal\n\t\t\t}\n\t\t};\n\t}\n\trowToOperationIndexEntry(row) {\n\t\treturn {\n\t\t\tordinal: row.ordinal,\n\t\t\tdocumentId: row.documentId,\n\t\t\tdocumentType: row.documentType,\n\t\t\tbranch: row.branch,\n\t\t\tscope: row.scope,\n\t\t\tindex: row.index,\n\t\t\ttimestampUtcMs: row.timestampUtcMs,\n\t\t\thash: row.hash,\n\t\t\tskip: row.skip,\n\t\t\taction: row.action,\n\t\t\tdeniedReason: row.deniedReason ?? void 0,\n\t\t\tid: row.opId,\n\t\t\tsourceRemote: row.sourceRemote\n\t\t};\n\t}\n\tasync getLatestTimestampForCollection(collectionId, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn (await this.queryExecutor.selectFrom(\"operation_index_operations as oi\").innerJoin(\"document_collections as dc\", \"oi.documentId\", \"dc.documentId\").select(\"oi.timestampUtcMs\").where(\"dc.collectionId\", \"=\", collectionId).where(sql`(dc.\"leftOrdinal\" IS NULL OR oi.ordinal < dc.\"leftOrdinal\")`).orderBy(\"oi.ordinal\", \"desc\").limit(1).executeTakeFirst())?.timestampUtcMs ?? null;\n\t}\n\tasync getCollectionsForDocuments(documentIds) {\n\t\tif (documentIds.length === 0) return {};\n\t\tconst rows = await this.queryExecutor.selectFrom(\"document_collections\").select([\"documentId\", \"collectionId\"]).where(\"documentId\", \"in\", documentIds).where(\"leftOrdinal\", \"is\", null).execute();\n\t\tconst result = {};\n\t\tfor (const row of rows) {\n\t\t\tif (!(row.documentId in result)) result[row.documentId] = [];\n\t\t\tresult[row.documentId].push(row.collectionId);\n\t\t}\n\t\treturn result;\n\t}\n};\n//#endregion\n//#region src/cache/buffer/ring-buffer.ts\n/**\n* RingBuffer is a generic circular buffer implementation that stores a fixed number\n* of items. When the buffer is full, new items overwrite the oldest items.\n*\n* This implementation maintains O(1) time complexity for push operations and provides\n* items in chronological order (oldest to newest) via getAll().\n*\n* @template T - The type of items stored in the buffer\n*/\nvar RingBuffer = class {\n\tbuffer;\n\thead = 0;\n\tsize = 0;\n\tcapacity;\n\tconstructor(capacity) {\n\t\tif (capacity <= 0) throw new Error(\"Ring buffer capacity must be greater than 0\");\n\t\tthis.capacity = capacity;\n\t\tthis.buffer = new Array(capacity);\n\t}\n\t/**\n\t* Adds an item to the buffer. If the buffer is full, overwrites the oldest item.\n\t*\n\t* @param item - The item to add\n\t*/\n\tpush(item) {\n\t\tconst index = (this.head + this.size) % this.capacity;\n\t\tif (this.size < this.capacity) {\n\t\t\tthis.buffer[index] = item;\n\t\t\tthis.size++;\n\t\t} else {\n\t\t\tthis.buffer[this.head] = item;\n\t\t\tthis.head = (this.head + 1) % this.capacity;\n\t\t}\n\t}\n\t/**\n\t* Returns all items in the buffer in chronological order (oldest to newest).\n\t*\n\t* @returns Array of items in insertion order\n\t*/\n\tgetAll() {\n\t\tif (this.size === 0) return [];\n\t\tconst result = [];\n\t\tfor (let i = 0; i < this.size; i++) {\n\t\t\tconst index = (this.head + i) % this.capacity;\n\t\t\tresult.push(this.buffer[index]);\n\t\t}\n\t\treturn result;\n\t}\n\t/**\n\t* Clears all items from the buffer.\n\t*/\n\tclear() {\n\t\tthis.buffer = new Array(this.capacity);\n\t\tthis.head = 0;\n\t\tthis.size = 0;\n\t}\n\t/**\n\t* Gets the current number of items in the buffer.\n\t*/\n\tget length() {\n\t\treturn this.size;\n\t}\n};\n//#endregion\n//#region src/cache/write-cache-types.ts\n/**\n* Where a snapshot sits in its stream.\n*\n* - `Head`: the newest revision of the stream when it was stored. Only these\n* can answer a read that asks for the head.\n* - `Historical`: state at an earlier revision. Usable as a starting point to\n* replay forward from, and as an answer to a read for that same revision.\n*/\nlet SnapshotPosition = /* @__PURE__ */ function(SnapshotPosition) {\n\tSnapshotPosition[\"Head\"] = \"head\";\n\tSnapshotPosition[\"Historical\"] = \"historical\";\n\treturn SnapshotPosition;\n}({});\n//#endregion\n//#region src/cache/kysely-write-cache.ts\n/**\n* The last operation index a keyframe's document reflects for the scope. A\n* keyframe only exists for a scope that has operations, so a missing entry\n* means the stored row is corrupt.\n*/\nfunction keyframeRevision(keyframe, documentId, scope) {\n\tconst nextIndex = keyframe.document.header.revision[scope];\n\tif (typeof nextIndex !== \"number\") throw new Error(`Corrupt keyframe for document ${documentId} at revision ${keyframe.revision}: header carries no ${scope} revision`);\n\treturn nextIndex - 1;\n}\nfunction extractModuleVersion(doc) {\n\tconst v = doc.state.document.version;\n\treturn normalizeDocumentModelVersion(v);\n}\n/** The highest revision held, latest push winning a tie. */\nfunction highestRevision(snapshots) {\n\tlet newest = void 0;\n\tfor (const snapshot of snapshots) if (!newest || snapshot.revision >= newest.revision) newest = snapshot;\n\treturn newest;\n}\n/**\n* Copies a document far enough that the caller cannot write through it. Inside\n* this class, callers only ever replace whole fields on these four, so one\n* level each is enough.\n*/\nfunction copyDocument(document) {\n\treturn {\n\t\t...document,\n\t\theader: { ...document.header },\n\t\tstate: { ...document.state },\n\t\toperations: { ...document.operations }\n\t};\n}\n/**\n* In-memory write cache with keyframe persistence for PHDocuments.\n*\n* Caches document snapshots in ring buffers with LRU eviction. On cache miss,\n* rebuilds documents from nearest keyframe or full operation history.\n*\n* **Performance Characteristics:**\n* - Cache hit: O(1) lookup in ring buffer\n* - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe\n* - Warm miss: O(m) where m is operations since cached revision\n* - Eviction: O(1) for LRU tracking and removal\n*\n* **Thread Safety:**\n* Not thread-safe. Designed for single-threaded job executor environment.\n* External synchronization required for concurrent access across multiple executors.\n*\n* **Example:**\n* ```typescript\n* const cache = new KyselyWriteCache(\n* keyframeStore,\n* operationStore,\n* registry,\n* { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }\n* );\n*\n* await cache.startup();\n*\n* // Retrieve or rebuild document\n* const doc = await cache.getState(docId, docType, scope, branch, revision);\n*\n* // Cache result after job execution\n* cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);\n*\n* await cache.shutdown();\n* ```\n*/\nvar KyselyWriteCache = class KyselyWriteCache {\n\tstreams;\n\tlruTracker;\n\tkeyframeStore;\n\toperationStore;\n\tregistry;\n\tconfig;\n\tconstructor(keyframeStore, operationStore, registry, config) {\n\t\tthis.keyframeStore = keyframeStore;\n\t\tthis.operationStore = operationStore;\n\t\tthis.registry = registry;\n\t\tthis.config = {\n\t\t\tmaxDocuments: config.maxDocuments,\n\t\t\tringBufferSize: config.ringBufferSize,\n\t\t\tkeyframeInterval: config.keyframeInterval\n\t\t};\n\t\tthis.streams = /* @__PURE__ */ new Map();\n\t\tthis.lruTracker = new LRUTracker();\n\t}\n\twithScopedStores(operationStore, keyframeStore) {\n\t\tconst scoped = new KyselyWriteCache(keyframeStore, operationStore, this.registry, this.config);\n\t\tscoped.streams = this.streams;\n\t\tscoped.lruTracker = this.lruTracker;\n\t\treturn scoped;\n\t}\n\t/**\n\t* Initializes the write cache.\n\t* Currently a no-op as keyframe store lifecycle is managed externally.\n\t*/\n\tasync startup() {\n\t\treturn Promise.resolve();\n\t}\n\t/**\n\t* Shuts down the write cache.\n\t* Currently a no-op as keyframe store lifecycle is managed externally.\n\t*/\n\tasync shutdown() {\n\t\treturn Promise.resolve();\n\t}\n\t/**\n\t* Retrieves document state at a specific revision from cache or rebuilds it.\n\t*\n\t* Note: this returns a _shallow_ copy of the document.\n\t*\n\t* Cache hit path: Returns cached snapshot if available (O(1))\n\t* Warm miss path: Rebuilds from cached base revision + incremental ops\n\t* Cold miss path: Rebuilds from keyframe or from scratch using all operations\n\t*\n\t* @param documentId - The document identifier\n\t* @param scope - The operation scope\n\t* @param branch - The operation branch\n\t* @param targetRevision - The target revision, or undefined for newest\n\t* @param signal - Optional abort signal to cancel the operation\n\t* @returns The document at the target revision\n\t* @throws {Error} \"Operation aborted\" if signal is aborted\n\t* @throws {ModuleNotFoundError} If document type not registered in registry\n\t* @throws {Error} \"Failed to rebuild document\" if operation store fails\n\t* @throws {Error} If reducer throws during operation application\n\t* @throws {Error} If document serialization fails\n\t*/\n\tasync getState(documentId, scope, branch, targetRevision, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst streamKey = this.makeStreamKey(documentId, scope, branch);\n\t\tconst stream = this.streams.get(streamKey);\n\t\tif (stream) {\n\t\t\tconst snapshots = stream.ringBuffer.getAll();\n\t\t\tif (targetRevision === void 0) {\n\t\t\t\tconst newest = highestRevision(snapshots);\n\t\t\t\tif (newest?.position === SnapshotPosition.Head) {\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn copyDocument(newest.document);\n\t\t\t\t}\n\t\t\t\tif (newest) {\n\t\t\t\t\tconst document = await this.warmMissRebuild(newest.document, newest.revision, documentId, scope, branch, void 0, signal);\n\t\t\t\t\tthis.store(documentId, scope, branch, (document.header.revision[scope] ?? 0) - 1, document, SnapshotPosition.Head);\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn document;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst exactMatch = snapshots.findLast((s) => s.revision === targetRevision);\n\t\t\t\tif (exactMatch) {\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn copyDocument(exactMatch.document);\n\t\t\t\t}\n\t\t\t\tconst newestOlder = this.findNearestOlderSnapshot(snapshots, targetRevision);\n\t\t\t\tif (newestOlder) {\n\t\t\t\t\tconst document = await this.warmMissRebuild(newestOlder.document, newestOlder.revision, documentId, scope, branch, targetRevision, signal);\n\t\t\t\t\tthis.store(documentId, scope, branch, targetRevision, document, SnapshotPosition.Historical);\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn document;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst document = await this.coldMissRebuild(documentId, scope, branch, targetRevision, signal);\n\t\tconst revision = targetRevision ?? (document.header.revision[scope] ?? 0) - 1;\n\t\tthis.store(documentId, scope, branch, revision, document, targetRevision === void 0 ? SnapshotPosition.Head : SnapshotPosition.Historical);\n\t\treturn document;\n\t}\n\t/**\n\t* Stores a document snapshot in the cache at a specific revision.\n\t*\n\t* The cached document is a shallow copy of the input with its operation history\n\t* truncated to the last operation per scope and its clipboard cleared. This keeps\n\t* memory use and copy costs constant regardless of operation count. Consumers of\n\t* getState() must not rely on the full operation history being present; the only\n\t* guaranteed invariant is that operations[scope].at(-1) reflects the latest\n\t* operation index for each scope.\n\t*\n\t* Updates LRU tracker and may evict least recently used stream if at capacity.\n\t* Asynchronously persists keyframes at configured intervals (fire-and-forget).\n\t*\n\t* @param documentId - The document identifier\n\t* @param scope - The operation scope\n\t* @param branch - The operation branch\n\t* @param revision - The revision number\n\t* @param document - The document to cache\n\t* @throws {Error} If document serialization fails\n\t*/\n\tputState(documentId, scope, branch, revision, document, position) {\n\t\tthis.store(documentId, scope, branch, revision, document, position);\n\t}\n\t/**\n\t* Stores the run's head and mints a keyframe for every interval the run\n\t* crossed on its way there. Only the head enters the ring buffer; the\n\t* earlier revisions are keyframe candidates and nothing more.\n\t*/\n\tputRun(documentId, scope, branch, run) {\n\t\tif (run.length === 0) return;\n\t\tfor (const entry of run.slice(0, -1)) this.persistKeyframe(documentId, scope, branch, entry.revision, entry.document);\n\t\tconst head = run[run.length - 1];\n\t\tthis.store(documentId, scope, branch, head.revision, head.document, SnapshotPosition.Head);\n\t}\n\tstore(documentId, scope, branch, revision, document, position) {\n\t\tconst streamKey = this.makeStreamKey(documentId, scope, branch);\n\t\tconst stream = this.getOrCreateStream(streamKey);\n\t\tconst snapshot = {\n\t\t\trevision,\n\t\t\tdocument: {\n\t\t\t\t...copyDocument(document),\n\t\t\t\toperations: Object.fromEntries(Object.entries(document.operations).map(([k, ops]) => [k, ops.length ? [ops.at(-1)] : []])),\n\t\t\t\tclipboard: []\n\t\t\t},\n\t\t\tposition\n\t\t};\n\t\tstream.ringBuffer.push(snapshot);\n\t\tthis.persistKeyframe(documentId, scope, branch, revision, document);\n\t}\n\t/** Persists the snapshot if this revision is one the interval falls on. */\n\tpersistKeyframe(documentId, scope, branch, revision, document) {\n\t\tif (!this.isKeyframeRevision(revision)) return;\n\t\tthis.keyframeStore.putKeyframe(documentId, scope, branch, revision, {\n\t\t\t...document,\n\t\t\toperations: {},\n\t\t\tclipboard: []\n\t\t}).catch((err) => {\n\t\t\tconsole.error(`Failed to persist keyframe ${documentId}@${revision}:`, err);\n\t\t});\n\t}\n\t/**\n\t* Invalidates cached document streams.\n\t*\n\t* Supports three invalidation scopes:\n\t* - Document-level: invalidate(documentId) - removes all streams for document\n\t* - Scope-level: invalidate(documentId, scope) - removes all branches for scope\n\t* - Stream-level: invalidate(documentId, scope, branch) - removes specific stream\n\t*\n\t* @param documentId - The document identifier\n\t* @param scope - Optional scope to narrow invalidation\n\t* @param branch - Optional branch to narrow invalidation (requires scope)\n\t* @returns The number of streams evicted\n\t*/\n\tinvalidate(documentId, scope, branch) {\n\t\tlet evicted = 0;\n\t\tif (scope === void 0 && branch === void 0) {\n\t\t\tfor (const [key] of this.streams.entries()) if (key.startsWith(`${documentId}:`)) {\n\t\t\t\tthis.streams.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted++;\n\t\t\t}\n\t\t} else if (scope !== void 0 && branch === void 0) {\n\t\t\tfor (const [key] of this.streams.entries()) if (key.startsWith(`${documentId}:${scope}:`)) {\n\t\t\t\tthis.streams.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted++;\n\t\t\t}\n\t\t} else if (scope !== void 0 && branch !== void 0) {\n\t\t\tconst key = this.makeStreamKey(documentId, scope, branch);\n\t\t\tif (this.streams.has(key)) {\n\t\t\t\tthis.streams.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted = 1;\n\t\t\t}\n\t\t}\n\t\treturn evicted;\n\t}\n\t/**\n\t* Clears the entire cache, removing all cached document streams.\n\t* Resets LRU tracking state. This operation always succeeds.\n\t*/\n\tclear() {\n\t\tthis.streams.clear();\n\t\tthis.lruTracker.clear();\n\t}\n\t/**\n\t* Retrieves a specific stream for a document. Exposed on the implementation\n\t* for testing, but not on the interface.\n\t*\n\t* @internal\n\t*/\n\tgetStream(documentId, scope, branch) {\n\t\tconst key = this.makeStreamKey(documentId, scope, branch);\n\t\treturn this.streams.get(key);\n\t}\n\tasync findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {\n\t\tif (targetRevision === Number.MAX_SAFE_INTEGER || targetRevision <= 0) return;\n\t\tconst keyframe = await this.keyframeStore.findNearestKeyframe(documentId, scope, branch, targetRevision, signal);\n\t\tif (!keyframe) return;\n\t\treturn {\n\t\t\trevision: Math.min(keyframeRevision(keyframe, documentId, scope), keyframe.revision),\n\t\t\tdocument: keyframe.document\n\t\t};\n\t}\n\t/**\n\t* Rebuilds a scope from a keyframe or from the whole operation history.\n\t*\n\t* The document scope is always rebuilt first, because it carries the type,\n\t* the upgrades and the deletion marker. Its version-changing upgrades are not\n\t* applied there though: an upgrade reducer must see the state the requested\n\t* scope has reached at that upgrade's boundary, so each one is held back and\n\t* applied when the replay below crosses the boundary that\n\t* resolveModuleVersionForOp derives from it. Upgrades whose boundary lies past\n\t* the last replayed operation are applied at the end. Creation-time 0->N seed\n\t* upgrades carry the initial state, so they still apply immediately.\n\t*/\n\tasync coldMissRebuild(documentId, scope, branch, targetRevision, signal) {\n\t\tconst effectiveTargetRevision = targetRevision || Number.MAX_SAFE_INTEGER;\n\t\tconst keyframe = await this.findNearestKeyframe(documentId, scope, branch, effectiveTargetRevision, signal);\n\t\tconst documentScopeBound = scope === \"document\" ? targetRevision : void 0;\n\t\tlet document;\n\t\tlet startRevision;\n\t\tlet documentType;\n\t\tconst validatedUpgrades = [];\n\t\tconst pendingUpgrades = [];\n\t\tlet lastDocumentScopeOperation;\n\t\tif (keyframe) {\n\t\t\tdocument = keyframe.document;\n\t\t\tstartRevision = keyframe.revision;\n\t\t\tdocumentType = keyframe.document.header.documentType;\n\t\t\tconst documentScopeResume = scope === \"document\" ? keyframe.revision : keyframeRevision(keyframe, documentId, \"document\");\n\t\t\tconst docScopeOpsAfterKeyframe = await this.operationStore.getSince(documentId, \"document\", branch, documentScopeResume, void 0, void 0, signal);\n\t\t\tfor (const operation of docScopeOpsAfterKeyframe.results) {\n\t\t\t\tif (documentScopeBound !== void 0 && operation.index > documentScopeBound) break;\n\t\t\t\tlastDocumentScopeOperation = operation;\n\t\t\t\tif (operation.error || isDenied(operation)) continue;\n\t\t\t\tif (operation.action.type === \"UPGRADE_DOCUMENT\") {\n\t\t\t\t\tconst upgradeAction = operation.action;\n\t\t\t\t\tconst fromVersion = upgradeAction.input.fromVersion;\n\t\t\t\t\tconst toVersion = upgradeAction.input.toVersion;\n\t\t\t\t\tif (fromVersion > 0 && fromVersion < toVersion) {\n\t\t\t\t\t\tlet upgradePath;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tupgradePath = this.registry.computeUpgradePath(documentType, fromVersion, toVersion);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (upgradeAction.input.initialState !== void 0) upgradePath = void 0;\n\t\t\t\t\t\t\telse throw new Error(`Failed to rebuild document ${documentId}: no upgrade manifest for ${documentType} v${fromVersion}→v${toVersion} and no initialState snapshot. ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvalidatedUpgrades.push({\n\t\t\t\t\t\t\tfromVersion,\n\t\t\t\t\t\t\ttoVersion,\n\t\t\t\t\t\t\trevision: upgradeAction.input.revision,\n\t\t\t\t\t\t\ttimestampUtcMs: operation.timestampUtcMs\n\t\t\t\t\t\t});\n\t\t\t\t\t\tpendingUpgrades.push({\n\t\t\t\t\t\t\taction: upgradeAction,\n\t\t\t\t\t\t\tupgradePath,\n\t\t\t\t\t\t\tindex: operation.index,\n\t\t\t\t\t\t\tsubsequentDeletes: []\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else if (operation.action.type === \"DELETE_DOCUMENT\") {\n\t\t\t\t\tapplyDeleteDocumentAction(document, operation.action);\n\t\t\t\t\tfor (const pending of pendingUpgrades) pending.subsequentDeletes.push(operation.action);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tstartRevision = -1;\n\t\t\tconst createOpResult = await this.operationStore.getSince(documentId, \"document\", branch, -1, void 0, {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: 1\n\t\t\t}, signal);\n\t\t\tif (createOpResult.results.length === 0) throw new DocumentNotFoundError(documentId);\n\t\t\tconst createOp = createOpResult.results[0];\n\t\t\tif (createOp.action.type !== \"CREATE_DOCUMENT\") throw new Error(`Failed to rebuild document ${documentId}: first operation in document scope must be CREATE_DOCUMENT, found ${createOp.action.type}`);\n\t\t\tconst documentCreateAction = createOp.action;\n\t\t\tdocumentType = documentCreateAction.input.model;\n\t\t\tif (!documentType) throw new Error(`Failed to rebuild document ${documentId}: CREATE_DOCUMENT action missing model in input`);\n\t\t\tdocument = createDocumentFromAction(documentCreateAction);\n\t\t\tlastDocumentScopeOperation = createOp;\n\t\t\tlet docModule = this.registry.getModule(documentType, extractModuleVersion(document));\n\t\t\tconst docScopeOps = await this.operationStore.getSince(documentId, \"document\", branch, 0, void 0, void 0, signal);\n\t\t\tfor (const operation of docScopeOps.results) {\n\t\t\t\tif (documentScopeBound !== void 0 && operation.index > documentScopeBound) break;\n\t\t\t\tlastDocumentScopeOperation = operation;\n\t\t\t\tif (operation.index === 0) continue;\n\t\t\t\tif (operation.error || isDenied(operation)) continue;\n\t\t\t\tif (operation.action.type === \"UPGRADE_DOCUMENT\") {\n\t\t\t\t\tconst upgradeAction = operation.action;\n\t\t\t\t\tconst fromVersion = upgradeAction.input.fromVersion;\n\t\t\t\t\tconst toVersion = upgradeAction.input.toVersion;\n\t\t\t\t\tif (fromVersion > 0 && fromVersion < toVersion) {\n\t\t\t\t\t\tlet upgradePath;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tupgradePath = this.registry.computeUpgradePath(documentType, fromVersion, toVersion);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (upgradeAction.input.initialState !== void 0) upgradePath = void 0;\n\t\t\t\t\t\t\telse throw new Error(`Failed to rebuild document ${documentId}: no upgrade manifest for ${documentType} v${fromVersion}→v${toVersion} and no initialState snapshot. ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvalidatedUpgrades.push({\n\t\t\t\t\t\t\tfromVersion,\n\t\t\t\t\t\t\ttoVersion,\n\t\t\t\t\t\t\trevision: upgradeAction.input.revision,\n\t\t\t\t\t\t\ttimestampUtcMs: operation.timestampUtcMs\n\t\t\t\t\t\t});\n\t\t\t\t\t\tpendingUpgrades.push({\n\t\t\t\t\t\t\taction: upgradeAction,\n\t\t\t\t\t\t\tupgradePath,\n\t\t\t\t\t\t\tindex: operation.index,\n\t\t\t\t\t\t\tsubsequentDeletes: []\n\t\t\t\t\t\t});\n\t\t\t\t\t} else document = applyUpgradeDocumentAction(document, upgradeAction, void 0);\n\t\t\t\t\tdocModule = this.registry.getModule(documentType, normalizeDocumentModelVersion(toVersion));\n\t\t\t\t} else if (operation.action.type === \"DELETE_DOCUMENT\") {\n\t\t\t\t\tapplyDeleteDocumentAction(document, operation.action);\n\t\t\t\t\tfor (const pending of pendingUpgrades) pending.subsequentDeletes.push(operation.action);\n\t\t\t\t} else {\n\t\t\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\t\t\tdocument = docModule.reducer(document, operation.action, void 0, {\n\t\t\t\t\t\tskip: operation.skip,\n\t\t\t\t\t\tprotocolVersion\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (scope === \"document\") {\n\t\t\tdocument = this.applyPendingUpgrades(document, pendingUpgrades, Number.MAX_SAFE_INTEGER);\n\t\t\tconst last = lastDocumentScopeOperation ?? await this.operationAt(documentId, \"document\", branch, startRevision, signal);\n\t\t\tdocument.operations = {\n\t\t\t\t...document.operations,\n\t\t\t\tdocument: last ? [last] : []\n\t\t\t};\n\t\t\treturn this.stampRevisions(document, documentId, scope, branch, targetRevision, signal);\n\t\t}\n\t\tif (keyframe) {\n\t\t\tconst resumeOperation = await this.operationAt(documentId, scope, branch, startRevision, signal);\n\t\t\tif (resumeOperation) document.operations = {\n\t\t\t\t...document.operations,\n\t\t\t\t[scope]: [resumeOperation]\n\t\t\t};\n\t\t}\n\t\tconst moduleCache = /* @__PURE__ */ new Map();\n\t\tconst getModuleCached = (version) => {\n\t\t\tconst key = version ?? 0;\n\t\t\tlet mod = moduleCache.get(key);\n\t\t\tif (!mod) {\n\t\t\t\tmod = this.registry.getModule(documentType, version);\n\t\t\t\tmoduleCache.set(key, mod);\n\t\t\t}\n\t\t\treturn mod;\n\t\t};\n\t\tconst finalVersion = validatedUpgrades.at(-1)?.toVersion ?? extractModuleVersion(document);\n\t\tlet cursor = void 0;\n\t\tconst pageSize = 100;\n\t\tlet hasMorePages;\n\t\tdo {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst paging = {\n\t\t\t\tcursor: cursor || \"0\",\n\t\t\t\tlimit: pageSize\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst result = await this.operationStore.getSince(documentId, scope, branch, startRevision, void 0, paging, signal);\n\t\t\t\tfor (const operation of result.results) {\n\t\t\t\t\tif (targetRevision !== void 0 && operation.index > targetRevision) break;\n\t\t\t\t\tconst moduleVersion = this.resolveModuleVersionForOp(operation.index, operation.timestampUtcMs, scope, validatedUpgrades, finalVersion);\n\t\t\t\t\tdocument = this.applyPendingUpgrades(document, pendingUpgrades, moduleVersion ?? Number.MAX_SAFE_INTEGER);\n\t\t\t\t\tif (isDenied(operation)) document = appendWithoutApplying(document, operation, scope);\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\t\t\t\tdocument = getModuleCached(moduleVersion).reducer(document, operation.action, void 0, {\n\t\t\t\t\t\t\tskip: operation.skip,\n\t\t\t\t\t\t\tprotocolVersion,\n\t\t\t\t\t\t\treplayOptions: { operation },\n\t\t\t\t\t\t\tskipIndexValidation: true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst reachedTarget = targetRevision !== void 0 && result.results.some((op) => op.index >= targetRevision);\n\t\t\t\thasMorePages = Boolean(result.nextCursor) && !reachedTarget;\n\t\t\t\tif (hasMorePages) cursor = result.nextCursor;\n\t\t\t} catch (err) {\n\t\t\t\tthrow new Error(`Failed to rebuild document ${documentId}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t\t}\n\t\t} while (hasMorePages);\n\t\tdocument = this.applyTailPendingUpgrades(document, pendingUpgrades, scope, targetRevision);\n\t\tdocument = await this.stampRevisions(document, documentId, scope, branch, targetRevision, signal);\n\t\tif (pendingUpgrades.length > 0) {\n\t\t\tconst firstHeldBack = pendingUpgrades[0];\n\t\t\tconst stamped = document.header.revision[\"document\"] ?? 0;\n\t\t\tdocument.header.revision = {\n\t\t\t\t...document.header.revision,\n\t\t\t\tdocument: Math.min(stamped, firstHeldBack.index)\n\t\t\t};\n\t\t}\n\t\treturn document;\n\t}\n\t/**\n\t* Applies and removes every held-back upgrade whose target version is at or\n\t* below `throughVersion`, in the order the document scope recorded them.\n\t*/\n\tapplyPendingUpgrades(document, pendingUpgrades, throughVersion) {\n\t\twhile (pendingUpgrades.length > 0) {\n\t\t\tconst pending = pendingUpgrades[0];\n\t\t\tif (throughVersion < pending.action.input.toVersion) break;\n\t\t\tpendingUpgrades.shift();\n\t\t\tdocument = this.applyPendingUpgrade(document, pending);\n\t\t}\n\t\treturn document;\n\t}\n\t/**\n\t* Applies the remaining held-back upgrades after the requested scope's\n\t* replay has finished. A head read applies them all. A positional read\n\t* applies only those whose boundary for this scope lies at or before the\n\t* target position: applying a later one would label migrated state with a\n\t* pre-upgrade revision, and a keyframe stored from that poisons every\n\t* rebuild that resumes from it. Boundaries come from the upgrade's revision\n\t* snapshot; an upgrade without one records no position for this scope, and\n\t* the replay loop not having crossed it already places it past the target.\n\t*/\n\tapplyTailPendingUpgrades(document, pendingUpgrades, scope, targetRevision) {\n\t\twhile (pendingUpgrades.length > 0) {\n\t\t\tconst pending = pendingUpgrades[0];\n\t\t\tif (targetRevision !== void 0) {\n\t\t\t\tconst snapshot = pending.action.input.revision;\n\t\t\t\tif (snapshot === void 0) break;\n\t\t\t\tif ((snapshot[scope] ?? 0) > targetRevision) break;\n\t\t\t}\n\t\t\tpendingUpgrades.shift();\n\t\t\tdocument = this.applyPendingUpgrade(document, pending);\n\t\t}\n\t\treturn document;\n\t}\n\t/**\n\t* Applies one held-back upgrade, then re-applies the deletes the document\n\t* scope recorded after it so the hold-back cannot invert their order.\n\t*/\n\tapplyPendingUpgrade(document, pending) {\n\t\tdocument = applyUpgradeDocumentAction(document, pending.action, pending.upgradePath);\n\t\tfor (const deleteAction of pending.subsequentDeletes) document = applyDeleteDocumentAction(document, deleteAction);\n\t\treturn document;\n\t}\n\t/**\n\t* Copies the current document revisions onto the document. Overwrites the\n\t* requested scope revision with the target revision, if provided.\n\t*/\n\tasync stampRevisions(document, documentId, scope, branch, targetRevision, signal) {\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tdocument.header.revision = revisions.revision;\n\t\tif (targetRevision !== void 0) document.header.revision = {\n\t\t\t...document.header.revision,\n\t\t\t[scope]: targetRevision + 1\n\t\t};\n\t\tdocument.header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n\t\treturn document;\n\t}\n\t/** The stored operation at `index`, or undefined if it is no longer there. */\n\tasync operationAt(documentId, scope, branch, index, signal) {\n\t\tif (index < 0) return;\n\t\tconst operation = (await this.operationStore.getSince(documentId, scope, branch, index - 1, void 0, {\n\t\t\tcursor: \"0\",\n\t\t\tlimit: 1\n\t\t}, signal)).results[0];\n\t\treturn operation && operation.index === index ? operation : void 0;\n\t}\n\t/**\n\t* Resolves which module version to use for a given operation in phase 2.\n\t*\n\t* Uses the validated-upgrade boundary rules from D7:\n\t* - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary\n\t* - Otherwise: timestamp fallback\n\t* - Falls back to final module version when neither is decidable\n\t*/\n\tresolveModuleVersionForOp(opIndex, opTimestamp, scope, validatedUpgrades, finalVersion) {\n\t\tif (validatedUpgrades.length === 0) return finalVersion;\n\t\tlet currentVersion = validatedUpgrades[0]?.fromVersion;\n\t\tfor (const upgrade of validatedUpgrades) {\n\t\t\tlet beforeUpgrade;\n\t\t\tif (upgrade.revision !== void 0) beforeUpgrade = opIndex < (upgrade.revision[scope] ?? 0);\n\t\t\telse beforeUpgrade = opTimestamp < upgrade.timestampUtcMs;\n\t\t\tif (beforeUpgrade) return currentVersion;\n\t\t\tcurrentVersion = upgrade.toVersion;\n\t\t}\n\t\treturn currentVersion;\n\t}\n\tasync warmMissRebuild(baseDocument, baseRevision, documentId, scope, branch, targetRevision, signal) {\n\t\tconst documentType = baseDocument.header.documentType;\n\t\tconst docScopeNextIndex = baseDocument.header.revision[\"document\"] ?? 0;\n\t\tif ((await this.operationStore.getSince(documentId, \"document\", branch, docScopeNextIndex - 1, void 0, void 0, signal)).results.length > 0) return this.coldMissRebuild(documentId, scope, branch, targetRevision, signal);\n\t\tconst module = this.registry.getModule(documentType, extractModuleVersion(baseDocument));\n\t\tlet document = copyDocument(baseDocument);\n\t\ttry {\n\t\t\tconst pagedResults = await this.operationStore.getSince(documentId, scope, branch, baseRevision, void 0, void 0, signal);\n\t\t\tfor (const operation of pagedResults.results) {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tif (targetRevision !== void 0 && operation.index > targetRevision) break;\n\t\t\t\tif (isDenied(operation)) document = appendWithoutApplying(document, operation, scope);\n\t\t\t\telse {\n\t\t\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\t\t\tdocument = module.reducer(document, operation.action, void 0, {\n\t\t\t\t\t\tskip: operation.skip,\n\t\t\t\t\t\tprotocolVersion,\n\t\t\t\t\t\treplayOptions: { operation },\n\t\t\t\t\t\tskipIndexValidation: true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (targetRevision !== void 0 && operation.index === targetRevision) break;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Failed to rebuild document ${documentId}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t}\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tdocument.header.revision = revisions.revision;\n\t\tif (targetRevision !== void 0) document.header.revision = {\n\t\t\t...document.header.revision,\n\t\t\t[scope]: targetRevision + 1\n\t\t};\n\t\tdocument.header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n\t\treturn document;\n\t}\n\tfindNearestOlderSnapshot(snapshots, targetRevision) {\n\t\tlet nearest = void 0;\n\t\tfor (const snapshot of snapshots) if (snapshot.revision < targetRevision) {\n\t\t\tif (!nearest || snapshot.revision > nearest.revision) nearest = snapshot;\n\t\t}\n\t\treturn nearest;\n\t}\n\tmakeStreamKey(documentId, scope, branch) {\n\t\treturn `${documentId}:${scope}:${branch}`;\n\t}\n\tgetOrCreateStream(key) {\n\t\tlet stream = this.streams.get(key);\n\t\tif (!stream) {\n\t\t\tif (this.streams.size >= this.config.maxDocuments) {\n\t\t\t\tconst evictKey = this.lruTracker.evict();\n\t\t\t\tif (evictKey) this.streams.delete(evictKey);\n\t\t\t}\n\t\t\tstream = {\n\t\t\t\tkey,\n\t\t\t\tringBuffer: new RingBuffer(this.config.ringBufferSize)\n\t\t\t};\n\t\t\tthis.streams.set(key, stream);\n\t\t}\n\t\tthis.lruTracker.touch(key);\n\t\treturn stream;\n\t}\n\tisKeyframeRevision(revision) {\n\t\treturn revision > 0 && revision % this.config.keyframeInterval === 0;\n\t}\n};\n//#endregion\n//#region src/events/event-bus.ts\nvar EventBus = class {\n\teventTypeToSubscribers = /* @__PURE__ */ new Map();\n\tsubscribe(type, subscriber) {\n\t\tlet list = this.eventTypeToSubscribers.get(type);\n\t\tif (!list) {\n\t\t\tlist = [];\n\t\t\tthis.eventTypeToSubscribers.set(type, list);\n\t\t}\n\t\tlist.push(subscriber);\n\t\tlet done = false;\n\t\treturn () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tconst arr = this.eventTypeToSubscribers.get(type);\n\t\t\tif (!arr) return;\n\t\t\tconst idx = arr.indexOf(subscriber);\n\t\t\tif (idx !== -1) arr.splice(idx, 1);\n\t\t\tif (arr.length === 0) this.eventTypeToSubscribers.delete(type);\n\t\t};\n\t}\n\tasync emit(type, data) {\n\t\tconst list = this.eventTypeToSubscribers.get(type);\n\t\tif (!list || list.length === 0) return;\n\t\tconst snapshot = list.slice();\n\t\tconst errors = [];\n\t\tfor (const fn of snapshot) try {\n\t\t\tawait Promise.resolve(fn(type, data));\n\t\t} catch (err) {\n\t\t\terrors.push(err);\n\t\t}\n\t\tif (errors.length > 0) throw new EventBusAggregateError(errors);\n\t}\n};\n//#endregion\n//#region src/core/feature-flags.ts\n/**\n* Every flag this reactor knows, with the flags it requires. A stage adds its\n* flag here when it ships, so asking an older reactor for a later stage's flag\n* is an unrecognized name rather than a flag that quietly does nothing.\n*/\nconst FLAG_PREREQUISITES = {\n\tdocumentDecisions: [],\n\tauthEnforcement: [\"documentDecisions\"],\n\tauthGroups: [\"authEnforcement\"],\n\tauthConditions: [\"authGroups\"]\n};\n/**\n* The flags as plain booleans, with anything unset off, validated. Callers hold\n* a partial set, because that is what crosses to a pooled worker, and every\n* consumer needs the same resolution of it.\n*/\nfunction resolveFeatureFlags(flags = {}) {\n\tconst resolved = {\n\t\tdocumentDecisions: flags.documentDecisions ?? false,\n\t\tauthEnforcement: flags.authEnforcement ?? false,\n\t\tauthGroups: flags.authGroups ?? false,\n\t\tauthConditions: flags.authConditions ?? false\n\t};\n\tvalidateFeatureFlags(flags, FLAG_PREREQUISITES);\n\treturn resolved;\n}\n/**\n* Throws when the flags ask for enforcement the reactor cannot deliver. Either\n* failure would otherwise read as enforcement being on while the reactor\n* applies less than the caller asked for.\n*/\nfunction validateFeatureFlags(flags, prerequisites) {\n\tconst known = Object.keys(prerequisites);\n\tconst unrecognized = Object.keys(flags).filter((name) => !known.includes(name));\n\tif (unrecognized.length > 0) throw new Error(`Unrecognized reactor feature flag: ${unrecognized.join(\", \")}. This reactor knows: ${known.join(\", \")}.`);\n\tfor (const name of known) {\n\t\tif (flags[name] !== true) continue;\n\t\tconst missing = prerequisites[name].filter((required) => flags[required] !== true);\n\t\tif (missing.length > 0) throw new Error(`Reactor feature flag ${name} requires ${missing.join(\", \")}.`);\n\t}\n}\n//#endregion\n//#region src/executor/execution-scope.ts\nvar DefaultExecutionScope = class {\n\tconstructor(operationStore, operationIndex, writeCache, documentMetaCache, collectionMembershipCache) {\n\t\tthis.operationStore = operationStore;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.writeCache = writeCache;\n\t\tthis.documentMetaCache = documentMetaCache;\n\t\tthis.collectionMembershipCache = collectionMembershipCache;\n\t}\n\tasync run(fn, signal) {\n\t\tsignal?.throwIfAborted();\n\t\treturn fn({\n\t\t\toperationStore: this.operationStore,\n\t\t\toperationIndex: this.operationIndex,\n\t\t\twriteCache: this.writeCache,\n\t\t\tdocumentMetaCache: this.documentMetaCache,\n\t\t\tcollectionMembershipCache: this.collectionMembershipCache\n\t\t});\n\t}\n};\nvar KyselyExecutionScope = class {\n\tconstructor(db, operationStore, operationIndex, keyframeStore, writeCache, documentMetaCache, collectionMembershipCache) {\n\t\tthis.db = db;\n\t\tthis.operationStore = operationStore;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.keyframeStore = keyframeStore;\n\t\tthis.writeCache = writeCache;\n\t\tthis.documentMetaCache = documentMetaCache;\n\t\tthis.collectionMembershipCache = collectionMembershipCache;\n\t}\n\tasync run(fn, signal) {\n\t\tsignal?.throwIfAborted();\n\t\treturn this.db.transaction().execute(async (trx) => {\n\t\t\tconst scopedOperationStore = this.operationStore.withTransaction(trx);\n\t\t\tconst scopedOperationIndex = this.operationIndex.withTransaction(trx);\n\t\t\tconst scopedKeyframeStore = this.keyframeStore.withTransaction(trx);\n\t\t\treturn fn({\n\t\t\t\toperationStore: scopedOperationStore,\n\t\t\t\toperationIndex: scopedOperationIndex,\n\t\t\t\twriteCache: this.writeCache.withScopedStores(scopedOperationStore, scopedKeyframeStore),\n\t\t\t\tdocumentMetaCache: this.documentMetaCache.withScopedStore(scopedOperationStore),\n\t\t\t\tcollectionMembershipCache: this.collectionMembershipCache.withScopedIndex(scopedOperationIndex)\n\t\t\t});\n\t\t});\n\t}\n};\n//#endregion\n//#region src/utils/reshuffle.ts\nconst STRICT_ORDER_ACTION_TYPES = new Set([\n\t\"CREATE_DOCUMENT\",\n\t\"DELETE_DOCUMENT\",\n\t\"UPGRADE_DOCUMENT\",\n\t\"ADD_RELATIONSHIP\",\n\t\"REMOVE_RELATIONSHIP\",\n\t\"UPDATE_RELATIONSHIP\",\n\t\"ADD_FOLDER\",\n\t\"UPDATE_FOLDER\",\n\t\"REMOVE_FOLDER\"\n]);\n/**\n* Reshuffles operations by timestamp, then applies deterministic tie-breaking.\n* Used for merging concurrent operations from different branches.\n*\n* For strict document-structure actions (e.g., CREATE_DOCUMENT/UPGRADE_DOCUMENT),\n* logical index (index - skip) is prioritized to preserve causal replay order.\n*\n* For other actions, action ID is prioritized to ensure a canonical cross-reactor order\n* for concurrent operations that may have diverged local indices due to prior reshuffles.\n* Logical index and operation ID are then used as deterministic tie-breakers.\n*\n* Example:\n* [0:0, 1:0, 2:0, A3:0, A4:0, A5:0] + [0:0, 1:0, 2:0, B3:0, B4:2, B5:0]\n* GC => [0:0, 1:0, 2:0, A3:0, A4:0, A5:0] + [0:0, 1:0, B4:2, B5:0]\n* Split => [0:0, 1:0] + [2:0, A3:0, A4:0, A5:0] + [B4:2, B5:0]\n* Reshuffle(6:4) => [6:4, 7:0, 8:0, 9:0, 10:0, 11:0]\n* merge => [0:0, 1:0, 6:4, 7:0, 8:0, 9:0, 10:0, 11:0]\n*/\nfunction reshuffleByTimestamp(startIndex, opsA, opsB) {\n\treturn [...opsA, ...opsB].sort((a, b) => {\n\t\tconst timestampDiff = new Date(a.timestampUtcMs).getTime() - new Date(b.timestampUtcMs).getTime();\n\t\tif (timestampDiff !== 0) return timestampDiff;\n\t\tconst rank = (op) => STRICT_ORDER_ACTION_TYPES.has(op.action?.type ?? \"\") ? 0 : 1;\n\t\tconst rankDiff = rank(a) - rank(b);\n\t\tif (rankDiff !== 0) return rankDiff;\n\t\tif (rank(a) === 0) {\n\t\t\tconst logicalIndexDiff = a.index - a.skip - (b.index - b.skip);\n\t\t\tif (logicalIndexDiff !== 0) return logicalIndexDiff;\n\t\t}\n\t\tconst actionIdDiff = (a.action?.id ?? \"\").localeCompare(b.action?.id ?? \"\");\n\t\tif (actionIdDiff !== 0) return actionIdDiff;\n\t\treturn a.id.localeCompare(b.id);\n\t}).map((op, i) => ({\n\t\t...op,\n\t\tindex: startIndex.index + i,\n\t\tskip: i === 0 ? startIndex.skip : 0\n\t}));\n}\n//#endregion\n//#region src/decision/merged-order.ts\n/** Identifies a stream within a walk. */\nfunction streamKey(query) {\n\treturn `${query.documentId}:${query.scope}:${query.branch}`;\n}\n/**\n* Orders two operations from different streams by position. Timestamp decides;\n* an equal timestamp puts an auth operation first, and otherwise falls to the\n* action id and then the operation id, so that two replicas holding the same\n* operations agree on the order whatever order they happen to store them in.\n*/\nfunction comparePositions(a, b) {\n\tconst aTime = Date.parse(a.operation.timestampUtcMs);\n\tconst bTime = Date.parse(b.operation.timestampUtcMs);\n\tif (aTime !== bTime) return aTime - bTime;\n\tif (a.streamKey === b.streamKey) return a.operation.index - b.operation.index;\n\tconst aAuth = a.scope === \"auth\";\n\tif (aAuth !== (b.scope === \"auth\")) return aAuth ? -1 : 1;\n\tconst actionIds = (a.operation.action.id ?? \"\").localeCompare(b.operation.action.id ?? \"\");\n\tif (actionIds !== 0) return actionIds;\n\treturn (a.operation.id ?? \"\").localeCompare(b.operation.id ?? \"\");\n}\n/**\n* Merges the read-set streams into one sequence by position. An operation's\n* place in the result is the bound a decision at that operation reads to: every\n* operation before it has been applied, and it has not.\n*/\nfunction mergeByPosition(streams) {\n\tconst merged = [];\n\tfor (const stream of streams) for (const operation of stream.operations) merged.push({\n\t\tstreamKey: stream.streamKey,\n\t\tscope: stream.scope,\n\t\toperation\n\t});\n\treturn merged.sort(comparePositions);\n}\n/**\n* The skip that retracts everything from `firstRetractedIndex` up to where the\n* re-appended operation lands. It spans the indexes rather than counting the\n* operations, because a stream with a gap in it makes those differ.\n*/\nfunction retractionSkip(nextIndex, firstRetractedIndex) {\n\treturn nextIndex - firstRetractedIndex;\n}\n//#endregion\n//#region src/decision/walk.ts\n/**\n* A single forward pass is only correct while a stream's effective operations\n* are ordered.\n*/\nfunction assertPositionOrder(streamKey, scope, operations) {\n\tfor (let i = 1; i < operations.length; i++) {\n\t\tconst previous = operations[i - 1];\n\t\tconst current = operations[i];\n\t\tif (comparePositions({\n\t\t\tstreamKey,\n\t\t\tscope,\n\t\t\toperation: previous\n\t\t}, {\n\t\t\tstreamKey,\n\t\t\tscope,\n\t\t\toperation: current\n\t\t}) > 0) throw new Error(`Stream ${streamKey} is out of position order: index ${previous.index} at ${previous.timestampUtcMs} precedes index ${current.index} at ${current.timestampUtcMs}`);\n\t}\n}\n/**\n* Visits every operation in the read-set once, in the order their positions\n* fall, and hands back the state each stream held just before it. That state is\n* what a decision at that operation reads.\n*\n* Skips are resolved first (i.e. this is performed on a garbage collected\n* stream), which means we can do a single forward pass.\n*\n* An operation that contributes no state, whether denied or holding a reducer\n* error, is visited but not applied (this matches the write cache's rebuild).\n*\n* The consumer sends back whether it refused the operation it was handed: a\n* refusal this pass produced must suppress it the same way a stored one does.\n*/\nfunction* walkByPosition(streams) {\n\tconst merged = mergeByPosition(streams.map((stream) => {\n\t\tconst operations = garbageCollect(sortOperations([...stream.operations]));\n\t\tassertPositionOrder(stream.streamKey, stream.scope, operations);\n\t\treturn {\n\t\t\tstreamKey: stream.streamKey,\n\t\t\tscope: stream.scope,\n\t\t\toperations\n\t\t};\n\t}));\n\tconst byKey = new Map(streams.map((stream) => [stream.streamKey, stream]));\n\tconst states = new Map(streams.map((stream) => [stream.streamKey, stream.document]));\n\tfor (const { streamKey, operation } of merged) {\n\t\tif ((yield {\n\t\t\tstreamKey,\n\t\t\toperation,\n\t\t\tstates: new Map(states)\n\t\t}) || operation.error !== void 0 || isDenied(operation)) continue;\n\t\tconst stream = byKey.get(streamKey);\n\t\tconst before = states.get(streamKey);\n\t\tif (before === void 0 || stream === void 0) throw new Error(`No state for stream ${streamKey}`);\n\t\tstates.set(streamKey, stream.apply(before, operation));\n\t}\n}\n//#endregion\n//#region src/decision/evaluation.ts\n/** The stream key for evaluated operations whose scope no projection reads. */\nconst EVALUATED_ONLY = \"evaluated\";\n/**\n* Whether any stream the model reads declares this operation's action type as\n* one that can change an evaluation.\n*/\nfunction isDecidingAction(operation, readSet) {\n\treturn readSet.some((stream) => stream.decidingActions.includes(operation.action.type));\n}\n/**\n* Who an operation acts as. A replayed operation is evaluated as its own signer,\n* so an address-scoped policy does not deny its own author's history.\n*/\nfunction subjectOf(operation) {\n\tconst signer = operation.action.context?.signer;\n\treturn {\n\t\taddress: signer?.user.address,\n\t\tkey: signer?.app.key\n\t};\n}\n/**\n* The model as the walk reached this operation: each static projection's value\n* is its own scope's state, and each derived projection's value maps document\n* id to that document's state, holding only the streams this replica walked. A\n* derived stream it does not hold stays out of the map, which fails closed.\n*/\nfunction modelAt(readSet, derivedNames, derived, states) {\n\tconst model = {};\n\tfor (const stream of readSet) {\n\t\tconst document = states.get(streamKey(stream.query));\n\t\tif (document === void 0) throw new Error(`No state walked for projection ${stream.name}`);\n\t\tmodel[stream.name] = document.state[stream.query.scope];\n\t}\n\tfor (const name of derivedNames) model[name] = {};\n\tfor (const entry of derived) {\n\t\tconst map = model[entry.name];\n\t\tconst document = states.get(streamKey(entry.query));\n\t\tif (document !== void 0) map[entry.query.documentId] = document.state[entry.query.scope];\n\t}\n\treturn model;\n}\n/**\n* Evaluates each operation at its own position and returns the refusals in an\n* array parallel to the operations, where undefined means allowed.\n*\n* A position is a timestamp, so an operation refused by a delete is one that\n* sorts after it, and the operations before it are left alone. That holds\n* whether the delete is already stored or is among the operations passed in.\n*/\nasync function evaluateByPosition(model, target, subject, stores, signal) {\n\tconst { scope, operations } = subject;\n\tconst { writeCache, operationStore } = stores;\n\tconst definition = model(target);\n\tconst readSet = staticReadSet(definition);\n\tconst derivedSet = derivedReadSet(definition);\n\tif (!definition.evaluatesScope(scope)) return operations.map(() => void 0);\n\tconst evaluating = new Set(operations.map((operation) => operation.id));\n\tconst readStreams = await Promise.all(readSet.map(async (stream) => ({\n\t\tstream,\n\t\toperations: (await operationStore.getSince(stream.query.documentId, stream.query.scope, stream.query.branch, -1, { actionTypes: stream.decidingActions }, void 0, signal)).results.filter((operation) => !evaluating.has(operation.id))\n\t})));\n\tconst decidingOperations = operations.filter((operation) => isDecidingAction(operation, readSet));\n\tif (readStreams.every((read) => read.operations.length === 0) && decidingOperations.length === 0) return operations.map(() => void 0);\n\tif (readStreams.length === 0) throw new Error(`Decision model for ${target.documentId} reads no stream whose query is known before it is built`);\n\tconst writtenProjection = readSet.find((stream) => stream.query.scope === scope);\n\tconst walked = [];\n\tconst histories = [];\n\tfor (const read of readStreams) {\n\t\tconst streamOperations = read.stream === writtenProjection ? [...read.operations, ...operations] : read.operations;\n\t\tconst before = await writeCache.getState(read.stream.query.documentId, read.stream.query.scope, read.stream.query.branch, -1, signal);\n\t\twalked.push({\n\t\t\tstreamKey: streamKey(read.stream.query),\n\t\t\tscope: read.stream.query.scope,\n\t\t\tdocument: before,\n\t\t\toperations: streamOperations,\n\t\t\tapply: read.stream.apply\n\t\t});\n\t\thistories.push({\n\t\t\tname: read.stream.name,\n\t\t\toperations: streamOperations\n\t\t});\n\t}\n\tlet evaluatedStateKey;\n\tif (writtenProjection !== void 0) evaluatedStateKey = streamKey(writtenProjection.query);\n\telse if (definition.foldEvaluatedScope !== void 0) {\n\t\tconst query = {\n\t\t\tdocumentId: target.documentId,\n\t\t\tscope,\n\t\t\tbranch: target.branch\n\t\t};\n\t\tconst storedOperations = (await operationStore.getSince(query.documentId, query.scope, query.branch, -1, void 0, void 0, signal)).results.filter((operation) => !evaluating.has(operation.id));\n\t\tconst before = await writeCache.getState(query.documentId, query.scope, query.branch, -1, signal);\n\t\tevaluatedStateKey = streamKey(query);\n\t\twalked.push({\n\t\t\tstreamKey: evaluatedStateKey,\n\t\t\tscope,\n\t\t\tdocument: before,\n\t\t\toperations: [...storedOperations, ...operations],\n\t\t\tapply: definition.foldEvaluatedScope\n\t\t});\n\t} else walked.push({\n\t\tstreamKey: EVALUATED_ONLY,\n\t\tscope,\n\t\tdocument: walked[0].document,\n\t\toperations,\n\t\tapply: (document) => document\n\t});\n\tconst derivedEntries = [];\n\tconst walkedKeys = new Set(walked.map((stream) => stream.streamKey));\n\tfor (const projection of derivedSet) {\n\t\tconst queries = projection.queryOverHistory?.(histories) ?? [];\n\t\tfor (const query of queries) {\n\t\t\tconst key = streamKey(query);\n\t\t\tif (walkedKeys.has(key)) continue;\n\t\t\tlet before;\n\t\t\ttry {\n\t\t\t\tbefore = await writeCache.getState(query.documentId, query.scope, query.branch, -1, signal);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof DocumentNotFoundError) continue;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst streamOperations = (await operationStore.getSince(query.documentId, query.scope, query.branch, -1, { actionTypes: projection.decidingActions }, void 0, signal)).results.filter((operation) => !evaluating.has(operation.id));\n\t\t\twalkedKeys.add(key);\n\t\t\twalked.push({\n\t\t\t\tstreamKey: key,\n\t\t\t\tscope: query.scope,\n\t\t\t\tdocument: before,\n\t\t\t\toperations: streamOperations,\n\t\t\t\tapply: projection.apply\n\t\t\t});\n\t\t\tderivedEntries.push({\n\t\t\t\tname: projection.name,\n\t\t\t\tquery\n\t\t\t});\n\t\t}\n\t}\n\tconst reasons = /* @__PURE__ */ new Map();\n\tconst walk = walkByPosition(walked);\n\tlet step = walk.next(false);\n\twhile (!step.done) {\n\t\tconst position = step.value;\n\t\tif (!evaluating.has(position.operation.id)) {\n\t\t\tstep = walk.next(false);\n\t\t\tcontinue;\n\t\t}\n\t\tconst evaluatedDocument = evaluatedStateKey === void 0 ? void 0 : position.states.get(evaluatedStateKey);\n\t\tconst scopeState = evaluatedDocument === void 0 ? void 0 : evaluatedDocument.state[scope];\n\t\tconst evaluation = definition.decide(modelAt(readSet, derivedSet.map((projection) => projection.name), derivedEntries, position.states), subjectOf(position.operation), {\n\t\t\tverb: \"execute\",\n\t\t\tscope: position.operation.action.scope,\n\t\t\toperation: position.operation.action.type\n\t\t}, {\n\t\t\tscopeState,\n\t\t\tactionInput: position.operation.action.input\n\t\t});\n\t\tconst denied = evaluation.decision === \"deny\";\n\t\treasons.set(position.operation.id, denied ? evaluation.reason : void 0);\n\t\tstep = walk.next(denied);\n\t}\n\treturn operations.map((operation) => reasons.get(operation.id));\n}\n//#endregion\n//#region src/cache/operation-index-types.ts\nconst DRIVE_COLLECTION_PREFIX = \"drive.\";\n/**\n* Identifies the collection a remote synchronizes. Collections are drive-level\n* abstractions (document-drive and reactor-drive), so a collection id is the\n* drive document id plus the branch it scopes to rather than an opaque string.\n*\n* The canonical string form (`drive.${branch}.${driveId}`) is produced only by\n* `key` and parsed only by `fromKey`; that string is the wire and storage\n* representation and is byte-for-byte identical to the legacy\n* `driveCollectionId(branch, driveId)` output, so existing `document_collections`\n* rows and persisted remotes remain valid without migration.\n*/\nvar DriveCollectionId = class DriveCollectionId {\n\tconstructor(driveId, branch) {\n\t\tthis.driveId = driveId;\n\t\tthis.branch = branch;\n\t}\n\tstatic forDrive(driveId, branch = \"main\") {\n\t\treturn new DriveCollectionId(driveId, branch);\n\t}\n\t/**\n\t* The single deserializer for the wire/storage form. `branch` may contain\n\t* dots, while `driveId` is a dot-free document id, so the drive id is the\n\t* final dot-delimited segment.\n\t*/\n\tstatic fromKey(key) {\n\t\tif (!key.startsWith(DRIVE_COLLECTION_PREFIX)) throw new Error(`Unsupported collection id: ${key}`);\n\t\tconst rest = key.slice(6);\n\t\tconst lastDot = rest.lastIndexOf(\".\");\n\t\tif (lastDot === -1 || lastDot === rest.length - 1) throw new Error(`Malformed drive collection id: ${key}`);\n\t\treturn new DriveCollectionId(rest.slice(lastDot + 1), rest.slice(0, lastDot));\n\t}\n\tget key() {\n\t\treturn `${DRIVE_COLLECTION_PREFIX}${this.branch}.${this.driveId}`;\n\t}\n\ttoString() {\n\t\treturn this.key;\n\t}\n\tequals(other) {\n\t\treturn this.driveId === other.driveId && this.branch === other.branch;\n\t}\n};\n//#endregion\n//#region src/executor/document-action-handler.ts\nvar DocumentActionHandler = class {\n\tconstructor(registry, logger, driveContainerTypes, featureFlags, decisionModel) {\n\t\tthis.registry = registry;\n\t\tthis.logger = logger;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.featureFlags = featureFlags;\n\t\tthis.decisionModel = decisionModel;\n\t}\n\t/** Whether the write arrives with its evaluation already decided. */\n\talreadyEvaluated(executing) {\n\t\treturn this.featureFlags.documentDecisions && (executing.replayingAcceptedHistory || executing.evaluatedByPosition);\n\t}\n\tasync execute(write, executing) {\n\t\tconst { action } = write;\n\t\tif (write.deniedReason !== void 0) return this.writeDenied(write, executing);\n\t\tconst refusal = await this.refuseIfPolicyDenies(write, executing);\n\t\tif (refusal) return refusal;\n\t\tswitch (action.type) {\n\t\t\tcase \"CREATE_DOCUMENT\": return this.executeCreate(write, executing);\n\t\t\tcase \"DELETE_DOCUMENT\": return this.executeDelete(write, executing);\n\t\t\tcase \"UPGRADE_DOCUMENT\": return this.executeUpgrade(write, executing);\n\t\t\tcase \"ADD_RELATIONSHIP\": return this.executeAddRelationship(write, executing);\n\t\t\tcase \"REMOVE_RELATIONSHIP\": return this.executeRemoveRelationship(write, executing);\n\t\t\tcase \"UPDATE_RELATIONSHIP\": return this.executeUpdateRelationship(write, executing);\n\t\t\tdefault: return buildErrorResult(executing.job, /* @__PURE__ */ new Error(`Unknown document action type: ${action.type}`), executing.startTime);\n\t\t}\n\t}\n\t/**\n\t* Refuses a document-scope write the policy denies, or undefined to proceed.\n\t* Without this an `execute`-on-`document` grant is unenforceable.\n\t*/\n\tasync refuseIfPolicyDenies(write, executing) {\n\t\tconst { action } = write;\n\t\tconst { job, startTime, stores, signal } = executing;\n\t\tif (!this.featureFlags.documentDecisions || !this.featureFlags.authEnforcement || this.alreadyEvaluated(executing) || !GATED_DOCUMENT_ACTIONS.has(action.type)) return;\n\t\tconst documentId = targetDocumentId(action, job.documentId);\n\t\tlet admission;\n\t\ttry {\n\t\t\tadmission = await decideAtHead(this.decisionModel, stores.writeCache, {\n\t\t\t\tdocumentId,\n\t\t\t\tbranch: job.branch\n\t\t\t}, {\n\t\t\t\taddress: action.context?.signer?.user.address,\n\t\t\t\tkey: action.context?.signer?.app.key\n\t\t\t}, {\n\t\t\t\tverb: \"execute\",\n\t\t\t\tscope: action.scope,\n\t\t\t\toperation: action.type\n\t\t\t}, signal, this.featureFlags.authConditions ? { actionInput: action.input } : void 0);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tif (admission.evaluation.decision === \"allow\") return;\n\t\treturn buildErrorResult(job, refusalError(admission.evaluation.reason, documentId, admission.deletedAtUtcIso, action), startTime);\n\t}\n\t/** A refused operation holds a position in the stream but changes nothing. */\n\tasync writeDenied(write, executing) {\n\t\tconst { action, skip, sourceRemote, deniedReason } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await stores.writeCache.getState(job.documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tconst index = getNextIndexForScope(document, job.scope);\n\t\tlet standing = document;\n\t\tif (skip > 0) try {\n\t\t\tstanding = await stores.writeCache.getState(job.documentId, job.scope, job.branch, index - skip - 1, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tlet operation = createOperation(action, index, skip, {\n\t\t\tdocumentId: job.documentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\toperation.deniedReason = deniedReason;\n\t\toperation.hash = hashDocumentStateForScope(standing, job.scope);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId: job.documentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(standing, job.scope, operation.index);\n\t\tstanding.operations = {\n\t\t\t...standing.operations,\n\t\t\t[job.scope]: [...standing.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(job.documentId, job.scope, job.branch);\n\t\tstores.writeCache.putState(job.documentId, job.scope, job.branch, operation.index, standing, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId: job.documentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tstores.documentMetaCache.putDocumentMeta(job.documentId, job.branch, {\n\t\t\tstate: standing.state.document,\n\t\t\tdocumentType: standing.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, job.documentId, standing.header.documentType, JSON.stringify({\n\t\t\theader: standing.header,\n\t\t\tdocument: standing.state.document\n\t\t}), startTime);\n\t}\n\tasync executeCreate(write, executing) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tif (job.scope !== \"document\") return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: /* @__PURE__ */ new Error(`CREATE_DOCUMENT must be in \"document\" scope, got \"${job.scope}\"`),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tconst document = createDocumentFromAction(action);\n\t\tlet operation = createOperation(action, 0, skip, {\n\t\t\tdocumentId: document.header.id,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tconst resultingStateObj = {\n\t\t\theader: document.header,\n\t\t\t...document.state\n\t\t};\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId: document.header.id,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(document, job.scope, operation.index);\n\t\tdocument.operations = {\n\t\t\t...document.operations,\n\t\t\t[job.scope]: [...document.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(document.header.id, job.scope, job.branch);\n\t\tstores.writeCache.putState(document.header.id, job.scope, job.branch, operation.index, document, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId: document.header.id,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tif (this.driveContainerTypes.has(document.header.documentType)) {\n\t\t\tconst collectionId = DriveCollectionId.forDrive(document.header.id, job.branch).key;\n\t\t\tindexTxn.createCollection(collectionId);\n\t\t\tindexTxn.addToCollection(collectionId, document.header.id);\n\t\t}\n\t\tstores.documentMetaCache.putDocumentMeta(document.header.id, job.branch, {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tdocumentScopeRevision: 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, document.header.id, document.header.documentType, resultingState, startTime);\n\t}\n\tasync executeDelete(write, executing) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tconst input = action.input;\n\t\tif (!input.documentId) return buildErrorResult(job, /* @__PURE__ */ new Error(\"DELETE_DOCUMENT action requires a documentId in input\"), startTime);\n\t\tconst documentId = input.documentId;\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await stores.writeCache.getState(documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch document before deletion: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t}\n\t\tconst documentState = document.state.document;\n\t\tif (documentState.isDeleted && !this.alreadyEvaluated(executing)) return buildErrorResult(job, new DocumentDeletedError(documentId, documentState.deletedAtUtcIso), startTime);\n\t\tlet operation = createOperation(action, getNextIndexForScope(document, job.scope), skip, {\n\t\t\tdocumentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tapplyDeleteDocumentAction$1(document, action);\n\t\tconst resultingStateObj = {\n\t\t\theader: document.header,\n\t\t\tdocument: document.state.document\n\t\t};\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(document, job.scope, operation.index);\n\t\tdocument.operations = {\n\t\t\t...document.operations,\n\t\t\t[job.scope]: [...document.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(documentId, job.scope, job.branch);\n\t\tstores.writeCache.putState(documentId, job.scope, job.branch, operation.index, document, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tstores.documentMetaCache.putDocumentMeta(documentId, job.branch, {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, documentId, document.header.documentType, resultingState, startTime);\n\t}\n\tasync executeUpgrade(write, executing) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tconst input = action.input;\n\t\tif (!input.documentId) return buildErrorResult(job, /* @__PURE__ */ new Error(\"UPGRADE_DOCUMENT action requires a documentId in input\"), startTime);\n\t\tconst documentId = input.documentId;\n\t\tconst fromVersion = input.fromVersion;\n\t\tconst toVersion = input.toVersion;\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await stores.writeCache.getState(documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch document for upgrade: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t}\n\t\tconst documentState = document.state.document;\n\t\tif (documentState.isDeleted && !this.alreadyEvaluated(executing)) return buildErrorResult(job, new DocumentDeletedError(documentId, documentState.deletedAtUtcIso), startTime);\n\t\tif (fromVersion === toVersion && fromVersion > 0) return {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: [],\n\t\t\toperationsWithContext: [],\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tconst arrivesDecided = executing.replayingAcceptedHistory || executing.evaluatedByPosition;\n\t\tif (fromVersion > 0 && !arrivesDecided) {\n\t\t\tconst stampedVersion = normalizeDocumentModelVersion(documentState.version);\n\t\t\tif (fromVersion !== stampedVersion) return buildErrorResult(job, new UpgradePreconditionFailedError(documentId, `fromVersion ${fromVersion} does not match the document's version ${stampedVersion}`), startTime);\n\t\t\tif (input.revision !== void 0) {\n\t\t\t\tlet actualRevisions;\n\t\t\t\ttry {\n\t\t\t\t\tactualRevisions = (await stores.operationStore.getRevisions(documentId, job.branch, signal)).revision;\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch revisions for upgrade: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t\t\t}\n\t\t\t\tconst revisionScopes = new Set([...Object.keys(input.revision), ...Object.keys(actualRevisions)]);\n\t\t\t\tfor (const revisionScope of revisionScopes) {\n\t\t\t\t\tconst snapshot = input.revision[revisionScope] ?? 0;\n\t\t\t\t\tconst actual = actualRevisions[revisionScope] ?? 0;\n\t\t\t\t\tif (snapshot !== actual) return buildErrorResult(job, new UpgradePreconditionFailedError(documentId, `revision snapshot for scope \"${revisionScope}\" is ${snapshot} but the document is at ${actual}`), startTime);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlet upgradePath;\n\t\tif (fromVersion > 0 && fromVersion < toVersion) try {\n\t\t\tupgradePath = this.registry.computeUpgradePath(document.header.documentType, fromVersion, toVersion);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tconst otherScopes = Object.keys(document.state).filter((scope) => scope !== job.scope);\n\t\tif (fromVersion > 0) for (const scope of otherScopes) {\n\t\t\tlet scopedDocument;\n\t\t\ttry {\n\t\t\t\tscopedDocument = await stores.writeCache.getState(documentId, scope, job.branch, void 0, signal);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch ${scope} scope for upgrade: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t\t}\n\t\t\tdocument = {\n\t\t\t\t...document,\n\t\t\t\tstate: {\n\t\t\t\t\t...document.state,\n\t\t\t\t\t[scope]: scopedDocument.state[scope]\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\tconst nextIndex = getNextIndexForScope(document, job.scope);\n\t\ttry {\n\t\t\tdocument = applyUpgradeDocumentAction$1(document, action, upgradePath);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tlet operation = createOperation(action, nextIndex, skip, {\n\t\t\tdocumentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tconst resultingStateObj = {\n\t\t\theader: document.header,\n\t\t\t...document.state\n\t\t};\n\t\tif (fromVersion > 0) resultingStateObj.__migrated = true;\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(document, job.scope, operation.index);\n\t\tdocument.operations = {\n\t\t\t...document.operations,\n\t\t\t[job.scope]: [...document.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(documentId, job.scope, job.branch);\n\t\tstores.writeCache.putState(documentId, job.scope, job.branch, operation.index, document, SnapshotPosition.Head);\n\t\tfor (const scope of otherScopes) executing.postCommitInvalidations.push({\n\t\t\tdocumentId,\n\t\t\tscope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tstores.documentMetaCache.putDocumentMeta(documentId, job.branch, {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, documentId, document.header.documentType, resultingState, startTime);\n\t}\n\texecuteAddRelationship(write, executing) {\n\t\treturn this.withRelationshipAction(\"ADD_RELATIONSHIP\", write, executing, (input) => input.sourceId === input.targetId ? /* @__PURE__ */ new Error(\"ADD_RELATIONSHIP: sourceId and targetId cannot be the same (self-relationships not allowed)\") : null, ({ indexTxn: txn, stores: s, sourceDoc, input, job: j }) => {\n\t\t\tif (this.driveContainerTypes.has(sourceDoc.header.documentType)) {\n\t\t\t\tconst collectionId = DriveCollectionId.forDrive(input.sourceId, j.branch).key;\n\t\t\t\ttxn.addToCollection(collectionId, input.targetId);\n\t\t\t\ts.collectionMembershipCache.invalidate(input.targetId);\n\t\t\t}\n\t\t});\n\t}\n\texecuteRemoveRelationship(write, executing) {\n\t\treturn this.withRelationshipAction(\"REMOVE_RELATIONSHIP\", write, executing, null, ({ indexTxn: txn, stores: s, sourceDoc, input, job: j }) => {\n\t\t\tif (this.driveContainerTypes.has(sourceDoc.header.documentType)) {\n\t\t\t\tconst collectionId = DriveCollectionId.forDrive(input.sourceId, j.branch).key;\n\t\t\t\ttxn.removeFromCollection(collectionId, input.targetId);\n\t\t\t\ts.collectionMembershipCache.invalidate(input.targetId);\n\t\t\t}\n\t\t});\n\t}\n\texecuteUpdateRelationship(write, executing) {\n\t\treturn this.withRelationshipAction(\"UPDATE_RELATIONSHIP\", write, executing, null, null);\n\t}\n\tasync withRelationshipAction(actionTypeName, write, executing, preValidate, postWrite) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tif (job.scope !== \"document\") return buildErrorResult(job, /* @__PURE__ */ new Error(`${actionTypeName} must be in \"document\" scope, got \"${job.scope}\"`), startTime);\n\t\tconst input = action.input;\n\t\tif (!input.sourceId || !input.targetId || !input.relationshipType) return buildErrorResult(job, /* @__PURE__ */ new Error(`${actionTypeName} action requires sourceId, targetId, and relationshipType in input`), startTime);\n\t\tif (preValidate !== null) {\n\t\t\tconst validationError = preValidate(input);\n\t\t\tif (validationError !== null) return buildErrorResult(job, validationError, startTime);\n\t\t}\n\t\tlet sourceDoc;\n\t\ttry {\n\t\t\tsourceDoc = await stores.writeCache.getState(input.sourceId, \"document\", job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\tif (DocumentNotFoundError.isError(error)) return buildErrorResult(job, new DocumentNotFoundError(input.sourceId, `${actionTypeName}: source document ${input.sourceId} not found`), startTime);\n\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`${actionTypeName}: source document ${input.sourceId} not found: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t}\n\t\tlet operation = createOperation(action, getNextIndexForScope(sourceDoc, job.scope), skip, {\n\t\t\tdocumentId: input.sourceId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId: input.sourceId,\n\t\t\tdocumentType: sourceDoc.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tsourceDoc.header.lastModifiedAtUtcIso = operation.timestampUtcMs || (/* @__PURE__ */ new Date()).toISOString();\n\t\tupdateDocumentRevision(sourceDoc, job.scope, operation.index);\n\t\tsourceDoc.operations = {\n\t\t\t...sourceDoc.operations,\n\t\t\t[job.scope]: [...sourceDoc.operations[job.scope] ?? [], operation]\n\t\t};\n\t\tconst scopeState = sourceDoc.state[job.scope];\n\t\tconst resultingStateObj = {\n\t\t\theader: structuredClone(sourceDoc.header),\n\t\t\t[job.scope]: scopeState === void 0 ? {} : structuredClone(scopeState)\n\t\t};\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\texecuting.touchedStreams.add(input.sourceId, job.scope, job.branch);\n\t\texecuting.touchedStreams.add(input.targetId, job.scope, job.branch);\n\t\tstores.writeCache.putState(input.sourceId, job.scope, job.branch, operation.index, sourceDoc, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId: input.sourceId,\n\t\t\tdocumentType: sourceDoc.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tif (postWrite !== null) postWrite({\n\t\t\tindexTxn,\n\t\t\tstores,\n\t\t\tsourceDoc,\n\t\t\tinput,\n\t\t\tjob\n\t\t});\n\t\tstores.documentMetaCache.putDocumentMeta(input.sourceId, job.branch, {\n\t\t\tstate: sourceDoc.state.document,\n\t\t\tdocumentType: sourceDoc.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, input.sourceId, sourceDoc.header.documentType, resultingState, startTime);\n\t}\n\tasync writeOperationToStore(target, operation, executing) {\n\t\tconst { documentId, documentType, scope, branch } = target;\n\t\tconst { job, startTime, stores, signal } = executing;\n\t\texecuting.touchedStreams.add(documentId, scope, branch);\n\t\tlet storedOperations;\n\t\ttry {\n\t\t\tstoredOperations = await stores.operationStore.apply(documentId, documentType, scope, branch, operation.index, (txn) => {\n\t\t\t\ttxn.addOperations(operation);\n\t\t\t}, signal);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to write operation to IOperationStore (@documentId @scope @branch): @Operation @Error\", documentId, scope, branch, operation, error);\n\t\t\tstores.writeCache.invalidate(documentId, scope, branch);\n\t\t\tif (AppendConditionFailedError.isError(error)) for (const stream of error.condition.streams) stores.writeCache.invalidate(stream.documentId, stream.scope, stream.branch);\n\t\t\treturn {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(`Failed to write operation to IOperationStore: ${String(error)}`),\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\treturn storedOperations;\n\t}\n};\n//#endregion\n//#region src/executor/signature-verifier.ts\nvar SignatureVerifier = class {\n\tconstructor(verifier) {\n\t\tthis.verifier = verifier;\n\t}\n\tasync verifyActions(documentId, branch, actions) {\n\t\tif (!this.verifier) return;\n\t\tfor (const action of actions) {\n\t\t\tconst signer = action.context?.signer;\n\t\t\tif (!signer) continue;\n\t\t\tif (signer.signatures.length === 0) throw new InvalidSignatureError(documentId, `Action ${action.id} has signer but no signatures`);\n\t\t\tconst publicKey = signer.app.key;\n\t\t\tlet isValid;\n\t\t\ttry {\n\t\t\t\tconst tempOperation = {\n\t\t\t\t\tid: deriveOperationId(documentId, action.scope, branch, action.id),\n\t\t\t\t\tindex: 0,\n\t\t\t\t\ttimestampUtcMs: action.timestampUtcMs || (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\t\thash: \"\",\n\t\t\t\t\tskip: 0,\n\t\t\t\t\taction\n\t\t\t\t};\n\t\t\t\tisValid = await this.verifier(tempOperation, publicKey);\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new InvalidSignatureError(documentId, `Action ${action.id} verification failed: ${errorMessage}`);\n\t\t\t}\n\t\t\tif (!isValid) throw new InvalidSignatureError(documentId, `Action ${action.id} signature verification returned false`);\n\t\t}\n\t}\n\tasync verifyOperations(documentId, operations) {\n\t\tif (!this.verifier) return;\n\t\tfor (let i = 0; i < operations.length; i++) {\n\t\t\tconst operation = operations[i];\n\t\t\tconst signer = operation.action.context?.signer;\n\t\t\tif (!signer) continue;\n\t\t\tif (signer.signatures.length === 0) throw new InvalidSignatureError(documentId, `Operation ${operation.id} at index ${operation.index} has signer but no signatures`);\n\t\t\tconst publicKey = signer.app.key;\n\t\t\tlet isValid;\n\t\t\ttry {\n\t\t\t\tisValid = await this.verifier(operation, publicKey);\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new InvalidSignatureError(documentId, `Operation ${operation.id} at index ${operation.index} verification failed: ${errorMessage}`);\n\t\t\t}\n\t\t\tif (!isValid) throw new InvalidSignatureError(documentId, `Operation ${operation.id} at index ${operation.index} signature verification returned false`);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/executor/simple-job-executor.ts\nconst MAX_SKIP_THRESHOLD = 1e3;\nconst ISO_TIMESTAMP_REGEX = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$/;\nfunction isValidISOTimestamp(value) {\n\tif (!ISO_TIMESTAMP_REGEX.test(value)) return false;\n\treturn !isNaN(new Date(value).getTime());\n}\n/**\n* Carries a failed job out of the execution scope so its transaction rolls\n* back. A scope callback that returns commits, whatever result it returns, so\n* a returned failure would leave the writes the job made before it failed\n* standing. Never escapes executeJob: the failure goes back to being a\n* returned JobResult there, which is what the queue, the worker protocol and\n* every test expect a failed job to look like.\n*/\nvar JobRollbackSignal = class extends Error {\n\tconstructor(result) {\n\t\tsuper(\"job rolled back\");\n\t\tthis.result = result;\n\t\tthis.name = \"JobRollbackSignal\";\n\t}\n};\nvar SimpleJobExecutor = class {\n\tconfig;\n\tfeatureFlags;\n\tdecisionModel;\n\tsignatureVerifierModule;\n\tdocumentActionHandler;\n\texecutionScope;\n\tconstructor(logger, registry, operationStore, eventBus, writeCache, operationIndex, documentMetaCache, collectionMembershipCache, driveContainerTypes, config, signatureVerifier, executionScope) {\n\t\tthis.logger = logger;\n\t\tthis.registry = registry;\n\t\tthis.operationStore = operationStore;\n\t\tthis.eventBus = eventBus;\n\t\tthis.writeCache = writeCache;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.documentMetaCache = documentMetaCache;\n\t\tthis.collectionMembershipCache = collectionMembershipCache;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.config = {\n\t\t\tfeatureFlags: config.featureFlags ?? {},\n\t\t\tmaxSkipThreshold: config.maxSkipThreshold ?? MAX_SKIP_THRESHOLD,\n\t\t\tmaxConcurrency: config.maxConcurrency ?? 1,\n\t\t\tjobTimeoutMs: config.jobTimeoutMs ?? 3e4,\n\t\t\tdeferredJobTtlMs: config.deferredJobTtlMs ?? 3e4,\n\t\t\tretryBaseDelayMs: config.retryBaseDelayMs ?? 100,\n\t\t\tretryMaxDelayMs: config.retryMaxDelayMs ?? 5e3,\n\t\t\tyieldDeadlineMs: config.yieldDeadlineMs ?? 50,\n\t\t\tbatchApplies: config.batchApplies ?? true\n\t\t};\n\t\tthis.featureFlags = resolveFeatureFlags(config.featureFlags);\n\t\tthis.decisionModel = selectDecisionModel(this.featureFlags, registry);\n\t\tthis.signatureVerifierModule = new SignatureVerifier(signatureVerifier);\n\t\tthis.documentActionHandler = new DocumentActionHandler(registry, logger, driveContainerTypes, this.featureFlags, this.decisionModel);\n\t\tthis.executionScope = executionScope ?? new DefaultExecutionScope(operationStore, operationIndex, writeCache, documentMetaCache, collectionMembershipCache);\n\t}\n\t/**\n\t* Execute a single job by applying all its actions through the appropriate reducers.\n\t* Actions are processed sequentially in order.\n\t*\n\t* The whole job runs inside one execution scope, and a scope callback that\n\t* returns commits. A failed job must therefore leave the scope by throwing,\n\t* or the writes it made before it failed would be durable: JobRollbackSignal\n\t* carries the failure out through the transaction and this method turns it\n\t* back into the returned JobResult every caller expects. A job either fully\n\t* applies or leaves nothing durable behind.\n\t*\n\t* Durable is the whole of the guarantee. The caches are shared with the\n\t* copies the scope hands the job, so a failed job's writes sit in them from\n\t* the moment it makes them until the eviction below, and a concurrent read\n\t* in that window sees a write that is never going to commit. The window is\n\t* not new -- it has always been there for a job that failed by throwing --\n\t* but nothing here closes it, and a caller that needs to know a write is\n\t* real has the job status to ask.\n\t*/\n\tasync executeJob(job, signal) {\n\t\tconst startTime = Date.now();\n\t\tconst touchedStreams = new TouchedStreams();\n\t\tconst postCommitInvalidations = [];\n\t\tconst postCommitMembershipInvalidations = [];\n\t\tlet outcome;\n\t\ttry {\n\t\t\toutcome = await this.executionScope.run(async (stores) => {\n\t\t\t\tconst scoped = await this.executeInScope({\n\t\t\t\t\tjob,\n\t\t\t\t\tstartTime,\n\t\t\t\t\tstores,\n\t\t\t\t\tsignal,\n\t\t\t\t\ttouchedStreams,\n\t\t\t\t\tpostCommitInvalidations,\n\t\t\t\t\tpostCommitMembershipInvalidations\n\t\t\t\t});\n\t\t\t\tif (!scoped.result.success) throw new JobRollbackSignal(scoped.result);\n\t\t\t\treturn scoped;\n\t\t\t}, signal);\n\t\t} catch (error) {\n\t\t\tthis.evictTouchedStreams(touchedStreams);\n\t\t\tif (error instanceof JobRollbackSignal) return error.result;\n\t\t\tthrow error;\n\t\t}\n\t\tfor (const entry of postCommitInvalidations) this.writeCache.invalidate(entry.documentId, entry.scope, entry.branch);\n\t\tfor (const documentId of postCommitMembershipInvalidations) this.collectionMembershipCache.invalidate(documentId);\n\t\tconst { pendingEvent } = outcome;\n\t\tif (pendingEvent) this.eventBus.emit(ReactorEventTypes.JOB_WRITE_READY, pendingEvent).catch((error) => {\n\t\t\tthis.logger.error(\"Failed to emit JOB_WRITE_READY event: @Event : @Error\", pendingEvent, error);\n\t\t});\n\t\treturn outcome.result;\n\t}\n\t/**\n\t* The body of a job, run inside the execution scope's transaction.\n\t*\n\t* The stores and caches it works through are the copies scoped to that\n\t* transaction, so nothing it does is durable until the scope commits. The\n\t* write-ready event is handed back rather than emitted, because a job that\n\t* has not committed yet has nothing to announce.\n\t*/\n\tasync executeInScope(params) {\n\t\tconst { job, startTime, stores, signal, touchedStreams, postCommitInvalidations, postCommitMembershipInvalidations } = params;\n\t\tlet pendingEvent;\n\t\tconst indexTxn = stores.operationIndex.start();\n\t\tif (job.kind === \"load\") {\n\t\t\tconst loadResult = await this.executeLoadJob({\n\t\t\t\tjob,\n\t\t\t\tstartTime,\n\t\t\t\tindexTxn,\n\t\t\t\tstores,\n\t\t\t\tsignal,\n\t\t\t\treplayingAcceptedHistory: true,\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\tpostCommitInvalidations,\n\t\t\t\tpostCommitMembershipInvalidations,\n\t\t\t\ttouchedStreams\n\t\t\t});\n\t\t\tif (loadResult.success && loadResult.operationsWithContext) {\n\t\t\t\tconst ordinals = await stores.operationIndex.commit(indexTxn, signal);\n\t\t\t\tpostCommitMembershipInvalidations.push(...indexTxn.getMembershipInvalidations());\n\t\t\t\tfor (let i = 0; i < loadResult.operationsWithContext.length; i++) loadResult.operationsWithContext[i].context.ordinal = ordinals[i];\n\t\t\t\tconst collectionMemberships = loadResult.operationsWithContext.length > 0 ? await this.getCollectionMembershipsForOperations(loadResult.operationsWithContext, stores) : {};\n\t\t\t\tpendingEvent = {\n\t\t\t\t\tjobId: job.id,\n\t\t\t\t\toperations: loadResult.operationsWithContext,\n\t\t\t\t\tjobMeta: job.meta,\n\t\t\t\t\tcollectionMemberships\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tresult: loadResult,\n\t\t\t\tpendingEvent\n\t\t\t};\n\t\t}\n\t\tif (job.kind === \"reevaluation\") {\n\t\t\tconst reevalResult = await this.executeReevaluationJob({\n\t\t\t\tjob,\n\t\t\t\tstartTime,\n\t\t\t\tindexTxn,\n\t\t\t\tstores,\n\t\t\t\tsignal,\n\t\t\t\treplayingAcceptedHistory: false,\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\tpostCommitInvalidations,\n\t\t\t\tpostCommitMembershipInvalidations,\n\t\t\t\ttouchedStreams\n\t\t\t});\n\t\t\tif (reevalResult.success && reevalResult.operationsWithContext) {\n\t\t\t\tconst ordinals = await stores.operationIndex.commit(indexTxn, signal);\n\t\t\t\tpostCommitMembershipInvalidations.push(...indexTxn.getMembershipInvalidations());\n\t\t\t\tfor (let i = 0; i < reevalResult.operationsWithContext.length; i++) reevalResult.operationsWithContext[i].context.ordinal = ordinals[i];\n\t\t\t\tif (reevalResult.operationsWithContext.length > 0) {\n\t\t\t\t\tconst collectionMemberships = await this.getCollectionMembershipsForOperations(reevalResult.operationsWithContext, stores);\n\t\t\t\t\tpendingEvent = {\n\t\t\t\t\t\tjobId: job.id,\n\t\t\t\t\t\toperations: reevalResult.operationsWithContext,\n\t\t\t\t\t\tjobMeta: job.meta,\n\t\t\t\t\t\tcollectionMemberships\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tresult: reevalResult,\n\t\t\t\tpendingEvent\n\t\t\t};\n\t\t}\n\t\tconst positioned = await this.positionByTimestamp(job, stores, signal);\n\t\tif (positioned.error) return { result: buildErrorResult(job, positioned.error, startTime) };\n\t\tconst executing = {\n\t\t\tjob,\n\t\t\tstartTime,\n\t\t\tindexTxn,\n\t\t\tstores,\n\t\t\tsignal,\n\t\t\treplayingAcceptedHistory: false,\n\t\t\tevaluatedByPosition: positioned.evaluatedByPosition,\n\t\t\tpostCommitInvalidations,\n\t\t\tpostCommitMembershipInvalidations,\n\t\t\ttouchedStreams\n\t\t};\n\t\tconst actionResult = await this.processActions(positioned.writes, executing);\n\t\tif (!actionResult.success) return { result: {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: actionResult.error,\n\t\t\tduration: Date.now() - startTime\n\t\t} };\n\t\tconst reevaluationError = await this.reevaluateIfCriteriaMet({\n\t\t\tscope: job.scope,\n\t\t\toperations: actionResult.generatedOperations\n\t\t}, executing);\n\t\tif (reevaluationError) return { result: {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: reevaluationError,\n\t\t\tduration: Date.now() - startTime\n\t\t} };\n\t\tconst ordinals = await stores.operationIndex.commit(indexTxn, signal);\n\t\tpostCommitMembershipInvalidations.push(...indexTxn.getMembershipInvalidations());\n\t\tif (actionResult.operationsWithContext.length > 0) {\n\t\t\tfor (let i = 0; i < actionResult.operationsWithContext.length; i++) actionResult.operationsWithContext[i].context.ordinal = ordinals[i];\n\t\t\tconst collectionMemberships = await this.getCollectionMembershipsForOperations(actionResult.operationsWithContext, stores);\n\t\t\tpendingEvent = {\n\t\t\t\tjobId: job.id,\n\t\t\t\toperations: actionResult.operationsWithContext,\n\t\t\t\tjobMeta: job.meta,\n\t\t\t\tcollectionMemberships\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tresult: {\n\t\t\t\tjob,\n\t\t\t\tsuccess: true,\n\t\t\t\toperations: actionResult.generatedOperations,\n\t\t\t\toperationsWithContext: actionResult.operationsWithContext,\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t},\n\t\t\tpendingEvent\n\t\t};\n\t}\n\t/**\n\t* Drops the cached state of every stream a job wrote, after its transaction\n\t* did not commit.\n\t*\n\t* The caches are shared by reference with the copies the scope hands the job,\n\t* so a rollback undoes nothing in them: what the job put there survives, as\n\t* does anything a read filled from the store while the job's own writes were\n\t* still uncommitted. An eviction that throws is swallowed rather than allowed\n\t* to replace the failure the caller is owed, and the remaining streams are\n\t* still evicted.\n\t*/\n\tevictTouchedStreams(touchedStreams) {\n\t\tfor (const entry of touchedStreams) try {\n\t\t\tthis.writeCache.invalidate(entry.documentId, entry.scope, entry.branch);\n\t\t\tthis.documentMetaCache.invalidate(entry.documentId, entry.branch);\n\t\t\tthis.collectionMembershipCache.invalidate(entry.documentId);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to evict cached state for rolled back @Stream : @Error\", entry, error);\n\t\t}\n\t}\n\tasync getCollectionMembershipsForOperations(operations, stores) {\n\t\tconst documentIds = [...new Set(operations.map((op) => op.context.documentId))];\n\t\treturn stores.collectionMembershipCache.getCollectionsForDocuments(documentIds);\n\t}\n\tasync processActions(writes, executing) {\n\t\tconst { job, signal } = executing;\n\t\tconst actions = writes.map((write) => write.action);\n\t\tconst generatedOperations = [];\n\t\tconst operationsWithContext = [];\n\t\ttry {\n\t\t\tawait this.signatureVerifierModule.verifyActions(job.documentId, job.branch, actions);\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext,\n\t\t\t\terror: error instanceof Error ? error : new Error(String(error))\n\t\t\t};\n\t\t}\n\t\tfor (const action of actions) if (action.timestampUtcMs && !isValidISOTimestamp(action.timestampUtcMs)) return {\n\t\t\tsuccess: false,\n\t\t\tgeneratedOperations,\n\t\t\toperationsWithContext,\n\t\t\terror: new InvalidOperationTimestampError(job.documentId, action.scope, action.timestampUtcMs, `action ${action.type} (id: ${action.id})`)\n\t\t};\n\t\tlet lastYield = performance.now();\n\t\tif (this.config.batchApplies && this.canBatch(writes, executing)) {\n\t\t\tconst batched = await this.executeRegularActionsBatched(writes, executing);\n\t\t\tconst error = this.accumulateResultOrReturnError(batched, generatedOperations, operationsWithContext);\n\t\t\tif (error !== null) return {\n\t\t\t\tsuccess: false,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext,\n\t\t\t\terror: error.error\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext\n\t\t\t};\n\t\t}\n\t\tfor (const write of writes) {\n\t\t\tconst result = DOCUMENT_SCOPE_ACTIONS.has(write.action.type) ? await this.documentActionHandler.execute(write, executing) : await this.executeRegularAction(write, executing);\n\t\t\tconst error = this.accumulateResultOrReturnError(result, generatedOperations, operationsWithContext);\n\t\t\tif (error !== null) return {\n\t\t\t\tsuccess: false,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext,\n\t\t\t\terror: error.error\n\t\t\t};\n\t\t\tif (performance.now() - lastYield > this.config.yieldDeadlineMs) {\n\t\t\t\tawait yieldToMain();\n\t\t\t\tlastYield = performance.now();\n\t\t\t\tif (signal?.aborted) return {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tgeneratedOperations,\n\t\t\t\t\toperationsWithContext,\n\t\t\t\t\terror: /* @__PURE__ */ new Error(\"Aborted\")\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tgeneratedOperations,\n\t\t\toperationsWithContext\n\t\t};\n\t}\n\t/**\n\t* Decides a write and reduces it, without persisting anything.\n\t*\n\t* Split from the commit so one write and a batch of them share this logic\n\t* rather than keeping two copies of it. `baseDocument` lets a batch thread\n\t* the previous action's result forward instead of reading its own write back\n\t* out of the cache, which is the only reason the reduce has to be sequential.\n\t*/\n\tasync prepareRegularWrite(write, executing, baseDocument) {\n\t\tconst { action, skip, sourceOperation, sourceRemote, deniedReason } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tlet appendCondition;\n\t\tlet documentVersion;\n\t\tconst alreadyEvaluated = this.featureFlags.documentDecisions && (executing.replayingAcceptedHistory || executing.evaluatedByPosition);\n\t\tif (this.featureFlags.documentDecisions && !alreadyEvaluated) {\n\t\t\tconst target = {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tbranch: job.branch\n\t\t\t};\n\t\t\tlet admission;\n\t\t\ttry {\n\t\t\t\tadmission = await decideAtHead(this.decisionModel, stores.writeCache, target, {\n\t\t\t\t\taddress: action.context?.signer?.user.address,\n\t\t\t\t\tkey: action.context?.signer?.app.key\n\t\t\t\t}, {\n\t\t\t\t\tverb: \"execute\",\n\t\t\t\t\tscope: action.scope,\n\t\t\t\t\toperation: action.type\n\t\t\t\t}, signal, this.featureFlags.authConditions ? {\n\t\t\t\t\tactionInput: action.input,\n\t\t\t\t\tcarriedDocument: baseDocument\n\t\t\t\t} : void 0);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t\t}\n\t\t\tif (admission.evaluation.decision === \"deny\") return buildErrorResult(job, refusalError(admission.evaluation.reason, job.documentId, admission.deletedAtUtcIso, action), startTime);\n\t\t\tappendCondition = admission.appendCondition;\n\t\t\tdocumentVersion = admission.documentVersion;\n\t\t} else if (alreadyEvaluated) documentVersion = (await stores.writeCache.getState(job.documentId, \"document\", job.branch, void 0, signal)).state.document.version;\n\t\telse {\n\t\t\tlet docMeta;\n\t\t\ttry {\n\t\t\t\tdocMeta = await stores.documentMetaCache.getDocumentMeta(job.documentId, job.branch, signal);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t\t}\n\t\t\tif (docMeta.state.isDeleted) return buildErrorResult(job, new DocumentDeletedError(job.documentId, docMeta.state.deletedAtUtcIso), startTime);\n\t\t\tdocumentVersion = docMeta.state.version;\n\t\t}\n\t\tif (isUndoRedo(action) || action.type === \"PRUNE\" || skip > 0) stores.writeCache.invalidate(job.documentId, job.scope, job.branch);\n\t\tlet document;\n\t\tif (baseDocument !== void 0) document = baseDocument;\n\t\telse try {\n\t\t\tdocument = await stores.writeCache.getState(job.documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tif (!this.featureFlags.authEnforcement && !executing.replayingAcceptedHistory) {\n\t\t\tconst subject = {\n\t\t\t\taddress: write.action.context?.signer?.user.address,\n\t\t\t\tkey: write.action.context?.signer?.app.key\n\t\t\t};\n\t\t\tif (decide(document.state.auth, subject, {\n\t\t\t\tverb: \"execute\",\n\t\t\t\tscope: action.scope,\n\t\t\t\toperation: action.type\n\t\t\t}) === \"deny\") return buildErrorResult(job, new AuthorizationDeniedError(job.documentId, action.scope, action.type, subject.address), startTime);\n\t\t}\n\t\tlet module;\n\t\ttry {\n\t\t\tmodule = this.registry.getModule(document.header.documentType, normalizeDocumentModelVersion(documentVersion));\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tlet updatedDocument;\n\t\tif (deniedReason !== void 0) {\n\t\t\tconst index = getNextIndexForScope(document, job.scope);\n\t\t\tconst denied = createOperation(action, index, skip, {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch\n\t\t\t});\n\t\t\tdenied.deniedReason = deniedReason;\n\t\t\tlet standing = document;\n\t\t\tif (skip > 0) try {\n\t\t\t\tstanding = await stores.writeCache.getState(job.documentId, job.scope, job.branch, index - skip - 1, signal);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t\t}\n\t\t\tdenied.hash = hashDocumentStateForScope(standing, job.scope);\n\t\t\tupdatedDocument = {\n\t\t\t\t...standing,\n\t\t\t\toperations: {\n\t\t\t\t\t...standing.operations,\n\t\t\t\t\t[job.scope]: [...standing.operations[job.scope] ?? [], denied]\n\t\t\t\t}\n\t\t\t};\n\t\t} else try {\n\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\tconst reducerOptions = sourceOperation ? {\n\t\t\t\tskip,\n\t\t\t\tbranch: job.branch,\n\t\t\t\treplayOptions: { operation: sourceOperation },\n\t\t\t\tprotocolVersion\n\t\t\t} : {\n\t\t\t\tskip,\n\t\t\t\tbranch: job.branch,\n\t\t\t\tprotocolVersion\n\t\t\t};\n\t\t\tupdatedDocument = module.reducer(document, action, void 0, reducerOptions);\n\t\t} catch (error) {\n\t\t\tconst contextMessage = `Failed to apply action to document:\\n Action type: ${action.type}\\n Document ID: ${job.documentId}\\n Document type: ${document.header.documentType}\\n Scope: ${job.scope}\\n Original error: ${error instanceof Error ? error.message : String(error)}`;\n\t\t\tconst enhancedError = new Error(contextMessage);\n\t\t\tif (error instanceof Error && error.stack) enhancedError.stack = `${contextMessage}\\n\\nOriginal stack trace:\\n${error.stack}`;\n\t\t\treturn buildErrorResult(job, enhancedError, startTime);\n\t\t}\n\t\tconst scope = job.scope;\n\t\tconst operations = updatedDocument.operations[scope];\n\t\tif (operations.length === 0) return buildErrorResult(job, /* @__PURE__ */ new Error(\"No operation generated from action\"), startTime);\n\t\tconst newOperation = operations[operations.length - 1];\n\t\tif (!isUndoRedo(action)) newOperation.skip = skip;\n\t\tconst resultingState = JSON.stringify({\n\t\t\t...updatedDocument.state,\n\t\t\theader: updatedDocument.header\n\t\t});\n\t\treturn {\n\t\t\taction,\n\t\t\tsourceRemote,\n\t\t\tscope,\n\t\t\tdocument,\n\t\t\tupdatedDocument,\n\t\t\toperation: newOperation,\n\t\t\tresultingState,\n\t\t\tappendCondition,\n\t\t\tdenied: deniedReason !== void 0\n\t\t};\n\t}\n\t/**\n\t* Persists a run of prepared writes in one store transaction.\n\t*\n\t* The store has always accepted many operations per apply; the executor only\n\t* ever handed it one. Passing the whole run means one advisory lock over the\n\t* read set and one guarded insert for the batch, instead of one of each per\n\t* operation.\n\t*\n\t* The append condition is taken from the first write. Every write in a run\n\t* reads the same streams at the same revisions, because nothing outside the\n\t* run can change them mid-batch, and the caller has already refused to batch\n\t* the scopes where that does not hold.\n\t*/\n\tasync commitPreparedWrites(prepared, executing) {\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tconst first = prepared[0];\n\t\tconst last = prepared[prepared.length - 1];\n\t\tconst scope = first.scope;\n\t\tconst documentType = first.document.header.documentType;\n\t\tconst operations = prepared.map((write) => write.operation);\n\t\texecuting.touchedStreams.add(job.documentId, scope, job.branch);\n\t\tlet storedOperations;\n\t\ttry {\n\t\t\tstoredOperations = await stores.operationStore.apply(job.documentId, documentType, scope, job.branch, first.operation.index, (txn) => {\n\t\t\t\ttxn.addOperations(...operations);\n\t\t\t}, signal, first.appendCondition);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to write operation to IOperationStore (@documentId @scope @branch): @Operation @Error\", job.documentId, scope, job.branch, operations, error);\n\t\t\tstores.writeCache.invalidate(job.documentId, scope, job.branch);\n\t\t\tif (AppendConditionFailedError.isError(error)) for (const stream of error.condition.streams) stores.writeCache.invalidate(stream.documentId, stream.scope, stream.branch);\n\t\t\treturn {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(`Failed to write operation to IOperationStore: ${String(error)}`),\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst head = storedOperations[storedOperations.length - 1];\n\t\tlast.updatedDocument.header.revision = {\n\t\t\t...last.updatedDocument.header.revision,\n\t\t\t[scope]: head.index + 1\n\t\t};\n\t\tstores.writeCache.putRun(job.documentId, scope, job.branch, storedOperations.map((operation, position) => ({\n\t\t\trevision: operation.index,\n\t\t\tdocument: prepared[position].updatedDocument\n\t\t})));\n\t\tindexTxn.write(storedOperations.map((operation, position) => ({\n\t\t\t...operation,\n\t\t\tdocumentId: job.documentId,\n\t\t\tdocumentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope,\n\t\t\tsourceRemote: prepared[position].sourceRemote\n\t\t})));\n\t\tif (scope === \"auth\") for (const write of prepared) indexTxn.recordGroupReferences(job.documentId, mentionedGroupIds(write.action));\n\t\treturn {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: storedOperations,\n\t\t\toperationsWithContext: storedOperations.map((operation, position) => ({\n\t\t\t\toperation,\n\t\t\t\tcontext: {\n\t\t\t\t\tdocumentId: job.documentId,\n\t\t\t\t\tscope,\n\t\t\t\t\tbranch: job.branch,\n\t\t\t\t\tdocumentType,\n\t\t\t\t\tresultingState: prepared[position].resultingState,\n\t\t\t\t\tordinal: 0\n\t\t\t\t}\n\t\t\t})),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t}\n\t/**\n\t* Whether a job's writes may share one store transaction.\n\t*\n\t* Deliberately narrow. Batching changes only how many transactions the\n\t* operations arrive in, and every condition below is a case where that would\n\t* change something else as well:\n\t*\n\t* - A document-scope action goes through its own handler, which has its own\n\t* apply and its own reasons for it.\n\t* - A positional or replayed run carries skips and re-appended operations,\n\t* whose indices are not a simple ascending run from the head.\n\t* - UNDO, REDO, PRUNE and NOOP-with-skip each invalidate the write cache to\n\t* force a full-history rebuild, so they cannot be reduced against state\n\t* threaded from the write before them.\n\t* - The auth scope decides later writes against the policy earlier ones\n\t* install, so a batch would decide them all against the policy as it stood\n\t* before the batch.\n\t* - The document scope is read by every decision model, so writing it is\n\t* writing part of the read set; the per-write conditions would not agree.\n\t*\n\t* A run that fails any of these is executed one write at a time, unchanged.\n\t*/\n\tcanBatch(writes, executing) {\n\t\tif (writes.length < 2) return false;\n\t\tif (executing.evaluatedByPosition || executing.replayingAcceptedHistory) return false;\n\t\tconst scope = executing.job.scope;\n\t\tif (scope === \"auth\" || scope === \"document\") return false;\n\t\treturn writes.every((write) => {\n\t\t\tconst type = write.action.type;\n\t\t\treturn write.skip === 0 && write.deniedReason === void 0 && write.sourceOperation === void 0 && !DOCUMENT_SCOPE_ACTIONS.has(type) && !isUndoRedo(write.action) && type !== \"PRUNE\" && type !== \"NOOP\";\n\t\t});\n\t}\n\t/**\n\t* Decides and reduces a run of writes, then persists them together.\n\t*\n\t* The reduce stays sequential - each action needs the state the one before it\n\t* produced - but the result is threaded in memory rather than read back from\n\t* the cache, and the whole run reaches the store in a single apply.\n\t*\n\t* A write that turns out to be denied abandons the batch and replays the run\n\t* one write at a time, because a denied write holds a position of its own and\n\t* that is the path where the per-write behaviour is load-bearing. A write\n\t* that cannot be prepared fails the job outright: preparing is a read, so the\n\t* replay would only reach the same failure, and the job leaves nothing behind\n\t* either way.\n\t*/\n\tasync executeRegularActionsBatched(writes, executing) {\n\t\tconst prepared = [];\n\t\tlet carried;\n\t\tlet lastYield = performance.now();\n\t\tfor (const write of writes) {\n\t\t\tconst outcome = await this.prepareRegularWrite(write, executing, carried);\n\t\t\tif (\"success\" in outcome) return outcome;\n\t\t\tif (outcome.denied) return this.executeRegularActionsSequentially(writes, executing);\n\t\t\tprepared.push(outcome);\n\t\t\tcarried = outcome.updatedDocument;\n\t\t\tif (performance.now() - lastYield > this.config.yieldDeadlineMs) {\n\t\t\t\tawait yieldToMain();\n\t\t\t\tlastYield = performance.now();\n\t\t\t\tif (executing.signal?.aborted) return buildErrorResult(executing.job, /* @__PURE__ */ new Error(\"Aborted\"), executing.startTime);\n\t\t\t}\n\t\t}\n\t\tif (!this.conditionsAgree(prepared)) return this.executeRegularActionsSequentially(writes, executing);\n\t\treturn this.commitPreparedWrites(prepared, executing);\n\t}\n\t/** Whether every prepared write carries the same read-set condition. */\n\tconditionsAgree(prepared) {\n\t\tconst shape = (write) => write.appendCondition === void 0 ? \"none\" : JSON.stringify([...write.appendCondition.streams].map((stream) => [\n\t\t\tstream.documentId,\n\t\t\tstream.scope,\n\t\t\tstream.branch,\n\t\t\tstream.revision\n\t\t]).sort());\n\t\tconst first = shape(prepared[0]);\n\t\treturn prepared.every((write) => shape(write) === first);\n\t}\n\t/**\n\t* The unbatched path, for a run that turned out not to qualify after its\n\t* writes were prepared. Nothing has been persisted at that point, so\n\t* replaying the whole run per write is safe.\n\t*/\n\tasync executeRegularActionsSequentially(writes, executing) {\n\t\tconst operations = [];\n\t\tconst contexts = [];\n\t\tlet lastYield = performance.now();\n\t\tfor (const write of writes) {\n\t\t\tconst result = await this.executeRegularAction(write, executing);\n\t\t\tif (!result.success) return result;\n\t\t\toperations.push(...result.operations ?? []);\n\t\t\tcontexts.push(...result.operationsWithContext ?? []);\n\t\t\tif (performance.now() - lastYield > this.config.yieldDeadlineMs) {\n\t\t\t\tawait yieldToMain();\n\t\t\t\tlastYield = performance.now();\n\t\t\t\tif (executing.signal?.aborted) return buildErrorResult(executing.job, /* @__PURE__ */ new Error(\"Aborted\"), executing.startTime);\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tjob: executing.job,\n\t\t\tsuccess: true,\n\t\t\toperations,\n\t\t\toperationsWithContext: contexts,\n\t\t\tduration: Date.now() - executing.startTime\n\t\t};\n\t}\n\t/** Decides, reduces and persists one write. */\n\tasync executeRegularAction(write, executing) {\n\t\tconst prepared = await this.prepareRegularWrite(write, executing);\n\t\tif (\"success\" in prepared) return prepared;\n\t\treturn this.commitPreparedWrites([prepared], executing);\n\t}\n\t/**\n\t* Orders a write by timestamp and decides it where it lands. The caller\n\t* supplies the timestamp, so a write can belong before operations already\n\t* stored; those are re-appended alongside it, the way a load reshuffles.\n\t*\n\t* Deciding a backdated write at the stream heads instead of at its position\n\t* would overwrite the verdict every other replica computes for it.\n\t*/\n\tasync positionByTimestamp(job, stores, signal) {\n\t\tconst plain = () => ({\n\t\t\twrites: job.actions.map((action) => ({\n\t\t\t\taction,\n\t\t\t\tskip: 0,\n\t\t\t\tsourceRemote: \"\"\n\t\t\t})),\n\t\t\tevaluatedByPosition: false\n\t\t});\n\t\tif (!this.featureFlags.documentDecisions || job.actions.length === 0) return plain();\n\t\tlet earliest = job.actions[0].timestampUtcMs;\n\t\tlet earliestAt = Date.parse(earliest);\n\t\tfor (const action of job.actions) {\n\t\t\tconst at = Date.parse(action.timestampUtcMs);\n\t\t\tif (at < earliestAt) {\n\t\t\t\tearliest = action.timestampUtcMs;\n\t\t\t\tearliestAt = at;\n\t\t\t}\n\t\t}\n\t\tconst revisions = await stores.operationStore.getRevisions(job.documentId, job.branch, signal);\n\t\tconst backdated = earliestAt < Date.parse(revisions.latestTimestamp);\n\t\tif (this.featureFlags.authEnforcement && job.scope === \"auth\") {\n\t\t\tconst newest = await stores.operationStore.getStreamLatestTimestamp(job.documentId, \"auth\", job.branch, signal);\n\t\t\tconst violation = this.firstNonMonotonicTimestamp(job.actions, newest, job.documentId, job.branch);\n\t\t\tif (violation) return {\n\t\t\t\twrites: [],\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\terror: violation\n\t\t\t};\n\t\t\tif (!backdated) return plain();\n\t\t\treturn this.evaluatePositioned(job, stores, this.appendedOperations(job, revisions.revision[job.scope] ?? 0), signal);\n\t\t}\n\t\tif (!backdated) return plain();\n\t\tconst conflicting = (await stores.operationStore.getConflicting(job.documentId, job.scope, job.branch, earliest, void 0, signal)).results.filter((operation) => !isGenesisOperation(operation));\n\t\tif (conflicting.length === 0) {\n\t\t\tif (!this.featureFlags.authEnforcement) return plain();\n\t\t\treturn this.evaluatePositioned(job, stores, this.appendedOperations(job, revisions.revision[job.scope] ?? 0), signal);\n\t\t}\n\t\tconst nextIndex = revisions.revision[job.scope] ?? 0;\n\t\tlet firstConflicting = conflicting[0].index;\n\t\tfor (const operation of conflicting) if (operation.index < firstConflicting) firstConflicting = operation.index;\n\t\tconst incoming = job.actions.map((action, i) => ({\n\t\t\tid: action.id,\n\t\t\tindex: nextIndex + i,\n\t\t\tskip: 0,\n\t\t\thash: \"\",\n\t\t\ttimestampUtcMs: action.timestampUtcMs,\n\t\t\taction\n\t\t}));\n\t\tconst merged = reshuffleByTimestamp({\n\t\t\tindex: nextIndex,\n\t\t\tskip: retractionSkip(nextIndex, firstConflicting)\n\t\t}, conflicting, incoming);\n\t\tstores.writeCache.invalidate(job.documentId, job.scope, job.branch);\n\t\tif (!this.featureFlags.authEnforcement) return {\n\t\t\twrites: merged.map((operation) => ({\n\t\t\t\taction: operation.action,\n\t\t\t\tskip: operation.skip,\n\t\t\t\tsourceRemote: \"\"\n\t\t\t})),\n\t\t\tevaluatedByPosition: false\n\t\t};\n\t\treturn this.evaluatePositioned(job, stores, merged, signal);\n\t}\n\t/**\n\t* Decides each operation where it lands and carries the verdict on it. A\n\t* refused submitted action is reported to the caller and nothing is stored; a\n\t* refused operation the reshuffle merely moved keeps its verdict, because it\n\t* already holds a position.\n\t*\n\t* The operations carry the indexes and skips they will be stored at, because\n\t* the walk resolves skips before it orders them.\n\t*/\n\tasync evaluatePositioned(job, stores, operations, signal) {\n\t\tconst reasons = await evaluateByPosition(this.decisionModel, {\n\t\t\tdocumentId: job.documentId,\n\t\t\tbranch: job.branch\n\t\t}, {\n\t\t\tscope: job.scope,\n\t\t\toperations\n\t\t}, stores, signal);\n\t\tconst submitted = new Set(job.actions.map((action) => action.id));\n\t\tfor (let i = 0; i < operations.length; i++) {\n\t\t\tconst reason = reasons[i];\n\t\t\tif (reason !== void 0 && submitted.has(operations[i].action.id)) return {\n\t\t\t\twrites: [],\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\terror: refusalError(reason, job.documentId, null, operations[i].action)\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\twrites: operations.map((operation, i) => ({\n\t\t\t\taction: operation.action,\n\t\t\t\tskip: operation.skip,\n\t\t\t\tsourceRemote: \"\",\n\t\t\t\tdeniedReason: reasons[i]\n\t\t\t})),\n\t\t\tevaluatedByPosition: true\n\t\t};\n\t}\n\t/**\n\t* The scopes a re-evaluation pass visits, in a fixed order.\n\t*\n\t* The revisions map comes from a query with no ORDER BY, and the order is\n\t* load-bearing: each scope's pass re-reads the auth stream, and the walk skips\n\t* an operation by its stored denial, so a denial this pass just wrote is\n\t* visible to a later-visited scope and invisible to an earlier one. The model's\n\t* own projection order leads, then the rest sorted, so the pass is reproducible\n\t* across replicas and across runs.\n\t*/\n\tevaluationOrder(target, revision) {\n\t\tconst definition = this.decisionModel(target);\n\t\tconst evaluated = Object.keys(revision).filter((scope) => definition.evaluatesScope(scope));\n\t\tconst leading = [];\n\t\tfor (const stream of staticReadSet(definition)) {\n\t\t\tconst scope = stream.query.scope;\n\t\t\tif (evaluated.includes(scope) && !leading.includes(scope)) leading.push(scope);\n\t\t}\n\t\tconst rest = evaluated.filter((scope) => !leading.includes(scope)).sort((a, b) => a.localeCompare(b));\n\t\treturn [...leading, ...rest];\n\t}\n\t/**\n\t* The first timestamp in the batch that does not strictly exceed everything\n\t* ahead of it, or undefined when the whole batch is monotonic.\n\t*\n\t* The bound is carried forward rather than compared against one stored maximum,\n\t* because a single execute can carry several auth actions stamped in the same\n\t* millisecond. Letting a tie through would store a stream the position walk\n\t* then refuses to read, with no repair path.\n\t*/\n\tfirstNonMonotonicTimestamp(entries, newest, documentId, branch) {\n\t\tlet boundIso = newest;\n\t\tlet bound = newest === void 0 ? Number.NEGATIVE_INFINITY : Date.parse(newest);\n\t\tfor (const entry of entries) {\n\t\t\tif (!isValidISOTimestamp(entry.timestampUtcMs)) return new InvalidOperationTimestampError(documentId, \"auth\", entry.timestampUtcMs, \"auth operation\");\n\t\t\tconst at = Date.parse(entry.timestampUtcMs);\n\t\t\tif (boundIso !== void 0 && at <= bound) return new AuthTimestampNotMonotonicError(documentId, branch, entry.timestampUtcMs, boundIso);\n\t\t\tbound = at;\n\t\t\tboundIso = entry.timestampUtcMs;\n\t\t}\n\t}\n\t/** The operations a batch of submitted actions appends at the scope's tail. */\n\tappendedOperations(job, nextIndex) {\n\t\treturn job.actions.map((action, i) => ({\n\t\t\tid: action.id,\n\t\t\tindex: nextIndex + i,\n\t\t\tskip: 0,\n\t\t\thash: \"\",\n\t\t\ttimestampUtcMs: action.timestampUtcMs,\n\t\t\taction\n\t\t}));\n\t}\n\t/**\n\t* Re-evaluates the document when a write meets both criteria: it was written\n\t* to a stream the model reads, and it is timestamped before an operation\n\t* already stored. The caller supplies the timestamp and the reactor does not replace\n\t* it, so a mutation job can write such an operation just as a load job can,\n\t* which is why both executeJob and executeLoadJob call this.\n\t*/\n\tasync reevaluateIfCriteriaMet(criteria, executing) {\n\t\tif (!this.featureFlags.documentDecisions) return;\n\t\tconst { job, stores, signal } = executing;\n\t\tconst target = {\n\t\t\tdocumentId: job.documentId,\n\t\t\tbranch: job.branch\n\t\t};\n\t\tif (!staticReadSet(this.decisionModel(target)).some((stream) => stream.query.documentId === job.documentId && stream.query.scope === criteria.scope && stream.query.branch === job.branch)) return;\n\t\tconst revisions = await stores.operationStore.getRevisions(job.documentId, job.branch, signal);\n\t\tconst latest = Date.parse(revisions.latestTimestamp);\n\t\tif (!criteria.operations.some((operation) => Date.parse(operation.timestampUtcMs) < latest)) return;\n\t\treturn (await this.reevaluateDocument(executing)).error;\n\t}\n\t/**\n\t* Re-evaluates every scope the model evaluates. Where an operation's\n\t* evaluation differs from what is stored, the tail from that operation is\n\t* re-appended, carrying a skip that spans the indices it supersedes.\n\t*/\n\tasync reevaluateDocument(executing) {\n\t\tconst { job, stores, signal } = executing;\n\t\tconst target = {\n\t\t\tdocumentId: job.documentId,\n\t\t\tbranch: job.branch\n\t\t};\n\t\tconst reappended = [];\n\t\tconst revisions = await stores.operationStore.getRevisions(job.documentId, job.branch, signal);\n\t\tfor (const scope of this.evaluationOrder(target, revisions.revision)) {\n\t\t\tconst stored = (await stores.operationStore.getSince(job.documentId, scope, job.branch, -1, void 0, void 0, signal)).results;\n\t\t\tconst effective = garbageCollect(sortOperations([...stored]));\n\t\t\tif (effective.length === 0) continue;\n\t\t\tconst reevaluated = await evaluateByPosition(this.decisionModel, target, {\n\t\t\t\tscope,\n\t\t\t\toperations: effective\n\t\t\t}, stores, signal);\n\t\t\tconst firstChange = effective.findIndex((operation, i) => operation.deniedReason !== reevaluated[i]);\n\t\t\tif (firstChange === -1) continue;\n\t\t\tconst tail = effective.slice(firstChange);\n\t\t\tconst nextIndex = revisions.revision[scope];\n\t\t\tstores.writeCache.invalidate(job.documentId, scope, job.branch);\n\t\t\tconst result = await this.processActions(tail.map((operation, i) => ({\n\t\t\t\taction: operation.action,\n\t\t\t\tskip: i === 0 ? retractionSkip(nextIndex, tail[0].index) : 0,\n\t\t\t\tsourceRemote: \"\",\n\t\t\t\tdeniedReason: reevaluated[firstChange + i]\n\t\t\t})), {\n\t\t\t\t...executing,\n\t\t\t\tjob: {\n\t\t\t\t\t...job,\n\t\t\t\t\tscope\n\t\t\t\t},\n\t\t\t\treplayingAcceptedHistory: true,\n\t\t\t\tevaluatedByPosition: true\n\t\t\t});\n\t\t\tif (!result.success) return {\n\t\t\t\terror: result.error ?? /* @__PURE__ */ new Error(`Re-evaluation of ${job.documentId} ${scope} failed`),\n\t\t\t\toperationsWithContext: reappended\n\t\t\t};\n\t\t\treappended.push(...result.operationsWithContext);\n\t\t}\n\t\treturn { operationsWithContext: reappended };\n\t}\n\t/**\n\t* Re-judges a document's stored operations because a read-set stream in\n\t* another document (a group) gained an operation. The trigger timestamp\n\t* bounds the work: an operation later than everything this document holds\n\t* cannot change any evaluation, so the pass is skipped.\n\t*/\n\tasync executeReevaluationJob(executing) {\n\t\tconst { job, startTime, stores, signal } = executing;\n\t\tif (!this.featureFlags.documentDecisions) return {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: [],\n\t\t\toperationsWithContext: [],\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tconst trigger = job.meta.triggerTimestampUtcMs;\n\t\tif (typeof trigger === \"string\") {\n\t\t\tlet latestTimestamp;\n\t\t\ttry {\n\t\t\t\tlatestTimestamp = (await stores.operationStore.getRevisions(job.documentId, job.branch, signal)).latestTimestamp;\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tjob,\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\toperations: [],\n\t\t\t\t\toperationsWithContext: [],\n\t\t\t\t\tduration: Date.now() - startTime\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (Date.parse(trigger) > Date.parse(latestTimestamp)) return {\n\t\t\t\tjob,\n\t\t\t\tsuccess: true,\n\t\t\t\toperations: [],\n\t\t\t\toperationsWithContext: [],\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst outcome = await this.reevaluateDocument(executing);\n\t\tif (outcome.error) return buildErrorResult(job, outcome.error, startTime);\n\t\treturn {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: outcome.operationsWithContext.map((owc) => owc.operation),\n\t\t\toperationsWithContext: outcome.operationsWithContext,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t}\n\tasync executeLoadJob(executing) {\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tif (job.operations.length === 0) return buildErrorResult(job, /* @__PURE__ */ new Error(\"Load job must include at least one operation\"), startTime);\n\t\tlet docMeta;\n\t\ttry {\n\t\t\tdocMeta = await stores.documentMetaCache.getDocumentMeta(job.documentId, job.branch, signal);\n\t\t} catch {}\n\t\tif (docMeta?.state.isDeleted && !this.featureFlags.documentDecisions) return buildErrorResult(job, new DocumentDeletedError(job.documentId, docMeta.state.deletedAtUtcIso), startTime);\n\t\tconst scope = job.scope;\n\t\tconst monotonicAuthStream = this.featureFlags.authEnforcement && scope === \"auth\";\n\t\tlet latestRevision;\n\t\ttry {\n\t\t\tlatestRevision = (await stores.operationStore.getRevisions(job.documentId, job.branch, signal)).revision[scope] ?? 0;\n\t\t} catch {\n\t\t\tlatestRevision = 0;\n\t\t}\n\t\tfor (const operation of job.operations) if (operation.timestampUtcMs && !isValidISOTimestamp(operation.timestampUtcMs)) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: new InvalidOperationTimestampError(job.documentId, scope, operation.timestampUtcMs, `operation (index: ${operation.index})`),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tlet minIncomingIndex = Number.POSITIVE_INFINITY;\n\t\tlet minIncomingTimestamp = job.operations[0]?.timestampUtcMs || \"\";\n\t\tfor (const operation of job.operations) {\n\t\t\tminIncomingIndex = Math.min(minIncomingIndex, operation.index);\n\t\t\tconst ts = operation.timestampUtcMs || \"\";\n\t\t\tif (Date.parse(ts) < Date.parse(minIncomingTimestamp)) minIncomingTimestamp = ts;\n\t\t}\n\t\tlet conflictingOps;\n\t\ttry {\n\t\t\tconflictingOps = (await stores.operationStore.getConflicting(job.documentId, scope, job.branch, minIncomingTimestamp, void 0, signal)).results;\n\t\t} catch {\n\t\t\tconflictingOps = [];\n\t\t}\n\t\tlet allOpsFromMinConflictingIndex = conflictingOps;\n\t\tif (conflictingOps.length > 0) {\n\t\t\tconst minConflictingIndex = Math.min(...conflictingOps.map((op) => op.index));\n\t\t\ttry {\n\t\t\t\tallOpsFromMinConflictingIndex = (await stores.operationStore.getSince(job.documentId, scope, job.branch, minConflictingIndex - 1, void 0, void 0, signal)).results;\n\t\t\t} catch {\n\t\t\t\tallOpsFromMinConflictingIndex = conflictingOps;\n\t\t\t}\n\t\t}\n\t\tconst incomingActionIds = new Set(job.operations.map((op) => op.action.id));\n\t\tconst nonSupersededOps = conflictingOps.filter((op) => {\n\t\t\tif (op.index < minIncomingIndex && !incomingActionIds.has(op.action.id)) return false;\n\t\t\tfor (const laterOp of allOpsFromMinConflictingIndex) if (laterOp.index > op.index && laterOp.skip > 0) {\n\t\t\t\tif (laterOp.index - laterOp.skip <= op.index) return false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\tconst existingOpsToReshuffle = monotonicAuthStream ? [] : nonSupersededOps.filter((operation) => !isGenesisOperation(operation));\n\t\tconst actionIdCounts = /* @__PURE__ */ new Map();\n\t\tfor (const operation of allOpsFromMinConflictingIndex) actionIdCounts.set(operation.action.id, (actionIdCounts.get(operation.action.id) ?? 0) + 1);\n\t\tconst reshuffleCost = existingOpsToReshuffle.filter((operation) => (actionIdCounts.get(operation.action.id) ?? 0) < 2).length;\n\t\tif (reshuffleCost > this.config.maxSkipThreshold) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: new ExcessiveReshuffleError(job.documentId, scope, reshuffleCost, this.config.maxSkipThreshold),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tlet skipCount = existingOpsToReshuffle.length;\n\t\tif (existingOpsToReshuffle.length > 0) {\n\t\t\tlet minLogicalIndex = Number.POSITIVE_INFINITY;\n\t\t\tfor (const op of existingOpsToReshuffle) {\n\t\t\t\tconst logical = op.index - op.skip;\n\t\t\t\tif (logical < minLogicalIndex) minLogicalIndex = logical;\n\t\t\t}\n\t\t\tconst logicalSkip = latestRevision - minLogicalIndex;\n\t\t\tif (logicalSkip > skipCount) skipCount = logicalSkip;\n\t\t}\n\t\tconst existingActionIds = new Set(nonSupersededOps.map((op) => op.action.id));\n\t\tconst seenIncomingActionIds = /* @__PURE__ */ new Set();\n\t\tconst incomingOpsToApply = job.operations.filter((op) => {\n\t\t\tif (existingActionIds.has(op.action.id)) return false;\n\t\t\tif (seenIncomingActionIds.has(op.action.id)) return false;\n\t\t\tseenIncomingActionIds.add(op.action.id);\n\t\t\treturn true;\n\t\t});\n\t\tif (incomingOpsToApply.length === 0) return {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: [],\n\t\t\toperationsWithContext: [],\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tif (monotonicAuthStream) {\n\t\t\tconst newest = await stores.operationStore.getStreamLatestTimestamp(job.documentId, \"auth\", job.branch, signal);\n\t\t\tconst violation = this.firstNonMonotonicTimestamp([...incomingOpsToApply].sort((a, b) => a.index - b.index), newest, job.documentId, job.branch);\n\t\t\tif (violation) return {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: violation,\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst reshuffledOperations = existingOpsToReshuffle.length === 0 && skipCount === 0 ? incomingOpsToApply.slice().sort((a, b) => a.index - b.index).map((operation, i) => ({\n\t\t\t...operation,\n\t\t\tindex: latestRevision + i\n\t\t})) : reshuffleByTimestamp({\n\t\t\tindex: latestRevision,\n\t\t\tskip: skipCount\n\t\t}, existingOpsToReshuffle, incomingOpsToApply.map((operation) => ({\n\t\t\t...operation,\n\t\t\tid: operation.id\n\t\t})));\n\t\tfor (const operation of reshuffledOperations) if (operation.action.type === \"NOOP\" && operation.skip === 0) operation.skip = 1;\n\t\tlet deniedReasons;\n\t\tif (this.featureFlags.documentDecisions) try {\n\t\t\tdeniedReasons = await evaluateByPosition(this.decisionModel, {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tbranch: job.branch\n\t\t\t}, {\n\t\t\t\tscope,\n\t\t\t\toperations: reshuffledOperations\n\t\t\t}, stores, signal);\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: error instanceof Error ? error : new Error(String(error)),\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst effectiveSourceRemote = skipCount > 0 ? \"\" : job.meta.sourceRemote || \"\";\n\t\tconst result = await this.processActions(reshuffledOperations.map((operation, i) => ({\n\t\t\taction: operation.action,\n\t\t\tskip: operation.skip,\n\t\t\tsourceOperation: operation,\n\t\t\tsourceRemote: effectiveSourceRemote,\n\t\t\tdeniedReason: deniedReasons?.[i]\n\t\t})), executing);\n\t\tif (!result.success) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: result.error,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tstores.writeCache.invalidate(job.documentId, scope, job.branch);\n\t\tif (scope === \"document\") stores.documentMetaCache.invalidate(job.documentId, job.branch);\n\t\tconst reevaluationError = await this.reevaluateIfCriteriaMet({\n\t\t\tscope,\n\t\t\toperations: result.generatedOperations\n\t\t}, executing);\n\t\tif (reevaluationError) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: reevaluationError,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\treturn {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: result.generatedOperations,\n\t\t\toperationsWithContext: result.operationsWithContext,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t}\n\taccumulateResultOrReturnError(result, generatedOperations, operationsWithContext) {\n\t\tif (!result.success) return result;\n\t\tif (result.operations && result.operations.length > 0) generatedOperations.push(...result.operations);\n\t\tif (result.operationsWithContext) operationsWithContext.push(...result.operationsWithContext);\n\t\treturn null;\n\t}\n};\n//#endregion\n//#region src/registry/implementation.ts\n/**\n* In-memory implementation of the IDocumentModelRegistry interface.\n* Manages document model modules with version-aware storage and upgrade manifest support.\n*/\nvar DocumentModelRegistry = class {\n\tmodules = [];\n\tmanifests = [];\n\tregisterModules(...modules) {\n\t\treturn modules.map((module) => {\n\t\t\ttry {\n\t\t\t\tconst documentType = module.documentModel.global.id;\n\t\t\t\tconst version = module.version ?? 1;\n\t\t\t\tfor (let i = 0; i < this.modules.length; i++) {\n\t\t\t\t\tconst existing = this.modules[i];\n\t\t\t\t\tconst existingType = existing.documentModel.global.id;\n\t\t\t\t\tconst existingVersion = existing.version ?? 1;\n\t\t\t\t\tif (existingType === documentType && existingVersion === version) throw new DuplicateModuleError(documentType, version);\n\t\t\t\t}\n\t\t\t\tthis.modules.push(module);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\titem: module\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\titem: module,\n\t\t\t\t\terror: error instanceof Error ? error : new Error(String(error))\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\tunregisterModules(...documentTypes) {\n\t\tlet allFound = true;\n\t\tfor (const documentType of documentTypes) {\n\t\t\tif (!this.modules.some((m) => m.documentModel.global.id === documentType)) allFound = false;\n\t\t\tthis.modules = this.modules.filter((m) => m.documentModel.global.id !== documentType);\n\t\t}\n\t\treturn allFound;\n\t}\n\tgetModule(documentType, version) {\n\t\tlet latestModule;\n\t\tlet latestVersion = -1;\n\t\tfor (let i = 0; i < this.modules.length; i++) {\n\t\t\tconst module = this.modules[i];\n\t\t\tconst moduleType = module.documentModel.global.id;\n\t\t\tconst moduleVersion = module.version ?? 1;\n\t\t\tif (moduleType === documentType) {\n\t\t\t\tif (version !== void 0 && moduleVersion === version) return module;\n\t\t\t\tif (moduleVersion > latestVersion) {\n\t\t\t\t\tlatestModule = module;\n\t\t\t\t\tlatestVersion = moduleVersion;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (version === void 0 && latestModule !== void 0) return latestModule;\n\t\tthrow new ModuleNotFoundError(documentType, version);\n\t}\n\tgetAllModules() {\n\t\treturn [...this.modules];\n\t}\n\tclear() {\n\t\tthis.modules = [];\n\t\tthis.manifests = [];\n\t}\n\tgetSupportedVersions(documentType) {\n\t\tconst versions = [];\n\t\tfor (const module of this.modules) if (module.documentModel.global.id === documentType) versions.push(module.version ?? 1);\n\t\tif (versions.length === 0) throw new ModuleNotFoundError(documentType);\n\t\treturn versions.sort((a, b) => a - b);\n\t}\n\tgetLatestVersion(documentType) {\n\t\tlet latest = -1;\n\t\tlet found = false;\n\t\tfor (const module of this.modules) if (module.documentModel.global.id === documentType) {\n\t\t\tfound = true;\n\t\t\tconst version = module.version ?? 1;\n\t\t\tif (version > latest) latest = version;\n\t\t}\n\t\tif (!found) throw new ModuleNotFoundError(documentType);\n\t\treturn latest;\n\t}\n\tregisterUpgradeManifests(...manifestsToRegister) {\n\t\treturn manifestsToRegister.map((manifestToRegister) => {\n\t\t\ttry {\n\t\t\t\tif (!manifestToRegister.documentType) throw new Error(\"Upgrade manifest is missing a documentType\");\n\t\t\t\tfor (const registeredManifest of this.manifests) if (registeredManifest.documentType === manifestToRegister.documentType) throw new DuplicateManifestError(manifestToRegister.documentType);\n\t\t\t\tthis.manifests.push(manifestToRegister);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\titem: manifestToRegister\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\titem: manifestToRegister,\n\t\t\t\t\terror: error instanceof Error ? error : new Error(String(error))\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\tunregisterUpgradeManifests(...documentTypes) {\n\t\tlet allFound = true;\n\t\tfor (const documentType of documentTypes) {\n\t\t\tif (!this.manifests.some((m) => m.documentType === documentType)) allFound = false;\n\t\t\tthis.manifests = this.manifests.filter((m) => m.documentType !== documentType);\n\t\t}\n\t\treturn allFound;\n\t}\n\tgetUpgradeManifest(documentType) {\n\t\tfor (let i = 0; i < this.manifests.length; i++) if (this.manifests[i].documentType === documentType) return this.manifests[i];\n\t\tthrow new ManifestNotFoundError(documentType);\n\t}\n\tcomputeUpgradePath(documentType, fromVersion, toVersion) {\n\t\tif (fromVersion === toVersion) return [];\n\t\tif (toVersion < fromVersion) throw new DowngradeNotSupportedError$1(documentType, fromVersion, toVersion);\n\t\tconst manifest = this.getUpgradeManifest(documentType);\n\t\tconst path = [];\n\t\tfor (let v = fromVersion + 1; v <= toVersion; v++) {\n\t\t\tconst key = `v${v}`;\n\t\t\tif (!(key in manifest.upgrades)) throw new MissingUpgradeTransitionError(documentType, v - 1, v);\n\t\t\tconst transition = manifest.upgrades[key];\n\t\t\tpath.push(transition);\n\t\t}\n\t\treturn path;\n\t}\n\tgetUpgradeReducer(documentType, fromVersion, toVersion) {\n\t\tif (toVersion !== fromVersion + 1) throw new InvalidUpgradeStepError(documentType, fromVersion, toVersion);\n\t\tconst manifest = this.getUpgradeManifest(documentType);\n\t\tconst key = `v${toVersion}`;\n\t\tif (!(key in manifest.upgrades)) throw new MissingUpgradeTransitionError(documentType, fromVersion, toVersion);\n\t\treturn manifest.upgrades[key].upgradeReducer;\n\t}\n};\n//#endregion\n//#region src/storage/kysely/keyframe-store.ts\nvar KyselyKeyframeStore = class KyselyKeyframeStore {\n\ttrx;\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tget queryExecutor() {\n\t\treturn this.trx ?? this.db;\n\t}\n\twithTransaction(trx) {\n\t\tconst instance = new KyselyKeyframeStore(this.db);\n\t\tinstance.trx = trx;\n\t\treturn instance;\n\t}\n\tasync putKeyframe(documentId, scope, branch, revision, document, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.queryExecutor.insertInto(\"Keyframe\").values({\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope,\n\t\t\tbranch,\n\t\t\trevision,\n\t\t\tdocument\n\t\t}).onConflict((oc) => oc.columns([\n\t\t\t\"documentId\",\n\t\t\t\"scope\",\n\t\t\t\"branch\",\n\t\t\t\"revision\"\n\t\t]).doUpdateSet({ document })).execute();\n\t}\n\tasync findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst row = await this.queryExecutor.selectFrom(\"Keyframe\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"revision\", \"<=\", targetRevision).orderBy(\"revision\", \"desc\").limit(1).executeTakeFirst();\n\t\tif (!row) return;\n\t\treturn {\n\t\t\trevision: row.revision,\n\t\t\tdocument: row.document\n\t\t};\n\t}\n\tasync listKeyframes(documentId, scope, branch, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tlet query = this.queryExecutor.selectFrom(\"Keyframe\").selectAll().where(\"documentId\", \"=\", documentId).orderBy(\"revision\", \"asc\");\n\t\tif (scope !== void 0) query = query.where(\"scope\", \"=\", scope);\n\t\tif (branch !== void 0) query = query.where(\"branch\", \"=\", branch);\n\t\treturn (await query.execute()).map((row) => ({\n\t\t\tscope: row.scope,\n\t\t\tbranch: row.branch,\n\t\t\trevision: row.revision,\n\t\t\tdocument: row.document\n\t\t}));\n\t}\n\tasync deleteKeyframes(documentId, scope, branch, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tlet query = this.queryExecutor.deleteFrom(\"Keyframe\").where(\"documentId\", \"=\", documentId);\n\t\tif (scope !== void 0 && branch !== void 0) query = query.where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch);\n\t\telse if (scope !== void 0) query = query.where(\"scope\", \"=\", scope);\n\t\tconst result = await query.executeTakeFirst();\n\t\treturn Number(result.numDeletedRows || 0n);\n\t}\n};\n//#endregion\n//#region src/storage/kysely/pagination.ts\nconst DEFAULT_LIMIT = 100;\nfunction paginateRows(rows, paging, cursorOf, toItem, refetch) {\n\tlet hasMore = false;\n\tlet items = rows;\n\tif (paging?.limit && rows.length > paging.limit) {\n\t\thasMore = true;\n\t\titems = rows.slice(0, paging.limit);\n\t}\n\tconst nextCursor = hasMore && items.length > 0 ? cursorOf(items[items.length - 1]).toString() : void 0;\n\tconst cursor = paging?.cursor || \"0\";\n\tconst limit = paging?.limit || DEFAULT_LIMIT;\n\treturn {\n\t\tresults: items.map(toItem),\n\t\toptions: {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t},\n\t\tnextCursor,\n\t\tnext: hasMore ? () => refetch(nextCursor, limit) : void 0\n\t};\n}\n//#endregion\n//#region src/storage/txn.ts\nvar AtomicTransaction = class {\n\toperations = [];\n\tconstructor(documentId, documentType, scope, branch, baseRevision) {\n\t\tthis.documentId = documentId;\n\t\tthis.documentType = documentType;\n\t\tthis.scope = scope;\n\t\tthis.branch = branch;\n\t\tthis.baseRevision = baseRevision;\n\t}\n\taddOperations(...operations) {\n\t\tfor (const op of operations) this.operations.push({\n\t\t\tjobId: v4(),\n\t\t\topId: op.id,\n\t\t\tprevOpId: \"\",\n\t\t\tdocumentId: this.documentId,\n\t\t\tdocumentType: this.documentType,\n\t\t\tscope: this.scope,\n\t\t\tbranch: this.branch,\n\t\t\ttimestampUtcMs: new Date(op.timestampUtcMs),\n\t\t\tindex: op.index,\n\t\t\taction: JSON.stringify(op.action),\n\t\t\tskip: op.skip,\n\t\t\terror: op.error || null,\n\t\t\tdeniedReason: op.deniedReason || null,\n\t\t\thash: op.hash\n\t\t});\n\t}\n\tgetOperations() {\n\t\treturn this.operations;\n\t}\n};\n//#endregion\n//#region src/storage/kysely/store.ts\nvar _UniqueConstraintContext = class extends Error {\n\tconstructor(documentId, scope, branch, revision, stagedOps) {\n\t\tsuper(\"unique constraint\");\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.branch = branch;\n\t\tthis.revision = revision;\n\t\tthis.stagedOps = stagedOps;\n\t\tthis.name = \"UniqueConstraintContext\";\n\t}\n};\nvar KyselyOperationStore = class KyselyOperationStore {\n\ttrx;\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tget queryExecutor() {\n\t\treturn this.trx ?? this.db;\n\t}\n\twithTransaction(trx) {\n\t\tconst instance = new KyselyOperationStore(this.db);\n\t\tinstance.trx = trx;\n\t\treturn instance;\n\t}\n\tasync apply(documentId, documentType, scope, branch, revision, fn, signal, condition) {\n\t\tif (this.trx) {\n\t\t\tlet executeResult = null;\n\t\t\tlet uniqueCtx = null;\n\t\t\ttry {\n\t\t\t\texecuteResult = await this.executeApply(this.trx, documentId, documentType, scope, branch, revision, fn, signal, condition);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof _UniqueConstraintContext) uniqueCtx = error;\n\t\t\t\telse throw error;\n\t\t\t}\n\t\t\tif (uniqueCtx !== null) return this.resolveUniqueConstraint(uniqueCtx);\n\t\t\treturn executeResult;\n\t\t} else {\n\t\t\tlet transactionResult = null;\n\t\t\tlet uniqueCtx = null;\n\t\t\ttry {\n\t\t\t\ttransactionResult = await this.db.transaction().execute(async (trx) => {\n\t\t\t\t\treturn this.executeApply(trx, documentId, documentType, scope, branch, revision, fn, signal, condition);\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof _UniqueConstraintContext) uniqueCtx = error;\n\t\t\t\telse throw error;\n\t\t\t}\n\t\t\tif (uniqueCtx !== null) return this.resolveUniqueConstraint(uniqueCtx);\n\t\t\treturn transactionResult;\n\t\t}\n\t}\n\tasync resolveUniqueConstraint(ctx) {\n\t\tlet replayOps = null;\n\t\ttry {\n\t\t\treplayOps = await this.findIdempotentReplay(this.db, ctx.documentId, ctx.scope, ctx.branch, ctx.revision, ctx.stagedOps);\n\t\t} catch {}\n\t\tif (replayOps !== null) return replayOps;\n\t\tconst op = ctx.stagedOps[0];\n\t\tthrow new DuplicateOperationError(`${op.opId} at index ${op.index} with skip ${op.skip}`);\n\t}\n\tasync executeApply(trx, documentId, documentType, scope, branch, revision, fn, signal, condition) {\n\t\tthrowIfAborted(signal);\n\t\tconst atomicTxn = new AtomicTransaction(documentId, documentType, scope, branch, revision);\n\t\tawait fn(atomicTxn);\n\t\tconst operations = atomicTxn.getOperations();\n\t\tif (operations.length === 0) return [];\n\t\tif (condition) await this.acquireStreamLocks(trx, documentId, scope, branch, condition);\n\t\tconst latestOp = await trx.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).orderBy(\"index\", \"desc\").limit(1).executeTakeFirst();\n\t\tconst currentRevision = latestOp ? latestOp.index : -1;\n\t\tif (currentRevision !== revision - 1) {\n\t\t\tlet replayOps = null;\n\t\t\ttry {\n\t\t\t\treplayOps = await this.findIdempotentReplay(trx, documentId, scope, branch, revision, operations);\n\t\t\t} catch {}\n\t\t\tif (replayOps !== null) return replayOps;\n\t\t\tif (revision === 0 && this.isCreate(operations)) throw new DocumentAlreadyExistsError(documentId, scope, currentRevision);\n\t\t\tthrow new RevisionMismatchError(currentRevision + 1, revision);\n\t\t}\n\t\tlet prevOpId = latestOp?.opId || \"\";\n\t\tfor (const op of operations) {\n\t\t\top.prevOpId = prevOpId;\n\t\t\tprevOpId = op.opId;\n\t\t}\n\t\tlet insertedCount = operations.length;\n\t\ttry {\n\t\t\tif (condition && condition.streams.length > 0) insertedCount = await this.insertGuarded(trx, operations, condition);\n\t\t\telse await trx.insertInto(\"Operation\").values(operations).execute();\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.includes(\"unique constraint\")) throw new _UniqueConstraintContext(documentId, scope, branch, revision, operations);\n\t\t\tthrow error;\n\t\t}\n\t\tif (insertedCount !== operations.length) throw new AppendConditionFailedError(condition);\n\t\treturn operations.map((op) => ({\n\t\t\tindex: op.index,\n\t\t\ttimestampUtcMs: op.timestampUtcMs.toISOString(),\n\t\t\thash: op.hash,\n\t\t\tskip: op.skip,\n\t\t\terror: op.error || void 0,\n\t\t\tdeniedReason: op.deniedReason || void 0,\n\t\t\tid: op.opId,\n\t\t\taction: JSON.parse(op.action)\n\t\t}));\n\t}\n\t/**\n\t* Locks the written stream and every read-set stream, in sorted key order\n\t* so that overlapping concurrent appends serialize rather than deadlock.\n\t* The locks are still taken one row at a time, so the query preserves that\n\t* order. It must stay separate from the guarded insert, which would\n\t* otherwise read a snapshot taken before the locks were held.\n\t*/\n\tasync acquireStreamLocks(trx, documentId, scope, branch, condition) {\n\t\tconst keys = new Set([`${documentId}:${scope}:${branch}`]);\n\t\tfor (const stream of condition.streams) keys.add(`${stream.documentId}:${stream.scope}:${stream.branch}`);\n\t\tawait sql`\n with ordered as materialized (\n select key\n from unnest(array[${sql.join([...keys].sort())}]::text[]) with ordinality as t(key, ord)\n order by ord\n )\n select pg_advisory_xact_lock(hashtext(key)) from ordered\n `.execute(trx);\n\t}\n\t/**\n\t* Inserts the staged operations with the condition compiled in as a WHERE\n\t* NOT EXISTS guard, making the check and the append one statement. Returns\n\t* the rows inserted; zero means the guard failed and nothing was written.\n\t*/\n\tasync insertGuarded(trx, operations, condition) {\n\t\tconst branches = operations.map((op) => trx.selectNoFrom([\n\t\t\tsql`${op.jobId}::text`.as(\"jobId\"),\n\t\t\tsql`${op.opId}::text`.as(\"opId\"),\n\t\t\tsql`${op.prevOpId}::text`.as(\"prevOpId\"),\n\t\t\tsql`${op.documentId}::text`.as(\"documentId\"),\n\t\t\tsql`${op.documentType}::text`.as(\"documentType\"),\n\t\t\tsql`${op.scope}::text`.as(\"scope\"),\n\t\t\tsql`${op.branch}::text`.as(\"branch\"),\n\t\t\tsql`${op.timestampUtcMs}::timestamptz`.as(\"timestampUtcMs\"),\n\t\t\tsql`${op.index}::integer`.as(\"index\"),\n\t\t\tsql`${op.action}::jsonb`.as(\"action\"),\n\t\t\tsql`${op.skip}::integer`.as(\"skip\"),\n\t\t\tsql`${op.error ?? null}::text`.as(\"error\"),\n\t\t\tsql`${op.deniedReason ?? null}::text`.as(\"deniedReason\"),\n\t\t\tsql`${op.hash}::text`.as(\"hash\")\n\t\t]).where((eb) => eb.not(eb.exists(eb.selectFrom(\"Operation\").select(\"Operation.id\").where((web) => web.or(condition.streams.map((s) => web.and([\n\t\t\tweb(\"Operation.documentId\", \"=\", s.documentId),\n\t\t\tweb(\"Operation.scope\", \"=\", s.scope),\n\t\t\tweb(\"Operation.branch\", \"=\", s.branch),\n\t\t\tweb(\"Operation.index\", \">\", s.revision)\n\t\t]))))))));\n\t\tlet expression = branches[0];\n\t\tfor (let i = 1; i < branches.length; i++) expression = expression.unionAll(branches[i]);\n\t\treturn (await trx.insertInto(\"Operation\").columns([\n\t\t\t\"jobId\",\n\t\t\t\"opId\",\n\t\t\t\"prevOpId\",\n\t\t\t\"documentId\",\n\t\t\t\"documentType\",\n\t\t\t\"scope\",\n\t\t\t\"branch\",\n\t\t\t\"timestampUtcMs\",\n\t\t\t\"index\",\n\t\t\t\"action\",\n\t\t\t\"skip\",\n\t\t\t\"error\",\n\t\t\t\"deniedReason\",\n\t\t\t\"hash\"\n\t\t]).expression(expression).returning(\"id\").execute()).length;\n\t}\n\tasync findIdempotentReplay(executor, documentId, scope, branch, revision, stagedOps) {\n\t\tconst minIndex = revision;\n\t\tconst maxIndex = revision + stagedOps.length - 1;\n\t\tconst storedRows = await executor.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"index\", \">=\", minIndex).where(\"index\", \"<=\", maxIndex).orderBy(\"index\", \"asc\").execute();\n\t\tif (storedRows.length !== stagedOps.length) return null;\n\t\tfor (let i = 0; i < stagedOps.length; i++) {\n\t\t\tconst staged = stagedOps[i];\n\t\t\tconst stored = storedRows[i];\n\t\t\tif (stored.opId !== staged.opId || stored.index !== staged.index || stored.skip !== staged.skip) return null;\n\t\t}\n\t\treturn storedRows.map((row) => this.rowToOperation(row));\n\t}\n\t/** True when the staged write creates a document rather than appending to one. */\n\tisCreate(operations) {\n\t\tfor (const operation of operations) {\n\t\t\tlet action = operation.action;\n\t\t\tif (typeof action === \"string\") try {\n\t\t\t\taction = JSON.parse(action);\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (typeof action === \"object\" && action !== null && \"type\" in action && typeof action.type === \"string\" && action.type === \"CREATE_DOCUMENT\") return true;\n\t\t}\n\t\treturn false;\n\t}\n\tasync getSince(documentId, scope, branch, revision, filter, paging, signal) {\n\t\tthrowIfAborted(signal);\n\t\tlet query = this.queryExecutor.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"index\", \">\", revision).orderBy(\"index\", \"asc\");\n\t\tif (filter) {\n\t\t\tif (filter.actionTypes && filter.actionTypes.length > 0) {\n\t\t\t\tconst actionTypesArray = filter.actionTypes.map((t) => `'${t.replace(/'/g, \"''\")}'`).join(\",\");\n\t\t\t\tquery = query.where(sql`action->>'type' = ANY(ARRAY[${sql.raw(actionTypesArray)}]::text[])`);\n\t\t\t}\n\t\t\tif (filter.timestampFrom) query = query.where(\"timestampUtcMs\", \">=\", new Date(filter.timestampFrom));\n\t\t\tif (filter.timestampTo) query = query.where(\"timestampUtcMs\", \"<=\", new Date(filter.timestampTo));\n\t\t\tif (filter.sinceRevision !== void 0) query = query.where(\"index\", \">=\", filter.sinceRevision);\n\t\t}\n\t\tif (paging) {\n\t\t\tconst cursorValue = Number.parseInt(paging.cursor, 10);\n\t\t\tif (cursorValue > 0) query = query.where(\"index\", \">\", cursorValue);\n\t\t\tif (paging.limit) query = query.limit(paging.limit + 1);\n\t\t}\n\t\treturn paginateRows(await query.execute(), paging, (row) => row.index, (row) => this.rowToOperation(row), (cursor, limit) => this.getSince(documentId, scope, branch, revision, filter, {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t}, signal));\n\t}\n\tasync getSinceId(id, paging, signal) {\n\t\tthrowIfAborted(signal);\n\t\tlet query = this.queryExecutor.selectFrom(\"Operation\").selectAll().where(\"id\", \">\", id).orderBy(\"id\", \"asc\");\n\t\tif (paging) {\n\t\t\tconst cursorValue = Number.parseInt(paging.cursor, 10);\n\t\t\tif (cursorValue > 0) query = query.where(\"id\", \">\", cursorValue);\n\t\t\tif (paging.limit) query = query.limit(paging.limit + 1);\n\t\t}\n\t\treturn paginateRows(await query.execute(), paging, (row) => row.id, (row) => this.rowToOperationWithContext(row), (cursor, limit) => this.getSinceId(id, {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t}, signal));\n\t}\n\tasync getConflicting(documentId, scope, branch, minTimestamp, paging, signal) {\n\t\tthrowIfAborted(signal);\n\t\tlet query = this.queryExecutor.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"timestampUtcMs\", \">=\", new Date(minTimestamp)).orderBy(\"index\", \"asc\");\n\t\tif (paging) {\n\t\t\tconst cursorValue = Number.parseInt(paging.cursor, 10);\n\t\t\tif (cursorValue > 0) query = query.where(\"index\", \">\", cursorValue);\n\t\t\tif (paging.limit) query = query.limit(paging.limit + 1);\n\t\t}\n\t\treturn paginateRows(await query.execute(), paging, (row) => row.index, (row) => this.rowToOperation(row), (cursor, limit) => this.getConflicting(documentId, scope, branch, minTimestamp, {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t}, signal));\n\t}\n\tasync getRevisions(documentId, branch, signal) {\n\t\tthrowIfAborted(signal);\n\t\tconst scopeRevisions = await this.queryExecutor.selectFrom(\"Operation as o1\").select([\n\t\t\t\"o1.scope\",\n\t\t\t\"o1.index\",\n\t\t\t\"o1.timestampUtcMs\"\n\t\t]).where(\"o1.documentId\", \"=\", documentId).where(\"o1.branch\", \"=\", branch).where((eb) => eb(\"o1.index\", \"=\", eb.selectFrom(\"Operation as o2\").select((eb2) => eb2.fn.max(\"o2.index\").as(\"maxIndex\")).where(\"o2.documentId\", \"=\", eb.ref(\"o1.documentId\")).where(\"o2.branch\", \"=\", eb.ref(\"o1.branch\")).where(\"o2.scope\", \"=\", eb.ref(\"o1.scope\")))).execute();\n\t\tconst latest = await this.queryExecutor.selectFrom(\"Operation\").select((eb) => eb.fn.max(\"timestampUtcMs\").as(\"latestTimestamp\")).where(\"documentId\", \"=\", documentId).where(\"branch\", \"=\", branch).executeTakeFirst();\n\t\tconst revision = {};\n\t\tfor (const row of scopeRevisions) revision[row.scope] = row.index + 1;\n\t\treturn {\n\t\t\trevision,\n\t\t\tlatestTimestamp: latest?.latestTimestamp ? new Date(latest.latestTimestamp).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString()\n\t\t};\n\t}\n\tasync getStreamLatestTimestamp(documentId, scope, branch, signal) {\n\t\tconst latest = await this.queryExecutor.selectFrom(\"Operation\").select((eb) => eb.fn.max(\"timestampUtcMs\").as(\"latestTimestamp\")).where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).executeTakeFirst();\n\t\treturn latest?.latestTimestamp ? new Date(latest.latestTimestamp).toISOString() : void 0;\n\t}\n\trowToOperation(row) {\n\t\treturn {\n\t\t\tindex: row.index,\n\t\t\ttimestampUtcMs: row.timestampUtcMs.toISOString(),\n\t\t\thash: row.hash,\n\t\t\tskip: row.skip,\n\t\t\terror: row.error || void 0,\n\t\t\tdeniedReason: row.deniedReason || void 0,\n\t\t\tid: row.opId,\n\t\t\taction: row.action\n\t\t};\n\t}\n\trowToOperationWithContext(row) {\n\t\treturn {\n\t\t\toperation: this.rowToOperation(row),\n\t\t\tcontext: {\n\t\t\t\tdocumentId: row.documentId,\n\t\t\t\tdocumentType: row.documentType,\n\t\t\t\tscope: row.scope,\n\t\t\t\tbranch: row.branch,\n\t\t\t\tordinal: row.id\n\t\t\t}\n\t\t};\n\t}\n};\n//#endregion\n//#region src/storage/pool-instrumentation.ts\n/**\n* Wraps an existing pg.Pool with acquire-wait timing and an event\n* subscription surface. The pool is mutated in place: pool.connect()\n* is replaced with a timing wrapper so all callers (Kysely included)\n* pick up the instrumentation transparently.\n*/\nfunction instrumentPgPool(pool, name) {\n\tconst listeners = /* @__PURE__ */ new Set();\n\tconst originalConnect = pool.connect.bind(pool);\n\tconst wrappedConnect = async () => {\n\t\tconst start = performance.now();\n\t\tconst client = await originalConnect();\n\t\tconst durationMs = performance.now() - start;\n\t\tfor (const listener of listeners) try {\n\t\t\tlistener(durationMs);\n\t\t} catch {}\n\t\treturn client;\n\t};\n\tpool.connect = wrappedConnect;\n\treturn {\n\t\tname,\n\t\tgetStats() {\n\t\t\treturn {\n\t\t\t\tsize: pool.totalCount,\n\t\t\t\tidle: pool.idleCount,\n\t\t\t\twaiting: pool.waitingCount\n\t\t\t};\n\t\t},\n\t\tonAcquire(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t}\n\t};\n}\nfunction createForwardingPoolInstrumentation(name) {\n\tconst listeners = /* @__PURE__ */ new Set();\n\tlet stats = {\n\t\tsize: 0,\n\t\tidle: 0,\n\t\twaiting: 0\n\t};\n\treturn {\n\t\tname,\n\t\tgetStats() {\n\t\t\treturn stats;\n\t\t},\n\t\tonAcquire(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tpushSamples(durations) {\n\t\t\tfor (const durationMs of durations) for (const listener of listeners) try {\n\t\t\t\tlistener(durationMs);\n\t\t\t} catch {}\n\t\t},\n\t\tupdateStats(next) {\n\t\t\tstats = next;\n\t\t}\n\t};\n}\n//#endregion\n//#region src/storage/migrations/001_create_operation_table.ts\nvar _001_create_operation_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$18 });\nasync function up$18(db) {\n\tawait db.schema.createTable(\"Operation\").addColumn(\"id\", \"serial\", (col) => col.primaryKey()).addColumn(\"jobId\", \"text\", (col) => col.notNull()).addColumn(\"opId\", \"text\", (col) => col.notNull()).addColumn(\"prevOpId\", \"text\", (col) => col.notNull()).addColumn(\"writeTimestampUtcMs\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"timestampUtcMs\", \"timestamptz\", (col) => col.notNull()).addColumn(\"index\", \"integer\", (col) => col.notNull()).addColumn(\"action\", \"jsonb\", (col) => col.notNull()).addColumn(\"skip\", \"integer\", (col) => col.notNull()).addColumn(\"error\", \"text\").addColumn(\"hash\", \"text\", (col) => col.notNull()).addUniqueConstraint(\"unique_revision\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"index\"\n\t]).addUniqueConstraint(\"unique_operation_instance\", [\n\t\t\"opId\",\n\t\t\"index\",\n\t\t\"skip\"\n\t]).execute();\n\tawait db.schema.createIndex(\"streamOperations\").on(\"Operation\").columns([\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"id\"\n\t]).execute();\n\tawait db.schema.createIndex(\"branchlessStreamOperations\").on(\"Operation\").columns([\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"id\"\n\t]).execute();\n}\n//#endregion\n//#region src/storage/migrations/002_create_keyframe_table.ts\nvar _002_create_keyframe_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$17 });\nasync function up$17(db) {\n\tawait db.schema.createTable(\"Keyframe\").addColumn(\"id\", \"serial\", (col) => col.primaryKey()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"revision\", \"integer\", (col) => col.notNull()).addColumn(\"document\", \"jsonb\", (col) => col.notNull()).addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint(\"unique_keyframe\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"revision\"\n\t]).execute();\n\tawait db.schema.createIndex(\"keyframe_lookup\").on(\"Keyframe\").columns([\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"revision\"\n\t]).execute();\n}\n//#endregion\n//#region src/storage/migrations/003_create_document_table.ts\nvar _003_create_document_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$16 });\nasync function up$16(db) {\n\tawait db.schema.createTable(\"Document\").addColumn(\"id\", \"text\", (col) => col.primaryKey()).addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/004_create_document_relationship_table.ts\nvar _004_create_document_relationship_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$15 });\nasync function up$15(db) {\n\tawait db.schema.createTable(\"DocumentRelationship\").addColumn(\"id\", \"text\", (col) => col.primaryKey()).addColumn(\"sourceId\", \"text\", (col) => col.notNull().references(\"Document.id\").onDelete(\"cascade\")).addColumn(\"targetId\", \"text\", (col) => col.notNull().references(\"Document.id\").onDelete(\"cascade\")).addColumn(\"relationshipType\", \"text\", (col) => col.notNull()).addColumn(\"metadata\", \"jsonb\").addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint(\"unique_source_target_type\", [\n\t\t\"sourceId\",\n\t\t\"targetId\",\n\t\t\"relationshipType\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_relationship_source\").on(\"DocumentRelationship\").column(\"sourceId\").execute();\n\tawait db.schema.createIndex(\"idx_relationship_target\").on(\"DocumentRelationship\").column(\"targetId\").execute();\n\tawait db.schema.createIndex(\"idx_relationship_type\").on(\"DocumentRelationship\").column(\"relationshipType\").execute();\n}\n//#endregion\n//#region src/storage/migrations/005_create_indexer_state_table.ts\nvar _005_create_indexer_state_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$14 });\nasync function up$14(db) {\n\tawait db.schema.createTable(\"IndexerState\").addColumn(\"id\", \"integer\", (col) => col.primaryKey().generatedAlwaysAsIdentity()).addColumn(\"lastOperationId\", \"integer\", (col) => col.notNull()).addColumn(\"lastOperationTimestamp\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/006_create_document_snapshot_table.ts\nvar _006_create_document_snapshot_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$13 });\nasync function up$13(db) {\n\tawait db.schema.createTable(\"DocumentSnapshot\").addColumn(\"id\", \"text\", (col) => col.primaryKey()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"slug\", \"text\").addColumn(\"name\", \"text\").addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"content\", \"jsonb\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"lastOperationIndex\", \"integer\", (col) => col.notNull()).addColumn(\"lastOperationHash\", \"text\", (col) => col.notNull()).addColumn(\"lastUpdatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"snapshotVersion\", \"integer\", (col) => col.notNull().defaultTo(1)).addColumn(\"identifiers\", \"jsonb\").addColumn(\"metadata\", \"jsonb\").addColumn(\"isDeleted\", \"boolean\", (col) => col.notNull().defaultTo(false)).addColumn(\"deletedAt\", \"timestamptz\").addUniqueConstraint(\"unique_doc_scope_branch\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_slug_scope_branch\").on(\"DocumentSnapshot\").columns([\n\t\t\"slug\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_doctype_scope_branch\").on(\"DocumentSnapshot\").columns([\n\t\t\"documentType\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_last_updated\").on(\"DocumentSnapshot\").column(\"lastUpdatedAt\").execute();\n\tawait db.schema.createIndex(\"idx_is_deleted\").on(\"DocumentSnapshot\").column(\"isDeleted\").execute();\n}\n//#endregion\n//#region src/storage/migrations/007_create_slug_mapping_table.ts\nvar _007_create_slug_mapping_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$12 });\nasync function up$12(db) {\n\tawait db.schema.createTable(\"SlugMapping\").addColumn(\"slug\", \"text\", (col) => col.primaryKey()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint(\"unique_docid_scope_branch\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_slug_documentid\").on(\"SlugMapping\").column(\"documentId\").execute();\n}\n//#endregion\n//#region src/storage/migrations/008_create_view_state_table.ts\nvar _008_create_view_state_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$11 });\nasync function up$11(db) {\n\tawait db.schema.createTable(\"ViewState\").addColumn(\"readModelId\", \"text\", (col) => col.primaryKey()).addColumn(\"lastOrdinal\", \"integer\", (col) => col.notNull().defaultTo(0)).addColumn(\"lastOperationTimestamp\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/009_create_operation_index_tables.ts\nvar _009_create_operation_index_tables_exports = /* @__PURE__ */ __exportAll({ up: () => up$10 });\nasync function up$10(db) {\n\tawait db.schema.createTable(\"document_collections\").addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"collectionId\", \"text\", (col) => col.notNull()).addColumn(\"joinedOrdinal\", \"bigint\", (col) => col.notNull().defaultTo(0)).addColumn(\"leftOrdinal\", \"bigint\").addPrimaryKeyConstraint(\"document_collections_pkey\", [\"documentId\", \"collectionId\"]).execute();\n\tawait db.schema.createIndex(\"idx_document_collections_collectionId\").on(\"document_collections\").column(\"collectionId\").execute();\n\tawait db.schema.createIndex(\"idx_doc_collections_collection_range\").on(\"document_collections\").columns([\"collectionId\", \"joinedOrdinal\"]).execute();\n\tawait db.schema.createTable(\"operation_index_operations\").addColumn(\"ordinal\", \"serial\", (col) => col.primaryKey()).addColumn(\"opId\", \"text\", (col) => col.notNull()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"timestampUtcMs\", \"text\", (col) => col.notNull()).addColumn(\"writeTimestampUtcMs\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"index\", \"integer\", (col) => col.notNull()).addColumn(\"skip\", \"integer\", (col) => col.notNull()).addColumn(\"hash\", \"text\", (col) => col.notNull()).addColumn(\"action\", \"jsonb\", (col) => col.notNull()).execute();\n\tawait db.schema.createIndex(\"idx_operation_index_operations_document\").on(\"operation_index_operations\").columns([\n\t\t\"documentId\",\n\t\t\"branch\",\n\t\t\"scope\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_operation_index_operations_ordinal\").on(\"operation_index_operations\").column(\"ordinal\").execute();\n}\n//#endregion\n//#region src/storage/migrations/010_create_sync_tables.ts\nvar _010_create_sync_tables_exports = /* @__PURE__ */ __exportAll({ up: () => up$9 });\nasync function up$9(db) {\n\tawait db.schema.createTable(\"sync_remotes\").addColumn(\"name\", \"text\", (col) => col.primaryKey()).addColumn(\"collection_id\", \"text\", (col) => col.notNull()).addColumn(\"channel_type\", \"text\", (col) => col.notNull()).addColumn(\"channel_id\", \"text\", (col) => col.notNull().defaultTo(\"\")).addColumn(\"remote_name\", \"text\", (col) => col.notNull().defaultTo(\"\")).addColumn(\"channel_parameters\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'{}'::jsonb`)).addColumn(\"filter_document_ids\", \"jsonb\").addColumn(\"filter_scopes\", \"jsonb\").addColumn(\"filter_branch\", \"text\", (col) => col.notNull().defaultTo(\"main\")).addColumn(\"push_state\", \"text\", (col) => col.notNull().defaultTo(\"idle\")).addColumn(\"push_last_success_utc_ms\", \"text\").addColumn(\"push_last_failure_utc_ms\", \"text\").addColumn(\"push_failure_count\", \"integer\", (col) => col.notNull().defaultTo(0)).addColumn(\"pull_state\", \"text\", (col) => col.notNull().defaultTo(\"idle\")).addColumn(\"pull_last_success_utc_ms\", \"text\").addColumn(\"pull_last_failure_utc_ms\", \"text\").addColumn(\"pull_failure_count\", \"integer\", (col) => col.notNull().defaultTo(0)).addColumn(\"created_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updated_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n\tawait db.schema.createIndex(\"idx_sync_remotes_collection\").on(\"sync_remotes\").column(\"collection_id\").execute();\n\tawait db.schema.createTable(\"sync_cursors\").addColumn(\"remote_name\", \"text\", (col) => col.primaryKey().references(\"sync_remotes.name\").onDelete(\"cascade\")).addColumn(\"cursor_ordinal\", \"bigint\", (col) => col.notNull().defaultTo(0)).addColumn(\"last_synced_at_utc_ms\", \"text\").addColumn(\"updated_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n\tawait db.schema.createIndex(\"idx_sync_cursors_ordinal\").on(\"sync_cursors\").column(\"cursor_ordinal\").execute();\n}\n//#endregion\n//#region src/storage/migrations/011_add_cursor_type_column.ts\nvar _011_add_cursor_type_column_exports = /* @__PURE__ */ __exportAll({ up: () => up$8 });\nasync function up$8(db) {\n\tawait db.deleteFrom(\"sync_cursors\").where(\"remote_name\", \"like\", \"outbox::%\").execute();\n\tawait db.deleteFrom(\"sync_remotes\").where(\"name\", \"like\", \"outbox::%\").execute();\n\tawait db.schema.dropTable(\"sync_cursors\").execute();\n\tawait db.schema.createTable(\"sync_cursors\").addColumn(\"remote_name\", \"text\", (col) => col.notNull()).addColumn(\"cursor_type\", \"text\", (col) => col.notNull().defaultTo(\"inbox\")).addColumn(\"cursor_ordinal\", \"bigint\", (col) => col.notNull().defaultTo(0)).addColumn(\"last_synced_at_utc_ms\", \"text\").addColumn(\"updated_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addPrimaryKeyConstraint(\"sync_cursors_pk\", [\"remote_name\", \"cursor_type\"]).execute();\n\tawait db.schema.createIndex(\"idx_sync_cursors_ordinal\").on(\"sync_cursors\").column(\"cursor_ordinal\").execute();\n}\n//#endregion\n//#region src/storage/migrations/012_add_source_remote_column.ts\nvar _012_add_source_remote_column_exports = /* @__PURE__ */ __exportAll({ up: () => up$7 });\nasync function up$7(db) {\n\tawait db.schema.alterTable(\"operation_index_operations\").addColumn(\"sourceRemote\", \"text\", (col) => col.notNull().defaultTo(\"\")).execute();\n}\n//#endregion\n//#region src/storage/migrations/013_create_sync_dead_letters_table.ts\nvar _013_create_sync_dead_letters_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$6 });\nasync function up$6(db) {\n\tawait db.schema.createTable(\"sync_dead_letters\").addColumn(\"ordinal\", \"serial\", (col) => col.primaryKey()).addColumn(\"id\", \"text\", (col) => col.unique().notNull()).addColumn(\"job_id\", \"text\", (col) => col.notNull()).addColumn(\"job_dependencies\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn(\"remote_name\", \"text\", (col) => col.notNull().references(\"sync_remotes.name\").onDelete(\"cascade\")).addColumn(\"document_id\", \"text\", (col) => col.notNull()).addColumn(\"scopes\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"operations\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn(\"error_source\", \"text\", (col) => col.notNull()).addColumn(\"error_message\", \"text\", (col) => col.notNull()).addColumn(\"created_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n\tawait db.schema.createIndex(\"idx_sync_dead_letters_remote\").on(\"sync_dead_letters\").column(\"remote_name\").execute();\n}\n//#endregion\n//#region src/storage/migrations/014_create_processor_cursor_table.ts\nvar _014_create_processor_cursor_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$5 });\nasync function up$5(db) {\n\tawait db.schema.createTable(\"ProcessorCursor\").addColumn(\"processorId\", \"text\", (col) => col.primaryKey()).addColumn(\"factoryId\", \"text\", (col) => col.notNull()).addColumn(\"driveId\", \"text\", (col) => col.notNull()).addColumn(\"processorIndex\", \"integer\", (col) => col.notNull()).addColumn(\"lastOrdinal\", \"integer\", (col) => col.notNull().defaultTo(sql`0`)).addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(sql`'active'`)).addColumn(\"lastError\", \"text\").addColumn(\"lastErrorTimestamp\", \"timestamptz\").addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/015_add_operation_denied_reason.ts\nvar _015_add_operation_denied_reason_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$4,\n\tup: () => up$4\n});\n/**\n* Records why authorization refused an operation. Separate from `error` so a\n* denial is distinguishable from a reducer failure without matching on a\n* message. Null for every operation written before decisions were enforced.\n*/\nasync function up$4(db) {\n\tawait db.schema.alterTable(\"Operation\").addColumn(\"deniedReason\", \"text\").execute();\n\tawait db.schema.alterTable(\"operation_index_operations\").addColumn(\"deniedReason\", \"text\").execute();\n}\nasync function down$4(db) {\n\tawait db.schema.alterTable(\"operation_index_operations\").dropColumn(\"deniedReason\").execute();\n\tawait db.schema.alterTable(\"Operation\").dropColumn(\"deniedReason\").execute();\n}\n//#endregion\n//#region src/storage/migrations/016_add_dead_letter_error_type.ts\nvar _016_add_dead_letter_error_type_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$3,\n\tup: () => up$3\n});\n/**\n* The classification a dead letter falls into, stored because it decides whether\n* the document stays quarantined and the in-memory error is gone after a restart.\n* Defaulted rather than nullable, so a pre-existing row rehydrates.\n*/\nasync function up$3(db) {\n\tawait db.schema.alterTable(\"sync_dead_letters\").addColumn(\"error_type\", \"text\", (col) => col.notNull().defaultTo(\"UNCLASSIFIED\")).execute();\n}\nasync function down$3(db) {\n\tawait db.schema.alterTable(\"sync_dead_letters\").dropColumn(\"error_type\").execute();\n}\n//#endregion\n//#region src/storage/migrations/017_create_group_references.ts\nvar _017_create_group_references_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$2,\n\tup: () => up$2\n});\n/**\n* One row per (document, group) reference ever discovered from an auth\n* operation's input. Rows are never updated or deleted: auth evaluation is\n* positional, so a grant that named a group at any position keeps that\n* group's stream in the document's read-set even after a later operation\n* removes the reference. Read by documentId for the groups a document\n* requires (sync), and by groupId for the documents a group change affects\n* (re-evaluation).\n*/\nasync function up$2(db) {\n\tawait db.schema.createTable(\"group_references\").addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"groupId\", \"text\", (col) => col.notNull()).addPrimaryKeyConstraint(\"group_references_pkey\", [\"documentId\", \"groupId\"]).execute();\n\tawait db.schema.createIndex(\"idx_group_references_groupId\").on(\"group_references\").column(\"groupId\").execute();\n}\nasync function down$2(db) {\n\tawait db.schema.dropTable(\"group_references\").execute();\n}\n//#endregion\n//#region src/storage/migrations/018_add_sync_remote_bound_address.ts\nvar _018_add_sync_remote_bound_address_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$1,\n\tup: () => up$1\n});\n/**\n* The address a sync channel is bound to, so a channel created by one subject\n* cannot be polled by another.\n*\n* Nullable rather than defaulted: null is a channel nobody has claimed, which is\n* what every pre-existing row is and what an anonymously created channel stays\n* until its first authenticated poll adopts it. A default would claim them all\n* for one address.\n*/\nasync function up$1(db) {\n\tawait db.schema.alterTable(\"sync_remotes\").addColumn(\"bound_address\", \"text\").execute();\n}\nasync function down$1(db) {\n\tawait db.schema.alterTable(\"sync_remotes\").dropColumn(\"bound_address\").execute();\n}\n//#endregion\n//#region src/storage/migrations/019_require_action_id.ts\nvar _019_require_action_id_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down,\n\tup: () => up\n});\n/**\n* Makes an operation whose action carries no id physically unstorable.\n*\n* The id is not decoration: `deriveOperationId` hashes it into the operation id\n* and replay dedupes incoming operations by it, so an action without one\n* collapses every id-less operation on a document/scope/branch onto a single\n* derived operation id. The API rejects such an action now, and this is the\n* last line of defense behind it.\n*\n* Both tables are constrained because sync reads operations from the index\n* rather than the operation table, so poison reaching only the index would\n* still be served to a replica.\n*\n* Pre-existing rows are backfilled rather than left behind a NOT VALID\n* constraint: a row the index and the operation table disagree about is worse\n* than a missing id, because dedup keys off the value each side serves. The\n* backfill therefore mints one id per operation and writes that same id to both\n* tables, joined on the identity they share. Rewriting the action is safe: the\n* operation hash is taken over the resulting state, not over the action, and a\n* signature is verified from the params carried in the signature tuple, which\n* do not include the action id.\n*\n* The empty string is rejected alongside null. It derives the same colliding\n* operation id as an absent id, so admitting it would leave the hole open.\n*/\nasync function up(db) {\n\tawait db.updateTable(\"Operation\").set({ action: sql`jsonb_set(action, '{id}', to_jsonb(gen_random_uuid()::text))` }).where(sql`jsonb_typeof(action) = 'object' and coalesce(action->>'id', '') = ''`).execute();\n\tawait db.updateTable(\"operation_index_operations as oio\").from(\"Operation as op\").set({ action: sql`jsonb_set(oio.action, '{id}', to_jsonb(op.action->>'id'))` }).whereRef(\"oio.opId\", \"=\", \"op.opId\").whereRef(\"oio.index\", \"=\", \"op.index\").whereRef(\"oio.skip\", \"=\", \"op.skip\").where(sql`jsonb_typeof(oio.action) = 'object' and coalesce(oio.action->>'id', '') = ''`).where(sql`coalesce(op.action->>'id', '') <> ''`).execute();\n\tawait db.updateTable(\"operation_index_operations\").set({ action: sql`jsonb_set(action, '{id}', to_jsonb(gen_random_uuid()::text))` }).where(sql`jsonb_typeof(action) = 'object' and coalesce(action->>'id', '') = ''`).execute();\n\tawait db.schema.alterTable(\"Operation\").addCheckConstraint(\"action_must_have_id\", sql`action->>'id' is not null and action->>'id' <> ''`).execute();\n\tawait db.schema.alterTable(\"operation_index_operations\").addCheckConstraint(\"action_must_have_id\", sql`action->>'id' is not null and action->>'id' <> ''`).execute();\n}\n/**\n* Only the constraints are dropped. The backfilled ids stay: they are the ids\n* their operations are now known by, and reverting them would reintroduce the\n* collision the migration removed.\n*/\nasync function down(db) {\n\tawait db.schema.alterTable(\"operation_index_operations\").dropConstraint(\"action_must_have_id\").execute();\n\tawait db.schema.alterTable(\"Operation\").dropConstraint(\"action_must_have_id\").execute();\n}\n//#endregion\n//#region src/storage/migrations/migrator.ts\nconst REACTOR_SCHEMA = \"reactor\";\nconst migrations = {\n\t\"001_create_operation_table\": _001_create_operation_table_exports,\n\t\"002_create_keyframe_table\": _002_create_keyframe_table_exports,\n\t\"003_create_document_table\": _003_create_document_table_exports,\n\t\"004_create_document_relationship_table\": _004_create_document_relationship_table_exports,\n\t\"005_create_indexer_state_table\": _005_create_indexer_state_table_exports,\n\t\"006_create_document_snapshot_table\": _006_create_document_snapshot_table_exports,\n\t\"007_create_slug_mapping_table\": _007_create_slug_mapping_table_exports,\n\t\"008_create_view_state_table\": _008_create_view_state_table_exports,\n\t\"009_create_operation_index_tables\": _009_create_operation_index_tables_exports,\n\t\"010_create_sync_tables\": _010_create_sync_tables_exports,\n\t\"011_add_cursor_type_column\": _011_add_cursor_type_column_exports,\n\t\"012_add_source_remote_column\": _012_add_source_remote_column_exports,\n\t\"013_create_sync_dead_letters_table\": _013_create_sync_dead_letters_table_exports,\n\t\"014_create_processor_cursor_table\": _014_create_processor_cursor_table_exports,\n\t\"015_add_operation_denied_reason\": _015_add_operation_denied_reason_exports,\n\t\"016_add_dead_letter_error_type\": _016_add_dead_letter_error_type_exports,\n\t\"017_create_group_references\": _017_create_group_references_exports,\n\t\"018_add_sync_remote_bound_address\": _018_add_sync_remote_bound_address_exports,\n\t\"019_require_action_id\": _019_require_action_id_exports\n};\nvar ProgrammaticMigrationProvider = class {\n\tgetMigrations() {\n\t\treturn Promise.resolve(migrations);\n\t}\n};\n/**\n* Applies every pending migration, or every one up to and including `upTo`.\n*\n* The bound exists so a test can reach the schema a data migration is written\n* against, populate it, and then migrate across the migration under test.\n*/\nasync function runMigrations(db, schema = REACTOR_SCHEMA, upTo) {\n\ttry {\n\t\tawait sql`CREATE SCHEMA IF NOT EXISTS ${sql.id(schema)}`.execute(db);\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmigrationsExecuted: [],\n\t\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(\"Failed to create schema\")\n\t\t};\n\t}\n\tconst migrator = new Migrator({\n\t\tdb: db.withSchema(schema),\n\t\tprovider: new ProgrammaticMigrationProvider(),\n\t\tmigrationTableSchema: schema\n\t});\n\tlet error;\n\tlet results;\n\ttry {\n\t\tconst result = upTo ? await migrator.migrateTo(upTo) : await migrator.migrateToLatest();\n\t\terror = result.error;\n\t\tresults = result.results;\n\t} catch (e) {\n\t\terror = e;\n\t\tresults = [];\n\t}\n\tconst migrationsExecuted = results?.map((result) => result.migrationName) ?? [];\n\tif (error) return {\n\t\tsuccess: false,\n\t\tmigrationsExecuted,\n\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(\"Unknown migration error\")\n\t};\n\treturn {\n\t\tsuccess: true,\n\t\tmigrationsExecuted\n\t};\n}\nasync function getMigrationStatus(db, schema = REACTOR_SCHEMA) {\n\treturn await new Migrator({\n\t\tdb: db.withSchema(schema),\n\t\tprovider: new ProgrammaticMigrationProvider(),\n\t\tmigrationTableSchema: schema\n\t}).getMigrations();\n}\n//#endregion\n//#region src/core/drive-container-types.ts\nconst DEFAULT_DRIVE_CONTAINER_TYPES = new Set([\"powerhouse/document-drive\", \"powerhouse/reactor-drive\"]);\n//#endregion\nexport { selectDecisionModel as A, RevisionMismatchError as B, InvalidModuleError as C, createEmptyConsistencyToken as D, createConsistencyToken as E, AppendConditionFailedError as F, DocumentNotFoundError as G, AuthTimestampNotMonotonicError as H, DocumentAlreadyExistsError as I, UpgradePreconditionFailedError as J, ExcessiveReshuffleError as K, DocumentExistence as L, authDecisionModel as M, buildDecisionModel as N, targetDocumentId as O, APPEND_CONDITION_FAILED_PREFIX as P, __exportAll as Q, DuplicateOperationError as R, DuplicateModuleError as S, GATED_DOCUMENT_ACTIONS as T, AuthorizationDeniedError as U, AuthEnforcementDisabledError as V, DocumentDeletedError as W, parsePagingOptions as X, matchesScope as Y, throwIfAborted as Z, DocumentMetaCache as _, createForwardingPoolInstrumentation as a, JobExecutorEventTypes as b, KyselyKeyframeStore as c, DriveCollectionId as d, KyselyExecutionScope as f, KyselyOperationIndex as g, KyselyWriteCache as h, runMigrations as i, documentDecisionModel as j, decideAtHead as k, DocumentModelRegistry as l, EventBus as m, REACTOR_SCHEMA as n, instrumentPgPool as o, resolveFeatureFlags as p, InvalidOperationTimestampError as q, getMigrationStatus as r, KyselyOperationStore as s, DEFAULT_DRIVE_CONTAINER_TYPES as t, SimpleJobExecutor as u, CollectionMembershipCache as v, ModuleNotFoundError as w, DuplicateManifestError as x, DEFAULT_DEFERRED_JOB_TTL_MS as y, OptimisticLockError as z };\n\n//# sourceMappingURL=drive-container-types-yZrksiJR.js.map","import { A as selectDecisionModel, B as RevisionMismatchError, C as InvalidModuleError, D as createEmptyConsistencyToken, E as createConsistencyToken, F as AppendConditionFailedError, G as DocumentNotFoundError, H as AuthTimestampNotMonotonicError, I as DocumentAlreadyExistsError, J as UpgradePreconditionFailedError, K as ExcessiveReshuffleError, L as DocumentExistence, M as authDecisionModel, N as buildDecisionModel, O as targetDocumentId, P as APPEND_CONDITION_FAILED_PREFIX, R as DuplicateOperationError, S as DuplicateModuleError, T as GATED_DOCUMENT_ACTIONS, U as AuthorizationDeniedError, V as AuthEnforcementDisabledError, W as DocumentDeletedError, X as parsePagingOptions, Y as matchesScope, Z as throwIfAborted, _ as DocumentMetaCache, a as createForwardingPoolInstrumentation, b as JobExecutorEventTypes, c as KyselyKeyframeStore, d as DriveCollectionId, f as KyselyExecutionScope, g as KyselyOperationIndex, h as KyselyWriteCache, i as runMigrations, j as documentDecisionModel, k as decideAtHead, l as DocumentModelRegistry, m as EventBus, n as REACTOR_SCHEMA, o as instrumentPgPool, p as resolveFeatureFlags, q as InvalidOperationTimestampError, r as getMigrationStatus, s as KyselyOperationStore, t as DEFAULT_DRIVE_CONTAINER_TYPES, u as SimpleJobExecutor, v as CollectionMembershipCache, w as ModuleNotFoundError, x as DuplicateManifestError, y as DEFAULT_DEFERRED_JOB_TTL_MS, z as OptimisticLockError } from \"./drive-container-types-yZrksiJR.js\";\nimport { n as ReactorEventTypes, t as EventBusAggregateError } from \"./types-DMKLa0Ok.js\";\nimport { i as WorkerInitFailedError, r as WorkerExitedError, t as WorkerAbortTimeoutError } from \"./errors-D3S6Eysd.js\";\nimport { a as DOCUMENT_INDEXER_READ_MODEL, c as BaseReadModel, i as KyselyDocumentView, n as ConsistencyTracker, o as DOCUMENT_VIEW_READ_MODEL, r as makeConsistencyKey, s as ReadModelCoordinator, t as KyselyDocumentIndexer } from \"./document-indexer-C5Gsa1B3.js\";\nimport { n as errorToInfo, r as sanitizeArg, t as createForwardingLogger } from \"./forwarding-logger-BBkMSxuJ.js\";\nimport { t as workerEntryPath } from \"./worker-HPysBfhx.js\";\nimport { DowngradeNotSupportedError, MAX_AUTH_GRANTS, UnsupportedDocumentModelVersionError, actions, actions as documentActions, createPresignedHeader, decide, deserializeSignature, garbageCollect, generateId, groupDocumentType, groupMembershipActionTypes, hashDocumentStateForScope, normalizeDocumentModelVersion, sortOperations, toTransportAction } from \"@powerhousedao/shared/document-model\";\nimport { addFile, addFolder, copyNode, deleteNode, driveCreateDocument, generateNodesCopy, getDescendants, handleTargetNameCollisions, isFileNode, isFolderNode, moveNode, updateNode } from \"@powerhousedao/shared/document-drive\";\nimport { v4 } from \"uuid\";\nimport { ConsoleLogger, childLogger } from \"document-model\";\nimport { sql } from \"kysely\";\nimport { RelationalDbProcessor, createRelationalDb } from \"@powerhousedao/shared/processors\";\n//#region src/actions/index.ts\n/**\n* Creates a CREATE_DOCUMENT action for document creation.\n*/\nfunction createDocumentAction(input) {\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"CREATE_DOCUMENT\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates an UPGRADE_DOCUMENT action to set initial document state.\n*/\nfunction upgradeDocumentAction(input) {\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"UPGRADE_DOCUMENT\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates a DELETE_DOCUMENT action for document deletion.\n*/\nfunction deleteDocumentAction(documentId) {\n\tconst input = { documentId };\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"DELETE_DOCUMENT\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates an ADD_RELATIONSHIP action that records a directed edge from\n* `sourceId` to `targetId` with an arbitrary `relationshipType` and optional\n* `metadata`. The edge is opaque to the reactor — consumers (e.g. reactor-drive)\n* define their own type strings such as `\"drive/child\"` and attach\n* domain-specific metadata.\n*/\nfunction addRelationshipAction(sourceId, targetId, relationshipType, metadata) {\n\tconst input = {\n\t\tsourceId,\n\t\ttargetId,\n\t\trelationshipType,\n\t\t...metadata !== void 0 ? { metadata } : {}\n\t};\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"ADD_RELATIONSHIP\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates an UPDATE_RELATIONSHIP action to replace a relationship's metadata\n* without losing its createdAt ordering.\n*/\nfunction updateRelationshipAction(sourceId, targetId, relationshipType, metadata) {\n\tconst input = {\n\t\tsourceId,\n\t\ttargetId,\n\t\trelationshipType,\n\t\tmetadata\n\t};\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"UPDATE_RELATIONSHIP\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates a REMOVE_RELATIONSHIP action to remove a parent-child relationship.\n*/\nfunction removeRelationshipAction(sourceId, targetId, relationshipType = \"child\") {\n\tconst input = {\n\t\tsourceId,\n\t\ttargetId,\n\t\trelationshipType\n\t};\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"REMOVE_RELATIONSHIP\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n//#endregion\n//#region src/core/utils.ts\n/**\n* Validates structural properties shared by all batch requests:\n* duplicate keys, missing dependencies, and dependency cycles.\n*/\nfunction validateBatchStructure(jobs) {\n\tconst keys = /* @__PURE__ */ new Set();\n\tfor (const job of jobs) {\n\t\tif (keys.has(job.key)) throw new Error(`Duplicate plan key: ${job.key}`);\n\t\tkeys.add(job.key);\n\t}\n\tfor (const job of jobs) for (const depKey of job.dependsOn) if (!keys.has(depKey)) throw new Error(`Job '${job.key}' depends on non-existent key: ${depKey}`);\n\tconst visited = /* @__PURE__ */ new Set();\n\tconst recStack = /* @__PURE__ */ new Set();\n\tconst detectCycle = (key) => {\n\t\tvisited.add(key);\n\t\trecStack.add(key);\n\t\tconst job = jobs.find((j) => j.key === key);\n\t\tif (job) {\n\t\t\tfor (const depKey of job.dependsOn) if (!visited.has(depKey)) {\n\t\t\t\tif (detectCycle(depKey)) return true;\n\t\t\t} else if (recStack.has(depKey)) return true;\n\t\t}\n\t\trecStack.delete(key);\n\t\treturn false;\n\t};\n\tfor (const job of jobs) if (!visited.has(job.key)) {\n\t\tif (detectCycle(job.key)) throw new Error(`Dependency cycle detected involving key: ${job.key}`);\n\t}\n}\n/**\n* Validates a batch mutation request for common errors\n*/\nfunction validateBatchRequest(jobs) {\n\tvalidateBatchStructure(jobs);\n\tfor (const job of jobs) if (job.actions.length === 0) throw new Error(`Job '${job.key}' has empty actions array`);\n}\n/**\n* Validates a batch load request for common errors\n*/\nfunction validateBatchLoadRequest(jobs) {\n\tvalidateBatchStructure(jobs);\n\tfor (const job of jobs) if (job.operations.length === 0) throw new Error(`Job '${job.key}' has empty operations array`);\n}\n/**\n* Validates that all actions in a job match the declared scope\n*/\nfunction validateActionScopes(job) {\n\tfor (const action of job.actions) {\n\t\tconst actionScope = action.scope || \"global\";\n\t\tif (actionScope !== job.scope) throw new Error(`Job '${job.key}' declares scope '${job.scope}' but action has scope '${actionScope}'`);\n\t}\n}\n/**\n* Validates that all operations in a job match the declared scope\n*/\nfunction validateOperationScopes(job) {\n\tfor (const operation of job.operations) {\n\t\tconst operationScope = operation.action.scope || \"global\";\n\t\tif (operationScope !== job.scope) throw new Error(`Job '${job.key}' declares scope '${job.scope}' but operation has scope '${operationScope}'`);\n\t}\n}\n/**\n* Performs topological sort on jobs based on dependencies\n*/\nfunction topologicalSort(jobs) {\n\tconst result = [];\n\tconst visited = /* @__PURE__ */ new Set();\n\tconst visit = (key) => {\n\t\tif (visited.has(key)) return;\n\t\tvisited.add(key);\n\t\tconst job = jobs.find((j) => j.key === key);\n\t\tif (job) for (const depKey of job.dependsOn) visit(depKey);\n\t\tresult.push(key);\n\t};\n\tfor (const job of jobs) visit(job.key);\n\treturn result;\n}\n/**\n* Converts an Error or string to ErrorInfo\n*/\nfunction toErrorInfo$1(error) {\n\tif (error instanceof Error) return {\n\t\tname: error.name,\n\t\tmessage: error.message,\n\t\tstack: error.stack || (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n\treturn {\n\t\tname: \"Error\",\n\t\tmessage: error,\n\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n}\n/**\n* Filters paged results by document type\n*/\nfunction filterByType(results, type) {\n\treturn {\n\t\tresults: results.results.filter((document) => document.header.documentType === type),\n\t\toptions: results.options,\n\t\tnextCursor: results.nextCursor,\n\t\tnext: results.next ? async () => {\n\t\t\treturn filterByType(await results.next(), type);\n\t\t} : void 0\n\t};\n}\n/**\n* Validates that all operations share the same scope.\n* Throws an error if any operation has a different scope.\n*/\nfunction getSharedOperationScope(operations) {\n\tif (operations.length === 0) throw new Error(\"No operations provided\");\n\tconst baseScope = operations[0].action.scope;\n\tfor (const [index, operation] of operations.entries()) {\n\t\tconst scope = operation.action.scope;\n\t\tif (scope !== baseScope) throw new Error(`All operations in load must share the same scope. Expected '${baseScope}', received '${scope}' at position ${index}`);\n\t}\n\treturn baseScope;\n}\n/**\n* Validates that all actions share the same scope.\n* Throws an error if any action has a different scope.\n*/\nfunction getSharedActionScope(actions) {\n\tif (actions.length === 0) throw new Error(\"No actions provided\");\n\tconst baseScope = actions[0].scope;\n\tfor (const action of actions) if (action.scope !== baseScope) throw new Error(`All actions must share the same scope. Expected '${baseScope}', received '${action.scope}'`);\n\treturn baseScope;\n}\n/**\n* Signs an action with the provided signer.\n* If the action already has valid signatures, it is returned unchanged.\n*/\nconst signAction = async (action, signer, signal) => {\n\tconst existingSignatures = action.context?.signer?.signatures;\n\tif (existingSignatures && existingSignatures.length > 0) return action;\n\tconst signature = await signer.signAction(action, signal);\n\treturn {\n\t\t...action,\n\t\tcontext: {\n\t\t\t...action.context,\n\t\t\tsigner: {\n\t\t\t\tuser: {\n\t\t\t\t\taddress: signer.user?.address || \"\",\n\t\t\t\t\tnetworkId: signer.user?.networkId || \"\",\n\t\t\t\t\tchainId: signer.user?.chainId || 0\n\t\t\t\t},\n\t\t\t\tapp: {\n\t\t\t\t\tname: signer.app?.name || \"\",\n\t\t\t\t\tkey: signer.app?.key || \"\"\n\t\t\t\t},\n\t\t\t\tsignatures: [signature]\n\t\t\t}\n\t\t}\n\t};\n};\n/**\n* Signs multiple actions with the provided signer\n*/\nconst signActions = async (actions, signer, signal) => {\n\treturn Promise.all(actions.map((action) => signAction(action, signer, signal)));\n};\nfunction buildSingleJobMeta(jobId, callerMeta) {\n\treturn {\n\t\t...callerMeta,\n\t\tbatchId: v4(),\n\t\tbatchJobIds: [jobId]\n\t};\n}\n//#endregion\n//#region src/shared/types.ts\n/**\n* Enum that determines deletion propagation.\n*/\nlet PropagationMode = /* @__PURE__ */ function(PropagationMode) {\n\tPropagationMode[\"None\"] = \"none\";\n\tPropagationMode[\"Cascade\"] = \"cascade\";\n\treturn PropagationMode;\n}({});\n/**\n* Enum that describes the type of relationship change.\n*/\nlet RelationshipChangeType = /* @__PURE__ */ function(RelationshipChangeType) {\n\tRelationshipChangeType[\"Added\"] = \"added\";\n\tRelationshipChangeType[\"Removed\"] = \"removed\";\n\treturn RelationshipChangeType;\n}({});\n/**\n* Job execution statuses\n*/\nlet JobStatus = /* @__PURE__ */ function(JobStatus) {\n\t/** Job is queued but not yet started */\n\tJobStatus[\"PENDING\"] = \"PENDING\";\n\t/** Job is currently being executed */\n\tJobStatus[\"RUNNING\"] = \"RUNNING\";\n\t/** Operations have been written to the operation store (JOB_WRITE_READY event) */\n\tJobStatus[\"WRITE_READY\"] = \"WRITE_READY\";\n\t/** Read models have finished indexing operations (JOB_READ_READY event) */\n\tJobStatus[\"READ_READY\"] = \"READ_READY\";\n\t/** Job failed (may be retried) */\n\tJobStatus[\"FAILED\"] = \"FAILED\";\n\treturn JobStatus;\n}({});\n//#endregion\n//#region src/client/drive-client.ts\n/**\n* Implementation of {@link IDriveClient}.\n*\n* Holds a back-reference to its parent {@link IReactorClient} for read and\n* single-document write primitives, plus direct access to {@link IReactor}\n* for batch execution. The back-reference is captured but never invoked\n* during construction, so the partial-`this` hazard does not apply.\n*/\nvar DriveClient = class {\n\tconstructor(client, logger, reactor, signer) {\n\t\tthis.client = client;\n\t\tthis.logger = logger;\n\t\tthis.reactor = reactor;\n\t\tthis.signer = signer;\n\t}\n\tasync create(input, signal) {\n\t\tthis.logger.verbose(\"drives.create(@input)\", input);\n\t\tconst driveDoc = driveCreateDocument({ global: {\n\t\t\tname: input.global.name || \"\",\n\t\t\ticon: input.global.icon ?? null,\n\t\t\tnodes: []\n\t\t} });\n\t\tif (input.preferredEditor) driveDoc.header.meta = {\n\t\t\t...driveDoc.header.meta,\n\t\t\tpreferredEditor: input.preferredEditor\n\t\t};\n\t\treturn this.client.create(driveDoc, void 0, signal);\n\t}\n\tasync addFile(driveIdentifier, document, parentFolder, signal) {\n\t\tthis.logger.verbose(\"drives.addFile(@driveIdentifier, @document, @parentFolder)\", driveIdentifier, document.header.id, parentFolder);\n\t\tconst documentId = document.header.id;\n\t\tconst documentActions = await signActions([\n\t\t\tcreateDocumentAction({\n\t\t\t\tmodel: document.header.documentType,\n\t\t\t\tversion: 0,\n\t\t\t\tdocumentId: document.header.id,\n\t\t\t\tsigning: {\n\t\t\t\t\tsignature: document.header.id,\n\t\t\t\t\tpublicKey: document.header.sig.publicKey,\n\t\t\t\t\tnonce: document.header.sig.nonce,\n\t\t\t\t\tcreatedAtUtcIso: document.header.createdAtUtcIso,\n\t\t\t\t\tdocumentType: document.header.documentType\n\t\t\t\t},\n\t\t\t\tslug: document.header.slug,\n\t\t\t\tname: document.header.name,\n\t\t\t\tbranch: document.header.branch,\n\t\t\t\tmeta: document.header.meta,\n\t\t\t\tprotocolVersions: document.header.protocolVersions ?? { \"base-reducer\": 2 }\n\t\t\t}),\n\t\t\tupgradeDocumentAction({\n\t\t\t\tdocumentId: document.header.id,\n\t\t\t\tmodel: document.header.documentType,\n\t\t\t\tfromVersion: 0,\n\t\t\t\ttoVersion: normalizeDocumentModelVersion(document.state.document?.version),\n\t\t\t\tinitialState: document.state\n\t\t\t}),\n\t\t\taddRelationshipAction(driveIdentifier, documentId, \"child\")\n\t\t], this.signer, signal);\n\t\tconst driveActions = await signActions([addFile({\n\t\t\tid: documentId,\n\t\t\tname: document.header.name || documentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tparentFolder\n\t\t})], this.signer, signal);\n\t\tawait this.runJobs([{\n\t\t\tkey: \"document\",\n\t\t\tdocumentId,\n\t\t\tscope: getSharedActionScope(documentActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: documentActions,\n\t\t\tdependsOn: []\n\t\t}], signal);\n\t\tawait this.runJobs([{\n\t\t\tkey: \"drive\",\n\t\t\tdocumentId: driveIdentifier,\n\t\t\tscope: getSharedActionScope(driveActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: driveActions,\n\t\t\tdependsOn: []\n\t\t}], signal);\n\t\treturn this.client.get(documentId, void 0, signal);\n\t}\n\tasync addFolder(driveIdentifier, name, parentFolder, signal) {\n\t\tthis.logger.verbose(\"drives.addFolder(@driveIdentifier, @name, @parentFolder)\", driveIdentifier, name, parentFolder);\n\t\tconst folderId = generateId();\n\t\tconst node = (await this.client.execute(driveIdentifier, \"main\", [addFolder({\n\t\t\tid: folderId,\n\t\t\tname,\n\t\t\tparentFolder\n\t\t})], signal)).state.global?.nodes.find((n) => n.id === folderId);\n\t\tif (!node || !isFolderNode(node)) throw new Error(\"Folder creation failed\");\n\t\treturn node;\n\t}\n\tasync removeNode(driveIdentifier, nodeId, signal) {\n\t\tthis.logger.verbose(\"drives.removeNode(@driveIdentifier, @nodeId)\", driveIdentifier, nodeId);\n\t\tconst drive = await this.client.get(driveIdentifier, void 0, signal);\n\t\tconst node = drive.state.global.nodes.find((n) => n.id === nodeId);\n\t\tif (!node) {\n\t\t\tif (!await this.documentExists(nodeId, signal)) throw new Error(`Node ${nodeId} not found in drive ${driveIdentifier}`);\n\t\t\tawait this.removeFileNode(driveIdentifier, nodeId, signal);\n\t\t\treturn;\n\t\t}\n\t\tif (isFolderNode(node)) {\n\t\t\tconst fileDescendants = getDescendants(node, drive.state.global.nodes).filter(isFileNode);\n\t\t\tfor (const file of fileDescendants) await this.removeFileNode(driveIdentifier, file.id, signal);\n\t\t\tawait this.client.execute(driveIdentifier, \"main\", [deleteNode({ id: nodeId })], signal);\n\t\t\treturn;\n\t\t}\n\t\tawait this.removeFileNode(driveIdentifier, nodeId, signal);\n\t}\n\tasync renameNode(driveIdentifier, nodeId, name, signal) {\n\t\tthis.logger.verbose(\"drives.renameNode(@driveIdentifier, @nodeId, @name)\", driveIdentifier, nodeId, name);\n\t\tif ((await this.client.execute(nodeId, \"main\", [actions.setName({ name })], signal)).header.name !== name) throw new Error(\"Document rename did not apply\");\n\t\tconst node = (await this.client.execute(driveIdentifier, \"main\", [updateNode({\n\t\t\tid: nodeId,\n\t\t\tname\n\t\t})], signal)).state.global?.nodes.find((n) => n.id === nodeId);\n\t\tif (!node) throw new Error(\"Node missing from drive after rename\");\n\t\treturn node;\n\t}\n\tasync setPreferredEditorOnNode(nodeId, preferredEditor, signal) {\n\t\tthis.logger.verbose(\"drives.setPreferredEditorOnNode(@nodeId, @preferredEditor)\", nodeId, preferredEditor);\n\t\treturn this.client.setPreferredEditor(nodeId, preferredEditor, \"main\", signal);\n\t}\n\tasync moveNode(driveIdentifier, srcNodeId, targetParentFolderId, signal) {\n\t\tthis.logger.verbose(\"drives.moveNode(@driveIdentifier, @srcNodeId, @targetParentFolderId)\", driveIdentifier, srcNodeId, targetParentFolderId);\n\t\treturn this.client.execute(driveIdentifier, \"main\", [moveNode({\n\t\t\tsrcFolder: srcNodeId,\n\t\t\ttargetParentFolder: targetParentFolderId\n\t\t})], signal);\n\t}\n\tasync copyNode(driveIdentifier, srcNodeId, targetParentFolderId, signal) {\n\t\tthis.logger.verbose(\"drives.copyNode(@driveIdentifier, @srcNodeId, @targetParentFolderId)\", driveIdentifier, srcNodeId, targetParentFolderId);\n\t\tconst drive = await this.client.get(driveIdentifier, void 0, signal);\n\t\tconst srcNode = drive.state.global.nodes.find((n) => n.id === srcNodeId);\n\t\tif (!srcNode) throw new Error(`Node ${srcNodeId} not found in drive ${driveIdentifier}`);\n\t\tconst copyPlan = generateNodesCopy({\n\t\t\tsrcId: srcNodeId,\n\t\t\ttargetParentFolder: targetParentFolderId,\n\t\t\ttargetName: srcNode.name\n\t\t}, () => generateId(), drive.state.global.nodes);\n\t\tconst resolvedNamesByTargetId = /* @__PURE__ */ new Map();\n\t\tfor (const entry of copyPlan) {\n\t\t\tconst node = drive.state.global.nodes.find((n) => n.id === entry.srcId);\n\t\t\tif (!node) continue;\n\t\t\tconst resolved = handleTargetNameCollisions({\n\t\t\t\tnodes: drive.state.global.nodes,\n\t\t\t\tsrcName: entry.targetName || node.name,\n\t\t\t\tsrcKind: isFileNode(node) ? \"file\" : \"folder\",\n\t\t\t\ttargetParentFolder: entry.targetParentFolder ?? null\n\t\t\t});\n\t\t\tresolvedNamesByTargetId.set(entry.targetId, resolved);\n\t\t}\n\t\tfor (const entry of copyPlan) {\n\t\t\tconst node = drive.state.global.nodes.find((n) => n.id === entry.srcId);\n\t\t\tif (!node || !isFileNode(node)) continue;\n\t\t\tconst srcDoc = await this.client.get(entry.srcId, void 0, signal);\n\t\t\tconst duplicated = {\n\t\t\t\t...srcDoc,\n\t\t\t\theader: createPresignedHeader(entry.targetId, srcDoc.header.documentType),\n\t\t\t\tinitialState: srcDoc.state,\n\t\t\t\toperations: {}\n\t\t\t};\n\t\t\tconst resolvedName = resolvedNamesByTargetId.get(entry.targetId);\n\t\t\tif (resolvedName) duplicated.header.name = resolvedName;\n\t\t\tawait this.addFile(driveIdentifier, duplicated, entry.targetParentFolder ?? void 0, signal);\n\t\t}\n\t\treturn this.client.execute(driveIdentifier, \"main\", copyPlan.map((entry) => copyNode(entry)), signal);\n\t}\n\tasync getNode(driveIdentifier, nodeId, signal) {\n\t\tthis.logger.verbose(\"drives.getNode(@driveIdentifier, @nodeId)\", driveIdentifier, nodeId);\n\t\tconst node = (await this.client.get(driveIdentifier, void 0, signal)).state.global.nodes.find((n) => n.id === nodeId);\n\t\tif (!node) throw new Error(`Node ${nodeId} not found in drive ${driveIdentifier}`);\n\t\treturn node;\n\t}\n\tasync listNodes(driveIdentifier, parentFolder, paging, signal) {\n\t\tthis.logger.verbose(\"drives.listNodes(@driveIdentifier, @parentFolder, @paging)\", driveIdentifier, parentFolder, paging);\n\t\tconst allNodes = (await this.client.get(driveIdentifier, void 0, signal)).state.global.nodes;\n\t\tconst filtered = parentFolder === void 0 ? [...allNodes] : allNodes.filter((n) => (n.parentFolder ?? null) === parentFolder);\n\t\tconst { offset: startIndex, limit } = parsePagingOptions(paging, filtered.length);\n\t\tconst effective = paging ?? {\n\t\t\tcursor: \"\",\n\t\t\tlimit\n\t\t};\n\t\tconst endIndex = startIndex + limit;\n\t\treturn {\n\t\t\tresults: filtered.slice(startIndex, endIndex),\n\t\t\toptions: effective,\n\t\t\t...endIndex < filtered.length ? { nextCursor: String(endIndex) } : {},\n\t\t\ttotalCount: filtered.length\n\t\t};\n\t}\n\t/**\n\t* Runs one batch to completion, throwing the first failure. The thrown error\n\t* carries the job error's name, which is what callers classify on: an id\n\t* collision has to be told apart from a transient failure.\n\t*/\n\tasync runJobs(jobs, signal) {\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw this.toError(job);\n\t\treturn completedJobs;\n\t}\n\ttoError(job) {\n\t\tconst error = new Error(job.error?.message ?? \"Job failed\");\n\t\tif (job.error?.name) error.name = job.error.name;\n\t\treturn error;\n\t}\n\tasync documentExists(documentId, signal) {\n\t\ttry {\n\t\t\tawait this.client.get(documentId, void 0, signal);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\tasync removeFileNode(driveId, fileId, signal) {\n\t\tconst relationshipActions = await signActions([removeRelationshipAction(driveId, fileId, \"child\")], this.signer, signal);\n\t\tconst driveActions = await signActions([deleteNode({ id: fileId })], this.signer, signal);\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs: [{\n\t\t\tkey: \"relationship\",\n\t\t\tdocumentId: driveId,\n\t\t\tscope: getSharedActionScope(relationshipActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: relationshipActions,\n\t\t\tdependsOn: []\n\t\t}, {\n\t\t\tkey: \"drive\",\n\t\t\tdocumentId: driveId,\n\t\t\tscope: getSharedActionScope(driveActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: driveActions,\n\t\t\tdependsOn: [\"relationship\"]\n\t\t}] }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);\n\t\tconst deleteJob = await this.reactor.deleteDocument(fileId, this.signer, signal);\n\t\tconst deleteCompleted = await this.client.waitForJob(deleteJob, signal);\n\t\tif (deleteCompleted.status === JobStatus.FAILED) throw new Error(deleteCompleted.error?.message);\n\t}\n};\n//#endregion\n//#region src/shared/awaiter.ts\n/**\n* Checks if a job status is terminal (job has finished).\n* WRITE_READY is not terminal - it's an intermediate state.\n* Only READ_READY and FAILED are truly terminal.\n*/\nfunction isTerminalStatus(status) {\n\treturn status === JobStatus.READ_READY || status === JobStatus.FAILED;\n}\n/**\n* Event-driven implementation of IJobAwaiter.\n* Subscribes to operation events to detect job completion without polling.\n*/\nvar JobAwaiter = class {\n\tpendingJobs = /* @__PURE__ */ new Map();\n\tunsubscribers = [];\n\tconstructor(eventBus, getJobStatus) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.getJobStatus = getJobStatus;\n\t\tthis.subscribeToEvents();\n\t}\n\tsubscribeToEvents() {\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, async (_type, event) => {\n\t\t\tawait this.handleWriteReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_READ_READY, async (_type, event) => {\n\t\t\tawait this.handleReadReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, async (_type, event) => {\n\t\t\tawait this.handleJobFailed(event);\n\t\t}));\n\t}\n\tshutdown() {\n\t\tfor (const unsubscribe of this.unsubscribers) unsubscribe();\n\t\tthis.unsubscribers = [];\n\t\tfor (const [, waiters] of this.pendingJobs) for (const waiter of waiters) waiter.reject(/* @__PURE__ */ new Error(\"JobAwaiter destroyed\"));\n\t\tthis.pendingJobs.clear();\n\t}\n\tasync waitForJob(jobId, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst currentStatus = await this.getJobStatus(jobId, signal);\n\t\tif (isTerminalStatus(currentStatus.status)) return currentStatus;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst waiter = {\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t\tsignal\n\t\t\t};\n\t\t\tconst existingWaiters = this.pendingJobs.get(jobId) || [];\n\t\t\texistingWaiters.push(waiter);\n\t\t\tthis.pendingJobs.set(jobId, existingWaiters);\n\t\t\tif (signal) {\n\t\t\t\tconst abortHandler = () => {\n\t\t\t\t\tconst waiters = this.pendingJobs.get(jobId);\n\t\t\t\t\tif (waiters) {\n\t\t\t\t\t\tconst index = waiters.indexOf(waiter);\n\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\twaiters.splice(index, 1);\n\t\t\t\t\t\t\tif (waiters.length === 0) this.pendingJobs.delete(jobId);\n\t\t\t\t\t\t\twaiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", abortHandler, { once: true });\n\t\t\t}\n\t\t});\n\t}\n\tasync handleWriteReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tawait this.checkAndResolveWaiters(jobId);\n\t}\n\tasync handleReadReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tawait this.checkAndResolveWaiters(jobId);\n\t}\n\tasync handleJobFailed(event) {\n\t\tawait this.checkAndResolveWaiters(event.jobId);\n\t}\n\tasync checkAndResolveWaiters(jobId) {\n\t\tconst waiters = this.pendingJobs.get(jobId);\n\t\tif (!waiters || waiters.length === 0) return;\n\t\ttry {\n\t\t\tconst activeWaiters = waiters.filter((w) => !w.signal?.aborted);\n\t\t\tif (activeWaiters.length === 0) {\n\t\t\t\tthis.pendingJobs.delete(jobId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst jobInfo = await this.getJobStatus(jobId, activeWaiters[0].signal);\n\t\t\tif (isTerminalStatus(jobInfo.status)) {\n\t\t\t\tthis.pendingJobs.delete(jobId);\n\t\t\t\tfor (const waiter of activeWaiters) waiter.resolve(jobInfo);\n\t\t\t\tfor (const waiter of waiters) if (waiter.signal?.aborted) waiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.pendingJobs.delete(jobId);\n\t\t\tfor (const waiter of waiters) waiter.reject(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t}\n};\n//#endregion\n//#region src/client/cursor.ts\nconst COMPOSITE_PREFIX = \"c:\";\n/**\n* Returns true if the cursor is a composite multi-scope cursor.\n*/\nfunction isCompositeCursor(cursor) {\n\treturn cursor.startsWith(COMPOSITE_PREFIX);\n}\n/**\n* Encodes per-scope cursors into a single composite cursor string.\n* Only scopes that still have more results should be included.\n*/\nfunction encodeCompositeCursor(scopeCursors) {\n\treturn COMPOSITE_PREFIX + JSON.stringify(scopeCursors);\n}\n/**\n* Decodes a composite cursor string into a map of scope to cursor.\n* Throws if the cursor is not a valid composite cursor.\n*/\nfunction decodeCompositeCursor(cursor) {\n\tif (!cursor.startsWith(COMPOSITE_PREFIX)) throw new Error(\"Invalid composite cursor format\");\n\tconst json = cursor.slice(2);\n\ttry {\n\t\tconst parsed = JSON.parse(json);\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) throw new Error(\"Invalid composite cursor format\");\n\t\treturn parsed;\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError) throw new Error(\"Invalid composite cursor format\", { cause: error });\n\t\tthrow error;\n\t}\n}\n//#endregion\n//#region src/client/types.ts\n/**\n* Describes the types of document changes that can occur.\n*/\nlet DocumentChangeType = /* @__PURE__ */ function(DocumentChangeType) {\n\tDocumentChangeType[\"Created\"] = \"created\";\n\tDocumentChangeType[\"Deleted\"] = \"deleted\";\n\tDocumentChangeType[\"Updated\"] = \"updated\";\n\tDocumentChangeType[\"ParentAdded\"] = \"parent_added\";\n\tDocumentChangeType[\"ParentRemoved\"] = \"parent_removed\";\n\tDocumentChangeType[\"ChildAdded\"] = \"child_added\";\n\tDocumentChangeType[\"ChildRemoved\"] = \"child_removed\";\n\treturn DocumentChangeType;\n}({});\n//#endregion\n//#region src/decision/read-gate.ts\n/**\n* Scopes every holder of a document may read, whatever the grants say. Denying\n* the policy itself would let a replica sync a document without it, read the\n* auth scope as uninitialized, and allow every operation it holds, so replicas\n* would diverge permanently. The document scope carries the metadata the same\n* argument covers. Grants gate domain-scope reads only.\n*/\nconst ALWAYS_READABLE_SCOPES = new Set([\"auth\", \"document\"]);\n/** What a gate does with an uninitialized policy when told nothing. */\nconst OPEN_BY_DEFAULT = { withholdUninitialized: false };\n/**\n* The branch a group is read on. A group's member list lives on its main\n* branch whatever branch the document naming it is on, and the reference\n* relation records no branch of its own.\n*/\nconst GROUP_BRANCH = \"main\";\n/**\n* The scope of a group document that holds its member list. It is the only\n* scope group serving reaches, because it is the only one the audience must\n* fold in order to evaluate auth with the group.\n*/\nconst GROUP_MEMBERSHIP_SCOPE = \"global\";\n/**\n* How many of a group's referencing documents are examined before a read of\n* that group gives up and withholds. Each one costs a model build, and the\n* relation is append-only, so an old and briefly-held reference still counts.\n* Truncating denies, which is the direction that withholds. It is the cap a\n* version-1 policy carries on its own grant list, taken from there rather than\n* restated: raising that cap raises the read fan-out here.\n*/\nconst MAX_EXAMINED_REFERENCERS = MAX_AUTH_GRANTS;\n/**\n* How many referencers are probed at once. The reactor's Postgres pool size is\n* optional and defaults to ten, and a listing resolves one gate per result, so\n* per-gate fan-out multiplies: a handful keeps one group read from claiming the\n* whole pool while still cutting the walk several times over. On PGlite the\n* queries serialize regardless, so a larger number buys nothing in a browser.\n*/\nconst REFERENCER_PROBE_CONCURRENCY = 4;\n/**\n* The policy carried on a document, if it carries one. A document handed to the\n* gate with no state at all is not policied, so it is not gated.\n*/\nfunction authOf(document) {\n\treturn document.state?.auth;\n}\n/**\n* The model reads enforce. Below `authEnforcement` there is no model to\n* enforce: the document-only model ignores the auth scope entirely, so reading\n* through it would serve every domain scope of a policied document to anyone.\n* Undefined therefore means \"evaluate the policy alone\", which is what the read\n* surface did before the model existed.\n*/\nfunction readDecisionModel(flags, registry) {\n\treturn flags.authEnforcement ? selectDecisionModel(flags, registry) : void 0;\n}\n/**\n* Evaluates the policy on its own, with no groups map and no condition context.\n* A `{ group }` or conditional grant therefore never applies: an allow that\n* does not apply withholds access, so this cannot widen a policy, but a policy\n* relying on a conditional deny is weaker here than it is written.\n*/\nvar BareReadGate = class {\n\tscopePredicate(document, subject) {\n\t\tconst auth = authOf(document);\n\t\treturn Promise.resolve((scope) => ALWAYS_READABLE_SCOPES.has(scope) || decide(auth, subject, {\n\t\t\tverb: \"read\",\n\t\t\tscope\n\t\t}) === \"allow\");\n\t}\n};\n/**\n* Answers a stream read from the document already fetched, and anything else\n* through the read side.\n*\n* The seed is why routing reads through a decision model costs no extra I/O for\n* the document being read: its `document` and `auth` scopes are the two static\n* projections, and the caller has both in hand. Only a group stream the grant\n* list names is fetched.\n*/\nvar SeededStateReader = class {\n\tconstructor(documentView, seed, branch) {\n\t\tthis.documentView = documentView;\n\t\tthis.seed = seed;\n\t\tthis.branch = branch;\n\t}\n\t/**\n\t* A stream this replica does not hold has to reach buildDecisionModel as the\n\t* absence it recognises, or the whole read fails instead of leaving the group\n\t* out of the model, where its principal does not match and the policy fails\n\t* closed. The read side reports absence as a plain Error, so the absence is\n\t* confirmed rather than inferred from the message: a transient failure must\n\t* surface, not silently deny.\n\t*/\n\tasync getState(documentId, scope, branch, targetRevision, signal) {\n\t\tif (targetRevision === void 0 && documentId === this.seed.header.id && branch === this.branch && scope in this.seed.state) return this.seed;\n\t\ttry {\n\t\t\treturn await this.documentView.get(documentId, {\n\t\t\t\tbranch,\n\t\t\t\tscopes: [scope]\n\t\t\t}, void 0, signal);\n\t\t} catch (error) {\n\t\t\tawait this.assertAbsent(documentId, error, signal);\n\t\t\tthrow new DocumentNotFoundError(documentId);\n\t\t}\n\t}\n\tasync assertAbsent(documentId, error, signal) {\n\t\tif (DocumentNotFoundError.isError(error)) return;\n\t\tlet exists;\n\t\ttry {\n\t\t\texists = await this.documentView.exists([documentId], DocumentExistence.LiveOnly, void 0, signal);\n\t\t} catch {\n\t\t\tthrow error;\n\t\t}\n\t\tif (exists[0]) throw error;\n\t}\n};\n/**\n* Evaluates a read against the registered decision model, built at the stream\n* heads. This is what makes `{ group }` principals and conditional grants apply\n* to a read: the model supplies the groups map and the scope's own state, the\n* same two things admission supplies.\n*\n* A read has no action, so a condition on `action.input.*` never holds for one.\n*\n* State is read through the read side rather than the write cache. The write\n* cache is invalidated by whichever process runs the executor, so a reactor\n* running its executors in worker processes would answer reads in the parent\n* from state no commit ever invalidates.\n*/\nvar ModelReadGate = class {\n\tconstructor(model, documentView, servesGroups, operationIndex, logger, options = OPEN_BY_DEFAULT) {\n\t\tthis.model = model;\n\t\tthis.documentView = documentView;\n\t\tthis.servesGroups = servesGroups;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.logger = logger;\n\t\tthis.options = options;\n\t}\n\t/**\n\t* A served group yields its member list and nothing else. What the audience\n\t* is owed is the state it must fold to evaluate auth with the group; a\n\t* group's other scopes are its own business and stay behind its own grants.\n\t*/\n\tasync scopePredicate(document, subject, branch, signal) {\n\t\tconst own = await this.ownPolicyPredicate(document, subject, branch, signal);\n\t\tif (!this.servesGroup(document) || own(GROUP_MEMBERSHIP_SCOPE)) return own;\n\t\tconst audience = await this.servesGroupTo(document.header.id, subject, signal);\n\t\treturn (scope) => own(scope) || audience && scope === GROUP_MEMBERSHIP_SCOPE;\n\t}\n\t/**\n\t* Whether the subject is served this group because a policy names it.\n\t*\n\t* A replica must fold a group's membership to evaluate auth with it, so a\n\t* group a grant names is served to the audience of the document that names\n\t* it, whatever the group's own read grants say. Naming a group in a policy\n\t* publishes its roster to that policy's audience; a group whose membership\n\t* must stay confidential does not belong in a grant.\n\t*\n\t* The referencing document's own domain scopes are the test. Its `auth` and\n\t* `document` scopes are readable by every holder, so testing those would\n\t* serve every referenced group to everybody.\n\t*\n\t* One level only. A referencer that is itself a group is skipped, and a\n\t* referencer's own readability is decided from its policy alone, so a\n\t* reference cycle terminates. Cycles are reachable: the reference relation\n\t* is recorded from an operation's input, including one later stored denied,\n\t* so a refused grant naming a group from inside another group leaves a row\n\t* behind that validation never saw.\n\t*\n\t* The referencers are probed a few at a time and the walk stops at the first\n\t* that serves, because a subject outside the audience is the case that runs to\n\t* the bound, and it is the common one. A probe that failed decides only when\n\t* nothing served: serving rests on a real allow, so this cannot widen, and it\n\t* stops one unreachable referencer from turning an allow already in hand into\n\t* a denial. A read records no operation, so replicas differing over a\n\t* transient failure has no consensus consequence.\n\t*\n\t* The probes are awaited together rather than raced, so none is ever left\n\t* running with nobody awaiting it, which is where unhandled rejections come\n\t* from.\n\t*/\n\tasync servesGroupTo(groupId, subject, signal) {\n\t\tif (!this.operationIndex) return false;\n\t\tconst referencers = await this.operationIndex.getGroupReferencers(groupId, signal);\n\t\tconst examined = referencers.slice(0, MAX_EXAMINED_REFERENCERS);\n\t\tif (examined.length < referencers.length) this.logger?.warn(`Group ${groupId} is referenced by ${referencers.length} documents; only the first ${MAX_EXAMINED_REFERENCERS} decide whether it is served`);\n\t\tconst walk = {\n\t\t\tnext: 0,\n\t\t\tserved: false,\n\t\t\tfailure: void 0\n\t\t};\n\t\tconst probe = async () => {\n\t\t\twhile (!walk.served && walk.next < examined.length) {\n\t\t\t\tconst referencerId = examined[walk.next++];\n\t\t\t\tlet serves = false;\n\t\t\t\ttry {\n\t\t\t\t\tserves = await this.servesThrough(referencerId, subject, signal);\n\t\t\t\t} catch (error) {\n\t\t\t\t\twalk.failure ??= Error.isError(error) ? error : /* @__PURE__ */ new Error(`Probing referencer ${referencerId} failed`);\n\t\t\t\t}\n\t\t\t\tif (serves) walk.served = true;\n\t\t\t}\n\t\t};\n\t\tawait Promise.all(Array.from({ length: Math.min(REFERENCER_PROBE_CONCURRENCY, examined.length) }, probe));\n\t\tif (!walk.served && walk.failure) throw walk.failure;\n\t\treturn walk.served;\n\t}\n\t/**\n\t* Whether one referencing document serves the subject any domain scope. A\n\t* referencer this replica does not hold serves nothing, which fails closed\n\t* the same way a group it does not hold does.\n\t*/\n\tasync servesThrough(referencerId, subject, signal) {\n\t\tlet referencer;\n\t\ttry {\n\t\t\treferencer = await this.documentView.get(referencerId, { branch: GROUP_BRANCH }, void 0, signal);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.servesGroup(referencer)) return false;\n\t\tconst readable = await this.ownPolicyPredicate(referencer, subject, GROUP_BRANCH, signal);\n\t\treturn Object.keys(referencer.state ?? {}).filter((scope) => !ALWAYS_READABLE_SCOPES.has(scope)).some((scope) => readable(scope));\n\t}\n\tservesGroup(document) {\n\t\treturn this.servesGroups && this.operationIndex !== void 0 && document.header.documentType === groupDocumentType;\n\t}\n\t/**\n\t* What this document's own policy says, with no group serving applied.\n\t*\n\t* An unpoliced document is readable in full unless the host closes by default,\n\t* and either way it is the common case and the one worth answering without\n\t* building anything. The test is the one `evaluate` makes: a legacy `{}` auth\n\t* scope and version 0 both mean uninitialized, and \"no grants\" does not,\n\t* because a policy with a version and an empty grant list denies everything.\n\t*\n\t* Closing here rather than around the gate is what keeps a policy able to\n\t* publish an unpoliced group it names: the referencer walk asks this question\n\t* of the referencing document, whose real policy answers it.\n\t*/\n\tasync ownPolicyPredicate(document, subject, branch, signal) {\n\t\tconst auth = authOf(document);\n\t\tif (!auth || !auth.version) return this.options.withholdUninitialized ? (scope) => ALWAYS_READABLE_SCOPES.has(scope) : () => true;\n\t\tconst target = {\n\t\t\tdocumentId: document.header.id,\n\t\t\tbranch\n\t\t};\n\t\tconst built = await buildDecisionModel(new SeededStateReader(this.documentView, document, branch), this.model, target, signal);\n\t\tconst definition = this.model(target);\n\t\tconst scopeStates = document.state ?? {};\n\t\treturn (scope) => ALWAYS_READABLE_SCOPES.has(scope) || definition.decide(built.model, subject, {\n\t\t\tverb: \"read\",\n\t\t\tscope\n\t\t}, {\n\t\t\tscopeState: scopeStates[scope],\n\t\t\tactionInput: void 0\n\t\t}).decision === \"allow\";\n\t}\n};\n//#endregion\n//#region src/client/util.ts\nfunction authSubjectFromSigner(signer) {\n\treturn {\n\t\taddress: signer.user?.address,\n\t\tkey: signer.app?.key\n\t};\n}\nfunction withAuthScope(view) {\n\tif (view?.scopes && view.scopes.length > 0) return {\n\t\t...view,\n\t\tscopes: [...new Set([...view.scopes, \"auth\"])]\n\t};\n\treturn view;\n}\n/**\n* Drops the scopes the predicate refuses. The predicate is resolved by the read\n* gate, which decides against the whole policy once per document; this only\n* applies the answer, so it stays synchronous.\n*/\nfunction filterReadableScopes(document, readable) {\n\tconst state = document.state;\n\tif (!state) return document;\n\treturn {\n\t\t...document,\n\t\tstate: keepReadableScopes(state, readable),\n\t\tinitialState: keepReadableScopes(document.initialState, readable)\n\t};\n}\nfunction keepReadableScopes(scopes, readable) {\n\tif (!scopes) return scopes;\n\tconst kept = {};\n\tfor (const scope of Object.keys(scopes)) if (readable(scope)) kept[scope] = scopes[scope];\n\treturn kept;\n}\n//#endregion\n//#region src/client/reactor-client.ts\n/**\n* The document a candidate is decided against. Routed on the action type alone,\n* which is what the executor routes on: every action the reactor reduces onto\n* the document scope carries that scope already, and the gate follows the\n* action's own target rather than the document the request named.\n*/\nfunction evaluationTargetId(candidate, fallback) {\n\treturn GATED_DOCUMENT_ACTIONS.has(candidate.type) ? targetDocumentId({\n\t\ttype: candidate.type,\n\t\tinput: candidate.input\n\t}, fallback) : fallback;\n}\n/**\n* One candidate's verdict, decided exactly as admission decides it: the same\n* request, and a condition context populated only while authConditions is on,\n* so a conditional grant applies here precisely when it would apply there.\n* Groups need nothing added, because the selected model carries them.\n*/\nfunction decideCandidate(config, target, subject, candidate) {\n\treturn target.definition.decide(target.model, subject, {\n\t\tverb: \"execute\",\n\t\tscope: candidate.scope,\n\t\toperation: candidate.type\n\t}, config.flags.authConditions ? {\n\t\tscopeState: target.scopeStates[candidate.scope],\n\t\tactionInput: candidate.input\n\t} : {\n\t\tscopeState: void 0,\n\t\tactionInput: void 0\n\t});\n}\n/**\n* ReactorClient implementation that wraps lower-level APIs to provide\n* a simpler interface for document operations.\n*\n* Features:\n* - Wraps Jobs with Promises for easier async handling\n* - Manages signing of submitted Action objects\n* - Provides quality-of-life functions for common tasks\n* - Wraps subscription interface with ViewFilters\n*/\nvar ReactorClient = class {\n\tlogger;\n\treactor;\n\tsigner;\n\tsubscriptionManager;\n\tjobAwaiter;\n\tdocumentIndexer;\n\tdocumentView;\n\treadGate;\n\tactionEvaluation;\n\tdrives;\n\tconstructor(logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, readGate = new BareReadGate(), actionEvaluation) {\n\t\tthis.logger = logger;\n\t\tthis.reactor = reactor;\n\t\tthis.signer = signer;\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\tthis.jobAwaiter = jobAwaiter;\n\t\tthis.documentIndexer = documentIndexer;\n\t\tthis.documentView = documentView;\n\t\tthis.readGate = readGate;\n\t\tthis.actionEvaluation = actionEvaluation;\n\t\tthis.drives = new DriveClient(this, logger, reactor, signer);\n\t\tthis.logger.verbose(\"ReactorClient initialized\");\n\t}\n\treadSubject(subject) {\n\t\treturn subject ?? authSubjectFromSigner(this.signer);\n\t}\n\t/**\n\t* Which scopes of one document the subject may read. Resolved once per\n\t* document, so the gate builds its model once however many scopes are then\n\t* tested, and the filtering itself stays synchronous.\n\t*/\n\treadableScopes(document, view, signal) {\n\t\treturn this.readGate.scopePredicate(document, this.readSubject(view?.subject), view?.branch ?? \"main\", signal);\n\t}\n\t/**\n\t* One document, filtered to the scopes the subject may read. Every method\n\t* that hands a document back goes through here, including the ones that\n\t* follow a write: a document returned from a mutation is a read like any\n\t* other, and returning it whole served scopes the same subject would be\n\t* refused by `get`. Its author still sees what it wrote, because an allow on\n\t* execute confers read of that scope.\n\t*/\n\tasync gateDocument(document, view, signal) {\n\t\treturn filterReadableScopes(document, await this.readableScopes(document, view, signal));\n\t}\n\t/**\n\t* Retrieves a list of document model modules.\n\t*/\n\tasync getDocumentModelModules(namespace, paging, signal) {\n\t\tthis.logger.verbose(\"getDocumentModels(@namespace, @paging)\", namespace, paging);\n\t\treturn this.reactor.getDocumentModels(namespace, paging, signal);\n\t}\n\t/**\n\t* Retrieves a specific document model module by document type.\n\t*\n\t* @param documentType - The document type identifier\n\t* @returns The document model module\n\t*/\n\tasync getDocumentModelModule(documentType) {\n\t\tconst modules = await this.reactor.getDocumentModels();\n\t\tlet latestModule;\n\t\tlet latestVersion = -1;\n\t\tfor (const module of modules.results) {\n\t\t\tif (module.documentModel.global.id !== documentType) continue;\n\t\t\tconst version = module.version ?? 1;\n\t\t\tif (version > latestVersion) {\n\t\t\t\tlatestVersion = version;\n\t\t\t\tlatestModule = module;\n\t\t\t}\n\t\t}\n\t\tif (!latestModule) throw new Error(`Document model module not found for type: ${documentType}`);\n\t\treturn latestModule;\n\t}\n\t/**\n\t* Retrieves the document model module matching the version the document is\n\t* stamped with, so not-yet-upgraded documents get the reducer their\n\t* history was written with rather than the latest.\n\t*/\n\tasync getDocumentModelModuleForDocument(document) {\n\t\tconst documentType = document.header.documentType;\n\t\tconst version = normalizeDocumentModelVersion(document.state.document?.version);\n\t\tconst modules = await this.reactor.getDocumentModels();\n\t\tconst availableVersions = [];\n\t\tfor (const module of modules.results) {\n\t\t\tif (module.documentModel.global.id !== documentType) continue;\n\t\t\tconst moduleVersion = normalizeDocumentModelVersion(module.version);\n\t\t\tif (moduleVersion === version) return module;\n\t\t\tavailableVersions.push(moduleVersion);\n\t\t}\n\t\tthrow new UnsupportedDocumentModelVersionError(documentType, version, availableVersions.sort((a, b) => a - b));\n\t}\n\t/**\n\t* Retrieves a specific PHDocument\n\t*/\n\tasync get(identifier, view, signal) {\n\t\tthis.logger.verbose(\"get(@identifier, @view)\", identifier, view);\n\t\tconst document = await this.reactor.getByIdOrSlug(identifier, withAuthScope(view), void 0, signal);\n\t\treturn this.gateDocument(document, view, signal);\n\t}\n\t/**\n\t* Resolves an identifier (id or slug) to the canonical document id, using the\n\t* same lookup as the data path. Resolves against the \"main\" branch. Throws if\n\t* the identifier cannot be resolved or is ambiguous.\n\t*/\n\tasync resolveIdOrSlug(identifier, view, signal) {\n\t\treturn this.documentView.resolveIdOrSlug(identifier, view, void 0, signal);\n\t}\n\t/** True when the id is taken; a soft-deleted document's id is still taken. */\n\tasync isDocumentIdTaken(documentId, signal) {\n\t\tthis.logger.verbose(\"isDocumentIdTaken(@documentId)\", documentId);\n\t\treturn (await this.documentView.exists([documentId], DocumentExistence.IncludingDeleted, void 0, signal))[0];\n\t}\n\t/**\n\t* Retrieves operations for a document\n\t*/\n\tasync getOperations(documentIdentifier, view, filter, paging, signal) {\n\t\tthis.logger.verbose(\"getOperations(@documentIdentifier, @view, @filter, @paging)\", documentIdentifier, view, filter, paging);\n\t\tconst documentId = await this.documentView.resolveIdOrSlug(documentIdentifier, view, void 0, signal);\n\t\tconst gated = await this.reactor.getByIdOrSlug(documentId, withAuthScope(view), void 0, signal);\n\t\tconst canRead = await this.readableScopes(gated, view, signal);\n\t\tif (paging?.cursor && isCompositeCursor(paging.cursor)) return this.getOperationsWithCompositeCursor(documentId, view, filter, paging, signal, canRead);\n\t\tconst operationsByScope = await this.reactor.getOperations(documentId, view, filter, paging, void 0, signal);\n\t\tfor (const scope of Object.keys(operationsByScope)) if (!canRead(scope)) delete operationsByScope[scope];\n\t\tconst scopeEntries = Object.entries(operationsByScope);\n\t\tconst effectivePaging = paging || {\n\t\t\tcursor: \"0\",\n\t\t\tlimit: 100\n\t\t};\n\t\tif (scopeEntries.length <= 1) {\n\t\t\tconst allOperations = scopeEntries.length === 1 ? [...scopeEntries[0][1].results] : [];\n\t\t\tallOperations.sort((a, b) => a.index - b.index);\n\t\t\treturn {\n\t\t\t\tresults: allOperations,\n\t\t\t\toptions: effectivePaging,\n\t\t\t\tnextCursor: scopeEntries.length === 1 ? scopeEntries[0][1].nextCursor : void 0\n\t\t\t};\n\t\t}\n\t\tconst allOperations = [];\n\t\tconst activeCursors = {};\n\t\tfor (const [scopeName, scopeResults] of scopeEntries) {\n\t\t\tallOperations.push(...scopeResults.results);\n\t\t\tif (scopeResults.nextCursor) activeCursors[scopeName] = scopeResults.nextCursor;\n\t\t}\n\t\tallOperations.sort((a, b) => a.index - b.index);\n\t\treturn {\n\t\t\tresults: allOperations,\n\t\t\toptions: effectivePaging,\n\t\t\tnextCursor: Object.keys(activeCursors).length > 0 ? encodeCompositeCursor(activeCursors) : void 0\n\t\t};\n\t}\n\tasync getOperationsWithCompositeCursor(documentId, view, filter, paging, signal, canRead) {\n\t\tconst scopeCursors = decodeCompositeCursor(paging.cursor);\n\t\tconst allOperations = [];\n\t\tconst activeCursors = {};\n\t\tfor (const [scopeName, cursor] of Object.entries(scopeCursors)) {\n\t\t\tif (!canRead(scopeName)) continue;\n\t\t\tconst scopeView = {\n\t\t\t\t...view,\n\t\t\t\tscopes: [scopeName]\n\t\t\t};\n\t\t\tconst scopePaging = {\n\t\t\t\tcursor,\n\t\t\t\tlimit: paging.limit\n\t\t\t};\n\t\t\tconst scopeResult = (await this.reactor.getOperations(documentId, scopeView, filter, scopePaging, void 0, signal))[scopeName];\n\t\t\tallOperations.push(...scopeResult.results);\n\t\t\tif (scopeResult.nextCursor) activeCursors[scopeName] = scopeResult.nextCursor;\n\t\t}\n\t\tallOperations.sort((a, b) => a.index - b.index);\n\t\treturn {\n\t\t\tresults: allOperations,\n\t\t\toptions: paging,\n\t\t\tnextCursor: Object.keys(activeCursors).length > 0 ? encodeCompositeCursor(activeCursors) : void 0\n\t\t};\n\t}\n\t/**\n\t* Retrieves outgoing relationships of a given type from a source document.\n\t*/\n\tasync getOutgoingRelationships(sourceIdentifier, relationshipType, view, paging, signal) {\n\t\tthis.logger.verbose(\"getOutgoingRelationships(@sourceIdentifier, @relationshipType, @view, @paging)\", sourceIdentifier, relationshipType, view, paging);\n\t\tconst sourceId = await this.documentView.resolveIdOrSlug(sourceIdentifier, view, void 0, signal);\n\t\tconst targetIds = (await this.documentIndexer.getOutgoing(sourceId, [relationshipType], void 0, void 0, signal)).results.map((rel) => rel.targetId);\n\t\tif (targetIds.length === 0) return {\n\t\t\tresults: [],\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: 0\n\t\t\t}\n\t\t};\n\t\treturn this.find({ ids: targetIds }, view, paging, signal);\n\t}\n\t/**\n\t* Retrieves incoming relationships of a given type to a target document.\n\t*/\n\tasync getIncomingRelationships(targetIdentifier, relationshipType, view, paging, signal) {\n\t\tthis.logger.verbose(\"getIncomingRelationships(@targetIdentifier, @relationshipType, @view, @paging)\", targetIdentifier, relationshipType, view, paging);\n\t\tconst targetId = await this.documentView.resolveIdOrSlug(targetIdentifier, view, void 0, signal);\n\t\tconst sourceIds = (await this.documentIndexer.getIncoming(targetId, [relationshipType], void 0, void 0, signal)).results.map((rel) => rel.sourceId);\n\t\tif (sourceIds.length === 0) return {\n\t\t\tresults: [],\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: 0\n\t\t\t}\n\t\t};\n\t\treturn this.find({ ids: sourceIds }, view, paging, signal);\n\t}\n\t/**\n\t* Filters documents by criteria and returns a list of them\n\t*/\n\tasync find(search, view, paging, signal) {\n\t\tthis.logger.verbose(\"find(@search, @view, @paging)\", search, view, paging);\n\t\tconst results = await this.reactor.find(search, withAuthScope(view), paging, void 0, signal);\n\t\treturn {\n\t\t\t...results,\n\t\t\tresults: await Promise.all(results.results.map(async (doc) => filterReadableScopes(doc, await this.readableScopes(doc, view, signal))))\n\t\t};\n\t}\n\t/**\n\t* Predicts the admission verdict for each candidate. See\n\t* {@link IReactorClient.evaluateActions} for the contract and its caveats.\n\t*\n\t* Read-only throughout, and never through the write cache: that cache is\n\t* invalidated by whichever process runs the executor, so a reactor running\n\t* its executors in worker processes would answer here from state no commit\n\t* ever invalidates.\n\t*/\n\tasync evaluateActions(documentIdentifier, branch, candidates, subject, signal) {\n\t\tthis.logger.verbose(\"evaluateActions(@documentIdentifier, @branch, @count candidates)\", documentIdentifier, branch, candidates.length);\n\t\tconst config = this.actionEvaluation;\n\t\tif (config === void 0) throw new AuthEnforcementDisabledError();\n\t\tconst decidedSubject = this.readSubject(subject);\n\t\tconst resolvedId = await this.documentView.resolveIdOrSlug(documentIdentifier, { branch }, void 0, signal);\n\t\tconst targets = /* @__PURE__ */ new Map();\n\t\tconst evaluations = [];\n\t\tfor (const candidate of candidates) {\n\t\t\tif (candidate.type === \"CREATE_DOCUMENT\") {\n\t\t\t\tevaluations.push({ decision: \"allow\" });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst targetId = evaluationTargetId(candidate, resolvedId);\n\t\t\tlet target = targets.get(targetId);\n\t\t\tif (target === void 0) {\n\t\t\t\ttarget = await this.buildEvaluationTarget(config, targetId, branch, signal);\n\t\t\t\ttargets.set(targetId, target);\n\t\t\t}\n\t\t\tevaluations.push(decideCandidate(config, target, decidedSubject, candidate));\n\t\t}\n\t\tconst allowed = evaluations.filter((evaluation) => evaluation.decision === \"allow\").length;\n\t\treturn {\n\t\t\tevaluations,\n\t\t\tallAllowed: candidates.length > 0 && allowed === candidates.length,\n\t\t\tanyAllowed: allowed > 0,\n\t\t\tallDenied: candidates.length > 0 && allowed === 0,\n\t\t\tanyDenied: allowed < candidates.length\n\t\t};\n\t}\n\t/**\n\t* The decision model for one target document, built at its stream heads.\n\t*\n\t* The document is fetched unfiltered, because the policy is what decides:\n\t* reading it through the read gate would withhold the very scopes the\n\t* decision is about. A deleted document is served at its deletion boundary,\n\t* which is what lets the model refuse an execute against it -- authEnforcement\n\t* requires documentDecisions, so that read is available whenever this runs.\n\t*\n\t* Reading past the gate discloses nothing a submit does not. The `auth` and\n\t* `document` scopes are readable by every holder, so a verdict resting on the\n\t* policy alone is one the caller could compute unaided; and a verdict resting\n\t* on a conditional grant reads the executing scope's state exactly as\n\t* admission reads it, so the answer here is what submitting and being refused\n\t* would have revealed anyway.\n\t*\n\t* The append condition the build records is dropped. It guards a write, and\n\t* this makes none; reproducing it is also what the preflight cannot do, which\n\t* is why the answer is a prediction.\n\t*/\n\tasync buildEvaluationTarget(config, documentId, branch, signal) {\n\t\tconst document = await this.documentView.get(documentId, { branch }, void 0, signal);\n\t\tconst target = {\n\t\t\tdocumentId,\n\t\t\tbranch\n\t\t};\n\t\tconst built = await buildDecisionModel(new SeededStateReader(this.documentView, document, branch), config.model, target, signal);\n\t\treturn {\n\t\t\tdefinition: config.model(target),\n\t\t\tmodel: built.model,\n\t\t\tscopeStates: document.state ?? {}\n\t\t};\n\t}\n\t/**\n\t* Creates a document and waits for completion\n\t*/\n\tasync create(document, parentIdentifier, signal) {\n\t\tthis.logger.verbose(\"create(@id, @parentIdentifier)\", document.header.id, parentIdentifier);\n\t\tconst documentId = document.header.id;\n\t\tconst createActions = await signActions([createDocumentAction({\n\t\t\tmodel: document.header.documentType,\n\t\t\tversion: 0,\n\t\t\tdocumentId,\n\t\t\tsigning: {\n\t\t\t\tsignature: documentId,\n\t\t\t\tpublicKey: document.header.sig.publicKey,\n\t\t\t\tnonce: document.header.sig.nonce,\n\t\t\t\tcreatedAtUtcIso: document.header.createdAtUtcIso,\n\t\t\t\tdocumentType: document.header.documentType\n\t\t\t},\n\t\t\tslug: document.header.slug,\n\t\t\tname: document.header.name,\n\t\t\tbranch: document.header.branch,\n\t\t\tmeta: document.header.meta,\n\t\t\tprotocolVersions: document.header.protocolVersions ?? { \"base-reducer\": 2 }\n\t\t}), upgradeDocumentAction({\n\t\t\tdocumentId,\n\t\t\tmodel: document.header.documentType,\n\t\t\tfromVersion: 0,\n\t\t\ttoVersion: normalizeDocumentModelVersion(document.state.document?.version),\n\t\t\tinitialState: document.state\n\t\t})], this.signer, signal);\n\t\tconst jobs = [{\n\t\t\tkey: \"create\",\n\t\t\tdocumentId,\n\t\t\tscope: getSharedActionScope(createActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: createActions,\n\t\t\tdependsOn: []\n\t\t}];\n\t\tif (parentIdentifier) {\n\t\t\tconst parentActions = await signActions([addRelationshipAction(parentIdentifier, documentId, \"child\")], this.signer, signal);\n\t\t\tjobs.push({\n\t\t\t\tkey: \"parent\",\n\t\t\t\tdocumentId: parentIdentifier,\n\t\t\t\tscope: getSharedActionScope(parentActions),\n\t\t\t\tbranch: \"main\",\n\t\t\t\tactions: parentActions,\n\t\t\t\tdependsOn: [\"create\"]\n\t\t\t});\n\t\t}\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);\n\t\tconst created = await this.reactor.get(documentId);\n\t\treturn this.gateDocument(created, void 0, signal);\n\t}\n\t/**\n\t* Creates an empty document and waits for completion\n\t*/\n\tasync createEmpty(documentModelType, options, signal) {\n\t\tthis.logger.verbose(\"createEmpty(@documentModelType, @options)\", documentModelType, options);\n\t\tconst matchingModules = (await this.reactor.getDocumentModels(void 0, void 0, signal)).results.filter((m) => m.documentModel.global.id === documentModelType);\n\t\tlet module;\n\t\tif (options?.documentModelVersion !== void 0) {\n\t\t\tconst requestedVersion = normalizeDocumentModelVersion(options.documentModelVersion);\n\t\t\tmodule = matchingModules.find((m) => normalizeDocumentModelVersion(m.version) === requestedVersion);\n\t\t\tif (!module) throw new Error(`Document model not found for type: ${documentModelType} with version: ${options.documentModelVersion}`);\n\t\t} else {\n\t\t\tmodule = matchingModules.reduce((latest, current) => {\n\t\t\t\tif (latest === void 0) return current;\n\t\t\t\treturn normalizeDocumentModelVersion(current.version) > normalizeDocumentModelVersion(latest.version) ? current : latest;\n\t\t\t}, void 0);\n\t\t\tif (!module) throw new Error(`Document model not found for type: ${documentModelType}`);\n\t\t}\n\t\tconst document = module.utils.createDocument();\n\t\tdocument.state.document.version = normalizeDocumentModelVersion(module.version);\n\t\treturn this.create(document, options?.parentIdentifier, signal);\n\t}\n\t/**\n\t* Upgrades a document to a newer document model version by dispatching an\n\t* UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the\n\t* latest registered module version for the document's type. Returns the\n\t* document unchanged when it is already at the target version.\n\t*\n\t* The executor validates the action's version and revision snapshot against\n\t* the state the migration actually runs on. When a concurrent edit\n\t* invalidates the snapshot, the upgrade is rebuilt from a fresh read and\n\t* retried up to maxConflictRetries times before the conflict is surfaced.\n\t*/\n\tasync upgradeDocument(documentIdentifier, toVersion, options, signal) {\n\t\tthis.logger.verbose(\"upgradeDocument(@documentIdentifier, @toVersion)\", documentIdentifier, toVersion);\n\t\tconst maxConflictRetries = options?.maxConflictRetries ?? 3;\n\t\tlet lastConflictMessage = \"\";\n\t\tfor (let attempt = 0; attempt <= maxConflictRetries; attempt++) {\n\t\t\tconst document = await this.reactor.getByIdOrSlug(documentIdentifier, void 0, void 0, signal);\n\t\t\tconst documentId = document.header.id;\n\t\t\tconst documentType = document.header.documentType;\n\t\t\tconst branch = document.header.branch || \"main\";\n\t\t\tconst fromVersion = normalizeDocumentModelVersion(document.state.document?.version);\n\t\t\tlet targetVersion = toVersion;\n\t\t\tif (targetVersion === void 0) targetVersion = normalizeDocumentModelVersion((await this.getDocumentModelModule(documentType)).version);\n\t\t\tif (targetVersion === fromVersion) return this.gateDocument(document, { branch }, signal);\n\t\t\tif (targetVersion < fromVersion) throw new DowngradeNotSupportedError(documentType, fromVersion, targetVersion);\n\t\t\tconst signedActions = await signActions([upgradeDocumentAction({\n\t\t\t\tdocumentId,\n\t\t\t\tmodel: documentType,\n\t\t\t\tfromVersion,\n\t\t\t\ttoVersion: targetVersion,\n\t\t\t\trevision: { ...document.header.revision }\n\t\t\t})], this.signer, signal);\n\t\t\tconst jobInfo = await this.reactor.execute(documentId, branch, signedActions, signal);\n\t\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\t\tif (completedJob.status !== JobStatus.FAILED) {\n\t\t\t\tconst upgraded = await this.reactor.getByIdOrSlug(documentId, { branch }, completedJob.consistencyToken, signal);\n\t\t\t\treturn this.gateDocument(upgraded, { branch }, signal);\n\t\t\t}\n\t\t\tif (completedJob.error?.name !== \"UpgradePreconditionFailedError\") throw new Error(completedJob.error?.message);\n\t\t\tlastConflictMessage = completedJob.error.message;\n\t\t}\n\t\tthrow new Error(`Upgrade of document ${documentIdentifier} conflicted with concurrent edits after ${maxConflictRetries + 1} attempts: ${lastConflictMessage}`);\n\t}\n\t/**\n\t* Creates an empty document in a drive as a single batched operation.\n\t* Delegates to {@link IDriveClient.addFile}.\n\t*\n\t* @deprecated Use `client.drives.addFile` instead. This method will be\n\t* removed in a future release.\n\t*/\n\tasync createDocumentInDrive(driveId, document, parentFolder, signal) {\n\t\treturn this.drives.addFile(driveId, document, parentFolder, signal);\n\t}\n\t/**\n\t* Applies a list of actions to a document and waits for completion.\n\t*\n\t* `subject` names who the returned document is read as; see\n\t* {@link IReactorClient.execute}.\n\t*/\n\tasync execute(documentIdentifier, branch, actions, signal, subject) {\n\t\tthis.logger.verbose(\"execute(@documentIdentifier, @branch, @count actions)\", documentIdentifier, branch, actions.length);\n\t\tconst signedActions = await signActions(actions, this.signer, signal);\n\t\tconst jobInfo = await this.reactor.execute(documentIdentifier, branch, signedActions, signal);\n\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\tif (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\tconst view = {\n\t\t\tbranch,\n\t\t\tsubject\n\t\t};\n\t\tconst result = await this.reactor.getByIdOrSlug(documentIdentifier, view, completedJob.consistencyToken, signal);\n\t\treturn this.gateDocument(result, view, signal);\n\t}\n\t/**\n\t* Submits a list of actions to a document\n\t*/\n\tasync executeAsync(documentIdentifier, branch, actions, signal) {\n\t\tthis.logger.verbose(\"executeAsync(@documentIdentifier, @branch, @count actions)\", documentIdentifier, branch, actions.length);\n\t\tconst signedActions = await signActions(actions, this.signer, signal);\n\t\treturn this.reactor.execute(documentIdentifier, branch, signedActions, signal);\n\t}\n\tasync executeBatch(request, signal) {\n\t\tthis.logger.verbose(\"executeBatch(@count jobs)\", request.jobs.length);\n\t\tconst signedJobs = await Promise.all(request.jobs.map(async (job) => ({\n\t\t\t...job,\n\t\t\tactions: await signActions(job.actions, this.signer, signal)\n\t\t})));\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs: signedJobs }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);\n\t\treturn batchResult;\n\t}\n\t/**\n\t* Renames a document and waits for completion\n\t*/\n\tasync rename(documentIdentifier, name, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"rename(@documentIdentifier, @name, @branch)\", documentIdentifier, name, branch);\n\t\treturn this.execute(documentIdentifier, branch, [actions.setName(name)], signal);\n\t}\n\t/**\n\t* Updates the preferred editor recorded in the document header meta.\n\t* Pass `null` to clear it.\n\t*/\n\tasync setPreferredEditor(documentIdentifier, preferredEditor, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"setPreferredEditor(@documentIdentifier, @preferredEditor, @branch)\", documentIdentifier, preferredEditor, branch);\n\t\treturn this.execute(documentIdentifier, branch, [actions.setPreferredEditor(preferredEditor)], signal);\n\t}\n\t/**\n\t* Adds multiple documents as children to another and waits for completion\n\t*/\n\tasync addRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"addRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @branch)\", sourceIdentifier, targetIdentifier, relationshipType, branch);\n\t\tconst jobInfo = await this.reactor.addRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\tif (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\tconst result = await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);\n\t\treturn this.gateDocument(result, { branch }, signal);\n\t}\n\t/**\n\t* Removes a relationship between two documents and waits for completion.\n\t*/\n\tasync removeRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"removeRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @branch)\", sourceIdentifier, targetIdentifier, relationshipType, branch);\n\t\tconst jobInfo = await this.reactor.removeRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\tif (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\tconst result = await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);\n\t\treturn this.gateDocument(result, { branch }, signal);\n\t}\n\t/**\n\t* Moves a relationship from one source document to another and waits for completion.\n\t*/\n\tasync moveRelationship(sourceParentIdentifier, targetParentIdentifier, targetIdentifier, relationshipType, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"moveRelationship(@sourceParentIdentifier, @targetParentIdentifier, @targetIdentifier, @relationshipType, @branch)\", sourceParentIdentifier, targetParentIdentifier, targetIdentifier, relationshipType, branch);\n\t\tconst removeJobInfo = await this.reactor.removeRelationship(sourceParentIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst removeCompletedJob = await this.waitForJob(removeJobInfo, signal);\n\t\tif (removeCompletedJob.status === JobStatus.FAILED) throw new Error(removeCompletedJob.error?.message);\n\t\tconst addJobInfo = await this.reactor.addRelationship(targetParentIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst addCompletedJob = await this.waitForJob(addJobInfo, signal);\n\t\tif (addCompletedJob.status === JobStatus.FAILED) throw new Error(addCompletedJob.error?.message);\n\t\tconst sourceResult = await this.reactor.getByIdOrSlug(sourceParentIdentifier, { branch }, removeCompletedJob.consistencyToken, signal);\n\t\tconst targetResult = await this.reactor.getByIdOrSlug(targetParentIdentifier, { branch }, addCompletedJob.consistencyToken, signal);\n\t\treturn {\n\t\t\tsource: await this.gateDocument(sourceResult, { branch }, signal),\n\t\t\ttarget: await this.gateDocument(targetResult, { branch }, signal)\n\t\t};\n\t}\n\tasync loadBatch(request, signal) {\n\t\tthis.logger.verbose(\"loadBatch(@count jobs)\", request.jobs.length);\n\t\tconst result = await this.reactor.loadBatch(request, signal);\n\t\tconst completedJobs = await Promise.all(Object.entries(result.jobs).map(async ([key, jobInfo]) => {\n\t\t\treturn [key, await this.waitForJob(jobInfo, signal)];\n\t\t}));\n\t\tfor (const [, completedJob] of completedJobs) if (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\treturn { jobs: Object.fromEntries(completedJobs) };\n\t}\n\t/**\n\t* Deletes a document and waits for completion\n\t*/\n\tasync deleteDocument(identifier, propagate, signal) {\n\t\tthis.logger.verbose(\"deleteDocument(@identifier, @propagate)\", identifier, propagate);\n\t\tconst jobs = [];\n\t\tif (propagate === PropagationMode.Cascade) {\n\t\t\tconst toDelete = new Set([identifier]);\n\t\t\tlet changed = true;\n\t\t\twhile (changed) {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tchanged = false;\n\t\t\t\tconst orphans = await this.documentIndexer.getOrphanedChildren([...toDelete], [\"child\"], signal);\n\t\t\t\tfor (const id of orphans) if (!toDelete.has(id)) {\n\t\t\t\t\ttoDelete.add(id);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const descendantId of toDelete) {\n\t\t\t\tif (descendantId === identifier) continue;\n\t\t\t\tconst removalJobs = await this.removeAllIncomingRelationships(descendantId, signal);\n\t\t\t\tjobs.push(...removalJobs);\n\t\t\t\tconst jobInfo = await this.reactor.deleteDocument(descendantId, this.signer, signal);\n\t\t\t\tjobs.push(jobInfo);\n\t\t\t}\n\t\t}\n\t\tconst removalJobs = await this.removeAllIncomingRelationships(identifier, signal);\n\t\tjobs.push(...removalJobs);\n\t\tconst jobInfo = await this.reactor.deleteDocument(identifier, this.signer, signal);\n\t\tjobs.push(jobInfo);\n\t\tconst completedJobs = await Promise.all(jobs.map((job) => this.waitForJob(job, signal)));\n\t\tfor (const completedJob of completedJobs) if (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t}\n\t/**\n\t* Deletes documents and waits for completion\n\t*/\n\tasync deleteDocuments(identifiers, propagate, signal) {\n\t\tthis.logger.verbose(\"deleteDocuments(@count identifiers, @propagate)\", identifiers.length, propagate);\n\t\tconst deletePromises = identifiers.map((identifier) => this.deleteDocument(identifier, propagate, signal));\n\t\tawait Promise.all(deletePromises);\n\t}\n\t/**\n\t* Retrieves the status of a job\n\t*/\n\tasync getJobStatus(jobId, signal) {\n\t\tthis.logger.verbose(\"getJobStatus(@jobId)\", jobId);\n\t\treturn this.reactor.getJobStatus(jobId, signal);\n\t}\n\t/**\n\t* Waits for a job to complete\n\t*/\n\tasync waitForJob(jobId, signal) {\n\t\tconst id = typeof jobId === \"string\" ? jobId : jobId.id;\n\t\tthis.logger.verbose(\"waitForJob(@id)\", id);\n\t\treturn this.jobAwaiter.waitForJob(id, signal);\n\t}\n\t/**\n\t* Subscribes to changes for documents matching specified filters\n\t*/\n\tsubscribe(search, callback, view) {\n\t\tthis.logger.verbose(\"subscribe(@search, @view)\", search, view);\n\t\tconst readable = async (document) => filterReadableScopes(document, await this.readableScopes(document, view));\n\t\tlet disposed = false;\n\t\tlet delivering = Promise.resolve();\n\t\t/**\n\t\t* Queues one event behind those already queued. Gating an event resolves\n\t\t* asynchronously, so an event needing a group fetch would otherwise be\n\t\t* overtaken by the one behind it, and one still in flight would reach a\n\t\t* subscriber that has already unsubscribed. Only delivery is ordered, not\n\t\t* the gating: a single subscription can cover every document in the\n\t\t* reactor, so serializing that work would make its delivery rate the sum\n\t\t* of every gate build rather than the slowest. An event that cannot be\n\t\t* gated is withheld, because serving it unfiltered would leak the scopes\n\t\t* the gate did not clear -- but it is logged rather than swallowed, since\n\t\t* the gate rethrows a transient failure precisely so it is not read as a\n\t\t* denial.\n\t\t*/\n\t\tconst deliver = (event) => {\n\t\t\tPromise.resolve(event).catch(() => void 0);\n\t\t\tdelivering = delivering.then(async () => {\n\t\t\t\tconst built = await event;\n\t\t\t\tif (disposed) return;\n\t\t\t\tcallback(built);\n\t\t\t}).catch((error) => {\n\t\t\t\tthis.logger.error(\"Subscription delivery failed for @search: @Error\", { search }, error);\n\t\t\t});\n\t\t};\n\t\tconst unsubscribeCreated = this.subscriptionManager.onDocumentCreated((result) => {\n\t\t\tdeliver((async () => {\n\t\t\t\tconst documents = await Promise.all(result.results.map((id) => this.reactor.get(id, withAuthScope(view), void 0, void 0)));\n\t\t\t\treturn {\n\t\t\t\t\ttype: DocumentChangeType.Created,\n\t\t\t\t\tdocuments: await Promise.all(documents.map(readable))\n\t\t\t\t};\n\t\t\t})());\n\t\t}, search);\n\t\tconst unsubscribeDeleted = this.subscriptionManager.onDocumentDeleted((documentIds) => {\n\t\t\tdeliver({\n\t\t\t\ttype: DocumentChangeType.Deleted,\n\t\t\t\tdocuments: [],\n\t\t\t\tcontext: { childId: documentIds[0] }\n\t\t\t});\n\t\t}, search);\n\t\tconst unsubscribeUpdated = this.subscriptionManager.onDocumentStateUpdated((result) => {\n\t\t\tdeliver((async () => ({\n\t\t\t\ttype: DocumentChangeType.Updated,\n\t\t\t\tdocuments: await Promise.all(result.results.map(readable))\n\t\t\t}))());\n\t\t}, search, view);\n\t\tconst unsubscribeRelationship = this.subscriptionManager.onRelationshipChanged((parentId, childId, changeType) => {\n\t\t\tdeliver({\n\t\t\t\ttype: changeType === RelationshipChangeType.Added ? DocumentChangeType.ChildAdded : DocumentChangeType.ChildRemoved,\n\t\t\t\tdocuments: [],\n\t\t\t\tcontext: {\n\t\t\t\t\tparentId,\n\t\t\t\t\tchildId\n\t\t\t\t}\n\t\t\t});\n\t\t}, search);\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tunsubscribeCreated();\n\t\t\tunsubscribeDeleted();\n\t\t\tunsubscribeUpdated();\n\t\t\tunsubscribeRelationship();\n\t\t};\n\t}\n\tasync removeAllIncomingRelationships(documentId, signal) {\n\t\tconst incoming = await this.documentIndexer.getIncoming(documentId, void 0, void 0, void 0, signal);\n\t\tconst jobs = [];\n\t\tfor (const rel of incoming.results) {\n\t\t\tconst jobInfo = await this.reactor.removeRelationship(rel.sourceId, documentId, rel.relationshipType, \"main\", this.signer, signal);\n\t\t\tjobs.push(jobInfo);\n\t\t}\n\t\treturn jobs;\n\t}\n};\n//#endregion\n//#region src/queue/types.ts\n/**\n* State of a job in the queue\n*/\nlet JobQueueState = /* @__PURE__ */ function(JobQueueState) {\n\tJobQueueState[JobQueueState[\"UNKNOWN\"] = -1] = \"UNKNOWN\";\n\tJobQueueState[JobQueueState[\"PREPROCESSING\"] = 0] = \"PREPROCESSING\";\n\tJobQueueState[JobQueueState[\"PENDING\"] = 1] = \"PENDING\";\n\tJobQueueState[JobQueueState[\"READY\"] = 2] = \"READY\";\n\tJobQueueState[JobQueueState[\"RUNNING\"] = 3] = \"RUNNING\";\n\tJobQueueState[JobQueueState[\"RESOLVED\"] = 4] = \"RESOLVED\";\n\treturn JobQueueState;\n}({});\n/**\n* How a retry is accounted against the job's retry limit.\n* - `CountAgainstLimit` (default): a fault; the job eventually exhausts its\n* retries and fails terminally.\n* - `ExemptFromLimit`: not a fault, so the attempt is not charged to the job.\n* Used for concurrency conflicts, where the retry does new work.\n*/\nlet RetryAccounting = /* @__PURE__ */ function(RetryAccounting) {\n\tRetryAccounting[\"CountAgainstLimit\"] = \"count-against-limit\";\n\tRetryAccounting[\"ExemptFromLimit\"] = \"exempt-from-limit\";\n\treturn RetryAccounting;\n}({});\n/**\n* Event types for the queue system\n*/\nconst QueueEventTypes = { JOB_AVAILABLE: 1e4 };\n//#endregion\n//#region src/executor/job-result-handler.ts\n/** Conflict retries a job may take without charging its retry limit. */\nconst MAX_EXEMPT_CONFLICT_RETRIES = 20;\nfunction toErrorInfo(error) {\n\tif (error instanceof Error) return {\n\t\tname: error.name,\n\t\tmessage: error.message,\n\t\tstack: error.stack || (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n\treturn {\n\t\tname: \"Error\",\n\t\tmessage: error,\n\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n}\nvar JobResultHandler = class {\n\tconstructor(queue, jobTracker, eventBus, resolver, logger) {\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.eventBus = eventBus;\n\t\tthis.resolver = resolver;\n\t\tthis.logger = logger;\n\t}\n\tasync handleResult(handle, result, callbacks) {\n\t\tif (result.success) {\n\t\t\thandle.complete();\n\t\t\tif (this.hasCreateDocumentAction(handle.job)) await callbacks.flushDeferredFor(handle.job.documentId);\n\t\t\treturn;\n\t\t}\n\t\tif (result.error && ModuleNotFoundError.isError(result.error)) {\n\t\t\tlet modelLoaded = false;\n\t\t\ttry {\n\t\t\t\tawait this.resolver.ensureModelLoaded(result.error.documentType);\n\t\t\t\tmodelLoaded = true;\n\t\t\t} catch {}\n\t\t\tif (modelLoaded) {\n\t\t\t\tconst errorInfo = toErrorInfo(result.error);\n\t\t\t\ttry {\n\t\t\t\t\tawait this.queue.retryJob(handle.job.id, errorInfo);\n\t\t\t\t\treturn;\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t}\n\t\tif (result.error && AppendConditionFailedError.isError(result.error) && this.countConflicts(handle.job) < MAX_EXEMPT_CONFLICT_RETRIES) {\n\t\t\tconst errorInfo = toErrorInfo(result.error);\n\t\t\ttry {\n\t\t\t\tawait this.queue.retryJob(handle.job.id, errorInfo, RetryAccounting.ExemptFromLimit);\n\t\t\t\treturn;\n\t\t\t} catch {}\n\t\t}\n\t\tif (result.error && DocumentNotFoundError.isError(result.error) && handle.job.kind === \"load\") {\n\t\t\thandle.defer();\n\t\t\tcallbacks.deferJob(result.error.documentId, handle.job);\n\t\t\treturn;\n\t\t}\n\t\tif (result.error && (DocumentDeletedError.isError(result.error) || DocumentAlreadyExistsError.isError(result.error) || DocumentNotFoundError.isError(result.error) || AuthorizationDeniedError.isError(result.error) || AuthTimestampNotMonotonicError.isError(result.error) || InvalidOperationTimestampError.isError(result.error) || ExcessiveReshuffleError.isError(result.error) || UpgradePreconditionFailedError.isError(result.error))) {\n\t\t\tconst errorInfo = toErrorInfo(result.error);\n\t\t\tthis.jobTracker.markFailed(handle.job.id, errorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: result.error,\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\thandle.fail(errorInfo);\n\t\t\treturn;\n\t\t}\n\t\tconst retryCount = handle.job.retryCount || 0;\n\t\tif (retryCount < (handle.job.maxRetries || 0)) {\n\t\t\tconst currentErrorInfo = result.error ? toErrorInfo(result.error) : toErrorInfo(\"Unknown error\");\n\t\t\ttry {\n\t\t\t\tawait this.queue.retryJob(handle.job.id, currentErrorInfo);\n\t\t\t} catch (error) {\n\t\t\t\tconst retryErrorInfo = toErrorInfo(error instanceof Error ? error : \"Failed to retry job\");\n\t\t\t\tthis.jobTracker.markFailed(handle.job.id, retryErrorInfo, handle.job);\n\t\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\t\tjobId: handle.job.id,\n\t\t\t\t\terror: result.error ?? new Error(retryErrorInfo.message),\n\t\t\t\t\tjob: handle.job\n\t\t\t\t}).catch(() => {});\n\t\t\t\thandle.fail(retryErrorInfo);\n\t\t\t}\n\t\t} else {\n\t\t\tconst currentErrorInfo = result.error ? toErrorInfo(result.error) : toErrorInfo(\"Unknown error\");\n\t\t\tconst fullErrorInfo = this.formatErrorHistory(handle.job.errorHistory, currentErrorInfo, retryCount + 1);\n\t\t\tthis.jobTracker.markFailed(handle.job.id, fullErrorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: result.error ?? new Error(fullErrorInfo.message),\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\thandle.fail(fullErrorInfo);\n\t\t}\n\t}\n\t/** How many times this job has already lost an append-condition race. */\n\tcountConflicts(job) {\n\t\tlet conflicts = 0;\n\t\tfor (const error of job.errorHistory) if (AppendConditionFailedError.isFailureMessage(error.message)) conflicts++;\n\t\treturn conflicts;\n\t}\n\thasCreateDocumentAction(job) {\n\t\tfor (const action of job.actions) if (action.type === \"CREATE_DOCUMENT\") return true;\n\t\tfor (const operation of job.operations) if (operation.action.type === \"CREATE_DOCUMENT\") return true;\n\t\treturn false;\n\t}\n\tformatErrorHistory(errorHistory, currentError, totalAttempts) {\n\t\tconst allErrors = [...errorHistory, currentError];\n\t\tif (allErrors.length === 1) return currentError;\n\t\tconst messageLines = [`Job failed after ${totalAttempts} attempts:`];\n\t\tconst stackLines = [];\n\t\tallErrors.forEach((error, index) => {\n\t\t\tmessageLines.push(`[Attempt ${index + 1}] ${error.message}`);\n\t\t\tstackLines.push(`[Attempt ${index + 1}] Stack trace:\\n${error.stack}`);\n\t\t});\n\t\treturn {\n\t\t\tname: currentError.name,\n\t\t\tmessage: messageLines.join(\"\\n\"),\n\t\t\tstack: stackLines.join(\"\\n\\n\")\n\t\t};\n\t}\n};\n//#endregion\n//#region src/executor/deferred-jobs.ts\n/**\n* The jobs held back because the document they write to was not there yet.\n*\n* A job whose document is missing is deferred rather than failed, because the\n* operations that create that document may still be on their way - out of order\n* from a peer, or a sibling job in the same batch. Deferring emits no event and\n* moves no job status, which is what makes it cheap: a job that gets flushed\n* runs as if it had merely waited its turn.\n*\n* That silence is also why the wait has to be bounded. A deferred job is only\n* released when a job carrying CREATE_DOCUMENT for that exact document id\n* completes, so a job deferred against an id nothing will ever create is\n* released by nothing. Its status stays RUNNING, which is not terminal, so a\n* caller awaiting it waits forever - there is no timeout on that side. The TTL\n* converts that silence into the failure the caller can act on.\n*\n* Failing through the queue rather than only the tracker matters: the queue\n* records the job as resolved, which is what unblocks anything that declared a\n* dependency on it. Deferring alone does not, so a dependent of a deferred job\n* is stranded at PENDING for as long as the deferral lasts.\n*/\nvar DeferredJobs = class {\n\t#byDocumentId = /* @__PURE__ */ new Map();\n\t#timers = /* @__PURE__ */ new Map();\n\tconstructor(queue, jobTracker, eventBus, logger, ttlMs = DEFAULT_DEFERRED_JOB_TTL_MS, onReleased = () => Promise.resolve()) {\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.eventBus = eventBus;\n\t\tthis.logger = logger;\n\t\tthis.ttlMs = ttlMs;\n\t\tthis.onReleased = onReleased;\n\t}\n\t/**\n\t* Holds a job until its document arrives, or until the TTL elapses.\n\t*\n\t* A job deferred again after a flush replaces its own timer rather than\n\t* accumulating one, so the wait is measured from the most recent attempt.\n\t*/\n\tadd(documentId, job) {\n\t\tconst existing = this.#byDocumentId.get(documentId) ?? [];\n\t\texisting.push(job);\n\t\tthis.#byDocumentId.set(documentId, existing);\n\t\tthis.#clearTimer(job.id);\n\t\tconst timer = setTimeout(() => {\n\t\t\tthis.#expire(documentId, job);\n\t\t}, this.ttlMs);\n\t\tif (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n\t\tthis.#timers.set(job.id, timer);\n\t}\n\t/** Re-enqueues everything waiting on a document that has now arrived. */\n\tasync flush(documentId) {\n\t\tconst jobs = this.#byDocumentId.get(documentId);\n\t\tif (!jobs || jobs.length === 0) return;\n\t\tthis.#byDocumentId.delete(documentId);\n\t\tfor (const job of jobs) {\n\t\t\tthis.#clearTimer(job.id);\n\t\t\ttry {\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Error re-enqueuing deferred job: @Error\", error);\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Fails everything still deferred, for a reactor that is shutting down.\n\t*\n\t* The queue is deliberately not told: it is going away too, and nothing is\n\t* left to unblock.\n\t*/\n\tfailAll() {\n\t\tfor (const [, jobs] of this.#byDocumentId) for (const job of jobs) {\n\t\t\tthis.#clearTimer(job.id);\n\t\t\tthis.#markFailed(job);\n\t\t}\n\t\tthis.#byDocumentId.clear();\n\t}\n\t/** The jobs still waiting on a document. Exposed for assertions. */\n\twaitingOn(documentId) {\n\t\treturn this.#byDocumentId.get(documentId) ?? [];\n\t}\n\tasync #expire(documentId, job) {\n\t\tconst jobs = this.#byDocumentId.get(documentId);\n\t\tif (!jobs?.includes(job)) return;\n\t\tconst remaining = jobs.filter((held) => held !== job);\n\t\tif (remaining.length === 0) this.#byDocumentId.delete(documentId);\n\t\telse this.#byDocumentId.set(documentId, remaining);\n\t\tthis.#timers.delete(job.id);\n\t\tthis.logger.error(\"Deferred job @jobId gave up waiting for document @documentId after @ttlMs ms\", job.id, documentId, this.ttlMs);\n\t\tconst errorInfo = this.#markFailed(job);\n\t\ttry {\n\t\t\tawait this.queue.failJob(job.id, errorInfo);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error failing an expired deferred job: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tthis.jobTracker.markFailed(job.id, errorInfo, job);\n\t\ttry {\n\t\t\tawait this.onReleased();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error dispatching after a deferred job expired: @Error\", error);\n\t\t}\n\t}\n\t#markFailed(job) {\n\t\tconst error = new DocumentNotFoundError(job.documentId);\n\t\tconst errorInfo = toErrorInfo(error);\n\t\tthis.jobTracker.markFailed(job.id, errorInfo, job);\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\tjobId: job.id,\n\t\t\terror,\n\t\t\tjob\n\t\t}).catch(() => {});\n\t\treturn errorInfo;\n\t}\n\t#clearTimer(jobId) {\n\t\tconst timer = this.#timers.get(jobId);\n\t\tif (timer !== void 0) {\n\t\t\tclearTimeout(timer);\n\t\t\tthis.#timers.delete(jobId);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/executor/worker-pool-router.ts\n/**\n* Sticky-by-document routing for the executor worker pool.\n*\n* Hashes `documentId` to a stable bucket so every job on a given document\n* lands on the same worker. The queue already enforces \"at most one job\n* executing per document at a time\", so a sticky worker always sees a fresh\n* post-commit snapshot before its next job on that document — which keeps\n* the per-worker `IWriteCache` and `IDocumentMetaCache` coherent for free.\n*\n* The hash is FNV-1a 32-bit: deterministic, dependency-free, and stable\n* across processes (so the same routing decision can be reproduced anywhere\n* the documentId is known).\n*\n* @see Executor Worker Pool Design wiki page\n* (Powerhouse board wiki id: d400d711-f07e-4389-a226-4e9fdd4fa8ba)\n*/\nconst FNV_OFFSET_BASIS = 2166136261;\nconst FNV_PRIME = 16777619;\nfunction hashDocumentId(documentId) {\n\tlet hash = FNV_OFFSET_BASIS;\n\tfor (let i = 0; i < documentId.length; i++) {\n\t\thash ^= documentId.charCodeAt(i);\n\t\thash = Math.imul(hash, FNV_PRIME);\n\t}\n\treturn hash >>> 0;\n}\nfunction bucketFor(documentId, numWorkers) {\n\tif (numWorkers < 1) throw new Error(`bucketFor: numWorkers must be >= 1 (got ${numWorkers})`);\n\treturn hashDocumentId(documentId) % numWorkers;\n}\n//#endregion\n//#region src/executor/worker-pool-job-executor-manager.ts\n/**\n* Manages a pool of executor workers and dispatches jobs across them with\n* sticky-by-documentId routing. Replaces `SimpleJobExecutorManager` when\n* the worker pool is enabled.\n*\n* Responsibilities that stay on the parent (not in the worker):\n* - Dequeueing from `IQueue` and routing to the matching worker bucket.\n* - Emitting `JOB_RUNNING` and `JOB_WRITE_READY` events; the worker's\n* local event bus is a no-op stub.\n* - Maintaining the deferred-jobs map for `DocumentNotFoundError`.\n* - Enriching the outgoing `JOB_WRITE_READY` with\n* `collectionMemberships`, read from the operation index after the\n* worker has committed. It takes the whole index rather than a\n* narrower read interface so that handing it a cache does not\n* compile: which documents a commit moves between collections is not\n* derivable from action shape, because joining a collection also\n* joins every group the joining document has referenced and that set\n* comes from selects run inside the commit. A parent-side cache\n* cannot learn it went stale, and a stale entry silently drops the\n* document's operations from the outbox of every remote subscribed to\n* the omitted collection. Costs one primary-key-prefix lookup on\n* `document_collections` per job that produced operations, on a\n* fire-and-forget path.\n*\n* @see Executor Worker Pool Design wiki page\n* (Powerhouse board wiki id: d400d711-f07e-4389-a226-4e9fdd4fa8ba)\n*/\nvar WorkerPoolJobExecutorManager = class {\n\tworkers = [];\n\tisRunning = false;\n\tactiveJobs = 0;\n\ttotalJobsProcessed = 0;\n\tunsubscribe;\n\tdeferredJobs;\n\tresultHandler;\n\tjobTimeoutMs;\n\tconstructor(workerFactory, eventBus, queue, jobTracker, logger, resolver, operationIndex, jobTimeoutMs = 3e4, deferredJobTtlMs = DEFAULT_DEFERRED_JOB_TTL_MS) {\n\t\tthis.workerFactory = workerFactory;\n\t\tthis.eventBus = eventBus;\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.logger = logger;\n\t\tthis.resolver = resolver;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.jobTimeoutMs = jobTimeoutMs;\n\t\tthis.deferredJobs = new DeferredJobs(queue, jobTracker, eventBus, logger, deferredJobTtlMs, () => this.tryDispatchAll());\n\t\tthis.resultHandler = new JobResultHandler(queue, jobTracker, eventBus, resolver, logger);\n\t}\n\tasync start(numWorkers) {\n\t\tif (this.isRunning) throw new Error(\"WorkerPoolJobExecutorManager is already running\");\n\t\tif (numWorkers < 1) throw new Error(\"Number of workers must be at least 1\");\n\t\tthis.workers = Array.from({ length: numWorkers }, (_, i) => this.workerFactory(i));\n\t\tawait Promise.all(this.workers.map((w) => w.start()));\n\t\tthis.unsubscribe = this.eventBus.subscribe(QueueEventTypes.JOB_AVAILABLE, async () => {\n\t\t\tawait this.tryDispatchAll();\n\t\t});\n\t\tthis.isRunning = true;\n\t\tawait this.tryDispatchAll();\n\t}\n\tasync stop(graceful = true) {\n\t\tif (!this.isRunning) return;\n\t\tif (this.unsubscribe) {\n\t\t\tthis.unsubscribe();\n\t\t\tthis.unsubscribe = void 0;\n\t\t}\n\t\tif (graceful) while (this.activeJobs > 0) await new Promise((resolve) => setTimeout(resolve, 10));\n\t\tthis.deferredJobs.failAll();\n\t\tawait Promise.all(this.workers.map((w) => w.shutdown(graceful).catch((err) => {\n\t\t\tthis.logger.warn(\"worker shutdown failed: @Error\", err);\n\t\t})));\n\t\tthis.workers = [];\n\t\tthis.isRunning = false;\n\t}\n\t/**\n\t* Worker-pool mode has no in-process `IJobExecutor` instances — the\n\t* executors live in worker threads behind `IExecutorWorker` handles.\n\t* Returns an empty array; callers that need pool-aware introspection\n\t* should use `getStatus()` instead.\n\t*/\n\tgetExecutors() {\n\t\treturn [];\n\t}\n\t/**\n\t* Broadcasts a `load-model` request to every running worker in parallel.\n\t* Rejects with the first worker's failure if any worker rejects (after\n\t* waiting for all in-flight broadcasts to settle). Workers that already\n\t* have the model registered respond with a `DuplicateModuleError`-rooted\n\t* failure; those are treated as success on the broadcast level so that\n\t* a model registered on some workers but not others still converges.\n\t*/\n\tasync loadModel(entry) {\n\t\tif (this.workers.length === 0) return;\n\t\tconst failures = (await Promise.allSettled(this.workers.map((w) => w.loadModel(entry)))).filter((r) => r.status === \"rejected\").filter((r) => !isDuplicateModuleFailure(r.reason));\n\t\tif (failures.length === 0) return;\n\t\tfor (const f of failures) this.logger.error(\"worker failed to load model @entry: @error\", entry, f.reason);\n\t\tthrow failures[0].reason instanceof Error ? failures[0].reason : new Error(String(failures[0].reason));\n\t}\n\tgetStatus() {\n\t\treturn {\n\t\t\tisRunning: this.isRunning,\n\t\t\tnumExecutors: this.workers.length,\n\t\t\tactiveJobs: this.activeJobs,\n\t\t\ttotalJobsProcessed: this.totalJobsProcessed\n\t\t};\n\t}\n\tasync tryDispatchAll() {\n\t\tif (!this.isRunning && this.workers.length === 0) return;\n\t\tawait Promise.all(this.workers.map((worker) => this.tryDispatchFor(worker)));\n\t}\n\tasync tryDispatchFor(worker) {\n\t\tif (!worker.isIdle()) return;\n\t\tconst index = worker.index;\n\t\tconst numWorkers = this.workers.length;\n\t\tconst predicate = (meta) => bucketFor(meta.documentId, numWorkers) === index;\n\t\tlet handle;\n\t\ttry {\n\t\t\thandle = await this.queue.dequeueNextMatching(predicate);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error dequeueing next job: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (!handle) return;\n\t\thandle.start();\n\t\tthis.activeJobs++;\n\t\tthis.jobTracker.markRunning(handle.job.id);\n\t\tconst runningEvent = {\n\t\t\tjobId: handle.job.id,\n\t\t\tjobMeta: handle.job.meta\n\t\t};\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_RUNNING, runningEvent).catch(() => {});\n\t\tconst workerId = worker.workerId;\n\t\tconst startedEvent = {\n\t\t\tjob: handle.job,\n\t\t\tstartedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tworkerId\n\t\t};\n\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_STARTED, startedEvent).catch(() => {});\n\t\tconst signal = AbortSignal.timeout(this.jobTimeoutMs);\n\t\tlet outcome;\n\t\ttry {\n\t\t\toutcome = await worker.execute(handle.job, signal);\n\t\t} catch (error) {\n\t\t\tconst errorInfo = toErrorInfo(error instanceof Error ? error : String(error));\n\t\t\tif (isWorkerTransportError(error)) {\n\t\t\t\tawait this.handleWorkerTransportFailure(worker, handle.job, errorInfo);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandle.fail(errorInfo);\n\t\t\tthis.activeJobs--;\n\t\t\tthis.jobTracker.markFailed(handle.job.id, errorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: new Error(errorInfo.message),\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: errorInfo.message,\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t\tawait this.tryDispatchFor(worker);\n\t\t\treturn;\n\t\t}\n\t\tif (outcome.result.success) {\n\t\t\tthis.totalJobsProcessed++;\n\t\t\tconst completedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\tresult: outcome.result,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_COMPLETED, completedEvent).catch(() => {});\n\t\t} else {\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: outcome.result.error?.message ?? \"unknown\",\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t}\n\t\tif (outcome.result.success && outcome.writeReady) this.emitWriteReady(handle.job, outcome.writeReady).catch((error) => {\n\t\t\tthis.logger.error(\"emitWriteReady failed for job @jobId: @Error\", { jobId: handle.job.id }, error);\n\t\t});\n\t\tawait this.resultHandler.handleResult(handle, outcome.result, {\n\t\t\tdeferJob: (documentId, job) => this.deferredJobs.add(documentId, job),\n\t\t\tflushDeferredFor: (documentId) => this.deferredJobs.flush(documentId)\n\t\t});\n\t\tthis.activeJobs--;\n\t\tawait this.tryDispatchFor(worker);\n\t}\n\tasync emitWriteReady(job, payload) {\n\t\tconst documentIds = [...new Set(payload.operations.map((op) => op.context.documentId))];\n\t\tlet collectionMemberships = {};\n\t\tif (documentIds.length > 0) try {\n\t\t\tcollectionMemberships = fillMissingMemberships(documentIds, await this.operationIndex.getCollectionsForDocuments(documentIds));\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to load collection memberships for JOB_WRITE_READY: @Error\", error);\n\t\t}\n\t\tconst event = {\n\t\t\tjobId: job.id,\n\t\t\toperations: payload.operations,\n\t\t\tjobMeta: payload.jobMeta,\n\t\t\tcollectionMemberships\n\t\t};\n\t\ttry {\n\t\t\tawait this.eventBus.emit(ReactorEventTypes.JOB_WRITE_READY, event);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to emit JOB_WRITE_READY event: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Handle a worker-transport failure (worker exited / init failed / abort\n\t* timed out) detected while `worker.execute` was in flight. Re-enqueues\n\t* the in-flight job via `queue.retryJob` so it is retried on a healthy\n\t* worker, then replaces the dead worker with a fresh handle and resumes\n\t* dispatch on the same bucket. Does NOT emit JOB_FAILED — the job is\n\t* not failed, only the worker is.\n\t*/\n\tasync handleWorkerTransportFailure(dead, job, errorInfo) {\n\t\tthis.logger.warn(\"worker transport error during execute; retrying job @jobId on a replacement worker: @error\", {\n\t\t\tjobId: job.id,\n\t\t\tworkerId: dead.workerId\n\t\t}, errorInfo.message);\n\t\tthis.activeJobs--;\n\t\tawait this.replaceWorker(dead);\n\t\ttry {\n\t\t\tawait this.queue.retryJob(job.id, errorInfo);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"failed to re-enqueue job after worker transport error: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Replace a dead worker at its existing pool index with a fresh handle\n\t* produced by `workerFactory`. Awaits `start()` on the replacement so it\n\t* is ready before dispatch resumes. On replacement failure the slot is\n\t* left empty (the index becomes a hole that subsequent retries will\n\t* route to no worker) and the error is logged — the manager keeps\n\t* running so other buckets continue to make progress.\n\t*/\n\tasync replaceWorker(dead) {\n\t\tconst deadIndex = dead.index;\n\t\tif (this.workers[deadIndex] !== dead) return;\n\t\tlet fresh;\n\t\ttry {\n\t\t\tfresh = this.workerFactory(deadIndex);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"workerFactory threw while replacing dead worker at index @index: @Error\", deadIndex, error);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tawait fresh.start();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"replacement worker at index @index failed to start: @Error\", deadIndex, error);\n\t\t\treturn;\n\t\t}\n\t\tthis.workers[deadIndex] = fresh;\n\t\tawait this.tryDispatchFor(fresh);\n\t}\n};\nfunction isWorkerTransportError(error) {\n\treturn error instanceof WorkerExitedError || error instanceof WorkerInitFailedError || error instanceof WorkerAbortTimeoutError;\n}\nfunction isDuplicateModuleFailure(reason) {\n\tif (!(reason instanceof Error)) return false;\n\tif (reason.name === \"DuplicateModuleError\") return true;\n\tconst cause = reason.cause;\n\treturn cause instanceof Error && cause.name === \"DuplicateModuleError\";\n}\n/**\n* Gives every requested document a key, empty when it belongs to no\n* collection. The operation index omits documents with no rows while the\n* membership cache defaulted them to `[]`, so this keeps the emitted\n* `JobWriteReadyEvent.collectionMemberships` shape unchanged.\n*/\nfunction fillMissingMemberships(documentIds, found) {\n\tconst result = {};\n\tfor (const documentId of documentIds) result[documentId] = found[documentId] ?? [];\n\treturn result;\n}\n//#endregion\n//#region src/executor/simple-job-executor-manager.ts\n/**\n* Manages multiple job executors and coordinates job distribution.\n* Listens for job available events and dispatches jobs to executors.\n*/\nvar SimpleJobExecutorManager = class {\n\texecutors = [];\n\tisRunning = false;\n\tactiveJobs = 0;\n\ttotalJobsProcessed = 0;\n\tunsubscribe;\n\tdeferredJobs;\n\tresultHandler;\n\tjobTimeoutMs;\n\tconstructor(executorFactory, eventBus, queue, jobTracker, logger, resolver, jobTimeoutMs = 3e4, deferredJobTtlMs = DEFAULT_DEFERRED_JOB_TTL_MS) {\n\t\tthis.executorFactory = executorFactory;\n\t\tthis.eventBus = eventBus;\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.logger = logger;\n\t\tthis.resolver = resolver;\n\t\tthis.jobTimeoutMs = jobTimeoutMs;\n\t\tthis.deferredJobs = new DeferredJobs(queue, jobTracker, eventBus, logger, deferredJobTtlMs, () => this.checkForMoreJobs());\n\t\tthis.resultHandler = new JobResultHandler(queue, jobTracker, eventBus, resolver, logger);\n\t}\n\tasync start(numExecutors) {\n\t\tif (this.isRunning) throw new Error(\"JobExecutorManager is already running\");\n\t\tif (numExecutors < 1) throw new Error(\"Number of executors must be at least 1\");\n\t\tthis.executors = [];\n\t\tfor (let i = 0; i < numExecutors; i++) this.executors.push(this.executorFactory());\n\t\tthis.unsubscribe = this.eventBus.subscribe(QueueEventTypes.JOB_AVAILABLE, async () => {\n\t\t\tif (this.activeJobs < this.executors.length) await this.processNextJob();\n\t\t});\n\t\tthis.isRunning = true;\n\t\tawait this.processExistingJobs();\n\t}\n\tasync stop(graceful = true) {\n\t\tif (!this.isRunning) return;\n\t\tif (this.unsubscribe) {\n\t\t\tthis.unsubscribe();\n\t\t\tthis.unsubscribe = void 0;\n\t\t}\n\t\tif (graceful) while (this.activeJobs > 0) await new Promise((resolve) => setTimeout(resolve, 100));\n\t\tthis.deferredJobs.failAll();\n\t\tthis.executors = [];\n\t\tthis.isRunning = false;\n\t}\n\tgetExecutors() {\n\t\treturn [...this.executors];\n\t}\n\tgetStatus() {\n\t\treturn {\n\t\t\tisRunning: this.isRunning,\n\t\t\tnumExecutors: this.executors.length,\n\t\t\tactiveJobs: this.activeJobs,\n\t\t\ttotalJobsProcessed: this.totalJobsProcessed\n\t\t};\n\t}\n\tasync processNextJob() {\n\t\tlet handle;\n\t\ttry {\n\t\t\thandle = await this.queue.dequeueNext();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error dequeueing next job: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (!handle) return;\n\t\thandle.start();\n\t\tthis.activeJobs++;\n\t\tthis.jobTracker.markRunning(handle.job.id);\n\t\tconst runningEvent = {\n\t\t\tjobId: handle.job.id,\n\t\t\tjobMeta: handle.job.meta\n\t\t};\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_RUNNING, runningEvent).catch(() => {});\n\t\tconst executorIndex = this.totalJobsProcessed % this.executors.length;\n\t\tconst executor = this.executors[executorIndex];\n\t\tconst workerId = `in-process-${executorIndex}`;\n\t\tconst startedEvent = {\n\t\t\tjob: handle.job,\n\t\t\tstartedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tworkerId\n\t\t};\n\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_STARTED, startedEvent).catch(() => {});\n\t\tconst signal = AbortSignal.timeout(this.jobTimeoutMs);\n\t\tconst toError = (reason) => reason instanceof Error ? reason : new Error(String(reason));\n\t\tconst abortPromise = new Promise((_, reject) => {\n\t\t\tif (signal.aborted) {\n\t\t\t\treject(toError(signal.reason));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsignal.addEventListener(\"abort\", () => reject(toError(signal.reason)), { once: true });\n\t\t});\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await Promise.race([executor.executeJob(handle.job, signal), abortPromise]);\n\t\t} catch (error) {\n\t\t\tconst errorInfo = toErrorInfo(error instanceof Error ? error : String(error));\n\t\t\thandle.fail(errorInfo);\n\t\t\tthis.activeJobs--;\n\t\t\tthis.jobTracker.markFailed(handle.job.id, errorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: new Error(errorInfo.message),\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: errorInfo.message,\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t\tawait this.checkForMoreJobs();\n\t\t\treturn;\n\t\t}\n\t\tif (result.success) this.totalJobsProcessed++;\n\t\tif (result.success) {\n\t\t\tconst completedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\tresult,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_COMPLETED, completedEvent).catch(() => {});\n\t\t} else {\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: result.error?.message ?? \"unknown\",\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t}\n\t\tawait this.resultHandler.handleResult(handle, result, {\n\t\t\tdeferJob: (documentId, job) => this.deferredJobs.add(documentId, job),\n\t\t\tflushDeferredFor: (documentId) => this.deferredJobs.flush(documentId)\n\t\t});\n\t\tthis.activeJobs--;\n\t\tawait this.checkForMoreJobs();\n\t}\n\tasync checkForMoreJobs() {\n\t\tif (!this.isRunning) return;\n\t\tlet hasMore;\n\t\ttry {\n\t\t\thasMore = await this.queue.hasJobs();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error checking for more jobs: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (hasMore) await this.processNextJob();\n\t}\n\tasync processExistingJobs() {\n\t\tlet hasJobs;\n\t\ttry {\n\t\t\thasJobs = await this.queue.hasJobs();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error checking for existing jobs: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (hasJobs) {\n\t\t\tconst promises = [];\n\t\t\tfor (let i = 0; i < Math.min(this.executors.length, 5); i++) promises.push(this.processNextJob());\n\t\t\ttry {\n\t\t\t\tawait Promise.all(promises);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Error processing existing jobs: @Error\", error);\n\t\t\t}\n\t\t}\n\t}\n};\n//#endregion\n//#region src/job-tracker/in-memory-job-tracker.ts\n/**\n* In-memory implementation of IJobTracker.\n* Maintains job status in a Map for synchronous access.\n* Subscribes to operation events to update job states.\n*/\nvar InMemoryJobTracker = class {\n\tjobs = /* @__PURE__ */ new Map();\n\tunsubscribers = [];\n\tconstructor(eventBus) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.subscribeToEvents();\n\t}\n\tsubscribeToEvents() {\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, (_type, event) => {\n\t\t\tthis.handleWriteReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_READ_READY, (_type, event) => {\n\t\t\tthis.handleReadReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, (_type, event) => {\n\t\t\tthis.handleJobFailed(event);\n\t\t}));\n\t}\n\thandleWriteReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tconst job = this.jobs.get(jobId);\n\t\tif (job && job.status === JobStatus.RUNNING) {\n\t\t\tconst consistencyToken = createConsistencyToken(event.operations);\n\t\t\tthis.jobs.set(jobId, {\n\t\t\t\t...job,\n\t\t\t\tstatus: JobStatus.WRITE_READY,\n\t\t\t\tconsistencyToken\n\t\t\t});\n\t\t}\n\t}\n\thandleReadReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tconst job = this.jobs.get(jobId);\n\t\tif (job && job.status === JobStatus.WRITE_READY) this.jobs.set(jobId, {\n\t\t\t...job,\n\t\t\tstatus: JobStatus.READ_READY\n\t\t});\n\t}\n\thandleJobFailed(event) {\n\t\tthis.markFailed(event.jobId, {\n\t\t\tname: event.error.name,\n\t\t\tmessage: event.error.message,\n\t\t\tstack: event.error.stack || \"\"\n\t\t}, event.job);\n\t}\n\tshutdown() {\n\t\tfor (const unsubscribe of this.unsubscribers) unsubscribe();\n\t\tthis.unsubscribers = [];\n\t}\n\tregisterJob(jobInfo) {\n\t\tthis.jobs.set(jobInfo.id, { ...jobInfo });\n\t}\n\tmarkRunning(jobId) {\n\t\tconst job = this.jobs.get(jobId);\n\t\tif (!job) {\n\t\t\tthis.jobs.set(jobId, {\n\t\t\t\tid: jobId,\n\t\t\t\tdocumentId: \"\",\n\t\t\t\tstatus: JobStatus.RUNNING,\n\t\t\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\tconsistencyToken: createEmptyConsistencyToken(),\n\t\t\t\tmeta: {\n\t\t\t\t\tbatchId: jobId,\n\t\t\t\t\tbatchJobIds: [jobId]\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.jobs.set(jobId, {\n\t\t\t...job,\n\t\t\tstatus: JobStatus.RUNNING\n\t\t});\n\t}\n\tmarkFailed(jobId, error, job) {\n\t\tconst existing = this.jobs.get(jobId);\n\t\tif (!existing) {\n\t\t\tthis.jobs.set(jobId, {\n\t\t\t\tid: jobId,\n\t\t\t\tdocumentId: job?.documentId ?? \"\",\n\t\t\t\tstatus: JobStatus.FAILED,\n\t\t\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\tcompletedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\terror,\n\t\t\t\tjob,\n\t\t\t\tconsistencyToken: createEmptyConsistencyToken(),\n\t\t\t\tmeta: {\n\t\t\t\t\tbatchId: jobId,\n\t\t\t\t\tbatchJobIds: [jobId]\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.jobs.set(jobId, {\n\t\t\t...existing,\n\t\t\tstatus: JobStatus.FAILED,\n\t\t\tcompletedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\terror,\n\t\t\tjob,\n\t\t\tconsistencyToken: createEmptyConsistencyToken()\n\t\t});\n\t}\n\tgetJobStatus(jobId) {\n\t\tconst job = this.jobs.get(jobId);\n\t\treturn job ? { ...job } : null;\n\t}\n};\n//#endregion\n//#region src/processors/utils.ts\nfunction isDriveDeletion(op) {\n\treturn op.operation.action.type === \"DELETE_DOCUMENT\";\n}\nfunction extractDriveHeader(op) {\n\tif (!op.context.resultingState) return void 0;\n\treturn JSON.parse(op.context.resultingState).header;\n}\nfunction extractDeletedDocumentId(op) {\n\treturn op.operation.action.input.documentId ?? op.context.documentId;\n}\nfunction createMinimalDriveHeader(driveId, documentType) {\n\treturn {\n\t\tid: driveId,\n\t\tdocumentType,\n\t\tsig: {\n\t\t\tpublicKey: {},\n\t\t\tnonce: \"\"\n\t\t},\n\t\tslug: \"\",\n\t\tname: \"\",\n\t\tbranch: \"main\",\n\t\trevision: {},\n\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tlastModifiedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString()\n\t};\n}\nfunction matchesFilter(op, filter) {\n\tif (filter.documentType && filter.documentType.length > 0) {\n\t\tif (!filter.documentType.includes(op.context.documentType)) return false;\n\t}\n\tif (filter.scope && filter.scope.length > 0) {\n\t\tif (!filter.scope.includes(op.context.scope)) return false;\n\t}\n\tif (filter.branch && filter.branch.length > 0) {\n\t\tif (!filter.branch.includes(op.context.branch)) return false;\n\t}\n\tif (filter.documentId && filter.documentId.length > 0) {\n\t\tif (!filter.documentId.includes(\"*\") && !filter.documentId.includes(op.context.documentId)) return false;\n\t}\n\treturn true;\n}\nfunction nonEmpty(value) {\n\treturn typeof value === \"string\" && value.length > 0 ? value : void 0;\n}\nfunction namespaceOf(processor) {\n\treturn nonEmpty(processor.namespace);\n}\nfunction classNameOf(processor) {\n\tconst name = processor.constructor.name;\n\treturn name && name !== \"Object\" ? name : void 0;\n}\nfunction resolveProcessorSlots(records, legacy) {\n\tif (legacy) return records.map((_, i) => String(i));\n\tconst seen = /* @__PURE__ */ new Map();\n\treturn records.map((record, i) => {\n\t\tconst base = nonEmpty(record.id) ?? namespaceOf(record.processor) ?? classNameOf(record.processor) ?? String(i);\n\t\tconst count = seen.get(base) ?? 0;\n\t\tseen.set(base, count + 1);\n\t\treturn count === 0 ? base : `${base}#${count}`;\n\t});\n}\n//#endregion\n//#region src/processors/processor-manager.ts\n/**\n* Manages processor lifecycle based on operations.\n* Extends BaseReadModel to receive operations from ReadModelCoordinator.\n*\n* Responsibilities:\n* 1. Detect drive creation from CREATE_DOCUMENT operations\n* 2. Create processors for each drive using registered factories\n* 3. Route operations to matching processors based on filters\n* 4. Clean up processors when drives are deleted or factories are unregistered\n* 5. Track per-processor cursors for failure recovery and backfill\n*/\nvar ProcessorManager = class extends BaseReadModel {\n\tfactoryRegistry = /* @__PURE__ */ new Map();\n\tprocessorsByDrive = /* @__PURE__ */ new Map();\n\tfactoryToProcessors = /* @__PURE__ */ new Map();\n\tknownDrives = /* @__PURE__ */ new Map();\n\tcursorCache = /* @__PURE__ */ new Map();\n\tlogger;\n\tdriveContainerTypes;\n\tlegacyProcessorIds;\n\tconstructor(db, operationIndex, writeCache, consistencyTracker, logger, driveContainerTypes, options = {}) {\n\t\tsuper(db, operationIndex, writeCache, consistencyTracker, {\n\t\t\treadModelId: \"processor-manager\",\n\t\t\trebuildStateOnInit: true\n\t\t});\n\t\tthis.logger = logger;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.legacyProcessorIds = options.legacyProcessorIds ?? true;\n\t}\n\tasync init() {\n\t\tawait super.init();\n\t\tawait this.loadAllCursors();\n\t\tawait this.discoverExistingDrives();\n\t}\n\tasync commitOperations(items) {\n\t\tawait this.detectAndRegisterNewDrives(items);\n\t\tawait this.detectAndCleanupDeletedDrives(items);\n\t\tawait this.routeOperationsToProcessors(items);\n\t}\n\tasync registerFactory(identifier, factory) {\n\t\tif (this.factoryRegistry.has(identifier)) await this.unregisterFactory(identifier);\n\t\tthis.factoryRegistry.set(identifier, factory);\n\t\tthis.factoryToProcessors.set(identifier, /* @__PURE__ */ new Map());\n\t\tfor (const [driveId, documentType] of this.knownDrives) {\n\t\t\tconst driveHeader = createMinimalDriveHeader(driveId, documentType);\n\t\t\tawait this.createProcessorsForDrive(driveId, identifier, factory, driveHeader);\n\t\t}\n\t}\n\tasync unregisterFactory(identifier) {\n\t\tconst factoryProcessors = this.factoryToProcessors.get(identifier);\n\t\tif (!factoryProcessors) return;\n\t\tfor (const [driveId, tracked] of factoryProcessors) {\n\t\t\tfor (const t of tracked) await this.safeDisconnect(t.record.processor);\n\t\t\tconst driveProcessors = this.processorsByDrive.get(driveId);\n\t\t\tif (driveProcessors) {\n\t\t\t\tconst remaining = driveProcessors.filter((p) => !tracked.includes(p));\n\t\t\t\tif (remaining.length > 0) this.processorsByDrive.set(driveId, remaining);\n\t\t\t\telse this.processorsByDrive.delete(driveId);\n\t\t\t}\n\t\t}\n\t\tawait this.deleteProcessorCursors({ factoryId: identifier });\n\t\tthis.factoryToProcessors.delete(identifier);\n\t\tthis.factoryRegistry.delete(identifier);\n\t}\n\tget(processorId) {\n\t\tfor (const tracked of this.allTrackedProcessors()) if (tracked.processorId === processorId) return tracked;\n\t}\n\tgetAll() {\n\t\treturn Array.from(this.allTrackedProcessors());\n\t}\n\t*allTrackedProcessors() {\n\t\tfor (const tracked of this.processorsByDrive.values()) yield* tracked;\n\t}\n\tasync detectAndRegisterNewDrives(operations) {\n\t\tfor (const op of operations) {\n\t\t\tif (!this.isDriveCreation(op)) continue;\n\t\t\tconst driveId = op.context.documentId;\n\t\t\tif (this.knownDrives.has(driveId)) continue;\n\t\t\tthis.knownDrives.set(driveId, op.context.documentType);\n\t\t\tconst driveHeader = extractDriveHeader(op);\n\t\t\tif (!driveHeader) continue;\n\t\t\tfor (const [identifier, factory] of this.factoryRegistry) await this.createProcessorsForDrive(driveId, identifier, factory, driveHeader);\n\t\t}\n\t}\n\tisDriveCreation(op) {\n\t\treturn op.operation.action.type === \"CREATE_DOCUMENT\" && this.driveContainerTypes.has(op.context.documentType);\n\t}\n\tasync detectAndCleanupDeletedDrives(operations) {\n\t\tfor (const op of operations) {\n\t\t\tif (!isDriveDeletion(op)) continue;\n\t\t\tconst driveId = extractDeletedDocumentId(op);\n\t\t\tif (!driveId || !this.knownDrives.has(driveId)) continue;\n\t\t\tif (!this.isDeletedDocumentADrive(driveId)) continue;\n\t\t\tawait this.cleanupDriveProcessors(driveId);\n\t\t\tthis.knownDrives.delete(driveId);\n\t\t}\n\t}\n\tasync discoverExistingDrives() {\n\t\tconst drives = await this.db.selectFrom(\"DocumentSnapshot\").select([\"documentId\", \"documentType\"]).where(\"documentType\", \"in\", [...this.driveContainerTypes]).where(\"isDeleted\", \"=\", false).execute();\n\t\tfor (const drive of drives) this.knownDrives.set(drive.documentId, drive.documentType);\n\t}\n\tisDeletedDocumentADrive(documentId) {\n\t\treturn this.knownDrives.has(documentId);\n\t}\n\tasync createProcessorsForDrive(driveId, identifier, factory, driveHeader) {\n\t\tlet records;\n\t\ttry {\n\t\t\trecords = await factory(driveHeader);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Factory '@FactoryId' failed for drive '@DriveId': @Error\", identifier, driveId, error);\n\t\t\treturn;\n\t\t}\n\t\tif (records.length === 0) return;\n\t\tconst trackedList = [];\n\t\tconst slots = resolveProcessorSlots(records, this.legacyProcessorIds);\n\t\tfor (let i = 0; i < records.length; i++) {\n\t\t\tconst record = records[i];\n\t\t\tconst processorId = `${identifier}:${driveId}:${slots[i]}`;\n\t\t\tconst cached = this.cursorCache.get(processorId);\n\t\t\tlet lastOrdinal;\n\t\t\tlet status;\n\t\t\tlet lastError;\n\t\t\tlet lastErrorTimestamp;\n\t\t\tif (cached) {\n\t\t\t\tlastOrdinal = cached.lastOrdinal;\n\t\t\t\tstatus = cached.status;\n\t\t\t\tlastError = cached.lastError ?? void 0;\n\t\t\t\tlastErrorTimestamp = cached.lastErrorTimestamp ?? void 0;\n\t\t\t} else {\n\t\t\t\tlastOrdinal = (record.startFrom ?? \"beginning\") === \"current\" ? this.lastOrdinal : 0;\n\t\t\t\tstatus = \"active\";\n\t\t\t\tlastError = void 0;\n\t\t\t\tlastErrorTimestamp = void 0;\n\t\t\t}\n\t\t\tconst tracked = {\n\t\t\t\tprocessorId,\n\t\t\t\tfactoryId: identifier,\n\t\t\t\tdriveId,\n\t\t\t\tprocessorIndex: i,\n\t\t\t\trecord,\n\t\t\t\tlastOrdinal,\n\t\t\t\tstatus,\n\t\t\t\tlastError,\n\t\t\t\tlastErrorTimestamp,\n\t\t\t\tretry: () => this.retryProcessor(tracked)\n\t\t\t};\n\t\t\ttrackedList.push(tracked);\n\t\t\tawait this.saveProcessorCursor(tracked);\n\t\t}\n\t\tconst liveIds = new Set(trackedList.map((t) => t.processorId));\n\t\tawait this.db.deleteFrom(\"ProcessorCursor\").where(\"factoryId\", \"=\", identifier).where(\"driveId\", \"=\", driveId).where(\"processorId\", \"not in\", [...liveIds]).execute();\n\t\tfor (const [id, row] of this.cursorCache) if (row.factoryId === identifier && row.driveId === driveId && !liveIds.has(id)) this.cursorCache.delete(id);\n\t\tconst factoryProcessors = this.factoryToProcessors.get(identifier);\n\t\tif (factoryProcessors) factoryProcessors.set(driveId, trackedList);\n\t\tconst existingDriveProcessors = this.processorsByDrive.get(driveId) ?? [];\n\t\tthis.processorsByDrive.set(driveId, [...existingDriveProcessors, ...trackedList]);\n\t\tfor (const tracked of trackedList) if (tracked.status === \"active\" && tracked.lastOrdinal < this.lastOrdinal) await this.backfillProcessor(tracked);\n\t}\n\tasync backfillProcessor(tracked) {\n\t\tlet page = await this.operationIndex.getSinceOrdinal(tracked.lastOrdinal);\n\t\twhile (page.results.length > 0) {\n\t\t\tconst matching = page.results.filter((op) => matchesFilter(op, tracked.record.filter));\n\t\t\tif (matching.length > 0) try {\n\t\t\t\tawait tracked.record.processor.onOperations(matching);\n\t\t\t} catch (error) {\n\t\t\t\ttracked.status = \"errored\";\n\t\t\t\ttracked.lastError = error instanceof Error ? error.message : String(error);\n\t\t\t\ttracked.lastErrorTimestamp = /* @__PURE__ */ new Date();\n\t\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t\t\tthis.logger.error(\"Processor '@ProcessorId' failed during backfill at ordinal @Ordinal: @Error\", tracked.processorId, tracked.lastOrdinal, error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttracked.lastOrdinal = page.results[page.results.length - 1].context.ordinal;\n\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t\tif (!page.next) break;\n\t\t\tpage = await page.next();\n\t\t}\n\t}\n\tasync retryProcessor(tracked) {\n\t\tif (tracked.status !== \"errored\") return;\n\t\ttracked.status = \"active\";\n\t\ttracked.lastError = void 0;\n\t\ttracked.lastErrorTimestamp = void 0;\n\t\tawait this.saveProcessorCursor(tracked);\n\t\tawait this.backfillProcessor(tracked);\n\t}\n\tasync cleanupDriveProcessors(driveId) {\n\t\tconst processors = this.processorsByDrive.get(driveId);\n\t\tif (!processors) return;\n\t\tfor (const tracked of processors) await this.safeDisconnect(tracked.record.processor);\n\t\tthis.processorsByDrive.delete(driveId);\n\t\tfor (const factoryProcessors of this.factoryToProcessors.values()) factoryProcessors.delete(driveId);\n\t\tawait this.deleteProcessorCursors({ driveId });\n\t}\n\tasync safeDisconnect(processor) {\n\t\ttry {\n\t\t\tawait processor.onDisconnect();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error disconnecting processor: @Error\", error);\n\t\t}\n\t}\n\tasync routeOperationsToProcessors(operations) {\n\t\tlet maxOrdinal = 0;\n\t\tfor (const op of operations) maxOrdinal = Math.max(maxOrdinal, op.context.ordinal);\n\t\tconst allTracked = Array.from(this.allTrackedProcessors());\n\t\tawait Promise.all(allTracked.map(async (tracked) => {\n\t\t\tif (tracked.status !== \"active\") return;\n\t\t\tconst matching = operations.filter((op) => op.context.ordinal > tracked.lastOrdinal).filter((op) => matchesFilter(op, tracked.record.filter));\n\t\t\tif (matching.length > 0) try {\n\t\t\t\tawait tracked.record.processor.onOperations(matching);\n\t\t\t} catch (error) {\n\t\t\t\ttracked.status = \"errored\";\n\t\t\t\ttracked.lastError = error instanceof Error ? error.message : String(error);\n\t\t\t\ttracked.lastErrorTimestamp = /* @__PURE__ */ new Date();\n\t\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t\t\tthis.logger.error(\"Processor '@ProcessorId' failed at ordinal @Ordinal: @Error\", tracked.processorId, tracked.lastOrdinal, error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttracked.lastOrdinal = maxOrdinal;\n\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t}));\n\t}\n\tasync loadAllCursors() {\n\t\tconst rows = await this.db.selectFrom(\"ProcessorCursor\").selectAll().execute();\n\t\tfor (const row of rows) this.cursorCache.set(row.processorId, row);\n\t}\n\tasync safeSaveProcessorCursor(tracked) {\n\t\ttry {\n\t\t\tawait this.saveProcessorCursor(tracked);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to persist cursor for '@ProcessorId': @Error\", tracked.processorId, error);\n\t\t}\n\t}\n\tasync saveProcessorCursor(tracked) {\n\t\tawait this.db.insertInto(\"ProcessorCursor\").values({\n\t\t\tprocessorId: tracked.processorId,\n\t\t\tfactoryId: tracked.factoryId,\n\t\t\tdriveId: tracked.driveId,\n\t\t\tprocessorIndex: tracked.processorIndex,\n\t\t\tlastOrdinal: tracked.lastOrdinal,\n\t\t\tstatus: tracked.status,\n\t\t\tlastError: tracked.lastError ?? null,\n\t\t\tlastErrorTimestamp: tracked.lastErrorTimestamp ?? null,\n\t\t\tupdatedAt: /* @__PURE__ */ new Date()\n\t\t}).onConflict((oc) => oc.column(\"processorId\").doUpdateSet({\n\t\t\tlastOrdinal: tracked.lastOrdinal,\n\t\t\tstatus: tracked.status,\n\t\t\tlastError: tracked.lastError ?? null,\n\t\t\tlastErrorTimestamp: tracked.lastErrorTimestamp ?? null,\n\t\t\tupdatedAt: /* @__PURE__ */ new Date()\n\t\t})).execute();\n\t\tthis.cursorCache.set(tracked.processorId, {\n\t\t\tprocessorId: tracked.processorId,\n\t\t\tfactoryId: tracked.factoryId,\n\t\t\tdriveId: tracked.driveId,\n\t\t\tprocessorIndex: tracked.processorIndex,\n\t\t\tlastOrdinal: tracked.lastOrdinal,\n\t\t\tstatus: tracked.status,\n\t\t\tlastError: tracked.lastError ?? null,\n\t\t\tlastErrorTimestamp: tracked.lastErrorTimestamp ?? null,\n\t\t\tcreatedAt: /* @__PURE__ */ new Date(),\n\t\t\tupdatedAt: /* @__PURE__ */ new Date()\n\t\t});\n\t}\n\tasync deleteProcessorCursors(filter) {\n\t\tif (\"factoryId\" in filter) {\n\t\t\tawait this.db.deleteFrom(\"ProcessorCursor\").where(\"factoryId\", \"=\", filter.factoryId).execute();\n\t\t\tfor (const [id, row] of this.cursorCache) if (row.factoryId === filter.factoryId) this.cursorCache.delete(id);\n\t\t} else {\n\t\t\tawait this.db.deleteFrom(\"ProcessorCursor\").where(\"driveId\", \"=\", filter.driveId).execute();\n\t\t\tfor (const [id, row] of this.cursorCache) if (row.driveId === filter.driveId) this.cursorCache.delete(id);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/queue/job-execution-handle.ts\n/**\n* Implementation of the IJobExecutionHandle interface\n*/\nvar JobExecutionHandle = class {\n\t_state;\n\t_job;\n\tonStart;\n\tonComplete;\n\tonFail;\n\tonDefer;\n\tgetStateName(state) {\n\t\tswitch (state) {\n\t\t\tcase JobQueueState.PREPROCESSING: return \"PREPROCESSING\";\n\t\t\tcase JobQueueState.PENDING: return \"PENDING\";\n\t\t\tcase JobQueueState.READY: return \"READY\";\n\t\t\tcase JobQueueState.RUNNING: return \"RUNNING\";\n\t\t\tcase JobQueueState.RESOLVED: return \"RESOLVED\";\n\t\t\tdefault: return `UNKNOWN`;\n\t\t}\n\t}\n\tconstructor(job, initialState, callbacks) {\n\t\tthis._job = job;\n\t\tthis._state = initialState;\n\t\tthis.onStart = callbacks?.onStart;\n\t\tthis.onComplete = callbacks?.onComplete;\n\t\tthis.onFail = callbacks?.onFail;\n\t\tthis.onDefer = callbacks?.onDefer;\n\t}\n\tget job() {\n\t\treturn this._job;\n\t}\n\tget state() {\n\t\treturn this._state;\n\t}\n\tstart() {\n\t\tif (this._state !== JobQueueState.READY) throw new Error(`Cannot start job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RUNNING;\n\t\tthis.onStart?.();\n\t}\n\tcomplete() {\n\t\tif (this._state !== JobQueueState.RUNNING) throw new Error(`Cannot complete job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RESOLVED;\n\t\tthis.onComplete?.();\n\t}\n\tfail(error) {\n\t\tif (this._state !== JobQueueState.RUNNING) throw new Error(`Cannot fail job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RESOLVED;\n\t\tthis.onFail?.(error);\n\t}\n\tdefer() {\n\t\tif (this._state !== JobQueueState.RUNNING) throw new Error(`Cannot defer job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RESOLVED;\n\t\tthis.onDefer?.();\n\t}\n};\n//#endregion\n//#region src/queue/queue.ts\n/**\n* In-memory implementation of the IQueue interface.\n* Organizes jobs by documentId, scope, and branch to ensure proper ordering.\n* Ensures serial execution per document by tracking executing jobs.\n* Implements dependency management through queue hints.\n*/\nvar InMemoryQueue = class {\n\tqueues = /* @__PURE__ */ new Map();\n\tjobIdToQueueKey = /* @__PURE__ */ new Map();\n\tdocIdToJobId = /* @__PURE__ */ new Map();\n\tjobIdToDocId = /* @__PURE__ */ new Map();\n\tcompletedJobs = /* @__PURE__ */ new Set();\n\tjobIndex = /* @__PURE__ */ new Map();\n\tisBlocked = false;\n\tonDrainedCallback;\n\tisPausedFlag = false;\n\tconstructor(eventBus, resolver) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.resolver = resolver;\n\t}\n\ttoErrorInfo(error) {\n\t\tif (error instanceof Error) return {\n\t\t\tname: error.name,\n\t\t\tmessage: error.message,\n\t\t\tstack: error.stack || (/* @__PURE__ */ new Error()).stack || \"\"\n\t\t};\n\t\treturn {\n\t\t\tname: \"Error\",\n\t\t\tmessage: error,\n\t\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t\t};\n\t}\n\t/**\n\t* Creates a unique key for a document/scope/branch combination\n\t*/\n\tcreateQueueKey(documentId, scope, branch) {\n\t\treturn `${documentId}:${scope}:${branch}`;\n\t}\n\t/**\n\t* Gets or creates a queue for the given key\n\t*/\n\tgetQueue(queueKey) {\n\t\tlet queue = this.queues.get(queueKey);\n\t\tif (!queue) {\n\t\t\tqueue = [];\n\t\t\tthis.queues.set(queueKey, queue);\n\t\t}\n\t\treturn queue;\n\t}\n\t/**\n\t* Check if a document has any jobs currently executing\n\t*/\n\tisDocumentExecuting(documentId) {\n\t\tconst executingSet = this.docIdToJobId.get(documentId);\n\t\treturn executingSet ? executingSet.size > 0 : false;\n\t}\n\t/**\n\t* Mark a job as executing for its document\n\t*/\n\tmarkJobExecuting(job) {\n\t\tlet executingSet = this.docIdToJobId.get(job.documentId);\n\t\tif (!executingSet) {\n\t\t\texecutingSet = /* @__PURE__ */ new Set();\n\t\t\tthis.docIdToJobId.set(job.documentId, executingSet);\n\t\t}\n\t\texecutingSet.add(job.id);\n\t\tthis.jobIdToDocId.set(job.id, job.documentId);\n\t}\n\t/**\n\t* Mark a job as no longer executing for its document\n\t*/\n\tmarkJobComplete(jobId, documentId) {\n\t\tconst executingSet = this.docIdToJobId.get(documentId);\n\t\tif (executingSet) {\n\t\t\texecutingSet.delete(jobId);\n\t\t\tif (executingSet.size === 0) this.docIdToJobId.delete(documentId);\n\t\t}\n\t\tthis.jobIdToDocId.delete(jobId);\n\t}\n\t/**\n\t* Check if all dependencies for a job have been completed\n\t*/\n\tareDependenciesMet(job) {\n\t\tif (job.queueHint.length === 0) return true;\n\t\treturn job.queueHint.every((depId) => this.completedJobs.has(depId));\n\t}\n\t/**\n\t* Returns the head of the sub-queue if its dependencies are met, or null.\n\t*\n\t* The dispatcher only ever considers the head — a dep-blocked head holds\n\t* the rest of its sub-queue. This preserves per-(documentId, scope, branch)\n\t* FIFO regardless of how dependencies are authored, and makes the queue's\n\t* documented \"serialized per document\" invariant hold even when callers\n\t* omit queueHint dependencies on jobs that share a sub-queue.\n\t*/\n\tgetNextJobWithMetDependencies(queue) {\n\t\tif (queue.length === 0) return null;\n\t\tconst head = queue[0];\n\t\treturn this.areDependenciesMet(head) ? head : null;\n\t}\n\tgetCreateDocumentType(job) {\n\t\tfor (const action of job.actions) if (action.type === \"CREATE_DOCUMENT\") return action.input.model;\n\t\tfor (const operation of job.operations) if (operation.action.type === \"CREATE_DOCUMENT\") return operation.action.input.model;\n\t}\n\tasync enqueue(job) {\n\t\tif (this.isBlocked) throw new Error(\"Queue is blocked\");\n\t\tconst queueKey = this.createQueueKey(job.documentId, job.scope, job.branch);\n\t\tthis.getQueue(queueKey).push(job);\n\t\tthis.jobIdToQueueKey.set(job.id, queueKey);\n\t\tthis.jobIndex.set(job.id, job);\n\t\tconst documentType = this.getCreateDocumentType(job);\n\t\tif (documentType) try {\n\t\t\tawait this.resolver.ensureModelLoaded(documentType);\n\t\t} catch {\n\t\t\tawait this.failJob(job.id, {\n\t\t\t\tname: \"Error\",\n\t\t\t\tmessage: `Failed to load document model for type: ${documentType}`,\n\t\t\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tconst eventData = {\n\t\t\tdocumentId: job.documentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch,\n\t\t\tjobId: job.id\n\t\t};\n\t\tawait this.eventBus.emit(QueueEventTypes.JOB_AVAILABLE, eventData);\n\t}\n\tdequeue(documentId, scope, branch, signal) {\n\t\tconst queueKey = this.createQueueKey(documentId, scope, branch);\n\t\tconst queue = this.queues.get(queueKey);\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (!queue || queue.length === 0) return Promise.resolve(null);\n\t\tconst job = this.getNextJobWithMetDependencies(queue);\n\t\tif (!job) return Promise.resolve(null);\n\t\tconst jobIndex = queue.indexOf(job);\n\t\tqueue.splice(jobIndex, 1);\n\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\tthis.markJobExecuting(job);\n\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\tconst handle = new JobExecutionHandle(job, JobQueueState.READY, {\n\t\t\tonStart: () => {},\n\t\t\tonComplete: () => {\n\t\t\t\tthis.completeJob(job.id);\n\t\t\t},\n\t\t\tonFail: (error) => {\n\t\t\t\tthis.failJob(job.id, error);\n\t\t\t},\n\t\t\tonDefer: () => {\n\t\t\t\tthis.deferJob(job.id);\n\t\t\t}\n\t\t});\n\t\treturn Promise.resolve(handle);\n\t}\n\tdequeueNext(signal) {\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (this.isPausedFlag) return Promise.resolve(null);\n\t\tfor (const [queueKey, queue] of this.queues.entries()) if (queue.length > 0) {\n\t\t\tconst job = this.getNextJobWithMetDependencies(queue);\n\t\t\tif (!job) continue;\n\t\t\tif (!this.isDocumentExecuting(job.documentId)) {\n\t\t\t\tconst jobIdx = queue.indexOf(job);\n\t\t\t\tqueue.splice(jobIdx, 1);\n\t\t\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\t\t\tthis.markJobExecuting(job);\n\t\t\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\t\t\tconst handle = new JobExecutionHandle(job, JobQueueState.READY, {\n\t\t\t\t\tonStart: () => {},\n\t\t\t\t\tonComplete: () => {\n\t\t\t\t\t\tthis.completeJob(job.id);\n\t\t\t\t\t},\n\t\t\t\t\tonFail: (error) => {\n\t\t\t\t\t\tthis.failJob(job.id, error);\n\t\t\t\t\t},\n\t\t\t\t\tonDefer: () => {\n\t\t\t\t\t\tthis.deferJob(job.id);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn Promise.resolve(handle);\n\t\t\t}\n\t\t}\n\t\treturn Promise.resolve(null);\n\t}\n\tdequeueNextMatching(predicate, signal) {\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (this.isPausedFlag) return Promise.resolve(null);\n\t\tfor (const [queueKey, queue] of this.queues.entries()) if (queue.length > 0) {\n\t\t\tconst job = this.getNextJobWithMetDependencies(queue);\n\t\t\tif (!job) continue;\n\t\t\tif (this.isDocumentExecuting(job.documentId)) continue;\n\t\t\tif (!predicate({\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch\n\t\t\t})) continue;\n\t\t\tconst jobIdx = queue.indexOf(job);\n\t\t\tqueue.splice(jobIdx, 1);\n\t\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\t\tthis.markJobExecuting(job);\n\t\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\t\tconst handle = new JobExecutionHandle(job, JobQueueState.READY, {\n\t\t\t\tonStart: () => {},\n\t\t\t\tonComplete: () => {\n\t\t\t\t\tthis.completeJob(job.id);\n\t\t\t\t},\n\t\t\t\tonFail: (error) => {\n\t\t\t\t\tthis.failJob(job.id, error);\n\t\t\t\t},\n\t\t\t\tonDefer: () => {\n\t\t\t\t\tthis.deferJob(job.id);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn Promise.resolve(handle);\n\t\t}\n\t\treturn Promise.resolve(null);\n\t}\n\tsize(documentId, scope, branch) {\n\t\tconst queueKey = this.createQueueKey(documentId, scope, branch);\n\t\tconst queue = this.queues.get(queueKey);\n\t\treturn Promise.resolve(queue ? queue.length : 0);\n\t}\n\ttotalSize() {\n\t\tlet total = 0;\n\t\tfor (const queue of this.queues.values()) total += queue.length;\n\t\treturn Promise.resolve(total);\n\t}\n\tremove(jobId) {\n\t\tconst queueKey = this.jobIdToQueueKey.get(jobId);\n\t\tif (!queueKey) return Promise.resolve(false);\n\t\tconst queue = this.queues.get(queueKey);\n\t\tif (!queue) {\n\t\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\t\tthis.jobIndex.delete(jobId);\n\t\t\treturn Promise.resolve(false);\n\t\t}\n\t\tconst jobIdx = queue.findIndex((job) => job.id === jobId);\n\t\tif (jobIdx === -1) {\n\t\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\t\tthis.jobIndex.delete(jobId);\n\t\t\treturn Promise.resolve(false);\n\t\t}\n\t\tqueue.splice(jobIdx, 1);\n\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\tthis.jobIndex.delete(jobId);\n\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\treturn Promise.resolve(true);\n\t}\n\tclear(documentId, scope, branch) {\n\t\tconst queueKey = this.createQueueKey(documentId, scope, branch);\n\t\tconst queue = this.queues.get(queueKey);\n\t\tif (queue) {\n\t\t\tfor (const job of queue) {\n\t\t\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\t\t\tthis.jobIndex.delete(job.id);\n\t\t\t}\n\t\t\tthis.queues.delete(queueKey);\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\tclearAll() {\n\t\tthis.jobIdToQueueKey.clear();\n\t\tthis.jobIndex.clear();\n\t\tthis.completedJobs.clear();\n\t\tthis.queues.clear();\n\t\treturn Promise.resolve();\n\t}\n\thasJobs() {\n\t\treturn Promise.resolve(this.queues.size > 0 && Array.from(this.queues.values()).some((q) => q.length > 0));\n\t}\n\tasync completeJob(jobId) {\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tthis.completedJobs.add(jobId);\n\t\tthis.jobIndex.delete(jobId);\n\t\tawait this.remove(jobId);\n\t\tthis.checkDrained();\n\t}\n\tasync failJob(jobId, error) {\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tconst job = this.jobIndex.get(jobId);\n\t\tif (job) {\n\t\t\tjob.lastError = error;\n\t\t\tif (error) job.errorHistory.push(error);\n\t\t}\n\t\tthis.jobIndex.delete(jobId);\n\t\tthis.completedJobs.add(jobId);\n\t\tawait this.remove(jobId);\n\t\tconst emittedError = new Error(error?.message ?? \"Job failed\");\n\t\tif (error?.name) emittedError.name = error.name;\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\tjobId,\n\t\t\terror: emittedError,\n\t\t\tjob\n\t\t}).catch(() => {});\n\t\tthis.checkDrained();\n\t}\n\tdeferJob(jobId) {\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tthis.jobIndex.delete(jobId);\n\t}\n\tasync retryJob(jobId, error, accounting = RetryAccounting.CountAgainstLimit) {\n\t\tconst job = this.jobIndex.get(jobId);\n\t\tif (!job) return;\n\t\tjob.lastError = error;\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tthis.jobIndex.delete(jobId);\n\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\tif (error) job.errorHistory.push(error);\n\t\tconst retryCount = job.retryCount || 0;\n\t\tconst updatedJob = {\n\t\t\t...job,\n\t\t\tretryCount: accounting === RetryAccounting.CountAgainstLimit ? retryCount + 1 : retryCount,\n\t\t\tlastError: error\n\t\t};\n\t\tawait this.enqueue(updatedJob);\n\t}\n\t/**\n\t* Check if the queue is drained and call the callback if it is\n\t*/\n\tcheckDrained() {\n\t\tif (this.isDrained && this.onDrainedCallback) {\n\t\t\tconst callback = this.onDrainedCallback;\n\t\t\tthis.onDrainedCallback = void 0;\n\t\t\tcallback();\n\t\t}\n\t}\n\t/**\n\t* Returns true if and only if all jobs have been resolved.\n\t*/\n\tget isDrained() {\n\t\tconst hasPendingJobs = this.queues.size > 0 && Array.from(this.queues.values()).some((q) => q.length > 0);\n\t\tconst hasExecutingJobs = this.docIdToJobId.size > 0 && Array.from(this.docIdToJobId.values()).some((set) => set.size > 0);\n\t\treturn !hasPendingJobs && !hasExecutingJobs;\n\t}\n\t/**\n\t* Blocks the queue from accepting new jobs.\n\t* @param onDrained - Optional callback to call when the queue is drained\n\t*/\n\tblock(onDrained) {\n\t\tthis.isBlocked = true;\n\t\tthis.onDrainedCallback = onDrained;\n\t\tthis.checkDrained();\n\t}\n\t/**\n\t* Unblocks the queue from accepting new jobs.\n\t*/\n\tunblock() {\n\t\tthis.isBlocked = false;\n\t\tthis.onDrainedCallback = void 0;\n\t}\n\t/**\n\t* Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.\n\t*/\n\tpause() {\n\t\tthis.isPausedFlag = true;\n\t}\n\t/**\n\t* Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.\n\t*/\n\tasync resume() {\n\t\tthis.isPausedFlag = false;\n\t\tfor (const [, queue] of this.queues.entries()) if (queue.length > 0) {\n\t\t\tconst job = queue[0];\n\t\t\tawait this.eventBus.emit(QueueEventTypes.JOB_AVAILABLE, {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch,\n\t\t\t\tjobId: job.id\n\t\t\t});\n\t\t}\n\t}\n\t/**\n\t* Returns whether job dequeuing is paused.\n\t*/\n\tget paused() {\n\t\treturn this.isPausedFlag;\n\t}\n\t/**\n\t* Returns all pending jobs across all queues.\n\t*/\n\tgetPendingJobs() {\n\t\tconst jobs = [];\n\t\tfor (const queue of this.queues.values()) jobs.push(...queue);\n\t\treturn jobs;\n\t}\n\t/**\n\t* Returns a map of document IDs to sets of executing job IDs.\n\t*/\n\tgetExecutingJobIds() {\n\t\treturn new Map(Array.from(this.docIdToJobId.entries()).map(([k, v]) => [k, new Set(v)]));\n\t}\n\t/**\n\t* Returns a job by ID from the job index.\n\t*/\n\tgetJob(jobId) {\n\t\treturn this.jobIndex.get(jobId);\n\t}\n};\n//#endregion\n//#region src/projection/read-model-kinds.ts\n/**\n* Every {@link BuiltInReadModelKind}, at runtime. Derived from a total\n* record so adding a kind to the union without adding it here is a compile\n* error: under projection sharding a kind missing from both `preReadyKinds`\n* and `postReadyKinds` is indexed by nobody — the host's own copies never\n* index an operation — so a gap here reads as silently stale data.\n*/\nconst BUILT_IN_READ_MODEL_KINDS = Object.keys({\n\t\"document-view\": true,\n\t\"document-indexer\": true\n});\n//#endregion\n//#region src/core/model-sources.ts\nfunction modelSourceKey(module) {\n\treturn `${module.documentModel.global.id}@${module.version ?? 1}`;\n}\nfunction isDocumentModelModule(value) {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = value;\n\treturn typeof candidate.reducer === \"function\" && typeof candidate.documentModel?.global?.id === \"string\";\n}\n/**\n* Resolves every source to live modules by importing file/package sources\n* host-side and scanning their exports, so the host registry and the worker\n* manifest are derived from one list and cannot diverge.\n*/\nasync function resolveModelSources(sources) {\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const source of sources) {\n\t\tif (isDocumentModelModule(source)) {\n\t\t\taddEntry(resolved, {\n\t\t\t\tmodule: source,\n\t\t\t\tspec: null\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of await resolveImportableSource(source)) addEntry(resolved, entry);\n\t}\n\tconst modules = [];\n\tconst manifest = [];\n\tconst moduleOnlyKeys = [];\n\tfor (const [key, entry] of resolved) {\n\t\tmodules.push(entry.module);\n\t\tif (entry.spec) manifest.push({\n\t\t\tdocumentType: entry.module.documentModel.global.id,\n\t\t\tversion: String(entry.module.version ?? 1),\n\t\t\tspec: entry.spec\n\t\t});\n\t\telse moduleOnlyKeys.push(key);\n\t}\n\treturn {\n\t\tmodules,\n\t\tmanifest,\n\t\tmoduleOnlyKeys\n\t};\n}\nfunction addEntry(map, entry) {\n\tconst key = modelSourceKey(entry.module);\n\tconst existing = map.get(key);\n\tif (!existing) {\n\t\tmap.set(key, entry);\n\t\treturn;\n\t}\n\tif (!existing.spec && entry.spec) existing.spec = entry.spec;\n}\nasync function resolveImportableSource(source) {\n\tconst isFile = \"filePath\" in source;\n\tconst specifier = isFile ? new URL(`file://${source.filePath}`).href : source.subpath ? `${source.packageName}/${source.subpath}` : source.packageName;\n\tconst moduleRef = isFile ? { filePath: source.filePath } : { packageName: specifier };\n\tlet moduleNs;\n\ttry {\n\t\tmoduleNs = await import(\n\t\t\t/* @vite-ignore */\n\t\t\tspecifier\n);\n\t} catch (error) {\n\t\tthrow new Error(`Failed to import document-model source \"${describeSource(source)}\"`, { cause: error });\n\t}\n\tif (source.exportName !== void 0) {\n\t\tconst value = moduleNs[source.exportName];\n\t\tif (!isDocumentModelModule(value)) throw new Error(`Export \"${source.exportName}\" of document-model source \"${describeSource(source)}\" is not a DocumentModelModule`);\n\t\treturn [{\n\t\t\tmodule: value,\n\t\t\tspec: { module: {\n\t\t\t\t...moduleRef,\n\t\t\t\texportName: source.exportName\n\t\t\t} }\n\t\t}];\n\t}\n\tconst entries = [];\n\tfor (const [exportName, value] of Object.entries(moduleNs)) if (isDocumentModelModule(value)) entries.push({\n\t\tmodule: value,\n\t\tspec: { module: {\n\t\t\t...moduleRef,\n\t\t\texportName\n\t\t} }\n\t});\n\tif (entries.length === 0) throw new Error(`Document-model source \"${describeSource(source)}\" has no DocumentModelModule exports`);\n\treturn entries;\n}\nfunction describeSource(source) {\n\treturn \"filePath\" in source ? source.filePath : source.subpath ? `${source.packageName}/${source.subpath}` : source.packageName;\n}\n//#endregion\n//#region src/registry/document-model-resolver.ts\n/**\n* Encapsulates the logic for resolving document model modules on demand.\n* Shared between the queue (CREATE_DOCUMENT gate) and the executor manager\n* (post-failure recovery) so that both paths use the same deduplication\n* and failure-caching state.\n*/\nvar DocumentModelResolver = class {\n\tloadingModels = /* @__PURE__ */ new Map();\n\tfailedModelTypes = /* @__PURE__ */ new Set();\n\tbroadcastHook = null;\n\tmodelLoadedHook = null;\n\tlogger = childLogger([\"reactor\", \"document-model-resolver\"]);\n\tconstructor(registry, loader) {\n\t\tthis.registry = registry;\n\t\tthis.loader = loader;\n\t}\n\t/**\n\t* Install a post-success hook called after the resolver registers a\n\t* newly loaded model. ReactorBuilder uses this to wire the worker-pool\n\t* `load-model` broadcast without touching the resolver's constructor.\n\t*/\n\tsetBroadcastHook(hook) {\n\t\tthis.broadcastHook = hook;\n\t}\n\t/**\n\t* Post-success hook called with the document type after a model loads, so\n\t* peers (tabs) can load the same type via the event bus.\n\t*/\n\tsetModelLoadedHook(hook) {\n\t\tthis.modelLoadedHook = hook;\n\t}\n\tasync ensureModelLoaded(documentType) {\n\t\ttry {\n\t\t\tthis.registry.getModule(documentType);\n\t\t\treturn;\n\t\t} catch (error) {\n\t\t\tif (!ModuleNotFoundError.isError(error)) throw error;\n\t\t}\n\t\tif (this.failedModelTypes.has(documentType)) throw new Error(`Document model type previously failed to load: ${documentType}`);\n\t\tconst existing = this.loadingModels.get(documentType);\n\t\tif (existing) return existing;\n\t\tconst loadPromise = (async () => {\n\t\t\ttry {\n\t\t\t\tawait this.loadRegisterAndBroadcast(documentType);\n\t\t\t} catch (error) {\n\t\t\t\tthis.failedModelTypes.add(documentType);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tthis.loadingModels.delete(documentType);\n\t\t\t}\n\t\t\tawait this.notifyPeersModelLoaded(documentType);\n\t\t})();\n\t\tthis.loadingModels.set(documentType, loadPromise);\n\t\treturn loadPromise;\n\t}\n\tasync loadRegisterAndBroadcast(documentType) {\n\t\tconst resolved = await resolveModelSources([await this.loader.load(documentType)]);\n\t\tif (!resolved.modules.some((module) => module.documentModel.global.id === documentType)) throw new Error(`Loader source resolved no module for document type: ${documentType}`);\n\t\tconst results = this.registry.registerModules(...resolved.modules);\n\t\tfor (const result of results) if (result.status === \"error\" && !DuplicateModuleError.isError(result.error)) throw result.error;\n\t\tif (this.broadcastHook) for (const entry of resolved.manifest) await this.broadcastHook(entry);\n\t}\n\tasync notifyPeersModelLoaded(documentType) {\n\t\tif (!this.modelLoadedHook) return;\n\t\ttry {\n\t\t\tawait this.modelLoadedHook(documentType);\n\t\t} catch (error) {\n\t\t\tthis.logger.warn(`MODEL_LOADED hook failed: ${documentType}`, error);\n\t\t}\n\t}\n};\n/**\n* No-op resolver used when no document model loader is configured.\n* Checks the registry for the model and returns if found; throws if not.\n* Since there is no loader, missing models cannot be recovered.\n*/\nvar NullDocumentModelResolver = class {\n\tconstructor(registry) {\n\t\tthis.registry = registry;\n\t}\n\tensureModelLoaded(documentType) {\n\t\tif (this.registry) try {\n\t\t\tthis.registry.getModule(documentType);\n\t\t\treturn Promise.resolve();\n\t\t} catch {}\n\t\treturn Promise.reject(new ModuleNotFoundError(documentType));\n\t}\n};\n//#endregion\n//#region src/subs/default-error-handler.ts\n/**\n* Default error handler that re-throws subscription errors.\n* This ensures that errors are not silently swallowed.\n*/\nvar DefaultSubscriptionErrorHandler = class {\n\thandleError(error, context) {\n\t\tconst errorMessage = `Subscription error in ${context.eventType} (${context.subscriptionId})`;\n\t\tif (error instanceof Error) {\n\t\t\tconst enhancedError = /* @__PURE__ */ new Error(`${errorMessage}: ${error.message}`);\n\t\t\tenhancedError.cause = error;\n\t\t\tenhancedError.stack = error.stack;\n\t\t\tthrow enhancedError;\n\t\t} else throw new Error(`${errorMessage}: ${String(error)}`);\n\t}\n};\n//#endregion\n//#region src/subs/react-subscription-manager.ts\nvar ReactorSubscriptionManager = class {\n\tcreatedSubscriptions = /* @__PURE__ */ new Map();\n\tdeletedSubscriptions = /* @__PURE__ */ new Map();\n\tupdatedSubscriptions = /* @__PURE__ */ new Map();\n\trelationshipSubscriptions = /* @__PURE__ */ new Map();\n\tsubscriptionCounter = 0;\n\terrorHandler;\n\tconstructor(errorHandler) {\n\t\tthis.errorHandler = errorHandler;\n\t}\n\tonDocumentCreated(callback, search) {\n\t\tconst id = `created-${++this.subscriptionCounter}`;\n\t\tthis.createdSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch\n\t\t});\n\t\treturn () => {\n\t\t\tthis.createdSubscriptions.delete(id);\n\t\t};\n\t}\n\tonDocumentDeleted(callback, search) {\n\t\tconst id = `deleted-${++this.subscriptionCounter}`;\n\t\tthis.deletedSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch\n\t\t});\n\t\treturn () => {\n\t\t\tthis.deletedSubscriptions.delete(id);\n\t\t};\n\t}\n\tonDocumentStateUpdated(callback, search, view) {\n\t\tconst id = `updated-${++this.subscriptionCounter}`;\n\t\tthis.updatedSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch,\n\t\t\tview\n\t\t});\n\t\treturn () => {\n\t\t\tthis.updatedSubscriptions.delete(id);\n\t\t};\n\t}\n\tonRelationshipChanged(callback, search) {\n\t\tconst id = `relationship-${++this.subscriptionCounter}`;\n\t\tthis.relationshipSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch\n\t\t});\n\t\treturn () => {\n\t\t\tthis.relationshipSubscriptions.delete(id);\n\t\t};\n\t}\n\t/**\n\t* Notify subscribers about created documents\n\t*/\n\tnotifyDocumentsCreated(documentIds, documentTypes, parentIds) {\n\t\tconst result = {\n\t\t\tresults: documentIds,\n\t\t\toptions: {\n\t\t\t\tcursor: \"\",\n\t\t\t\tlimit: documentIds.length\n\t\t\t}\n\t\t};\n\t\tfor (const subscription of this.createdSubscriptions.values()) {\n\t\t\tconst filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);\n\t\t\tif (filteredIds.length > 0) try {\n\t\t\t\tsubscription.callback({\n\t\t\t\t\t...result,\n\t\t\t\t\tresults: filteredIds\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\t\teventType: \"created\",\n\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\teventData: filteredIds\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Notify subscribers about deleted documents\n\t*/\n\tnotifyDocumentsDeleted(documentIds, documentTypes, parentIds) {\n\t\tfor (const subscription of this.deletedSubscriptions.values()) {\n\t\t\tconst filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);\n\t\t\tif (filteredIds.length > 0) try {\n\t\t\t\tsubscription.callback(filteredIds);\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\t\teventType: \"deleted\",\n\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\teventData: filteredIds\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Notify subscribers about updated documents\n\t*/\n\tnotifyDocumentsUpdated(documents) {\n\t\tconst result = {\n\t\t\tresults: documents,\n\t\t\toptions: {\n\t\t\t\tcursor: \"\",\n\t\t\t\tlimit: documents.length\n\t\t\t}\n\t\t};\n\t\tfor (const subscription of this.updatedSubscriptions.values()) {\n\t\t\tconst filteredDocs = this.filterDocuments(documents, subscription.search);\n\t\t\tif (filteredDocs.length > 0) try {\n\t\t\t\tsubscription.callback({\n\t\t\t\t\t...result,\n\t\t\t\t\tresults: filteredDocs\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\t\teventType: \"updated\",\n\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\teventData: filteredDocs\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Notify subscribers about relationship changes\n\t*/\n\tnotifyRelationshipChanged(parentId, childId, changeType, childType) {\n\t\tfor (const subscription of this.relationshipSubscriptions.values()) if (this.matchesRelationshipFilter(parentId, childId, childType, subscription.search)) try {\n\t\t\tsubscription.callback(parentId, childId, changeType);\n\t\t} catch (error) {\n\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\teventType: \"relationshipChanged\",\n\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\teventData: {\n\t\t\t\t\tparentId,\n\t\t\t\t\tchildId,\n\t\t\t\t\tchangeType\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\t/**\n\t* Clear all subscriptions\n\t*/\n\tclearAll() {\n\t\tthis.createdSubscriptions.clear();\n\t\tthis.deletedSubscriptions.clear();\n\t\tthis.updatedSubscriptions.clear();\n\t\tthis.relationshipSubscriptions.clear();\n\t}\n\tfilterDocumentIds(documentIds, search, documentTypes, parentIds) {\n\t\tif (!search) return documentIds;\n\t\treturn documentIds.filter((id) => {\n\t\t\tif (search.ids && !search.ids.includes(id)) return false;\n\t\t\tif (search.type && documentTypes) {\n\t\t\t\tif (documentTypes.get(id) !== search.type) return false;\n\t\t\t}\n\t\t\tif (search.parentId && parentIds) {\n\t\t\t\tif (parentIds.get(id) !== search.parentId) return false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t}\n\tfilterDocuments(documents, search) {\n\t\tif (!search) return documents;\n\t\treturn documents.filter((doc) => {\n\t\t\tif (search.ids && !search.ids.includes(doc.header.id)) return false;\n\t\t\tif (search.type && doc.header.documentType !== search.type) return false;\n\t\t\tif (search.slugs && !search.slugs.includes(doc.header.slug)) return false;\n\t\t\treturn true;\n\t\t});\n\t}\n\tmatchesRelationshipFilter(parentId, childId, childType, search) {\n\t\tif (!search) return true;\n\t\tif (search.parentId && parentId !== search.parentId) return false;\n\t\tif (search.ids && !search.ids.includes(childId)) return false;\n\t\tif (search.type && childType && childType !== search.type) return false;\n\t\treturn true;\n\t}\n};\n//#endregion\n//#region src/subs/subscription-notification-read-model.ts\n/**\n* A read model that notifies the subscription manager when operations are processed.\n* This bridges the gap between operation processing and subscription callbacks.\n*\n* Must be processed AFTER other read models have completed and AFTER READ_READY\n* is emitted, so that reactor.get() returns fresh data when callbacks fire.\n*/\nvar SubscriptionNotificationReadModel = class {\n\tname = \"subscription-notification\";\n\tconstructor(subscriptionManager, documentView) {\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\tthis.documentView = documentView;\n\t}\n\tasync indexOperations(operations) {\n\t\tif (operations.length === 0) return;\n\t\tconst created = [];\n\t\tconst deleted = [];\n\t\tconst updatedIds = /* @__PURE__ */ new Set();\n\t\tconst documentTypes = /* @__PURE__ */ new Map();\n\t\tconst parentIds = /* @__PURE__ */ new Map();\n\t\tfor (const item of operations) {\n\t\t\tconst { operation, context } = item;\n\t\t\tconst actionType = operation.action.type;\n\t\t\tdocumentTypes.set(context.documentId, context.documentType);\n\t\t\tif (actionType === \"CREATE_DOCUMENT\") created.push(context.documentId);\n\t\t\telse if (actionType === \"DELETE_DOCUMENT\") {\n\t\t\t\tconst deletedId = operation.action.input.documentId ?? context.documentId;\n\t\t\t\tdeleted.push(deletedId);\n\t\t\t} else if (actionType === \"ADD_RELATIONSHIP\") {\n\t\t\t\tconst input = operation.action.input;\n\t\t\t\tthis.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, RelationshipChangeType.Added, input.childType);\n\t\t\t} else if (actionType === \"REMOVE_RELATIONSHIP\") {\n\t\t\t\tconst input = operation.action.input;\n\t\t\t\tthis.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, RelationshipChangeType.Removed, input.childType);\n\t\t\t} else if (!created.includes(context.documentId)) updatedIds.add(context.documentId);\n\t\t}\n\t\tif (created.length > 0) this.subscriptionManager.notifyDocumentsCreated(created, documentTypes, parentIds);\n\t\tif (deleted.length > 0) this.subscriptionManager.notifyDocumentsDeleted(deleted, documentTypes, parentIds);\n\t\tif (updatedIds.size > 0 && this.documentView) {\n\t\t\tconst documents = await Promise.all(Array.from(updatedIds).map((id) => this.documentView.get(id)));\n\t\t\tthis.subscriptionManager.notifyDocumentsUpdated(documents);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/core/group-reevaluation-trigger.ts\n/**\n* Watches committed writes for group membership changes and enqueues a\n* re-evaluation job for every document whose auth history references the\n* changed group, found through the reverse direction of the group-reference\n* relation. Each affected document is re-judged in its own job, so the work\n* runs under that document's execution slot rather than the group's.\n*\n* The job carries the earliest changed membership timestamp; the executor\n* skips the pass when everything the document holds sorts before it, which\n* keeps the common case (a membership write later than all history) free.\n*/\nvar GroupReevaluationTrigger = class {\n\tunsubscribe;\n\tconstructor(logger, eventBus, queue, operationIndex) {\n\t\tthis.logger = logger;\n\t\tthis.eventBus = eventBus;\n\t\tthis.queue = queue;\n\t\tthis.operationIndex = operationIndex;\n\t}\n\tstartup() {\n\t\tthis.unsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, async (_type, event) => this.onWriteReady(event));\n\t}\n\tshutdown() {\n\t\tthis.unsubscribe?.();\n\t\tthis.unsubscribe = void 0;\n\t}\n\tasync onWriteReady(event) {\n\t\tconst changed = /* @__PURE__ */ new Map();\n\t\tfor (const { operation, context } of event.operations) {\n\t\t\tif (context.documentType !== groupDocumentType || context.scope !== \"global\" || !groupMembershipActionTypes.includes(operation.action.type)) continue;\n\t\t\tconst existing = changed.get(context.documentId);\n\t\t\tif (existing === void 0 || Date.parse(operation.timestampUtcMs) < Date.parse(existing)) changed.set(context.documentId, operation.timestampUtcMs);\n\t\t}\n\t\tif (changed.size === 0) return;\n\t\tconst affected = /* @__PURE__ */ new Map();\n\t\tfor (const [groupId, timestamp] of changed) {\n\t\t\tlet referencers;\n\t\t\ttry {\n\t\t\t\treferencers = await this.operationIndex.getGroupReferencers(groupId);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Failed to resolve referencers of group @groupId: @error\", groupId, error);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const documentId of referencers) {\n\t\t\t\tconst existing = affected.get(documentId);\n\t\t\t\tif (existing === void 0 || Date.parse(timestamp) < Date.parse(existing)) affected.set(documentId, timestamp);\n\t\t\t}\n\t\t}\n\t\tfor (const [documentId, timestamp] of affected) {\n\t\t\tconst jobId = v4();\n\t\t\tconst job = {\n\t\t\t\tid: jobId,\n\t\t\t\tkind: \"reevaluation\",\n\t\t\t\tdocumentId,\n\t\t\t\tscope: \"global\",\n\t\t\t\tbranch: \"main\",\n\t\t\t\tactions: [],\n\t\t\t\toperations: [],\n\t\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\tqueueHint: [],\n\t\t\t\tmaxRetries: 3,\n\t\t\t\terrorHistory: [],\n\t\t\t\tmeta: {\n\t\t\t\t\t...buildSingleJobMeta(jobId),\n\t\t\t\t\ttriggerTimestampUtcMs: timestamp\n\t\t\t\t}\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Failed to enqueue re-evaluation of @documentId: @error\", documentId, error);\n\t\t\t}\n\t\t}\n\t}\n};\n//#endregion\n//#region src/sync/types.ts\nlet ChannelScheme = /* @__PURE__ */ function(ChannelScheme) {\n\tChannelScheme[\"CONNECT\"] = \"connect\";\n\tChannelScheme[\"SWITCHBOARD\"] = \"switchboard\";\n\treturn ChannelScheme;\n}({});\n/**\n* Controls how a remote drives its polling schedule.\n* - `Auto` (default): the channel runs the configured interval timer in the background.\n* - `Manual`: the channel registers and connects but never ticks on its own.\n* Callers must invoke ISyncManager.triggerPull(name) to fetch.\n*/\nlet PollBehavior = /* @__PURE__ */ function(PollBehavior) {\n\tPollBehavior[\"Auto\"] = \"auto\";\n\tPollBehavior[\"Manual\"] = \"manual\";\n\treturn PollBehavior;\n}({});\nlet SyncOperationStatus = /* @__PURE__ */ function(SyncOperationStatus) {\n\tSyncOperationStatus[SyncOperationStatus[\"Unknown\"] = -1] = \"Unknown\";\n\tSyncOperationStatus[SyncOperationStatus[\"TransportPending\"] = 0] = \"TransportPending\";\n\tSyncOperationStatus[SyncOperationStatus[\"ExecutionPending\"] = 1] = \"ExecutionPending\";\n\tSyncOperationStatus[SyncOperationStatus[\"Applied\"] = 2] = \"Applied\";\n\tSyncOperationStatus[SyncOperationStatus[\"Error\"] = 3] = \"Error\";\n\treturn SyncOperationStatus;\n}({});\nlet ChannelErrorSource = /* @__PURE__ */ function(ChannelErrorSource) {\n\tChannelErrorSource[\"None\"] = \"none\";\n\tChannelErrorSource[\"Channel\"] = \"channel\";\n\tChannelErrorSource[\"Inbox\"] = \"inbox\";\n\tChannelErrorSource[\"Outbox\"] = \"outbox\";\n\treturn ChannelErrorSource;\n}({});\n/**\n* Event types for sync lifecycle events.\n* These events track the sync progress of a job's operations to remotes.\n* Uses a separate namespace (20000 range) from ReactorEventTypes (10000 range).\n*/\nconst SyncEventTypes = {\n\tSYNC_PENDING: 20001,\n\tSYNC_SUCCEEDED: 20002,\n\tSYNC_FAILED: 20003,\n\tDEAD_LETTER_ADDED: 20004,\n\tCONNECTION_STATE_CHANGED: 20005\n};\n//#endregion\n//#region src/sync/mailbox.ts\nvar MailboxAggregateError = class extends Error {\n\terrors;\n\tconstructor(errors) {\n\t\tconst messages = errors.map((e) => e.message).join(\"; \");\n\t\tsuper(`Mailbox callback failed with ${errors.length} error(s): ${messages}`);\n\t\tthis.name = \"MailboxAggregateError\";\n\t\tthis.errors = errors;\n\t}\n};\nvar Mailbox = class {\n\titemsMap = /* @__PURE__ */ new Map();\n\taddedCallbacks = [];\n\tremovedCallbacks = [];\n\tpaused = false;\n\taddedBuffer = [];\n\tremovedBuffer = [];\n\t_ack = 0;\n\t_latestOrdinal = 0;\n\tinit(ackOrdinal) {\n\t\tthis._ack = this._latestOrdinal = ackOrdinal;\n\t}\n\tadvanceOrdinal(ordinal) {\n\t\tthis._latestOrdinal = Math.max(this._latestOrdinal, ordinal);\n\t}\n\tget items() {\n\t\treturn Array.from(this.itemsMap.values());\n\t}\n\tget ackOrdinal() {\n\t\treturn this._ack;\n\t}\n\tget latestOrdinal() {\n\t\treturn this._latestOrdinal;\n\t}\n\tget(id) {\n\t\treturn this.itemsMap.get(id);\n\t}\n\tadd(...items) {\n\t\tfor (const item of items) {\n\t\t\tthis.itemsMap.set(item.id, item);\n\t\t\tfor (const op of item.operations) this._latestOrdinal = Math.max(this._latestOrdinal, op.context.ordinal);\n\t\t\titem.on((syncOp, _, next) => {\n\t\t\t\tif (next === SyncOperationStatus.Applied) for (const op of syncOp.operations) this._ack = Math.max(this._ack, op.context.ordinal);\n\t\t\t});\n\t\t}\n\t\tif (this.paused) {\n\t\t\tthis.addedBuffer.push(...items);\n\t\t\treturn;\n\t\t}\n\t\tconst callbacks = [...this.addedCallbacks];\n\t\tconst errors = [];\n\t\tfor (const callback of callbacks) try {\n\t\t\tcallback(items);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t}\n\tremove(...items) {\n\t\tfor (const item of items) this.itemsMap.delete(item.id);\n\t\tif (this.paused) {\n\t\t\tthis.removedBuffer.push(...items);\n\t\t\treturn;\n\t\t}\n\t\tconst callbacks = [...this.removedCallbacks];\n\t\tconst errors = [];\n\t\tfor (const callback of callbacks) try {\n\t\t\tcallback(items);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t}\n\tonAdded(callback) {\n\t\tthis.addedCallbacks.push(callback);\n\t}\n\tonRemoved(callback) {\n\t\tthis.removedCallbacks.push(callback);\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t}\n\tresume() {\n\t\tthis.paused = false;\n\t\tthis.flush();\n\t}\n\tflush() {\n\t\tif (this.addedBuffer.length > 0) {\n\t\t\tconst items = this.addedBuffer.splice(0);\n\t\t\tconst callbacks = [...this.addedCallbacks];\n\t\t\tconst errors = [];\n\t\t\tfor (const callback of callbacks) try {\n\t\t\t\tcallback(items);\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t\t}\n\t\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t\t}\n\t\tif (this.removedBuffer.length > 0) {\n\t\t\tconst items = this.removedBuffer.splice(0);\n\t\t\tconst callbacks = [...this.removedCallbacks];\n\t\t\tconst errors = [];\n\t\t\tfor (const callback of callbacks) try {\n\t\t\t\tcallback(items);\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t\t}\n\t\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t\t}\n\t}\n\tisPaused() {\n\t\treturn this.paused;\n\t}\n};\n//#endregion\n//#region src/sync/buffered-mailbox.ts\nvar BufferedMailbox = class {\n\titemsMap = /* @__PURE__ */ new Map();\n\taddedCallbacks = [];\n\tremovedCallbacks = [];\n\taddedBuffer = [];\n\tremovedBuffer = [];\n\taddedTimer = null;\n\tremovedTimer = null;\n\tmilliseconds;\n\tmaxQueued;\n\tpaused = false;\n\t_ack = 0;\n\t_latestOrdinal = 0;\n\tconstructor(milliseconds, maxQueued) {\n\t\tthis.milliseconds = milliseconds;\n\t\tthis.maxQueued = maxQueued;\n\t}\n\tinit(ackOrdinal) {\n\t\tthis._ack = this._latestOrdinal = ackOrdinal;\n\t}\n\tadvanceOrdinal(ordinal) {\n\t\tthis._latestOrdinal = Math.max(this._latestOrdinal, ordinal);\n\t}\n\tget items() {\n\t\treturn Array.from(this.itemsMap.values());\n\t}\n\tget ackOrdinal() {\n\t\treturn this._ack;\n\t}\n\tget latestOrdinal() {\n\t\treturn this._latestOrdinal;\n\t}\n\tget(id) {\n\t\treturn this.itemsMap.get(id);\n\t}\n\tadd(...items) {\n\t\tfor (const item of items) {\n\t\t\tthis.itemsMap.set(item.id, item);\n\t\t\tfor (const op of item.operations) this._latestOrdinal = Math.max(this._latestOrdinal, op.context.ordinal);\n\t\t\titem.on((syncOp, _, next) => {\n\t\t\t\tif (next === SyncOperationStatus.Applied) for (const op of syncOp.operations) this._ack = Math.max(this._ack, op.context.ordinal);\n\t\t\t});\n\t\t}\n\t\tthis.addedBuffer.push(...items);\n\t\tif (this.paused) return;\n\t\tif (this.addedBuffer.length >= this.maxQueued) this.flushAdded();\n\t\telse this.scheduleAddedFlush();\n\t}\n\tremove(...items) {\n\t\tfor (const item of items) this.itemsMap.delete(item.id);\n\t\tthis.removedBuffer.push(...items);\n\t\tif (this.paused) return;\n\t\tif (this.removedBuffer.length >= this.maxQueued) this.flushRemoved();\n\t\telse this.scheduleRemovedFlush();\n\t}\n\tonAdded(callback) {\n\t\tthis.addedCallbacks.push(callback);\n\t}\n\tonRemoved(callback) {\n\t\tthis.removedCallbacks.push(callback);\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t\tif (this.addedTimer !== null) {\n\t\t\tclearTimeout(this.addedTimer);\n\t\t\tthis.addedTimer = null;\n\t\t}\n\t\tif (this.removedTimer !== null) {\n\t\t\tclearTimeout(this.removedTimer);\n\t\t\tthis.removedTimer = null;\n\t\t}\n\t}\n\tresume() {\n\t\tthis.paused = false;\n\t\tif (this.addedBuffer.length > 0) this.scheduleAddedFlush();\n\t\tif (this.removedBuffer.length > 0) this.scheduleRemovedFlush();\n\t}\n\tisPaused() {\n\t\treturn this.paused;\n\t}\n\tflush() {\n\t\tthis.flushAdded();\n\t\tthis.flushRemoved();\n\t}\n\tscheduleAddedFlush() {\n\t\tif (this.addedTimer !== null) clearTimeout(this.addedTimer);\n\t\tthis.addedTimer = setTimeout(() => {\n\t\t\tthis.flushAdded();\n\t\t}, this.milliseconds);\n\t}\n\tscheduleRemovedFlush() {\n\t\tif (this.removedTimer !== null) clearTimeout(this.removedTimer);\n\t\tthis.removedTimer = setTimeout(() => {\n\t\t\tthis.flushRemoved();\n\t\t}, this.milliseconds);\n\t}\n\tflushAdded() {\n\t\tif (this.addedTimer !== null) {\n\t\t\tclearTimeout(this.addedTimer);\n\t\t\tthis.addedTimer = null;\n\t\t}\n\t\tconst items = this.addedBuffer;\n\t\tthis.addedBuffer = [];\n\t\tif (items.length > 0) this.invokeCallbacks(this.addedCallbacks, items);\n\t}\n\tflushRemoved() {\n\t\tif (this.removedTimer !== null) {\n\t\t\tclearTimeout(this.removedTimer);\n\t\t\tthis.removedTimer = null;\n\t\t}\n\t\tconst items = this.removedBuffer;\n\t\tthis.removedBuffer = [];\n\t\tif (items.length > 0) this.invokeCallbacks(this.removedCallbacks, items);\n\t}\n\tinvokeCallbacks(callbacks, items) {\n\t\tconst callbacksCopy = [...callbacks];\n\t\tconst errors = [];\n\t\tfor (const callback of callbacksCopy) try {\n\t\t\tcallback(items);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t}\n};\n//#endregion\n//#region src/sync/errors.ts\nvar GraphQLRequestError = class extends Error {\n\tstatusCode;\n\tcategory;\n\t/**\n\t* One entry per error the response carried, in order, holding its\n\t* `extensions.code` - undefined where it declared none. Kept per error rather\n\t* than as a set, because a response that mixes a classified error with an\n\t* unclassified one must not be read as if only the classified one arrived.\n\t*/\n\tcodes;\n\tconstructor(message, category, statusCode, codes = []) {\n\t\tsuper(message);\n\t\tthis.name = \"GraphQLRequestError\";\n\t\tthis.category = category;\n\t\tthis.statusCode = statusCode;\n\t\tthis.codes = codes;\n\t}\n};\n/**\n* Extension codes a remote uses to say a failure is worth polling through.\n*\n* Shared with reactor-api so the server throws what this check reads and the two\n* cannot drift. A `graphql` category error is otherwise permanent: it stops the\n* poll timer, and nothing restarts it, so a code that lands here is the\n* difference between a channel that recovers and one that is dead for the\n* process lifetime.\n*/\nconst RECOVERABLE_GRAPHQL_ERROR_CODES = { malformedStoredOperation: \"MALFORMED_STORED_OPERATION\" };\nconst RECOVERABLE_CODES = new Set(Object.values(RECOVERABLE_GRAPHQL_ERROR_CODES));\n/**\n* True when every error the response carried named a recoverable code.\n*\n* Unanimity is the requirement: one unclassified error alongside a recoverable\n* one means something else also went wrong, and polling through that would be\n* guessing.\n*/\nfunction isRecoverableGraphQLError(error) {\n\treturn error.codes.length > 0 && error.codes.every((code) => code !== void 0 && RECOVERABLE_CODES.has(code));\n}\n/** Auth-rejection message fragments the switchboard emits. Shared with\n* reactor-api so server throws and this client check can't drift. */\nconst DRIVE_AUTH_ERROR_MESSAGES = {\n\tforbidden: \"Forbidden: insufficient permissions\",\n\tauthenticationRequired: \"Forbidden: authentication required\"\n};\n/** True when the remote rejected the caller as unauthenticated/unauthorized:\n* an HTTP 401/403, or a Forbidden/Unauthorized GraphQL error. */\nfunction isDriveAuthError(error) {\n\tif (!(error instanceof GraphQLRequestError)) return false;\n\tif (error.category === \"http\") return error.statusCode === 401 || error.statusCode === 403;\n\tif (error.category === \"graphql\") return Object.values(DRIVE_AUTH_ERROR_MESSAGES).some((m) => error.message.includes(m));\n\treturn false;\n}\nvar PollingChannelError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message);\n\t\tthis.name = \"PollingChannelError\";\n\t}\n};\nvar ChannelError = class extends Error {\n\tsource;\n\terror;\n\t/**\n\t* The classification when something other than the error carries it. Absent\n\t* means derive it from `error.name`; a dead letter mirrored from a peer sets it,\n\t* because only the message crosses the wire.\n\t*/\n\terrorType;\n\tconstructor(source, error, errorType) {\n\t\tsuper(`ChannelError[${source}]: ${error.message}`);\n\t\tthis.name = \"ChannelError\";\n\t\tthis.source = source;\n\t\tthis.error = error;\n\t\tthis.errorType = errorType;\n\t}\n};\n//#endregion\n//#region src/sync/sync-operation.ts\nvar SyncOperationAggregateError = class extends Error {\n\terrors;\n\tconstructor(errors) {\n\t\tconst messages = errors.map((e) => e.message).join(\"; \");\n\t\tsuper(`SyncOperation callback failed with ${errors.length} error(s): ${messages}`);\n\t\tthis.name = \"SyncOperationAggregateError\";\n\t\tthis.errors = errors;\n\t}\n};\nvar SyncOperation = class {\n\tid;\n\tjobId;\n\tjobDependencies;\n\tremoteName;\n\tdocumentId;\n\tscopes;\n\tbranch;\n\toperations;\n\tstatus;\n\terror;\n\tdeliveredCount = 0;\n\temittedCount = 0;\n\tcallbacks = [];\n\tconstructor(id, jobId, jobDependencies, remoteName, documentId, scopes, branch, operations) {\n\t\tthis.id = id;\n\t\tthis.jobId = jobId;\n\t\tthis.jobDependencies = jobDependencies;\n\t\tthis.remoteName = remoteName;\n\t\tthis.documentId = documentId;\n\t\tthis.scopes = scopes;\n\t\tthis.branch = branch;\n\t\tthis.operations = operations;\n\t\tthis.status = SyncOperationStatus.Unknown;\n\t}\n\ton(callback) {\n\t\tthis.callbacks.push(callback);\n\t}\n\tstarted() {\n\t\tthis.transition(SyncOperationStatus.TransportPending);\n\t}\n\ttransported() {\n\t\tthis.transition(SyncOperationStatus.ExecutionPending);\n\t}\n\texecuted() {\n\t\tthis.transition(SyncOperationStatus.Applied);\n\t}\n\tfailed(error) {\n\t\tthis.error = error;\n\t\tthis.transition(SyncOperationStatus.Error);\n\t}\n\ttransition(next) {\n\t\tconst prev = this.status;\n\t\tif (next <= prev) return;\n\t\tthis.status = next;\n\t\tconst errors = [];\n\t\tfor (const callback of this.callbacks) try {\n\t\t\tcallback(this, prev, next);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new SyncOperationAggregateError(errors);\n\t}\n};\n//#endregion\n//#region src/sync/utils.ts\n/**\n* Trims a mailbox using the jobIds from a batch.\n*/\nfunction trimMailboxFromBatch(mailbox, batch) {\n\tconst toRemove = [];\n\tfor (const syncOp of batch.entries) for (const item of mailbox.items) if (syncOp.event.jobId === item.jobId) {\n\t\ttoRemove.push(item);\n\t\tbreak;\n\t}\n\tif (toRemove.length > 0) {\n\t\tfor (const syncOp of toRemove) syncOp.executed();\n\t\tmailbox.remove(...toRemove);\n\t}\n}\n/**\n* Trims a mailbox using the ack ordinal.\n*/\nfunction trimMailboxFromAckOrdinal(mailbox, ackOrdinal) {\n\tconst toRemove = [];\n\tfor (const syncOp of mailbox.items) {\n\t\tlet maxOrdinal = 0;\n\t\tfor (const op of syncOp.operations) maxOrdinal = Math.max(maxOrdinal, op.context.ordinal);\n\t\tif (maxOrdinal <= ackOrdinal) toRemove.push(syncOp);\n\t}\n\tif (toRemove.length > 0) {\n\t\tfor (const syncOp of toRemove) syncOp.executed();\n\t\tmailbox.remove(...toRemove);\n\t}\n}\n/**\n* Filters operations based on a remote's filter criteria.\n*\n* @param operations - The operations to filter\n* @param filter - The filter criteria to apply\n* @returns The filtered operations that match the criteria\n*/\nfunction filterOperations(operations, filter) {\n\treturn operations.filter((op) => {\n\t\tif (filter.branch && op.context.branch !== filter.branch) return false;\n\t\tif (filter.documentId.length > 0 && !filter.documentId.includes(op.context.documentId)) return false;\n\t\tif (filter.scope.length > 0 && !filter.scope.includes(op.context.scope)) return false;\n\t\treturn true;\n\t});\n}\n/**\n* Creates an idle channel health status.\n*\n* @returns A new idle channel health object\n*/\nfunction createIdleHealth() {\n\treturn {\n\t\tstate: \"idle\",\n\t\tfailureCount: 0\n\t};\n}\n/**\n* Batches consecutive operations by documentId and scope, preserving ordering.\n*\n* For operations [a1_doc, a1_global, a2_doc, b1_global], this returns:\n* - Batch 1: [a1_doc] for doc-a, document scope\n* - Batch 2: [a1_global] for doc-a, global scope\n* - Batch 3: [a2_doc] for doc-a, document scope\n* - Batch 4: [b1_global] for doc-b, global scope\n*\n* This ensures operations are grouped for efficient processing while maintaining\n* causality across documents and scopes.\n*/\nfunction batchOperationsByDocument(operations) {\n\tconst batches = [];\n\tlet currentDocId = null;\n\tlet currentScope = null;\n\tlet currentBatch = [];\n\tconst flushBatch = () => {\n\t\tif (currentBatch.length === 0 || currentDocId === null || currentScope === null) return;\n\t\tbatches.push({\n\t\t\tdocumentId: currentDocId,\n\t\t\tbranch: currentBatch[0].context.branch,\n\t\t\tscope: currentScope,\n\t\t\toperations: currentBatch\n\t\t});\n\t\tcurrentBatch = [];\n\t};\n\tfor (const op of operations) {\n\t\tconst docId = op.context.documentId;\n\t\tconst scope = op.context.scope;\n\t\tif (docId !== currentDocId || scope !== currentScope) {\n\t\t\tflushBatch();\n\t\t\tcurrentDocId = docId;\n\t\t\tcurrentScope = scope;\n\t\t}\n\t\tcurrentBatch.push(op);\n\t}\n\tflushBatch();\n\treturn batches;\n}\n/**\n* Splits a sorted page of operations into a safe-to-emit prefix and a\n* deferred tail containing the trailing run that shares the same\n* (documentId, branch, scope, timestampUtcMs) as the last operation.\n*\n* The page is assumed to be sorted by (documentId, scope, ordinal), so a\n* same-(docId, scope, ts) run is contiguous and lives at the end of any\n* page that contains its last member. Holding that tail back lets callers\n* prepend it to the next page so a single producer-side execute() call\n* never gets split across two outbound envelopes.\n*/\nfunction splitTrailingSameTimestampRun(operations) {\n\tif (operations.length === 0) return {\n\t\temit: [],\n\t\tcarry: []\n\t};\n\tconst last = operations[operations.length - 1];\n\tconst lastDocId = last.context.documentId;\n\tconst lastBranch = last.context.branch;\n\tconst lastScope = last.context.scope;\n\tconst lastTs = last.operation.timestampUtcMs;\n\tlet carryStart = operations.length;\n\tfor (let i = operations.length - 1; i >= 0; i--) {\n\t\tconst op = operations[i];\n\t\tif (op.context.documentId === lastDocId && op.context.branch === lastBranch && op.context.scope === lastScope && op.operation.timestampUtcMs === lastTs) carryStart = i;\n\t\telse break;\n\t}\n\treturn {\n\t\temit: operations.slice(0, carryStart),\n\t\tcarry: operations.slice(carryStart)\n\t};\n}\nfunction toOperationWithContext(entry) {\n\treturn {\n\t\toperation: {\n\t\t\tid: entry.id,\n\t\t\tindex: entry.index,\n\t\t\tskip: entry.skip,\n\t\t\thash: entry.hash,\n\t\t\ttimestampUtcMs: entry.timestampUtcMs,\n\t\t\tdeniedReason: entry.deniedReason,\n\t\t\taction: entry.action\n\t\t},\n\t\tcontext: {\n\t\t\tdocumentId: entry.documentId,\n\t\t\tdocumentType: entry.documentType,\n\t\t\tscope: entry.scope,\n\t\t\tbranch: entry.branch,\n\t\t\tordinal: entry.ordinal ?? 0\n\t\t}\n\t};\n}\n/**\n* Merges SyncOperations that share the same (documentId, scope, branch) into\n* a single SyncOperation per group. Within each group, operations are sorted\n* by context.ordinal. The merged SyncOperation keeps the first group member's\n* jobId; all other jobIds are remapped so external dependencies still resolve.\n*\n* Only CONTIGUOUS runs merge. A document whose scopes interleave arrives as an\n* alternating chain (document -> auth -> document -> auth) where each entry\n* depends on the one before it. Merging every occurrence of a\n* (documentId, scope, branch) collapses that chain into two nodes that each\n* depend on the other, which validateBatchStructure rejects as a dependency\n* cycle. Merging only adjacent entries keeps the chain linear.\n*/\nfunction consolidateSyncOperations(syncOps) {\n\tif (syncOps.length <= 1) return syncOps;\n\tconst groups = [];\n\tconst jobIdRemap = /* @__PURE__ */ new Map();\n\tlet prevKey = null;\n\tfor (const syncOp of syncOps) {\n\t\tconst key = `${syncOp.documentId}|${syncOp.scopes.slice().sort().join(\",\")}|${syncOp.branch}`;\n\t\tconst current = key === prevKey ? groups[groups.length - 1] : void 0;\n\t\tif (current) {\n\t\t\tcurrent.ops.push(syncOp);\n\t\t\tif (syncOp.jobId && syncOp.jobId !== current.canonicalJobId) jobIdRemap.set(syncOp.jobId, current.canonicalJobId);\n\t\t} else {\n\t\t\tgroups.push({\n\t\t\t\tops: [syncOp],\n\t\t\t\tcanonicalJobId: syncOp.jobId\n\t\t\t});\n\t\t\tprevKey = key;\n\t\t}\n\t}\n\tconst result = [];\n\tfor (const group of groups) {\n\t\tconst allOperations = group.ops.flatMap((op) => op.operations).sort((a, b) => a.context.ordinal - b.context.ordinal);\n\t\tconst allDeps = /* @__PURE__ */ new Set();\n\t\tfor (const op of group.ops) for (const dep of op.jobDependencies) allDeps.add(dep);\n\t\tallDeps.delete(group.canonicalJobId);\n\t\tfor (const op of group.ops) allDeps.delete(op.jobId);\n\t\tconst remappedDeps = [];\n\t\tfor (const dep of allDeps) {\n\t\t\tconst mapped = jobIdRemap.get(dep) ?? dep;\n\t\t\tif (!remappedDeps.includes(mapped) && mapped !== group.canonicalJobId) remappedDeps.push(mapped);\n\t\t}\n\t\tconst first = group.ops[0];\n\t\tconst merged = new SyncOperation(first.id, first.jobId, remappedDeps, first.remoteName, first.documentId, first.scopes, first.branch, allOperations);\n\t\tif (first.status > SyncOperationStatus.TransportPending) if (first.status >= SyncOperationStatus.Error) merged.executed();\n\t\telse if (first.status >= SyncOperationStatus.Applied) merged.transported();\n\t\telse merged.started();\n\t\tresult.push(merged);\n\t}\n\treturn result;\n}\n/**\n* Chunks sync operations into batches that respect dependency-connected\n* components. SyncOps linked by jobDependencies are kept in the same chunk.\n* If a connected component exceeds maxSize, it is split by topological order.\n*/\nfunction chunkSyncOperations(items, maxSize) {\n\tif (items.length === 0) return [];\n\tif (items.length <= maxSize) return [items];\n\tconst parent = items.map((_, i) => i);\n\tconst rank = new Array(items.length).fill(0);\n\tfunction find(x) {\n\t\twhile (parent[x] !== x) {\n\t\t\tparent[x] = parent[parent[x]];\n\t\t\tx = parent[x];\n\t\t}\n\t\treturn x;\n\t}\n\tfunction union(a, b) {\n\t\tconst ra = find(a);\n\t\tconst rb = find(b);\n\t\tif (ra === rb) return;\n\t\tif (rank[ra] < rank[rb]) parent[ra] = rb;\n\t\telse if (rank[ra] > rank[rb]) parent[rb] = ra;\n\t\telse {\n\t\t\tparent[rb] = ra;\n\t\t\trank[ra]++;\n\t\t}\n\t}\n\tconst jobIdToIndex = /* @__PURE__ */ new Map();\n\tfor (let i = 0; i < items.length; i++) jobIdToIndex.set(items[i].syncOp.jobId, i);\n\tfor (let i = 0; i < items.length; i++) for (const dep of items[i].syncOp.jobDependencies) {\n\t\tconst depIdx = jobIdToIndex.get(dep);\n\t\tif (depIdx !== void 0) union(i, depIdx);\n\t}\n\tconst componentMap = /* @__PURE__ */ new Map();\n\tfor (let i = 0; i < items.length; i++) {\n\t\tconst root = find(i);\n\t\tlet component = componentMap.get(root);\n\t\tif (!component) {\n\t\t\tcomponent = [];\n\t\t\tcomponentMap.set(root, component);\n\t\t}\n\t\tcomponent.push(items[i]);\n\t}\n\tconst components = [...componentMap.values()];\n\tconst chunks = [];\n\tlet currentChunk = [];\n\tfor (const component of components) {\n\t\tif (component.length > maxSize) {\n\t\t\tif (currentChunk.length > 0) {\n\t\t\t\tchunks.push(currentChunk);\n\t\t\t\tcurrentChunk = [];\n\t\t\t}\n\t\t\tfor (const subChunk of splitComponent(component, maxSize)) chunks.push(subChunk);\n\t\t\tcontinue;\n\t\t}\n\t\tif (currentChunk.length + component.length > maxSize) {\n\t\t\tif (currentChunk.length > 0) chunks.push(currentChunk);\n\t\t\tcurrentChunk = [...component];\n\t\t} else currentChunk.push(...component);\n\t}\n\tif (currentChunk.length > 0) chunks.push(currentChunk);\n\treturn chunks;\n}\n/**\n* Splits an oversized connected component into chunks by topological order.\n* Cross-chunk dependency references are handled by the caller's dep filter.\n*/\nfunction splitComponent(items, maxSize) {\n\tconst jobIdToItem = /* @__PURE__ */ new Map();\n\tconst jobIds = /* @__PURE__ */ new Set();\n\tfor (const item of items) {\n\t\tjobIdToItem.set(item.syncOp.jobId, item);\n\t\tjobIds.add(item.syncOp.jobId);\n\t}\n\tconst inDegree = /* @__PURE__ */ new Map();\n\tconst adjacency = /* @__PURE__ */ new Map();\n\tfor (const item of items) {\n\t\tconst key = item.syncOp.jobId;\n\t\tif (!inDegree.has(key)) inDegree.set(key, 0);\n\t\tif (!adjacency.has(key)) adjacency.set(key, []);\n\t\tfor (const dep of item.syncOp.jobDependencies) if (jobIds.has(dep)) {\n\t\t\tinDegree.set(key, (inDegree.get(key) ?? 0) + 1);\n\t\t\tif (!adjacency.has(dep)) adjacency.set(dep, []);\n\t\t\tadjacency.get(dep).push(key);\n\t\t}\n\t}\n\tconst queue = [];\n\tfor (const [key, degree] of inDegree) if (degree === 0) queue.push(key);\n\tconst sorted = [];\n\twhile (queue.length > 0) {\n\t\tconst key = queue.shift();\n\t\tsorted.push(jobIdToItem.get(key));\n\t\tfor (const neighbor of adjacency.get(key) ?? []) {\n\t\t\tconst newDegree = (inDegree.get(neighbor) ?? 1) - 1;\n\t\t\tinDegree.set(neighbor, newDegree);\n\t\t\tif (newDegree === 0) queue.push(neighbor);\n\t\t}\n\t}\n\tif (sorted.length < items.length) {\n\t\tconst sortedIds = new Set(sorted.map((item) => item.syncOp.jobId));\n\t\tfor (const item of items) if (!sortedIds.has(item.syncOp.jobId)) sorted.push(item);\n\t}\n\tconst chunks = [];\n\tfor (let i = 0; i < sorted.length; i += maxSize) chunks.push(sorted.slice(i, i + maxSize));\n\treturn chunks;\n}\n/**\n* Classifies a failure by error name rather than `instanceof`, because a failure\n* that crossed the pooled-worker boundary arrives as plain data.\n*/\nfunction classifyJobFailure(errorName) {\n\tswitch (errorName) {\n\t\tcase \"AuthTimestampNotMonotonicError\": return \"AUTH_TIMESTAMP_NOT_MONOTONIC\";\n\t\tcase \"InvalidOperationTimestampError\": return \"INVALID_TIMESTAMP\";\n\t\tcase \"ExcessiveReshuffleError\": return \"EXCESSIVE_SHUFFLE\";\n\t\tcase \"InvalidSignatureError\": return \"SIGNATURE_INVALID\";\n\t\tcase \"HashMismatchError\": return \"HASH_MISMATCH\";\n\t\tdefault: return \"UNCLASSIFIED\";\n\t}\n}\n/** The explicit type when something else carried it, else derived by name. */\nfunction syncOperationErrorType(error) {\n\treturn error?.errorType ?? classifyJobFailure(error?.error?.name ?? \"Error\");\n}\n/** Dead-letter types that must not stop the document syncing. */\nconst NON_QUARANTINING_ERROR_TYPES = new Set([\"AUTH_TIMESTAMP_NOT_MONOTONIC\"]);\n/**\n* A held auth operation must not quarantine: reconciling the two policies needs\n* the traffic a quarantine would stop.\n*/\nfunction quarantinesDocument(errorType) {\n\treturn !NON_QUARANTINING_ERROR_TYPES.has(errorType);\n}\n//#endregion\n//#region src/sync/channels/interval-poll-timer.ts\nconst DEFAULT_CONFIG = {\n\tintervalMs: 2e3,\n\tmaxQueueDepth: 100,\n\tbackpressureCheckIntervalMs: 500,\n\tretryBaseDelayMs: 1e3,\n\tretryMaxDelayMs: 3e5,\n\tstartPaused: false\n};\nfunction calculateBackoffDelay(consecutiveFailures, retryBaseDelayMs, retryMaxDelayMs, random) {\n\tconst backoff = Math.min(retryMaxDelayMs, retryBaseDelayMs * Math.pow(2, consecutiveFailures - 1));\n\treturn backoff / 2 + random * (backoff / 2);\n}\n/**\n* Default poll timer using setTimeout.\n* Waits for delegate completion before scheduling next tick.\n* Checks queue depth and defers polling when backpressure is detected.\n*/\nvar IntervalPollTimer = class {\n\tdelegate;\n\ttimer;\n\trunning;\n\tpaused;\n\tconsecutiveFailures;\n\tqueue;\n\tconfig;\n\tconstructor(queue, config = {}) {\n\t\tthis.queue = queue;\n\t\tthis.config = {\n\t\t\t...DEFAULT_CONFIG,\n\t\t\t...config\n\t\t};\n\t\tthis.running = false;\n\t\tthis.paused = this.config.startPaused;\n\t\tthis.consecutiveFailures = 0;\n\t}\n\tsetDelegate(delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\tstart() {\n\t\tthis.running = true;\n\t\tthis.consecutiveFailures = 0;\n\t\tif (!this.paused) this.tick();\n\t}\n\tstop() {\n\t\tthis.running = false;\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = void 0;\n\t\t}\n\t}\n\ttick() {\n\t\tif (!this.delegate || !this.running) return;\n\t\tconst delegate = this.delegate;\n\t\tthis.queue.totalSize().then((size) => {\n\t\t\tif (!this.running) return;\n\t\t\tif (size > this.config.maxQueueDepth) this.scheduleBackpressureRecheck();\n\t\t\telse delegate().then(() => {\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t\tthis.scheduleNext();\n\t\t\t}).catch(() => {\n\t\t\t\tthis.consecutiveFailures++;\n\t\t\t\tthis.scheduleRetry();\n\t\t\t});\n\t\t}).catch(() => {\n\t\t\tthis.scheduleNext();\n\t\t});\n\t}\n\tscheduleNext() {\n\t\tif (!this.running || this.paused) return;\n\t\tthis.timer = setTimeout(() => this.tick(), this.config.intervalMs);\n\t}\n\tscheduleRetry() {\n\t\tif (!this.running || this.paused) return;\n\t\tconst delay = calculateBackoffDelay(this.consecutiveFailures, this.config.retryBaseDelayMs, this.config.retryMaxDelayMs, Math.random());\n\t\tthis.timer = setTimeout(() => this.tick(), delay);\n\t}\n\tscheduleBackpressureRecheck() {\n\t\tif (!this.running || this.paused) return;\n\t\tthis.timer = setTimeout(() => this.tick(), this.config.backpressureCheckIntervalMs);\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = void 0;\n\t\t}\n\t}\n\tresume() {\n\t\tthis.paused = false;\n\t\tif (this.running) this.scheduleNext();\n\t}\n\ttriggerNow() {\n\t\tif (this.running && this.delegate) this.tick();\n\t}\n\tisPaused() {\n\t\treturn this.paused;\n\t}\n\tisRunning() {\n\t\treturn this.running;\n\t}\n\tgetIntervalMs() {\n\t\treturn this.config.intervalMs;\n\t}\n\tsetIntervalMs(ms) {\n\t\tthis.config.intervalMs = ms;\n\t}\n};\n//#endregion\n//#region src/sync/channels/utils.ts\nlet syncOpCounter = 0;\n/**\n* Serializes an action for GraphQL transport.\n*\n* Projects onto exactly the fields `ActionInput` declares, which is what keeps a\n* stale runtime-only field - a legacy `attachments` array, say - from riding\n* along into the mutation variables, where the schema would reject the whole\n* request rather than the field.\n*/\nfunction serializeAction(action) {\n\treturn toTransportAction(action);\n}\n/**\n* Serializes a SyncEnvelope for GraphQL transport.\n*\n* Signatures are serialized as comma-separated strings since GraphQL schema\n* defines them as [String!]!. The resultingState context field is stripped\n* since it is not defined in OperationContextInput.\n*/\nfunction serializeEnvelope(envelope) {\n\treturn {\n\t\ttype: envelope.type.toUpperCase(),\n\t\tchannelMeta: envelope.channelMeta,\n\t\toperations: envelope.operations?.map((opWithContext) => ({\n\t\t\toperation: {\n\t\t\t\tindex: opWithContext.operation.index,\n\t\t\t\ttimestampUtcMs: opWithContext.operation.timestampUtcMs,\n\t\t\t\thash: opWithContext.operation.hash,\n\t\t\t\tskip: opWithContext.operation.skip,\n\t\t\t\terror: opWithContext.operation.error,\n\t\t\t\t...opWithContext.operation.deniedReason !== void 0 ? { deniedReason: opWithContext.operation.deniedReason } : {},\n\t\t\t\tid: opWithContext.operation.id,\n\t\t\t\taction: serializeAction(opWithContext.operation.action)\n\t\t\t},\n\t\t\tcontext: {\n\t\t\t\tdocumentId: opWithContext.context.documentId,\n\t\t\t\tdocumentType: opWithContext.context.documentType,\n\t\t\t\tscope: opWithContext.context.scope,\n\t\t\t\tbranch: opWithContext.context.branch,\n\t\t\t\tordinal: opWithContext.context.ordinal\n\t\t\t}\n\t\t})),\n\t\tcursor: envelope.cursor,\n\t\tkey: envelope.key,\n\t\tdependsOn: envelope.dependsOn\n\t};\n}\n/**\n* `isDenied` tests strictly against undefined, so a null left in place would mark\n* every synced operation denied. The key is removed rather than set to undefined,\n* so an operation that arrived without it stays identical to the one sent.\n*/\nfunction normalizeAbsentFields(operation) {\n\tconst wire = operation;\n\tif (wire.error !== null && wire.deniedReason !== null) return operation;\n\tconst normalized = { ...operation };\n\tif (wire.error === null) delete normalized.error;\n\tif (wire.deniedReason === null) delete normalized.deniedReason;\n\treturn normalized;\n}\n/** Restores signature tuples and null-valued optional fields to undefined. */\nfunction deserializeOperation(opWithContext) {\n\tconst operation = normalizeAbsentFields(opWithContext.operation);\n\tconst signer = operation.action.context?.signer;\n\tif (!signer?.signatures || signer.signatures.length === 0) return {\n\t\t...opWithContext,\n\t\toperation\n\t};\n\tconst deserializedSignatures = signer.signatures.map(deserializeSignature);\n\tconst deserializedOperation = {\n\t\t...operation,\n\t\taction: {\n\t\t\t...operation.action,\n\t\t\tcontext: {\n\t\t\t\t...operation.action.context,\n\t\t\t\tsigner: {\n\t\t\t\t\t...signer,\n\t\t\t\t\tsignatures: deserializedSignatures\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\treturn {\n\t\t...opWithContext,\n\t\toperation: deserializedOperation\n\t};\n}\n/**\n* Converts a SyncEnvelope containing operations into multiple SyncOperations.\n*\n* This function batches operations by documentId, preserving cross-document ordering.\n* For operations [a1, a2, a3, b1, b2, a4], it returns:\n* - SyncOperation 1: [a1, a2, a3] for doc-a\n* - SyncOperation 2: [b1, b2] for doc-b\n* - SyncOperation 3: [a4] for doc-a\n*\n* This ensures operations are grouped for efficient processing while maintaining\n* causality across documents.\n*/\nfunction envelopesToSyncOperations(envelope, remoteName) {\n\tif (!envelope.operations || envelope.operations.length === 0) return [];\n\treturn batchOperationsByDocument(envelope.operations.map(deserializeOperation)).map((batch) => {\n\t\treturn new SyncOperation(`syncop-${envelope.channelMeta.id}-${Date.now()}-${syncOpCounter++}`, envelope.key ?? \"\", (envelope.dependsOn ?? []).filter(Boolean), remoteName, batch.documentId, [batch.scope], batch.branch, batch.operations);\n\t});\n}\nconst getLatestAppliedOrdinal = (syncOps) => {\n\tlet maxOrdinal = 0;\n\tfor (const syncOp of syncOps) if (syncOp.status === SyncOperationStatus.Applied) for (const op of syncOp.operations) maxOrdinal = Math.max(maxOrdinal, op.context.ordinal);\n\treturn maxOrdinal;\n};\n//#endregion\n//#region src/sync/channels/gql-req-channel.ts\n/**\n* Fields the auth projection added to the sync schema. A remote that predates\n* them rejects the whole query for naming one, so they are selected only while\n* the remote is known to serve them.\n*/\nconst DECISION_FIELDS = [\"deniedReason\", \"errorType\"];\n/**\n* GraphQL-based synchronization channel for network communication between reactors.\n*/\nvar GqlRequestChannel = class {\n\tinbox;\n\toutbox;\n\tdeadLetter;\n\tconfig;\n\tbufferedOutbox;\n\tchannelId;\n\tremoteName;\n\tcursorStorage;\n\toperationIndex;\n\tpollTimer;\n\tabortController = new AbortController();\n\tisShutdown;\n\tfailureCount;\n\tlastSuccessUtcMs;\n\tlastFailureUtcMs;\n\tlastPersistedInboxOrdinal = 0;\n\tlastPersistedOutboxOrdinal = 0;\n\tpushFailureCount = 0;\n\tpushRetryTimer = null;\n\tpushBlocked = false;\n\tisPushing = false;\n\tpendingDrain = false;\n\treceivingPages = false;\n\t/** Cleared for good the first time the remote rejects {@link DECISION_FIELDS}. */\n\tpeerServesDecisionFields = true;\n\tisRecovering = false;\n\tconnectionState = \"connecting\";\n\t/** Latest unrecoverable error was an auth rejection; cleared on connect. */\n\trequiresAuth = false;\n\tconnectionStateCallbacks = /* @__PURE__ */ new Set();\n\tconstructor(logger, channelId, remoteName, cursorStorage, config, operationIndex, pollTimer) {\n\t\tthis.logger = logger;\n\t\tthis.channelId = channelId;\n\t\tthis.remoteName = remoteName;\n\t\tthis.cursorStorage = cursorStorage;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.pollTimer = pollTimer;\n\t\tthis.config = {\n\t\t\turl: config.url,\n\t\t\tjwtHandler: config.jwtHandler,\n\t\t\tfetchFn: config.fetchFn,\n\t\t\tcollectionId: config.collectionId,\n\t\t\tfilter: config.filter,\n\t\t\tretryBaseDelayMs: config.retryBaseDelayMs,\n\t\t\tretryMaxDelayMs: config.retryMaxDelayMs\n\t\t};\n\t\tthis.isShutdown = false;\n\t\tthis.failureCount = 0;\n\t\tthis.inbox = new Mailbox();\n\t\tthis.bufferedOutbox = new BufferedMailbox(500, 25);\n\t\tthis.outbox = this.bufferedOutbox;\n\t\tthis.deadLetter = new Mailbox();\n\t\tthis.deadLetter.onAdded((syncOps) => {\n\t\t\tfor (const syncOp of syncOps) this.logger.warn(\"Dead letter added for document @DocumentId on channel @ChannelId\", syncOp.documentId, this.channelId);\n\t\t});\n\t\tthis.outbox.onAdded((syncOps) => {\n\t\t\tif (this.isShutdown) return;\n\t\t\tif (this.isPushing) {\n\t\t\t\tthis.pendingDrain = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.pushBlocked) return;\n\t\t\tif (this.receivingPages) {\n\t\t\t\tthis.pendingDrain = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.attemptPush(syncOps);\n\t\t});\n\t\tthis.outbox.onRemoved((syncOps) => {\n\t\t\tconst maxOrdinal = getLatestAppliedOrdinal(syncOps);\n\t\t\tif (maxOrdinal > this.lastPersistedOutboxOrdinal) {\n\t\t\t\tthis.lastPersistedOutboxOrdinal = maxOrdinal;\n\t\t\t\tthis.cursorStorage.upsert({\n\t\t\t\t\tremoteName: this.remoteName,\n\t\t\t\t\tcursorType: \"outbox\",\n\t\t\t\t\tcursorOrdinal: maxOrdinal,\n\t\t\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\tthis.logger.error(\"Failed to update outbox cursor for @ChannelId! This means that future application runs may resend duplicate operations. This is recoverable (with deduplication protection), but not-optimal: @Error\", this.channelId, error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tthis.inbox.onRemoved((syncOps) => {\n\t\t\tconst maxOrdinal = getLatestAppliedOrdinal(syncOps);\n\t\t\tif (maxOrdinal > this.lastPersistedInboxOrdinal) {\n\t\t\t\tthis.lastPersistedInboxOrdinal = maxOrdinal;\n\t\t\t\tthis.cursorStorage.upsert({\n\t\t\t\t\tremoteName: this.remoteName,\n\t\t\t\t\tcursorType: \"inbox\",\n\t\t\t\t\tcursorOrdinal: maxOrdinal,\n\t\t\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\tthis.logger.error(\"Failed to update inbox cursor for @ChannelId! This is unlikely to cause a problem, but not-optimal: @Error\", this.channelId, error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Shuts down the channel and prevents further operations.\n\t*/\n\tshutdown() {\n\t\tthis.abortController.abort();\n\t\tthis.bufferedOutbox.flush();\n\t\tthis.isShutdown = true;\n\t\tthis.pollTimer.stop();\n\t\tif (this.pushRetryTimer) {\n\t\t\tclearTimeout(this.pushRetryTimer);\n\t\t\tthis.pushRetryTimer = null;\n\t\t}\n\t\tthis.transitionConnectionState(\"disconnected\");\n\t\treturn Promise.resolve();\n\t}\n\tgetConnectionState() {\n\t\treturn {\n\t\t\tstate: this.connectionState,\n\t\t\tfailureCount: this.failureCount,\n\t\t\tlastSuccessUtcMs: this.lastSuccessUtcMs ?? 0,\n\t\t\tlastFailureUtcMs: this.lastFailureUtcMs ?? 0,\n\t\t\tpushBlocked: this.pushBlocked,\n\t\t\tpushFailureCount: this.pushFailureCount,\n\t\t\treceivingPages: this.receivingPages,\n\t\t\trequiresAuth: this.requiresAuth\n\t\t};\n\t}\n\tonConnectionStateChange(callback) {\n\t\tthis.connectionStateCallbacks.add(callback);\n\t\treturn () => {\n\t\t\tthis.connectionStateCallbacks.delete(callback);\n\t\t};\n\t}\n\ttriggerPull() {\n\t\tif (this.isShutdown) return;\n\t\tthis.pollTimer.triggerNow();\n\t}\n\t/**\n\t* Initializes the channel by registering it on the remote server and starting polling.\n\t*/\n\tasync init() {\n\t\tconst { ackOrdinal } = await this.touchRemoteChannel();\n\t\tconst cursors = await this.cursorStorage.list(this.remoteName);\n\t\tconst inboxOrdinal = cursors.find((c) => c.cursorType === \"inbox\")?.cursorOrdinal ?? 0;\n\t\tconst outboxOrdinal = cursors.find((c) => c.cursorType === \"outbox\")?.cursorOrdinal ?? 0;\n\t\tthis.inbox.init(inboxOrdinal);\n\t\tthis.outbox.init(outboxOrdinal);\n\t\tthis.lastPersistedInboxOrdinal = inboxOrdinal;\n\t\tthis.lastPersistedOutboxOrdinal = outboxOrdinal;\n\t\tif (ackOrdinal > 0) trimMailboxFromAckOrdinal(this.outbox, ackOrdinal);\n\t\tthis.pollTimer.setDelegate(() => this.poll());\n\t\tthis.pollTimer.start();\n\t\tthis.transitionConnectionState(\"connected\");\n\t}\n\ttransitionConnectionState(next) {\n\t\tif (next === \"connected\") this.requiresAuth = false;\n\t\tif (this.connectionState === next) return;\n\t\tthis.connectionState = next;\n\t\tconst snapshot = this.getConnectionState();\n\t\tfor (const callback of this.connectionStateCallbacks) try {\n\t\t\tcallback(snapshot);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Connection state change callback error: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Polls the remote for new sync envelopes.\n\t*/\n\tasync poll() {\n\t\tif (this.isShutdown) return;\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await this.pollSyncEnvelopes(this.inbox.ackOrdinal, this.inbox.latestOrdinal);\n\t\t} catch (error) {\n\t\t\tif (!this.handlePollError(error)) throw error;\n\t\t\treturn;\n\t\t}\n\t\tconst { envelopes, ackOrdinal, deadLetters, hasMore } = response;\n\t\tif (ackOrdinal > 0) trimMailboxFromAckOrdinal(this.outbox, ackOrdinal);\n\t\tconst allSyncOps = [];\n\t\tfor (const envelope of envelopes) if (envelope.type.toLowerCase() === \"operations\" && envelope.operations) {\n\t\t\tconst syncOps = envelopesToSyncOperations(envelope, this.remoteName);\n\t\t\tfor (const syncOp of syncOps) syncOp.transported();\n\t\t\tallSyncOps.push(...syncOps);\n\t\t}\n\t\tconst consolidated = allSyncOps.length > 1 ? consolidateSyncOperations(allSyncOps) : allSyncOps;\n\t\tif (consolidated.length > 0) this.inbox.add(...consolidated);\n\t\tif (deadLetters.length > 0) this.handleRemoteDeadLetters(deadLetters);\n\t\tif (hasMore) this.receivingPages = true;\n\t\telse if (this.receivingPages) {\n\t\t\tthis.receivingPages = false;\n\t\t\tthis.drainOutbox();\n\t\t}\n\t\tthis.lastSuccessUtcMs = Date.now();\n\t\tthis.failureCount = 0;\n\t\tthis.transitionConnectionState(\"connected\");\n\t}\n\t/**\n\t* Handles dead letters reported by the remote server.\n\t* Creates local dead letter SyncOperations so the channel quiesces.\n\t*/\n\thandleRemoteDeadLetters(deadLetters) {\n\t\tfor (const dl of deadLetters) this.logger.error(\"Remote dead letter on @ChannelId: document @DocumentId failed with: @Error\", this.channelId, dl.documentId, dl.error);\n\t\tconst syncOps = [];\n\t\tfor (const dl of deadLetters) {\n\t\t\tconst syncOp = new SyncOperation(crypto.randomUUID(), dl.jobId, [], this.remoteName, dl.documentId, dl.scopes, dl.branch, []);\n\t\t\tsyncOp.failed(new ChannelError(ChannelErrorSource.Outbox, new Error(dl.error), dl.errorType ?? void 0));\n\t\t\tsyncOps.push(syncOp);\n\t\t}\n\t\tthis.deadLetter.add(...syncOps);\n\t}\n\t/**\n\t* Handles polling errors with error classification.\n\t* Returns true if the error was handled (caller should not rethrow).\n\t*/\n\thandlePollError(error) {\n\t\tif (this.isShutdown) return true;\n\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\tif (err.message.includes(\"Channel not found\")) {\n\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\tthis.recoverFromChannelNotFound();\n\t\t\treturn true;\n\t\t}\n\t\tconst classification = this.classifyError(err);\n\t\tthis.failureCount++;\n\t\tthis.lastFailureUtcMs = Date.now();\n\t\tconst channelError = new ChannelError(ChannelErrorSource.Inbox, err);\n\t\tthis.logger.error(\"GqlChannel poll error (@FailureCount, @Classification): @Error\", this.failureCount, classification, channelError);\n\t\tif (classification === \"unrecoverable\") {\n\t\t\tthis.pollTimer.stop();\n\t\t\tthis.requiresAuth = isDriveAuthError(err);\n\t\t\tthis.transitionConnectionState(\"error\");\n\t\t\treturn true;\n\t\t}\n\t\tthis.transitionConnectionState(\"error\");\n\t\treturn false;\n\t}\n\t/**\n\t* Recovers from a \"Channel not found\" error by re-registering and restarting polling.\n\t* Self-retries with backoff instead of restarting the poll timer on failure.\n\t*/\n\trecoverFromChannelNotFound() {\n\t\tif (this.isRecovering) return;\n\t\tthis.isRecovering = true;\n\t\tthis.logger.info(\"GqlChannel @ChannelId not found on remote, re-registering...\", this.channelId);\n\t\tthis.pollTimer.stop();\n\t\tconst attemptRecovery = (attempt) => {\n\t\t\tif (this.isShutdown) {\n\t\t\t\tthis.isRecovering = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.touchRemoteChannel().then(({ ackOrdinal }) => {\n\t\t\t\tthis.logger.info(\"GqlChannel @ChannelId re-registered successfully\", this.channelId);\n\t\t\t\tthis.isRecovering = false;\n\t\t\t\tthis.failureCount = 0;\n\t\t\t\tif (ackOrdinal > 0) trimMailboxFromAckOrdinal(this.outbox, ackOrdinal);\n\t\t\t\tthis.pollTimer.start();\n\t\t\t\tthis.transitionConnectionState(\"connected\");\n\t\t\t\tthis.resumePushAfterRecovery();\n\t\t\t}).catch((recoveryError) => {\n\t\t\t\tconst err = recoveryError instanceof Error ? recoveryError : new Error(String(recoveryError));\n\t\t\t\tconst classification = this.classifyError(err);\n\t\t\t\tthis.logger.error(\"GqlChannel @ChannelId recovery attempt @Attempt failed (@Classification): @Error\", this.channelId, attempt, classification, recoveryError);\n\t\t\t\tthis.failureCount++;\n\t\t\t\tthis.lastFailureUtcMs = Date.now();\n\t\t\t\tif (classification === \"unrecoverable\") {\n\t\t\t\t\tthis.isRecovering = false;\n\t\t\t\t\tthis.requiresAuth = isDriveAuthError(err);\n\t\t\t\t\tthis.transitionConnectionState(\"error\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\t\tconst delay = calculateBackoffDelay(attempt, this.config.retryBaseDelayMs, this.config.retryMaxDelayMs, Math.random());\n\t\t\t\tsetTimeout(() => attemptRecovery(attempt + 1), delay);\n\t\t\t});\n\t\t};\n\t\tattemptRecovery(1);\n\t}\n\t/**\n\t* Resumes pushing outbox items that were blocked while the channel was being\n\t* recreated. Called after a successful re-registration.\n\t*/\n\tresumePushAfterRecovery() {\n\t\tif (this.isShutdown) return;\n\t\tif (!this.pushBlocked) return;\n\t\tif (this.pushRetryTimer) {\n\t\t\tclearTimeout(this.pushRetryTimer);\n\t\t\tthis.pushRetryTimer = null;\n\t\t}\n\t\tthis.pushBlocked = false;\n\t\tthis.pushFailureCount = 0;\n\t\tconst items = this.outbox.items;\n\t\tif (items.length > 0) this.attemptPush([...items]);\n\t}\n\t/**\n\t* Queries the remote GraphQL endpoint for sync envelopes.\n\t*/\n\tasync pollSyncEnvelopes(ackOrdinal, latestOrdinal) {\n\t\tconst variables = {\n\t\t\tchannelId: this.channelId,\n\t\t\toutboxAck: ackOrdinal,\n\t\t\toutboxLatest: latestOrdinal\n\t\t};\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await this.executeGraphQL(this.pollQuery(this.peerServesDecisionFields), variables);\n\t\t} catch (error) {\n\t\t\tif (!this.rejectsDecisionFields(error)) throw error;\n\t\t\tthis.logger.warn(\"Remote @channelId does not serve deniedReason/errorType; polling without them. The remote is on an older schema, so it has neither to report.\", this.channelId);\n\t\t\tthis.peerServesDecisionFields = false;\n\t\t\tresponse = await this.executeGraphQL(this.pollQuery(false), variables);\n\t\t}\n\t\treturn {\n\t\t\tenvelopes: response.pollSyncEnvelopes.envelopes,\n\t\t\tackOrdinal: response.pollSyncEnvelopes.ackOrdinal,\n\t\t\tdeadLetters: response.pollSyncEnvelopes.deadLetters ?? [],\n\t\t\thasMore: response.pollSyncEnvelopes.hasMore\n\t\t};\n\t}\n\t/**\n\t* True when the remote rejected the query for naming a field it does not\n\t* have. Selecting an unknown field fails validation for the whole query, so\n\t* an unhandled one takes the channel's polling down until the process\n\t* restarts rather than degrading.\n\t*/\n\trejectsDecisionFields(error) {\n\t\tif (!this.peerServesDecisionFields) return false;\n\t\tif (!(error instanceof GraphQLRequestError) || error.category !== \"graphql\") return false;\n\t\treturn DECISION_FIELDS.some((field) => error.message.includes(field));\n\t}\n\t/**\n\t* The poll query. `withDecisionFields` selects the two fields added with the\n\t* auth projection; a remote on the previous schema is polled without them.\n\t*/\n\tpollQuery(withDecisionFields) {\n\t\treturn `\n query PollSyncEnvelopes($channelId: String!, $outboxAck: Int!, $outboxLatest: Int!) {\n pollSyncEnvelopes(channelId: $channelId, outboxAck: $outboxAck, outboxLatest: $outboxLatest) {\n envelopes {\n type\n channelMeta {\n id\n }\n operations {\n operation {\n index\n timestampUtcMs\n hash\n skip\n error\n ${withDecisionFields ? \"deniedReason\" : \"\"}\n id\n action {\n id\n type\n timestampUtcMs\n input\n scope\n context {\n signer {\n user {\n address\n networkId\n chainId\n }\n app {\n name\n key\n }\n signatures\n }\n }\n }\n }\n context {\n documentId\n documentType\n scope\n branch\n ordinal\n }\n }\n cursor {\n remoteName\n cursorOrdinal\n lastSyncedAtUtcMs\n }\n key\n dependsOn\n }\n ackOrdinal\n deadLetters {\n documentId\n error\n ${withDecisionFields ? \"errorType\" : \"\"}\n jobId\n branch\n scopes\n operationCount\n }\n hasMore\n }\n }\n `;\n\t}\n\t/**\n\t* Registers or updates this channel on the remote server via GraphQL mutation.\n\t* Returns the remote's ack ordinal so the client can trim its outbox.\n\t*/\n\tasync touchRemoteChannel() {\n\t\tlet sinceTimestampUtcMs = \"0\";\n\t\ttry {\n\t\t\tconst result = await this.operationIndex.getLatestTimestampForCollection(this.config.collectionId.key);\n\t\t\tif (result) sinceTimestampUtcMs = result;\n\t\t} catch {}\n\t\tconst mutation = `\n mutation TouchChannel($input: TouchChannelInput!) {\n touchChannel(input: $input) {\n success\n ackOrdinal\n }\n }\n `;\n\t\tconst variables = { input: {\n\t\t\tid: this.channelId,\n\t\t\tname: this.channelId,\n\t\t\tcollectionId: this.config.collectionId.key,\n\t\t\tfilter: {\n\t\t\t\tdocumentId: this.config.filter.documentId,\n\t\t\t\tscope: this.config.filter.scope,\n\t\t\t\tbranch: this.config.filter.branch\n\t\t\t},\n\t\t\tsinceTimestampUtcMs\n\t\t} };\n\t\tconst data = await this.executeGraphQL(mutation, variables);\n\t\tif (!data.touchChannel.success) throw new GraphQLRequestError(\"touchChannel returned success=false\", \"graphql\");\n\t\treturn { ackOrdinal: data.touchChannel.ackOrdinal };\n\t}\n\t/**\n\t* Fire-and-forget push with retry on recoverable errors.\n\t* On success, clears push blocked state. On recoverable error, blocks\n\t* further pushes and schedules a retry. On unrecoverable error, moves\n\t* ops to deadLetter.\n\t*/\n\tattemptPush(syncOps) {\n\t\tthis.isPushing = true;\n\t\tthis.pushSyncOperations(syncOps).then(() => {\n\t\t\tthis.isPushing = false;\n\t\t\tthis.pushBlocked = false;\n\t\t\tthis.pushFailureCount = 0;\n\t\t\tif (this.connectionState === \"reconnecting\" || this.connectionState === \"error\") this.transitionConnectionState(\"connected\");\n\t\t\tthis.drainOutbox();\n\t\t}).catch((error) => {\n\t\t\tthis.isPushing = false;\n\t\t\tthis.pendingDrain = false;\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\tif (err.message.includes(\"Channel not found\")) {\n\t\t\t\tthis.pushBlocked = true;\n\t\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\t\tthis.recoverFromChannelNotFound();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.classifyError(err) === \"recoverable\") {\n\t\t\t\tthis.pushFailureCount++;\n\t\t\t\tthis.pushBlocked = true;\n\t\t\t\tthis.logger.error(\"GqlChannel push failed (attempt @FailureCount), will retry: @Error\", this.pushFailureCount, err);\n\t\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\t\tthis.schedulePushRetry();\n\t\t\t} else {\n\t\t\t\tconst channelError = new ChannelError(ChannelErrorSource.Outbox, err);\n\t\t\t\tfor (const syncOp of syncOps) syncOp.failed(channelError);\n\t\t\t\tthis.deadLetter.add(...syncOps);\n\t\t\t\tthis.outbox.remove(...syncOps);\n\t\t\t\tthis.requiresAuth = isDriveAuthError(err);\n\t\t\t\tthis.transitionConnectionState(\"error\");\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Schedules a retry of all current outbox items using exponential backoff.\n\t*/\n\tschedulePushRetry() {\n\t\tif (this.pushRetryTimer) return;\n\t\tconst delay = calculateBackoffDelay(this.pushFailureCount, this.config.retryBaseDelayMs, this.config.retryMaxDelayMs, Math.random());\n\t\tthis.pushRetryTimer = setTimeout(() => {\n\t\t\tthis.pushRetryTimer = null;\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst allItems = this.outbox.items;\n\t\t\tif (allItems.length === 0) {\n\t\t\t\tthis.pushBlocked = false;\n\t\t\t\tthis.pushFailureCount = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.attemptPush([...allItems]);\n\t\t}, delay);\n\t}\n\t/**\n\t* Drains pending outbox items that arrived while a push was in-flight.\n\t* Server-side action.id dedup handles any overlap with the previous push.\n\t*/\n\tdrainOutbox() {\n\t\tif (!this.pendingDrain) return;\n\t\tthis.pendingDrain = false;\n\t\tif (this.isShutdown) return;\n\t\tconst items = this.outbox.items;\n\t\tif (items.length === 0) return;\n\t\tthis.attemptPush([...items]);\n\t}\n\t/**\n\t* Classifies an error as recoverable or unrecoverable based on its type.\n\t* Recoverable errors are transient and worth retrying (network, 5xx, parse).\n\t* Unrecoverable errors will not self-heal (auth, client errors, GraphQL rejections).\n\t*/\n\tclassifyError(error) {\n\t\tif (!(error instanceof GraphQLRequestError)) return \"recoverable\";\n\t\tswitch (error.category) {\n\t\t\tcase \"network\": return \"recoverable\";\n\t\t\tcase \"http\":\n\t\t\t\tif (error.statusCode !== void 0 && error.statusCode >= 500) return \"recoverable\";\n\t\t\t\treturn \"unrecoverable\";\n\t\t\tcase \"parse\": return \"recoverable\";\n\t\t\tcase \"graphql\": return isRecoverableGraphQLError(error) ? \"recoverable\" : \"unrecoverable\";\n\t\t\tcase \"missing-data\": return \"unrecoverable\";\n\t\t}\n\t}\n\t/**\n\t* Pushes multiple sync operations to the remote via a single GraphQL mutation.\n\t* Creates one SyncEnvelope per SyncOperation with key/dependsOn for batch ordering.\n\t*/\n\tasync pushSyncOperations(syncOps) {\n\t\tfor (const syncOp of syncOps) syncOp.started();\n\t\tconst jobIdToKeys = /* @__PURE__ */ new Map();\n\t\tconst envelopes = [];\n\t\tfor (let i = 0; i < syncOps.length; i++) {\n\t\t\tconst syncOp = syncOps[i];\n\t\t\tconst key = String(i);\n\t\t\tif (syncOp.jobId) {\n\t\t\t\tif (!jobIdToKeys.has(syncOp.jobId)) jobIdToKeys.set(syncOp.jobId, []);\n\t\t\t\tjobIdToKeys.get(syncOp.jobId).push(key);\n\t\t\t}\n\t\t\tconst dependsOn = [];\n\t\t\tfor (const dep of syncOp.jobDependencies) {\n\t\t\t\tconst depKeys = jobIdToKeys.get(dep);\n\t\t\t\tif (depKeys) dependsOn.push(...depKeys);\n\t\t\t}\n\t\t\tthis.logger.debug(\"[PUSH]: @Operations\", syncOp.operations.map((op) => `(${op.context.documentId}, ${op.context.branch}, ${op.context.scope}, ${op.operation.index})`));\n\t\t\tenvelopes.push({\n\t\t\t\ttype: \"operations\",\n\t\t\t\tchannelMeta: { id: this.channelId },\n\t\t\t\toperations: syncOp.operations,\n\t\t\t\tkey,\n\t\t\t\tdependsOn\n\t\t\t});\n\t\t}\n\t\tconst mutation = `\n mutation PushSyncEnvelopes($envelopes: [SyncEnvelopeInput!]!) {\n pushSyncEnvelopes(envelopes: $envelopes)\n }\n `;\n\t\tconst variables = { envelopes: envelopes.map((e) => serializeEnvelope(e)) };\n\t\tawait this.executeGraphQL(mutation, variables);\n\t}\n\t/**\n\t* Gets the authorization header value using jwtHandler.\n\t*/\n\tasync getAuthorizationHeader() {\n\t\tif (!this.config.jwtHandler) return;\n\t\ttry {\n\t\t\tconst token = await this.config.jwtHandler(this.config.url);\n\t\t\tif (token) return `Bearer ${token}`;\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"JWT handler failed: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Executes a GraphQL query or mutation against the remote endpoint.\n\t*/\n\tasync executeGraphQL(query, variables) {\n\t\tconst headers = { \"Content-Type\": \"application/json\" };\n\t\tconst authHeader = await this.getAuthorizationHeader();\n\t\tif (authHeader) headers[\"Authorization\"] = authHeader;\n\t\tconst operationName = query.match(/(?:query|mutation)\\s+(\\w+)/)?.[1] ?? \"unknown\";\n\t\tthis.logger.verbose(\"GQL request @channelId @operation @url vars=@variables\", this.channelId, operationName, this.config.url, JSON.stringify(variables));\n\t\tconst fetchFn = this.config.fetchFn ?? fetch;\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await fetchFn(this.config.url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tquery,\n\t\t\t\t\tvariables\n\t\t\t\t}),\n\t\t\t\tsignal: this.abortController.signal\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow new GraphQLRequestError(`GraphQL request failed: ${error instanceof Error ? error.message : String(error)}`, \"network\");\n\t\t}\n\t\tif (!response.ok) throw new GraphQLRequestError(`GraphQL request failed: ${response.status} ${response.statusText}`, \"http\", response.status);\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await response.json();\n\t\t} catch (error) {\n\t\t\tthrow new GraphQLRequestError(`Failed to parse GraphQL response: ${error instanceof Error ? error.message : String(error)}`, \"parse\");\n\t\t}\n\t\tthis.logger.verbose(\"GQL response @channelId @operation status=@status data=@data errors=@errors\", this.channelId, operationName, response.status, JSON.stringify(result.data), result.errors ? JSON.stringify(result.errors) : \"none\");\n\t\tif (result.errors) throw new GraphQLRequestError(`GraphQL errors: ${JSON.stringify(result.errors, null, 2)}`, \"graphql\", void 0, result.errors.map((error) => error.extensions?.code));\n\t\tif (!result.data) throw new GraphQLRequestError(\"GraphQL response missing data field\", \"missing-data\");\n\t\treturn result.data;\n\t}\n\tget poller() {\n\t\treturn this.pollTimer;\n\t}\n};\n//#endregion\n//#region src/sync/channels/gql-request-channel-factory.ts\n/**\n* Factory for creating GqlRequestChannel instances.\n*\n* Extracts GraphQL-specific configuration from ChannelConfig.parameters and\n* instantiates GqlRequestChannel instances for network-based synchronization.\n*\n* The optional jwtHandler enables dynamic JWT token generation per-request,\n* which is useful for short-lived tokens with audience-specific claims.\n*/\nvar GqlRequestChannelFactory = class {\n\tlogger;\n\tjwtHandler;\n\tqueue;\n\tconstructor(logger, jwtHandler, queue) {\n\t\tthis.logger = logger;\n\t\tthis.jwtHandler = jwtHandler;\n\t\tthis.queue = queue;\n\t}\n\t/**\n\t* Creates a new GqlRequestChannel instance with the given configuration.\n\t* See GqlChannelConfig for the expected parameters.\n\t*\n\t* @param config - Channel configuration including type and parameters\n\t* @param cursorStorage - Storage for persisting synchronization cursors\n\t* @param operationIndex - Operation index for querying timestamps\n\t* @returns A new GqlRequestChannel instance\n\t*/\n\tinstance(remoteId, remoteName, config, cursorStorage, collectionId, filter, operationIndex, options) {\n\t\tconst url = config.parameters.url;\n\t\tif (typeof url !== \"string\" || !url) throw new Error(\"GqlRequestChannelFactory requires \\\"url\\\" parameter in config.parameters\");\n\t\tconst gqlConfig = {\n\t\t\turl,\n\t\t\tcollectionId,\n\t\t\tfilter,\n\t\t\tjwtHandler: this.jwtHandler,\n\t\t\tretryBaseDelayMs: 1e3,\n\t\t\tretryMaxDelayMs: 3e5\n\t\t};\n\t\tlet pollIntervalMs = 2e3;\n\t\tif (config.parameters.pollIntervalMs !== void 0) {\n\t\t\tif (typeof config.parameters.pollIntervalMs !== \"number\") throw new Error(\"\\\"pollIntervalMs\\\" parameter must be a number\");\n\t\t\tpollIntervalMs = config.parameters.pollIntervalMs;\n\t\t}\n\t\tlet retryBaseDelayMs;\n\t\tif (config.parameters.retryBaseDelayMs !== void 0) {\n\t\t\tif (typeof config.parameters.retryBaseDelayMs !== \"number\") throw new Error(\"\\\"retryBaseDelayMs\\\" parameter must be a number\");\n\t\t\tretryBaseDelayMs = config.parameters.retryBaseDelayMs;\n\t\t}\n\t\tlet retryMaxDelayMs;\n\t\tif (config.parameters.retryMaxDelayMs !== void 0) {\n\t\t\tif (typeof config.parameters.retryMaxDelayMs !== \"number\") throw new Error(\"\\\"retryMaxDelayMs\\\" parameter must be a number\");\n\t\t\tretryMaxDelayMs = config.parameters.retryMaxDelayMs;\n\t\t}\n\t\tif (config.parameters.fetchFn !== void 0) {\n\t\t\tif (typeof config.parameters.fetchFn !== \"function\") throw new Error(\"\\\"fetchFn\\\" parameter must be a function\");\n\t\t\tgqlConfig.fetchFn = config.parameters.fetchFn;\n\t\t}\n\t\tif (retryBaseDelayMs !== void 0) gqlConfig.retryBaseDelayMs = retryBaseDelayMs;\n\t\tif (retryMaxDelayMs !== void 0) gqlConfig.retryMaxDelayMs = retryMaxDelayMs;\n\t\tlet maxQueueDepth;\n\t\tif (config.parameters.maxQueueDepth !== void 0) {\n\t\t\tif (typeof config.parameters.maxQueueDepth !== \"number\") throw new Error(\"\\\"maxQueueDepth\\\" parameter must be a number\");\n\t\t\tmaxQueueDepth = config.parameters.maxQueueDepth;\n\t\t}\n\t\tlet backpressureCheckIntervalMs;\n\t\tif (config.parameters.backpressureCheckIntervalMs !== void 0) {\n\t\t\tif (typeof config.parameters.backpressureCheckIntervalMs !== \"number\") throw new Error(\"\\\"backpressureCheckIntervalMs\\\" parameter must be a number\");\n\t\t\tbackpressureCheckIntervalMs = config.parameters.backpressureCheckIntervalMs;\n\t\t}\n\t\tconst pollTimer = new IntervalPollTimer(this.queue, {\n\t\t\tintervalMs: pollIntervalMs,\n\t\t\t...retryBaseDelayMs !== void 0 && { retryBaseDelayMs },\n\t\t\t...retryMaxDelayMs !== void 0 && { retryMaxDelayMs },\n\t\t\t...maxQueueDepth !== void 0 && { maxQueueDepth },\n\t\t\t...backpressureCheckIntervalMs !== void 0 && { backpressureCheckIntervalMs },\n\t\t\tstartPaused: options?.pollBehavior === PollBehavior.Manual\n\t\t});\n\t\treturn new GqlRequestChannel(this.logger, remoteId, remoteName, cursorStorage, gqlConfig, operationIndex, pollTimer);\n\t}\n};\n//#endregion\n//#region src/sync/channels/gql-res-channel.ts\n/** Where a sync operation's run of ordinals begins. */\nfunction firstOrdinalOf$1(syncOp) {\n\treturn syncOp.operations.length > 0 ? syncOp.operations[0].context.ordinal : 0;\n}\n/**\n* This class is used server-side to accumulate inbox + outbox operations.\n*\n* In general, the resolvers are responsible for updating mailboxes.\n*/\nvar GqlResponseChannel = class {\n\tinbox;\n\toutbox;\n\tdeadLetter;\n\tchannelId;\n\tremoteName;\n\tcursorStorage;\n\tisShutdown;\n\tlastPersistedInboxOrdinal = 0;\n\tlastPersistedOutboxOrdinal = 0;\n\tevictedOutboxFloor = Number.POSITIVE_INFINITY;\n\tappliedOutboxOrdinal = 0;\n\tconnectionState = \"connecting\";\n\tconnectionStateCallbacks = /* @__PURE__ */ new Set();\n\tconstructor(logger, channelId, remoteName, cursorStorage) {\n\t\tthis.logger = logger;\n\t\tthis.channelId = channelId;\n\t\tthis.remoteName = remoteName;\n\t\tthis.cursorStorage = cursorStorage;\n\t\tthis.isShutdown = false;\n\t\tthis.inbox = new Mailbox();\n\t\tthis.outbox = new Mailbox();\n\t\tthis.deadLetter = new Mailbox();\n\t\tthis.outbox.onRemoved((syncOps) => {\n\t\t\tthis.rememberUnserved(syncOps);\n\t\t\tthis.persistOutboxCursor(getLatestAppliedOrdinal(syncOps));\n\t\t});\n\t\tthis.outbox.onAdded((syncOps) => {\n\t\t\tthis.forgetEvictedBelow(syncOps);\n\t\t});\n\t\tthis.inbox.onRemoved((syncOps) => {\n\t\t\tconst maxOrdinal = getLatestAppliedOrdinal(syncOps);\n\t\t\tif (maxOrdinal > this.lastPersistedInboxOrdinal) {\n\t\t\t\tthis.lastPersistedInboxOrdinal = maxOrdinal;\n\t\t\t\tthis.cursorStorage.upsert({\n\t\t\t\t\tremoteName: this.remoteName,\n\t\t\t\t\tcursorType: \"inbox\",\n\t\t\t\t\tcursorOrdinal: maxOrdinal,\n\t\t\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\tthis.logger.error(\"Failed to update inbox cursor for @ChannelId! This is unlikely to cause a problem, but not-optimal: @Error\", this.channelId, error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\tshutdown() {\n\t\tthis.isShutdown = true;\n\t\tthis.transitionConnectionState(\"disconnected\");\n\t\treturn Promise.resolve();\n\t}\n\tgetConnectionState() {\n\t\treturn {\n\t\t\tstate: this.connectionState,\n\t\t\tfailureCount: 0,\n\t\t\tlastSuccessUtcMs: 0,\n\t\t\tlastFailureUtcMs: 0,\n\t\t\tpushBlocked: false,\n\t\t\tpushFailureCount: 0,\n\t\t\treceivingPages: false,\n\t\t\trequiresAuth: false\n\t\t};\n\t}\n\tonConnectionStateChange(callback) {\n\t\tthis.connectionStateCallbacks.add(callback);\n\t\treturn () => {\n\t\t\tthis.connectionStateCallbacks.delete(callback);\n\t\t};\n\t}\n\t/** Response channels are push-driven; resolvers populate mailboxes directly. */\n\ttriggerPull() {}\n\tasync init() {\n\t\tconst cursors = await this.cursorStorage.list(this.remoteName);\n\t\tconst inboxOrdinal = cursors.find((c) => c.cursorType === \"inbox\")?.cursorOrdinal ?? 0;\n\t\tconst outboxOrdinal = cursors.find((c) => c.cursorType === \"outbox\")?.cursorOrdinal ?? 0;\n\t\tthis.inbox.init(inboxOrdinal);\n\t\tthis.outbox.init(outboxOrdinal);\n\t\tthis.lastPersistedInboxOrdinal = inboxOrdinal;\n\t\tthis.lastPersistedOutboxOrdinal = outboxOrdinal;\n\t\tthis.appliedOutboxOrdinal = outboxOrdinal;\n\t\tthis.transitionConnectionState(\"connected\");\n\t}\n\ttransitionConnectionState(next) {\n\t\tif (this.connectionState === next) return;\n\t\tthis.connectionState = next;\n\t\tconst snapshot = this.getConnectionState();\n\t\tfor (const callback of this.connectionStateCallbacks) try {\n\t\t\tcallback(snapshot);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Connection state change callback error: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Records the ordinals of entries that left the outbox without being served,\n\t* so the cursor cannot advance past them.\n\t*\n\t* An entry can leave unserved because a bound evicted it, and an evicted entry\n\t* is exactly one this channel intends to re-derive: it is still owed to the\n\t* remote. Remembering the floor across the whole run rather than only while\n\t* the entry is present is what makes that true after a later ack would\n\t* otherwise have swept the cursor past it.\n\t*/\n\trememberUnserved(syncOps) {\n\t\tfor (const syncOp of syncOps) {\n\t\t\tif (syncOp.status === SyncOperationStatus.Applied) continue;\n\t\t\tconst first = firstOrdinalOf$1(syncOp);\n\t\t\tif (first > 0 && first < this.evictedOutboxFloor) this.evictedOutboxFloor = first;\n\t\t}\n\t}\n\t/**\n\t* Persists the outbox cursor, never past an operation this remote has not\n\t* been served.\n\t*\n\t* The cursor is where a restart resumes deriving the outbox from, so an\n\t* ordinal persisted past an unserved entry loses that entry for good: the\n\t* rebuild starts beyond it and nothing else remembers it was owed. Acks\n\t* arrive out of order with respect to what is withheld -- a later entry can\n\t* be acknowledged while an earlier one is still being withheld from this\n\t* subject -- so the applied high-water mark alone is not a safe cursor.\n\t*/\n\tpersistOutboxCursor(appliedOrdinal) {\n\t\tthis.appliedOutboxOrdinal = Math.max(this.appliedOutboxOrdinal, appliedOrdinal);\n\t\tconst ordinal = Math.min(this.appliedOutboxOrdinal, this.unservedFloor() - 1);\n\t\tif (ordinal <= this.lastPersistedOutboxOrdinal) return;\n\t\tthis.lastPersistedOutboxOrdinal = ordinal;\n\t\tthis.cursorStorage.upsert({\n\t\t\tremoteName: this.remoteName,\n\t\t\tcursorType: \"outbox\",\n\t\t\tcursorOrdinal: ordinal,\n\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t}).catch((error) => {\n\t\t\tthis.logger.error(\"Failed to update outbox cursor for @ChannelId! This means that future application runs may resend duplicate operations. This is recoverable (with deduplication protection), but not-optimal: @Error\", this.channelId, error);\n\t\t});\n\t}\n\t/** Drops the evicted floor once the entries it stood for are queued again. */\n\tforgetEvictedBelow(syncOps) {\n\t\tif (this.evictedOutboxFloor === Number.POSITIVE_INFINITY) return;\n\t\tfor (const syncOp of syncOps) {\n\t\t\tconst first = firstOrdinalOf$1(syncOp);\n\t\t\tif (first > 0 && first <= this.evictedOutboxFloor) {\n\t\t\t\tthis.evictedOutboxFloor = Number.POSITIVE_INFINITY;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\t/** The lowest ordinal still owed to this remote, evicted or still queued. */\n\tunservedFloor() {\n\t\tlet floor = this.evictedOutboxFloor;\n\t\tfor (const syncOp of this.outbox.items) {\n\t\t\tif (syncOp.status === SyncOperationStatus.Applied) continue;\n\t\t\tconst first = firstOrdinalOf$1(syncOp);\n\t\t\tif (first > 0 && first < floor) floor = first;\n\t\t}\n\t\treturn floor;\n\t}\n};\n//#endregion\n//#region src/sync/channels/gql-response-channel-factory.ts\n/**\n* Factory for creating GqlResponseChannel instances.\n*/\nvar GqlResponseChannelFactory = class {\n\tlogger;\n\tconstructor(logger) {\n\t\tthis.logger = logger;\n\t}\n\tinstance(remoteId, remoteName, config, cursorStorage) {\n\t\treturn new GqlResponseChannel(this.logger, remoteId, remoteName, cursorStorage);\n\t}\n};\n//#endregion\n//#region src/storage/kysely/sync-cursor-storage.ts\nfunction rowToRemoteCursor(row) {\n\treturn {\n\t\tremoteName: row.remote_name,\n\t\tcursorType: row.cursor_type,\n\t\tcursorOrdinal: Number(row.cursor_ordinal),\n\t\tlastSyncedAtUtcMs: row.last_synced_at_utc_ms ? new Date(row.last_synced_at_utc_ms).getTime() : void 0\n\t};\n}\nfunction remoteCursorToRow(cursor) {\n\treturn {\n\t\tremote_name: cursor.remoteName,\n\t\tcursor_type: cursor.cursorType,\n\t\tcursor_ordinal: BigInt(cursor.cursorOrdinal),\n\t\tlast_synced_at_utc_ms: cursor.lastSyncedAtUtcMs ? new Date(cursor.lastSyncedAtUtcMs).toISOString() : null\n\t};\n}\nvar KyselySyncCursorStorage = class {\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tasync list(remoteName, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst rows = await this.db.selectFrom(\"sync_cursors\").selectAll().where(\"remote_name\", \"=\", remoteName).execute();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn rows.map(rowToRemoteCursor);\n\t}\n\tasync get(remoteName, cursorType, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst row = await this.db.selectFrom(\"sync_cursors\").selectAll().where(\"remote_name\", \"=\", remoteName).where(\"cursor_type\", \"=\", cursorType).executeTakeFirst();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tif (!row) return {\n\t\t\tremoteName,\n\t\t\tcursorType,\n\t\t\tcursorOrdinal: 0\n\t\t};\n\t\treturn rowToRemoteCursor(row);\n\t}\n\tasync upsert(cursor, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tconst insertable = remoteCursorToRow(cursor);\n\t\t\tawait trx.insertInto(\"sync_cursors\").values(insertable).onConflict((oc) => oc.columns([\"remote_name\", \"cursor_type\"]).doUpdateSet({\n\t\t\t\t...insertable,\n\t\t\t\tupdated_at: sql`NOW()`\n\t\t\t})).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync remove(remoteName, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_cursors\").where(\"remote_name\", \"=\", remoteName).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n};\n//#endregion\n//#region src/storage/kysely/sync-dead-letter-storage.ts\nfunction rowToDeadLetterRecord(row) {\n\treturn {\n\t\tid: row.id,\n\t\tjobId: row.job_id,\n\t\tjobDependencies: row.job_dependencies,\n\t\tremoteName: row.remote_name,\n\t\tdocumentId: row.document_id,\n\t\tscopes: row.scopes,\n\t\tbranch: row.branch,\n\t\toperations: row.operations,\n\t\terrorSource: row.error_source,\n\t\terrorMessage: row.error_message,\n\t\terrorType: row.error_type ?? \"UNCLASSIFIED\"\n\t};\n}\nfunction deadLetterRecordToRow(record) {\n\treturn {\n\t\tid: record.id,\n\t\tjob_id: record.jobId,\n\t\tjob_dependencies: JSON.stringify(record.jobDependencies),\n\t\tremote_name: record.remoteName,\n\t\tdocument_id: record.documentId,\n\t\tscopes: JSON.stringify(record.scopes),\n\t\tbranch: record.branch,\n\t\toperations: JSON.stringify(record.operations),\n\t\terror_source: record.errorSource,\n\t\terror_message: record.errorMessage,\n\t\terror_type: record.errorType\n\t};\n}\n/**\n* PGlite/Kysely-backed implementation of {@link ISyncDeadLetterStorage}.\n*/\nvar KyselySyncDeadLetterStorage = class {\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tasync list(remoteName, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n\t\tconst limit = paging?.limit || 100;\n\t\tconst rows = await this.db.selectFrom(\"sync_dead_letters\").selectAll().where(\"remote_name\", \"=\", remoteName).orderBy(\"ordinal\", \"desc\").offset(startIndex).limit(limit + 1).execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (paging?.limit && rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore ? String(startIndex + limit) : void 0;\n\t\tconst cursor = paging?.cursor || \"0\";\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn {\n\t\t\tresults: items.map(rowToDeadLetterRecord),\n\t\t\toptions: {\n\t\t\t\tcursor,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor\n\t\t};\n\t}\n\tasync add(deadLetter, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tconst insertable = deadLetterRecordToRow(deadLetter);\n\t\t\tawait trx.insertInto(\"sync_dead_letters\").values(insertable).onConflict((oc) => oc.column(\"id\").doNothing()).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync remove(id, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_dead_letters\").where(\"id\", \"=\", id).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync removeByRemote(remoteName, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_dead_letters\").where(\"remote_name\", \"=\", remoteName).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync listQuarantinedDocumentIds(signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst rows = await this.db.selectFrom(\"sync_dead_letters\").select([\"document_id\", \"error_type\"]).distinct().execute();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst quarantined = /* @__PURE__ */ new Set();\n\t\tfor (const row of rows) if (quarantinesDocument(row.error_type ?? \"UNCLASSIFIED\")) quarantined.add(row.document_id);\n\t\treturn [...quarantined];\n\t}\n};\n//#endregion\n//#region src/storage/kysely/sync-remote-storage.ts\nfunction rowToRemoteRecord(row) {\n\treturn {\n\t\tid: row.channel_id,\n\t\tname: row.name,\n\t\tcollectionId: DriveCollectionId.fromKey(row.collection_id),\n\t\tchannelConfig: {\n\t\t\ttype: row.channel_type,\n\t\t\tparameters: row.channel_parameters ?? {}\n\t\t},\n\t\tfilter: {\n\t\t\tdocumentId: row.filter_document_ids ?? [],\n\t\t\tscope: row.filter_scopes ?? [],\n\t\t\tbranch: row.filter_branch\n\t\t},\n\t\toptions: {\n\t\t\tsinceTimestampUtcMs: \"0\",\n\t\t\tboundAddress: row.bound_address ?? void 0\n\t\t},\n\t\tstatus: {\n\t\t\tpush: {\n\t\t\t\tstate: row.push_state,\n\t\t\t\tlastSuccessUtcMs: row.push_last_success_utc_ms ? new Date(row.push_last_success_utc_ms).getTime() : void 0,\n\t\t\t\tlastFailureUtcMs: row.push_last_failure_utc_ms ? new Date(row.push_last_failure_utc_ms).getTime() : void 0,\n\t\t\t\tfailureCount: row.push_failure_count\n\t\t\t},\n\t\t\tpull: {\n\t\t\t\tstate: row.pull_state,\n\t\t\t\tlastSuccessUtcMs: row.pull_last_success_utc_ms ? new Date(row.pull_last_success_utc_ms).getTime() : void 0,\n\t\t\t\tlastFailureUtcMs: row.pull_last_failure_utc_ms ? new Date(row.pull_last_failure_utc_ms).getTime() : void 0,\n\t\t\t\tfailureCount: row.pull_failure_count\n\t\t\t}\n\t\t}\n\t};\n}\n/**\n* Maps a RemoteRecord to a row. jsonb array columns are JSON-encoded because the\n* pg driver would otherwise emit a Postgres array literal (\"{a,b}\"), which jsonb\n* rejects (matches sync-dead-letter-storage).\n*/\nfunction remoteRecordToRow(remote) {\n\treturn {\n\t\tname: remote.name,\n\t\tcollection_id: remote.collectionId.key,\n\t\tchannel_type: remote.channelConfig.type,\n\t\tchannel_id: remote.id,\n\t\tremote_name: remote.name,\n\t\tchannel_parameters: remote.channelConfig.parameters,\n\t\tfilter_document_ids: remote.filter.documentId.length > 0 ? JSON.stringify(remote.filter.documentId) : null,\n\t\tfilter_scopes: remote.filter.scope.length > 0 ? JSON.stringify(remote.filter.scope) : null,\n\t\tfilter_branch: remote.filter.branch,\n\t\tpush_state: remote.status.push.state,\n\t\tpush_last_success_utc_ms: remote.status.push.lastSuccessUtcMs ? new Date(remote.status.push.lastSuccessUtcMs).toISOString() : null,\n\t\tpush_last_failure_utc_ms: remote.status.push.lastFailureUtcMs ? new Date(remote.status.push.lastFailureUtcMs).toISOString() : null,\n\t\tpush_failure_count: remote.status.push.failureCount,\n\t\tpull_state: remote.status.pull.state,\n\t\tpull_last_success_utc_ms: remote.status.pull.lastSuccessUtcMs ? new Date(remote.status.pull.lastSuccessUtcMs).toISOString() : null,\n\t\tpull_last_failure_utc_ms: remote.status.pull.lastFailureUtcMs ? new Date(remote.status.pull.lastFailureUtcMs).toISOString() : null,\n\t\tpull_failure_count: remote.status.pull.failureCount,\n\t\tbound_address: remote.options.boundAddress ?? null\n\t};\n}\nvar KyselySyncRemoteStorage = class {\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tasync list(signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst rows = await this.db.selectFrom(\"sync_remotes\").selectAll().execute();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn rows.map(rowToRemoteRecord);\n\t}\n\tasync get(name, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst row = await this.db.selectFrom(\"sync_remotes\").selectAll().where(\"name\", \"=\", name).executeTakeFirst();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tif (!row) throw new Error(`Remote not found: ${name}`);\n\t\treturn rowToRemoteRecord(row);\n\t}\n\tasync upsert(remote, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tconst insertable = remoteRecordToRow(remote);\n\t\t\tawait trx.insertInto(\"sync_remotes\").values(insertable).onConflict((oc) => oc.column(\"name\").doUpdateSet({\n\t\t\t\t...insertable,\n\t\t\t\tupdated_at: sql`NOW()`\n\t\t\t})).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync remove(name, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_remotes\").where(\"name\", \"=\", name).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n};\n//#endregion\n//#region src/sync/batch-aggregator.ts\nvar BatchAggregator = class {\n\tlogger;\n\tdriveContainerTypes;\n\tonBatchReady;\n\tqueue = [];\n\tprocessing = false;\n\tpendingBatches = /* @__PURE__ */ new Map();\n\tconstructor(logger, driveContainerTypes, onBatchReady) {\n\t\tthis.logger = logger;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.onBatchReady = onBatchReady;\n\t}\n\tasync enqueueWriteReady(event) {\n\t\tthis.queue.push(event);\n\t\tawait this.processQueue();\n\t}\n\tasync handleJobFailed(event) {\n\t\tconst batchId = event.job?.meta.batchId;\n\t\tif (!batchId) return;\n\t\tconst pending = this.pendingBatches.get(batchId);\n\t\tif (!pending) return;\n\t\tthis.pendingBatches.delete(batchId);\n\t\tif (pending.events.length > 0) await this.onBatchReady(this.prepareBatch(pending.events));\n\t}\n\tclear() {\n\t\tthis.queue = [];\n\t\tthis.pendingBatches.clear();\n\t}\n\tasync processQueue() {\n\t\tif (this.processing) return;\n\t\tthis.processing = true;\n\t\ttry {\n\t\t\twhile (this.queue.length > 0) {\n\t\t\t\tconst event = this.queue.shift();\n\t\t\t\ttry {\n\t\t\t\t\tawait this.handleWriteReady(event);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\tthis.logger.error(\"Failed to process write-ready event (@jobId, @error)\", event.jobId, err.message);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.processing = false;\n\t\t}\n\t}\n\tasync handleWriteReady(event) {\n\t\tconst { batchId, batchJobIds } = event.jobMeta;\n\t\tif (batchJobIds.length <= 1) {\n\t\t\tawait this.onBatchReady(this.prepareBatch([event]));\n\t\t\treturn;\n\t\t}\n\t\tlet pending = this.pendingBatches.get(batchId);\n\t\tif (!pending) {\n\t\t\tpending = {\n\t\t\t\texpectedJobIds: new Set(batchJobIds),\n\t\t\t\tarrivedJobIds: /* @__PURE__ */ new Set(),\n\t\t\t\tevents: []\n\t\t\t};\n\t\t\tthis.pendingBatches.set(batchId, pending);\n\t\t}\n\t\tpending.arrivedJobIds.add(event.jobId);\n\t\tpending.events.push(event);\n\t\tif (pending.arrivedJobIds.size >= pending.expectedJobIds.size) {\n\t\t\tthis.pendingBatches.delete(batchId);\n\t\t\tawait this.onBatchReady(this.prepareBatch(pending.events));\n\t\t}\n\t}\n\tprepareBatch(events) {\n\t\tconst collectionMemberships = this.mergeCollectionMemberships(events);\n\t\tconst isBatch = events.length > 1;\n\t\tconst priorJobIds = [];\n\t\tconst entries = [];\n\t\tfor (const event of events) {\n\t\t\tentries.push({\n\t\t\t\tevent,\n\t\t\t\tjobDependencies: isBatch ? [...priorJobIds] : []\n\t\t\t});\n\t\t\tif (isBatch && event.jobId) priorJobIds.push(event.jobId);\n\t\t}\n\t\treturn {\n\t\t\tcollectionMemberships,\n\t\t\tentries\n\t\t};\n\t}\n\tmergeCollectionMemberships(events) {\n\t\tconst mergedMemberships = {};\n\t\tfor (const event of events) {\n\t\t\tif (event.collectionMemberships) for (const [docId, collections] of Object.entries(event.collectionMemberships)) {\n\t\t\t\tif (!(docId in mergedMemberships)) mergedMemberships[docId] = [];\n\t\t\t\tfor (const c of collections) if (!mergedMemberships[docId].includes(c)) mergedMemberships[docId].push(c);\n\t\t\t}\n\t\t\tfor (const op of event.operations) {\n\t\t\t\tconst action = op.operation.action;\n\t\t\t\tif (action.type !== \"ADD_RELATIONSHIP\") continue;\n\t\t\t\tif (!this.driveContainerTypes.has(op.context.documentType)) continue;\n\t\t\t\tconst input = action.input;\n\t\t\t\tif (!input?.sourceId || !input.targetId) continue;\n\t\t\t\tconst collectionId = DriveCollectionId.forDrive(input.sourceId, op.context.branch).key;\n\t\t\t\tif (!(input.targetId in mergedMemberships)) mergedMemberships[input.targetId] = [];\n\t\t\t\tif (!mergedMemberships[input.targetId].includes(collectionId)) mergedMemberships[input.targetId].push(collectionId);\n\t\t\t}\n\t\t}\n\t\treturn mergedMemberships;\n\t}\n};\n//#endregion\n//#region src/sync/sync-awaiter.ts\n/**\n* Provides a promise-based interface for waiting on sync completion.\n* Subscribes to sync events at construction and tracks completed sync results\n* to provide a fast path for jobs that have already synced.\n*/\nvar SyncAwaiter = class {\n\tcompletedResults = /* @__PURE__ */ new Map();\n\tpendingWaiters = /* @__PURE__ */ new Map();\n\tunsubscribers = [];\n\tisShutdown = false;\n\tconstructor(eventBus) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.subscribeToEvents();\n\t}\n\t/**\n\t* Waits for sync operations for a job to complete.\n\t* Resolves when SYNC_SUCCEEDED is emitted.\n\t* Rejects when SYNC_FAILED is emitted.\n\t*\n\t* @param jobId - The job id to wait for\n\t* @param signal - Optional abort signal\n\t* @returns The sync result\n\t*/\n\twaitForSync(jobId, signal) {\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (this.isShutdown) return Promise.reject(/* @__PURE__ */ new Error(\"SyncAwaiter is shutdown\"));\n\t\tconst completedResult = this.completedResults.get(jobId);\n\t\tif (completedResult) return Promise.resolve(completedResult);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst waiter = {\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t\tsignal\n\t\t\t};\n\t\t\tconst existingWaiters = this.pendingWaiters.get(jobId) || [];\n\t\t\texistingWaiters.push(waiter);\n\t\t\tthis.pendingWaiters.set(jobId, existingWaiters);\n\t\t\tif (signal) {\n\t\t\t\tconst abortHandler = () => {\n\t\t\t\t\tconst waiters = this.pendingWaiters.get(jobId);\n\t\t\t\t\tif (waiters) {\n\t\t\t\t\t\tconst index = waiters.indexOf(waiter);\n\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\twaiters.splice(index, 1);\n\t\t\t\t\t\t\tif (waiters.length === 0) this.pendingWaiters.delete(jobId);\n\t\t\t\t\t\t\twaiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", abortHandler, { once: true });\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Shuts down the sync awaiter. This will synchronously reject all pending waiters.\n\t*/\n\tshutdown() {\n\t\tthis.isShutdown = true;\n\t\tfor (const unsubscribe of this.unsubscribers) unsubscribe();\n\t\tthis.unsubscribers.length = 0;\n\t\tfor (const [, waiters] of this.pendingWaiters) for (const waiter of waiters) waiter.reject(/* @__PURE__ */ new Error(\"SyncAwaiter shutdown\"));\n\t\tthis.pendingWaiters.clear();\n\t}\n\tsubscribeToEvents() {\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(SyncEventTypes.SYNC_SUCCEEDED, (_type, event) => {\n\t\t\tthis.handleSyncSucceeded(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(SyncEventTypes.SYNC_FAILED, (_type, event) => {\n\t\t\tthis.handleSyncFailed(event);\n\t\t}));\n\t}\n\thandleSyncSucceeded(event) {\n\t\tconst result = {\n\t\t\tjobId: event.jobId,\n\t\t\tstatus: \"succeeded\",\n\t\t\tsyncOperationCount: event.syncOperationCount,\n\t\t\tsuccessCount: event.syncOperationCount,\n\t\t\tfailureCount: 0,\n\t\t\terrors: []\n\t\t};\n\t\tthis.completedResults.set(event.jobId, result);\n\t\tthis.resolveWaiters(event.jobId, result);\n\t}\n\thandleSyncFailed(event) {\n\t\tconst result = {\n\t\t\tjobId: event.jobId,\n\t\t\tstatus: \"failed\",\n\t\t\tsyncOperationCount: event.successCount + event.failureCount,\n\t\t\tsuccessCount: event.successCount,\n\t\t\tfailureCount: event.failureCount,\n\t\t\terrors: event.errors\n\t\t};\n\t\tthis.completedResults.set(event.jobId, result);\n\t\tthis.resolveWaiters(event.jobId, result);\n\t}\n\tresolveWaiters(jobId, result) {\n\t\tconst waiters = this.pendingWaiters.get(jobId);\n\t\tif (!waiters || waiters.length === 0) return;\n\t\tthis.pendingWaiters.delete(jobId);\n\t\tfor (const waiter of waiters) if (waiter.signal?.aborted) waiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\telse waiter.resolve(result);\n\t}\n};\n//#endregion\n//#region src/sync/sync-status-tracker.ts\nlet SyncStatus = /* @__PURE__ */ function(SyncStatus) {\n\tSyncStatus[\"Synced\"] = \"SYNCED\";\n\tSyncStatus[\"Outgoing\"] = \"OUTGOING\";\n\tSyncStatus[\"Incoming\"] = \"INCOMING\";\n\tSyncStatus[\"OutgoingAndIncoming\"] = \"OUTGOING_AND_INCOMING\";\n\tSyncStatus[\"Error\"] = \"ERROR\";\n\treturn SyncStatus;\n}({});\nvar SyncStatusTracker = class {\n\tremotes = /* @__PURE__ */ new Map();\n\tseen = /* @__PURE__ */ new Set();\n\tcallbacks = /* @__PURE__ */ new Set();\n\tgetStatus(documentId) {\n\t\tif (!this.seen.has(documentId)) return;\n\t\tlet totalInbox = 0;\n\t\tlet totalOutbox = 0;\n\t\tlet totalErrors = 0;\n\t\tfor (const documents of this.remotes.values()) {\n\t\t\tconst counts = documents.get(documentId);\n\t\t\tif (counts) {\n\t\t\t\ttotalInbox += counts.inboxCount;\n\t\t\t\ttotalOutbox += counts.outboxCount;\n\t\t\t\ttotalErrors += counts.errorCount;\n\t\t\t}\n\t\t}\n\t\treturn deriveStatus(totalInbox, totalOutbox, totalErrors);\n\t}\n\tonChange(callback) {\n\t\tthis.callbacks.add(callback);\n\t\treturn () => {\n\t\t\tthis.callbacks.delete(callback);\n\t\t};\n\t}\n\ttrackRemote(remoteName, channel) {\n\t\tthis.remotes.set(remoteName, /* @__PURE__ */ new Map());\n\t\tchannel.inbox.onAdded((syncOps) => this.handleAdded(remoteName, \"inbox\", syncOps));\n\t\tchannel.inbox.onRemoved((syncOps) => this.handleRemoved(remoteName, \"inbox\", syncOps));\n\t\tchannel.outbox.onAdded((syncOps) => this.handleAdded(remoteName, \"outbox\", syncOps));\n\t\tchannel.outbox.onRemoved((syncOps) => this.handleRemoved(remoteName, \"outbox\", syncOps));\n\t\tchannel.deadLetter.onAdded((syncOps) => this.handleAdded(remoteName, \"deadLetter\", syncOps));\n\t}\n\tuntrackRemote(remoteName) {\n\t\tconst documents = this.remotes.get(remoteName);\n\t\tif (!documents) return;\n\t\tconst affectedDocumentIds = [...documents.keys()];\n\t\tthis.remotes.delete(remoteName);\n\t\tfor (const documentId of affectedDocumentIds) this.notifyChange(documentId);\n\t}\n\tclear() {\n\t\tthis.remotes.clear();\n\t\tthis.seen.clear();\n\t\tthis.callbacks.clear();\n\t}\n\thandleAdded(remoteName, mailboxType, syncOps) {\n\t\tconst changedDocuments = /* @__PURE__ */ new Set();\n\t\tfor (const syncOp of syncOps) {\n\t\t\tif (mailboxType === \"inbox\" && !syncOp.remoteName) continue;\n\t\t\tconst counts = this.getOrCreateCounts(remoteName, syncOp.documentId);\n\t\t\tthis.seen.add(syncOp.documentId);\n\t\t\tif (mailboxType === \"inbox\") counts.inboxCount++;\n\t\t\telse if (mailboxType === \"outbox\") counts.outboxCount++;\n\t\t\telse counts.errorCount++;\n\t\t\tchangedDocuments.add(syncOp.documentId);\n\t\t}\n\t\tfor (const documentId of changedDocuments) this.notifyChange(documentId);\n\t}\n\thandleRemoved(remoteName, mailboxType, syncOps) {\n\t\tconst changedDocuments = /* @__PURE__ */ new Set();\n\t\tfor (const syncOp of syncOps) {\n\t\t\tconst counts = this.getOrCreateCounts(remoteName, syncOp.documentId);\n\t\t\tif (mailboxType === \"inbox\") counts.inboxCount = Math.max(0, counts.inboxCount - 1);\n\t\t\telse if (mailboxType === \"outbox\") counts.outboxCount = Math.max(0, counts.outboxCount - 1);\n\t\t\tchangedDocuments.add(syncOp.documentId);\n\t\t}\n\t\tfor (const documentId of changedDocuments) this.notifyChange(documentId);\n\t}\n\tgetOrCreateCounts(remoteName, documentId) {\n\t\tlet documents = this.remotes.get(remoteName);\n\t\tif (!documents) {\n\t\t\tdocuments = /* @__PURE__ */ new Map();\n\t\t\tthis.remotes.set(remoteName, documents);\n\t\t}\n\t\tlet counts = documents.get(documentId);\n\t\tif (!counts) {\n\t\t\tcounts = {\n\t\t\t\tinboxCount: 0,\n\t\t\t\toutboxCount: 0,\n\t\t\t\terrorCount: 0\n\t\t\t};\n\t\t\tdocuments.set(documentId, counts);\n\t\t}\n\t\treturn counts;\n\t}\n\tnotifyChange(documentId) {\n\t\tconst status = this.getStatus(documentId);\n\t\tif (status === void 0) return;\n\t\tfor (const callback of [...this.callbacks]) callback(documentId, status);\n\t}\n};\nfunction deriveStatus(inboxCount, outboxCount, errorCount) {\n\tif (errorCount > 0) return SyncStatus.Error;\n\tif (inboxCount > 0 && outboxCount > 0) return SyncStatus.OutgoingAndIncoming;\n\tif (inboxCount > 0) return SyncStatus.Incoming;\n\tif (outboxCount > 0) return SyncStatus.Outgoing;\n\treturn SyncStatus.Synced;\n}\n//#endregion\n//#region src/sync/sync-manager.ts\nvar OutboxMode = /* @__PURE__ */ function(OutboxMode) {\n\tOutboxMode[\"Backfill\"] = \"backfill\";\n\tOutboxMode[\"BatchTriggered\"] = \"batch-triggered\";\n\treturn OutboxMode;\n}(OutboxMode || {});\nconst defaultSyncManagerConfig = {\n\tmaxDeadLettersPerRemote: 100,\n\tmaxInboxBatchSize: 32,\n\tmaxHeldOperationsPerRemote: 1e4\n};\nconst PLAN_KEY_TO_JOB_UUID_CAP = 1e4;\n/** Where a sync operation's run of ordinals begins. */\nfunction firstOrdinalOf(syncOp) {\n\treturn syncOp.operations.length > 0 ? syncOp.operations[0].context.ordinal : 0;\n}\nvar SyncManager = class {\n\tlogger;\n\tremoteStorage;\n\tcursorStorage;\n\tdeadLetterStorage;\n\tchannelFactory;\n\toperationIndex;\n\treactor;\n\teventBus;\n\tremotes;\n\tawaiter;\n\tsyncAwaiter;\n\tabortController = new AbortController();\n\tisShutdown;\n\teventUnsubscribe;\n\tfailedEventUnsubscribe;\n\tbatchAggregator;\n\tsyncStatusTracker;\n\tconfig;\n\tconnectionStateUnsubscribes = /* @__PURE__ */ new Map();\n\tquarantinedDocumentIds = /* @__PURE__ */ new Set();\n\tbackfillAbortControllers = /* @__PURE__ */ new Map();\n\tplanKeyToJobUuid = /* @__PURE__ */ new Map();\n\tevictedOutboxFloors = /* @__PURE__ */ new Map();\n\tlastEnqueuedJobIdByKey = /* @__PURE__ */ new Map();\n\tinboxChunkChain = Promise.resolve();\n\tconstructor(logger, remoteStorage, cursorStorage, deadLetterStorage, channelFactory, operationIndex, reactor, eventBus, driveContainerTypes, config = {}) {\n\t\tthis.logger = logger;\n\t\tthis.remoteStorage = remoteStorage;\n\t\tthis.cursorStorage = cursorStorage;\n\t\tthis.deadLetterStorage = deadLetterStorage;\n\t\tthis.channelFactory = channelFactory;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.reactor = reactor;\n\t\tthis.eventBus = eventBus;\n\t\tthis.config = {\n\t\t\t...defaultSyncManagerConfig,\n\t\t\t...config\n\t\t};\n\t\tthis.remotes = /* @__PURE__ */ new Map();\n\t\tthis.awaiter = new JobAwaiter(eventBus, (jobId, signal) => reactor.getJobStatus(jobId, signal));\n\t\tthis.syncAwaiter = new SyncAwaiter(eventBus);\n\t\tthis.isShutdown = false;\n\t\tthis.batchAggregator = new BatchAggregator(logger, driveContainerTypes, (batch) => this.processCompleteBatch(batch));\n\t\tthis.syncStatusTracker = new SyncStatusTracker();\n\t}\n\tasync startup() {\n\t\tif (this.isShutdown) throw new Error(\"SyncManager is already shutdown and cannot be started\");\n\t\ttry {\n\t\t\tconst quarantinedIds = await this.deadLetterStorage.listQuarantinedDocumentIds();\n\t\t\tfor (const id of quarantinedIds) this.quarantinedDocumentIds.add(id);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to load quarantined document IDs (@error)\", error instanceof Error ? error.message : String(error));\n\t\t}\n\t\tconst remoteRecords = await this.remoteStorage.list();\n\t\tfor (const record of remoteRecords) {\n\t\t\tconst channel = this.channelFactory.instance(record.id, record.name, record.channelConfig, this.cursorStorage, record.collectionId, record.filter, this.operationIndex, record.options);\n\t\t\tconst remote = {\n\t\t\t\tmeta: {\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tname: record.name,\n\t\t\t\t\tcollectionId: record.collectionId,\n\t\t\t\t\tchannelConfig: record.channelConfig,\n\t\t\t\t\tfilter: record.filter,\n\t\t\t\t\toptions: record.options\n\t\t\t\t},\n\t\t\t\tchannel\n\t\t\t};\n\t\t\tthis.remotes.set(record.name, remote);\n\t\t\tawait this.loadDeadLetters(remote);\n\t\t\tthis.wireChannelCallbacks(remote);\n\t\t\ttry {\n\t\t\t\tawait channel.init();\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Error initializing channel for remote (@name, @error)\", record.name, error instanceof Error ? error.message : String(error));\n\t\t\t\tthis.remotes.delete(record.name);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst outboxAckOrdinal = remote.channel.outbox.ackOrdinal;\n\t\t\tif (outboxAckOrdinal > 0) {\n\t\t\t\tconst backfillController = new AbortController();\n\t\t\t\tthis.backfillAbortControllers.set(record.name, backfillController);\n\t\t\t\tthis.updateOutbox(remote, outboxAckOrdinal, OutboxMode.Backfill, backfillController.signal).catch((error) => {\n\t\t\t\t\tif (backfillController.signal.aborted) return;\n\t\t\t\t\tthis.logger.error(\"Backfill failed for remote @RemoteName: @Error\", remote.meta.name, error instanceof Error ? error : new Error(String(error)));\n\t\t\t\t}).finally(() => {\n\t\t\t\t\tthis.backfillAbortControllers.delete(record.name);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.eventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, async (_type, event) => this.batchAggregator.enqueueWriteReady(event));\n\t\tthis.failedEventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, async (_type, event) => this.batchAggregator.handleJobFailed(event));\n\t}\n\tshutdown() {\n\t\tthis.isShutdown = true;\n\t\tthis.abortController.abort();\n\t\tfor (const controller of this.backfillAbortControllers.values()) controller.abort();\n\t\tthis.backfillAbortControllers.clear();\n\t\tthis.planKeyToJobUuid.clear();\n\t\tthis.lastEnqueuedJobIdByKey.clear();\n\t\tthis.batchAggregator.clear();\n\t\tif (this.eventUnsubscribe) {\n\t\t\tthis.eventUnsubscribe();\n\t\t\tthis.eventUnsubscribe = void 0;\n\t\t}\n\t\tif (this.failedEventUnsubscribe) {\n\t\t\tthis.failedEventUnsubscribe();\n\t\t\tthis.failedEventUnsubscribe = void 0;\n\t\t}\n\t\tthis.awaiter.shutdown();\n\t\tthis.syncAwaiter.shutdown();\n\t\tthis.syncStatusTracker.clear();\n\t\tfor (const unsub of this.connectionStateUnsubscribes.values()) unsub();\n\t\tthis.connectionStateUnsubscribes.clear();\n\t\tconst promises = [];\n\t\tfor (const remote of this.remotes.values()) promises.push(remote.channel.shutdown());\n\t\tthis.remotes.clear();\n\t\treturn {\n\t\t\tisShutdown: true,\n\t\t\tcompleted: Promise.all(promises).then(() => void 0)\n\t\t};\n\t}\n\tgetByName(name) {\n\t\tconst remote = this.remotes.get(name);\n\t\tif (!remote) throw new Error(`Remote with name '${name}' does not exist`);\n\t\treturn remote;\n\t}\n\tgetById(id) {\n\t\tfor (const remote of this.remotes.values()) if (remote.meta.id === id) return remote;\n\t\tthrow new Error(`Remote with id '${id}' does not exist`);\n\t}\n\tasync bindRemote(id, boundAddress) {\n\t\tconst remote = this.getById(id);\n\t\tconst bound = remote.meta.options.boundAddress;\n\t\tif (bound === boundAddress) return;\n\t\tif (bound !== void 0) throw new Error(`Remote with id '${id}' is already bound to another address`);\n\t\tremote.meta.options = {\n\t\t\t...remote.meta.options,\n\t\t\tboundAddress\n\t\t};\n\t\tawait this.remoteStorage.upsert({\n\t\t\tid: remote.meta.id,\n\t\t\tname: remote.meta.name,\n\t\t\tcollectionId: remote.meta.collectionId,\n\t\t\tchannelConfig: remote.meta.channelConfig,\n\t\t\tfilter: remote.meta.filter,\n\t\t\toptions: remote.meta.options,\n\t\t\tstatus: {\n\t\t\t\tpush: createIdleHealth(),\n\t\t\t\tpull: createIdleHealth()\n\t\t\t}\n\t\t});\n\t}\n\tasync add(name, collectionId, channelConfig, filter = {\n\t\tdocumentId: [],\n\t\tscope: [],\n\t\tbranch: \"\"\n\t}, options = { sinceTimestampUtcMs: \"0\" }, id) {\n\t\tif (this.isShutdown) throw new Error(\"SyncManager is shutdown and cannot add remotes\");\n\t\tif (this.remotes.has(name)) throw new Error(`Remote with name '${name}' already exists`);\n\t\tthis.logger.debug(\"Adding remote (@name, @collectionId, @channelConfig, @filter, @options, @id)\", name, collectionId.key, channelConfig, filter, options, id);\n\t\tconst remoteId = id ?? crypto.randomUUID();\n\t\tconst remoteRecord = {\n\t\t\tid: remoteId,\n\t\t\tname,\n\t\t\tcollectionId,\n\t\t\tchannelConfig,\n\t\t\tfilter,\n\t\t\toptions,\n\t\t\tstatus: {\n\t\t\t\tpush: createIdleHealth(),\n\t\t\t\tpull: createIdleHealth()\n\t\t\t}\n\t\t};\n\t\tawait this.remoteStorage.upsert(remoteRecord);\n\t\tconst channel = this.channelFactory.instance(remoteId, name, channelConfig, this.cursorStorage, collectionId, filter, this.operationIndex, options);\n\t\tconst remote = {\n\t\t\tmeta: {\n\t\t\t\tid: remoteId,\n\t\t\t\tname,\n\t\t\t\tcollectionId,\n\t\t\t\tchannelConfig,\n\t\t\t\tfilter,\n\t\t\t\toptions\n\t\t\t},\n\t\t\tchannel\n\t\t};\n\t\tthis.remotes.set(name, remote);\n\t\tawait this.loadDeadLetters(remote);\n\t\tthis.wireChannelCallbacks(remote);\n\t\ttry {\n\t\t\tawait channel.init();\n\t\t} catch (error) {\n\t\t\tthis.remotes.delete(name);\n\t\t\tawait this.remoteStorage.remove(name);\n\t\t\tthrow error;\n\t\t}\n\t\tconst backfillController = new AbortController();\n\t\tthis.backfillAbortControllers.set(name, backfillController);\n\t\tthis.updateOutbox(remote, 0, OutboxMode.Backfill, backfillController.signal).catch((error) => {\n\t\t\tif (backfillController.signal.aborted) return;\n\t\t\tthis.logger.error(\"Backfill failed for remote @RemoteName: @Error\", remote.meta.name, error instanceof Error ? error : new Error(String(error)));\n\t\t}).finally(() => {\n\t\t\tthis.backfillAbortControllers.delete(name);\n\t\t});\n\t\treturn remote;\n\t}\n\ttriggerPull(name) {\n\t\tconst remote = this.remotes.get(name);\n\t\tif (!remote) throw new Error(`Remote with name '${name}' does not exist`);\n\t\tremote.channel.triggerPull();\n\t}\n\tasync remove(name) {\n\t\tconst remote = this.remotes.get(name);\n\t\tif (!remote) throw new Error(`Remote with name '${name}' does not exist`);\n\t\tconst backfillController = this.backfillAbortControllers.get(name);\n\t\tif (backfillController) {\n\t\t\tbackfillController.abort();\n\t\t\tthis.backfillAbortControllers.delete(name);\n\t\t}\n\t\tawait remote.channel.shutdown();\n\t\tawait this.remoteStorage.remove(name);\n\t\tawait this.cursorStorage.remove(name);\n\t\tthis.syncStatusTracker.untrackRemote(name);\n\t\tconst unsub = this.connectionStateUnsubscribes.get(name);\n\t\tif (unsub) {\n\t\t\tunsub();\n\t\t\tthis.connectionStateUnsubscribes.delete(name);\n\t\t}\n\t\tthis.remotes.delete(name);\n\t}\n\tlist() {\n\t\treturn Array.from(this.remotes.values());\n\t}\n\twaitForSync(jobId, signal) {\n\t\treturn this.syncAwaiter.waitForSync(jobId, signal);\n\t}\n\tgetSyncStatus(documentId) {\n\t\treturn this.syncStatusTracker.getStatus(documentId);\n\t}\n\tonSyncStatusChange(callback) {\n\t\treturn this.syncStatusTracker.onChange(callback);\n\t}\n\trecordPlanKeyMapping(planKey, jobId) {\n\t\tif (!this.planKeyToJobUuid.has(planKey) && this.planKeyToJobUuid.size >= PLAN_KEY_TO_JOB_UUID_CAP) {\n\t\t\tconst oldest = this.planKeyToJobUuid.keys().next().value;\n\t\t\tif (oldest !== void 0) this.planKeyToJobUuid.delete(oldest);\n\t\t}\n\t\tthis.planKeyToJobUuid.set(planKey, jobId);\n\t}\n\twireChannelCallbacks(remote) {\n\t\tremote.channel.inbox.onAdded((syncOps) => this.handleInboxAdded(remote, syncOps));\n\t\tthis.syncStatusTracker.trackRemote(remote.meta.name, remote.channel);\n\t\tconst unsubscribe = remote.channel.onConnectionStateChange((snapshot) => {\n\t\t\tthis.eventBus.emit(SyncEventTypes.CONNECTION_STATE_CHANGED, {\n\t\t\t\tremoteName: remote.meta.name,\n\t\t\t\tremoteId: remote.meta.id,\n\t\t\t\tprevious: snapshot.state,\n\t\t\t\tcurrent: snapshot.state,\n\t\t\t\tsnapshot\n\t\t\t}).catch(() => {});\n\t\t});\n\t\tthis.connectionStateUnsubscribes.set(remote.meta.name, unsubscribe);\n\t\tremote.channel.deadLetter.onAdded((syncOps) => {\n\t\t\tfor (const syncOp of syncOps) {\n\t\t\t\tthis.logger.error(\"Dead letter (@remote, @documentId, @jobId, @error, @dependencies)\", remote.meta.name, syncOp.documentId, syncOp.jobId, syncOp.error?.message ?? \"unknown\", syncOp.jobDependencies);\n\t\t\t\tconst errorType = syncOperationErrorType(syncOp.error);\n\t\t\t\tif (quarantinesDocument(errorType)) this.quarantinedDocumentIds.add(syncOp.documentId);\n\t\t\t\tconst record = {\n\t\t\t\t\tid: syncOp.id,\n\t\t\t\t\tjobId: syncOp.jobId,\n\t\t\t\t\tjobDependencies: syncOp.jobDependencies,\n\t\t\t\t\tremoteName: syncOp.remoteName,\n\t\t\t\t\tdocumentId: syncOp.documentId,\n\t\t\t\t\tscopes: syncOp.scopes,\n\t\t\t\t\tbranch: syncOp.branch,\n\t\t\t\t\toperations: syncOp.operations,\n\t\t\t\t\terrorSource: syncOp.error?.source ?? ChannelErrorSource.None,\n\t\t\t\t\terrorMessage: syncOp.error?.error.message ?? \"unknown\",\n\t\t\t\t\terrorType\n\t\t\t\t};\n\t\t\t\tthis.deadLetterStorage.add(record).catch((err) => {\n\t\t\t\t\tthis.logger.error(\"Failed to persist dead letter (@id, @error)\", record.id, err instanceof Error ? err.message : String(err));\n\t\t\t\t});\n\t\t\t\tthis.eventBus.emit(SyncEventTypes.DEAD_LETTER_ADDED, {\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tjobId: record.jobId,\n\t\t\t\t\tremoteName: record.remoteName,\n\t\t\t\t\tdocumentId: record.documentId,\n\t\t\t\t\terrorSource: record.errorSource,\n\t\t\t\t\terrorType: record.errorType\n\t\t\t\t}).catch(() => {});\n\t\t\t}\n\t\t\tconst items = remote.channel.deadLetter.items;\n\t\t\tif (items.length > this.config.maxDeadLettersPerRemote) {\n\t\t\t\tconst excessCount = items.length - this.config.maxDeadLettersPerRemote;\n\t\t\t\tconst toEvict = items.slice(0, excessCount);\n\t\t\t\tremote.channel.deadLetter.remove(...toEvict);\n\t\t\t}\n\t\t});\n\t}\n\tasync loadDeadLetters(remote) {\n\t\tlet records;\n\t\ttry {\n\t\t\trecords = (await this.deadLetterStorage.list(remote.meta.name, {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: this.config.maxDeadLettersPerRemote\n\t\t\t})).results;\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to load dead letters for remote (@name, @error)\", remote.meta.name, error instanceof Error ? error.message : String(error));\n\t\t\treturn;\n\t\t}\n\t\tif (records.length === 0) return;\n\t\trecords.reverse();\n\t\tconst syncOps = [];\n\t\tfor (const record of records) {\n\t\t\tconst syncOp = new SyncOperation(record.id, record.jobId, record.jobDependencies, record.remoteName, record.documentId, record.scopes, record.branch, record.operations);\n\t\t\tsyncOp.failed(new ChannelError(record.errorSource, new Error(record.errorMessage), record.errorType));\n\t\t\tsyncOps.push(syncOp);\n\t\t}\n\t\tremote.channel.deadLetter.add(...syncOps);\n\t\tthis.logger.debug(\"Loaded @count persisted dead letters for remote @name\", records.length, remote.meta.name);\n\t}\n\tgetRemotesForCollection(collectionId) {\n\t\treturn Array.from(this.remotes.values()).filter((remote) => remote.meta.collectionId.key === collectionId);\n\t}\n\tasync processCompleteBatch(batch) {\n\t\tif (this.isShutdown) return;\n\t\tconst collectionIds = [...new Set(Object.values(batch.collectionMemberships).flatMap((collections) => collections))];\n\t\tconst affectedRemotes = [];\n\t\tfor (const collectionId of collectionIds) {\n\t\t\tconst remotes = this.getRemotesForCollection(collectionId);\n\t\t\tfor (const remote of remotes) if (!affectedRemotes.includes(remote)) affectedRemotes.push(remote);\n\t\t}\n\t\tfor (const remote of affectedRemotes) trimMailboxFromBatch(remote.channel.inbox, batch);\n\t\tfor (const remote of affectedRemotes) await this.updateOutbox(remote, remote.channel.outbox.latestOrdinal, OutboxMode.BatchTriggered);\n\t}\n\thandleInboxAdded(remote, syncOps) {\n\t\tif (this.isShutdown) return;\n\t\tconst eligible = syncOps.filter((op) => !this.quarantinedDocumentIds.has(op.documentId));\n\t\tif (eligible.length === 0) return;\n\t\tconst keyed = [];\n\t\tconst nonKeyed = [];\n\t\tfor (const syncOp of eligible) if (syncOp.jobId) keyed.push(syncOp);\n\t\telse nonKeyed.push(syncOp);\n\t\tfor (const syncOp of nonKeyed) this.applyInboxJob(remote, syncOp);\n\t\tif (keyed.length > 0) {\n\t\t\tconst chunks = chunkSyncOperations(keyed.map((syncOp) => ({\n\t\t\t\tremote,\n\t\t\t\tsyncOp\n\t\t\t})), this.config.maxInboxBatchSize);\n\t\t\tthis.processInboxChunks(chunks);\n\t\t}\n\t}\n\tprocessInboxChunks(chunks) {\n\t\tconst next = this.inboxChunkChain.then(async () => {\n\t\t\tfor (const chunk of chunks) {\n\t\t\t\tif (this.isShutdown) return;\n\t\t\t\tawait this.applyInboxBatch(chunk);\n\t\t\t}\n\t\t});\n\t\tthis.inboxChunkChain = next.catch((err) => {\n\t\t\tthis.logger.error(\"Inbox chunk processing failed (@error)\", err instanceof Error ? err.message : String(err));\n\t\t});\n\t\treturn next;\n\t}\n\tasync applyInboxJob(remote, syncOp) {\n\t\tconst operations = syncOp.operations.map((op) => op.operation);\n\t\tlet jobInfo;\n\t\ttry {\n\t\t\tjobInfo = await this.reactor.load(syncOp.documentId, syncOp.branch, operations, this.abortController.signal, { sourceRemote: remote.meta.name });\n\t\t} catch (error) {\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\tthis.logger.error(\"Failed to load operations from inbox (@remote, @documentId, @error)\", remote.meta.name, syncOp.documentId, err.message);\n\t\t\tconst channelError = new ChannelError(ChannelErrorSource.Inbox, err);\n\t\t\tsyncOp.failed(channelError);\n\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\treturn;\n\t\t}\n\t\tlet completedJobInfo;\n\t\ttry {\n\t\t\tcompletedJobInfo = await this.awaiter.waitForJob(jobInfo.id, this.abortController.signal);\n\t\t} catch (error) {\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\tthis.logger.error(\"Failed to wait for job completion (@remote, @documentId, @jobId, @error)\", remote.meta.name, syncOp.documentId, jobInfo.id, err.message);\n\t\t\tconst channelError = new ChannelError(ChannelErrorSource.Inbox, err);\n\t\t\tsyncOp.failed(channelError);\n\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\treturn;\n\t\t}\n\t\tif (this.isShutdown) return;\n\t\tif (completedJobInfo.status === JobStatus.FAILED) {\n\t\t\tconst errorMessage = completedJobInfo.error?.message || \"Unknown error\";\n\t\t\tthis.logger.error(\"Failed to apply operations from inbox (@remote, @documentId, @jobId, @error)\", remote.meta.name, syncOp.documentId, completedJobInfo.id, errorMessage);\n\t\t\tsyncOp.failed(this.inboxFailure(completedJobInfo.error));\n\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t} else syncOp.executed();\n\t\tremote.channel.inbox.remove(syncOp);\n\t}\n\tasync applyInboxBatch(items) {\n\t\tconst sourceRemote = items[0].remote.meta.name;\n\t\tconst chunkKeys = new Set(items.map(({ syncOp }) => syncOp.jobId));\n\t\tconst jobs = items.map(({ syncOp }) => {\n\t\t\tconst dependsOn = [];\n\t\t\tconst externalDeps = [];\n\t\t\tfor (const dep of syncOp.jobDependencies) {\n\t\t\t\tif (!dep) continue;\n\t\t\t\tif (chunkKeys.has(dep)) dependsOn.push(dep);\n\t\t\t\telse {\n\t\t\t\t\tconst uuid = this.planKeyToJobUuid.get(dep);\n\t\t\t\t\tif (uuid !== void 0) externalDeps.push(uuid);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst fifoKey = `${syncOp.documentId}:${syncOp.scopes[0]}:${syncOp.branch}`;\n\t\t\tconst prevUuid = this.lastEnqueuedJobIdByKey.get(fifoKey);\n\t\t\tif (prevUuid !== void 0) externalDeps.push(prevUuid);\n\t\t\treturn {\n\t\t\t\tkey: syncOp.jobId,\n\t\t\t\tdocumentId: syncOp.documentId,\n\t\t\t\tscope: syncOp.scopes[0],\n\t\t\t\tbranch: syncOp.branch,\n\t\t\t\toperations: syncOp.operations.map((op) => op.operation),\n\t\t\t\tdependsOn,\n\t\t\t\texternalDeps\n\t\t\t};\n\t\t});\n\t\tconst request = { jobs };\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await this.reactor.loadBatch(request, this.abortController.signal, { sourceRemote });\n\t\t} catch (error) {\n\t\t\tif (this.isShutdown) return;\n\t\t\tfor (const { remote, syncOp } of items) {\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tsyncOp.failed(new ChannelError(ChannelErrorSource.Inbox, err));\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.isShutdown) return;\n\t\tfor (const plan of jobs) {\n\t\t\tif (!(plan.key in result.jobs)) continue;\n\t\t\tconst info = result.jobs[plan.key];\n\t\t\tthis.recordPlanKeyMapping(plan.key, info.id);\n\t\t\tconst fifoKey = `${plan.documentId}:${plan.scope}:${plan.branch}`;\n\t\t\tthis.lastEnqueuedJobIdByKey.set(fifoKey, info.id);\n\t\t}\n\t\tfor (const { remote, syncOp } of items) {\n\t\t\tif (!(syncOp.jobId in result.jobs)) {\n\t\t\t\tthis.logger.error(\"Job key missing from batch load result (@remote, @documentId, @jobId)\", remote.meta.name, syncOp.documentId, syncOp.jobId);\n\t\t\t\tconst error = new ChannelError(ChannelErrorSource.Inbox, /* @__PURE__ */ new Error(`Job key '${syncOp.jobId}' missing from batch load result`));\n\t\t\t\tsyncOp.failed(error);\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst jobInfo = result.jobs[syncOp.jobId];\n\t\t\tlet completedJobInfo;\n\t\t\ttry {\n\t\t\t\tcompletedJobInfo = await this.awaiter.waitForJob(jobInfo.id, this.abortController.signal);\n\t\t\t} catch (error) {\n\t\t\t\tif (this.isShutdown) continue;\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tsyncOp.failed(new ChannelError(ChannelErrorSource.Inbox, err));\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (this.isShutdown) return;\n\t\t\tif (completedJobInfo.status === JobStatus.FAILED) {\n\t\t\t\tsyncOp.failed(this.inboxFailure(completedJobInfo.error));\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t} else syncOp.executed();\n\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t}\n\t}\n\t/**\n\t* The dead letter for a load job the executor failed.\n\t*\n\t* The classification is passed explicitly because it cannot be recovered\n\t* downstream: the wrapper carries the failure's message, not the failure, so\n\t* deriving it from the wrapper's own name would classify every one of these\n\t* as unclassified and quarantine the document. A held auth operation must\n\t* keep syncing, because reconciling the two policies needs the traffic a\n\t* quarantine would stop.\n\t*/\n\tinboxFailure(error) {\n\t\tconst message = error?.message || \"Unknown error\";\n\t\treturn new ChannelError(ChannelErrorSource.Inbox, /* @__PURE__ */ new Error(`Failed to apply operations: ${message}`), classifyJobFailure(error?.name ?? \"Error\"));\n\t}\n\t/**\n\t* Where the next outbox derivation starts: at the evicted floor when there is\n\t* room to take those entries back, and at the caller's cursor otherwise.\n\t*\n\t* The floor is forgotten as it is folded in. If the refill overflows again the\n\t* eviction records a new one, and if it does not, the entries are queued and\n\t* the outbox itself holds the cursor down.\n\t*/\n\trefillOrdinal(remote, ackOrdinal) {\n\t\tconst floor = this.evictedOutboxFloors.get(remote.meta.name);\n\t\tif (floor === void 0) return ackOrdinal;\n\t\tif (this.outboxOperationCount(remote) >= this.config.maxHeldOperationsPerRemote) return ackOrdinal;\n\t\tthis.evictedOutboxFloors.delete(remote.meta.name);\n\t\treturn Math.min(ackOrdinal, floor - 1);\n\t}\n\t/**\n\t* Evicts the newest entries of an outbox that has grown past its bound.\n\t*\n\t* Only entries that have never been taken up for transport are eligible, which\n\t* is what makes this a bound on withheld work rather than a way to drop\n\t* something already in flight. One entry is always kept, so an outbox whose\n\t* first entry is larger than the whole cap still makes progress.\n\t*/\n\tevictPastOutboxBound(remote) {\n\t\tconst cap = this.config.maxHeldOperationsPerRemote;\n\t\tconst queued = remote.channel.outbox.items.filter((syncOp) => syncOp.status === SyncOperationStatus.Unknown).sort((a, b) => firstOrdinalOf(a) - firstOrdinalOf(b));\n\t\tlet kept = 0;\n\t\tlet cut = queued.length;\n\t\tfor (let i = 0; i < queued.length; i++) {\n\t\t\tconst size = queued[i].operations.length;\n\t\t\tif (i > 0 && kept + size > cap) {\n\t\t\t\tcut = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tkept += size;\n\t\t}\n\t\tconst evicted = queued.slice(cut);\n\t\tif (evicted.length === 0) return;\n\t\tconst floor = firstOrdinalOf(evicted[0]);\n\t\tconst known = this.evictedOutboxFloors.get(remote.meta.name);\n\t\tthis.evictedOutboxFloors.set(remote.meta.name, known === void 0 ? floor : Math.min(known, floor));\n\t\tthis.logger.warn(\"Outbox for @RemoteName is past its bound of @Cap operations; evicting @Count entries from ordinal @Floor, to be derived again once it drains\", remote.meta.name, cap, evicted.length, floor);\n\t\tremote.channel.outbox.remove(...evicted);\n\t}\n\toutboxOperationCount(remote) {\n\t\tlet count = 0;\n\t\tfor (const syncOp of remote.channel.outbox.items) count += syncOp.operations.length;\n\t\treturn count;\n\t}\n\tasync updateOutbox(remote, ackOrdinal, mode = OutboxMode.Backfill, signal) {\n\t\tconst composedSignal = signal ? AbortSignal.any([signal, this.abortController.signal]) : this.abortController.signal;\n\t\tconst startOrdinal = this.refillOrdinal(remote, ackOrdinal);\n\t\tlet maxOrdinal = startOrdinal;\n\t\tconst lastJobByDoc = /* @__PURE__ */ new Map();\n\t\tlet prevChainJobId;\n\t\tconst sinceTimestamp = remote.meta.options.sinceTimestampUtcMs;\n\t\tconst emitBatches = (operations) => {\n\t\t\tif (operations.length === 0) return;\n\t\t\tconst batches = batchOperationsByDocument(operations);\n\t\t\tconst syncOps = [];\n\t\t\tfor (const batch of batches) {\n\t\t\t\tconst jobId = crypto.randomUUID();\n\t\t\t\tconst prevJobId = lastJobByDoc.get(batch.documentId);\n\t\t\t\tconst deps = [];\n\t\t\t\tif (prevJobId) deps.push(prevJobId);\n\t\t\t\tif (mode === OutboxMode.BatchTriggered && prevChainJobId && prevChainJobId !== prevJobId) deps.push(prevChainJobId);\n\t\t\t\tconst syncOp = new SyncOperation(crypto.randomUUID(), jobId, deps, remote.meta.name, batch.documentId, [batch.scope], batch.branch, batch.operations);\n\t\t\t\tsyncOps.push(syncOp);\n\t\t\t\tlastJobByDoc.set(batch.documentId, jobId);\n\t\t\t\tif (mode === OutboxMode.BatchTriggered) prevChainJobId = jobId;\n\t\t\t}\n\t\t\tremote.channel.outbox.add(...syncOps);\n\t\t\tthis.evictPastOutboxBound(remote);\n\t\t};\n\t\tlet page = await this.operationIndex.find(remote.meta.collectionId.key, startOrdinal, { excludeSourceRemote: remote.meta.name }, void 0, composedSignal);\n\t\tlet carry = [];\n\t\tlet hasMore;\n\t\tdo {\n\t\t\tif (composedSignal.aborted) return;\n\t\t\tfor (const entry of page.results) maxOrdinal = Math.max(maxOrdinal, entry.ordinal ?? 0);\n\t\t\tlet operations = page.results.map((entry) => toOperationWithContext(entry));\n\t\t\tif (carry.length > 0) {\n\t\t\t\toperations = [...carry, ...operations];\n\t\t\t\tcarry = [];\n\t\t\t}\n\t\t\tif (sinceTimestamp && sinceTimestamp !== \"0\") operations = operations.filter((op) => op.operation.timestampUtcMs >= sinceTimestamp);\n\t\t\toperations = filterOperations(operations, remote.meta.filter);\n\t\t\toperations = operations.filter((op) => !this.quarantinedDocumentIds.has(op.context.documentId));\n\t\t\thasMore = !!page.next;\n\t\t\tif (operations.length > 0) {\n\t\t\t\tconst created = /* @__PURE__ */ new Set();\n\t\t\t\tfor (const entry of operations) if (entry.operation.action.type === \"CREATE_DOCUMENT\") created.add(entry.context.documentId);\n\t\t\t\toperations.sort((a, b) => {\n\t\t\t\t\tif (a.context.documentId !== b.context.documentId) return a.context.documentId < b.context.documentId ? -1 : 1;\n\t\t\t\t\tif (a.context.scope !== b.context.scope) {\n\t\t\t\t\t\tif (created.has(a.context.documentId)) {\n\t\t\t\t\t\t\tif (a.context.scope === \"document\") return -1;\n\t\t\t\t\t\t\tif (b.context.scope === \"document\") return 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn a.context.scope < b.context.scope ? -1 : 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn a.context.ordinal - b.context.ordinal;\n\t\t\t\t});\n\t\t\t\tif (hasMore) {\n\t\t\t\t\tconst split = splitTrailingSameTimestampRun(operations);\n\t\t\t\t\tcarry = split.carry;\n\t\t\t\t\temitBatches(split.emit);\n\t\t\t\t} else emitBatches(operations);\n\t\t\t}\n\t\t\tif (hasMore) page = await page.next();\n\t\t} while (hasMore);\n\t\tif (carry.length > 0) emitBatches(carry);\n\t\tremote.channel.outbox.advanceOrdinal(maxOrdinal);\n\t}\n};\n//#endregion\n//#region src/sync/sync-builder.ts\nvar SyncBuilder = class {\n\tchannelFactory;\n\tremoteStorage;\n\tcursorStorage;\n\tdeadLetterStorage;\n\tconfig = {};\n\twithChannelFactory(factory) {\n\t\tthis.channelFactory = factory;\n\t\treturn this;\n\t}\n\twithRemoteStorage(storage) {\n\t\tthis.remoteStorage = storage;\n\t\treturn this;\n\t}\n\twithCursorStorage(storage) {\n\t\tthis.cursorStorage = storage;\n\t\treturn this;\n\t}\n\twithDeadLetterStorage(storage) {\n\t\tthis.deadLetterStorage = storage;\n\t\treturn this;\n\t}\n\twithMaxDeadLettersPerRemote(limit) {\n\t\tthis.config.maxDeadLettersPerRemote = limit;\n\t\treturn this;\n\t}\n\twithMaxInboxBatchSize(limit) {\n\t\tthis.config.maxInboxBatchSize = limit;\n\t\treturn this;\n\t}\n\twithMaxHeldOperationsPerRemote(limit) {\n\t\tthis.config.maxHeldOperationsPerRemote = limit;\n\t\treturn this;\n\t}\n\tbuild(reactor, logger, operationIndex, eventBus, db, driveContainerTypes) {\n\t\treturn this.buildModule(reactor, logger, operationIndex, eventBus, db, driveContainerTypes).syncManager;\n\t}\n\tbuildModule(reactor, logger, operationIndex, eventBus, db, driveContainerTypes) {\n\t\tif (!this.channelFactory) throw new Error(\"Channel factory is required\");\n\t\tconst remoteStorage = this.remoteStorage ?? new KyselySyncRemoteStorage(db);\n\t\tconst cursorStorage = this.cursorStorage ?? new KyselySyncCursorStorage(db);\n\t\tconst deadLetterStorage = this.deadLetterStorage ?? new KyselySyncDeadLetterStorage(db);\n\t\tconst syncManager = new SyncManager(logger, remoteStorage, cursorStorage, deadLetterStorage, this.channelFactory, operationIndex, reactor, eventBus, driveContainerTypes, this.config);\n\t\treturn {\n\t\t\tremoteStorage,\n\t\t\tcursorStorage,\n\t\t\tdeadLetterStorage,\n\t\t\tchannelFactory: this.channelFactory,\n\t\t\tsyncManager\n\t\t};\n\t}\n};\n//#endregion\n//#region src/core/create-default-database.ts\nasync function createDefaultDatabase() {\n\tconst { Kysely } = await import(\"kysely\");\n\tconst { PGlite } = await import(\"@electric-sql/pglite\");\n\tconst { PGliteDialect } = await import(\"kysely-pglite-dialect\");\n\treturn new Kysely({ dialect: new PGliteDialect(new PGlite()) });\n}\n//#endregion\n//#region src/shared/factories.ts\n/**\n* Factory method to create a ShutdownStatus that can be updated\n*\n* @param initialState - Initial shutdown state (default: false)\n* @returns A tuple of [ShutdownStatus, setShutdown function, setCompleted function]\n*/\nfunction createMutableShutdownStatus(initialState = false) {\n\tlet shutdownState = initialState;\n\tlet completedPromise = Promise.resolve();\n\tconst status = {\n\t\tget isShutdown() {\n\t\t\treturn shutdownState;\n\t\t},\n\t\tget completed() {\n\t\t\treturn completedPromise;\n\t\t}\n\t};\n\tconst setShutdown = (value) => {\n\t\tshutdownState = value;\n\t};\n\tconst setCompleted = (promise) => {\n\t\tcompletedPromise = promise;\n\t};\n\treturn [\n\t\tstatus,\n\t\tsetShutdown,\n\t\tsetCompleted\n\t];\n}\n//#endregion\n//#region src/core/types.ts\nvar AbortError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message || \"Aborted\");\n\t\tthis.name = \"AbortError\";\n\t}\n};\n//#endregion\n//#region src/core/reactor.ts\n/**\n* This class implements the IReactor interface and serves as the main entry point\n* for the new Reactor architecture.\n*/\nvar Reactor = class {\n\tlogger;\n\tdocumentModelRegistry;\n\tshutdownStatus;\n\tsetShutdown;\n\tsetCompleted;\n\tqueue;\n\tjobTracker;\n\treadModelCoordinator;\n\tfeatures;\n\tdocumentView;\n\tdocumentIndexer;\n\toperationStore;\n\teventBus;\n\texecutorManager;\n\tconstructor(logger, documentModelRegistry, queue, jobTracker, readModelCoordinator, features, documentView, documentIndexer, operationStore, eventBus, executorManager) {\n\t\tthis.logger = logger;\n\t\tthis.documentModelRegistry = documentModelRegistry;\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.readModelCoordinator = readModelCoordinator;\n\t\tthis.features = features;\n\t\tthis.documentView = documentView;\n\t\tthis.documentIndexer = documentIndexer;\n\t\tthis.operationStore = operationStore;\n\t\tthis.eventBus = eventBus;\n\t\tthis.executorManager = executorManager;\n\t\tconst [status, setShutdown, setCompleted] = createMutableShutdownStatus(false);\n\t\tthis.shutdownStatus = status;\n\t\tthis.setShutdown = setShutdown;\n\t\tthis.setCompleted = setCompleted;\n\t\tthis.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, (_type, event) => {\n\t\t\tthis.logger.error(\"Job @JobId failed with @Message: @Job\", event.jobId, event.error.message, event.job);\n\t\t});\n\t\tthis.readModelCoordinator.start();\n\t}\n\tkill() {\n\t\tthis.logger.verbose(\"kill()\");\n\t\tif (this.shutdownStatus.isShutdown) return this.shutdownStatus;\n\t\tthis.setShutdown(true);\n\t\tconst shutdownAsync = async () => {\n\t\t\tawait this.executorManager.stop(true);\n\t\t\tthis.readModelCoordinator.stop();\n\t\t\tthis.jobTracker.shutdown();\n\t\t};\n\t\tthis.setCompleted(shutdownAsync());\n\t\treturn this.shutdownStatus;\n\t}\n\tgetDocumentModels(namespace, paging, signal) {\n\t\tthis.logger.verbose(\"getDocumentModels(@namespace, @paging)\", namespace, paging);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst filteredModels = this.documentModelRegistry.getAllModules().filter((module) => !namespace || module.documentModel.global.id.startsWith(namespace));\n\t\tconst startIndex = paging ? parseInt(paging.cursor) || 0 : 0;\n\t\tconst limit = paging?.limit || filteredModels.length;\n\t\tconst pagedModels = filteredModels.slice(startIndex, startIndex + limit);\n\t\tconst hasMore = startIndex + limit < filteredModels.length;\n\t\tconst nextCursor = hasMore ? String(startIndex + limit) : void 0;\n\t\treturn Promise.resolve({\n\t\t\tresults: pagedModels,\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: filteredModels.length\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.getDocumentModels(namespace, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t});\n\t}\n\tasync get(id, view, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"get(@id, @view)\", id, view);\n\t\treturn await this.documentView.get(id, view, consistencyToken, signal);\n\t}\n\tasync getBySlug(slug, view, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"getBySlug(@slug, @view)\", slug, view);\n\t\tconst documentId = await this.documentView.resolveSlug(slug, view, consistencyToken, signal);\n\t\tif (!documentId) throw new Error(`Document not found with slug: ${slug}`);\n\t\treturn await this.get(documentId, view, consistencyToken, signal);\n\t}\n\tasync getByIdOrSlug(identifier, view, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"getByIdOrSlug(@identifier, @view)\", identifier, view);\n\t\treturn await this.documentView.getByIdOrSlug(identifier, view, consistencyToken, signal);\n\t}\n\tasync getOutgoingRelationships(sourceId, relationshipType, consistencyToken, signal) {\n\t\tconst relationships = await this.documentIndexer.getOutgoing(sourceId, [relationshipType], void 0, consistencyToken, signal);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn relationships.results.map((rel) => rel.targetId);\n\t}\n\tasync getIncomingRelationships(targetId, relationshipType, consistencyToken, signal) {\n\t\tconst relationships = await this.documentIndexer.getIncoming(targetId, [relationshipType], void 0, consistencyToken, signal);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn relationships.results.map((rel) => rel.sourceId);\n\t}\n\tasync getOperations(documentId, view, filter, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"getOperations(@documentId, @view, @filter, @paging)\", documentId, view, filter, paging);\n\t\tconst branch = view?.branch || \"main\";\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst allScopes = Object.keys(revisions.revision);\n\t\tconst result = {};\n\t\tfor (const scope of allScopes) {\n\t\t\tif (!matchesScope(view, scope)) continue;\n\t\t\tthrowIfAborted(signal, () => new AbortError());\n\t\t\tconst scopeResult = await this.operationStore.getSince(documentId, scope, branch, -1, filter, paging, signal);\n\t\t\tresult[scope] = {\n\t\t\t\tresults: scopeResult.results,\n\t\t\t\toptions: scopeResult.options,\n\t\t\t\tnextCursor: scopeResult.nextCursor,\n\t\t\t\tnext: scopeResult.next ? async () => {\n\t\t\t\t\treturn (await this.getOperations(documentId, view, filter, {\n\t\t\t\t\t\tcursor: scopeResult.nextCursor,\n\t\t\t\t\t\tlimit: scopeResult.options.limit\n\t\t\t\t\t}, consistencyToken, signal))[scope];\n\t\t\t\t} : void 0\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n\tasync find(search, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"find(@search, @view, @paging)\", search, view, paging);\n\t\tlet results;\n\t\tif (search.ids) {\n\t\t\tif (search.slugs && search.slugs.length > 0) throw new Error(\"Cannot use both ids and slugs in the same search\");\n\t\t\tresults = await this.findByIds(search.ids, view, paging, consistencyToken, signal);\n\t\t\tif (search.type) results = filterByType(results, search.type);\n\t\t} else if (search.slugs) {\n\t\t\tresults = await this.findBySlugs(search.slugs, view, paging, consistencyToken, signal);\n\t\t\tif (search.type) results = filterByType(results, search.type);\n\t\t} else if (search.parentId) {\n\t\t\tresults = await this.findByParentId(search.parentId, view, paging, consistencyToken, signal);\n\t\t\tif (search.type) results = filterByType(results, search.type);\n\t\t} else if (search.type) results = await this.findByType(search.type, view, paging, consistencyToken, signal);\n\t\telse throw new Error(\"No search criteria provided\");\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn results;\n\t}\n\tasync create(document, signer, signal, meta) {\n\t\tthis.logger.verbose(\"create(@id, @type, @slug)\", document.header.id, document.header.documentType, document.header.slug);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet actions = [createDocumentAction({\n\t\t\tmodel: document.header.documentType,\n\t\t\tversion: 0,\n\t\t\tdocumentId: document.header.id,\n\t\t\tsigning: {\n\t\t\t\tsignature: document.header.id,\n\t\t\t\tpublicKey: document.header.sig.publicKey,\n\t\t\t\tnonce: document.header.sig.nonce,\n\t\t\t\tcreatedAtUtcIso: document.header.createdAtUtcIso,\n\t\t\t\tdocumentType: document.header.documentType\n\t\t\t},\n\t\t\tslug: document.header.slug,\n\t\t\tname: document.header.name,\n\t\t\tbranch: document.header.branch,\n\t\t\tmeta: document.header.meta,\n\t\t\tprotocolVersions: document.header.protocolVersions ?? { \"base-reducer\": 2 }\n\t\t}), upgradeDocumentAction({\n\t\t\tdocumentId: document.header.id,\n\t\t\tmodel: document.header.documentType,\n\t\t\tfromVersion: 0,\n\t\t\ttoVersion: normalizeDocumentModelVersion(document.state.document?.version),\n\t\t\tinitialState: document.state\n\t\t})];\n\t\tif (signer) actions = await signActions(actions, signer, signal);\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"mutation\",\n\t\t\tdocumentId: document.header.id,\n\t\t\tscope: \"document\",\n\t\t\tbranch: \"main\",\n\t\t\tactions,\n\t\t\toperations: [],\n\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\treturn jobInfo;\n\t}\n\tasync deleteDocument(id, signer, signal, meta) {\n\t\tthis.logger.verbose(\"deleteDocument(@id)\", id);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet action = deleteDocumentAction(id);\n\t\tif (signer) action = await signAction(action, signer, signal);\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"mutation\",\n\t\t\tdocumentId: id,\n\t\t\tscope: \"document\",\n\t\t\tbranch: \"main\",\n\t\t\tactions: [action],\n\t\t\toperations: [],\n\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\treturn jobInfo;\n\t}\n\tasync execute(docId, branch, actions, signal, meta) {\n\t\tthis.logger.verbose(\"execute(@docId, @branch, @actions)\", docId, branch, actions);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst scope = getSharedActionScope(actions);\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"mutation\",\n\t\t\tdocumentId: docId,\n\t\t\tscope,\n\t\t\tbranch,\n\t\t\tactions,\n\t\t\toperations: [],\n\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn jobInfo;\n\t}\n\tasync load(docId, branch, operations, signal, meta) {\n\t\tthis.logger.verbose(\"load(@docId, @branch, @count, @operations)\", docId, branch, operations.length, operations);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tif (operations.length === 0) throw new Error(\"load requires at least one operation\");\n\t\tconst scope = getSharedOperationScope(operations);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"load\",\n\t\t\tdocumentId: docId,\n\t\t\tscope,\n\t\t\tbranch,\n\t\t\tactions: [],\n\t\t\toperations,\n\t\t\tcreatedAt: createdAtUtcIso,\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn jobInfo;\n\t}\n\tasync executeBatch(request, signal, meta) {\n\t\tthis.logger.verbose(\"executeBatch(@count jobs)\", request.jobs.length);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tvalidateBatchRequest(request.jobs);\n\t\tfor (const jobPlan of request.jobs) validateActionScopes(jobPlan);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst planKeyToJobId = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) planKeyToJobId.set(jobPlan.key, v4());\n\t\tconst batchId = v4();\n\t\tconst batchJobIds = [...planKeyToJobId.values()];\n\t\tconst batchMeta = {\n\t\t\t...meta,\n\t\t\tbatchId,\n\t\t\tbatchJobIds\n\t\t};\n\t\tconst jobInfos = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) {\n\t\t\tconst jobInfo = {\n\t\t\t\tid: planKeyToJobId.get(jobPlan.key),\n\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\tstatus: JobStatus.PENDING,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tconsistencyToken: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcreatedAtUtcIso,\n\t\t\t\t\tcoordinates: []\n\t\t\t\t},\n\t\t\t\tmeta: batchMeta\n\t\t\t};\n\t\t\tthis.jobTracker.registerJob(jobInfo);\n\t\t\tthis.emitJobPending(jobInfo.id, batchMeta);\n\t\t\tjobInfos.set(jobPlan.key, jobInfo);\n\t\t}\n\t\tconst sortedKeys = topologicalSort(request.jobs);\n\t\tconst enqueuedKeys = [];\n\t\ttry {\n\t\t\tfor (const key of sortedKeys) {\n\t\t\t\tthrowIfAborted(signal, () => new AbortError());\n\t\t\t\tconst jobPlan = request.jobs.find((j) => j.key === key);\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\tconst queueHint = jobPlan.dependsOn.map((depKey) => planKeyToJobId.get(depKey));\n\t\t\t\tconst job = {\n\t\t\t\t\tid: jobId,\n\t\t\t\t\tkind: \"mutation\",\n\t\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\t\tscope: jobPlan.scope,\n\t\t\t\t\tbranch: jobPlan.branch,\n\t\t\t\t\tactions: jobPlan.actions,\n\t\t\t\t\toperations: [],\n\t\t\t\t\tcreatedAt: createdAtUtcIso,\n\t\t\t\t\tqueueHint,\n\t\t\t\t\tmaxRetries: 3,\n\t\t\t\t\terrorHistory: [],\n\t\t\t\t\tmeta: batchMeta\n\t\t\t\t};\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t\tenqueuedKeys.push(key);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfor (const key of enqueuedKeys) {\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\ttry {\n\t\t\t\t\tawait this.queue.remove(jobId);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tfor (const jobInfo of jobInfos.values()) this.jobTracker.markFailed(jobInfo.id, toErrorInfo$1(\"Batch enqueue failed\"));\n\t\t\tthrow error;\n\t\t}\n\t\treturn { jobs: Object.fromEntries(jobInfos) };\n\t}\n\tasync loadBatch(request, signal, meta) {\n\t\tthis.logger.verbose(\"loadBatch(@count jobs)\", request.jobs.length);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tvalidateBatchLoadRequest(request.jobs);\n\t\tfor (const jobPlan of request.jobs) validateOperationScopes(jobPlan);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst planKeyToJobId = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) planKeyToJobId.set(jobPlan.key, v4());\n\t\tconst batchId = v4();\n\t\tconst batchJobIds = [...planKeyToJobId.values()];\n\t\tconst batchMeta = {\n\t\t\t...meta,\n\t\t\tbatchId,\n\t\t\tbatchJobIds\n\t\t};\n\t\tconst jobInfos = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) {\n\t\t\tconst jobInfo = {\n\t\t\t\tid: planKeyToJobId.get(jobPlan.key),\n\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\tstatus: JobStatus.PENDING,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tconsistencyToken: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcreatedAtUtcIso,\n\t\t\t\t\tcoordinates: []\n\t\t\t\t},\n\t\t\t\tmeta: batchMeta\n\t\t\t};\n\t\t\tthis.jobTracker.registerJob(jobInfo);\n\t\t\tthis.emitJobPending(jobInfo.id, batchMeta);\n\t\t\tjobInfos.set(jobPlan.key, jobInfo);\n\t\t}\n\t\tconst sortedKeys = topologicalSort(request.jobs);\n\t\tconst enqueuedKeys = [];\n\t\ttry {\n\t\t\tfor (const key of sortedKeys) {\n\t\t\t\tthrowIfAborted(signal, () => new AbortError());\n\t\t\t\tconst jobPlan = request.jobs.find((j) => j.key === key);\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\tconst queueHint = [...jobPlan.dependsOn.map((depKey) => planKeyToJobId.get(depKey)), ...jobPlan.externalDeps];\n\t\t\t\tconst job = {\n\t\t\t\t\tid: jobId,\n\t\t\t\t\tkind: \"load\",\n\t\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\t\tscope: jobPlan.scope,\n\t\t\t\t\tbranch: jobPlan.branch,\n\t\t\t\t\tactions: [],\n\t\t\t\t\toperations: jobPlan.operations,\n\t\t\t\t\tcreatedAt: createdAtUtcIso,\n\t\t\t\t\tqueueHint,\n\t\t\t\t\tmaxRetries: 3,\n\t\t\t\t\terrorHistory: [],\n\t\t\t\t\tmeta: batchMeta\n\t\t\t\t};\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t\tenqueuedKeys.push(key);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfor (const key of enqueuedKeys) {\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\ttry {\n\t\t\t\t\tawait this.queue.remove(jobId);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tfor (const jobInfo of jobInfos.values()) this.jobTracker.markFailed(jobInfo.id, toErrorInfo$1(\"Batch enqueue failed\"));\n\t\t\tthrow error;\n\t\t}\n\t\treturn { jobs: Object.fromEntries(jobInfos) };\n\t}\n\tasync addRelationship(sourceId, targetId, relationshipType, branch = \"main\", signer, signal) {\n\t\tthis.logger.verbose(\"addRelationship(@sourceId, @targetId, @relationshipType, @branch)\", sourceId, targetId, relationshipType, branch);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet actions = [addRelationshipAction(sourceId, targetId, relationshipType)];\n\t\tif (signer) actions = await signActions(actions, signer, signal);\n\t\treturn await this.execute(sourceId, branch, actions, signal);\n\t}\n\tasync removeRelationship(sourceId, targetId, relationshipType, branch = \"main\", signer, signal) {\n\t\tthis.logger.verbose(\"removeRelationship(@sourceId, @targetId, @relationshipType, @branch)\", sourceId, targetId, relationshipType, branch);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet actions = [removeRelationshipAction(sourceId, targetId, relationshipType)];\n\t\tif (signer) actions = await signActions(actions, signer, signal);\n\t\treturn await this.execute(sourceId, branch, actions, signal);\n\t}\n\tgetJobStatus(jobId, signal) {\n\t\tthis.logger.verbose(\"getJobStatus(@jobId)\", jobId);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst jobInfo = this.jobTracker.getJobStatus(jobId);\n\t\tif (!jobInfo) {\n\t\t\tconst now = (/* @__PURE__ */ new Date()).toISOString();\n\t\t\treturn Promise.resolve({\n\t\t\t\tid: jobId,\n\t\t\t\tdocumentId: \"\",\n\t\t\t\tstatus: JobStatus.FAILED,\n\t\t\t\tcreatedAtUtcIso: now,\n\t\t\t\tcompletedAtUtcIso: now,\n\t\t\t\terror: toErrorInfo$1(\"Job not found\"),\n\t\t\t\tconsistencyToken: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcreatedAtUtcIso: now,\n\t\t\t\t\tcoordinates: []\n\t\t\t\t},\n\t\t\t\tmeta: {\n\t\t\t\t\tbatchId: jobId,\n\t\t\t\t\tbatchJobIds: [jobId]\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn Promise.resolve(jobInfo);\n\t}\n\tasync findByIds(ids, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findByIds(@count ids)\", ids.length);\n\t\tconst startIndex = paging?.cursor ? parseInt(paging.cursor) || 0 : 0;\n\t\tconst limit = paging?.limit || ids.length;\n\t\tconst pagedIds = ids.slice(startIndex, startIndex + limit);\n\t\tconst results = await this.documentView.getMany(pagedIds, view, consistencyToken, signal);\n\t\tconst nextCursor = startIndex + limit < ids.length ? String(startIndex + limit) : void 0;\n\t\treturn {\n\t\t\tresults,\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: ids.length\n\t\t\t},\n\t\t\tnextCursor\n\t\t};\n\t}\n\tasync findBySlugs(slugs, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findBySlugs(@count slugs)\", slugs.length);\n\t\tconst ids = await this.documentView.resolveSlugs(slugs, view, consistencyToken, signal);\n\t\treturn await this.findByIds(ids, view, paging, consistencyToken, signal);\n\t}\n\tasync findByParentId(parentId, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findByParentId(@parentId)\", parentId);\n\t\tconst ids = (await this.documentIndexer.getOutgoing(parentId, [\"child\"], paging, consistencyToken, signal)).results.map((rel) => rel.targetId);\n\t\treturn await this.findByIds(ids, view, paging, void 0, signal);\n\t}\n\tasync findByType(type, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findByType(@type)\", type);\n\t\treturn await this.documentView.findByType(type, view, paging, consistencyToken, signal);\n\t}\n\temitJobPending(jobId, meta) {\n\t\tconst event = {\n\t\t\tjobId,\n\t\t\tjobMeta: meta\n\t\t};\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_PENDING, event).catch(() => {});\n\t}\n};\n//#endregion\n//#region src/core/reactor-builder.ts\nfunction sameDatabaseTarget(a, b) {\n\treturn a.host === b.host && a.port === b.port && a.database === b.database;\n}\n/**\n* Requires each built-in kind exactly once across both lists. A kind in\n* neither list is indexed by nobody (host copies never index under a\n* worker), so its reads go stale and its consistency-token waits never\n* resolve; a kind in both is indexed twice per operation.\n*/\nfunction validateBuiltInKindCoverage(preReadyKinds, postReadyKinds) {\n\tconst named = [...preReadyKinds, ...postReadyKinds];\n\tconst missing = BUILT_IN_READ_MODEL_KINDS.filter((kind) => !named.includes(kind));\n\tconst duplicated = BUILT_IN_READ_MODEL_KINDS.filter((kind) => named.filter((entry) => entry === kind).length > 1);\n\tif (missing.length === 0 && duplicated.length === 0) return;\n\tconst problems = [missing.length > 0 ? `never named: ${missing.join(\", \")} (would be indexed by no shard, leaving those reads permanently stale and their consistency-token waits unresolvable)` : void 0, duplicated.length > 0 ? `named more than once: ${duplicated.join(\", \")} (would be indexed twice per operation)` : void 0].filter((problem) => problem !== void 0);\n\tthrow new Error(`withProjectionShards requires preReadyKinds and postReadyKinds to name each built-in read model (${BUILT_IN_READ_MODEL_KINDS.join(\", \")}) exactly once between them; ${problems.join(\"; \")}`);\n}\nvar ReactorBuilder = class {\n\tlogger;\n\tdocumentModelSources = [];\n\tupgradeManifests = [];\n\tfeatures = {\n\t\tlegacyStorageEnabled: false,\n\t\tlegacyProcessorIds: true\n\t};\n\treadModels = [];\n\treadModelFactories = [];\n\texecutorManager;\n\texecutorConfig = {};\n\twriteCacheConfig;\n\tmigrationStrategy = \"auto\";\n\tsyncBuilder;\n\teventBus;\n\treadModelCoordinator;\n\treadModelCoordinatorFactory;\n\tsignatureVerifier;\n\tkyselyInstance;\n\tsignalHandlersEnabled = false;\n\tqueueInstance;\n\tchannelScheme;\n\tjwtHandler;\n\tdocumentModelLoader;\n\tshutdownHooks = [];\n\tdriveContainerTypes = DEFAULT_DRIVE_CONTAINER_TYPES;\n\tworkerPool;\n\tresolvedModelManifest;\n\tmoduleOnlyModelKeys = [];\n\tprojectionShardConfig;\n\tprojectionWorkerFactory;\n\tinstrumentedPools = [];\n\twithLogger(logger) {\n\t\tthis.logger = logger;\n\t\treturn this;\n\t}\n\t/**\n\t* Register document-model sources: live modules, importable files, or\n\t* importable packages. Appends across calls. At `buildModule()` every\n\t* source is resolved host-side and registered on the registry; file and\n\t* package sources additionally form the worker manifest when the worker\n\t* pool is enabled (live modules cannot cross a thread boundary).\n\t*/\n\twithDocumentModelSources(sources) {\n\t\tthis.documentModelSources.push(...sources);\n\t\treturn this;\n\t}\n\twithUpgradeManifests(manifests) {\n\t\tthis.upgradeManifests = manifests;\n\t\treturn this;\n\t}\n\twithFeatures(features) {\n\t\tthis.features = {\n\t\t\t...this.features,\n\t\t\t...features\n\t\t};\n\t\treturn this;\n\t}\n\twithReadModel(readModel) {\n\t\tthis.readModels.push(readModel);\n\t\treturn this;\n\t}\n\t/**\n\t* Register a factory that builds a pre-ready read model after the reactor's\n\t* internal `operationIndex`, `writeCache`, and processor-manager consistency\n\t* tracker are constructed. Use this for read models (e.g. `BaseReadModel`\n\t* subclasses) that need those dependencies and therefore cannot be built\n\t* before calling `buildModule()`.\n\t*/\n\twithReadModelFactory(factory) {\n\t\tthis.readModelFactories.push(factory);\n\t\treturn this;\n\t}\n\twithReadModelCoordinator(readModelCoordinator) {\n\t\tthis.readModelCoordinator = readModelCoordinator;\n\t\treturn this;\n\t}\n\t/**\n\t* Register a factory that builds the coordinator once the subscription\n\t* read model, processor manager and host read models exist. Use this, not\n\t* `withReadModelCoordinator`, for coordinators that compose those internals.\n\t*/\n\twithReadModelCoordinatorFactory(factory) {\n\t\tthis.readModelCoordinatorFactory = factory;\n\t\treturn this;\n\t}\n\twithExecutor(executor) {\n\t\tthis.executorManager = executor;\n\t\treturn this;\n\t}\n\twithExecutorConfig(config) {\n\t\tthis.executorConfig = {\n\t\t\t...this.executorConfig,\n\t\t\t...config\n\t\t};\n\t\treturn this;\n\t}\n\twithWriteCacheConfig(config) {\n\t\tthis.writeCacheConfig = config;\n\t\treturn this;\n\t}\n\twithDriveContainerTypes(types) {\n\t\tthis.driveContainerTypes = new Set(types);\n\t\treturn this;\n\t}\n\twithMigrationStrategy(strategy) {\n\t\tthis.migrationStrategy = strategy;\n\t\treturn this;\n\t}\n\twithSync(syncBuilder) {\n\t\tthis.syncBuilder = syncBuilder;\n\t\treturn this;\n\t}\n\twithEventBus(eventBus) {\n\t\tthis.eventBus = eventBus;\n\t\treturn this;\n\t}\n\twithSignatureVerifier(verifier) {\n\t\tthis.signatureVerifier = verifier;\n\t\treturn this;\n\t}\n\twithKysely(kysely) {\n\t\tthis.kyselyInstance = kysely;\n\t\treturn this;\n\t}\n\t/**\n\t* Register an externally-constructed pg.Pool's {@link PoolInstrumentation}\n\t* so it surfaces through {@link ReactorModule.pools}. Use this when the\n\t* caller built the pool itself (e.g. the in-process bench host wiring) so\n\t* pool acquire-wait and pool-stat metrics still emit. The builder also\n\t* registers any pool it constructs internally via {@link createPostgresDatabase}.\n\t*/\n\twithInstrumentedPool(instrumentation) {\n\t\tthis.instrumentedPools.push(instrumentation);\n\t\treturn this;\n\t}\n\twithQueue(queue) {\n\t\tthis.queueInstance = queue;\n\t\treturn this;\n\t}\n\twithChannelScheme(scheme) {\n\t\tthis.channelScheme = scheme;\n\t\treturn this;\n\t}\n\twithJwtHandler(handler) {\n\t\tthis.jwtHandler = handler;\n\t\treturn this;\n\t}\n\twithDocumentModelLoader(loader) {\n\t\tthis.documentModelLoader = loader;\n\t\treturn this;\n\t}\n\twithSignalHandlers() {\n\t\tthis.signalHandlersEnabled = true;\n\t\treturn this;\n\t}\n\t/**\n\t* Register an async cleanup hook to run during graceful shutdown. Hooks fire\n\t* after `reactor.kill()` resolves and before `database.destroy()`, so callers\n\t* that depend on the reactor (e.g. an HTTP API layered on top) can drain\n\t* cleanly before the underlying kysely instance is torn down. Hook errors are\n\t* logged and otherwise ignored — one bad hook cannot strand the rest of the\n\t* shutdown chain.\n\t*/\n\twithShutdownHook(hook) {\n\t\tthis.shutdownHooks.push(hook);\n\t\treturn this;\n\t}\n\t/**\n\t* Enable the executor worker pool: N `node:worker_threads` workers with\n\t* sticky per-document routing, replacing the in-process executor. Calling\n\t* this enables the pool — there is no `enabled` flag. Provide `db`\n\t* (each worker opens its own Postgres pool; the parent database is built\n\t* from it too unless {@link withKysely} is set) or a custom `factory`\n\t* transport. `verifier` is imported by the default transport's workers;\n\t* omitted = no executor-side signature verification.\n\t*/\n\twithWorkerPool(options) {\n\t\tthis.workerPool = options;\n\t\treturn this;\n\t}\n\t/**\n\t* Configure N sharded projection workers. When set, the builder replaces\n\t* the default in-process {@link ReadModelCoordinator} with a\n\t* {@link ProjectionShardManager}.\n\t*\n\t* Projection workers open their own Postgres pools from `config.db`,\n\t* falling back to the executor worker pool's `db` when\n\t* {@link withWorkerPool} is configured with one; only the `poolSize` is\n\t* overridden by {@link ProjectionShardBuilderConfig.poolSize}. The same\n\t* model manifest resolved from {@link withDocumentModelSources} is\n\t* forwarded.\n\t*/\n\twithProjectionShards(config) {\n\t\tthis.projectionShardConfig = config;\n\t\treturn this;\n\t}\n\t/**\n\t* Inject a custom {@link ProjectionWorkerFactory}. When set, the builder\n\t* skips default thread-transport wiring for the projection shards and\n\t* hands the factory directly to {@link ProjectionShardManager}.\n\t*/\n\twithProjectionWorkerFactory(factory) {\n\t\tthis.projectionWorkerFactory = factory;\n\t\treturn this;\n\t}\n\tgetResolvedModelManifest() {\n\t\treturn this.resolvedModelManifest;\n\t}\n\tasync build() {\n\t\treturn (await this.buildModule()).reactor;\n\t}\n\tasync buildModule() {\n\t\tif (!this.logger) this.logger = new ConsoleLogger([\"reactor\"]);\n\t\tconst featureFlags = resolveFeatureFlags(this.executorConfig.featureFlags);\n\t\tif (this.readModelCoordinator !== void 0 && this.readModelCoordinatorFactory !== void 0) throw new Error(\"withReadModelCoordinator and withReadModelCoordinatorFactory are mutually exclusive; register one coordinator source\");\n\t\tif (this.projectionShardConfig !== void 0 && this.readModelCoordinatorFactory !== void 0) throw new Error(\"withProjectionShards and withReadModelCoordinatorFactory are mutually exclusive; the factory owns the projection worker through its createProjectionShardManager dependency\");\n\t\tif (this.projectionShardConfig !== void 0 && this.readModelFactories.length > 0) throw new Error(\"withProjectionShards does not support read models registered through withReadModelFactory; projection workers cannot receive host-only factory dependencies\");\n\t\tif (this.projectionShardConfig !== void 0 && this.readModels.length > 0) throw new Error(\"withProjectionShards does not support read models registered through withReadModel; projection workers build their own read models from the shard config and would silently omit these\");\n\t\tif (this.projectionShardConfig !== void 0) validateBuiltInKindCoverage(this.projectionShardConfig.preReadyKinds, this.projectionShardConfig.postReadyKinds);\n\t\tconst resolvedSources = await resolveModelSources(this.documentModelSources);\n\t\tif (this.workerPool) {\n\t\t\tif (resolvedSources.manifest.length === 0) throw new Error(\"withWorkerPool requires at least one worker-importable document-model source ({ filePath } or { packageName }).\");\n\t\t\tif (resolvedSources.moduleOnlyKeys.length > 0) throw new Error(`withWorkerPool requires worker-importable sources, but these models were registered only as live modules: ${resolvedSources.moduleOnlyKeys.join(\", \")}. Provide a { filePath } or { packageName } source for each.`);\n\t\t}\n\t\tthis.resolvedModelManifest = resolvedSources.manifest.length > 0 ? resolvedSources.manifest : void 0;\n\t\tthis.moduleOnlyModelKeys = resolvedSources.moduleOnlyKeys;\n\t\tconst documentModelRegistry = new DocumentModelRegistry();\n\t\tif (this.upgradeManifests.length > 0) {\n\t\t\tconst results = documentModelRegistry.registerUpgradeManifests(...this.upgradeManifests);\n\t\t\tfor (const result of results) if (result.status === \"error\") this.logger.error(\"Failed to register upgrade manifest: @error\", result.error.message);\n\t\t}\n\t\tif (resolvedSources.modules.length > 0) {\n\t\t\tconst results = documentModelRegistry.registerModules(...resolvedSources.modules);\n\t\t\tfor (const result of results) if (result.status === \"error\") this.logger.error(\"Failed to register document model: @error\", result.error.message);\n\t\t}\n\t\tconst reactorDbConfig = this.resolveReactorDbConfig();\n\t\tconst baseDatabase = this.kyselyInstance ?? (reactorDbConfig ? await this.createPostgresDatabase(reactorDbConfig) : await createDefaultDatabase());\n\t\tif (this.migrationStrategy === \"auto\") {\n\t\t\tconst result = await runMigrations(baseDatabase, REACTOR_SCHEMA);\n\t\t\tif (!result.success && result.error) throw new Error(`Database migration failed: ${result.error.message}`);\n\t\t}\n\t\tconst database = baseDatabase.withSchema(REACTOR_SCHEMA);\n\t\tconst operationStore = new KyselyOperationStore(database);\n\t\tconst keyframeStore = new KyselyKeyframeStore(database);\n\t\tconst eventBus = this.eventBus || new EventBus();\n\t\tconst resolver = this.documentModelLoader ? new DocumentModelResolver(documentModelRegistry, this.documentModelLoader) : new NullDocumentModelResolver(documentModelRegistry);\n\t\tif (resolver instanceof DocumentModelResolver) resolver.setModelLoadedHook((documentType) => eventBus.emit(ReactorEventTypes.MODEL_LOADED, { documentType }));\n\t\tconst queue = this.queueInstance ?? new InMemoryQueue(eventBus, resolver);\n\t\tconst jobTracker = new InMemoryJobTracker(eventBus);\n\t\tconst writeCache = new KyselyWriteCache(keyframeStore, operationStore, documentModelRegistry, {\n\t\t\tmaxDocuments: this.writeCacheConfig?.maxDocuments ?? 100,\n\t\t\tringBufferSize: this.writeCacheConfig?.ringBufferSize ?? 10,\n\t\t\tkeyframeInterval: this.writeCacheConfig?.keyframeInterval ?? 10\n\t\t});\n\t\tawait writeCache.startup();\n\t\tconst operationIndex = new KyselyOperationIndex(database);\n\t\tconst documentMetaCache = new DocumentMetaCache(operationStore, { maxDocuments: 1e3 });\n\t\tawait documentMetaCache.startup();\n\t\tconst collectionMembershipCache = new CollectionMembershipCache(operationIndex);\n\t\tconst executionScope = new KyselyExecutionScope(database, operationStore, operationIndex, keyframeStore, writeCache, documentMetaCache, collectionMembershipCache);\n\t\tlet executorManager = this.executorManager;\n\t\tlet executorStartCount = this.executorConfig.maxConcurrency ?? 1;\n\t\tif (!executorManager) if (this.workerPool) {\n\t\t\tconst pool = this.workerPool;\n\t\t\tlet factory = pool.factory;\n\t\t\tif (!factory) {\n\t\t\t\tif (pool.db === void 0) throw new Error(\"unreachable: worker pool configured without db or factory\");\n\t\t\t\tfactory = await this.createDefaultWorkerFactory(pool.numWorkers, pool.db, pool.verifier);\n\t\t\t}\n\t\t\tconst poolManager = new WorkerPoolJobExecutorManager(factory, eventBus, queue, jobTracker, this.logger, resolver, operationIndex, this.executorConfig.jobTimeoutMs, this.executorConfig.deferredJobTtlMs);\n\t\t\texecutorManager = poolManager;\n\t\t\texecutorStartCount = pool.numWorkers;\n\t\t\tif (resolver instanceof DocumentModelResolver) resolver.setBroadcastHook((entry) => poolManager.loadModel(entry));\n\t\t} else executorManager = new SimpleJobExecutorManager(() => new SimpleJobExecutor(this.logger, documentModelRegistry, operationStore, eventBus, writeCache, operationIndex, documentMetaCache, collectionMembershipCache, this.driveContainerTypes, this.executorConfig, this.signatureVerifier, executionScope), eventBus, queue, jobTracker, this.logger, resolver, this.executorConfig.jobTimeoutMs, this.executorConfig.deferredJobTtlMs);\n\t\tawait executorManager.start(executorStartCount);\n\t\tconst callerReadModels = Array.from(new Set([...this.readModels]));\n\t\tconst documentViewConsistencyTracker = new ConsistencyTracker();\n\t\tconst documentView = new KyselyDocumentView(database, operationStore, operationIndex, writeCache, documentViewConsistencyTracker, featureFlags.documentDecisions);\n\t\ttry {\n\t\t\tawait documentView.init();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error initializing document view\", error);\n\t\t}\n\t\tconst documentIndexerConsistencyTracker = new ConsistencyTracker();\n\t\tconst documentIndexer = new KyselyDocumentIndexer(database, operationIndex, writeCache, documentIndexerConsistencyTracker);\n\t\ttry {\n\t\t\tawait documentIndexer.init();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error initializing document indexer\", error);\n\t\t}\n\t\tconst subscriptionManager = new ReactorSubscriptionManager(new DefaultSubscriptionErrorHandler());\n\t\tconst subscriptionNotificationReadModel = new SubscriptionNotificationReadModel(subscriptionManager, documentView);\n\t\tconst processorManagerConsistencyTracker = new ConsistencyTracker();\n\t\tconst processorManager = new ProcessorManager(database, operationIndex, writeCache, processorManagerConsistencyTracker, this.logger, this.driveContainerTypes, { legacyProcessorIds: this.features.legacyProcessorIds !== false });\n\t\ttry {\n\t\t\tawait processorManager.init();\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error initializing processor manager\", error);\n\t\t}\n\t\tfor (const factory of this.readModelFactories) {\n\t\t\tconst readModel = await factory({\n\t\t\t\tdocumentModelRegistry,\n\t\t\t\toperationIndex,\n\t\t\t\twriteCache,\n\t\t\t\tprocessorManagerConsistencyTracker\n\t\t\t});\n\t\t\tcallerReadModels.push(readModel);\n\t\t}\n\t\tconst readModelInstances = [\n\t\t\t...callerReadModels,\n\t\t\tdocumentView,\n\t\t\tdocumentIndexer\n\t\t];\n\t\tconst hostTrackers = {\n\t\t\t\"document-view\": documentViewConsistencyTracker,\n\t\t\t\"document-indexer\": documentIndexerConsistencyTracker\n\t\t};\n\t\tconst readModelCoordinator = this.readModelCoordinator ? this.readModelCoordinator : this.readModelCoordinatorFactory ? await this.readModelCoordinatorFactory({\n\t\t\teventBus,\n\t\t\tlogger: this.logger,\n\t\t\treadModels: callerReadModels,\n\t\t\tsubscriptionNotificationReadModel,\n\t\t\tprocessorManager,\n\t\t\tdocumentView,\n\t\t\tdocumentIndexer,\n\t\t\tcreateProjectionShardManager: (config) => this.createProjectionShardManager(config, eventBus, hostTrackers, false),\n\t\t\tregisterShutdownHook: (hook) => this.shutdownHooks.push(hook)\n\t\t}) : this.projectionShardConfig ? await this.createProjectionShardManager(this.projectionShardConfig, eventBus, hostTrackers, true) : new ReadModelCoordinator(eventBus, readModelInstances, [subscriptionNotificationReadModel, processorManager]);\n\t\tconst reactor = new Reactor(this.logger, documentModelRegistry, queue, jobTracker, readModelCoordinator, this.features, documentView, documentIndexer, operationStore, eventBus, executorManager);\n\t\tlet syncModule = void 0;\n\t\tif (this.channelScheme) {\n\t\t\tconst factory = this.channelScheme === ChannelScheme.CONNECT ? new GqlRequestChannelFactory(this.logger, this.jwtHandler, queue) : new GqlResponseChannelFactory(this.logger);\n\t\t\tsyncModule = new SyncBuilder().withChannelFactory(factory).buildModule(reactor, this.logger, operationIndex, eventBus, database, this.driveContainerTypes);\n\t\t\tawait syncModule.syncManager.startup();\n\t\t} else if (this.syncBuilder) {\n\t\t\tsyncModule = this.syncBuilder.buildModule(reactor, this.logger, operationIndex, eventBus, database, this.driveContainerTypes);\n\t\t\tawait syncModule.syncManager.startup();\n\t\t}\n\t\tlet groupReevaluationTrigger;\n\t\tif (featureFlags.authGroups) {\n\t\t\tgroupReevaluationTrigger = new GroupReevaluationTrigger(this.logger, eventBus, queue, operationIndex);\n\t\t\tgroupReevaluationTrigger.startup();\n\t\t}\n\t\tconst module = {\n\t\t\teventBus,\n\t\t\tdocumentModelRegistry,\n\t\t\tfeatureFlags,\n\t\t\tqueue,\n\t\t\tjobTracker,\n\t\t\texecutorManager,\n\t\t\tdatabase,\n\t\t\toperationStore,\n\t\t\tkeyframeStore,\n\t\t\twriteCache,\n\t\t\toperationIndex,\n\t\t\tdocumentView,\n\t\t\tdocumentViewConsistencyTracker,\n\t\t\tdocumentIndexer,\n\t\t\tdocumentIndexerConsistencyTracker,\n\t\t\treadModelCoordinator,\n\t\t\tsubscriptionManager,\n\t\t\tprocessorManager,\n\t\t\tprocessorManagerConsistencyTracker,\n\t\t\tsyncModule,\n\t\t\treactor,\n\t\t\tgroupReevaluationTrigger,\n\t\t\tpools: this.instrumentedPools\n\t\t};\n\t\tif (this.signalHandlersEnabled) this.attachSignalHandlers(module);\n\t\treturn module;\n\t}\n\t/**\n\t* The single Postgres config for the parent, executor workers, and\n\t* projection shards. They must share one physical database (the parent\n\t* writes operations; workers and shards read them), so divergent\n\t* worker/shard targets throw. `withKysely` overrides the parent and is not\n\t* validated against a worker/shard `db`.\n\t*/\n\tresolveReactorDbConfig() {\n\t\tconst workerDb = this.workerPool?.db;\n\t\tconst projectionDb = this.projectionShardConfig?.db;\n\t\tif (workerDb && projectionDb && !sameDatabaseTarget(workerDb, projectionDb)) throw new Error(\"withWorkerPool({ db }) and withProjectionShards({ db }) must address the same Postgres database (same host, port, and database); the parent writes operations there and the projection shards read them.\");\n\t\treturn workerDb ?? projectionDb;\n\t}\n\t/**\n\t* Constructs a {@link ProjectionShardManager} bound to the host event\n\t* bus. Builds the default thread-transport factory unless one was\n\t* injected via {@link withProjectionWorkerFactory}. Calls\n\t* `manager.startup()` so all N workers reach READY before the reactor\n\t* is returned to the caller.\n\t*\n\t* @param consistencyTrackers The host's trackers for the built-in read\n\t* models, keyed by kind. Under sharding the host's own copies of those\n\t* models never index an operation, so the manager advances these from the\n\t* shards' relayed indexing reports; without them every read carrying a\n\t* consistency token waits forever.\n\t* @param registerShutdownHook Whether the builder owns `manager.shutdown()`\n\t* at signal time. False for the coordinator-factory path, whose factory\n\t* registers its own hook so host chains drain before the worker stops.\n\t*/\n\tasync createProjectionShardManager(config, eventBus, consistencyTrackers, registerShutdownHook) {\n\t\tconst parentDb = this.resolveReactorDbConfig();\n\t\tconst baseDb = config.db ?? parentDb;\n\t\tconst caller = this.projectionShardConfig !== void 0 ? \"withProjectionShards\" : \"withReadModelCoordinatorFactory\";\n\t\tif (!baseDb) throw new Error(`${caller} requires a db (or an executor worker pool configured with one); projection workers need connection info to open their own pools.`);\n\t\tconst workerDb = this.workerPool?.db;\n\t\tif (config.db && workerDb && !sameDatabaseTarget(workerDb, config.db)) throw new Error(\"withWorkerPool({ db }) and the projection worker db must address the same Postgres database (same host, port, and database); the parent writes operations there and the projection shards read them.\");\n\t\tif (config.db && this.kyselyInstance === void 0) {\n\t\t\tif (!parentDb) throw new Error(`The projection worker db passed to ${caller} must also be the parent reactor's database, but nothing configures the parent: it would fall back to the default embedded database while the worker projects into Postgres. Pass the same { db } to withWorkerPool, or give the parent its connection with withKysely.`);\n\t\t\tif (!sameDatabaseTarget(config.db, parentDb)) throw new Error(`The projection worker db passed to ${caller} and the parent reactor database must address the same Postgres database (same host, port, and database); the parent writes operations there and the projection shards read them.`);\n\t\t}\n\t\tvalidateBuiltInKindCoverage(config.preReadyKinds, config.postReadyKinds);\n\t\tif (this.moduleOnlyModelKeys.length > 0) throw new Error(`projection workers require worker-importable sources, but these models were registered only as live modules: ${this.moduleOnlyModelKeys.join(\", \")}. Provide a { filePath } or { packageName } source for each.`);\n\t\tconst models = this.resolvedModelManifest ?? [];\n\t\tconst db = {\n\t\t\t...baseDb,\n\t\t\tpoolSize: config.poolSize ?? baseDb.poolSize,\n\t\t\tapplicationName: config.db?.applicationName ?? \"reactor-projection-shard\"\n\t\t};\n\t\tconst factory = this.projectionWorkerFactory ?? await this.createDefaultProjectionWorkerFactory();\n\t\tconst poolInstrumentations = [];\n\t\tfor (let i = 0; i < config.shardCount; i++) {\n\t\t\tconst forwarder = createForwardingPoolInstrumentation(`projection-shard-${i}`);\n\t\t\tpoolInstrumentations.push(forwarder);\n\t\t\tthis.instrumentedPools.push(forwarder);\n\t\t}\n\t\tconst { ProjectionShardManager } = await import(\"./projection-shard-manager-CPQc5XHL.js\");\n\t\tconst manager = new ProjectionShardManager({\n\t\t\tshardCount: config.shardCount,\n\t\t\tdb,\n\t\t\tmodels,\n\t\t\tpreReadyKinds: config.preReadyKinds,\n\t\t\tpostReadyKinds: config.postReadyKinds,\n\t\t\tfactory,\n\t\t\tlogger: this.logger,\n\t\t\thostBus: eventBus,\n\t\t\tinitTimeoutMs: config.initTimeoutMs,\n\t\t\tshutdownGraceMs: config.shutdownGraceMs,\n\t\t\tdrainTimeoutMs: config.drainTimeoutMs,\n\t\t\tchainDepthReportIntervalMs: config.chainDepthReportIntervalMs,\n\t\t\tpoolInstrumentations,\n\t\t\tconsistencyTrackers,\n\t\t\tonReadReady: config.onReadReady,\n\t\t\tonShardFatal: config.onShardFatal\n\t\t});\n\t\ttry {\n\t\t\tawait manager.startup();\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait manager.shutdown();\n\t\t\t} catch (shutdownError) {\n\t\t\t\tthis.logger.warn(\"projection shard manager shutdown after a failed startup also failed: @error\", shutdownError);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tif (registerShutdownHook) this.shutdownHooks.push(() => manager.shutdown());\n\t\treturn manager;\n\t}\n\tasync createDefaultProjectionWorkerFactory() {\n\t\tconst [{ createProjectionThreadTransport }, { projectionWorkerEntryPath }] = await Promise.all([import(\"./transport-CuogVKN_.js\"), import(\"./projection-worker-wI4PwcV2.js\")]);\n\t\treturn () => createProjectionThreadTransport(projectionWorkerEntryPath);\n\t}\n\t/**\n\t* Default {@link WorkerFactory} used when the pool options carry no\n\t* custom `factory`. Each worker spawns a real `node:worker_threads`\n\t* Worker pointing at the compiled `worker/entry.js`.\n\t*/\n\tasync createDefaultWorkerFactory(numWorkers, db, signatureVerifier) {\n\t\tconst [{ WorkerHandle }, { createThreadTransport }, { workerEntryPath }] = await Promise.all([\n\t\t\timport(\"./worker-handle-CrERzl8s.js\"),\n\t\t\timport(\"./transport-ByGviWdZ.js\"),\n\t\t\timport(\"./worker-HPysBfhx.js\").then((n) => n.n)\n\t\t]);\n\t\tconst poolConfig = {\n\t\t\tenabled: true,\n\t\t\tnumWorkers,\n\t\t\tworkerType: \"thread\"\n\t\t};\n\t\tconst models = this.resolvedModelManifest ?? [];\n\t\tconst logger = this.logger;\n\t\treturn (index) => {\n\t\t\tconst workerId = `reactor-worker-${index}`;\n\t\t\tconst poolInstrumentation = createForwardingPoolInstrumentation(workerId);\n\t\t\tthis.instrumentedPools.push(poolInstrumentation);\n\t\t\treturn new WorkerHandle({\n\t\t\t\tworkerId,\n\t\t\t\tindex,\n\t\t\t\ttransport: createThreadTransport(workerEntryPath),\n\t\t\t\tinitPayload: {\n\t\t\t\t\tpoolConfig,\n\t\t\t\t\tdb,\n\t\t\t\t\tsignatureVerifier,\n\t\t\t\t\tmodels,\n\t\t\t\t\texecutorConfig: this.executorConfig\n\t\t\t\t},\n\t\t\t\tlogger,\n\t\t\t\tpoolInstrumentation\n\t\t\t});\n\t\t};\n\t}\n\t/**\n\t* Builds the parent Kysely instance against a real Postgres server using\n\t* the same {@link DbConfig} the workers receive at init. Used in the\n\t* worker-pool path so the parent reactor and each worker thread share\n\t* storage; PGlite cannot be shared across threads. The constructed pool\n\t* is wrapped with {@link instrumentPgPool} and the resulting\n\t* {@link PoolInstrumentation} is pushed onto {@link instrumentedPools} so\n\t* the reactor module exposes acquire-wait and pool-stat surfaces.\n\t*/\n\tasync createPostgresDatabase(config) {\n\t\tconst { Kysely, PostgresDialect } = await import(\"kysely\");\n\t\tconst Pool = (await import(\"pg\")).default.Pool;\n\t\tconst pool = new Pool({\n\t\t\thost: config.host,\n\t\t\tport: config.port,\n\t\t\tdatabase: config.database,\n\t\t\tuser: config.user,\n\t\t\tpassword: config.password,\n\t\t\tssl: config.ssl ? { rejectUnauthorized: false } : void 0,\n\t\t\tapplication_name: config.applicationName,\n\t\t\tmax: config.poolSize,\n\t\t\tconnectionTimeoutMillis: config.connectionTimeoutMillis,\n\t\t\tidleTimeoutMillis: config.idleTimeoutMillis\n\t\t});\n\t\tthis.instrumentedPools.push(instrumentPgPool(pool, config.applicationName ?? \"reactor-host\"));\n\t\treturn new Kysely({ dialect: new PostgresDialect({ pool }) });\n\t}\n\tattachSignalHandlers(module) {\n\t\tif (typeof globalThis === \"undefined\" || !(\"process\" in globalThis) || typeof globalThis.process.on !== \"function\") return;\n\t\tconst nodeProcess = globalThis.process;\n\t\tconst realExit = nodeProcess.exit.bind(nodeProcess);\n\t\tlet shutdownInProgress = false;\n\t\tlet pendingExitCode;\n\t\tconst handler = async (signal) => {\n\t\t\tif (shutdownInProgress) {\n\t\t\t\tthis.logger.warn(`Received ${signal} again, continuing graceful shutdown...`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tshutdownInProgress = true;\n\t\t\tnodeProcess.exit = ((code) => {\n\t\t\t\tpendingExitCode ??= code ?? 0;\n\t\t\t});\n\t\t\tthis.logger.info(`Received ${signal}, starting graceful shutdown...`);\n\t\t\tconst status = module.reactor.kill();\n\t\t\ttry {\n\t\t\t\tawait status.completed;\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Shutdown failed waiting for reactor:\", error);\n\t\t\t\tnodeProcess.exit = realExit;\n\t\t\t\trealExit(1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const hook of this.shutdownHooks) try {\n\t\t\t\tawait hook();\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Shutdown hook failed:\", error);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait module.database.destroy();\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Shutdown failed destroying database:\", error);\n\t\t\t\tnodeProcess.exit = realExit;\n\t\t\t\trealExit(1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.logger.info(\"Shutdown complete\");\n\t\t\tnodeProcess.exit = realExit;\n\t\t\trealExit(pendingExitCode ?? 0);\n\t\t};\n\t\tnodeProcess.prependListener(\"SIGINT\", () => void handler(\"SIGINT\"));\n\t\tnodeProcess.prependListener(\"SIGTERM\", () => void handler(\"SIGTERM\"));\n\t}\n};\n//#endregion\n//#region src/projection/hybrid-projection-coordinator.ts\n/** Host-side stages on a per-queueKey chain driven by the worker's read-ready. */\nvar HybridProjectionCoordinator = class {\n\t/** One array, mutated in place: reactor-api captures it by reference once. */\n\treadModels;\n\teventBus;\n\tlogger;\n\tmanager;\n\tpreReady;\n\tpostReady;\n\tchains = /* @__PURE__ */ new Map();\n\tconstructor(options) {\n\t\tthis.eventBus = options.eventBus;\n\t\tthis.logger = options.logger;\n\t\tthis.manager = options.manager;\n\t\tthis.preReady = options.preReady;\n\t\tthis.postReady = options.postReady;\n\t\tthis.readModels = [\n\t\t\t...options.preReady,\n\t\t\t...options.postReady,\n\t\t\t...options.lookupOnly\n\t\t];\n\t}\n\tstart() {\n\t\tthis.manager.start();\n\t}\n\tstop() {\n\t\tthis.manager.stop();\n\t}\n\t/** Wired as `onReadReady`; host trackers are already advanced (port FIFO). */\n\tacceptReadReady(event) {\n\t\tif (event.operations.length === 0) {\n\t\t\tthis.manager.emitReadReady(event).catch((err) => this.logger.error(\"JOB_READ_READY emit failed for job @jobId: @Error\", { jobId: event.jobId }, err));\n\t\t\treturn;\n\t\t}\n\t\tconst enqueuedAt = performance.now();\n\t\tconst key = this.queueKeyFor(event);\n\t\tconst current = (this.chains.get(key) ?? Promise.resolve()).then(() => this.runHostChain(event, enqueuedAt));\n\t\tthis.chains.set(key, current);\n\t\tcurrent.finally(() => {\n\t\t\tif (this.chains.get(key) === current) this.chains.delete(key);\n\t\t});\n\t}\n\taddReadModel(readModel, stage) {\n\t\tif (this.readModels.some(({ name }) => name === readModel.name)) throw new Error(`Read model \"${readModel.name}\" is already registered`);\n\t\tif (stage === \"pre_ready\") this.preReady.push(readModel);\n\t\telse this.postReady.push(readModel);\n\t\tthis.readModels.push(readModel);\n\t}\n\tgetChainDepth() {\n\t\treturn this.manager.getChainDepth() + this.chains.size;\n\t}\n\t/** Worker chains flush first, so every relayed read-ready is in `chains`. */\n\tasync drain() {\n\t\tawait this.manager.drain();\n\t\twhile (this.chains.size > 0) {\n\t\t\tconst pending = Array.from(this.chains.values());\n\t\t\tawait Promise.allSettled(pending);\n\t\t}\n\t}\n\t/** Builder shutdown hook; reaches `manager.shutdown()` even when drain fails. */\n\tasync shutdown() {\n\t\ttry {\n\t\t\tawait this.drain();\n\t\t} catch (error) {\n\t\t\tthis.logger.warn(\"hybrid coordinator drain failed during shutdown: @Error\", error);\n\t\t}\n\t\tawait this.manager.shutdown();\n\t}\n\tasync runHostChain(event, enqueuedAt) {\n\t\tconst chainWaitDurationMs = performance.now() - enqueuedAt;\n\t\tconst preReadyStart = performance.now();\n\t\ttry {\n\t\t\tawait Promise.all(this.preReady.map((readModel) => this.indexWithTiming(readModel, \"pre_ready\", event)));\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Host pre-ready read model indexing failed for job @jobId: @Error\", { jobId: event.jobId }, error);\n\t\t}\n\t\tconst preReadyDurationMs = performance.now() - preReadyStart;\n\t\tconst emitStart = performance.now();\n\t\ttry {\n\t\t\tawait this.manager.emitReadReady(event);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"JOB_READ_READY emit failed for job @jobId: @Error\", { jobId: event.jobId }, error);\n\t\t}\n\t\tconst emitDurationMs = performance.now() - emitStart;\n\t\tconst postReadyStart = performance.now();\n\t\ttry {\n\t\t\tawait Promise.all(this.postReady.map((readModel) => this.indexWithTiming(readModel, \"post_ready\", event)));\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Host post-ready read model indexing failed for job @jobId: @Error\", { jobId: event.jobId }, error);\n\t\t}\n\t\tconst postReadyDurationMs = performance.now() - postReadyStart;\n\t\tthis.emitBatchCompleted({\n\t\t\tjobId: event.jobId,\n\t\t\tbatchSize: event.operations.length,\n\t\t\tchainWaitDurationMs,\n\t\t\tpreReadyDurationMs,\n\t\t\temitDurationMs,\n\t\t\tpostReadyDurationMs\n\t\t});\n\t}\n\tasync indexWithTiming(readModel, stage, event) {\n\t\tconst start = performance.now();\n\t\tlet success = false;\n\t\ttry {\n\t\t\tawait readModel.indexOperations(event.operations);\n\t\t\tsuccess = true;\n\t\t} finally {\n\t\t\tthis.emitReadModelIndexed({\n\t\t\t\tjobId: event.jobId,\n\t\t\t\treadModelName: readModel.name,\n\t\t\t\tstage,\n\t\t\t\tdurationMs: performance.now() - start,\n\t\t\t\toperationCount: event.operations.length,\n\t\t\t\tsuccess\n\t\t\t});\n\t\t}\n\t}\n\temitBatchCompleted(payload) {\n\t\tthis.eventBus.emit(ReactorEventTypes.READMODEL_BATCH_COMPLETED, payload).catch((err) => this.logger.error(\"READMODEL_BATCH_COMPLETED emit failed for job @jobId: @Error\", { jobId: payload.jobId }, err));\n\t}\n\temitReadModelIndexed(payload) {\n\t\tthis.eventBus.emit(ReactorEventTypes.READMODEL_INDEXED, payload).catch((err) => this.logger.error(\"READMODEL_INDEXED emit failed for job @jobId: @Error\", { jobId: payload.jobId }, err));\n\t}\n\tqueueKeyFor(event) {\n\t\tconst ctx = event.operations[0].context;\n\t\treturn `${ctx.documentId}:${ctx.scope}:${ctx.branch}`;\n\t}\n};\n//#endregion\n//#region src/projection/create-hybrid-projection-coordinator.ts\n/** Built-ins in one projection worker; all other read models stay on the host. */\nfunction createHybridProjectionCoordinatorFactory(options = {}) {\n\treturn async (deps) => {\n\t\tconst ref = { current: void 0 };\n\t\tconst manager = await deps.createProjectionShardManager({\n\t\t\tshardCount: options.shardCount ?? 1,\n\t\t\tpreReadyKinds: [\"document-view\", \"document-indexer\"],\n\t\t\tpostReadyKinds: [],\n\t\t\tdb: options.db,\n\t\t\tpoolSize: options.poolSize,\n\t\t\tinitTimeoutMs: options.initTimeoutMs,\n\t\t\tshutdownGraceMs: options.shutdownGraceMs,\n\t\t\tdrainTimeoutMs: options.drainTimeoutMs,\n\t\t\tchainDepthReportIntervalMs: options.chainDepthReportIntervalMs,\n\t\t\tonReadReady: (event) => ref.current.acceptReadReady(event),\n\t\t\tonShardFatal: options.onFatal\n\t\t});\n\t\tconst coordinator = new HybridProjectionCoordinator({\n\t\t\teventBus: deps.eventBus,\n\t\t\tlogger: deps.logger,\n\t\t\tmanager,\n\t\t\tpreReady: deps.readModels,\n\t\t\tpostReady: [deps.subscriptionNotificationReadModel, deps.processorManager],\n\t\t\tlookupOnly: [deps.documentView, deps.documentIndexer]\n\t\t});\n\t\tref.current = coordinator;\n\t\tdeps.registerShutdownHook(() => coordinator.shutdown());\n\t\treturn coordinator;\n\t};\n}\n//#endregion\n//#region src/signer/passthrough-signer.ts\n/**\n* A no-op signer that returns empty values for all methods.\n* Used when signing is not required.\n*/\nvar PassthroughSigner = class {\n\tpublicKey = {};\n\tsign() {\n\t\treturn Promise.resolve(new Uint8Array(0));\n\t}\n\tverify() {\n\t\treturn Promise.resolve();\n\t}\n\tsignAction() {\n\t\treturn Promise.resolve([\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\"\n\t\t]);\n\t}\n};\n//#endregion\n//#region src/core/reactor-client-builder.ts\n/**\n* Builder class for constructing ReactorClient instances with proper configuration\n*/\nvar ReactorClientBuilder = class {\n\tlogger;\n\treactorBuilder;\n\treactor;\n\teventBus;\n\tdocumentIndexer;\n\tdocumentView;\n\tsigner;\n\tsignatureVerifier;\n\tsubscriptionManager;\n\tjobAwaiter;\n\tdocumentModelLoader;\n\treadGate;\n\t/**\n\t* Sets the logger for the ReactorClient.\n\t* @param logger - The logger to use.\n\t* @returns The ReactorClientBuilder instance.\n\t*/\n\twithLogger(logger) {\n\t\tthis.logger = logger;\n\t\treturn this;\n\t}\n\t/**\n\t* Either this or withReactor must be set.\n\t*/\n\twithReactorBuilder(reactorBuilder) {\n\t\tif (this.reactor) throw new Error(\"Reactor is already set\");\n\t\tthis.reactorBuilder = reactorBuilder;\n\t\treturn this;\n\t}\n\t/**\n\t* Either this or withReactorBuilder must be set.\n\t*/\n\twithReactor(reactor, eventBus, documentIndexer, documentView) {\n\t\tif (this.reactorBuilder) throw new Error(\"ReactorBuilder is already set\");\n\t\tthis.reactor = reactor;\n\t\tthis.eventBus = eventBus;\n\t\tthis.documentIndexer = documentIndexer;\n\t\tthis.documentView = documentView;\n\t\treturn this;\n\t}\n\t/**\n\t* Sets the signer configuration for signing and verifying actions.\n\t*\n\t* @param config - Either an ISigner for signing only, or a SignerConfig for both signing and verification\n\t*/\n\twithSigner(config) {\n\t\tif (\"signer\" in config) {\n\t\t\tthis.signer = config.signer;\n\t\t\tthis.signatureVerifier = config.verifier;\n\t\t} else this.signer = config;\n\t\treturn this;\n\t}\n\twithSubscriptionManager(subscriptionManager) {\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\treturn this;\n\t}\n\twithJobAwaiter(jobAwaiter) {\n\t\tthis.jobAwaiter = jobAwaiter;\n\t\treturn this;\n\t}\n\twithDocumentModelLoader(loader) {\n\t\tthis.documentModelLoader = loader;\n\t\treturn this;\n\t}\n\t/**\n\t* Overrides how reads are gated. A client built from a ReactorBuilder derives\n\t* this from that reactor's flags; one built from `withReactor` cannot, because\n\t* it is handed no flags and no registry, so it gates on the policy alone\n\t* unless a gate is supplied here.\n\t*/\n\twithReadGate(readGate) {\n\t\tthis.readGate = readGate;\n\t\treturn this;\n\t}\n\t/**\n\t* The gate the resolved model calls for. Below authEnforcement there is no\n\t* model to enforce -- the registered one ignores the auth scope -- so the\n\t* policy is evaluated on its own, which is what reads did before the model\n\t* existed. Group serving turns on with authGroups, because below it a\n\t* `{ group }` grant does not match, so a served roster is one no grant can\n\t* use.\n\t*/\n\tresolveReadGate(reactorModule, documentView, model) {\n\t\tif (!reactorModule || model === void 0) return new BareReadGate();\n\t\treturn new ModelReadGate(model, documentView, reactorModule.featureFlags.authGroups, reactorModule.operationIndex, this.logger);\n\t}\n\t/**\n\t* What the client answers an authorization preflight from, or undefined when\n\t* it answers none.\n\t*\n\t* Resolved from the same model reads enforce, so a preflight and a read can\n\t* never decide against different models. Undefined below authEnforcement, and\n\t* undefined on the `withReactor` path, where there are no flags and no\n\t* registry to select a model with -- a client with no model refuses the\n\t* preflight rather than answering it from the legacy host-side permission\n\t* tables. Deliberately not derived from the read gate: `withReadGate`\n\t* overrides that, so sniffing the gate's type would report enforcement from a\n\t* caller's substitution.\n\t*/\n\tresolveActionEvaluation(reactorModule, model) {\n\t\treturn reactorModule && model ? {\n\t\t\tmodel,\n\t\t\tflags: reactorModule.featureFlags\n\t\t} : void 0;\n\t}\n\tasync build() {\n\t\treturn (await this.buildModule()).client;\n\t}\n\tasync buildModule() {\n\t\tif (!this.logger) this.logger = new ConsoleLogger([\"reactor-client\"]);\n\t\tlet reactor;\n\t\tlet eventBus;\n\t\tlet documentIndexer;\n\t\tlet documentView;\n\t\tlet reactorModule;\n\t\tif (this.reactorBuilder) {\n\t\t\tif (this.signatureVerifier) this.reactorBuilder.withSignatureVerifier(this.signatureVerifier);\n\t\t\tif (this.documentModelLoader) this.reactorBuilder.withDocumentModelLoader(this.documentModelLoader);\n\t\t\treactorModule = await this.reactorBuilder.buildModule();\n\t\t\treactor = reactorModule.reactor;\n\t\t\teventBus = reactorModule.eventBus;\n\t\t\tdocumentIndexer = reactorModule.documentIndexer;\n\t\t\tdocumentView = reactorModule.documentView;\n\t\t} else if (this.reactor && this.eventBus && this.documentIndexer && this.documentView) {\n\t\t\treactor = this.reactor;\n\t\t\teventBus = this.eventBus;\n\t\t\tdocumentIndexer = this.documentIndexer;\n\t\t\tdocumentView = this.documentView;\n\t\t\treactorModule = void 0;\n\t\t} else throw new Error(\"Either ReactorBuilder or (Reactor + EventBus + DocumentIndexer + DocumentView) is required\");\n\t\tconst signer = this.signer ?? new PassthroughSigner();\n\t\tconst subscriptionManager = this.subscriptionManager ?? reactorModule?.subscriptionManager ?? new ReactorSubscriptionManager(new DefaultSubscriptionErrorHandler());\n\t\tconst jobAwaiter = this.jobAwaiter ?? new JobAwaiter(eventBus, (jobId, signal) => reactor.getJobStatus(jobId, signal));\n\t\tconst decisionModel = reactorModule ? readDecisionModel(reactorModule.featureFlags, reactorModule.documentModelRegistry) : void 0;\n\t\treturn {\n\t\t\tclient: new ReactorClient(this.logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, this.readGate ?? this.resolveReadGate(reactorModule, documentView, decisionModel), this.resolveActionEvaluation(reactorModule, decisionModel)),\n\t\t\treactor,\n\t\t\teventBus,\n\t\t\tdocumentIndexer,\n\t\t\tdocumentView,\n\t\t\tsigner,\n\t\t\tsubscriptionManager,\n\t\t\tjobAwaiter,\n\t\t\treactorModule\n\t\t};\n\t}\n};\n//#endregion\n//#region src/shared/drive-url.ts\n/**\n* Parse a drive URL to extract drive ID and construct GraphQL endpoint.\n* Preserves any subpath prefix so the result is correct when the reactor is\n* served behind a proxy at a non-root path.\n* e.g., \"http://localhost:4001/d/abc123\" -> { driveId: \"abc123\", graphqlEndpoint: \"http://localhost:4001/graphql/r\" }\n* e.g., \"https://example.com/api/reactor/d/abc123\" -> { ..., graphqlEndpoint: \"https://example.com/api/reactor/graphql/r\" }\n*/\nfunction parseDriveUrl(url) {\n\tconst parsedUrl = new URL(url);\n\tconst driveId = url.split(\"/\").pop() ?? \"\";\n\tconst basePath = parsedUrl.pathname.replace(/\\/d\\/[^/]+\\/?$/, \"\");\n\treturn {\n\t\turl,\n\t\tdriveId,\n\t\tgraphqlEndpoint: `${parsedUrl.protocol}//${parsedUrl.host}${basePath}/graphql/r`\n\t};\n}\n/**\n* Extract drive ID from a drive URL.\n*/\nfunction driveIdFromUrl(url) {\n\treturn url.split(\"/\").pop() ?? \"\";\n}\n//#endregion\n//#region src/decision/sync-scope-gate.ts\n/** What a subject may read of a document that is not there to be read. */\nconst META_ONLY = (scope) => ALWAYS_READABLE_SCOPES.has(scope);\n/**\n* A read gate asked by document id rather than by document.\n*\n* Serving works from an id: an outbox entry names a document, a branch and a\n* scope, and carries no state. Fetching the document is therefore the serving\n* path's own job, and it is the only thing this adds to the gate it wraps.\n*/\nvar SyncScopeGate = class {\n\tconstructor(gate, documentView, logger) {\n\t\tthis.gate = gate;\n\t\tthis.documentView = documentView;\n\t\tthis.logger = logger;\n\t}\n\t/**\n\t* Which scopes of one document the subject may be served.\n\t*\n\t* A document this replica cannot produce yields the metadata scopes and\n\t* nothing else. That is the fail-closed direction, and it is safe to fail\n\t* closed here precisely because serving withholds rather than consumes: the\n\t* entry stays in the outbox and the next poll asks again, so a document that\n\t* is merely not indexed yet is delayed rather than lost.\n\t*\n\t* Any other failure is rethrown. A read side that is down must not read as a\n\t* silent, universal denial, because a denial that looks like a policy is one\n\t* nobody investigates.\n\t*/\n\tasync scopePredicateById(documentId, subject, branch, signal) {\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await this.documentView.get(documentId, { branch }, void 0, signal);\n\t\t} catch (error) {\n\t\t\tif (!DocumentNotFoundError.isError(error)) throw error;\n\t\t\tthis.logger?.verbose(`Withholding ${documentId} on branch ${branch}: the read side does not hold it`);\n\t\t\treturn META_ONLY;\n\t\t}\n\t\treturn this.gate.scopePredicate(document, subject, branch, signal);\n\t}\n};\n//#endregion\n//#region src/decision/stream-order.ts\n/**\n* The first pair of effective operations whose stored order contradicts their\n* timestamps, or undefined when the stream is in position order.\n*\n* Such a stream cannot be walked, and the auth stream is never reshuffled once\n* the monotonic rule is on, so run this before enabling enforcement on a fleet.\n*\n* `requireStrict` additionally rejects a tie, which is what the auth stream's\n* monotonic rule requires and what the walk alone does not care about.\n*/\nfunction firstOutOfOrderPair(operations, options) {\n\tconst requireStrict = options?.requireStrict ?? false;\n\tconst effective = garbageCollect(sortOperations([...operations]));\n\tfor (let i = 1; i < effective.length; i++) {\n\t\tconst previous = effective[i - 1];\n\t\tconst current = effective[i];\n\t\tconst previousAt = Date.parse(previous.timestampUtcMs);\n\t\tconst currentAt = Date.parse(current.timestampUtcMs);\n\t\tif (currentAt < previousAt) return {\n\t\t\tprevious,\n\t\t\tcurrent,\n\t\t\tkind: \"descending\"\n\t\t};\n\t\tif (requireStrict && currentAt === previousAt) return {\n\t\t\tprevious,\n\t\t\tcurrent,\n\t\t\tkind: \"tied\"\n\t\t};\n\t}\n}\n//#endregion\n//#region src/read-models/interfaces.ts\nfunction supportsLiveReadModelRegistration(coordinator) {\n\treturn \"addReadModel\" in coordinator && typeof coordinator.addReadModel === \"function\";\n}\n//#endregion\n//#region src/processors/host-module.ts\n/** Builds the reactor-level host module; hosts spread it and add their own fields. */\nfunction createReactorHostModuleBase(options) {\n\tconst { client, readModels, ...core } = options;\n\treturn {\n\t\t...core,\n\t\tclient,\n\t\tdispatch: { async execute(docId, branch, actions, signal) {\n\t\t\tconst jobInfo = await client.executeAsync(docId, branch, actions, signal);\n\t\t\treturn {\n\t\t\t\tid: jobInfo.id,\n\t\t\t\tstatus: jobInfo.status\n\t\t\t};\n\t\t} },\n\t\tgetReadModel(name) {\n\t\t\tconst model = readModels.find((m) => m.name === name);\n\t\t\tif (!model) throw new Error(`Read model \"${name}\" not found`);\n\t\t\treturn model;\n\t\t}\n\t};\n}\n//#endregion\n//#region src/admin/passthrough-keyframe-store.ts\nconst passthroughKeyframeStore = {\n\tputKeyframe: () => Promise.resolve(),\n\tfindNearestKeyframe: () => Promise.resolve(void 0),\n\tlistKeyframes: () => Promise.resolve([]),\n\tdeleteKeyframes: () => Promise.resolve(0)\n};\n//#endregion\n//#region src/admin/document-integrity-service.ts\nvar DocumentIntegrityService = class {\n\tkeyframeStore;\n\toperationStore;\n\twriteCache;\n\tdocumentView;\n\tdocumentModelRegistry;\n\tconstructor(keyframeStore, operationStore, writeCache, documentView, documentModelRegistry) {\n\t\tthis.keyframeStore = keyframeStore;\n\t\tthis.operationStore = operationStore;\n\t\tthis.writeCache = writeCache;\n\t\tthis.documentView = documentView;\n\t\tthis.documentModelRegistry = documentModelRegistry;\n\t}\n\tasync validateDocument(documentId, branch = \"main\", signal) {\n\t\tconst keyframeIssues = [];\n\t\tconst snapshotIssues = [];\n\t\tconst streamOrderIssues = await this.findStreamOrderIssues(documentId, branch, signal);\n\t\tconst replayCache = new KyselyWriteCache(passthroughKeyframeStore, this.operationStore, this.documentModelRegistry, {\n\t\t\tmaxDocuments: 1,\n\t\t\tringBufferSize: 1,\n\t\t\tkeyframeInterval: Number.MAX_SAFE_INTEGER\n\t\t});\n\t\tconst keyframes = await this.keyframeStore.listKeyframes(documentId, void 0, branch, signal);\n\t\tfor (const keyframe of keyframes) {\n\t\t\tthrowIfAborted(signal);\n\t\t\treplayCache.invalidate(documentId, keyframe.scope, branch);\n\t\t\tconst replayedDoc = await replayCache.getState(documentId, keyframe.scope, branch, keyframe.revision, signal);\n\t\t\tconst kfHash = hashDocumentStateForScope(keyframe.document, keyframe.scope);\n\t\t\tconst replayHash = hashDocumentStateForScope(replayedDoc, keyframe.scope);\n\t\t\tif (kfHash !== replayHash) keyframeIssues.push({\n\t\t\t\tscope: keyframe.scope,\n\t\t\t\tbranch,\n\t\t\t\trevision: keyframe.revision,\n\t\t\t\tkeyframeHash: kfHash,\n\t\t\t\treplayedHash: replayHash\n\t\t\t});\n\t\t}\n\t\tlet currentDoc;\n\t\ttry {\n\t\t\tcurrentDoc = await this.documentView.get(documentId);\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tdocumentId,\n\t\t\t\tisConsistent: keyframeIssues.length === 0 && streamOrderIssues.length === 0,\n\t\t\t\tkeyframeIssues,\n\t\t\t\tsnapshotIssues,\n\t\t\t\tstreamOrderIssues\n\t\t\t};\n\t\t}\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tconst allScopes = Object.keys(revisions.revision);\n\t\tfor (const scope of allScopes) {\n\t\t\tif (scope === \"document\") continue;\n\t\t\treplayCache.invalidate(documentId, scope, branch);\n\t\t\tlet replayedDoc;\n\t\t\ttry {\n\t\t\t\treplayedDoc = await replayCache.getState(documentId, scope, branch, void 0, signal);\n\t\t\t} catch {\n\t\t\t\tthrowIfAborted(signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst snapshotHash = hashDocumentStateForScope(currentDoc, scope);\n\t\t\tconst replayHash = hashDocumentStateForScope(replayedDoc, scope);\n\t\t\tif (snapshotHash !== replayHash) snapshotIssues.push({\n\t\t\t\tscope,\n\t\t\t\tbranch,\n\t\t\t\tsnapshotHash,\n\t\t\t\treplayedHash: replayHash\n\t\t\t});\n\t\t}\n\t\treturn {\n\t\t\tdocumentId,\n\t\t\tisConsistent: keyframeIssues.length === 0 && snapshotIssues.length === 0 && streamOrderIssues.length === 0,\n\t\t\tkeyframeIssues,\n\t\t\tsnapshotIssues,\n\t\t\tstreamOrderIssues\n\t\t};\n\t}\n\tasync rebuildKeyframes(documentId, branch = \"main\", signal) {\n\t\treturn {\n\t\t\tdocumentId,\n\t\t\tkeyframesDeleted: await this.keyframeStore.deleteKeyframes(documentId, void 0, branch, signal),\n\t\t\tscopesInvalidated: 0\n\t\t};\n\t}\n\tasync rebuildSnapshots(documentId, branch = \"main\", signal) {\n\t\tconst scopes = await this.discoverScopes(documentId, branch, signal);\n\t\tfor (const scope of scopes) {\n\t\t\tthrowIfAborted(signal);\n\t\t\tthis.writeCache.invalidate(documentId, scope, branch);\n\t\t}\n\t\treturn {\n\t\t\tdocumentId,\n\t\t\tkeyframesDeleted: 0,\n\t\t\tscopesInvalidated: scopes.length\n\t\t};\n\t}\n\tasync findStreamOrderIssues(documentId, branch, signal) {\n\t\tconst scopes = await this.discoverScopes(documentId, branch, signal);\n\t\tconst issues = [];\n\t\tfor (const scope of scopes) {\n\t\t\tthrowIfAborted(signal);\n\t\t\tconst pair = firstOutOfOrderPair((await this.operationStore.getSince(documentId, scope, branch, -1, void 0, void 0, signal)).results, { requireStrict: scope === \"auth\" });\n\t\t\tif (pair !== void 0) issues.push({\n\t\t\t\tscope,\n\t\t\t\tbranch,\n\t\t\t\t...pair\n\t\t\t});\n\t\t}\n\t\treturn issues;\n\t}\n\tasync discoverScopes(documentId, branch, signal) {\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\treturn Object.keys(revisions.revision);\n\t}\n};\n//#endregion\nexport { ALWAYS_READABLE_SCOPES, APPEND_CONDITION_FAILED_PREFIX, AppendConditionFailedError, AuthEnforcementDisabledError, BareReadGate, BaseReadModel, ChannelError, ChannelErrorSource, ChannelScheme, ConsistencyTracker, DEFAULT_DRIVE_CONTAINER_TYPES, DOCUMENT_INDEXER_READ_MODEL, DOCUMENT_VIEW_READ_MODEL, DRIVE_AUTH_ERROR_MESSAGES, DefaultSubscriptionErrorHandler, DocumentAlreadyExistsError, DocumentChangeType, DocumentExistence, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, DriveClient, DriveCollectionId, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, HybridProjectionCoordinator, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, IntervalPollTimer, InvalidModuleError, JobAwaiter, JobExecutorEventTypes, JobStatus, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, Mailbox, ModelReadGate, ModuleNotFoundError, NullDocumentModelResolver, OptimisticLockError, PollBehavior, PollingChannelError, ProcessorManager, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, RECOVERABLE_GRAPHQL_ERROR_CODES, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, ReactorEventTypes, ReactorSubscriptionManager, ReadModelCoordinator, RelationalDbProcessor, RelationshipChangeType, RetryAccounting, RevisionMismatchError, SeededStateReader, SimpleJobExecutorManager, SyncBuilder, SyncEventTypes, SyncOperation, SyncOperationAggregateError, SyncOperationStatus, SyncScopeGate, SyncStatus, SyncStatusTracker, addRelationshipAction, authDecisionModel, batchOperationsByDocument, buildDecisionModel, classifyJobFailure, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createHybridProjectionCoordinatorFactory, createMutableShutdownStatus, createReactorHostModuleBase, createRelationalDb, decideAtHead, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, isRecoverableGraphQLError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };\n\n//# sourceMappingURL=index.js.map","/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nvar ownKeys = function(o) {\n ownKeys = Object.getOwnPropertyNames || function (o) {\n var ar = [];\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\n return ar;\n };\n return ownKeys(o);\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\n });\n }\n return path;\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __esDecorate,\n __runInitializers,\n __propKey,\n __setFunctionName,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n __rewriteRelativeImportExtension,\n};\n","(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('tslib'), require('graphql')) :\n typeof define === 'function' && define.amd ? define(['exports', 'tslib', 'graphql'], factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['graphql-tag'] = {}, global.tslib, global.graphql));\n}(this, (function (exports, tslib, graphql) { 'use strict';\n\n var docCache = new Map();\n var fragmentSourceMap = new Map();\n var printFragmentWarnings = true;\n var experimentalFragmentVariables = false;\n function normalize(string) {\n return string.replace(/[\\s,]+/g, ' ').trim();\n }\n function cacheKeyFromLoc(loc) {\n return normalize(loc.source.body.substring(loc.start, loc.end));\n }\n function processFragments(ast) {\n var seenKeys = new Set();\n var definitions = [];\n ast.definitions.forEach(function (fragmentDefinition) {\n if (fragmentDefinition.kind === 'FragmentDefinition') {\n var fragmentName = fragmentDefinition.name.value;\n var sourceKey = cacheKeyFromLoc(fragmentDefinition.loc);\n var sourceKeySet = fragmentSourceMap.get(fragmentName);\n if (sourceKeySet && !sourceKeySet.has(sourceKey)) {\n if (printFragmentWarnings) {\n console.warn(\"Warning: fragment with name \" + fragmentName + \" already exists.\\n\"\n + \"graphql-tag enforces all fragment names across your application to be unique; read more about\\n\"\n + \"this in the docs: http://dev.apollodata.com/core/fragments.html#unique-names\");\n }\n }\n else if (!sourceKeySet) {\n fragmentSourceMap.set(fragmentName, sourceKeySet = new Set);\n }\n sourceKeySet.add(sourceKey);\n if (!seenKeys.has(sourceKey)) {\n seenKeys.add(sourceKey);\n definitions.push(fragmentDefinition);\n }\n }\n else {\n definitions.push(fragmentDefinition);\n }\n });\n return tslib.__assign(tslib.__assign({}, ast), { definitions: definitions });\n }\n function stripLoc(doc) {\n var workSet = new Set(doc.definitions);\n workSet.forEach(function (node) {\n if (node.loc)\n delete node.loc;\n Object.keys(node).forEach(function (key) {\n var value = node[key];\n if (value && typeof value === 'object') {\n workSet.add(value);\n }\n });\n });\n var loc = doc.loc;\n if (loc) {\n delete loc.startToken;\n delete loc.endToken;\n }\n return doc;\n }\n function parseDocument(source) {\n var cacheKey = normalize(source);\n if (!docCache.has(cacheKey)) {\n var parsed = graphql.parse(source, {\n experimentalFragmentVariables: experimentalFragmentVariables,\n allowLegacyFragmentVariables: experimentalFragmentVariables\n });\n if (!parsed || parsed.kind !== 'Document') {\n throw new Error('Not a valid GraphQL document.');\n }\n docCache.set(cacheKey, stripLoc(processFragments(parsed)));\n }\n return docCache.get(cacheKey);\n }\n function gql(literals) {\n var args = [];\n for (var _i = 1; _i < arguments.length; _i++) {\n args[_i - 1] = arguments[_i];\n }\n if (typeof literals === 'string') {\n literals = [literals];\n }\n var result = literals[0];\n args.forEach(function (arg, i) {\n if (arg && arg.kind === 'Document') {\n result += arg.loc.source.body;\n }\n else {\n result += arg;\n }\n result += literals[i + 1];\n });\n return parseDocument(result);\n }\n function resetCaches() {\n docCache.clear();\n fragmentSourceMap.clear();\n }\n function disableFragmentWarnings() {\n printFragmentWarnings = false;\n }\n function enableExperimentalFragmentVariables() {\n experimentalFragmentVariables = true;\n }\n function disableExperimentalFragmentVariables() {\n experimentalFragmentVariables = false;\n }\n var extras = {\n gql: gql,\n resetCaches: resetCaches,\n disableFragmentWarnings: disableFragmentWarnings,\n enableExperimentalFragmentVariables: enableExperimentalFragmentVariables,\n disableExperimentalFragmentVariables: disableExperimentalFragmentVariables\n };\n (function (gql_1) {\n gql_1.gql = extras.gql, gql_1.resetCaches = extras.resetCaches, gql_1.disableFragmentWarnings = extras.disableFragmentWarnings, gql_1.enableExperimentalFragmentVariables = extras.enableExperimentalFragmentVariables, gql_1.disableExperimentalFragmentVariables = extras.disableExperimentalFragmentVariables;\n })(gql || (gql = {}));\n gql[\"default\"] = gql;\n var gql$1 = gql;\n\n exports.default = gql$1;\n exports.disableExperimentalFragmentVariables = disableExperimentalFragmentVariables;\n exports.disableFragmentWarnings = disableFragmentWarnings;\n exports.enableExperimentalFragmentVariables = enableExperimentalFragmentVariables;\n exports.gql = gql;\n exports.resetCaches = resetCaches;\n\n Object.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=graphql-tag.umd.js.map\n","// For backwards compatibility, make sure require(\"graphql-tag\") returns\n// the gql function, rather than an exports object.\nmodule.exports = require('./lib/graphql-tag.umd.js').gql;\n"],"x_google_ignoreList":[2,3,4],"mappings":";;;;AAorBA,MAAM,yBAAyB,IAAI,IAAI;CACtC;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;AAK6B,IAAI,IAAI,CAAC,GAAG,uBAAuB,CAAC,QAAQ,SAAS,SAAS,kBAAkB,CAAC;;;;AAuMhH,IAAI,sBAAsB,cAAc,MAAM;CAC7C;CACA;CACA,YAAY,cAAc,SAAS;EAClC,MAAM,gBAAgB,YAAY,KAAK,IAAI,YAAY,YAAY;AACnE,QAAM,6CAA6C,eAAe,gBAAgB;AAClF,OAAK,OAAO;AACZ,OAAK,eAAe;AACpB,OAAK,mBAAmB;;CAEzB,OAAO,QAAQ,OAAO;AACrB,SAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS;;;AA+vDhD,MAAM,0BAA0B;;;;;;;;;;;;AAYhC,IAAI,oBAAoB,MAAM,kBAAkB;CAC/C,YAAY,SAAS,QAAQ;AAC5B,OAAK,UAAU;AACf,OAAK,SAAS;;CAEf,OAAO,SAAS,SAAS,SAAS,QAAQ;AACzC,SAAO,IAAI,kBAAkB,SAAS,OAAO;;;;;;;CAO9C,OAAO,QAAQ,KAAK;AACnB,MAAI,CAAC,IAAI,WAAW,wBAAwB,CAAE,OAAM,IAAI,MAAM,8BAA8B,MAAM;EAClG,MAAM,OAAO,IAAI,MAAM,EAAE;EACzB,MAAM,UAAU,KAAK,YAAY,IAAI;AACrC,MAAI,YAAY,MAAM,YAAY,KAAK,SAAS,EAAG,OAAM,IAAI,MAAM,kCAAkC,MAAM;AAC3G,SAAO,IAAI,kBAAkB,KAAK,MAAM,UAAU,EAAE,EAAE,KAAK,MAAM,GAAG,QAAQ,CAAC;;CAE9E,IAAI,MAAM;AACT,SAAO,GAAG,0BAA0B,KAAK,OAAO,GAAG,KAAK;;CAEzD,WAAW;AACV,SAAO,KAAK;;CAEb,OAAO,OAAO;AACb,SAAO,KAAK,YAAY,MAAM,WAAW,KAAK,WAAW,MAAM;;;AC87CvC,IAAI,IAAI,OAAO,OADD,EAAE,0BAA0B,8BAA8B,CAClB,CAAC;AAo+DjF,IAAI,aAA6B,yBAAS,YAAY;AACrD,YAAW,YAAY;AACvB,YAAW,cAAc;AACzB,YAAW,cAAc;AACzB,YAAW,yBAAyB;AACpC,YAAW,WAAW;AACtB,QAAO;EACN,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1kML,SAAgB,UAAU,GAAG,GAAG;AAC9B,KAAI,OAAO,MAAM,cAAc,MAAM,KACjC,OAAM,IAAI,UAAU,yBAAyB,OAAO,EAAE,GAAG,gCAAgC;AAC7F,eAAc,GAAG,EAAE;CACnB,SAAS,KAAK;AAAE,OAAK,cAAc;;AACnC,GAAE,YAAY,MAAM,OAAO,OAAO,OAAO,EAAE,IAAI,GAAG,YAAY,EAAE,WAAW,IAAI,IAAI;;AAcrF,SAAgB,OAAO,GAAG,GAAG;CAC3B,IAAI,IAAI,EAAE;AACV,MAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAC9E,GAAE,KAAK,EAAE;AACb,KAAI,KAAK,QAAQ,OAAO,OAAO,0BAA0B;OAChD,IAAI,IAAI,GAAG,IAAI,OAAO,sBAAsB,EAAE,EAAE,IAAI,EAAE,QAAQ,IAC/D,KAAI,EAAE,QAAQ,EAAE,GAAG,GAAG,KAAK,OAAO,UAAU,qBAAqB,KAAK,GAAG,EAAE,GAAG,CAC1E,GAAE,EAAE,MAAM,EAAE,EAAE;;AAE1B,QAAO;;AAGT,SAAgB,WAAW,YAAY,QAAQ,KAAK,MAAM;CACxD,IAAI,IAAI,UAAU,QAAQ,IAAI,IAAI,IAAI,SAAS,SAAS,OAAO,OAAO,OAAO,yBAAyB,QAAQ,IAAI,GAAG,MAAM;AAC3H,KAAI,OAAO,YAAY,YAAY,OAAO,QAAQ,aAAa,WAAY,KAAI,QAAQ,SAAS,YAAY,QAAQ,KAAK,KAAK;KACzH,MAAK,IAAI,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,IAAK,KAAI,IAAI,WAAW,GAAI,MAAK,IAAI,IAAI,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,QAAQ,KAAK,EAAE,GAAG,EAAE,QAAQ,IAAI,KAAK;AAChJ,QAAO,IAAI,KAAK,KAAK,OAAO,eAAe,QAAQ,KAAK,EAAE,EAAE;;AAG9D,SAAgB,QAAQ,YAAY,WAAW;AAC7C,QAAO,SAAU,QAAQ,KAAK;AAAE,YAAU,QAAQ,KAAK,WAAW;;;AAGpE,SAAgB,aAAa,MAAM,cAAc,YAAY,WAAW,cAAc,mBAAmB;CACvG,SAAS,OAAO,GAAG;AAAE,MAAI,MAAM,KAAK,KAAK,OAAO,MAAM,WAAY,OAAM,IAAI,UAAU,oBAAoB;AAAE,SAAO;;CACnH,IAAI,OAAO,UAAU,MAAM,MAAM,SAAS,WAAW,QAAQ,SAAS,WAAW,QAAQ;CACzF,IAAI,SAAS,CAAC,gBAAgB,OAAO,UAAU,YAAY,OAAO,KAAK,YAAY;CACnF,IAAI,aAAa,iBAAiB,SAAS,OAAO,yBAAyB,QAAQ,UAAU,KAAK,GAAG,EAAE;CACvG,IAAI,GAAG,OAAO;AACd,MAAK,IAAI,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,KAAK;EAC7C,IAAI,UAAU,EAAE;AAChB,OAAK,IAAI,KAAK,UAAW,SAAQ,KAAK,MAAM,WAAW,EAAE,GAAG,UAAU;AACtE,OAAK,IAAI,KAAK,UAAU,OAAQ,SAAQ,OAAO,KAAK,UAAU,OAAO;AACrE,UAAQ,iBAAiB,SAAU,GAAG;AAAE,OAAI,KAAM,OAAM,IAAI,UAAU,yDAAyD;AAAE,qBAAkB,KAAK,OAAO,KAAK,KAAK,CAAC;;EAC1K,IAAI,UAAU,GAAG,WAAW,IAAI,SAAS,aAAa;GAAE,KAAK,WAAW;GAAK,KAAK,WAAW;GAAK,GAAG,WAAW,MAAM,QAAQ;AAC9H,MAAI,SAAS,YAAY;AACrB,OAAI,WAAW,KAAK,EAAG;AACvB,OAAI,WAAW,QAAQ,OAAO,WAAW,SAAU,OAAM,IAAI,UAAU,kBAAkB;AACzF,OAAI,IAAI,OAAO,OAAO,IAAI,CAAE,YAAW,MAAM;AAC7C,OAAI,IAAI,OAAO,OAAO,IAAI,CAAE,YAAW,MAAM;AAC7C,OAAI,IAAI,OAAO,OAAO,KAAK,CAAE,cAAa,QAAQ,EAAE;aAE/C,IAAI,OAAO,OAAO,CACvB,KAAI,SAAS,QAAS,cAAa,QAAQ,EAAE;MACxC,YAAW,OAAO;;AAG/B,KAAI,OAAQ,QAAO,eAAe,QAAQ,UAAU,MAAM,WAAW;AACrE,QAAO;;AAGT,SAAgB,kBAAkB,SAAS,cAAc,OAAO;CAC9D,IAAI,WAAW,UAAU,SAAS;AAClC,MAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACrC,SAAQ,WAAW,aAAa,GAAG,KAAK,SAAS,MAAM,GAAG,aAAa,GAAG,KAAK,QAAQ;AAE3F,QAAO,WAAW,QAAQ,KAAK;;AAGjC,SAAgB,UAAU,GAAG;AAC3B,QAAO,OAAO,MAAM,WAAW,IAAI,GAAG,OAAO,EAAE;;AAGjD,SAAgB,kBAAkB,GAAG,MAAM,QAAQ;AACjD,KAAI,OAAO,SAAS,SAAU,QAAO,KAAK,cAAc,IAAI,OAAO,KAAK,aAAa,IAAI,GAAG;AAC5F,QAAO,OAAO,eAAe,GAAG,QAAQ;EAAE,cAAc;EAAM,OAAO,SAAS,GAAG,OAAO,QAAQ,KAAK,KAAK,GAAG;EAAM,CAAC;;AAGtH,SAAgB,WAAW,aAAa,eAAe;AACrD,KAAI,OAAO,YAAY,YAAY,OAAO,QAAQ,aAAa,WAAY,QAAO,QAAQ,SAAS,aAAa,cAAc;;AAGhI,SAAgB,UAAU,SAAS,YAAY,GAAG,WAAW;CAC3D,SAAS,MAAM,OAAO;AAAE,SAAO,iBAAiB,IAAI,QAAQ,IAAI,EAAE,SAAU,SAAS;AAAE,WAAQ,MAAM;IAAI;;AACzG,QAAO,KAAK,MAAM,IAAI,UAAU,SAAU,SAAS,QAAQ;EACvD,SAAS,UAAU,OAAO;AAAE,OAAI;AAAE,SAAK,UAAU,KAAK,MAAM,CAAC;YAAW,GAAG;AAAE,WAAO,EAAE;;;EACtF,SAAS,SAAS,OAAO;AAAE,OAAI;AAAE,SAAK,UAAU,SAAS,MAAM,CAAC;YAAW,GAAG;AAAE,WAAO,EAAE;;;EACzF,SAAS,KAAK,QAAQ;AAAE,UAAO,OAAO,QAAQ,OAAO,MAAM,GAAG,MAAM,OAAO,MAAM,CAAC,KAAK,WAAW,SAAS;;AAC3G,QAAM,YAAY,UAAU,MAAM,SAAS,cAAc,EAAE,CAAC,EAAE,MAAM,CAAC;GACvE;;AAGJ,SAAgB,YAAY,SAAS,MAAM;CACzC,IAAI,IAAI;EAAE,OAAO;EAAG,MAAM,WAAW;AAAE,OAAI,EAAE,KAAK,EAAG,OAAM,EAAE;AAAI,UAAO,EAAE;;EAAO,MAAM,EAAE;EAAE,KAAK,EAAE;EAAE,EAAE,GAAG,GAAG,GAAG,IAAI,OAAO,QAAQ,OAAO,aAAa,aAAa,WAAW,QAAQ,UAAU;AAChM,QAAO,EAAE,OAAO,KAAK,EAAE,EAAE,EAAE,WAAW,KAAK,EAAE,EAAE,EAAE,YAAY,KAAK,EAAE,EAAE,OAAO,WAAW,eAAe,EAAE,OAAO,YAAY,WAAW;AAAE,SAAO;KAAU;CAC1J,SAAS,KAAK,GAAG;AAAE,SAAO,SAAU,GAAG;AAAE,UAAO,KAAK,CAAC,GAAG,EAAE,CAAC;;;CAC5D,SAAS,KAAK,IAAI;AACd,MAAI,EAAG,OAAM,IAAI,UAAU,kCAAkC;AAC7D,SAAO,MAAM,IAAI,GAAG,GAAG,OAAO,IAAI,KAAK,EAAG,KAAI;AAC1C,OAAI,IAAI,GAAG,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE,YAAY,GAAG,KAAK,EAAE,cAAc,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,GAAG,GAAG,GAAG,EAAE,KAAM,QAAO;AAC3J,OAAI,IAAI,GAAG,EAAG,MAAK,CAAC,GAAG,KAAK,GAAG,EAAE,MAAM;AACvC,WAAQ,GAAG,IAAX;IACI,KAAK;IAAG,KAAK;AAAG,SAAI;AAAI;IACxB,KAAK;AAAG,OAAE;AAAS,YAAO;MAAE,OAAO,GAAG;MAAI,MAAM;MAAO;IACvD,KAAK;AAAG,OAAE;AAAS,SAAI,GAAG;AAAI,UAAK,CAAC,EAAE;AAAE;IACxC,KAAK;AAAG,UAAK,EAAE,IAAI,KAAK;AAAE,OAAE,KAAK,KAAK;AAAE;IACxC;AACI,SAAI,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,SAAS,KAAK,EAAE,EAAE,SAAS,QAAQ,GAAG,OAAO,KAAK,GAAG,OAAO,IAAI;AAAE,UAAI;AAAG;;AACjG,SAAI,GAAG,OAAO,MAAM,CAAC,KAAM,GAAG,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,KAAM;AAAE,QAAE,QAAQ,GAAG;AAAI;;AAC9E,SAAI,GAAG,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI;AAAE,QAAE,QAAQ,EAAE;AAAI,UAAI;AAAI;;AAC7D,SAAI,KAAK,EAAE,QAAQ,EAAE,IAAI;AAAE,QAAE,QAAQ,EAAE;AAAI,QAAE,IAAI,KAAK,GAAG;AAAE;;AAC3D,SAAI,EAAE,GAAI,GAAE,IAAI,KAAK;AACrB,OAAE,KAAK,KAAK;AAAE;;AAEtB,QAAK,KAAK,KAAK,SAAS,EAAE;WACrB,GAAG;AAAE,QAAK,CAAC,GAAG,EAAE;AAAE,OAAI;YAAa;AAAE,OAAI,IAAI;;AACtD,MAAI,GAAG,KAAK,EAAG,OAAM,GAAG;AAAI,SAAO;GAAE,OAAO,GAAG,KAAK,GAAG,KAAK,KAAK;GAAG,MAAM;GAAM;;;AAgBtF,SAAgB,aAAa,GAAG,GAAG;AACjC,MAAK,IAAI,KAAK,EAAG,KAAI,MAAM,aAAa,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,iBAAgB,GAAG,GAAG,EAAE;;AAG/G,SAAgB,SAAS,GAAG;CAC1B,IAAI,IAAI,OAAO,WAAW,cAAc,OAAO,UAAU,IAAI,KAAK,EAAE,IAAI,IAAI;AAC5E,KAAI,EAAG,QAAO,EAAE,KAAK,EAAE;AACvB,KAAI,KAAK,OAAO,EAAE,WAAW,SAAU,QAAO,EAC1C,MAAM,WAAY;AACd,MAAI,KAAK,KAAK,EAAE,OAAQ,KAAI,KAAK;AACjC,SAAO;GAAE,OAAO,KAAK,EAAE;GAAM,MAAM,CAAC;GAAG;IAE9C;AACD,OAAM,IAAI,UAAU,IAAI,4BAA4B,kCAAkC;;AAGxF,SAAgB,OAAO,GAAG,GAAG;CAC3B,IAAI,IAAI,OAAO,WAAW,cAAc,EAAE,OAAO;AACjD,KAAI,CAAC,EAAG,QAAO;CACf,IAAI,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE;AAC/B,KAAI;AACA,UAAQ,MAAM,KAAK,KAAK,MAAM,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAM,IAAG,KAAK,EAAE,MAAM;UAEvE,OAAO;AAAE,MAAI,EAAS,OAAO;WAC5B;AACJ,MAAI;AACA,OAAI,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,WAAY,GAAE,KAAK,EAAE;YAE5C;AAAE,OAAI,EAAG,OAAM,EAAE;;;AAE7B,QAAO;;;AAIT,SAAgB,WAAW;AACzB,MAAK,IAAI,KAAK,EAAE,EAAE,IAAI,GAAG,IAAI,UAAU,QAAQ,IAC3C,MAAK,GAAG,OAAO,OAAO,UAAU,GAAG,CAAC;AACxC,QAAO;;;AAIT,SAAgB,iBAAiB;AAC/B,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,UAAU,QAAQ,IAAI,IAAI,IAAK,MAAK,UAAU,GAAG;AAC7E,MAAK,IAAI,IAAI,MAAM,EAAE,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,IACzC,MAAK,IAAI,IAAI,UAAU,IAAI,IAAI,GAAG,KAAK,EAAE,QAAQ,IAAI,IAAI,KAAK,IAC1D,GAAE,KAAK,EAAE;AACjB,QAAO;;AAGT,SAAgB,cAAc,IAAI,MAAM,MAAM;AAC5C,KAAI,QAAQ,UAAU,WAAW;OAAQ,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAI,IAAI,GAAG,IAC5E,KAAI,MAAM,EAAE,KAAK,OAAO;AACpB,OAAI,CAAC,GAAI,MAAK,MAAM,UAAU,MAAM,KAAK,MAAM,GAAG,EAAE;AACpD,MAAG,KAAK,KAAK;;;AAGrB,QAAO,GAAG,OAAO,MAAM,MAAM,UAAU,MAAM,KAAK,KAAK,CAAC;;AAG1D,SAAgB,QAAQ,GAAG;AACzB,QAAO,gBAAgB,WAAW,KAAK,IAAI,GAAG,QAAQ,IAAI,QAAQ,EAAE;;AAGtE,SAAgB,iBAAiB,SAAS,YAAY,WAAW;AAC/D,KAAI,CAAC,OAAO,cAAe,OAAM,IAAI,UAAU,uCAAuC;CACtF,IAAI,IAAI,UAAU,MAAM,SAAS,cAAc,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE;AAC7D,QAAO,IAAI,OAAO,QAAQ,OAAO,kBAAkB,aAAa,gBAAgB,QAAQ,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,YAAY,EAAE,EAAE,OAAO,iBAAiB,WAAY;AAAE,SAAO;IAAS;CACtN,SAAS,YAAY,GAAG;AAAE,SAAO,SAAU,GAAG;AAAE,UAAO,QAAQ,QAAQ,EAAE,CAAC,KAAK,GAAG,OAAO;;;CACzF,SAAS,KAAK,GAAG,GAAG;AAAE,MAAI,EAAE,IAAI;AAAE,KAAE,KAAK,SAAU,GAAG;AAAE,WAAO,IAAI,QAAQ,SAAU,GAAG,GAAG;AAAE,OAAE,KAAK;MAAC;MAAG;MAAG;MAAG;MAAE,CAAC,GAAG,KAAK,OAAO,GAAG,EAAE;MAAI;;AAAK,OAAI,EAAG,GAAE,KAAK,EAAE,EAAE,GAAG;;;CACnK,SAAS,OAAO,GAAG,GAAG;AAAE,MAAI;AAAE,QAAK,EAAE,GAAG,EAAE,CAAC;WAAW,GAAG;AAAE,UAAO,EAAE,GAAG,IAAI,EAAE;;;CAC7E,SAAS,KAAK,GAAG;AAAE,IAAE,iBAAiB,UAAU,QAAQ,QAAQ,EAAE,MAAM,EAAE,CAAC,KAAK,SAAS,OAAO,GAAG,OAAO,EAAE,GAAG,IAAI,EAAE;;CACrH,SAAS,QAAQ,OAAO;AAAE,SAAO,QAAQ,MAAM;;CAC/C,SAAS,OAAO,OAAO;AAAE,SAAO,SAAS,MAAM;;CAC/C,SAAS,OAAO,GAAG,GAAG;AAAE,MAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,OAAQ,QAAO,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG;;;AAGjF,SAAgB,iBAAiB,GAAG;CAClC,IAAI,GAAG;AACP,QAAO,IAAI,EAAE,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,SAAU,GAAG;AAAE,QAAM;GAAK,EAAE,KAAK,SAAS,EAAE,EAAE,OAAO,YAAY,WAAY;AAAE,SAAO;IAAS;CAC1I,SAAS,KAAK,GAAG,GAAG;AAAE,IAAE,KAAK,EAAE,KAAK,SAAU,GAAG;AAAE,WAAQ,IAAI,CAAC,KAAK;IAAE,OAAO,QAAQ,EAAE,GAAG,EAAE,CAAC;IAAE,MAAM;IAAO,GAAG,IAAI,EAAE,EAAE,GAAG;MAAO;;;AAGpI,SAAgB,cAAc,GAAG;AAC/B,KAAI,CAAC,OAAO,cAAe,OAAM,IAAI,UAAU,uCAAuC;CACtF,IAAI,IAAI,EAAE,OAAO,gBAAgB;AACjC,QAAO,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,OAAO,aAAa,aAAa,SAAS,EAAE,GAAG,EAAE,OAAO,WAAW,EAAE,IAAI,EAAE,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,OAAO,iBAAiB,WAAY;AAAE,SAAO;IAAS;CAC9M,SAAS,KAAK,GAAG;AAAE,IAAE,KAAK,EAAE,MAAM,SAAU,GAAG;AAAE,UAAO,IAAI,QAAQ,SAAU,SAAS,QAAQ;AAAE,QAAI,EAAE,GAAG,EAAE,EAAE,OAAO,SAAS,QAAQ,EAAE,MAAM,EAAE,MAAM;KAAI;;;CAC1J,SAAS,OAAO,SAAS,QAAQ,GAAG,GAAG;AAAE,UAAQ,QAAQ,EAAE,CAAC,KAAK,SAAS,GAAG;AAAE,WAAQ;IAAE,OAAO;IAAG,MAAM;IAAG,CAAC;KAAK,OAAO;;;AAG3H,SAAgB,qBAAqB,QAAQ,KAAK;AAChD,KAAI,OAAO,eAAkB,QAAO,eAAe,QAAQ,OAAO,EAAE,OAAO,KAAK,CAAC;KAAW,QAAO,MAAM;AACzG,QAAO;;AAkBT,SAAgB,aAAa,KAAK;AAChC,KAAI,OAAO,IAAI,WAAY,QAAO;CAClC,IAAI,SAAS,EAAE;AACf,KAAI,OAAO;OAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,KAAI,EAAE,OAAO,UAAW,iBAAgB,QAAQ,KAAK,EAAE,GAAG;;AAChI,oBAAmB,QAAQ,IAAI;AAC/B,QAAO;;AAGT,SAAgB,gBAAgB,KAAK;AACnC,QAAQ,OAAO,IAAI,aAAc,MAAM,EAAE,SAAS,KAAK;;AAGzD,SAAgB,uBAAuB,UAAU,OAAO,MAAM,GAAG;AAC/D,KAAI,SAAS,OAAO,CAAC,EAAG,OAAM,IAAI,UAAU,gDAAgD;AAC5F,KAAI,OAAO,UAAU,aAAa,aAAa,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,SAAS,CAAE,OAAM,IAAI,UAAU,2EAA2E;AAClL,QAAO,SAAS,MAAM,IAAI,SAAS,MAAM,EAAE,KAAK,SAAS,GAAG,IAAI,EAAE,QAAQ,MAAM,IAAI,SAAS;;AAG/F,SAAgB,uBAAuB,UAAU,OAAO,OAAO,MAAM,GAAG;AACtE,KAAI,SAAS,IAAK,OAAM,IAAI,UAAU,iCAAiC;AACvE,KAAI,SAAS,OAAO,CAAC,EAAG,OAAM,IAAI,UAAU,gDAAgD;AAC5F,KAAI,OAAO,UAAU,aAAa,aAAa,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,SAAS,CAAE,OAAM,IAAI,UAAU,0EAA0E;AACjL,QAAQ,SAAS,MAAM,EAAE,KAAK,UAAU,MAAM,GAAG,IAAI,EAAE,QAAQ,QAAQ,MAAM,IAAI,UAAU,MAAM,EAAG;;AAGtG,SAAgB,sBAAsB,OAAO,UAAU;AACrD,KAAI,aAAa,QAAS,OAAO,aAAa,YAAY,OAAO,aAAa,WAAa,OAAM,IAAI,UAAU,yCAAyC;AACxJ,QAAO,OAAO,UAAU,aAAa,aAAa,QAAQ,MAAM,IAAI,SAAS;;AAG/E,SAAgB,wBAAwB,KAAK,OAAO,OAAO;AACzD,KAAI,UAAU,QAAQ,UAAU,KAAK,GAAG;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAAY,OAAM,IAAI,UAAU,mBAAmB;EACrG,IAAI,SAAS;AACb,MAAI,OAAO;AACT,OAAI,CAAC,OAAO,aAAc,OAAM,IAAI,UAAU,sCAAsC;AACpF,aAAU,MAAM,OAAO;;AAEzB,MAAI,YAAY,KAAK,GAAG;AACtB,OAAI,CAAC,OAAO,QAAS,OAAM,IAAI,UAAU,iCAAiC;AAC1E,aAAU,MAAM,OAAO;AACvB,OAAI,MAAO,SAAQ;;AAErB,MAAI,OAAO,YAAY,WAAY,OAAM,IAAI,UAAU,yBAAyB;AAChF,MAAI,MAAO,WAAU,WAAW;AAAE,OAAI;AAAE,UAAM,KAAK,KAAK;YAAW,GAAG;AAAE,WAAO,QAAQ,OAAO,EAAE;;;AAChG,MAAI,MAAM,KAAK;GAAS;GAAgB;GAAgB;GAAO,CAAC;YAEzD,MACP,KAAI,MAAM,KAAK,EAAE,OAAO,MAAM,CAAC;AAEjC,QAAO;;AAQT,SAAgB,mBAAmB,KAAK;CACtC,SAAS,KAAK,GAAG;AACf,MAAI,QAAQ,IAAI,WAAW,IAAI,iBAAiB,GAAG,IAAI,OAAO,2CAA2C,GAAG;AAC5G,MAAI,WAAW;;CAEjB,IAAI,GAAG,IAAI;CACX,SAAS,OAAO;AACd,SAAO,IAAI,IAAI,MAAM,KAAK,CACxB,KAAI;AACF,OAAI,CAAC,EAAE,SAAS,MAAM,EAAG,QAAO,IAAI,GAAG,IAAI,MAAM,KAAK,EAAE,EAAE,QAAQ,SAAS,CAAC,KAAK,KAAK;AACtF,OAAI,EAAE,SAAS;IACb,IAAI,SAAS,EAAE,QAAQ,KAAK,EAAE,MAAM;AACpC,QAAI,EAAE,MAAO,QAAO,KAAK,GAAG,QAAQ,QAAQ,OAAO,CAAC,KAAK,MAAM,SAAS,GAAG;AAAE,UAAK,EAAE;AAAE,YAAO,MAAM;MAAI;SAEpG,MAAK;WAEL,GAAG;AACR,QAAK,EAAE;;AAGX,MAAI,MAAM,EAAG,QAAO,IAAI,WAAW,QAAQ,OAAO,IAAI,MAAM,GAAG,QAAQ,SAAS;AAChF,MAAI,IAAI,SAAU,OAAM,IAAI;;AAE9B,QAAO,MAAM;;AAGf,SAAgB,iCAAiC,MAAM,aAAa;AAClE,KAAI,OAAO,SAAS,YAAY,WAAW,KAAK,KAAK,CACjD,QAAO,KAAK,QAAQ,oDAAoD,SAAU,GAAG,KAAK,GAAG,KAAK,IAAI;AAClG,SAAO,MAAM,cAAc,SAAS,QAAQ,MAAM,CAAC,OAAO,CAAC,MAAM,IAAK,IAAI,MAAM,MAAM,GAAG,aAAa,GAAG;GAC3G;AAEN,QAAO;;;;AA5VL,iBAAgB,SAAS,GAAG,GAAG;AACjC,kBAAgB,OAAO,kBAClB,EAAE,WAAW,EAAE,EAAE,YAAY,SAAS,SAAU,GAAG,GAAG;AAAE,KAAE,YAAY;OACvE,SAAU,GAAG,GAAG;AAAE,QAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,GAAE,KAAK,EAAE;;AAChG,SAAO,cAAc,GAAG,EAAE;;AAWjB,YAAW,WAAW;AAC/B,aAAW,OAAO,UAAU,SAAS,SAAS,GAAG;AAC7C,QAAK,IAAI,GAAG,IAAI,GAAG,IAAI,UAAU,QAAQ,IAAI,GAAG,KAAK;AACjD,QAAI,UAAU;AACd,SAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,GAAE,KAAK,EAAE;;AAE9E,UAAO;;AAEX,SAAO,SAAS,MAAM,MAAM,UAAU;;AAiH7B,mBAAkB,OAAO,UAAU,SAAS,GAAG,GAAG,GAAG,IAAI;AAClE,MAAI,OAAO,KAAA,EAAW,MAAK;EAC3B,IAAI,OAAO,OAAO,yBAAyB,GAAG,EAAE;AAChD,MAAI,CAAC,SAAS,SAAS,OAAO,CAAC,EAAE,aAAa,KAAK,YAAY,KAAK,cAChE,QAAO;GAAE,YAAY;GAAM,KAAK,WAAW;AAAE,WAAO,EAAE;;GAAO;AAEjE,SAAO,eAAe,GAAG,IAAI,KAAK;OAC9B,SAAS,GAAG,GAAG,GAAG,IAAI;AAC1B,MAAI,OAAO,KAAA,EAAW,MAAK;AAC3B,IAAE,MAAM,EAAE;;AAkGR,sBAAqB,OAAO,UAAU,SAAS,GAAG,GAAG;AACvD,SAAO,eAAe,GAAG,WAAW;GAAE,YAAY;GAAM,OAAO;GAAG,CAAC;MAChE,SAAS,GAAG,GAAG;AAClB,IAAE,aAAa;;AAGb,WAAU,SAAS,GAAG;AACxB,YAAU,OAAO,uBAAuB,SAAU,GAAG;GACnD,IAAI,KAAK,EAAE;AACX,QAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,IAAG,GAAG,UAAU;AACjF,UAAO;;AAET,SAAO,QAAQ,EAAE;;AAwDf,oBAAmB,OAAO,oBAAoB,aAAa,kBAAkB,SAAU,OAAO,YAAY,SAAS;EACrH,IAAI,IAAI,IAAI,MAAM,QAAQ;AAC1B,SAAO,EAAE,OAAO,mBAAmB,EAAE,QAAQ,OAAO,EAAE,aAAa,YAAY;;qBAsClE;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;;;;AChZD,EAAC,SAAU,QAAQ,SAAS;AACxB,SAAO,YAAY,YAAY,OAAO,WAAW,cAAc,QAAQ,UAAA,gBAAA,EAAA,aAAA,kBAAA,GAAA,iBAAA,CAA8C,GACrH,OAAO,WAAW,cAAc,OAAO,MAAM,OAAO;GAAC;GAAW;GAAS;GAAU,EAAE,QAAQ,IAC5F,SAAS,OAAO,eAAe,cAAc,aAAa,UAAU,MAAM,QAAQ,OAAO,iBAAiB,EAAE,EAAE,OAAO,OAAO,OAAO,QAAQ;cACvI,SAAU,WAAS,OAAO,SAAS;AAAE;EAE1C,IAAI,2BAAW,IAAI,KAAK;EACxB,IAAI,oCAAoB,IAAI,KAAK;EACjC,IAAI,wBAAwB;EAC5B,IAAI,gCAAgC;EACpC,SAAS,UAAU,QAAQ;AACvB,UAAO,OAAO,QAAQ,WAAW,IAAI,CAAC,MAAM;;EAEhD,SAAS,gBAAgB,KAAK;AAC1B,UAAO,UAAU,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,IAAI,IAAI,CAAC;;EAEnE,SAAS,iBAAiB,KAAK;GAC3B,IAAI,2BAAW,IAAI,KAAK;GACxB,IAAI,cAAc,EAAE;AACpB,OAAI,YAAY,QAAQ,SAAU,oBAAoB;AAClD,QAAI,mBAAmB,SAAS,sBAAsB;KAClD,IAAI,eAAe,mBAAmB,KAAK;KAC3C,IAAI,YAAY,gBAAgB,mBAAmB,IAAI;KACvD,IAAI,eAAe,kBAAkB,IAAI,aAAa;AACtD,SAAI,gBAAgB,CAAC,aAAa,IAAI,UAAU;UACxC,sBACA,SAAQ,KAAK,iCAAiC,eAAe,gMAEwB;gBAGpF,CAAC,aACN,mBAAkB,IAAI,cAAc,+BAAe,IAAI,KAAG,CAAC;AAE/D,kBAAa,IAAI,UAAU;AAC3B,SAAI,CAAC,SAAS,IAAI,UAAU,EAAE;AAC1B,eAAS,IAAI,UAAU;AACvB,kBAAY,KAAK,mBAAmB;;UAIxC,aAAY,KAAK,mBAAmB;KAE1C;AACF,UAAO,MAAM,SAAS,MAAM,SAAS,EAAE,EAAE,IAAI,EAAE,EAAe,aAAa,CAAC;;EAEhF,SAAS,SAAS,KAAK;GACnB,IAAI,UAAU,IAAI,IAAI,IAAI,YAAY;AACtC,WAAQ,QAAQ,SAAU,MAAM;AAC5B,QAAI,KAAK,IACL,QAAO,KAAK;AAChB,WAAO,KAAK,KAAK,CAAC,QAAQ,SAAU,KAAK;KACrC,IAAI,QAAQ,KAAK;AACjB,SAAI,SAAS,OAAO,UAAU,SAC1B,SAAQ,IAAI,MAAM;MAExB;KACJ;GACF,IAAI,MAAM,IAAI;AACd,OAAI,KAAK;AACL,WAAO,IAAI;AACX,WAAO,IAAI;;AAEf,UAAO;;EAEX,SAAS,cAAc,QAAQ;GAC3B,IAAI,WAAW,UAAU,OAAO;AAChC,OAAI,CAAC,SAAS,IAAI,SAAS,EAAE;IACzB,IAAI,SAAS,QAAQ,MAAM,QAAQ;KACA;KAC/B,8BAA8B;KACjC,CAAC;AACF,QAAI,CAAC,UAAU,OAAO,SAAS,WAC3B,OAAM,IAAI,MAAM,gCAAgC;AAEpD,aAAS,IAAI,UAAU,SAAS,iBAAiB,OAAO,CAAC,CAAC;;AAE9D,UAAO,SAAS,IAAI,SAAS;;EAEjC,SAAS,IAAI,UAAU;GACnB,IAAI,OAAO,EAAE;AACb,QAAK,IAAI,KAAK,GAAG,KAAK,UAAU,QAAQ,KACpC,MAAK,KAAK,KAAK,UAAU;AAE7B,OAAI,OAAO,aAAa,SACpB,YAAW,CAAC,SAAS;GAEzB,IAAI,SAAS,SAAS;AACtB,QAAK,QAAQ,SAAU,KAAK,GAAG;AAC3B,QAAI,OAAO,IAAI,SAAS,WACpB,WAAU,IAAI,IAAI,OAAO;QAGzB,WAAU;AAEd,cAAU,SAAS,IAAI;KACzB;AACF,UAAO,cAAc,OAAO;;EAEhC,SAAS,cAAc;AACnB,YAAS,OAAO;AAChB,qBAAkB,OAAO;;EAE7B,SAAS,0BAA0B;AAC/B,2BAAwB;;EAE5B,SAAS,sCAAsC;AAC3C,mCAAgC;;EAEpC,SAAS,uCAAuC;AAC5C,mCAAgC;;EAEpC,IAAI,SAAS;GACJ;GACQ;GACY;GACY;GACC;GACzC;AACD,GAAC,SAAU,OAAO;AACd,SAAM,MAAM,OAAO,KAAK,MAAM,cAAc,OAAO,aAAa,MAAM,0BAA0B,OAAO,yBAAyB,MAAM,sCAAsC,OAAO,qCAAqC,MAAM,uCAAuC,OAAO;KAC7Q,QAAQ,MAAM,EAAE,EAAE;AACrB,MAAI,aAAa;AAGjB,YAAQ,UAFI;AAGZ,YAAQ,uCAAuC;AAC/C,YAAQ,0BAA0B;AAClC,YAAQ,sCAAsC;AAC9C,YAAQ,MAAM;AACd,YAAQ,cAAc;AAEtB,SAAO,eAAeA,WAAS,cAAc,EAAE,OAAO,MAAM,CAAC;IAE9D;;;;;ACpIH,QAAO,UAAA,yBAAA,CAA8C"}
|
|
1
|
+
{"version":3,"file":"main-B1tRsYOp.mjs","names":["exports"],"sources":["../../../reactor/dist/drive-container-types-yZrksiJR.js","../../../reactor/dist/index.js","../../../../node_modules/.pnpm/tslib@2.8.1/node_modules/tslib/tslib.es6.mjs","../../../../node_modules/.pnpm/graphql-tag@2.12.6_graphql@16.12.0/node_modules/graphql-tag/lib/graphql-tag.umd.js","../../../../node_modules/.pnpm/graphql-tag@2.12.6_graphql@16.12.0/node_modules/graphql-tag/main.js"],"sourcesContent":["import { n as ReactorEventTypes, t as EventBusAggregateError } from \"./types-DMKLa0Ok.js\";\nimport { AUTH_ACTION_TYPES, AUTH_DENIED_BY_GRANT_REASON, AUTH_NO_GRANT_REASON, AUTH_VERSION_UNSUPPORTED_REASON, DOCUMENT_DELETED_REASON, DowngradeNotSupportedError as DowngradeNotSupportedError$1, appendWithoutApplying, applyAuthAction, applyDeleteDocumentAction, applyDeleteDocumentAction as applyDeleteDocumentAction$1, applyUpgradeDocumentAction, applyUpgradeDocumentAction as applyUpgradeDocumentAction$1, baseReducerVersion, createPresignedHeader, decide, defaultBaseState, deriveOperationId, evaluate, garbageCollect, groupDocumentType, groupMembershipActionTypes, hashDocumentStateForScope, isDenied, isUndoRedo, mentionedGroupIds, normalizeDocumentModelVersion, referencedGroupIds, sortOperations } from \"@powerhousedao/shared/document-model\";\nimport { v4 } from \"uuid\";\nimport { Migrator, sql } from \"kysely\";\n//#region \\0rolldown/runtime.js\nvar __defProp = Object.defineProperty;\nvar __exportAll = (all, no_symbols) => {\n\tlet target = {};\n\tfor (var name in all) __defProp(target, name, {\n\t\tget: all[name],\n\t\tenumerable: true\n\t});\n\tif (!no_symbols) __defProp(target, Symbol.toStringTag, { value: \"Module\" });\n\treturn target;\n};\n//#endregion\n//#region src/shared/utils.ts\nfunction matchesScope(view = {}, scope) {\n\tif (view.scopes) return view.scopes.includes(scope);\n\treturn true;\n}\nfunction yieldToMain() {\n\tconst s = globalThis.scheduler;\n\tif (s?.yield) return s.yield();\n\treturn new Promise((resolve) => setTimeout(resolve, 0));\n}\nconst defaultAbortError = () => /* @__PURE__ */ new Error(\"Operation aborted\");\nfunction throwIfAborted(signal, makeError = defaultAbortError) {\n\tif (signal?.aborted) throw makeError();\n}\n/**\n* Validates PagingOptions and returns a normalized offset and limit.\n* Throws if the cursor is not empty and not a non-negative integer, or if\n* limit is less than 1. When `paging` is undefined, returns offset 0 and\n* the caller-supplied `defaultLimit`.\n*/\nfunction parsePagingOptions(paging, defaultLimit) {\n\tif (paging === void 0) return {\n\t\toffset: 0,\n\t\tlimit: defaultLimit\n\t};\n\tif (!Number.isInteger(paging.limit) || paging.limit < 1) throw new Error(`Invalid paging limit: ${String(paging.limit)} (must be an integer >= 1)`);\n\tif (paging.cursor === \"\") return {\n\t\toffset: 0,\n\t\tlimit: paging.limit\n\t};\n\tconst parsed = Number(paging.cursor);\n\tif (!Number.isInteger(parsed) || parsed < 0) throw new Error(`Invalid paging cursor: ${JSON.stringify(paging.cursor)} (must be empty or a non-negative integer)`);\n\treturn {\n\t\toffset: parsed,\n\t\tlimit: paging.limit\n\t};\n}\n//#endregion\n//#region src/shared/errors.ts\n/**\n* Error thrown when attempting to access a deleted document.\n*/\nvar DocumentDeletedError = class DocumentDeletedError extends Error {\n\tdocumentId;\n\tdeletedAtUtcIso;\n\tconstructor(documentId, deletedAtUtcIso = null) {\n\t\tconst message = deletedAtUtcIso ? `Document ${documentId} was deleted at ${deletedAtUtcIso}` : `Document ${documentId} has been deleted`;\n\t\tsuper(message);\n\t\tthis.name = \"DocumentDeletedError\";\n\t\tthis.documentId = documentId;\n\t\tthis.deletedAtUtcIso = deletedAtUtcIso;\n\t\tError.captureStackTrace(this, DocumentDeletedError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DocumentDeletedError\";\n\t}\n};\n/**\n* Error thrown when the auth policy denies an action at the executor gate.\n*/\nvar AuthorizationDeniedError = class AuthorizationDeniedError extends Error {\n\tdocumentId;\n\tscope;\n\toperation;\n\tsubject;\n\tconstructor(documentId, scope, operation, subject) {\n\t\tsuper(`Authorization denied: ${subject ?? \"anonymous\"} may not execute ${operation} in scope \"${scope}\" of document ${documentId}`);\n\t\tthis.name = \"AuthorizationDeniedError\";\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.operation = operation;\n\t\tthis.subject = subject;\n\t\tError.captureStackTrace(this, AuthorizationDeniedError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AuthorizationDeniedError\";\n\t}\n};\n/**\n* An auth operation did not strictly exceed the newest timestamp in its stream.\n*\n* Terminal and asymmetric by design: no ordering rule can reconcile two replicas\n* that each accepted an auth operation offline, because either order hands one\n* authority the other never granted, so the replica ahead holds the arrival.\n*/\nvar AuthTimestampNotMonotonicError = class AuthTimestampNotMonotonicError extends Error {\n\tdocumentId;\n\tbranch;\n\ttimestampUtcMs;\n\tnewestTimestampUtcMs;\n\tconstructor(documentId, branch, timestampUtcMs, newestTimestampUtcMs) {\n\t\tsuper(`Auth timestamp not monotonic: ${timestampUtcMs} does not exceed ${newestTimestampUtcMs} in the auth stream of document ${documentId} on branch ${branch}`);\n\t\tthis.name = \"AuthTimestampNotMonotonicError\";\n\t\tthis.documentId = documentId;\n\t\tthis.branch = branch;\n\t\tthis.timestampUtcMs = timestampUtcMs;\n\t\tthis.newestTimestampUtcMs = newestTimestampUtcMs;\n\t\tError.captureStackTrace(this, AuthTimestampNotMonotonicError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AuthTimestampNotMonotonicError\";\n\t}\n};\n/**\n* An operation or action carried a timestamp that is not an ISO-8601 UTC\n* instant.\n*\n* Terminal rather than retryable: the value does not change between attempts,\n* so a retry re-runs the whole job to fail identically. Quarantining, unlike a\n* held auth operation — this is malformed data rather than two replicas\n* disagreeing, and nothing further from that source should be trusted until it\n* is looked at.\n*/\nvar InvalidOperationTimestampError = class InvalidOperationTimestampError extends Error {\n\tdocumentId;\n\tscope;\n\ttimestampUtcMs;\n\tconstructor(documentId, scope, timestampUtcMs, context) {\n\t\tsuper(`Invalid timestamp \"${timestampUtcMs}\" on ${context} in scope \"${scope}\" of document ${documentId}`);\n\t\tthis.name = \"InvalidOperationTimestampError\";\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.timestampUtcMs = timestampUtcMs;\n\t\tError.captureStackTrace(this, InvalidOperationTimestampError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"InvalidOperationTimestampError\";\n\t}\n};\n/**\n* A load would move more operations than the bound allows, indicating a real\n* divergence between local and incoming history. Counts only first-time moves,\n* so a re-evaluation pass's re-appends do not make busy documents\n* revocation-proof. Terminal: the condition is deterministic.\n*/\nvar ExcessiveReshuffleError = class ExcessiveReshuffleError extends Error {\n\tdocumentId;\n\tscope;\n\tcount;\n\tthreshold;\n\tconstructor(documentId, scope, count, threshold) {\n\t\tsuper(`Excessive reshuffle detected: ${count} operations in scope \"${scope}\" of document ${documentId} exceeds the threshold of ${threshold}. This indicates a significant divergence between local and incoming operations.`);\n\t\tthis.name = \"ExcessiveReshuffleError\";\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.count = count;\n\t\tthis.threshold = threshold;\n\t\tError.captureStackTrace(this, ExcessiveReshuffleError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"ExcessiveReshuffleError\";\n\t}\n};\n/**\n* Error thrown when an operation has an invalid signature.\n*/\nvar InvalidSignatureError = class InvalidSignatureError extends Error {\n\tdocumentId;\n\treason;\n\tconstructor(documentId, reason) {\n\t\tsuper(`Invalid signature in document ${documentId}: ${reason}`);\n\t\tthis.name = \"InvalidSignatureError\";\n\t\tthis.documentId = documentId;\n\t\tthis.reason = reason;\n\t\tError.captureStackTrace(this, InvalidSignatureError);\n\t}\n};\n/**\n* An UPGRADE_DOCUMENT action's preconditions (fromVersion and the per-scope\n* revision snapshot) did not match the document state the executor loaded.\n*\n* Terminal rather than retryable: the action carries the client's snapshot,\n* which stays stale no matter how often the job re-runs. The client is\n* expected to re-read the document and submit a fresh action instead.\n*/\nvar UpgradePreconditionFailedError = class UpgradePreconditionFailedError extends Error {\n\tdocumentId;\n\tdetail;\n\tconstructor(documentId, detail) {\n\t\tsuper(`Upgrade precondition failed for document ${documentId}: ${detail}`);\n\t\tthis.name = \"UpgradePreconditionFailedError\";\n\t\tthis.documentId = documentId;\n\t\tthis.detail = detail;\n\t\tError.captureStackTrace(this, UpgradePreconditionFailedError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"UpgradePreconditionFailedError\";\n\t}\n};\n/**\n* Error thrown when a document is not found (no operations exist for the document ID).\n*/\nvar DocumentNotFoundError = class DocumentNotFoundError extends Error {\n\tdocumentId;\n\t/**\n\t* @param message Overrides the default text. A handler that knows which of\n\t* several documents an action reads - a relationship's source, say - says so\n\t* here rather than rewrapping in a bare Error, which would strip the name the\n\t* executor classifies by.\n\t*/\n\tconstructor(documentId, message) {\n\t\tsuper(message ?? `Document ${documentId} not found`);\n\t\tthis.name = \"DocumentNotFoundError\";\n\t\tthis.documentId = documentId;\n\t\tError.captureStackTrace(this, DocumentNotFoundError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DocumentNotFoundError\";\n\t}\n};\n/**\n* An authorization preflight was asked for while the reactor's decision model\n* is off, so there is no model to answer from.\n*\n* Thrown rather than answered from the legacy host-side permission tables. The\n* two systems do not compose: the tables record which addresses a host lets\n* near a drive, the policy records what a document's own grants permit, and an\n* answer stitched from both would report an admission verdict neither system\n* would reach. A caller that cannot get a prediction disables nothing, which\n* leaves the submit path -- and its real gate -- as the only authority.\n*\n* Detection is by `name`, not `instanceof`: the SharedWorker RPC boundary\n* rebuilds a thrown error from `{ name, message, stack, cause }` alone\n* (`reactor-browser/src/rpc/error-info.ts`), so the class identity and any\n* custom field are lost in transit. This error therefore carries no fields.\n*/\nvar AuthEnforcementDisabledError = class AuthEnforcementDisabledError extends Error {\n\tconstructor() {\n\t\tsuper(\"Authorization evaluation requires the authEnforcement feature flag; this reactor holds no decision model, and the legacy host-table permission system cannot answer for one\");\n\t\tthis.name = \"AuthEnforcementDisabledError\";\n\t\tError.captureStackTrace(this, AuthEnforcementDisabledError);\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AuthEnforcementDisabledError\";\n\t}\n};\n//#endregion\n//#region src/storage/interfaces.ts\n/**\n* Thrown when an operation with the same identity already exists in the store.\n*/\nvar DuplicateOperationError = class extends Error {\n\tconstructor(description) {\n\t\tsuper(`Duplicate operation: ${description}`);\n\t\tthis.name = \"DuplicateOperationError\";\n\t}\n};\n/**\n* Thrown when a concurrent write conflict is detected during an atomic apply.\n*/\nvar OptimisticLockError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message);\n\t\tthis.name = \"OptimisticLockError\";\n\t}\n};\n/**\n* Thrown when the caller-provided revision does not match the current\n* stored revision, indicating a stale read.\n*/\nvar RevisionMismatchError = class extends Error {\n\tconstructor(expected, actual) {\n\t\tsuper(`Revision mismatch: expected ${expected}, got ${actual}`);\n\t\tthis.name = \"RevisionMismatchError\";\n\t}\n};\n/**\n* A create based on an empty stream that already has operations: the id is\n* taken, and no retry can resolve it. Matched by `name`, all the RPC boundary keeps.\n*/\nvar DocumentAlreadyExistsError = class extends Error {\n\tdocumentId;\n\tconstructor(documentId, scope, headRevision) {\n\t\tsuper(`Document ${documentId} already exists: create requested revision 0 but the \"${scope}\" stream is at revision ${headRevision}`);\n\t\tthis.name = \"DocumentAlreadyExistsError\";\n\t\tthis.documentId = documentId;\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DocumentAlreadyExistsError\";\n\t}\n};\n/** Error history keeps messages, not classes, so failures match by prefix. */\nconst APPEND_CONDITION_FAILED_PREFIX = \"Append condition failed: \";\n/**\n* A read-set stream grew before the append committed. A concurrency\n* conflict, not a fault: the caller retries against the new stream heads.\n*/\nvar AppendConditionFailedError = class extends Error {\n\tconstructor(condition) {\n\t\tconst streams = condition.streams.map((s) => `${s.documentId}:${s.scope}:${s.branch}@${s.revision}`).join(\", \");\n\t\tsuper(`${APPEND_CONDITION_FAILED_PREFIX}a read-set stream advanced [${streams}]`);\n\t\tthis.condition = condition;\n\t\tthis.name = \"AppendConditionFailedError\";\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"AppendConditionFailedError\";\n\t}\n\t/** True when a recorded error message is an append-condition failure. */\n\tstatic isFailureMessage(message) {\n\t\treturn message.startsWith(APPEND_CONDITION_FAILED_PREFIX);\n\t}\n};\n/**\n* Which sense of \"exists\" a caller of {@link IDocumentView.exists} means.\n*/\nlet DocumentExistence = /* @__PURE__ */ function(DocumentExistence) {\n\t/**\n\t* A document that is present and not deleted. This is the question a read\n\t* asks: a deleted document is not readable, so it does not exist.\n\t*/\n\tDocumentExistence[\"LiveOnly\"] = \"LiveOnly\";\n\t/**\n\t* Whether the id is taken, deleted or not. This is the question a write\n\t* asks: a deleted document keeps its operation stream, so its id can never\n\t* be reused, and answering from snapshots alone would say otherwise whenever\n\t* a snapshot row is missing while the stream is intact.\n\t*/\n\tDocumentExistence[\"IncludingDeleted\"] = \"IncludingDeleted\";\n\treturn DocumentExistence;\n}({});\n//#endregion\n//#region src/decision/build-decision-model.ts\n/**\n* Reads each projection's stream through the supplied reader, recording the\n* revision observed. Static projections resolve first; derived projections\n* see only those and contribute a map from document id to state. Each\n* distinct stream is read once and yields one append condition entry.\n*/\nasync function buildDecisionModel(reader, definition, target, signal) {\n\tconst decisionModel = definition(target);\n\tconst projections = Object.entries(decisionModel.projections);\n\tconst reads = /* @__PURE__ */ new Map();\n\tconst model = {};\n\tfor (const [key, projection] of projections) {\n\t\tif (typeof projection.query === \"function\") continue;\n\t\tmodel[key] = (await readStream(reader, projection.query, reads, signal)).state;\n\t}\n\tconst staticModel = { ...model };\n\tfor (const [key, projection] of projections) {\n\t\tif (typeof projection.query !== \"function\") continue;\n\t\tconst queries = projection.query(staticModel);\n\t\tconst value = {};\n\t\tfor (const query of queries) {\n\t\t\tlet read;\n\t\t\ttry {\n\t\t\t\tread = await readStream(reader, query, reads, signal);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof DocumentNotFoundError) {\n\t\t\t\t\trecordEmptyStream(query, reads);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tvalue[query.documentId] = read.state;\n\t\t}\n\t\tmodel[key] = value;\n\t}\n\treturn {\n\t\tmodel,\n\t\tappendCondition: { streams: [...reads.values()].map((read) => read.stream) }\n\t};\n}\n/** Guards a stream that holds nothing yet: any operation appearing is growth. */\nfunction recordEmptyStream(query, reads) {\n\tconst key = `${query.documentId}:${query.scope}:${query.branch}`;\n\tif (reads.has(key)) return;\n\treads.set(key, {\n\t\tstate: void 0,\n\t\tstream: {\n\t\t\tdocumentId: query.documentId,\n\t\t\tscope: query.scope,\n\t\t\tbranch: query.branch,\n\t\t\trevision: -1\n\t\t}\n\t});\n}\nasync function readStream(reader, query, reads, signal) {\n\tconst key = `${query.documentId}:${query.scope}:${query.branch}`;\n\tconst existing = reads.get(key);\n\tif (existing) return existing;\n\tconst document = await reader.getState(query.documentId, query.scope, query.branch, void 0, signal);\n\tconst read = {\n\t\tstate: document.state[query.scope],\n\t\tstream: {\n\t\t\tdocumentId: query.documentId,\n\t\t\tscope: query.scope,\n\t\t\tbranch: query.branch,\n\t\t\trevision: observedRevision(document, query.scope)\n\t\t}\n\t};\n\treads.set(key, read);\n\treturn read;\n}\n/**\n* The highest operation index the document reflects for the scope, or -1 if\n* empty. `header.revision` is authoritative, not the rebuilt operation list.\n*/\nfunction observedRevision(document, scope) {\n\tif (scope in document.header.revision) return document.header.revision[scope] - 1;\n\tif (scope in document.operations) {\n\t\tconst operations = document.operations[scope];\n\t\tif (operations.length > 0) return operations[operations.length - 1].index;\n\t}\n\tif (!(scope in document.header.revision)) return -1;\n\treturn document.header.revision[scope] - 1;\n}\n/**\n* The projections whose queries depend on folded state. A positional walk\n* resolves their streams through `queryOverHistory`; a projection without one\n* contributes no streams to a walk.\n*/\nfunction derivedReadSet(definition) {\n\tconst projections = [];\n\tfor (const [name, projection] of Object.entries(definition.projections)) {\n\t\tif (typeof projection.query !== \"function\") continue;\n\t\tprojections.push({\n\t\t\tname,\n\t\t\tdecidingActions: projection.decidingActions,\n\t\t\tapply: projection.apply,\n\t\t\tqueryOverHistory: projection.queryOverHistory\n\t\t});\n\t}\n\treturn projections;\n}\n/**\n* The streams a model reads whose queries are known before it is built. A\n* derived query needs the statically-queried projections first, so it is not\n* included here.\n*/\nfunction staticReadSet(definition) {\n\tconst streams = [];\n\tfor (const [name, projection] of Object.entries(definition.projections)) {\n\t\tif (typeof projection.query === \"function\") continue;\n\t\tstreams.push({\n\t\t\tname,\n\t\t\tquery: projection.query,\n\t\t\tdecidingActions: projection.decidingActions,\n\t\t\tapply: projection.apply\n\t\t});\n\t}\n\treturn streams;\n}\n//#endregion\n//#region src/decision/auth-decision-model.ts\nfunction refusalReason(refusal) {\n\tswitch (refusal) {\n\t\tcase \"version-unsupported\": return AUTH_VERSION_UNSUPPORTED_REASON;\n\t\tcase \"denied-by-grant\": return AUTH_DENIED_BY_GRANT_REASON;\n\t\tcase \"no-applicable-grant\": return AUTH_NO_GRANT_REASON;\n\t}\n}\nfunction decideAuthModel(model, subject, request, groups, conditions) {\n\tif (request.verb === \"execute\" && model.document.isDeleted) return {\n\t\tdecision: \"deny\",\n\t\treason: DOCUMENT_DELETED_REASON\n\t};\n\tconst evaluation = evaluate(model.auth, subject, request, groups, conditions);\n\tif (evaluation.decision === \"allow\") return { decision: \"allow\" };\n\treturn {\n\t\tdecision: \"deny\",\n\t\treason: refusalReason(evaluation.refusal)\n\t};\n}\nfunction documentProjection(target) {\n\treturn {\n\t\tdecidingActions: [\"DELETE_DOCUMENT\"],\n\t\tapply: (document, operation) => operation.action.type === \"DELETE_DOCUMENT\" ? applyDeleteDocumentAction({\n\t\t\t...document,\n\t\t\tstate: { ...document.state }\n\t\t}, operation.action) : document,\n\t\tquery: {\n\t\t\tdocumentId: target.documentId,\n\t\t\tbranch: target.branch,\n\t\t\tscope: \"document\"\n\t\t}\n\t};\n}\nfunction authProjection(target) {\n\treturn {\n\t\tdecidingActions: [...AUTH_ACTION_TYPES],\n\t\tapply: (document, operation) => applyAuthAction(document, operation.action),\n\t\tquery: {\n\t\t\tdocumentId: target.documentId,\n\t\t\tbranch: target.branch,\n\t\t\tscope: \"auth\"\n\t\t}\n\t};\n}\n/** This decision model uses both the document and the auth streams. */\nfunction authDecisionModel(target) {\n\treturn {\n\t\tprojections: {\n\t\t\tdocument: documentProjection(target),\n\t\t\tauth: authProjection(target)\n\t\t},\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request) {\n\t\t\treturn decideAuthModel(model, subject, request);\n\t\t}\n\t};\n}\n/**\n* Folds one group-stream operation with the registered group model's reducer.\n* A reactor without the module registered folds nothing, so the member list\n* stays as read and a missing reducer never widens access.\n*/\nfunction applyGroupOperation(registry, document, operation) {\n\tlet reducer;\n\ttry {\n\t\treducer = registry.getModule(groupDocumentType).reducer;\n\t} catch {\n\t\treturn document;\n\t}\n\treturn reducer(document, operation.action);\n}\n/**\n* Folds one evaluated-scope operation with the reducer registered for the\n* document's own type, at the document's stamped version. A reactor without\n* that module folds nothing, so conditions read the base state and an\n* unresolvable reducer never widens access.\n*/\nfunction applyModelOperation(registry, document, operation) {\n\tlet reducer;\n\ttry {\n\t\tconst version = normalizeDocumentModelVersion(document.state.document?.version);\n\t\treducer = registry.getModule(document.header.documentType, version).reducer;\n\t} catch {\n\t\treturn document;\n\t}\n\treturn reducer(document, operation.action);\n}\n/**\n* The auth model extended with a derived groups projection: the streams it\n* reads are the group documents the folded grant list names, so adding a\n* grant that names a new group pulls that group's stream into the read-set.\n* Group queries pin the main branch, because a group's member list lives on\n* its main branch no matter which branch the referencing document is on.\n*/\nfunction groupsProjection(registry) {\n\treturn {\n\t\tdecidingActions: [...groupMembershipActionTypes],\n\t\tapply: (document, operation) => applyGroupOperation(registry, document, operation),\n\t\tquery: (model) => referencedGroupIds(model.auth?.grants ?? []).map((id) => ({\n\t\t\tdocumentId: id,\n\t\t\tbranch: \"main\",\n\t\t\tscope: \"global\"\n\t\t})),\n\t\tqueryOverHistory: (reads) => {\n\t\t\tconst ids = [];\n\t\t\tfor (const read of reads) {\n\t\t\t\tif (read.name !== \"auth\") continue;\n\t\t\t\tfor (const operation of read.operations) for (const id of mentionedGroupIds(operation.action)) if (!ids.includes(id)) ids.push(id);\n\t\t\t}\n\t\t\treturn ids.map((id) => ({\n\t\t\t\tdocumentId: id,\n\t\t\t\tbranch: \"main\",\n\t\t\t\tscope: \"global\"\n\t\t\t}));\n\t\t}\n\t};\n}\nfunction authGroupsDecisionModel(registry) {\n\treturn (target) => ({\n\t\tprojections: {\n\t\t\tdocument: documentProjection(target),\n\t\t\tauth: authProjection(target),\n\t\t\tgroups: groupsProjection(registry)\n\t\t},\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request) {\n\t\t\treturn decideAuthModel(model, subject, request, model.groups);\n\t\t}\n\t});\n}\n/**\n* The groups model with conditions live: decide hands the executing scope's\n* state and the action input through to the evaluator, so `where` clauses\n* and { match } principals apply. The model folds the evaluated scope during\n* a positional walk, so a condition reads the state as it stood at each\n* operation's position.\n*/\nfunction authConditionsDecisionModel(registry) {\n\treturn (target) => ({\n\t\tprojections: {\n\t\t\tdocument: documentProjection(target),\n\t\t\tauth: authProjection(target),\n\t\t\tgroups: groupsProjection(registry)\n\t\t},\n\t\tfoldEvaluatedScope: (document, operation) => applyModelOperation(registry, document, operation),\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request, ctx) {\n\t\t\treturn decideAuthModel(model, subject, request, model.groups, {\n\t\t\t\tscopeState: ctx.scopeState,\n\t\t\t\tactionInput: ctx.actionInput\n\t\t\t});\n\t\t}\n\t});\n}\n//#endregion\n//#region src/decision/document-decision-model.ts\n/**\n* The simplest decision model: one projection over the document scope, which\n* rejects on a deleted document.\n*/\nfunction documentDecisionModel(target) {\n\treturn {\n\t\tprojections: { document: {\n\t\t\tdecidingActions: [\"DELETE_DOCUMENT\"],\n\t\t\tapply: (document, operation) => operation.action.type === \"DELETE_DOCUMENT\" ? applyDeleteDocumentAction({\n\t\t\t\t...document,\n\t\t\t\tstate: { ...document.state }\n\t\t\t}, operation.action) : document,\n\t\t\tquery: {\n\t\t\t\tdocumentId: target.documentId,\n\t\t\t\tbranch: target.branch,\n\t\t\t\tscope: \"document\"\n\t\t\t}\n\t\t} },\n\t\tevaluatesScope() {\n\t\t\treturn true;\n\t\t},\n\t\tdecide(model, subject, request) {\n\t\t\treturn request.verb === \"execute\" && model.document.isDeleted ? {\n\t\t\t\tdecision: \"deny\",\n\t\t\t\treason: DOCUMENT_DELETED_REASON\n\t\t\t} : { decision: \"allow\" };\n\t\t}\n\t};\n}\n//#endregion\n//#region src/decision/registered-model.ts\n/**\n* Builds the model at the stream heads and decides one request against it. The\n* append condition it returns is the read-set the store enforces at write time.\n*\n* With `conditions` supplied, the executing scope's state is read at the head\n* for `doc.<scope>.*` paths, or taken from the run's carried document when the\n* caller has already reduced earlier writes into it. That read carries no\n* append-condition entry of its own: the written stream's expected-revision\n* check already refuses a write whose scope grew between the read and the\n* append.\n*/\nasync function decideAtHead(model, cache, target, subject, request, signal, conditions) {\n\tconst built = await buildDecisionModel(cache, model, target, signal);\n\tlet scopeState;\n\tif (conditions !== void 0) scopeState = (conditions.carriedDocument ?? await cache.getState(target.documentId, request.scope, target.branch, void 0, signal)).state[request.scope];\n\treturn {\n\t\tevaluation: model(target).decide(built.model, subject, request, {\n\t\t\tscopeState,\n\t\t\tactionInput: conditions?.actionInput\n\t\t}),\n\t\tappendCondition: built.appendCondition,\n\t\tdocumentVersion: built.model.document.version,\n\t\tdeletedAtUtcIso: built.model.document.deletedAtUtcIso ?? null\n\t};\n}\n/**\n* The model this reactor enforces. With `authEnforcement` off the auth scope is\n* absent from every append condition and no load walks it; with `authGroups`\n* on, the group documents the grant list names join the read-set and the\n* registry supplies the reducer that folds them.\n*/\nfunction selectDecisionModel(flags, registry) {\n\tif (flags.authConditions) return authConditionsDecisionModel(registry);\n\tif (flags.authGroups) return authGroupsDecisionModel(registry);\n\treturn flags.authEnforcement ? authDecisionModel : documentDecisionModel;\n}\n//#endregion\n//#region src/executor/util.ts\n/** Actions the reactor reduces itself, onto the document scope. */\nconst DOCUMENT_SCOPE_ACTIONS = new Set([\n\t\"CREATE_DOCUMENT\",\n\t\"DELETE_DOCUMENT\",\n\t\"UPGRADE_DOCUMENT\",\n\t\"ADD_RELATIONSHIP\",\n\t\"REMOVE_RELATIONSHIP\",\n\t\"UPDATE_RELATIONSHIP\"\n]);\n/**\n* `CREATE_DOCUMENT` is exempt by necessity: it runs before the document exists,\n* so building a decision model would throw and defer the job forever.\n*/\nconst GATED_DOCUMENT_ACTIONS = new Set([...DOCUMENT_SCOPE_ACTIONS].filter((type) => type !== \"CREATE_DOCUMENT\"));\n/**\n* The document a document-scope action writes to, which is not always the job's\n* own document: delete and upgrade name it in `input.documentId`, and the\n* relationship actions in `input.sourceId`. `execute` only checks that a batch\n* shares one scope, so a caller can submit an action whose target is a document\n* other than the one the job is keyed by. The policy gate has to follow the\n* action rather than the job, or it decides against a policy the caller may\n* control instead of the one guarding the write.\n*/\nfunction targetDocumentId(action, fallback) {\n\tconst input = action.input;\n\tif (action.type === \"ADD_RELATIONSHIP\" || action.type === \"REMOVE_RELATIONSHIP\" || action.type === \"UPDATE_RELATIONSHIP\") return typeof input?.sourceId === \"string\" && input.sourceId.length > 0 ? input.sourceId : fallback;\n\treturn typeof input?.documentId === \"string\" && input.documentId.length > 0 ? input.documentId : fallback;\n}\n/**\n* Creates a PHDocument from a CREATE_DOCUMENT action input.\n* Reconstructs the document header and initializes the base state.\n*\n* @param action - The CREATE_DOCUMENT action containing the document parameters\n* @returns A newly constructed PHDocument with initialized header and base state\n*/\nfunction createDocumentFromAction(action) {\n\tconst input = action.input;\n\tconst header = createPresignedHeader();\n\theader.id = input.documentId;\n\theader.documentType = input.model;\n\tif (input.signing) {\n\t\theader.createdAtUtcIso = input.signing.createdAtUtcIso;\n\t\theader.lastModifiedAtUtcIso = input.signing.createdAtUtcIso;\n\t\theader.sig = {\n\t\t\tpublicKey: input.signing.publicKey,\n\t\t\tnonce: input.signing.nonce\n\t\t};\n\t}\n\tif (input.slug !== void 0) header.slug = input.slug;\n\tif (!header.slug) header.slug = input.documentId;\n\tif (input.name !== void 0) header.name = input.name;\n\tif (input.branch !== void 0) header.branch = input.branch;\n\tif (input.meta !== void 0) header.meta = input.meta;\n\tif (input.protocolVersions !== void 0) header.protocolVersions = input.protocolVersions;\n\tconst baseState = defaultBaseState();\n\treturn {\n\t\theader,\n\t\toperations: {},\n\t\tstate: baseState,\n\t\tinitialState: baseState,\n\t\tclipboard: []\n\t};\n}\n/**\n* Calculate the next operation index for a specific scope.\n* Each scope maintains its own independent index sequence.\n*\n* Per-scope indexing means:\n* - Each scope (document, global, local, etc.) has independent indexes\n* - Indexes start at 0 for each scope\n* - Different scopes can have operations with the same index value\n*\n* This function uses header.revision which is populated by the cache/storage layer\n* and contains the next available index for each scope. This design avoids requiring\n* the full operation history to be loaded, which is crucial for snapshot-based caching.\n*\n* @param document - The document whose header.revision to inspect\n* @param scope - The scope to calculate the next index for\n* @returns The next available index in the specified scope\n*/\nconst getNextIndexForScope = (document, scope) => {\n\treturn document.header.revision[scope] || 0;\n};\n/**\n* Creates an empty consistency token with no coordinates.\n* Used when a job is registered or fails without writing operations.\n*\n* @returns A consistency token with an empty coordinates array\n*/\nfunction createEmptyConsistencyToken() {\n\treturn {\n\t\tversion: 1,\n\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tcoordinates: []\n\t};\n}\n/**\n* Creates a consistency token from operations written during job execution.\n* Maps each operation to a consistency coordinate tracking (documentId, scope, branch, operationIndex).\n* If no operations are provided, returns an empty token.\n*\n* @param operationsWithContext - Array of operations with their execution context\n* @returns A consistency token representing all operations written\n*/\nfunction createConsistencyToken(operationsWithContext) {\n\tif (operationsWithContext.length === 0) return createEmptyConsistencyToken();\n\tconst coordinates = [];\n\tfor (let i = 0; i < operationsWithContext.length; i++) {\n\t\tconst opWithContext = operationsWithContext[i];\n\t\tcoordinates.push({\n\t\t\tdocumentId: opWithContext.context.documentId,\n\t\t\tscope: opWithContext.context.scope,\n\t\t\tbranch: opWithContext.context.branch,\n\t\t\toperationIndex: opWithContext.operation.index\n\t\t});\n\t}\n\treturn {\n\t\tversion: 1,\n\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tcoordinates\n\t};\n}\nfunction createOperation(action, index, skip, context) {\n\treturn {\n\t\tid: deriveOperationId(context.documentId, context.scope, context.branch, action.id),\n\t\tindex,\n\t\ttimestampUtcMs: action.timestampUtcMs || (/* @__PURE__ */ new Date()).toISOString(),\n\t\thash: \"\",\n\t\tskip,\n\t\taction\n\t};\n}\nfunction updateDocumentRevision(document, scope, operationIndex) {\n\tdocument.header.revision = {\n\t\t...document.header.revision,\n\t\t[scope]: operationIndex + 1\n\t};\n}\nfunction buildSuccessResult(job, operation, documentId, documentType, resultingState, startTime) {\n\treturn {\n\t\tjob,\n\t\tsuccess: true,\n\t\toperations: [operation],\n\t\toperationsWithContext: [{\n\t\t\toperation,\n\t\t\tcontext: {\n\t\t\t\tdocumentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch,\n\t\t\t\tdocumentType,\n\t\t\t\tresultingState,\n\t\t\t\tordinal: 0\n\t\t\t}\n\t\t}],\n\t\tduration: Date.now() - startTime\n\t};\n}\nfunction buildErrorResult(job, error, startTime) {\n\treturn {\n\t\tjob,\n\t\tsuccess: false,\n\t\terror,\n\t\tduration: Date.now() - startTime\n\t};\n}\n/**\n* The error a refusal surfaces as. Both classes are already terminal in the job\n* result handler, so a refusal never burns a retry.\n*/\nfunction refusalError(reason, documentId, deletedAtUtcIso, action) {\n\tif (reason === DOCUMENT_DELETED_REASON) return new DocumentDeletedError(documentId, deletedAtUtcIso);\n\treturn new AuthorizationDeniedError(documentId, action.scope, action.type, action.context?.signer?.user.address);\n}\n/**\n* Whether this operation is part of the document's creation. The create and the\n* upgrade from version zero hold the first two indexes for the life of the\n* document, so a reshuffle has to leave them where they are.\n*/\nfunction isGenesisOperation(operation) {\n\tif (operation.action.type === \"CREATE_DOCUMENT\") return true;\n\tif (operation.action.type !== \"UPGRADE_DOCUMENT\") return false;\n\treturn operation.action.input.fromVersion === 0;\n}\n/**\n* The distinct streams a job wrote, collected so a rollback knows what to evict.\n*\n* A write records its stream on every apply, and a long run applies the same\n* stream hundreds of times, so this keeps one entry per stream rather than one\n* per write: the eviction only cares which streams were touched, and the\n* successful jobs that never read this back pay for a lookup instead of an\n* allocation.\n*/\nvar TouchedStreams = class {\n\tstreams = /* @__PURE__ */ new Map();\n\tadd(documentId, scope, branch) {\n\t\tconst key = `${documentId}\\u0000${scope}\\u0000${branch}`;\n\t\tif (this.streams.has(key)) return;\n\t\tthis.streams.set(key, {\n\t\t\tdocumentId,\n\t\t\tscope,\n\t\t\tbranch\n\t\t});\n\t}\n\t[Symbol.iterator]() {\n\t\treturn this.streams.values();\n\t}\n};\n//#endregion\n//#region src/registry/errors.ts\n/**\n* Error thrown when a document model module is not found in the registry.\n*/\nvar ModuleNotFoundError = class extends Error {\n\tdocumentType;\n\trequestedVersion;\n\tconstructor(documentType, version) {\n\t\tconst versionSuffix = version !== void 0 ? ` version ${version}` : \"\";\n\t\tsuper(`Document model module not found for type: ${documentType}${versionSuffix}`);\n\t\tthis.name = \"ModuleNotFoundError\";\n\t\tthis.documentType = documentType;\n\t\tthis.requestedVersion = version;\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"ModuleNotFoundError\";\n\t}\n};\n/**\n* Error thrown when attempting to register a module that already exists.\n*/\nvar DuplicateModuleError = class extends Error {\n\tconstructor(documentType, version) {\n\t\tconst versionSuffix = version !== void 0 ? ` (version ${version})` : \"\";\n\t\tsuper(`Document model module already registered for type: ${documentType}${versionSuffix}`);\n\t\tthis.name = \"DuplicateModuleError\";\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DuplicateModuleError\";\n\t}\n};\n/**\n* Error thrown when a module is invalid or malformed.\n*/\nvar InvalidModuleError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(`Invalid document model module: ${message}`);\n\t\tthis.name = \"InvalidModuleError\";\n\t}\n};\n/**\n* Error thrown when attempting to register an upgrade manifest that already exists.\n*/\nvar DuplicateManifestError = class extends Error {\n\tconstructor(documentType) {\n\t\tsuper(`Upgrade manifest already registered for type: ${documentType}`);\n\t\tthis.name = \"DuplicateManifestError\";\n\t}\n\tstatic isError(error) {\n\t\treturn Error.isError(error) && error.name === \"DuplicateManifestError\";\n\t}\n};\n/**\n* Error thrown when an upgrade manifest is not found.\n*/\nvar ManifestNotFoundError = class extends Error {\n\tconstructor(documentType) {\n\t\tsuper(`Upgrade manifest not found for type: ${documentType}`);\n\t\tthis.name = \"ManifestNotFoundError\";\n\t}\n};\n/**\n* Error thrown when a required upgrade transition is missing from the manifest.\n*/\nvar MissingUpgradeTransitionError = class extends Error {\n\tconstructor(documentType, fromVersion, toVersion) {\n\t\tsuper(`Missing upgrade transition for ${documentType}: v${fromVersion} to v${toVersion}`);\n\t\tthis.name = \"MissingUpgradeTransitionError\";\n\t}\n};\n/**\n* Error thrown when getUpgradeReducer is called with a non-single-step version increment.\n*/\nvar InvalidUpgradeStepError = class extends Error {\n\tconstructor(documentType, fromVersion, toVersion) {\n\t\tsuper(`Invalid upgrade step for ${documentType}: must be single version increment, got v${fromVersion} to v${toVersion}`);\n\t\tthis.name = \"InvalidUpgradeStepError\";\n\t}\n};\n//#endregion\n//#region src/executor/types.ts\n/** How long a deferred job waits for its document before it fails. */\nconst DEFAULT_DEFERRED_JOB_TTL_MS = 3e4;\n/**\n* Event types for the job executor\n*/\nconst JobExecutorEventTypes = {\n\tJOB_STARTED: 2e4,\n\tJOB_COMPLETED: 20001,\n\tJOB_FAILED: 20002,\n\tEXECUTOR_STARTED: 20003,\n\tEXECUTOR_STOPPED: 20004\n};\n//#endregion\n//#region src/cache/collection-membership-cache.ts\nvar CollectionMembershipCache = class CollectionMembershipCache {\n\tcache = /* @__PURE__ */ new Map();\n\tconstructor(operationIndex) {\n\t\tthis.operationIndex = operationIndex;\n\t}\n\twithScopedIndex(operationIndex) {\n\t\tconst scoped = new CollectionMembershipCache(operationIndex);\n\t\tscoped.cache = this.cache;\n\t\treturn scoped;\n\t}\n\tasync getCollectionsForDocuments(documentIds) {\n\t\tconst result = {};\n\t\tconst missing = [];\n\t\tfor (const docId of documentIds) {\n\t\t\tconst cached = this.cache.get(docId);\n\t\t\tif (cached !== void 0) result[docId] = cached;\n\t\t\telse missing.push(docId);\n\t\t}\n\t\tif (missing.length > 0) {\n\t\t\tconst fromDb = await this.operationIndex.getCollectionsForDocuments(missing);\n\t\t\tfor (const docId of missing) {\n\t\t\t\tconst collections = fromDb[docId] ?? [];\n\t\t\t\tresult[docId] = collections;\n\t\t\t\tthis.cache.set(docId, collections);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\tinvalidate(documentId) {\n\t\tthis.cache.delete(documentId);\n\t}\n};\n//#endregion\n//#region src/cache/lru/lru-tracker.ts\nvar LRUNode = class {\n\tkey;\n\tprev;\n\tnext;\n\tconstructor(key) {\n\t\tthis.key = key;\n\t\tthis.prev = void 0;\n\t\tthis.next = void 0;\n\t}\n};\nvar LRUTracker = class {\n\tmap;\n\thead;\n\ttail;\n\tconstructor() {\n\t\tthis.map = /* @__PURE__ */ new Map();\n\t\tthis.head = void 0;\n\t\tthis.tail = void 0;\n\t}\n\tget size() {\n\t\treturn this.map.size;\n\t}\n\ttouch(key) {\n\t\tconst node = this.map.get(key);\n\t\tif (node) this.moveToFront(node);\n\t\telse this.addToFront(key);\n\t}\n\tevict() {\n\t\tif (!this.tail) return;\n\t\tconst key = this.tail.key;\n\t\tthis.remove(key);\n\t\treturn key;\n\t}\n\tremove(key) {\n\t\tconst node = this.map.get(key);\n\t\tif (!node) return;\n\t\tthis.removeNode(node);\n\t\tthis.map.delete(key);\n\t}\n\tclear() {\n\t\tthis.map.clear();\n\t\tthis.head = void 0;\n\t\tthis.tail = void 0;\n\t}\n\taddToFront(key) {\n\t\tconst node = new LRUNode(key);\n\t\tthis.map.set(key, node);\n\t\tif (!this.head) {\n\t\t\tthis.head = node;\n\t\t\tthis.tail = node;\n\t\t} else {\n\t\t\tnode.next = this.head;\n\t\t\tthis.head.prev = node;\n\t\t\tthis.head = node;\n\t\t}\n\t}\n\tmoveToFront(node) {\n\t\tif (node === this.head) return;\n\t\tthis.removeNode(node);\n\t\tnode.prev = void 0;\n\t\tnode.next = this.head;\n\t\tif (this.head) this.head.prev = node;\n\t\tthis.head = node;\n\t\tif (!this.tail) this.tail = node;\n\t}\n\tremoveNode(node) {\n\t\tif (node.prev) node.prev.next = node.next;\n\t\telse this.head = node.next;\n\t\tif (node.next) node.next.prev = node.prev;\n\t\telse this.tail = node.prev;\n\t}\n};\n//#endregion\n//#region src/cache/document-meta-cache.ts\n/**\n* In-memory document metadata cache with LRU eviction.\n*\n* Caches PHDocumentState per (documentId, branch) key. On cache miss,\n* rebuilds from document scope operations. Provides an explicit cross-scope\n* contract for accessing document scope metadata.\n*\n* **Thread Safety:**\n* Not thread-safe. Designed for single-threaded job executor environment.\n*/\nvar DocumentMetaCache = class DocumentMetaCache {\n\tcache;\n\tlruTracker;\n\toperationStore;\n\tconfig;\n\tconstructor(operationStore, config) {\n\t\tthis.operationStore = operationStore;\n\t\tthis.config = { maxDocuments: config.maxDocuments };\n\t\tthis.cache = /* @__PURE__ */ new Map();\n\t\tthis.lruTracker = new LRUTracker();\n\t}\n\twithScopedStore(operationStore) {\n\t\tconst scoped = new DocumentMetaCache(operationStore, this.config);\n\t\tscoped.cache = this.cache;\n\t\tscoped.lruTracker = this.lruTracker;\n\t\treturn scoped;\n\t}\n\tasync startup() {\n\t\treturn Promise.resolve();\n\t}\n\tasync shutdown() {\n\t\treturn Promise.resolve();\n\t}\n\tasync getDocumentMeta(documentId, branch, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst key = this.makeKey(documentId, branch);\n\t\tconst cached = this.cache.get(key);\n\t\tif (cached) {\n\t\t\tthis.lruTracker.touch(key);\n\t\t\treturn cached;\n\t\t}\n\t\tconst meta = await this.rebuildLatest(documentId, branch, signal);\n\t\tthis.putDocumentMeta(documentId, branch, meta);\n\t\treturn meta;\n\t}\n\tasync rebuildAtRevision(documentId, branch, targetRevision, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn this.rebuildFromOperations(documentId, branch, targetRevision, signal);\n\t}\n\tputDocumentMeta(documentId, branch, meta) {\n\t\tconst key = this.makeKey(documentId, branch);\n\t\tif (!this.cache.has(key) && this.cache.size >= this.config.maxDocuments) {\n\t\t\tconst evictKey = this.lruTracker.evict();\n\t\t\tif (evictKey) this.cache.delete(evictKey);\n\t\t}\n\t\tthis.cache.set(key, structuredClone(meta));\n\t\tthis.lruTracker.touch(key);\n\t}\n\tinvalidate(documentId, branch) {\n\t\tlet evicted = 0;\n\t\tif (branch === void 0) {\n\t\t\tfor (const key of this.cache.keys()) if (key.startsWith(`${documentId}:`)) {\n\t\t\t\tthis.cache.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted++;\n\t\t\t}\n\t\t} else {\n\t\t\tconst key = this.makeKey(documentId, branch);\n\t\t\tif (this.cache.has(key)) {\n\t\t\t\tthis.cache.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted = 1;\n\t\t\t}\n\t\t}\n\t\treturn evicted;\n\t}\n\tclear() {\n\t\tthis.cache.clear();\n\t\tthis.lruTracker.clear();\n\t}\n\tmakeKey(documentId, branch) {\n\t\treturn `${documentId}:${branch}`;\n\t}\n\tasync rebuildLatest(documentId, branch, signal) {\n\t\treturn this.rebuildFromOperations(documentId, branch, void 0, signal);\n\t}\n\tasync rebuildFromOperations(documentId, branch, targetRevision, signal) {\n\t\tconst docScopeOps = await this.operationStore.getSince(documentId, \"document\", branch, -1, void 0, void 0, signal);\n\t\tif (docScopeOps.results.length === 0) throw new DocumentNotFoundError(documentId);\n\t\tconst createOp = docScopeOps.results[0];\n\t\tif (createOp.action.type !== \"CREATE_DOCUMENT\") throw new Error(`Invalid document: first operation must be CREATE_DOCUMENT, found ${createOp.action.type}`);\n\t\tconst createAction = createOp.action;\n\t\tconst documentType = createAction.input.model;\n\t\tlet document = createDocumentFromAction(createAction);\n\t\tlet documentScopeRevision = 0;\n\t\tfor (const op of docScopeOps.results) {\n\t\t\tif (targetRevision !== void 0 && op.index > targetRevision) break;\n\t\t\tdocumentScopeRevision = op.index;\n\t\t\tif (op.action.type === \"UPGRADE_DOCUMENT\") {\n\t\t\t\tconst upgradeAction = op.action;\n\t\t\t\tdocument = applyUpgradeDocumentAction$1(document, upgradeAction);\n\t\t\t} else if (op.action.type === \"DELETE_DOCUMENT\") document = applyDeleteDocumentAction$1(document, op.action);\n\t\t}\n\t\treturn {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType,\n\t\t\tdocumentScopeRevision: documentScopeRevision + 1\n\t\t};\n\t}\n};\nvar KyselyOperationIndexTxn = class {\n\tcollections = [];\n\tcollectionMemberships = [];\n\tcollectionRemovals = [];\n\tgroupReferences = [];\n\toperations = [];\n\tmembershipInvalidations = /* @__PURE__ */ new Set();\n\t/** Called by the commit as it writes each document_collections row. */\n\trecordMembershipInvalidation(documentId) {\n\t\tthis.membershipInvalidations.add(documentId);\n\t}\n\tgetMembershipInvalidations() {\n\t\treturn [...this.membershipInvalidations];\n\t}\n\tcreateCollection(collectionId) {\n\t\tthis.collections.push(collectionId);\n\t}\n\taddToCollection(collectionId, documentId) {\n\t\tconst lastOpIndex = this.operations.length - 1;\n\t\tif (lastOpIndex < 0) throw new Error(\"addToCollection must be called after write() - no operations in transaction\");\n\t\tthis.collectionMemberships.push({\n\t\t\tcollectionId,\n\t\t\tdocumentId,\n\t\t\toperationIndex: lastOpIndex\n\t\t});\n\t}\n\tremoveFromCollection(collectionId, documentId) {\n\t\tconst lastOpIndex = this.operations.length - 1;\n\t\tif (lastOpIndex < 0) throw new Error(\"removeFromCollection must be called after write() - no operations in transaction\");\n\t\tthis.collectionRemovals.push({\n\t\t\tcollectionId,\n\t\t\tdocumentId,\n\t\t\toperationIndex: lastOpIndex\n\t\t});\n\t}\n\trecordGroupReferences(documentId, groupIds) {\n\t\tconst lastOpIndex = this.operations.length - 1;\n\t\tif (lastOpIndex < 0) throw new Error(\"recordGroupReferences must be called after write() - no operations in transaction\");\n\t\tif (groupIds.length === 0) return;\n\t\tthis.groupReferences.push({\n\t\t\tdocumentId,\n\t\t\tgroupIds,\n\t\t\toperationIndex: lastOpIndex\n\t\t});\n\t}\n\twrite(operations) {\n\t\tthis.operations.push(...operations);\n\t}\n\tgetCollections() {\n\t\treturn this.collections;\n\t}\n\tgetGroupReferenceRecords() {\n\t\treturn this.groupReferences;\n\t}\n\tgetCollectionMembershipRecords() {\n\t\treturn this.collectionMemberships;\n\t}\n\tgetCollectionRemovals() {\n\t\treturn this.collectionRemovals;\n\t}\n\tgetOperations() {\n\t\treturn this.operations;\n\t}\n};\nvar KyselyOperationIndex = class KyselyOperationIndex {\n\ttrx;\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tget queryExecutor() {\n\t\treturn this.trx ?? this.db;\n\t}\n\twithTransaction(trx) {\n\t\tconst instance = new KyselyOperationIndex(this.db);\n\t\tinstance.trx = trx;\n\t\treturn instance;\n\t}\n\tstart() {\n\t\treturn new KyselyOperationIndexTxn();\n\t}\n\tasync commit(txn, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst kyselyTxn = txn;\n\t\tif (this.trx) return this.executeCommit(this.trx, kyselyTxn);\n\t\tlet resultOrdinals = [];\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tresultOrdinals = await this.executeCommit(trx, kyselyTxn);\n\t\t});\n\t\treturn resultOrdinals;\n\t}\n\t/**\n\t* A policy-driven join: keeps the earliest join so a rediscovered reference\n\t* never shrinks a backfill window remotes already rely on, and reopens a\n\t* closed membership because a policy reference is not a removable one.\n\t*/\n\tasync joinKeepingEarliest(trx, kyselyTxn, documentId, collectionId, ordinal) {\n\t\tkyselyTxn.recordMembershipInvalidation(documentId);\n\t\tawait trx.insertInto(\"document_collections\").values({\n\t\t\tdocumentId,\n\t\t\tcollectionId,\n\t\t\tjoinedOrdinal: ordinal,\n\t\t\tleftOrdinal: null\n\t\t}).onConflict((oc) => oc.columns([\"documentId\", \"collectionId\"]).doUpdateSet({\n\t\t\tjoinedOrdinal: sql`LEAST(\"document_collections\".\"joinedOrdinal\", EXCLUDED.\"joinedOrdinal\")`,\n\t\t\tleftOrdinal: null\n\t\t})).execute();\n\t}\n\tasync executeCommit(trx, kyselyTxn) {\n\t\tconst collections = kyselyTxn.getCollections();\n\t\tconst memberships = kyselyTxn.getCollectionMembershipRecords();\n\t\tconst removals = kyselyTxn.getCollectionRemovals();\n\t\tconst groupReferences = kyselyTxn.getGroupReferenceRecords();\n\t\tconst operations = kyselyTxn.getOperations();\n\t\tif (collections.length > 0) {\n\t\t\tconst collectionRows = collections.map((collectionId) => ({\n\t\t\t\tdocumentId: collectionId,\n\t\t\t\tcollectionId,\n\t\t\t\tjoinedOrdinal: BigInt(0),\n\t\t\t\tleftOrdinal: null\n\t\t\t}));\n\t\t\tfor (const collectionId of collections) kyselyTxn.recordMembershipInvalidation(collectionId);\n\t\t\tawait trx.insertInto(\"document_collections\").values(collectionRows).onConflict((oc) => oc.doNothing()).execute();\n\t\t}\n\t\tlet operationOrdinals = [];\n\t\tif (operations.length > 0) {\n\t\t\tconst operationRows = operations.map((op) => ({\n\t\t\t\topId: op.id || \"\",\n\t\t\t\tdocumentId: op.documentId,\n\t\t\t\tdocumentType: op.documentType,\n\t\t\t\tscope: op.scope,\n\t\t\t\tbranch: op.branch,\n\t\t\t\ttimestampUtcMs: op.timestampUtcMs,\n\t\t\t\tindex: op.index,\n\t\t\t\tskip: op.skip,\n\t\t\t\thash: op.hash,\n\t\t\t\taction: op.action,\n\t\t\t\tdeniedReason: op.deniedReason ?? null,\n\t\t\t\tsourceRemote: op.sourceRemote\n\t\t\t}));\n\t\t\toperationOrdinals = (await trx.insertInto(\"operation_index_operations\").values(operationRows).returning(\"ordinal\").execute()).map((row) => row.ordinal);\n\t\t}\n\t\tif (memberships.length > 0) for (const m of memberships) {\n\t\t\tconst ordinal = operationOrdinals[m.operationIndex];\n\t\t\tkyselyTxn.recordMembershipInvalidation(m.documentId);\n\t\t\tawait trx.insertInto(\"document_collections\").values({\n\t\t\t\tdocumentId: m.documentId,\n\t\t\t\tcollectionId: m.collectionId,\n\t\t\t\tjoinedOrdinal: BigInt(ordinal),\n\t\t\t\tleftOrdinal: null\n\t\t\t}).onConflict((oc) => oc.columns([\"documentId\", \"collectionId\"]).doUpdateSet({\n\t\t\t\tjoinedOrdinal: BigInt(ordinal),\n\t\t\t\tleftOrdinal: null\n\t\t\t})).execute();\n\t\t\tconst references = await trx.selectFrom(\"group_references\").select(\"groupId\").where(\"documentId\", \"=\", m.documentId).execute();\n\t\t\tfor (const { groupId } of references) await this.joinKeepingEarliest(trx, kyselyTxn, groupId, m.collectionId, BigInt(ordinal));\n\t\t}\n\t\tif (removals.length > 0) for (const r of removals) {\n\t\t\tconst ordinal = operationOrdinals[r.operationIndex];\n\t\t\tkyselyTxn.recordMembershipInvalidation(r.documentId);\n\t\t\tawait trx.updateTable(\"document_collections\").set({ leftOrdinal: BigInt(ordinal) }).where(\"collectionId\", \"=\", r.collectionId).where(\"documentId\", \"=\", r.documentId).where(\"leftOrdinal\", \"is\", null).execute();\n\t\t}\n\t\tif (groupReferences.length > 0) for (const record of groupReferences) {\n\t\t\tconst ordinal = operationOrdinals[record.operationIndex];\n\t\t\tawait trx.insertInto(\"group_references\").values(record.groupIds.map((groupId) => ({\n\t\t\t\tdocumentId: record.documentId,\n\t\t\t\tgroupId\n\t\t\t}))).onConflict((oc) => oc.doNothing()).execute();\n\t\t\tconst rows = await trx.selectFrom(\"document_collections\").select(\"collectionId\").where(\"documentId\", \"=\", record.documentId).execute();\n\t\t\tfor (const groupId of record.groupIds) for (const { collectionId } of rows) await this.joinKeepingEarliest(trx, kyselyTxn, groupId, collectionId, BigInt(ordinal));\n\t\t}\n\t\treturn operationOrdinals;\n\t}\n\tasync getGroupReferencers(groupId, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn (await this.queryExecutor.selectFrom(\"group_references\").select(\"documentId\").where(\"groupId\", \"=\", groupId).orderBy(\"documentId\").execute()).map((row) => row.documentId);\n\t}\n\tasync find(collectionId, cursor, view, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst outerCursor = cursor ?? -1;\n\t\tconst limit = paging?.limit ?? 500;\n\t\tconst pagingCursorOrdinal = paging?.cursor !== void 0 ? Number.parseInt(paging.cursor, 10) : -1;\n\t\tconst buildBranch = (kind) => {\n\t\t\tlet qb = this.queryExecutor.selectFrom(\"operation_index_operations as oi\").innerJoin(\"document_collections as dc\", \"oi.documentId\", \"dc.documentId\").selectAll(\"oi\").select([\"dc.documentId\", \"dc.collectionId\"]).where(\"dc.collectionId\", \"=\", collectionId).where(sql`(dc.\"leftOrdinal\" IS NULL OR oi.ordinal < dc.\"leftOrdinal\")`);\n\t\t\tif (kind === \"joiner\") qb = qb.where(\"dc.joinedOrdinal\", \">\", BigInt(outerCursor)).where(\"oi.ordinal\", \"<=\", outerCursor);\n\t\t\telse qb = qb.where(\"oi.ordinal\", \">\", outerCursor);\n\t\t\tqb = qb.where(\"oi.ordinal\", \">\", pagingCursorOrdinal);\n\t\t\tif (view?.branch) qb = qb.where(\"oi.branch\", \"=\", view.branch);\n\t\t\tif (view?.scopes && view.scopes.length > 0) qb = qb.where(\"oi.scope\", \"in\", view.scopes);\n\t\t\tif (view?.excludeSourceRemote) qb = qb.where(\"oi.sourceRemote\", \"!=\", view.excludeSourceRemote);\n\t\t\treturn qb;\n\t\t};\n\t\tconst rows = await buildBranch(\"joiner\").unionAll(buildBranch(\"newOps\")).orderBy(\"ordinal\", \"asc\").limit(limit + 1).execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore && items.length > 0 ? items[items.length - 1].ordinal.toString() : void 0;\n\t\tconst cursorValue = paging?.cursor || \"0\";\n\t\treturn {\n\t\t\tresults: items.map((row) => this.rowToOperationIndexEntry(row)),\n\t\t\toptions: {\n\t\t\t\tcursor: cursorValue,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.find(collectionId, cursor, view, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t};\n\t}\n\tasync get(documentId, view, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst limit = paging?.limit ?? 500;\n\t\tlet query = this.queryExecutor.selectFrom(\"operation_index_operations\").selectAll().where(\"documentId\", \"=\", documentId).orderBy(\"ordinal\", \"asc\");\n\t\tif (view?.branch) query = query.where(\"branch\", \"=\", view.branch);\n\t\tif (view?.scopes && view.scopes.length > 0) query = query.where(\"scope\", \"in\", view.scopes);\n\t\tif (paging?.cursor) {\n\t\t\tconst cursorOrdinal = Number.parseInt(paging.cursor, 10);\n\t\t\tquery = query.where(\"ordinal\", \">\", cursorOrdinal);\n\t\t}\n\t\tquery = query.limit(limit + 1);\n\t\tconst rows = await query.execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore && items.length > 0 ? items[items.length - 1].ordinal.toString() : void 0;\n\t\tconst cursorValue = paging?.cursor || \"0\";\n\t\treturn {\n\t\t\tresults: items.map((row) => this.rowToOperationIndexEntry(row)),\n\t\t\toptions: {\n\t\t\t\tcursor: cursorValue,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.get(documentId, view, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t};\n\t}\n\tasync getSinceOrdinal(ordinal, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst limit = paging?.limit ?? 500;\n\t\tlet query = this.queryExecutor.selectFrom(\"operation_index_operations\").selectAll().where(\"ordinal\", \">\", ordinal).orderBy(\"ordinal\", \"asc\");\n\t\tif (paging?.cursor) {\n\t\t\tconst cursorOrdinal = Number.parseInt(paging.cursor, 10);\n\t\t\tquery = query.where(\"ordinal\", \">\", cursorOrdinal);\n\t\t}\n\t\tquery = query.limit(limit + 1);\n\t\tconst rows = await query.execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore && items.length > 0 ? items[items.length - 1].ordinal.toString() : void 0;\n\t\tconst cursorValue = paging?.cursor || \"0\";\n\t\treturn {\n\t\t\tresults: items.map((row) => this.rowToOperationWithContext(row)),\n\t\t\toptions: {\n\t\t\t\tcursor: cursorValue,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.getSinceOrdinal(ordinal, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t};\n\t}\n\trowToOperationWithContext(row) {\n\t\treturn {\n\t\t\toperation: {\n\t\t\t\tindex: row.index,\n\t\t\t\ttimestampUtcMs: row.timestampUtcMs,\n\t\t\t\thash: row.hash,\n\t\t\t\tskip: row.skip,\n\t\t\t\taction: row.action,\n\t\t\t\tdeniedReason: row.deniedReason ?? void 0,\n\t\t\t\tid: row.opId\n\t\t\t},\n\t\t\tcontext: {\n\t\t\t\tdocumentId: row.documentId,\n\t\t\t\tdocumentType: row.documentType,\n\t\t\t\tscope: row.scope,\n\t\t\t\tbranch: row.branch,\n\t\t\t\tordinal: row.ordinal\n\t\t\t}\n\t\t};\n\t}\n\trowToOperationIndexEntry(row) {\n\t\treturn {\n\t\t\tordinal: row.ordinal,\n\t\t\tdocumentId: row.documentId,\n\t\t\tdocumentType: row.documentType,\n\t\t\tbranch: row.branch,\n\t\t\tscope: row.scope,\n\t\t\tindex: row.index,\n\t\t\ttimestampUtcMs: row.timestampUtcMs,\n\t\t\thash: row.hash,\n\t\t\tskip: row.skip,\n\t\t\taction: row.action,\n\t\t\tdeniedReason: row.deniedReason ?? void 0,\n\t\t\tid: row.opId,\n\t\t\tsourceRemote: row.sourceRemote\n\t\t};\n\t}\n\tasync getLatestTimestampForCollection(collectionId, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn (await this.queryExecutor.selectFrom(\"operation_index_operations as oi\").innerJoin(\"document_collections as dc\", \"oi.documentId\", \"dc.documentId\").select(\"oi.timestampUtcMs\").where(\"dc.collectionId\", \"=\", collectionId).where(sql`(dc.\"leftOrdinal\" IS NULL OR oi.ordinal < dc.\"leftOrdinal\")`).orderBy(\"oi.ordinal\", \"desc\").limit(1).executeTakeFirst())?.timestampUtcMs ?? null;\n\t}\n\tasync getCollectionsForDocuments(documentIds) {\n\t\tif (documentIds.length === 0) return {};\n\t\tconst rows = await this.queryExecutor.selectFrom(\"document_collections\").select([\"documentId\", \"collectionId\"]).where(\"documentId\", \"in\", documentIds).where(\"leftOrdinal\", \"is\", null).execute();\n\t\tconst result = {};\n\t\tfor (const row of rows) {\n\t\t\tif (!(row.documentId in result)) result[row.documentId] = [];\n\t\t\tresult[row.documentId].push(row.collectionId);\n\t\t}\n\t\treturn result;\n\t}\n};\n//#endregion\n//#region src/cache/buffer/ring-buffer.ts\n/**\n* RingBuffer is a generic circular buffer implementation that stores a fixed number\n* of items. When the buffer is full, new items overwrite the oldest items.\n*\n* This implementation maintains O(1) time complexity for push operations and provides\n* items in chronological order (oldest to newest) via getAll().\n*\n* @template T - The type of items stored in the buffer\n*/\nvar RingBuffer = class {\n\tbuffer;\n\thead = 0;\n\tsize = 0;\n\tcapacity;\n\tconstructor(capacity) {\n\t\tif (capacity <= 0) throw new Error(\"Ring buffer capacity must be greater than 0\");\n\t\tthis.capacity = capacity;\n\t\tthis.buffer = new Array(capacity);\n\t}\n\t/**\n\t* Adds an item to the buffer. If the buffer is full, overwrites the oldest item.\n\t*\n\t* @param item - The item to add\n\t*/\n\tpush(item) {\n\t\tconst index = (this.head + this.size) % this.capacity;\n\t\tif (this.size < this.capacity) {\n\t\t\tthis.buffer[index] = item;\n\t\t\tthis.size++;\n\t\t} else {\n\t\t\tthis.buffer[this.head] = item;\n\t\t\tthis.head = (this.head + 1) % this.capacity;\n\t\t}\n\t}\n\t/**\n\t* Returns all items in the buffer in chronological order (oldest to newest).\n\t*\n\t* @returns Array of items in insertion order\n\t*/\n\tgetAll() {\n\t\tif (this.size === 0) return [];\n\t\tconst result = [];\n\t\tfor (let i = 0; i < this.size; i++) {\n\t\t\tconst index = (this.head + i) % this.capacity;\n\t\t\tresult.push(this.buffer[index]);\n\t\t}\n\t\treturn result;\n\t}\n\t/**\n\t* Clears all items from the buffer.\n\t*/\n\tclear() {\n\t\tthis.buffer = new Array(this.capacity);\n\t\tthis.head = 0;\n\t\tthis.size = 0;\n\t}\n\t/**\n\t* Gets the current number of items in the buffer.\n\t*/\n\tget length() {\n\t\treturn this.size;\n\t}\n};\n//#endregion\n//#region src/cache/write-cache-types.ts\n/**\n* Where a snapshot sits in its stream.\n*\n* - `Head`: the newest revision of the stream when it was stored. Only these\n* can answer a read that asks for the head.\n* - `Historical`: state at an earlier revision. Usable as a starting point to\n* replay forward from, and as an answer to a read for that same revision.\n*/\nlet SnapshotPosition = /* @__PURE__ */ function(SnapshotPosition) {\n\tSnapshotPosition[\"Head\"] = \"head\";\n\tSnapshotPosition[\"Historical\"] = \"historical\";\n\treturn SnapshotPosition;\n}({});\n//#endregion\n//#region src/cache/kysely-write-cache.ts\n/**\n* The last operation index a keyframe's document reflects for the scope. A\n* keyframe only exists for a scope that has operations, so a missing entry\n* means the stored row is corrupt.\n*/\nfunction keyframeRevision(keyframe, documentId, scope) {\n\tconst nextIndex = keyframe.document.header.revision[scope];\n\tif (typeof nextIndex !== \"number\") throw new Error(`Corrupt keyframe for document ${documentId} at revision ${keyframe.revision}: header carries no ${scope} revision`);\n\treturn nextIndex - 1;\n}\nfunction extractModuleVersion(doc) {\n\tconst v = doc.state.document.version;\n\treturn normalizeDocumentModelVersion(v);\n}\n/** The highest revision held, latest push winning a tie. */\nfunction highestRevision(snapshots) {\n\tlet newest = void 0;\n\tfor (const snapshot of snapshots) if (!newest || snapshot.revision >= newest.revision) newest = snapshot;\n\treturn newest;\n}\n/**\n* Copies a document far enough that the caller cannot write through it. Inside\n* this class, callers only ever replace whole fields on these four, so one\n* level each is enough.\n*/\nfunction copyDocument(document) {\n\treturn {\n\t\t...document,\n\t\theader: { ...document.header },\n\t\tstate: { ...document.state },\n\t\toperations: { ...document.operations }\n\t};\n}\n/**\n* In-memory write cache with keyframe persistence for PHDocuments.\n*\n* Caches document snapshots in ring buffers with LRU eviction. On cache miss,\n* rebuilds documents from nearest keyframe or full operation history.\n*\n* **Performance Characteristics:**\n* - Cache hit: O(1) lookup in ring buffer\n* - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe\n* - Warm miss: O(m) where m is operations since cached revision\n* - Eviction: O(1) for LRU tracking and removal\n*\n* **Thread Safety:**\n* Not thread-safe. Designed for single-threaded job executor environment.\n* External synchronization required for concurrent access across multiple executors.\n*\n* **Example:**\n* ```typescript\n* const cache = new KyselyWriteCache(\n* keyframeStore,\n* operationStore,\n* registry,\n* { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }\n* );\n*\n* await cache.startup();\n*\n* // Retrieve or rebuild document\n* const doc = await cache.getState(docId, docType, scope, branch, revision);\n*\n* // Cache result after job execution\n* cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);\n*\n* await cache.shutdown();\n* ```\n*/\nvar KyselyWriteCache = class KyselyWriteCache {\n\tstreams;\n\tlruTracker;\n\tkeyframeStore;\n\toperationStore;\n\tregistry;\n\tconfig;\n\tconstructor(keyframeStore, operationStore, registry, config) {\n\t\tthis.keyframeStore = keyframeStore;\n\t\tthis.operationStore = operationStore;\n\t\tthis.registry = registry;\n\t\tthis.config = {\n\t\t\tmaxDocuments: config.maxDocuments,\n\t\t\tringBufferSize: config.ringBufferSize,\n\t\t\tkeyframeInterval: config.keyframeInterval\n\t\t};\n\t\tthis.streams = /* @__PURE__ */ new Map();\n\t\tthis.lruTracker = new LRUTracker();\n\t}\n\twithScopedStores(operationStore, keyframeStore) {\n\t\tconst scoped = new KyselyWriteCache(keyframeStore, operationStore, this.registry, this.config);\n\t\tscoped.streams = this.streams;\n\t\tscoped.lruTracker = this.lruTracker;\n\t\treturn scoped;\n\t}\n\t/**\n\t* Initializes the write cache.\n\t* Currently a no-op as keyframe store lifecycle is managed externally.\n\t*/\n\tasync startup() {\n\t\treturn Promise.resolve();\n\t}\n\t/**\n\t* Shuts down the write cache.\n\t* Currently a no-op as keyframe store lifecycle is managed externally.\n\t*/\n\tasync shutdown() {\n\t\treturn Promise.resolve();\n\t}\n\t/**\n\t* Retrieves document state at a specific revision from cache or rebuilds it.\n\t*\n\t* Note: this returns a _shallow_ copy of the document.\n\t*\n\t* Cache hit path: Returns cached snapshot if available (O(1))\n\t* Warm miss path: Rebuilds from cached base revision + incremental ops\n\t* Cold miss path: Rebuilds from keyframe or from scratch using all operations\n\t*\n\t* @param documentId - The document identifier\n\t* @param scope - The operation scope\n\t* @param branch - The operation branch\n\t* @param targetRevision - The target revision, or undefined for newest\n\t* @param signal - Optional abort signal to cancel the operation\n\t* @returns The document at the target revision\n\t* @throws {Error} \"Operation aborted\" if signal is aborted\n\t* @throws {ModuleNotFoundError} If document type not registered in registry\n\t* @throws {Error} \"Failed to rebuild document\" if operation store fails\n\t* @throws {Error} If reducer throws during operation application\n\t* @throws {Error} If document serialization fails\n\t*/\n\tasync getState(documentId, scope, branch, targetRevision, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst streamKey = this.makeStreamKey(documentId, scope, branch);\n\t\tconst stream = this.streams.get(streamKey);\n\t\tif (stream) {\n\t\t\tconst snapshots = stream.ringBuffer.getAll();\n\t\t\tif (targetRevision === void 0) {\n\t\t\t\tconst newest = highestRevision(snapshots);\n\t\t\t\tif (newest?.position === SnapshotPosition.Head) {\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn copyDocument(newest.document);\n\t\t\t\t}\n\t\t\t\tif (newest) {\n\t\t\t\t\tconst document = await this.warmMissRebuild(newest.document, newest.revision, documentId, scope, branch, void 0, signal);\n\t\t\t\t\tthis.store(documentId, scope, branch, (document.header.revision[scope] ?? 0) - 1, document, SnapshotPosition.Head);\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn document;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst exactMatch = snapshots.findLast((s) => s.revision === targetRevision);\n\t\t\t\tif (exactMatch) {\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn copyDocument(exactMatch.document);\n\t\t\t\t}\n\t\t\t\tconst newestOlder = this.findNearestOlderSnapshot(snapshots, targetRevision);\n\t\t\t\tif (newestOlder) {\n\t\t\t\t\tconst document = await this.warmMissRebuild(newestOlder.document, newestOlder.revision, documentId, scope, branch, targetRevision, signal);\n\t\t\t\t\tthis.store(documentId, scope, branch, targetRevision, document, SnapshotPosition.Historical);\n\t\t\t\t\tthis.lruTracker.touch(streamKey);\n\t\t\t\t\treturn document;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst document = await this.coldMissRebuild(documentId, scope, branch, targetRevision, signal);\n\t\tconst revision = targetRevision ?? (document.header.revision[scope] ?? 0) - 1;\n\t\tthis.store(documentId, scope, branch, revision, document, targetRevision === void 0 ? SnapshotPosition.Head : SnapshotPosition.Historical);\n\t\treturn document;\n\t}\n\t/**\n\t* Stores a document snapshot in the cache at a specific revision.\n\t*\n\t* The cached document is a shallow copy of the input with its operation history\n\t* truncated to the last operation per scope and its clipboard cleared. This keeps\n\t* memory use and copy costs constant regardless of operation count. Consumers of\n\t* getState() must not rely on the full operation history being present; the only\n\t* guaranteed invariant is that operations[scope].at(-1) reflects the latest\n\t* operation index for each scope.\n\t*\n\t* Updates LRU tracker and may evict least recently used stream if at capacity.\n\t* Asynchronously persists keyframes at configured intervals (fire-and-forget).\n\t*\n\t* @param documentId - The document identifier\n\t* @param scope - The operation scope\n\t* @param branch - The operation branch\n\t* @param revision - The revision number\n\t* @param document - The document to cache\n\t* @throws {Error} If document serialization fails\n\t*/\n\tputState(documentId, scope, branch, revision, document, position) {\n\t\tthis.store(documentId, scope, branch, revision, document, position);\n\t}\n\t/**\n\t* Stores the run's head and mints a keyframe for every interval the run\n\t* crossed on its way there. Only the head enters the ring buffer; the\n\t* earlier revisions are keyframe candidates and nothing more.\n\t*/\n\tputRun(documentId, scope, branch, run) {\n\t\tif (run.length === 0) return;\n\t\tfor (const entry of run.slice(0, -1)) this.persistKeyframe(documentId, scope, branch, entry.revision, entry.document);\n\t\tconst head = run[run.length - 1];\n\t\tthis.store(documentId, scope, branch, head.revision, head.document, SnapshotPosition.Head);\n\t}\n\tstore(documentId, scope, branch, revision, document, position) {\n\t\tconst streamKey = this.makeStreamKey(documentId, scope, branch);\n\t\tconst stream = this.getOrCreateStream(streamKey);\n\t\tconst snapshot = {\n\t\t\trevision,\n\t\t\tdocument: {\n\t\t\t\t...copyDocument(document),\n\t\t\t\toperations: Object.fromEntries(Object.entries(document.operations).map(([k, ops]) => [k, ops.length ? [ops.at(-1)] : []])),\n\t\t\t\tclipboard: []\n\t\t\t},\n\t\t\tposition\n\t\t};\n\t\tstream.ringBuffer.push(snapshot);\n\t\tthis.persistKeyframe(documentId, scope, branch, revision, document);\n\t}\n\t/** Persists the snapshot if this revision is one the interval falls on. */\n\tpersistKeyframe(documentId, scope, branch, revision, document) {\n\t\tif (!this.isKeyframeRevision(revision)) return;\n\t\tthis.keyframeStore.putKeyframe(documentId, scope, branch, revision, {\n\t\t\t...document,\n\t\t\toperations: {},\n\t\t\tclipboard: []\n\t\t}).catch((err) => {\n\t\t\tconsole.error(`Failed to persist keyframe ${documentId}@${revision}:`, err);\n\t\t});\n\t}\n\t/**\n\t* Invalidates cached document streams.\n\t*\n\t* Supports three invalidation scopes:\n\t* - Document-level: invalidate(documentId) - removes all streams for document\n\t* - Scope-level: invalidate(documentId, scope) - removes all branches for scope\n\t* - Stream-level: invalidate(documentId, scope, branch) - removes specific stream\n\t*\n\t* @param documentId - The document identifier\n\t* @param scope - Optional scope to narrow invalidation\n\t* @param branch - Optional branch to narrow invalidation (requires scope)\n\t* @returns The number of streams evicted\n\t*/\n\tinvalidate(documentId, scope, branch) {\n\t\tlet evicted = 0;\n\t\tif (scope === void 0 && branch === void 0) {\n\t\t\tfor (const [key] of this.streams.entries()) if (key.startsWith(`${documentId}:`)) {\n\t\t\t\tthis.streams.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted++;\n\t\t\t}\n\t\t} else if (scope !== void 0 && branch === void 0) {\n\t\t\tfor (const [key] of this.streams.entries()) if (key.startsWith(`${documentId}:${scope}:`)) {\n\t\t\t\tthis.streams.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted++;\n\t\t\t}\n\t\t} else if (scope !== void 0 && branch !== void 0) {\n\t\t\tconst key = this.makeStreamKey(documentId, scope, branch);\n\t\t\tif (this.streams.has(key)) {\n\t\t\t\tthis.streams.delete(key);\n\t\t\t\tthis.lruTracker.remove(key);\n\t\t\t\tevicted = 1;\n\t\t\t}\n\t\t}\n\t\treturn evicted;\n\t}\n\t/**\n\t* Clears the entire cache, removing all cached document streams.\n\t* Resets LRU tracking state. This operation always succeeds.\n\t*/\n\tclear() {\n\t\tthis.streams.clear();\n\t\tthis.lruTracker.clear();\n\t}\n\t/**\n\t* Retrieves a specific stream for a document. Exposed on the implementation\n\t* for testing, but not on the interface.\n\t*\n\t* @internal\n\t*/\n\tgetStream(documentId, scope, branch) {\n\t\tconst key = this.makeStreamKey(documentId, scope, branch);\n\t\treturn this.streams.get(key);\n\t}\n\tasync findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {\n\t\tif (targetRevision === Number.MAX_SAFE_INTEGER || targetRevision <= 0) return;\n\t\tconst keyframe = await this.keyframeStore.findNearestKeyframe(documentId, scope, branch, targetRevision, signal);\n\t\tif (!keyframe) return;\n\t\treturn {\n\t\t\trevision: Math.min(keyframeRevision(keyframe, documentId, scope), keyframe.revision),\n\t\t\tdocument: keyframe.document\n\t\t};\n\t}\n\t/**\n\t* Rebuilds a scope from a keyframe or from the whole operation history.\n\t*\n\t* The document scope is always rebuilt first, because it carries the type,\n\t* the upgrades and the deletion marker. Its version-changing upgrades are not\n\t* applied there though: an upgrade reducer must see the state the requested\n\t* scope has reached at that upgrade's boundary, so each one is held back and\n\t* applied when the replay below crosses the boundary that\n\t* resolveModuleVersionForOp derives from it. Upgrades whose boundary lies past\n\t* the last replayed operation are applied at the end. Creation-time 0->N seed\n\t* upgrades carry the initial state, so they still apply immediately.\n\t*/\n\tasync coldMissRebuild(documentId, scope, branch, targetRevision, signal) {\n\t\tconst effectiveTargetRevision = targetRevision || Number.MAX_SAFE_INTEGER;\n\t\tconst keyframe = await this.findNearestKeyframe(documentId, scope, branch, effectiveTargetRevision, signal);\n\t\tconst documentScopeBound = scope === \"document\" ? targetRevision : void 0;\n\t\tlet document;\n\t\tlet startRevision;\n\t\tlet documentType;\n\t\tconst validatedUpgrades = [];\n\t\tconst pendingUpgrades = [];\n\t\tlet lastDocumentScopeOperation;\n\t\tif (keyframe) {\n\t\t\tdocument = keyframe.document;\n\t\t\tstartRevision = keyframe.revision;\n\t\t\tdocumentType = keyframe.document.header.documentType;\n\t\t\tconst documentScopeResume = scope === \"document\" ? keyframe.revision : keyframeRevision(keyframe, documentId, \"document\");\n\t\t\tconst docScopeOpsAfterKeyframe = await this.operationStore.getSince(documentId, \"document\", branch, documentScopeResume, void 0, void 0, signal);\n\t\t\tfor (const operation of docScopeOpsAfterKeyframe.results) {\n\t\t\t\tif (documentScopeBound !== void 0 && operation.index > documentScopeBound) break;\n\t\t\t\tlastDocumentScopeOperation = operation;\n\t\t\t\tif (operation.error || isDenied(operation)) continue;\n\t\t\t\tif (operation.action.type === \"UPGRADE_DOCUMENT\") {\n\t\t\t\t\tconst upgradeAction = operation.action;\n\t\t\t\t\tconst fromVersion = upgradeAction.input.fromVersion;\n\t\t\t\t\tconst toVersion = upgradeAction.input.toVersion;\n\t\t\t\t\tif (fromVersion > 0 && fromVersion < toVersion) {\n\t\t\t\t\t\tlet upgradePath;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tupgradePath = this.registry.computeUpgradePath(documentType, fromVersion, toVersion);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (upgradeAction.input.initialState !== void 0) upgradePath = void 0;\n\t\t\t\t\t\t\telse throw new Error(`Failed to rebuild document ${documentId}: no upgrade manifest for ${documentType} v${fromVersion}→v${toVersion} and no initialState snapshot. ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvalidatedUpgrades.push({\n\t\t\t\t\t\t\tfromVersion,\n\t\t\t\t\t\t\ttoVersion,\n\t\t\t\t\t\t\trevision: upgradeAction.input.revision,\n\t\t\t\t\t\t\ttimestampUtcMs: operation.timestampUtcMs\n\t\t\t\t\t\t});\n\t\t\t\t\t\tpendingUpgrades.push({\n\t\t\t\t\t\t\taction: upgradeAction,\n\t\t\t\t\t\t\tupgradePath,\n\t\t\t\t\t\t\tindex: operation.index,\n\t\t\t\t\t\t\tsubsequentDeletes: []\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else if (operation.action.type === \"DELETE_DOCUMENT\") {\n\t\t\t\t\tapplyDeleteDocumentAction(document, operation.action);\n\t\t\t\t\tfor (const pending of pendingUpgrades) pending.subsequentDeletes.push(operation.action);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tstartRevision = -1;\n\t\t\tconst createOpResult = await this.operationStore.getSince(documentId, \"document\", branch, -1, void 0, {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: 1\n\t\t\t}, signal);\n\t\t\tif (createOpResult.results.length === 0) throw new DocumentNotFoundError(documentId);\n\t\t\tconst createOp = createOpResult.results[0];\n\t\t\tif (createOp.action.type !== \"CREATE_DOCUMENT\") throw new Error(`Failed to rebuild document ${documentId}: first operation in document scope must be CREATE_DOCUMENT, found ${createOp.action.type}`);\n\t\t\tconst documentCreateAction = createOp.action;\n\t\t\tdocumentType = documentCreateAction.input.model;\n\t\t\tif (!documentType) throw new Error(`Failed to rebuild document ${documentId}: CREATE_DOCUMENT action missing model in input`);\n\t\t\tdocument = createDocumentFromAction(documentCreateAction);\n\t\t\tlastDocumentScopeOperation = createOp;\n\t\t\tlet docModule = this.registry.getModule(documentType, extractModuleVersion(document));\n\t\t\tconst docScopeOps = await this.operationStore.getSince(documentId, \"document\", branch, 0, void 0, void 0, signal);\n\t\t\tfor (const operation of docScopeOps.results) {\n\t\t\t\tif (documentScopeBound !== void 0 && operation.index > documentScopeBound) break;\n\t\t\t\tlastDocumentScopeOperation = operation;\n\t\t\t\tif (operation.index === 0) continue;\n\t\t\t\tif (operation.error || isDenied(operation)) continue;\n\t\t\t\tif (operation.action.type === \"UPGRADE_DOCUMENT\") {\n\t\t\t\t\tconst upgradeAction = operation.action;\n\t\t\t\t\tconst fromVersion = upgradeAction.input.fromVersion;\n\t\t\t\t\tconst toVersion = upgradeAction.input.toVersion;\n\t\t\t\t\tif (fromVersion > 0 && fromVersion < toVersion) {\n\t\t\t\t\t\tlet upgradePath;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tupgradePath = this.registry.computeUpgradePath(documentType, fromVersion, toVersion);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (upgradeAction.input.initialState !== void 0) upgradePath = void 0;\n\t\t\t\t\t\t\telse throw new Error(`Failed to rebuild document ${documentId}: no upgrade manifest for ${documentType} v${fromVersion}→v${toVersion} and no initialState snapshot. ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvalidatedUpgrades.push({\n\t\t\t\t\t\t\tfromVersion,\n\t\t\t\t\t\t\ttoVersion,\n\t\t\t\t\t\t\trevision: upgradeAction.input.revision,\n\t\t\t\t\t\t\ttimestampUtcMs: operation.timestampUtcMs\n\t\t\t\t\t\t});\n\t\t\t\t\t\tpendingUpgrades.push({\n\t\t\t\t\t\t\taction: upgradeAction,\n\t\t\t\t\t\t\tupgradePath,\n\t\t\t\t\t\t\tindex: operation.index,\n\t\t\t\t\t\t\tsubsequentDeletes: []\n\t\t\t\t\t\t});\n\t\t\t\t\t} else document = applyUpgradeDocumentAction(document, upgradeAction, void 0);\n\t\t\t\t\tdocModule = this.registry.getModule(documentType, normalizeDocumentModelVersion(toVersion));\n\t\t\t\t} else if (operation.action.type === \"DELETE_DOCUMENT\") {\n\t\t\t\t\tapplyDeleteDocumentAction(document, operation.action);\n\t\t\t\t\tfor (const pending of pendingUpgrades) pending.subsequentDeletes.push(operation.action);\n\t\t\t\t} else {\n\t\t\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\t\t\tdocument = docModule.reducer(document, operation.action, void 0, {\n\t\t\t\t\t\tskip: operation.skip,\n\t\t\t\t\t\tprotocolVersion\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (scope === \"document\") {\n\t\t\tdocument = this.applyPendingUpgrades(document, pendingUpgrades, Number.MAX_SAFE_INTEGER);\n\t\t\tconst last = lastDocumentScopeOperation ?? await this.operationAt(documentId, \"document\", branch, startRevision, signal);\n\t\t\tdocument.operations = {\n\t\t\t\t...document.operations,\n\t\t\t\tdocument: last ? [last] : []\n\t\t\t};\n\t\t\treturn this.stampRevisions(document, documentId, scope, branch, targetRevision, signal);\n\t\t}\n\t\tif (keyframe) {\n\t\t\tconst resumeOperation = await this.operationAt(documentId, scope, branch, startRevision, signal);\n\t\t\tif (resumeOperation) document.operations = {\n\t\t\t\t...document.operations,\n\t\t\t\t[scope]: [resumeOperation]\n\t\t\t};\n\t\t}\n\t\tconst moduleCache = /* @__PURE__ */ new Map();\n\t\tconst getModuleCached = (version) => {\n\t\t\tconst key = version ?? 0;\n\t\t\tlet mod = moduleCache.get(key);\n\t\t\tif (!mod) {\n\t\t\t\tmod = this.registry.getModule(documentType, version);\n\t\t\t\tmoduleCache.set(key, mod);\n\t\t\t}\n\t\t\treturn mod;\n\t\t};\n\t\tconst finalVersion = validatedUpgrades.at(-1)?.toVersion ?? extractModuleVersion(document);\n\t\tlet cursor = void 0;\n\t\tconst pageSize = 100;\n\t\tlet hasMorePages;\n\t\tdo {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst paging = {\n\t\t\t\tcursor: cursor || \"0\",\n\t\t\t\tlimit: pageSize\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst result = await this.operationStore.getSince(documentId, scope, branch, startRevision, void 0, paging, signal);\n\t\t\t\tfor (const operation of result.results) {\n\t\t\t\t\tif (targetRevision !== void 0 && operation.index > targetRevision) break;\n\t\t\t\t\tconst moduleVersion = this.resolveModuleVersionForOp(operation.index, operation.timestampUtcMs, scope, validatedUpgrades, finalVersion);\n\t\t\t\t\tdocument = this.applyPendingUpgrades(document, pendingUpgrades, moduleVersion ?? Number.MAX_SAFE_INTEGER);\n\t\t\t\t\tif (isDenied(operation)) document = appendWithoutApplying(document, operation, scope);\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\t\t\t\tdocument = getModuleCached(moduleVersion).reducer(document, operation.action, void 0, {\n\t\t\t\t\t\t\tskip: operation.skip,\n\t\t\t\t\t\t\tprotocolVersion,\n\t\t\t\t\t\t\treplayOptions: { operation },\n\t\t\t\t\t\t\tskipIndexValidation: true\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst reachedTarget = targetRevision !== void 0 && result.results.some((op) => op.index >= targetRevision);\n\t\t\t\thasMorePages = Boolean(result.nextCursor) && !reachedTarget;\n\t\t\t\tif (hasMorePages) cursor = result.nextCursor;\n\t\t\t} catch (err) {\n\t\t\t\tthrow new Error(`Failed to rebuild document ${documentId}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t\t}\n\t\t} while (hasMorePages);\n\t\tdocument = this.applyTailPendingUpgrades(document, pendingUpgrades, scope, targetRevision);\n\t\tdocument = await this.stampRevisions(document, documentId, scope, branch, targetRevision, signal);\n\t\tif (pendingUpgrades.length > 0) {\n\t\t\tconst firstHeldBack = pendingUpgrades[0];\n\t\t\tconst stamped = document.header.revision[\"document\"] ?? 0;\n\t\t\tdocument.header.revision = {\n\t\t\t\t...document.header.revision,\n\t\t\t\tdocument: Math.min(stamped, firstHeldBack.index)\n\t\t\t};\n\t\t}\n\t\treturn document;\n\t}\n\t/**\n\t* Applies and removes every held-back upgrade whose target version is at or\n\t* below `throughVersion`, in the order the document scope recorded them.\n\t*/\n\tapplyPendingUpgrades(document, pendingUpgrades, throughVersion) {\n\t\twhile (pendingUpgrades.length > 0) {\n\t\t\tconst pending = pendingUpgrades[0];\n\t\t\tif (throughVersion < pending.action.input.toVersion) break;\n\t\t\tpendingUpgrades.shift();\n\t\t\tdocument = this.applyPendingUpgrade(document, pending);\n\t\t}\n\t\treturn document;\n\t}\n\t/**\n\t* Applies the remaining held-back upgrades after the requested scope's\n\t* replay has finished. A head read applies them all. A positional read\n\t* applies only those whose boundary for this scope lies at or before the\n\t* target position: applying a later one would label migrated state with a\n\t* pre-upgrade revision, and a keyframe stored from that poisons every\n\t* rebuild that resumes from it. Boundaries come from the upgrade's revision\n\t* snapshot; an upgrade without one records no position for this scope, and\n\t* the replay loop not having crossed it already places it past the target.\n\t*/\n\tapplyTailPendingUpgrades(document, pendingUpgrades, scope, targetRevision) {\n\t\twhile (pendingUpgrades.length > 0) {\n\t\t\tconst pending = pendingUpgrades[0];\n\t\t\tif (targetRevision !== void 0) {\n\t\t\t\tconst snapshot = pending.action.input.revision;\n\t\t\t\tif (snapshot === void 0) break;\n\t\t\t\tif ((snapshot[scope] ?? 0) > targetRevision) break;\n\t\t\t}\n\t\t\tpendingUpgrades.shift();\n\t\t\tdocument = this.applyPendingUpgrade(document, pending);\n\t\t}\n\t\treturn document;\n\t}\n\t/**\n\t* Applies one held-back upgrade, then re-applies the deletes the document\n\t* scope recorded after it so the hold-back cannot invert their order.\n\t*/\n\tapplyPendingUpgrade(document, pending) {\n\t\tdocument = applyUpgradeDocumentAction(document, pending.action, pending.upgradePath);\n\t\tfor (const deleteAction of pending.subsequentDeletes) document = applyDeleteDocumentAction(document, deleteAction);\n\t\treturn document;\n\t}\n\t/**\n\t* Copies the current document revisions onto the document. Overwrites the\n\t* requested scope revision with the target revision, if provided.\n\t*/\n\tasync stampRevisions(document, documentId, scope, branch, targetRevision, signal) {\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tdocument.header.revision = revisions.revision;\n\t\tif (targetRevision !== void 0) document.header.revision = {\n\t\t\t...document.header.revision,\n\t\t\t[scope]: targetRevision + 1\n\t\t};\n\t\tdocument.header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n\t\treturn document;\n\t}\n\t/** The stored operation at `index`, or undefined if it is no longer there. */\n\tasync operationAt(documentId, scope, branch, index, signal) {\n\t\tif (index < 0) return;\n\t\tconst operation = (await this.operationStore.getSince(documentId, scope, branch, index - 1, void 0, {\n\t\t\tcursor: \"0\",\n\t\t\tlimit: 1\n\t\t}, signal)).results[0];\n\t\treturn operation && operation.index === index ? operation : void 0;\n\t}\n\t/**\n\t* Resolves which module version to use for a given operation in phase 2.\n\t*\n\t* Uses the validated-upgrade boundary rules from D7:\n\t* - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary\n\t* - Otherwise: timestamp fallback\n\t* - Falls back to final module version when neither is decidable\n\t*/\n\tresolveModuleVersionForOp(opIndex, opTimestamp, scope, validatedUpgrades, finalVersion) {\n\t\tif (validatedUpgrades.length === 0) return finalVersion;\n\t\tlet currentVersion = validatedUpgrades[0]?.fromVersion;\n\t\tfor (const upgrade of validatedUpgrades) {\n\t\t\tlet beforeUpgrade;\n\t\t\tif (upgrade.revision !== void 0) beforeUpgrade = opIndex < (upgrade.revision[scope] ?? 0);\n\t\t\telse beforeUpgrade = opTimestamp < upgrade.timestampUtcMs;\n\t\t\tif (beforeUpgrade) return currentVersion;\n\t\t\tcurrentVersion = upgrade.toVersion;\n\t\t}\n\t\treturn currentVersion;\n\t}\n\tasync warmMissRebuild(baseDocument, baseRevision, documentId, scope, branch, targetRevision, signal) {\n\t\tconst documentType = baseDocument.header.documentType;\n\t\tconst docScopeNextIndex = baseDocument.header.revision[\"document\"] ?? 0;\n\t\tif ((await this.operationStore.getSince(documentId, \"document\", branch, docScopeNextIndex - 1, void 0, void 0, signal)).results.length > 0) return this.coldMissRebuild(documentId, scope, branch, targetRevision, signal);\n\t\tconst module = this.registry.getModule(documentType, extractModuleVersion(baseDocument));\n\t\tlet document = copyDocument(baseDocument);\n\t\ttry {\n\t\t\tconst pagedResults = await this.operationStore.getSince(documentId, scope, branch, baseRevision, void 0, void 0, signal);\n\t\t\tfor (const operation of pagedResults.results) {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tif (targetRevision !== void 0 && operation.index > targetRevision) break;\n\t\t\t\tif (isDenied(operation)) document = appendWithoutApplying(document, operation, scope);\n\t\t\t\telse {\n\t\t\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\t\t\tdocument = module.reducer(document, operation.action, void 0, {\n\t\t\t\t\t\tskip: operation.skip,\n\t\t\t\t\t\tprotocolVersion,\n\t\t\t\t\t\treplayOptions: { operation },\n\t\t\t\t\t\tskipIndexValidation: true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (targetRevision !== void 0 && operation.index === targetRevision) break;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow new Error(`Failed to rebuild document ${documentId}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n\t\t}\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tdocument.header.revision = revisions.revision;\n\t\tif (targetRevision !== void 0) document.header.revision = {\n\t\t\t...document.header.revision,\n\t\t\t[scope]: targetRevision + 1\n\t\t};\n\t\tdocument.header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n\t\treturn document;\n\t}\n\tfindNearestOlderSnapshot(snapshots, targetRevision) {\n\t\tlet nearest = void 0;\n\t\tfor (const snapshot of snapshots) if (snapshot.revision < targetRevision) {\n\t\t\tif (!nearest || snapshot.revision > nearest.revision) nearest = snapshot;\n\t\t}\n\t\treturn nearest;\n\t}\n\tmakeStreamKey(documentId, scope, branch) {\n\t\treturn `${documentId}:${scope}:${branch}`;\n\t}\n\tgetOrCreateStream(key) {\n\t\tlet stream = this.streams.get(key);\n\t\tif (!stream) {\n\t\t\tif (this.streams.size >= this.config.maxDocuments) {\n\t\t\t\tconst evictKey = this.lruTracker.evict();\n\t\t\t\tif (evictKey) this.streams.delete(evictKey);\n\t\t\t}\n\t\t\tstream = {\n\t\t\t\tkey,\n\t\t\t\tringBuffer: new RingBuffer(this.config.ringBufferSize)\n\t\t\t};\n\t\t\tthis.streams.set(key, stream);\n\t\t}\n\t\tthis.lruTracker.touch(key);\n\t\treturn stream;\n\t}\n\tisKeyframeRevision(revision) {\n\t\treturn revision > 0 && revision % this.config.keyframeInterval === 0;\n\t}\n};\n//#endregion\n//#region src/events/event-bus.ts\nvar EventBus = class {\n\teventTypeToSubscribers = /* @__PURE__ */ new Map();\n\tsubscribe(type, subscriber) {\n\t\tlet list = this.eventTypeToSubscribers.get(type);\n\t\tif (!list) {\n\t\t\tlist = [];\n\t\t\tthis.eventTypeToSubscribers.set(type, list);\n\t\t}\n\t\tlist.push(subscriber);\n\t\tlet done = false;\n\t\treturn () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tconst arr = this.eventTypeToSubscribers.get(type);\n\t\t\tif (!arr) return;\n\t\t\tconst idx = arr.indexOf(subscriber);\n\t\t\tif (idx !== -1) arr.splice(idx, 1);\n\t\t\tif (arr.length === 0) this.eventTypeToSubscribers.delete(type);\n\t\t};\n\t}\n\tasync emit(type, data) {\n\t\tconst list = this.eventTypeToSubscribers.get(type);\n\t\tif (!list || list.length === 0) return;\n\t\tconst snapshot = list.slice();\n\t\tconst errors = [];\n\t\tfor (const fn of snapshot) try {\n\t\t\tawait Promise.resolve(fn(type, data));\n\t\t} catch (err) {\n\t\t\terrors.push(err);\n\t\t}\n\t\tif (errors.length > 0) throw new EventBusAggregateError(errors);\n\t}\n};\n//#endregion\n//#region src/core/feature-flags.ts\n/**\n* Every flag this reactor knows, with the flags it requires. A stage adds its\n* flag here when it ships, so asking an older reactor for a later stage's flag\n* is an unrecognized name rather than a flag that quietly does nothing.\n*/\nconst FLAG_PREREQUISITES = {\n\tdocumentDecisions: [],\n\tauthEnforcement: [\"documentDecisions\"],\n\tauthGroups: [\"authEnforcement\"],\n\tauthConditions: [\"authGroups\"]\n};\n/**\n* The flags as plain booleans, with anything unset off, validated. Callers hold\n* a partial set, because that is what crosses to a pooled worker, and every\n* consumer needs the same resolution of it.\n*/\nfunction resolveFeatureFlags(flags = {}) {\n\tconst resolved = {\n\t\tdocumentDecisions: flags.documentDecisions ?? false,\n\t\tauthEnforcement: flags.authEnforcement ?? false,\n\t\tauthGroups: flags.authGroups ?? false,\n\t\tauthConditions: flags.authConditions ?? false\n\t};\n\tvalidateFeatureFlags(flags, FLAG_PREREQUISITES);\n\treturn resolved;\n}\n/**\n* Throws when the flags ask for enforcement the reactor cannot deliver. Either\n* failure would otherwise read as enforcement being on while the reactor\n* applies less than the caller asked for.\n*/\nfunction validateFeatureFlags(flags, prerequisites) {\n\tconst known = Object.keys(prerequisites);\n\tconst unrecognized = Object.keys(flags).filter((name) => !known.includes(name));\n\tif (unrecognized.length > 0) throw new Error(`Unrecognized reactor feature flag: ${unrecognized.join(\", \")}. This reactor knows: ${known.join(\", \")}.`);\n\tfor (const name of known) {\n\t\tif (flags[name] !== true) continue;\n\t\tconst missing = prerequisites[name].filter((required) => flags[required] !== true);\n\t\tif (missing.length > 0) throw new Error(`Reactor feature flag ${name} requires ${missing.join(\", \")}.`);\n\t}\n}\n//#endregion\n//#region src/executor/execution-scope.ts\nvar DefaultExecutionScope = class {\n\tconstructor(operationStore, operationIndex, writeCache, documentMetaCache, collectionMembershipCache) {\n\t\tthis.operationStore = operationStore;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.writeCache = writeCache;\n\t\tthis.documentMetaCache = documentMetaCache;\n\t\tthis.collectionMembershipCache = collectionMembershipCache;\n\t}\n\tasync run(fn, signal) {\n\t\tsignal?.throwIfAborted();\n\t\treturn fn({\n\t\t\toperationStore: this.operationStore,\n\t\t\toperationIndex: this.operationIndex,\n\t\t\twriteCache: this.writeCache,\n\t\t\tdocumentMetaCache: this.documentMetaCache,\n\t\t\tcollectionMembershipCache: this.collectionMembershipCache\n\t\t});\n\t}\n};\nvar KyselyExecutionScope = class {\n\tconstructor(db, operationStore, operationIndex, keyframeStore, writeCache, documentMetaCache, collectionMembershipCache) {\n\t\tthis.db = db;\n\t\tthis.operationStore = operationStore;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.keyframeStore = keyframeStore;\n\t\tthis.writeCache = writeCache;\n\t\tthis.documentMetaCache = documentMetaCache;\n\t\tthis.collectionMembershipCache = collectionMembershipCache;\n\t}\n\tasync run(fn, signal) {\n\t\tsignal?.throwIfAborted();\n\t\treturn this.db.transaction().execute(async (trx) => {\n\t\t\tconst scopedOperationStore = this.operationStore.withTransaction(trx);\n\t\t\tconst scopedOperationIndex = this.operationIndex.withTransaction(trx);\n\t\t\tconst scopedKeyframeStore = this.keyframeStore.withTransaction(trx);\n\t\t\treturn fn({\n\t\t\t\toperationStore: scopedOperationStore,\n\t\t\t\toperationIndex: scopedOperationIndex,\n\t\t\t\twriteCache: this.writeCache.withScopedStores(scopedOperationStore, scopedKeyframeStore),\n\t\t\t\tdocumentMetaCache: this.documentMetaCache.withScopedStore(scopedOperationStore),\n\t\t\t\tcollectionMembershipCache: this.collectionMembershipCache.withScopedIndex(scopedOperationIndex)\n\t\t\t});\n\t\t});\n\t}\n};\n//#endregion\n//#region src/utils/reshuffle.ts\nconst STRICT_ORDER_ACTION_TYPES = new Set([\n\t\"CREATE_DOCUMENT\",\n\t\"DELETE_DOCUMENT\",\n\t\"UPGRADE_DOCUMENT\",\n\t\"ADD_RELATIONSHIP\",\n\t\"REMOVE_RELATIONSHIP\",\n\t\"UPDATE_RELATIONSHIP\",\n\t\"ADD_FOLDER\",\n\t\"UPDATE_FOLDER\",\n\t\"REMOVE_FOLDER\"\n]);\n/**\n* Reshuffles operations by timestamp, then applies deterministic tie-breaking.\n* Used for merging concurrent operations from different branches.\n*\n* For strict document-structure actions (e.g., CREATE_DOCUMENT/UPGRADE_DOCUMENT),\n* logical index (index - skip) is prioritized to preserve causal replay order.\n*\n* For other actions, action ID is prioritized to ensure a canonical cross-reactor order\n* for concurrent operations that may have diverged local indices due to prior reshuffles.\n* Logical index and operation ID are then used as deterministic tie-breakers.\n*\n* Example:\n* [0:0, 1:0, 2:0, A3:0, A4:0, A5:0] + [0:0, 1:0, 2:0, B3:0, B4:2, B5:0]\n* GC => [0:0, 1:0, 2:0, A3:0, A4:0, A5:0] + [0:0, 1:0, B4:2, B5:0]\n* Split => [0:0, 1:0] + [2:0, A3:0, A4:0, A5:0] + [B4:2, B5:0]\n* Reshuffle(6:4) => [6:4, 7:0, 8:0, 9:0, 10:0, 11:0]\n* merge => [0:0, 1:0, 6:4, 7:0, 8:0, 9:0, 10:0, 11:0]\n*/\nfunction reshuffleByTimestamp(startIndex, opsA, opsB) {\n\treturn [...opsA, ...opsB].sort((a, b) => {\n\t\tconst timestampDiff = new Date(a.timestampUtcMs).getTime() - new Date(b.timestampUtcMs).getTime();\n\t\tif (timestampDiff !== 0) return timestampDiff;\n\t\tconst rank = (op) => STRICT_ORDER_ACTION_TYPES.has(op.action?.type ?? \"\") ? 0 : 1;\n\t\tconst rankDiff = rank(a) - rank(b);\n\t\tif (rankDiff !== 0) return rankDiff;\n\t\tif (rank(a) === 0) {\n\t\t\tconst logicalIndexDiff = a.index - a.skip - (b.index - b.skip);\n\t\t\tif (logicalIndexDiff !== 0) return logicalIndexDiff;\n\t\t}\n\t\tconst actionIdDiff = (a.action?.id ?? \"\").localeCompare(b.action?.id ?? \"\");\n\t\tif (actionIdDiff !== 0) return actionIdDiff;\n\t\treturn a.id.localeCompare(b.id);\n\t}).map((op, i) => ({\n\t\t...op,\n\t\tindex: startIndex.index + i,\n\t\tskip: i === 0 ? startIndex.skip : 0\n\t}));\n}\n//#endregion\n//#region src/decision/merged-order.ts\n/** Identifies a stream within a walk. */\nfunction streamKey(query) {\n\treturn `${query.documentId}:${query.scope}:${query.branch}`;\n}\n/**\n* Orders two operations from different streams by position. Timestamp decides;\n* an equal timestamp puts an auth operation first, and otherwise falls to the\n* action id and then the operation id, so that two replicas holding the same\n* operations agree on the order whatever order they happen to store them in.\n*/\nfunction comparePositions(a, b) {\n\tconst aTime = Date.parse(a.operation.timestampUtcMs);\n\tconst bTime = Date.parse(b.operation.timestampUtcMs);\n\tif (aTime !== bTime) return aTime - bTime;\n\tif (a.streamKey === b.streamKey) return a.operation.index - b.operation.index;\n\tconst aAuth = a.scope === \"auth\";\n\tif (aAuth !== (b.scope === \"auth\")) return aAuth ? -1 : 1;\n\tconst actionIds = (a.operation.action.id ?? \"\").localeCompare(b.operation.action.id ?? \"\");\n\tif (actionIds !== 0) return actionIds;\n\treturn (a.operation.id ?? \"\").localeCompare(b.operation.id ?? \"\");\n}\n/**\n* Merges the read-set streams into one sequence by position. An operation's\n* place in the result is the bound a decision at that operation reads to: every\n* operation before it has been applied, and it has not.\n*/\nfunction mergeByPosition(streams) {\n\tconst merged = [];\n\tfor (const stream of streams) for (const operation of stream.operations) merged.push({\n\t\tstreamKey: stream.streamKey,\n\t\tscope: stream.scope,\n\t\toperation\n\t});\n\treturn merged.sort(comparePositions);\n}\n/**\n* The skip that retracts everything from `firstRetractedIndex` up to where the\n* re-appended operation lands. It spans the indexes rather than counting the\n* operations, because a stream with a gap in it makes those differ.\n*/\nfunction retractionSkip(nextIndex, firstRetractedIndex) {\n\treturn nextIndex - firstRetractedIndex;\n}\n//#endregion\n//#region src/decision/walk.ts\n/**\n* A single forward pass is only correct while a stream's effective operations\n* are ordered.\n*/\nfunction assertPositionOrder(streamKey, scope, operations) {\n\tfor (let i = 1; i < operations.length; i++) {\n\t\tconst previous = operations[i - 1];\n\t\tconst current = operations[i];\n\t\tif (comparePositions({\n\t\t\tstreamKey,\n\t\t\tscope,\n\t\t\toperation: previous\n\t\t}, {\n\t\t\tstreamKey,\n\t\t\tscope,\n\t\t\toperation: current\n\t\t}) > 0) throw new Error(`Stream ${streamKey} is out of position order: index ${previous.index} at ${previous.timestampUtcMs} precedes index ${current.index} at ${current.timestampUtcMs}`);\n\t}\n}\n/**\n* Visits every operation in the read-set once, in the order their positions\n* fall, and hands back the state each stream held just before it. That state is\n* what a decision at that operation reads.\n*\n* Skips are resolved first (i.e. this is performed on a garbage collected\n* stream), which means we can do a single forward pass.\n*\n* An operation that contributes no state, whether denied or holding a reducer\n* error, is visited but not applied (this matches the write cache's rebuild).\n*\n* The consumer sends back whether it refused the operation it was handed: a\n* refusal this pass produced must suppress it the same way a stored one does.\n*/\nfunction* walkByPosition(streams) {\n\tconst merged = mergeByPosition(streams.map((stream) => {\n\t\tconst operations = garbageCollect(sortOperations([...stream.operations]));\n\t\tassertPositionOrder(stream.streamKey, stream.scope, operations);\n\t\treturn {\n\t\t\tstreamKey: stream.streamKey,\n\t\t\tscope: stream.scope,\n\t\t\toperations\n\t\t};\n\t}));\n\tconst byKey = new Map(streams.map((stream) => [stream.streamKey, stream]));\n\tconst states = new Map(streams.map((stream) => [stream.streamKey, stream.document]));\n\tfor (const { streamKey, operation } of merged) {\n\t\tif ((yield {\n\t\t\tstreamKey,\n\t\t\toperation,\n\t\t\tstates: new Map(states)\n\t\t}) || operation.error !== void 0 || isDenied(operation)) continue;\n\t\tconst stream = byKey.get(streamKey);\n\t\tconst before = states.get(streamKey);\n\t\tif (before === void 0 || stream === void 0) throw new Error(`No state for stream ${streamKey}`);\n\t\tstates.set(streamKey, stream.apply(before, operation));\n\t}\n}\n//#endregion\n//#region src/decision/evaluation.ts\n/** The stream key for evaluated operations whose scope no projection reads. */\nconst EVALUATED_ONLY = \"evaluated\";\n/**\n* Whether any stream the model reads declares this operation's action type as\n* one that can change an evaluation.\n*/\nfunction isDecidingAction(operation, readSet) {\n\treturn readSet.some((stream) => stream.decidingActions.includes(operation.action.type));\n}\n/**\n* Who an operation acts as. A replayed operation is evaluated as its own signer,\n* so an address-scoped policy does not deny its own author's history.\n*/\nfunction subjectOf(operation) {\n\tconst signer = operation.action.context?.signer;\n\treturn {\n\t\taddress: signer?.user.address,\n\t\tkey: signer?.app.key\n\t};\n}\n/**\n* The model as the walk reached this operation: each static projection's value\n* is its own scope's state, and each derived projection's value maps document\n* id to that document's state, holding only the streams this replica walked. A\n* derived stream it does not hold stays out of the map, which fails closed.\n*/\nfunction modelAt(readSet, derivedNames, derived, states) {\n\tconst model = {};\n\tfor (const stream of readSet) {\n\t\tconst document = states.get(streamKey(stream.query));\n\t\tif (document === void 0) throw new Error(`No state walked for projection ${stream.name}`);\n\t\tmodel[stream.name] = document.state[stream.query.scope];\n\t}\n\tfor (const name of derivedNames) model[name] = {};\n\tfor (const entry of derived) {\n\t\tconst map = model[entry.name];\n\t\tconst document = states.get(streamKey(entry.query));\n\t\tif (document !== void 0) map[entry.query.documentId] = document.state[entry.query.scope];\n\t}\n\treturn model;\n}\n/**\n* Evaluates each operation at its own position and returns the refusals in an\n* array parallel to the operations, where undefined means allowed.\n*\n* A position is a timestamp, so an operation refused by a delete is one that\n* sorts after it, and the operations before it are left alone. That holds\n* whether the delete is already stored or is among the operations passed in.\n*/\nasync function evaluateByPosition(model, target, subject, stores, signal) {\n\tconst { scope, operations } = subject;\n\tconst { writeCache, operationStore } = stores;\n\tconst definition = model(target);\n\tconst readSet = staticReadSet(definition);\n\tconst derivedSet = derivedReadSet(definition);\n\tif (!definition.evaluatesScope(scope)) return operations.map(() => void 0);\n\tconst evaluating = new Set(operations.map((operation) => operation.id));\n\tconst readStreams = await Promise.all(readSet.map(async (stream) => ({\n\t\tstream,\n\t\toperations: (await operationStore.getSince(stream.query.documentId, stream.query.scope, stream.query.branch, -1, { actionTypes: stream.decidingActions }, void 0, signal)).results.filter((operation) => !evaluating.has(operation.id))\n\t})));\n\tconst decidingOperations = operations.filter((operation) => isDecidingAction(operation, readSet));\n\tif (readStreams.every((read) => read.operations.length === 0) && decidingOperations.length === 0) return operations.map(() => void 0);\n\tif (readStreams.length === 0) throw new Error(`Decision model for ${target.documentId} reads no stream whose query is known before it is built`);\n\tconst writtenProjection = readSet.find((stream) => stream.query.scope === scope);\n\tconst walked = [];\n\tconst histories = [];\n\tfor (const read of readStreams) {\n\t\tconst streamOperations = read.stream === writtenProjection ? [...read.operations, ...operations] : read.operations;\n\t\tconst before = await writeCache.getState(read.stream.query.documentId, read.stream.query.scope, read.stream.query.branch, -1, signal);\n\t\twalked.push({\n\t\t\tstreamKey: streamKey(read.stream.query),\n\t\t\tscope: read.stream.query.scope,\n\t\t\tdocument: before,\n\t\t\toperations: streamOperations,\n\t\t\tapply: read.stream.apply\n\t\t});\n\t\thistories.push({\n\t\t\tname: read.stream.name,\n\t\t\toperations: streamOperations\n\t\t});\n\t}\n\tlet evaluatedStateKey;\n\tif (writtenProjection !== void 0) evaluatedStateKey = streamKey(writtenProjection.query);\n\telse if (definition.foldEvaluatedScope !== void 0) {\n\t\tconst query = {\n\t\t\tdocumentId: target.documentId,\n\t\t\tscope,\n\t\t\tbranch: target.branch\n\t\t};\n\t\tconst storedOperations = (await operationStore.getSince(query.documentId, query.scope, query.branch, -1, void 0, void 0, signal)).results.filter((operation) => !evaluating.has(operation.id));\n\t\tconst before = await writeCache.getState(query.documentId, query.scope, query.branch, -1, signal);\n\t\tevaluatedStateKey = streamKey(query);\n\t\twalked.push({\n\t\t\tstreamKey: evaluatedStateKey,\n\t\t\tscope,\n\t\t\tdocument: before,\n\t\t\toperations: [...storedOperations, ...operations],\n\t\t\tapply: definition.foldEvaluatedScope\n\t\t});\n\t} else walked.push({\n\t\tstreamKey: EVALUATED_ONLY,\n\t\tscope,\n\t\tdocument: walked[0].document,\n\t\toperations,\n\t\tapply: (document) => document\n\t});\n\tconst derivedEntries = [];\n\tconst walkedKeys = new Set(walked.map((stream) => stream.streamKey));\n\tfor (const projection of derivedSet) {\n\t\tconst queries = projection.queryOverHistory?.(histories) ?? [];\n\t\tfor (const query of queries) {\n\t\t\tconst key = streamKey(query);\n\t\t\tif (walkedKeys.has(key)) continue;\n\t\t\tlet before;\n\t\t\ttry {\n\t\t\t\tbefore = await writeCache.getState(query.documentId, query.scope, query.branch, -1, signal);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof DocumentNotFoundError) continue;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst streamOperations = (await operationStore.getSince(query.documentId, query.scope, query.branch, -1, { actionTypes: projection.decidingActions }, void 0, signal)).results.filter((operation) => !evaluating.has(operation.id));\n\t\t\twalkedKeys.add(key);\n\t\t\twalked.push({\n\t\t\t\tstreamKey: key,\n\t\t\t\tscope: query.scope,\n\t\t\t\tdocument: before,\n\t\t\t\toperations: streamOperations,\n\t\t\t\tapply: projection.apply\n\t\t\t});\n\t\t\tderivedEntries.push({\n\t\t\t\tname: projection.name,\n\t\t\t\tquery\n\t\t\t});\n\t\t}\n\t}\n\tconst reasons = /* @__PURE__ */ new Map();\n\tconst walk = walkByPosition(walked);\n\tlet step = walk.next(false);\n\twhile (!step.done) {\n\t\tconst position = step.value;\n\t\tif (!evaluating.has(position.operation.id)) {\n\t\t\tstep = walk.next(false);\n\t\t\tcontinue;\n\t\t}\n\t\tconst evaluatedDocument = evaluatedStateKey === void 0 ? void 0 : position.states.get(evaluatedStateKey);\n\t\tconst scopeState = evaluatedDocument === void 0 ? void 0 : evaluatedDocument.state[scope];\n\t\tconst evaluation = definition.decide(modelAt(readSet, derivedSet.map((projection) => projection.name), derivedEntries, position.states), subjectOf(position.operation), {\n\t\t\tverb: \"execute\",\n\t\t\tscope: position.operation.action.scope,\n\t\t\toperation: position.operation.action.type\n\t\t}, {\n\t\t\tscopeState,\n\t\t\tactionInput: position.operation.action.input\n\t\t});\n\t\tconst denied = evaluation.decision === \"deny\";\n\t\treasons.set(position.operation.id, denied ? evaluation.reason : void 0);\n\t\tstep = walk.next(denied);\n\t}\n\treturn operations.map((operation) => reasons.get(operation.id));\n}\n//#endregion\n//#region src/cache/operation-index-types.ts\nconst DRIVE_COLLECTION_PREFIX = \"drive.\";\n/**\n* Identifies the collection a remote synchronizes. Collections are drive-level\n* abstractions (document-drive and reactor-drive), so a collection id is the\n* drive document id plus the branch it scopes to rather than an opaque string.\n*\n* The canonical string form (`drive.${branch}.${driveId}`) is produced only by\n* `key` and parsed only by `fromKey`; that string is the wire and storage\n* representation and is byte-for-byte identical to the legacy\n* `driveCollectionId(branch, driveId)` output, so existing `document_collections`\n* rows and persisted remotes remain valid without migration.\n*/\nvar DriveCollectionId = class DriveCollectionId {\n\tconstructor(driveId, branch) {\n\t\tthis.driveId = driveId;\n\t\tthis.branch = branch;\n\t}\n\tstatic forDrive(driveId, branch = \"main\") {\n\t\treturn new DriveCollectionId(driveId, branch);\n\t}\n\t/**\n\t* The single deserializer for the wire/storage form. `branch` may contain\n\t* dots, while `driveId` is a dot-free document id, so the drive id is the\n\t* final dot-delimited segment.\n\t*/\n\tstatic fromKey(key) {\n\t\tif (!key.startsWith(DRIVE_COLLECTION_PREFIX)) throw new Error(`Unsupported collection id: ${key}`);\n\t\tconst rest = key.slice(6);\n\t\tconst lastDot = rest.lastIndexOf(\".\");\n\t\tif (lastDot === -1 || lastDot === rest.length - 1) throw new Error(`Malformed drive collection id: ${key}`);\n\t\treturn new DriveCollectionId(rest.slice(lastDot + 1), rest.slice(0, lastDot));\n\t}\n\tget key() {\n\t\treturn `${DRIVE_COLLECTION_PREFIX}${this.branch}.${this.driveId}`;\n\t}\n\ttoString() {\n\t\treturn this.key;\n\t}\n\tequals(other) {\n\t\treturn this.driveId === other.driveId && this.branch === other.branch;\n\t}\n};\n//#endregion\n//#region src/executor/document-action-handler.ts\nvar DocumentActionHandler = class {\n\tconstructor(registry, logger, driveContainerTypes, featureFlags, decisionModel) {\n\t\tthis.registry = registry;\n\t\tthis.logger = logger;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.featureFlags = featureFlags;\n\t\tthis.decisionModel = decisionModel;\n\t}\n\t/** Whether the write arrives with its evaluation already decided. */\n\talreadyEvaluated(executing) {\n\t\treturn this.featureFlags.documentDecisions && (executing.replayingAcceptedHistory || executing.evaluatedByPosition);\n\t}\n\tasync execute(write, executing) {\n\t\tconst { action } = write;\n\t\tif (write.deniedReason !== void 0) return this.writeDenied(write, executing);\n\t\tconst refusal = await this.refuseIfPolicyDenies(write, executing);\n\t\tif (refusal) return refusal;\n\t\tswitch (action.type) {\n\t\t\tcase \"CREATE_DOCUMENT\": return this.executeCreate(write, executing);\n\t\t\tcase \"DELETE_DOCUMENT\": return this.executeDelete(write, executing);\n\t\t\tcase \"UPGRADE_DOCUMENT\": return this.executeUpgrade(write, executing);\n\t\t\tcase \"ADD_RELATIONSHIP\": return this.executeAddRelationship(write, executing);\n\t\t\tcase \"REMOVE_RELATIONSHIP\": return this.executeRemoveRelationship(write, executing);\n\t\t\tcase \"UPDATE_RELATIONSHIP\": return this.executeUpdateRelationship(write, executing);\n\t\t\tdefault: return buildErrorResult(executing.job, /* @__PURE__ */ new Error(`Unknown document action type: ${action.type}`), executing.startTime);\n\t\t}\n\t}\n\t/**\n\t* Refuses a document-scope write the policy denies, or undefined to proceed.\n\t* Without this an `execute`-on-`document` grant is unenforceable.\n\t*/\n\tasync refuseIfPolicyDenies(write, executing) {\n\t\tconst { action } = write;\n\t\tconst { job, startTime, stores, signal } = executing;\n\t\tif (!this.featureFlags.documentDecisions || !this.featureFlags.authEnforcement || this.alreadyEvaluated(executing) || !GATED_DOCUMENT_ACTIONS.has(action.type)) return;\n\t\tconst documentId = targetDocumentId(action, job.documentId);\n\t\tlet admission;\n\t\ttry {\n\t\t\tadmission = await decideAtHead(this.decisionModel, stores.writeCache, {\n\t\t\t\tdocumentId,\n\t\t\t\tbranch: job.branch\n\t\t\t}, {\n\t\t\t\taddress: action.context?.signer?.user.address,\n\t\t\t\tkey: action.context?.signer?.app.key\n\t\t\t}, {\n\t\t\t\tverb: \"execute\",\n\t\t\t\tscope: action.scope,\n\t\t\t\toperation: action.type\n\t\t\t}, signal, this.featureFlags.authConditions ? { actionInput: action.input } : void 0);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tif (admission.evaluation.decision === \"allow\") return;\n\t\treturn buildErrorResult(job, refusalError(admission.evaluation.reason, documentId, admission.deletedAtUtcIso, action), startTime);\n\t}\n\t/** A refused operation holds a position in the stream but changes nothing. */\n\tasync writeDenied(write, executing) {\n\t\tconst { action, skip, sourceRemote, deniedReason } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await stores.writeCache.getState(job.documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tconst index = getNextIndexForScope(document, job.scope);\n\t\tlet standing = document;\n\t\tif (skip > 0) try {\n\t\t\tstanding = await stores.writeCache.getState(job.documentId, job.scope, job.branch, index - skip - 1, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tlet operation = createOperation(action, index, skip, {\n\t\t\tdocumentId: job.documentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\toperation.deniedReason = deniedReason;\n\t\toperation.hash = hashDocumentStateForScope(standing, job.scope);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId: job.documentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(standing, job.scope, operation.index);\n\t\tstanding.operations = {\n\t\t\t...standing.operations,\n\t\t\t[job.scope]: [...standing.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(job.documentId, job.scope, job.branch);\n\t\tstores.writeCache.putState(job.documentId, job.scope, job.branch, operation.index, standing, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId: job.documentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tstores.documentMetaCache.putDocumentMeta(job.documentId, job.branch, {\n\t\t\tstate: standing.state.document,\n\t\t\tdocumentType: standing.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, job.documentId, standing.header.documentType, JSON.stringify({\n\t\t\theader: standing.header,\n\t\t\tdocument: standing.state.document\n\t\t}), startTime);\n\t}\n\tasync executeCreate(write, executing) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tif (job.scope !== \"document\") return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: /* @__PURE__ */ new Error(`CREATE_DOCUMENT must be in \"document\" scope, got \"${job.scope}\"`),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tconst document = createDocumentFromAction(action);\n\t\tlet operation = createOperation(action, 0, skip, {\n\t\t\tdocumentId: document.header.id,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tconst resultingStateObj = {\n\t\t\theader: document.header,\n\t\t\t...document.state\n\t\t};\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId: document.header.id,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(document, job.scope, operation.index);\n\t\tdocument.operations = {\n\t\t\t...document.operations,\n\t\t\t[job.scope]: [...document.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(document.header.id, job.scope, job.branch);\n\t\tstores.writeCache.putState(document.header.id, job.scope, job.branch, operation.index, document, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId: document.header.id,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tif (this.driveContainerTypes.has(document.header.documentType)) {\n\t\t\tconst collectionId = DriveCollectionId.forDrive(document.header.id, job.branch).key;\n\t\t\tindexTxn.createCollection(collectionId);\n\t\t\tindexTxn.addToCollection(collectionId, document.header.id);\n\t\t}\n\t\tstores.documentMetaCache.putDocumentMeta(document.header.id, job.branch, {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tdocumentScopeRevision: 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, document.header.id, document.header.documentType, resultingState, startTime);\n\t}\n\tasync executeDelete(write, executing) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tconst input = action.input;\n\t\tif (!input.documentId) return buildErrorResult(job, /* @__PURE__ */ new Error(\"DELETE_DOCUMENT action requires a documentId in input\"), startTime);\n\t\tconst documentId = input.documentId;\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await stores.writeCache.getState(documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch document before deletion: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t}\n\t\tconst documentState = document.state.document;\n\t\tif (documentState.isDeleted && !this.alreadyEvaluated(executing)) return buildErrorResult(job, new DocumentDeletedError(documentId, documentState.deletedAtUtcIso), startTime);\n\t\tlet operation = createOperation(action, getNextIndexForScope(document, job.scope), skip, {\n\t\t\tdocumentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tapplyDeleteDocumentAction$1(document, action);\n\t\tconst resultingStateObj = {\n\t\t\theader: document.header,\n\t\t\tdocument: document.state.document\n\t\t};\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(document, job.scope, operation.index);\n\t\tdocument.operations = {\n\t\t\t...document.operations,\n\t\t\t[job.scope]: [...document.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(documentId, job.scope, job.branch);\n\t\tstores.writeCache.putState(documentId, job.scope, job.branch, operation.index, document, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tstores.documentMetaCache.putDocumentMeta(documentId, job.branch, {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, documentId, document.header.documentType, resultingState, startTime);\n\t}\n\tasync executeUpgrade(write, executing) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tconst input = action.input;\n\t\tif (!input.documentId) return buildErrorResult(job, /* @__PURE__ */ new Error(\"UPGRADE_DOCUMENT action requires a documentId in input\"), startTime);\n\t\tconst documentId = input.documentId;\n\t\tconst fromVersion = input.fromVersion;\n\t\tconst toVersion = input.toVersion;\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await stores.writeCache.getState(documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch document for upgrade: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t}\n\t\tconst documentState = document.state.document;\n\t\tif (documentState.isDeleted && !this.alreadyEvaluated(executing)) return buildErrorResult(job, new DocumentDeletedError(documentId, documentState.deletedAtUtcIso), startTime);\n\t\tif (fromVersion === toVersion && fromVersion > 0) return {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: [],\n\t\t\toperationsWithContext: [],\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tconst arrivesDecided = executing.replayingAcceptedHistory || executing.evaluatedByPosition;\n\t\tif (fromVersion > 0 && !arrivesDecided) {\n\t\t\tconst stampedVersion = normalizeDocumentModelVersion(documentState.version);\n\t\t\tif (fromVersion !== stampedVersion) return buildErrorResult(job, new UpgradePreconditionFailedError(documentId, `fromVersion ${fromVersion} does not match the document's version ${stampedVersion}`), startTime);\n\t\t\tif (input.revision !== void 0) {\n\t\t\t\tlet actualRevisions;\n\t\t\t\ttry {\n\t\t\t\t\tactualRevisions = (await stores.operationStore.getRevisions(documentId, job.branch, signal)).revision;\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch revisions for upgrade: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t\t\t}\n\t\t\t\tconst revisionScopes = new Set([...Object.keys(input.revision), ...Object.keys(actualRevisions)]);\n\t\t\t\tfor (const revisionScope of revisionScopes) {\n\t\t\t\t\tconst snapshot = input.revision[revisionScope] ?? 0;\n\t\t\t\t\tconst actual = actualRevisions[revisionScope] ?? 0;\n\t\t\t\t\tif (snapshot !== actual) return buildErrorResult(job, new UpgradePreconditionFailedError(documentId, `revision snapshot for scope \"${revisionScope}\" is ${snapshot} but the document is at ${actual}`), startTime);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlet upgradePath;\n\t\tif (fromVersion > 0 && fromVersion < toVersion) try {\n\t\t\tupgradePath = this.registry.computeUpgradePath(document.header.documentType, fromVersion, toVersion);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tconst otherScopes = Object.keys(document.state).filter((scope) => scope !== job.scope);\n\t\tif (fromVersion > 0) for (const scope of otherScopes) {\n\t\t\tlet scopedDocument;\n\t\t\ttry {\n\t\t\t\tscopedDocument = await stores.writeCache.getState(documentId, scope, job.branch, void 0, signal);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`Failed to fetch ${scope} scope for upgrade: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t\t}\n\t\t\tdocument = {\n\t\t\t\t...document,\n\t\t\t\tstate: {\n\t\t\t\t\t...document.state,\n\t\t\t\t\t[scope]: scopedDocument.state[scope]\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\tconst nextIndex = getNextIndexForScope(document, job.scope);\n\t\ttry {\n\t\t\tdocument = applyUpgradeDocumentAction$1(document, action, upgradePath);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tlet operation = createOperation(action, nextIndex, skip, {\n\t\t\tdocumentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tconst resultingStateObj = {\n\t\t\theader: document.header,\n\t\t\t...document.state\n\t\t};\n\t\tif (fromVersion > 0) resultingStateObj.__migrated = true;\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tupdateDocumentRevision(document, job.scope, operation.index);\n\t\tdocument.operations = {\n\t\t\t...document.operations,\n\t\t\t[job.scope]: [...document.operations[job.scope] ?? [], operation]\n\t\t};\n\t\texecuting.touchedStreams.add(documentId, job.scope, job.branch);\n\t\tstores.writeCache.putState(documentId, job.scope, job.branch, operation.index, document, SnapshotPosition.Head);\n\t\tfor (const scope of otherScopes) executing.postCommitInvalidations.push({\n\t\t\tdocumentId,\n\t\t\tscope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tstores.documentMetaCache.putDocumentMeta(documentId, job.branch, {\n\t\t\tstate: document.state.document,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, documentId, document.header.documentType, resultingState, startTime);\n\t}\n\texecuteAddRelationship(write, executing) {\n\t\treturn this.withRelationshipAction(\"ADD_RELATIONSHIP\", write, executing, (input) => input.sourceId === input.targetId ? /* @__PURE__ */ new Error(\"ADD_RELATIONSHIP: sourceId and targetId cannot be the same (self-relationships not allowed)\") : null, ({ indexTxn: txn, stores: s, sourceDoc, input, job: j }) => {\n\t\t\tif (this.driveContainerTypes.has(sourceDoc.header.documentType)) {\n\t\t\t\tconst collectionId = DriveCollectionId.forDrive(input.sourceId, j.branch).key;\n\t\t\t\ttxn.addToCollection(collectionId, input.targetId);\n\t\t\t\ts.collectionMembershipCache.invalidate(input.targetId);\n\t\t\t}\n\t\t});\n\t}\n\texecuteRemoveRelationship(write, executing) {\n\t\treturn this.withRelationshipAction(\"REMOVE_RELATIONSHIP\", write, executing, null, ({ indexTxn: txn, stores: s, sourceDoc, input, job: j }) => {\n\t\t\tif (this.driveContainerTypes.has(sourceDoc.header.documentType)) {\n\t\t\t\tconst collectionId = DriveCollectionId.forDrive(input.sourceId, j.branch).key;\n\t\t\t\ttxn.removeFromCollection(collectionId, input.targetId);\n\t\t\t\ts.collectionMembershipCache.invalidate(input.targetId);\n\t\t\t}\n\t\t});\n\t}\n\texecuteUpdateRelationship(write, executing) {\n\t\treturn this.withRelationshipAction(\"UPDATE_RELATIONSHIP\", write, executing, null, null);\n\t}\n\tasync withRelationshipAction(actionTypeName, write, executing, preValidate, postWrite) {\n\t\tconst { action, skip, sourceRemote } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tif (job.scope !== \"document\") return buildErrorResult(job, /* @__PURE__ */ new Error(`${actionTypeName} must be in \"document\" scope, got \"${job.scope}\"`), startTime);\n\t\tconst input = action.input;\n\t\tif (!input.sourceId || !input.targetId || !input.relationshipType) return buildErrorResult(job, /* @__PURE__ */ new Error(`${actionTypeName} action requires sourceId, targetId, and relationshipType in input`), startTime);\n\t\tif (preValidate !== null) {\n\t\t\tconst validationError = preValidate(input);\n\t\t\tif (validationError !== null) return buildErrorResult(job, validationError, startTime);\n\t\t}\n\t\tlet sourceDoc;\n\t\ttry {\n\t\t\tsourceDoc = await stores.writeCache.getState(input.sourceId, \"document\", job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\tif (DocumentNotFoundError.isError(error)) return buildErrorResult(job, new DocumentNotFoundError(input.sourceId, `${actionTypeName}: source document ${input.sourceId} not found`), startTime);\n\t\t\treturn buildErrorResult(job, /* @__PURE__ */ new Error(`${actionTypeName}: source document ${input.sourceId} not found: ${error instanceof Error ? error.message : String(error)}`), startTime);\n\t\t}\n\t\tlet operation = createOperation(action, getNextIndexForScope(sourceDoc, job.scope), skip, {\n\t\t\tdocumentId: input.sourceId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t});\n\t\tconst writeResult = await this.writeOperationToStore({\n\t\t\tdocumentId: input.sourceId,\n\t\t\tdocumentType: sourceDoc.header.documentType,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch\n\t\t}, operation, executing);\n\t\tif (!Array.isArray(writeResult)) return writeResult;\n\t\toperation = writeResult[0];\n\t\tsourceDoc.header.lastModifiedAtUtcIso = operation.timestampUtcMs || (/* @__PURE__ */ new Date()).toISOString();\n\t\tupdateDocumentRevision(sourceDoc, job.scope, operation.index);\n\t\tsourceDoc.operations = {\n\t\t\t...sourceDoc.operations,\n\t\t\t[job.scope]: [...sourceDoc.operations[job.scope] ?? [], operation]\n\t\t};\n\t\tconst scopeState = sourceDoc.state[job.scope];\n\t\tconst resultingStateObj = {\n\t\t\theader: structuredClone(sourceDoc.header),\n\t\t\t[job.scope]: scopeState === void 0 ? {} : structuredClone(scopeState)\n\t\t};\n\t\tconst resultingState = JSON.stringify(resultingStateObj);\n\t\texecuting.touchedStreams.add(input.sourceId, job.scope, job.branch);\n\t\texecuting.touchedStreams.add(input.targetId, job.scope, job.branch);\n\t\tstores.writeCache.putState(input.sourceId, job.scope, job.branch, operation.index, sourceDoc, SnapshotPosition.Head);\n\t\tindexTxn.write([{\n\t\t\t...operation,\n\t\t\tdocumentId: input.sourceId,\n\t\t\tdocumentType: sourceDoc.header.documentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope: job.scope,\n\t\t\tsourceRemote\n\t\t}]);\n\t\tif (postWrite !== null) postWrite({\n\t\t\tindexTxn,\n\t\t\tstores,\n\t\t\tsourceDoc,\n\t\t\tinput,\n\t\t\tjob\n\t\t});\n\t\tstores.documentMetaCache.putDocumentMeta(input.sourceId, job.branch, {\n\t\t\tstate: sourceDoc.state.document,\n\t\t\tdocumentType: sourceDoc.header.documentType,\n\t\t\tdocumentScopeRevision: operation.index + 1\n\t\t});\n\t\treturn buildSuccessResult(job, operation, input.sourceId, sourceDoc.header.documentType, resultingState, startTime);\n\t}\n\tasync writeOperationToStore(target, operation, executing) {\n\t\tconst { documentId, documentType, scope, branch } = target;\n\t\tconst { job, startTime, stores, signal } = executing;\n\t\texecuting.touchedStreams.add(documentId, scope, branch);\n\t\tlet storedOperations;\n\t\ttry {\n\t\t\tstoredOperations = await stores.operationStore.apply(documentId, documentType, scope, branch, operation.index, (txn) => {\n\t\t\t\ttxn.addOperations(operation);\n\t\t\t}, signal);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to write operation to IOperationStore (@documentId @scope @branch): @Operation @Error\", documentId, scope, branch, operation, error);\n\t\t\tstores.writeCache.invalidate(documentId, scope, branch);\n\t\t\tif (AppendConditionFailedError.isError(error)) for (const stream of error.condition.streams) stores.writeCache.invalidate(stream.documentId, stream.scope, stream.branch);\n\t\t\treturn {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(`Failed to write operation to IOperationStore: ${String(error)}`),\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\treturn storedOperations;\n\t}\n};\n//#endregion\n//#region src/executor/signature-verifier.ts\nvar SignatureVerifier = class {\n\tconstructor(verifier) {\n\t\tthis.verifier = verifier;\n\t}\n\tasync verifyActions(documentId, branch, actions) {\n\t\tif (!this.verifier) return;\n\t\tfor (const action of actions) {\n\t\t\tconst signer = action.context?.signer;\n\t\t\tif (!signer) continue;\n\t\t\tif (signer.signatures.length === 0) throw new InvalidSignatureError(documentId, `Action ${action.id} has signer but no signatures`);\n\t\t\tconst publicKey = signer.app.key;\n\t\t\tlet isValid;\n\t\t\ttry {\n\t\t\t\tconst tempOperation = {\n\t\t\t\t\tid: deriveOperationId(documentId, action.scope, branch, action.id),\n\t\t\t\t\tindex: 0,\n\t\t\t\t\ttimestampUtcMs: action.timestampUtcMs || (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\t\thash: \"\",\n\t\t\t\t\tskip: 0,\n\t\t\t\t\taction\n\t\t\t\t};\n\t\t\t\tisValid = await this.verifier(tempOperation, publicKey);\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new InvalidSignatureError(documentId, `Action ${action.id} verification failed: ${errorMessage}`);\n\t\t\t}\n\t\t\tif (!isValid) throw new InvalidSignatureError(documentId, `Action ${action.id} signature verification returned false`);\n\t\t}\n\t}\n\tasync verifyOperations(documentId, operations) {\n\t\tif (!this.verifier) return;\n\t\tfor (let i = 0; i < operations.length; i++) {\n\t\t\tconst operation = operations[i];\n\t\t\tconst signer = operation.action.context?.signer;\n\t\t\tif (!signer) continue;\n\t\t\tif (signer.signatures.length === 0) throw new InvalidSignatureError(documentId, `Operation ${operation.id} at index ${operation.index} has signer but no signatures`);\n\t\t\tconst publicKey = signer.app.key;\n\t\t\tlet isValid;\n\t\t\ttry {\n\t\t\t\tisValid = await this.verifier(operation, publicKey);\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new InvalidSignatureError(documentId, `Operation ${operation.id} at index ${operation.index} verification failed: ${errorMessage}`);\n\t\t\t}\n\t\t\tif (!isValid) throw new InvalidSignatureError(documentId, `Operation ${operation.id} at index ${operation.index} signature verification returned false`);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/executor/simple-job-executor.ts\nconst MAX_SKIP_THRESHOLD = 1e3;\nconst ISO_TIMESTAMP_REGEX = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$/;\nfunction isValidISOTimestamp(value) {\n\tif (!ISO_TIMESTAMP_REGEX.test(value)) return false;\n\treturn !isNaN(new Date(value).getTime());\n}\n/**\n* Carries a failed job out of the execution scope so its transaction rolls\n* back. A scope callback that returns commits, whatever result it returns, so\n* a returned failure would leave the writes the job made before it failed\n* standing. Never escapes executeJob: the failure goes back to being a\n* returned JobResult there, which is what the queue, the worker protocol and\n* every test expect a failed job to look like.\n*/\nvar JobRollbackSignal = class extends Error {\n\tconstructor(result) {\n\t\tsuper(\"job rolled back\");\n\t\tthis.result = result;\n\t\tthis.name = \"JobRollbackSignal\";\n\t}\n};\nvar SimpleJobExecutor = class {\n\tconfig;\n\tfeatureFlags;\n\tdecisionModel;\n\tsignatureVerifierModule;\n\tdocumentActionHandler;\n\texecutionScope;\n\tconstructor(logger, registry, operationStore, eventBus, writeCache, operationIndex, documentMetaCache, collectionMembershipCache, driveContainerTypes, config, signatureVerifier, executionScope) {\n\t\tthis.logger = logger;\n\t\tthis.registry = registry;\n\t\tthis.operationStore = operationStore;\n\t\tthis.eventBus = eventBus;\n\t\tthis.writeCache = writeCache;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.documentMetaCache = documentMetaCache;\n\t\tthis.collectionMembershipCache = collectionMembershipCache;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.config = {\n\t\t\tfeatureFlags: config.featureFlags ?? {},\n\t\t\tmaxSkipThreshold: config.maxSkipThreshold ?? MAX_SKIP_THRESHOLD,\n\t\t\tmaxConcurrency: config.maxConcurrency ?? 1,\n\t\t\tjobTimeoutMs: config.jobTimeoutMs ?? 3e4,\n\t\t\tdeferredJobTtlMs: config.deferredJobTtlMs ?? 3e4,\n\t\t\tretryBaseDelayMs: config.retryBaseDelayMs ?? 100,\n\t\t\tretryMaxDelayMs: config.retryMaxDelayMs ?? 5e3,\n\t\t\tyieldDeadlineMs: config.yieldDeadlineMs ?? 50,\n\t\t\tbatchApplies: config.batchApplies ?? true\n\t\t};\n\t\tthis.featureFlags = resolveFeatureFlags(config.featureFlags);\n\t\tthis.decisionModel = selectDecisionModel(this.featureFlags, registry);\n\t\tthis.signatureVerifierModule = new SignatureVerifier(signatureVerifier);\n\t\tthis.documentActionHandler = new DocumentActionHandler(registry, logger, driveContainerTypes, this.featureFlags, this.decisionModel);\n\t\tthis.executionScope = executionScope ?? new DefaultExecutionScope(operationStore, operationIndex, writeCache, documentMetaCache, collectionMembershipCache);\n\t}\n\t/**\n\t* Execute a single job by applying all its actions through the appropriate reducers.\n\t* Actions are processed sequentially in order.\n\t*\n\t* The whole job runs inside one execution scope, and a scope callback that\n\t* returns commits. A failed job must therefore leave the scope by throwing,\n\t* or the writes it made before it failed would be durable: JobRollbackSignal\n\t* carries the failure out through the transaction and this method turns it\n\t* back into the returned JobResult every caller expects. A job either fully\n\t* applies or leaves nothing durable behind.\n\t*\n\t* Durable is the whole of the guarantee. The caches are shared with the\n\t* copies the scope hands the job, so a failed job's writes sit in them from\n\t* the moment it makes them until the eviction below, and a concurrent read\n\t* in that window sees a write that is never going to commit. The window is\n\t* not new -- it has always been there for a job that failed by throwing --\n\t* but nothing here closes it, and a caller that needs to know a write is\n\t* real has the job status to ask.\n\t*/\n\tasync executeJob(job, signal) {\n\t\tconst startTime = Date.now();\n\t\tconst touchedStreams = new TouchedStreams();\n\t\tconst postCommitInvalidations = [];\n\t\tconst postCommitMembershipInvalidations = [];\n\t\tlet outcome;\n\t\ttry {\n\t\t\toutcome = await this.executionScope.run(async (stores) => {\n\t\t\t\tconst scoped = await this.executeInScope({\n\t\t\t\t\tjob,\n\t\t\t\t\tstartTime,\n\t\t\t\t\tstores,\n\t\t\t\t\tsignal,\n\t\t\t\t\ttouchedStreams,\n\t\t\t\t\tpostCommitInvalidations,\n\t\t\t\t\tpostCommitMembershipInvalidations\n\t\t\t\t});\n\t\t\t\tif (!scoped.result.success) throw new JobRollbackSignal(scoped.result);\n\t\t\t\treturn scoped;\n\t\t\t}, signal);\n\t\t} catch (error) {\n\t\t\tthis.evictTouchedStreams(touchedStreams);\n\t\t\tif (error instanceof JobRollbackSignal) return error.result;\n\t\t\tthrow error;\n\t\t}\n\t\tfor (const entry of postCommitInvalidations) this.writeCache.invalidate(entry.documentId, entry.scope, entry.branch);\n\t\tfor (const documentId of postCommitMembershipInvalidations) this.collectionMembershipCache.invalidate(documentId);\n\t\tconst { pendingEvent } = outcome;\n\t\tif (pendingEvent) this.eventBus.emit(ReactorEventTypes.JOB_WRITE_READY, pendingEvent).catch((error) => {\n\t\t\tthis.logger.error(\"Failed to emit JOB_WRITE_READY event: @Event : @Error\", pendingEvent, error);\n\t\t});\n\t\treturn outcome.result;\n\t}\n\t/**\n\t* The body of a job, run inside the execution scope's transaction.\n\t*\n\t* The stores and caches it works through are the copies scoped to that\n\t* transaction, so nothing it does is durable until the scope commits. The\n\t* write-ready event is handed back rather than emitted, because a job that\n\t* has not committed yet has nothing to announce.\n\t*/\n\tasync executeInScope(params) {\n\t\tconst { job, startTime, stores, signal, touchedStreams, postCommitInvalidations, postCommitMembershipInvalidations } = params;\n\t\tlet pendingEvent;\n\t\tconst indexTxn = stores.operationIndex.start();\n\t\tif (job.kind === \"load\") {\n\t\t\tconst loadResult = await this.executeLoadJob({\n\t\t\t\tjob,\n\t\t\t\tstartTime,\n\t\t\t\tindexTxn,\n\t\t\t\tstores,\n\t\t\t\tsignal,\n\t\t\t\treplayingAcceptedHistory: true,\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\tpostCommitInvalidations,\n\t\t\t\tpostCommitMembershipInvalidations,\n\t\t\t\ttouchedStreams\n\t\t\t});\n\t\t\tif (loadResult.success && loadResult.operationsWithContext) {\n\t\t\t\tconst ordinals = await stores.operationIndex.commit(indexTxn, signal);\n\t\t\t\tpostCommitMembershipInvalidations.push(...indexTxn.getMembershipInvalidations());\n\t\t\t\tfor (let i = 0; i < loadResult.operationsWithContext.length; i++) loadResult.operationsWithContext[i].context.ordinal = ordinals[i];\n\t\t\t\tconst collectionMemberships = loadResult.operationsWithContext.length > 0 ? await this.getCollectionMembershipsForOperations(loadResult.operationsWithContext, stores) : {};\n\t\t\t\tpendingEvent = {\n\t\t\t\t\tjobId: job.id,\n\t\t\t\t\toperations: loadResult.operationsWithContext,\n\t\t\t\t\tjobMeta: job.meta,\n\t\t\t\t\tcollectionMemberships\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tresult: loadResult,\n\t\t\t\tpendingEvent\n\t\t\t};\n\t\t}\n\t\tif (job.kind === \"reevaluation\") {\n\t\t\tconst reevalResult = await this.executeReevaluationJob({\n\t\t\t\tjob,\n\t\t\t\tstartTime,\n\t\t\t\tindexTxn,\n\t\t\t\tstores,\n\t\t\t\tsignal,\n\t\t\t\treplayingAcceptedHistory: false,\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\tpostCommitInvalidations,\n\t\t\t\tpostCommitMembershipInvalidations,\n\t\t\t\ttouchedStreams\n\t\t\t});\n\t\t\tif (reevalResult.success && reevalResult.operationsWithContext) {\n\t\t\t\tconst ordinals = await stores.operationIndex.commit(indexTxn, signal);\n\t\t\t\tpostCommitMembershipInvalidations.push(...indexTxn.getMembershipInvalidations());\n\t\t\t\tfor (let i = 0; i < reevalResult.operationsWithContext.length; i++) reevalResult.operationsWithContext[i].context.ordinal = ordinals[i];\n\t\t\t\tif (reevalResult.operationsWithContext.length > 0) {\n\t\t\t\t\tconst collectionMemberships = await this.getCollectionMembershipsForOperations(reevalResult.operationsWithContext, stores);\n\t\t\t\t\tpendingEvent = {\n\t\t\t\t\t\tjobId: job.id,\n\t\t\t\t\t\toperations: reevalResult.operationsWithContext,\n\t\t\t\t\t\tjobMeta: job.meta,\n\t\t\t\t\t\tcollectionMemberships\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tresult: reevalResult,\n\t\t\t\tpendingEvent\n\t\t\t};\n\t\t}\n\t\tconst positioned = await this.positionByTimestamp(job, stores, signal);\n\t\tif (positioned.error) return { result: buildErrorResult(job, positioned.error, startTime) };\n\t\tconst executing = {\n\t\t\tjob,\n\t\t\tstartTime,\n\t\t\tindexTxn,\n\t\t\tstores,\n\t\t\tsignal,\n\t\t\treplayingAcceptedHistory: false,\n\t\t\tevaluatedByPosition: positioned.evaluatedByPosition,\n\t\t\tpostCommitInvalidations,\n\t\t\tpostCommitMembershipInvalidations,\n\t\t\ttouchedStreams\n\t\t};\n\t\tconst actionResult = await this.processActions(positioned.writes, executing);\n\t\tif (!actionResult.success) return { result: {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: actionResult.error,\n\t\t\tduration: Date.now() - startTime\n\t\t} };\n\t\tconst reevaluationError = await this.reevaluateIfCriteriaMet({\n\t\t\tscope: job.scope,\n\t\t\toperations: actionResult.generatedOperations\n\t\t}, executing);\n\t\tif (reevaluationError) return { result: {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: reevaluationError,\n\t\t\tduration: Date.now() - startTime\n\t\t} };\n\t\tconst ordinals = await stores.operationIndex.commit(indexTxn, signal);\n\t\tpostCommitMembershipInvalidations.push(...indexTxn.getMembershipInvalidations());\n\t\tif (actionResult.operationsWithContext.length > 0) {\n\t\t\tfor (let i = 0; i < actionResult.operationsWithContext.length; i++) actionResult.operationsWithContext[i].context.ordinal = ordinals[i];\n\t\t\tconst collectionMemberships = await this.getCollectionMembershipsForOperations(actionResult.operationsWithContext, stores);\n\t\t\tpendingEvent = {\n\t\t\t\tjobId: job.id,\n\t\t\t\toperations: actionResult.operationsWithContext,\n\t\t\t\tjobMeta: job.meta,\n\t\t\t\tcollectionMemberships\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tresult: {\n\t\t\t\tjob,\n\t\t\t\tsuccess: true,\n\t\t\t\toperations: actionResult.generatedOperations,\n\t\t\t\toperationsWithContext: actionResult.operationsWithContext,\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t},\n\t\t\tpendingEvent\n\t\t};\n\t}\n\t/**\n\t* Drops the cached state of every stream a job wrote, after its transaction\n\t* did not commit.\n\t*\n\t* The caches are shared by reference with the copies the scope hands the job,\n\t* so a rollback undoes nothing in them: what the job put there survives, as\n\t* does anything a read filled from the store while the job's own writes were\n\t* still uncommitted. An eviction that throws is swallowed rather than allowed\n\t* to replace the failure the caller is owed, and the remaining streams are\n\t* still evicted.\n\t*/\n\tevictTouchedStreams(touchedStreams) {\n\t\tfor (const entry of touchedStreams) try {\n\t\t\tthis.writeCache.invalidate(entry.documentId, entry.scope, entry.branch);\n\t\t\tthis.documentMetaCache.invalidate(entry.documentId, entry.branch);\n\t\t\tthis.collectionMembershipCache.invalidate(entry.documentId);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to evict cached state for rolled back @Stream : @Error\", entry, error);\n\t\t}\n\t}\n\tasync getCollectionMembershipsForOperations(operations, stores) {\n\t\tconst documentIds = [...new Set(operations.map((op) => op.context.documentId))];\n\t\treturn stores.collectionMembershipCache.getCollectionsForDocuments(documentIds);\n\t}\n\tasync processActions(writes, executing) {\n\t\tconst { job, signal } = executing;\n\t\tconst actions = writes.map((write) => write.action);\n\t\tconst generatedOperations = [];\n\t\tconst operationsWithContext = [];\n\t\ttry {\n\t\t\tawait this.signatureVerifierModule.verifyActions(job.documentId, job.branch, actions);\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext,\n\t\t\t\terror: error instanceof Error ? error : new Error(String(error))\n\t\t\t};\n\t\t}\n\t\tfor (const action of actions) if (action.timestampUtcMs && !isValidISOTimestamp(action.timestampUtcMs)) return {\n\t\t\tsuccess: false,\n\t\t\tgeneratedOperations,\n\t\t\toperationsWithContext,\n\t\t\terror: new InvalidOperationTimestampError(job.documentId, action.scope, action.timestampUtcMs, `action ${action.type} (id: ${action.id})`)\n\t\t};\n\t\tlet lastYield = performance.now();\n\t\tif (this.config.batchApplies && this.canBatch(writes, executing)) {\n\t\t\tconst batched = await this.executeRegularActionsBatched(writes, executing);\n\t\t\tconst error = this.accumulateResultOrReturnError(batched, generatedOperations, operationsWithContext);\n\t\t\tif (error !== null) return {\n\t\t\t\tsuccess: false,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext,\n\t\t\t\terror: error.error\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext\n\t\t\t};\n\t\t}\n\t\tfor (const write of writes) {\n\t\t\tconst result = DOCUMENT_SCOPE_ACTIONS.has(write.action.type) ? await this.documentActionHandler.execute(write, executing) : await this.executeRegularAction(write, executing);\n\t\t\tconst error = this.accumulateResultOrReturnError(result, generatedOperations, operationsWithContext);\n\t\t\tif (error !== null) return {\n\t\t\t\tsuccess: false,\n\t\t\t\tgeneratedOperations,\n\t\t\t\toperationsWithContext,\n\t\t\t\terror: error.error\n\t\t\t};\n\t\t\tif (performance.now() - lastYield > this.config.yieldDeadlineMs) {\n\t\t\t\tawait yieldToMain();\n\t\t\t\tlastYield = performance.now();\n\t\t\t\tif (signal?.aborted) return {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tgeneratedOperations,\n\t\t\t\t\toperationsWithContext,\n\t\t\t\t\terror: /* @__PURE__ */ new Error(\"Aborted\")\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tgeneratedOperations,\n\t\t\toperationsWithContext\n\t\t};\n\t}\n\t/**\n\t* Decides a write and reduces it, without persisting anything.\n\t*\n\t* Split from the commit so one write and a batch of them share this logic\n\t* rather than keeping two copies of it. `baseDocument` lets a batch thread\n\t* the previous action's result forward instead of reading its own write back\n\t* out of the cache, which is the only reason the reduce has to be sequential.\n\t*/\n\tasync prepareRegularWrite(write, executing, baseDocument) {\n\t\tconst { action, skip, sourceOperation, sourceRemote, deniedReason } = write;\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tlet appendCondition;\n\t\tlet documentVersion;\n\t\tconst alreadyEvaluated = this.featureFlags.documentDecisions && (executing.replayingAcceptedHistory || executing.evaluatedByPosition);\n\t\tif (this.featureFlags.documentDecisions && !alreadyEvaluated) {\n\t\t\tconst target = {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tbranch: job.branch\n\t\t\t};\n\t\t\tlet admission;\n\t\t\ttry {\n\t\t\t\tadmission = await decideAtHead(this.decisionModel, stores.writeCache, target, {\n\t\t\t\t\taddress: action.context?.signer?.user.address,\n\t\t\t\t\tkey: action.context?.signer?.app.key\n\t\t\t\t}, {\n\t\t\t\t\tverb: \"execute\",\n\t\t\t\t\tscope: action.scope,\n\t\t\t\t\toperation: action.type\n\t\t\t\t}, signal, this.featureFlags.authConditions ? {\n\t\t\t\t\tactionInput: action.input,\n\t\t\t\t\tcarriedDocument: baseDocument\n\t\t\t\t} : void 0);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t\t}\n\t\t\tif (admission.evaluation.decision === \"deny\") return buildErrorResult(job, refusalError(admission.evaluation.reason, job.documentId, admission.deletedAtUtcIso, action), startTime);\n\t\t\tappendCondition = admission.appendCondition;\n\t\t\tdocumentVersion = admission.documentVersion;\n\t\t} else if (alreadyEvaluated) documentVersion = (await stores.writeCache.getState(job.documentId, \"document\", job.branch, void 0, signal)).state.document.version;\n\t\telse {\n\t\t\tlet docMeta;\n\t\t\ttry {\n\t\t\t\tdocMeta = await stores.documentMetaCache.getDocumentMeta(job.documentId, job.branch, signal);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t\t}\n\t\t\tif (docMeta.state.isDeleted) return buildErrorResult(job, new DocumentDeletedError(job.documentId, docMeta.state.deletedAtUtcIso), startTime);\n\t\t\tdocumentVersion = docMeta.state.version;\n\t\t}\n\t\tif (isUndoRedo(action) || action.type === \"PRUNE\" || skip > 0) stores.writeCache.invalidate(job.documentId, job.scope, job.branch);\n\t\tlet document;\n\t\tif (baseDocument !== void 0) document = baseDocument;\n\t\telse try {\n\t\t\tdocument = await stores.writeCache.getState(job.documentId, job.scope, job.branch, void 0, signal);\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tif (!this.featureFlags.authEnforcement && !executing.replayingAcceptedHistory) {\n\t\t\tconst subject = {\n\t\t\t\taddress: write.action.context?.signer?.user.address,\n\t\t\t\tkey: write.action.context?.signer?.app.key\n\t\t\t};\n\t\t\tif (decide(document.state.auth, subject, {\n\t\t\t\tverb: \"execute\",\n\t\t\t\tscope: action.scope,\n\t\t\t\toperation: action.type\n\t\t\t}) === \"deny\") return buildErrorResult(job, new AuthorizationDeniedError(job.documentId, action.scope, action.type, subject.address), startTime);\n\t\t}\n\t\tlet module;\n\t\ttry {\n\t\t\tmodule = this.registry.getModule(document.header.documentType, normalizeDocumentModelVersion(documentVersion));\n\t\t} catch (error) {\n\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t}\n\t\tlet updatedDocument;\n\t\tif (deniedReason !== void 0) {\n\t\t\tconst index = getNextIndexForScope(document, job.scope);\n\t\t\tconst denied = createOperation(action, index, skip, {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch\n\t\t\t});\n\t\t\tdenied.deniedReason = deniedReason;\n\t\t\tlet standing = document;\n\t\t\tif (skip > 0) try {\n\t\t\t\tstanding = await stores.writeCache.getState(job.documentId, job.scope, job.branch, index - skip - 1, signal);\n\t\t\t} catch (error) {\n\t\t\t\treturn buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);\n\t\t\t}\n\t\t\tdenied.hash = hashDocumentStateForScope(standing, job.scope);\n\t\t\tupdatedDocument = {\n\t\t\t\t...standing,\n\t\t\t\toperations: {\n\t\t\t\t\t...standing.operations,\n\t\t\t\t\t[job.scope]: [...standing.operations[job.scope] ?? [], denied]\n\t\t\t\t}\n\t\t\t};\n\t\t} else try {\n\t\t\tconst protocolVersion = baseReducerVersion(document.header);\n\t\t\tconst reducerOptions = sourceOperation ? {\n\t\t\t\tskip,\n\t\t\t\tbranch: job.branch,\n\t\t\t\treplayOptions: { operation: sourceOperation },\n\t\t\t\tprotocolVersion\n\t\t\t} : {\n\t\t\t\tskip,\n\t\t\t\tbranch: job.branch,\n\t\t\t\tprotocolVersion\n\t\t\t};\n\t\t\tupdatedDocument = module.reducer(document, action, void 0, reducerOptions);\n\t\t} catch (error) {\n\t\t\tconst contextMessage = `Failed to apply action to document:\\n Action type: ${action.type}\\n Document ID: ${job.documentId}\\n Document type: ${document.header.documentType}\\n Scope: ${job.scope}\\n Original error: ${error instanceof Error ? error.message : String(error)}`;\n\t\t\tconst enhancedError = new Error(contextMessage);\n\t\t\tif (error instanceof Error && error.stack) enhancedError.stack = `${contextMessage}\\n\\nOriginal stack trace:\\n${error.stack}`;\n\t\t\treturn buildErrorResult(job, enhancedError, startTime);\n\t\t}\n\t\tconst scope = job.scope;\n\t\tconst operations = updatedDocument.operations[scope];\n\t\tif (operations.length === 0) return buildErrorResult(job, /* @__PURE__ */ new Error(\"No operation generated from action\"), startTime);\n\t\tconst newOperation = operations[operations.length - 1];\n\t\tif (!isUndoRedo(action)) newOperation.skip = skip;\n\t\tconst resultingState = JSON.stringify({\n\t\t\t...updatedDocument.state,\n\t\t\theader: updatedDocument.header\n\t\t});\n\t\treturn {\n\t\t\taction,\n\t\t\tsourceRemote,\n\t\t\tscope,\n\t\t\tdocument,\n\t\t\tupdatedDocument,\n\t\t\toperation: newOperation,\n\t\t\tresultingState,\n\t\t\tappendCondition,\n\t\t\tdenied: deniedReason !== void 0\n\t\t};\n\t}\n\t/**\n\t* Persists a run of prepared writes in one store transaction.\n\t*\n\t* The store has always accepted many operations per apply; the executor only\n\t* ever handed it one. Passing the whole run means one advisory lock over the\n\t* read set and one guarded insert for the batch, instead of one of each per\n\t* operation.\n\t*\n\t* The append condition is taken from the first write. Every write in a run\n\t* reads the same streams at the same revisions, because nothing outside the\n\t* run can change them mid-batch, and the caller has already refused to batch\n\t* the scopes where that does not hold.\n\t*/\n\tasync commitPreparedWrites(prepared, executing) {\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tconst first = prepared[0];\n\t\tconst last = prepared[prepared.length - 1];\n\t\tconst scope = first.scope;\n\t\tconst documentType = first.document.header.documentType;\n\t\tconst operations = prepared.map((write) => write.operation);\n\t\texecuting.touchedStreams.add(job.documentId, scope, job.branch);\n\t\tlet storedOperations;\n\t\ttry {\n\t\t\tstoredOperations = await stores.operationStore.apply(job.documentId, documentType, scope, job.branch, first.operation.index, (txn) => {\n\t\t\t\ttxn.addOperations(...operations);\n\t\t\t}, signal, first.appendCondition);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to write operation to IOperationStore (@documentId @scope @branch): @Operation @Error\", job.documentId, scope, job.branch, operations, error);\n\t\t\tstores.writeCache.invalidate(job.documentId, scope, job.branch);\n\t\t\tif (AppendConditionFailedError.isError(error)) for (const stream of error.condition.streams) stores.writeCache.invalidate(stream.documentId, stream.scope, stream.branch);\n\t\t\treturn {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(`Failed to write operation to IOperationStore: ${String(error)}`),\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst head = storedOperations[storedOperations.length - 1];\n\t\tlast.updatedDocument.header.revision = {\n\t\t\t...last.updatedDocument.header.revision,\n\t\t\t[scope]: head.index + 1\n\t\t};\n\t\tstores.writeCache.putRun(job.documentId, scope, job.branch, storedOperations.map((operation, position) => ({\n\t\t\trevision: operation.index,\n\t\t\tdocument: prepared[position].updatedDocument\n\t\t})));\n\t\tindexTxn.write(storedOperations.map((operation, position) => ({\n\t\t\t...operation,\n\t\t\tdocumentId: job.documentId,\n\t\t\tdocumentType,\n\t\t\tbranch: job.branch,\n\t\t\tscope,\n\t\t\tsourceRemote: prepared[position].sourceRemote\n\t\t})));\n\t\tif (scope === \"auth\") for (const write of prepared) indexTxn.recordGroupReferences(job.documentId, mentionedGroupIds(write.action));\n\t\treturn {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: storedOperations,\n\t\t\toperationsWithContext: storedOperations.map((operation, position) => ({\n\t\t\t\toperation,\n\t\t\t\tcontext: {\n\t\t\t\t\tdocumentId: job.documentId,\n\t\t\t\t\tscope,\n\t\t\t\t\tbranch: job.branch,\n\t\t\t\t\tdocumentType,\n\t\t\t\t\tresultingState: prepared[position].resultingState,\n\t\t\t\t\tordinal: 0\n\t\t\t\t}\n\t\t\t})),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t}\n\t/**\n\t* Whether a job's writes may share one store transaction.\n\t*\n\t* Deliberately narrow. Batching changes only how many transactions the\n\t* operations arrive in, and every condition below is a case where that would\n\t* change something else as well:\n\t*\n\t* - A document-scope action goes through its own handler, which has its own\n\t* apply and its own reasons for it.\n\t* - A positional or replayed run carries skips and re-appended operations,\n\t* whose indices are not a simple ascending run from the head.\n\t* - UNDO, REDO, PRUNE and NOOP-with-skip each invalidate the write cache to\n\t* force a full-history rebuild, so they cannot be reduced against state\n\t* threaded from the write before them.\n\t* - The auth scope decides later writes against the policy earlier ones\n\t* install, so a batch would decide them all against the policy as it stood\n\t* before the batch.\n\t* - The document scope is read by every decision model, so writing it is\n\t* writing part of the read set; the per-write conditions would not agree.\n\t*\n\t* A run that fails any of these is executed one write at a time, unchanged.\n\t*/\n\tcanBatch(writes, executing) {\n\t\tif (writes.length < 2) return false;\n\t\tif (executing.evaluatedByPosition || executing.replayingAcceptedHistory) return false;\n\t\tconst scope = executing.job.scope;\n\t\tif (scope === \"auth\" || scope === \"document\") return false;\n\t\treturn writes.every((write) => {\n\t\t\tconst type = write.action.type;\n\t\t\treturn write.skip === 0 && write.deniedReason === void 0 && write.sourceOperation === void 0 && !DOCUMENT_SCOPE_ACTIONS.has(type) && !isUndoRedo(write.action) && type !== \"PRUNE\" && type !== \"NOOP\";\n\t\t});\n\t}\n\t/**\n\t* Decides and reduces a run of writes, then persists them together.\n\t*\n\t* The reduce stays sequential - each action needs the state the one before it\n\t* produced - but the result is threaded in memory rather than read back from\n\t* the cache, and the whole run reaches the store in a single apply.\n\t*\n\t* A write that turns out to be denied abandons the batch and replays the run\n\t* one write at a time, because a denied write holds a position of its own and\n\t* that is the path where the per-write behaviour is load-bearing. A write\n\t* that cannot be prepared fails the job outright: preparing is a read, so the\n\t* replay would only reach the same failure, and the job leaves nothing behind\n\t* either way.\n\t*/\n\tasync executeRegularActionsBatched(writes, executing) {\n\t\tconst prepared = [];\n\t\tlet carried;\n\t\tlet lastYield = performance.now();\n\t\tfor (const write of writes) {\n\t\t\tconst outcome = await this.prepareRegularWrite(write, executing, carried);\n\t\t\tif (\"success\" in outcome) return outcome;\n\t\t\tif (outcome.denied) return this.executeRegularActionsSequentially(writes, executing);\n\t\t\tprepared.push(outcome);\n\t\t\tcarried = outcome.updatedDocument;\n\t\t\tif (performance.now() - lastYield > this.config.yieldDeadlineMs) {\n\t\t\t\tawait yieldToMain();\n\t\t\t\tlastYield = performance.now();\n\t\t\t\tif (executing.signal?.aborted) return buildErrorResult(executing.job, /* @__PURE__ */ new Error(\"Aborted\"), executing.startTime);\n\t\t\t}\n\t\t}\n\t\tif (!this.conditionsAgree(prepared)) return this.executeRegularActionsSequentially(writes, executing);\n\t\treturn this.commitPreparedWrites(prepared, executing);\n\t}\n\t/** Whether every prepared write carries the same read-set condition. */\n\tconditionsAgree(prepared) {\n\t\tconst shape = (write) => write.appendCondition === void 0 ? \"none\" : JSON.stringify([...write.appendCondition.streams].map((stream) => [\n\t\t\tstream.documentId,\n\t\t\tstream.scope,\n\t\t\tstream.branch,\n\t\t\tstream.revision\n\t\t]).sort());\n\t\tconst first = shape(prepared[0]);\n\t\treturn prepared.every((write) => shape(write) === first);\n\t}\n\t/**\n\t* The unbatched path, for a run that turned out not to qualify after its\n\t* writes were prepared. Nothing has been persisted at that point, so\n\t* replaying the whole run per write is safe.\n\t*/\n\tasync executeRegularActionsSequentially(writes, executing) {\n\t\tconst operations = [];\n\t\tconst contexts = [];\n\t\tlet lastYield = performance.now();\n\t\tfor (const write of writes) {\n\t\t\tconst result = await this.executeRegularAction(write, executing);\n\t\t\tif (!result.success) return result;\n\t\t\toperations.push(...result.operations ?? []);\n\t\t\tcontexts.push(...result.operationsWithContext ?? []);\n\t\t\tif (performance.now() - lastYield > this.config.yieldDeadlineMs) {\n\t\t\t\tawait yieldToMain();\n\t\t\t\tlastYield = performance.now();\n\t\t\t\tif (executing.signal?.aborted) return buildErrorResult(executing.job, /* @__PURE__ */ new Error(\"Aborted\"), executing.startTime);\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tjob: executing.job,\n\t\t\tsuccess: true,\n\t\t\toperations,\n\t\t\toperationsWithContext: contexts,\n\t\t\tduration: Date.now() - executing.startTime\n\t\t};\n\t}\n\t/** Decides, reduces and persists one write. */\n\tasync executeRegularAction(write, executing) {\n\t\tconst prepared = await this.prepareRegularWrite(write, executing);\n\t\tif (\"success\" in prepared) return prepared;\n\t\treturn this.commitPreparedWrites([prepared], executing);\n\t}\n\t/**\n\t* Orders a write by timestamp and decides it where it lands. The caller\n\t* supplies the timestamp, so a write can belong before operations already\n\t* stored; those are re-appended alongside it, the way a load reshuffles.\n\t*\n\t* Deciding a backdated write at the stream heads instead of at its position\n\t* would overwrite the verdict every other replica computes for it.\n\t*/\n\tasync positionByTimestamp(job, stores, signal) {\n\t\tconst plain = () => ({\n\t\t\twrites: job.actions.map((action) => ({\n\t\t\t\taction,\n\t\t\t\tskip: 0,\n\t\t\t\tsourceRemote: \"\"\n\t\t\t})),\n\t\t\tevaluatedByPosition: false\n\t\t});\n\t\tif (!this.featureFlags.documentDecisions || job.actions.length === 0) return plain();\n\t\tlet earliest = job.actions[0].timestampUtcMs;\n\t\tlet earliestAt = Date.parse(earliest);\n\t\tfor (const action of job.actions) {\n\t\t\tconst at = Date.parse(action.timestampUtcMs);\n\t\t\tif (at < earliestAt) {\n\t\t\t\tearliest = action.timestampUtcMs;\n\t\t\t\tearliestAt = at;\n\t\t\t}\n\t\t}\n\t\tconst revisions = await stores.operationStore.getRevisions(job.documentId, job.branch, signal);\n\t\tconst backdated = earliestAt < Date.parse(revisions.latestTimestamp);\n\t\tif (this.featureFlags.authEnforcement && job.scope === \"auth\") {\n\t\t\tconst newest = await stores.operationStore.getStreamLatestTimestamp(job.documentId, \"auth\", job.branch, signal);\n\t\t\tconst violation = this.firstNonMonotonicTimestamp(job.actions, newest, job.documentId, job.branch);\n\t\t\tif (violation) return {\n\t\t\t\twrites: [],\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\terror: violation\n\t\t\t};\n\t\t\tif (!backdated) return plain();\n\t\t\treturn this.evaluatePositioned(job, stores, this.appendedOperations(job, revisions.revision[job.scope] ?? 0), signal);\n\t\t}\n\t\tif (!backdated) return plain();\n\t\tconst conflicting = (await stores.operationStore.getConflicting(job.documentId, job.scope, job.branch, earliest, void 0, signal)).results.filter((operation) => !isGenesisOperation(operation));\n\t\tif (conflicting.length === 0) {\n\t\t\tif (!this.featureFlags.authEnforcement) return plain();\n\t\t\treturn this.evaluatePositioned(job, stores, this.appendedOperations(job, revisions.revision[job.scope] ?? 0), signal);\n\t\t}\n\t\tconst nextIndex = revisions.revision[job.scope] ?? 0;\n\t\tlet firstConflicting = conflicting[0].index;\n\t\tfor (const operation of conflicting) if (operation.index < firstConflicting) firstConflicting = operation.index;\n\t\tconst incoming = job.actions.map((action, i) => ({\n\t\t\tid: action.id,\n\t\t\tindex: nextIndex + i,\n\t\t\tskip: 0,\n\t\t\thash: \"\",\n\t\t\ttimestampUtcMs: action.timestampUtcMs,\n\t\t\taction\n\t\t}));\n\t\tconst merged = reshuffleByTimestamp({\n\t\t\tindex: nextIndex,\n\t\t\tskip: retractionSkip(nextIndex, firstConflicting)\n\t\t}, conflicting, incoming);\n\t\tstores.writeCache.invalidate(job.documentId, job.scope, job.branch);\n\t\tif (!this.featureFlags.authEnforcement) return {\n\t\t\twrites: merged.map((operation) => ({\n\t\t\t\taction: operation.action,\n\t\t\t\tskip: operation.skip,\n\t\t\t\tsourceRemote: \"\"\n\t\t\t})),\n\t\t\tevaluatedByPosition: false\n\t\t};\n\t\treturn this.evaluatePositioned(job, stores, merged, signal);\n\t}\n\t/**\n\t* Decides each operation where it lands and carries the verdict on it. A\n\t* refused submitted action is reported to the caller and nothing is stored; a\n\t* refused operation the reshuffle merely moved keeps its verdict, because it\n\t* already holds a position.\n\t*\n\t* The operations carry the indexes and skips they will be stored at, because\n\t* the walk resolves skips before it orders them.\n\t*/\n\tasync evaluatePositioned(job, stores, operations, signal) {\n\t\tconst reasons = await evaluateByPosition(this.decisionModel, {\n\t\t\tdocumentId: job.documentId,\n\t\t\tbranch: job.branch\n\t\t}, {\n\t\t\tscope: job.scope,\n\t\t\toperations\n\t\t}, stores, signal);\n\t\tconst submitted = new Set(job.actions.map((action) => action.id));\n\t\tfor (let i = 0; i < operations.length; i++) {\n\t\t\tconst reason = reasons[i];\n\t\t\tif (reason !== void 0 && submitted.has(operations[i].action.id)) return {\n\t\t\t\twrites: [],\n\t\t\t\tevaluatedByPosition: false,\n\t\t\t\terror: refusalError(reason, job.documentId, null, operations[i].action)\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\twrites: operations.map((operation, i) => ({\n\t\t\t\taction: operation.action,\n\t\t\t\tskip: operation.skip,\n\t\t\t\tsourceRemote: \"\",\n\t\t\t\tdeniedReason: reasons[i]\n\t\t\t})),\n\t\t\tevaluatedByPosition: true\n\t\t};\n\t}\n\t/**\n\t* The scopes a re-evaluation pass visits, in a fixed order.\n\t*\n\t* The revisions map comes from a query with no ORDER BY, and the order is\n\t* load-bearing: each scope's pass re-reads the auth stream, and the walk skips\n\t* an operation by its stored denial, so a denial this pass just wrote is\n\t* visible to a later-visited scope and invisible to an earlier one. The model's\n\t* own projection order leads, then the rest sorted, so the pass is reproducible\n\t* across replicas and across runs.\n\t*/\n\tevaluationOrder(target, revision) {\n\t\tconst definition = this.decisionModel(target);\n\t\tconst evaluated = Object.keys(revision).filter((scope) => definition.evaluatesScope(scope));\n\t\tconst leading = [];\n\t\tfor (const stream of staticReadSet(definition)) {\n\t\t\tconst scope = stream.query.scope;\n\t\t\tif (evaluated.includes(scope) && !leading.includes(scope)) leading.push(scope);\n\t\t}\n\t\tconst rest = evaluated.filter((scope) => !leading.includes(scope)).sort((a, b) => a.localeCompare(b));\n\t\treturn [...leading, ...rest];\n\t}\n\t/**\n\t* The first timestamp in the batch that does not strictly exceed everything\n\t* ahead of it, or undefined when the whole batch is monotonic.\n\t*\n\t* The bound is carried forward rather than compared against one stored maximum,\n\t* because a single execute can carry several auth actions stamped in the same\n\t* millisecond. Letting a tie through would store a stream the position walk\n\t* then refuses to read, with no repair path.\n\t*/\n\tfirstNonMonotonicTimestamp(entries, newest, documentId, branch) {\n\t\tlet boundIso = newest;\n\t\tlet bound = newest === void 0 ? Number.NEGATIVE_INFINITY : Date.parse(newest);\n\t\tfor (const entry of entries) {\n\t\t\tif (!isValidISOTimestamp(entry.timestampUtcMs)) return new InvalidOperationTimestampError(documentId, \"auth\", entry.timestampUtcMs, \"auth operation\");\n\t\t\tconst at = Date.parse(entry.timestampUtcMs);\n\t\t\tif (boundIso !== void 0 && at <= bound) return new AuthTimestampNotMonotonicError(documentId, branch, entry.timestampUtcMs, boundIso);\n\t\t\tbound = at;\n\t\t\tboundIso = entry.timestampUtcMs;\n\t\t}\n\t}\n\t/** The operations a batch of submitted actions appends at the scope's tail. */\n\tappendedOperations(job, nextIndex) {\n\t\treturn job.actions.map((action, i) => ({\n\t\t\tid: action.id,\n\t\t\tindex: nextIndex + i,\n\t\t\tskip: 0,\n\t\t\thash: \"\",\n\t\t\ttimestampUtcMs: action.timestampUtcMs,\n\t\t\taction\n\t\t}));\n\t}\n\t/**\n\t* Re-evaluates the document when a write meets both criteria: it was written\n\t* to a stream the model reads, and it is timestamped before an operation\n\t* already stored. The caller supplies the timestamp and the reactor does not replace\n\t* it, so a mutation job can write such an operation just as a load job can,\n\t* which is why both executeJob and executeLoadJob call this.\n\t*/\n\tasync reevaluateIfCriteriaMet(criteria, executing) {\n\t\tif (!this.featureFlags.documentDecisions) return;\n\t\tconst { job, stores, signal } = executing;\n\t\tconst target = {\n\t\t\tdocumentId: job.documentId,\n\t\t\tbranch: job.branch\n\t\t};\n\t\tif (!staticReadSet(this.decisionModel(target)).some((stream) => stream.query.documentId === job.documentId && stream.query.scope === criteria.scope && stream.query.branch === job.branch)) return;\n\t\tconst revisions = await stores.operationStore.getRevisions(job.documentId, job.branch, signal);\n\t\tconst latest = Date.parse(revisions.latestTimestamp);\n\t\tif (!criteria.operations.some((operation) => Date.parse(operation.timestampUtcMs) < latest)) return;\n\t\treturn (await this.reevaluateDocument(executing)).error;\n\t}\n\t/**\n\t* Re-evaluates every scope the model evaluates. Where an operation's\n\t* evaluation differs from what is stored, the tail from that operation is\n\t* re-appended, carrying a skip that spans the indices it supersedes.\n\t*/\n\tasync reevaluateDocument(executing) {\n\t\tconst { job, stores, signal } = executing;\n\t\tconst target = {\n\t\t\tdocumentId: job.documentId,\n\t\t\tbranch: job.branch\n\t\t};\n\t\tconst reappended = [];\n\t\tconst revisions = await stores.operationStore.getRevisions(job.documentId, job.branch, signal);\n\t\tfor (const scope of this.evaluationOrder(target, revisions.revision)) {\n\t\t\tconst stored = (await stores.operationStore.getSince(job.documentId, scope, job.branch, -1, void 0, void 0, signal)).results;\n\t\t\tconst effective = garbageCollect(sortOperations([...stored]));\n\t\t\tif (effective.length === 0) continue;\n\t\t\tconst reevaluated = await evaluateByPosition(this.decisionModel, target, {\n\t\t\t\tscope,\n\t\t\t\toperations: effective\n\t\t\t}, stores, signal);\n\t\t\tconst firstChange = effective.findIndex((operation, i) => operation.deniedReason !== reevaluated[i]);\n\t\t\tif (firstChange === -1) continue;\n\t\t\tconst tail = effective.slice(firstChange);\n\t\t\tconst nextIndex = revisions.revision[scope];\n\t\t\tstores.writeCache.invalidate(job.documentId, scope, job.branch);\n\t\t\tconst result = await this.processActions(tail.map((operation, i) => ({\n\t\t\t\taction: operation.action,\n\t\t\t\tskip: i === 0 ? retractionSkip(nextIndex, tail[0].index) : 0,\n\t\t\t\tsourceRemote: \"\",\n\t\t\t\tdeniedReason: reevaluated[firstChange + i]\n\t\t\t})), {\n\t\t\t\t...executing,\n\t\t\t\tjob: {\n\t\t\t\t\t...job,\n\t\t\t\t\tscope\n\t\t\t\t},\n\t\t\t\treplayingAcceptedHistory: true,\n\t\t\t\tevaluatedByPosition: true\n\t\t\t});\n\t\t\tif (!result.success) return {\n\t\t\t\terror: result.error ?? /* @__PURE__ */ new Error(`Re-evaluation of ${job.documentId} ${scope} failed`),\n\t\t\t\toperationsWithContext: reappended\n\t\t\t};\n\t\t\treappended.push(...result.operationsWithContext);\n\t\t}\n\t\treturn { operationsWithContext: reappended };\n\t}\n\t/**\n\t* Re-judges a document's stored operations because a read-set stream in\n\t* another document (a group) gained an operation. The trigger timestamp\n\t* bounds the work: an operation later than everything this document holds\n\t* cannot change any evaluation, so the pass is skipped.\n\t*/\n\tasync executeReevaluationJob(executing) {\n\t\tconst { job, startTime, stores, signal } = executing;\n\t\tif (!this.featureFlags.documentDecisions) return {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: [],\n\t\t\toperationsWithContext: [],\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tconst trigger = job.meta.triggerTimestampUtcMs;\n\t\tif (typeof trigger === \"string\") {\n\t\t\tlet latestTimestamp;\n\t\t\ttry {\n\t\t\t\tlatestTimestamp = (await stores.operationStore.getRevisions(job.documentId, job.branch, signal)).latestTimestamp;\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tjob,\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\toperations: [],\n\t\t\t\t\toperationsWithContext: [],\n\t\t\t\t\tduration: Date.now() - startTime\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (Date.parse(trigger) > Date.parse(latestTimestamp)) return {\n\t\t\t\tjob,\n\t\t\t\tsuccess: true,\n\t\t\t\toperations: [],\n\t\t\t\toperationsWithContext: [],\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst outcome = await this.reevaluateDocument(executing);\n\t\tif (outcome.error) return buildErrorResult(job, outcome.error, startTime);\n\t\treturn {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: outcome.operationsWithContext.map((owc) => owc.operation),\n\t\t\toperationsWithContext: outcome.operationsWithContext,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t}\n\tasync executeLoadJob(executing) {\n\t\tconst { job, startTime, indexTxn, stores, signal } = executing;\n\t\tif (job.operations.length === 0) return buildErrorResult(job, /* @__PURE__ */ new Error(\"Load job must include at least one operation\"), startTime);\n\t\tlet docMeta;\n\t\ttry {\n\t\t\tdocMeta = await stores.documentMetaCache.getDocumentMeta(job.documentId, job.branch, signal);\n\t\t} catch {}\n\t\tif (docMeta?.state.isDeleted && !this.featureFlags.documentDecisions) return buildErrorResult(job, new DocumentDeletedError(job.documentId, docMeta.state.deletedAtUtcIso), startTime);\n\t\tconst scope = job.scope;\n\t\tconst monotonicAuthStream = this.featureFlags.authEnforcement && scope === \"auth\";\n\t\tlet latestRevision;\n\t\ttry {\n\t\t\tlatestRevision = (await stores.operationStore.getRevisions(job.documentId, job.branch, signal)).revision[scope] ?? 0;\n\t\t} catch {\n\t\t\tlatestRevision = 0;\n\t\t}\n\t\tfor (const operation of job.operations) if (operation.timestampUtcMs && !isValidISOTimestamp(operation.timestampUtcMs)) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: new InvalidOperationTimestampError(job.documentId, scope, operation.timestampUtcMs, `operation (index: ${operation.index})`),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tlet minIncomingIndex = Number.POSITIVE_INFINITY;\n\t\tlet minIncomingTimestamp = job.operations[0]?.timestampUtcMs || \"\";\n\t\tfor (const operation of job.operations) {\n\t\t\tminIncomingIndex = Math.min(minIncomingIndex, operation.index);\n\t\t\tconst ts = operation.timestampUtcMs || \"\";\n\t\t\tif (Date.parse(ts) < Date.parse(minIncomingTimestamp)) minIncomingTimestamp = ts;\n\t\t}\n\t\tlet conflictingOps;\n\t\ttry {\n\t\t\tconflictingOps = (await stores.operationStore.getConflicting(job.documentId, scope, job.branch, minIncomingTimestamp, void 0, signal)).results;\n\t\t} catch {\n\t\t\tconflictingOps = [];\n\t\t}\n\t\tlet allOpsFromMinConflictingIndex = conflictingOps;\n\t\tif (conflictingOps.length > 0) {\n\t\t\tconst minConflictingIndex = Math.min(...conflictingOps.map((op) => op.index));\n\t\t\ttry {\n\t\t\t\tallOpsFromMinConflictingIndex = (await stores.operationStore.getSince(job.documentId, scope, job.branch, minConflictingIndex - 1, void 0, void 0, signal)).results;\n\t\t\t} catch {\n\t\t\t\tallOpsFromMinConflictingIndex = conflictingOps;\n\t\t\t}\n\t\t}\n\t\tconst incomingActionIds = new Set(job.operations.map((op) => op.action.id));\n\t\tconst nonSupersededOps = conflictingOps.filter((op) => {\n\t\t\tif (op.index < minIncomingIndex && !incomingActionIds.has(op.action.id)) return false;\n\t\t\tfor (const laterOp of allOpsFromMinConflictingIndex) if (laterOp.index > op.index && laterOp.skip > 0) {\n\t\t\t\tif (laterOp.index - laterOp.skip <= op.index) return false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\tconst existingOpsToReshuffle = monotonicAuthStream ? [] : nonSupersededOps.filter((operation) => !isGenesisOperation(operation));\n\t\tconst actionIdCounts = /* @__PURE__ */ new Map();\n\t\tfor (const operation of allOpsFromMinConflictingIndex) actionIdCounts.set(operation.action.id, (actionIdCounts.get(operation.action.id) ?? 0) + 1);\n\t\tconst reshuffleCost = existingOpsToReshuffle.filter((operation) => (actionIdCounts.get(operation.action.id) ?? 0) < 2).length;\n\t\tif (reshuffleCost > this.config.maxSkipThreshold) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: new ExcessiveReshuffleError(job.documentId, scope, reshuffleCost, this.config.maxSkipThreshold),\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tlet skipCount = existingOpsToReshuffle.length;\n\t\tif (existingOpsToReshuffle.length > 0) {\n\t\t\tlet minLogicalIndex = Number.POSITIVE_INFINITY;\n\t\t\tfor (const op of existingOpsToReshuffle) {\n\t\t\t\tconst logical = op.index - op.skip;\n\t\t\t\tif (logical < minLogicalIndex) minLogicalIndex = logical;\n\t\t\t}\n\t\t\tconst logicalSkip = latestRevision - minLogicalIndex;\n\t\t\tif (logicalSkip > skipCount) skipCount = logicalSkip;\n\t\t}\n\t\tconst existingActionIds = new Set(nonSupersededOps.map((op) => op.action.id));\n\t\tconst seenIncomingActionIds = /* @__PURE__ */ new Set();\n\t\tconst incomingOpsToApply = job.operations.filter((op) => {\n\t\t\tif (existingActionIds.has(op.action.id)) return false;\n\t\t\tif (seenIncomingActionIds.has(op.action.id)) return false;\n\t\t\tseenIncomingActionIds.add(op.action.id);\n\t\t\treturn true;\n\t\t});\n\t\tif (incomingOpsToApply.length === 0) return {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: [],\n\t\t\toperationsWithContext: [],\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tif (monotonicAuthStream) {\n\t\t\tconst newest = await stores.operationStore.getStreamLatestTimestamp(job.documentId, \"auth\", job.branch, signal);\n\t\t\tconst violation = this.firstNonMonotonicTimestamp([...incomingOpsToApply].sort((a, b) => a.index - b.index), newest, job.documentId, job.branch);\n\t\t\tif (violation) return {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: violation,\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst reshuffledOperations = existingOpsToReshuffle.length === 0 && skipCount === 0 ? incomingOpsToApply.slice().sort((a, b) => a.index - b.index).map((operation, i) => ({\n\t\t\t...operation,\n\t\t\tindex: latestRevision + i\n\t\t})) : reshuffleByTimestamp({\n\t\t\tindex: latestRevision,\n\t\t\tskip: skipCount\n\t\t}, existingOpsToReshuffle, incomingOpsToApply.map((operation) => ({\n\t\t\t...operation,\n\t\t\tid: operation.id\n\t\t})));\n\t\tfor (const operation of reshuffledOperations) if (operation.action.type === \"NOOP\" && operation.skip === 0) operation.skip = 1;\n\t\tlet deniedReasons;\n\t\tif (this.featureFlags.documentDecisions) try {\n\t\t\tdeniedReasons = await evaluateByPosition(this.decisionModel, {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tbranch: job.branch\n\t\t\t}, {\n\t\t\t\tscope,\n\t\t\t\toperations: reshuffledOperations\n\t\t\t}, stores, signal);\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tjob,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: error instanceof Error ? error : new Error(String(error)),\n\t\t\t\tduration: Date.now() - startTime\n\t\t\t};\n\t\t}\n\t\tconst effectiveSourceRemote = skipCount > 0 ? \"\" : job.meta.sourceRemote || \"\";\n\t\tconst result = await this.processActions(reshuffledOperations.map((operation, i) => ({\n\t\t\taction: operation.action,\n\t\t\tskip: operation.skip,\n\t\t\tsourceOperation: operation,\n\t\t\tsourceRemote: effectiveSourceRemote,\n\t\t\tdeniedReason: deniedReasons?.[i]\n\t\t})), executing);\n\t\tif (!result.success) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: result.error,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\tstores.writeCache.invalidate(job.documentId, scope, job.branch);\n\t\tif (scope === \"document\") stores.documentMetaCache.invalidate(job.documentId, job.branch);\n\t\tconst reevaluationError = await this.reevaluateIfCriteriaMet({\n\t\t\tscope,\n\t\t\toperations: result.generatedOperations\n\t\t}, executing);\n\t\tif (reevaluationError) return {\n\t\t\tjob,\n\t\t\tsuccess: false,\n\t\t\terror: reevaluationError,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t\treturn {\n\t\t\tjob,\n\t\t\tsuccess: true,\n\t\t\toperations: result.generatedOperations,\n\t\t\toperationsWithContext: result.operationsWithContext,\n\t\t\tduration: Date.now() - startTime\n\t\t};\n\t}\n\taccumulateResultOrReturnError(result, generatedOperations, operationsWithContext) {\n\t\tif (!result.success) return result;\n\t\tif (result.operations && result.operations.length > 0) generatedOperations.push(...result.operations);\n\t\tif (result.operationsWithContext) operationsWithContext.push(...result.operationsWithContext);\n\t\treturn null;\n\t}\n};\n//#endregion\n//#region src/registry/implementation.ts\n/**\n* In-memory implementation of the IDocumentModelRegistry interface.\n* Manages document model modules with version-aware storage and upgrade manifest support.\n*/\nvar DocumentModelRegistry = class {\n\tmodules = [];\n\tmanifests = [];\n\tregisterModules(...modules) {\n\t\treturn modules.map((module) => {\n\t\t\ttry {\n\t\t\t\tconst documentType = module.documentModel.global.id;\n\t\t\t\tconst version = module.version ?? 1;\n\t\t\t\tfor (let i = 0; i < this.modules.length; i++) {\n\t\t\t\t\tconst existing = this.modules[i];\n\t\t\t\t\tconst existingType = existing.documentModel.global.id;\n\t\t\t\t\tconst existingVersion = existing.version ?? 1;\n\t\t\t\t\tif (existingType === documentType && existingVersion === version) throw new DuplicateModuleError(documentType, version);\n\t\t\t\t}\n\t\t\t\tthis.modules.push(module);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\titem: module\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\titem: module,\n\t\t\t\t\terror: error instanceof Error ? error : new Error(String(error))\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\tunregisterModules(...documentTypes) {\n\t\tlet allFound = true;\n\t\tfor (const documentType of documentTypes) {\n\t\t\tif (!this.modules.some((m) => m.documentModel.global.id === documentType)) allFound = false;\n\t\t\tthis.modules = this.modules.filter((m) => m.documentModel.global.id !== documentType);\n\t\t}\n\t\treturn allFound;\n\t}\n\tgetModule(documentType, version) {\n\t\tlet latestModule;\n\t\tlet latestVersion = -1;\n\t\tfor (let i = 0; i < this.modules.length; i++) {\n\t\t\tconst module = this.modules[i];\n\t\t\tconst moduleType = module.documentModel.global.id;\n\t\t\tconst moduleVersion = module.version ?? 1;\n\t\t\tif (moduleType === documentType) {\n\t\t\t\tif (version !== void 0 && moduleVersion === version) return module;\n\t\t\t\tif (moduleVersion > latestVersion) {\n\t\t\t\t\tlatestModule = module;\n\t\t\t\t\tlatestVersion = moduleVersion;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (version === void 0 && latestModule !== void 0) return latestModule;\n\t\tthrow new ModuleNotFoundError(documentType, version);\n\t}\n\tgetAllModules() {\n\t\treturn [...this.modules];\n\t}\n\tclear() {\n\t\tthis.modules = [];\n\t\tthis.manifests = [];\n\t}\n\tgetSupportedVersions(documentType) {\n\t\tconst versions = [];\n\t\tfor (const module of this.modules) if (module.documentModel.global.id === documentType) versions.push(module.version ?? 1);\n\t\tif (versions.length === 0) throw new ModuleNotFoundError(documentType);\n\t\treturn versions.sort((a, b) => a - b);\n\t}\n\tgetLatestVersion(documentType) {\n\t\tlet latest = -1;\n\t\tlet found = false;\n\t\tfor (const module of this.modules) if (module.documentModel.global.id === documentType) {\n\t\t\tfound = true;\n\t\t\tconst version = module.version ?? 1;\n\t\t\tif (version > latest) latest = version;\n\t\t}\n\t\tif (!found) throw new ModuleNotFoundError(documentType);\n\t\treturn latest;\n\t}\n\tregisterUpgradeManifests(...manifestsToRegister) {\n\t\treturn manifestsToRegister.map((manifestToRegister) => {\n\t\t\ttry {\n\t\t\t\tif (!manifestToRegister.documentType) throw new Error(\"Upgrade manifest is missing a documentType\");\n\t\t\t\tfor (const registeredManifest of this.manifests) if (registeredManifest.documentType === manifestToRegister.documentType) throw new DuplicateManifestError(manifestToRegister.documentType);\n\t\t\t\tthis.manifests.push(manifestToRegister);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\titem: manifestToRegister\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\titem: manifestToRegister,\n\t\t\t\t\terror: error instanceof Error ? error : new Error(String(error))\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\tunregisterUpgradeManifests(...documentTypes) {\n\t\tlet allFound = true;\n\t\tfor (const documentType of documentTypes) {\n\t\t\tif (!this.manifests.some((m) => m.documentType === documentType)) allFound = false;\n\t\t\tthis.manifests = this.manifests.filter((m) => m.documentType !== documentType);\n\t\t}\n\t\treturn allFound;\n\t}\n\tgetUpgradeManifest(documentType) {\n\t\tfor (let i = 0; i < this.manifests.length; i++) if (this.manifests[i].documentType === documentType) return this.manifests[i];\n\t\tthrow new ManifestNotFoundError(documentType);\n\t}\n\tcomputeUpgradePath(documentType, fromVersion, toVersion) {\n\t\tif (fromVersion === toVersion) return [];\n\t\tif (toVersion < fromVersion) throw new DowngradeNotSupportedError$1(documentType, fromVersion, toVersion);\n\t\tconst manifest = this.getUpgradeManifest(documentType);\n\t\tconst path = [];\n\t\tfor (let v = fromVersion + 1; v <= toVersion; v++) {\n\t\t\tconst key = `v${v}`;\n\t\t\tif (!(key in manifest.upgrades)) throw new MissingUpgradeTransitionError(documentType, v - 1, v);\n\t\t\tconst transition = manifest.upgrades[key];\n\t\t\tpath.push(transition);\n\t\t}\n\t\treturn path;\n\t}\n\tgetUpgradeReducer(documentType, fromVersion, toVersion) {\n\t\tif (toVersion !== fromVersion + 1) throw new InvalidUpgradeStepError(documentType, fromVersion, toVersion);\n\t\tconst manifest = this.getUpgradeManifest(documentType);\n\t\tconst key = `v${toVersion}`;\n\t\tif (!(key in manifest.upgrades)) throw new MissingUpgradeTransitionError(documentType, fromVersion, toVersion);\n\t\treturn manifest.upgrades[key].upgradeReducer;\n\t}\n};\n//#endregion\n//#region src/storage/kysely/keyframe-store.ts\nvar KyselyKeyframeStore = class KyselyKeyframeStore {\n\ttrx;\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tget queryExecutor() {\n\t\treturn this.trx ?? this.db;\n\t}\n\twithTransaction(trx) {\n\t\tconst instance = new KyselyKeyframeStore(this.db);\n\t\tinstance.trx = trx;\n\t\treturn instance;\n\t}\n\tasync putKeyframe(documentId, scope, branch, revision, document, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.queryExecutor.insertInto(\"Keyframe\").values({\n\t\t\tdocumentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tscope,\n\t\t\tbranch,\n\t\t\trevision,\n\t\t\tdocument\n\t\t}).onConflict((oc) => oc.columns([\n\t\t\t\"documentId\",\n\t\t\t\"scope\",\n\t\t\t\"branch\",\n\t\t\t\"revision\"\n\t\t]).doUpdateSet({ document })).execute();\n\t}\n\tasync findNearestKeyframe(documentId, scope, branch, targetRevision, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst row = await this.queryExecutor.selectFrom(\"Keyframe\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"revision\", \"<=\", targetRevision).orderBy(\"revision\", \"desc\").limit(1).executeTakeFirst();\n\t\tif (!row) return;\n\t\treturn {\n\t\t\trevision: row.revision,\n\t\t\tdocument: row.document\n\t\t};\n\t}\n\tasync listKeyframes(documentId, scope, branch, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tlet query = this.queryExecutor.selectFrom(\"Keyframe\").selectAll().where(\"documentId\", \"=\", documentId).orderBy(\"revision\", \"asc\");\n\t\tif (scope !== void 0) query = query.where(\"scope\", \"=\", scope);\n\t\tif (branch !== void 0) query = query.where(\"branch\", \"=\", branch);\n\t\treturn (await query.execute()).map((row) => ({\n\t\t\tscope: row.scope,\n\t\t\tbranch: row.branch,\n\t\t\trevision: row.revision,\n\t\t\tdocument: row.document\n\t\t}));\n\t}\n\tasync deleteKeyframes(documentId, scope, branch, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tlet query = this.queryExecutor.deleteFrom(\"Keyframe\").where(\"documentId\", \"=\", documentId);\n\t\tif (scope !== void 0 && branch !== void 0) query = query.where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch);\n\t\telse if (scope !== void 0) query = query.where(\"scope\", \"=\", scope);\n\t\tconst result = await query.executeTakeFirst();\n\t\treturn Number(result.numDeletedRows || 0n);\n\t}\n};\n//#endregion\n//#region src/storage/kysely/pagination.ts\nconst DEFAULT_LIMIT = 100;\nfunction paginateRows(rows, paging, cursorOf, toItem, refetch) {\n\tlet hasMore = false;\n\tlet items = rows;\n\tif (paging?.limit && rows.length > paging.limit) {\n\t\thasMore = true;\n\t\titems = rows.slice(0, paging.limit);\n\t}\n\tconst nextCursor = hasMore && items.length > 0 ? cursorOf(items[items.length - 1]).toString() : void 0;\n\tconst cursor = paging?.cursor || \"0\";\n\tconst limit = paging?.limit || DEFAULT_LIMIT;\n\treturn {\n\t\tresults: items.map(toItem),\n\t\toptions: {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t},\n\t\tnextCursor,\n\t\tnext: hasMore ? () => refetch(nextCursor, limit) : void 0\n\t};\n}\n//#endregion\n//#region src/storage/txn.ts\nvar AtomicTransaction = class {\n\toperations = [];\n\tconstructor(documentId, documentType, scope, branch, baseRevision) {\n\t\tthis.documentId = documentId;\n\t\tthis.documentType = documentType;\n\t\tthis.scope = scope;\n\t\tthis.branch = branch;\n\t\tthis.baseRevision = baseRevision;\n\t}\n\taddOperations(...operations) {\n\t\tfor (const op of operations) this.operations.push({\n\t\t\tjobId: v4(),\n\t\t\topId: op.id,\n\t\t\tprevOpId: \"\",\n\t\t\tdocumentId: this.documentId,\n\t\t\tdocumentType: this.documentType,\n\t\t\tscope: this.scope,\n\t\t\tbranch: this.branch,\n\t\t\ttimestampUtcMs: new Date(op.timestampUtcMs),\n\t\t\tindex: op.index,\n\t\t\taction: JSON.stringify(op.action),\n\t\t\tskip: op.skip,\n\t\t\terror: op.error || null,\n\t\t\tdeniedReason: op.deniedReason || null,\n\t\t\thash: op.hash\n\t\t});\n\t}\n\tgetOperations() {\n\t\treturn this.operations;\n\t}\n};\n//#endregion\n//#region src/storage/kysely/store.ts\nvar _UniqueConstraintContext = class extends Error {\n\tconstructor(documentId, scope, branch, revision, stagedOps) {\n\t\tsuper(\"unique constraint\");\n\t\tthis.documentId = documentId;\n\t\tthis.scope = scope;\n\t\tthis.branch = branch;\n\t\tthis.revision = revision;\n\t\tthis.stagedOps = stagedOps;\n\t\tthis.name = \"UniqueConstraintContext\";\n\t}\n};\nvar KyselyOperationStore = class KyselyOperationStore {\n\ttrx;\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tget queryExecutor() {\n\t\treturn this.trx ?? this.db;\n\t}\n\twithTransaction(trx) {\n\t\tconst instance = new KyselyOperationStore(this.db);\n\t\tinstance.trx = trx;\n\t\treturn instance;\n\t}\n\tasync apply(documentId, documentType, scope, branch, revision, fn, signal, condition) {\n\t\tif (this.trx) {\n\t\t\tlet executeResult = null;\n\t\t\tlet uniqueCtx = null;\n\t\t\ttry {\n\t\t\t\texecuteResult = await this.executeApply(this.trx, documentId, documentType, scope, branch, revision, fn, signal, condition);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof _UniqueConstraintContext) uniqueCtx = error;\n\t\t\t\telse throw error;\n\t\t\t}\n\t\t\tif (uniqueCtx !== null) return this.resolveUniqueConstraint(uniqueCtx);\n\t\t\treturn executeResult;\n\t\t} else {\n\t\t\tlet transactionResult = null;\n\t\t\tlet uniqueCtx = null;\n\t\t\ttry {\n\t\t\t\ttransactionResult = await this.db.transaction().execute(async (trx) => {\n\t\t\t\t\treturn this.executeApply(trx, documentId, documentType, scope, branch, revision, fn, signal, condition);\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof _UniqueConstraintContext) uniqueCtx = error;\n\t\t\t\telse throw error;\n\t\t\t}\n\t\t\tif (uniqueCtx !== null) return this.resolveUniqueConstraint(uniqueCtx);\n\t\t\treturn transactionResult;\n\t\t}\n\t}\n\tasync resolveUniqueConstraint(ctx) {\n\t\tlet replayOps = null;\n\t\ttry {\n\t\t\treplayOps = await this.findIdempotentReplay(this.db, ctx.documentId, ctx.scope, ctx.branch, ctx.revision, ctx.stagedOps);\n\t\t} catch {}\n\t\tif (replayOps !== null) return replayOps;\n\t\tconst op = ctx.stagedOps[0];\n\t\tthrow new DuplicateOperationError(`${op.opId} at index ${op.index} with skip ${op.skip}`);\n\t}\n\tasync executeApply(trx, documentId, documentType, scope, branch, revision, fn, signal, condition) {\n\t\tthrowIfAborted(signal);\n\t\tconst atomicTxn = new AtomicTransaction(documentId, documentType, scope, branch, revision);\n\t\tawait fn(atomicTxn);\n\t\tconst operations = atomicTxn.getOperations();\n\t\tif (operations.length === 0) return [];\n\t\tif (condition) await this.acquireStreamLocks(trx, documentId, scope, branch, condition);\n\t\tconst latestOp = await trx.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).orderBy(\"index\", \"desc\").limit(1).executeTakeFirst();\n\t\tconst currentRevision = latestOp ? latestOp.index : -1;\n\t\tif (currentRevision !== revision - 1) {\n\t\t\tlet replayOps = null;\n\t\t\ttry {\n\t\t\t\treplayOps = await this.findIdempotentReplay(trx, documentId, scope, branch, revision, operations);\n\t\t\t} catch {}\n\t\t\tif (replayOps !== null) return replayOps;\n\t\t\tif (revision === 0 && this.isCreate(operations)) throw new DocumentAlreadyExistsError(documentId, scope, currentRevision);\n\t\t\tthrow new RevisionMismatchError(currentRevision + 1, revision);\n\t\t}\n\t\tlet prevOpId = latestOp?.opId || \"\";\n\t\tfor (const op of operations) {\n\t\t\top.prevOpId = prevOpId;\n\t\t\tprevOpId = op.opId;\n\t\t}\n\t\tlet insertedCount = operations.length;\n\t\ttry {\n\t\t\tif (condition && condition.streams.length > 0) insertedCount = await this.insertGuarded(trx, operations, condition);\n\t\t\telse await trx.insertInto(\"Operation\").values(operations).execute();\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.includes(\"unique constraint\")) throw new _UniqueConstraintContext(documentId, scope, branch, revision, operations);\n\t\t\tthrow error;\n\t\t}\n\t\tif (insertedCount !== operations.length) throw new AppendConditionFailedError(condition);\n\t\treturn operations.map((op) => ({\n\t\t\tindex: op.index,\n\t\t\ttimestampUtcMs: op.timestampUtcMs.toISOString(),\n\t\t\thash: op.hash,\n\t\t\tskip: op.skip,\n\t\t\terror: op.error || void 0,\n\t\t\tdeniedReason: op.deniedReason || void 0,\n\t\t\tid: op.opId,\n\t\t\taction: JSON.parse(op.action)\n\t\t}));\n\t}\n\t/**\n\t* Locks the written stream and every read-set stream, in sorted key order\n\t* so that overlapping concurrent appends serialize rather than deadlock.\n\t* The locks are still taken one row at a time, so the query preserves that\n\t* order. It must stay separate from the guarded insert, which would\n\t* otherwise read a snapshot taken before the locks were held.\n\t*/\n\tasync acquireStreamLocks(trx, documentId, scope, branch, condition) {\n\t\tconst keys = new Set([`${documentId}:${scope}:${branch}`]);\n\t\tfor (const stream of condition.streams) keys.add(`${stream.documentId}:${stream.scope}:${stream.branch}`);\n\t\tawait sql`\n with ordered as materialized (\n select key\n from unnest(array[${sql.join([...keys].sort())}]::text[]) with ordinality as t(key, ord)\n order by ord\n )\n select pg_advisory_xact_lock(hashtext(key)) from ordered\n `.execute(trx);\n\t}\n\t/**\n\t* Inserts the staged operations with the condition compiled in as a WHERE\n\t* NOT EXISTS guard, making the check and the append one statement. Returns\n\t* the rows inserted; zero means the guard failed and nothing was written.\n\t*/\n\tasync insertGuarded(trx, operations, condition) {\n\t\tconst branches = operations.map((op) => trx.selectNoFrom([\n\t\t\tsql`${op.jobId}::text`.as(\"jobId\"),\n\t\t\tsql`${op.opId}::text`.as(\"opId\"),\n\t\t\tsql`${op.prevOpId}::text`.as(\"prevOpId\"),\n\t\t\tsql`${op.documentId}::text`.as(\"documentId\"),\n\t\t\tsql`${op.documentType}::text`.as(\"documentType\"),\n\t\t\tsql`${op.scope}::text`.as(\"scope\"),\n\t\t\tsql`${op.branch}::text`.as(\"branch\"),\n\t\t\tsql`${op.timestampUtcMs}::timestamptz`.as(\"timestampUtcMs\"),\n\t\t\tsql`${op.index}::integer`.as(\"index\"),\n\t\t\tsql`${op.action}::jsonb`.as(\"action\"),\n\t\t\tsql`${op.skip}::integer`.as(\"skip\"),\n\t\t\tsql`${op.error ?? null}::text`.as(\"error\"),\n\t\t\tsql`${op.deniedReason ?? null}::text`.as(\"deniedReason\"),\n\t\t\tsql`${op.hash}::text`.as(\"hash\")\n\t\t]).where((eb) => eb.not(eb.exists(eb.selectFrom(\"Operation\").select(\"Operation.id\").where((web) => web.or(condition.streams.map((s) => web.and([\n\t\t\tweb(\"Operation.documentId\", \"=\", s.documentId),\n\t\t\tweb(\"Operation.scope\", \"=\", s.scope),\n\t\t\tweb(\"Operation.branch\", \"=\", s.branch),\n\t\t\tweb(\"Operation.index\", \">\", s.revision)\n\t\t]))))))));\n\t\tlet expression = branches[0];\n\t\tfor (let i = 1; i < branches.length; i++) expression = expression.unionAll(branches[i]);\n\t\treturn (await trx.insertInto(\"Operation\").columns([\n\t\t\t\"jobId\",\n\t\t\t\"opId\",\n\t\t\t\"prevOpId\",\n\t\t\t\"documentId\",\n\t\t\t\"documentType\",\n\t\t\t\"scope\",\n\t\t\t\"branch\",\n\t\t\t\"timestampUtcMs\",\n\t\t\t\"index\",\n\t\t\t\"action\",\n\t\t\t\"skip\",\n\t\t\t\"error\",\n\t\t\t\"deniedReason\",\n\t\t\t\"hash\"\n\t\t]).expression(expression).returning(\"id\").execute()).length;\n\t}\n\tasync findIdempotentReplay(executor, documentId, scope, branch, revision, stagedOps) {\n\t\tconst minIndex = revision;\n\t\tconst maxIndex = revision + stagedOps.length - 1;\n\t\tconst storedRows = await executor.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"index\", \">=\", minIndex).where(\"index\", \"<=\", maxIndex).orderBy(\"index\", \"asc\").execute();\n\t\tif (storedRows.length !== stagedOps.length) return null;\n\t\tfor (let i = 0; i < stagedOps.length; i++) {\n\t\t\tconst staged = stagedOps[i];\n\t\t\tconst stored = storedRows[i];\n\t\t\tif (stored.opId !== staged.opId || stored.index !== staged.index || stored.skip !== staged.skip) return null;\n\t\t}\n\t\treturn storedRows.map((row) => this.rowToOperation(row));\n\t}\n\t/** True when the staged write creates a document rather than appending to one. */\n\tisCreate(operations) {\n\t\tfor (const operation of operations) {\n\t\t\tlet action = operation.action;\n\t\t\tif (typeof action === \"string\") try {\n\t\t\t\taction = JSON.parse(action);\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (typeof action === \"object\" && action !== null && \"type\" in action && typeof action.type === \"string\" && action.type === \"CREATE_DOCUMENT\") return true;\n\t\t}\n\t\treturn false;\n\t}\n\tasync getSince(documentId, scope, branch, revision, filter, paging, signal) {\n\t\tthrowIfAborted(signal);\n\t\tlet query = this.queryExecutor.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"index\", \">\", revision).orderBy(\"index\", \"asc\");\n\t\tif (filter) {\n\t\t\tif (filter.actionTypes && filter.actionTypes.length > 0) {\n\t\t\t\tconst actionTypesArray = filter.actionTypes.map((t) => `'${t.replace(/'/g, \"''\")}'`).join(\",\");\n\t\t\t\tquery = query.where(sql`action->>'type' = ANY(ARRAY[${sql.raw(actionTypesArray)}]::text[])`);\n\t\t\t}\n\t\t\tif (filter.timestampFrom) query = query.where(\"timestampUtcMs\", \">=\", new Date(filter.timestampFrom));\n\t\t\tif (filter.timestampTo) query = query.where(\"timestampUtcMs\", \"<=\", new Date(filter.timestampTo));\n\t\t\tif (filter.sinceRevision !== void 0) query = query.where(\"index\", \">=\", filter.sinceRevision);\n\t\t}\n\t\tif (paging) {\n\t\t\tconst cursorValue = Number.parseInt(paging.cursor, 10);\n\t\t\tif (cursorValue > 0) query = query.where(\"index\", \">\", cursorValue);\n\t\t\tif (paging.limit) query = query.limit(paging.limit + 1);\n\t\t}\n\t\treturn paginateRows(await query.execute(), paging, (row) => row.index, (row) => this.rowToOperation(row), (cursor, limit) => this.getSince(documentId, scope, branch, revision, filter, {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t}, signal));\n\t}\n\tasync getSinceId(id, paging, signal) {\n\t\tthrowIfAborted(signal);\n\t\tlet query = this.queryExecutor.selectFrom(\"Operation\").selectAll().where(\"id\", \">\", id).orderBy(\"id\", \"asc\");\n\t\tif (paging) {\n\t\t\tconst cursorValue = Number.parseInt(paging.cursor, 10);\n\t\t\tif (cursorValue > 0) query = query.where(\"id\", \">\", cursorValue);\n\t\t\tif (paging.limit) query = query.limit(paging.limit + 1);\n\t\t}\n\t\treturn paginateRows(await query.execute(), paging, (row) => row.id, (row) => this.rowToOperationWithContext(row), (cursor, limit) => this.getSinceId(id, {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t}, signal));\n\t}\n\tasync getConflicting(documentId, scope, branch, minTimestamp, paging, signal) {\n\t\tthrowIfAborted(signal);\n\t\tlet query = this.queryExecutor.selectFrom(\"Operation\").selectAll().where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).where(\"timestampUtcMs\", \">=\", new Date(minTimestamp)).orderBy(\"index\", \"asc\");\n\t\tif (paging) {\n\t\t\tconst cursorValue = Number.parseInt(paging.cursor, 10);\n\t\t\tif (cursorValue > 0) query = query.where(\"index\", \">\", cursorValue);\n\t\t\tif (paging.limit) query = query.limit(paging.limit + 1);\n\t\t}\n\t\treturn paginateRows(await query.execute(), paging, (row) => row.index, (row) => this.rowToOperation(row), (cursor, limit) => this.getConflicting(documentId, scope, branch, minTimestamp, {\n\t\t\tcursor,\n\t\t\tlimit\n\t\t}, signal));\n\t}\n\tasync getRevisions(documentId, branch, signal) {\n\t\tthrowIfAborted(signal);\n\t\tconst scopeRevisions = await this.queryExecutor.selectFrom(\"Operation as o1\").select([\n\t\t\t\"o1.scope\",\n\t\t\t\"o1.index\",\n\t\t\t\"o1.timestampUtcMs\"\n\t\t]).where(\"o1.documentId\", \"=\", documentId).where(\"o1.branch\", \"=\", branch).where((eb) => eb(\"o1.index\", \"=\", eb.selectFrom(\"Operation as o2\").select((eb2) => eb2.fn.max(\"o2.index\").as(\"maxIndex\")).where(\"o2.documentId\", \"=\", eb.ref(\"o1.documentId\")).where(\"o2.branch\", \"=\", eb.ref(\"o1.branch\")).where(\"o2.scope\", \"=\", eb.ref(\"o1.scope\")))).execute();\n\t\tconst latest = await this.queryExecutor.selectFrom(\"Operation\").select((eb) => eb.fn.max(\"timestampUtcMs\").as(\"latestTimestamp\")).where(\"documentId\", \"=\", documentId).where(\"branch\", \"=\", branch).executeTakeFirst();\n\t\tconst revision = {};\n\t\tfor (const row of scopeRevisions) revision[row.scope] = row.index + 1;\n\t\treturn {\n\t\t\trevision,\n\t\t\tlatestTimestamp: latest?.latestTimestamp ? new Date(latest.latestTimestamp).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString()\n\t\t};\n\t}\n\tasync getStreamLatestTimestamp(documentId, scope, branch, signal) {\n\t\tconst latest = await this.queryExecutor.selectFrom(\"Operation\").select((eb) => eb.fn.max(\"timestampUtcMs\").as(\"latestTimestamp\")).where(\"documentId\", \"=\", documentId).where(\"scope\", \"=\", scope).where(\"branch\", \"=\", branch).executeTakeFirst();\n\t\treturn latest?.latestTimestamp ? new Date(latest.latestTimestamp).toISOString() : void 0;\n\t}\n\trowToOperation(row) {\n\t\treturn {\n\t\t\tindex: row.index,\n\t\t\ttimestampUtcMs: row.timestampUtcMs.toISOString(),\n\t\t\thash: row.hash,\n\t\t\tskip: row.skip,\n\t\t\terror: row.error || void 0,\n\t\t\tdeniedReason: row.deniedReason || void 0,\n\t\t\tid: row.opId,\n\t\t\taction: row.action\n\t\t};\n\t}\n\trowToOperationWithContext(row) {\n\t\treturn {\n\t\t\toperation: this.rowToOperation(row),\n\t\t\tcontext: {\n\t\t\t\tdocumentId: row.documentId,\n\t\t\t\tdocumentType: row.documentType,\n\t\t\t\tscope: row.scope,\n\t\t\t\tbranch: row.branch,\n\t\t\t\tordinal: row.id\n\t\t\t}\n\t\t};\n\t}\n};\n//#endregion\n//#region src/storage/pool-instrumentation.ts\n/**\n* Wraps an existing pg.Pool with acquire-wait timing and an event\n* subscription surface. The pool is mutated in place: pool.connect()\n* is replaced with a timing wrapper so all callers (Kysely included)\n* pick up the instrumentation transparently.\n*/\nfunction instrumentPgPool(pool, name) {\n\tconst listeners = /* @__PURE__ */ new Set();\n\tconst originalConnect = pool.connect.bind(pool);\n\tconst wrappedConnect = async () => {\n\t\tconst start = performance.now();\n\t\tconst client = await originalConnect();\n\t\tconst durationMs = performance.now() - start;\n\t\tfor (const listener of listeners) try {\n\t\t\tlistener(durationMs);\n\t\t} catch {}\n\t\treturn client;\n\t};\n\tpool.connect = wrappedConnect;\n\treturn {\n\t\tname,\n\t\tgetStats() {\n\t\t\treturn {\n\t\t\t\tsize: pool.totalCount,\n\t\t\t\tidle: pool.idleCount,\n\t\t\t\twaiting: pool.waitingCount\n\t\t\t};\n\t\t},\n\t\tonAcquire(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t}\n\t};\n}\nfunction createForwardingPoolInstrumentation(name) {\n\tconst listeners = /* @__PURE__ */ new Set();\n\tlet stats = {\n\t\tsize: 0,\n\t\tidle: 0,\n\t\twaiting: 0\n\t};\n\treturn {\n\t\tname,\n\t\tgetStats() {\n\t\t\treturn stats;\n\t\t},\n\t\tonAcquire(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tpushSamples(durations) {\n\t\t\tfor (const durationMs of durations) for (const listener of listeners) try {\n\t\t\t\tlistener(durationMs);\n\t\t\t} catch {}\n\t\t},\n\t\tupdateStats(next) {\n\t\t\tstats = next;\n\t\t}\n\t};\n}\n//#endregion\n//#region src/storage/migrations/001_create_operation_table.ts\nvar _001_create_operation_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$18 });\nasync function up$18(db) {\n\tawait db.schema.createTable(\"Operation\").addColumn(\"id\", \"serial\", (col) => col.primaryKey()).addColumn(\"jobId\", \"text\", (col) => col.notNull()).addColumn(\"opId\", \"text\", (col) => col.notNull()).addColumn(\"prevOpId\", \"text\", (col) => col.notNull()).addColumn(\"writeTimestampUtcMs\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"timestampUtcMs\", \"timestamptz\", (col) => col.notNull()).addColumn(\"index\", \"integer\", (col) => col.notNull()).addColumn(\"action\", \"jsonb\", (col) => col.notNull()).addColumn(\"skip\", \"integer\", (col) => col.notNull()).addColumn(\"error\", \"text\").addColumn(\"hash\", \"text\", (col) => col.notNull()).addUniqueConstraint(\"unique_revision\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"index\"\n\t]).addUniqueConstraint(\"unique_operation_instance\", [\n\t\t\"opId\",\n\t\t\"index\",\n\t\t\"skip\"\n\t]).execute();\n\tawait db.schema.createIndex(\"streamOperations\").on(\"Operation\").columns([\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"id\"\n\t]).execute();\n\tawait db.schema.createIndex(\"branchlessStreamOperations\").on(\"Operation\").columns([\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"id\"\n\t]).execute();\n}\n//#endregion\n//#region src/storage/migrations/002_create_keyframe_table.ts\nvar _002_create_keyframe_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$17 });\nasync function up$17(db) {\n\tawait db.schema.createTable(\"Keyframe\").addColumn(\"id\", \"serial\", (col) => col.primaryKey()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"revision\", \"integer\", (col) => col.notNull()).addColumn(\"document\", \"jsonb\", (col) => col.notNull()).addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint(\"unique_keyframe\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"revision\"\n\t]).execute();\n\tawait db.schema.createIndex(\"keyframe_lookup\").on(\"Keyframe\").columns([\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\",\n\t\t\"revision\"\n\t]).execute();\n}\n//#endregion\n//#region src/storage/migrations/003_create_document_table.ts\nvar _003_create_document_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$16 });\nasync function up$16(db) {\n\tawait db.schema.createTable(\"Document\").addColumn(\"id\", \"text\", (col) => col.primaryKey()).addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/004_create_document_relationship_table.ts\nvar _004_create_document_relationship_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$15 });\nasync function up$15(db) {\n\tawait db.schema.createTable(\"DocumentRelationship\").addColumn(\"id\", \"text\", (col) => col.primaryKey()).addColumn(\"sourceId\", \"text\", (col) => col.notNull().references(\"Document.id\").onDelete(\"cascade\")).addColumn(\"targetId\", \"text\", (col) => col.notNull().references(\"Document.id\").onDelete(\"cascade\")).addColumn(\"relationshipType\", \"text\", (col) => col.notNull()).addColumn(\"metadata\", \"jsonb\").addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint(\"unique_source_target_type\", [\n\t\t\"sourceId\",\n\t\t\"targetId\",\n\t\t\"relationshipType\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_relationship_source\").on(\"DocumentRelationship\").column(\"sourceId\").execute();\n\tawait db.schema.createIndex(\"idx_relationship_target\").on(\"DocumentRelationship\").column(\"targetId\").execute();\n\tawait db.schema.createIndex(\"idx_relationship_type\").on(\"DocumentRelationship\").column(\"relationshipType\").execute();\n}\n//#endregion\n//#region src/storage/migrations/005_create_indexer_state_table.ts\nvar _005_create_indexer_state_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$14 });\nasync function up$14(db) {\n\tawait db.schema.createTable(\"IndexerState\").addColumn(\"id\", \"integer\", (col) => col.primaryKey().generatedAlwaysAsIdentity()).addColumn(\"lastOperationId\", \"integer\", (col) => col.notNull()).addColumn(\"lastOperationTimestamp\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/006_create_document_snapshot_table.ts\nvar _006_create_document_snapshot_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$13 });\nasync function up$13(db) {\n\tawait db.schema.createTable(\"DocumentSnapshot\").addColumn(\"id\", \"text\", (col) => col.primaryKey()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"slug\", \"text\").addColumn(\"name\", \"text\").addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"content\", \"jsonb\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"lastOperationIndex\", \"integer\", (col) => col.notNull()).addColumn(\"lastOperationHash\", \"text\", (col) => col.notNull()).addColumn(\"lastUpdatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"snapshotVersion\", \"integer\", (col) => col.notNull().defaultTo(1)).addColumn(\"identifiers\", \"jsonb\").addColumn(\"metadata\", \"jsonb\").addColumn(\"isDeleted\", \"boolean\", (col) => col.notNull().defaultTo(false)).addColumn(\"deletedAt\", \"timestamptz\").addUniqueConstraint(\"unique_doc_scope_branch\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_slug_scope_branch\").on(\"DocumentSnapshot\").columns([\n\t\t\"slug\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_doctype_scope_branch\").on(\"DocumentSnapshot\").columns([\n\t\t\"documentType\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_last_updated\").on(\"DocumentSnapshot\").column(\"lastUpdatedAt\").execute();\n\tawait db.schema.createIndex(\"idx_is_deleted\").on(\"DocumentSnapshot\").column(\"isDeleted\").execute();\n}\n//#endregion\n//#region src/storage/migrations/007_create_slug_mapping_table.ts\nvar _007_create_slug_mapping_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$12 });\nasync function up$12(db) {\n\tawait db.schema.createTable(\"SlugMapping\").addColumn(\"slug\", \"text\", (col) => col.primaryKey()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addUniqueConstraint(\"unique_docid_scope_branch\", [\n\t\t\"documentId\",\n\t\t\"scope\",\n\t\t\"branch\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_slug_documentid\").on(\"SlugMapping\").column(\"documentId\").execute();\n}\n//#endregion\n//#region src/storage/migrations/008_create_view_state_table.ts\nvar _008_create_view_state_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$11 });\nasync function up$11(db) {\n\tawait db.schema.createTable(\"ViewState\").addColumn(\"readModelId\", \"text\", (col) => col.primaryKey()).addColumn(\"lastOrdinal\", \"integer\", (col) => col.notNull().defaultTo(0)).addColumn(\"lastOperationTimestamp\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/009_create_operation_index_tables.ts\nvar _009_create_operation_index_tables_exports = /* @__PURE__ */ __exportAll({ up: () => up$10 });\nasync function up$10(db) {\n\tawait db.schema.createTable(\"document_collections\").addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"collectionId\", \"text\", (col) => col.notNull()).addColumn(\"joinedOrdinal\", \"bigint\", (col) => col.notNull().defaultTo(0)).addColumn(\"leftOrdinal\", \"bigint\").addPrimaryKeyConstraint(\"document_collections_pkey\", [\"documentId\", \"collectionId\"]).execute();\n\tawait db.schema.createIndex(\"idx_document_collections_collectionId\").on(\"document_collections\").column(\"collectionId\").execute();\n\tawait db.schema.createIndex(\"idx_doc_collections_collection_range\").on(\"document_collections\").columns([\"collectionId\", \"joinedOrdinal\"]).execute();\n\tawait db.schema.createTable(\"operation_index_operations\").addColumn(\"ordinal\", \"serial\", (col) => col.primaryKey()).addColumn(\"opId\", \"text\", (col) => col.notNull()).addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"documentType\", \"text\", (col) => col.notNull()).addColumn(\"scope\", \"text\", (col) => col.notNull()).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"timestampUtcMs\", \"text\", (col) => col.notNull()).addColumn(\"writeTimestampUtcMs\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"index\", \"integer\", (col) => col.notNull()).addColumn(\"skip\", \"integer\", (col) => col.notNull()).addColumn(\"hash\", \"text\", (col) => col.notNull()).addColumn(\"action\", \"jsonb\", (col) => col.notNull()).execute();\n\tawait db.schema.createIndex(\"idx_operation_index_operations_document\").on(\"operation_index_operations\").columns([\n\t\t\"documentId\",\n\t\t\"branch\",\n\t\t\"scope\"\n\t]).execute();\n\tawait db.schema.createIndex(\"idx_operation_index_operations_ordinal\").on(\"operation_index_operations\").column(\"ordinal\").execute();\n}\n//#endregion\n//#region src/storage/migrations/010_create_sync_tables.ts\nvar _010_create_sync_tables_exports = /* @__PURE__ */ __exportAll({ up: () => up$9 });\nasync function up$9(db) {\n\tawait db.schema.createTable(\"sync_remotes\").addColumn(\"name\", \"text\", (col) => col.primaryKey()).addColumn(\"collection_id\", \"text\", (col) => col.notNull()).addColumn(\"channel_type\", \"text\", (col) => col.notNull()).addColumn(\"channel_id\", \"text\", (col) => col.notNull().defaultTo(\"\")).addColumn(\"remote_name\", \"text\", (col) => col.notNull().defaultTo(\"\")).addColumn(\"channel_parameters\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'{}'::jsonb`)).addColumn(\"filter_document_ids\", \"jsonb\").addColumn(\"filter_scopes\", \"jsonb\").addColumn(\"filter_branch\", \"text\", (col) => col.notNull().defaultTo(\"main\")).addColumn(\"push_state\", \"text\", (col) => col.notNull().defaultTo(\"idle\")).addColumn(\"push_last_success_utc_ms\", \"text\").addColumn(\"push_last_failure_utc_ms\", \"text\").addColumn(\"push_failure_count\", \"integer\", (col) => col.notNull().defaultTo(0)).addColumn(\"pull_state\", \"text\", (col) => col.notNull().defaultTo(\"idle\")).addColumn(\"pull_last_success_utc_ms\", \"text\").addColumn(\"pull_last_failure_utc_ms\", \"text\").addColumn(\"pull_failure_count\", \"integer\", (col) => col.notNull().defaultTo(0)).addColumn(\"created_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updated_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n\tawait db.schema.createIndex(\"idx_sync_remotes_collection\").on(\"sync_remotes\").column(\"collection_id\").execute();\n\tawait db.schema.createTable(\"sync_cursors\").addColumn(\"remote_name\", \"text\", (col) => col.primaryKey().references(\"sync_remotes.name\").onDelete(\"cascade\")).addColumn(\"cursor_ordinal\", \"bigint\", (col) => col.notNull().defaultTo(0)).addColumn(\"last_synced_at_utc_ms\", \"text\").addColumn(\"updated_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n\tawait db.schema.createIndex(\"idx_sync_cursors_ordinal\").on(\"sync_cursors\").column(\"cursor_ordinal\").execute();\n}\n//#endregion\n//#region src/storage/migrations/011_add_cursor_type_column.ts\nvar _011_add_cursor_type_column_exports = /* @__PURE__ */ __exportAll({ up: () => up$8 });\nasync function up$8(db) {\n\tawait db.deleteFrom(\"sync_cursors\").where(\"remote_name\", \"like\", \"outbox::%\").execute();\n\tawait db.deleteFrom(\"sync_remotes\").where(\"name\", \"like\", \"outbox::%\").execute();\n\tawait db.schema.dropTable(\"sync_cursors\").execute();\n\tawait db.schema.createTable(\"sync_cursors\").addColumn(\"remote_name\", \"text\", (col) => col.notNull()).addColumn(\"cursor_type\", \"text\", (col) => col.notNull().defaultTo(\"inbox\")).addColumn(\"cursor_ordinal\", \"bigint\", (col) => col.notNull().defaultTo(0)).addColumn(\"last_synced_at_utc_ms\", \"text\").addColumn(\"updated_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addPrimaryKeyConstraint(\"sync_cursors_pk\", [\"remote_name\", \"cursor_type\"]).execute();\n\tawait db.schema.createIndex(\"idx_sync_cursors_ordinal\").on(\"sync_cursors\").column(\"cursor_ordinal\").execute();\n}\n//#endregion\n//#region src/storage/migrations/012_add_source_remote_column.ts\nvar _012_add_source_remote_column_exports = /* @__PURE__ */ __exportAll({ up: () => up$7 });\nasync function up$7(db) {\n\tawait db.schema.alterTable(\"operation_index_operations\").addColumn(\"sourceRemote\", \"text\", (col) => col.notNull().defaultTo(\"\")).execute();\n}\n//#endregion\n//#region src/storage/migrations/013_create_sync_dead_letters_table.ts\nvar _013_create_sync_dead_letters_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$6 });\nasync function up$6(db) {\n\tawait db.schema.createTable(\"sync_dead_letters\").addColumn(\"ordinal\", \"serial\", (col) => col.primaryKey()).addColumn(\"id\", \"text\", (col) => col.unique().notNull()).addColumn(\"job_id\", \"text\", (col) => col.notNull()).addColumn(\"job_dependencies\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn(\"remote_name\", \"text\", (col) => col.notNull().references(\"sync_remotes.name\").onDelete(\"cascade\")).addColumn(\"document_id\", \"text\", (col) => col.notNull()).addColumn(\"scopes\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn(\"branch\", \"text\", (col) => col.notNull()).addColumn(\"operations\", \"jsonb\", (col) => col.notNull().defaultTo(sql`'[]'::jsonb`)).addColumn(\"error_source\", \"text\", (col) => col.notNull()).addColumn(\"error_message\", \"text\", (col) => col.notNull()).addColumn(\"created_at\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n\tawait db.schema.createIndex(\"idx_sync_dead_letters_remote\").on(\"sync_dead_letters\").column(\"remote_name\").execute();\n}\n//#endregion\n//#region src/storage/migrations/014_create_processor_cursor_table.ts\nvar _014_create_processor_cursor_table_exports = /* @__PURE__ */ __exportAll({ up: () => up$5 });\nasync function up$5(db) {\n\tawait db.schema.createTable(\"ProcessorCursor\").addColumn(\"processorId\", \"text\", (col) => col.primaryKey()).addColumn(\"factoryId\", \"text\", (col) => col.notNull()).addColumn(\"driveId\", \"text\", (col) => col.notNull()).addColumn(\"processorIndex\", \"integer\", (col) => col.notNull()).addColumn(\"lastOrdinal\", \"integer\", (col) => col.notNull().defaultTo(sql`0`)).addColumn(\"status\", \"text\", (col) => col.notNull().defaultTo(sql`'active'`)).addColumn(\"lastError\", \"text\").addColumn(\"lastErrorTimestamp\", \"timestamptz\").addColumn(\"createdAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).addColumn(\"updatedAt\", \"timestamptz\", (col) => col.notNull().defaultTo(sql`NOW()`)).execute();\n}\n//#endregion\n//#region src/storage/migrations/015_add_operation_denied_reason.ts\nvar _015_add_operation_denied_reason_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$4,\n\tup: () => up$4\n});\n/**\n* Records why authorization refused an operation. Separate from `error` so a\n* denial is distinguishable from a reducer failure without matching on a\n* message. Null for every operation written before decisions were enforced.\n*/\nasync function up$4(db) {\n\tawait db.schema.alterTable(\"Operation\").addColumn(\"deniedReason\", \"text\").execute();\n\tawait db.schema.alterTable(\"operation_index_operations\").addColumn(\"deniedReason\", \"text\").execute();\n}\nasync function down$4(db) {\n\tawait db.schema.alterTable(\"operation_index_operations\").dropColumn(\"deniedReason\").execute();\n\tawait db.schema.alterTable(\"Operation\").dropColumn(\"deniedReason\").execute();\n}\n//#endregion\n//#region src/storage/migrations/016_add_dead_letter_error_type.ts\nvar _016_add_dead_letter_error_type_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$3,\n\tup: () => up$3\n});\n/**\n* The classification a dead letter falls into, stored because it decides whether\n* the document stays quarantined and the in-memory error is gone after a restart.\n* Defaulted rather than nullable, so a pre-existing row rehydrates.\n*/\nasync function up$3(db) {\n\tawait db.schema.alterTable(\"sync_dead_letters\").addColumn(\"error_type\", \"text\", (col) => col.notNull().defaultTo(\"UNCLASSIFIED\")).execute();\n}\nasync function down$3(db) {\n\tawait db.schema.alterTable(\"sync_dead_letters\").dropColumn(\"error_type\").execute();\n}\n//#endregion\n//#region src/storage/migrations/017_create_group_references.ts\nvar _017_create_group_references_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$2,\n\tup: () => up$2\n});\n/**\n* One row per (document, group) reference ever discovered from an auth\n* operation's input. Rows are never updated or deleted: auth evaluation is\n* positional, so a grant that named a group at any position keeps that\n* group's stream in the document's read-set even after a later operation\n* removes the reference. Read by documentId for the groups a document\n* requires (sync), and by groupId for the documents a group change affects\n* (re-evaluation).\n*/\nasync function up$2(db) {\n\tawait db.schema.createTable(\"group_references\").addColumn(\"documentId\", \"text\", (col) => col.notNull()).addColumn(\"groupId\", \"text\", (col) => col.notNull()).addPrimaryKeyConstraint(\"group_references_pkey\", [\"documentId\", \"groupId\"]).execute();\n\tawait db.schema.createIndex(\"idx_group_references_groupId\").on(\"group_references\").column(\"groupId\").execute();\n}\nasync function down$2(db) {\n\tawait db.schema.dropTable(\"group_references\").execute();\n}\n//#endregion\n//#region src/storage/migrations/018_add_sync_remote_bound_address.ts\nvar _018_add_sync_remote_bound_address_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down$1,\n\tup: () => up$1\n});\n/**\n* The address a sync channel is bound to, so a channel created by one subject\n* cannot be polled by another.\n*\n* Nullable rather than defaulted: null is a channel nobody has claimed, which is\n* what every pre-existing row is and what an anonymously created channel stays\n* until its first authenticated poll adopts it. A default would claim them all\n* for one address.\n*/\nasync function up$1(db) {\n\tawait db.schema.alterTable(\"sync_remotes\").addColumn(\"bound_address\", \"text\").execute();\n}\nasync function down$1(db) {\n\tawait db.schema.alterTable(\"sync_remotes\").dropColumn(\"bound_address\").execute();\n}\n//#endregion\n//#region src/storage/migrations/019_require_action_id.ts\nvar _019_require_action_id_exports = /* @__PURE__ */ __exportAll({\n\tdown: () => down,\n\tup: () => up\n});\n/**\n* Makes an operation whose action carries no id physically unstorable.\n*\n* The id is not decoration: `deriveOperationId` hashes it into the operation id\n* and replay dedupes incoming operations by it, so an action without one\n* collapses every id-less operation on a document/scope/branch onto a single\n* derived operation id. The API rejects such an action now, and this is the\n* last line of defense behind it.\n*\n* Both tables are constrained because sync reads operations from the index\n* rather than the operation table, so poison reaching only the index would\n* still be served to a replica.\n*\n* Pre-existing rows are backfilled rather than left behind a NOT VALID\n* constraint: a row the index and the operation table disagree about is worse\n* than a missing id, because dedup keys off the value each side serves. The\n* backfill therefore mints one id per operation and writes that same id to both\n* tables, joined on the identity they share. Rewriting the action is safe: the\n* operation hash is taken over the resulting state, not over the action, and a\n* signature is verified from the params carried in the signature tuple, which\n* do not include the action id.\n*\n* The empty string is rejected alongside null. It derives the same colliding\n* operation id as an absent id, so admitting it would leave the hole open.\n*/\nasync function up(db) {\n\tawait db.updateTable(\"Operation\").set({ action: sql`jsonb_set(action, '{id}', to_jsonb(gen_random_uuid()::text))` }).where(sql`jsonb_typeof(action) = 'object' and coalesce(action->>'id', '') = ''`).execute();\n\tawait db.updateTable(\"operation_index_operations as oio\").from(\"Operation as op\").set({ action: sql`jsonb_set(oio.action, '{id}', to_jsonb(op.action->>'id'))` }).whereRef(\"oio.opId\", \"=\", \"op.opId\").whereRef(\"oio.index\", \"=\", \"op.index\").whereRef(\"oio.skip\", \"=\", \"op.skip\").where(sql`jsonb_typeof(oio.action) = 'object' and coalesce(oio.action->>'id', '') = ''`).where(sql`coalesce(op.action->>'id', '') <> ''`).execute();\n\tawait db.updateTable(\"operation_index_operations\").set({ action: sql`jsonb_set(action, '{id}', to_jsonb(gen_random_uuid()::text))` }).where(sql`jsonb_typeof(action) = 'object' and coalesce(action->>'id', '') = ''`).execute();\n\tawait db.schema.alterTable(\"Operation\").addCheckConstraint(\"action_must_have_id\", sql`action->>'id' is not null and action->>'id' <> ''`).execute();\n\tawait db.schema.alterTable(\"operation_index_operations\").addCheckConstraint(\"action_must_have_id\", sql`action->>'id' is not null and action->>'id' <> ''`).execute();\n}\n/**\n* Only the constraints are dropped. The backfilled ids stay: they are the ids\n* their operations are now known by, and reverting them would reintroduce the\n* collision the migration removed.\n*/\nasync function down(db) {\n\tawait db.schema.alterTable(\"operation_index_operations\").dropConstraint(\"action_must_have_id\").execute();\n\tawait db.schema.alterTable(\"Operation\").dropConstraint(\"action_must_have_id\").execute();\n}\n//#endregion\n//#region src/storage/migrations/migrator.ts\nconst REACTOR_SCHEMA = \"reactor\";\nconst migrations = {\n\t\"001_create_operation_table\": _001_create_operation_table_exports,\n\t\"002_create_keyframe_table\": _002_create_keyframe_table_exports,\n\t\"003_create_document_table\": _003_create_document_table_exports,\n\t\"004_create_document_relationship_table\": _004_create_document_relationship_table_exports,\n\t\"005_create_indexer_state_table\": _005_create_indexer_state_table_exports,\n\t\"006_create_document_snapshot_table\": _006_create_document_snapshot_table_exports,\n\t\"007_create_slug_mapping_table\": _007_create_slug_mapping_table_exports,\n\t\"008_create_view_state_table\": _008_create_view_state_table_exports,\n\t\"009_create_operation_index_tables\": _009_create_operation_index_tables_exports,\n\t\"010_create_sync_tables\": _010_create_sync_tables_exports,\n\t\"011_add_cursor_type_column\": _011_add_cursor_type_column_exports,\n\t\"012_add_source_remote_column\": _012_add_source_remote_column_exports,\n\t\"013_create_sync_dead_letters_table\": _013_create_sync_dead_letters_table_exports,\n\t\"014_create_processor_cursor_table\": _014_create_processor_cursor_table_exports,\n\t\"015_add_operation_denied_reason\": _015_add_operation_denied_reason_exports,\n\t\"016_add_dead_letter_error_type\": _016_add_dead_letter_error_type_exports,\n\t\"017_create_group_references\": _017_create_group_references_exports,\n\t\"018_add_sync_remote_bound_address\": _018_add_sync_remote_bound_address_exports,\n\t\"019_require_action_id\": _019_require_action_id_exports\n};\nvar ProgrammaticMigrationProvider = class {\n\tgetMigrations() {\n\t\treturn Promise.resolve(migrations);\n\t}\n};\n/**\n* Applies every pending migration, or every one up to and including `upTo`.\n*\n* The bound exists so a test can reach the schema a data migration is written\n* against, populate it, and then migrate across the migration under test.\n*/\nasync function runMigrations(db, schema = REACTOR_SCHEMA, upTo) {\n\ttry {\n\t\tawait sql`CREATE SCHEMA IF NOT EXISTS ${sql.id(schema)}`.execute(db);\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmigrationsExecuted: [],\n\t\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(\"Failed to create schema\")\n\t\t};\n\t}\n\tconst migrator = new Migrator({\n\t\tdb: db.withSchema(schema),\n\t\tprovider: new ProgrammaticMigrationProvider(),\n\t\tmigrationTableSchema: schema\n\t});\n\tlet error;\n\tlet results;\n\ttry {\n\t\tconst result = upTo ? await migrator.migrateTo(upTo) : await migrator.migrateToLatest();\n\t\terror = result.error;\n\t\tresults = result.results;\n\t} catch (e) {\n\t\terror = e;\n\t\tresults = [];\n\t}\n\tconst migrationsExecuted = results?.map((result) => result.migrationName) ?? [];\n\tif (error) return {\n\t\tsuccess: false,\n\t\tmigrationsExecuted,\n\t\terror: error instanceof Error ? error : /* @__PURE__ */ new Error(\"Unknown migration error\")\n\t};\n\treturn {\n\t\tsuccess: true,\n\t\tmigrationsExecuted\n\t};\n}\nasync function getMigrationStatus(db, schema = REACTOR_SCHEMA) {\n\treturn await new Migrator({\n\t\tdb: db.withSchema(schema),\n\t\tprovider: new ProgrammaticMigrationProvider(),\n\t\tmigrationTableSchema: schema\n\t}).getMigrations();\n}\n//#endregion\n//#region src/core/drive-container-types.ts\nconst DEFAULT_DRIVE_CONTAINER_TYPES = new Set([\"powerhouse/document-drive\", \"powerhouse/reactor-drive\"]);\n//#endregion\nexport { selectDecisionModel as A, RevisionMismatchError as B, InvalidModuleError as C, createEmptyConsistencyToken as D, createConsistencyToken as E, AppendConditionFailedError as F, DocumentNotFoundError as G, AuthTimestampNotMonotonicError as H, DocumentAlreadyExistsError as I, UpgradePreconditionFailedError as J, ExcessiveReshuffleError as K, DocumentExistence as L, authDecisionModel as M, buildDecisionModel as N, targetDocumentId as O, APPEND_CONDITION_FAILED_PREFIX as P, __exportAll as Q, DuplicateOperationError as R, DuplicateModuleError as S, GATED_DOCUMENT_ACTIONS as T, AuthorizationDeniedError as U, AuthEnforcementDisabledError as V, DocumentDeletedError as W, parsePagingOptions as X, matchesScope as Y, throwIfAborted as Z, DocumentMetaCache as _, createForwardingPoolInstrumentation as a, JobExecutorEventTypes as b, KyselyKeyframeStore as c, DriveCollectionId as d, KyselyExecutionScope as f, KyselyOperationIndex as g, KyselyWriteCache as h, runMigrations as i, documentDecisionModel as j, decideAtHead as k, DocumentModelRegistry as l, EventBus as m, REACTOR_SCHEMA as n, instrumentPgPool as o, resolveFeatureFlags as p, InvalidOperationTimestampError as q, getMigrationStatus as r, KyselyOperationStore as s, DEFAULT_DRIVE_CONTAINER_TYPES as t, SimpleJobExecutor as u, CollectionMembershipCache as v, ModuleNotFoundError as w, DuplicateManifestError as x, DEFAULT_DEFERRED_JOB_TTL_MS as y, OptimisticLockError as z };\n\n//# sourceMappingURL=drive-container-types-yZrksiJR.js.map","import { A as selectDecisionModel, B as RevisionMismatchError, C as InvalidModuleError, D as createEmptyConsistencyToken, E as createConsistencyToken, F as AppendConditionFailedError, G as DocumentNotFoundError, H as AuthTimestampNotMonotonicError, I as DocumentAlreadyExistsError, J as UpgradePreconditionFailedError, K as ExcessiveReshuffleError, L as DocumentExistence, M as authDecisionModel, N as buildDecisionModel, O as targetDocumentId, P as APPEND_CONDITION_FAILED_PREFIX, R as DuplicateOperationError, S as DuplicateModuleError, T as GATED_DOCUMENT_ACTIONS, U as AuthorizationDeniedError, V as AuthEnforcementDisabledError, W as DocumentDeletedError, X as parsePagingOptions, Y as matchesScope, Z as throwIfAborted, _ as DocumentMetaCache, a as createForwardingPoolInstrumentation, b as JobExecutorEventTypes, c as KyselyKeyframeStore, d as DriveCollectionId, f as KyselyExecutionScope, g as KyselyOperationIndex, h as KyselyWriteCache, i as runMigrations, j as documentDecisionModel, k as decideAtHead, l as DocumentModelRegistry, m as EventBus, n as REACTOR_SCHEMA, o as instrumentPgPool, p as resolveFeatureFlags, q as InvalidOperationTimestampError, r as getMigrationStatus, s as KyselyOperationStore, t as DEFAULT_DRIVE_CONTAINER_TYPES, u as SimpleJobExecutor, v as CollectionMembershipCache, w as ModuleNotFoundError, x as DuplicateManifestError, y as DEFAULT_DEFERRED_JOB_TTL_MS, z as OptimisticLockError } from \"./drive-container-types-yZrksiJR.js\";\nimport { n as ReactorEventTypes, t as EventBusAggregateError } from \"./types-DMKLa0Ok.js\";\nimport { i as WorkerInitFailedError, r as WorkerExitedError, t as WorkerAbortTimeoutError } from \"./errors-D3S6Eysd.js\";\nimport { a as DOCUMENT_INDEXER_READ_MODEL, c as BaseReadModel, i as KyselyDocumentView, n as ConsistencyTracker, o as DOCUMENT_VIEW_READ_MODEL, r as makeConsistencyKey, s as ReadModelCoordinator, t as KyselyDocumentIndexer } from \"./document-indexer-C5Gsa1B3.js\";\nimport { n as errorToInfo, r as sanitizeArg, t as createForwardingLogger } from \"./forwarding-logger-BBkMSxuJ.js\";\nimport { t as workerEntryPath } from \"./worker-HPysBfhx.js\";\nimport { DowngradeNotSupportedError, MAX_AUTH_GRANTS, UnsupportedDocumentModelVersionError, actions, actions as documentActions, createPresignedHeader, decide, deserializeSignature, garbageCollect, generateId, groupDocumentType, groupMembershipActionTypes, hashDocumentStateForScope, normalizeDocumentModelVersion, sortOperations, toTransportAction } from \"@powerhousedao/shared/document-model\";\nimport { addFile, addFolder, copyNode, deleteNode, driveCreateDocument, generateNodesCopy, getDescendants, handleTargetNameCollisions, isFileNode, isFolderNode, moveNode, updateNode } from \"@powerhousedao/shared/document-drive\";\nimport { v4 } from \"uuid\";\nimport { ConsoleLogger, childLogger } from \"document-model\";\nimport { sql } from \"kysely\";\nimport { RelationalDbProcessor, createRelationalDb } from \"@powerhousedao/shared/processors\";\n//#region src/actions/index.ts\n/**\n* Creates a CREATE_DOCUMENT action for document creation.\n*/\nfunction createDocumentAction(input) {\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"CREATE_DOCUMENT\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates an UPGRADE_DOCUMENT action to set initial document state.\n*/\nfunction upgradeDocumentAction(input) {\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"UPGRADE_DOCUMENT\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates a DELETE_DOCUMENT action for document deletion.\n*/\nfunction deleteDocumentAction(documentId) {\n\tconst input = { documentId };\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"DELETE_DOCUMENT\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates an ADD_RELATIONSHIP action that records a directed edge from\n* `sourceId` to `targetId` with an arbitrary `relationshipType` and optional\n* `metadata`. The edge is opaque to the reactor — consumers (e.g. reactor-drive)\n* define their own type strings such as `\"drive/child\"` and attach\n* domain-specific metadata.\n*/\nfunction addRelationshipAction(sourceId, targetId, relationshipType, metadata) {\n\tconst input = {\n\t\tsourceId,\n\t\ttargetId,\n\t\trelationshipType,\n\t\t...metadata !== void 0 ? { metadata } : {}\n\t};\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"ADD_RELATIONSHIP\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates an UPDATE_RELATIONSHIP action to replace a relationship's metadata\n* without losing its createdAt ordering.\n*/\nfunction updateRelationshipAction(sourceId, targetId, relationshipType, metadata) {\n\tconst input = {\n\t\tsourceId,\n\t\ttargetId,\n\t\trelationshipType,\n\t\tmetadata\n\t};\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"UPDATE_RELATIONSHIP\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n/**\n* Creates a REMOVE_RELATIONSHIP action to remove a parent-child relationship.\n*/\nfunction removeRelationshipAction(sourceId, targetId, relationshipType = \"child\") {\n\tconst input = {\n\t\tsourceId,\n\t\ttargetId,\n\t\trelationshipType\n\t};\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"REMOVE_RELATIONSHIP\",\n\t\tscope: \"document\",\n\t\ttimestampUtcMs: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tinput\n\t};\n}\n//#endregion\n//#region src/core/utils.ts\n/**\n* Validates structural properties shared by all batch requests:\n* duplicate keys, missing dependencies, and dependency cycles.\n*/\nfunction validateBatchStructure(jobs) {\n\tconst keys = /* @__PURE__ */ new Set();\n\tfor (const job of jobs) {\n\t\tif (keys.has(job.key)) throw new Error(`Duplicate plan key: ${job.key}`);\n\t\tkeys.add(job.key);\n\t}\n\tfor (const job of jobs) for (const depKey of job.dependsOn) if (!keys.has(depKey)) throw new Error(`Job '${job.key}' depends on non-existent key: ${depKey}`);\n\tconst visited = /* @__PURE__ */ new Set();\n\tconst recStack = /* @__PURE__ */ new Set();\n\tconst detectCycle = (key) => {\n\t\tvisited.add(key);\n\t\trecStack.add(key);\n\t\tconst job = jobs.find((j) => j.key === key);\n\t\tif (job) {\n\t\t\tfor (const depKey of job.dependsOn) if (!visited.has(depKey)) {\n\t\t\t\tif (detectCycle(depKey)) return true;\n\t\t\t} else if (recStack.has(depKey)) return true;\n\t\t}\n\t\trecStack.delete(key);\n\t\treturn false;\n\t};\n\tfor (const job of jobs) if (!visited.has(job.key)) {\n\t\tif (detectCycle(job.key)) throw new Error(`Dependency cycle detected involving key: ${job.key}`);\n\t}\n}\n/**\n* Validates a batch mutation request for common errors\n*/\nfunction validateBatchRequest(jobs) {\n\tvalidateBatchStructure(jobs);\n\tfor (const job of jobs) if (job.actions.length === 0) throw new Error(`Job '${job.key}' has empty actions array`);\n}\n/**\n* Validates a batch load request for common errors\n*/\nfunction validateBatchLoadRequest(jobs) {\n\tvalidateBatchStructure(jobs);\n\tfor (const job of jobs) if (job.operations.length === 0) throw new Error(`Job '${job.key}' has empty operations array`);\n}\n/**\n* Validates that all actions in a job match the declared scope\n*/\nfunction validateActionScopes(job) {\n\tfor (const action of job.actions) {\n\t\tconst actionScope = action.scope || \"global\";\n\t\tif (actionScope !== job.scope) throw new Error(`Job '${job.key}' declares scope '${job.scope}' but action has scope '${actionScope}'`);\n\t}\n}\n/**\n* Validates that all operations in a job match the declared scope\n*/\nfunction validateOperationScopes(job) {\n\tfor (const operation of job.operations) {\n\t\tconst operationScope = operation.action.scope || \"global\";\n\t\tif (operationScope !== job.scope) throw new Error(`Job '${job.key}' declares scope '${job.scope}' but operation has scope '${operationScope}'`);\n\t}\n}\n/**\n* Performs topological sort on jobs based on dependencies\n*/\nfunction topologicalSort(jobs) {\n\tconst result = [];\n\tconst visited = /* @__PURE__ */ new Set();\n\tconst visit = (key) => {\n\t\tif (visited.has(key)) return;\n\t\tvisited.add(key);\n\t\tconst job = jobs.find((j) => j.key === key);\n\t\tif (job) for (const depKey of job.dependsOn) visit(depKey);\n\t\tresult.push(key);\n\t};\n\tfor (const job of jobs) visit(job.key);\n\treturn result;\n}\n/**\n* Converts an Error or string to ErrorInfo\n*/\nfunction toErrorInfo$1(error) {\n\tif (error instanceof Error) return {\n\t\tname: error.name,\n\t\tmessage: error.message,\n\t\tstack: error.stack || (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n\treturn {\n\t\tname: \"Error\",\n\t\tmessage: error,\n\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n}\n/**\n* Filters paged results by document type\n*/\nfunction filterByType(results, type) {\n\treturn {\n\t\tresults: results.results.filter((document) => document.header.documentType === type),\n\t\toptions: results.options,\n\t\tnextCursor: results.nextCursor,\n\t\tnext: results.next ? async () => {\n\t\t\treturn filterByType(await results.next(), type);\n\t\t} : void 0\n\t};\n}\n/**\n* Validates that all operations share the same scope.\n* Throws an error if any operation has a different scope.\n*/\nfunction getSharedOperationScope(operations) {\n\tif (operations.length === 0) throw new Error(\"No operations provided\");\n\tconst baseScope = operations[0].action.scope;\n\tfor (const [index, operation] of operations.entries()) {\n\t\tconst scope = operation.action.scope;\n\t\tif (scope !== baseScope) throw new Error(`All operations in load must share the same scope. Expected '${baseScope}', received '${scope}' at position ${index}`);\n\t}\n\treturn baseScope;\n}\n/**\n* Validates that all actions share the same scope.\n* Throws an error if any action has a different scope.\n*/\nfunction getSharedActionScope(actions) {\n\tif (actions.length === 0) throw new Error(\"No actions provided\");\n\tconst baseScope = actions[0].scope;\n\tfor (const action of actions) if (action.scope !== baseScope) throw new Error(`All actions must share the same scope. Expected '${baseScope}', received '${action.scope}'`);\n\treturn baseScope;\n}\n/**\n* Signs an action with the provided signer.\n* If the action already has valid signatures, it is returned unchanged.\n*/\nconst signAction = async (action, signer, signal) => {\n\tconst existingSignatures = action.context?.signer?.signatures;\n\tif (existingSignatures && existingSignatures.length > 0) return action;\n\tconst signature = await signer.signAction(action, signal);\n\treturn {\n\t\t...action,\n\t\tcontext: {\n\t\t\t...action.context,\n\t\t\tsigner: {\n\t\t\t\tuser: {\n\t\t\t\t\taddress: signer.user?.address || \"\",\n\t\t\t\t\tnetworkId: signer.user?.networkId || \"\",\n\t\t\t\t\tchainId: signer.user?.chainId || 0\n\t\t\t\t},\n\t\t\t\tapp: {\n\t\t\t\t\tname: signer.app?.name || \"\",\n\t\t\t\t\tkey: signer.app?.key || \"\"\n\t\t\t\t},\n\t\t\t\tsignatures: [signature]\n\t\t\t}\n\t\t}\n\t};\n};\n/**\n* Signs multiple actions with the provided signer\n*/\nconst signActions = async (actions, signer, signal) => {\n\treturn Promise.all(actions.map((action) => signAction(action, signer, signal)));\n};\nfunction buildSingleJobMeta(jobId, callerMeta) {\n\treturn {\n\t\t...callerMeta,\n\t\tbatchId: v4(),\n\t\tbatchJobIds: [jobId]\n\t};\n}\n//#endregion\n//#region src/shared/types.ts\n/**\n* Enum that determines deletion propagation.\n*/\nlet PropagationMode = /* @__PURE__ */ function(PropagationMode) {\n\tPropagationMode[\"None\"] = \"none\";\n\tPropagationMode[\"Cascade\"] = \"cascade\";\n\treturn PropagationMode;\n}({});\n/**\n* Enum that describes the type of relationship change.\n*/\nlet RelationshipChangeType = /* @__PURE__ */ function(RelationshipChangeType) {\n\tRelationshipChangeType[\"Added\"] = \"added\";\n\tRelationshipChangeType[\"Removed\"] = \"removed\";\n\treturn RelationshipChangeType;\n}({});\n/**\n* Job execution statuses\n*/\nlet JobStatus = /* @__PURE__ */ function(JobStatus) {\n\t/** Job is queued but not yet started */\n\tJobStatus[\"PENDING\"] = \"PENDING\";\n\t/** Job is currently being executed */\n\tJobStatus[\"RUNNING\"] = \"RUNNING\";\n\t/** Operations have been written to the operation store (JOB_WRITE_READY event) */\n\tJobStatus[\"WRITE_READY\"] = \"WRITE_READY\";\n\t/** Read models have finished indexing operations (JOB_READ_READY event) */\n\tJobStatus[\"READ_READY\"] = \"READ_READY\";\n\t/** Job failed (may be retried) */\n\tJobStatus[\"FAILED\"] = \"FAILED\";\n\treturn JobStatus;\n}({});\n//#endregion\n//#region src/client/drive-client.ts\n/**\n* Implementation of {@link IDriveClient}.\n*\n* Holds a back-reference to its parent {@link IReactorClient} for read and\n* single-document write primitives, plus direct access to {@link IReactor}\n* for batch execution. The back-reference is captured but never invoked\n* during construction, so the partial-`this` hazard does not apply.\n*/\nvar DriveClient = class {\n\tconstructor(client, logger, reactor, signer) {\n\t\tthis.client = client;\n\t\tthis.logger = logger;\n\t\tthis.reactor = reactor;\n\t\tthis.signer = signer;\n\t}\n\tasync create(input, signal) {\n\t\tthis.logger.verbose(\"drives.create(@input)\", input);\n\t\tconst driveDoc = driveCreateDocument({ global: {\n\t\t\tname: input.global.name || \"\",\n\t\t\ticon: input.global.icon ?? null,\n\t\t\tnodes: []\n\t\t} });\n\t\tif (input.preferredEditor) driveDoc.header.meta = {\n\t\t\t...driveDoc.header.meta,\n\t\t\tpreferredEditor: input.preferredEditor\n\t\t};\n\t\treturn this.client.create(driveDoc, void 0, signal);\n\t}\n\tasync addFile(driveIdentifier, document, parentFolder, signal) {\n\t\tthis.logger.verbose(\"drives.addFile(@driveIdentifier, @document, @parentFolder)\", driveIdentifier, document.header.id, parentFolder);\n\t\tconst documentId = document.header.id;\n\t\tconst documentActions = await signActions([\n\t\t\tcreateDocumentAction({\n\t\t\t\tmodel: document.header.documentType,\n\t\t\t\tversion: 0,\n\t\t\t\tdocumentId: document.header.id,\n\t\t\t\tsigning: {\n\t\t\t\t\tsignature: document.header.id,\n\t\t\t\t\tpublicKey: document.header.sig.publicKey,\n\t\t\t\t\tnonce: document.header.sig.nonce,\n\t\t\t\t\tcreatedAtUtcIso: document.header.createdAtUtcIso,\n\t\t\t\t\tdocumentType: document.header.documentType\n\t\t\t\t},\n\t\t\t\tslug: document.header.slug,\n\t\t\t\tname: document.header.name,\n\t\t\t\tbranch: document.header.branch,\n\t\t\t\tmeta: document.header.meta,\n\t\t\t\tprotocolVersions: document.header.protocolVersions ?? { \"base-reducer\": 2 }\n\t\t\t}),\n\t\t\tupgradeDocumentAction({\n\t\t\t\tdocumentId: document.header.id,\n\t\t\t\tmodel: document.header.documentType,\n\t\t\t\tfromVersion: 0,\n\t\t\t\ttoVersion: normalizeDocumentModelVersion(document.state.document?.version),\n\t\t\t\tinitialState: document.state\n\t\t\t}),\n\t\t\taddRelationshipAction(driveIdentifier, documentId, \"child\")\n\t\t], this.signer, signal);\n\t\tconst driveActions = await signActions([addFile({\n\t\t\tid: documentId,\n\t\t\tname: document.header.name || documentId,\n\t\t\tdocumentType: document.header.documentType,\n\t\t\tparentFolder\n\t\t})], this.signer, signal);\n\t\tawait this.runJobs([{\n\t\t\tkey: \"document\",\n\t\t\tdocumentId,\n\t\t\tscope: getSharedActionScope(documentActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: documentActions,\n\t\t\tdependsOn: []\n\t\t}], signal);\n\t\tawait this.runJobs([{\n\t\t\tkey: \"drive\",\n\t\t\tdocumentId: driveIdentifier,\n\t\t\tscope: getSharedActionScope(driveActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: driveActions,\n\t\t\tdependsOn: []\n\t\t}], signal);\n\t\treturn this.client.get(documentId, void 0, signal);\n\t}\n\tasync addFolder(driveIdentifier, name, parentFolder, signal) {\n\t\tthis.logger.verbose(\"drives.addFolder(@driveIdentifier, @name, @parentFolder)\", driveIdentifier, name, parentFolder);\n\t\tconst folderId = generateId();\n\t\tconst node = (await this.client.execute(driveIdentifier, \"main\", [addFolder({\n\t\t\tid: folderId,\n\t\t\tname,\n\t\t\tparentFolder\n\t\t})], signal)).state.global?.nodes.find((n) => n.id === folderId);\n\t\tif (!node || !isFolderNode(node)) throw new Error(\"Folder creation failed\");\n\t\treturn node;\n\t}\n\tasync removeNode(driveIdentifier, nodeId, signal) {\n\t\tthis.logger.verbose(\"drives.removeNode(@driveIdentifier, @nodeId)\", driveIdentifier, nodeId);\n\t\tconst drive = await this.client.get(driveIdentifier, void 0, signal);\n\t\tconst node = drive.state.global.nodes.find((n) => n.id === nodeId);\n\t\tif (!node) {\n\t\t\tif (!await this.documentExists(nodeId, signal)) throw new Error(`Node ${nodeId} not found in drive ${driveIdentifier}`);\n\t\t\tawait this.removeFileNode(driveIdentifier, nodeId, signal);\n\t\t\treturn;\n\t\t}\n\t\tif (isFolderNode(node)) {\n\t\t\tconst fileDescendants = getDescendants(node, drive.state.global.nodes).filter(isFileNode);\n\t\t\tfor (const file of fileDescendants) await this.removeFileNode(driveIdentifier, file.id, signal);\n\t\t\tawait this.client.execute(driveIdentifier, \"main\", [deleteNode({ id: nodeId })], signal);\n\t\t\treturn;\n\t\t}\n\t\tawait this.removeFileNode(driveIdentifier, nodeId, signal);\n\t}\n\tasync renameNode(driveIdentifier, nodeId, name, signal) {\n\t\tthis.logger.verbose(\"drives.renameNode(@driveIdentifier, @nodeId, @name)\", driveIdentifier, nodeId, name);\n\t\tif ((await this.client.execute(nodeId, \"main\", [actions.setName({ name })], signal)).header.name !== name) throw new Error(\"Document rename did not apply\");\n\t\tconst node = (await this.client.execute(driveIdentifier, \"main\", [updateNode({\n\t\t\tid: nodeId,\n\t\t\tname\n\t\t})], signal)).state.global?.nodes.find((n) => n.id === nodeId);\n\t\tif (!node) throw new Error(\"Node missing from drive after rename\");\n\t\treturn node;\n\t}\n\tasync setPreferredEditorOnNode(nodeId, preferredEditor, signal) {\n\t\tthis.logger.verbose(\"drives.setPreferredEditorOnNode(@nodeId, @preferredEditor)\", nodeId, preferredEditor);\n\t\treturn this.client.setPreferredEditor(nodeId, preferredEditor, \"main\", signal);\n\t}\n\tasync moveNode(driveIdentifier, srcNodeId, targetParentFolderId, signal) {\n\t\tthis.logger.verbose(\"drives.moveNode(@driveIdentifier, @srcNodeId, @targetParentFolderId)\", driveIdentifier, srcNodeId, targetParentFolderId);\n\t\treturn this.client.execute(driveIdentifier, \"main\", [moveNode({\n\t\t\tsrcFolder: srcNodeId,\n\t\t\ttargetParentFolder: targetParentFolderId\n\t\t})], signal);\n\t}\n\tasync copyNode(driveIdentifier, srcNodeId, targetParentFolderId, signal) {\n\t\tthis.logger.verbose(\"drives.copyNode(@driveIdentifier, @srcNodeId, @targetParentFolderId)\", driveIdentifier, srcNodeId, targetParentFolderId);\n\t\tconst drive = await this.client.get(driveIdentifier, void 0, signal);\n\t\tconst srcNode = drive.state.global.nodes.find((n) => n.id === srcNodeId);\n\t\tif (!srcNode) throw new Error(`Node ${srcNodeId} not found in drive ${driveIdentifier}`);\n\t\tconst copyPlan = generateNodesCopy({\n\t\t\tsrcId: srcNodeId,\n\t\t\ttargetParentFolder: targetParentFolderId,\n\t\t\ttargetName: srcNode.name\n\t\t}, () => generateId(), drive.state.global.nodes);\n\t\tconst resolvedNamesByTargetId = /* @__PURE__ */ new Map();\n\t\tfor (const entry of copyPlan) {\n\t\t\tconst node = drive.state.global.nodes.find((n) => n.id === entry.srcId);\n\t\t\tif (!node) continue;\n\t\t\tconst resolved = handleTargetNameCollisions({\n\t\t\t\tnodes: drive.state.global.nodes,\n\t\t\t\tsrcName: entry.targetName || node.name,\n\t\t\t\tsrcKind: isFileNode(node) ? \"file\" : \"folder\",\n\t\t\t\ttargetParentFolder: entry.targetParentFolder ?? null\n\t\t\t});\n\t\t\tresolvedNamesByTargetId.set(entry.targetId, resolved);\n\t\t}\n\t\tfor (const entry of copyPlan) {\n\t\t\tconst node = drive.state.global.nodes.find((n) => n.id === entry.srcId);\n\t\t\tif (!node || !isFileNode(node)) continue;\n\t\t\tconst srcDoc = await this.client.get(entry.srcId, void 0, signal);\n\t\t\tconst duplicated = {\n\t\t\t\t...srcDoc,\n\t\t\t\theader: createPresignedHeader(entry.targetId, srcDoc.header.documentType),\n\t\t\t\tinitialState: srcDoc.state,\n\t\t\t\toperations: {}\n\t\t\t};\n\t\t\tconst resolvedName = resolvedNamesByTargetId.get(entry.targetId);\n\t\t\tif (resolvedName) duplicated.header.name = resolvedName;\n\t\t\tawait this.addFile(driveIdentifier, duplicated, entry.targetParentFolder ?? void 0, signal);\n\t\t}\n\t\treturn this.client.execute(driveIdentifier, \"main\", copyPlan.map((entry) => copyNode(entry)), signal);\n\t}\n\tasync getNode(driveIdentifier, nodeId, signal) {\n\t\tthis.logger.verbose(\"drives.getNode(@driveIdentifier, @nodeId)\", driveIdentifier, nodeId);\n\t\tconst node = (await this.client.get(driveIdentifier, void 0, signal)).state.global.nodes.find((n) => n.id === nodeId);\n\t\tif (!node) throw new Error(`Node ${nodeId} not found in drive ${driveIdentifier}`);\n\t\treturn node;\n\t}\n\tasync listNodes(driveIdentifier, parentFolder, paging, signal) {\n\t\tthis.logger.verbose(\"drives.listNodes(@driveIdentifier, @parentFolder, @paging)\", driveIdentifier, parentFolder, paging);\n\t\tconst allNodes = (await this.client.get(driveIdentifier, void 0, signal)).state.global.nodes;\n\t\tconst filtered = parentFolder === void 0 ? [...allNodes] : allNodes.filter((n) => (n.parentFolder ?? null) === parentFolder);\n\t\tconst { offset: startIndex, limit } = parsePagingOptions(paging, filtered.length);\n\t\tconst effective = paging ?? {\n\t\t\tcursor: \"\",\n\t\t\tlimit\n\t\t};\n\t\tconst endIndex = startIndex + limit;\n\t\treturn {\n\t\t\tresults: filtered.slice(startIndex, endIndex),\n\t\t\toptions: effective,\n\t\t\t...endIndex < filtered.length ? { nextCursor: String(endIndex) } : {},\n\t\t\ttotalCount: filtered.length\n\t\t};\n\t}\n\t/**\n\t* Runs one batch to completion, throwing the first failure. The thrown error\n\t* carries the job error's name, which is what callers classify on: an id\n\t* collision has to be told apart from a transient failure.\n\t*/\n\tasync runJobs(jobs, signal) {\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw this.toError(job);\n\t\treturn completedJobs;\n\t}\n\ttoError(job) {\n\t\tconst error = new Error(job.error?.message ?? \"Job failed\");\n\t\tif (job.error?.name) error.name = job.error.name;\n\t\treturn error;\n\t}\n\tasync documentExists(documentId, signal) {\n\t\ttry {\n\t\t\tawait this.client.get(documentId, void 0, signal);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\tasync removeFileNode(driveId, fileId, signal) {\n\t\tconst relationshipActions = await signActions([removeRelationshipAction(driveId, fileId, \"child\")], this.signer, signal);\n\t\tconst driveActions = await signActions([deleteNode({ id: fileId })], this.signer, signal);\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs: [{\n\t\t\tkey: \"relationship\",\n\t\t\tdocumentId: driveId,\n\t\t\tscope: getSharedActionScope(relationshipActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: relationshipActions,\n\t\t\tdependsOn: []\n\t\t}, {\n\t\t\tkey: \"drive\",\n\t\t\tdocumentId: driveId,\n\t\t\tscope: getSharedActionScope(driveActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: driveActions,\n\t\t\tdependsOn: [\"relationship\"]\n\t\t}] }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);\n\t\tconst deleteJob = await this.reactor.deleteDocument(fileId, this.signer, signal);\n\t\tconst deleteCompleted = await this.client.waitForJob(deleteJob, signal);\n\t\tif (deleteCompleted.status === JobStatus.FAILED) throw new Error(deleteCompleted.error?.message);\n\t}\n};\n//#endregion\n//#region src/shared/awaiter.ts\n/**\n* Checks if a job status is terminal (job has finished).\n* WRITE_READY is not terminal - it's an intermediate state.\n* Only READ_READY and FAILED are truly terminal.\n*/\nfunction isTerminalStatus(status) {\n\treturn status === JobStatus.READ_READY || status === JobStatus.FAILED;\n}\n/**\n* Event-driven implementation of IJobAwaiter.\n* Subscribes to operation events to detect job completion without polling.\n*/\nvar JobAwaiter = class {\n\tpendingJobs = /* @__PURE__ */ new Map();\n\tunsubscribers = [];\n\tconstructor(eventBus, getJobStatus) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.getJobStatus = getJobStatus;\n\t\tthis.subscribeToEvents();\n\t}\n\tsubscribeToEvents() {\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, async (_type, event) => {\n\t\t\tawait this.handleWriteReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_READ_READY, async (_type, event) => {\n\t\t\tawait this.handleReadReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, async (_type, event) => {\n\t\t\tawait this.handleJobFailed(event);\n\t\t}));\n\t}\n\tshutdown() {\n\t\tfor (const unsubscribe of this.unsubscribers) unsubscribe();\n\t\tthis.unsubscribers = [];\n\t\tfor (const [, waiters] of this.pendingJobs) for (const waiter of waiters) waiter.reject(/* @__PURE__ */ new Error(\"JobAwaiter destroyed\"));\n\t\tthis.pendingJobs.clear();\n\t}\n\tasync waitForJob(jobId, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst currentStatus = await this.getJobStatus(jobId, signal);\n\t\tif (isTerminalStatus(currentStatus.status)) return currentStatus;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst waiter = {\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t\tsignal\n\t\t\t};\n\t\t\tconst existingWaiters = this.pendingJobs.get(jobId) || [];\n\t\t\texistingWaiters.push(waiter);\n\t\t\tthis.pendingJobs.set(jobId, existingWaiters);\n\t\t\tif (signal) {\n\t\t\t\tconst abortHandler = () => {\n\t\t\t\t\tconst waiters = this.pendingJobs.get(jobId);\n\t\t\t\t\tif (waiters) {\n\t\t\t\t\t\tconst index = waiters.indexOf(waiter);\n\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\twaiters.splice(index, 1);\n\t\t\t\t\t\t\tif (waiters.length === 0) this.pendingJobs.delete(jobId);\n\t\t\t\t\t\t\twaiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", abortHandler, { once: true });\n\t\t\t}\n\t\t});\n\t}\n\tasync handleWriteReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tawait this.checkAndResolveWaiters(jobId);\n\t}\n\tasync handleReadReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tawait this.checkAndResolveWaiters(jobId);\n\t}\n\tasync handleJobFailed(event) {\n\t\tawait this.checkAndResolveWaiters(event.jobId);\n\t}\n\tasync checkAndResolveWaiters(jobId) {\n\t\tconst waiters = this.pendingJobs.get(jobId);\n\t\tif (!waiters || waiters.length === 0) return;\n\t\ttry {\n\t\t\tconst activeWaiters = waiters.filter((w) => !w.signal?.aborted);\n\t\t\tif (activeWaiters.length === 0) {\n\t\t\t\tthis.pendingJobs.delete(jobId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst jobInfo = await this.getJobStatus(jobId, activeWaiters[0].signal);\n\t\t\tif (isTerminalStatus(jobInfo.status)) {\n\t\t\t\tthis.pendingJobs.delete(jobId);\n\t\t\t\tfor (const waiter of activeWaiters) waiter.resolve(jobInfo);\n\t\t\t\tfor (const waiter of waiters) if (waiter.signal?.aborted) waiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.pendingJobs.delete(jobId);\n\t\t\tfor (const waiter of waiters) waiter.reject(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t}\n};\n//#endregion\n//#region src/client/cursor.ts\nconst COMPOSITE_PREFIX = \"c:\";\n/**\n* Returns true if the cursor is a composite multi-scope cursor.\n*/\nfunction isCompositeCursor(cursor) {\n\treturn cursor.startsWith(COMPOSITE_PREFIX);\n}\n/**\n* Encodes per-scope cursors into a single composite cursor string.\n* Only scopes that still have more results should be included.\n*/\nfunction encodeCompositeCursor(scopeCursors) {\n\treturn COMPOSITE_PREFIX + JSON.stringify(scopeCursors);\n}\n/**\n* Decodes a composite cursor string into a map of scope to cursor.\n* Throws if the cursor is not a valid composite cursor.\n*/\nfunction decodeCompositeCursor(cursor) {\n\tif (!cursor.startsWith(COMPOSITE_PREFIX)) throw new Error(\"Invalid composite cursor format\");\n\tconst json = cursor.slice(2);\n\ttry {\n\t\tconst parsed = JSON.parse(json);\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) throw new Error(\"Invalid composite cursor format\");\n\t\treturn parsed;\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError) throw new Error(\"Invalid composite cursor format\", { cause: error });\n\t\tthrow error;\n\t}\n}\n//#endregion\n//#region src/client/types.ts\n/**\n* Describes the types of document changes that can occur.\n*/\nlet DocumentChangeType = /* @__PURE__ */ function(DocumentChangeType) {\n\tDocumentChangeType[\"Created\"] = \"created\";\n\tDocumentChangeType[\"Deleted\"] = \"deleted\";\n\tDocumentChangeType[\"Updated\"] = \"updated\";\n\tDocumentChangeType[\"ParentAdded\"] = \"parent_added\";\n\tDocumentChangeType[\"ParentRemoved\"] = \"parent_removed\";\n\tDocumentChangeType[\"ChildAdded\"] = \"child_added\";\n\tDocumentChangeType[\"ChildRemoved\"] = \"child_removed\";\n\treturn DocumentChangeType;\n}({});\n//#endregion\n//#region src/decision/read-gate.ts\n/**\n* Scopes every holder of a document may read, whatever the grants say. Denying\n* the policy itself would let a replica sync a document without it, read the\n* auth scope as uninitialized, and allow every operation it holds, so replicas\n* would diverge permanently. The document scope carries the metadata the same\n* argument covers. Grants gate domain-scope reads only.\n*/\nconst ALWAYS_READABLE_SCOPES = new Set([\"auth\", \"document\"]);\n/** What a gate does with an uninitialized policy when told nothing. */\nconst OPEN_BY_DEFAULT = { withholdUninitialized: false };\n/**\n* The branch a group is read on. A group's member list lives on its main\n* branch whatever branch the document naming it is on, and the reference\n* relation records no branch of its own.\n*/\nconst GROUP_BRANCH = \"main\";\n/**\n* The scope of a group document that holds its member list. It is the only\n* scope group serving reaches, because it is the only one the audience must\n* fold in order to evaluate auth with the group.\n*/\nconst GROUP_MEMBERSHIP_SCOPE = \"global\";\n/**\n* How many of a group's referencing documents are examined before a read of\n* that group gives up and withholds. Each one costs a model build, and the\n* relation is append-only, so an old and briefly-held reference still counts.\n* Truncating denies, which is the direction that withholds. It is the cap a\n* version-1 policy carries on its own grant list, taken from there rather than\n* restated: raising that cap raises the read fan-out here.\n*/\nconst MAX_EXAMINED_REFERENCERS = MAX_AUTH_GRANTS;\n/**\n* How many referencers are probed at once. The reactor's Postgres pool size is\n* optional and defaults to ten, and a listing resolves one gate per result, so\n* per-gate fan-out multiplies: a handful keeps one group read from claiming the\n* whole pool while still cutting the walk several times over. On PGlite the\n* queries serialize regardless, so a larger number buys nothing in a browser.\n*/\nconst REFERENCER_PROBE_CONCURRENCY = 4;\n/**\n* The policy carried on a document, if it carries one. A document handed to the\n* gate with no state at all is not policied, so it is not gated.\n*/\nfunction authOf(document) {\n\treturn document.state?.auth;\n}\n/**\n* The model reads enforce. Below `authEnforcement` there is no model to\n* enforce: the document-only model ignores the auth scope entirely, so reading\n* through it would serve every domain scope of a policied document to anyone.\n* Undefined therefore means \"evaluate the policy alone\", which is what the read\n* surface did before the model existed.\n*/\nfunction readDecisionModel(flags, registry) {\n\treturn flags.authEnforcement ? selectDecisionModel(flags, registry) : void 0;\n}\n/**\n* Evaluates the policy on its own, with no groups map and no condition context.\n* A `{ group }` or conditional grant therefore never applies: an allow that\n* does not apply withholds access, so this cannot widen a policy, but a policy\n* relying on a conditional deny is weaker here than it is written.\n*/\nvar BareReadGate = class {\n\tscopePredicate(document, subject) {\n\t\tconst auth = authOf(document);\n\t\treturn Promise.resolve((scope) => ALWAYS_READABLE_SCOPES.has(scope) || decide(auth, subject, {\n\t\t\tverb: \"read\",\n\t\t\tscope\n\t\t}) === \"allow\");\n\t}\n};\n/**\n* Answers a stream read from the document already fetched, and anything else\n* through the read side.\n*\n* The seed is why routing reads through a decision model costs no extra I/O for\n* the document being read: its `document` and `auth` scopes are the two static\n* projections, and the caller has both in hand. Only a group stream the grant\n* list names is fetched.\n*/\nvar SeededStateReader = class {\n\tconstructor(documentView, seed, branch) {\n\t\tthis.documentView = documentView;\n\t\tthis.seed = seed;\n\t\tthis.branch = branch;\n\t}\n\t/**\n\t* A stream this replica does not hold has to reach buildDecisionModel as the\n\t* absence it recognises, or the whole read fails instead of leaving the group\n\t* out of the model, where its principal does not match and the policy fails\n\t* closed. The read side reports absence as a plain Error, so the absence is\n\t* confirmed rather than inferred from the message: a transient failure must\n\t* surface, not silently deny.\n\t*/\n\tasync getState(documentId, scope, branch, targetRevision, signal) {\n\t\tif (targetRevision === void 0 && documentId === this.seed.header.id && branch === this.branch && scope in this.seed.state) return this.seed;\n\t\ttry {\n\t\t\treturn await this.documentView.get(documentId, {\n\t\t\t\tbranch,\n\t\t\t\tscopes: [scope]\n\t\t\t}, void 0, signal);\n\t\t} catch (error) {\n\t\t\tawait this.assertAbsent(documentId, error, signal);\n\t\t\tthrow new DocumentNotFoundError(documentId);\n\t\t}\n\t}\n\tasync assertAbsent(documentId, error, signal) {\n\t\tif (DocumentNotFoundError.isError(error)) return;\n\t\tlet exists;\n\t\ttry {\n\t\t\texists = await this.documentView.exists([documentId], DocumentExistence.LiveOnly, void 0, signal);\n\t\t} catch {\n\t\t\tthrow error;\n\t\t}\n\t\tif (exists[0]) throw error;\n\t}\n};\n/**\n* Evaluates a read against the registered decision model, built at the stream\n* heads. This is what makes `{ group }` principals and conditional grants apply\n* to a read: the model supplies the groups map and the scope's own state, the\n* same two things admission supplies.\n*\n* A read has no action, so a condition on `action.input.*` never holds for one.\n*\n* State is read through the read side rather than the write cache. The write\n* cache is invalidated by whichever process runs the executor, so a reactor\n* running its executors in worker processes would answer reads in the parent\n* from state no commit ever invalidates.\n*/\nvar ModelReadGate = class {\n\tconstructor(model, documentView, servesGroups, operationIndex, logger, options = OPEN_BY_DEFAULT) {\n\t\tthis.model = model;\n\t\tthis.documentView = documentView;\n\t\tthis.servesGroups = servesGroups;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.logger = logger;\n\t\tthis.options = options;\n\t}\n\t/**\n\t* A served group yields its member list and nothing else. What the audience\n\t* is owed is the state it must fold to evaluate auth with the group; a\n\t* group's other scopes are its own business and stay behind its own grants.\n\t*/\n\tasync scopePredicate(document, subject, branch, signal) {\n\t\tconst own = await this.ownPolicyPredicate(document, subject, branch, signal);\n\t\tif (!this.servesGroup(document) || own(GROUP_MEMBERSHIP_SCOPE)) return own;\n\t\tconst audience = await this.servesGroupTo(document.header.id, subject, signal);\n\t\treturn (scope) => own(scope) || audience && scope === GROUP_MEMBERSHIP_SCOPE;\n\t}\n\t/**\n\t* Whether the subject is served this group because a policy names it.\n\t*\n\t* A replica must fold a group's membership to evaluate auth with it, so a\n\t* group a grant names is served to the audience of the document that names\n\t* it, whatever the group's own read grants say. Naming a group in a policy\n\t* publishes its roster to that policy's audience; a group whose membership\n\t* must stay confidential does not belong in a grant.\n\t*\n\t* The referencing document's own domain scopes are the test. Its `auth` and\n\t* `document` scopes are readable by every holder, so testing those would\n\t* serve every referenced group to everybody.\n\t*\n\t* One level only. A referencer that is itself a group is skipped, and a\n\t* referencer's own readability is decided from its policy alone, so a\n\t* reference cycle terminates. Cycles are reachable: the reference relation\n\t* is recorded from an operation's input, including one later stored denied,\n\t* so a refused grant naming a group from inside another group leaves a row\n\t* behind that validation never saw.\n\t*\n\t* The referencers are probed a few at a time and the walk stops at the first\n\t* that serves, because a subject outside the audience is the case that runs to\n\t* the bound, and it is the common one. A probe that failed decides only when\n\t* nothing served: serving rests on a real allow, so this cannot widen, and it\n\t* stops one unreachable referencer from turning an allow already in hand into\n\t* a denial. A read records no operation, so replicas differing over a\n\t* transient failure has no consensus consequence.\n\t*\n\t* The probes are awaited together rather than raced, so none is ever left\n\t* running with nobody awaiting it, which is where unhandled rejections come\n\t* from.\n\t*/\n\tasync servesGroupTo(groupId, subject, signal) {\n\t\tif (!this.operationIndex) return false;\n\t\tconst referencers = await this.operationIndex.getGroupReferencers(groupId, signal);\n\t\tconst examined = referencers.slice(0, MAX_EXAMINED_REFERENCERS);\n\t\tif (examined.length < referencers.length) this.logger?.warn(`Group ${groupId} is referenced by ${referencers.length} documents; only the first ${MAX_EXAMINED_REFERENCERS} decide whether it is served`);\n\t\tconst walk = {\n\t\t\tnext: 0,\n\t\t\tserved: false,\n\t\t\tfailure: void 0\n\t\t};\n\t\tconst probe = async () => {\n\t\t\twhile (!walk.served && walk.next < examined.length) {\n\t\t\t\tconst referencerId = examined[walk.next++];\n\t\t\t\tlet serves = false;\n\t\t\t\ttry {\n\t\t\t\t\tserves = await this.servesThrough(referencerId, subject, signal);\n\t\t\t\t} catch (error) {\n\t\t\t\t\twalk.failure ??= Error.isError(error) ? error : /* @__PURE__ */ new Error(`Probing referencer ${referencerId} failed`);\n\t\t\t\t}\n\t\t\t\tif (serves) walk.served = true;\n\t\t\t}\n\t\t};\n\t\tawait Promise.all(Array.from({ length: Math.min(REFERENCER_PROBE_CONCURRENCY, examined.length) }, probe));\n\t\tif (!walk.served && walk.failure) throw walk.failure;\n\t\treturn walk.served;\n\t}\n\t/**\n\t* Whether one referencing document serves the subject any domain scope. A\n\t* referencer this replica does not hold serves nothing, which fails closed\n\t* the same way a group it does not hold does.\n\t*/\n\tasync servesThrough(referencerId, subject, signal) {\n\t\tlet referencer;\n\t\ttry {\n\t\t\treferencer = await this.documentView.get(referencerId, { branch: GROUP_BRANCH }, void 0, signal);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.servesGroup(referencer)) return false;\n\t\tconst readable = await this.ownPolicyPredicate(referencer, subject, GROUP_BRANCH, signal);\n\t\treturn Object.keys(referencer.state ?? {}).filter((scope) => !ALWAYS_READABLE_SCOPES.has(scope)).some((scope) => readable(scope));\n\t}\n\tservesGroup(document) {\n\t\treturn this.servesGroups && this.operationIndex !== void 0 && document.header.documentType === groupDocumentType;\n\t}\n\t/**\n\t* What this document's own policy says, with no group serving applied.\n\t*\n\t* An unpoliced document is readable in full unless the host closes by default,\n\t* and either way it is the common case and the one worth answering without\n\t* building anything. The test is the one `evaluate` makes: a legacy `{}` auth\n\t* scope and version 0 both mean uninitialized, and \"no grants\" does not,\n\t* because a policy with a version and an empty grant list denies everything.\n\t*\n\t* Closing here rather than around the gate is what keeps a policy able to\n\t* publish an unpoliced group it names: the referencer walk asks this question\n\t* of the referencing document, whose real policy answers it.\n\t*/\n\tasync ownPolicyPredicate(document, subject, branch, signal) {\n\t\tconst auth = authOf(document);\n\t\tif (!auth || !auth.version) return this.options.withholdUninitialized ? (scope) => ALWAYS_READABLE_SCOPES.has(scope) : () => true;\n\t\tconst target = {\n\t\t\tdocumentId: document.header.id,\n\t\t\tbranch\n\t\t};\n\t\tconst built = await buildDecisionModel(new SeededStateReader(this.documentView, document, branch), this.model, target, signal);\n\t\tconst definition = this.model(target);\n\t\tconst scopeStates = document.state ?? {};\n\t\treturn (scope) => ALWAYS_READABLE_SCOPES.has(scope) || definition.decide(built.model, subject, {\n\t\t\tverb: \"read\",\n\t\t\tscope\n\t\t}, {\n\t\t\tscopeState: scopeStates[scope],\n\t\t\tactionInput: void 0\n\t\t}).decision === \"allow\";\n\t}\n};\n//#endregion\n//#region src/client/util.ts\nfunction authSubjectFromSigner(signer) {\n\treturn {\n\t\taddress: signer.user?.address,\n\t\tkey: signer.app?.key\n\t};\n}\nfunction withAuthScope(view) {\n\tif (view?.scopes && view.scopes.length > 0) return {\n\t\t...view,\n\t\tscopes: [...new Set([...view.scopes, \"auth\"])]\n\t};\n\treturn view;\n}\n/**\n* Drops the scopes the predicate refuses. The predicate is resolved by the read\n* gate, which decides against the whole policy once per document; this only\n* applies the answer, so it stays synchronous.\n*/\nfunction filterReadableScopes(document, readable) {\n\tconst state = document.state;\n\tif (!state) return document;\n\treturn {\n\t\t...document,\n\t\tstate: keepReadableScopes(state, readable),\n\t\tinitialState: keepReadableScopes(document.initialState, readable)\n\t};\n}\nfunction keepReadableScopes(scopes, readable) {\n\tif (!scopes) return scopes;\n\tconst kept = {};\n\tfor (const scope of Object.keys(scopes)) if (readable(scope)) kept[scope] = scopes[scope];\n\treturn kept;\n}\n//#endregion\n//#region src/client/reactor-client.ts\n/**\n* The document a candidate is decided against. Routed on the action type alone,\n* which is what the executor routes on: every action the reactor reduces onto\n* the document scope carries that scope already, and the gate follows the\n* action's own target rather than the document the request named.\n*/\nfunction evaluationTargetId(candidate, fallback) {\n\treturn GATED_DOCUMENT_ACTIONS.has(candidate.type) ? targetDocumentId({\n\t\ttype: candidate.type,\n\t\tinput: candidate.input\n\t}, fallback) : fallback;\n}\n/**\n* One candidate's verdict, decided exactly as admission decides it: the same\n* request, and a condition context populated only while authConditions is on,\n* so a conditional grant applies here precisely when it would apply there.\n* Groups need nothing added, because the selected model carries them.\n*/\nfunction decideCandidate(config, target, subject, candidate) {\n\treturn target.definition.decide(target.model, subject, {\n\t\tverb: \"execute\",\n\t\tscope: candidate.scope,\n\t\toperation: candidate.type\n\t}, config.flags.authConditions ? {\n\t\tscopeState: target.scopeStates[candidate.scope],\n\t\tactionInput: candidate.input\n\t} : {\n\t\tscopeState: void 0,\n\t\tactionInput: void 0\n\t});\n}\n/**\n* ReactorClient implementation that wraps lower-level APIs to provide\n* a simpler interface for document operations.\n*\n* Features:\n* - Wraps Jobs with Promises for easier async handling\n* - Manages signing of submitted Action objects\n* - Provides quality-of-life functions for common tasks\n* - Wraps subscription interface with ViewFilters\n*/\nvar ReactorClient = class {\n\tlogger;\n\treactor;\n\tsigner;\n\tsubscriptionManager;\n\tjobAwaiter;\n\tdocumentIndexer;\n\tdocumentView;\n\treadGate;\n\tactionEvaluation;\n\tdrives;\n\tconstructor(logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, readGate = new BareReadGate(), actionEvaluation) {\n\t\tthis.logger = logger;\n\t\tthis.reactor = reactor;\n\t\tthis.signer = signer;\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\tthis.jobAwaiter = jobAwaiter;\n\t\tthis.documentIndexer = documentIndexer;\n\t\tthis.documentView = documentView;\n\t\tthis.readGate = readGate;\n\t\tthis.actionEvaluation = actionEvaluation;\n\t\tthis.drives = new DriveClient(this, logger, reactor, signer);\n\t\tthis.logger.verbose(\"ReactorClient initialized\");\n\t}\n\treadSubject(subject) {\n\t\treturn subject ?? authSubjectFromSigner(this.signer);\n\t}\n\t/**\n\t* Which scopes of one document the subject may read. Resolved once per\n\t* document, so the gate builds its model once however many scopes are then\n\t* tested, and the filtering itself stays synchronous.\n\t*/\n\treadableScopes(document, view, signal) {\n\t\treturn this.readGate.scopePredicate(document, this.readSubject(view?.subject), view?.branch ?? \"main\", signal);\n\t}\n\t/**\n\t* One document, filtered to the scopes the subject may read. Every method\n\t* that hands a document back goes through here, including the ones that\n\t* follow a write: a document returned from a mutation is a read like any\n\t* other, and returning it whole served scopes the same subject would be\n\t* refused by `get`. Its author still sees what it wrote, because an allow on\n\t* execute confers read of that scope.\n\t*/\n\tasync gateDocument(document, view, signal) {\n\t\treturn filterReadableScopes(document, await this.readableScopes(document, view, signal));\n\t}\n\t/**\n\t* Retrieves a list of document model modules.\n\t*/\n\tasync getDocumentModelModules(namespace, paging, signal) {\n\t\tthis.logger.verbose(\"getDocumentModels(@namespace, @paging)\", namespace, paging);\n\t\treturn this.reactor.getDocumentModels(namespace, paging, signal);\n\t}\n\t/**\n\t* Retrieves a specific document model module by document type.\n\t*\n\t* @param documentType - The document type identifier\n\t* @returns The document model module\n\t*/\n\tasync getDocumentModelModule(documentType) {\n\t\tconst modules = await this.reactor.getDocumentModels();\n\t\tlet latestModule;\n\t\tlet latestVersion = -1;\n\t\tfor (const module of modules.results) {\n\t\t\tif (module.documentModel.global.id !== documentType) continue;\n\t\t\tconst version = module.version ?? 1;\n\t\t\tif (version > latestVersion) {\n\t\t\t\tlatestVersion = version;\n\t\t\t\tlatestModule = module;\n\t\t\t}\n\t\t}\n\t\tif (!latestModule) throw new Error(`Document model module not found for type: ${documentType}`);\n\t\treturn latestModule;\n\t}\n\t/**\n\t* Retrieves the document model module matching the version the document is\n\t* stamped with, so not-yet-upgraded documents get the reducer their\n\t* history was written with rather than the latest.\n\t*/\n\tasync getDocumentModelModuleForDocument(document) {\n\t\tconst documentType = document.header.documentType;\n\t\tconst version = normalizeDocumentModelVersion(document.state.document?.version);\n\t\tconst modules = await this.reactor.getDocumentModels();\n\t\tconst availableVersions = [];\n\t\tfor (const module of modules.results) {\n\t\t\tif (module.documentModel.global.id !== documentType) continue;\n\t\t\tconst moduleVersion = normalizeDocumentModelVersion(module.version);\n\t\t\tif (moduleVersion === version) return module;\n\t\t\tavailableVersions.push(moduleVersion);\n\t\t}\n\t\tthrow new UnsupportedDocumentModelVersionError(documentType, version, availableVersions.sort((a, b) => a - b));\n\t}\n\t/**\n\t* Retrieves a specific PHDocument\n\t*/\n\tasync get(identifier, view, signal) {\n\t\tthis.logger.verbose(\"get(@identifier, @view)\", identifier, view);\n\t\tconst document = await this.reactor.getByIdOrSlug(identifier, withAuthScope(view), void 0, signal);\n\t\treturn this.gateDocument(document, view, signal);\n\t}\n\t/**\n\t* Resolves an identifier (id or slug) to the canonical document id, using the\n\t* same lookup as the data path. Resolves against the \"main\" branch. Throws if\n\t* the identifier cannot be resolved or is ambiguous.\n\t*/\n\tasync resolveIdOrSlug(identifier, view, signal) {\n\t\treturn this.documentView.resolveIdOrSlug(identifier, view, void 0, signal);\n\t}\n\t/** True when the id is taken; a soft-deleted document's id is still taken. */\n\tasync isDocumentIdTaken(documentId, signal) {\n\t\tthis.logger.verbose(\"isDocumentIdTaken(@documentId)\", documentId);\n\t\treturn (await this.documentView.exists([documentId], DocumentExistence.IncludingDeleted, void 0, signal))[0];\n\t}\n\t/**\n\t* Retrieves operations for a document\n\t*/\n\tasync getOperations(documentIdentifier, view, filter, paging, signal) {\n\t\tthis.logger.verbose(\"getOperations(@documentIdentifier, @view, @filter, @paging)\", documentIdentifier, view, filter, paging);\n\t\tconst documentId = await this.documentView.resolveIdOrSlug(documentIdentifier, view, void 0, signal);\n\t\tconst gated = await this.reactor.getByIdOrSlug(documentId, withAuthScope(view), void 0, signal);\n\t\tconst canRead = await this.readableScopes(gated, view, signal);\n\t\tif (paging?.cursor && isCompositeCursor(paging.cursor)) return this.getOperationsWithCompositeCursor(documentId, view, filter, paging, signal, canRead);\n\t\tconst operationsByScope = await this.reactor.getOperations(documentId, view, filter, paging, void 0, signal);\n\t\tfor (const scope of Object.keys(operationsByScope)) if (!canRead(scope)) delete operationsByScope[scope];\n\t\tconst scopeEntries = Object.entries(operationsByScope);\n\t\tconst effectivePaging = paging || {\n\t\t\tcursor: \"0\",\n\t\t\tlimit: 100\n\t\t};\n\t\tif (scopeEntries.length <= 1) {\n\t\t\tconst allOperations = scopeEntries.length === 1 ? [...scopeEntries[0][1].results] : [];\n\t\t\tallOperations.sort((a, b) => a.index - b.index);\n\t\t\treturn {\n\t\t\t\tresults: allOperations,\n\t\t\t\toptions: effectivePaging,\n\t\t\t\tnextCursor: scopeEntries.length === 1 ? scopeEntries[0][1].nextCursor : void 0\n\t\t\t};\n\t\t}\n\t\tconst allOperations = [];\n\t\tconst activeCursors = {};\n\t\tfor (const [scopeName, scopeResults] of scopeEntries) {\n\t\t\tallOperations.push(...scopeResults.results);\n\t\t\tif (scopeResults.nextCursor) activeCursors[scopeName] = scopeResults.nextCursor;\n\t\t}\n\t\tallOperations.sort((a, b) => a.index - b.index);\n\t\treturn {\n\t\t\tresults: allOperations,\n\t\t\toptions: effectivePaging,\n\t\t\tnextCursor: Object.keys(activeCursors).length > 0 ? encodeCompositeCursor(activeCursors) : void 0\n\t\t};\n\t}\n\tasync getOperationsWithCompositeCursor(documentId, view, filter, paging, signal, canRead) {\n\t\tconst scopeCursors = decodeCompositeCursor(paging.cursor);\n\t\tconst allOperations = [];\n\t\tconst activeCursors = {};\n\t\tfor (const [scopeName, cursor] of Object.entries(scopeCursors)) {\n\t\t\tif (!canRead(scopeName)) continue;\n\t\t\tconst scopeView = {\n\t\t\t\t...view,\n\t\t\t\tscopes: [scopeName]\n\t\t\t};\n\t\t\tconst scopePaging = {\n\t\t\t\tcursor,\n\t\t\t\tlimit: paging.limit\n\t\t\t};\n\t\t\tconst scopeResult = (await this.reactor.getOperations(documentId, scopeView, filter, scopePaging, void 0, signal))[scopeName];\n\t\t\tallOperations.push(...scopeResult.results);\n\t\t\tif (scopeResult.nextCursor) activeCursors[scopeName] = scopeResult.nextCursor;\n\t\t}\n\t\tallOperations.sort((a, b) => a.index - b.index);\n\t\treturn {\n\t\t\tresults: allOperations,\n\t\t\toptions: paging,\n\t\t\tnextCursor: Object.keys(activeCursors).length > 0 ? encodeCompositeCursor(activeCursors) : void 0\n\t\t};\n\t}\n\t/**\n\t* Retrieves outgoing relationships of a given type from a source document.\n\t*/\n\tasync getOutgoingRelationships(sourceIdentifier, relationshipType, view, paging, signal) {\n\t\tthis.logger.verbose(\"getOutgoingRelationships(@sourceIdentifier, @relationshipType, @view, @paging)\", sourceIdentifier, relationshipType, view, paging);\n\t\tconst sourceId = await this.documentView.resolveIdOrSlug(sourceIdentifier, view, void 0, signal);\n\t\tconst targetIds = (await this.documentIndexer.getOutgoing(sourceId, [relationshipType], void 0, void 0, signal)).results.map((rel) => rel.targetId);\n\t\tif (targetIds.length === 0) return {\n\t\t\tresults: [],\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: 0\n\t\t\t}\n\t\t};\n\t\treturn this.find({ ids: targetIds }, view, paging, signal);\n\t}\n\t/**\n\t* Retrieves incoming relationships of a given type to a target document.\n\t*/\n\tasync getIncomingRelationships(targetIdentifier, relationshipType, view, paging, signal) {\n\t\tthis.logger.verbose(\"getIncomingRelationships(@targetIdentifier, @relationshipType, @view, @paging)\", targetIdentifier, relationshipType, view, paging);\n\t\tconst targetId = await this.documentView.resolveIdOrSlug(targetIdentifier, view, void 0, signal);\n\t\tconst sourceIds = (await this.documentIndexer.getIncoming(targetId, [relationshipType], void 0, void 0, signal)).results.map((rel) => rel.sourceId);\n\t\tif (sourceIds.length === 0) return {\n\t\t\tresults: [],\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: 0\n\t\t\t}\n\t\t};\n\t\treturn this.find({ ids: sourceIds }, view, paging, signal);\n\t}\n\t/**\n\t* Filters documents by criteria and returns a list of them\n\t*/\n\tasync find(search, view, paging, signal) {\n\t\tthis.logger.verbose(\"find(@search, @view, @paging)\", search, view, paging);\n\t\tconst results = await this.reactor.find(search, withAuthScope(view), paging, void 0, signal);\n\t\treturn {\n\t\t\t...results,\n\t\t\tresults: await Promise.all(results.results.map(async (doc) => filterReadableScopes(doc, await this.readableScopes(doc, view, signal))))\n\t\t};\n\t}\n\t/**\n\t* Predicts the admission verdict for each candidate. See\n\t* {@link IReactorClient.evaluateActions} for the contract and its caveats.\n\t*\n\t* Read-only throughout, and never through the write cache: that cache is\n\t* invalidated by whichever process runs the executor, so a reactor running\n\t* its executors in worker processes would answer here from state no commit\n\t* ever invalidates.\n\t*/\n\tasync evaluateActions(documentIdentifier, branch, candidates, subject, signal) {\n\t\tthis.logger.verbose(\"evaluateActions(@documentIdentifier, @branch, @count candidates)\", documentIdentifier, branch, candidates.length);\n\t\tconst config = this.actionEvaluation;\n\t\tif (config === void 0) throw new AuthEnforcementDisabledError();\n\t\tconst decidedSubject = this.readSubject(subject);\n\t\tconst resolvedId = await this.documentView.resolveIdOrSlug(documentIdentifier, { branch }, void 0, signal);\n\t\tconst targets = /* @__PURE__ */ new Map();\n\t\tconst evaluations = [];\n\t\tfor (const candidate of candidates) {\n\t\t\tif (candidate.type === \"CREATE_DOCUMENT\") {\n\t\t\t\tevaluations.push({ decision: \"allow\" });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst targetId = evaluationTargetId(candidate, resolvedId);\n\t\t\tlet target = targets.get(targetId);\n\t\t\tif (target === void 0) {\n\t\t\t\ttarget = await this.buildEvaluationTarget(config, targetId, branch, signal);\n\t\t\t\ttargets.set(targetId, target);\n\t\t\t}\n\t\t\tevaluations.push(decideCandidate(config, target, decidedSubject, candidate));\n\t\t}\n\t\tconst allowed = evaluations.filter((evaluation) => evaluation.decision === \"allow\").length;\n\t\treturn {\n\t\t\tevaluations,\n\t\t\tallAllowed: candidates.length > 0 && allowed === candidates.length,\n\t\t\tanyAllowed: allowed > 0,\n\t\t\tallDenied: candidates.length > 0 && allowed === 0,\n\t\t\tanyDenied: allowed < candidates.length\n\t\t};\n\t}\n\t/**\n\t* The decision model for one target document, built at its stream heads.\n\t*\n\t* The document is fetched unfiltered, because the policy is what decides:\n\t* reading it through the read gate would withhold the very scopes the\n\t* decision is about. A deleted document is served at its deletion boundary,\n\t* which is what lets the model refuse an execute against it -- authEnforcement\n\t* requires documentDecisions, so that read is available whenever this runs.\n\t*\n\t* Reading past the gate discloses nothing a submit does not. The `auth` and\n\t* `document` scopes are readable by every holder, so a verdict resting on the\n\t* policy alone is one the caller could compute unaided; and a verdict resting\n\t* on a conditional grant reads the executing scope's state exactly as\n\t* admission reads it, so the answer here is what submitting and being refused\n\t* would have revealed anyway.\n\t*\n\t* The append condition the build records is dropped. It guards a write, and\n\t* this makes none; reproducing it is also what the preflight cannot do, which\n\t* is why the answer is a prediction.\n\t*/\n\tasync buildEvaluationTarget(config, documentId, branch, signal) {\n\t\tconst document = await this.documentView.get(documentId, { branch }, void 0, signal);\n\t\tconst target = {\n\t\t\tdocumentId,\n\t\t\tbranch\n\t\t};\n\t\tconst built = await buildDecisionModel(new SeededStateReader(this.documentView, document, branch), config.model, target, signal);\n\t\treturn {\n\t\t\tdefinition: config.model(target),\n\t\t\tmodel: built.model,\n\t\t\tscopeStates: document.state ?? {}\n\t\t};\n\t}\n\t/**\n\t* Creates a document and waits for completion\n\t*/\n\tasync create(document, parentIdentifier, signal) {\n\t\tthis.logger.verbose(\"create(@id, @parentIdentifier)\", document.header.id, parentIdentifier);\n\t\tconst documentId = document.header.id;\n\t\tconst createActions = await signActions([createDocumentAction({\n\t\t\tmodel: document.header.documentType,\n\t\t\tversion: 0,\n\t\t\tdocumentId,\n\t\t\tsigning: {\n\t\t\t\tsignature: documentId,\n\t\t\t\tpublicKey: document.header.sig.publicKey,\n\t\t\t\tnonce: document.header.sig.nonce,\n\t\t\t\tcreatedAtUtcIso: document.header.createdAtUtcIso,\n\t\t\t\tdocumentType: document.header.documentType\n\t\t\t},\n\t\t\tslug: document.header.slug,\n\t\t\tname: document.header.name,\n\t\t\tbranch: document.header.branch,\n\t\t\tmeta: document.header.meta,\n\t\t\tprotocolVersions: document.header.protocolVersions ?? { \"base-reducer\": 2 }\n\t\t}), upgradeDocumentAction({\n\t\t\tdocumentId,\n\t\t\tmodel: document.header.documentType,\n\t\t\tfromVersion: 0,\n\t\t\ttoVersion: normalizeDocumentModelVersion(document.state.document?.version),\n\t\t\tinitialState: document.state\n\t\t})], this.signer, signal);\n\t\tconst jobs = [{\n\t\t\tkey: \"create\",\n\t\t\tdocumentId,\n\t\t\tscope: getSharedActionScope(createActions),\n\t\t\tbranch: \"main\",\n\t\t\tactions: createActions,\n\t\t\tdependsOn: []\n\t\t}];\n\t\tif (parentIdentifier) {\n\t\t\tconst parentActions = await signActions([addRelationshipAction(parentIdentifier, documentId, \"child\")], this.signer, signal);\n\t\t\tjobs.push({\n\t\t\t\tkey: \"parent\",\n\t\t\t\tdocumentId: parentIdentifier,\n\t\t\t\tscope: getSharedActionScope(parentActions),\n\t\t\t\tbranch: \"main\",\n\t\t\t\tactions: parentActions,\n\t\t\t\tdependsOn: [\"create\"]\n\t\t\t});\n\t\t}\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);\n\t\tconst created = await this.reactor.get(documentId);\n\t\treturn this.gateDocument(created, void 0, signal);\n\t}\n\t/**\n\t* Creates an empty document and waits for completion\n\t*/\n\tasync createEmpty(documentModelType, options, signal) {\n\t\tthis.logger.verbose(\"createEmpty(@documentModelType, @options)\", documentModelType, options);\n\t\tconst matchingModules = (await this.reactor.getDocumentModels(void 0, void 0, signal)).results.filter((m) => m.documentModel.global.id === documentModelType);\n\t\tlet module;\n\t\tif (options?.documentModelVersion !== void 0) {\n\t\t\tconst requestedVersion = normalizeDocumentModelVersion(options.documentModelVersion);\n\t\t\tmodule = matchingModules.find((m) => normalizeDocumentModelVersion(m.version) === requestedVersion);\n\t\t\tif (!module) throw new Error(`Document model not found for type: ${documentModelType} with version: ${options.documentModelVersion}`);\n\t\t} else {\n\t\t\tmodule = matchingModules.reduce((latest, current) => {\n\t\t\t\tif (latest === void 0) return current;\n\t\t\t\treturn normalizeDocumentModelVersion(current.version) > normalizeDocumentModelVersion(latest.version) ? current : latest;\n\t\t\t}, void 0);\n\t\t\tif (!module) throw new Error(`Document model not found for type: ${documentModelType}`);\n\t\t}\n\t\tconst document = module.utils.createDocument();\n\t\tdocument.state.document.version = normalizeDocumentModelVersion(module.version);\n\t\treturn this.create(document, options?.parentIdentifier, signal);\n\t}\n\t/**\n\t* Upgrades a document to a newer document model version by dispatching an\n\t* UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the\n\t* latest registered module version for the document's type. Returns the\n\t* document unchanged when it is already at the target version.\n\t*\n\t* The executor validates the action's version and revision snapshot against\n\t* the state the migration actually runs on. When a concurrent edit\n\t* invalidates the snapshot, the upgrade is rebuilt from a fresh read and\n\t* retried up to maxConflictRetries times before the conflict is surfaced.\n\t*/\n\tasync upgradeDocument(documentIdentifier, toVersion, options, signal) {\n\t\tthis.logger.verbose(\"upgradeDocument(@documentIdentifier, @toVersion)\", documentIdentifier, toVersion);\n\t\tconst maxConflictRetries = options?.maxConflictRetries ?? 3;\n\t\tlet lastConflictMessage = \"\";\n\t\tfor (let attempt = 0; attempt <= maxConflictRetries; attempt++) {\n\t\t\tconst document = await this.reactor.getByIdOrSlug(documentIdentifier, void 0, void 0, signal);\n\t\t\tconst documentId = document.header.id;\n\t\t\tconst documentType = document.header.documentType;\n\t\t\tconst branch = document.header.branch || \"main\";\n\t\t\tconst fromVersion = normalizeDocumentModelVersion(document.state.document?.version);\n\t\t\tlet targetVersion = toVersion;\n\t\t\tif (targetVersion === void 0) targetVersion = normalizeDocumentModelVersion((await this.getDocumentModelModule(documentType)).version);\n\t\t\tif (targetVersion === fromVersion) return this.gateDocument(document, { branch }, signal);\n\t\t\tif (targetVersion < fromVersion) throw new DowngradeNotSupportedError(documentType, fromVersion, targetVersion);\n\t\t\tconst signedActions = await signActions([upgradeDocumentAction({\n\t\t\t\tdocumentId,\n\t\t\t\tmodel: documentType,\n\t\t\t\tfromVersion,\n\t\t\t\ttoVersion: targetVersion,\n\t\t\t\trevision: { ...document.header.revision }\n\t\t\t})], this.signer, signal);\n\t\t\tconst jobInfo = await this.reactor.execute(documentId, branch, signedActions, signal);\n\t\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\t\tif (completedJob.status !== JobStatus.FAILED) {\n\t\t\t\tconst upgraded = await this.reactor.getByIdOrSlug(documentId, { branch }, completedJob.consistencyToken, signal);\n\t\t\t\treturn this.gateDocument(upgraded, { branch }, signal);\n\t\t\t}\n\t\t\tif (completedJob.error?.name !== \"UpgradePreconditionFailedError\") throw new Error(completedJob.error?.message);\n\t\t\tlastConflictMessage = completedJob.error.message;\n\t\t}\n\t\tthrow new Error(`Upgrade of document ${documentIdentifier} conflicted with concurrent edits after ${maxConflictRetries + 1} attempts: ${lastConflictMessage}`);\n\t}\n\t/**\n\t* Creates an empty document in a drive as a single batched operation.\n\t* Delegates to {@link IDriveClient.addFile}.\n\t*\n\t* @deprecated Use `client.drives.addFile` instead. This method will be\n\t* removed in a future release.\n\t*/\n\tasync createDocumentInDrive(driveId, document, parentFolder, signal) {\n\t\treturn this.drives.addFile(driveId, document, parentFolder, signal);\n\t}\n\t/**\n\t* Applies a list of actions to a document and waits for completion.\n\t*\n\t* `subject` names who the returned document is read as; see\n\t* {@link IReactorClient.execute}.\n\t*/\n\tasync execute(documentIdentifier, branch, actions, signal, subject) {\n\t\tthis.logger.verbose(\"execute(@documentIdentifier, @branch, @count actions)\", documentIdentifier, branch, actions.length);\n\t\tconst signedActions = await signActions(actions, this.signer, signal);\n\t\tconst jobInfo = await this.reactor.execute(documentIdentifier, branch, signedActions, signal);\n\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\tif (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\tconst view = {\n\t\t\tbranch,\n\t\t\tsubject\n\t\t};\n\t\tconst result = await this.reactor.getByIdOrSlug(documentIdentifier, view, completedJob.consistencyToken, signal);\n\t\treturn this.gateDocument(result, view, signal);\n\t}\n\t/**\n\t* Submits a list of actions to a document\n\t*/\n\tasync executeAsync(documentIdentifier, branch, actions, signal) {\n\t\tthis.logger.verbose(\"executeAsync(@documentIdentifier, @branch, @count actions)\", documentIdentifier, branch, actions.length);\n\t\tconst signedActions = await signActions(actions, this.signer, signal);\n\t\treturn this.reactor.execute(documentIdentifier, branch, signedActions, signal);\n\t}\n\tasync executeBatch(request, signal) {\n\t\tthis.logger.verbose(\"executeBatch(@count jobs)\", request.jobs.length);\n\t\tconst signedJobs = await Promise.all(request.jobs.map(async (job) => ({\n\t\t\t...job,\n\t\t\tactions: await signActions(job.actions, this.signer, signal)\n\t\t})));\n\t\tconst batchResult = await this.reactor.executeBatch({ jobs: signedJobs }, signal);\n\t\tconst completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));\n\t\tfor (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);\n\t\treturn batchResult;\n\t}\n\t/**\n\t* Renames a document and waits for completion\n\t*/\n\tasync rename(documentIdentifier, name, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"rename(@documentIdentifier, @name, @branch)\", documentIdentifier, name, branch);\n\t\treturn this.execute(documentIdentifier, branch, [actions.setName(name)], signal);\n\t}\n\t/**\n\t* Updates the preferred editor recorded in the document header meta.\n\t* Pass `null` to clear it.\n\t*/\n\tasync setPreferredEditor(documentIdentifier, preferredEditor, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"setPreferredEditor(@documentIdentifier, @preferredEditor, @branch)\", documentIdentifier, preferredEditor, branch);\n\t\treturn this.execute(documentIdentifier, branch, [actions.setPreferredEditor(preferredEditor)], signal);\n\t}\n\t/**\n\t* Adds multiple documents as children to another and waits for completion\n\t*/\n\tasync addRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"addRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @branch)\", sourceIdentifier, targetIdentifier, relationshipType, branch);\n\t\tconst jobInfo = await this.reactor.addRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\tif (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\tconst result = await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);\n\t\treturn this.gateDocument(result, { branch }, signal);\n\t}\n\t/**\n\t* Removes a relationship between two documents and waits for completion.\n\t*/\n\tasync removeRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"removeRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @branch)\", sourceIdentifier, targetIdentifier, relationshipType, branch);\n\t\tconst jobInfo = await this.reactor.removeRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst completedJob = await this.waitForJob(jobInfo, signal);\n\t\tif (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\tconst result = await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);\n\t\treturn this.gateDocument(result, { branch }, signal);\n\t}\n\t/**\n\t* Moves a relationship from one source document to another and waits for completion.\n\t*/\n\tasync moveRelationship(sourceParentIdentifier, targetParentIdentifier, targetIdentifier, relationshipType, branch = \"main\", signal) {\n\t\tthis.logger.verbose(\"moveRelationship(@sourceParentIdentifier, @targetParentIdentifier, @targetIdentifier, @relationshipType, @branch)\", sourceParentIdentifier, targetParentIdentifier, targetIdentifier, relationshipType, branch);\n\t\tconst removeJobInfo = await this.reactor.removeRelationship(sourceParentIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst removeCompletedJob = await this.waitForJob(removeJobInfo, signal);\n\t\tif (removeCompletedJob.status === JobStatus.FAILED) throw new Error(removeCompletedJob.error?.message);\n\t\tconst addJobInfo = await this.reactor.addRelationship(targetParentIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);\n\t\tconst addCompletedJob = await this.waitForJob(addJobInfo, signal);\n\t\tif (addCompletedJob.status === JobStatus.FAILED) throw new Error(addCompletedJob.error?.message);\n\t\tconst sourceResult = await this.reactor.getByIdOrSlug(sourceParentIdentifier, { branch }, removeCompletedJob.consistencyToken, signal);\n\t\tconst targetResult = await this.reactor.getByIdOrSlug(targetParentIdentifier, { branch }, addCompletedJob.consistencyToken, signal);\n\t\treturn {\n\t\t\tsource: await this.gateDocument(sourceResult, { branch }, signal),\n\t\t\ttarget: await this.gateDocument(targetResult, { branch }, signal)\n\t\t};\n\t}\n\tasync loadBatch(request, signal) {\n\t\tthis.logger.verbose(\"loadBatch(@count jobs)\", request.jobs.length);\n\t\tconst result = await this.reactor.loadBatch(request, signal);\n\t\tconst completedJobs = await Promise.all(Object.entries(result.jobs).map(async ([key, jobInfo]) => {\n\t\t\treturn [key, await this.waitForJob(jobInfo, signal)];\n\t\t}));\n\t\tfor (const [, completedJob] of completedJobs) if (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t\treturn { jobs: Object.fromEntries(completedJobs) };\n\t}\n\t/**\n\t* Deletes a document and waits for completion\n\t*/\n\tasync deleteDocument(identifier, propagate, signal) {\n\t\tthis.logger.verbose(\"deleteDocument(@identifier, @propagate)\", identifier, propagate);\n\t\tconst jobs = [];\n\t\tif (propagate === PropagationMode.Cascade) {\n\t\t\tconst toDelete = new Set([identifier]);\n\t\t\tlet changed = true;\n\t\t\twhile (changed) {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tchanged = false;\n\t\t\t\tconst orphans = await this.documentIndexer.getOrphanedChildren([...toDelete], [\"child\"], signal);\n\t\t\t\tfor (const id of orphans) if (!toDelete.has(id)) {\n\t\t\t\t\ttoDelete.add(id);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const descendantId of toDelete) {\n\t\t\t\tif (descendantId === identifier) continue;\n\t\t\t\tconst removalJobs = await this.removeAllIncomingRelationships(descendantId, signal);\n\t\t\t\tjobs.push(...removalJobs);\n\t\t\t\tconst jobInfo = await this.reactor.deleteDocument(descendantId, this.signer, signal);\n\t\t\t\tjobs.push(jobInfo);\n\t\t\t}\n\t\t}\n\t\tconst removalJobs = await this.removeAllIncomingRelationships(identifier, signal);\n\t\tjobs.push(...removalJobs);\n\t\tconst jobInfo = await this.reactor.deleteDocument(identifier, this.signer, signal);\n\t\tjobs.push(jobInfo);\n\t\tconst completedJobs = await Promise.all(jobs.map((job) => this.waitForJob(job, signal)));\n\t\tfor (const completedJob of completedJobs) if (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);\n\t}\n\t/**\n\t* Deletes documents and waits for completion\n\t*/\n\tasync deleteDocuments(identifiers, propagate, signal) {\n\t\tthis.logger.verbose(\"deleteDocuments(@count identifiers, @propagate)\", identifiers.length, propagate);\n\t\tconst deletePromises = identifiers.map((identifier) => this.deleteDocument(identifier, propagate, signal));\n\t\tawait Promise.all(deletePromises);\n\t}\n\t/**\n\t* Retrieves the status of a job\n\t*/\n\tasync getJobStatus(jobId, signal) {\n\t\tthis.logger.verbose(\"getJobStatus(@jobId)\", jobId);\n\t\treturn this.reactor.getJobStatus(jobId, signal);\n\t}\n\t/**\n\t* Waits for a job to complete\n\t*/\n\tasync waitForJob(jobId, signal) {\n\t\tconst id = typeof jobId === \"string\" ? jobId : jobId.id;\n\t\tthis.logger.verbose(\"waitForJob(@id)\", id);\n\t\treturn this.jobAwaiter.waitForJob(id, signal);\n\t}\n\t/**\n\t* Subscribes to changes for documents matching specified filters\n\t*/\n\tsubscribe(search, callback, view) {\n\t\tthis.logger.verbose(\"subscribe(@search, @view)\", search, view);\n\t\tconst readable = async (document) => filterReadableScopes(document, await this.readableScopes(document, view));\n\t\tlet disposed = false;\n\t\tlet delivering = Promise.resolve();\n\t\t/**\n\t\t* Queues one event behind those already queued. Gating an event resolves\n\t\t* asynchronously, so an event needing a group fetch would otherwise be\n\t\t* overtaken by the one behind it, and one still in flight would reach a\n\t\t* subscriber that has already unsubscribed. Only delivery is ordered, not\n\t\t* the gating: a single subscription can cover every document in the\n\t\t* reactor, so serializing that work would make its delivery rate the sum\n\t\t* of every gate build rather than the slowest. An event that cannot be\n\t\t* gated is withheld, because serving it unfiltered would leak the scopes\n\t\t* the gate did not clear -- but it is logged rather than swallowed, since\n\t\t* the gate rethrows a transient failure precisely so it is not read as a\n\t\t* denial.\n\t\t*/\n\t\tconst deliver = (event) => {\n\t\t\tPromise.resolve(event).catch(() => void 0);\n\t\t\tdelivering = delivering.then(async () => {\n\t\t\t\tconst built = await event;\n\t\t\t\tif (disposed) return;\n\t\t\t\tcallback(built);\n\t\t\t}).catch((error) => {\n\t\t\t\tthis.logger.error(\"Subscription delivery failed for @search: @Error\", { search }, error);\n\t\t\t});\n\t\t};\n\t\tconst unsubscribeCreated = this.subscriptionManager.onDocumentCreated((result) => {\n\t\t\tdeliver((async () => {\n\t\t\t\tconst documents = await Promise.all(result.results.map((id) => this.reactor.get(id, withAuthScope(view), void 0, void 0)));\n\t\t\t\treturn {\n\t\t\t\t\ttype: DocumentChangeType.Created,\n\t\t\t\t\tdocuments: await Promise.all(documents.map(readable))\n\t\t\t\t};\n\t\t\t})());\n\t\t}, search);\n\t\tconst unsubscribeDeleted = this.subscriptionManager.onDocumentDeleted((documentIds) => {\n\t\t\tdeliver({\n\t\t\t\ttype: DocumentChangeType.Deleted,\n\t\t\t\tdocuments: [],\n\t\t\t\tcontext: { childId: documentIds[0] }\n\t\t\t});\n\t\t}, search);\n\t\tconst unsubscribeUpdated = this.subscriptionManager.onDocumentStateUpdated((result) => {\n\t\t\tdeliver((async () => ({\n\t\t\t\ttype: DocumentChangeType.Updated,\n\t\t\t\tdocuments: await Promise.all(result.results.map(readable))\n\t\t\t}))());\n\t\t}, search, view);\n\t\tconst unsubscribeRelationship = this.subscriptionManager.onRelationshipChanged((parentId, childId, changeType) => {\n\t\t\tdeliver({\n\t\t\t\ttype: changeType === RelationshipChangeType.Added ? DocumentChangeType.ChildAdded : DocumentChangeType.ChildRemoved,\n\t\t\t\tdocuments: [],\n\t\t\t\tcontext: {\n\t\t\t\t\tparentId,\n\t\t\t\t\tchildId\n\t\t\t\t}\n\t\t\t});\n\t\t}, search);\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tunsubscribeCreated();\n\t\t\tunsubscribeDeleted();\n\t\t\tunsubscribeUpdated();\n\t\t\tunsubscribeRelationship();\n\t\t};\n\t}\n\tasync removeAllIncomingRelationships(documentId, signal) {\n\t\tconst incoming = await this.documentIndexer.getIncoming(documentId, void 0, void 0, void 0, signal);\n\t\tconst jobs = [];\n\t\tfor (const rel of incoming.results) {\n\t\t\tconst jobInfo = await this.reactor.removeRelationship(rel.sourceId, documentId, rel.relationshipType, \"main\", this.signer, signal);\n\t\t\tjobs.push(jobInfo);\n\t\t}\n\t\treturn jobs;\n\t}\n};\n//#endregion\n//#region src/queue/types.ts\n/**\n* State of a job in the queue\n*/\nlet JobQueueState = /* @__PURE__ */ function(JobQueueState) {\n\tJobQueueState[JobQueueState[\"UNKNOWN\"] = -1] = \"UNKNOWN\";\n\tJobQueueState[JobQueueState[\"PREPROCESSING\"] = 0] = \"PREPROCESSING\";\n\tJobQueueState[JobQueueState[\"PENDING\"] = 1] = \"PENDING\";\n\tJobQueueState[JobQueueState[\"READY\"] = 2] = \"READY\";\n\tJobQueueState[JobQueueState[\"RUNNING\"] = 3] = \"RUNNING\";\n\tJobQueueState[JobQueueState[\"RESOLVED\"] = 4] = \"RESOLVED\";\n\treturn JobQueueState;\n}({});\n/**\n* How a retry is accounted against the job's retry limit.\n* - `CountAgainstLimit` (default): a fault; the job eventually exhausts its\n* retries and fails terminally.\n* - `ExemptFromLimit`: not a fault, so the attempt is not charged to the job.\n* Used for concurrency conflicts, where the retry does new work.\n*/\nlet RetryAccounting = /* @__PURE__ */ function(RetryAccounting) {\n\tRetryAccounting[\"CountAgainstLimit\"] = \"count-against-limit\";\n\tRetryAccounting[\"ExemptFromLimit\"] = \"exempt-from-limit\";\n\treturn RetryAccounting;\n}({});\n/**\n* Event types for the queue system\n*/\nconst QueueEventTypes = { JOB_AVAILABLE: 1e4 };\n//#endregion\n//#region src/executor/job-result-handler.ts\n/** Conflict retries a job may take without charging its retry limit. */\nconst MAX_EXEMPT_CONFLICT_RETRIES = 20;\nfunction toErrorInfo(error) {\n\tif (error instanceof Error) return {\n\t\tname: error.name,\n\t\tmessage: error.message,\n\t\tstack: error.stack || (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n\treturn {\n\t\tname: \"Error\",\n\t\tmessage: error,\n\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t};\n}\nvar JobResultHandler = class {\n\tconstructor(queue, jobTracker, eventBus, resolver, logger) {\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.eventBus = eventBus;\n\t\tthis.resolver = resolver;\n\t\tthis.logger = logger;\n\t}\n\tasync handleResult(handle, result, callbacks) {\n\t\tif (result.success) {\n\t\t\thandle.complete();\n\t\t\tif (this.hasCreateDocumentAction(handle.job)) await callbacks.flushDeferredFor(handle.job.documentId);\n\t\t\treturn;\n\t\t}\n\t\tif (result.error && ModuleNotFoundError.isError(result.error)) {\n\t\t\tlet modelLoaded = false;\n\t\t\ttry {\n\t\t\t\tawait this.resolver.ensureModelLoaded(result.error.documentType);\n\t\t\t\tmodelLoaded = true;\n\t\t\t} catch {}\n\t\t\tif (modelLoaded) {\n\t\t\t\tconst errorInfo = toErrorInfo(result.error);\n\t\t\t\ttry {\n\t\t\t\t\tawait this.queue.retryJob(handle.job.id, errorInfo);\n\t\t\t\t\treturn;\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t}\n\t\tif (result.error && AppendConditionFailedError.isError(result.error) && this.countConflicts(handle.job) < MAX_EXEMPT_CONFLICT_RETRIES) {\n\t\t\tconst errorInfo = toErrorInfo(result.error);\n\t\t\ttry {\n\t\t\t\tawait this.queue.retryJob(handle.job.id, errorInfo, RetryAccounting.ExemptFromLimit);\n\t\t\t\treturn;\n\t\t\t} catch {}\n\t\t}\n\t\tif (result.error && DocumentNotFoundError.isError(result.error) && handle.job.kind === \"load\") {\n\t\t\thandle.defer();\n\t\t\tcallbacks.deferJob(result.error.documentId, handle.job);\n\t\t\treturn;\n\t\t}\n\t\tif (result.error && (DocumentDeletedError.isError(result.error) || DocumentAlreadyExistsError.isError(result.error) || DocumentNotFoundError.isError(result.error) || AuthorizationDeniedError.isError(result.error) || AuthTimestampNotMonotonicError.isError(result.error) || InvalidOperationTimestampError.isError(result.error) || ExcessiveReshuffleError.isError(result.error) || UpgradePreconditionFailedError.isError(result.error))) {\n\t\t\tconst errorInfo = toErrorInfo(result.error);\n\t\t\tthis.jobTracker.markFailed(handle.job.id, errorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: result.error,\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\thandle.fail(errorInfo);\n\t\t\treturn;\n\t\t}\n\t\tconst retryCount = handle.job.retryCount || 0;\n\t\tif (retryCount < (handle.job.maxRetries || 0)) {\n\t\t\tconst currentErrorInfo = result.error ? toErrorInfo(result.error) : toErrorInfo(\"Unknown error\");\n\t\t\ttry {\n\t\t\t\tawait this.queue.retryJob(handle.job.id, currentErrorInfo);\n\t\t\t} catch (error) {\n\t\t\t\tconst retryErrorInfo = toErrorInfo(error instanceof Error ? error : \"Failed to retry job\");\n\t\t\t\tthis.jobTracker.markFailed(handle.job.id, retryErrorInfo, handle.job);\n\t\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\t\tjobId: handle.job.id,\n\t\t\t\t\terror: result.error ?? new Error(retryErrorInfo.message),\n\t\t\t\t\tjob: handle.job\n\t\t\t\t}).catch(() => {});\n\t\t\t\thandle.fail(retryErrorInfo);\n\t\t\t}\n\t\t} else {\n\t\t\tconst currentErrorInfo = result.error ? toErrorInfo(result.error) : toErrorInfo(\"Unknown error\");\n\t\t\tconst fullErrorInfo = this.formatErrorHistory(handle.job.errorHistory, currentErrorInfo, retryCount + 1);\n\t\t\tthis.jobTracker.markFailed(handle.job.id, fullErrorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: result.error ?? new Error(fullErrorInfo.message),\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\thandle.fail(fullErrorInfo);\n\t\t}\n\t}\n\t/** How many times this job has already lost an append-condition race. */\n\tcountConflicts(job) {\n\t\tlet conflicts = 0;\n\t\tfor (const error of job.errorHistory) if (AppendConditionFailedError.isFailureMessage(error.message)) conflicts++;\n\t\treturn conflicts;\n\t}\n\thasCreateDocumentAction(job) {\n\t\tfor (const action of job.actions) if (action.type === \"CREATE_DOCUMENT\") return true;\n\t\tfor (const operation of job.operations) if (operation.action.type === \"CREATE_DOCUMENT\") return true;\n\t\treturn false;\n\t}\n\tformatErrorHistory(errorHistory, currentError, totalAttempts) {\n\t\tconst allErrors = [...errorHistory, currentError];\n\t\tif (allErrors.length === 1) return currentError;\n\t\tconst messageLines = [`Job failed after ${totalAttempts} attempts:`];\n\t\tconst stackLines = [];\n\t\tallErrors.forEach((error, index) => {\n\t\t\tmessageLines.push(`[Attempt ${index + 1}] ${error.message}`);\n\t\t\tstackLines.push(`[Attempt ${index + 1}] Stack trace:\\n${error.stack}`);\n\t\t});\n\t\treturn {\n\t\t\tname: currentError.name,\n\t\t\tmessage: messageLines.join(\"\\n\"),\n\t\t\tstack: stackLines.join(\"\\n\\n\")\n\t\t};\n\t}\n};\n//#endregion\n//#region src/executor/deferred-jobs.ts\n/**\n* The jobs held back because the document they write to was not there yet.\n*\n* A job whose document is missing is deferred rather than failed, because the\n* operations that create that document may still be on their way - out of order\n* from a peer, or a sibling job in the same batch. Deferring emits no event and\n* moves no job status, which is what makes it cheap: a job that gets flushed\n* runs as if it had merely waited its turn.\n*\n* That silence is also why the wait has to be bounded. A deferred job is only\n* released when a job carrying CREATE_DOCUMENT for that exact document id\n* completes, so a job deferred against an id nothing will ever create is\n* released by nothing. Its status stays RUNNING, which is not terminal, so a\n* caller awaiting it waits forever - there is no timeout on that side. The TTL\n* converts that silence into the failure the caller can act on.\n*\n* Failing through the queue rather than only the tracker matters: the queue\n* records the job as resolved, which is what unblocks anything that declared a\n* dependency on it. Deferring alone does not, so a dependent of a deferred job\n* is stranded at PENDING for as long as the deferral lasts.\n*/\nvar DeferredJobs = class {\n\t#byDocumentId = /* @__PURE__ */ new Map();\n\t#timers = /* @__PURE__ */ new Map();\n\tconstructor(queue, jobTracker, eventBus, logger, ttlMs = DEFAULT_DEFERRED_JOB_TTL_MS, onReleased = () => Promise.resolve()) {\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.eventBus = eventBus;\n\t\tthis.logger = logger;\n\t\tthis.ttlMs = ttlMs;\n\t\tthis.onReleased = onReleased;\n\t}\n\t/**\n\t* Holds a job until its document arrives, or until the TTL elapses.\n\t*\n\t* A job deferred again after a flush replaces its own timer rather than\n\t* accumulating one, so the wait is measured from the most recent attempt.\n\t*/\n\tadd(documentId, job) {\n\t\tconst existing = this.#byDocumentId.get(documentId) ?? [];\n\t\texisting.push(job);\n\t\tthis.#byDocumentId.set(documentId, existing);\n\t\tthis.#clearTimer(job.id);\n\t\tconst timer = setTimeout(() => {\n\t\t\tthis.#expire(documentId, job);\n\t\t}, this.ttlMs);\n\t\tif (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n\t\tthis.#timers.set(job.id, timer);\n\t}\n\t/** Re-enqueues everything waiting on a document that has now arrived. */\n\tasync flush(documentId) {\n\t\tconst jobs = this.#byDocumentId.get(documentId);\n\t\tif (!jobs || jobs.length === 0) return;\n\t\tthis.#byDocumentId.delete(documentId);\n\t\tfor (const job of jobs) {\n\t\t\tthis.#clearTimer(job.id);\n\t\t\ttry {\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Error re-enqueuing deferred job: @Error\", error);\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Fails everything still deferred, for a reactor that is shutting down.\n\t*\n\t* The queue is deliberately not told: it is going away too, and nothing is\n\t* left to unblock.\n\t*/\n\tfailAll() {\n\t\tfor (const [, jobs] of this.#byDocumentId) for (const job of jobs) {\n\t\t\tthis.#clearTimer(job.id);\n\t\t\tthis.#markFailed(job);\n\t\t}\n\t\tthis.#byDocumentId.clear();\n\t}\n\t/** The jobs still waiting on a document. Exposed for assertions. */\n\twaitingOn(documentId) {\n\t\treturn this.#byDocumentId.get(documentId) ?? [];\n\t}\n\tasync #expire(documentId, job) {\n\t\tconst jobs = this.#byDocumentId.get(documentId);\n\t\tif (!jobs?.includes(job)) return;\n\t\tconst remaining = jobs.filter((held) => held !== job);\n\t\tif (remaining.length === 0) this.#byDocumentId.delete(documentId);\n\t\telse this.#byDocumentId.set(documentId, remaining);\n\t\tthis.#timers.delete(job.id);\n\t\tthis.logger.error(\"Deferred job @jobId gave up waiting for document @documentId after @ttlMs ms\", job.id, documentId, this.ttlMs);\n\t\tconst errorInfo = this.#markFailed(job);\n\t\ttry {\n\t\t\tawait this.queue.failJob(job.id, errorInfo);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error failing an expired deferred job: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tthis.jobTracker.markFailed(job.id, errorInfo, job);\n\t\ttry {\n\t\t\tawait this.onReleased();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error dispatching after a deferred job expired: @Error\", error);\n\t\t}\n\t}\n\t#markFailed(job) {\n\t\tconst error = new DocumentNotFoundError(job.documentId);\n\t\tconst errorInfo = toErrorInfo(error);\n\t\tthis.jobTracker.markFailed(job.id, errorInfo, job);\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\tjobId: job.id,\n\t\t\terror,\n\t\t\tjob\n\t\t}).catch(() => {});\n\t\treturn errorInfo;\n\t}\n\t#clearTimer(jobId) {\n\t\tconst timer = this.#timers.get(jobId);\n\t\tif (timer !== void 0) {\n\t\t\tclearTimeout(timer);\n\t\t\tthis.#timers.delete(jobId);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/executor/worker-pool-router.ts\n/**\n* Sticky-by-document routing for the executor worker pool.\n*\n* Hashes `documentId` to a stable bucket so every job on a given document\n* lands on the same worker. The queue already enforces \"at most one job\n* executing per document at a time\", so a sticky worker always sees a fresh\n* post-commit snapshot before its next job on that document — which keeps\n* the per-worker `IWriteCache` and `IDocumentMetaCache` coherent for free.\n*\n* The hash is FNV-1a 32-bit: deterministic, dependency-free, and stable\n* across processes (so the same routing decision can be reproduced anywhere\n* the documentId is known).\n*\n* @see Executor Worker Pool Design wiki page\n* (Powerhouse board wiki id: d400d711-f07e-4389-a226-4e9fdd4fa8ba)\n*/\nconst FNV_OFFSET_BASIS = 2166136261;\nconst FNV_PRIME = 16777619;\nfunction hashDocumentId(documentId) {\n\tlet hash = FNV_OFFSET_BASIS;\n\tfor (let i = 0; i < documentId.length; i++) {\n\t\thash ^= documentId.charCodeAt(i);\n\t\thash = Math.imul(hash, FNV_PRIME);\n\t}\n\treturn hash >>> 0;\n}\nfunction bucketFor(documentId, numWorkers) {\n\tif (numWorkers < 1) throw new Error(`bucketFor: numWorkers must be >= 1 (got ${numWorkers})`);\n\treturn hashDocumentId(documentId) % numWorkers;\n}\n//#endregion\n//#region src/executor/worker-pool-job-executor-manager.ts\n/**\n* Manages a pool of executor workers and dispatches jobs across them with\n* sticky-by-documentId routing. Replaces `SimpleJobExecutorManager` when\n* the worker pool is enabled.\n*\n* Responsibilities that stay on the parent (not in the worker):\n* - Dequeueing from `IQueue` and routing to the matching worker bucket.\n* - Emitting `JOB_RUNNING` and `JOB_WRITE_READY` events; the worker's\n* local event bus is a no-op stub.\n* - Maintaining the deferred-jobs map for `DocumentNotFoundError`.\n* - Enriching the outgoing `JOB_WRITE_READY` with\n* `collectionMemberships`, read from the operation index after the\n* worker has committed. It takes the whole index rather than a\n* narrower read interface so that handing it a cache does not\n* compile: which documents a commit moves between collections is not\n* derivable from action shape, because joining a collection also\n* joins every group the joining document has referenced and that set\n* comes from selects run inside the commit. A parent-side cache\n* cannot learn it went stale, and a stale entry silently drops the\n* document's operations from the outbox of every remote subscribed to\n* the omitted collection. Costs one primary-key-prefix lookup on\n* `document_collections` per job that produced operations, on a\n* fire-and-forget path.\n*\n* @see Executor Worker Pool Design wiki page\n* (Powerhouse board wiki id: d400d711-f07e-4389-a226-4e9fdd4fa8ba)\n*/\nvar WorkerPoolJobExecutorManager = class {\n\tworkers = [];\n\tisRunning = false;\n\tactiveJobs = 0;\n\ttotalJobsProcessed = 0;\n\tunsubscribe;\n\tdeferredJobs;\n\tresultHandler;\n\tjobTimeoutMs;\n\tconstructor(workerFactory, eventBus, queue, jobTracker, logger, resolver, operationIndex, jobTimeoutMs = 3e4, deferredJobTtlMs = DEFAULT_DEFERRED_JOB_TTL_MS) {\n\t\tthis.workerFactory = workerFactory;\n\t\tthis.eventBus = eventBus;\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.logger = logger;\n\t\tthis.resolver = resolver;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.jobTimeoutMs = jobTimeoutMs;\n\t\tthis.deferredJobs = new DeferredJobs(queue, jobTracker, eventBus, logger, deferredJobTtlMs, () => this.tryDispatchAll());\n\t\tthis.resultHandler = new JobResultHandler(queue, jobTracker, eventBus, resolver, logger);\n\t}\n\tasync start(numWorkers) {\n\t\tif (this.isRunning) throw new Error(\"WorkerPoolJobExecutorManager is already running\");\n\t\tif (numWorkers < 1) throw new Error(\"Number of workers must be at least 1\");\n\t\tthis.workers = Array.from({ length: numWorkers }, (_, i) => this.workerFactory(i));\n\t\tawait Promise.all(this.workers.map((w) => w.start()));\n\t\tthis.unsubscribe = this.eventBus.subscribe(QueueEventTypes.JOB_AVAILABLE, async () => {\n\t\t\tawait this.tryDispatchAll();\n\t\t});\n\t\tthis.isRunning = true;\n\t\tawait this.tryDispatchAll();\n\t}\n\tasync stop(graceful = true) {\n\t\tif (!this.isRunning) return;\n\t\tif (this.unsubscribe) {\n\t\t\tthis.unsubscribe();\n\t\t\tthis.unsubscribe = void 0;\n\t\t}\n\t\tif (graceful) while (this.activeJobs > 0) await new Promise((resolve) => setTimeout(resolve, 10));\n\t\tthis.deferredJobs.failAll();\n\t\tawait Promise.all(this.workers.map((w) => w.shutdown(graceful).catch((err) => {\n\t\t\tthis.logger.warn(\"worker shutdown failed: @Error\", err);\n\t\t})));\n\t\tthis.workers = [];\n\t\tthis.isRunning = false;\n\t}\n\t/**\n\t* Worker-pool mode has no in-process `IJobExecutor` instances — the\n\t* executors live in worker threads behind `IExecutorWorker` handles.\n\t* Returns an empty array; callers that need pool-aware introspection\n\t* should use `getStatus()` instead.\n\t*/\n\tgetExecutors() {\n\t\treturn [];\n\t}\n\t/**\n\t* Broadcasts a `load-model` request to every running worker in parallel.\n\t* Rejects with the first worker's failure if any worker rejects (after\n\t* waiting for all in-flight broadcasts to settle). Workers that already\n\t* have the model registered respond with a `DuplicateModuleError`-rooted\n\t* failure; those are treated as success on the broadcast level so that\n\t* a model registered on some workers but not others still converges.\n\t*/\n\tasync loadModel(entry) {\n\t\tif (this.workers.length === 0) return;\n\t\tconst failures = (await Promise.allSettled(this.workers.map((w) => w.loadModel(entry)))).filter((r) => r.status === \"rejected\").filter((r) => !isDuplicateModuleFailure(r.reason));\n\t\tif (failures.length === 0) return;\n\t\tfor (const f of failures) this.logger.error(\"worker failed to load model @entry: @error\", entry, f.reason);\n\t\tthrow failures[0].reason instanceof Error ? failures[0].reason : new Error(String(failures[0].reason));\n\t}\n\tgetStatus() {\n\t\treturn {\n\t\t\tisRunning: this.isRunning,\n\t\t\tnumExecutors: this.workers.length,\n\t\t\tactiveJobs: this.activeJobs,\n\t\t\ttotalJobsProcessed: this.totalJobsProcessed\n\t\t};\n\t}\n\tasync tryDispatchAll() {\n\t\tif (!this.isRunning && this.workers.length === 0) return;\n\t\tawait Promise.all(this.workers.map((worker) => this.tryDispatchFor(worker)));\n\t}\n\tasync tryDispatchFor(worker) {\n\t\tif (!worker.isIdle()) return;\n\t\tconst index = worker.index;\n\t\tconst numWorkers = this.workers.length;\n\t\tconst predicate = (meta) => bucketFor(meta.documentId, numWorkers) === index;\n\t\tlet handle;\n\t\ttry {\n\t\t\thandle = await this.queue.dequeueNextMatching(predicate);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error dequeueing next job: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (!handle) return;\n\t\thandle.start();\n\t\tthis.activeJobs++;\n\t\tthis.jobTracker.markRunning(handle.job.id);\n\t\tconst runningEvent = {\n\t\t\tjobId: handle.job.id,\n\t\t\tjobMeta: handle.job.meta\n\t\t};\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_RUNNING, runningEvent).catch(() => {});\n\t\tconst workerId = worker.workerId;\n\t\tconst startedEvent = {\n\t\t\tjob: handle.job,\n\t\t\tstartedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tworkerId\n\t\t};\n\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_STARTED, startedEvent).catch(() => {});\n\t\tconst signal = AbortSignal.timeout(this.jobTimeoutMs);\n\t\tlet outcome;\n\t\ttry {\n\t\t\toutcome = await worker.execute(handle.job, signal);\n\t\t} catch (error) {\n\t\t\tconst errorInfo = toErrorInfo(error instanceof Error ? error : String(error));\n\t\t\tif (isWorkerTransportError(error)) {\n\t\t\t\tawait this.handleWorkerTransportFailure(worker, handle.job, errorInfo);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandle.fail(errorInfo);\n\t\t\tthis.activeJobs--;\n\t\t\tthis.jobTracker.markFailed(handle.job.id, errorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: new Error(errorInfo.message),\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: errorInfo.message,\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t\tawait this.tryDispatchFor(worker);\n\t\t\treturn;\n\t\t}\n\t\tif (outcome.result.success) {\n\t\t\tthis.totalJobsProcessed++;\n\t\t\tconst completedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\tresult: outcome.result,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_COMPLETED, completedEvent).catch(() => {});\n\t\t} else {\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: outcome.result.error?.message ?? \"unknown\",\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t}\n\t\tif (outcome.result.success && outcome.writeReady) this.emitWriteReady(handle.job, outcome.writeReady).catch((error) => {\n\t\t\tthis.logger.error(\"emitWriteReady failed for job @jobId: @Error\", { jobId: handle.job.id }, error);\n\t\t});\n\t\tawait this.resultHandler.handleResult(handle, outcome.result, {\n\t\t\tdeferJob: (documentId, job) => this.deferredJobs.add(documentId, job),\n\t\t\tflushDeferredFor: (documentId) => this.deferredJobs.flush(documentId)\n\t\t});\n\t\tthis.activeJobs--;\n\t\tawait this.tryDispatchFor(worker);\n\t}\n\tasync emitWriteReady(job, payload) {\n\t\tconst documentIds = [...new Set(payload.operations.map((op) => op.context.documentId))];\n\t\tlet collectionMemberships = {};\n\t\tif (documentIds.length > 0) try {\n\t\t\tcollectionMemberships = fillMissingMemberships(documentIds, await this.operationIndex.getCollectionsForDocuments(documentIds));\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to load collection memberships for JOB_WRITE_READY: @Error\", error);\n\t\t}\n\t\tconst event = {\n\t\t\tjobId: job.id,\n\t\t\toperations: payload.operations,\n\t\t\tjobMeta: payload.jobMeta,\n\t\t\tcollectionMemberships\n\t\t};\n\t\ttry {\n\t\t\tawait this.eventBus.emit(ReactorEventTypes.JOB_WRITE_READY, event);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to emit JOB_WRITE_READY event: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Handle a worker-transport failure (worker exited / init failed / abort\n\t* timed out) detected while `worker.execute` was in flight. Re-enqueues\n\t* the in-flight job via `queue.retryJob` so it is retried on a healthy\n\t* worker, then replaces the dead worker with a fresh handle and resumes\n\t* dispatch on the same bucket. Does NOT emit JOB_FAILED — the job is\n\t* not failed, only the worker is.\n\t*/\n\tasync handleWorkerTransportFailure(dead, job, errorInfo) {\n\t\tthis.logger.warn(\"worker transport error during execute; retrying job @jobId on a replacement worker: @error\", {\n\t\t\tjobId: job.id,\n\t\t\tworkerId: dead.workerId\n\t\t}, errorInfo.message);\n\t\tthis.activeJobs--;\n\t\tawait this.replaceWorker(dead);\n\t\ttry {\n\t\t\tawait this.queue.retryJob(job.id, errorInfo);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"failed to re-enqueue job after worker transport error: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Replace a dead worker at its existing pool index with a fresh handle\n\t* produced by `workerFactory`. Awaits `start()` on the replacement so it\n\t* is ready before dispatch resumes. On replacement failure the slot is\n\t* left empty (the index becomes a hole that subsequent retries will\n\t* route to no worker) and the error is logged — the manager keeps\n\t* running so other buckets continue to make progress.\n\t*/\n\tasync replaceWorker(dead) {\n\t\tconst deadIndex = dead.index;\n\t\tif (this.workers[deadIndex] !== dead) return;\n\t\tlet fresh;\n\t\ttry {\n\t\t\tfresh = this.workerFactory(deadIndex);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"workerFactory threw while replacing dead worker at index @index: @Error\", deadIndex, error);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tawait fresh.start();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"replacement worker at index @index failed to start: @Error\", deadIndex, error);\n\t\t\treturn;\n\t\t}\n\t\tthis.workers[deadIndex] = fresh;\n\t\tawait this.tryDispatchFor(fresh);\n\t}\n};\nfunction isWorkerTransportError(error) {\n\treturn error instanceof WorkerExitedError || error instanceof WorkerInitFailedError || error instanceof WorkerAbortTimeoutError;\n}\nfunction isDuplicateModuleFailure(reason) {\n\tif (!(reason instanceof Error)) return false;\n\tif (reason.name === \"DuplicateModuleError\") return true;\n\tconst cause = reason.cause;\n\treturn cause instanceof Error && cause.name === \"DuplicateModuleError\";\n}\n/**\n* Gives every requested document a key, empty when it belongs to no\n* collection. The operation index omits documents with no rows while the\n* membership cache defaulted them to `[]`, so this keeps the emitted\n* `JobWriteReadyEvent.collectionMemberships` shape unchanged.\n*/\nfunction fillMissingMemberships(documentIds, found) {\n\tconst result = {};\n\tfor (const documentId of documentIds) result[documentId] = found[documentId] ?? [];\n\treturn result;\n}\n//#endregion\n//#region src/executor/simple-job-executor-manager.ts\n/**\n* Manages multiple job executors and coordinates job distribution.\n* Listens for job available events and dispatches jobs to executors.\n*/\nvar SimpleJobExecutorManager = class {\n\texecutors = [];\n\tisRunning = false;\n\tactiveJobs = 0;\n\ttotalJobsProcessed = 0;\n\tunsubscribe;\n\tdeferredJobs;\n\tresultHandler;\n\tjobTimeoutMs;\n\tconstructor(executorFactory, eventBus, queue, jobTracker, logger, resolver, jobTimeoutMs = 3e4, deferredJobTtlMs = DEFAULT_DEFERRED_JOB_TTL_MS) {\n\t\tthis.executorFactory = executorFactory;\n\t\tthis.eventBus = eventBus;\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.logger = logger;\n\t\tthis.resolver = resolver;\n\t\tthis.jobTimeoutMs = jobTimeoutMs;\n\t\tthis.deferredJobs = new DeferredJobs(queue, jobTracker, eventBus, logger, deferredJobTtlMs, () => this.checkForMoreJobs());\n\t\tthis.resultHandler = new JobResultHandler(queue, jobTracker, eventBus, resolver, logger);\n\t}\n\tasync start(numExecutors) {\n\t\tif (this.isRunning) throw new Error(\"JobExecutorManager is already running\");\n\t\tif (numExecutors < 1) throw new Error(\"Number of executors must be at least 1\");\n\t\tthis.executors = [];\n\t\tfor (let i = 0; i < numExecutors; i++) this.executors.push(this.executorFactory());\n\t\tthis.unsubscribe = this.eventBus.subscribe(QueueEventTypes.JOB_AVAILABLE, async () => {\n\t\t\tif (this.activeJobs < this.executors.length) await this.processNextJob();\n\t\t});\n\t\tthis.isRunning = true;\n\t\tawait this.processExistingJobs();\n\t}\n\tasync stop(graceful = true) {\n\t\tif (!this.isRunning) return;\n\t\tif (this.unsubscribe) {\n\t\t\tthis.unsubscribe();\n\t\t\tthis.unsubscribe = void 0;\n\t\t}\n\t\tif (graceful) while (this.activeJobs > 0) await new Promise((resolve) => setTimeout(resolve, 100));\n\t\tthis.deferredJobs.failAll();\n\t\tthis.executors = [];\n\t\tthis.isRunning = false;\n\t}\n\tgetExecutors() {\n\t\treturn [...this.executors];\n\t}\n\tgetStatus() {\n\t\treturn {\n\t\t\tisRunning: this.isRunning,\n\t\t\tnumExecutors: this.executors.length,\n\t\t\tactiveJobs: this.activeJobs,\n\t\t\ttotalJobsProcessed: this.totalJobsProcessed\n\t\t};\n\t}\n\tasync processNextJob() {\n\t\tlet handle;\n\t\ttry {\n\t\t\thandle = await this.queue.dequeueNext();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error dequeueing next job: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (!handle) return;\n\t\thandle.start();\n\t\tthis.activeJobs++;\n\t\tthis.jobTracker.markRunning(handle.job.id);\n\t\tconst runningEvent = {\n\t\t\tjobId: handle.job.id,\n\t\t\tjobMeta: handle.job.meta\n\t\t};\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_RUNNING, runningEvent).catch(() => {});\n\t\tconst executorIndex = this.totalJobsProcessed % this.executors.length;\n\t\tconst executor = this.executors[executorIndex];\n\t\tconst workerId = `in-process-${executorIndex}`;\n\t\tconst startedEvent = {\n\t\t\tjob: handle.job,\n\t\t\tstartedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tworkerId\n\t\t};\n\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_STARTED, startedEvent).catch(() => {});\n\t\tconst signal = AbortSignal.timeout(this.jobTimeoutMs);\n\t\tconst toError = (reason) => reason instanceof Error ? reason : new Error(String(reason));\n\t\tconst abortPromise = new Promise((_, reject) => {\n\t\t\tif (signal.aborted) {\n\t\t\t\treject(toError(signal.reason));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsignal.addEventListener(\"abort\", () => reject(toError(signal.reason)), { once: true });\n\t\t});\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await Promise.race([executor.executeJob(handle.job, signal), abortPromise]);\n\t\t} catch (error) {\n\t\t\tconst errorInfo = toErrorInfo(error instanceof Error ? error : String(error));\n\t\t\thandle.fail(errorInfo);\n\t\t\tthis.activeJobs--;\n\t\t\tthis.jobTracker.markFailed(handle.job.id, errorInfo, handle.job);\n\t\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\t\tjobId: handle.job.id,\n\t\t\t\terror: new Error(errorInfo.message),\n\t\t\t\tjob: handle.job\n\t\t\t}).catch(() => {});\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: errorInfo.message,\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t\tawait this.checkForMoreJobs();\n\t\t\treturn;\n\t\t}\n\t\tif (result.success) this.totalJobsProcessed++;\n\t\tif (result.success) {\n\t\t\tconst completedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\tresult,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_COMPLETED, completedEvent).catch(() => {});\n\t\t} else {\n\t\t\tconst failedEvent = {\n\t\t\t\tjob: handle.job,\n\t\t\t\terror: result.error?.message ?? \"unknown\",\n\t\t\t\twillRetry: false,\n\t\t\t\tretryCount: 0,\n\t\t\t\tworkerId\n\t\t\t};\n\t\t\tthis.eventBus.emit(JobExecutorEventTypes.JOB_FAILED, failedEvent).catch(() => {});\n\t\t}\n\t\tawait this.resultHandler.handleResult(handle, result, {\n\t\t\tdeferJob: (documentId, job) => this.deferredJobs.add(documentId, job),\n\t\t\tflushDeferredFor: (documentId) => this.deferredJobs.flush(documentId)\n\t\t});\n\t\tthis.activeJobs--;\n\t\tawait this.checkForMoreJobs();\n\t}\n\tasync checkForMoreJobs() {\n\t\tif (!this.isRunning) return;\n\t\tlet hasMore;\n\t\ttry {\n\t\t\thasMore = await this.queue.hasJobs();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error checking for more jobs: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (hasMore) await this.processNextJob();\n\t}\n\tasync processExistingJobs() {\n\t\tlet hasJobs;\n\t\ttry {\n\t\t\thasJobs = await this.queue.hasJobs();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error checking for existing jobs: @Error\", error);\n\t\t\treturn;\n\t\t}\n\t\tif (hasJobs) {\n\t\t\tconst promises = [];\n\t\t\tfor (let i = 0; i < Math.min(this.executors.length, 5); i++) promises.push(this.processNextJob());\n\t\t\ttry {\n\t\t\t\tawait Promise.all(promises);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Error processing existing jobs: @Error\", error);\n\t\t\t}\n\t\t}\n\t}\n};\n//#endregion\n//#region src/job-tracker/in-memory-job-tracker.ts\n/**\n* In-memory implementation of IJobTracker.\n* Maintains job status in a Map for synchronous access.\n* Subscribes to operation events to update job states.\n*/\nvar InMemoryJobTracker = class {\n\tjobs = /* @__PURE__ */ new Map();\n\tunsubscribers = [];\n\tconstructor(eventBus) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.subscribeToEvents();\n\t}\n\tsubscribeToEvents() {\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, (_type, event) => {\n\t\t\tthis.handleWriteReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_READ_READY, (_type, event) => {\n\t\t\tthis.handleReadReady(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, (_type, event) => {\n\t\t\tthis.handleJobFailed(event);\n\t\t}));\n\t}\n\thandleWriteReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tconst job = this.jobs.get(jobId);\n\t\tif (job && job.status === JobStatus.RUNNING) {\n\t\t\tconst consistencyToken = createConsistencyToken(event.operations);\n\t\t\tthis.jobs.set(jobId, {\n\t\t\t\t...job,\n\t\t\t\tstatus: JobStatus.WRITE_READY,\n\t\t\t\tconsistencyToken\n\t\t\t});\n\t\t}\n\t}\n\thandleReadReady(event) {\n\t\tconst jobId = event.jobId;\n\t\tconst job = this.jobs.get(jobId);\n\t\tif (job && job.status === JobStatus.WRITE_READY) this.jobs.set(jobId, {\n\t\t\t...job,\n\t\t\tstatus: JobStatus.READ_READY\n\t\t});\n\t}\n\thandleJobFailed(event) {\n\t\tthis.markFailed(event.jobId, {\n\t\t\tname: event.error.name,\n\t\t\tmessage: event.error.message,\n\t\t\tstack: event.error.stack || \"\"\n\t\t}, event.job);\n\t}\n\tshutdown() {\n\t\tfor (const unsubscribe of this.unsubscribers) unsubscribe();\n\t\tthis.unsubscribers = [];\n\t}\n\tregisterJob(jobInfo) {\n\t\tthis.jobs.set(jobInfo.id, { ...jobInfo });\n\t}\n\tmarkRunning(jobId) {\n\t\tconst job = this.jobs.get(jobId);\n\t\tif (!job) {\n\t\t\tthis.jobs.set(jobId, {\n\t\t\t\tid: jobId,\n\t\t\t\tdocumentId: \"\",\n\t\t\t\tstatus: JobStatus.RUNNING,\n\t\t\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\tconsistencyToken: createEmptyConsistencyToken(),\n\t\t\t\tmeta: {\n\t\t\t\t\tbatchId: jobId,\n\t\t\t\t\tbatchJobIds: [jobId]\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.jobs.set(jobId, {\n\t\t\t...job,\n\t\t\tstatus: JobStatus.RUNNING\n\t\t});\n\t}\n\tmarkFailed(jobId, error, job) {\n\t\tconst existing = this.jobs.get(jobId);\n\t\tif (!existing) {\n\t\t\tthis.jobs.set(jobId, {\n\t\t\t\tid: jobId,\n\t\t\t\tdocumentId: job?.documentId ?? \"\",\n\t\t\t\tstatus: JobStatus.FAILED,\n\t\t\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\tcompletedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\terror,\n\t\t\t\tjob,\n\t\t\t\tconsistencyToken: createEmptyConsistencyToken(),\n\t\t\t\tmeta: {\n\t\t\t\t\tbatchId: jobId,\n\t\t\t\t\tbatchJobIds: [jobId]\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.jobs.set(jobId, {\n\t\t\t...existing,\n\t\t\tstatus: JobStatus.FAILED,\n\t\t\tcompletedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\terror,\n\t\t\tjob,\n\t\t\tconsistencyToken: createEmptyConsistencyToken()\n\t\t});\n\t}\n\tgetJobStatus(jobId) {\n\t\tconst job = this.jobs.get(jobId);\n\t\treturn job ? { ...job } : null;\n\t}\n};\n//#endregion\n//#region src/processors/utils.ts\nfunction isDriveDeletion(op) {\n\treturn op.operation.action.type === \"DELETE_DOCUMENT\";\n}\nfunction extractDriveHeader(op) {\n\tif (!op.context.resultingState) return void 0;\n\treturn JSON.parse(op.context.resultingState).header;\n}\nfunction extractDeletedDocumentId(op) {\n\treturn op.operation.action.input.documentId ?? op.context.documentId;\n}\nfunction createMinimalDriveHeader(driveId, documentType) {\n\treturn {\n\t\tid: driveId,\n\t\tdocumentType,\n\t\tsig: {\n\t\t\tpublicKey: {},\n\t\t\tnonce: \"\"\n\t\t},\n\t\tslug: \"\",\n\t\tname: \"\",\n\t\tbranch: \"main\",\n\t\trevision: {},\n\t\tcreatedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),\n\t\tlastModifiedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString()\n\t};\n}\nfunction matchesFilter(op, filter) {\n\tif (filter.documentType && filter.documentType.length > 0) {\n\t\tif (!filter.documentType.includes(op.context.documentType)) return false;\n\t}\n\tif (filter.scope && filter.scope.length > 0) {\n\t\tif (!filter.scope.includes(op.context.scope)) return false;\n\t}\n\tif (filter.branch && filter.branch.length > 0) {\n\t\tif (!filter.branch.includes(op.context.branch)) return false;\n\t}\n\tif (filter.documentId && filter.documentId.length > 0) {\n\t\tif (!filter.documentId.includes(\"*\") && !filter.documentId.includes(op.context.documentId)) return false;\n\t}\n\treturn true;\n}\nfunction nonEmpty(value) {\n\treturn typeof value === \"string\" && value.length > 0 ? value : void 0;\n}\nfunction namespaceOf(processor) {\n\treturn nonEmpty(processor.namespace);\n}\nfunction classNameOf(processor) {\n\tconst name = processor.constructor.name;\n\treturn name && name !== \"Object\" ? name : void 0;\n}\nfunction resolveProcessorSlots(records, legacy) {\n\tif (legacy) return records.map((_, i) => String(i));\n\tconst seen = /* @__PURE__ */ new Map();\n\treturn records.map((record, i) => {\n\t\tconst base = nonEmpty(record.id) ?? namespaceOf(record.processor) ?? classNameOf(record.processor) ?? String(i);\n\t\tconst count = seen.get(base) ?? 0;\n\t\tseen.set(base, count + 1);\n\t\treturn count === 0 ? base : `${base}#${count}`;\n\t});\n}\n//#endregion\n//#region src/processors/processor-manager.ts\n/**\n* Manages processor lifecycle based on operations.\n* Extends BaseReadModel to receive operations from ReadModelCoordinator.\n*\n* Responsibilities:\n* 1. Detect drive creation from CREATE_DOCUMENT operations\n* 2. Create processors for each drive using registered factories\n* 3. Route operations to matching processors based on filters\n* 4. Clean up processors when drives are deleted or factories are unregistered\n* 5. Track per-processor cursors for failure recovery and backfill\n*/\nvar ProcessorManager = class extends BaseReadModel {\n\tfactoryRegistry = /* @__PURE__ */ new Map();\n\tprocessorsByDrive = /* @__PURE__ */ new Map();\n\tfactoryToProcessors = /* @__PURE__ */ new Map();\n\tknownDrives = /* @__PURE__ */ new Map();\n\tcursorCache = /* @__PURE__ */ new Map();\n\tlogger;\n\tdriveContainerTypes;\n\tlegacyProcessorIds;\n\tconstructor(db, operationIndex, writeCache, consistencyTracker, logger, driveContainerTypes, options = {}) {\n\t\tsuper(db, operationIndex, writeCache, consistencyTracker, {\n\t\t\treadModelId: \"processor-manager\",\n\t\t\trebuildStateOnInit: true\n\t\t});\n\t\tthis.logger = logger;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.legacyProcessorIds = options.legacyProcessorIds ?? true;\n\t}\n\tasync init() {\n\t\tawait super.init();\n\t\tawait this.loadAllCursors();\n\t\tawait this.discoverExistingDrives();\n\t}\n\tasync commitOperations(items) {\n\t\tawait this.detectAndRegisterNewDrives(items);\n\t\tawait this.detectAndCleanupDeletedDrives(items);\n\t\tawait this.routeOperationsToProcessors(items);\n\t}\n\tasync registerFactory(identifier, factory) {\n\t\tif (this.factoryRegistry.has(identifier)) await this.unregisterFactory(identifier);\n\t\tthis.factoryRegistry.set(identifier, factory);\n\t\tthis.factoryToProcessors.set(identifier, /* @__PURE__ */ new Map());\n\t\tfor (const [driveId, documentType] of this.knownDrives) {\n\t\t\tconst driveHeader = createMinimalDriveHeader(driveId, documentType);\n\t\t\tawait this.createProcessorsForDrive(driveId, identifier, factory, driveHeader);\n\t\t}\n\t}\n\tasync unregisterFactory(identifier) {\n\t\tconst factoryProcessors = this.factoryToProcessors.get(identifier);\n\t\tif (!factoryProcessors) return;\n\t\tfor (const [driveId, tracked] of factoryProcessors) {\n\t\t\tfor (const t of tracked) await this.safeDisconnect(t.record.processor);\n\t\t\tconst driveProcessors = this.processorsByDrive.get(driveId);\n\t\t\tif (driveProcessors) {\n\t\t\t\tconst remaining = driveProcessors.filter((p) => !tracked.includes(p));\n\t\t\t\tif (remaining.length > 0) this.processorsByDrive.set(driveId, remaining);\n\t\t\t\telse this.processorsByDrive.delete(driveId);\n\t\t\t}\n\t\t}\n\t\tawait this.deleteProcessorCursors({ factoryId: identifier });\n\t\tthis.factoryToProcessors.delete(identifier);\n\t\tthis.factoryRegistry.delete(identifier);\n\t}\n\tget(processorId) {\n\t\tfor (const tracked of this.allTrackedProcessors()) if (tracked.processorId === processorId) return tracked;\n\t}\n\tgetAll() {\n\t\treturn Array.from(this.allTrackedProcessors());\n\t}\n\t*allTrackedProcessors() {\n\t\tfor (const tracked of this.processorsByDrive.values()) yield* tracked;\n\t}\n\tasync detectAndRegisterNewDrives(operations) {\n\t\tfor (const op of operations) {\n\t\t\tif (!this.isDriveCreation(op)) continue;\n\t\t\tconst driveId = op.context.documentId;\n\t\t\tif (this.knownDrives.has(driveId)) continue;\n\t\t\tthis.knownDrives.set(driveId, op.context.documentType);\n\t\t\tconst driveHeader = extractDriveHeader(op);\n\t\t\tif (!driveHeader) continue;\n\t\t\tfor (const [identifier, factory] of this.factoryRegistry) await this.createProcessorsForDrive(driveId, identifier, factory, driveHeader);\n\t\t}\n\t}\n\tisDriveCreation(op) {\n\t\treturn op.operation.action.type === \"CREATE_DOCUMENT\" && this.driveContainerTypes.has(op.context.documentType);\n\t}\n\tasync detectAndCleanupDeletedDrives(operations) {\n\t\tfor (const op of operations) {\n\t\t\tif (!isDriveDeletion(op)) continue;\n\t\t\tconst driveId = extractDeletedDocumentId(op);\n\t\t\tif (!driveId || !this.knownDrives.has(driveId)) continue;\n\t\t\tif (!this.isDeletedDocumentADrive(driveId)) continue;\n\t\t\tawait this.cleanupDriveProcessors(driveId);\n\t\t\tthis.knownDrives.delete(driveId);\n\t\t}\n\t}\n\tasync discoverExistingDrives() {\n\t\tconst drives = await this.db.selectFrom(\"DocumentSnapshot\").select([\"documentId\", \"documentType\"]).where(\"documentType\", \"in\", [...this.driveContainerTypes]).where(\"isDeleted\", \"=\", false).execute();\n\t\tfor (const drive of drives) this.knownDrives.set(drive.documentId, drive.documentType);\n\t}\n\tisDeletedDocumentADrive(documentId) {\n\t\treturn this.knownDrives.has(documentId);\n\t}\n\tasync createProcessorsForDrive(driveId, identifier, factory, driveHeader) {\n\t\tlet records;\n\t\ttry {\n\t\t\trecords = await factory(driveHeader);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Factory '@FactoryId' failed for drive '@DriveId': @Error\", identifier, driveId, error);\n\t\t\treturn;\n\t\t}\n\t\tif (records.length === 0) return;\n\t\tconst trackedList = [];\n\t\tconst slots = resolveProcessorSlots(records, this.legacyProcessorIds);\n\t\tfor (let i = 0; i < records.length; i++) {\n\t\t\tconst record = records[i];\n\t\t\tconst processorId = `${identifier}:${driveId}:${slots[i]}`;\n\t\t\tconst cached = this.cursorCache.get(processorId);\n\t\t\tlet lastOrdinal;\n\t\t\tlet status;\n\t\t\tlet lastError;\n\t\t\tlet lastErrorTimestamp;\n\t\t\tif (cached) {\n\t\t\t\tlastOrdinal = cached.lastOrdinal;\n\t\t\t\tstatus = cached.status;\n\t\t\t\tlastError = cached.lastError ?? void 0;\n\t\t\t\tlastErrorTimestamp = cached.lastErrorTimestamp ?? void 0;\n\t\t\t} else {\n\t\t\t\tlastOrdinal = (record.startFrom ?? \"beginning\") === \"current\" ? this.lastOrdinal : 0;\n\t\t\t\tstatus = \"active\";\n\t\t\t\tlastError = void 0;\n\t\t\t\tlastErrorTimestamp = void 0;\n\t\t\t}\n\t\t\tconst tracked = {\n\t\t\t\tprocessorId,\n\t\t\t\tfactoryId: identifier,\n\t\t\t\tdriveId,\n\t\t\t\tprocessorIndex: i,\n\t\t\t\trecord,\n\t\t\t\tlastOrdinal,\n\t\t\t\tstatus,\n\t\t\t\tlastError,\n\t\t\t\tlastErrorTimestamp,\n\t\t\t\tretry: () => this.retryProcessor(tracked)\n\t\t\t};\n\t\t\ttrackedList.push(tracked);\n\t\t\tawait this.saveProcessorCursor(tracked);\n\t\t}\n\t\tconst liveIds = new Set(trackedList.map((t) => t.processorId));\n\t\tawait this.db.deleteFrom(\"ProcessorCursor\").where(\"factoryId\", \"=\", identifier).where(\"driveId\", \"=\", driveId).where(\"processorId\", \"not in\", [...liveIds]).execute();\n\t\tfor (const [id, row] of this.cursorCache) if (row.factoryId === identifier && row.driveId === driveId && !liveIds.has(id)) this.cursorCache.delete(id);\n\t\tconst factoryProcessors = this.factoryToProcessors.get(identifier);\n\t\tif (factoryProcessors) factoryProcessors.set(driveId, trackedList);\n\t\tconst existingDriveProcessors = this.processorsByDrive.get(driveId) ?? [];\n\t\tthis.processorsByDrive.set(driveId, [...existingDriveProcessors, ...trackedList]);\n\t\tfor (const tracked of trackedList) if (tracked.status === \"active\" && tracked.lastOrdinal < this.lastOrdinal) await this.backfillProcessor(tracked);\n\t}\n\tasync backfillProcessor(tracked) {\n\t\tlet page = await this.operationIndex.getSinceOrdinal(tracked.lastOrdinal);\n\t\twhile (page.results.length > 0) {\n\t\t\tconst matching = page.results.filter((op) => matchesFilter(op, tracked.record.filter));\n\t\t\tif (matching.length > 0) try {\n\t\t\t\tawait tracked.record.processor.onOperations(matching);\n\t\t\t} catch (error) {\n\t\t\t\ttracked.status = \"errored\";\n\t\t\t\ttracked.lastError = error instanceof Error ? error.message : String(error);\n\t\t\t\ttracked.lastErrorTimestamp = /* @__PURE__ */ new Date();\n\t\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t\t\tthis.logger.error(\"Processor '@ProcessorId' failed during backfill at ordinal @Ordinal: @Error\", tracked.processorId, tracked.lastOrdinal, error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttracked.lastOrdinal = page.results[page.results.length - 1].context.ordinal;\n\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t\tif (!page.next) break;\n\t\t\tpage = await page.next();\n\t\t}\n\t}\n\tasync retryProcessor(tracked) {\n\t\tif (tracked.status !== \"errored\") return;\n\t\ttracked.status = \"active\";\n\t\ttracked.lastError = void 0;\n\t\ttracked.lastErrorTimestamp = void 0;\n\t\tawait this.saveProcessorCursor(tracked);\n\t\tawait this.backfillProcessor(tracked);\n\t}\n\tasync cleanupDriveProcessors(driveId) {\n\t\tconst processors = this.processorsByDrive.get(driveId);\n\t\tif (!processors) return;\n\t\tfor (const tracked of processors) await this.safeDisconnect(tracked.record.processor);\n\t\tthis.processorsByDrive.delete(driveId);\n\t\tfor (const factoryProcessors of this.factoryToProcessors.values()) factoryProcessors.delete(driveId);\n\t\tawait this.deleteProcessorCursors({ driveId });\n\t}\n\tasync safeDisconnect(processor) {\n\t\ttry {\n\t\t\tawait processor.onDisconnect();\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error disconnecting processor: @Error\", error);\n\t\t}\n\t}\n\tasync routeOperationsToProcessors(operations) {\n\t\tlet maxOrdinal = 0;\n\t\tfor (const op of operations) maxOrdinal = Math.max(maxOrdinal, op.context.ordinal);\n\t\tconst allTracked = Array.from(this.allTrackedProcessors());\n\t\tawait Promise.all(allTracked.map(async (tracked) => {\n\t\t\tif (tracked.status !== \"active\") return;\n\t\t\tconst matching = operations.filter((op) => op.context.ordinal > tracked.lastOrdinal).filter((op) => matchesFilter(op, tracked.record.filter));\n\t\t\tif (matching.length > 0) try {\n\t\t\t\tawait tracked.record.processor.onOperations(matching);\n\t\t\t} catch (error) {\n\t\t\t\ttracked.status = \"errored\";\n\t\t\t\ttracked.lastError = error instanceof Error ? error.message : String(error);\n\t\t\t\ttracked.lastErrorTimestamp = /* @__PURE__ */ new Date();\n\t\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t\t\tthis.logger.error(\"Processor '@ProcessorId' failed at ordinal @Ordinal: @Error\", tracked.processorId, tracked.lastOrdinal, error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttracked.lastOrdinal = maxOrdinal;\n\t\t\tawait this.safeSaveProcessorCursor(tracked);\n\t\t}));\n\t}\n\tasync loadAllCursors() {\n\t\tconst rows = await this.db.selectFrom(\"ProcessorCursor\").selectAll().execute();\n\t\tfor (const row of rows) this.cursorCache.set(row.processorId, row);\n\t}\n\tasync safeSaveProcessorCursor(tracked) {\n\t\ttry {\n\t\t\tawait this.saveProcessorCursor(tracked);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to persist cursor for '@ProcessorId': @Error\", tracked.processorId, error);\n\t\t}\n\t}\n\tasync saveProcessorCursor(tracked) {\n\t\tawait this.db.insertInto(\"ProcessorCursor\").values({\n\t\t\tprocessorId: tracked.processorId,\n\t\t\tfactoryId: tracked.factoryId,\n\t\t\tdriveId: tracked.driveId,\n\t\t\tprocessorIndex: tracked.processorIndex,\n\t\t\tlastOrdinal: tracked.lastOrdinal,\n\t\t\tstatus: tracked.status,\n\t\t\tlastError: tracked.lastError ?? null,\n\t\t\tlastErrorTimestamp: tracked.lastErrorTimestamp ?? null,\n\t\t\tupdatedAt: /* @__PURE__ */ new Date()\n\t\t}).onConflict((oc) => oc.column(\"processorId\").doUpdateSet({\n\t\t\tlastOrdinal: tracked.lastOrdinal,\n\t\t\tstatus: tracked.status,\n\t\t\tlastError: tracked.lastError ?? null,\n\t\t\tlastErrorTimestamp: tracked.lastErrorTimestamp ?? null,\n\t\t\tupdatedAt: /* @__PURE__ */ new Date()\n\t\t})).execute();\n\t\tthis.cursorCache.set(tracked.processorId, {\n\t\t\tprocessorId: tracked.processorId,\n\t\t\tfactoryId: tracked.factoryId,\n\t\t\tdriveId: tracked.driveId,\n\t\t\tprocessorIndex: tracked.processorIndex,\n\t\t\tlastOrdinal: tracked.lastOrdinal,\n\t\t\tstatus: tracked.status,\n\t\t\tlastError: tracked.lastError ?? null,\n\t\t\tlastErrorTimestamp: tracked.lastErrorTimestamp ?? null,\n\t\t\tcreatedAt: /* @__PURE__ */ new Date(),\n\t\t\tupdatedAt: /* @__PURE__ */ new Date()\n\t\t});\n\t}\n\tasync deleteProcessorCursors(filter) {\n\t\tif (\"factoryId\" in filter) {\n\t\t\tawait this.db.deleteFrom(\"ProcessorCursor\").where(\"factoryId\", \"=\", filter.factoryId).execute();\n\t\t\tfor (const [id, row] of this.cursorCache) if (row.factoryId === filter.factoryId) this.cursorCache.delete(id);\n\t\t} else {\n\t\t\tawait this.db.deleteFrom(\"ProcessorCursor\").where(\"driveId\", \"=\", filter.driveId).execute();\n\t\t\tfor (const [id, row] of this.cursorCache) if (row.driveId === filter.driveId) this.cursorCache.delete(id);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/queue/job-execution-handle.ts\n/**\n* Implementation of the IJobExecutionHandle interface\n*/\nvar JobExecutionHandle = class {\n\t_state;\n\t_job;\n\tonStart;\n\tonComplete;\n\tonFail;\n\tonDefer;\n\tgetStateName(state) {\n\t\tswitch (state) {\n\t\t\tcase JobQueueState.PREPROCESSING: return \"PREPROCESSING\";\n\t\t\tcase JobQueueState.PENDING: return \"PENDING\";\n\t\t\tcase JobQueueState.READY: return \"READY\";\n\t\t\tcase JobQueueState.RUNNING: return \"RUNNING\";\n\t\t\tcase JobQueueState.RESOLVED: return \"RESOLVED\";\n\t\t\tdefault: return `UNKNOWN`;\n\t\t}\n\t}\n\tconstructor(job, initialState, callbacks) {\n\t\tthis._job = job;\n\t\tthis._state = initialState;\n\t\tthis.onStart = callbacks?.onStart;\n\t\tthis.onComplete = callbacks?.onComplete;\n\t\tthis.onFail = callbacks?.onFail;\n\t\tthis.onDefer = callbacks?.onDefer;\n\t}\n\tget job() {\n\t\treturn this._job;\n\t}\n\tget state() {\n\t\treturn this._state;\n\t}\n\tstart() {\n\t\tif (this._state !== JobQueueState.READY) throw new Error(`Cannot start job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RUNNING;\n\t\tthis.onStart?.();\n\t}\n\tcomplete() {\n\t\tif (this._state !== JobQueueState.RUNNING) throw new Error(`Cannot complete job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RESOLVED;\n\t\tthis.onComplete?.();\n\t}\n\tfail(error) {\n\t\tif (this._state !== JobQueueState.RUNNING) throw new Error(`Cannot fail job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RESOLVED;\n\t\tthis.onFail?.(error);\n\t}\n\tdefer() {\n\t\tif (this._state !== JobQueueState.RUNNING) throw new Error(`Cannot defer job in state ${this.getStateName(this._state)}`);\n\t\tthis._state = JobQueueState.RESOLVED;\n\t\tthis.onDefer?.();\n\t}\n};\n//#endregion\n//#region src/queue/queue.ts\n/**\n* In-memory implementation of the IQueue interface.\n* Organizes jobs by documentId, scope, and branch to ensure proper ordering.\n* Ensures serial execution per document by tracking executing jobs.\n* Implements dependency management through queue hints.\n*/\nvar InMemoryQueue = class {\n\tqueues = /* @__PURE__ */ new Map();\n\tjobIdToQueueKey = /* @__PURE__ */ new Map();\n\tdocIdToJobId = /* @__PURE__ */ new Map();\n\tjobIdToDocId = /* @__PURE__ */ new Map();\n\tcompletedJobs = /* @__PURE__ */ new Set();\n\tjobIndex = /* @__PURE__ */ new Map();\n\tisBlocked = false;\n\tonDrainedCallback;\n\tisPausedFlag = false;\n\tconstructor(eventBus, resolver) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.resolver = resolver;\n\t}\n\ttoErrorInfo(error) {\n\t\tif (error instanceof Error) return {\n\t\t\tname: error.name,\n\t\t\tmessage: error.message,\n\t\t\tstack: error.stack || (/* @__PURE__ */ new Error()).stack || \"\"\n\t\t};\n\t\treturn {\n\t\t\tname: \"Error\",\n\t\t\tmessage: error,\n\t\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t\t};\n\t}\n\t/**\n\t* Creates a unique key for a document/scope/branch combination\n\t*/\n\tcreateQueueKey(documentId, scope, branch) {\n\t\treturn `${documentId}:${scope}:${branch}`;\n\t}\n\t/**\n\t* Gets or creates a queue for the given key\n\t*/\n\tgetQueue(queueKey) {\n\t\tlet queue = this.queues.get(queueKey);\n\t\tif (!queue) {\n\t\t\tqueue = [];\n\t\t\tthis.queues.set(queueKey, queue);\n\t\t}\n\t\treturn queue;\n\t}\n\t/**\n\t* Check if a document has any jobs currently executing\n\t*/\n\tisDocumentExecuting(documentId) {\n\t\tconst executingSet = this.docIdToJobId.get(documentId);\n\t\treturn executingSet ? executingSet.size > 0 : false;\n\t}\n\t/**\n\t* Mark a job as executing for its document\n\t*/\n\tmarkJobExecuting(job) {\n\t\tlet executingSet = this.docIdToJobId.get(job.documentId);\n\t\tif (!executingSet) {\n\t\t\texecutingSet = /* @__PURE__ */ new Set();\n\t\t\tthis.docIdToJobId.set(job.documentId, executingSet);\n\t\t}\n\t\texecutingSet.add(job.id);\n\t\tthis.jobIdToDocId.set(job.id, job.documentId);\n\t}\n\t/**\n\t* Mark a job as no longer executing for its document\n\t*/\n\tmarkJobComplete(jobId, documentId) {\n\t\tconst executingSet = this.docIdToJobId.get(documentId);\n\t\tif (executingSet) {\n\t\t\texecutingSet.delete(jobId);\n\t\t\tif (executingSet.size === 0) this.docIdToJobId.delete(documentId);\n\t\t}\n\t\tthis.jobIdToDocId.delete(jobId);\n\t}\n\t/**\n\t* Check if all dependencies for a job have been completed\n\t*/\n\tareDependenciesMet(job) {\n\t\tif (job.queueHint.length === 0) return true;\n\t\treturn job.queueHint.every((depId) => this.completedJobs.has(depId));\n\t}\n\t/**\n\t* Returns the head of the sub-queue if its dependencies are met, or null.\n\t*\n\t* The dispatcher only ever considers the head — a dep-blocked head holds\n\t* the rest of its sub-queue. This preserves per-(documentId, scope, branch)\n\t* FIFO regardless of how dependencies are authored, and makes the queue's\n\t* documented \"serialized per document\" invariant hold even when callers\n\t* omit queueHint dependencies on jobs that share a sub-queue.\n\t*/\n\tgetNextJobWithMetDependencies(queue) {\n\t\tif (queue.length === 0) return null;\n\t\tconst head = queue[0];\n\t\treturn this.areDependenciesMet(head) ? head : null;\n\t}\n\tgetCreateDocumentType(job) {\n\t\tfor (const action of job.actions) if (action.type === \"CREATE_DOCUMENT\") return action.input.model;\n\t\tfor (const operation of job.operations) if (operation.action.type === \"CREATE_DOCUMENT\") return operation.action.input.model;\n\t}\n\tasync enqueue(job) {\n\t\tif (this.isBlocked) throw new Error(\"Queue is blocked\");\n\t\tconst queueKey = this.createQueueKey(job.documentId, job.scope, job.branch);\n\t\tthis.getQueue(queueKey).push(job);\n\t\tthis.jobIdToQueueKey.set(job.id, queueKey);\n\t\tthis.jobIndex.set(job.id, job);\n\t\tconst documentType = this.getCreateDocumentType(job);\n\t\tif (documentType) try {\n\t\t\tawait this.resolver.ensureModelLoaded(documentType);\n\t\t} catch {\n\t\t\tawait this.failJob(job.id, {\n\t\t\t\tname: \"Error\",\n\t\t\t\tmessage: `Failed to load document model for type: ${documentType}`,\n\t\t\t\tstack: (/* @__PURE__ */ new Error()).stack || \"\"\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tconst eventData = {\n\t\t\tdocumentId: job.documentId,\n\t\t\tscope: job.scope,\n\t\t\tbranch: job.branch,\n\t\t\tjobId: job.id\n\t\t};\n\t\tawait this.eventBus.emit(QueueEventTypes.JOB_AVAILABLE, eventData);\n\t}\n\tdequeue(documentId, scope, branch, signal) {\n\t\tconst queueKey = this.createQueueKey(documentId, scope, branch);\n\t\tconst queue = this.queues.get(queueKey);\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (!queue || queue.length === 0) return Promise.resolve(null);\n\t\tconst job = this.getNextJobWithMetDependencies(queue);\n\t\tif (!job) return Promise.resolve(null);\n\t\tconst jobIndex = queue.indexOf(job);\n\t\tqueue.splice(jobIndex, 1);\n\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\tthis.markJobExecuting(job);\n\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\tconst handle = new JobExecutionHandle(job, JobQueueState.READY, {\n\t\t\tonStart: () => {},\n\t\t\tonComplete: () => {\n\t\t\t\tthis.completeJob(job.id);\n\t\t\t},\n\t\t\tonFail: (error) => {\n\t\t\t\tthis.failJob(job.id, error);\n\t\t\t},\n\t\t\tonDefer: () => {\n\t\t\t\tthis.deferJob(job.id);\n\t\t\t}\n\t\t});\n\t\treturn Promise.resolve(handle);\n\t}\n\tdequeueNext(signal) {\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (this.isPausedFlag) return Promise.resolve(null);\n\t\tfor (const [queueKey, queue] of this.queues.entries()) if (queue.length > 0) {\n\t\t\tconst job = this.getNextJobWithMetDependencies(queue);\n\t\t\tif (!job) continue;\n\t\t\tif (!this.isDocumentExecuting(job.documentId)) {\n\t\t\t\tconst jobIdx = queue.indexOf(job);\n\t\t\t\tqueue.splice(jobIdx, 1);\n\t\t\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\t\t\tthis.markJobExecuting(job);\n\t\t\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\t\t\tconst handle = new JobExecutionHandle(job, JobQueueState.READY, {\n\t\t\t\t\tonStart: () => {},\n\t\t\t\t\tonComplete: () => {\n\t\t\t\t\t\tthis.completeJob(job.id);\n\t\t\t\t\t},\n\t\t\t\t\tonFail: (error) => {\n\t\t\t\t\t\tthis.failJob(job.id, error);\n\t\t\t\t\t},\n\t\t\t\t\tonDefer: () => {\n\t\t\t\t\t\tthis.deferJob(job.id);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn Promise.resolve(handle);\n\t\t\t}\n\t\t}\n\t\treturn Promise.resolve(null);\n\t}\n\tdequeueNextMatching(predicate, signal) {\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (this.isPausedFlag) return Promise.resolve(null);\n\t\tfor (const [queueKey, queue] of this.queues.entries()) if (queue.length > 0) {\n\t\t\tconst job = this.getNextJobWithMetDependencies(queue);\n\t\t\tif (!job) continue;\n\t\t\tif (this.isDocumentExecuting(job.documentId)) continue;\n\t\t\tif (!predicate({\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch\n\t\t\t})) continue;\n\t\t\tconst jobIdx = queue.indexOf(job);\n\t\t\tqueue.splice(jobIdx, 1);\n\t\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\t\tthis.markJobExecuting(job);\n\t\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\t\tconst handle = new JobExecutionHandle(job, JobQueueState.READY, {\n\t\t\t\tonStart: () => {},\n\t\t\t\tonComplete: () => {\n\t\t\t\t\tthis.completeJob(job.id);\n\t\t\t\t},\n\t\t\t\tonFail: (error) => {\n\t\t\t\t\tthis.failJob(job.id, error);\n\t\t\t\t},\n\t\t\t\tonDefer: () => {\n\t\t\t\t\tthis.deferJob(job.id);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn Promise.resolve(handle);\n\t\t}\n\t\treturn Promise.resolve(null);\n\t}\n\tsize(documentId, scope, branch) {\n\t\tconst queueKey = this.createQueueKey(documentId, scope, branch);\n\t\tconst queue = this.queues.get(queueKey);\n\t\treturn Promise.resolve(queue ? queue.length : 0);\n\t}\n\ttotalSize() {\n\t\tlet total = 0;\n\t\tfor (const queue of this.queues.values()) total += queue.length;\n\t\treturn Promise.resolve(total);\n\t}\n\tremove(jobId) {\n\t\tconst queueKey = this.jobIdToQueueKey.get(jobId);\n\t\tif (!queueKey) return Promise.resolve(false);\n\t\tconst queue = this.queues.get(queueKey);\n\t\tif (!queue) {\n\t\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\t\tthis.jobIndex.delete(jobId);\n\t\t\treturn Promise.resolve(false);\n\t\t}\n\t\tconst jobIdx = queue.findIndex((job) => job.id === jobId);\n\t\tif (jobIdx === -1) {\n\t\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\t\tthis.jobIndex.delete(jobId);\n\t\t\treturn Promise.resolve(false);\n\t\t}\n\t\tqueue.splice(jobIdx, 1);\n\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\tthis.jobIndex.delete(jobId);\n\t\tif (queue.length === 0) this.queues.delete(queueKey);\n\t\treturn Promise.resolve(true);\n\t}\n\tclear(documentId, scope, branch) {\n\t\tconst queueKey = this.createQueueKey(documentId, scope, branch);\n\t\tconst queue = this.queues.get(queueKey);\n\t\tif (queue) {\n\t\t\tfor (const job of queue) {\n\t\t\t\tthis.jobIdToQueueKey.delete(job.id);\n\t\t\t\tthis.jobIndex.delete(job.id);\n\t\t\t}\n\t\t\tthis.queues.delete(queueKey);\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\tclearAll() {\n\t\tthis.jobIdToQueueKey.clear();\n\t\tthis.jobIndex.clear();\n\t\tthis.completedJobs.clear();\n\t\tthis.queues.clear();\n\t\treturn Promise.resolve();\n\t}\n\thasJobs() {\n\t\treturn Promise.resolve(this.queues.size > 0 && Array.from(this.queues.values()).some((q) => q.length > 0));\n\t}\n\tasync completeJob(jobId) {\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tthis.completedJobs.add(jobId);\n\t\tthis.jobIndex.delete(jobId);\n\t\tawait this.remove(jobId);\n\t\tthis.checkDrained();\n\t}\n\tasync failJob(jobId, error) {\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tconst job = this.jobIndex.get(jobId);\n\t\tif (job) {\n\t\t\tjob.lastError = error;\n\t\t\tif (error) job.errorHistory.push(error);\n\t\t}\n\t\tthis.jobIndex.delete(jobId);\n\t\tthis.completedJobs.add(jobId);\n\t\tawait this.remove(jobId);\n\t\tconst emittedError = new Error(error?.message ?? \"Job failed\");\n\t\tif (error?.name) emittedError.name = error.name;\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_FAILED, {\n\t\t\tjobId,\n\t\t\terror: emittedError,\n\t\t\tjob\n\t\t}).catch(() => {});\n\t\tthis.checkDrained();\n\t}\n\tdeferJob(jobId) {\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tthis.jobIndex.delete(jobId);\n\t}\n\tasync retryJob(jobId, error, accounting = RetryAccounting.CountAgainstLimit) {\n\t\tconst job = this.jobIndex.get(jobId);\n\t\tif (!job) return;\n\t\tjob.lastError = error;\n\t\tconst documentId = this.jobIdToDocId.get(jobId);\n\t\tif (documentId) this.markJobComplete(jobId, documentId);\n\t\tthis.jobIndex.delete(jobId);\n\t\tthis.jobIdToQueueKey.delete(jobId);\n\t\tif (error) job.errorHistory.push(error);\n\t\tconst retryCount = job.retryCount || 0;\n\t\tconst updatedJob = {\n\t\t\t...job,\n\t\t\tretryCount: accounting === RetryAccounting.CountAgainstLimit ? retryCount + 1 : retryCount,\n\t\t\tlastError: error\n\t\t};\n\t\tawait this.enqueue(updatedJob);\n\t}\n\t/**\n\t* Check if the queue is drained and call the callback if it is\n\t*/\n\tcheckDrained() {\n\t\tif (this.isDrained && this.onDrainedCallback) {\n\t\t\tconst callback = this.onDrainedCallback;\n\t\t\tthis.onDrainedCallback = void 0;\n\t\t\tcallback();\n\t\t}\n\t}\n\t/**\n\t* Returns true if and only if all jobs have been resolved.\n\t*/\n\tget isDrained() {\n\t\tconst hasPendingJobs = this.queues.size > 0 && Array.from(this.queues.values()).some((q) => q.length > 0);\n\t\tconst hasExecutingJobs = this.docIdToJobId.size > 0 && Array.from(this.docIdToJobId.values()).some((set) => set.size > 0);\n\t\treturn !hasPendingJobs && !hasExecutingJobs;\n\t}\n\t/**\n\t* Blocks the queue from accepting new jobs.\n\t* @param onDrained - Optional callback to call when the queue is drained\n\t*/\n\tblock(onDrained) {\n\t\tthis.isBlocked = true;\n\t\tthis.onDrainedCallback = onDrained;\n\t\tthis.checkDrained();\n\t}\n\t/**\n\t* Unblocks the queue from accepting new jobs.\n\t*/\n\tunblock() {\n\t\tthis.isBlocked = false;\n\t\tthis.onDrainedCallback = void 0;\n\t}\n\t/**\n\t* Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.\n\t*/\n\tpause() {\n\t\tthis.isPausedFlag = true;\n\t}\n\t/**\n\t* Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.\n\t*/\n\tasync resume() {\n\t\tthis.isPausedFlag = false;\n\t\tfor (const [, queue] of this.queues.entries()) if (queue.length > 0) {\n\t\t\tconst job = queue[0];\n\t\t\tawait this.eventBus.emit(QueueEventTypes.JOB_AVAILABLE, {\n\t\t\t\tdocumentId: job.documentId,\n\t\t\t\tscope: job.scope,\n\t\t\t\tbranch: job.branch,\n\t\t\t\tjobId: job.id\n\t\t\t});\n\t\t}\n\t}\n\t/**\n\t* Returns whether job dequeuing is paused.\n\t*/\n\tget paused() {\n\t\treturn this.isPausedFlag;\n\t}\n\t/**\n\t* Returns all pending jobs across all queues.\n\t*/\n\tgetPendingJobs() {\n\t\tconst jobs = [];\n\t\tfor (const queue of this.queues.values()) jobs.push(...queue);\n\t\treturn jobs;\n\t}\n\t/**\n\t* Returns a map of document IDs to sets of executing job IDs.\n\t*/\n\tgetExecutingJobIds() {\n\t\treturn new Map(Array.from(this.docIdToJobId.entries()).map(([k, v]) => [k, new Set(v)]));\n\t}\n\t/**\n\t* Returns a job by ID from the job index.\n\t*/\n\tgetJob(jobId) {\n\t\treturn this.jobIndex.get(jobId);\n\t}\n};\n//#endregion\n//#region src/projection/read-model-kinds.ts\n/**\n* Every {@link BuiltInReadModelKind}, at runtime. Derived from a total\n* record so adding a kind to the union without adding it here is a compile\n* error: under projection sharding a kind missing from both `preReadyKinds`\n* and `postReadyKinds` is indexed by nobody — the host's own copies never\n* index an operation — so a gap here reads as silently stale data.\n*/\nconst BUILT_IN_READ_MODEL_KINDS = Object.keys({\n\t\"document-view\": true,\n\t\"document-indexer\": true\n});\n//#endregion\n//#region src/core/model-sources.ts\nfunction modelSourceKey(module) {\n\treturn `${module.documentModel.global.id}@${module.version ?? 1}`;\n}\nfunction isDocumentModelModule(value) {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = value;\n\treturn typeof candidate.reducer === \"function\" && typeof candidate.documentModel?.global?.id === \"string\";\n}\n/**\n* Resolves every source to live modules by importing file/package sources\n* host-side and scanning their exports, so the host registry and the worker\n* manifest are derived from one list and cannot diverge.\n*/\nasync function resolveModelSources(sources) {\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const source of sources) {\n\t\tif (isDocumentModelModule(source)) {\n\t\t\taddEntry(resolved, {\n\t\t\t\tmodule: source,\n\t\t\t\tspec: null\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of await resolveImportableSource(source)) addEntry(resolved, entry);\n\t}\n\tconst modules = [];\n\tconst manifest = [];\n\tconst moduleOnlyKeys = [];\n\tfor (const [key, entry] of resolved) {\n\t\tmodules.push(entry.module);\n\t\tif (entry.spec) manifest.push({\n\t\t\tdocumentType: entry.module.documentModel.global.id,\n\t\t\tversion: String(entry.module.version ?? 1),\n\t\t\tspec: entry.spec\n\t\t});\n\t\telse moduleOnlyKeys.push(key);\n\t}\n\treturn {\n\t\tmodules,\n\t\tmanifest,\n\t\tmoduleOnlyKeys\n\t};\n}\nfunction addEntry(map, entry) {\n\tconst key = modelSourceKey(entry.module);\n\tconst existing = map.get(key);\n\tif (!existing) {\n\t\tmap.set(key, entry);\n\t\treturn;\n\t}\n\tif (!existing.spec && entry.spec) existing.spec = entry.spec;\n}\nasync function resolveImportableSource(source) {\n\tconst isFile = \"filePath\" in source;\n\tconst specifier = isFile ? new URL(`file://${source.filePath}`).href : source.subpath ? `${source.packageName}/${source.subpath}` : source.packageName;\n\tconst moduleRef = isFile ? { filePath: source.filePath } : { packageName: specifier };\n\tlet moduleNs;\n\ttry {\n\t\tmoduleNs = await import(\n\t\t\t/* @vite-ignore */\n\t\t\tspecifier\n);\n\t} catch (error) {\n\t\tthrow new Error(`Failed to import document-model source \"${describeSource(source)}\"`, { cause: error });\n\t}\n\tif (source.exportName !== void 0) {\n\t\tconst value = moduleNs[source.exportName];\n\t\tif (!isDocumentModelModule(value)) throw new Error(`Export \"${source.exportName}\" of document-model source \"${describeSource(source)}\" is not a DocumentModelModule`);\n\t\treturn [{\n\t\t\tmodule: value,\n\t\t\tspec: { module: {\n\t\t\t\t...moduleRef,\n\t\t\t\texportName: source.exportName\n\t\t\t} }\n\t\t}];\n\t}\n\tconst entries = [];\n\tfor (const [exportName, value] of Object.entries(moduleNs)) if (isDocumentModelModule(value)) entries.push({\n\t\tmodule: value,\n\t\tspec: { module: {\n\t\t\t...moduleRef,\n\t\t\texportName\n\t\t} }\n\t});\n\tif (entries.length === 0) throw new Error(`Document-model source \"${describeSource(source)}\" has no DocumentModelModule exports`);\n\treturn entries;\n}\nfunction describeSource(source) {\n\treturn \"filePath\" in source ? source.filePath : source.subpath ? `${source.packageName}/${source.subpath}` : source.packageName;\n}\n//#endregion\n//#region src/registry/document-model-resolver.ts\n/**\n* Encapsulates the logic for resolving document model modules on demand.\n* Shared between the queue (CREATE_DOCUMENT gate) and the executor manager\n* (post-failure recovery) so that both paths use the same deduplication\n* and failure-caching state.\n*/\nvar DocumentModelResolver = class {\n\tloadingModels = /* @__PURE__ */ new Map();\n\tfailedModelTypes = /* @__PURE__ */ new Set();\n\tbroadcastHook = null;\n\tmodelLoadedHook = null;\n\tlogger = childLogger([\"reactor\", \"document-model-resolver\"]);\n\tconstructor(registry, loader) {\n\t\tthis.registry = registry;\n\t\tthis.loader = loader;\n\t}\n\t/**\n\t* Install a post-success hook called after the resolver registers a\n\t* newly loaded model. ReactorBuilder uses this to wire the worker-pool\n\t* `load-model` broadcast without touching the resolver's constructor.\n\t*/\n\tsetBroadcastHook(hook) {\n\t\tthis.broadcastHook = hook;\n\t}\n\t/**\n\t* Post-success hook called with the document type after a model loads, so\n\t* peers (tabs) can load the same type via the event bus.\n\t*/\n\tsetModelLoadedHook(hook) {\n\t\tthis.modelLoadedHook = hook;\n\t}\n\tasync ensureModelLoaded(documentType) {\n\t\ttry {\n\t\t\tthis.registry.getModule(documentType);\n\t\t\treturn;\n\t\t} catch (error) {\n\t\t\tif (!ModuleNotFoundError.isError(error)) throw error;\n\t\t}\n\t\tif (this.failedModelTypes.has(documentType)) throw new Error(`Document model type previously failed to load: ${documentType}`);\n\t\tconst existing = this.loadingModels.get(documentType);\n\t\tif (existing) return existing;\n\t\tconst loadPromise = (async () => {\n\t\t\ttry {\n\t\t\t\tawait this.loadRegisterAndBroadcast(documentType);\n\t\t\t} catch (error) {\n\t\t\t\tthis.failedModelTypes.add(documentType);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tthis.loadingModels.delete(documentType);\n\t\t\t}\n\t\t\tawait this.notifyPeersModelLoaded(documentType);\n\t\t})();\n\t\tthis.loadingModels.set(documentType, loadPromise);\n\t\treturn loadPromise;\n\t}\n\tasync loadRegisterAndBroadcast(documentType) {\n\t\tconst resolved = await resolveModelSources([await this.loader.load(documentType)]);\n\t\tif (!resolved.modules.some((module) => module.documentModel.global.id === documentType)) throw new Error(`Loader source resolved no module for document type: ${documentType}`);\n\t\tconst results = this.registry.registerModules(...resolved.modules);\n\t\tfor (const result of results) if (result.status === \"error\" && !DuplicateModuleError.isError(result.error)) throw result.error;\n\t\tif (this.broadcastHook) for (const entry of resolved.manifest) await this.broadcastHook(entry);\n\t}\n\tasync notifyPeersModelLoaded(documentType) {\n\t\tif (!this.modelLoadedHook) return;\n\t\ttry {\n\t\t\tawait this.modelLoadedHook(documentType);\n\t\t} catch (error) {\n\t\t\tthis.logger.warn(`MODEL_LOADED hook failed: ${documentType}`, error);\n\t\t}\n\t}\n};\n/**\n* No-op resolver used when no document model loader is configured.\n* Checks the registry for the model and returns if found; throws if not.\n* Since there is no loader, missing models cannot be recovered.\n*/\nvar NullDocumentModelResolver = class {\n\tconstructor(registry) {\n\t\tthis.registry = registry;\n\t}\n\tensureModelLoaded(documentType) {\n\t\tif (this.registry) try {\n\t\t\tthis.registry.getModule(documentType);\n\t\t\treturn Promise.resolve();\n\t\t} catch {}\n\t\treturn Promise.reject(new ModuleNotFoundError(documentType));\n\t}\n};\n//#endregion\n//#region src/subs/default-error-handler.ts\n/**\n* Default error handler that re-throws subscription errors.\n* This ensures that errors are not silently swallowed.\n*/\nvar DefaultSubscriptionErrorHandler = class {\n\thandleError(error, context) {\n\t\tconst errorMessage = `Subscription error in ${context.eventType} (${context.subscriptionId})`;\n\t\tif (error instanceof Error) {\n\t\t\tconst enhancedError = /* @__PURE__ */ new Error(`${errorMessage}: ${error.message}`);\n\t\t\tenhancedError.cause = error;\n\t\t\tenhancedError.stack = error.stack;\n\t\t\tthrow enhancedError;\n\t\t} else throw new Error(`${errorMessage}: ${String(error)}`);\n\t}\n};\n//#endregion\n//#region src/subs/react-subscription-manager.ts\nvar ReactorSubscriptionManager = class {\n\tcreatedSubscriptions = /* @__PURE__ */ new Map();\n\tdeletedSubscriptions = /* @__PURE__ */ new Map();\n\tupdatedSubscriptions = /* @__PURE__ */ new Map();\n\trelationshipSubscriptions = /* @__PURE__ */ new Map();\n\tsubscriptionCounter = 0;\n\terrorHandler;\n\tconstructor(errorHandler) {\n\t\tthis.errorHandler = errorHandler;\n\t}\n\tonDocumentCreated(callback, search) {\n\t\tconst id = `created-${++this.subscriptionCounter}`;\n\t\tthis.createdSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch\n\t\t});\n\t\treturn () => {\n\t\t\tthis.createdSubscriptions.delete(id);\n\t\t};\n\t}\n\tonDocumentDeleted(callback, search) {\n\t\tconst id = `deleted-${++this.subscriptionCounter}`;\n\t\tthis.deletedSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch\n\t\t});\n\t\treturn () => {\n\t\t\tthis.deletedSubscriptions.delete(id);\n\t\t};\n\t}\n\tonDocumentStateUpdated(callback, search, view) {\n\t\tconst id = `updated-${++this.subscriptionCounter}`;\n\t\tthis.updatedSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch,\n\t\t\tview\n\t\t});\n\t\treturn () => {\n\t\t\tthis.updatedSubscriptions.delete(id);\n\t\t};\n\t}\n\tonRelationshipChanged(callback, search) {\n\t\tconst id = `relationship-${++this.subscriptionCounter}`;\n\t\tthis.relationshipSubscriptions.set(id, {\n\t\t\tid,\n\t\t\tcallback,\n\t\t\tsearch\n\t\t});\n\t\treturn () => {\n\t\t\tthis.relationshipSubscriptions.delete(id);\n\t\t};\n\t}\n\t/**\n\t* Notify subscribers about created documents\n\t*/\n\tnotifyDocumentsCreated(documentIds, documentTypes, parentIds) {\n\t\tconst result = {\n\t\t\tresults: documentIds,\n\t\t\toptions: {\n\t\t\t\tcursor: \"\",\n\t\t\t\tlimit: documentIds.length\n\t\t\t}\n\t\t};\n\t\tfor (const subscription of this.createdSubscriptions.values()) {\n\t\t\tconst filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);\n\t\t\tif (filteredIds.length > 0) try {\n\t\t\t\tsubscription.callback({\n\t\t\t\t\t...result,\n\t\t\t\t\tresults: filteredIds\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\t\teventType: \"created\",\n\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\teventData: filteredIds\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Notify subscribers about deleted documents\n\t*/\n\tnotifyDocumentsDeleted(documentIds, documentTypes, parentIds) {\n\t\tfor (const subscription of this.deletedSubscriptions.values()) {\n\t\t\tconst filteredIds = this.filterDocumentIds(documentIds, subscription.search, documentTypes, parentIds);\n\t\t\tif (filteredIds.length > 0) try {\n\t\t\t\tsubscription.callback(filteredIds);\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\t\teventType: \"deleted\",\n\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\teventData: filteredIds\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Notify subscribers about updated documents\n\t*/\n\tnotifyDocumentsUpdated(documents) {\n\t\tconst result = {\n\t\t\tresults: documents,\n\t\t\toptions: {\n\t\t\t\tcursor: \"\",\n\t\t\t\tlimit: documents.length\n\t\t\t}\n\t\t};\n\t\tfor (const subscription of this.updatedSubscriptions.values()) {\n\t\t\tconst filteredDocs = this.filterDocuments(documents, subscription.search);\n\t\t\tif (filteredDocs.length > 0) try {\n\t\t\t\tsubscription.callback({\n\t\t\t\t\t...result,\n\t\t\t\t\tresults: filteredDocs\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\t\teventType: \"updated\",\n\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\teventData: filteredDocs\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Notify subscribers about relationship changes\n\t*/\n\tnotifyRelationshipChanged(parentId, childId, changeType, childType) {\n\t\tfor (const subscription of this.relationshipSubscriptions.values()) if (this.matchesRelationshipFilter(parentId, childId, childType, subscription.search)) try {\n\t\t\tsubscription.callback(parentId, childId, changeType);\n\t\t} catch (error) {\n\t\t\tthis.errorHandler.handleError(error, {\n\t\t\t\teventType: \"relationshipChanged\",\n\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\teventData: {\n\t\t\t\t\tparentId,\n\t\t\t\t\tchildId,\n\t\t\t\t\tchangeType\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\t/**\n\t* Clear all subscriptions\n\t*/\n\tclearAll() {\n\t\tthis.createdSubscriptions.clear();\n\t\tthis.deletedSubscriptions.clear();\n\t\tthis.updatedSubscriptions.clear();\n\t\tthis.relationshipSubscriptions.clear();\n\t}\n\tfilterDocumentIds(documentIds, search, documentTypes, parentIds) {\n\t\tif (!search) return documentIds;\n\t\treturn documentIds.filter((id) => {\n\t\t\tif (search.ids && !search.ids.includes(id)) return false;\n\t\t\tif (search.type && documentTypes) {\n\t\t\t\tif (documentTypes.get(id) !== search.type) return false;\n\t\t\t}\n\t\t\tif (search.parentId && parentIds) {\n\t\t\t\tif (parentIds.get(id) !== search.parentId) return false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t}\n\tfilterDocuments(documents, search) {\n\t\tif (!search) return documents;\n\t\treturn documents.filter((doc) => {\n\t\t\tif (search.ids && !search.ids.includes(doc.header.id)) return false;\n\t\t\tif (search.type && doc.header.documentType !== search.type) return false;\n\t\t\tif (search.slugs && !search.slugs.includes(doc.header.slug)) return false;\n\t\t\treturn true;\n\t\t});\n\t}\n\tmatchesRelationshipFilter(parentId, childId, childType, search) {\n\t\tif (!search) return true;\n\t\tif (search.parentId && parentId !== search.parentId) return false;\n\t\tif (search.ids && !search.ids.includes(childId)) return false;\n\t\tif (search.type && childType && childType !== search.type) return false;\n\t\treturn true;\n\t}\n};\n//#endregion\n//#region src/subs/subscription-notification-read-model.ts\n/**\n* A read model that notifies the subscription manager when operations are processed.\n* This bridges the gap between operation processing and subscription callbacks.\n*\n* Must be processed AFTER other read models have completed and AFTER READ_READY\n* is emitted, so that reactor.get() returns fresh data when callbacks fire.\n*/\nvar SubscriptionNotificationReadModel = class {\n\tname = \"subscription-notification\";\n\tconstructor(subscriptionManager, documentView) {\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\tthis.documentView = documentView;\n\t}\n\tasync indexOperations(operations) {\n\t\tif (operations.length === 0) return;\n\t\tconst created = [];\n\t\tconst deleted = [];\n\t\tconst updatedIds = /* @__PURE__ */ new Set();\n\t\tconst documentTypes = /* @__PURE__ */ new Map();\n\t\tconst parentIds = /* @__PURE__ */ new Map();\n\t\tfor (const item of operations) {\n\t\t\tconst { operation, context } = item;\n\t\t\tconst actionType = operation.action.type;\n\t\t\tdocumentTypes.set(context.documentId, context.documentType);\n\t\t\tif (actionType === \"CREATE_DOCUMENT\") created.push(context.documentId);\n\t\t\telse if (actionType === \"DELETE_DOCUMENT\") {\n\t\t\t\tconst deletedId = operation.action.input.documentId ?? context.documentId;\n\t\t\t\tdeleted.push(deletedId);\n\t\t\t} else if (actionType === \"ADD_RELATIONSHIP\") {\n\t\t\t\tconst input = operation.action.input;\n\t\t\t\tthis.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, RelationshipChangeType.Added, input.childType);\n\t\t\t} else if (actionType === \"REMOVE_RELATIONSHIP\") {\n\t\t\t\tconst input = operation.action.input;\n\t\t\t\tthis.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, RelationshipChangeType.Removed, input.childType);\n\t\t\t} else if (!created.includes(context.documentId)) updatedIds.add(context.documentId);\n\t\t}\n\t\tif (created.length > 0) this.subscriptionManager.notifyDocumentsCreated(created, documentTypes, parentIds);\n\t\tif (deleted.length > 0) this.subscriptionManager.notifyDocumentsDeleted(deleted, documentTypes, parentIds);\n\t\tif (updatedIds.size > 0 && this.documentView) {\n\t\t\tconst documents = await Promise.all(Array.from(updatedIds).map((id) => this.documentView.get(id)));\n\t\t\tthis.subscriptionManager.notifyDocumentsUpdated(documents);\n\t\t}\n\t}\n};\n//#endregion\n//#region src/core/group-reevaluation-trigger.ts\n/**\n* Watches committed writes for group membership changes and enqueues a\n* re-evaluation job for every document whose auth history references the\n* changed group, found through the reverse direction of the group-reference\n* relation. Each affected document is re-judged in its own job, so the work\n* runs under that document's execution slot rather than the group's.\n*\n* The job carries the earliest changed membership timestamp; the executor\n* skips the pass when everything the document holds sorts before it, which\n* keeps the common case (a membership write later than all history) free.\n*/\nvar GroupReevaluationTrigger = class {\n\tunsubscribe;\n\tconstructor(logger, eventBus, queue, operationIndex) {\n\t\tthis.logger = logger;\n\t\tthis.eventBus = eventBus;\n\t\tthis.queue = queue;\n\t\tthis.operationIndex = operationIndex;\n\t}\n\tstartup() {\n\t\tthis.unsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, async (_type, event) => this.onWriteReady(event));\n\t}\n\tshutdown() {\n\t\tthis.unsubscribe?.();\n\t\tthis.unsubscribe = void 0;\n\t}\n\tasync onWriteReady(event) {\n\t\tconst changed = /* @__PURE__ */ new Map();\n\t\tfor (const { operation, context } of event.operations) {\n\t\t\tif (context.documentType !== groupDocumentType || context.scope !== \"global\" || !groupMembershipActionTypes.includes(operation.action.type)) continue;\n\t\t\tconst existing = changed.get(context.documentId);\n\t\t\tif (existing === void 0 || Date.parse(operation.timestampUtcMs) < Date.parse(existing)) changed.set(context.documentId, operation.timestampUtcMs);\n\t\t}\n\t\tif (changed.size === 0) return;\n\t\tconst affected = /* @__PURE__ */ new Map();\n\t\tfor (const [groupId, timestamp] of changed) {\n\t\t\tlet referencers;\n\t\t\ttry {\n\t\t\t\treferencers = await this.operationIndex.getGroupReferencers(groupId);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Failed to resolve referencers of group @groupId: @error\", groupId, error);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const documentId of referencers) {\n\t\t\t\tconst existing = affected.get(documentId);\n\t\t\t\tif (existing === void 0 || Date.parse(timestamp) < Date.parse(existing)) affected.set(documentId, timestamp);\n\t\t\t}\n\t\t}\n\t\tfor (const [documentId, timestamp] of affected) {\n\t\t\tconst jobId = v4();\n\t\t\tconst job = {\n\t\t\t\tid: jobId,\n\t\t\t\tkind: \"reevaluation\",\n\t\t\t\tdocumentId,\n\t\t\t\tscope: \"global\",\n\t\t\t\tbranch: \"main\",\n\t\t\t\tactions: [],\n\t\t\t\toperations: [],\n\t\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\t\tqueueHint: [],\n\t\t\t\tmaxRetries: 3,\n\t\t\t\terrorHistory: [],\n\t\t\t\tmeta: {\n\t\t\t\t\t...buildSingleJobMeta(jobId),\n\t\t\t\t\ttriggerTimestampUtcMs: timestamp\n\t\t\t\t}\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Failed to enqueue re-evaluation of @documentId: @error\", documentId, error);\n\t\t\t}\n\t\t}\n\t}\n};\n//#endregion\n//#region src/sync/types.ts\nlet ChannelScheme = /* @__PURE__ */ function(ChannelScheme) {\n\tChannelScheme[\"CONNECT\"] = \"connect\";\n\tChannelScheme[\"SWITCHBOARD\"] = \"switchboard\";\n\treturn ChannelScheme;\n}({});\n/**\n* Controls how a remote drives its polling schedule.\n* - `Auto` (default): the channel runs the configured interval timer in the background.\n* - `Manual`: the channel registers and connects but never ticks on its own.\n* Callers must invoke ISyncManager.triggerPull(name) to fetch.\n*/\nlet PollBehavior = /* @__PURE__ */ function(PollBehavior) {\n\tPollBehavior[\"Auto\"] = \"auto\";\n\tPollBehavior[\"Manual\"] = \"manual\";\n\treturn PollBehavior;\n}({});\nlet SyncOperationStatus = /* @__PURE__ */ function(SyncOperationStatus) {\n\tSyncOperationStatus[SyncOperationStatus[\"Unknown\"] = -1] = \"Unknown\";\n\tSyncOperationStatus[SyncOperationStatus[\"TransportPending\"] = 0] = \"TransportPending\";\n\tSyncOperationStatus[SyncOperationStatus[\"ExecutionPending\"] = 1] = \"ExecutionPending\";\n\tSyncOperationStatus[SyncOperationStatus[\"Applied\"] = 2] = \"Applied\";\n\tSyncOperationStatus[SyncOperationStatus[\"Error\"] = 3] = \"Error\";\n\treturn SyncOperationStatus;\n}({});\nlet ChannelErrorSource = /* @__PURE__ */ function(ChannelErrorSource) {\n\tChannelErrorSource[\"None\"] = \"none\";\n\tChannelErrorSource[\"Channel\"] = \"channel\";\n\tChannelErrorSource[\"Inbox\"] = \"inbox\";\n\tChannelErrorSource[\"Outbox\"] = \"outbox\";\n\treturn ChannelErrorSource;\n}({});\n/**\n* Event types for sync lifecycle events.\n* These events track the sync progress of a job's operations to remotes.\n* Uses a separate namespace (20000 range) from ReactorEventTypes (10000 range).\n*/\nconst SyncEventTypes = {\n\tSYNC_PENDING: 20001,\n\tSYNC_SUCCEEDED: 20002,\n\tSYNC_FAILED: 20003,\n\tDEAD_LETTER_ADDED: 20004,\n\tCONNECTION_STATE_CHANGED: 20005\n};\n//#endregion\n//#region src/sync/mailbox.ts\nvar MailboxAggregateError = class extends Error {\n\terrors;\n\tconstructor(errors) {\n\t\tconst messages = errors.map((e) => e.message).join(\"; \");\n\t\tsuper(`Mailbox callback failed with ${errors.length} error(s): ${messages}`);\n\t\tthis.name = \"MailboxAggregateError\";\n\t\tthis.errors = errors;\n\t}\n};\nvar Mailbox = class {\n\titemsMap = /* @__PURE__ */ new Map();\n\taddedCallbacks = [];\n\tremovedCallbacks = [];\n\tpaused = false;\n\taddedBuffer = [];\n\tremovedBuffer = [];\n\t_ack = 0;\n\t_latestOrdinal = 0;\n\tinit(ackOrdinal) {\n\t\tthis._ack = this._latestOrdinal = ackOrdinal;\n\t}\n\tadvanceOrdinal(ordinal) {\n\t\tthis._latestOrdinal = Math.max(this._latestOrdinal, ordinal);\n\t}\n\tget items() {\n\t\treturn Array.from(this.itemsMap.values());\n\t}\n\tget ackOrdinal() {\n\t\treturn this._ack;\n\t}\n\tget latestOrdinal() {\n\t\treturn this._latestOrdinal;\n\t}\n\tget(id) {\n\t\treturn this.itemsMap.get(id);\n\t}\n\tadd(...items) {\n\t\tfor (const item of items) {\n\t\t\tthis.itemsMap.set(item.id, item);\n\t\t\tfor (const op of item.operations) this._latestOrdinal = Math.max(this._latestOrdinal, op.context.ordinal);\n\t\t\titem.on((syncOp, _, next) => {\n\t\t\t\tif (next === SyncOperationStatus.Applied) for (const op of syncOp.operations) this._ack = Math.max(this._ack, op.context.ordinal);\n\t\t\t});\n\t\t}\n\t\tif (this.paused) {\n\t\t\tthis.addedBuffer.push(...items);\n\t\t\treturn;\n\t\t}\n\t\tconst callbacks = [...this.addedCallbacks];\n\t\tconst errors = [];\n\t\tfor (const callback of callbacks) try {\n\t\t\tcallback(items);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t}\n\tremove(...items) {\n\t\tfor (const item of items) this.itemsMap.delete(item.id);\n\t\tif (this.paused) {\n\t\t\tthis.removedBuffer.push(...items);\n\t\t\treturn;\n\t\t}\n\t\tconst callbacks = [...this.removedCallbacks];\n\t\tconst errors = [];\n\t\tfor (const callback of callbacks) try {\n\t\t\tcallback(items);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t}\n\tonAdded(callback) {\n\t\tthis.addedCallbacks.push(callback);\n\t}\n\tonRemoved(callback) {\n\t\tthis.removedCallbacks.push(callback);\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t}\n\tresume() {\n\t\tthis.paused = false;\n\t\tthis.flush();\n\t}\n\tflush() {\n\t\tif (this.addedBuffer.length > 0) {\n\t\t\tconst items = this.addedBuffer.splice(0);\n\t\t\tconst callbacks = [...this.addedCallbacks];\n\t\t\tconst errors = [];\n\t\t\tfor (const callback of callbacks) try {\n\t\t\t\tcallback(items);\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t\t}\n\t\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t\t}\n\t\tif (this.removedBuffer.length > 0) {\n\t\t\tconst items = this.removedBuffer.splice(0);\n\t\t\tconst callbacks = [...this.removedCallbacks];\n\t\t\tconst errors = [];\n\t\t\tfor (const callback of callbacks) try {\n\t\t\t\tcallback(items);\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t\t}\n\t\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t\t}\n\t}\n\tisPaused() {\n\t\treturn this.paused;\n\t}\n};\n//#endregion\n//#region src/sync/buffered-mailbox.ts\nvar BufferedMailbox = class {\n\titemsMap = /* @__PURE__ */ new Map();\n\taddedCallbacks = [];\n\tremovedCallbacks = [];\n\taddedBuffer = [];\n\tremovedBuffer = [];\n\taddedTimer = null;\n\tremovedTimer = null;\n\tmilliseconds;\n\tmaxQueued;\n\tpaused = false;\n\t_ack = 0;\n\t_latestOrdinal = 0;\n\tconstructor(milliseconds, maxQueued) {\n\t\tthis.milliseconds = milliseconds;\n\t\tthis.maxQueued = maxQueued;\n\t}\n\tinit(ackOrdinal) {\n\t\tthis._ack = this._latestOrdinal = ackOrdinal;\n\t}\n\tadvanceOrdinal(ordinal) {\n\t\tthis._latestOrdinal = Math.max(this._latestOrdinal, ordinal);\n\t}\n\tget items() {\n\t\treturn Array.from(this.itemsMap.values());\n\t}\n\tget ackOrdinal() {\n\t\treturn this._ack;\n\t}\n\tget latestOrdinal() {\n\t\treturn this._latestOrdinal;\n\t}\n\tget(id) {\n\t\treturn this.itemsMap.get(id);\n\t}\n\tadd(...items) {\n\t\tfor (const item of items) {\n\t\t\tthis.itemsMap.set(item.id, item);\n\t\t\tfor (const op of item.operations) this._latestOrdinal = Math.max(this._latestOrdinal, op.context.ordinal);\n\t\t\titem.on((syncOp, _, next) => {\n\t\t\t\tif (next === SyncOperationStatus.Applied) for (const op of syncOp.operations) this._ack = Math.max(this._ack, op.context.ordinal);\n\t\t\t});\n\t\t}\n\t\tthis.addedBuffer.push(...items);\n\t\tif (this.paused) return;\n\t\tif (this.addedBuffer.length >= this.maxQueued) this.flushAdded();\n\t\telse this.scheduleAddedFlush();\n\t}\n\tremove(...items) {\n\t\tfor (const item of items) this.itemsMap.delete(item.id);\n\t\tthis.removedBuffer.push(...items);\n\t\tif (this.paused) return;\n\t\tif (this.removedBuffer.length >= this.maxQueued) this.flushRemoved();\n\t\telse this.scheduleRemovedFlush();\n\t}\n\tonAdded(callback) {\n\t\tthis.addedCallbacks.push(callback);\n\t}\n\tonRemoved(callback) {\n\t\tthis.removedCallbacks.push(callback);\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t\tif (this.addedTimer !== null) {\n\t\t\tclearTimeout(this.addedTimer);\n\t\t\tthis.addedTimer = null;\n\t\t}\n\t\tif (this.removedTimer !== null) {\n\t\t\tclearTimeout(this.removedTimer);\n\t\t\tthis.removedTimer = null;\n\t\t}\n\t}\n\tresume() {\n\t\tthis.paused = false;\n\t\tif (this.addedBuffer.length > 0) this.scheduleAddedFlush();\n\t\tif (this.removedBuffer.length > 0) this.scheduleRemovedFlush();\n\t}\n\tisPaused() {\n\t\treturn this.paused;\n\t}\n\tflush() {\n\t\tthis.flushAdded();\n\t\tthis.flushRemoved();\n\t}\n\tscheduleAddedFlush() {\n\t\tif (this.addedTimer !== null) clearTimeout(this.addedTimer);\n\t\tthis.addedTimer = setTimeout(() => {\n\t\t\tthis.flushAdded();\n\t\t}, this.milliseconds);\n\t}\n\tscheduleRemovedFlush() {\n\t\tif (this.removedTimer !== null) clearTimeout(this.removedTimer);\n\t\tthis.removedTimer = setTimeout(() => {\n\t\t\tthis.flushRemoved();\n\t\t}, this.milliseconds);\n\t}\n\tflushAdded() {\n\t\tif (this.addedTimer !== null) {\n\t\t\tclearTimeout(this.addedTimer);\n\t\t\tthis.addedTimer = null;\n\t\t}\n\t\tconst items = this.addedBuffer;\n\t\tthis.addedBuffer = [];\n\t\tif (items.length > 0) this.invokeCallbacks(this.addedCallbacks, items);\n\t}\n\tflushRemoved() {\n\t\tif (this.removedTimer !== null) {\n\t\t\tclearTimeout(this.removedTimer);\n\t\t\tthis.removedTimer = null;\n\t\t}\n\t\tconst items = this.removedBuffer;\n\t\tthis.removedBuffer = [];\n\t\tif (items.length > 0) this.invokeCallbacks(this.removedCallbacks, items);\n\t}\n\tinvokeCallbacks(callbacks, items) {\n\t\tconst callbacksCopy = [...callbacks];\n\t\tconst errors = [];\n\t\tfor (const callback of callbacksCopy) try {\n\t\t\tcallback(items);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new MailboxAggregateError(errors);\n\t}\n};\n//#endregion\n//#region src/sync/errors.ts\nvar GraphQLRequestError = class extends Error {\n\tstatusCode;\n\tcategory;\n\t/**\n\t* One entry per error the response carried, in order, holding its\n\t* `extensions.code` - undefined where it declared none. Kept per error rather\n\t* than as a set, because a response that mixes a classified error with an\n\t* unclassified one must not be read as if only the classified one arrived.\n\t*/\n\tcodes;\n\tconstructor(message, category, statusCode, codes = []) {\n\t\tsuper(message);\n\t\tthis.name = \"GraphQLRequestError\";\n\t\tthis.category = category;\n\t\tthis.statusCode = statusCode;\n\t\tthis.codes = codes;\n\t}\n};\n/**\n* Extension codes a remote uses to say a failure is worth polling through.\n*\n* Shared with reactor-api so the server throws what this check reads and the two\n* cannot drift. A `graphql` category error is otherwise permanent: it stops the\n* poll timer, and nothing restarts it, so a code that lands here is the\n* difference between a channel that recovers and one that is dead for the\n* process lifetime.\n*/\nconst RECOVERABLE_GRAPHQL_ERROR_CODES = { malformedStoredOperation: \"MALFORMED_STORED_OPERATION\" };\nconst RECOVERABLE_CODES = new Set(Object.values(RECOVERABLE_GRAPHQL_ERROR_CODES));\n/**\n* True when every error the response carried named a recoverable code.\n*\n* Unanimity is the requirement: one unclassified error alongside a recoverable\n* one means something else also went wrong, and polling through that would be\n* guessing.\n*/\nfunction isRecoverableGraphQLError(error) {\n\treturn error.codes.length > 0 && error.codes.every((code) => code !== void 0 && RECOVERABLE_CODES.has(code));\n}\n/** Auth-rejection message fragments the switchboard emits. Shared with\n* reactor-api so server throws and this client check can't drift. */\nconst DRIVE_AUTH_ERROR_MESSAGES = {\n\tforbidden: \"Forbidden: insufficient permissions\",\n\tauthenticationRequired: \"Forbidden: authentication required\"\n};\n/**\n* A non-GraphQL HTTP failure against a drive endpoint.\n*\n* Drive discovery (`GET <base>/d/:drive`) is REST, not GraphQL, so its\n* failures cannot be a `GraphQLRequestError` without the name lying about\n* what was called. It carries the status for the same reason that one does:\n* `isDriveAuthError` is what decides whether a failure prompts a login, and a\n* bare `Error` tells it nothing.\n*/\nvar DriveRequestError = class extends Error {\n\tstatusCode;\n\tconstructor(message, statusCode) {\n\t\tsuper(message);\n\t\tthis.name = \"DriveRequestError\";\n\t\tthis.statusCode = statusCode;\n\t}\n};\n/** True when the remote rejected the caller as unauthenticated/unauthorized:\n* an HTTP 401/403, or a Forbidden/Unauthorized GraphQL error.\n*\n* 403 and 401 only — NOT 404. The drive info endpoint answers a drive the\n* caller may not read with the same 404 it gives a drive that does not exist,\n* so that an unauthorized caller cannot enumerate drives by probing slugs.\n* That is deliberate, and it costs exactly this: a protected drive is\n* indistinguishable from a typo, and prompting for a login on every 404 would\n* fire on every mistyped URL. See the `WWW-Authenticate` note on the endpoint\n* for the signal that would let a client tell the two apart. */\nfunction isDriveAuthError(error) {\n\tif (error instanceof DriveRequestError) return error.statusCode === 401 || error.statusCode === 403;\n\tif (!(error instanceof GraphQLRequestError)) return false;\n\tif (error.category === \"http\") return error.statusCode === 401 || error.statusCode === 403;\n\tif (error.category === \"graphql\") return Object.values(DRIVE_AUTH_ERROR_MESSAGES).some((m) => error.message.includes(m));\n\treturn false;\n}\nvar PollingChannelError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message);\n\t\tthis.name = \"PollingChannelError\";\n\t}\n};\nvar ChannelError = class extends Error {\n\tsource;\n\terror;\n\t/**\n\t* The classification when something other than the error carries it. Absent\n\t* means derive it from `error.name`; a dead letter mirrored from a peer sets it,\n\t* because only the message crosses the wire.\n\t*/\n\terrorType;\n\tconstructor(source, error, errorType) {\n\t\tsuper(`ChannelError[${source}]: ${error.message}`);\n\t\tthis.name = \"ChannelError\";\n\t\tthis.source = source;\n\t\tthis.error = error;\n\t\tthis.errorType = errorType;\n\t}\n};\n//#endregion\n//#region src/sync/sync-operation.ts\nvar SyncOperationAggregateError = class extends Error {\n\terrors;\n\tconstructor(errors) {\n\t\tconst messages = errors.map((e) => e.message).join(\"; \");\n\t\tsuper(`SyncOperation callback failed with ${errors.length} error(s): ${messages}`);\n\t\tthis.name = \"SyncOperationAggregateError\";\n\t\tthis.errors = errors;\n\t}\n};\nvar SyncOperation = class {\n\tid;\n\tjobId;\n\tjobDependencies;\n\tremoteName;\n\tdocumentId;\n\tscopes;\n\tbranch;\n\toperations;\n\tstatus;\n\terror;\n\tdeliveredCount = 0;\n\temittedCount = 0;\n\tcallbacks = [];\n\tconstructor(id, jobId, jobDependencies, remoteName, documentId, scopes, branch, operations) {\n\t\tthis.id = id;\n\t\tthis.jobId = jobId;\n\t\tthis.jobDependencies = jobDependencies;\n\t\tthis.remoteName = remoteName;\n\t\tthis.documentId = documentId;\n\t\tthis.scopes = scopes;\n\t\tthis.branch = branch;\n\t\tthis.operations = operations;\n\t\tthis.status = SyncOperationStatus.Unknown;\n\t}\n\ton(callback) {\n\t\tthis.callbacks.push(callback);\n\t}\n\tstarted() {\n\t\tthis.transition(SyncOperationStatus.TransportPending);\n\t}\n\ttransported() {\n\t\tthis.transition(SyncOperationStatus.ExecutionPending);\n\t}\n\texecuted() {\n\t\tthis.transition(SyncOperationStatus.Applied);\n\t}\n\tfailed(error) {\n\t\tthis.error = error;\n\t\tthis.transition(SyncOperationStatus.Error);\n\t}\n\ttransition(next) {\n\t\tconst prev = this.status;\n\t\tif (next <= prev) return;\n\t\tthis.status = next;\n\t\tconst errors = [];\n\t\tfor (const callback of this.callbacks) try {\n\t\t\tcallback(this, prev, next);\n\t\t} catch (error) {\n\t\t\terrors.push(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t\tif (errors.length > 0) throw new SyncOperationAggregateError(errors);\n\t}\n};\n//#endregion\n//#region src/sync/utils.ts\n/**\n* Trims a mailbox using the jobIds from a batch.\n*/\nfunction trimMailboxFromBatch(mailbox, batch) {\n\tconst toRemove = [];\n\tfor (const syncOp of batch.entries) for (const item of mailbox.items) if (syncOp.event.jobId === item.jobId) {\n\t\ttoRemove.push(item);\n\t\tbreak;\n\t}\n\tif (toRemove.length > 0) {\n\t\tfor (const syncOp of toRemove) syncOp.executed();\n\t\tmailbox.remove(...toRemove);\n\t}\n}\n/**\n* Trims a mailbox using the ack ordinal.\n*/\nfunction trimMailboxFromAckOrdinal(mailbox, ackOrdinal) {\n\tconst toRemove = [];\n\tfor (const syncOp of mailbox.items) {\n\t\tlet maxOrdinal = 0;\n\t\tfor (const op of syncOp.operations) maxOrdinal = Math.max(maxOrdinal, op.context.ordinal);\n\t\tif (maxOrdinal <= ackOrdinal) toRemove.push(syncOp);\n\t}\n\tif (toRemove.length > 0) {\n\t\tfor (const syncOp of toRemove) syncOp.executed();\n\t\tmailbox.remove(...toRemove);\n\t}\n}\n/**\n* Filters operations based on a remote's filter criteria.\n*\n* @param operations - The operations to filter\n* @param filter - The filter criteria to apply\n* @returns The filtered operations that match the criteria\n*/\nfunction filterOperations(operations, filter) {\n\treturn operations.filter((op) => {\n\t\tif (filter.branch && op.context.branch !== filter.branch) return false;\n\t\tif (filter.documentId.length > 0 && !filter.documentId.includes(op.context.documentId)) return false;\n\t\tif (filter.scope.length > 0 && !filter.scope.includes(op.context.scope)) return false;\n\t\treturn true;\n\t});\n}\n/**\n* Creates an idle channel health status.\n*\n* @returns A new idle channel health object\n*/\nfunction createIdleHealth() {\n\treturn {\n\t\tstate: \"idle\",\n\t\tfailureCount: 0\n\t};\n}\n/**\n* Batches consecutive operations by documentId and scope, preserving ordering.\n*\n* For operations [a1_doc, a1_global, a2_doc, b1_global], this returns:\n* - Batch 1: [a1_doc] for doc-a, document scope\n* - Batch 2: [a1_global] for doc-a, global scope\n* - Batch 3: [a2_doc] for doc-a, document scope\n* - Batch 4: [b1_global] for doc-b, global scope\n*\n* This ensures operations are grouped for efficient processing while maintaining\n* causality across documents and scopes.\n*/\nfunction batchOperationsByDocument(operations) {\n\tconst batches = [];\n\tlet currentDocId = null;\n\tlet currentScope = null;\n\tlet currentBatch = [];\n\tconst flushBatch = () => {\n\t\tif (currentBatch.length === 0 || currentDocId === null || currentScope === null) return;\n\t\tbatches.push({\n\t\t\tdocumentId: currentDocId,\n\t\t\tbranch: currentBatch[0].context.branch,\n\t\t\tscope: currentScope,\n\t\t\toperations: currentBatch\n\t\t});\n\t\tcurrentBatch = [];\n\t};\n\tfor (const op of operations) {\n\t\tconst docId = op.context.documentId;\n\t\tconst scope = op.context.scope;\n\t\tif (docId !== currentDocId || scope !== currentScope) {\n\t\t\tflushBatch();\n\t\t\tcurrentDocId = docId;\n\t\t\tcurrentScope = scope;\n\t\t}\n\t\tcurrentBatch.push(op);\n\t}\n\tflushBatch();\n\treturn batches;\n}\n/**\n* Splits a sorted page of operations into a safe-to-emit prefix and a\n* deferred tail containing the trailing run that shares the same\n* (documentId, branch, scope, timestampUtcMs) as the last operation.\n*\n* The page is assumed to be sorted by (documentId, scope, ordinal), so a\n* same-(docId, scope, ts) run is contiguous and lives at the end of any\n* page that contains its last member. Holding that tail back lets callers\n* prepend it to the next page so a single producer-side execute() call\n* never gets split across two outbound envelopes.\n*/\nfunction splitTrailingSameTimestampRun(operations) {\n\tif (operations.length === 0) return {\n\t\temit: [],\n\t\tcarry: []\n\t};\n\tconst last = operations[operations.length - 1];\n\tconst lastDocId = last.context.documentId;\n\tconst lastBranch = last.context.branch;\n\tconst lastScope = last.context.scope;\n\tconst lastTs = last.operation.timestampUtcMs;\n\tlet carryStart = operations.length;\n\tfor (let i = operations.length - 1; i >= 0; i--) {\n\t\tconst op = operations[i];\n\t\tif (op.context.documentId === lastDocId && op.context.branch === lastBranch && op.context.scope === lastScope && op.operation.timestampUtcMs === lastTs) carryStart = i;\n\t\telse break;\n\t}\n\treturn {\n\t\temit: operations.slice(0, carryStart),\n\t\tcarry: operations.slice(carryStart)\n\t};\n}\nfunction toOperationWithContext(entry) {\n\treturn {\n\t\toperation: {\n\t\t\tid: entry.id,\n\t\t\tindex: entry.index,\n\t\t\tskip: entry.skip,\n\t\t\thash: entry.hash,\n\t\t\ttimestampUtcMs: entry.timestampUtcMs,\n\t\t\tdeniedReason: entry.deniedReason,\n\t\t\taction: entry.action\n\t\t},\n\t\tcontext: {\n\t\t\tdocumentId: entry.documentId,\n\t\t\tdocumentType: entry.documentType,\n\t\t\tscope: entry.scope,\n\t\t\tbranch: entry.branch,\n\t\t\tordinal: entry.ordinal ?? 0\n\t\t}\n\t};\n}\n/**\n* Merges SyncOperations that share the same (documentId, scope, branch) into\n* a single SyncOperation per group. Within each group, operations are sorted\n* by context.ordinal. The merged SyncOperation keeps the first group member's\n* jobId; all other jobIds are remapped so external dependencies still resolve.\n*\n* Only CONTIGUOUS runs merge. A document whose scopes interleave arrives as an\n* alternating chain (document -> auth -> document -> auth) where each entry\n* depends on the one before it. Merging every occurrence of a\n* (documentId, scope, branch) collapses that chain into two nodes that each\n* depend on the other, which validateBatchStructure rejects as a dependency\n* cycle. Merging only adjacent entries keeps the chain linear.\n*/\nfunction consolidateSyncOperations(syncOps) {\n\tif (syncOps.length <= 1) return syncOps;\n\tconst groups = [];\n\tconst jobIdRemap = /* @__PURE__ */ new Map();\n\tlet prevKey = null;\n\tfor (const syncOp of syncOps) {\n\t\tconst key = `${syncOp.documentId}|${syncOp.scopes.slice().sort().join(\",\")}|${syncOp.branch}`;\n\t\tconst current = key === prevKey ? groups[groups.length - 1] : void 0;\n\t\tif (current) {\n\t\t\tcurrent.ops.push(syncOp);\n\t\t\tif (syncOp.jobId && syncOp.jobId !== current.canonicalJobId) jobIdRemap.set(syncOp.jobId, current.canonicalJobId);\n\t\t} else {\n\t\t\tgroups.push({\n\t\t\t\tops: [syncOp],\n\t\t\t\tcanonicalJobId: syncOp.jobId\n\t\t\t});\n\t\t\tprevKey = key;\n\t\t}\n\t}\n\tconst result = [];\n\tfor (const group of groups) {\n\t\tconst allOperations = group.ops.flatMap((op) => op.operations).sort((a, b) => a.context.ordinal - b.context.ordinal);\n\t\tconst allDeps = /* @__PURE__ */ new Set();\n\t\tfor (const op of group.ops) for (const dep of op.jobDependencies) allDeps.add(dep);\n\t\tallDeps.delete(group.canonicalJobId);\n\t\tfor (const op of group.ops) allDeps.delete(op.jobId);\n\t\tconst remappedDeps = [];\n\t\tfor (const dep of allDeps) {\n\t\t\tconst mapped = jobIdRemap.get(dep) ?? dep;\n\t\t\tif (!remappedDeps.includes(mapped) && mapped !== group.canonicalJobId) remappedDeps.push(mapped);\n\t\t}\n\t\tconst first = group.ops[0];\n\t\tconst merged = new SyncOperation(first.id, first.jobId, remappedDeps, first.remoteName, first.documentId, first.scopes, first.branch, allOperations);\n\t\tif (first.status > SyncOperationStatus.TransportPending) if (first.status >= SyncOperationStatus.Error) merged.executed();\n\t\telse if (first.status >= SyncOperationStatus.Applied) merged.transported();\n\t\telse merged.started();\n\t\tresult.push(merged);\n\t}\n\treturn result;\n}\n/**\n* Chunks sync operations into batches that respect dependency-connected\n* components. SyncOps linked by jobDependencies are kept in the same chunk.\n* If a connected component exceeds maxSize, it is split by topological order.\n*/\nfunction chunkSyncOperations(items, maxSize) {\n\tif (items.length === 0) return [];\n\tif (items.length <= maxSize) return [items];\n\tconst parent = items.map((_, i) => i);\n\tconst rank = new Array(items.length).fill(0);\n\tfunction find(x) {\n\t\twhile (parent[x] !== x) {\n\t\t\tparent[x] = parent[parent[x]];\n\t\t\tx = parent[x];\n\t\t}\n\t\treturn x;\n\t}\n\tfunction union(a, b) {\n\t\tconst ra = find(a);\n\t\tconst rb = find(b);\n\t\tif (ra === rb) return;\n\t\tif (rank[ra] < rank[rb]) parent[ra] = rb;\n\t\telse if (rank[ra] > rank[rb]) parent[rb] = ra;\n\t\telse {\n\t\t\tparent[rb] = ra;\n\t\t\trank[ra]++;\n\t\t}\n\t}\n\tconst jobIdToIndex = /* @__PURE__ */ new Map();\n\tfor (let i = 0; i < items.length; i++) jobIdToIndex.set(items[i].syncOp.jobId, i);\n\tfor (let i = 0; i < items.length; i++) for (const dep of items[i].syncOp.jobDependencies) {\n\t\tconst depIdx = jobIdToIndex.get(dep);\n\t\tif (depIdx !== void 0) union(i, depIdx);\n\t}\n\tconst componentMap = /* @__PURE__ */ new Map();\n\tfor (let i = 0; i < items.length; i++) {\n\t\tconst root = find(i);\n\t\tlet component = componentMap.get(root);\n\t\tif (!component) {\n\t\t\tcomponent = [];\n\t\t\tcomponentMap.set(root, component);\n\t\t}\n\t\tcomponent.push(items[i]);\n\t}\n\tconst components = [...componentMap.values()];\n\tconst chunks = [];\n\tlet currentChunk = [];\n\tfor (const component of components) {\n\t\tif (component.length > maxSize) {\n\t\t\tif (currentChunk.length > 0) {\n\t\t\t\tchunks.push(currentChunk);\n\t\t\t\tcurrentChunk = [];\n\t\t\t}\n\t\t\tfor (const subChunk of splitComponent(component, maxSize)) chunks.push(subChunk);\n\t\t\tcontinue;\n\t\t}\n\t\tif (currentChunk.length + component.length > maxSize) {\n\t\t\tif (currentChunk.length > 0) chunks.push(currentChunk);\n\t\t\tcurrentChunk = [...component];\n\t\t} else currentChunk.push(...component);\n\t}\n\tif (currentChunk.length > 0) chunks.push(currentChunk);\n\treturn chunks;\n}\n/**\n* Splits an oversized connected component into chunks by topological order.\n* Cross-chunk dependency references are handled by the caller's dep filter.\n*/\nfunction splitComponent(items, maxSize) {\n\tconst jobIdToItem = /* @__PURE__ */ new Map();\n\tconst jobIds = /* @__PURE__ */ new Set();\n\tfor (const item of items) {\n\t\tjobIdToItem.set(item.syncOp.jobId, item);\n\t\tjobIds.add(item.syncOp.jobId);\n\t}\n\tconst inDegree = /* @__PURE__ */ new Map();\n\tconst adjacency = /* @__PURE__ */ new Map();\n\tfor (const item of items) {\n\t\tconst key = item.syncOp.jobId;\n\t\tif (!inDegree.has(key)) inDegree.set(key, 0);\n\t\tif (!adjacency.has(key)) adjacency.set(key, []);\n\t\tfor (const dep of item.syncOp.jobDependencies) if (jobIds.has(dep)) {\n\t\t\tinDegree.set(key, (inDegree.get(key) ?? 0) + 1);\n\t\t\tif (!adjacency.has(dep)) adjacency.set(dep, []);\n\t\t\tadjacency.get(dep).push(key);\n\t\t}\n\t}\n\tconst queue = [];\n\tfor (const [key, degree] of inDegree) if (degree === 0) queue.push(key);\n\tconst sorted = [];\n\twhile (queue.length > 0) {\n\t\tconst key = queue.shift();\n\t\tsorted.push(jobIdToItem.get(key));\n\t\tfor (const neighbor of adjacency.get(key) ?? []) {\n\t\t\tconst newDegree = (inDegree.get(neighbor) ?? 1) - 1;\n\t\t\tinDegree.set(neighbor, newDegree);\n\t\t\tif (newDegree === 0) queue.push(neighbor);\n\t\t}\n\t}\n\tif (sorted.length < items.length) {\n\t\tconst sortedIds = new Set(sorted.map((item) => item.syncOp.jobId));\n\t\tfor (const item of items) if (!sortedIds.has(item.syncOp.jobId)) sorted.push(item);\n\t}\n\tconst chunks = [];\n\tfor (let i = 0; i < sorted.length; i += maxSize) chunks.push(sorted.slice(i, i + maxSize));\n\treturn chunks;\n}\n/**\n* Classifies a failure by error name rather than `instanceof`, because a failure\n* that crossed the pooled-worker boundary arrives as plain data.\n*/\nfunction classifyJobFailure(errorName) {\n\tswitch (errorName) {\n\t\tcase \"AuthTimestampNotMonotonicError\": return \"AUTH_TIMESTAMP_NOT_MONOTONIC\";\n\t\tcase \"InvalidOperationTimestampError\": return \"INVALID_TIMESTAMP\";\n\t\tcase \"ExcessiveReshuffleError\": return \"EXCESSIVE_SHUFFLE\";\n\t\tcase \"InvalidSignatureError\": return \"SIGNATURE_INVALID\";\n\t\tcase \"HashMismatchError\": return \"HASH_MISMATCH\";\n\t\tdefault: return \"UNCLASSIFIED\";\n\t}\n}\n/** The explicit type when something else carried it, else derived by name. */\nfunction syncOperationErrorType(error) {\n\treturn error?.errorType ?? classifyJobFailure(error?.error?.name ?? \"Error\");\n}\n/** Dead-letter types that must not stop the document syncing. */\nconst NON_QUARANTINING_ERROR_TYPES = new Set([\"AUTH_TIMESTAMP_NOT_MONOTONIC\"]);\n/**\n* A held auth operation must not quarantine: reconciling the two policies needs\n* the traffic a quarantine would stop.\n*/\nfunction quarantinesDocument(errorType) {\n\treturn !NON_QUARANTINING_ERROR_TYPES.has(errorType);\n}\n//#endregion\n//#region src/sync/channels/interval-poll-timer.ts\nconst DEFAULT_CONFIG = {\n\tintervalMs: 2e3,\n\tmaxQueueDepth: 100,\n\tbackpressureCheckIntervalMs: 500,\n\tretryBaseDelayMs: 1e3,\n\tretryMaxDelayMs: 3e5,\n\tstartPaused: false\n};\nfunction calculateBackoffDelay(consecutiveFailures, retryBaseDelayMs, retryMaxDelayMs, random) {\n\tconst backoff = Math.min(retryMaxDelayMs, retryBaseDelayMs * Math.pow(2, consecutiveFailures - 1));\n\treturn backoff / 2 + random * (backoff / 2);\n}\n/**\n* Default poll timer using setTimeout.\n* Waits for delegate completion before scheduling next tick.\n* Checks queue depth and defers polling when backpressure is detected.\n*/\nvar IntervalPollTimer = class {\n\tdelegate;\n\ttimer;\n\trunning;\n\tpaused;\n\tconsecutiveFailures;\n\tqueue;\n\tconfig;\n\tconstructor(queue, config = {}) {\n\t\tthis.queue = queue;\n\t\tthis.config = {\n\t\t\t...DEFAULT_CONFIG,\n\t\t\t...config\n\t\t};\n\t\tthis.running = false;\n\t\tthis.paused = this.config.startPaused;\n\t\tthis.consecutiveFailures = 0;\n\t}\n\tsetDelegate(delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\tstart() {\n\t\tthis.running = true;\n\t\tthis.consecutiveFailures = 0;\n\t\tif (!this.paused) this.tick();\n\t}\n\tstop() {\n\t\tthis.running = false;\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = void 0;\n\t\t}\n\t}\n\ttick() {\n\t\tif (!this.delegate || !this.running) return;\n\t\tconst delegate = this.delegate;\n\t\tthis.queue.totalSize().then((size) => {\n\t\t\tif (!this.running) return;\n\t\t\tif (size > this.config.maxQueueDepth) this.scheduleBackpressureRecheck();\n\t\t\telse delegate().then(() => {\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t\tthis.scheduleNext();\n\t\t\t}).catch(() => {\n\t\t\t\tthis.consecutiveFailures++;\n\t\t\t\tthis.scheduleRetry();\n\t\t\t});\n\t\t}).catch(() => {\n\t\t\tthis.scheduleNext();\n\t\t});\n\t}\n\tscheduleNext() {\n\t\tif (!this.running || this.paused) return;\n\t\tthis.timer = setTimeout(() => this.tick(), this.config.intervalMs);\n\t}\n\tscheduleRetry() {\n\t\tif (!this.running || this.paused) return;\n\t\tconst delay = calculateBackoffDelay(this.consecutiveFailures, this.config.retryBaseDelayMs, this.config.retryMaxDelayMs, Math.random());\n\t\tthis.timer = setTimeout(() => this.tick(), delay);\n\t}\n\tscheduleBackpressureRecheck() {\n\t\tif (!this.running || this.paused) return;\n\t\tthis.timer = setTimeout(() => this.tick(), this.config.backpressureCheckIntervalMs);\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = void 0;\n\t\t}\n\t}\n\tresume() {\n\t\tthis.paused = false;\n\t\tif (this.running) this.scheduleNext();\n\t}\n\ttriggerNow() {\n\t\tif (this.running && this.delegate) this.tick();\n\t}\n\tisPaused() {\n\t\treturn this.paused;\n\t}\n\tisRunning() {\n\t\treturn this.running;\n\t}\n\tgetIntervalMs() {\n\t\treturn this.config.intervalMs;\n\t}\n\tsetIntervalMs(ms) {\n\t\tthis.config.intervalMs = ms;\n\t}\n};\n//#endregion\n//#region src/sync/channels/utils.ts\nlet syncOpCounter = 0;\n/**\n* Serializes an action for GraphQL transport.\n*\n* Projects onto exactly the fields `ActionInput` declares, which is what keeps a\n* stale runtime-only field - a legacy `attachments` array, say - from riding\n* along into the mutation variables, where the schema would reject the whole\n* request rather than the field.\n*/\nfunction serializeAction(action) {\n\treturn toTransportAction(action);\n}\n/**\n* Serializes a SyncEnvelope for GraphQL transport.\n*\n* Signatures are serialized as comma-separated strings since GraphQL schema\n* defines them as [String!]!. The resultingState context field is stripped\n* since it is not defined in OperationContextInput.\n*/\nfunction serializeEnvelope(envelope) {\n\treturn {\n\t\ttype: envelope.type.toUpperCase(),\n\t\tchannelMeta: envelope.channelMeta,\n\t\toperations: envelope.operations?.map((opWithContext) => ({\n\t\t\toperation: {\n\t\t\t\tindex: opWithContext.operation.index,\n\t\t\t\ttimestampUtcMs: opWithContext.operation.timestampUtcMs,\n\t\t\t\thash: opWithContext.operation.hash,\n\t\t\t\tskip: opWithContext.operation.skip,\n\t\t\t\terror: opWithContext.operation.error,\n\t\t\t\t...opWithContext.operation.deniedReason !== void 0 ? { deniedReason: opWithContext.operation.deniedReason } : {},\n\t\t\t\tid: opWithContext.operation.id,\n\t\t\t\taction: serializeAction(opWithContext.operation.action)\n\t\t\t},\n\t\t\tcontext: {\n\t\t\t\tdocumentId: opWithContext.context.documentId,\n\t\t\t\tdocumentType: opWithContext.context.documentType,\n\t\t\t\tscope: opWithContext.context.scope,\n\t\t\t\tbranch: opWithContext.context.branch,\n\t\t\t\tordinal: opWithContext.context.ordinal\n\t\t\t}\n\t\t})),\n\t\tcursor: envelope.cursor,\n\t\tkey: envelope.key,\n\t\tdependsOn: envelope.dependsOn\n\t};\n}\n/**\n* `isDenied` tests strictly against undefined, so a null left in place would mark\n* every synced operation denied. The key is removed rather than set to undefined,\n* so an operation that arrived without it stays identical to the one sent.\n*/\nfunction normalizeAbsentFields(operation) {\n\tconst wire = operation;\n\tif (wire.error !== null && wire.deniedReason !== null) return operation;\n\tconst normalized = { ...operation };\n\tif (wire.error === null) delete normalized.error;\n\tif (wire.deniedReason === null) delete normalized.deniedReason;\n\treturn normalized;\n}\n/** Restores signature tuples and null-valued optional fields to undefined. */\nfunction deserializeOperation(opWithContext) {\n\tconst operation = normalizeAbsentFields(opWithContext.operation);\n\tconst signer = operation.action.context?.signer;\n\tif (!signer?.signatures || signer.signatures.length === 0) return {\n\t\t...opWithContext,\n\t\toperation\n\t};\n\tconst deserializedSignatures = signer.signatures.map(deserializeSignature);\n\tconst deserializedOperation = {\n\t\t...operation,\n\t\taction: {\n\t\t\t...operation.action,\n\t\t\tcontext: {\n\t\t\t\t...operation.action.context,\n\t\t\t\tsigner: {\n\t\t\t\t\t...signer,\n\t\t\t\t\tsignatures: deserializedSignatures\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\treturn {\n\t\t...opWithContext,\n\t\toperation: deserializedOperation\n\t};\n}\n/**\n* Converts a SyncEnvelope containing operations into multiple SyncOperations.\n*\n* This function batches operations by documentId, preserving cross-document ordering.\n* For operations [a1, a2, a3, b1, b2, a4], it returns:\n* - SyncOperation 1: [a1, a2, a3] for doc-a\n* - SyncOperation 2: [b1, b2] for doc-b\n* - SyncOperation 3: [a4] for doc-a\n*\n* This ensures operations are grouped for efficient processing while maintaining\n* causality across documents.\n*/\nfunction envelopesToSyncOperations(envelope, remoteName) {\n\tif (!envelope.operations || envelope.operations.length === 0) return [];\n\treturn batchOperationsByDocument(envelope.operations.map(deserializeOperation)).map((batch) => {\n\t\treturn new SyncOperation(`syncop-${envelope.channelMeta.id}-${Date.now()}-${syncOpCounter++}`, envelope.key ?? \"\", (envelope.dependsOn ?? []).filter(Boolean), remoteName, batch.documentId, [batch.scope], batch.branch, batch.operations);\n\t});\n}\nconst getLatestAppliedOrdinal = (syncOps) => {\n\tlet maxOrdinal = 0;\n\tfor (const syncOp of syncOps) if (syncOp.status === SyncOperationStatus.Applied) for (const op of syncOp.operations) maxOrdinal = Math.max(maxOrdinal, op.context.ordinal);\n\treturn maxOrdinal;\n};\n//#endregion\n//#region src/sync/channels/gql-req-channel.ts\n/**\n* Fields the auth projection added to the sync schema. A remote that predates\n* them rejects the whole query for naming one, so they are selected only while\n* the remote is known to serve them.\n*/\nconst DECISION_FIELDS = [\"deniedReason\", \"errorType\"];\n/**\n* GraphQL-based synchronization channel for network communication between reactors.\n*/\nvar GqlRequestChannel = class {\n\tinbox;\n\toutbox;\n\tdeadLetter;\n\tconfig;\n\tbufferedOutbox;\n\tchannelId;\n\tremoteName;\n\tcursorStorage;\n\toperationIndex;\n\tpollTimer;\n\tabortController = new AbortController();\n\tisShutdown;\n\tfailureCount;\n\tlastSuccessUtcMs;\n\tlastFailureUtcMs;\n\tlastPersistedInboxOrdinal = 0;\n\tlastPersistedOutboxOrdinal = 0;\n\tpushFailureCount = 0;\n\tpushRetryTimer = null;\n\tpushBlocked = false;\n\tisPushing = false;\n\tpendingDrain = false;\n\treceivingPages = false;\n\t/** Cleared for good the first time the remote rejects {@link DECISION_FIELDS}. */\n\tpeerServesDecisionFields = true;\n\tisRecovering = false;\n\tconnectionState = \"connecting\";\n\t/** Latest unrecoverable error was an auth rejection; cleared on connect. */\n\trequiresAuth = false;\n\tconnectionStateCallbacks = /* @__PURE__ */ new Set();\n\tconstructor(logger, channelId, remoteName, cursorStorage, config, operationIndex, pollTimer) {\n\t\tthis.logger = logger;\n\t\tthis.channelId = channelId;\n\t\tthis.remoteName = remoteName;\n\t\tthis.cursorStorage = cursorStorage;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.pollTimer = pollTimer;\n\t\tthis.config = {\n\t\t\turl: config.url,\n\t\t\tjwtHandler: config.jwtHandler,\n\t\t\tfetchFn: config.fetchFn,\n\t\t\tcollectionId: config.collectionId,\n\t\t\tfilter: config.filter,\n\t\t\tretryBaseDelayMs: config.retryBaseDelayMs,\n\t\t\tretryMaxDelayMs: config.retryMaxDelayMs\n\t\t};\n\t\tthis.isShutdown = false;\n\t\tthis.failureCount = 0;\n\t\tthis.inbox = new Mailbox();\n\t\tthis.bufferedOutbox = new BufferedMailbox(500, 25);\n\t\tthis.outbox = this.bufferedOutbox;\n\t\tthis.deadLetter = new Mailbox();\n\t\tthis.deadLetter.onAdded((syncOps) => {\n\t\t\tfor (const syncOp of syncOps) this.logger.warn(\"Dead letter added for document @DocumentId on channel @ChannelId\", syncOp.documentId, this.channelId);\n\t\t});\n\t\tthis.outbox.onAdded((syncOps) => {\n\t\t\tif (this.isShutdown) return;\n\t\t\tif (this.isPushing) {\n\t\t\t\tthis.pendingDrain = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.pushBlocked) return;\n\t\t\tif (this.receivingPages) {\n\t\t\t\tthis.pendingDrain = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.attemptPush(syncOps);\n\t\t});\n\t\tthis.outbox.onRemoved((syncOps) => {\n\t\t\tconst maxOrdinal = getLatestAppliedOrdinal(syncOps);\n\t\t\tif (maxOrdinal > this.lastPersistedOutboxOrdinal) {\n\t\t\t\tthis.lastPersistedOutboxOrdinal = maxOrdinal;\n\t\t\t\tthis.cursorStorage.upsert({\n\t\t\t\t\tremoteName: this.remoteName,\n\t\t\t\t\tcursorType: \"outbox\",\n\t\t\t\t\tcursorOrdinal: maxOrdinal,\n\t\t\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\tthis.logger.error(\"Failed to update outbox cursor for @ChannelId! This means that future application runs may resend duplicate operations. This is recoverable (with deduplication protection), but not-optimal: @Error\", this.channelId, error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tthis.inbox.onRemoved((syncOps) => {\n\t\t\tconst maxOrdinal = getLatestAppliedOrdinal(syncOps);\n\t\t\tif (maxOrdinal > this.lastPersistedInboxOrdinal) {\n\t\t\t\tthis.lastPersistedInboxOrdinal = maxOrdinal;\n\t\t\t\tthis.cursorStorage.upsert({\n\t\t\t\t\tremoteName: this.remoteName,\n\t\t\t\t\tcursorType: \"inbox\",\n\t\t\t\t\tcursorOrdinal: maxOrdinal,\n\t\t\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\tthis.logger.error(\"Failed to update inbox cursor for @ChannelId! This is unlikely to cause a problem, but not-optimal: @Error\", this.channelId, error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Shuts down the channel and prevents further operations.\n\t*/\n\tshutdown() {\n\t\tthis.abortController.abort();\n\t\tthis.bufferedOutbox.flush();\n\t\tthis.isShutdown = true;\n\t\tthis.pollTimer.stop();\n\t\tif (this.pushRetryTimer) {\n\t\t\tclearTimeout(this.pushRetryTimer);\n\t\t\tthis.pushRetryTimer = null;\n\t\t}\n\t\tthis.transitionConnectionState(\"disconnected\");\n\t\treturn Promise.resolve();\n\t}\n\tgetConnectionState() {\n\t\treturn {\n\t\t\tstate: this.connectionState,\n\t\t\tfailureCount: this.failureCount,\n\t\t\tlastSuccessUtcMs: this.lastSuccessUtcMs ?? 0,\n\t\t\tlastFailureUtcMs: this.lastFailureUtcMs ?? 0,\n\t\t\tpushBlocked: this.pushBlocked,\n\t\t\tpushFailureCount: this.pushFailureCount,\n\t\t\treceivingPages: this.receivingPages,\n\t\t\trequiresAuth: this.requiresAuth\n\t\t};\n\t}\n\tonConnectionStateChange(callback) {\n\t\tthis.connectionStateCallbacks.add(callback);\n\t\treturn () => {\n\t\t\tthis.connectionStateCallbacks.delete(callback);\n\t\t};\n\t}\n\ttriggerPull() {\n\t\tif (this.isShutdown) return;\n\t\tthis.pollTimer.triggerNow();\n\t}\n\t/** This channel polls a remote itself; it has no holder to hear from. */\n\tnotePoll() {}\n\t/** No holder, so nothing this channel reports may strand one. */\n\tlastHolderPollUtcMs() {}\n\t/**\n\t* Initializes the channel by registering it on the remote server and starting polling.\n\t*/\n\tasync init() {\n\t\tconst { ackOrdinal } = await this.touchRemoteChannel();\n\t\tconst cursors = await this.cursorStorage.list(this.remoteName);\n\t\tconst inboxOrdinal = cursors.find((c) => c.cursorType === \"inbox\")?.cursorOrdinal ?? 0;\n\t\tconst outboxOrdinal = cursors.find((c) => c.cursorType === \"outbox\")?.cursorOrdinal ?? 0;\n\t\tthis.inbox.init(inboxOrdinal);\n\t\tthis.outbox.init(outboxOrdinal);\n\t\tthis.lastPersistedInboxOrdinal = inboxOrdinal;\n\t\tthis.lastPersistedOutboxOrdinal = outboxOrdinal;\n\t\tif (ackOrdinal > 0) trimMailboxFromAckOrdinal(this.outbox, ackOrdinal);\n\t\tthis.pollTimer.setDelegate(() => this.poll());\n\t\tthis.pollTimer.start();\n\t\tthis.transitionConnectionState(\"connected\");\n\t}\n\ttransitionConnectionState(next) {\n\t\tif (next === \"connected\") this.requiresAuth = false;\n\t\tif (this.connectionState === next) return;\n\t\tthis.connectionState = next;\n\t\tconst snapshot = this.getConnectionState();\n\t\tfor (const callback of this.connectionStateCallbacks) try {\n\t\t\tcallback(snapshot);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Connection state change callback error: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Polls the remote for new sync envelopes.\n\t*/\n\tasync poll() {\n\t\tif (this.isShutdown) return;\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await this.pollSyncEnvelopes(this.inbox.ackOrdinal, this.inbox.latestOrdinal);\n\t\t} catch (error) {\n\t\t\tif (!this.handlePollError(error)) throw error;\n\t\t\treturn;\n\t\t}\n\t\tconst { envelopes, ackOrdinal, deadLetters, hasMore } = response;\n\t\tif (ackOrdinal > 0) trimMailboxFromAckOrdinal(this.outbox, ackOrdinal);\n\t\tconst allSyncOps = [];\n\t\tfor (const envelope of envelopes) if (envelope.type.toLowerCase() === \"operations\" && envelope.operations) {\n\t\t\tconst syncOps = envelopesToSyncOperations(envelope, this.remoteName);\n\t\t\tfor (const syncOp of syncOps) syncOp.transported();\n\t\t\tallSyncOps.push(...syncOps);\n\t\t}\n\t\tconst consolidated = allSyncOps.length > 1 ? consolidateSyncOperations(allSyncOps) : allSyncOps;\n\t\tif (consolidated.length > 0) this.inbox.add(...consolidated);\n\t\tif (deadLetters.length > 0) this.handleRemoteDeadLetters(deadLetters);\n\t\tif (hasMore) this.receivingPages = true;\n\t\telse if (this.receivingPages) {\n\t\t\tthis.receivingPages = false;\n\t\t\tthis.drainOutbox();\n\t\t}\n\t\tthis.lastSuccessUtcMs = Date.now();\n\t\tthis.failureCount = 0;\n\t\tthis.transitionConnectionState(\"connected\");\n\t}\n\t/**\n\t* Handles dead letters reported by the remote server.\n\t* Creates local dead letter SyncOperations so the channel quiesces.\n\t*/\n\thandleRemoteDeadLetters(deadLetters) {\n\t\tfor (const dl of deadLetters) this.logger.error(\"Remote dead letter on @ChannelId: document @DocumentId failed with: @Error\", this.channelId, dl.documentId, dl.error);\n\t\tconst syncOps = [];\n\t\tfor (const dl of deadLetters) {\n\t\t\tconst syncOp = new SyncOperation(crypto.randomUUID(), dl.jobId, [], this.remoteName, dl.documentId, dl.scopes, dl.branch, []);\n\t\t\tsyncOp.failed(new ChannelError(ChannelErrorSource.Outbox, new Error(dl.error), dl.errorType ?? void 0));\n\t\t\tsyncOps.push(syncOp);\n\t\t}\n\t\tthis.deadLetter.add(...syncOps);\n\t}\n\t/**\n\t* Handles polling errors with error classification.\n\t* Returns true if the error was handled (caller should not rethrow).\n\t*/\n\thandlePollError(error) {\n\t\tif (this.isShutdown) return true;\n\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\tif (err.message.includes(\"Channel not found\")) {\n\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\tthis.recoverFromChannelNotFound();\n\t\t\treturn true;\n\t\t}\n\t\tconst classification = this.classifyError(err);\n\t\tthis.failureCount++;\n\t\tthis.lastFailureUtcMs = Date.now();\n\t\tconst channelError = new ChannelError(ChannelErrorSource.Inbox, err);\n\t\tthis.logger.error(\"GqlChannel poll error (@FailureCount, @Classification): @Error\", this.failureCount, classification, channelError);\n\t\tif (classification === \"unrecoverable\") {\n\t\t\tthis.pollTimer.stop();\n\t\t\tthis.requiresAuth = isDriveAuthError(err);\n\t\t\tthis.transitionConnectionState(\"error\");\n\t\t\treturn true;\n\t\t}\n\t\tthis.transitionConnectionState(\"error\");\n\t\treturn false;\n\t}\n\t/**\n\t* Recovers from a \"Channel not found\" error by re-registering and restarting polling.\n\t* Self-retries with backoff instead of restarting the poll timer on failure.\n\t*/\n\trecoverFromChannelNotFound() {\n\t\tif (this.isRecovering) return;\n\t\tthis.isRecovering = true;\n\t\tthis.logger.info(\"GqlChannel @ChannelId not found on remote, re-registering...\", this.channelId);\n\t\tthis.pollTimer.stop();\n\t\tconst attemptRecovery = (attempt) => {\n\t\t\tif (this.isShutdown) {\n\t\t\t\tthis.isRecovering = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.touchRemoteChannel().then(({ ackOrdinal }) => {\n\t\t\t\tthis.logger.info(\"GqlChannel @ChannelId re-registered successfully\", this.channelId);\n\t\t\t\tthis.isRecovering = false;\n\t\t\t\tthis.failureCount = 0;\n\t\t\t\tif (ackOrdinal > 0) trimMailboxFromAckOrdinal(this.outbox, ackOrdinal);\n\t\t\t\tthis.pollTimer.start();\n\t\t\t\tthis.transitionConnectionState(\"connected\");\n\t\t\t\tthis.resumePushAfterRecovery();\n\t\t\t}).catch((recoveryError) => {\n\t\t\t\tconst err = recoveryError instanceof Error ? recoveryError : new Error(String(recoveryError));\n\t\t\t\tconst classification = this.classifyError(err);\n\t\t\t\tthis.logger.error(\"GqlChannel @ChannelId recovery attempt @Attempt failed (@Classification): @Error\", this.channelId, attempt, classification, recoveryError);\n\t\t\t\tthis.failureCount++;\n\t\t\t\tthis.lastFailureUtcMs = Date.now();\n\t\t\t\tif (classification === \"unrecoverable\") {\n\t\t\t\t\tthis.isRecovering = false;\n\t\t\t\t\tthis.requiresAuth = isDriveAuthError(err);\n\t\t\t\t\tthis.transitionConnectionState(\"error\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\t\tconst delay = calculateBackoffDelay(attempt, this.config.retryBaseDelayMs, this.config.retryMaxDelayMs, Math.random());\n\t\t\t\tsetTimeout(() => attemptRecovery(attempt + 1), delay);\n\t\t\t});\n\t\t};\n\t\tattemptRecovery(1);\n\t}\n\t/**\n\t* Resumes pushing outbox items that were blocked while the channel was being\n\t* recreated. Called after a successful re-registration.\n\t*/\n\tresumePushAfterRecovery() {\n\t\tif (this.isShutdown) return;\n\t\tif (!this.pushBlocked) return;\n\t\tif (this.pushRetryTimer) {\n\t\t\tclearTimeout(this.pushRetryTimer);\n\t\t\tthis.pushRetryTimer = null;\n\t\t}\n\t\tthis.pushBlocked = false;\n\t\tthis.pushFailureCount = 0;\n\t\tconst items = this.outbox.items;\n\t\tif (items.length > 0) this.attemptPush([...items]);\n\t}\n\t/**\n\t* Queries the remote GraphQL endpoint for sync envelopes.\n\t*/\n\tasync pollSyncEnvelopes(ackOrdinal, latestOrdinal) {\n\t\tconst variables = {\n\t\t\tchannelId: this.channelId,\n\t\t\toutboxAck: ackOrdinal,\n\t\t\toutboxLatest: latestOrdinal\n\t\t};\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await this.executeGraphQL(this.pollQuery(this.peerServesDecisionFields), variables);\n\t\t} catch (error) {\n\t\t\tif (!this.rejectsDecisionFields(error)) throw error;\n\t\t\tthis.logger.warn(\"Remote @channelId does not serve deniedReason/errorType; polling without them. The remote is on an older schema, so it has neither to report.\", this.channelId);\n\t\t\tthis.peerServesDecisionFields = false;\n\t\t\tresponse = await this.executeGraphQL(this.pollQuery(false), variables);\n\t\t}\n\t\treturn {\n\t\t\tenvelopes: response.pollSyncEnvelopes.envelopes,\n\t\t\tackOrdinal: response.pollSyncEnvelopes.ackOrdinal,\n\t\t\tdeadLetters: response.pollSyncEnvelopes.deadLetters ?? [],\n\t\t\thasMore: response.pollSyncEnvelopes.hasMore\n\t\t};\n\t}\n\t/**\n\t* True when the remote rejected the query for naming a field it does not\n\t* have. Selecting an unknown field fails validation for the whole query, so\n\t* an unhandled one takes the channel's polling down until the process\n\t* restarts rather than degrading.\n\t*/\n\trejectsDecisionFields(error) {\n\t\tif (!this.peerServesDecisionFields) return false;\n\t\tif (!(error instanceof GraphQLRequestError) || error.category !== \"graphql\") return false;\n\t\treturn DECISION_FIELDS.some((field) => error.message.includes(field));\n\t}\n\t/**\n\t* The poll query. `withDecisionFields` selects the two fields added with the\n\t* auth projection; a remote on the previous schema is polled without them.\n\t*/\n\tpollQuery(withDecisionFields) {\n\t\treturn `\n query PollSyncEnvelopes($channelId: String!, $outboxAck: Int!, $outboxLatest: Int!) {\n pollSyncEnvelopes(channelId: $channelId, outboxAck: $outboxAck, outboxLatest: $outboxLatest) {\n envelopes {\n type\n channelMeta {\n id\n }\n operations {\n operation {\n index\n timestampUtcMs\n hash\n skip\n error\n ${withDecisionFields ? \"deniedReason\" : \"\"}\n id\n action {\n id\n type\n timestampUtcMs\n input\n scope\n context {\n signer {\n user {\n address\n networkId\n chainId\n }\n app {\n name\n key\n }\n signatures\n }\n }\n }\n }\n context {\n documentId\n documentType\n scope\n branch\n ordinal\n }\n }\n cursor {\n remoteName\n cursorOrdinal\n lastSyncedAtUtcMs\n }\n key\n dependsOn\n }\n ackOrdinal\n deadLetters {\n documentId\n error\n ${withDecisionFields ? \"errorType\" : \"\"}\n jobId\n branch\n scopes\n operationCount\n }\n hasMore\n }\n }\n `;\n\t}\n\t/**\n\t* Registers or updates this channel on the remote server via GraphQL mutation.\n\t* Returns the remote's ack ordinal so the client can trim its outbox.\n\t*/\n\tasync touchRemoteChannel() {\n\t\tlet sinceTimestampUtcMs = \"0\";\n\t\ttry {\n\t\t\tconst result = await this.operationIndex.getLatestTimestampForCollection(this.config.collectionId.key);\n\t\t\tif (result) sinceTimestampUtcMs = result;\n\t\t} catch {}\n\t\tconst mutation = `\n mutation TouchChannel($input: TouchChannelInput!) {\n touchChannel(input: $input) {\n success\n ackOrdinal\n }\n }\n `;\n\t\tconst variables = { input: {\n\t\t\tid: this.channelId,\n\t\t\tname: this.channelId,\n\t\t\tcollectionId: this.config.collectionId.key,\n\t\t\tfilter: {\n\t\t\t\tdocumentId: this.config.filter.documentId,\n\t\t\t\tscope: this.config.filter.scope,\n\t\t\t\tbranch: this.config.filter.branch\n\t\t\t},\n\t\t\tsinceTimestampUtcMs\n\t\t} };\n\t\tconst data = await this.executeGraphQL(mutation, variables);\n\t\tif (!data.touchChannel.success) throw new GraphQLRequestError(\"touchChannel returned success=false\", \"graphql\");\n\t\treturn { ackOrdinal: data.touchChannel.ackOrdinal };\n\t}\n\t/**\n\t* Fire-and-forget push with retry on recoverable errors.\n\t* On success, clears push blocked state. On recoverable error, blocks\n\t* further pushes and schedules a retry. On unrecoverable error, moves\n\t* ops to deadLetter.\n\t*/\n\tattemptPush(syncOps) {\n\t\tthis.isPushing = true;\n\t\tthis.pushSyncOperations(syncOps).then(() => {\n\t\t\tthis.isPushing = false;\n\t\t\tthis.pushBlocked = false;\n\t\t\tthis.pushFailureCount = 0;\n\t\t\tif (this.connectionState === \"reconnecting\" || this.connectionState === \"error\") this.transitionConnectionState(\"connected\");\n\t\t\tthis.drainOutbox();\n\t\t}).catch((error) => {\n\t\t\tthis.isPushing = false;\n\t\t\tthis.pendingDrain = false;\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\tif (err.message.includes(\"Channel not found\")) {\n\t\t\t\tthis.pushBlocked = true;\n\t\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\t\tthis.recoverFromChannelNotFound();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.classifyError(err) === \"recoverable\") {\n\t\t\t\tthis.pushFailureCount++;\n\t\t\t\tthis.pushBlocked = true;\n\t\t\t\tthis.logger.error(\"GqlChannel push failed (attempt @FailureCount), will retry: @Error\", this.pushFailureCount, err);\n\t\t\t\tthis.transitionConnectionState(\"reconnecting\");\n\t\t\t\tthis.schedulePushRetry();\n\t\t\t} else {\n\t\t\t\tconst channelError = new ChannelError(ChannelErrorSource.Outbox, err);\n\t\t\t\tfor (const syncOp of syncOps) syncOp.failed(channelError);\n\t\t\t\tthis.deadLetter.add(...syncOps);\n\t\t\t\tthis.outbox.remove(...syncOps);\n\t\t\t\tthis.requiresAuth = isDriveAuthError(err);\n\t\t\t\tthis.transitionConnectionState(\"error\");\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Schedules a retry of all current outbox items using exponential backoff.\n\t*/\n\tschedulePushRetry() {\n\t\tif (this.pushRetryTimer) return;\n\t\tconst delay = calculateBackoffDelay(this.pushFailureCount, this.config.retryBaseDelayMs, this.config.retryMaxDelayMs, Math.random());\n\t\tthis.pushRetryTimer = setTimeout(() => {\n\t\t\tthis.pushRetryTimer = null;\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst allItems = this.outbox.items;\n\t\t\tif (allItems.length === 0) {\n\t\t\t\tthis.pushBlocked = false;\n\t\t\t\tthis.pushFailureCount = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.attemptPush([...allItems]);\n\t\t}, delay);\n\t}\n\t/**\n\t* Drains pending outbox items that arrived while a push was in-flight.\n\t* Server-side action.id dedup handles any overlap with the previous push.\n\t*/\n\tdrainOutbox() {\n\t\tif (!this.pendingDrain) return;\n\t\tthis.pendingDrain = false;\n\t\tif (this.isShutdown) return;\n\t\tconst items = this.outbox.items;\n\t\tif (items.length === 0) return;\n\t\tthis.attemptPush([...items]);\n\t}\n\t/**\n\t* Classifies an error as recoverable or unrecoverable based on its type.\n\t* Recoverable errors are transient and worth retrying (network, 5xx, parse).\n\t* Unrecoverable errors will not self-heal (auth, client errors, GraphQL rejections).\n\t*/\n\tclassifyError(error) {\n\t\tif (!(error instanceof GraphQLRequestError)) return \"recoverable\";\n\t\tswitch (error.category) {\n\t\t\tcase \"network\": return \"recoverable\";\n\t\t\tcase \"http\":\n\t\t\t\tif (error.statusCode !== void 0 && error.statusCode >= 500) return \"recoverable\";\n\t\t\t\treturn \"unrecoverable\";\n\t\t\tcase \"parse\": return \"recoverable\";\n\t\t\tcase \"graphql\": return isRecoverableGraphQLError(error) ? \"recoverable\" : \"unrecoverable\";\n\t\t\tcase \"missing-data\": return \"unrecoverable\";\n\t\t}\n\t}\n\t/**\n\t* Pushes multiple sync operations to the remote via a single GraphQL mutation.\n\t* Creates one SyncEnvelope per SyncOperation with key/dependsOn for batch ordering.\n\t*/\n\tasync pushSyncOperations(syncOps) {\n\t\tfor (const syncOp of syncOps) syncOp.started();\n\t\tconst jobIdToKeys = /* @__PURE__ */ new Map();\n\t\tconst envelopes = [];\n\t\tfor (let i = 0; i < syncOps.length; i++) {\n\t\t\tconst syncOp = syncOps[i];\n\t\t\tconst key = String(i);\n\t\t\tif (syncOp.jobId) {\n\t\t\t\tif (!jobIdToKeys.has(syncOp.jobId)) jobIdToKeys.set(syncOp.jobId, []);\n\t\t\t\tjobIdToKeys.get(syncOp.jobId).push(key);\n\t\t\t}\n\t\t\tconst dependsOn = [];\n\t\t\tfor (const dep of syncOp.jobDependencies) {\n\t\t\t\tconst depKeys = jobIdToKeys.get(dep);\n\t\t\t\tif (depKeys) dependsOn.push(...depKeys);\n\t\t\t}\n\t\t\tthis.logger.debug(\"[PUSH]: @Operations\", syncOp.operations.map((op) => `(${op.context.documentId}, ${op.context.branch}, ${op.context.scope}, ${op.operation.index})`));\n\t\t\tenvelopes.push({\n\t\t\t\ttype: \"operations\",\n\t\t\t\tchannelMeta: { id: this.channelId },\n\t\t\t\toperations: syncOp.operations,\n\t\t\t\tkey,\n\t\t\t\tdependsOn\n\t\t\t});\n\t\t}\n\t\tconst mutation = `\n mutation PushSyncEnvelopes($envelopes: [SyncEnvelopeInput!]!) {\n pushSyncEnvelopes(envelopes: $envelopes)\n }\n `;\n\t\tconst variables = { envelopes: envelopes.map((e) => serializeEnvelope(e)) };\n\t\tawait this.executeGraphQL(mutation, variables);\n\t}\n\t/**\n\t* Gets the authorization header value using jwtHandler.\n\t*/\n\tasync getAuthorizationHeader() {\n\t\tif (!this.config.jwtHandler) return;\n\t\ttry {\n\t\t\tconst token = await this.config.jwtHandler(this.config.url);\n\t\t\tif (token) return `Bearer ${token}`;\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"JWT handler failed: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Executes a GraphQL query or mutation against the remote endpoint.\n\t*/\n\tasync executeGraphQL(query, variables) {\n\t\tconst headers = { \"Content-Type\": \"application/json\" };\n\t\tconst authHeader = await this.getAuthorizationHeader();\n\t\tif (authHeader) headers[\"Authorization\"] = authHeader;\n\t\tconst operationName = query.match(/(?:query|mutation)\\s+(\\w+)/)?.[1] ?? \"unknown\";\n\t\tthis.logger.verbose(\"GQL request @channelId @operation @url vars=@variables\", this.channelId, operationName, this.config.url, JSON.stringify(variables));\n\t\tconst fetchFn = this.config.fetchFn ?? fetch;\n\t\tlet response;\n\t\ttry {\n\t\t\tresponse = await fetchFn(this.config.url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tquery,\n\t\t\t\t\tvariables\n\t\t\t\t}),\n\t\t\t\tsignal: this.abortController.signal\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow new GraphQLRequestError(`GraphQL request failed: ${error instanceof Error ? error.message : String(error)}`, \"network\");\n\t\t}\n\t\tif (!response.ok) throw new GraphQLRequestError(`GraphQL request failed: ${response.status} ${response.statusText}`, \"http\", response.status);\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await response.json();\n\t\t} catch (error) {\n\t\t\tthrow new GraphQLRequestError(`Failed to parse GraphQL response: ${error instanceof Error ? error.message : String(error)}`, \"parse\");\n\t\t}\n\t\tthis.logger.verbose(\"GQL response @channelId @operation status=@status data=@data errors=@errors\", this.channelId, operationName, response.status, JSON.stringify(result.data), result.errors ? JSON.stringify(result.errors) : \"none\");\n\t\tif (result.errors) throw new GraphQLRequestError(`GraphQL errors: ${JSON.stringify(result.errors, null, 2)}`, \"graphql\", void 0, result.errors.map((error) => error.extensions?.code));\n\t\tif (!result.data) throw new GraphQLRequestError(\"GraphQL response missing data field\", \"missing-data\");\n\t\treturn result.data;\n\t}\n\tget poller() {\n\t\treturn this.pollTimer;\n\t}\n};\n//#endregion\n//#region src/sync/channels/gql-request-channel-factory.ts\n/**\n* Factory for creating GqlRequestChannel instances.\n*\n* Extracts GraphQL-specific configuration from ChannelConfig.parameters and\n* instantiates GqlRequestChannel instances for network-based synchronization.\n*\n* The optional jwtHandler enables dynamic JWT token generation per-request,\n* which is useful for short-lived tokens with audience-specific claims.\n*/\nvar GqlRequestChannelFactory = class {\n\tlogger;\n\tjwtHandler;\n\tqueue;\n\tconstructor(logger, jwtHandler, queue) {\n\t\tthis.logger = logger;\n\t\tthis.jwtHandler = jwtHandler;\n\t\tthis.queue = queue;\n\t}\n\t/**\n\t* Creates a new GqlRequestChannel instance with the given configuration.\n\t* See GqlChannelConfig for the expected parameters.\n\t*\n\t* @param config - Channel configuration including type and parameters\n\t* @param cursorStorage - Storage for persisting synchronization cursors\n\t* @param operationIndex - Operation index for querying timestamps\n\t* @returns A new GqlRequestChannel instance\n\t*/\n\tinstance(remoteId, remoteName, config, cursorStorage, collectionId, filter, operationIndex, options) {\n\t\tconst url = config.parameters.url;\n\t\tif (typeof url !== \"string\" || !url) throw new Error(\"GqlRequestChannelFactory requires \\\"url\\\" parameter in config.parameters\");\n\t\tconst gqlConfig = {\n\t\t\turl,\n\t\t\tcollectionId,\n\t\t\tfilter,\n\t\t\tjwtHandler: this.jwtHandler,\n\t\t\tretryBaseDelayMs: 1e3,\n\t\t\tretryMaxDelayMs: 3e5\n\t\t};\n\t\tlet pollIntervalMs = 2e3;\n\t\tif (config.parameters.pollIntervalMs !== void 0) {\n\t\t\tif (typeof config.parameters.pollIntervalMs !== \"number\") throw new Error(\"\\\"pollIntervalMs\\\" parameter must be a number\");\n\t\t\tpollIntervalMs = config.parameters.pollIntervalMs;\n\t\t}\n\t\tlet retryBaseDelayMs;\n\t\tif (config.parameters.retryBaseDelayMs !== void 0) {\n\t\t\tif (typeof config.parameters.retryBaseDelayMs !== \"number\") throw new Error(\"\\\"retryBaseDelayMs\\\" parameter must be a number\");\n\t\t\tretryBaseDelayMs = config.parameters.retryBaseDelayMs;\n\t\t}\n\t\tlet retryMaxDelayMs;\n\t\tif (config.parameters.retryMaxDelayMs !== void 0) {\n\t\t\tif (typeof config.parameters.retryMaxDelayMs !== \"number\") throw new Error(\"\\\"retryMaxDelayMs\\\" parameter must be a number\");\n\t\t\tretryMaxDelayMs = config.parameters.retryMaxDelayMs;\n\t\t}\n\t\tif (config.parameters.fetchFn !== void 0) {\n\t\t\tif (typeof config.parameters.fetchFn !== \"function\") throw new Error(\"\\\"fetchFn\\\" parameter must be a function\");\n\t\t\tgqlConfig.fetchFn = config.parameters.fetchFn;\n\t\t}\n\t\tif (retryBaseDelayMs !== void 0) gqlConfig.retryBaseDelayMs = retryBaseDelayMs;\n\t\tif (retryMaxDelayMs !== void 0) gqlConfig.retryMaxDelayMs = retryMaxDelayMs;\n\t\tlet maxQueueDepth;\n\t\tif (config.parameters.maxQueueDepth !== void 0) {\n\t\t\tif (typeof config.parameters.maxQueueDepth !== \"number\") throw new Error(\"\\\"maxQueueDepth\\\" parameter must be a number\");\n\t\t\tmaxQueueDepth = config.parameters.maxQueueDepth;\n\t\t}\n\t\tlet backpressureCheckIntervalMs;\n\t\tif (config.parameters.backpressureCheckIntervalMs !== void 0) {\n\t\t\tif (typeof config.parameters.backpressureCheckIntervalMs !== \"number\") throw new Error(\"\\\"backpressureCheckIntervalMs\\\" parameter must be a number\");\n\t\t\tbackpressureCheckIntervalMs = config.parameters.backpressureCheckIntervalMs;\n\t\t}\n\t\tconst pollTimer = new IntervalPollTimer(this.queue, {\n\t\t\tintervalMs: pollIntervalMs,\n\t\t\t...retryBaseDelayMs !== void 0 && { retryBaseDelayMs },\n\t\t\t...retryMaxDelayMs !== void 0 && { retryMaxDelayMs },\n\t\t\t...maxQueueDepth !== void 0 && { maxQueueDepth },\n\t\t\t...backpressureCheckIntervalMs !== void 0 && { backpressureCheckIntervalMs },\n\t\t\tstartPaused: options?.pollBehavior === PollBehavior.Manual\n\t\t});\n\t\treturn new GqlRequestChannel(this.logger, remoteId, remoteName, cursorStorage, gqlConfig, operationIndex, pollTimer);\n\t}\n};\n//#endregion\n//#region src/sync/channels/gql-res-channel.ts\n/** Where a sync operation's run of ordinals begins. */\nfunction firstOrdinalOf$1(syncOp) {\n\treturn syncOp.operations.length > 0 ? syncOp.operations[0].context.ordinal : 0;\n}\n/**\n* This class is used server-side to accumulate inbox + outbox operations.\n*\n* In general, the resolvers are responsible for updating mailboxes.\n*/\nvar GqlResponseChannel = class {\n\tinbox;\n\toutbox;\n\tdeadLetter;\n\tchannelId;\n\tremoteName;\n\tcursorStorage;\n\tisShutdown;\n\tlastPersistedInboxOrdinal = 0;\n\tlastPersistedOutboxOrdinal = 0;\n\tevictedOutboxFloor = Number.POSITIVE_INFINITY;\n\tappliedOutboxOrdinal = 0;\n\tlastPollUtcMs = Date.now();\n\tconnectionState = \"connecting\";\n\tconnectionStateCallbacks = /* @__PURE__ */ new Set();\n\tconstructor(logger, channelId, remoteName, cursorStorage) {\n\t\tthis.logger = logger;\n\t\tthis.channelId = channelId;\n\t\tthis.remoteName = remoteName;\n\t\tthis.cursorStorage = cursorStorage;\n\t\tthis.isShutdown = false;\n\t\tthis.inbox = new Mailbox();\n\t\tthis.outbox = new Mailbox();\n\t\tthis.deadLetter = new Mailbox();\n\t\tthis.outbox.onRemoved((syncOps) => {\n\t\t\tthis.rememberUnserved(syncOps);\n\t\t\tthis.persistOutboxCursor(getLatestAppliedOrdinal(syncOps));\n\t\t});\n\t\tthis.outbox.onAdded((syncOps) => {\n\t\t\tthis.forgetEvictedBelow(syncOps);\n\t\t});\n\t\tthis.inbox.onRemoved((syncOps) => {\n\t\t\tconst maxOrdinal = getLatestAppliedOrdinal(syncOps);\n\t\t\tif (maxOrdinal > this.lastPersistedInboxOrdinal) {\n\t\t\t\tthis.lastPersistedInboxOrdinal = maxOrdinal;\n\t\t\t\tthis.cursorStorage.upsert({\n\t\t\t\t\tremoteName: this.remoteName,\n\t\t\t\t\tcursorType: \"inbox\",\n\t\t\t\t\tcursorOrdinal: maxOrdinal,\n\t\t\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t\t\t}).catch((error) => {\n\t\t\t\t\tthis.logger.error(\"Failed to update inbox cursor for @ChannelId! This is unlikely to cause a problem, but not-optimal: @Error\", this.channelId, error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\tshutdown() {\n\t\tthis.isShutdown = true;\n\t\tthis.transitionConnectionState(\"disconnected\");\n\t\treturn Promise.resolve();\n\t}\n\tgetConnectionState() {\n\t\treturn {\n\t\t\tstate: this.connectionState,\n\t\t\tfailureCount: 0,\n\t\t\tlastSuccessUtcMs: this.lastPollUtcMs,\n\t\t\tlastFailureUtcMs: 0,\n\t\t\tpushBlocked: false,\n\t\t\tpushFailureCount: 0,\n\t\t\treceivingPages: false,\n\t\t\trequiresAuth: false\n\t\t};\n\t}\n\tonConnectionStateChange(callback) {\n\t\tthis.connectionStateCallbacks.add(callback);\n\t\treturn () => {\n\t\t\tthis.connectionStateCallbacks.delete(callback);\n\t\t};\n\t}\n\t/** Response channels are push-driven; resolvers populate mailboxes directly. */\n\ttriggerPull() {}\n\tnotePoll() {\n\t\tthis.lastPollUtcMs = Date.now();\n\t}\n\t/** This channel is served: its holder's polls are the liveness it reports. */\n\tlastHolderPollUtcMs() {\n\t\treturn this.lastPollUtcMs;\n\t}\n\tasync init() {\n\t\tconst cursors = await this.cursorStorage.list(this.remoteName);\n\t\tconst inboxOrdinal = cursors.find((c) => c.cursorType === \"inbox\")?.cursorOrdinal ?? 0;\n\t\tconst outboxOrdinal = cursors.find((c) => c.cursorType === \"outbox\")?.cursorOrdinal ?? 0;\n\t\tthis.inbox.init(inboxOrdinal);\n\t\tthis.outbox.init(outboxOrdinal);\n\t\tthis.lastPersistedInboxOrdinal = inboxOrdinal;\n\t\tthis.lastPersistedOutboxOrdinal = outboxOrdinal;\n\t\tthis.appliedOutboxOrdinal = outboxOrdinal;\n\t\tthis.transitionConnectionState(\"connected\");\n\t}\n\ttransitionConnectionState(next) {\n\t\tif (this.connectionState === next) return;\n\t\tthis.connectionState = next;\n\t\tconst snapshot = this.getConnectionState();\n\t\tfor (const callback of this.connectionStateCallbacks) try {\n\t\t\tcallback(snapshot);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Connection state change callback error: @Error\", error);\n\t\t}\n\t}\n\t/**\n\t* Records the ordinals of entries that left the outbox without being served,\n\t* so the cursor cannot advance past them.\n\t*\n\t* An entry can leave unserved because a bound evicted it, and an evicted entry\n\t* is exactly one this channel intends to re-derive: it is still owed to the\n\t* remote. Remembering the floor across the whole run rather than only while\n\t* the entry is present is what makes that true after a later ack would\n\t* otherwise have swept the cursor past it.\n\t*/\n\trememberUnserved(syncOps) {\n\t\tfor (const syncOp of syncOps) {\n\t\t\tif (syncOp.status === SyncOperationStatus.Applied) continue;\n\t\t\tconst first = firstOrdinalOf$1(syncOp);\n\t\t\tif (first > 0 && first < this.evictedOutboxFloor) this.evictedOutboxFloor = first;\n\t\t}\n\t}\n\t/**\n\t* Persists the outbox cursor, never past an operation this remote has not\n\t* been served.\n\t*\n\t* The cursor is where a restart resumes deriving the outbox from, so an\n\t* ordinal persisted past an unserved entry loses that entry for good: the\n\t* rebuild starts beyond it and nothing else remembers it was owed. Acks\n\t* arrive out of order with respect to what is withheld -- a later entry can\n\t* be acknowledged while an earlier one is still being withheld from this\n\t* subject -- so the applied high-water mark alone is not a safe cursor.\n\t*/\n\tpersistOutboxCursor(appliedOrdinal) {\n\t\tthis.appliedOutboxOrdinal = Math.max(this.appliedOutboxOrdinal, appliedOrdinal);\n\t\tconst ordinal = Math.min(this.appliedOutboxOrdinal, this.unservedFloor() - 1);\n\t\tif (ordinal <= this.lastPersistedOutboxOrdinal) return;\n\t\tthis.lastPersistedOutboxOrdinal = ordinal;\n\t\tthis.cursorStorage.upsert({\n\t\t\tremoteName: this.remoteName,\n\t\t\tcursorType: \"outbox\",\n\t\t\tcursorOrdinal: ordinal,\n\t\t\tlastSyncedAtUtcMs: Date.now()\n\t\t}).catch((error) => {\n\t\t\tthis.logger.error(\"Failed to update outbox cursor for @ChannelId! This means that future application runs may resend duplicate operations. This is recoverable (with deduplication protection), but not-optimal: @Error\", this.channelId, error);\n\t\t});\n\t}\n\t/** Drops the evicted floor once the entries it stood for are queued again. */\n\tforgetEvictedBelow(syncOps) {\n\t\tif (this.evictedOutboxFloor === Number.POSITIVE_INFINITY) return;\n\t\tfor (const syncOp of syncOps) {\n\t\t\tconst first = firstOrdinalOf$1(syncOp);\n\t\t\tif (first > 0 && first <= this.evictedOutboxFloor) {\n\t\t\t\tthis.evictedOutboxFloor = Number.POSITIVE_INFINITY;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\t/** The lowest ordinal still owed to this remote, evicted or still queued. */\n\tunservedFloor() {\n\t\tlet floor = this.evictedOutboxFloor;\n\t\tfor (const syncOp of this.outbox.items) {\n\t\t\tif (syncOp.status === SyncOperationStatus.Applied) continue;\n\t\t\tconst first = firstOrdinalOf$1(syncOp);\n\t\t\tif (first > 0 && first < floor) floor = first;\n\t\t}\n\t\treturn floor;\n\t}\n};\n//#endregion\n//#region src/sync/channels/gql-response-channel-factory.ts\n/**\n* Factory for creating GqlResponseChannel instances.\n*/\nvar GqlResponseChannelFactory = class {\n\tlogger;\n\tconstructor(logger) {\n\t\tthis.logger = logger;\n\t}\n\tinstance(remoteId, remoteName, config, cursorStorage) {\n\t\treturn new GqlResponseChannel(this.logger, remoteId, remoteName, cursorStorage);\n\t}\n};\n//#endregion\n//#region src/storage/kysely/sync-cursor-storage.ts\nfunction rowToRemoteCursor(row) {\n\treturn {\n\t\tremoteName: row.remote_name,\n\t\tcursorType: row.cursor_type,\n\t\tcursorOrdinal: Number(row.cursor_ordinal),\n\t\tlastSyncedAtUtcMs: row.last_synced_at_utc_ms ? new Date(row.last_synced_at_utc_ms).getTime() : void 0\n\t};\n}\nfunction remoteCursorToRow(cursor) {\n\treturn {\n\t\tremote_name: cursor.remoteName,\n\t\tcursor_type: cursor.cursorType,\n\t\tcursor_ordinal: BigInt(cursor.cursorOrdinal),\n\t\tlast_synced_at_utc_ms: cursor.lastSyncedAtUtcMs ? new Date(cursor.lastSyncedAtUtcMs).toISOString() : null\n\t};\n}\nvar KyselySyncCursorStorage = class {\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tasync list(remoteName, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst rows = await this.db.selectFrom(\"sync_cursors\").selectAll().where(\"remote_name\", \"=\", remoteName).execute();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn rows.map(rowToRemoteCursor);\n\t}\n\tasync get(remoteName, cursorType, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst row = await this.db.selectFrom(\"sync_cursors\").selectAll().where(\"remote_name\", \"=\", remoteName).where(\"cursor_type\", \"=\", cursorType).executeTakeFirst();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tif (!row) return {\n\t\t\tremoteName,\n\t\t\tcursorType,\n\t\t\tcursorOrdinal: 0\n\t\t};\n\t\treturn rowToRemoteCursor(row);\n\t}\n\tasync upsert(cursor, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tconst insertable = remoteCursorToRow(cursor);\n\t\t\tawait trx.insertInto(\"sync_cursors\").values(insertable).onConflict((oc) => oc.columns([\"remote_name\", \"cursor_type\"]).doUpdateSet({\n\t\t\t\t...insertable,\n\t\t\t\tupdated_at: sql`NOW()`\n\t\t\t})).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync remove(remoteName, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_cursors\").where(\"remote_name\", \"=\", remoteName).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n};\n//#endregion\n//#region src/storage/kysely/sync-dead-letter-storage.ts\nfunction rowToDeadLetterRecord(row) {\n\treturn {\n\t\tid: row.id,\n\t\tjobId: row.job_id,\n\t\tjobDependencies: row.job_dependencies,\n\t\tremoteName: row.remote_name,\n\t\tdocumentId: row.document_id,\n\t\tscopes: row.scopes,\n\t\tbranch: row.branch,\n\t\toperations: row.operations,\n\t\terrorSource: row.error_source,\n\t\terrorMessage: row.error_message,\n\t\terrorType: row.error_type ?? \"UNCLASSIFIED\"\n\t};\n}\nfunction deadLetterRecordToRow(record) {\n\treturn {\n\t\tid: record.id,\n\t\tjob_id: record.jobId,\n\t\tjob_dependencies: JSON.stringify(record.jobDependencies),\n\t\tremote_name: record.remoteName,\n\t\tdocument_id: record.documentId,\n\t\tscopes: JSON.stringify(record.scopes),\n\t\tbranch: record.branch,\n\t\toperations: JSON.stringify(record.operations),\n\t\terror_source: record.errorSource,\n\t\terror_message: record.errorMessage,\n\t\terror_type: record.errorType\n\t};\n}\n/**\n* PGlite/Kysely-backed implementation of {@link ISyncDeadLetterStorage}.\n*/\nvar KyselySyncDeadLetterStorage = class {\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tasync list(remoteName, paging, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n\t\tconst limit = paging?.limit || 100;\n\t\tconst rows = await this.db.selectFrom(\"sync_dead_letters\").selectAll().where(\"remote_name\", \"=\", remoteName).orderBy(\"ordinal\", \"desc\").offset(startIndex).limit(limit + 1).execute();\n\t\tlet hasMore = false;\n\t\tlet items = rows;\n\t\tif (paging?.limit && rows.length > limit) {\n\t\t\thasMore = true;\n\t\t\titems = rows.slice(0, limit);\n\t\t}\n\t\tconst nextCursor = hasMore ? String(startIndex + limit) : void 0;\n\t\tconst cursor = paging?.cursor || \"0\";\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn {\n\t\t\tresults: items.map(rowToDeadLetterRecord),\n\t\t\toptions: {\n\t\t\t\tcursor,\n\t\t\t\tlimit\n\t\t\t},\n\t\t\tnextCursor\n\t\t};\n\t}\n\tasync add(deadLetter, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tconst insertable = deadLetterRecordToRow(deadLetter);\n\t\t\tawait trx.insertInto(\"sync_dead_letters\").values(insertable).onConflict((oc) => oc.column(\"id\").doNothing()).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync remove(id, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_dead_letters\").where(\"id\", \"=\", id).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync removeByRemote(remoteName, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_dead_letters\").where(\"remote_name\", \"=\", remoteName).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync listQuarantinedDocumentIds(signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst rows = await this.db.selectFrom(\"sync_dead_letters\").select([\"document_id\", \"error_type\"]).distinct().execute();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst quarantined = /* @__PURE__ */ new Set();\n\t\tfor (const row of rows) if (quarantinesDocument(row.error_type ?? \"UNCLASSIFIED\")) quarantined.add(row.document_id);\n\t\treturn [...quarantined];\n\t}\n};\n//#endregion\n//#region src/storage/kysely/sync-remote-storage.ts\nfunction rowToRemoteRecord(row) {\n\treturn {\n\t\tid: row.channel_id,\n\t\tname: row.name,\n\t\tcollectionId: DriveCollectionId.fromKey(row.collection_id),\n\t\tchannelConfig: {\n\t\t\ttype: row.channel_type,\n\t\t\tparameters: row.channel_parameters ?? {}\n\t\t},\n\t\tfilter: {\n\t\t\tdocumentId: row.filter_document_ids ?? [],\n\t\t\tscope: row.filter_scopes ?? [],\n\t\t\tbranch: row.filter_branch\n\t\t},\n\t\toptions: {\n\t\t\tsinceTimestampUtcMs: \"0\",\n\t\t\tboundAddress: row.bound_address ?? void 0\n\t\t},\n\t\tstatus: {\n\t\t\tpush: {\n\t\t\t\tstate: row.push_state,\n\t\t\t\tlastSuccessUtcMs: row.push_last_success_utc_ms ? new Date(row.push_last_success_utc_ms).getTime() : void 0,\n\t\t\t\tlastFailureUtcMs: row.push_last_failure_utc_ms ? new Date(row.push_last_failure_utc_ms).getTime() : void 0,\n\t\t\t\tfailureCount: row.push_failure_count\n\t\t\t},\n\t\t\tpull: {\n\t\t\t\tstate: row.pull_state,\n\t\t\t\tlastSuccessUtcMs: row.pull_last_success_utc_ms ? new Date(row.pull_last_success_utc_ms).getTime() : void 0,\n\t\t\t\tlastFailureUtcMs: row.pull_last_failure_utc_ms ? new Date(row.pull_last_failure_utc_ms).getTime() : void 0,\n\t\t\t\tfailureCount: row.pull_failure_count\n\t\t\t}\n\t\t}\n\t};\n}\n/**\n* Maps a RemoteRecord to a row. jsonb array columns are JSON-encoded because the\n* pg driver would otherwise emit a Postgres array literal (\"{a,b}\"), which jsonb\n* rejects (matches sync-dead-letter-storage).\n*/\nfunction remoteRecordToRow(remote) {\n\treturn {\n\t\tname: remote.name,\n\t\tcollection_id: remote.collectionId.key,\n\t\tchannel_type: remote.channelConfig.type,\n\t\tchannel_id: remote.id,\n\t\tremote_name: remote.name,\n\t\tchannel_parameters: remote.channelConfig.parameters,\n\t\tfilter_document_ids: remote.filter.documentId.length > 0 ? JSON.stringify(remote.filter.documentId) : null,\n\t\tfilter_scopes: remote.filter.scope.length > 0 ? JSON.stringify(remote.filter.scope) : null,\n\t\tfilter_branch: remote.filter.branch,\n\t\tpush_state: remote.status.push.state,\n\t\tpush_last_success_utc_ms: remote.status.push.lastSuccessUtcMs ? new Date(remote.status.push.lastSuccessUtcMs).toISOString() : null,\n\t\tpush_last_failure_utc_ms: remote.status.push.lastFailureUtcMs ? new Date(remote.status.push.lastFailureUtcMs).toISOString() : null,\n\t\tpush_failure_count: remote.status.push.failureCount,\n\t\tpull_state: remote.status.pull.state,\n\t\tpull_last_success_utc_ms: remote.status.pull.lastSuccessUtcMs ? new Date(remote.status.pull.lastSuccessUtcMs).toISOString() : null,\n\t\tpull_last_failure_utc_ms: remote.status.pull.lastFailureUtcMs ? new Date(remote.status.pull.lastFailureUtcMs).toISOString() : null,\n\t\tpull_failure_count: remote.status.pull.failureCount,\n\t\tbound_address: remote.options.boundAddress ?? null\n\t};\n}\nvar KyselySyncRemoteStorage = class {\n\tconstructor(db) {\n\t\tthis.db = db;\n\t}\n\tasync list(signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst rows = await this.db.selectFrom(\"sync_remotes\").selectAll().execute();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\treturn rows.map(rowToRemoteRecord);\n\t}\n\tasync get(name, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tconst row = await this.db.selectFrom(\"sync_remotes\").selectAll().where(\"name\", \"=\", name).executeTakeFirst();\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tif (!row) throw new Error(`Remote not found: ${name}`);\n\t\treturn rowToRemoteRecord(row);\n\t}\n\tasync upsert(remote, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tconst insertable = remoteRecordToRow(remote);\n\t\t\tawait trx.insertInto(\"sync_remotes\").values(insertable).onConflict((oc) => oc.column(\"name\").doUpdateSet({\n\t\t\t\t...insertable,\n\t\t\t\tupdated_at: sql`NOW()`\n\t\t\t})).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n\tasync remove(name, signal) {\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"sync_remotes\").where(\"name\", \"=\", name).execute();\n\t\t});\n\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t}\n};\n//#endregion\n//#region src/sync/batch-aggregator.ts\nvar BatchAggregator = class {\n\tlogger;\n\tdriveContainerTypes;\n\tonBatchReady;\n\tqueue = [];\n\tprocessing = false;\n\tpendingBatches = /* @__PURE__ */ new Map();\n\tconstructor(logger, driveContainerTypes, onBatchReady) {\n\t\tthis.logger = logger;\n\t\tthis.driveContainerTypes = driveContainerTypes;\n\t\tthis.onBatchReady = onBatchReady;\n\t}\n\tasync enqueueWriteReady(event) {\n\t\tthis.queue.push(event);\n\t\tawait this.processQueue();\n\t}\n\tasync handleJobFailed(event) {\n\t\tconst batchId = event.job?.meta.batchId;\n\t\tif (!batchId) return;\n\t\tconst pending = this.pendingBatches.get(batchId);\n\t\tif (!pending) return;\n\t\tthis.pendingBatches.delete(batchId);\n\t\tif (pending.events.length > 0) await this.onBatchReady(this.prepareBatch(pending.events));\n\t}\n\tclear() {\n\t\tthis.queue = [];\n\t\tthis.pendingBatches.clear();\n\t}\n\tasync processQueue() {\n\t\tif (this.processing) return;\n\t\tthis.processing = true;\n\t\ttry {\n\t\t\twhile (this.queue.length > 0) {\n\t\t\t\tconst event = this.queue.shift();\n\t\t\t\ttry {\n\t\t\t\t\tawait this.handleWriteReady(event);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\tthis.logger.error(\"Failed to process write-ready event (@jobId, @error)\", event.jobId, err.message);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.processing = false;\n\t\t}\n\t}\n\tasync handleWriteReady(event) {\n\t\tconst { batchId, batchJobIds } = event.jobMeta;\n\t\tif (batchJobIds.length <= 1) {\n\t\t\tawait this.onBatchReady(this.prepareBatch([event]));\n\t\t\treturn;\n\t\t}\n\t\tlet pending = this.pendingBatches.get(batchId);\n\t\tif (!pending) {\n\t\t\tpending = {\n\t\t\t\texpectedJobIds: new Set(batchJobIds),\n\t\t\t\tarrivedJobIds: /* @__PURE__ */ new Set(),\n\t\t\t\tevents: []\n\t\t\t};\n\t\t\tthis.pendingBatches.set(batchId, pending);\n\t\t}\n\t\tpending.arrivedJobIds.add(event.jobId);\n\t\tpending.events.push(event);\n\t\tif (pending.arrivedJobIds.size >= pending.expectedJobIds.size) {\n\t\t\tthis.pendingBatches.delete(batchId);\n\t\t\tawait this.onBatchReady(this.prepareBatch(pending.events));\n\t\t}\n\t}\n\tprepareBatch(events) {\n\t\tconst collectionMemberships = this.mergeCollectionMemberships(events);\n\t\tconst isBatch = events.length > 1;\n\t\tconst priorJobIds = [];\n\t\tconst entries = [];\n\t\tfor (const event of events) {\n\t\t\tentries.push({\n\t\t\t\tevent,\n\t\t\t\tjobDependencies: isBatch ? [...priorJobIds] : []\n\t\t\t});\n\t\t\tif (isBatch && event.jobId) priorJobIds.push(event.jobId);\n\t\t}\n\t\treturn {\n\t\t\tcollectionMemberships,\n\t\t\tentries\n\t\t};\n\t}\n\tmergeCollectionMemberships(events) {\n\t\tconst mergedMemberships = {};\n\t\tfor (const event of events) {\n\t\t\tif (event.collectionMemberships) for (const [docId, collections] of Object.entries(event.collectionMemberships)) {\n\t\t\t\tif (!(docId in mergedMemberships)) mergedMemberships[docId] = [];\n\t\t\t\tfor (const c of collections) if (!mergedMemberships[docId].includes(c)) mergedMemberships[docId].push(c);\n\t\t\t}\n\t\t\tfor (const op of event.operations) {\n\t\t\t\tconst action = op.operation.action;\n\t\t\t\tif (action.type !== \"ADD_RELATIONSHIP\") continue;\n\t\t\t\tif (!this.driveContainerTypes.has(op.context.documentType)) continue;\n\t\t\t\tconst input = action.input;\n\t\t\t\tif (!input?.sourceId || !input.targetId) continue;\n\t\t\t\tconst collectionId = DriveCollectionId.forDrive(input.sourceId, op.context.branch).key;\n\t\t\t\tif (!(input.targetId in mergedMemberships)) mergedMemberships[input.targetId] = [];\n\t\t\t\tif (!mergedMemberships[input.targetId].includes(collectionId)) mergedMemberships[input.targetId].push(collectionId);\n\t\t\t}\n\t\t}\n\t\treturn mergedMemberships;\n\t}\n};\n//#endregion\n//#region src/sync/sync-awaiter.ts\n/**\n* Provides a promise-based interface for waiting on sync completion.\n* Subscribes to sync events at construction and tracks completed sync results\n* to provide a fast path for jobs that have already synced.\n*/\nvar SyncAwaiter = class {\n\tcompletedResults = /* @__PURE__ */ new Map();\n\tpendingWaiters = /* @__PURE__ */ new Map();\n\tunsubscribers = [];\n\tisShutdown = false;\n\tconstructor(eventBus) {\n\t\tthis.eventBus = eventBus;\n\t\tthis.subscribeToEvents();\n\t}\n\t/**\n\t* Waits for sync operations for a job to complete.\n\t* Resolves when SYNC_SUCCEEDED is emitted.\n\t* Rejects when SYNC_FAILED is emitted.\n\t*\n\t* @param jobId - The job id to wait for\n\t* @param signal - Optional abort signal\n\t* @returns The sync result\n\t*/\n\twaitForSync(jobId, signal) {\n\t\tif (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\tif (this.isShutdown) return Promise.reject(/* @__PURE__ */ new Error(\"SyncAwaiter is shutdown\"));\n\t\tconst completedResult = this.completedResults.get(jobId);\n\t\tif (completedResult) return Promise.resolve(completedResult);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst waiter = {\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t\tsignal\n\t\t\t};\n\t\t\tconst existingWaiters = this.pendingWaiters.get(jobId) || [];\n\t\t\texistingWaiters.push(waiter);\n\t\t\tthis.pendingWaiters.set(jobId, existingWaiters);\n\t\t\tif (signal) {\n\t\t\t\tconst abortHandler = () => {\n\t\t\t\t\tconst waiters = this.pendingWaiters.get(jobId);\n\t\t\t\t\tif (waiters) {\n\t\t\t\t\t\tconst index = waiters.indexOf(waiter);\n\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\twaiters.splice(index, 1);\n\t\t\t\t\t\t\tif (waiters.length === 0) this.pendingWaiters.delete(jobId);\n\t\t\t\t\t\t\twaiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", abortHandler, { once: true });\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t* Shuts down the sync awaiter. This will synchronously reject all pending waiters.\n\t*/\n\tshutdown() {\n\t\tthis.isShutdown = true;\n\t\tfor (const unsubscribe of this.unsubscribers) unsubscribe();\n\t\tthis.unsubscribers.length = 0;\n\t\tfor (const [, waiters] of this.pendingWaiters) for (const waiter of waiters) waiter.reject(/* @__PURE__ */ new Error(\"SyncAwaiter shutdown\"));\n\t\tthis.pendingWaiters.clear();\n\t}\n\tsubscribeToEvents() {\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(SyncEventTypes.SYNC_SUCCEEDED, (_type, event) => {\n\t\t\tthis.handleSyncSucceeded(event);\n\t\t}));\n\t\tthis.unsubscribers.push(this.eventBus.subscribe(SyncEventTypes.SYNC_FAILED, (_type, event) => {\n\t\t\tthis.handleSyncFailed(event);\n\t\t}));\n\t}\n\thandleSyncSucceeded(event) {\n\t\tconst result = {\n\t\t\tjobId: event.jobId,\n\t\t\tstatus: \"succeeded\",\n\t\t\tsyncOperationCount: event.syncOperationCount,\n\t\t\tsuccessCount: event.syncOperationCount,\n\t\t\tfailureCount: 0,\n\t\t\terrors: []\n\t\t};\n\t\tthis.completedResults.set(event.jobId, result);\n\t\tthis.resolveWaiters(event.jobId, result);\n\t}\n\thandleSyncFailed(event) {\n\t\tconst result = {\n\t\t\tjobId: event.jobId,\n\t\t\tstatus: \"failed\",\n\t\t\tsyncOperationCount: event.successCount + event.failureCount,\n\t\t\tsuccessCount: event.successCount,\n\t\t\tfailureCount: event.failureCount,\n\t\t\terrors: event.errors\n\t\t};\n\t\tthis.completedResults.set(event.jobId, result);\n\t\tthis.resolveWaiters(event.jobId, result);\n\t}\n\tresolveWaiters(jobId, result) {\n\t\tconst waiters = this.pendingWaiters.get(jobId);\n\t\tif (!waiters || waiters.length === 0) return;\n\t\tthis.pendingWaiters.delete(jobId);\n\t\tfor (const waiter of waiters) if (waiter.signal?.aborted) waiter.reject(/* @__PURE__ */ new Error(\"Operation aborted\"));\n\t\telse waiter.resolve(result);\n\t}\n};\n//#endregion\n//#region src/sync/sync-status-tracker.ts\nlet SyncStatus = /* @__PURE__ */ function(SyncStatus) {\n\tSyncStatus[\"Synced\"] = \"SYNCED\";\n\tSyncStatus[\"Outgoing\"] = \"OUTGOING\";\n\tSyncStatus[\"Incoming\"] = \"INCOMING\";\n\tSyncStatus[\"OutgoingAndIncoming\"] = \"OUTGOING_AND_INCOMING\";\n\tSyncStatus[\"Error\"] = \"ERROR\";\n\treturn SyncStatus;\n}({});\nvar SyncStatusTracker = class {\n\tremotes = /* @__PURE__ */ new Map();\n\tseen = /* @__PURE__ */ new Set();\n\tcallbacks = /* @__PURE__ */ new Set();\n\tgetStatus(documentId) {\n\t\tif (!this.seen.has(documentId)) return;\n\t\tlet totalInbox = 0;\n\t\tlet totalOutbox = 0;\n\t\tlet totalErrors = 0;\n\t\tfor (const documents of this.remotes.values()) {\n\t\t\tconst counts = documents.get(documentId);\n\t\t\tif (counts) {\n\t\t\t\ttotalInbox += counts.inboxCount;\n\t\t\t\ttotalOutbox += counts.outboxCount;\n\t\t\t\ttotalErrors += counts.errorCount;\n\t\t\t}\n\t\t}\n\t\treturn deriveStatus(totalInbox, totalOutbox, totalErrors);\n\t}\n\tonChange(callback) {\n\t\tthis.callbacks.add(callback);\n\t\treturn () => {\n\t\t\tthis.callbacks.delete(callback);\n\t\t};\n\t}\n\ttrackRemote(remoteName, channel) {\n\t\tthis.remotes.set(remoteName, /* @__PURE__ */ new Map());\n\t\tchannel.inbox.onAdded((syncOps) => this.handleAdded(remoteName, \"inbox\", syncOps));\n\t\tchannel.inbox.onRemoved((syncOps) => this.handleRemoved(remoteName, \"inbox\", syncOps));\n\t\tchannel.outbox.onAdded((syncOps) => this.handleAdded(remoteName, \"outbox\", syncOps));\n\t\tchannel.outbox.onRemoved((syncOps) => this.handleRemoved(remoteName, \"outbox\", syncOps));\n\t\tchannel.deadLetter.onAdded((syncOps) => this.handleAdded(remoteName, \"deadLetter\", syncOps));\n\t}\n\tuntrackRemote(remoteName) {\n\t\tconst documents = this.remotes.get(remoteName);\n\t\tif (!documents) return;\n\t\tconst affectedDocumentIds = [...documents.keys()];\n\t\tthis.remotes.delete(remoteName);\n\t\tfor (const documentId of affectedDocumentIds) this.notifyChange(documentId);\n\t}\n\tclear() {\n\t\tthis.remotes.clear();\n\t\tthis.seen.clear();\n\t\tthis.callbacks.clear();\n\t}\n\thandleAdded(remoteName, mailboxType, syncOps) {\n\t\tconst changedDocuments = /* @__PURE__ */ new Set();\n\t\tfor (const syncOp of syncOps) {\n\t\t\tif (mailboxType === \"inbox\" && !syncOp.remoteName) continue;\n\t\t\tconst counts = this.getOrCreateCounts(remoteName, syncOp.documentId);\n\t\t\tthis.seen.add(syncOp.documentId);\n\t\t\tif (mailboxType === \"inbox\") counts.inboxCount++;\n\t\t\telse if (mailboxType === \"outbox\") counts.outboxCount++;\n\t\t\telse counts.errorCount++;\n\t\t\tchangedDocuments.add(syncOp.documentId);\n\t\t}\n\t\tfor (const documentId of changedDocuments) this.notifyChange(documentId);\n\t}\n\thandleRemoved(remoteName, mailboxType, syncOps) {\n\t\tconst changedDocuments = /* @__PURE__ */ new Set();\n\t\tfor (const syncOp of syncOps) {\n\t\t\tconst counts = this.getOrCreateCounts(remoteName, syncOp.documentId);\n\t\t\tif (mailboxType === \"inbox\") counts.inboxCount = Math.max(0, counts.inboxCount - 1);\n\t\t\telse if (mailboxType === \"outbox\") counts.outboxCount = Math.max(0, counts.outboxCount - 1);\n\t\t\tchangedDocuments.add(syncOp.documentId);\n\t\t}\n\t\tfor (const documentId of changedDocuments) this.notifyChange(documentId);\n\t}\n\tgetOrCreateCounts(remoteName, documentId) {\n\t\tlet documents = this.remotes.get(remoteName);\n\t\tif (!documents) {\n\t\t\tdocuments = /* @__PURE__ */ new Map();\n\t\t\tthis.remotes.set(remoteName, documents);\n\t\t}\n\t\tlet counts = documents.get(documentId);\n\t\tif (!counts) {\n\t\t\tcounts = {\n\t\t\t\tinboxCount: 0,\n\t\t\t\toutboxCount: 0,\n\t\t\t\terrorCount: 0\n\t\t\t};\n\t\t\tdocuments.set(documentId, counts);\n\t\t}\n\t\treturn counts;\n\t}\n\tnotifyChange(documentId) {\n\t\tconst status = this.getStatus(documentId);\n\t\tif (status === void 0) return;\n\t\tfor (const callback of [...this.callbacks]) callback(documentId, status);\n\t}\n};\nfunction deriveStatus(inboxCount, outboxCount, errorCount) {\n\tif (errorCount > 0) return SyncStatus.Error;\n\tif (inboxCount > 0 && outboxCount > 0) return SyncStatus.OutgoingAndIncoming;\n\tif (inboxCount > 0) return SyncStatus.Incoming;\n\tif (outboxCount > 0) return SyncStatus.Outgoing;\n\treturn SyncStatus.Synced;\n}\n//#endregion\n//#region src/sync/sync-manager.ts\nvar OutboxMode = /* @__PURE__ */ function(OutboxMode) {\n\tOutboxMode[\"Backfill\"] = \"backfill\";\n\tOutboxMode[\"BatchTriggered\"] = \"batch-triggered\";\n\treturn OutboxMode;\n}(OutboxMode || {});\nconst defaultSyncManagerConfig = {\n\tmaxDeadLettersPerRemote: 100,\n\tmaxInboxBatchSize: 32,\n\tmaxHeldOperationsPerRemote: 1e4,\n\tstaleRemotePollWindowMs: 5 * 6e4\n};\nconst PLAN_KEY_TO_JOB_UUID_CAP = 1e4;\n/**\n* Whether a channel failure says the caller could not authenticate or could not\n* reach the remote, rather than that the remote itself is misconfigured. The\n* remote record stays on disk for these so a retry after sign-in can re-add it.\n*/\nfunction isCredentialOrNetworkError(error) {\n\tif (isDriveAuthError(error)) return true;\n\treturn error instanceof GraphQLRequestError && error.category === \"network\";\n}\n/** Where a sync operation's run of ordinals begins. */\nfunction firstOrdinalOf(syncOp) {\n\treturn syncOp.operations.length > 0 ? syncOp.operations[0].context.ordinal : 0;\n}\nvar SyncManager = class {\n\tlogger;\n\tremoteStorage;\n\tcursorStorage;\n\tdeadLetterStorage;\n\tchannelFactory;\n\toperationIndex;\n\treactor;\n\teventBus;\n\tremotes;\n\tawaiter;\n\tsyncAwaiter;\n\tabortController = new AbortController();\n\tisShutdown;\n\teventUnsubscribe;\n\tfailedEventUnsubscribe;\n\tbatchAggregator;\n\tsyncStatusTracker;\n\tconfig;\n\tconnectionStateUnsubscribes = /* @__PURE__ */ new Map();\n\tquarantinedDocumentIds = /* @__PURE__ */ new Set();\n\tbackfillAbortControllers = /* @__PURE__ */ new Map();\n\tplanKeyToJobUuid = /* @__PURE__ */ new Map();\n\tevictedOutboxFloors = /* @__PURE__ */ new Map();\n\tprunePending = /* @__PURE__ */ new Set();\n\tpruneChain = Promise.resolve();\n\tderivingOutboxes = 0;\n\tpruneDrainDeferred = false;\n\tremoving = /* @__PURE__ */ new Set();\n\tlastEnqueuedJobIdByKey = /* @__PURE__ */ new Map();\n\tinboxChunkChain = Promise.resolve();\n\tconstructor(logger, remoteStorage, cursorStorage, deadLetterStorage, channelFactory, operationIndex, reactor, eventBus, driveContainerTypes, config = {}) {\n\t\tthis.logger = logger;\n\t\tthis.remoteStorage = remoteStorage;\n\t\tthis.cursorStorage = cursorStorage;\n\t\tthis.deadLetterStorage = deadLetterStorage;\n\t\tthis.channelFactory = channelFactory;\n\t\tthis.operationIndex = operationIndex;\n\t\tthis.reactor = reactor;\n\t\tthis.eventBus = eventBus;\n\t\tthis.config = {\n\t\t\t...defaultSyncManagerConfig,\n\t\t\t...config\n\t\t};\n\t\tthis.remotes = /* @__PURE__ */ new Map();\n\t\tthis.awaiter = new JobAwaiter(eventBus, (jobId, signal) => reactor.getJobStatus(jobId, signal));\n\t\tthis.syncAwaiter = new SyncAwaiter(eventBus);\n\t\tthis.isShutdown = false;\n\t\tthis.batchAggregator = new BatchAggregator(logger, driveContainerTypes, (batch) => this.processCompleteBatch(batch));\n\t\tthis.syncStatusTracker = new SyncStatusTracker();\n\t}\n\tasync startup() {\n\t\tif (this.isShutdown) throw new Error(\"SyncManager is already shutdown and cannot be started\");\n\t\ttry {\n\t\t\tconst quarantinedIds = await this.deadLetterStorage.listQuarantinedDocumentIds();\n\t\t\tfor (const id of quarantinedIds) this.quarantinedDocumentIds.add(id);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to load quarantined document IDs (@error)\", error instanceof Error ? error.message : String(error));\n\t\t}\n\t\tconst remoteRecords = await this.remoteStorage.list();\n\t\tfor (const record of remoteRecords) {\n\t\t\tconst channel = this.channelFactory.instance(record.id, record.name, record.channelConfig, this.cursorStorage, record.collectionId, record.filter, this.operationIndex, record.options);\n\t\t\tconst remote = {\n\t\t\t\tmeta: {\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tname: record.name,\n\t\t\t\t\tcollectionId: record.collectionId,\n\t\t\t\t\tchannelConfig: record.channelConfig,\n\t\t\t\t\tfilter: record.filter,\n\t\t\t\t\toptions: record.options\n\t\t\t\t},\n\t\t\t\tchannel\n\t\t\t};\n\t\t\tthis.remotes.set(record.name, remote);\n\t\t\tawait this.loadDeadLetters(remote);\n\t\t\tthis.wireChannelCallbacks(remote);\n\t\t\ttry {\n\t\t\t\tawait channel.init();\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Error initializing channel for remote (@name, @error)\", record.name, error instanceof Error ? error.message : String(error));\n\t\t\t\tawait this.dropRemoteAfterFailedInit(remote, false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst outboxAckOrdinal = remote.channel.outbox.ackOrdinal;\n\t\t\tif (outboxAckOrdinal > 0) {\n\t\t\t\tconst backfillController = new AbortController();\n\t\t\t\tthis.backfillAbortControllers.set(record.name, backfillController);\n\t\t\t\tthis.updateOutbox(remote, outboxAckOrdinal, OutboxMode.Backfill, backfillController.signal).catch((error) => {\n\t\t\t\t\tif (backfillController.signal.aborted) return;\n\t\t\t\t\tthis.logger.error(\"Backfill failed for remote @RemoteName: @Error\", remote.meta.name, error instanceof Error ? error : new Error(String(error)));\n\t\t\t\t}).finally(() => {\n\t\t\t\t\tthis.backfillAbortControllers.delete(record.name);\n\t\t\t\t\tthis.drainPrunes();\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.eventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, async (_type, event) => this.batchAggregator.enqueueWriteReady(event));\n\t\tthis.failedEventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, async (_type, event) => this.batchAggregator.handleJobFailed(event));\n\t}\n\tshutdown() {\n\t\tthis.isShutdown = true;\n\t\tthis.abortController.abort();\n\t\tfor (const controller of this.backfillAbortControllers.values()) controller.abort();\n\t\tthis.backfillAbortControllers.clear();\n\t\tthis.planKeyToJobUuid.clear();\n\t\tthis.lastEnqueuedJobIdByKey.clear();\n\t\tthis.prunePending.clear();\n\t\tthis.pruneDrainDeferred = false;\n\t\tthis.batchAggregator.clear();\n\t\tif (this.eventUnsubscribe) {\n\t\t\tthis.eventUnsubscribe();\n\t\t\tthis.eventUnsubscribe = void 0;\n\t\t}\n\t\tif (this.failedEventUnsubscribe) {\n\t\t\tthis.failedEventUnsubscribe();\n\t\t\tthis.failedEventUnsubscribe = void 0;\n\t\t}\n\t\tthis.awaiter.shutdown();\n\t\tthis.syncAwaiter.shutdown();\n\t\tthis.syncStatusTracker.clear();\n\t\tfor (const unsub of this.connectionStateUnsubscribes.values()) unsub();\n\t\tthis.connectionStateUnsubscribes.clear();\n\t\tconst promises = [];\n\t\tfor (const remote of this.remotes.values()) promises.push(remote.channel.shutdown());\n\t\tthis.remotes.clear();\n\t\treturn {\n\t\t\tisShutdown: true,\n\t\t\tcompleted: Promise.all(promises).then(() => void 0)\n\t\t};\n\t}\n\tgetByName(name) {\n\t\tconst remote = this.remotes.get(name);\n\t\tif (!remote) throw new Error(`Remote with name '${name}' does not exist`);\n\t\treturn remote;\n\t}\n\tgetById(id) {\n\t\tfor (const remote of this.remotes.values()) if (remote.meta.id === id) return remote;\n\t\tthrow new Error(`Remote with id '${id}' does not exist`);\n\t}\n\tasync bindRemote(id, boundAddress) {\n\t\tconst remote = this.getById(id);\n\t\tconst bound = remote.meta.options.boundAddress;\n\t\tif (bound === boundAddress) return;\n\t\tif (bound !== void 0) throw new Error(`Remote with id '${id}' is already bound to another address`);\n\t\tremote.meta.options = {\n\t\t\t...remote.meta.options,\n\t\t\tboundAddress\n\t\t};\n\t\tawait this.remoteStorage.upsert({\n\t\t\tid: remote.meta.id,\n\t\t\tname: remote.meta.name,\n\t\t\tcollectionId: remote.meta.collectionId,\n\t\t\tchannelConfig: remote.meta.channelConfig,\n\t\t\tfilter: remote.meta.filter,\n\t\t\toptions: remote.meta.options,\n\t\t\tstatus: {\n\t\t\t\tpush: createIdleHealth(),\n\t\t\t\tpull: createIdleHealth()\n\t\t\t}\n\t\t});\n\t}\n\tasync add(name, collectionId, channelConfig, filter = {\n\t\tdocumentId: [],\n\t\tscope: [],\n\t\tbranch: \"\"\n\t}, options = { sinceTimestampUtcMs: \"0\" }, id) {\n\t\tif (this.isShutdown) throw new Error(\"SyncManager is shutdown and cannot add remotes\");\n\t\tif (this.remotes.has(name)) throw new Error(`Remote with name '${name}' already exists`);\n\t\tthis.logger.debug(\"Adding remote (@name, @collectionId, @channelConfig, @filter, @options, @id)\", name, collectionId.key, channelConfig, filter, options, id);\n\t\tconst remoteId = id ?? crypto.randomUUID();\n\t\tconst remoteRecord = {\n\t\t\tid: remoteId,\n\t\t\tname,\n\t\t\tcollectionId,\n\t\t\tchannelConfig,\n\t\t\tfilter,\n\t\t\toptions,\n\t\t\tstatus: {\n\t\t\t\tpush: createIdleHealth(),\n\t\t\t\tpull: createIdleHealth()\n\t\t\t}\n\t\t};\n\t\tawait this.remoteStorage.upsert(remoteRecord);\n\t\tconst channel = this.channelFactory.instance(remoteId, name, channelConfig, this.cursorStorage, collectionId, filter, this.operationIndex, options);\n\t\tconst remote = {\n\t\t\tmeta: {\n\t\t\t\tid: remoteId,\n\t\t\t\tname,\n\t\t\t\tcollectionId,\n\t\t\t\tchannelConfig,\n\t\t\t\tfilter,\n\t\t\t\toptions\n\t\t\t},\n\t\t\tchannel\n\t\t};\n\t\tthis.remotes.set(name, remote);\n\t\tawait this.loadDeadLetters(remote);\n\t\tthis.wireChannelCallbacks(remote);\n\t\ttry {\n\t\t\tawait channel.init();\n\t\t} catch (error) {\n\t\t\tawait this.dropRemoteAfterFailedInit(remote, !isCredentialOrNetworkError(error));\n\t\t\tthrow error;\n\t\t}\n\t\tconst backfillController = new AbortController();\n\t\tthis.backfillAbortControllers.set(name, backfillController);\n\t\tthis.updateOutbox(remote, 0, OutboxMode.Backfill, backfillController.signal).catch((error) => {\n\t\t\tif (backfillController.signal.aborted) return;\n\t\t\tthis.logger.error(\"Backfill failed for remote @RemoteName: @Error\", remote.meta.name, error instanceof Error ? error : new Error(String(error)));\n\t\t}).finally(() => {\n\t\t\tthis.backfillAbortControllers.delete(name);\n\t\t\tthis.drainPrunes();\n\t\t});\n\t\treturn remote;\n\t}\n\ttriggerPull(name) {\n\t\tconst remote = this.remotes.get(name);\n\t\tif (!remote) throw new Error(`Remote with name '${name}' does not exist`);\n\t\tremote.channel.triggerPull();\n\t}\n\tasync remove(name) {\n\t\tconst remote = this.remotes.get(name);\n\t\tif (!remote) throw new Error(`Remote with name '${name}' does not exist`);\n\t\tthis.removing.add(name);\n\t\ttry {\n\t\t\tawait this.teardownRemoteResources(remote);\n\t\t\tawait this.remoteStorage.remove(name);\n\t\t\tawait this.cursorStorage.remove(name);\n\t\t} finally {\n\t\t\tthis.remotes.delete(name);\n\t\t\tthis.removing.delete(name);\n\t\t}\n\t}\n\t/**\n\t* Drops a remote whose channel.init() rejected, optionally removing its\n\t* stored record. Ordered like remove(): the registry slot is released last,\n\t* so a concurrent add of the same name cannot slip in and have its record\n\t* deleted by the removal below. A failure to tear down must not replace the\n\t* init error the caller has to classify.\n\t*/\n\tasync dropRemoteAfterFailedInit(remote, removeStorageRecord) {\n\t\tconst name = remote.meta.name;\n\t\tthis.removing.add(name);\n\t\ttry {\n\t\t\tawait this.teardownRemoteResources(remote);\n\t\t\tif (removeStorageRecord) await this.remoteStorage.remove(name);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Error tearing down remote after failed init (@name, @error)\", name, error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\tthis.remotes.delete(name);\n\t\t\tthis.removing.delete(name);\n\t\t}\n\t}\n\t/**\n\t* Releases everything wiring a remote up holds: the in-flight backfill, the\n\t* channel, the status tracker entry and the connection-state subscription.\n\t* The registry slot is deliberately NOT released here -- the caller holds it\n\t* until any storage removal has finished, so a concurrent add of the same\n\t* name is refused for the whole teardown.\n\t*/\n\tasync teardownRemoteResources(remote) {\n\t\tconst name = remote.meta.name;\n\t\tconst backfillController = this.backfillAbortControllers.get(name);\n\t\tif (backfillController) {\n\t\t\tbackfillController.abort();\n\t\t\tthis.backfillAbortControllers.delete(name);\n\t\t}\n\t\ttry {\n\t\t\tawait remote.channel.shutdown();\n\t\t} finally {\n\t\t\tthis.syncStatusTracker.untrackRemote(name);\n\t\t\tconst unsub = this.connectionStateUnsubscribes.get(name);\n\t\t\tif (unsub) {\n\t\t\t\tunsub();\n\t\t\t\tthis.connectionStateUnsubscribes.delete(name);\n\t\t\t}\n\t\t\tthis.evictedOutboxFloors.delete(name);\n\t\t\tthis.prunePending.delete(name);\n\t\t}\n\t}\n\tlist() {\n\t\treturn Array.from(this.remotes.values());\n\t}\n\twaitForSync(jobId, signal) {\n\t\treturn this.syncAwaiter.waitForSync(jobId, signal);\n\t}\n\tgetSyncStatus(documentId) {\n\t\treturn this.syncStatusTracker.getStatus(documentId);\n\t}\n\tonSyncStatusChange(callback) {\n\t\treturn this.syncStatusTracker.onChange(callback);\n\t}\n\trecordPlanKeyMapping(planKey, jobId) {\n\t\tif (!this.planKeyToJobUuid.has(planKey) && this.planKeyToJobUuid.size >= PLAN_KEY_TO_JOB_UUID_CAP) {\n\t\t\tconst oldest = this.planKeyToJobUuid.keys().next().value;\n\t\t\tif (oldest !== void 0) this.planKeyToJobUuid.delete(oldest);\n\t\t}\n\t\tthis.planKeyToJobUuid.set(planKey, jobId);\n\t}\n\twireChannelCallbacks(remote) {\n\t\tremote.channel.inbox.onAdded((syncOps) => this.handleInboxAdded(remote, syncOps));\n\t\tthis.syncStatusTracker.trackRemote(remote.meta.name, remote.channel);\n\t\tconst unsubscribe = remote.channel.onConnectionStateChange((snapshot) => {\n\t\t\tthis.eventBus.emit(SyncEventTypes.CONNECTION_STATE_CHANGED, {\n\t\t\t\tremoteName: remote.meta.name,\n\t\t\t\tremoteId: remote.meta.id,\n\t\t\t\tprevious: snapshot.state,\n\t\t\t\tcurrent: snapshot.state,\n\t\t\t\tsnapshot\n\t\t\t}).catch(() => {});\n\t\t});\n\t\tthis.connectionStateUnsubscribes.set(remote.meta.name, unsubscribe);\n\t\tremote.channel.deadLetter.onAdded((syncOps) => {\n\t\t\tfor (const syncOp of syncOps) {\n\t\t\t\tthis.logger.error(\"Dead letter (@remote, @documentId, @jobId, @error, @dependencies)\", remote.meta.name, syncOp.documentId, syncOp.jobId, syncOp.error?.message ?? \"unknown\", syncOp.jobDependencies);\n\t\t\t\tconst errorType = syncOperationErrorType(syncOp.error);\n\t\t\t\tif (quarantinesDocument(errorType)) this.quarantinedDocumentIds.add(syncOp.documentId);\n\t\t\t\tconst record = {\n\t\t\t\t\tid: syncOp.id,\n\t\t\t\t\tjobId: syncOp.jobId,\n\t\t\t\t\tjobDependencies: syncOp.jobDependencies,\n\t\t\t\t\tremoteName: syncOp.remoteName,\n\t\t\t\t\tdocumentId: syncOp.documentId,\n\t\t\t\t\tscopes: syncOp.scopes,\n\t\t\t\t\tbranch: syncOp.branch,\n\t\t\t\t\toperations: syncOp.operations,\n\t\t\t\t\terrorSource: syncOp.error?.source ?? ChannelErrorSource.None,\n\t\t\t\t\terrorMessage: syncOp.error?.error.message ?? \"unknown\",\n\t\t\t\t\terrorType\n\t\t\t\t};\n\t\t\t\tthis.deadLetterStorage.add(record).catch((err) => {\n\t\t\t\t\tthis.logger.error(\"Failed to persist dead letter (@id, @error)\", record.id, err instanceof Error ? err.message : String(err));\n\t\t\t\t});\n\t\t\t\tthis.eventBus.emit(SyncEventTypes.DEAD_LETTER_ADDED, {\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tjobId: record.jobId,\n\t\t\t\t\tremoteName: record.remoteName,\n\t\t\t\t\tdocumentId: record.documentId,\n\t\t\t\t\terrorSource: record.errorSource,\n\t\t\t\t\terrorType: record.errorType\n\t\t\t\t}).catch(() => {});\n\t\t\t}\n\t\t\tconst items = remote.channel.deadLetter.items;\n\t\t\tif (items.length > this.config.maxDeadLettersPerRemote) {\n\t\t\t\tconst excessCount = items.length - this.config.maxDeadLettersPerRemote;\n\t\t\t\tconst toEvict = items.slice(0, excessCount);\n\t\t\t\tremote.channel.deadLetter.remove(...toEvict);\n\t\t\t}\n\t\t});\n\t}\n\tasync loadDeadLetters(remote) {\n\t\tlet records;\n\t\ttry {\n\t\t\trecords = (await this.deadLetterStorage.list(remote.meta.name, {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: this.config.maxDeadLettersPerRemote\n\t\t\t})).results;\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Failed to load dead letters for remote (@name, @error)\", remote.meta.name, error instanceof Error ? error.message : String(error));\n\t\t\treturn;\n\t\t}\n\t\tif (records.length === 0) return;\n\t\trecords.reverse();\n\t\tconst syncOps = [];\n\t\tfor (const record of records) {\n\t\t\tconst syncOp = new SyncOperation(record.id, record.jobId, record.jobDependencies, record.remoteName, record.documentId, record.scopes, record.branch, record.operations);\n\t\t\tsyncOp.failed(new ChannelError(record.errorSource, new Error(record.errorMessage), record.errorType));\n\t\t\tsyncOps.push(syncOp);\n\t\t}\n\t\tremote.channel.deadLetter.add(...syncOps);\n\t\tthis.logger.debug(\"Loaded @count persisted dead letters for remote @name\", records.length, remote.meta.name);\n\t}\n\tgetRemotesForCollection(collectionId) {\n\t\treturn Array.from(this.remotes.values()).filter((remote) => remote.meta.collectionId.key === collectionId && !this.removing.has(remote.meta.name));\n\t}\n\tasync processCompleteBatch(batch) {\n\t\tif (this.isShutdown) return;\n\t\tconst collectionIds = [...new Set(Object.values(batch.collectionMemberships).flatMap((collections) => collections))];\n\t\tconst affectedRemotes = [];\n\t\tfor (const collectionId of collectionIds) {\n\t\t\tconst remotes = this.getRemotesForCollection(collectionId);\n\t\t\tfor (const remote of remotes) if (!affectedRemotes.includes(remote)) affectedRemotes.push(remote);\n\t\t}\n\t\tfor (const remote of affectedRemotes) trimMailboxFromBatch(remote.channel.inbox, batch);\n\t\tfor (const remote of affectedRemotes) {\n\t\t\tif (!this.remotes.has(remote.meta.name) || this.removing.has(remote.meta.name)) continue;\n\t\t\tawait this.updateOutbox(remote, remote.channel.outbox.latestOrdinal, OutboxMode.BatchTriggered);\n\t\t}\n\t\tawait this.drainPrunes();\n\t}\n\thandleInboxAdded(remote, syncOps) {\n\t\tif (this.isShutdown) return;\n\t\tconst eligible = syncOps.filter((op) => !this.quarantinedDocumentIds.has(op.documentId));\n\t\tif (eligible.length === 0) return;\n\t\tconst keyed = [];\n\t\tconst nonKeyed = [];\n\t\tfor (const syncOp of eligible) if (syncOp.jobId) keyed.push(syncOp);\n\t\telse nonKeyed.push(syncOp);\n\t\tfor (const syncOp of nonKeyed) this.applyInboxJob(remote, syncOp);\n\t\tif (keyed.length > 0) {\n\t\t\tconst chunks = chunkSyncOperations(keyed.map((syncOp) => ({\n\t\t\t\tremote,\n\t\t\t\tsyncOp\n\t\t\t})), this.config.maxInboxBatchSize);\n\t\t\tthis.processInboxChunks(chunks);\n\t\t}\n\t}\n\tprocessInboxChunks(chunks) {\n\t\tconst next = this.inboxChunkChain.then(async () => {\n\t\t\tfor (const chunk of chunks) {\n\t\t\t\tif (this.isShutdown) return;\n\t\t\t\tawait this.applyInboxBatch(chunk);\n\t\t\t}\n\t\t});\n\t\tthis.inboxChunkChain = next.catch((err) => {\n\t\t\tthis.logger.error(\"Inbox chunk processing failed (@error)\", err instanceof Error ? err.message : String(err));\n\t\t});\n\t\treturn next;\n\t}\n\tasync applyInboxJob(remote, syncOp) {\n\t\tconst operations = syncOp.operations.map((op) => op.operation);\n\t\tlet jobInfo;\n\t\ttry {\n\t\t\tjobInfo = await this.reactor.load(syncOp.documentId, syncOp.branch, operations, this.abortController.signal, { sourceRemote: remote.meta.name });\n\t\t} catch (error) {\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\tthis.logger.error(\"Failed to load operations from inbox (@remote, @documentId, @error)\", remote.meta.name, syncOp.documentId, err.message);\n\t\t\tconst channelError = new ChannelError(ChannelErrorSource.Inbox, err);\n\t\t\tsyncOp.failed(channelError);\n\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\treturn;\n\t\t}\n\t\tlet completedJobInfo;\n\t\ttry {\n\t\t\tcompletedJobInfo = await this.awaiter.waitForJob(jobInfo.id, this.abortController.signal);\n\t\t} catch (error) {\n\t\t\tif (this.isShutdown) return;\n\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\tthis.logger.error(\"Failed to wait for job completion (@remote, @documentId, @jobId, @error)\", remote.meta.name, syncOp.documentId, jobInfo.id, err.message);\n\t\t\tconst channelError = new ChannelError(ChannelErrorSource.Inbox, err);\n\t\t\tsyncOp.failed(channelError);\n\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\treturn;\n\t\t}\n\t\tif (this.isShutdown) return;\n\t\tif (completedJobInfo.status === JobStatus.FAILED) {\n\t\t\tconst errorMessage = completedJobInfo.error?.message || \"Unknown error\";\n\t\t\tthis.logger.error(\"Failed to apply operations from inbox (@remote, @documentId, @jobId, @error)\", remote.meta.name, syncOp.documentId, completedJobInfo.id, errorMessage);\n\t\t\tsyncOp.failed(this.inboxFailure(completedJobInfo.error));\n\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t} else syncOp.executed();\n\t\tremote.channel.inbox.remove(syncOp);\n\t}\n\tasync applyInboxBatch(items) {\n\t\tconst sourceRemote = items[0].remote.meta.name;\n\t\tconst chunkKeys = new Set(items.map(({ syncOp }) => syncOp.jobId));\n\t\tconst jobs = items.map(({ syncOp }) => {\n\t\t\tconst dependsOn = [];\n\t\t\tconst externalDeps = [];\n\t\t\tfor (const dep of syncOp.jobDependencies) {\n\t\t\t\tif (!dep) continue;\n\t\t\t\tif (chunkKeys.has(dep)) dependsOn.push(dep);\n\t\t\t\telse {\n\t\t\t\t\tconst uuid = this.planKeyToJobUuid.get(dep);\n\t\t\t\t\tif (uuid !== void 0) externalDeps.push(uuid);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst fifoKey = `${syncOp.documentId}:${syncOp.scopes[0]}:${syncOp.branch}`;\n\t\t\tconst prevUuid = this.lastEnqueuedJobIdByKey.get(fifoKey);\n\t\t\tif (prevUuid !== void 0) externalDeps.push(prevUuid);\n\t\t\treturn {\n\t\t\t\tkey: syncOp.jobId,\n\t\t\t\tdocumentId: syncOp.documentId,\n\t\t\t\tscope: syncOp.scopes[0],\n\t\t\t\tbranch: syncOp.branch,\n\t\t\t\toperations: syncOp.operations.map((op) => op.operation),\n\t\t\t\tdependsOn,\n\t\t\t\texternalDeps\n\t\t\t};\n\t\t});\n\t\tconst request = { jobs };\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await this.reactor.loadBatch(request, this.abortController.signal, { sourceRemote });\n\t\t} catch (error) {\n\t\t\tif (this.isShutdown) return;\n\t\t\tfor (const { remote, syncOp } of items) {\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tsyncOp.failed(new ChannelError(ChannelErrorSource.Inbox, err));\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.isShutdown) return;\n\t\tfor (const plan of jobs) {\n\t\t\tif (!(plan.key in result.jobs)) continue;\n\t\t\tconst info = result.jobs[plan.key];\n\t\t\tthis.recordPlanKeyMapping(plan.key, info.id);\n\t\t\tconst fifoKey = `${plan.documentId}:${plan.scope}:${plan.branch}`;\n\t\t\tthis.lastEnqueuedJobIdByKey.set(fifoKey, info.id);\n\t\t}\n\t\tfor (const { remote, syncOp } of items) {\n\t\t\tif (!(syncOp.jobId in result.jobs)) {\n\t\t\t\tthis.logger.error(\"Job key missing from batch load result (@remote, @documentId, @jobId)\", remote.meta.name, syncOp.documentId, syncOp.jobId);\n\t\t\t\tconst error = new ChannelError(ChannelErrorSource.Inbox, /* @__PURE__ */ new Error(`Job key '${syncOp.jobId}' missing from batch load result`));\n\t\t\t\tsyncOp.failed(error);\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst jobInfo = result.jobs[syncOp.jobId];\n\t\t\tlet completedJobInfo;\n\t\t\ttry {\n\t\t\t\tcompletedJobInfo = await this.awaiter.waitForJob(jobInfo.id, this.abortController.signal);\n\t\t\t} catch (error) {\n\t\t\t\tif (this.isShutdown) continue;\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tsyncOp.failed(new ChannelError(ChannelErrorSource.Inbox, err));\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (this.isShutdown) return;\n\t\t\tif (completedJobInfo.status === JobStatus.FAILED) {\n\t\t\t\tsyncOp.failed(this.inboxFailure(completedJobInfo.error));\n\t\t\t\tremote.channel.deadLetter.add(syncOp);\n\t\t\t} else syncOp.executed();\n\t\t\tremote.channel.inbox.remove(syncOp);\n\t\t}\n\t}\n\t/**\n\t* The dead letter for a load job the executor failed.\n\t*\n\t* The classification is passed explicitly because it cannot be recovered\n\t* downstream: the wrapper carries the failure's message, not the failure, so\n\t* deriving it from the wrapper's own name would classify every one of these\n\t* as unclassified and quarantine the document. A held auth operation must\n\t* keep syncing, because reconciling the two policies needs the traffic a\n\t* quarantine would stop.\n\t*/\n\tinboxFailure(error) {\n\t\tconst message = error?.message || \"Unknown error\";\n\t\treturn new ChannelError(ChannelErrorSource.Inbox, /* @__PURE__ */ new Error(`Failed to apply operations: ${message}`), classifyJobFailure(error?.name ?? \"Error\"));\n\t}\n\t/**\n\t* Where the next outbox derivation starts: at the evicted floor when there is\n\t* room to take those entries back, and at the caller's cursor otherwise.\n\t*\n\t* The floor is forgotten as it is folded in. If the refill overflows again the\n\t* eviction records a new one, and if it does not, the entries are queued and\n\t* the outbox itself holds the cursor down.\n\t*/\n\trefillOrdinal(remote, ackOrdinal) {\n\t\tconst floor = this.evictedOutboxFloors.get(remote.meta.name);\n\t\tif (floor === void 0) return ackOrdinal;\n\t\tif (this.outboxOperationCount(remote) >= this.config.maxHeldOperationsPerRemote) return ackOrdinal;\n\t\tthis.evictedOutboxFloors.delete(remote.meta.name);\n\t\treturn Math.min(ackOrdinal, floor - 1);\n\t}\n\t/**\n\t* Evicts the newest entries of an outbox that has grown past its bound.\n\t*\n\t* Only entries that have never been taken up for transport are eligible, which\n\t* is what makes this a bound on withheld work rather than a way to drop\n\t* something already in flight. One entry is always kept, so an outbox whose\n\t* first entry is larger than the whole cap still makes progress.\n\t*/\n\tevictPastOutboxBound(remote) {\n\t\tconst cap = this.config.maxHeldOperationsPerRemote;\n\t\tconst queued = remote.channel.outbox.items.filter((syncOp) => syncOp.status === SyncOperationStatus.Unknown).sort((a, b) => firstOrdinalOf(a) - firstOrdinalOf(b));\n\t\tlet kept = 0;\n\t\tlet cut = queued.length;\n\t\tfor (let i = 0; i < queued.length; i++) {\n\t\t\tconst size = queued[i].operations.length;\n\t\t\tif (i > 0 && kept + size > cap) {\n\t\t\t\tcut = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tkept += size;\n\t\t}\n\t\tconst evicted = queued.slice(cut);\n\t\tif (evicted.length === 0) return;\n\t\tconst floor = firstOrdinalOf(evicted[0]);\n\t\tconst known = this.evictedOutboxFloors.get(remote.meta.name);\n\t\tthis.evictedOutboxFloors.set(remote.meta.name, known === void 0 ? floor : Math.min(known, floor));\n\t\tconst staleMs = this.stalePollAgeMs(remote);\n\t\tif (staleMs !== void 0) {\n\t\t\tlet held = kept;\n\t\t\tfor (const syncOp of evicted) held += syncOp.operations.length;\n\t\t\tif (!this.prunePending.has(remote.meta.name)) {\n\t\t\t\tthis.prunePending.add(remote.meta.name);\n\t\t\t\tthis.logger.warn(\"Outbox for @RemoteName (@Collection) is past its bound of @Cap operations holding @Held, and it has not been polled for @StaleMs ms; marking the channel for removal once this derivation ends\", remote.meta.name, remote.meta.collectionId.key, cap, held, staleMs);\n\t\t\t}\n\t\t} else this.logger.warn(\"Outbox for @RemoteName is past its bound of @Cap operations; evicting @Count entries from ordinal @Floor, to be derived again once it drains\", remote.meta.name, cap, evicted.length, floor);\n\t\tremote.channel.outbox.remove(...evicted);\n\t}\n\t/**\n\t* How long a served remote's holder has been silent, if past the window.\n\t*\n\t* The channel is asked, rather than its config inspected: SyncManager serves\n\t* and subscribes with the same interface, both kinds report lastSuccessUtcMs,\n\t* and the caller-supplied channelConfig.type is a free-form string the\n\t* factories do not read -- so neither could tell a dead served channel from a\n\t* client whose switchboard is merely unreachable. Only a channel that claims\n\t* a holder by reporting when it last heard from one can be removed for that\n\t* holder's silence; a channel that reports nothing (or 0) is never pruned.\n\t*/\n\tstalePollAgeMs(remote) {\n\t\tconst last = remote.channel.lastHolderPollUtcMs();\n\t\tif (last === void 0 || last <= 0) return;\n\t\tconst age = Date.now() - last;\n\t\treturn age >= this.config.staleRemotePollWindowMs ? age : void 0;\n\t}\n\t/**\n\t* Removes the remotes marked stale during eviction.\n\t*\n\t* Removing a remote that a derivation is still iterating would pull its\n\t* mailboxes out from under it, so a drain that arrives during one is deferred\n\t* rather than run; the last derivation to finish re-arms it.\n\t*/\n\tdrainPrunes() {\n\t\tif (this.derivingOutboxes > 0) {\n\t\t\tthis.pruneDrainDeferred = true;\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tconst next = this.pruneChain.then(async () => {\n\t\t\tif (this.isShutdown) return;\n\t\t\tfor (const name of [...this.prunePending]) {\n\t\t\t\tif (this.derivingOutboxes > 0) {\n\t\t\t\t\tthis.pruneDrainDeferred = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.prunePending.delete(name);\n\t\t\t\tconst remote = this.remotes.get(name);\n\t\t\t\tif (!remote) continue;\n\t\t\t\tif (this.stalePollAgeMs(remote) === void 0) {\n\t\t\t\t\tthis.logger.info(\"Stale removal of @name revoked: its holder polled while the outbox was being derived\", name);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait this.remove(name);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.logger.error(\"Failed to remove stale remote (@name, @error)\", name, error instanceof Error ? error.message : String(error));\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.pruneChain = next.catch(() => {});\n\t\treturn next;\n\t}\n\toutboxOperationCount(remote) {\n\t\tlet count = 0;\n\t\tfor (const syncOp of remote.channel.outbox.items) count += syncOp.operations.length;\n\t\treturn count;\n\t}\n\t/**\n\t* Derives this remote's outbox, holding off prunes for the duration.\n\t*\n\t* A backfill elsewhere can finish at any await in here and drain the prunes\n\t* it marked; the count is what keeps that drain from removing the remote this\n\t* call is still adding to.\n\t*/\n\tasync updateOutbox(remote, ackOrdinal, mode = OutboxMode.Backfill, signal) {\n\t\tthis.derivingOutboxes++;\n\t\ttry {\n\t\t\tawait this.deriveOutbox(remote, ackOrdinal, mode, signal);\n\t\t} finally {\n\t\t\tthis.derivingOutboxes--;\n\t\t\tif (this.derivingOutboxes === 0 && this.pruneDrainDeferred) {\n\t\t\t\tthis.pruneDrainDeferred = false;\n\t\t\t\tthis.drainPrunes();\n\t\t\t}\n\t\t}\n\t}\n\tasync deriveOutbox(remote, ackOrdinal, mode, signal) {\n\t\tconst composedSignal = signal ? AbortSignal.any([signal, this.abortController.signal]) : this.abortController.signal;\n\t\tconst startOrdinal = this.refillOrdinal(remote, ackOrdinal);\n\t\tlet maxOrdinal = startOrdinal;\n\t\tconst lastJobByDoc = /* @__PURE__ */ new Map();\n\t\tlet prevChainJobId;\n\t\tconst sinceTimestamp = remote.meta.options.sinceTimestampUtcMs;\n\t\tconst emitBatches = (operations) => {\n\t\t\tif (operations.length === 0) return;\n\t\t\tconst batches = batchOperationsByDocument(operations);\n\t\t\tconst syncOps = [];\n\t\t\tfor (const batch of batches) {\n\t\t\t\tconst jobId = crypto.randomUUID();\n\t\t\t\tconst prevJobId = lastJobByDoc.get(batch.documentId);\n\t\t\t\tconst deps = [];\n\t\t\t\tif (prevJobId) deps.push(prevJobId);\n\t\t\t\tif (mode === OutboxMode.BatchTriggered && prevChainJobId && prevChainJobId !== prevJobId) deps.push(prevChainJobId);\n\t\t\t\tconst syncOp = new SyncOperation(crypto.randomUUID(), jobId, deps, remote.meta.name, batch.documentId, [batch.scope], batch.branch, batch.operations);\n\t\t\t\tsyncOps.push(syncOp);\n\t\t\t\tlastJobByDoc.set(batch.documentId, jobId);\n\t\t\t\tif (mode === OutboxMode.BatchTriggered) prevChainJobId = jobId;\n\t\t\t}\n\t\t\tremote.channel.outbox.add(...syncOps);\n\t\t\tthis.evictPastOutboxBound(remote);\n\t\t};\n\t\tlet page = await this.operationIndex.find(remote.meta.collectionId.key, startOrdinal, { excludeSourceRemote: remote.meta.name }, void 0, composedSignal);\n\t\tlet carry = [];\n\t\tlet hasMore;\n\t\tdo {\n\t\t\tif (composedSignal.aborted) return;\n\t\t\tfor (const entry of page.results) maxOrdinal = Math.max(maxOrdinal, entry.ordinal ?? 0);\n\t\t\tlet operations = page.results.map((entry) => toOperationWithContext(entry));\n\t\t\tif (carry.length > 0) {\n\t\t\t\toperations = [...carry, ...operations];\n\t\t\t\tcarry = [];\n\t\t\t}\n\t\t\tif (sinceTimestamp && sinceTimestamp !== \"0\") operations = operations.filter((op) => op.operation.timestampUtcMs >= sinceTimestamp);\n\t\t\toperations = filterOperations(operations, remote.meta.filter);\n\t\t\toperations = operations.filter((op) => !this.quarantinedDocumentIds.has(op.context.documentId));\n\t\t\thasMore = !!page.next;\n\t\t\tif (operations.length > 0) {\n\t\t\t\tconst created = /* @__PURE__ */ new Set();\n\t\t\t\tfor (const entry of operations) if (entry.operation.action.type === \"CREATE_DOCUMENT\") created.add(entry.context.documentId);\n\t\t\t\toperations.sort((a, b) => {\n\t\t\t\t\tif (a.context.documentId !== b.context.documentId) return a.context.documentId < b.context.documentId ? -1 : 1;\n\t\t\t\t\tif (a.context.scope !== b.context.scope) {\n\t\t\t\t\t\tif (created.has(a.context.documentId)) {\n\t\t\t\t\t\t\tif (a.context.scope === \"document\") return -1;\n\t\t\t\t\t\t\tif (b.context.scope === \"document\") return 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn a.context.scope < b.context.scope ? -1 : 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn a.context.ordinal - b.context.ordinal;\n\t\t\t\t});\n\t\t\t\tif (hasMore) {\n\t\t\t\t\tconst split = splitTrailingSameTimestampRun(operations);\n\t\t\t\t\tcarry = split.carry;\n\t\t\t\t\temitBatches(split.emit);\n\t\t\t\t} else emitBatches(operations);\n\t\t\t}\n\t\t\tif (hasMore) page = await page.next();\n\t\t} while (hasMore);\n\t\tif (carry.length > 0) emitBatches(carry);\n\t\tremote.channel.outbox.advanceOrdinal(maxOrdinal);\n\t}\n};\n//#endregion\n//#region src/sync/sync-builder.ts\nvar SyncBuilder = class {\n\tchannelFactory;\n\tremoteStorage;\n\tcursorStorage;\n\tdeadLetterStorage;\n\tconfig = {};\n\twithChannelFactory(factory) {\n\t\tthis.channelFactory = factory;\n\t\treturn this;\n\t}\n\twithRemoteStorage(storage) {\n\t\tthis.remoteStorage = storage;\n\t\treturn this;\n\t}\n\twithCursorStorage(storage) {\n\t\tthis.cursorStorage = storage;\n\t\treturn this;\n\t}\n\twithDeadLetterStorage(storage) {\n\t\tthis.deadLetterStorage = storage;\n\t\treturn this;\n\t}\n\twithMaxDeadLettersPerRemote(limit) {\n\t\tthis.config.maxDeadLettersPerRemote = limit;\n\t\treturn this;\n\t}\n\twithMaxInboxBatchSize(limit) {\n\t\tthis.config.maxInboxBatchSize = limit;\n\t\treturn this;\n\t}\n\twithMaxHeldOperationsPerRemote(limit) {\n\t\tthis.config.maxHeldOperationsPerRemote = limit;\n\t\treturn this;\n\t}\n\twithStaleRemotePollWindowMs(windowMs) {\n\t\tthis.config.staleRemotePollWindowMs = windowMs;\n\t\treturn this;\n\t}\n\tbuild(reactor, logger, operationIndex, eventBus, db, driveContainerTypes) {\n\t\treturn this.buildModule(reactor, logger, operationIndex, eventBus, db, driveContainerTypes).syncManager;\n\t}\n\tbuildModule(reactor, logger, operationIndex, eventBus, db, driveContainerTypes) {\n\t\tif (!this.channelFactory) throw new Error(\"Channel factory is required\");\n\t\tconst remoteStorage = this.remoteStorage ?? new KyselySyncRemoteStorage(db);\n\t\tconst cursorStorage = this.cursorStorage ?? new KyselySyncCursorStorage(db);\n\t\tconst deadLetterStorage = this.deadLetterStorage ?? new KyselySyncDeadLetterStorage(db);\n\t\tconst syncManager = new SyncManager(logger, remoteStorage, cursorStorage, deadLetterStorage, this.channelFactory, operationIndex, reactor, eventBus, driveContainerTypes, this.config);\n\t\treturn {\n\t\t\tremoteStorage,\n\t\t\tcursorStorage,\n\t\t\tdeadLetterStorage,\n\t\t\tchannelFactory: this.channelFactory,\n\t\t\tsyncManager\n\t\t};\n\t}\n};\n//#endregion\n//#region src/core/create-default-database.ts\nasync function createDefaultDatabase() {\n\tconst { Kysely } = await import(\"kysely\");\n\tconst { PGlite } = await import(\"@electric-sql/pglite\");\n\tconst { PGliteDialect } = await import(\"kysely-pglite-dialect\");\n\treturn new Kysely({ dialect: new PGliteDialect(new PGlite()) });\n}\n//#endregion\n//#region src/shared/factories.ts\n/**\n* Factory method to create a ShutdownStatus that can be updated\n*\n* @param initialState - Initial shutdown state (default: false)\n* @returns A tuple of [ShutdownStatus, setShutdown function, setCompleted function]\n*/\nfunction createMutableShutdownStatus(initialState = false) {\n\tlet shutdownState = initialState;\n\tlet completedPromise = Promise.resolve();\n\tconst status = {\n\t\tget isShutdown() {\n\t\t\treturn shutdownState;\n\t\t},\n\t\tget completed() {\n\t\t\treturn completedPromise;\n\t\t}\n\t};\n\tconst setShutdown = (value) => {\n\t\tshutdownState = value;\n\t};\n\tconst setCompleted = (promise) => {\n\t\tcompletedPromise = promise;\n\t};\n\treturn [\n\t\tstatus,\n\t\tsetShutdown,\n\t\tsetCompleted\n\t];\n}\n//#endregion\n//#region src/core/types.ts\nvar AbortError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message || \"Aborted\");\n\t\tthis.name = \"AbortError\";\n\t}\n};\n//#endregion\n//#region src/core/reactor.ts\n/**\n* This class implements the IReactor interface and serves as the main entry point\n* for the new Reactor architecture.\n*/\nvar Reactor = class {\n\tlogger;\n\tdocumentModelRegistry;\n\tshutdownStatus;\n\tsetShutdown;\n\tsetCompleted;\n\tqueue;\n\tjobTracker;\n\treadModelCoordinator;\n\tfeatures;\n\tdocumentView;\n\tdocumentIndexer;\n\toperationStore;\n\teventBus;\n\texecutorManager;\n\tconstructor(logger, documentModelRegistry, queue, jobTracker, readModelCoordinator, features, documentView, documentIndexer, operationStore, eventBus, executorManager) {\n\t\tthis.logger = logger;\n\t\tthis.documentModelRegistry = documentModelRegistry;\n\t\tthis.queue = queue;\n\t\tthis.jobTracker = jobTracker;\n\t\tthis.readModelCoordinator = readModelCoordinator;\n\t\tthis.features = features;\n\t\tthis.documentView = documentView;\n\t\tthis.documentIndexer = documentIndexer;\n\t\tthis.operationStore = operationStore;\n\t\tthis.eventBus = eventBus;\n\t\tthis.executorManager = executorManager;\n\t\tconst [status, setShutdown, setCompleted] = createMutableShutdownStatus(false);\n\t\tthis.shutdownStatus = status;\n\t\tthis.setShutdown = setShutdown;\n\t\tthis.setCompleted = setCompleted;\n\t\tthis.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, (_type, event) => {\n\t\t\tthis.logger.error(\"Job @JobId failed with @Message: @Job\", event.jobId, event.error.message, event.job);\n\t\t});\n\t\tthis.readModelCoordinator.start();\n\t}\n\tkill() {\n\t\tthis.logger.verbose(\"kill()\");\n\t\tif (this.shutdownStatus.isShutdown) return this.shutdownStatus;\n\t\tthis.setShutdown(true);\n\t\tconst shutdownAsync = async () => {\n\t\t\tawait this.executorManager.stop(true);\n\t\t\tthis.readModelCoordinator.stop();\n\t\t\tthis.jobTracker.shutdown();\n\t\t};\n\t\tthis.setCompleted(shutdownAsync());\n\t\treturn this.shutdownStatus;\n\t}\n\tgetDocumentModels(namespace, paging, signal) {\n\t\tthis.logger.verbose(\"getDocumentModels(@namespace, @paging)\", namespace, paging);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst filteredModels = this.documentModelRegistry.getAllModules().filter((module) => !namespace || module.documentModel.global.id.startsWith(namespace));\n\t\tconst startIndex = paging ? parseInt(paging.cursor) || 0 : 0;\n\t\tconst limit = paging?.limit || filteredModels.length;\n\t\tconst pagedModels = filteredModels.slice(startIndex, startIndex + limit);\n\t\tconst hasMore = startIndex + limit < filteredModels.length;\n\t\tconst nextCursor = hasMore ? String(startIndex + limit) : void 0;\n\t\treturn Promise.resolve({\n\t\t\tresults: pagedModels,\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: filteredModels.length\n\t\t\t},\n\t\t\tnextCursor,\n\t\t\tnext: hasMore ? () => this.getDocumentModels(namespace, {\n\t\t\t\tcursor: nextCursor,\n\t\t\t\tlimit\n\t\t\t}, signal) : void 0\n\t\t});\n\t}\n\tasync get(id, view, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"get(@id, @view)\", id, view);\n\t\treturn await this.documentView.get(id, view, consistencyToken, signal);\n\t}\n\tasync getBySlug(slug, view, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"getBySlug(@slug, @view)\", slug, view);\n\t\tconst documentId = await this.documentView.resolveSlug(slug, view, consistencyToken, signal);\n\t\tif (!documentId) throw new Error(`Document not found with slug: ${slug}`);\n\t\treturn await this.get(documentId, view, consistencyToken, signal);\n\t}\n\tasync getByIdOrSlug(identifier, view, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"getByIdOrSlug(@identifier, @view)\", identifier, view);\n\t\treturn await this.documentView.getByIdOrSlug(identifier, view, consistencyToken, signal);\n\t}\n\tasync getOutgoingRelationships(sourceId, relationshipType, consistencyToken, signal) {\n\t\tconst relationships = await this.documentIndexer.getOutgoing(sourceId, [relationshipType], void 0, consistencyToken, signal);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn relationships.results.map((rel) => rel.targetId);\n\t}\n\tasync getIncomingRelationships(targetId, relationshipType, consistencyToken, signal) {\n\t\tconst relationships = await this.documentIndexer.getIncoming(targetId, [relationshipType], void 0, consistencyToken, signal);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn relationships.results.map((rel) => rel.sourceId);\n\t}\n\tasync getOperations(documentId, view, filter, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"getOperations(@documentId, @view, @filter, @paging)\", documentId, view, filter, paging);\n\t\tconst branch = view?.branch || \"main\";\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst allScopes = Object.keys(revisions.revision);\n\t\tconst result = {};\n\t\tfor (const scope of allScopes) {\n\t\t\tif (!matchesScope(view, scope)) continue;\n\t\t\tthrowIfAborted(signal, () => new AbortError());\n\t\t\tconst scopeResult = await this.operationStore.getSince(documentId, scope, branch, -1, filter, paging, signal);\n\t\t\tresult[scope] = {\n\t\t\t\tresults: scopeResult.results,\n\t\t\t\toptions: scopeResult.options,\n\t\t\t\tnextCursor: scopeResult.nextCursor,\n\t\t\t\tnext: scopeResult.next ? async () => {\n\t\t\t\t\treturn (await this.getOperations(documentId, view, filter, {\n\t\t\t\t\t\tcursor: scopeResult.nextCursor,\n\t\t\t\t\t\tlimit: scopeResult.options.limit\n\t\t\t\t\t}, consistencyToken, signal))[scope];\n\t\t\t\t} : void 0\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n\tasync find(search, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"find(@search, @view, @paging)\", search, view, paging);\n\t\tlet results;\n\t\tif (search.ids) {\n\t\t\tif (search.slugs && search.slugs.length > 0) throw new Error(\"Cannot use both ids and slugs in the same search\");\n\t\t\tresults = await this.findByIds(search.ids, view, paging, consistencyToken, signal);\n\t\t\tif (search.type) results = filterByType(results, search.type);\n\t\t} else if (search.slugs) {\n\t\t\tresults = await this.findBySlugs(search.slugs, view, paging, consistencyToken, signal);\n\t\t\tif (search.type) results = filterByType(results, search.type);\n\t\t} else if (search.parentId) {\n\t\t\tresults = await this.findByParentId(search.parentId, view, paging, consistencyToken, signal);\n\t\t\tif (search.type) results = filterByType(results, search.type);\n\t\t} else if (search.type) results = await this.findByType(search.type, view, paging, consistencyToken, signal);\n\t\telse throw new Error(\"No search criteria provided\");\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn results;\n\t}\n\tasync create(document, signer, signal, meta) {\n\t\tthis.logger.verbose(\"create(@id, @type, @slug)\", document.header.id, document.header.documentType, document.header.slug);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet actions = [createDocumentAction({\n\t\t\tmodel: document.header.documentType,\n\t\t\tversion: 0,\n\t\t\tdocumentId: document.header.id,\n\t\t\tsigning: {\n\t\t\t\tsignature: document.header.id,\n\t\t\t\tpublicKey: document.header.sig.publicKey,\n\t\t\t\tnonce: document.header.sig.nonce,\n\t\t\t\tcreatedAtUtcIso: document.header.createdAtUtcIso,\n\t\t\t\tdocumentType: document.header.documentType\n\t\t\t},\n\t\t\tslug: document.header.slug,\n\t\t\tname: document.header.name,\n\t\t\tbranch: document.header.branch,\n\t\t\tmeta: document.header.meta,\n\t\t\tprotocolVersions: document.header.protocolVersions ?? { \"base-reducer\": 2 }\n\t\t}), upgradeDocumentAction({\n\t\t\tdocumentId: document.header.id,\n\t\t\tmodel: document.header.documentType,\n\t\t\tfromVersion: 0,\n\t\t\ttoVersion: normalizeDocumentModelVersion(document.state.document?.version),\n\t\t\tinitialState: document.state\n\t\t})];\n\t\tif (signer) actions = await signActions(actions, signer, signal);\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"mutation\",\n\t\t\tdocumentId: document.header.id,\n\t\t\tscope: \"document\",\n\t\t\tbranch: \"main\",\n\t\t\tactions,\n\t\t\toperations: [],\n\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\treturn jobInfo;\n\t}\n\tasync deleteDocument(id, signer, signal, meta) {\n\t\tthis.logger.verbose(\"deleteDocument(@id)\", id);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet action = deleteDocumentAction(id);\n\t\tif (signer) action = await signAction(action, signer, signal);\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"mutation\",\n\t\t\tdocumentId: id,\n\t\t\tscope: \"document\",\n\t\t\tbranch: \"main\",\n\t\t\tactions: [action],\n\t\t\toperations: [],\n\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\treturn jobInfo;\n\t}\n\tasync execute(docId, branch, actions, signal, meta) {\n\t\tthis.logger.verbose(\"execute(@docId, @branch, @actions)\", docId, branch, actions);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst scope = getSharedActionScope(actions);\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"mutation\",\n\t\t\tdocumentId: docId,\n\t\t\tscope,\n\t\t\tbranch,\n\t\t\tactions,\n\t\t\toperations: [],\n\t\t\tcreatedAt: (/* @__PURE__ */ new Date()).toISOString(),\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn jobInfo;\n\t}\n\tasync load(docId, branch, operations, signal, meta) {\n\t\tthis.logger.verbose(\"load(@docId, @branch, @count, @operations)\", docId, branch, operations.length, operations);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tif (operations.length === 0) throw new Error(\"load requires at least one operation\");\n\t\tconst scope = getSharedOperationScope(operations);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst jobId = v4();\n\t\tconst jobMeta = buildSingleJobMeta(jobId, meta);\n\t\tconst job = {\n\t\t\tid: jobId,\n\t\t\tkind: \"load\",\n\t\t\tdocumentId: docId,\n\t\t\tscope,\n\t\t\tbranch,\n\t\t\tactions: [],\n\t\t\toperations,\n\t\t\tcreatedAt: createdAtUtcIso,\n\t\t\tqueueHint: [],\n\t\t\tmaxRetries: 3,\n\t\t\terrorHistory: [],\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tconst jobInfo = {\n\t\t\tid: jobId,\n\t\t\tdocumentId: job.documentId,\n\t\t\tstatus: JobStatus.PENDING,\n\t\t\tcreatedAtUtcIso,\n\t\t\tconsistencyToken: {\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tcoordinates: []\n\t\t\t},\n\t\t\tmeta: jobMeta\n\t\t};\n\t\tthis.jobTracker.registerJob(jobInfo);\n\t\tthis.emitJobPending(jobInfo.id, jobMeta);\n\t\tawait this.queue.enqueue(job);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\treturn jobInfo;\n\t}\n\tasync executeBatch(request, signal, meta) {\n\t\tthis.logger.verbose(\"executeBatch(@count jobs)\", request.jobs.length);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tvalidateBatchRequest(request.jobs);\n\t\tfor (const jobPlan of request.jobs) validateActionScopes(jobPlan);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst planKeyToJobId = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) planKeyToJobId.set(jobPlan.key, v4());\n\t\tconst batchId = v4();\n\t\tconst batchJobIds = [...planKeyToJobId.values()];\n\t\tconst batchMeta = {\n\t\t\t...meta,\n\t\t\tbatchId,\n\t\t\tbatchJobIds\n\t\t};\n\t\tconst jobInfos = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) {\n\t\t\tconst jobInfo = {\n\t\t\t\tid: planKeyToJobId.get(jobPlan.key),\n\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\tstatus: JobStatus.PENDING,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tconsistencyToken: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcreatedAtUtcIso,\n\t\t\t\t\tcoordinates: []\n\t\t\t\t},\n\t\t\t\tmeta: batchMeta\n\t\t\t};\n\t\t\tthis.jobTracker.registerJob(jobInfo);\n\t\t\tthis.emitJobPending(jobInfo.id, batchMeta);\n\t\t\tjobInfos.set(jobPlan.key, jobInfo);\n\t\t}\n\t\tconst sortedKeys = topologicalSort(request.jobs);\n\t\tconst enqueuedKeys = [];\n\t\ttry {\n\t\t\tfor (const key of sortedKeys) {\n\t\t\t\tthrowIfAborted(signal, () => new AbortError());\n\t\t\t\tconst jobPlan = request.jobs.find((j) => j.key === key);\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\tconst queueHint = jobPlan.dependsOn.map((depKey) => planKeyToJobId.get(depKey));\n\t\t\t\tconst job = {\n\t\t\t\t\tid: jobId,\n\t\t\t\t\tkind: \"mutation\",\n\t\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\t\tscope: jobPlan.scope,\n\t\t\t\t\tbranch: jobPlan.branch,\n\t\t\t\t\tactions: jobPlan.actions,\n\t\t\t\t\toperations: [],\n\t\t\t\t\tcreatedAt: createdAtUtcIso,\n\t\t\t\t\tqueueHint,\n\t\t\t\t\tmaxRetries: 3,\n\t\t\t\t\terrorHistory: [],\n\t\t\t\t\tmeta: batchMeta\n\t\t\t\t};\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t\tenqueuedKeys.push(key);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfor (const key of enqueuedKeys) {\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\ttry {\n\t\t\t\t\tawait this.queue.remove(jobId);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tfor (const jobInfo of jobInfos.values()) this.jobTracker.markFailed(jobInfo.id, toErrorInfo$1(\"Batch enqueue failed\"));\n\t\t\tthrow error;\n\t\t}\n\t\treturn { jobs: Object.fromEntries(jobInfos) };\n\t}\n\tasync loadBatch(request, signal, meta) {\n\t\tthis.logger.verbose(\"loadBatch(@count jobs)\", request.jobs.length);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tvalidateBatchLoadRequest(request.jobs);\n\t\tfor (const jobPlan of request.jobs) validateOperationScopes(jobPlan);\n\t\tconst createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();\n\t\tconst planKeyToJobId = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) planKeyToJobId.set(jobPlan.key, v4());\n\t\tconst batchId = v4();\n\t\tconst batchJobIds = [...planKeyToJobId.values()];\n\t\tconst batchMeta = {\n\t\t\t...meta,\n\t\t\tbatchId,\n\t\t\tbatchJobIds\n\t\t};\n\t\tconst jobInfos = /* @__PURE__ */ new Map();\n\t\tfor (const jobPlan of request.jobs) {\n\t\t\tconst jobInfo = {\n\t\t\t\tid: planKeyToJobId.get(jobPlan.key),\n\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\tstatus: JobStatus.PENDING,\n\t\t\t\tcreatedAtUtcIso,\n\t\t\t\tconsistencyToken: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcreatedAtUtcIso,\n\t\t\t\t\tcoordinates: []\n\t\t\t\t},\n\t\t\t\tmeta: batchMeta\n\t\t\t};\n\t\t\tthis.jobTracker.registerJob(jobInfo);\n\t\t\tthis.emitJobPending(jobInfo.id, batchMeta);\n\t\t\tjobInfos.set(jobPlan.key, jobInfo);\n\t\t}\n\t\tconst sortedKeys = topologicalSort(request.jobs);\n\t\tconst enqueuedKeys = [];\n\t\ttry {\n\t\t\tfor (const key of sortedKeys) {\n\t\t\t\tthrowIfAborted(signal, () => new AbortError());\n\t\t\t\tconst jobPlan = request.jobs.find((j) => j.key === key);\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\tconst queueHint = [...jobPlan.dependsOn.map((depKey) => planKeyToJobId.get(depKey)), ...jobPlan.externalDeps];\n\t\t\t\tconst job = {\n\t\t\t\t\tid: jobId,\n\t\t\t\t\tkind: \"load\",\n\t\t\t\t\tdocumentId: jobPlan.documentId,\n\t\t\t\t\tscope: jobPlan.scope,\n\t\t\t\t\tbranch: jobPlan.branch,\n\t\t\t\t\tactions: [],\n\t\t\t\t\toperations: jobPlan.operations,\n\t\t\t\t\tcreatedAt: createdAtUtcIso,\n\t\t\t\t\tqueueHint,\n\t\t\t\t\tmaxRetries: 3,\n\t\t\t\t\terrorHistory: [],\n\t\t\t\t\tmeta: batchMeta\n\t\t\t\t};\n\t\t\t\tawait this.queue.enqueue(job);\n\t\t\t\tenqueuedKeys.push(key);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfor (const key of enqueuedKeys) {\n\t\t\t\tconst jobId = planKeyToJobId.get(key);\n\t\t\t\ttry {\n\t\t\t\t\tawait this.queue.remove(jobId);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tfor (const jobInfo of jobInfos.values()) this.jobTracker.markFailed(jobInfo.id, toErrorInfo$1(\"Batch enqueue failed\"));\n\t\t\tthrow error;\n\t\t}\n\t\treturn { jobs: Object.fromEntries(jobInfos) };\n\t}\n\tasync addRelationship(sourceId, targetId, relationshipType, branch = \"main\", signer, signal) {\n\t\tthis.logger.verbose(\"addRelationship(@sourceId, @targetId, @relationshipType, @branch)\", sourceId, targetId, relationshipType, branch);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet actions = [addRelationshipAction(sourceId, targetId, relationshipType)];\n\t\tif (signer) actions = await signActions(actions, signer, signal);\n\t\treturn await this.execute(sourceId, branch, actions, signal);\n\t}\n\tasync removeRelationship(sourceId, targetId, relationshipType, branch = \"main\", signer, signal) {\n\t\tthis.logger.verbose(\"removeRelationship(@sourceId, @targetId, @relationshipType, @branch)\", sourceId, targetId, relationshipType, branch);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tlet actions = [removeRelationshipAction(sourceId, targetId, relationshipType)];\n\t\tif (signer) actions = await signActions(actions, signer, signal);\n\t\treturn await this.execute(sourceId, branch, actions, signal);\n\t}\n\tgetJobStatus(jobId, signal) {\n\t\tthis.logger.verbose(\"getJobStatus(@jobId)\", jobId);\n\t\tthrowIfAborted(signal, () => new AbortError());\n\t\tconst jobInfo = this.jobTracker.getJobStatus(jobId);\n\t\tif (!jobInfo) {\n\t\t\tconst now = (/* @__PURE__ */ new Date()).toISOString();\n\t\t\treturn Promise.resolve({\n\t\t\t\tid: jobId,\n\t\t\t\tdocumentId: \"\",\n\t\t\t\tstatus: JobStatus.FAILED,\n\t\t\t\tcreatedAtUtcIso: now,\n\t\t\t\tcompletedAtUtcIso: now,\n\t\t\t\terror: toErrorInfo$1(\"Job not found\"),\n\t\t\t\tconsistencyToken: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcreatedAtUtcIso: now,\n\t\t\t\t\tcoordinates: []\n\t\t\t\t},\n\t\t\t\tmeta: {\n\t\t\t\t\tbatchId: jobId,\n\t\t\t\t\tbatchJobIds: [jobId]\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn Promise.resolve(jobInfo);\n\t}\n\tasync findByIds(ids, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findByIds(@count ids)\", ids.length);\n\t\tconst startIndex = paging?.cursor ? parseInt(paging.cursor) || 0 : 0;\n\t\tconst limit = paging?.limit || ids.length;\n\t\tconst pagedIds = ids.slice(startIndex, startIndex + limit);\n\t\tconst results = await this.documentView.getMany(pagedIds, view, consistencyToken, signal);\n\t\tconst nextCursor = startIndex + limit < ids.length ? String(startIndex + limit) : void 0;\n\t\treturn {\n\t\t\tresults,\n\t\t\toptions: paging || {\n\t\t\t\tcursor: \"0\",\n\t\t\t\tlimit: ids.length\n\t\t\t},\n\t\t\tnextCursor\n\t\t};\n\t}\n\tasync findBySlugs(slugs, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findBySlugs(@count slugs)\", slugs.length);\n\t\tconst ids = await this.documentView.resolveSlugs(slugs, view, consistencyToken, signal);\n\t\treturn await this.findByIds(ids, view, paging, consistencyToken, signal);\n\t}\n\tasync findByParentId(parentId, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findByParentId(@parentId)\", parentId);\n\t\tconst ids = (await this.documentIndexer.getOutgoing(parentId, [\"child\"], paging, consistencyToken, signal)).results.map((rel) => rel.targetId);\n\t\treturn await this.findByIds(ids, view, paging, void 0, signal);\n\t}\n\tasync findByType(type, view, paging, consistencyToken, signal) {\n\t\tthis.logger.verbose(\"findByType(@type)\", type);\n\t\treturn await this.documentView.findByType(type, view, paging, consistencyToken, signal);\n\t}\n\temitJobPending(jobId, meta) {\n\t\tconst event = {\n\t\t\tjobId,\n\t\t\tjobMeta: meta\n\t\t};\n\t\tthis.eventBus.emit(ReactorEventTypes.JOB_PENDING, event).catch(() => {});\n\t}\n};\n//#endregion\n//#region src/core/reactor-builder.ts\nfunction sameDatabaseTarget(a, b) {\n\treturn a.host === b.host && a.port === b.port && a.database === b.database;\n}\n/**\n* Requires each built-in kind exactly once across both lists. A kind in\n* neither list is indexed by nobody (host copies never index under a\n* worker), so its reads go stale and its consistency-token waits never\n* resolve; a kind in both is indexed twice per operation.\n*/\nfunction validateBuiltInKindCoverage(preReadyKinds, postReadyKinds) {\n\tconst named = [...preReadyKinds, ...postReadyKinds];\n\tconst missing = BUILT_IN_READ_MODEL_KINDS.filter((kind) => !named.includes(kind));\n\tconst duplicated = BUILT_IN_READ_MODEL_KINDS.filter((kind) => named.filter((entry) => entry === kind).length > 1);\n\tif (missing.length === 0 && duplicated.length === 0) return;\n\tconst problems = [missing.length > 0 ? `never named: ${missing.join(\", \")} (would be indexed by no shard, leaving those reads permanently stale and their consistency-token waits unresolvable)` : void 0, duplicated.length > 0 ? `named more than once: ${duplicated.join(\", \")} (would be indexed twice per operation)` : void 0].filter((problem) => problem !== void 0);\n\tthrow new Error(`withProjectionShards requires preReadyKinds and postReadyKinds to name each built-in read model (${BUILT_IN_READ_MODEL_KINDS.join(\", \")}) exactly once between them; ${problems.join(\"; \")}`);\n}\nvar ReactorBuilder = class {\n\tlogger;\n\tdocumentModelSources = [];\n\tupgradeManifests = [];\n\tfeatures = {\n\t\tlegacyStorageEnabled: false,\n\t\tlegacyProcessorIds: true\n\t};\n\treadModels = [];\n\treadModelFactories = [];\n\texecutorManager;\n\texecutorConfig = {};\n\twriteCacheConfig;\n\tmigrationStrategy = \"auto\";\n\tsyncBuilder;\n\teventBus;\n\treadModelCoordinator;\n\treadModelCoordinatorFactory;\n\tsignatureVerifier;\n\tkyselyInstance;\n\tsignalHandlersEnabled = false;\n\tqueueInstance;\n\tchannelScheme;\n\tjwtHandler;\n\tdocumentModelLoader;\n\tshutdownHooks = [];\n\tdriveContainerTypes = DEFAULT_DRIVE_CONTAINER_TYPES;\n\tworkerPool;\n\tresolvedModelManifest;\n\tmoduleOnlyModelKeys = [];\n\tprojectionShardConfig;\n\tprojectionWorkerFactory;\n\tinstrumentedPools = [];\n\twithLogger(logger) {\n\t\tthis.logger = logger;\n\t\treturn this;\n\t}\n\t/**\n\t* Register document-model sources: live modules, importable files, or\n\t* importable packages. Appends across calls. At `buildModule()` every\n\t* source is resolved host-side and registered on the registry; file and\n\t* package sources additionally form the worker manifest when the worker\n\t* pool is enabled (live modules cannot cross a thread boundary).\n\t*/\n\twithDocumentModelSources(sources) {\n\t\tthis.documentModelSources.push(...sources);\n\t\treturn this;\n\t}\n\twithUpgradeManifests(manifests) {\n\t\tthis.upgradeManifests = manifests;\n\t\treturn this;\n\t}\n\twithFeatures(features) {\n\t\tthis.features = {\n\t\t\t...this.features,\n\t\t\t...features\n\t\t};\n\t\treturn this;\n\t}\n\twithReadModel(readModel) {\n\t\tthis.readModels.push(readModel);\n\t\treturn this;\n\t}\n\t/**\n\t* Register a factory that builds a pre-ready read model after the reactor's\n\t* internal `operationIndex`, `writeCache`, and processor-manager consistency\n\t* tracker are constructed. Use this for read models (e.g. `BaseReadModel`\n\t* subclasses) that need those dependencies and therefore cannot be built\n\t* before calling `buildModule()`.\n\t*/\n\twithReadModelFactory(factory) {\n\t\tthis.readModelFactories.push(factory);\n\t\treturn this;\n\t}\n\twithReadModelCoordinator(readModelCoordinator) {\n\t\tthis.readModelCoordinator = readModelCoordinator;\n\t\treturn this;\n\t}\n\t/**\n\t* Register a factory that builds the coordinator once the subscription\n\t* read model, processor manager and host read models exist. Use this, not\n\t* `withReadModelCoordinator`, for coordinators that compose those internals.\n\t*/\n\twithReadModelCoordinatorFactory(factory) {\n\t\tthis.readModelCoordinatorFactory = factory;\n\t\treturn this;\n\t}\n\twithExecutor(executor) {\n\t\tthis.executorManager = executor;\n\t\treturn this;\n\t}\n\twithExecutorConfig(config) {\n\t\tthis.executorConfig = {\n\t\t\t...this.executorConfig,\n\t\t\t...config\n\t\t};\n\t\treturn this;\n\t}\n\twithWriteCacheConfig(config) {\n\t\tthis.writeCacheConfig = config;\n\t\treturn this;\n\t}\n\twithDriveContainerTypes(types) {\n\t\tthis.driveContainerTypes = new Set(types);\n\t\treturn this;\n\t}\n\twithMigrationStrategy(strategy) {\n\t\tthis.migrationStrategy = strategy;\n\t\treturn this;\n\t}\n\twithSync(syncBuilder) {\n\t\tthis.syncBuilder = syncBuilder;\n\t\treturn this;\n\t}\n\twithEventBus(eventBus) {\n\t\tthis.eventBus = eventBus;\n\t\treturn this;\n\t}\n\twithSignatureVerifier(verifier) {\n\t\tthis.signatureVerifier = verifier;\n\t\treturn this;\n\t}\n\twithKysely(kysely) {\n\t\tthis.kyselyInstance = kysely;\n\t\treturn this;\n\t}\n\t/**\n\t* Register an externally-constructed pg.Pool's {@link PoolInstrumentation}\n\t* so it surfaces through {@link ReactorModule.pools}. Use this when the\n\t* caller built the pool itself (e.g. the in-process bench host wiring) so\n\t* pool acquire-wait and pool-stat metrics still emit. The builder also\n\t* registers any pool it constructs internally via {@link createPostgresDatabase}.\n\t*/\n\twithInstrumentedPool(instrumentation) {\n\t\tthis.instrumentedPools.push(instrumentation);\n\t\treturn this;\n\t}\n\twithQueue(queue) {\n\t\tthis.queueInstance = queue;\n\t\treturn this;\n\t}\n\twithChannelScheme(scheme) {\n\t\tthis.channelScheme = scheme;\n\t\treturn this;\n\t}\n\twithJwtHandler(handler) {\n\t\tthis.jwtHandler = handler;\n\t\treturn this;\n\t}\n\twithDocumentModelLoader(loader) {\n\t\tthis.documentModelLoader = loader;\n\t\treturn this;\n\t}\n\twithSignalHandlers() {\n\t\tthis.signalHandlersEnabled = true;\n\t\treturn this;\n\t}\n\t/**\n\t* Register an async cleanup hook to run during graceful shutdown. Hooks fire\n\t* after `reactor.kill()` resolves and before `database.destroy()`, so callers\n\t* that depend on the reactor (e.g. an HTTP API layered on top) can drain\n\t* cleanly before the underlying kysely instance is torn down. Hook errors are\n\t* logged and otherwise ignored — one bad hook cannot strand the rest of the\n\t* shutdown chain.\n\t*/\n\twithShutdownHook(hook) {\n\t\tthis.shutdownHooks.push(hook);\n\t\treturn this;\n\t}\n\t/**\n\t* Enable the executor worker pool: N `node:worker_threads` workers with\n\t* sticky per-document routing, replacing the in-process executor. Calling\n\t* this enables the pool — there is no `enabled` flag. Provide `db`\n\t* (each worker opens its own Postgres pool; the parent database is built\n\t* from it too unless {@link withKysely} is set) or a custom `factory`\n\t* transport. `verifier` is imported by the default transport's workers;\n\t* omitted = no executor-side signature verification.\n\t*/\n\twithWorkerPool(options) {\n\t\tthis.workerPool = options;\n\t\treturn this;\n\t}\n\t/**\n\t* Configure N sharded projection workers. When set, the builder replaces\n\t* the default in-process {@link ReadModelCoordinator} with a\n\t* {@link ProjectionShardManager}.\n\t*\n\t* Projection workers open their own Postgres pools from `config.db`,\n\t* falling back to the executor worker pool's `db` when\n\t* {@link withWorkerPool} is configured with one; only the `poolSize` is\n\t* overridden by {@link ProjectionShardBuilderConfig.poolSize}. The same\n\t* model manifest resolved from {@link withDocumentModelSources} is\n\t* forwarded.\n\t*/\n\twithProjectionShards(config) {\n\t\tthis.projectionShardConfig = config;\n\t\treturn this;\n\t}\n\t/**\n\t* Inject a custom {@link ProjectionWorkerFactory}. When set, the builder\n\t* skips default thread-transport wiring for the projection shards and\n\t* hands the factory directly to {@link ProjectionShardManager}.\n\t*/\n\twithProjectionWorkerFactory(factory) {\n\t\tthis.projectionWorkerFactory = factory;\n\t\treturn this;\n\t}\n\tgetResolvedModelManifest() {\n\t\treturn this.resolvedModelManifest;\n\t}\n\tasync build() {\n\t\treturn (await this.buildModule()).reactor;\n\t}\n\tasync buildModule() {\n\t\tif (!this.logger) this.logger = new ConsoleLogger([\"reactor\"]);\n\t\tconst featureFlags = resolveFeatureFlags(this.executorConfig.featureFlags);\n\t\tif (this.readModelCoordinator !== void 0 && this.readModelCoordinatorFactory !== void 0) throw new Error(\"withReadModelCoordinator and withReadModelCoordinatorFactory are mutually exclusive; register one coordinator source\");\n\t\tif (this.projectionShardConfig !== void 0 && this.readModelCoordinatorFactory !== void 0) throw new Error(\"withProjectionShards and withReadModelCoordinatorFactory are mutually exclusive; the factory owns the projection worker through its createProjectionShardManager dependency\");\n\t\tif (this.projectionShardConfig !== void 0 && this.readModelFactories.length > 0) throw new Error(\"withProjectionShards does not support read models registered through withReadModelFactory; projection workers cannot receive host-only factory dependencies\");\n\t\tif (this.projectionShardConfig !== void 0 && this.readModels.length > 0) throw new Error(\"withProjectionShards does not support read models registered through withReadModel; projection workers build their own read models from the shard config and would silently omit these\");\n\t\tif (this.projectionShardConfig !== void 0) validateBuiltInKindCoverage(this.projectionShardConfig.preReadyKinds, this.projectionShardConfig.postReadyKinds);\n\t\tconst resolvedSources = await resolveModelSources(this.documentModelSources);\n\t\tif (this.workerPool) {\n\t\t\tif (resolvedSources.manifest.length === 0) throw new Error(\"withWorkerPool requires at least one worker-importable document-model source ({ filePath } or { packageName }).\");\n\t\t\tif (resolvedSources.moduleOnlyKeys.length > 0) throw new Error(`withWorkerPool requires worker-importable sources, but these models were registered only as live modules: ${resolvedSources.moduleOnlyKeys.join(\", \")}. Provide a { filePath } or { packageName } source for each.`);\n\t\t}\n\t\tthis.resolvedModelManifest = resolvedSources.manifest.length > 0 ? resolvedSources.manifest : void 0;\n\t\tthis.moduleOnlyModelKeys = resolvedSources.moduleOnlyKeys;\n\t\tconst documentModelRegistry = new DocumentModelRegistry();\n\t\tif (this.upgradeManifests.length > 0) {\n\t\t\tconst results = documentModelRegistry.registerUpgradeManifests(...this.upgradeManifests);\n\t\t\tfor (const result of results) if (result.status === \"error\") this.logger.error(\"Failed to register upgrade manifest: @error\", result.error.message);\n\t\t}\n\t\tif (resolvedSources.modules.length > 0) {\n\t\t\tconst results = documentModelRegistry.registerModules(...resolvedSources.modules);\n\t\t\tfor (const result of results) if (result.status === \"error\") this.logger.error(\"Failed to register document model: @error\", result.error.message);\n\t\t}\n\t\tconst reactorDbConfig = this.resolveReactorDbConfig();\n\t\tconst baseDatabase = this.kyselyInstance ?? (reactorDbConfig ? await this.createPostgresDatabase(reactorDbConfig) : await createDefaultDatabase());\n\t\tif (this.migrationStrategy === \"auto\") {\n\t\t\tconst result = await runMigrations(baseDatabase, REACTOR_SCHEMA);\n\t\t\tif (!result.success && result.error) throw new Error(`Database migration failed: ${result.error.message}`);\n\t\t}\n\t\tconst database = baseDatabase.withSchema(REACTOR_SCHEMA);\n\t\tconst operationStore = new KyselyOperationStore(database);\n\t\tconst keyframeStore = new KyselyKeyframeStore(database);\n\t\tconst eventBus = this.eventBus || new EventBus();\n\t\tconst resolver = this.documentModelLoader ? new DocumentModelResolver(documentModelRegistry, this.documentModelLoader) : new NullDocumentModelResolver(documentModelRegistry);\n\t\tif (resolver instanceof DocumentModelResolver) resolver.setModelLoadedHook((documentType) => eventBus.emit(ReactorEventTypes.MODEL_LOADED, { documentType }));\n\t\tconst queue = this.queueInstance ?? new InMemoryQueue(eventBus, resolver);\n\t\tconst jobTracker = new InMemoryJobTracker(eventBus);\n\t\tconst writeCache = new KyselyWriteCache(keyframeStore, operationStore, documentModelRegistry, {\n\t\t\tmaxDocuments: this.writeCacheConfig?.maxDocuments ?? 100,\n\t\t\tringBufferSize: this.writeCacheConfig?.ringBufferSize ?? 10,\n\t\t\tkeyframeInterval: this.writeCacheConfig?.keyframeInterval ?? 10\n\t\t});\n\t\tawait writeCache.startup();\n\t\tconst operationIndex = new KyselyOperationIndex(database);\n\t\tconst documentMetaCache = new DocumentMetaCache(operationStore, { maxDocuments: 1e3 });\n\t\tawait documentMetaCache.startup();\n\t\tconst collectionMembershipCache = new CollectionMembershipCache(operationIndex);\n\t\tconst executionScope = new KyselyExecutionScope(database, operationStore, operationIndex, keyframeStore, writeCache, documentMetaCache, collectionMembershipCache);\n\t\tlet executorManager = this.executorManager;\n\t\tlet executorStartCount = this.executorConfig.maxConcurrency ?? 1;\n\t\tif (!executorManager) if (this.workerPool) {\n\t\t\tconst pool = this.workerPool;\n\t\t\tlet factory = pool.factory;\n\t\t\tif (!factory) {\n\t\t\t\tif (pool.db === void 0) throw new Error(\"unreachable: worker pool configured without db or factory\");\n\t\t\t\tfactory = await this.createDefaultWorkerFactory(pool.numWorkers, pool.db, pool.verifier);\n\t\t\t}\n\t\t\tconst poolManager = new WorkerPoolJobExecutorManager(factory, eventBus, queue, jobTracker, this.logger, resolver, operationIndex, this.executorConfig.jobTimeoutMs, this.executorConfig.deferredJobTtlMs);\n\t\t\texecutorManager = poolManager;\n\t\t\texecutorStartCount = pool.numWorkers;\n\t\t\tif (resolver instanceof DocumentModelResolver) resolver.setBroadcastHook((entry) => poolManager.loadModel(entry));\n\t\t} else executorManager = new SimpleJobExecutorManager(() => new SimpleJobExecutor(this.logger, documentModelRegistry, operationStore, eventBus, writeCache, operationIndex, documentMetaCache, collectionMembershipCache, this.driveContainerTypes, this.executorConfig, this.signatureVerifier, executionScope), eventBus, queue, jobTracker, this.logger, resolver, this.executorConfig.jobTimeoutMs, this.executorConfig.deferredJobTtlMs);\n\t\tawait executorManager.start(executorStartCount);\n\t\tconst callerReadModels = Array.from(new Set([...this.readModels]));\n\t\tconst degradedComponents = [];\n\t\tconst startDegraded = (component, error) => {\n\t\t\tdegradedComponents.push({\n\t\t\t\tcomponent,\n\t\t\t\terror: error instanceof Error ? error : new Error(String(error))\n\t\t\t});\n\t\t\tthis.logger?.error(\"Reactor component started degraded: @component\", component, error);\n\t\t};\n\t\tconst documentViewConsistencyTracker = new ConsistencyTracker();\n\t\tconst documentView = new KyselyDocumentView(database, operationStore, operationIndex, writeCache, documentViewConsistencyTracker, featureFlags.documentDecisions);\n\t\ttry {\n\t\t\tawait documentView.init();\n\t\t} catch (error) {\n\t\t\tstartDegraded(\"document view\", error);\n\t\t}\n\t\tconst documentIndexerConsistencyTracker = new ConsistencyTracker();\n\t\tconst documentIndexer = new KyselyDocumentIndexer(database, operationIndex, writeCache, documentIndexerConsistencyTracker);\n\t\ttry {\n\t\t\tawait documentIndexer.init();\n\t\t} catch (error) {\n\t\t\tstartDegraded(\"document indexer\", error);\n\t\t}\n\t\tconst subscriptionManager = new ReactorSubscriptionManager(new DefaultSubscriptionErrorHandler());\n\t\tconst subscriptionNotificationReadModel = new SubscriptionNotificationReadModel(subscriptionManager, documentView);\n\t\tconst processorManagerConsistencyTracker = new ConsistencyTracker();\n\t\tconst processorManager = new ProcessorManager(database, operationIndex, writeCache, processorManagerConsistencyTracker, this.logger, this.driveContainerTypes, { legacyProcessorIds: this.features.legacyProcessorIds !== false });\n\t\ttry {\n\t\t\tawait processorManager.init();\n\t\t} catch (error) {\n\t\t\tstartDegraded(\"processor manager\", error);\n\t\t}\n\t\tfor (const [index, factory] of this.readModelFactories.entries()) try {\n\t\t\tconst readModel = await factory({\n\t\t\t\tdocumentModelRegistry,\n\t\t\t\toperationIndex,\n\t\t\t\twriteCache,\n\t\t\t\tprocessorManagerConsistencyTracker\n\t\t\t});\n\t\t\tcallerReadModels.push(readModel);\n\t\t} catch (error) {\n\t\t\tstartDegraded(`read model ${index}${factory.name ? ` (${factory.name})` : \"\"}`, error);\n\t\t}\n\t\tconst readModelInstances = [\n\t\t\t...callerReadModels,\n\t\t\tdocumentView,\n\t\t\tdocumentIndexer\n\t\t];\n\t\tconst hostTrackers = {\n\t\t\t\"document-view\": documentViewConsistencyTracker,\n\t\t\t\"document-indexer\": documentIndexerConsistencyTracker\n\t\t};\n\t\tconst readModelCoordinator = this.readModelCoordinator ? this.readModelCoordinator : this.readModelCoordinatorFactory ? await this.readModelCoordinatorFactory({\n\t\t\teventBus,\n\t\t\tlogger: this.logger,\n\t\t\treadModels: callerReadModels,\n\t\t\tsubscriptionNotificationReadModel,\n\t\t\tprocessorManager,\n\t\t\tdocumentView,\n\t\t\tdocumentIndexer,\n\t\t\tcreateProjectionShardManager: (config) => this.createProjectionShardManager(config, eventBus, hostTrackers, false),\n\t\t\tregisterShutdownHook: (hook) => this.shutdownHooks.push(hook)\n\t\t}) : this.projectionShardConfig ? await this.createProjectionShardManager(this.projectionShardConfig, eventBus, hostTrackers, true) : new ReadModelCoordinator(eventBus, readModelInstances, [subscriptionNotificationReadModel, processorManager]);\n\t\tconst reactor = new Reactor(this.logger, documentModelRegistry, queue, jobTracker, readModelCoordinator, this.features, documentView, documentIndexer, operationStore, eventBus, executorManager);\n\t\tlet syncModule = void 0;\n\t\tif (this.channelScheme) {\n\t\t\tconst factory = this.channelScheme === ChannelScheme.CONNECT ? new GqlRequestChannelFactory(this.logger, this.jwtHandler, queue) : new GqlResponseChannelFactory(this.logger);\n\t\t\tsyncModule = new SyncBuilder().withChannelFactory(factory).buildModule(reactor, this.logger, operationIndex, eventBus, database, this.driveContainerTypes);\n\t\t\tawait syncModule.syncManager.startup();\n\t\t} else if (this.syncBuilder) {\n\t\t\tsyncModule = this.syncBuilder.buildModule(reactor, this.logger, operationIndex, eventBus, database, this.driveContainerTypes);\n\t\t\tawait syncModule.syncManager.startup();\n\t\t}\n\t\tlet groupReevaluationTrigger;\n\t\tif (featureFlags.authGroups) {\n\t\t\tgroupReevaluationTrigger = new GroupReevaluationTrigger(this.logger, eventBus, queue, operationIndex);\n\t\t\tgroupReevaluationTrigger.startup();\n\t\t}\n\t\tconst module = {\n\t\t\teventBus,\n\t\t\tdocumentModelRegistry,\n\t\t\tfeatureFlags,\n\t\t\tqueue,\n\t\t\tjobTracker,\n\t\t\texecutorManager,\n\t\t\tdatabase,\n\t\t\toperationStore,\n\t\t\tkeyframeStore,\n\t\t\twriteCache,\n\t\t\toperationIndex,\n\t\t\tdocumentView,\n\t\t\tdocumentViewConsistencyTracker,\n\t\t\tdocumentIndexer,\n\t\t\tdocumentIndexerConsistencyTracker,\n\t\t\treadModelCoordinator,\n\t\t\tsubscriptionManager,\n\t\t\tprocessorManager,\n\t\t\tprocessorManagerConsistencyTracker,\n\t\t\tsyncModule,\n\t\t\treactor,\n\t\t\tgroupReevaluationTrigger,\n\t\t\tpools: this.instrumentedPools,\n\t\t\tdegradedComponents\n\t\t};\n\t\tif (degradedComponents.length > 0) this.logger.warn(\"Reactor started with @count degraded component(s): @components\", degradedComponents.length, degradedComponents.map(({ component }) => component).join(\", \"));\n\t\tif (this.signalHandlersEnabled) this.attachSignalHandlers(module);\n\t\treturn module;\n\t}\n\t/**\n\t* The single Postgres config for the parent, executor workers, and\n\t* projection shards. They must share one physical database (the parent\n\t* writes operations; workers and shards read them), so divergent\n\t* worker/shard targets throw. `withKysely` overrides the parent and is not\n\t* validated against a worker/shard `db`.\n\t*/\n\tresolveReactorDbConfig() {\n\t\tconst workerDb = this.workerPool?.db;\n\t\tconst projectionDb = this.projectionShardConfig?.db;\n\t\tif (workerDb && projectionDb && !sameDatabaseTarget(workerDb, projectionDb)) throw new Error(\"withWorkerPool({ db }) and withProjectionShards({ db }) must address the same Postgres database (same host, port, and database); the parent writes operations there and the projection shards read them.\");\n\t\treturn workerDb ?? projectionDb;\n\t}\n\t/**\n\t* Constructs a {@link ProjectionShardManager} bound to the host event\n\t* bus. Builds the default thread-transport factory unless one was\n\t* injected via {@link withProjectionWorkerFactory}. Calls\n\t* `manager.startup()` so all N workers reach READY before the reactor\n\t* is returned to the caller.\n\t*\n\t* @param consistencyTrackers The host's trackers for the built-in read\n\t* models, keyed by kind. Under sharding the host's own copies of those\n\t* models never index an operation, so the manager advances these from the\n\t* shards' relayed indexing reports; without them every read carrying a\n\t* consistency token waits forever.\n\t* @param registerShutdownHook Whether the builder owns `manager.shutdown()`\n\t* at signal time. False for the coordinator-factory path, whose factory\n\t* registers its own hook so host chains drain before the worker stops.\n\t*/\n\tasync createProjectionShardManager(config, eventBus, consistencyTrackers, registerShutdownHook) {\n\t\tconst parentDb = this.resolveReactorDbConfig();\n\t\tconst baseDb = config.db ?? parentDb;\n\t\tconst caller = this.projectionShardConfig !== void 0 ? \"withProjectionShards\" : \"withReadModelCoordinatorFactory\";\n\t\tif (!baseDb) throw new Error(`${caller} requires a db (or an executor worker pool configured with one); projection workers need connection info to open their own pools.`);\n\t\tconst workerDb = this.workerPool?.db;\n\t\tif (config.db && workerDb && !sameDatabaseTarget(workerDb, config.db)) throw new Error(\"withWorkerPool({ db }) and the projection worker db must address the same Postgres database (same host, port, and database); the parent writes operations there and the projection shards read them.\");\n\t\tif (config.db && this.kyselyInstance === void 0) {\n\t\t\tif (!parentDb) throw new Error(`The projection worker db passed to ${caller} must also be the parent reactor's database, but nothing configures the parent: it would fall back to the default embedded database while the worker projects into Postgres. Pass the same { db } to withWorkerPool, or give the parent its connection with withKysely.`);\n\t\t\tif (!sameDatabaseTarget(config.db, parentDb)) throw new Error(`The projection worker db passed to ${caller} and the parent reactor database must address the same Postgres database (same host, port, and database); the parent writes operations there and the projection shards read them.`);\n\t\t}\n\t\tvalidateBuiltInKindCoverage(config.preReadyKinds, config.postReadyKinds);\n\t\tif (this.moduleOnlyModelKeys.length > 0) throw new Error(`projection workers require worker-importable sources, but these models were registered only as live modules: ${this.moduleOnlyModelKeys.join(\", \")}. Provide a { filePath } or { packageName } source for each.`);\n\t\tconst models = this.resolvedModelManifest ?? [];\n\t\tconst db = {\n\t\t\t...baseDb,\n\t\t\tpoolSize: config.poolSize ?? baseDb.poolSize,\n\t\t\tapplicationName: config.db?.applicationName ?? \"reactor-projection-shard\"\n\t\t};\n\t\tconst factory = this.projectionWorkerFactory ?? await this.createDefaultProjectionWorkerFactory();\n\t\tconst poolInstrumentations = [];\n\t\tfor (let i = 0; i < config.shardCount; i++) {\n\t\t\tconst forwarder = createForwardingPoolInstrumentation(`projection-shard-${i}`);\n\t\t\tpoolInstrumentations.push(forwarder);\n\t\t\tthis.instrumentedPools.push(forwarder);\n\t\t}\n\t\tconst { ProjectionShardManager } = await import(\"./projection-shard-manager-CPQc5XHL.js\");\n\t\tconst manager = new ProjectionShardManager({\n\t\t\tshardCount: config.shardCount,\n\t\t\tdb,\n\t\t\tmodels,\n\t\t\tpreReadyKinds: config.preReadyKinds,\n\t\t\tpostReadyKinds: config.postReadyKinds,\n\t\t\tfactory,\n\t\t\tlogger: this.logger,\n\t\t\thostBus: eventBus,\n\t\t\tinitTimeoutMs: config.initTimeoutMs,\n\t\t\tshutdownGraceMs: config.shutdownGraceMs,\n\t\t\tdrainTimeoutMs: config.drainTimeoutMs,\n\t\t\tchainDepthReportIntervalMs: config.chainDepthReportIntervalMs,\n\t\t\tpoolInstrumentations,\n\t\t\tconsistencyTrackers,\n\t\t\tonReadReady: config.onReadReady,\n\t\t\tonShardFatal: config.onShardFatal\n\t\t});\n\t\ttry {\n\t\t\tawait manager.startup();\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait manager.shutdown();\n\t\t\t} catch (shutdownError) {\n\t\t\t\tthis.logger.warn(\"projection shard manager shutdown after a failed startup also failed: @error\", shutdownError);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tif (registerShutdownHook) this.shutdownHooks.push(() => manager.shutdown());\n\t\treturn manager;\n\t}\n\tasync createDefaultProjectionWorkerFactory() {\n\t\tconst [{ createProjectionThreadTransport }, { projectionWorkerEntryPath }] = await Promise.all([import(\"./transport-CuogVKN_.js\"), import(\"./projection-worker-wI4PwcV2.js\")]);\n\t\treturn () => createProjectionThreadTransport(projectionWorkerEntryPath);\n\t}\n\t/**\n\t* Default {@link WorkerFactory} used when the pool options carry no\n\t* custom `factory`. Each worker spawns a real `node:worker_threads`\n\t* Worker pointing at the compiled `worker/entry.js`.\n\t*/\n\tasync createDefaultWorkerFactory(numWorkers, db, signatureVerifier) {\n\t\tconst [{ WorkerHandle }, { createThreadTransport }, { workerEntryPath }] = await Promise.all([\n\t\t\timport(\"./worker-handle-CrERzl8s.js\"),\n\t\t\timport(\"./transport-ByGviWdZ.js\"),\n\t\t\timport(\"./worker-HPysBfhx.js\").then((n) => n.n)\n\t\t]);\n\t\tconst poolConfig = {\n\t\t\tenabled: true,\n\t\t\tnumWorkers,\n\t\t\tworkerType: \"thread\"\n\t\t};\n\t\tconst models = this.resolvedModelManifest ?? [];\n\t\tconst logger = this.logger;\n\t\treturn (index) => {\n\t\t\tconst workerId = `reactor-worker-${index}`;\n\t\t\tconst poolInstrumentation = createForwardingPoolInstrumentation(workerId);\n\t\t\tthis.instrumentedPools.push(poolInstrumentation);\n\t\t\treturn new WorkerHandle({\n\t\t\t\tworkerId,\n\t\t\t\tindex,\n\t\t\t\ttransport: createThreadTransport(workerEntryPath),\n\t\t\t\tinitPayload: {\n\t\t\t\t\tpoolConfig,\n\t\t\t\t\tdb,\n\t\t\t\t\tsignatureVerifier,\n\t\t\t\t\tmodels,\n\t\t\t\t\texecutorConfig: this.executorConfig\n\t\t\t\t},\n\t\t\t\tlogger,\n\t\t\t\tpoolInstrumentation\n\t\t\t});\n\t\t};\n\t}\n\t/**\n\t* Builds the parent Kysely instance against a real Postgres server using\n\t* the same {@link DbConfig} the workers receive at init. Used in the\n\t* worker-pool path so the parent reactor and each worker thread share\n\t* storage; PGlite cannot be shared across threads. The constructed pool\n\t* is wrapped with {@link instrumentPgPool} and the resulting\n\t* {@link PoolInstrumentation} is pushed onto {@link instrumentedPools} so\n\t* the reactor module exposes acquire-wait and pool-stat surfaces.\n\t*/\n\tasync createPostgresDatabase(config) {\n\t\tconst { Kysely, PostgresDialect } = await import(\"kysely\");\n\t\tconst Pool = (await import(\"pg\")).default.Pool;\n\t\tconst pool = new Pool({\n\t\t\thost: config.host,\n\t\t\tport: config.port,\n\t\t\tdatabase: config.database,\n\t\t\tuser: config.user,\n\t\t\tpassword: config.password,\n\t\t\tssl: config.ssl ? { rejectUnauthorized: false } : void 0,\n\t\t\tapplication_name: config.applicationName,\n\t\t\tmax: config.poolSize,\n\t\t\tconnectionTimeoutMillis: config.connectionTimeoutMillis,\n\t\t\tidleTimeoutMillis: config.idleTimeoutMillis\n\t\t});\n\t\tthis.instrumentedPools.push(instrumentPgPool(pool, config.applicationName ?? \"reactor-host\"));\n\t\treturn new Kysely({ dialect: new PostgresDialect({ pool }) });\n\t}\n\tattachSignalHandlers(module) {\n\t\tif (typeof globalThis === \"undefined\" || !(\"process\" in globalThis) || typeof globalThis.process.on !== \"function\") return;\n\t\tconst nodeProcess = globalThis.process;\n\t\tconst realExit = nodeProcess.exit.bind(nodeProcess);\n\t\tlet shutdownInProgress = false;\n\t\tlet pendingExitCode;\n\t\tconst handler = async (signal) => {\n\t\t\tif (shutdownInProgress) {\n\t\t\t\tthis.logger.warn(`Received ${signal} again, continuing graceful shutdown...`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tshutdownInProgress = true;\n\t\t\tnodeProcess.exit = ((code) => {\n\t\t\t\tpendingExitCode ??= code ?? 0;\n\t\t\t});\n\t\t\tthis.logger.info(`Received ${signal}, starting graceful shutdown...`);\n\t\t\tconst status = module.reactor.kill();\n\t\t\ttry {\n\t\t\t\tawait status.completed;\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Shutdown failed waiting for reactor:\", error);\n\t\t\t\tnodeProcess.exit = realExit;\n\t\t\t\trealExit(1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const hook of this.shutdownHooks) try {\n\t\t\t\tawait hook();\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Shutdown hook failed:\", error);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait module.database.destroy();\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(\"Shutdown failed destroying database:\", error);\n\t\t\t\tnodeProcess.exit = realExit;\n\t\t\t\trealExit(1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.logger.info(\"Shutdown complete\");\n\t\t\tnodeProcess.exit = realExit;\n\t\t\trealExit(pendingExitCode ?? 0);\n\t\t};\n\t\tnodeProcess.prependListener(\"SIGINT\", () => void handler(\"SIGINT\"));\n\t\tnodeProcess.prependListener(\"SIGTERM\", () => void handler(\"SIGTERM\"));\n\t}\n};\n//#endregion\n//#region src/projection/hybrid-projection-coordinator.ts\n/** Host-side stages on a per-queueKey chain driven by the worker's read-ready. */\nvar HybridProjectionCoordinator = class {\n\t/** One array, mutated in place: reactor-api captures it by reference once. */\n\treadModels;\n\teventBus;\n\tlogger;\n\tmanager;\n\tpreReady;\n\tpostReady;\n\tchains = /* @__PURE__ */ new Map();\n\tconstructor(options) {\n\t\tthis.eventBus = options.eventBus;\n\t\tthis.logger = options.logger;\n\t\tthis.manager = options.manager;\n\t\tthis.preReady = options.preReady;\n\t\tthis.postReady = options.postReady;\n\t\tthis.readModels = [\n\t\t\t...options.preReady,\n\t\t\t...options.postReady,\n\t\t\t...options.lookupOnly\n\t\t];\n\t}\n\tstart() {\n\t\tthis.manager.start();\n\t}\n\tstop() {\n\t\tthis.manager.stop();\n\t}\n\t/** Wired as `onReadReady`; host trackers are already advanced (port FIFO). */\n\tacceptReadReady(event) {\n\t\tif (event.operations.length === 0) {\n\t\t\tthis.manager.emitReadReady(event).catch((err) => this.logger.error(\"JOB_READ_READY emit failed for job @jobId: @Error\", { jobId: event.jobId }, err));\n\t\t\treturn;\n\t\t}\n\t\tconst enqueuedAt = performance.now();\n\t\tconst key = this.queueKeyFor(event);\n\t\tconst current = (this.chains.get(key) ?? Promise.resolve()).then(() => this.runHostChain(event, enqueuedAt));\n\t\tthis.chains.set(key, current);\n\t\tcurrent.finally(() => {\n\t\t\tif (this.chains.get(key) === current) this.chains.delete(key);\n\t\t});\n\t}\n\taddReadModel(readModel, stage) {\n\t\tif (this.readModels.some(({ name }) => name === readModel.name)) throw new Error(`Read model \"${readModel.name}\" is already registered`);\n\t\tif (stage === \"pre_ready\") this.preReady.push(readModel);\n\t\telse this.postReady.push(readModel);\n\t\tthis.readModels.push(readModel);\n\t}\n\tgetChainDepth() {\n\t\treturn this.manager.getChainDepth() + this.chains.size;\n\t}\n\t/** Worker chains flush first, so every relayed read-ready is in `chains`. */\n\tasync drain() {\n\t\tawait this.manager.drain();\n\t\twhile (this.chains.size > 0) {\n\t\t\tconst pending = Array.from(this.chains.values());\n\t\t\tawait Promise.allSettled(pending);\n\t\t}\n\t}\n\t/** Builder shutdown hook; reaches `manager.shutdown()` even when drain fails. */\n\tasync shutdown() {\n\t\ttry {\n\t\t\tawait this.drain();\n\t\t} catch (error) {\n\t\t\tthis.logger.warn(\"hybrid coordinator drain failed during shutdown: @Error\", error);\n\t\t}\n\t\tawait this.manager.shutdown();\n\t}\n\tasync runHostChain(event, enqueuedAt) {\n\t\tconst chainWaitDurationMs = performance.now() - enqueuedAt;\n\t\tconst preReadyStart = performance.now();\n\t\ttry {\n\t\t\tawait Promise.all(this.preReady.map((readModel) => this.indexWithTiming(readModel, \"pre_ready\", event)));\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Host pre-ready read model indexing failed for job @jobId: @Error\", { jobId: event.jobId }, error);\n\t\t}\n\t\tconst preReadyDurationMs = performance.now() - preReadyStart;\n\t\tconst emitStart = performance.now();\n\t\ttry {\n\t\t\tawait this.manager.emitReadReady(event);\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"JOB_READ_READY emit failed for job @jobId: @Error\", { jobId: event.jobId }, error);\n\t\t}\n\t\tconst emitDurationMs = performance.now() - emitStart;\n\t\tconst postReadyStart = performance.now();\n\t\ttry {\n\t\t\tawait Promise.all(this.postReady.map((readModel) => this.indexWithTiming(readModel, \"post_ready\", event)));\n\t\t} catch (error) {\n\t\t\tthis.logger.error(\"Host post-ready read model indexing failed for job @jobId: @Error\", { jobId: event.jobId }, error);\n\t\t}\n\t\tconst postReadyDurationMs = performance.now() - postReadyStart;\n\t\tthis.emitBatchCompleted({\n\t\t\tjobId: event.jobId,\n\t\t\tbatchSize: event.operations.length,\n\t\t\tchainWaitDurationMs,\n\t\t\tpreReadyDurationMs,\n\t\t\temitDurationMs,\n\t\t\tpostReadyDurationMs\n\t\t});\n\t}\n\tasync indexWithTiming(readModel, stage, event) {\n\t\tconst start = performance.now();\n\t\tlet success = false;\n\t\ttry {\n\t\t\tawait readModel.indexOperations(event.operations);\n\t\t\tsuccess = true;\n\t\t} finally {\n\t\t\tthis.emitReadModelIndexed({\n\t\t\t\tjobId: event.jobId,\n\t\t\t\treadModelName: readModel.name,\n\t\t\t\tstage,\n\t\t\t\tdurationMs: performance.now() - start,\n\t\t\t\toperationCount: event.operations.length,\n\t\t\t\tsuccess\n\t\t\t});\n\t\t}\n\t}\n\temitBatchCompleted(payload) {\n\t\tthis.eventBus.emit(ReactorEventTypes.READMODEL_BATCH_COMPLETED, payload).catch((err) => this.logger.error(\"READMODEL_BATCH_COMPLETED emit failed for job @jobId: @Error\", { jobId: payload.jobId }, err));\n\t}\n\temitReadModelIndexed(payload) {\n\t\tthis.eventBus.emit(ReactorEventTypes.READMODEL_INDEXED, payload).catch((err) => this.logger.error(\"READMODEL_INDEXED emit failed for job @jobId: @Error\", { jobId: payload.jobId }, err));\n\t}\n\tqueueKeyFor(event) {\n\t\tconst ctx = event.operations[0].context;\n\t\treturn `${ctx.documentId}:${ctx.scope}:${ctx.branch}`;\n\t}\n};\n//#endregion\n//#region src/projection/create-hybrid-projection-coordinator.ts\n/** Built-ins in one projection worker; all other read models stay on the host. */\nfunction createHybridProjectionCoordinatorFactory(options = {}) {\n\treturn async (deps) => {\n\t\tconst ref = { current: void 0 };\n\t\tconst manager = await deps.createProjectionShardManager({\n\t\t\tshardCount: options.shardCount ?? 1,\n\t\t\tpreReadyKinds: [\"document-view\", \"document-indexer\"],\n\t\t\tpostReadyKinds: [],\n\t\t\tdb: options.db,\n\t\t\tpoolSize: options.poolSize,\n\t\t\tinitTimeoutMs: options.initTimeoutMs,\n\t\t\tshutdownGraceMs: options.shutdownGraceMs,\n\t\t\tdrainTimeoutMs: options.drainTimeoutMs,\n\t\t\tchainDepthReportIntervalMs: options.chainDepthReportIntervalMs,\n\t\t\tonReadReady: (event) => ref.current.acceptReadReady(event),\n\t\t\tonShardFatal: options.onFatal\n\t\t});\n\t\tconst coordinator = new HybridProjectionCoordinator({\n\t\t\teventBus: deps.eventBus,\n\t\t\tlogger: deps.logger,\n\t\t\tmanager,\n\t\t\tpreReady: deps.readModels,\n\t\t\tpostReady: [deps.subscriptionNotificationReadModel, deps.processorManager],\n\t\t\tlookupOnly: [deps.documentView, deps.documentIndexer]\n\t\t});\n\t\tref.current = coordinator;\n\t\tdeps.registerShutdownHook(() => coordinator.shutdown());\n\t\treturn coordinator;\n\t};\n}\n//#endregion\n//#region src/signer/passthrough-signer.ts\n/**\n* A no-op signer that returns empty values for all methods.\n* Used when signing is not required.\n*/\nvar PassthroughSigner = class {\n\tpublicKey = {};\n\tsign() {\n\t\treturn Promise.resolve(new Uint8Array(0));\n\t}\n\tverify() {\n\t\treturn Promise.resolve();\n\t}\n\tsignAction() {\n\t\treturn Promise.resolve([\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\"\n\t\t]);\n\t}\n};\n//#endregion\n//#region src/core/reactor-client-builder.ts\n/**\n* Builder class for constructing ReactorClient instances with proper configuration\n*/\nvar ReactorClientBuilder = class {\n\tlogger;\n\treactorBuilder;\n\treactor;\n\teventBus;\n\tdocumentIndexer;\n\tdocumentView;\n\tsigner;\n\tsignatureVerifier;\n\tsubscriptionManager;\n\tjobAwaiter;\n\tdocumentModelLoader;\n\treadGate;\n\t/**\n\t* Sets the logger for the ReactorClient.\n\t* @param logger - The logger to use.\n\t* @returns The ReactorClientBuilder instance.\n\t*/\n\twithLogger(logger) {\n\t\tthis.logger = logger;\n\t\treturn this;\n\t}\n\t/**\n\t* Either this or withReactor must be set.\n\t*/\n\twithReactorBuilder(reactorBuilder) {\n\t\tif (this.reactor) throw new Error(\"Reactor is already set\");\n\t\tthis.reactorBuilder = reactorBuilder;\n\t\treturn this;\n\t}\n\t/**\n\t* Either this or withReactorBuilder must be set.\n\t*/\n\twithReactor(reactor, eventBus, documentIndexer, documentView) {\n\t\tif (this.reactorBuilder) throw new Error(\"ReactorBuilder is already set\");\n\t\tthis.reactor = reactor;\n\t\tthis.eventBus = eventBus;\n\t\tthis.documentIndexer = documentIndexer;\n\t\tthis.documentView = documentView;\n\t\treturn this;\n\t}\n\t/**\n\t* Sets the signer configuration for signing and verifying actions.\n\t*\n\t* @param config - Either an ISigner for signing only, or a SignerConfig for both signing and verification\n\t*/\n\twithSigner(config) {\n\t\tif (\"signer\" in config) {\n\t\t\tthis.signer = config.signer;\n\t\t\tthis.signatureVerifier = config.verifier;\n\t\t} else this.signer = config;\n\t\treturn this;\n\t}\n\twithSubscriptionManager(subscriptionManager) {\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\treturn this;\n\t}\n\twithJobAwaiter(jobAwaiter) {\n\t\tthis.jobAwaiter = jobAwaiter;\n\t\treturn this;\n\t}\n\twithDocumentModelLoader(loader) {\n\t\tthis.documentModelLoader = loader;\n\t\treturn this;\n\t}\n\t/**\n\t* Overrides how reads are gated. A client built from a ReactorBuilder derives\n\t* this from that reactor's flags; one built from `withReactor` cannot, because\n\t* it is handed no flags and no registry, so it gates on the policy alone\n\t* unless a gate is supplied here.\n\t*/\n\twithReadGate(readGate) {\n\t\tthis.readGate = readGate;\n\t\treturn this;\n\t}\n\t/**\n\t* The gate the resolved model calls for. Below authEnforcement there is no\n\t* model to enforce -- the registered one ignores the auth scope -- so the\n\t* policy is evaluated on its own, which is what reads did before the model\n\t* existed. Group serving turns on with authGroups, because below it a\n\t* `{ group }` grant does not match, so a served roster is one no grant can\n\t* use.\n\t*/\n\tresolveReadGate(reactorModule, documentView, model) {\n\t\tif (!reactorModule || model === void 0) return new BareReadGate();\n\t\treturn new ModelReadGate(model, documentView, reactorModule.featureFlags.authGroups, reactorModule.operationIndex, this.logger);\n\t}\n\t/**\n\t* What the client answers an authorization preflight from, or undefined when\n\t* it answers none.\n\t*\n\t* Resolved from the same model reads enforce, so a preflight and a read can\n\t* never decide against different models. Undefined below authEnforcement, and\n\t* undefined on the `withReactor` path, where there are no flags and no\n\t* registry to select a model with -- a client with no model refuses the\n\t* preflight rather than answering it from the legacy host-side permission\n\t* tables. Deliberately not derived from the read gate: `withReadGate`\n\t* overrides that, so sniffing the gate's type would report enforcement from a\n\t* caller's substitution.\n\t*/\n\tresolveActionEvaluation(reactorModule, model) {\n\t\treturn reactorModule && model ? {\n\t\t\tmodel,\n\t\t\tflags: reactorModule.featureFlags\n\t\t} : void 0;\n\t}\n\tasync build() {\n\t\treturn (await this.buildModule()).client;\n\t}\n\tasync buildModule() {\n\t\tif (!this.logger) this.logger = new ConsoleLogger([\"reactor-client\"]);\n\t\tlet reactor;\n\t\tlet eventBus;\n\t\tlet documentIndexer;\n\t\tlet documentView;\n\t\tlet reactorModule;\n\t\tif (this.reactorBuilder) {\n\t\t\tif (this.signatureVerifier) this.reactorBuilder.withSignatureVerifier(this.signatureVerifier);\n\t\t\tif (this.documentModelLoader) this.reactorBuilder.withDocumentModelLoader(this.documentModelLoader);\n\t\t\treactorModule = await this.reactorBuilder.buildModule();\n\t\t\treactor = reactorModule.reactor;\n\t\t\teventBus = reactorModule.eventBus;\n\t\t\tdocumentIndexer = reactorModule.documentIndexer;\n\t\t\tdocumentView = reactorModule.documentView;\n\t\t} else if (this.reactor && this.eventBus && this.documentIndexer && this.documentView) {\n\t\t\treactor = this.reactor;\n\t\t\teventBus = this.eventBus;\n\t\t\tdocumentIndexer = this.documentIndexer;\n\t\t\tdocumentView = this.documentView;\n\t\t\treactorModule = void 0;\n\t\t} else throw new Error(\"Either ReactorBuilder or (Reactor + EventBus + DocumentIndexer + DocumentView) is required\");\n\t\tconst signer = this.signer ?? new PassthroughSigner();\n\t\tconst subscriptionManager = this.subscriptionManager ?? reactorModule?.subscriptionManager ?? new ReactorSubscriptionManager(new DefaultSubscriptionErrorHandler());\n\t\tconst jobAwaiter = this.jobAwaiter ?? new JobAwaiter(eventBus, (jobId, signal) => reactor.getJobStatus(jobId, signal));\n\t\tconst decisionModel = reactorModule ? readDecisionModel(reactorModule.featureFlags, reactorModule.documentModelRegistry) : void 0;\n\t\treturn {\n\t\t\tclient: new ReactorClient(this.logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, this.readGate ?? this.resolveReadGate(reactorModule, documentView, decisionModel), this.resolveActionEvaluation(reactorModule, decisionModel)),\n\t\t\treactor,\n\t\t\teventBus,\n\t\t\tdocumentIndexer,\n\t\t\tdocumentView,\n\t\t\tsigner,\n\t\t\tsubscriptionManager,\n\t\t\tjobAwaiter,\n\t\t\treactorModule\n\t\t};\n\t}\n};\n//#endregion\n//#region src/shared/drive-url.ts\n/**\n* Parse a drive URL to extract drive ID and construct GraphQL endpoint.\n* Preserves any subpath prefix so the result is correct when the reactor is\n* served behind a proxy at a non-root path.\n* e.g., \"http://localhost:4001/d/abc123\" -> { driveId: \"abc123\", graphqlEndpoint: \"http://localhost:4001/graphql/r\" }\n* e.g., \"https://example.com/api/reactor/d/abc123\" -> { ..., graphqlEndpoint: \"https://example.com/api/reactor/graphql/r\" }\n*/\nfunction parseDriveUrl(url) {\n\tconst parsedUrl = new URL(url);\n\tconst driveId = url.split(\"/\").pop() ?? \"\";\n\tconst basePath = parsedUrl.pathname.replace(/\\/d\\/[^/]+\\/?$/, \"\");\n\treturn {\n\t\turl,\n\t\tdriveId,\n\t\tgraphqlEndpoint: `${parsedUrl.protocol}//${parsedUrl.host}${basePath}/graphql/r`\n\t};\n}\n/**\n* Extract drive ID from a drive URL.\n*/\nfunction driveIdFromUrl(url) {\n\treturn url.split(\"/\").pop() ?? \"\";\n}\n//#endregion\n//#region src/decision/sync-scope-gate.ts\n/** What a subject may read of a document that is not there to be read. */\nconst META_ONLY = (scope) => ALWAYS_READABLE_SCOPES.has(scope);\n/**\n* A read gate asked by document id rather than by document.\n*\n* Serving works from an id: an outbox entry names a document, a branch and a\n* scope, and carries no state. Fetching the document is therefore the serving\n* path's own job, and it is the only thing this adds to the gate it wraps.\n*/\nvar SyncScopeGate = class {\n\tconstructor(gate, documentView, logger) {\n\t\tthis.gate = gate;\n\t\tthis.documentView = documentView;\n\t\tthis.logger = logger;\n\t}\n\t/**\n\t* Which scopes of one document the subject may be served.\n\t*\n\t* A document this replica cannot produce yields the metadata scopes and\n\t* nothing else. That is the fail-closed direction, and it is safe to fail\n\t* closed here precisely because serving withholds rather than consumes: the\n\t* entry stays in the outbox and the next poll asks again, so a document that\n\t* is merely not indexed yet is delayed rather than lost.\n\t*\n\t* Any other failure is rethrown. A read side that is down must not read as a\n\t* silent, universal denial, because a denial that looks like a policy is one\n\t* nobody investigates.\n\t*/\n\tasync scopePredicateById(documentId, subject, branch, signal) {\n\t\tlet document;\n\t\ttry {\n\t\t\tdocument = await this.documentView.get(documentId, { branch }, void 0, signal);\n\t\t} catch (error) {\n\t\t\tif (!DocumentNotFoundError.isError(error)) throw error;\n\t\t\tthis.logger?.verbose(`Withholding ${documentId} on branch ${branch}: the read side does not hold it`);\n\t\t\treturn META_ONLY;\n\t\t}\n\t\treturn this.gate.scopePredicate(document, subject, branch, signal);\n\t}\n};\n//#endregion\n//#region src/decision/stream-order.ts\n/**\n* The first pair of effective operations whose stored order contradicts their\n* timestamps, or undefined when the stream is in position order.\n*\n* Such a stream cannot be walked, and the auth stream is never reshuffled once\n* the monotonic rule is on, so run this before enabling enforcement on a fleet.\n*\n* `requireStrict` additionally rejects a tie, which is what the auth stream's\n* monotonic rule requires and what the walk alone does not care about.\n*/\nfunction firstOutOfOrderPair(operations, options) {\n\tconst requireStrict = options?.requireStrict ?? false;\n\tconst effective = garbageCollect(sortOperations([...operations]));\n\tfor (let i = 1; i < effective.length; i++) {\n\t\tconst previous = effective[i - 1];\n\t\tconst current = effective[i];\n\t\tconst previousAt = Date.parse(previous.timestampUtcMs);\n\t\tconst currentAt = Date.parse(current.timestampUtcMs);\n\t\tif (currentAt < previousAt) return {\n\t\t\tprevious,\n\t\t\tcurrent,\n\t\t\tkind: \"descending\"\n\t\t};\n\t\tif (requireStrict && currentAt === previousAt) return {\n\t\t\tprevious,\n\t\t\tcurrent,\n\t\t\tkind: \"tied\"\n\t\t};\n\t}\n}\n//#endregion\n//#region src/read-models/interfaces.ts\nfunction supportsLiveReadModelRegistration(coordinator) {\n\treturn \"addReadModel\" in coordinator && typeof coordinator.addReadModel === \"function\";\n}\n//#endregion\n//#region src/processors/host-module.ts\n/** Builds the reactor-level host module; hosts spread it and add their own fields. */\nfunction createReactorHostModuleBase(options) {\n\tconst { client, readModels, ...core } = options;\n\treturn {\n\t\t...core,\n\t\tclient,\n\t\tdispatch: { async execute(docId, branch, actions, signal) {\n\t\t\tconst jobInfo = await client.executeAsync(docId, branch, actions, signal);\n\t\t\treturn {\n\t\t\t\tid: jobInfo.id,\n\t\t\t\tstatus: jobInfo.status\n\t\t\t};\n\t\t} },\n\t\tgetReadModel(name) {\n\t\t\tconst model = readModels.find((m) => m.name === name);\n\t\t\tif (!model) throw new Error(`Read model \"${name}\" not found`);\n\t\t\treturn model;\n\t\t}\n\t};\n}\n//#endregion\n//#region src/admin/passthrough-keyframe-store.ts\nconst passthroughKeyframeStore = {\n\tputKeyframe: () => Promise.resolve(),\n\tfindNearestKeyframe: () => Promise.resolve(void 0),\n\tlistKeyframes: () => Promise.resolve([]),\n\tdeleteKeyframes: () => Promise.resolve(0)\n};\n//#endregion\n//#region src/admin/document-integrity-service.ts\nvar DocumentIntegrityService = class {\n\tkeyframeStore;\n\toperationStore;\n\twriteCache;\n\tdocumentView;\n\tdocumentModelRegistry;\n\tconstructor(keyframeStore, operationStore, writeCache, documentView, documentModelRegistry) {\n\t\tthis.keyframeStore = keyframeStore;\n\t\tthis.operationStore = operationStore;\n\t\tthis.writeCache = writeCache;\n\t\tthis.documentView = documentView;\n\t\tthis.documentModelRegistry = documentModelRegistry;\n\t}\n\tasync validateDocument(documentId, branch = \"main\", signal) {\n\t\tconst keyframeIssues = [];\n\t\tconst snapshotIssues = [];\n\t\tconst streamOrderIssues = await this.findStreamOrderIssues(documentId, branch, signal);\n\t\tconst replayCache = new KyselyWriteCache(passthroughKeyframeStore, this.operationStore, this.documentModelRegistry, {\n\t\t\tmaxDocuments: 1,\n\t\t\tringBufferSize: 1,\n\t\t\tkeyframeInterval: Number.MAX_SAFE_INTEGER\n\t\t});\n\t\tconst keyframes = await this.keyframeStore.listKeyframes(documentId, void 0, branch, signal);\n\t\tfor (const keyframe of keyframes) {\n\t\t\tthrowIfAborted(signal);\n\t\t\treplayCache.invalidate(documentId, keyframe.scope, branch);\n\t\t\tconst replayedDoc = await replayCache.getState(documentId, keyframe.scope, branch, keyframe.revision, signal);\n\t\t\tconst kfHash = hashDocumentStateForScope(keyframe.document, keyframe.scope);\n\t\t\tconst replayHash = hashDocumentStateForScope(replayedDoc, keyframe.scope);\n\t\t\tif (kfHash !== replayHash) keyframeIssues.push({\n\t\t\t\tscope: keyframe.scope,\n\t\t\t\tbranch,\n\t\t\t\trevision: keyframe.revision,\n\t\t\t\tkeyframeHash: kfHash,\n\t\t\t\treplayedHash: replayHash\n\t\t\t});\n\t\t}\n\t\tlet currentDoc;\n\t\ttry {\n\t\t\tcurrentDoc = await this.documentView.get(documentId);\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tdocumentId,\n\t\t\t\tisConsistent: keyframeIssues.length === 0 && streamOrderIssues.length === 0,\n\t\t\t\tkeyframeIssues,\n\t\t\t\tsnapshotIssues,\n\t\t\t\tstreamOrderIssues\n\t\t\t};\n\t\t}\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\tconst allScopes = Object.keys(revisions.revision);\n\t\tfor (const scope of allScopes) {\n\t\t\tif (scope === \"document\") continue;\n\t\t\treplayCache.invalidate(documentId, scope, branch);\n\t\t\tlet replayedDoc;\n\t\t\ttry {\n\t\t\t\treplayedDoc = await replayCache.getState(documentId, scope, branch, void 0, signal);\n\t\t\t} catch {\n\t\t\t\tthrowIfAborted(signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst snapshotHash = hashDocumentStateForScope(currentDoc, scope);\n\t\t\tconst replayHash = hashDocumentStateForScope(replayedDoc, scope);\n\t\t\tif (snapshotHash !== replayHash) snapshotIssues.push({\n\t\t\t\tscope,\n\t\t\t\tbranch,\n\t\t\t\tsnapshotHash,\n\t\t\t\treplayedHash: replayHash\n\t\t\t});\n\t\t}\n\t\treturn {\n\t\t\tdocumentId,\n\t\t\tisConsistent: keyframeIssues.length === 0 && snapshotIssues.length === 0 && streamOrderIssues.length === 0,\n\t\t\tkeyframeIssues,\n\t\t\tsnapshotIssues,\n\t\t\tstreamOrderIssues\n\t\t};\n\t}\n\tasync rebuildKeyframes(documentId, branch = \"main\", signal) {\n\t\treturn {\n\t\t\tdocumentId,\n\t\t\tkeyframesDeleted: await this.keyframeStore.deleteKeyframes(documentId, void 0, branch, signal),\n\t\t\tscopesInvalidated: 0\n\t\t};\n\t}\n\tasync rebuildSnapshots(documentId, branch = \"main\", signal) {\n\t\tconst scopes = await this.discoverScopes(documentId, branch, signal);\n\t\tfor (const scope of scopes) {\n\t\t\tthrowIfAborted(signal);\n\t\t\tthis.writeCache.invalidate(documentId, scope, branch);\n\t\t}\n\t\treturn {\n\t\t\tdocumentId,\n\t\t\tkeyframesDeleted: 0,\n\t\t\tscopesInvalidated: scopes.length\n\t\t};\n\t}\n\tasync findStreamOrderIssues(documentId, branch, signal) {\n\t\tconst scopes = await this.discoverScopes(documentId, branch, signal);\n\t\tconst issues = [];\n\t\tfor (const scope of scopes) {\n\t\t\tthrowIfAborted(signal);\n\t\t\tconst pair = firstOutOfOrderPair((await this.operationStore.getSince(documentId, scope, branch, -1, void 0, void 0, signal)).results, { requireStrict: scope === \"auth\" });\n\t\t\tif (pair !== void 0) issues.push({\n\t\t\t\tscope,\n\t\t\t\tbranch,\n\t\t\t\t...pair\n\t\t\t});\n\t\t}\n\t\treturn issues;\n\t}\n\tasync discoverScopes(documentId, branch, signal) {\n\t\tconst revisions = await this.operationStore.getRevisions(documentId, branch, signal);\n\t\treturn Object.keys(revisions.revision);\n\t}\n};\n//#endregion\nexport { ALWAYS_READABLE_SCOPES, APPEND_CONDITION_FAILED_PREFIX, AppendConditionFailedError, AuthEnforcementDisabledError, BareReadGate, BaseReadModel, ChannelError, ChannelErrorSource, ChannelScheme, ConsistencyTracker, DEFAULT_DRIVE_CONTAINER_TYPES, DOCUMENT_INDEXER_READ_MODEL, DOCUMENT_VIEW_READ_MODEL, DRIVE_AUTH_ERROR_MESSAGES, DefaultSubscriptionErrorHandler, DocumentAlreadyExistsError, DocumentChangeType, DocumentExistence, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, DriveClient, DriveCollectionId, DriveRequestError, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, HybridProjectionCoordinator, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, IntervalPollTimer, InvalidModuleError, JobAwaiter, JobExecutorEventTypes, JobStatus, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, Mailbox, ModelReadGate, ModuleNotFoundError, NullDocumentModelResolver, OptimisticLockError, PollBehavior, PollingChannelError, ProcessorManager, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, RECOVERABLE_GRAPHQL_ERROR_CODES, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, ReactorEventTypes, ReactorSubscriptionManager, ReadModelCoordinator, RelationalDbProcessor, RelationshipChangeType, RetryAccounting, RevisionMismatchError, SeededStateReader, SimpleJobExecutorManager, SyncBuilder, SyncEventTypes, SyncOperation, SyncOperationAggregateError, SyncOperationStatus, SyncScopeGate, SyncStatus, SyncStatusTracker, addRelationshipAction, authDecisionModel, batchOperationsByDocument, buildDecisionModel, classifyJobFailure, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createHybridProjectionCoordinatorFactory, createMutableShutdownStatus, createReactorHostModuleBase, createRelationalDb, decideAtHead, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, isRecoverableGraphQLError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };\n\n//# sourceMappingURL=index.js.map","/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nvar ownKeys = function(o) {\n ownKeys = Object.getOwnPropertyNames || function (o) {\n var ar = [];\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\n return ar;\n };\n return ownKeys(o);\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\n });\n }\n return path;\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __esDecorate,\n __runInitializers,\n __propKey,\n __setFunctionName,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n __rewriteRelativeImportExtension,\n};\n","(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('tslib'), require('graphql')) :\n typeof define === 'function' && define.amd ? define(['exports', 'tslib', 'graphql'], factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['graphql-tag'] = {}, global.tslib, global.graphql));\n}(this, (function (exports, tslib, graphql) { 'use strict';\n\n var docCache = new Map();\n var fragmentSourceMap = new Map();\n var printFragmentWarnings = true;\n var experimentalFragmentVariables = false;\n function normalize(string) {\n return string.replace(/[\\s,]+/g, ' ').trim();\n }\n function cacheKeyFromLoc(loc) {\n return normalize(loc.source.body.substring(loc.start, loc.end));\n }\n function processFragments(ast) {\n var seenKeys = new Set();\n var definitions = [];\n ast.definitions.forEach(function (fragmentDefinition) {\n if (fragmentDefinition.kind === 'FragmentDefinition') {\n var fragmentName = fragmentDefinition.name.value;\n var sourceKey = cacheKeyFromLoc(fragmentDefinition.loc);\n var sourceKeySet = fragmentSourceMap.get(fragmentName);\n if (sourceKeySet && !sourceKeySet.has(sourceKey)) {\n if (printFragmentWarnings) {\n console.warn(\"Warning: fragment with name \" + fragmentName + \" already exists.\\n\"\n + \"graphql-tag enforces all fragment names across your application to be unique; read more about\\n\"\n + \"this in the docs: http://dev.apollodata.com/core/fragments.html#unique-names\");\n }\n }\n else if (!sourceKeySet) {\n fragmentSourceMap.set(fragmentName, sourceKeySet = new Set);\n }\n sourceKeySet.add(sourceKey);\n if (!seenKeys.has(sourceKey)) {\n seenKeys.add(sourceKey);\n definitions.push(fragmentDefinition);\n }\n }\n else {\n definitions.push(fragmentDefinition);\n }\n });\n return tslib.__assign(tslib.__assign({}, ast), { definitions: definitions });\n }\n function stripLoc(doc) {\n var workSet = new Set(doc.definitions);\n workSet.forEach(function (node) {\n if (node.loc)\n delete node.loc;\n Object.keys(node).forEach(function (key) {\n var value = node[key];\n if (value && typeof value === 'object') {\n workSet.add(value);\n }\n });\n });\n var loc = doc.loc;\n if (loc) {\n delete loc.startToken;\n delete loc.endToken;\n }\n return doc;\n }\n function parseDocument(source) {\n var cacheKey = normalize(source);\n if (!docCache.has(cacheKey)) {\n var parsed = graphql.parse(source, {\n experimentalFragmentVariables: experimentalFragmentVariables,\n allowLegacyFragmentVariables: experimentalFragmentVariables\n });\n if (!parsed || parsed.kind !== 'Document') {\n throw new Error('Not a valid GraphQL document.');\n }\n docCache.set(cacheKey, stripLoc(processFragments(parsed)));\n }\n return docCache.get(cacheKey);\n }\n function gql(literals) {\n var args = [];\n for (var _i = 1; _i < arguments.length; _i++) {\n args[_i - 1] = arguments[_i];\n }\n if (typeof literals === 'string') {\n literals = [literals];\n }\n var result = literals[0];\n args.forEach(function (arg, i) {\n if (arg && arg.kind === 'Document') {\n result += arg.loc.source.body;\n }\n else {\n result += arg;\n }\n result += literals[i + 1];\n });\n return parseDocument(result);\n }\n function resetCaches() {\n docCache.clear();\n fragmentSourceMap.clear();\n }\n function disableFragmentWarnings() {\n printFragmentWarnings = false;\n }\n function enableExperimentalFragmentVariables() {\n experimentalFragmentVariables = true;\n }\n function disableExperimentalFragmentVariables() {\n experimentalFragmentVariables = false;\n }\n var extras = {\n gql: gql,\n resetCaches: resetCaches,\n disableFragmentWarnings: disableFragmentWarnings,\n enableExperimentalFragmentVariables: enableExperimentalFragmentVariables,\n disableExperimentalFragmentVariables: disableExperimentalFragmentVariables\n };\n (function (gql_1) {\n gql_1.gql = extras.gql, gql_1.resetCaches = extras.resetCaches, gql_1.disableFragmentWarnings = extras.disableFragmentWarnings, gql_1.enableExperimentalFragmentVariables = extras.enableExperimentalFragmentVariables, gql_1.disableExperimentalFragmentVariables = extras.disableExperimentalFragmentVariables;\n })(gql || (gql = {}));\n gql[\"default\"] = gql;\n var gql$1 = gql;\n\n exports.default = gql$1;\n exports.disableExperimentalFragmentVariables = disableExperimentalFragmentVariables;\n exports.disableFragmentWarnings = disableFragmentWarnings;\n exports.enableExperimentalFragmentVariables = enableExperimentalFragmentVariables;\n exports.gql = gql;\n exports.resetCaches = resetCaches;\n\n Object.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=graphql-tag.umd.js.map\n","// For backwards compatibility, make sure require(\"graphql-tag\") returns\n// the gql function, rather than an exports object.\nmodule.exports = require('./lib/graphql-tag.umd.js').gql;\n"],"x_google_ignoreList":[2,3,4],"mappings":";;;;AAorBA,MAAM,yBAAyB,IAAI,IAAI;CACtC;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;AAK6B,IAAI,IAAI,CAAC,GAAG,uBAAuB,CAAC,QAAQ,SAAS,SAAS,kBAAkB,CAAC;;;;AAuMhH,IAAI,sBAAsB,cAAc,MAAM;CAC7C;CACA;CACA,YAAY,cAAc,SAAS;EAClC,MAAM,gBAAgB,YAAY,KAAK,IAAI,YAAY,YAAY;AACnE,QAAM,6CAA6C,eAAe,gBAAgB;AAClF,OAAK,OAAO;AACZ,OAAK,eAAe;AACpB,OAAK,mBAAmB;;CAEzB,OAAO,QAAQ,OAAO;AACrB,SAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS;;;AA+vDhD,MAAM,0BAA0B;;;;;;;;;;;;AAYhC,IAAI,oBAAoB,MAAM,kBAAkB;CAC/C,YAAY,SAAS,QAAQ;AAC5B,OAAK,UAAU;AACf,OAAK,SAAS;;CAEf,OAAO,SAAS,SAAS,SAAS,QAAQ;AACzC,SAAO,IAAI,kBAAkB,SAAS,OAAO;;;;;;;CAO9C,OAAO,QAAQ,KAAK;AACnB,MAAI,CAAC,IAAI,WAAW,wBAAwB,CAAE,OAAM,IAAI,MAAM,8BAA8B,MAAM;EAClG,MAAM,OAAO,IAAI,MAAM,EAAE;EACzB,MAAM,UAAU,KAAK,YAAY,IAAI;AACrC,MAAI,YAAY,MAAM,YAAY,KAAK,SAAS,EAAG,OAAM,IAAI,MAAM,kCAAkC,MAAM;AAC3G,SAAO,IAAI,kBAAkB,KAAK,MAAM,UAAU,EAAE,EAAE,KAAK,MAAM,GAAG,QAAQ,CAAC;;CAE9E,IAAI,MAAM;AACT,SAAO,GAAG,0BAA0B,KAAK,OAAO,GAAG,KAAK;;CAEzD,WAAW;AACV,SAAO,KAAK;;CAEb,OAAO,OAAO;AACb,SAAO,KAAK,YAAY,MAAM,WAAW,KAAK,WAAW,MAAM;;;AC87CvC,IAAI,IAAI,OAAO,OADD,EAAE,0BAA0B,8BAA8B,CAClB,CAAC;AA0gEjF,IAAI,aAA6B,yBAAS,YAAY;AACrD,YAAW,YAAY;AACvB,YAAW,cAAc;AACzB,YAAW,cAAc;AACzB,YAAW,yBAAyB;AACpC,YAAW,WAAW;AACtB,QAAO;EACN,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChnML,SAAgB,UAAU,GAAG,GAAG;AAC9B,KAAI,OAAO,MAAM,cAAc,MAAM,KACjC,OAAM,IAAI,UAAU,yBAAyB,OAAO,EAAE,GAAG,gCAAgC;AAC7F,eAAc,GAAG,EAAE;CACnB,SAAS,KAAK;AAAE,OAAK,cAAc;;AACnC,GAAE,YAAY,MAAM,OAAO,OAAO,OAAO,EAAE,IAAI,GAAG,YAAY,EAAE,WAAW,IAAI,IAAI;;AAcrF,SAAgB,OAAO,GAAG,GAAG;CAC3B,IAAI,IAAI,EAAE;AACV,MAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAC9E,GAAE,KAAK,EAAE;AACb,KAAI,KAAK,QAAQ,OAAO,OAAO,0BAA0B;OAChD,IAAI,IAAI,GAAG,IAAI,OAAO,sBAAsB,EAAE,EAAE,IAAI,EAAE,QAAQ,IAC/D,KAAI,EAAE,QAAQ,EAAE,GAAG,GAAG,KAAK,OAAO,UAAU,qBAAqB,KAAK,GAAG,EAAE,GAAG,CAC1E,GAAE,EAAE,MAAM,EAAE,EAAE;;AAE1B,QAAO;;AAGT,SAAgB,WAAW,YAAY,QAAQ,KAAK,MAAM;CACxD,IAAI,IAAI,UAAU,QAAQ,IAAI,IAAI,IAAI,SAAS,SAAS,OAAO,OAAO,OAAO,yBAAyB,QAAQ,IAAI,GAAG,MAAM;AAC3H,KAAI,OAAO,YAAY,YAAY,OAAO,QAAQ,aAAa,WAAY,KAAI,QAAQ,SAAS,YAAY,QAAQ,KAAK,KAAK;KACzH,MAAK,IAAI,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,IAAK,KAAI,IAAI,WAAW,GAAI,MAAK,IAAI,IAAI,EAAE,EAAE,GAAG,IAAI,IAAI,EAAE,QAAQ,KAAK,EAAE,GAAG,EAAE,QAAQ,IAAI,KAAK;AAChJ,QAAO,IAAI,KAAK,KAAK,OAAO,eAAe,QAAQ,KAAK,EAAE,EAAE;;AAG9D,SAAgB,QAAQ,YAAY,WAAW;AAC7C,QAAO,SAAU,QAAQ,KAAK;AAAE,YAAU,QAAQ,KAAK,WAAW;;;AAGpE,SAAgB,aAAa,MAAM,cAAc,YAAY,WAAW,cAAc,mBAAmB;CACvG,SAAS,OAAO,GAAG;AAAE,MAAI,MAAM,KAAK,KAAK,OAAO,MAAM,WAAY,OAAM,IAAI,UAAU,oBAAoB;AAAE,SAAO;;CACnH,IAAI,OAAO,UAAU,MAAM,MAAM,SAAS,WAAW,QAAQ,SAAS,WAAW,QAAQ;CACzF,IAAI,SAAS,CAAC,gBAAgB,OAAO,UAAU,YAAY,OAAO,KAAK,YAAY;CACnF,IAAI,aAAa,iBAAiB,SAAS,OAAO,yBAAyB,QAAQ,UAAU,KAAK,GAAG,EAAE;CACvG,IAAI,GAAG,OAAO;AACd,MAAK,IAAI,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,KAAK;EAC7C,IAAI,UAAU,EAAE;AAChB,OAAK,IAAI,KAAK,UAAW,SAAQ,KAAK,MAAM,WAAW,EAAE,GAAG,UAAU;AACtE,OAAK,IAAI,KAAK,UAAU,OAAQ,SAAQ,OAAO,KAAK,UAAU,OAAO;AACrE,UAAQ,iBAAiB,SAAU,GAAG;AAAE,OAAI,KAAM,OAAM,IAAI,UAAU,yDAAyD;AAAE,qBAAkB,KAAK,OAAO,KAAK,KAAK,CAAC;;EAC1K,IAAI,UAAU,GAAG,WAAW,IAAI,SAAS,aAAa;GAAE,KAAK,WAAW;GAAK,KAAK,WAAW;GAAK,GAAG,WAAW,MAAM,QAAQ;AAC9H,MAAI,SAAS,YAAY;AACrB,OAAI,WAAW,KAAK,EAAG;AACvB,OAAI,WAAW,QAAQ,OAAO,WAAW,SAAU,OAAM,IAAI,UAAU,kBAAkB;AACzF,OAAI,IAAI,OAAO,OAAO,IAAI,CAAE,YAAW,MAAM;AAC7C,OAAI,IAAI,OAAO,OAAO,IAAI,CAAE,YAAW,MAAM;AAC7C,OAAI,IAAI,OAAO,OAAO,KAAK,CAAE,cAAa,QAAQ,EAAE;aAE/C,IAAI,OAAO,OAAO,CACvB,KAAI,SAAS,QAAS,cAAa,QAAQ,EAAE;MACxC,YAAW,OAAO;;AAG/B,KAAI,OAAQ,QAAO,eAAe,QAAQ,UAAU,MAAM,WAAW;AACrE,QAAO;;AAGT,SAAgB,kBAAkB,SAAS,cAAc,OAAO;CAC9D,IAAI,WAAW,UAAU,SAAS;AAClC,MAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACrC,SAAQ,WAAW,aAAa,GAAG,KAAK,SAAS,MAAM,GAAG,aAAa,GAAG,KAAK,QAAQ;AAE3F,QAAO,WAAW,QAAQ,KAAK;;AAGjC,SAAgB,UAAU,GAAG;AAC3B,QAAO,OAAO,MAAM,WAAW,IAAI,GAAG,OAAO,EAAE;;AAGjD,SAAgB,kBAAkB,GAAG,MAAM,QAAQ;AACjD,KAAI,OAAO,SAAS,SAAU,QAAO,KAAK,cAAc,IAAI,OAAO,KAAK,aAAa,IAAI,GAAG;AAC5F,QAAO,OAAO,eAAe,GAAG,QAAQ;EAAE,cAAc;EAAM,OAAO,SAAS,GAAG,OAAO,QAAQ,KAAK,KAAK,GAAG;EAAM,CAAC;;AAGtH,SAAgB,WAAW,aAAa,eAAe;AACrD,KAAI,OAAO,YAAY,YAAY,OAAO,QAAQ,aAAa,WAAY,QAAO,QAAQ,SAAS,aAAa,cAAc;;AAGhI,SAAgB,UAAU,SAAS,YAAY,GAAG,WAAW;CAC3D,SAAS,MAAM,OAAO;AAAE,SAAO,iBAAiB,IAAI,QAAQ,IAAI,EAAE,SAAU,SAAS;AAAE,WAAQ,MAAM;IAAI;;AACzG,QAAO,KAAK,MAAM,IAAI,UAAU,SAAU,SAAS,QAAQ;EACvD,SAAS,UAAU,OAAO;AAAE,OAAI;AAAE,SAAK,UAAU,KAAK,MAAM,CAAC;YAAW,GAAG;AAAE,WAAO,EAAE;;;EACtF,SAAS,SAAS,OAAO;AAAE,OAAI;AAAE,SAAK,UAAU,SAAS,MAAM,CAAC;YAAW,GAAG;AAAE,WAAO,EAAE;;;EACzF,SAAS,KAAK,QAAQ;AAAE,UAAO,OAAO,QAAQ,OAAO,MAAM,GAAG,MAAM,OAAO,MAAM,CAAC,KAAK,WAAW,SAAS;;AAC3G,QAAM,YAAY,UAAU,MAAM,SAAS,cAAc,EAAE,CAAC,EAAE,MAAM,CAAC;GACvE;;AAGJ,SAAgB,YAAY,SAAS,MAAM;CACzC,IAAI,IAAI;EAAE,OAAO;EAAG,MAAM,WAAW;AAAE,OAAI,EAAE,KAAK,EAAG,OAAM,EAAE;AAAI,UAAO,EAAE;;EAAO,MAAM,EAAE;EAAE,KAAK,EAAE;EAAE,EAAE,GAAG,GAAG,GAAG,IAAI,OAAO,QAAQ,OAAO,aAAa,aAAa,WAAW,QAAQ,UAAU;AAChM,QAAO,EAAE,OAAO,KAAK,EAAE,EAAE,EAAE,WAAW,KAAK,EAAE,EAAE,EAAE,YAAY,KAAK,EAAE,EAAE,OAAO,WAAW,eAAe,EAAE,OAAO,YAAY,WAAW;AAAE,SAAO;KAAU;CAC1J,SAAS,KAAK,GAAG;AAAE,SAAO,SAAU,GAAG;AAAE,UAAO,KAAK,CAAC,GAAG,EAAE,CAAC;;;CAC5D,SAAS,KAAK,IAAI;AACd,MAAI,EAAG,OAAM,IAAI,UAAU,kCAAkC;AAC7D,SAAO,MAAM,IAAI,GAAG,GAAG,OAAO,IAAI,KAAK,EAAG,KAAI;AAC1C,OAAI,IAAI,GAAG,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE,YAAY,GAAG,KAAK,EAAE,cAAc,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,GAAG,GAAG,GAAG,EAAE,KAAM,QAAO;AAC3J,OAAI,IAAI,GAAG,EAAG,MAAK,CAAC,GAAG,KAAK,GAAG,EAAE,MAAM;AACvC,WAAQ,GAAG,IAAX;IACI,KAAK;IAAG,KAAK;AAAG,SAAI;AAAI;IACxB,KAAK;AAAG,OAAE;AAAS,YAAO;MAAE,OAAO,GAAG;MAAI,MAAM;MAAO;IACvD,KAAK;AAAG,OAAE;AAAS,SAAI,GAAG;AAAI,UAAK,CAAC,EAAE;AAAE;IACxC,KAAK;AAAG,UAAK,EAAE,IAAI,KAAK;AAAE,OAAE,KAAK,KAAK;AAAE;IACxC;AACI,SAAI,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,SAAS,KAAK,EAAE,EAAE,SAAS,QAAQ,GAAG,OAAO,KAAK,GAAG,OAAO,IAAI;AAAE,UAAI;AAAG;;AACjG,SAAI,GAAG,OAAO,MAAM,CAAC,KAAM,GAAG,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,KAAM;AAAE,QAAE,QAAQ,GAAG;AAAI;;AAC9E,SAAI,GAAG,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI;AAAE,QAAE,QAAQ,EAAE;AAAI,UAAI;AAAI;;AAC7D,SAAI,KAAK,EAAE,QAAQ,EAAE,IAAI;AAAE,QAAE,QAAQ,EAAE;AAAI,QAAE,IAAI,KAAK,GAAG;AAAE;;AAC3D,SAAI,EAAE,GAAI,GAAE,IAAI,KAAK;AACrB,OAAE,KAAK,KAAK;AAAE;;AAEtB,QAAK,KAAK,KAAK,SAAS,EAAE;WACrB,GAAG;AAAE,QAAK,CAAC,GAAG,EAAE;AAAE,OAAI;YAAa;AAAE,OAAI,IAAI;;AACtD,MAAI,GAAG,KAAK,EAAG,OAAM,GAAG;AAAI,SAAO;GAAE,OAAO,GAAG,KAAK,GAAG,KAAK,KAAK;GAAG,MAAM;GAAM;;;AAgBtF,SAAgB,aAAa,GAAG,GAAG;AACjC,MAAK,IAAI,KAAK,EAAG,KAAI,MAAM,aAAa,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,iBAAgB,GAAG,GAAG,EAAE;;AAG/G,SAAgB,SAAS,GAAG;CAC1B,IAAI,IAAI,OAAO,WAAW,cAAc,OAAO,UAAU,IAAI,KAAK,EAAE,IAAI,IAAI;AAC5E,KAAI,EAAG,QAAO,EAAE,KAAK,EAAE;AACvB,KAAI,KAAK,OAAO,EAAE,WAAW,SAAU,QAAO,EAC1C,MAAM,WAAY;AACd,MAAI,KAAK,KAAK,EAAE,OAAQ,KAAI,KAAK;AACjC,SAAO;GAAE,OAAO,KAAK,EAAE;GAAM,MAAM,CAAC;GAAG;IAE9C;AACD,OAAM,IAAI,UAAU,IAAI,4BAA4B,kCAAkC;;AAGxF,SAAgB,OAAO,GAAG,GAAG;CAC3B,IAAI,IAAI,OAAO,WAAW,cAAc,EAAE,OAAO;AACjD,KAAI,CAAC,EAAG,QAAO;CACf,IAAI,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE;AAC/B,KAAI;AACA,UAAQ,MAAM,KAAK,KAAK,MAAM,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAM,IAAG,KAAK,EAAE,MAAM;UAEvE,OAAO;AAAE,MAAI,EAAS,OAAO;WAC5B;AACJ,MAAI;AACA,OAAI,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,WAAY,GAAE,KAAK,EAAE;YAE5C;AAAE,OAAI,EAAG,OAAM,EAAE;;;AAE7B,QAAO;;;AAIT,SAAgB,WAAW;AACzB,MAAK,IAAI,KAAK,EAAE,EAAE,IAAI,GAAG,IAAI,UAAU,QAAQ,IAC3C,MAAK,GAAG,OAAO,OAAO,UAAU,GAAG,CAAC;AACxC,QAAO;;;AAIT,SAAgB,iBAAiB;AAC/B,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,UAAU,QAAQ,IAAI,IAAI,IAAK,MAAK,UAAU,GAAG;AAC7E,MAAK,IAAI,IAAI,MAAM,EAAE,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,IACzC,MAAK,IAAI,IAAI,UAAU,IAAI,IAAI,GAAG,KAAK,EAAE,QAAQ,IAAI,IAAI,KAAK,IAC1D,GAAE,KAAK,EAAE;AACjB,QAAO;;AAGT,SAAgB,cAAc,IAAI,MAAM,MAAM;AAC5C,KAAI,QAAQ,UAAU,WAAW;OAAQ,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAI,IAAI,GAAG,IAC5E,KAAI,MAAM,EAAE,KAAK,OAAO;AACpB,OAAI,CAAC,GAAI,MAAK,MAAM,UAAU,MAAM,KAAK,MAAM,GAAG,EAAE;AACpD,MAAG,KAAK,KAAK;;;AAGrB,QAAO,GAAG,OAAO,MAAM,MAAM,UAAU,MAAM,KAAK,KAAK,CAAC;;AAG1D,SAAgB,QAAQ,GAAG;AACzB,QAAO,gBAAgB,WAAW,KAAK,IAAI,GAAG,QAAQ,IAAI,QAAQ,EAAE;;AAGtE,SAAgB,iBAAiB,SAAS,YAAY,WAAW;AAC/D,KAAI,CAAC,OAAO,cAAe,OAAM,IAAI,UAAU,uCAAuC;CACtF,IAAI,IAAI,UAAU,MAAM,SAAS,cAAc,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE;AAC7D,QAAO,IAAI,OAAO,QAAQ,OAAO,kBAAkB,aAAa,gBAAgB,QAAQ,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,YAAY,EAAE,EAAE,OAAO,iBAAiB,WAAY;AAAE,SAAO;IAAS;CACtN,SAAS,YAAY,GAAG;AAAE,SAAO,SAAU,GAAG;AAAE,UAAO,QAAQ,QAAQ,EAAE,CAAC,KAAK,GAAG,OAAO;;;CACzF,SAAS,KAAK,GAAG,GAAG;AAAE,MAAI,EAAE,IAAI;AAAE,KAAE,KAAK,SAAU,GAAG;AAAE,WAAO,IAAI,QAAQ,SAAU,GAAG,GAAG;AAAE,OAAE,KAAK;MAAC;MAAG;MAAG;MAAG;MAAE,CAAC,GAAG,KAAK,OAAO,GAAG,EAAE;MAAI;;AAAK,OAAI,EAAG,GAAE,KAAK,EAAE,EAAE,GAAG;;;CACnK,SAAS,OAAO,GAAG,GAAG;AAAE,MAAI;AAAE,QAAK,EAAE,GAAG,EAAE,CAAC;WAAW,GAAG;AAAE,UAAO,EAAE,GAAG,IAAI,EAAE;;;CAC7E,SAAS,KAAK,GAAG;AAAE,IAAE,iBAAiB,UAAU,QAAQ,QAAQ,EAAE,MAAM,EAAE,CAAC,KAAK,SAAS,OAAO,GAAG,OAAO,EAAE,GAAG,IAAI,EAAE;;CACrH,SAAS,QAAQ,OAAO;AAAE,SAAO,QAAQ,MAAM;;CAC/C,SAAS,OAAO,OAAO;AAAE,SAAO,SAAS,MAAM;;CAC/C,SAAS,OAAO,GAAG,GAAG;AAAE,MAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,OAAQ,QAAO,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG;;;AAGjF,SAAgB,iBAAiB,GAAG;CAClC,IAAI,GAAG;AACP,QAAO,IAAI,EAAE,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,SAAU,GAAG;AAAE,QAAM;GAAK,EAAE,KAAK,SAAS,EAAE,EAAE,OAAO,YAAY,WAAY;AAAE,SAAO;IAAS;CAC1I,SAAS,KAAK,GAAG,GAAG;AAAE,IAAE,KAAK,EAAE,KAAK,SAAU,GAAG;AAAE,WAAQ,IAAI,CAAC,KAAK;IAAE,OAAO,QAAQ,EAAE,GAAG,EAAE,CAAC;IAAE,MAAM;IAAO,GAAG,IAAI,EAAE,EAAE,GAAG;MAAO;;;AAGpI,SAAgB,cAAc,GAAG;AAC/B,KAAI,CAAC,OAAO,cAAe,OAAM,IAAI,UAAU,uCAAuC;CACtF,IAAI,IAAI,EAAE,OAAO,gBAAgB;AACjC,QAAO,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,OAAO,aAAa,aAAa,SAAS,EAAE,GAAG,EAAE,OAAO,WAAW,EAAE,IAAI,EAAE,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,OAAO,iBAAiB,WAAY;AAAE,SAAO;IAAS;CAC9M,SAAS,KAAK,GAAG;AAAE,IAAE,KAAK,EAAE,MAAM,SAAU,GAAG;AAAE,UAAO,IAAI,QAAQ,SAAU,SAAS,QAAQ;AAAE,QAAI,EAAE,GAAG,EAAE,EAAE,OAAO,SAAS,QAAQ,EAAE,MAAM,EAAE,MAAM;KAAI;;;CAC1J,SAAS,OAAO,SAAS,QAAQ,GAAG,GAAG;AAAE,UAAQ,QAAQ,EAAE,CAAC,KAAK,SAAS,GAAG;AAAE,WAAQ;IAAE,OAAO;IAAG,MAAM;IAAG,CAAC;KAAK,OAAO;;;AAG3H,SAAgB,qBAAqB,QAAQ,KAAK;AAChD,KAAI,OAAO,eAAkB,QAAO,eAAe,QAAQ,OAAO,EAAE,OAAO,KAAK,CAAC;KAAW,QAAO,MAAM;AACzG,QAAO;;AAkBT,SAAgB,aAAa,KAAK;AAChC,KAAI,OAAO,IAAI,WAAY,QAAO;CAClC,IAAI,SAAS,EAAE;AACf,KAAI,OAAO;OAAW,IAAI,IAAI,QAAQ,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,KAAI,EAAE,OAAO,UAAW,iBAAgB,QAAQ,KAAK,EAAE,GAAG;;AAChI,oBAAmB,QAAQ,IAAI;AAC/B,QAAO;;AAGT,SAAgB,gBAAgB,KAAK;AACnC,QAAQ,OAAO,IAAI,aAAc,MAAM,EAAE,SAAS,KAAK;;AAGzD,SAAgB,uBAAuB,UAAU,OAAO,MAAM,GAAG;AAC/D,KAAI,SAAS,OAAO,CAAC,EAAG,OAAM,IAAI,UAAU,gDAAgD;AAC5F,KAAI,OAAO,UAAU,aAAa,aAAa,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,SAAS,CAAE,OAAM,IAAI,UAAU,2EAA2E;AAClL,QAAO,SAAS,MAAM,IAAI,SAAS,MAAM,EAAE,KAAK,SAAS,GAAG,IAAI,EAAE,QAAQ,MAAM,IAAI,SAAS;;AAG/F,SAAgB,uBAAuB,UAAU,OAAO,OAAO,MAAM,GAAG;AACtE,KAAI,SAAS,IAAK,OAAM,IAAI,UAAU,iCAAiC;AACvE,KAAI,SAAS,OAAO,CAAC,EAAG,OAAM,IAAI,UAAU,gDAAgD;AAC5F,KAAI,OAAO,UAAU,aAAa,aAAa,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,SAAS,CAAE,OAAM,IAAI,UAAU,0EAA0E;AACjL,QAAQ,SAAS,MAAM,EAAE,KAAK,UAAU,MAAM,GAAG,IAAI,EAAE,QAAQ,QAAQ,MAAM,IAAI,UAAU,MAAM,EAAG;;AAGtG,SAAgB,sBAAsB,OAAO,UAAU;AACrD,KAAI,aAAa,QAAS,OAAO,aAAa,YAAY,OAAO,aAAa,WAAa,OAAM,IAAI,UAAU,yCAAyC;AACxJ,QAAO,OAAO,UAAU,aAAa,aAAa,QAAQ,MAAM,IAAI,SAAS;;AAG/E,SAAgB,wBAAwB,KAAK,OAAO,OAAO;AACzD,KAAI,UAAU,QAAQ,UAAU,KAAK,GAAG;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAAY,OAAM,IAAI,UAAU,mBAAmB;EACrG,IAAI,SAAS;AACb,MAAI,OAAO;AACT,OAAI,CAAC,OAAO,aAAc,OAAM,IAAI,UAAU,sCAAsC;AACpF,aAAU,MAAM,OAAO;;AAEzB,MAAI,YAAY,KAAK,GAAG;AACtB,OAAI,CAAC,OAAO,QAAS,OAAM,IAAI,UAAU,iCAAiC;AAC1E,aAAU,MAAM,OAAO;AACvB,OAAI,MAAO,SAAQ;;AAErB,MAAI,OAAO,YAAY,WAAY,OAAM,IAAI,UAAU,yBAAyB;AAChF,MAAI,MAAO,WAAU,WAAW;AAAE,OAAI;AAAE,UAAM,KAAK,KAAK;YAAW,GAAG;AAAE,WAAO,QAAQ,OAAO,EAAE;;;AAChG,MAAI,MAAM,KAAK;GAAS;GAAgB;GAAgB;GAAO,CAAC;YAEzD,MACP,KAAI,MAAM,KAAK,EAAE,OAAO,MAAM,CAAC;AAEjC,QAAO;;AAQT,SAAgB,mBAAmB,KAAK;CACtC,SAAS,KAAK,GAAG;AACf,MAAI,QAAQ,IAAI,WAAW,IAAI,iBAAiB,GAAG,IAAI,OAAO,2CAA2C,GAAG;AAC5G,MAAI,WAAW;;CAEjB,IAAI,GAAG,IAAI;CACX,SAAS,OAAO;AACd,SAAO,IAAI,IAAI,MAAM,KAAK,CACxB,KAAI;AACF,OAAI,CAAC,EAAE,SAAS,MAAM,EAAG,QAAO,IAAI,GAAG,IAAI,MAAM,KAAK,EAAE,EAAE,QAAQ,SAAS,CAAC,KAAK,KAAK;AACtF,OAAI,EAAE,SAAS;IACb,IAAI,SAAS,EAAE,QAAQ,KAAK,EAAE,MAAM;AACpC,QAAI,EAAE,MAAO,QAAO,KAAK,GAAG,QAAQ,QAAQ,OAAO,CAAC,KAAK,MAAM,SAAS,GAAG;AAAE,UAAK,EAAE;AAAE,YAAO,MAAM;MAAI;SAEpG,MAAK;WAEL,GAAG;AACR,QAAK,EAAE;;AAGX,MAAI,MAAM,EAAG,QAAO,IAAI,WAAW,QAAQ,OAAO,IAAI,MAAM,GAAG,QAAQ,SAAS;AAChF,MAAI,IAAI,SAAU,OAAM,IAAI;;AAE9B,QAAO,MAAM;;AAGf,SAAgB,iCAAiC,MAAM,aAAa;AAClE,KAAI,OAAO,SAAS,YAAY,WAAW,KAAK,KAAK,CACjD,QAAO,KAAK,QAAQ,oDAAoD,SAAU,GAAG,KAAK,GAAG,KAAK,IAAI;AAClG,SAAO,MAAM,cAAc,SAAS,QAAQ,MAAM,CAAC,OAAO,CAAC,MAAM,IAAK,IAAI,MAAM,MAAM,GAAG,aAAa,GAAG;GAC3G;AAEN,QAAO;;;;AA5VL,iBAAgB,SAAS,GAAG,GAAG;AACjC,kBAAgB,OAAO,kBAClB,EAAE,WAAW,EAAE,EAAE,YAAY,SAAS,SAAU,GAAG,GAAG;AAAE,KAAE,YAAY;OACvE,SAAU,GAAG,GAAG;AAAE,QAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,GAAE,KAAK,EAAE;;AAChG,SAAO,cAAc,GAAG,EAAE;;AAWjB,YAAW,WAAW;AAC/B,aAAW,OAAO,UAAU,SAAS,SAAS,GAAG;AAC7C,QAAK,IAAI,GAAG,IAAI,GAAG,IAAI,UAAU,QAAQ,IAAI,GAAG,KAAK;AACjD,QAAI,UAAU;AACd,SAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,GAAE,KAAK,EAAE;;AAE9E,UAAO;;AAEX,SAAO,SAAS,MAAM,MAAM,UAAU;;AAiH7B,mBAAkB,OAAO,UAAU,SAAS,GAAG,GAAG,GAAG,IAAI;AAClE,MAAI,OAAO,KAAA,EAAW,MAAK;EAC3B,IAAI,OAAO,OAAO,yBAAyB,GAAG,EAAE;AAChD,MAAI,CAAC,SAAS,SAAS,OAAO,CAAC,EAAE,aAAa,KAAK,YAAY,KAAK,cAChE,QAAO;GAAE,YAAY;GAAM,KAAK,WAAW;AAAE,WAAO,EAAE;;GAAO;AAEjE,SAAO,eAAe,GAAG,IAAI,KAAK;OAC9B,SAAS,GAAG,GAAG,GAAG,IAAI;AAC1B,MAAI,OAAO,KAAA,EAAW,MAAK;AAC3B,IAAE,MAAM,EAAE;;AAkGR,sBAAqB,OAAO,UAAU,SAAS,GAAG,GAAG;AACvD,SAAO,eAAe,GAAG,WAAW;GAAE,YAAY;GAAM,OAAO;GAAG,CAAC;MAChE,SAAS,GAAG,GAAG;AAClB,IAAE,aAAa;;AAGb,WAAU,SAAS,GAAG;AACxB,YAAU,OAAO,uBAAuB,SAAU,GAAG;GACnD,IAAI,KAAK,EAAE;AACX,QAAK,IAAI,KAAK,EAAG,KAAI,OAAO,UAAU,eAAe,KAAK,GAAG,EAAE,CAAE,IAAG,GAAG,UAAU;AACjF,UAAO;;AAET,SAAO,QAAQ,EAAE;;AAwDf,oBAAmB,OAAO,oBAAoB,aAAa,kBAAkB,SAAU,OAAO,YAAY,SAAS;EACrH,IAAI,IAAI,IAAI,MAAM,QAAQ;AAC1B,SAAO,EAAE,OAAO,mBAAmB,EAAE,QAAQ,OAAO,EAAE,aAAa,YAAY;;qBAsClE;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;;;;AChZD,EAAC,SAAU,QAAQ,SAAS;AACxB,SAAO,YAAY,YAAY,OAAO,WAAW,cAAc,QAAQ,UAAA,gBAAA,EAAA,aAAA,kBAAA,GAAA,iBAAA,CAA8C,GACrH,OAAO,WAAW,cAAc,OAAO,MAAM,OAAO;GAAC;GAAW;GAAS;GAAU,EAAE,QAAQ,IAC5F,SAAS,OAAO,eAAe,cAAc,aAAa,UAAU,MAAM,QAAQ,OAAO,iBAAiB,EAAE,EAAE,OAAO,OAAO,OAAO,QAAQ;cACvI,SAAU,WAAS,OAAO,SAAS;AAAE;EAE1C,IAAI,2BAAW,IAAI,KAAK;EACxB,IAAI,oCAAoB,IAAI,KAAK;EACjC,IAAI,wBAAwB;EAC5B,IAAI,gCAAgC;EACpC,SAAS,UAAU,QAAQ;AACvB,UAAO,OAAO,QAAQ,WAAW,IAAI,CAAC,MAAM;;EAEhD,SAAS,gBAAgB,KAAK;AAC1B,UAAO,UAAU,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,IAAI,IAAI,CAAC;;EAEnE,SAAS,iBAAiB,KAAK;GAC3B,IAAI,2BAAW,IAAI,KAAK;GACxB,IAAI,cAAc,EAAE;AACpB,OAAI,YAAY,QAAQ,SAAU,oBAAoB;AAClD,QAAI,mBAAmB,SAAS,sBAAsB;KAClD,IAAI,eAAe,mBAAmB,KAAK;KAC3C,IAAI,YAAY,gBAAgB,mBAAmB,IAAI;KACvD,IAAI,eAAe,kBAAkB,IAAI,aAAa;AACtD,SAAI,gBAAgB,CAAC,aAAa,IAAI,UAAU;UACxC,sBACA,SAAQ,KAAK,iCAAiC,eAAe,gMAEwB;gBAGpF,CAAC,aACN,mBAAkB,IAAI,cAAc,+BAAe,IAAI,KAAG,CAAC;AAE/D,kBAAa,IAAI,UAAU;AAC3B,SAAI,CAAC,SAAS,IAAI,UAAU,EAAE;AAC1B,eAAS,IAAI,UAAU;AACvB,kBAAY,KAAK,mBAAmB;;UAIxC,aAAY,KAAK,mBAAmB;KAE1C;AACF,UAAO,MAAM,SAAS,MAAM,SAAS,EAAE,EAAE,IAAI,EAAE,EAAe,aAAa,CAAC;;EAEhF,SAAS,SAAS,KAAK;GACnB,IAAI,UAAU,IAAI,IAAI,IAAI,YAAY;AACtC,WAAQ,QAAQ,SAAU,MAAM;AAC5B,QAAI,KAAK,IACL,QAAO,KAAK;AAChB,WAAO,KAAK,KAAK,CAAC,QAAQ,SAAU,KAAK;KACrC,IAAI,QAAQ,KAAK;AACjB,SAAI,SAAS,OAAO,UAAU,SAC1B,SAAQ,IAAI,MAAM;MAExB;KACJ;GACF,IAAI,MAAM,IAAI;AACd,OAAI,KAAK;AACL,WAAO,IAAI;AACX,WAAO,IAAI;;AAEf,UAAO;;EAEX,SAAS,cAAc,QAAQ;GAC3B,IAAI,WAAW,UAAU,OAAO;AAChC,OAAI,CAAC,SAAS,IAAI,SAAS,EAAE;IACzB,IAAI,SAAS,QAAQ,MAAM,QAAQ;KACA;KAC/B,8BAA8B;KACjC,CAAC;AACF,QAAI,CAAC,UAAU,OAAO,SAAS,WAC3B,OAAM,IAAI,MAAM,gCAAgC;AAEpD,aAAS,IAAI,UAAU,SAAS,iBAAiB,OAAO,CAAC,CAAC;;AAE9D,UAAO,SAAS,IAAI,SAAS;;EAEjC,SAAS,IAAI,UAAU;GACnB,IAAI,OAAO,EAAE;AACb,QAAK,IAAI,KAAK,GAAG,KAAK,UAAU,QAAQ,KACpC,MAAK,KAAK,KAAK,UAAU;AAE7B,OAAI,OAAO,aAAa,SACpB,YAAW,CAAC,SAAS;GAEzB,IAAI,SAAS,SAAS;AACtB,QAAK,QAAQ,SAAU,KAAK,GAAG;AAC3B,QAAI,OAAO,IAAI,SAAS,WACpB,WAAU,IAAI,IAAI,OAAO;QAGzB,WAAU;AAEd,cAAU,SAAS,IAAI;KACzB;AACF,UAAO,cAAc,OAAO;;EAEhC,SAAS,cAAc;AACnB,YAAS,OAAO;AAChB,qBAAkB,OAAO;;EAE7B,SAAS,0BAA0B;AAC/B,2BAAwB;;EAE5B,SAAS,sCAAsC;AAC3C,mCAAgC;;EAEpC,SAAS,uCAAuC;AAC5C,mCAAgC;;EAEpC,IAAI,SAAS;GACJ;GACQ;GACY;GACY;GACC;GACzC;AACD,GAAC,SAAU,OAAO;AACd,SAAM,MAAM,OAAO,KAAK,MAAM,cAAc,OAAO,aAAa,MAAM,0BAA0B,OAAO,yBAAyB,MAAM,sCAAsC,OAAO,qCAAqC,MAAM,uCAAuC,OAAO;KAC7Q,QAAQ,MAAM,EAAE,EAAE;AACrB,MAAI,aAAa;AAGjB,YAAQ,UAFI;AAGZ,YAAQ,uCAAuC;AAC/C,YAAQ,0BAA0B;AAClC,YAAQ,sCAAsC;AAC9C,YAAQ,MAAM;AACd,YAAQ,cAAc;AAEtB,SAAO,eAAeA,WAAS,cAAc,EAAE,OAAO,MAAM,CAAC;IAE9D;;;;;ACpIH,QAAO,UAAA,yBAAA,CAA8C"}
|