@victframework/runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-governance.d.ts +285 -0
- package/dist/agent-governance.js +438 -0
- package/dist/agent-governance.js.map +1 -0
- package/dist/agent-registry.d.ts +103 -0
- package/dist/agent-registry.js +758 -0
- package/dist/agent-registry.js.map +1 -0
- package/dist/agent-types.d.ts +433 -0
- package/dist/agent-types.js +480 -0
- package/dist/agent-types.js.map +1 -0
- package/dist/authority.d.ts +83 -0
- package/dist/authority.js +170 -0
- package/dist/authority.js.map +1 -0
- package/dist/boundary-conformance.d.ts +51 -0
- package/dist/boundary-conformance.js +364 -0
- package/dist/boundary-conformance.js.map +1 -0
- package/dist/control-conformance.d.ts +68 -0
- package/dist/control-conformance.js +1131 -0
- package/dist/control-conformance.js.map +1 -0
- package/dist/control-in-memory.d.ts +257 -0
- package/dist/control-in-memory.js +886 -0
- package/dist/control-in-memory.js.map +1 -0
- package/dist/control-types.d.ts +1017 -0
- package/dist/control-types.js +779 -0
- package/dist/control-types.js.map +1 -0
- package/dist/durable-run.d.ts +73 -0
- package/dist/durable-run.js +262 -0
- package/dist/durable-run.js.map +1 -0
- package/dist/effect-policy.d.ts +22 -0
- package/dist/effect-policy.js +45 -0
- package/dist/effect-policy.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.js +71 -0
- package/dist/errors.js.map +1 -0
- package/dist/in-memory-stores.d.ts +16 -0
- package/dist/in-memory-stores.js +522 -0
- package/dist/in-memory-stores.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/operator-config.d.ts +141 -0
- package/dist/operator-config.js +289 -0
- package/dist/operator-config.js.map +1 -0
- package/dist/orchestration-activation.d.ts +116 -0
- package/dist/orchestration-activation.js +223 -0
- package/dist/orchestration-activation.js.map +1 -0
- package/dist/orchestration-canary-conformance.d.ts +10 -0
- package/dist/orchestration-canary-conformance.js +726 -0
- package/dist/orchestration-canary-conformance.js.map +1 -0
- package/dist/orchestration-commands.d.ts +47 -0
- package/dist/orchestration-commands.js +538 -0
- package/dist/orchestration-commands.js.map +1 -0
- package/dist/orchestration-conformance.d.ts +59 -0
- package/dist/orchestration-conformance.js +594 -0
- package/dist/orchestration-conformance.js.map +1 -0
- package/dist/orchestration-driver-types.d.ts +163 -0
- package/dist/orchestration-driver-types.js +21 -0
- package/dist/orchestration-driver-types.js.map +1 -0
- package/dist/orchestration-driver.d.ts +48 -0
- package/dist/orchestration-driver.js +1030 -0
- package/dist/orchestration-driver.js.map +1 -0
- package/dist/orchestration-in-memory.d.ts +18 -0
- package/dist/orchestration-in-memory.js +1313 -0
- package/dist/orchestration-in-memory.js.map +1 -0
- package/dist/orchestration-join-conformance.d.ts +20 -0
- package/dist/orchestration-join-conformance.js +542 -0
- package/dist/orchestration-join-conformance.js.map +1 -0
- package/dist/orchestration-plan.d.ts +52 -0
- package/dist/orchestration-plan.js +265 -0
- package/dist/orchestration-plan.js.map +1 -0
- package/dist/orchestration-race-conformance.d.ts +35 -0
- package/dist/orchestration-race-conformance.js +1265 -0
- package/dist/orchestration-race-conformance.js.map +1 -0
- package/dist/orchestration-remediation-conformance.d.ts +54 -0
- package/dist/orchestration-remediation-conformance.js +632 -0
- package/dist/orchestration-remediation-conformance.js.map +1 -0
- package/dist/orchestration-store-types.d.ts +568 -0
- package/dist/orchestration-store-types.js +2 -0
- package/dist/orchestration-store-types.js.map +1 -0
- package/dist/pack-conformance.d.ts +59 -0
- package/dist/pack-conformance.js +222 -0
- package/dist/pack-conformance.js.map +1 -0
- package/dist/pack-install.d.ts +44 -0
- package/dist/pack-install.js +126 -0
- package/dist/pack-install.js.map +1 -0
- package/dist/registry.d.ts +107 -0
- package/dist/registry.js +481 -0
- package/dist/registry.js.map +1 -0
- package/dist/runtime.d.ts +158 -0
- package/dist/runtime.js +1341 -0
- package/dist/runtime.js.map +1 -0
- package/dist/serialization.d.ts +26 -0
- package/dist/serialization.js +162 -0
- package/dist/serialization.js.map +1 -0
- package/dist/store-conformance.d.ts +45 -0
- package/dist/store-conformance.js +876 -0
- package/dist/store-conformance.js.map +1 -0
- package/dist/store-errors.d.ts +49 -0
- package/dist/store-errors.js +48 -0
- package/dist/store-errors.js.map +1 -0
- package/dist/store-types.d.ts +331 -0
- package/dist/store-types.js +14 -0
- package/dist/store-types.js.map +1 -0
- package/dist/store-validation.d.ts +63 -0
- package/dist/store-validation.js +164 -0
- package/dist/store-validation.js.map +1 -0
- package/dist/stream-hub.d.ts +151 -0
- package/dist/stream-hub.js +402 -0
- package/dist/stream-hub.js.map +1 -0
- package/dist/testing.d.ts +25 -0
- package/dist/testing.js +19 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +221 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { canonicalJson, canonicalSemanticForm, canonicalSemanticFormV2, computeActivationVersion, computeCapabilitySetVersion, computeGraphVersion, } from '@victframework/kernel';
|
|
2
|
+
import { VictStoreError } from './store-errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared store-level identity validation, executed identically by every
|
|
5
|
+
* conforming adapter (in-memory and SQLite).
|
|
6
|
+
*
|
|
7
|
+
* Identity is CONTENT-derived (Stage 02): the three activation identities
|
|
8
|
+
* are SHA-256 fingerprints computed by the kernel's canonical identity
|
|
9
|
+
* functions. Stores therefore do not trust top-level strings — they
|
|
10
|
+
* recompute every identity from the canonical content and reject any
|
|
11
|
+
* disagreement with a structured, safe error and no partial mutation.
|
|
12
|
+
*/
|
|
13
|
+
function mismatch(operation, message, details) {
|
|
14
|
+
return new VictStoreError('VICT_STORE_ACTIVATION_MISMATCH', message, {
|
|
15
|
+
operation,
|
|
16
|
+
...details,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Publish-time validation: the supplied canonical JSON must be exactly the
|
|
21
|
+
* canonical representation of the supplied manifest, and every
|
|
22
|
+
* content-derived identity must be reproducible from that content:
|
|
23
|
+
*
|
|
24
|
+
* - `manifest.graph` must already be the canonical semantic form of the
|
|
25
|
+
* graph declaration;
|
|
26
|
+
* - `graphVersion` must equal the canonical fingerprint of that form;
|
|
27
|
+
* - `capabilitySetVersion` must equal the canonical fingerprint of the
|
|
28
|
+
* effective bindings;
|
|
29
|
+
* - `activationVersion` must equal the canonical combination of the two.
|
|
30
|
+
*
|
|
31
|
+
* This catches manifests whose top-level identifiers look valid while the
|
|
32
|
+
* binding or graph content differs (the identity would not recompute).
|
|
33
|
+
*/
|
|
34
|
+
export function assertPublishableManifest(command) {
|
|
35
|
+
const manifest = command.manifest;
|
|
36
|
+
if (typeof command.canonicalManifest !== 'string' || command.canonicalManifest.length === 0) {
|
|
37
|
+
throw new VictStoreError('VICT_STORE_INVALID_COMMAND', 'A canonical manifest string is required.', { operation: 'catalog.publish' });
|
|
38
|
+
}
|
|
39
|
+
let recomputed;
|
|
40
|
+
try {
|
|
41
|
+
recomputed = canonicalJson(manifest);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new VictStoreError('VICT_STORE_INVALID_COMMAND', 'The manifest is not a persistable canonical value.', { operation: 'catalog.publish' });
|
|
45
|
+
}
|
|
46
|
+
if (recomputed !== command.canonicalManifest) {
|
|
47
|
+
throw mismatch('catalog.publish', 'The supplied canonical manifest is not the canonical representation of the supplied manifest.', { activationVersion: manifest.activationVersion });
|
|
48
|
+
}
|
|
49
|
+
const isV2 = manifest.graph?.schema === 'vict.graph@2';
|
|
50
|
+
let canonicalGraph;
|
|
51
|
+
try {
|
|
52
|
+
// canonicalSemanticForm is idempotent on an already-canonical graph;
|
|
53
|
+
// comparing its JSON against the stored form detects tampering.
|
|
54
|
+
canonicalGraph = isV2
|
|
55
|
+
? canonicalSemanticFormV2(manifest.graph)
|
|
56
|
+
: canonicalSemanticForm(manifest.graph);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw mismatch('catalog.publish', 'The manifest graph declaration is not in canonical semantic form.', { activationVersion: manifest.activationVersion });
|
|
60
|
+
}
|
|
61
|
+
if (canonicalJson(canonicalGraph) !== canonicalJson(manifest.graph)) {
|
|
62
|
+
throw mismatch('catalog.publish', 'The manifest graph declaration is not in canonical semantic form.', { activationVersion: manifest.activationVersion });
|
|
63
|
+
}
|
|
64
|
+
let graphVersion;
|
|
65
|
+
try {
|
|
66
|
+
graphVersion = computeGraphVersion(manifest.graph);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw mismatch('catalog.publish', 'The graph version could not be recomputed from the manifest content.', { activationVersion: manifest.activationVersion });
|
|
70
|
+
}
|
|
71
|
+
if (graphVersion !== manifest.graphVersion) {
|
|
72
|
+
throw mismatch('catalog.publish', 'The manifest graphVersion does not match its graph content.', { activationVersion: manifest.activationVersion });
|
|
73
|
+
}
|
|
74
|
+
let capabilitySetVersion;
|
|
75
|
+
try {
|
|
76
|
+
capabilitySetVersion = computeCapabilitySetVersion(manifest.bindings);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw mismatch('catalog.publish', 'The capability-set version could not be recomputed from the manifest bindings.', { activationVersion: manifest.activationVersion });
|
|
80
|
+
}
|
|
81
|
+
if (capabilitySetVersion !== manifest.capabilitySetVersion) {
|
|
82
|
+
throw mismatch('catalog.publish', 'The manifest capabilitySetVersion does not match its bindings.', { activationVersion: manifest.activationVersion });
|
|
83
|
+
}
|
|
84
|
+
const activationVersion = computeActivationVersion(graphVersion, capabilitySetVersion, graphVersion.startsWith('v2_') ? 'vict.activation@2' : 'vict.activation@1');
|
|
85
|
+
if (activationVersion !== manifest.activationVersion) {
|
|
86
|
+
throw mismatch('catalog.publish', 'The manifest activationVersion does not match its graph and capability-set versions.', { activationVersion: manifest.activationVersion });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Run-creation validation: the run's graph, graph version, capability-set
|
|
91
|
+
* version, and activation version must describe ONE coherent published
|
|
92
|
+
* activation — the exact stored one.
|
|
93
|
+
*/
|
|
94
|
+
export function assertRunMatchesActivation(stored, identity, operation) {
|
|
95
|
+
if (stored.graphId !== identity.graphId ||
|
|
96
|
+
stored.graphVersion !== identity.graphVersion ||
|
|
97
|
+
stored.capabilitySetVersion !== identity.capabilitySetVersion ||
|
|
98
|
+
stored.activationVersion !== identity.activationVersion) {
|
|
99
|
+
throw mismatch(operation, 'The run identity does not describe the referenced published activation.', {
|
|
100
|
+
activationVersion: identity.activationVersion,
|
|
101
|
+
graphId: identity.graphId,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Selection validation: an activation may only be selected for the graph it
|
|
107
|
+
* belongs to.
|
|
108
|
+
*/
|
|
109
|
+
export function assertActivationBelongsToGraph(stored, graphId, operation) {
|
|
110
|
+
if (stored.graphId !== graphId) {
|
|
111
|
+
throw mismatch(operation, 'The activation does not belong to the graph being selected for.', {
|
|
112
|
+
activationVersion: stored.activationVersion,
|
|
113
|
+
graphId,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Event-append validation: every appended event must carry exactly its
|
|
119
|
+
* stored run's identity columns.
|
|
120
|
+
*/
|
|
121
|
+
export function assertEventMatchesRun(event, run) {
|
|
122
|
+
if (event.runId !== run.runId ||
|
|
123
|
+
event.graphId !== run.graphId ||
|
|
124
|
+
event.graphVersion !== run.graphVersion ||
|
|
125
|
+
event.capabilitySetVersion !== run.capabilitySetVersion ||
|
|
126
|
+
event.activationVersion !== run.activationVersion) {
|
|
127
|
+
throw new VictStoreError('VICT_STORE_INVALID_COMMAND', 'An event references a different run or activation identity than the transition targets.', { operation: 'execution.appendEvents', runId: run.runId, eventRunId: event.runId });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Read-time validation for a stored activation: recompute every identity
|
|
132
|
+
* from the persisted canonical manifest and reject corrupt content instead
|
|
133
|
+
* of silently normalizing it. Used defensively on read paths.
|
|
134
|
+
*/
|
|
135
|
+
export function assertStoredActivationReadable(row) {
|
|
136
|
+
const fail = () => new VictStoreError('VICT_STORE_INVALID_RECORD', 'A stored activation manifest disagrees with its identity columns.', { operation: 'catalog.readActivation', activationVersion: row.activationVersion });
|
|
137
|
+
const manifest = row.manifest;
|
|
138
|
+
if (manifest.activationVersion !== row.activationVersion ||
|
|
139
|
+
manifest.graphId !== row.graphId ||
|
|
140
|
+
manifest.graphVersion !== row.graphVersion ||
|
|
141
|
+
manifest.capabilitySetVersion !== row.capabilitySetVersion) {
|
|
142
|
+
throw fail();
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const isV2 = manifest.graph?.schema === 'vict.graph@2';
|
|
146
|
+
const canonicalGraph = isV2
|
|
147
|
+
? canonicalSemanticFormV2(manifest.graph)
|
|
148
|
+
: canonicalSemanticForm(manifest.graph);
|
|
149
|
+
if (canonicalJson(canonicalGraph) !== canonicalJson(manifest.graph) ||
|
|
150
|
+
computeGraphVersion(manifest.graph) !==
|
|
151
|
+
manifest.graphVersion ||
|
|
152
|
+
computeCapabilitySetVersion(manifest.bindings) !== manifest.capabilitySetVersion ||
|
|
153
|
+
computeActivationVersion(manifest.graphVersion, manifest.capabilitySetVersion, manifest.graphVersion.startsWith('v2_') ? 'vict.activation@2' : 'vict.activation@1') !== manifest.activationVersion) {
|
|
154
|
+
throw fail();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (cause) {
|
|
158
|
+
if (cause instanceof VictStoreError) {
|
|
159
|
+
throw cause;
|
|
160
|
+
}
|
|
161
|
+
throw fail();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=store-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-validation.js","sourceRoot":"","sources":["../src/store-validation.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;;;;;;GASG;AAEH,SAAS,QAAQ,CACf,SAAiB,EACjB,OAAe,EACf,OAAgC;IAEhC,OAAO,IAAI,cAAc,CAAC,gCAAgC,EAAE,OAAO,EAAE;QACnE,SAAS;QACT,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAiC;IACzE,MAAM,QAAQ,GAAuB,OAAO,CAAC,QAAQ,CAAC;IACtD,IAAI,OAAO,OAAO,CAAC,iBAAiB,KAAK,QAAQ,IAAI,OAAO,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,cAAc,CACtB,4BAA4B,EAC5B,0CAA0C,EAC1C,EAAE,SAAS,EAAE,iBAAiB,EAAE,CACjC,CAAC;IACJ,CAAC;IACD,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,cAAc,CACtB,4BAA4B,EAC5B,oDAAoD,EACpD,EAAE,SAAS,EAAE,iBAAiB,EAAE,CACjC,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC7C,MAAM,QAAQ,CACZ,iBAAiB,EACjB,+FAA+F,EAC/F,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAI,QAAQ,CAAC,KAAoC,EAAE,MAAM,KAAK,cAAc,CAAC;IACvF,IAAI,cAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,qEAAqE;QACrE,gEAAgE;QAChE,cAAc,GAAG,IAAI;YACnB,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,KAAsD,CAAC;YAC1F,CAAC,CAAC,qBAAqB,CAAC,QAAQ,CAAC,KAAoD,CAAC,CAAC;IAC3F,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,QAAQ,CACZ,iBAAiB,EACjB,mEAAmE,EACnE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,CAAC,cAAc,CAAC,KAAK,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpE,MAAM,QAAQ,CACZ,iBAAiB,EACjB,mEAAmE,EACnE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACH,YAAY,GAAG,mBAAmB,CAAC,QAAQ,CAAC,KAAkD,CAAC,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,QAAQ,CACZ,iBAAiB,EACjB,sEAAsE,EACtE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,IAAI,YAAY,KAAK,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC3C,MAAM,QAAQ,CACZ,iBAAiB,EACjB,6DAA6D,EAC7D,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,IAAI,oBAA4B,CAAC;IACjC,IAAI,CAAC;QACH,oBAAoB,GAAG,2BAA2B,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,QAAQ,CACZ,iBAAiB,EACjB,gFAAgF,EAChF,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,IAAI,oBAAoB,KAAK,QAAQ,CAAC,oBAAoB,EAAE,CAAC;QAC3D,MAAM,QAAQ,CACZ,iBAAiB,EACjB,gEAAgE,EAChE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,MAAM,iBAAiB,GAAG,wBAAwB,CAChD,YAAY,EACZ,oBAAoB,EACpB,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CAC3E,CAAC;IACF,IAAI,iBAAiB,KAAK,QAAQ,CAAC,iBAAiB,EAAE,CAAC;QACrD,MAAM,QAAQ,CACZ,iBAAiB,EACjB,sFAAsF,EACtF,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAClD,CAAC;IACJ,CAAC;AACH,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAA0B,EAC1B,QAA4B,EAC5B,SAAiB;IAEjB,IACE,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO;QACnC,MAAM,CAAC,YAAY,KAAK,QAAQ,CAAC,YAAY;QAC7C,MAAM,CAAC,oBAAoB,KAAK,QAAQ,CAAC,oBAAoB;QAC7D,MAAM,CAAC,iBAAiB,KAAK,QAAQ,CAAC,iBAAiB,EACvD,CAAC;QACD,MAAM,QAAQ,CACZ,SAAS,EACT,yEAAyE,EACzE;YACE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;YAC7C,OAAO,EAAE,QAAQ,CAAC,OAAO;SAC1B,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAC5C,MAAwE,EACxE,OAAe,EACf,SAAiB;IAEjB,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,QAAQ,CAAC,SAAS,EAAE,iEAAiE,EAAE;YAC3F,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,OAAO;SACR,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAkB,EAAE,GAAuB;IAC/E,IACE,KAAK,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK;QACzB,KAAK,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO;QAC7B,KAAK,CAAC,YAAY,KAAK,GAAG,CAAC,YAAY;QACvC,KAAK,CAAC,oBAAoB,KAAK,GAAG,CAAC,oBAAoB;QACvD,KAAK,CAAC,iBAAiB,KAAK,GAAG,CAAC,iBAAiB,EACjD,CAAC;QACD,MAAM,IAAI,cAAc,CACtB,4BAA4B,EAC5B,yFAAyF,EACzF,EAAE,SAAS,EAAE,wBAAwB,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,EAAE,CACnF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAAC,GAO9C;IACC,MAAM,IAAI,GAAG,GAAmB,EAAE,CAChC,IAAI,cAAc,CAChB,2BAA2B,EAC3B,mEAAmE,EACnE,EAAE,SAAS,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,GAAG,CAAC,iBAAiB,EAAE,CAClF,CAAC;IACJ,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC9B,IACE,QAAQ,CAAC,iBAAiB,KAAK,GAAG,CAAC,iBAAiB;QACpD,QAAQ,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO;QAChC,QAAQ,CAAC,YAAY,KAAK,GAAG,CAAC,YAAY;QAC1C,QAAQ,CAAC,oBAAoB,KAAK,GAAG,CAAC,oBAAoB,EAC1D,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAI,QAAQ,CAAC,KAAoC,EAAE,MAAM,KAAK,cAAc,CAAC;QACvF,MAAM,cAAc,GAAG,IAAI;YACzB,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,KAAsD,CAAC;YAC1F,CAAC,CAAC,qBAAqB,CAAC,QAAQ,CAAC,KAAoD,CAAC,CAAC;QACzF,IACE,aAAa,CAAC,cAAc,CAAC,KAAK,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC/D,mBAAmB,CAAC,QAAQ,CAAC,KAAkD,CAAC;gBAC9E,QAAQ,CAAC,YAAY;YACvB,2BAA2B,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,oBAAoB;YAChF,wBAAwB,CACtB,QAAQ,CAAC,YAAY,EACrB,QAAQ,CAAC,oBAAoB,EAC7B,QAAQ,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CACpF,KAAK,QAAQ,CAAC,iBAAiB,EAChC,CAAC;YACD,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;YACpC,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { type AgentStreamEvent } from '@victframework/contracts';
|
|
2
|
+
import type { AgentStreamLedgerStore } from './control-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Stage 06B — the neutral agent-stream hub (AI-009).
|
|
5
|
+
*
|
|
6
|
+
* One hub owns the per-stream event flow above a durable ledger:
|
|
7
|
+
*
|
|
8
|
+
* - every event is validated against the FINAL `vict.agent-stream@1`
|
|
9
|
+
* field-level schema (fail closed on unknown kinds/fields);
|
|
10
|
+
* - sequence numbers are assigned by the durable ledger (strictly
|
|
11
|
+
* monotonic per stream, survive restart);
|
|
12
|
+
* - durable kinds are persisted ledger rows; `text.delta` is transient and
|
|
13
|
+
* lives only in the bounded replay buffer;
|
|
14
|
+
* - delivery is at-least-once in sequence order (clients deduplicate by
|
|
15
|
+
* streamId + seq);
|
|
16
|
+
* - replay and live delivery use ISOLATED copies: no stored/frozen event
|
|
17
|
+
* object is ever handed to a subscriber queue or mutated after publish;
|
|
18
|
+
* - backpressure coalesces CONSECUTIVE pending `text.delta` events for a
|
|
19
|
+
* slow subscriber only, and never drops, reorders, or coalesces
|
|
20
|
+
* non-delta events; a coalesced delta carries the cursor semantics of
|
|
21
|
+
* the COMPLETE coalesced range (its sequence is the LAST combined
|
|
22
|
+
* sequence, so a reconnect cannot re-deliver part of its text);
|
|
23
|
+
* - reconnect replays from a cursor: durable ledger rows plus buffered
|
|
24
|
+
* transient deltas, detected against the AUTHORITATIVE ledger
|
|
25
|
+
* high-watermark; a cursor older than the replayable transient content
|
|
26
|
+
* reports `olderThanBuffer` so completed content is recovered from
|
|
27
|
+
* durable state — including after a restart when the memory buffer is
|
|
28
|
+
* empty;
|
|
29
|
+
* - a bounded subscriber queue that overflows follows an EXPLICIT
|
|
30
|
+
* recoverable policy: the subscriber is detached through
|
|
31
|
+
* `onOverflow()` and MUST reconnect/replay from its last acknowledged
|
|
32
|
+
* cursor. Durable, control, and terminal events are never silently
|
|
33
|
+
* discarded.
|
|
34
|
+
*
|
|
35
|
+
* The hub is transport-free: SSE belongs to `@victframework/server`.
|
|
36
|
+
*/
|
|
37
|
+
/** One hub subscriber (transport-owned delivery mechanism). */
|
|
38
|
+
export interface AgentStreamSubscriber {
|
|
39
|
+
readonly subscriberId: string;
|
|
40
|
+
/**
|
|
41
|
+
* Deliver one event. Returning `false` signals backpressure: the hub
|
|
42
|
+
* switches this subscriber to buffered mode with delta coalescing until
|
|
43
|
+
* it drains via `pull()`.
|
|
44
|
+
*/
|
|
45
|
+
deliver(event: AgentStreamEvent): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Called when the subscriber's bounded pending queue OVERFLOWS, immediately
|
|
48
|
+
* before the hub detaches the subscriber. The transport MUST recover by
|
|
49
|
+
* reconnecting/replaying from its last acknowledged cursor — the hub never
|
|
50
|
+
* silently discards events to fit the bound.
|
|
51
|
+
*/
|
|
52
|
+
onOverflow?(): void;
|
|
53
|
+
/** Called when the subscriber is detached (clean completion or overflow). */
|
|
54
|
+
detach?(): void;
|
|
55
|
+
}
|
|
56
|
+
/** The reconnect cursor: stream identity + last processed sequence. */
|
|
57
|
+
export interface AgentStreamCursor {
|
|
58
|
+
readonly streamId: string;
|
|
59
|
+
readonly lastSeq: number;
|
|
60
|
+
}
|
|
61
|
+
/** Replay/status disclosure for a reconnect (bounded-memory computation). */
|
|
62
|
+
export interface AgentStreamReplayStatus {
|
|
63
|
+
/** The newest sequence the stream has assigned (ledger high-watermark). */
|
|
64
|
+
readonly newestSeq: number;
|
|
65
|
+
/**
|
|
66
|
+
* True when transient content after the cursor is no longer replayable:
|
|
67
|
+
* at least one sequence in `(lastSeq, newestSeq]` is neither a durable
|
|
68
|
+
* row nor a buffered transient delta (lost transient interval), so
|
|
69
|
+
* completed content must be restored from authoritative durable state.
|
|
70
|
+
* Detected against the ledger high-watermark — a fresh hub over the same
|
|
71
|
+
* ledger with an EMPTY memory buffer still reports the lost interval.
|
|
72
|
+
*/
|
|
73
|
+
readonly olderThanBuffer: boolean;
|
|
74
|
+
}
|
|
75
|
+
/** Result of a materialized replay. */
|
|
76
|
+
export interface AgentStreamReplay extends AgentStreamReplayStatus {
|
|
77
|
+
readonly events: readonly AgentStreamEvent[];
|
|
78
|
+
}
|
|
79
|
+
export interface AgentStreamHubOptions {
|
|
80
|
+
readonly ledger: AgentStreamLedgerStore;
|
|
81
|
+
/** Injected clock (epoch ms). */
|
|
82
|
+
readonly clock?: () => number;
|
|
83
|
+
/** Bounded transient replay buffer per stream (default 512). */
|
|
84
|
+
readonly transientBufferSize?: number;
|
|
85
|
+
/** Hard pending-queue bound per slow subscriber (default 4096 events). */
|
|
86
|
+
readonly pendingLimit?: number;
|
|
87
|
+
/** Ledger read page size for bounded-memory replay (default 256). */
|
|
88
|
+
readonly replayPageSize?: number;
|
|
89
|
+
}
|
|
90
|
+
export declare class AgentStreamHub {
|
|
91
|
+
#private;
|
|
92
|
+
constructor(options: AgentStreamHubOptions);
|
|
93
|
+
/**
|
|
94
|
+
* Validate and publish one event. Assigns the monotonic sequence via the
|
|
95
|
+
* durable ledger, persists durable kinds, buffers transient deltas, and
|
|
96
|
+
* delivers to subscribers. Throws (fail closed) on any schema-invalid
|
|
97
|
+
* event.
|
|
98
|
+
*/
|
|
99
|
+
publish(event: Omit<AgentStreamEvent, 'seq'> & {
|
|
100
|
+
readonly seq?: number;
|
|
101
|
+
}): Promise<AgentStreamEvent>;
|
|
102
|
+
/**
|
|
103
|
+
* Subscribe to a stream and replay everything after the cursor: durable
|
|
104
|
+
* ledger rows plus buffered transient deltas, in strict sequence order.
|
|
105
|
+
*
|
|
106
|
+
* The subscriber is REGISTERED before the ledger is read, so a concurrent
|
|
107
|
+
* publish can never fall into the gap between the replay read and the
|
|
108
|
+
* live attachment: events published during the replay read are captured
|
|
109
|
+
* in the subscriber's private pending queue and delivered in sequence
|
|
110
|
+
* order as part of the backlog.
|
|
111
|
+
*
|
|
112
|
+
* Delivery is at-least-once and CURSOR-DEDUPLICATED. Backpressure NEVER
|
|
113
|
+
* discards events: the remaining backlog is buffered (bounded) for this
|
|
114
|
+
* subscriber and delivered through `pull()`. If the bounded pending
|
|
115
|
+
* queue overflows, the explicit recoverable policy applies: `onOverflow()`
|
|
116
|
+
* is called and the subscriber is detached (reconnect from the last
|
|
117
|
+
* acknowledged cursor).
|
|
118
|
+
*/
|
|
119
|
+
subscribe(streamId: string, subscriber: AgentStreamSubscriber, cursor?: {
|
|
120
|
+
lastSeq?: number;
|
|
121
|
+
}): Promise<void>;
|
|
122
|
+
/** Detach a subscriber (clean completion/cancellation/overflow). */
|
|
123
|
+
unsubscribe(streamId: string, subscriberId: string): void;
|
|
124
|
+
/** Latest assigned sequence for a stream (ledger high-watermark). */
|
|
125
|
+
latestSeq(streamId: string): Promise<number>;
|
|
126
|
+
/**
|
|
127
|
+
* Drain the pending queue of a slow subscriber. Consecutive pending
|
|
128
|
+
* `text.delta` events are coalesced into one delta whose sequence is the
|
|
129
|
+
* LAST combined sequence (complete-range cursor semantics: a client that
|
|
130
|
+
* acknowledges the coalesced event acknowledges every delta inside it).
|
|
131
|
+
* Non-delta events are never dropped, reordered, or coalesced. Returned
|
|
132
|
+
* events are private copies of this subscriber's queue — coalescing never
|
|
133
|
+
* mutates any event that another consumer can observe.
|
|
134
|
+
*/
|
|
135
|
+
pull(streamId: string, subscriberId: string): readonly AgentStreamEvent[];
|
|
136
|
+
/**
|
|
137
|
+
* Reconnect status WITHOUT materializing the replay: ledger high-watermark
|
|
138
|
+
* plus exact transient-gap detection against the durable rows. Bounded
|
|
139
|
+
* memory: the durable coverage is counted page by page.
|
|
140
|
+
*/
|
|
141
|
+
replayStatus(cursor: AgentStreamCursor): Promise<AgentStreamReplayStatus>;
|
|
142
|
+
/**
|
|
143
|
+
* Materialized replay for reconnect: durable ledger rows plus buffered
|
|
144
|
+
* transient deltas after the cursor, in strict sequence order. The
|
|
145
|
+
* returned events are private copies; `olderThanBuffer` is detected
|
|
146
|
+
* against the authoritative ledger high-watermark (exact, restart-safe).
|
|
147
|
+
* For arbitrarily large histories prefer `replayIterate`/`replayStatus`,
|
|
148
|
+
* which never materialize the whole range.
|
|
149
|
+
*/
|
|
150
|
+
replay(cursor: AgentStreamCursor): Promise<AgentStreamReplay>;
|
|
151
|
+
}
|