@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,402 @@
|
|
|
1
|
+
import { assertAgentStreamEvent, validateAgentStreamEvent, } from '@victframework/contracts';
|
|
2
|
+
import { isDurableStreamKind, streamEventPayloadOf } from './control-types.js';
|
|
3
|
+
export class AgentStreamHub {
|
|
4
|
+
#ledger;
|
|
5
|
+
#clock;
|
|
6
|
+
#transientBufferSize;
|
|
7
|
+
#pendingLimit;
|
|
8
|
+
#replayPageSize;
|
|
9
|
+
#streams = new Map();
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.#ledger = options.ledger;
|
|
12
|
+
this.#clock = options.clock ?? (() => Date.now());
|
|
13
|
+
this.#transientBufferSize = options.transientBufferSize ?? 512;
|
|
14
|
+
this.#pendingLimit = options.pendingLimit ?? 4096;
|
|
15
|
+
this.#replayPageSize = options.replayPageSize ?? 256;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validate and publish one event. Assigns the monotonic sequence via the
|
|
19
|
+
* durable ledger, persists durable kinds, buffers transient deltas, and
|
|
20
|
+
* delivers to subscribers. Throws (fail closed) on any schema-invalid
|
|
21
|
+
* event.
|
|
22
|
+
*/
|
|
23
|
+
async publish(event) {
|
|
24
|
+
// Pre-validate the event STRUCTURE with a placeholder sequence (the
|
|
25
|
+
// durable ledger assigns the authoritative monotonic sequence next).
|
|
26
|
+
const { seq: _ignored, ...withoutSeq } = event;
|
|
27
|
+
void _ignored;
|
|
28
|
+
const validation = validateAgentStreamEvent({ ...withoutSeq, seq: 1 });
|
|
29
|
+
if (!validation.ok) {
|
|
30
|
+
throw new Error(`AGENT_STREAM_EVENT_INVALID: event rejected by the vict.agent-stream@1 schema (${validation.issues
|
|
31
|
+
.map((issue) => issue.code)
|
|
32
|
+
.join(', ')}).`);
|
|
33
|
+
}
|
|
34
|
+
const { seq } = await this.#ledger.appendEvent({
|
|
35
|
+
streamId: event.streamId,
|
|
36
|
+
kind: event.kind,
|
|
37
|
+
payload: streamEventPayloadOf(event),
|
|
38
|
+
at: this.#clock(),
|
|
39
|
+
});
|
|
40
|
+
// The stored event is ONE immutable, frozen copy: the replay buffer and
|
|
41
|
+
// every subscriber receive their OWN copies, so no delivery path can
|
|
42
|
+
// ever mutate an event object that another path still reads.
|
|
43
|
+
const assigned = deepFreezeEvent({ ...event, seq });
|
|
44
|
+
assertAgentStreamEvent(assigned);
|
|
45
|
+
const state = this.#stateOf(event.streamId);
|
|
46
|
+
if (!isDurableStreamKind(event.kind)) {
|
|
47
|
+
pushBounded(state.buffer, assigned, this.#transientBufferSize);
|
|
48
|
+
}
|
|
49
|
+
this.#deliver(state, assigned);
|
|
50
|
+
return assigned;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Subscribe to a stream and replay everything after the cursor: durable
|
|
54
|
+
* ledger rows plus buffered transient deltas, in strict sequence order.
|
|
55
|
+
*
|
|
56
|
+
* The subscriber is REGISTERED before the ledger is read, so a concurrent
|
|
57
|
+
* publish can never fall into the gap between the replay read and the
|
|
58
|
+
* live attachment: events published during the replay read are captured
|
|
59
|
+
* in the subscriber's private pending queue and delivered in sequence
|
|
60
|
+
* order as part of the backlog.
|
|
61
|
+
*
|
|
62
|
+
* Delivery is at-least-once and CURSOR-DEDUPLICATED. Backpressure NEVER
|
|
63
|
+
* discards events: the remaining backlog is buffered (bounded) for this
|
|
64
|
+
* subscriber and delivered through `pull()`. If the bounded pending
|
|
65
|
+
* queue overflows, the explicit recoverable policy applies: `onOverflow()`
|
|
66
|
+
* is called and the subscriber is detached (reconnect from the last
|
|
67
|
+
* acknowledged cursor).
|
|
68
|
+
*/
|
|
69
|
+
async subscribe(streamId, subscriber, cursor) {
|
|
70
|
+
const state = this.#stateOf(streamId);
|
|
71
|
+
if (state.subscribers.has(subscriber.subscriberId)) {
|
|
72
|
+
throw new Error('AGENT_STREAM_SUBSCRIBER_EXISTS: the subscriber id is already attached.');
|
|
73
|
+
}
|
|
74
|
+
const afterSeq = cursor?.lastSeq ?? 0;
|
|
75
|
+
// Register in the REGISTERING phase: every live event published during
|
|
76
|
+
// the ledger read lands in this subscriber's private pending queue
|
|
77
|
+
// (never lost to the replay/live race, never out of order).
|
|
78
|
+
const entry = {
|
|
79
|
+
subscriber,
|
|
80
|
+
registering: true,
|
|
81
|
+
slow: false,
|
|
82
|
+
pending: [],
|
|
83
|
+
detached: false,
|
|
84
|
+
};
|
|
85
|
+
state.subscribers.set(subscriber.subscriberId, entry);
|
|
86
|
+
// Deliver the ordered backlog page by page (bounded memory) plus any
|
|
87
|
+
// live events that were captured during registration. Everything goes
|
|
88
|
+
// through the private pending queue during registration so the ordered
|
|
89
|
+
// backlog and live captures stay strictly ordered relative to each
|
|
90
|
+
// other; the epilogue then hands them off and leaves the subscriber in
|
|
91
|
+
// the mode the LAST delivery dictated (fast transport keeps receiving
|
|
92
|
+
// directly; a saturated transport buffers with coalescing).
|
|
93
|
+
for await (const event of this.#replayIterator(streamId, afterSeq)) {
|
|
94
|
+
if (entry.detached) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Registration buffers EXACTLY (no coalescing): every replayed and
|
|
98
|
+
// captured event keeps its identity and sequence, and the epilogue
|
|
99
|
+
// hands each one off individually, in order.
|
|
100
|
+
if (entry.pending.length < this.#pendingLimit) {
|
|
101
|
+
entry.pending.push(cloneEvent(event));
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Hard bound reached during registration: explicit recoverable
|
|
105
|
+
// overflow (never silent loss).
|
|
106
|
+
this.#overflow(state, entry);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.#flushPending(state, entry);
|
|
110
|
+
}
|
|
111
|
+
/** Detach a subscriber (clean completion/cancellation/overflow). */
|
|
112
|
+
unsubscribe(streamId, subscriberId) {
|
|
113
|
+
const state = this.#stateOf(streamId);
|
|
114
|
+
const entry = state.subscribers.get(subscriberId);
|
|
115
|
+
if (entry !== undefined && !entry.detached) {
|
|
116
|
+
entry.detached = true;
|
|
117
|
+
state.subscribers.delete(subscriberId);
|
|
118
|
+
entry.subscriber.detach?.();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Latest assigned sequence for a stream (ledger high-watermark). */
|
|
122
|
+
async latestSeq(streamId) {
|
|
123
|
+
return this.#ledger.latestSeq(streamId);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Drain the pending queue of a slow subscriber. Consecutive pending
|
|
127
|
+
* `text.delta` events are coalesced into one delta whose sequence is the
|
|
128
|
+
* LAST combined sequence (complete-range cursor semantics: a client that
|
|
129
|
+
* acknowledges the coalesced event acknowledges every delta inside it).
|
|
130
|
+
* Non-delta events are never dropped, reordered, or coalesced. Returned
|
|
131
|
+
* events are private copies of this subscriber's queue — coalescing never
|
|
132
|
+
* mutates any event that another consumer can observe.
|
|
133
|
+
*/
|
|
134
|
+
pull(streamId, subscriberId) {
|
|
135
|
+
const state = this.#stateOf(streamId);
|
|
136
|
+
const entry = state.subscribers.get(subscriberId);
|
|
137
|
+
if (entry === undefined) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
// REGISTRATION phase: the private queue belongs to the ordered backlog
|
|
141
|
+
// handoff (subscribe epilogue). Draining it here would steal events
|
|
142
|
+
// mid-handoff and coalesce live captures that must be delivered
|
|
143
|
+
// exactly — wait until the epilogue completed.
|
|
144
|
+
if (entry.registering) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
const coalesced = coalesceDeltas(entry.pending);
|
|
148
|
+
entry.pending = [];
|
|
149
|
+
entry.slow = false;
|
|
150
|
+
return coalesced;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Reconnect status WITHOUT materializing the replay: ledger high-watermark
|
|
154
|
+
* plus exact transient-gap detection against the durable rows. Bounded
|
|
155
|
+
* memory: the durable coverage is counted page by page.
|
|
156
|
+
*/
|
|
157
|
+
async replayStatus(cursor) {
|
|
158
|
+
return this.#computeStatus(cursor);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Materialized replay for reconnect: durable ledger rows plus buffered
|
|
162
|
+
* transient deltas after the cursor, in strict sequence order. The
|
|
163
|
+
* returned events are private copies; `olderThanBuffer` is detected
|
|
164
|
+
* against the authoritative ledger high-watermark (exact, restart-safe).
|
|
165
|
+
* For arbitrarily large histories prefer `replayIterate`/`replayStatus`,
|
|
166
|
+
* which never materialize the whole range.
|
|
167
|
+
*/
|
|
168
|
+
async replay(cursor) {
|
|
169
|
+
const events = [];
|
|
170
|
+
for await (const event of this.#replayIterator(cursor.streamId, cursor.lastSeq)) {
|
|
171
|
+
events.push(event);
|
|
172
|
+
}
|
|
173
|
+
const status = await this.#computeStatus(cursor);
|
|
174
|
+
return { events, newestSeq: status.newestSeq, olderThanBuffer: status.olderThanBuffer };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Bounded-memory replay iterator: merges paged durable ledger reads with
|
|
178
|
+
* the bounded transient buffer in strict sequence order. Each yielded
|
|
179
|
+
* event is a private copy for this consumption path.
|
|
180
|
+
*/
|
|
181
|
+
async *#replayIterator(streamId, afterSeq) {
|
|
182
|
+
const state = this.#stateOf(streamId);
|
|
183
|
+
// Buffered transients are bounded by the buffer size: snapshot them
|
|
184
|
+
// once (private copies; the buffer itself may keep growing).
|
|
185
|
+
const buffered = state.buffer
|
|
186
|
+
.filter((event) => event.seq > afterSeq)
|
|
187
|
+
.map((event) => cloneEvent(event))
|
|
188
|
+
.sort((a, b) => a.seq - b.seq);
|
|
189
|
+
let bufferIndex = 0;
|
|
190
|
+
let after = afterSeq;
|
|
191
|
+
for (;;) {
|
|
192
|
+
const page = await this.#ledger.listEventsFrom(streamId, after, this.#replayPageSize);
|
|
193
|
+
if (page.length === 0) {
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
for (const row of page) {
|
|
197
|
+
const durableEvent = ledgerRowToEvent(row);
|
|
198
|
+
while (bufferIndex < buffered.length && buffered[bufferIndex].seq < row.seq) {
|
|
199
|
+
yield buffered[bufferIndex];
|
|
200
|
+
bufferIndex += 1;
|
|
201
|
+
}
|
|
202
|
+
// Durable rows and buffered transients are disjoint sequences
|
|
203
|
+
// (durable kinds are never buffered); the merge stays strict.
|
|
204
|
+
yield cloneEvent(durableEvent);
|
|
205
|
+
after = row.seq;
|
|
206
|
+
}
|
|
207
|
+
if (page.length < this.#replayPageSize) {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
while (bufferIndex < buffered.length) {
|
|
212
|
+
yield buffered[bufferIndex];
|
|
213
|
+
bufferIndex += 1;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Exact transient-gap detection against the AUTHORITATIVE ledger
|
|
218
|
+
* high-watermark. Bounded memory: durable coverage is counted page by
|
|
219
|
+
* page; buffered coverage comes from the bounded buffer.
|
|
220
|
+
*/
|
|
221
|
+
async #computeStatus(cursor) {
|
|
222
|
+
const state = this.#stateOf(cursor.streamId);
|
|
223
|
+
// The high-watermark is read FIRST so every row read afterwards (with a
|
|
224
|
+
// seq ≤ watermark) is included: no publish can fall into the gap.
|
|
225
|
+
const ledgerNewest = await this.#ledger.latestSeq(cursor.streamId);
|
|
226
|
+
const bufferedInRange = state.buffer.filter((event) => event.seq > cursor.lastSeq);
|
|
227
|
+
const bufferedNewest = bufferedInRange.at(-1)?.seq ?? 0;
|
|
228
|
+
const newestSeq = Math.max(ledgerNewest, bufferedNewest, cursor.lastSeq);
|
|
229
|
+
const rangeSize = newestSeq - cursor.lastSeq;
|
|
230
|
+
let covered = 0;
|
|
231
|
+
if (rangeSize > 0) {
|
|
232
|
+
covered += bufferedInRange.length;
|
|
233
|
+
let after = cursor.lastSeq;
|
|
234
|
+
for (;;) {
|
|
235
|
+
const page = await this.#ledger.listEventsFrom(cursor.streamId, after, this.#replayPageSize);
|
|
236
|
+
if (page.length === 0) {
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
covered += page.length;
|
|
240
|
+
after = page.at(-1).seq;
|
|
241
|
+
if (page.length < this.#replayPageSize) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return { newestSeq, olderThanBuffer: covered < rangeSize };
|
|
247
|
+
}
|
|
248
|
+
#stateOf(streamId) {
|
|
249
|
+
let state = this.#streams.get(streamId);
|
|
250
|
+
if (state === undefined) {
|
|
251
|
+
state = { streamId, buffer: [], subscribers: new Map() };
|
|
252
|
+
this.#streams.set(streamId, state);
|
|
253
|
+
}
|
|
254
|
+
return state;
|
|
255
|
+
}
|
|
256
|
+
/** Deliver to every subscriber; slow subscribers buffer with coalescing. */
|
|
257
|
+
#deliver(state, event) {
|
|
258
|
+
for (const entry of [...state.subscribers.values()]) {
|
|
259
|
+
if (entry.detached) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (entry.registering) {
|
|
263
|
+
// Registration phase: buffer EXACTLY (no coalescing) so every
|
|
264
|
+
// captured event keeps its identity and sequence — the epilogue
|
|
265
|
+
// hands each one off individually, in order with the backlog.
|
|
266
|
+
if (entry.pending.length < this.#pendingLimit) {
|
|
267
|
+
entry.pending.push(cloneEvent(event));
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
// Hard bound reached during registration: explicit recoverable
|
|
271
|
+
// overflow (never silent loss).
|
|
272
|
+
this.#overflow(state, entry);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (!entry.slow) {
|
|
276
|
+
// Each subscriber receives its OWN copy: no delivery path can
|
|
277
|
+
// mutate an event the replay buffer (or another subscriber) reads.
|
|
278
|
+
// A `false` return means the event was ACCEPTED and the transport
|
|
279
|
+
// is saturated: only SUBSEQUENT events buffer.
|
|
280
|
+
if (!entry.subscriber.deliver(cloneEvent(event))) {
|
|
281
|
+
entry.slow = true;
|
|
282
|
+
}
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
// Buffered mode: enqueue honoring the hard bound. Overflow follows
|
|
286
|
+
// the explicit recoverable policy (never silent loss).
|
|
287
|
+
this.#enqueue(state, entry, event);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Enqueue one event into a slow subscriber's private pending queue.
|
|
292
|
+
* Consecutive transient deltas coalesce (the coalesced delta carries the
|
|
293
|
+
* LAST sequence of its range). A queue overflow detaches the subscriber
|
|
294
|
+
* through the explicit recoverable policy: `onOverflow()` then detach.
|
|
295
|
+
* Returns false when the subscriber was detached by overflow.
|
|
296
|
+
*/
|
|
297
|
+
#enqueue(state, entry, event) {
|
|
298
|
+
const last = entry.pending.at(-1);
|
|
299
|
+
if (event.kind === 'text.delta' && last !== undefined && last.kind === 'text.delta') {
|
|
300
|
+
// Coalesce into the private pending copy; the coalesced delta covers
|
|
301
|
+
// the complete range (cursor semantics = LAST combined sequence).
|
|
302
|
+
coalesceInto(last, event);
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
if (entry.pending.length < this.#pendingLimit) {
|
|
306
|
+
entry.pending.push(cloneEvent(event));
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
// Hard bound reached. A further transient delta with no pending delta
|
|
310
|
+
// neighbor cannot fit: overflow policy. Non-delta (durable, control,
|
|
311
|
+
// terminal) events are NEVER discarded: overflow policy.
|
|
312
|
+
this.#overflow(state, entry);
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
/** The explicit recoverable overflow policy: signal, then detach. */
|
|
316
|
+
#overflow(state, entry) {
|
|
317
|
+
if (entry.detached) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
entry.subscriber.onOverflow?.();
|
|
321
|
+
this.unsubscribe(state.streamId, entry.subscriber.subscriberId);
|
|
322
|
+
}
|
|
323
|
+
/** Deliver the pending queue of a slow subscriber (subscribe epilogue). */
|
|
324
|
+
#flushPending(state, entry) {
|
|
325
|
+
while (entry.pending.length > 0 && !entry.detached) {
|
|
326
|
+
const next = entry.pending[0];
|
|
327
|
+
if (!entry.slow) {
|
|
328
|
+
entry.pending.shift();
|
|
329
|
+
if (!entry.subscriber.deliver(next)) {
|
|
330
|
+
entry.slow = true;
|
|
331
|
+
}
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
// Registration is complete: live publishes now follow the mode the
|
|
337
|
+
// last delivery dictated. A transport that never signaled saturation
|
|
338
|
+
// receives events DIRECTLY (per-event identity is preserved for the
|
|
339
|
+
// byte-level transport pump); a saturated transport buffers (with
|
|
340
|
+
// coalescing) for pull-based draining.
|
|
341
|
+
entry.registering = false;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
/** Bounded push; drops the OLDEST transient delta when full. */
|
|
345
|
+
function pushBounded(buffer, event, size) {
|
|
346
|
+
buffer.push(event);
|
|
347
|
+
if (buffer.length > size) {
|
|
348
|
+
buffer.splice(0, buffer.length - size);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/** A private deep copy of one event (delivery paths never share objects). */
|
|
352
|
+
function cloneEvent(event) {
|
|
353
|
+
return JSON.parse(JSON.stringify(event));
|
|
354
|
+
}
|
|
355
|
+
/** Freeze one event deeply (stored events are immutable by construction). */
|
|
356
|
+
function deepFreezeEvent(event) {
|
|
357
|
+
if (event !== null && typeof event === 'object') {
|
|
358
|
+
for (const value of Object.values(event)) {
|
|
359
|
+
if (value !== null && typeof value === 'object') {
|
|
360
|
+
deepFreezeEvent(value);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
Object.freeze(event);
|
|
364
|
+
}
|
|
365
|
+
return event;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Coalesce one transient delta into a PRIVATE pending copy. The combined
|
|
369
|
+
* event carries the complete-range cursor semantics: its sequence is the
|
|
370
|
+
* LAST combined sequence, so acknowledging it acknowledges every delta in
|
|
371
|
+
* the range and a reconnect cannot re-deliver part of the text.
|
|
372
|
+
*/
|
|
373
|
+
function coalesceInto(target, incoming) {
|
|
374
|
+
target.delta =
|
|
375
|
+
target.delta + incoming.delta;
|
|
376
|
+
target.seq = incoming.seq;
|
|
377
|
+
}
|
|
378
|
+
/** Coalesce CONSECUTIVE text.delta events; all other events pass through. */
|
|
379
|
+
function coalesceDeltas(events) {
|
|
380
|
+
const result = [];
|
|
381
|
+
for (const event of events) {
|
|
382
|
+
const last = result.at(-1);
|
|
383
|
+
if (event.kind === 'text.delta' && last !== undefined && last.kind === 'text.delta') {
|
|
384
|
+
coalesceInto(last, event);
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
result.push(cloneEvent(event));
|
|
388
|
+
}
|
|
389
|
+
return result.map((event) => deepFreezeEvent(event));
|
|
390
|
+
}
|
|
391
|
+
/** Reconstruct one full event from a durable ledger row (fail closed). */
|
|
392
|
+
function ledgerRowToEvent(row) {
|
|
393
|
+
const payload = JSON.parse(row.payload);
|
|
394
|
+
const event = {
|
|
395
|
+
...payload,
|
|
396
|
+
streamId: row.streamId,
|
|
397
|
+
seq: row.seq,
|
|
398
|
+
};
|
|
399
|
+
assertAgentStreamEvent(event);
|
|
400
|
+
return event;
|
|
401
|
+
}
|
|
402
|
+
//# sourceMappingURL=stream-hub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-hub.js","sourceRoot":"","sources":["../src/stream-hub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Testing utilities for `@victframework/runtime`. Import from `@victframework/runtime/testing`.
|
|
3
|
+
*
|
|
4
|
+
* Includes the adapter-neutral store conformance suite: every conforming
|
|
5
|
+
* store backend (in-memory, SQLite, future adapters) must pass the same
|
|
6
|
+
* behavioral source.
|
|
7
|
+
*/
|
|
8
|
+
export { runStoreConformanceSuite } from './store-conformance.js';
|
|
9
|
+
export { runOrchestrationConformanceSuite, stringContract, recordContract, decisionGraph, fanoutGraph, signalWaitGraph, timerWaitGraph, retryGraph, unsafeWriteGraph, } from './orchestration-conformance.js';
|
|
10
|
+
export { runOrchestrationJoinSuite } from './orchestration-join-conformance.js';
|
|
11
|
+
export { createManualOrchestrationClock } from './orchestration-race-conformance.js';
|
|
12
|
+
export { runOrchestrationRaceSuite } from './orchestration-race-conformance.js';
|
|
13
|
+
export { runOrchestrationCanarySuite } from './orchestration-canary-conformance.js';
|
|
14
|
+
export { runOrchestrationRemediationSuite } from './orchestration-remediation-conformance.js';
|
|
15
|
+
export type { OrchestrationRemediationFixture, OrchestrationRemediationHandle, OrchestrationRemediationStores, } from './orchestration-remediation-conformance.js';
|
|
16
|
+
export type { OrchestrationCanaryFixture, OrchestrationCanaryStores, } from './orchestration-canary-conformance.js';
|
|
17
|
+
export type { OrchestrationRaceFixture, OrchestrationRaceStores, } from './orchestration-race-conformance.js';
|
|
18
|
+
export type { ConformanceTestRunner as OrchestrationConformanceRunner, ConformanceExpect as OrchestrationConformanceExpect, OrchestrationConformanceFixture, OrchestrationConformanceStores, } from './orchestration-conformance.js';
|
|
19
|
+
export type { StoreConformanceFactory, ConformanceTestRunner, ConformanceStores, ConformanceExpect, } from './store-conformance.js';
|
|
20
|
+
export { runDurableBoundarySuite } from './boundary-conformance.js';
|
|
21
|
+
export type { BoundaryConformanceFactory, BoundaryGates } from './boundary-conformance.js';
|
|
22
|
+
export { RECOVERY_CODE, RECOVERY_REASON, RECOVERY_REMEDIATION } from './runtime.js';
|
|
23
|
+
export { runCapabilityPackConformanceSuite } from './pack-conformance.js';
|
|
24
|
+
export type { CapabilityPackConformanceFixture, CapabilityPackConformanceOptions, } from './pack-conformance.js';
|
|
25
|
+
export { installCapabilityPack } from './pack-install.js';
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Testing utilities for `@victframework/runtime`. Import from `@victframework/runtime/testing`.
|
|
3
|
+
*
|
|
4
|
+
* Includes the adapter-neutral store conformance suite: every conforming
|
|
5
|
+
* store backend (in-memory, SQLite, future adapters) must pass the same
|
|
6
|
+
* behavioral source.
|
|
7
|
+
*/
|
|
8
|
+
export { runStoreConformanceSuite } from './store-conformance.js';
|
|
9
|
+
export { runOrchestrationConformanceSuite, stringContract, recordContract, decisionGraph, fanoutGraph, signalWaitGraph, timerWaitGraph, retryGraph, unsafeWriteGraph, } from './orchestration-conformance.js';
|
|
10
|
+
export { runOrchestrationJoinSuite } from './orchestration-join-conformance.js';
|
|
11
|
+
export { createManualOrchestrationClock } from './orchestration-race-conformance.js';
|
|
12
|
+
export { runOrchestrationRaceSuite } from './orchestration-race-conformance.js';
|
|
13
|
+
export { runOrchestrationCanarySuite } from './orchestration-canary-conformance.js';
|
|
14
|
+
export { runOrchestrationRemediationSuite } from './orchestration-remediation-conformance.js';
|
|
15
|
+
export { runDurableBoundarySuite } from './boundary-conformance.js';
|
|
16
|
+
export { RECOVERY_CODE, RECOVERY_REASON, RECOVERY_REMEDIATION } from './runtime.js';
|
|
17
|
+
export { runCapabilityPackConformanceSuite } from './pack-conformance.js';
|
|
18
|
+
export { installCapabilityPack } from './pack-install.js';
|
|
19
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EACL,gCAAgC,EAChC,cAAc,EACd,cAAc,EACd,aAAa,EACb,WAAW,EACX,eAAe,EACf,cAAc,EACd,UAAU,EACV,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,gCAAgC,EAAE,MAAM,4CAA4C,CAAC;AA0B9F,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,iCAAiC,EAAE,MAAM,uBAAuB,CAAC;AAK1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
|