@twoabove/cue 0.4.6 → 0.5.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/README.md +72 -4
- package/dist/api/create.d.ts.map +1 -1
- package/dist/api/create.js +16 -1
- package/dist/core/StateKernel.d.ts.map +1 -1
- package/dist/core/StateKernel.js +4 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/runtime/Entity.d.ts +2 -1
- package/dist/runtime/Entity.d.ts.map +1 -1
- package/dist/runtime/Entity.js +61 -5
- package/dist/stream/constants.d.ts +3 -0
- package/dist/stream/constants.d.ts.map +1 -0
- package/dist/stream/constants.js +2 -0
- package/dist/stream/index.d.ts +4 -0
- package/dist/stream/index.d.ts.map +1 -0
- package/dist/stream/index.js +2 -0
- package/dist/stream/reader.d.ts +5 -0
- package/dist/stream/reader.d.ts.map +1 -0
- package/dist/stream/reader.js +63 -0
- package/dist/stream/types.d.ts +39 -0
- package/dist/stream/types.d.ts.map +1 -0
- package/dist/stream/types.js +1 -0
- package/dist/types/public.d.ts +9 -1
- package/dist/types/public.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ console.log(await counter.read.value()); // 5
|
|
|
31
31
|
- **Durable.** State survives restarts. Plug in Postgres, SQLite, or Redis—or run in-memory for tests.
|
|
32
32
|
- **Safe.** One operation at a time, always. No race conditions, no corrupted state.
|
|
33
33
|
- **Evolvable.** Schema changes are type-checked and automatic. Add a field, rename a property—old entities migrate on load.
|
|
34
|
-
- **Streamable.** Long-running operations yield progress in real-time.
|
|
34
|
+
- **Streamable.** Long-running operations yield progress in real-time. Streams survive client disconnects—reconnect and resume where you left off.
|
|
35
35
|
- **Time-travel.** Query historical state at any point with full type safety.
|
|
36
36
|
|
|
37
37
|
## Installation
|
|
@@ -146,7 +146,7 @@ const ref = manager.get("entity-id");
|
|
|
146
146
|
|
|
147
147
|
await ref.send.someCommand(); // Execute a command (may modify state)
|
|
148
148
|
await ref.read.someQuery(); // Execute a query (read-only)
|
|
149
|
-
ref.stream.streamingCommand(); //
|
|
149
|
+
const run = ref.stream.streamingCommand(); // StreamRun with .id for reconnection
|
|
150
150
|
await ref.snapshot(); // Get current state and version
|
|
151
151
|
await ref.stateAt(version); // Get historical state at a specific event version
|
|
152
152
|
await ref.stop(); // Manually stop this entity
|
|
@@ -186,6 +186,46 @@ const Entity = define("Entity")
|
|
|
186
186
|
.build();
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
+
## Durable Streams
|
|
190
|
+
|
|
191
|
+
When persistence is enabled, streams automatically record every yielded value. If a client disconnects mid-stream - browser refresh, network blip, mobile app backgrounded - the stream keeps running on the server. The client reconnects and picks up exactly where it left off. No lost data, no restarting from scratch.
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Start a long-running operation
|
|
195
|
+
const run = ref.stream.generateReport(params);
|
|
196
|
+
|
|
197
|
+
// Return the stream ID to the client immediately
|
|
198
|
+
res.json({ streamId: run.id });
|
|
199
|
+
|
|
200
|
+
// Stream continues in the background, persisting each chunk
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The client consumes live or reconnects later:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// First connection: consume live
|
|
207
|
+
for await (const { seq, data } of manager.readStream(streamId)) {
|
|
208
|
+
render(data);
|
|
209
|
+
lastSeq = seq; // Track position for reconnection
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// After disconnect: resume from last position
|
|
213
|
+
for await (const { seq, data } of manager.readStream(streamId, { after: lastSeq })) {
|
|
214
|
+
render(data);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Check stream status without consuming:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
const status = await manager.streamStatus(streamId);
|
|
222
|
+
// { state: 'running', seq: 42n }
|
|
223
|
+
// { state: 'complete', seq: 100n }
|
|
224
|
+
// { state: 'error', seq: 50n, error: 'timeout' }
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
This is essential for AI assistants, file processors, report generators - any operation that takes longer than a network timeout.
|
|
228
|
+
|
|
189
229
|
## Schema Evolution
|
|
190
230
|
|
|
191
231
|
Migrate entity state without downtime:
|
|
@@ -354,6 +394,25 @@ Under the hood, Cue uses **event sourcing**. Every state change is recorded as a
|
|
|
354
394
|
|
|
355
395
|
But you don't need to think about events. Write mutations directly—Cue captures them automatically via Immer.
|
|
356
396
|
|
|
397
|
+
## On Persistence Complexity
|
|
398
|
+
|
|
399
|
+
Cue doesn't force a specific persistence provider. You implement `PersistenceAdapter` for whatever database you have. This flexibility adds some decision-making, but most applications won't need anything complicated.
|
|
400
|
+
|
|
401
|
+
**PostgreSQL handles more than you think:**
|
|
402
|
+
|
|
403
|
+
| Workload | PostgreSQL (single instance) |
|
|
404
|
+
| -------- | ---------------------------- |
|
|
405
|
+
| < 500 events/sec | Comfortable, no tuning needed |
|
|
406
|
+
| 500 - 2,000 events/sec | Add connection pooling |
|
|
407
|
+
| 2,000 - 5,000 events/sec | Tune indexes, batch writes, consider read replicas |
|
|
408
|
+
| > 5,000 events/sec | Time to think about Redis or sharding |
|
|
409
|
+
|
|
410
|
+
These are rough estimates for a typical cloud database. Your mileage varies with hardware, event size, and query patterns.
|
|
411
|
+
|
|
412
|
+
**Redis is powerful but often unnecessary.** Redis Streams map beautifully to Cue's event model - fast writes, blocking reads for live streaming, built-in consumer groups. But remember: Cue already keeps hot entities in memory. The EntityManager holds active entities, passivation evicts idle ones. Your database only sees hydration reads and event writes, not every state access.
|
|
413
|
+
|
|
414
|
+
For most applications - even busy ones - PostgreSQL with snapshotting enabled is plenty. Add Redis when you have evidence you need it, not before.
|
|
415
|
+
|
|
357
416
|
## API Reference
|
|
358
417
|
|
|
359
418
|
### `define(name)`
|
|
@@ -391,16 +450,25 @@ const ref = manager.get("id");
|
|
|
391
450
|
|
|
392
451
|
ref.send.command(...args); // Execute command, returns Promise
|
|
393
452
|
ref.read.query(...args); // Execute query, returns Promise
|
|
394
|
-
ref.stream.command(...args); // Returns
|
|
453
|
+
ref.stream.command(...args); // Returns StreamRun<T> with .id, .seq, .isLive
|
|
395
454
|
ref.snapshot(); // Returns Promise<{ state, version }>
|
|
396
455
|
ref.stateAt(eventVersion); // Returns Promise<{ schemaVersion, state }>
|
|
397
456
|
ref.stop(); // Stop and release this entity
|
|
398
457
|
```
|
|
399
458
|
|
|
459
|
+
### `EntityManager`
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
manager.get("id"); // Get or create entity reference
|
|
463
|
+
manager.readStream(streamId, { after? }); // Read durable stream by ID
|
|
464
|
+
manager.streamStatus(streamId); // Get stream state without consuming
|
|
465
|
+
manager.stop(); // Shut down all entities
|
|
466
|
+
```
|
|
467
|
+
|
|
400
468
|
### Type Utilities
|
|
401
469
|
|
|
402
470
|
```typescript
|
|
403
|
-
import { HistoryOf, VersionState, StateOf } from "@twoabove/cue";
|
|
471
|
+
import { HistoryOf, VersionState, StateOf, StreamRun, StreamStatus } from "@twoabove/cue";
|
|
404
472
|
|
|
405
473
|
type History = HistoryOf<typeof Entity>; // Discriminated union of all versions
|
|
406
474
|
type V2State = VersionState<typeof Entity, 2>; // State type at schema version 2
|
package/dist/api/create.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/api/create.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/api/create.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EAUpB,MAAM,iBAAiB,CAAC;AAEzB,wBAAgB,MAAM,CAAC,IAAI,SAAS,mBAAmB,EACrD,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,GAChC,aAAa,CAAC,IAAI,CAAC,CAwKrB"}
|
package/dist/api/create.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ManagerShutdownError } from "../errors";
|
|
2
2
|
import { RuntimeEntityManager } from "../runtime/EntityManager";
|
|
3
|
+
import { readStream, streamStatus } from "../stream/reader";
|
|
3
4
|
export function create(config) {
|
|
4
5
|
const manager = new RuntimeEntityManager(config);
|
|
5
6
|
const entries = new Map();
|
|
@@ -57,7 +58,9 @@ export function create(config) {
|
|
|
57
58
|
return {
|
|
58
59
|
get(id) {
|
|
59
60
|
const existing = entries.get(id);
|
|
60
|
-
if (existing &&
|
|
61
|
+
if (existing &&
|
|
62
|
+
!existing.entity.isFailed &&
|
|
63
|
+
!existing.entity.isShutdown) {
|
|
61
64
|
return existing.ref;
|
|
62
65
|
}
|
|
63
66
|
let entity = manager.getEntity(id);
|
|
@@ -101,6 +104,18 @@ export function create(config) {
|
|
|
101
104
|
entries.set(id, entry);
|
|
102
105
|
return ref;
|
|
103
106
|
},
|
|
107
|
+
readStream(streamId, options) {
|
|
108
|
+
if (!config.store) {
|
|
109
|
+
throw new Error("readStream requires a persistence store");
|
|
110
|
+
}
|
|
111
|
+
return readStream(config.store, streamId, options);
|
|
112
|
+
},
|
|
113
|
+
async streamStatus(streamId) {
|
|
114
|
+
if (!config.store) {
|
|
115
|
+
throw new Error("streamStatus requires a persistence store");
|
|
116
|
+
}
|
|
117
|
+
return streamStatus(config.store, streamId);
|
|
118
|
+
},
|
|
104
119
|
stop: () => manager.terminate(),
|
|
105
120
|
};
|
|
106
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateKernel.d.ts","sourceRoot":"","sources":["../../src/core/StateKernel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StateKernel.d.ts","sourceRoot":"","sources":["../../src/core/StateKernel.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EACd,KAAK,EACN,MAAM,iBAAiB,CAAC;AAIzB,qBAAa,WAAW,CAAC,MAAM,SAAS,MAAM;;IAIhC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,mBAAmB;IAErD,IAAI,KAAK,IAAI,MAAM,CAMlB;IAED,IAAI,OAAO,IAAI,MAAM,CAMpB;IAED,kBAAkB;IAKlB,OAAO,CAAC,MAAM,EAAE;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,MAAM,EAAE,KAAK,CAAC;YAAE,aAAa,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,KAAK,CAAA;SAAE,CAAC,CAAC;KAC1D;IAqBD,qBAAqB,IAAI,MAAM;IAI/B,mBAAmB,CAAC,SAAS,EAAE,MAAM;IAK/B,YAAY,CAChB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,OAAO,EAAE,EACf,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,KAAK,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAsBvE,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO;IAgB5E,WAAW,CACT,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,OAAO,EAAE,EACf,GAAG,EAAE,cAAc,GAClB;QACD,SAAS,EAAE,cAAc,CAAC;QAC1B,QAAQ,EAAE,MAAM;YAAE,OAAO,EAAE,KAAK,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;QACtD,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB;CAiDF"}
|
package/dist/core/StateKernel.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { applyPatches, createDraft, finishDraft, isDraft, } from "immer";
|
|
2
|
+
import { clone } from "../serde";
|
|
2
3
|
import { _handlers } from "../types/internal";
|
|
3
4
|
import { invariant } from "../utils/invariants";
|
|
4
5
|
import { Evolution } from "./Evolution";
|
|
@@ -31,7 +32,6 @@ export class StateKernel {
|
|
|
31
32
|
}
|
|
32
33
|
state = applyPatches(state, event.patches);
|
|
33
34
|
}
|
|
34
|
-
// Upcast to latest schema version
|
|
35
35
|
this.#state = Evolution.applyUpcasters(state, currentSchema, this.def);
|
|
36
36
|
this.#version = params.baseVersion + BigInt(params.events.length);
|
|
37
37
|
}
|
|
@@ -64,10 +64,11 @@ export class StateKernel {
|
|
|
64
64
|
invariant(entry && entry.type === "query", `Handler "${handlerName}" not found or not a query.`);
|
|
65
65
|
const draft = createDraft(this.state);
|
|
66
66
|
try {
|
|
67
|
-
|
|
67
|
+
const result = entry.fn(draft, ...args, ctx);
|
|
68
|
+
return clone(result);
|
|
68
69
|
}
|
|
69
70
|
finally {
|
|
70
|
-
finishDraft(draft);
|
|
71
|
+
finishDraft(draft);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
startStream(handlerName, args, ctx) {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type { Draft, Immutable } from "immer";
|
|
|
2
2
|
export * from "./api/index";
|
|
3
3
|
export * from "./errors/index";
|
|
4
4
|
export type * from "./persistence/types";
|
|
5
|
+
export type { ReadStreamOptions, StreamChunk, StreamReader, StreamRun, StreamStatus, } from "./stream/types";
|
|
5
6
|
export { _handlers, _initialStateFn, _messages, _name, _persistence, _state, _tag, _upcasters, _versions, } from "./types/internal";
|
|
6
7
|
export type * from "./types/public";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,mBAAmB,qBAAqB,CAAC;AACzC,OAAO,EACL,SAAS,EACT,eAAe,EACf,SAAS,EACT,KAAK,EACL,YAAY,EACZ,MAAM,EACN,IAAI,EACJ,UAAU,EACV,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,mBAAmB,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,mBAAmB,qBAAqB,CAAC;AACzC,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,SAAS,EACT,eAAe,EACf,SAAS,EACT,KAAK,EACL,YAAY,EACZ,MAAM,EACN,IAAI,EACJ,UAAU,EACV,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,mBAAmB,gBAAgB,CAAC"}
|
package/dist/runtime/Entity.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PersistenceAdapter } from "../persistence/types";
|
|
2
|
+
import type { StreamRun } from "../stream/types";
|
|
2
3
|
import type { AnyEntityDefinition, EntityMetrics, Supervisor } from "../types/public";
|
|
3
4
|
import type { Clock } from "../utils/clock";
|
|
4
5
|
export declare class Entity<TState extends object> {
|
|
@@ -21,7 +22,7 @@ export declare class Entity<TState extends object> {
|
|
|
21
22
|
get lastActivity(): number;
|
|
22
23
|
tell: (handlerName: string, args: unknown[]) => Promise<unknown>;
|
|
23
24
|
ask: (handlerName: string, args: unknown[]) => Promise<unknown>;
|
|
24
|
-
stream: (handlerName: string, args: unknown[]) =>
|
|
25
|
+
stream: (handlerName: string, args: unknown[]) => StreamRun<unknown>;
|
|
25
26
|
inspect: () => Promise<{
|
|
26
27
|
state: TState;
|
|
27
28
|
version: bigint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Entity.d.ts","sourceRoot":"","sources":["../../src/runtime/Entity.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"Entity.d.ts","sourceRoot":"","sources":["../../src/runtime/Entity.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,KAAK,EAGV,SAAS,EACV,MAAM,iBAAiB,CAAC;AAQzB,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EAEb,UAAU,EACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAQ5C,qBAAa,MAAM,CAAC,MAAM,SAAS,MAAM;aASrB,EAAE,EAAE,MAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAdxB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,gBAAgB,CAAC,CAAgB;gBAGvB,EAAE,EAAE,MAAM,EACT,GAAG,EAAE,mBAAmB,EACxB,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,kBAAkB,YAAA,EAC1B,UAAU,CAAC,EAAE,UAAU,YAAA,EACvB,OAAO,CAAC,EAAE,aAAa,YAAA,EACvB,KAAK,GAAE,KAAiB;IAM3C,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAEM,IAAI,GAAI,aAAa,MAAM,EAAE,MAAM,OAAO,EAAE,KAAG,OAAO,CAAC,OAAO,CAAC,CA6DpE;IAEK,GAAG,GAAI,aAAa,MAAM,EAAE,MAAM,OAAO,EAAE,KAAG,OAAO,CAAC,OAAO,CAAC,CAKnE;IAEK,MAAM,GACX,aAAa,MAAM,EACnB,MAAM,OAAO,EAAE,KACd,SAAS,CAAC,OAAO,CAAC,CA+JnB;IAEK,OAAO,QAAa,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAMpE;IAEK,SAAS,QAAa,OAAO,CAAC,IAAI,CAAC,CAKxC;IAEK,OAAO,GACZ,eAAe,MAAM,KACpB,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CA8CnD;YAEY,MAAM;YAkCN,YAAY;YASZ,OAAO;IAgER,aAAa,CAAC,KAAK,UAAQ;IA0BxC,OAAO,CAAC,OAAO,CAOb;IAEF,OAAO,CAAC,MAAM,CAIZ;IAEF,OAAO,CAAC,YAAY;CAOrB"}
|
package/dist/runtime/Entity.js
CHANGED
|
@@ -3,8 +3,10 @@ import { Evolution } from "../core/Evolution";
|
|
|
3
3
|
import { StateKernel } from "../core/StateKernel";
|
|
4
4
|
import { CommitError, DefinitionMismatchError, HydrationError, OutOfOrderEventsError, StoppedEntityError, } from "../errors";
|
|
5
5
|
import { clone, deserialize, serialize } from "../serde";
|
|
6
|
+
import { STREAM_ENTITY_DEF_NAME, STREAM_SCHEMA_VERSION, } from "../stream/constants";
|
|
6
7
|
import { _handlers, _initialStateFn, _name, _persistence, _upcasters, } from "../types/internal";
|
|
7
8
|
import { WallClock } from "../utils/clock";
|
|
9
|
+
import { newId } from "../utils/id";
|
|
8
10
|
import { Mailbox } from "./Mailbox";
|
|
9
11
|
import { Supervise } from "./Supervision";
|
|
10
12
|
export class Entity {
|
|
@@ -87,13 +89,14 @@ export class Entity {
|
|
|
87
89
|
});
|
|
88
90
|
};
|
|
89
91
|
stream = (handlerName, args) => {
|
|
90
|
-
// Stream holds the mailbox for its entire duration to prevent interleaved
|
|
91
|
-
// commands from causing state overwrites when the stream commits.
|
|
92
92
|
const self = this;
|
|
93
|
+
const streamId = `${this.id}:${handlerName}:${newId()}`;
|
|
93
94
|
const channel = [];
|
|
94
95
|
let consumerWaiting = null;
|
|
95
96
|
let producerWaiting = null;
|
|
96
97
|
let aborted = false;
|
|
98
|
+
let currentSeq = 0n;
|
|
99
|
+
let isLive = true;
|
|
97
100
|
function push(item) {
|
|
98
101
|
if (consumerWaiting) {
|
|
99
102
|
const resolve = consumerWaiting;
|
|
@@ -127,24 +130,60 @@ export class Entity {
|
|
|
127
130
|
reject(new Error("stream aborted"));
|
|
128
131
|
}
|
|
129
132
|
}
|
|
133
|
+
async function commitStreamChunk(value) {
|
|
134
|
+
if (!self.store)
|
|
135
|
+
return;
|
|
136
|
+
currentSeq += 1n;
|
|
137
|
+
const envelope = {
|
|
138
|
+
entityDefName: STREAM_ENTITY_DEF_NAME,
|
|
139
|
+
schemaVersion: STREAM_SCHEMA_VERSION,
|
|
140
|
+
handler: "chunk",
|
|
141
|
+
payload: [value],
|
|
142
|
+
patches: [],
|
|
143
|
+
};
|
|
144
|
+
await self.store.commitEvent(streamId, currentSeq, serialize(envelope));
|
|
145
|
+
}
|
|
146
|
+
async function commitStreamEnd(state, error) {
|
|
147
|
+
if (!self.store)
|
|
148
|
+
return;
|
|
149
|
+
currentSeq += 1n;
|
|
150
|
+
const payload = { state };
|
|
151
|
+
if (error) {
|
|
152
|
+
payload.error = error;
|
|
153
|
+
}
|
|
154
|
+
const envelope = {
|
|
155
|
+
entityDefName: STREAM_ENTITY_DEF_NAME,
|
|
156
|
+
schemaVersion: STREAM_SCHEMA_VERSION,
|
|
157
|
+
handler: "end",
|
|
158
|
+
payload: [payload],
|
|
159
|
+
patches: [],
|
|
160
|
+
};
|
|
161
|
+
await self.store.commitEvent(streamId, currentSeq, serialize(envelope));
|
|
162
|
+
}
|
|
130
163
|
const mailboxTask = self.mailbox.enqueue(async () => {
|
|
131
164
|
await self.ensureActive();
|
|
132
165
|
const stream = self.kernel.startStream(handlerName, args, self.buildContext());
|
|
133
166
|
try {
|
|
134
167
|
for await (const value of stream.generator) {
|
|
168
|
+
await commitStreamChunk(value);
|
|
135
169
|
push({ type: "value", value });
|
|
136
170
|
await new Promise((resolve, reject) => {
|
|
137
171
|
producerWaiting = { resolve, reject };
|
|
138
172
|
});
|
|
139
173
|
}
|
|
140
174
|
push({ type: "done" });
|
|
175
|
+
await commitStreamEnd("complete");
|
|
141
176
|
}
|
|
142
177
|
catch (e) {
|
|
143
178
|
if (!aborted) {
|
|
144
179
|
stream.discard();
|
|
180
|
+
const errorMsg = e instanceof Error ? e.message : String(e);
|
|
181
|
+
await commitStreamEnd("error", errorMsg);
|
|
145
182
|
push({ type: "error", error: e });
|
|
146
183
|
return;
|
|
147
184
|
}
|
|
185
|
+
// If aborted by consumer, still write end event
|
|
186
|
+
await commitStreamEnd("complete");
|
|
148
187
|
}
|
|
149
188
|
const { patches, nextState } = stream.finalize();
|
|
150
189
|
if (patches.length > 0) {
|
|
@@ -155,10 +194,14 @@ export class Entity {
|
|
|
155
194
|
try {
|
|
156
195
|
while (true) {
|
|
157
196
|
const item = await pull();
|
|
158
|
-
if (item.type === "done")
|
|
197
|
+
if (item.type === "done") {
|
|
198
|
+
isLive = false;
|
|
159
199
|
return;
|
|
160
|
-
|
|
200
|
+
}
|
|
201
|
+
if (item.type === "error") {
|
|
202
|
+
isLive = false;
|
|
161
203
|
throw item.error;
|
|
204
|
+
}
|
|
162
205
|
yield item.value;
|
|
163
206
|
signalProducerContinue();
|
|
164
207
|
}
|
|
@@ -166,9 +209,22 @@ export class Entity {
|
|
|
166
209
|
finally {
|
|
167
210
|
signalProducerAbort();
|
|
168
211
|
await mailboxTask;
|
|
212
|
+
isLive = false;
|
|
169
213
|
}
|
|
170
214
|
}
|
|
171
|
-
|
|
215
|
+
const streamRun = {
|
|
216
|
+
id: streamId,
|
|
217
|
+
get seq() {
|
|
218
|
+
return currentSeq;
|
|
219
|
+
},
|
|
220
|
+
get isLive() {
|
|
221
|
+
return isLive;
|
|
222
|
+
},
|
|
223
|
+
[Symbol.asyncIterator]() {
|
|
224
|
+
return outerGenerator();
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
return streamRun;
|
|
172
228
|
};
|
|
173
229
|
inspect = async () => {
|
|
174
230
|
await this.ensureActive();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/stream/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,EAAG,YAAqB,CAAC;AAC5D,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { STREAM_ENTITY_DEF_NAME, STREAM_SCHEMA_VERSION } from "./constants";
|
|
2
|
+
export { readStream, streamStatus } from "./reader";
|
|
3
|
+
export type { ReadStreamOptions, StreamChunk, StreamReader, StreamRun, StreamStatus, } from "./types";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stream/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,YAAY,GACb,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PersistenceAdapter } from "../persistence/types";
|
|
2
|
+
import type { ReadStreamOptions, StreamReader, StreamStatus } from "./types";
|
|
3
|
+
export declare function streamStatus(store: PersistenceAdapter, streamId: string): Promise<StreamStatus | null>;
|
|
4
|
+
export declare function readStream<T>(store: PersistenceAdapter, streamId: string, options?: ReadStreamOptions): StreamReader<T>;
|
|
5
|
+
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/stream/reader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG/D,OAAO,KAAK,EACV,iBAAiB,EAGjB,YAAY,EACZ,YAAY,EACb,MAAM,SAAS,CAAC;AAEjB,wBAAsB,YAAY,CAChC,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAgC9B;AAED,wBAAgB,UAAU,CAAC,CAAC,EAC1B,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,YAAY,CAAC,CAAC,CAAC,CAwCjB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { deserialize } from "../serde";
|
|
2
|
+
import { STREAM_ENTITY_DEF_NAME } from "./constants";
|
|
3
|
+
export async function streamStatus(store, streamId) {
|
|
4
|
+
const events = await store.getEvents(streamId, 0n);
|
|
5
|
+
if (events.length === 0) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const lastEvent = events[events.length - 1];
|
|
9
|
+
if (!lastEvent)
|
|
10
|
+
return null;
|
|
11
|
+
const envelope = deserialize(lastEvent.data);
|
|
12
|
+
if (envelope.entityDefName !== STREAM_ENTITY_DEF_NAME) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (envelope.handler === "end") {
|
|
16
|
+
const endPayload = envelope.payload[0];
|
|
17
|
+
const status = {
|
|
18
|
+
state: endPayload.state,
|
|
19
|
+
seq: BigInt(events.length - 1),
|
|
20
|
+
};
|
|
21
|
+
if (endPayload.error) {
|
|
22
|
+
status.error = endPayload.error;
|
|
23
|
+
}
|
|
24
|
+
return status;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
state: "running",
|
|
28
|
+
seq: BigInt(events.length),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function readStream(store, streamId, options) {
|
|
32
|
+
const afterSeq = options?.after ?? 0n;
|
|
33
|
+
let isLive = true;
|
|
34
|
+
const reader = {
|
|
35
|
+
get isLive() {
|
|
36
|
+
return isLive;
|
|
37
|
+
},
|
|
38
|
+
async *[Symbol.asyncIterator]() {
|
|
39
|
+
const events = await store.getEvents(streamId, afterSeq);
|
|
40
|
+
for (const event of events) {
|
|
41
|
+
const envelope = deserialize(event.data);
|
|
42
|
+
if (envelope.entityDefName !== STREAM_ENTITY_DEF_NAME) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (envelope.handler === "end") {
|
|
46
|
+
isLive = false;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (envelope.handler === "chunk") {
|
|
50
|
+
yield {
|
|
51
|
+
seq: event.version,
|
|
52
|
+
data: envelope.payload[0],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const status = await streamStatus(store, streamId);
|
|
57
|
+
if (status && status.state !== "running") {
|
|
58
|
+
isLive = false;
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
return reader;
|
|
63
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface StreamChunk<T> {
|
|
2
|
+
seq: bigint;
|
|
3
|
+
data: T;
|
|
4
|
+
}
|
|
5
|
+
export interface StreamStatus {
|
|
6
|
+
state: "running" | "complete" | "error";
|
|
7
|
+
seq: bigint;
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface StreamRun<T> extends AsyncIterable<T> {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly seq: bigint;
|
|
13
|
+
readonly isLive: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface StreamReader<T> extends AsyncIterable<StreamChunk<T>> {
|
|
16
|
+
readonly isLive: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface ReadStreamOptions {
|
|
19
|
+
after?: bigint;
|
|
20
|
+
}
|
|
21
|
+
export interface StreamChunkEnvelope {
|
|
22
|
+
entityDefName: "__stream__";
|
|
23
|
+
schemaVersion: 1;
|
|
24
|
+
handler: "chunk";
|
|
25
|
+
payload: [unknown];
|
|
26
|
+
patches: readonly [];
|
|
27
|
+
}
|
|
28
|
+
export interface StreamEndEnvelope {
|
|
29
|
+
entityDefName: "__stream__";
|
|
30
|
+
schemaVersion: 1;
|
|
31
|
+
handler: "end";
|
|
32
|
+
payload: [{
|
|
33
|
+
state: "complete" | "error";
|
|
34
|
+
error?: string;
|
|
35
|
+
}];
|
|
36
|
+
patches: readonly [];
|
|
37
|
+
}
|
|
38
|
+
export type StreamEventEnvelope = StreamChunkEnvelope | StreamEndEnvelope;
|
|
39
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/stream/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,CAAE,SAAQ,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACpE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,YAAY,CAAC;IAC5B,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;IACnB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,YAAY,CAAC;IAC5B,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,CAAC;QAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/public.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { Draft as ImmerDraft, Patch as ImmerPatch } from "immer";
|
|
2
2
|
import type { PersistenceAdapter } from "../persistence/types";
|
|
3
|
+
import type { ReadStreamOptions as _ReadStreamOptions, StreamChunk as _StreamChunk, StreamReader as _StreamReader, StreamRun as _StreamRun, StreamStatus as _StreamStatus } from "../stream/types";
|
|
3
4
|
import type { _handlers, _initialStateFn, _messages, _name, _persistence, _state, _tag, _upcasters, _versions } from "./internal";
|
|
5
|
+
export type ReadStreamOptions = _ReadStreamOptions;
|
|
6
|
+
export type StreamChunk<T> = _StreamChunk<T>;
|
|
7
|
+
export type StreamReader<T> = _StreamReader<T>;
|
|
8
|
+
export type StreamRun<T> = _StreamRun<T>;
|
|
9
|
+
export type StreamStatus = _StreamStatus;
|
|
4
10
|
export type AnyHandler = (...args: any[]) => any;
|
|
5
11
|
export type Patch = readonly ImmerPatch[];
|
|
6
12
|
export type Draft<T> = ImmerDraft<T>;
|
|
@@ -98,7 +104,7 @@ export type ReadProxy<TDef extends AnyEntityDefinition> = {
|
|
|
98
104
|
export type StreamProxy<TDef extends AnyEntityDefinition> = {
|
|
99
105
|
[K in keyof MessagesOf<TDef> as MessagesOf<TDef>[K] extends {
|
|
100
106
|
verb: "stream";
|
|
101
|
-
} ? K : never]: (...args: MessagesOf<TDef>[K]["payload"]) =>
|
|
107
|
+
} ? K : never]: (...args: MessagesOf<TDef>[K]["payload"]) => StreamRun<MessagesOf<TDef>[K]["progress"]>;
|
|
102
108
|
};
|
|
103
109
|
export type EntityRef<TDef extends AnyEntityDefinition> = {
|
|
104
110
|
readonly read: ReadProxy<TDef>;
|
|
@@ -136,6 +142,8 @@ export interface EntityManagerConfig<TDef extends AnyEntityDefinition> {
|
|
|
136
142
|
}
|
|
137
143
|
export interface EntityManager<TDef extends AnyEntityDefinition> {
|
|
138
144
|
get(id: string): EntityRef<TDef>;
|
|
145
|
+
readStream<T = unknown>(streamId: string, options?: ReadStreamOptions): StreamReader<T>;
|
|
146
|
+
streamStatus(streamId: string): Promise<StreamStatus | null>;
|
|
139
147
|
stop(): Promise<void>;
|
|
140
148
|
}
|
|
141
149
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/types/public.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,IAAI,UAAU,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,OAAO,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,SAAS,EACT,KAAK,EACL,YAAY,EACZ,MAAM,EACN,IAAI,EACJ,UAAU,EACV,SAAS,EACV,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/types/public.ts"],"names":[],"mappings":"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"}
|