@rotorsoft/act-sse 1.2.2 → 1.2.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/README.md +32 -153
- package/dist/.tsbuildinfo +1 -0
- package/dist/@types/apply-patch.d.ts +37 -0
- package/dist/@types/apply-patch.d.ts.map +1 -0
- package/dist/@types/broadcast.d.ts +70 -0
- package/dist/@types/broadcast.d.ts.map +1 -0
- package/dist/@types/index.d.ts +46 -0
- package/dist/@types/index.d.ts.map +1 -0
- package/dist/@types/presence.d.ts +34 -0
- package/dist/@types/presence.d.ts.map +1 -0
- package/dist/@types/state-cache.d.ts +29 -0
- package/dist/@types/state-cache.d.ts.map +1 -0
- package/dist/@types/types.d.ts +20 -0
- package/dist/@types/types.d.ts.map +1 -0
- package/dist/index.cjs +204 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +175 -0
- package/dist/index.js.map +1 -0
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -4,181 +4,60 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@rotorsoft/act-sse)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
_Incremental state broadcast over Server-Sent Events for [@rotorsoft/act](https://www.npmjs.com/package/@rotorsoft/act) event-sourced apps._
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
> [!WARNING]
|
|
10
|
+
> **This package is being deprecated.** Its surface lives on as the `@rotorsoft/act-http/sse` subpath of the [@rotorsoft/act-http](https://www.npmjs.com/package/@rotorsoft/act-http) umbrella package, which consolidates webhook and SSE integrations under one install.
|
|
11
|
+
>
|
|
12
|
+
> New projects: install `@rotorsoft/act-http` and import from the `/sse` subpath. Existing projects: migration is a one-import change (see below). This package will receive bug fixes only and be removed in a future release.
|
|
10
13
|
|
|
11
|
-
##
|
|
14
|
+
## Migration to `@rotorsoft/act-http/sse`
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
npm install @rotorsoft/act-sse
|
|
15
|
-
# or
|
|
16
|
-
pnpm add @rotorsoft/act-sse
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
**Requirements:** Node.js >= 22.18.0
|
|
20
|
-
|
|
21
|
-
## Architecture
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
app.do() → Snapshot[] (each carries its event's domain patch)
|
|
25
|
-
│
|
|
26
|
-
▼
|
|
27
|
-
deriveState(snap) ← app-specific (overlay presence, deadlines, etc.)
|
|
28
|
-
state._v = snap.event.version ← event store version is the single source of truth
|
|
29
|
-
│
|
|
30
|
-
▼
|
|
31
|
-
broadcast.publish(streamId, state, patches)
|
|
32
|
-
│
|
|
33
|
-
└── version-key each patch → { "5": { count: 3 }, "6": { name: "updated" } }
|
|
34
|
-
└── push to all SSE subscribers
|
|
35
|
-
│
|
|
36
|
-
▼
|
|
37
|
-
Client: applyPatchMessage(msg, cached)
|
|
38
|
-
│
|
|
39
|
-
├── contiguous → deep merge patches in version order
|
|
40
|
-
├── stale → skip (client already ahead)
|
|
41
|
-
└── behind → invalidate + refetch (client missed versions)
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Wire Format
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
// Version-keyed domain patches
|
|
48
|
-
// Keys = state version after that patch is applied
|
|
49
|
-
// Values = domain patch (deep partial of state)
|
|
50
|
-
{
|
|
51
|
-
"5": { territories: { brazil: { armies: 3 } } },
|
|
52
|
-
"6": { currentPlayerIndex: 2, phase: "reinforce" }
|
|
53
|
-
}
|
|
54
|
-
```
|
|
16
|
+
`@rotorsoft/act-http/sse` is a verbatim copy of this package's surface — same classes, same functions, same wire format, same semantics. Migration is one import change per file:
|
|
55
17
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
import { BroadcastChannel } from "@rotorsoft/act-sse";
|
|
62
|
-
|
|
63
|
-
const broadcast = new BroadcastChannel<MyAppState>();
|
|
64
|
-
|
|
65
|
-
// After every app.do():
|
|
66
|
-
const snaps = await app.do(action, target, payload);
|
|
67
|
-
const snap = snaps.at(-1)!;
|
|
68
|
-
const patches = snaps.map(s => s.patch).filter(Boolean);
|
|
69
|
-
const state = deriveState(snap);
|
|
70
|
-
broadcast.publish(streamId, state, patches);
|
|
71
|
-
|
|
72
|
-
// For non-event state changes (e.g. presence overlay):
|
|
73
|
-
broadcast.publishOverlay(streamId, { players: { pid: { connected: true } } });
|
|
74
|
-
|
|
75
|
-
// SSE subscription (tRPC example):
|
|
76
|
-
onStateChange: publicProcedure
|
|
77
|
-
.input(z.object({ streamId: z.string() }))
|
|
78
|
-
.subscription(async function* ({ input, signal }) {
|
|
79
|
-
let resolve: (() => void) | null = null;
|
|
80
|
-
let pending: PatchMessage | null = null;
|
|
81
|
-
|
|
82
|
-
const cleanup = broadcast.subscribe(input.streamId, (msg) => {
|
|
83
|
-
pending = msg;
|
|
84
|
-
if (resolve) { resolve(); resolve = null; }
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
while (!signal?.aborted) {
|
|
89
|
-
if (!pending) {
|
|
90
|
-
await new Promise<void>((r) => {
|
|
91
|
-
resolve = r;
|
|
92
|
-
signal?.addEventListener("abort", () => r(), { once: true });
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
if (signal?.aborted) break;
|
|
96
|
-
if (pending) { const msg = pending; pending = null; yield msg; }
|
|
97
|
-
}
|
|
98
|
-
} finally {
|
|
99
|
-
cleanup();
|
|
100
|
-
}
|
|
101
|
-
}),
|
|
18
|
+
```diff
|
|
19
|
+
- import { BroadcastChannel, applyPatchMessage } from "@rotorsoft/act-sse";
|
|
20
|
+
+ import { BroadcastChannel, applyPatchMessage } from "@rotorsoft/act-http/sse";
|
|
102
21
|
```
|
|
103
22
|
|
|
104
|
-
|
|
23
|
+
Then:
|
|
105
24
|
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// In your SSE onData handler (React Query example):
|
|
110
|
-
onData: (msg) => {
|
|
111
|
-
const cached = utils.getState.getData({ streamId });
|
|
112
|
-
const result = applyPatchMessage(msg, cached);
|
|
113
|
-
|
|
114
|
-
if (result.ok) {
|
|
115
|
-
utils.getState.setData({ streamId }, result.state);
|
|
116
|
-
} else if (result.reason === "behind") {
|
|
117
|
-
// Client missed versions — trigger full refetch
|
|
118
|
-
utils.getState.invalidate({ streamId });
|
|
119
|
-
}
|
|
120
|
-
// "stale" → no-op (client already has newer state from mutation response)
|
|
121
|
-
}
|
|
25
|
+
```bash
|
|
26
|
+
pnpm remove @rotorsoft/act-sse
|
|
27
|
+
pnpm add @rotorsoft/act-http
|
|
122
28
|
```
|
|
123
29
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
### `BroadcastChannel<S>`
|
|
127
|
-
|
|
128
|
-
Server-side broadcast manager with per-stream subscriber channels and LRU state cache.
|
|
129
|
-
|
|
130
|
-
| Method | Description |
|
|
131
|
-
|--------|-------------|
|
|
132
|
-
| `publish(streamId, state, patches?)` | Cache state, version-key patches, push to subscribers |
|
|
133
|
-
| `publishOverlay(streamId, patch)` | Same-version update (e.g. presence change) |
|
|
134
|
-
| `subscribe(streamId, cb)` | Register subscriber, returns cleanup function |
|
|
135
|
-
| `getState(streamId)` | Get cached state (for reconnects) |
|
|
136
|
-
| `getSubscriberCount(streamId)` | Number of active subscribers |
|
|
137
|
-
| `cache` | Direct access to `StateCache` instance |
|
|
30
|
+
The umbrella package keeps SSE and `webhook` as independent subpath exports (`@rotorsoft/act-http/sse` and `@rotorsoft/act-http/webhook`) — nothing in one depends on the other, so the bundle cost is the same. Future HTTP-adjacent integrations (OAuth refresh, signed-webhook senders, gRPC-web) will land as additional subpaths rather than separate packages.
|
|
138
31
|
|
|
139
|
-
|
|
32
|
+
## What this package does (legacy)
|
|
140
33
|
|
|
141
|
-
|
|
34
|
+
Instead of sending full aggregate state after each action, `act-sse` forwards the domain patches that event handlers already compute — sending only what changed as version-keyed partials. The wire format, server surface (`BroadcastChannel`, `PresenceTracker`, `StateCache`, `publishOverlay`), and client patch applicator (`applyPatchMessage`) are all preserved unchanged in `@rotorsoft/act-http/sse`.
|
|
142
35
|
|
|
143
|
-
|
|
36
|
+
For the full reference (architecture diagram, wire format, server + client usage, version contract, bandwidth savings), see the [@rotorsoft/act-http README](https://github.com/Rotorsoft/act-root/blob/master/libs/act-http/README.md#sse--incremental-state-broadcast).
|
|
144
37
|
|
|
145
|
-
|
|
38
|
+
## Installation (legacy)
|
|
146
39
|
|
|
147
|
-
|
|
40
|
+
Still works. New projects should use `@rotorsoft/act-http` instead.
|
|
148
41
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
Generic LRU cache. Methods: `get`, `set`, `delete`, `has`, `size`, `entries`.
|
|
152
|
-
|
|
153
|
-
### Types
|
|
154
|
-
|
|
155
|
-
```typescript
|
|
156
|
-
type BroadcastState = Record<string, unknown> & { _v: number };
|
|
157
|
-
type PatchMessage<S extends BroadcastState> = Record<number, DeepPartial<S>>;
|
|
158
|
-
type Subscriber<S extends BroadcastState> = (msg: PatchMessage<S>) => void;
|
|
42
|
+
```bash
|
|
43
|
+
pnpm add @rotorsoft/act-sse
|
|
159
44
|
```
|
|
160
45
|
|
|
161
|
-
##
|
|
162
|
-
|
|
163
|
-
The `_v` field **must** be set from `snap.event.version` — the event store's monotonic stream version. This is the single source of truth for ordering. No separate version counters.
|
|
46
|
+
## Stability
|
|
164
47
|
|
|
165
|
-
|
|
48
|
+
Public API governed by the [Act Stability Charter](../../STABILITY.md) — but this package is on the deprecation track. New work goes to `@rotorsoft/act-http/sse`.
|
|
166
49
|
|
|
167
|
-
|
|
50
|
+
## Related packages
|
|
168
51
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
| Multi-field update | ~5,000 | ~400 | 92% |
|
|
173
|
-
| Presence toggle | ~5,000 | ~80 | 98% |
|
|
52
|
+
- **[@rotorsoft/act-http](https://www.npmjs.com/package/@rotorsoft/act-http)** ← **migrate here.** The umbrella package that now owns SSE + webhook integrations.
|
|
53
|
+
- **[@rotorsoft/act](https://www.npmjs.com/package/@rotorsoft/act)** — core framework.
|
|
54
|
+
- **[@rotorsoft/act-patch](https://www.npmjs.com/package/@rotorsoft/act-patch)** — immutable patch utility this package uses for state merging.
|
|
174
55
|
|
|
175
|
-
##
|
|
56
|
+
## Documentation
|
|
176
57
|
|
|
177
|
-
- [
|
|
178
|
-
- [@rotorsoft/act-
|
|
179
|
-
- [Documentation](https://rotorsoft.github.io/act-root/)
|
|
180
|
-
- [Examples](https://github.com/rotorsoft/act-root/tree/master/packages)
|
|
58
|
+
- **[Real-time with SSE](https://github.com/Rotorsoft/act-root/blob/master/docs/docs/concepts/real-time.md)** — the concept guide; same content applies to `@rotorsoft/act-http/sse`.
|
|
59
|
+
- **[@rotorsoft/act-http README](https://github.com/Rotorsoft/act-root/blob/master/libs/act-http/README.md)** — full SSE reference at its new home.
|
|
181
60
|
|
|
182
61
|
## License
|
|
183
62
|
|
|
184
|
-
|
|
63
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.scripthost.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2025.float16.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.full.d.ts","../../act-patch/dist/@types/types.d.ts","../../act-patch/dist/@types/delta.d.ts","../../act-patch/dist/@types/patch.d.ts","../../act-patch/dist/@types/index.d.ts","../src/types.ts","../src/apply-patch.ts","../src/state-cache.ts","../src/broadcast.ts","../src/presence.ts","../src/index.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/compatibility/iterators.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/globals.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/blob.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/console.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/crypto.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/domexception.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/encoding.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/events.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/utility.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/header.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/readable.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/fetch.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/formdata.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/connector.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/client-stats.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/client.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/errors.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/global-origin.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/pool-stats.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/pool.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/handlers.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/round-robin-pool.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/h2c-client.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/agent.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-call-history.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-agent.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-client.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-pool.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/snapshot-agent.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-errors.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/socks5-proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/retry-handler.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/retry-agent.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/api.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/cache-interceptor.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/interceptors.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/util.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/cookies.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/patch.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/websocket.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/eventsource.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/content-type.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/cache.d.ts","../../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/index.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/fetch.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/importmeta.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/messaging.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/navigator.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/performance.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/storage.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/streams.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/timers.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/web-globals/url.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/assert.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/assert/strict.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/async_hooks.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/buffer.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/child_process.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/cluster.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/console.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/constants.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/crypto.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/dgram.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/dns.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/dns/promises.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/domain.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/events.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/fs.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/fs/promises.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/http.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/http2.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/https.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/inspector.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/inspector.generated.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/inspector/promises.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/module.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/net.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/os.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/path.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/path/posix.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/path/win32.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/process.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/punycode.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/querystring.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/quic.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/readline.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/readline/promises.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/repl.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/sea.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/sqlite.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/stream.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/stream/iter.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/stream/promises.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/stream/web.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/string_decoder.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/test.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/test/reporters.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/timers.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/timers/promises.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/tls.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/trace_events.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/tty.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/url.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/util.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/util/types.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/v8.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/vm.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/wasi.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/worker_threads.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/zlib.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/zlib/iter.d.ts","../../../node_modules/.pnpm/@types+node@25.9.1/node_modules/@types/node/index.d.ts","../../../node_modules/.pnpm/@vitest+pretty-format@4.1.8/node_modules/@vitest/pretty-format/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+utils@4.1.8/node_modules/@vitest/utils/dist/display.d.ts","../../../node_modules/.pnpm/@vitest+utils@4.1.8/node_modules/@vitest/utils/dist/types.d.ts","../../../node_modules/.pnpm/@vitest+utils@4.1.8/node_modules/@vitest/utils/dist/helpers.d.ts","../../../node_modules/.pnpm/@vitest+utils@4.1.8/node_modules/@vitest/utils/dist/timers.d.ts","../../../node_modules/.pnpm/@vitest+utils@4.1.8/node_modules/@vitest/utils/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+utils@4.1.8/node_modules/@vitest/utils/dist/types.d-BCElaP-c.d.ts","../../../node_modules/.pnpm/@vitest+utils@4.1.8/node_modules/@vitest/utils/dist/diff.d.ts","../../../node_modules/.pnpm/@vitest+runner@4.1.8/node_modules/@vitest/runner/dist/tasks.d-DEYaIMIu.d.ts","../../../node_modules/.pnpm/@vitest+runner@4.1.8/node_modules/@vitest/runner/dist/index.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/traces.d.D2T_R8rx.d.ts","../../../node_modules/.pnpm/vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0/node_modules/vite/types/hmrPayload.d.ts","../../../node_modules/.pnpm/vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0/node_modules/vite/dist/node/chunks/moduleRunnerTransport.d.ts","../../../node_modules/.pnpm/vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0/node_modules/vite/types/customEvent.d.ts","../../../node_modules/.pnpm/vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0/node_modules/vite/types/hot.d.ts","../../../node_modules/.pnpm/vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0/node_modules/vite/dist/node/module-runner.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@4.1.8/node_modules/@vitest/snapshot/dist/environment.d-DOJxxZV9.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@4.1.8/node_modules/@vitest/snapshot/dist/rawSnapshot.d-D_X3-62x.d.ts","../../../node_modules/.pnpm/@vitest+snapshot@4.1.8/node_modules/@vitest/snapshot/dist/index.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/config.d.A1h_Y6Jt.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/rpc.d.B_8sPU0w.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/worker.d.ZpHpO4yb.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/browser.d.BcoexmFG.d.ts","../../../node_modules/.pnpm/@vitest+spy@4.1.8/node_modules/@vitest/spy/optional-types.d.ts","../../../node_modules/.pnpm/@vitest+spy@4.1.8/node_modules/@vitest/spy/dist/index.d.ts","../../../node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.d.ts","../../../node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts","../../../node_modules/.pnpm/@types+deep-eql@4.0.2/node_modules/@types/deep-eql/index.d.ts","../../../node_modules/.pnpm/assertion-error@2.0.1/node_modules/assertion-error/index.d.ts","../../../node_modules/.pnpm/@types+chai@5.2.3/node_modules/@types/chai/index.d.ts","../../../node_modules/.pnpm/@vitest+expect@4.1.8/node_modules/@vitest/expect/dist/index.d.ts","../../../node_modules/.pnpm/@vitest+runner@4.1.8/node_modules/@vitest/runner/dist/utils.d.ts","../../../node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/global.d.DVsSRdQ5.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/optional-runtime-types.d.ts","../../../node_modules/.pnpm/@vitest+mocker@4.1.8_vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0_/node_modules/@vitest/mocker/dist/types.d-BjI5eAwu.d.ts","../../../node_modules/.pnpm/@vitest+mocker@4.1.8_vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0_/node_modules/@vitest/mocker/dist/index.d-B41z0AuW.d.ts","../../../node_modules/.pnpm/@vitest+mocker@4.1.8_vite@8.0.16_@types+node@25.9.1_esbuild@0.27.2_jiti@2.6.1_terser@5.46.1_tsx@4.22.4_yaml@2.9.0_/node_modules/@vitest/mocker/dist/index.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/suite.d.udJtyAgw.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/runners.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.d.ts","../../../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/dist/index.d.ts","../../../node_modules/.pnpm/vitest@4.1.8_@types+node@25.9.1_@vitest+coverage-v8@4.1.8_vite@8.0.16_@types+node@25.9._87965f5280639f5a2754f2fd84ad1804/node_modules/vitest/globals.d.ts"],"fileIdsList":[[66,78,142,150,154,157,159,160,161,173],[66,67,68,78,142,150,154,157,159,160,161,173],[78,142,150,154,157,159,160,161,173],[69,70,78,142,150,154,157,159,160,161,173],[69,70,72,78,142,150,154,157,159,160,161,173],[69,70,71,72,73,74,78,142,150,154,157,159,160,161,173],[70,78,142,150,154,157,159,160,161,173],[69,78,142,150,154,157,159,160,161,173],[78,142,150,154,157,159,160,161,173,229,230],[78,139,140,142,150,154,157,159,160,161,173],[78,141,142,150,154,157,159,160,161,173],[142,150,154,157,159,160,161,173],[78,142,150,154,157,159,160,161,173,182],[78,142,143,148,150,153,154,157,159,160,161,163,173,178,191],[78,142,143,144,150,153,154,157,159,160,161,173],[78,142,145,150,154,157,159,160,161,173,192],[78,142,146,147,150,154,157,159,160,161,164,173],[78,142,147,150,154,157,159,160,161,173,178,188],[78,142,148,150,153,154,157,159,160,161,163,173],[78,141,142,149,150,154,157,159,160,161,173],[78,142,150,151,154,157,159,160,161,173],[78,142,150,152,153,154,157,159,160,161,173],[78,141,142,150,153,154,157,159,160,161,173],[78,142,150,153,154,155,157,159,160,161,173,178,191],[78,142,150,153,154,155,157,159,160,161,173,178,180,182],[78,129,142,150,153,154,156,157,159,160,161,163,173,178,191],[78,142,150,153,154,156,157,159,160,161,163,173,178,188,191],[78,142,150,154,156,157,158,159,160,161,173,178,188,191],[76,77,78,79,80,81,82,83,84,85,86,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199],[78,142,150,153,154,157,159,160,161,173],[78,142,150,154,157,159,161,173],[78,142,150,154,157,159,160,161,162,173,191],[78,142,150,153,154,157,159,160,161,163,173,178],[78,142,150,154,157,159,160,161,164,173],[78,142,150,154,157,159,160,161,165,173],[78,142,150,153,154,157,159,160,161,168,173],[78,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198],[78,142,150,154,157,159,160,161,170,173],[78,142,150,154,157,159,160,161,171,173],[78,142,147,150,154,157,159,160,161,163,173,182],[78,142,150,153,154,157,159,160,161,173,174],[78,142,150,154,157,159,160,161,173,175,192,195],[78,142,150,153,154,157,159,160,161,173,178,181,182],[78,142,150,154,157,159,160,161,173,179,182],[78,142,150,154,157,159,160,161,173,180],[78,142,150,154,157,159,160,161,173,182,192],[78,142,150,154,157,159,160,161,173,183],[78,139,142,150,154,157,159,160,161,173,178,185,191],[78,142,150,154,157,159,160,161,173,178,184],[78,142,150,153,154,157,159,160,161,173,186,187],[78,142,150,154,157,159,160,161,173,186,187],[78,142,147,150,154,157,159,160,161,163,173,178,188],[78,142,150,154,157,159,160,161,173,189],[78,142,150,154,157,159,160,161,163,173,190],[78,142,150,154,156,157,159,160,161,171,173,191],[78,142,150,154,157,159,160,161,173,192,193],[78,142,147,150,154,157,159,160,161,173,193],[78,142,150,154,157,159,160,161,173,178,194],[78,142,150,154,157,159,160,161,162,173,195],[78,142,150,154,157,159,160,161,173,196],[78,142,145,150,154,157,159,160,161,173],[78,142,147,150,154,157,159,160,161,173],[78,142,150,154,157,159,160,161,173,192],[78,129,142,150,154,157,159,160,161,173],[78,142,150,154,157,159,160,161,173,191],[78,142,150,154,157,159,160,161,173,197],[78,142,150,154,157,159,160,161,168,173],[78,142,150,154,157,159,160,161,173,187],[78,129,142,150,153,154,155,157,159,160,161,168,173,178,182,191,194,195,197],[78,142,150,154,157,159,160,161,173,178,198],[78,142,150,154,157,159,160,161,173,180,199],[78,142,150,154,157,159,160,161,173,202,208,226,227,228,231],[78,142,150,154,157,159,160,161,173,238],[78,142,150,154,157,159,160,161,173,238,239],[78,142,150,154,157,159,160,161,173,206,208,209],[78,142,150,154,157,159,160,161,173,206,208],[78,142,150,154,157,159,160,161,173,206],[78,142,150,154,157,159,160,161,173,201,206,217,218],[78,142,150,154,157,159,160,161,173,201,206,217],[78,142,150,154,157,159,160,161,173,225],[78,142,150,154,157,159,160,161,173,201,207],[78,142,150,154,157,159,160,161,173,201],[78,142,150,154,157,159,160,161,173,203],[78,142,150,154,157,159,160,161,173,201,202,203,204,205],[78,142,150,154,157,159,160,161,173,244,245],[78,142,150,154,157,159,160,161,173,244,245,246,247],[78,142,150,154,157,159,160,161,173,244,246],[78,142,150,154,157,159,160,161,173,244],[78,93,96,99,100,142,150,154,157,159,160,161,173,191],[78,96,142,150,154,157,159,160,161,173,178,191],[78,96,100,142,150,154,157,159,160,161,173,191],[78,142,150,154,157,159,160,161,173,178],[78,90,142,150,154,157,159,160,161,173],[78,94,142,150,154,157,159,160,161,173],[78,92,93,96,142,150,154,157,159,160,161,173,191],[78,142,150,154,157,159,160,161,163,173,188],[78,142,150,154,157,159,160,161,173,200],[78,90,142,150,154,157,159,160,161,173,200],[78,92,96,142,150,154,157,159,160,161,163,173,191],[78,87,88,89,91,95,142,150,153,154,157,159,160,161,173,178,191],[78,96,105,113,142,150,154,157,159,160,161,173],[78,88,94,142,150,154,157,159,160,161,173],[78,96,123,124,142,150,154,157,159,160,161,173],[78,88,91,96,142,150,154,157,159,160,161,173,182,191,200],[78,96,142,150,154,157,159,160,161,173],[78,92,96,142,150,154,157,159,160,161,173,191],[78,87,142,150,154,157,159,160,161,173],[78,90,91,92,94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,124,125,126,127,128,142,150,154,157,159,160,161,173],[78,96,116,119,142,150,154,157,159,160,161,173],[78,96,105,106,107,142,150,154,157,159,160,161,173],[78,94,96,106,108,142,150,154,157,159,160,161,173],[78,95,142,150,154,157,159,160,161,173],[78,88,90,96,142,150,154,157,159,160,161,173],[78,96,100,106,108,142,150,154,157,159,160,161,173],[78,100,142,150,154,157,159,160,161,173],[78,94,96,99,142,150,154,157,159,160,161,173,191],[78,88,92,96,105,142,150,154,157,159,160,161,173],[78,96,116,142,150,154,157,159,160,161,173],[78,108,142,150,154,157,159,160,161,173],[78,88,92,96,100,142,150,154,157,159,160,161,173],[78,90,96,123,142,150,154,157,159,160,161,173,182,197,200],[78,142,150,154,157,159,160,161,173,212],[78,142,150,154,157,159,160,161,173,212,213,214,215],[78,142,150,154,157,159,160,161,173,214],[78,142,150,154,157,159,160,161,173,210,233,234,236],[78,142,150,154,157,159,160,161,173,210,211,223,236],[78,142,150,154,157,159,160,161,173,201,208,210,211,219,236],[78,142,150,154,157,159,160,161,173,216],[78,142,150,154,157,159,160,161,173,201,210,211,219,232,235,236],[78,142,150,154,157,159,160,161,173,210,211,216,219,236],[78,142,150,154,157,159,160,161,173,210,233,234,235,236],[78,142,150,154,157,159,160,161,173,210,216,220,221,222,236],[78,142,150,154,157,159,160,161,173,201,206,208,210,211,216,219,220,221,222,223,224,226,232,233,234,235,236,237,240,241,242,243,248],[78,142,150,154,157,159,160,161,173,201,208,210,211,219,220,233,234,235,236,241],[78,142,150,154,157,159,160,161,173,249]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"2a2de5b9459b3fc44decd9ce6100b72f1b002ef523126c1d3d8b2a4a63d74d78","affectsGlobalScope":true,"impliedFormat":1},{"version":"f13f4b465c99041e912db5c44129a94588e1aafee35a50eab51044833f50b4ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ecb8e347cb6b2a8927c09b86263663289418df375f5e68e11a0ae683776978f","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"01a30f9e8582b369075c0808df71121e6855cb06fd8d3d39511d9ebb66405205","impliedFormat":1},{"version":"adddb46115ea335eb856958251a6f5d38905da39ba9d4af6e801818de26df45c","impliedFormat":99},{"version":"09227d94665edb85fd40b293bca5a0a691d6071863ee43f0c2e979bd898f3c6d","impliedFormat":99},{"version":"0f87241ea10e949f45d5310162a649099246918a40ab2c11a2c99e561f8bd8d9","impliedFormat":99},{"version":"211a7a7c6be66a0504a246d268aeaa2faf4e3728cf2e3c40d9771518adb9f7d7","impliedFormat":99},{"version":"d150b509281060dbad33ac3f7a4242b3428320657f0aec8e7278d37d8849c10c","signature":"528241117504fac8802039906879b4195368392a66ffb13b8f9fd1b518735618","impliedFormat":99},{"version":"eceb67ccc9c9d5d1616b065504d780b4fc2f480adff073c6362ca957b320f531","signature":"6ebd4ce95e96b0fc1005e0e800db05a550a1b9d0990ba31c1edb6d24ee24aca3","impliedFormat":99},{"version":"04590593b4dfa6e8af32712e6c64681b3a075ad4979c18a4ac4a38a6d9259ab0","signature":"295489981f12851f4146c951dff875bb6b025a8e76abdc500bf553ede7ad147b","impliedFormat":99},{"version":"3ea9943ebae1065b44c7b1eddb723243470913e38ac2b22b3b71bec8eadf6a40","signature":"27c4490f6132ab8d0592c26cb80e0e2a3f4b4e77e4f086e019ebe960ad7d101b","impliedFormat":99},{"version":"4b41a1daba0e73597c9fb5b912345af0a4f6d47422759ee8752e2bb6a4382a36","signature":"d164c332ba86b2b745045e72c31900eef11b3314bb587ebde9969a8a9a45b602","impliedFormat":99},{"version":"210d002828c7fbc346d0323e555530758b21c6f31a13b36e4d89ec4d3cc548a7","signature":"289c37246b5fa7594c16642d7c42fc021747799f0970bbab6005d398168b3761","impliedFormat":99},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc2110f7decca6bfb9392e30421cfa1436479e4a6756e8fec6cbc22625d4f881","affectsGlobalScope":true,"impliedFormat":1},{"version":"096116f8fedc1765d5bd6ef360c257b4a9048e5415054b3bf3c41b07f8951b0b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"14e9acf826baba0ef4b5665704084896e7bcc06f65a9ab13af7e93d27d6b7069","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"21adf13435b9b748529c8cedf80f884e5130b9684188120a686cd2b26a2059c7","impliedFormat":1},{"version":"eec76bf6b9346f3f95fa402621b889489e96930e72295b0369022f332e9b4a6a","impliedFormat":1},{"version":"0ecd58f413f9bc3b7d4383eae31b0c8fc576985cd7404d6f99f8c643543ade74","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"d33ce35e3f9cfcc1d94eca415bdd3bde94d5b153ffdd33e6c4455c029986c630","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"98498b101803bb3dde9f76a56e65c14b75db1cc8bec5f4db72be541570f74fc5","impliedFormat":1},{"version":"4dc59f6e1dbf3d5f66660fceabe6c174d3261b37b696ae1854f0dbaf255fc753","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"436d7b4543b340b0f3eef4310d524242e41369b9652aa9c70428767c4dcac455","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"114f493b30f364255290472111b5a4791d5902c308645670cd0401429cbc6930","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"d2ae155afe8a01cc0ae612d99117cf8ef16692ba7c4366590156fdec1bcf2d8c","impliedFormat":1},{"version":"3f5e5d9be35913db9fea42a63f3df0b7e3c8703b97670a2125587b4dbbd56d7c","impliedFormat":1},{"version":"c8b8968311ec4e5e97b7b5fb8a65efaba455db9bdcfd7fff7fb15f6e317bfba0","impliedFormat":1},{"version":"57c23df0b5f7a8e26363a3849b0bc7763f6b241207157c8e40089d1df4116f35","affectsGlobalScope":true,"impliedFormat":1},{"version":"3b8bc0c17b54081b0878673989216229e575d67a10874e84566a21025a2461ee","impliedFormat":1},{"version":"5b0db5a58b73498792a29bfebc333438e61906fef75da898b410e24e52229e6f","impliedFormat":1},{"version":"dbe055b2b29a7bab2c1ca8f259436306adb43f469dca7e639a02cd3695d3f621","impliedFormat":1},{"version":"1678b04557dca52feab73cc67610918a7f5e25bfdba3e7fa081acd625d93106d","impliedFormat":1},{"version":"aecbf1d9e6a18dab7d92ef8a89a1444b47e1eb6134cb2bb776a26d55ff58c29a","impliedFormat":1},{"version":"2ea729503db9793f2691162fec3dd1118cab62e96d025f8eeb376d43ec293395","impliedFormat":1},{"version":"9ec87fea42b92894b0f209931a880789d43c3397d09dd99c631ae40a2f7071d1","impliedFormat":1},{"version":"c68e88cdfadfb6c8ba5fc38e58a3a166b0beae77b1f05b7d921150a32a5ffb8d","impliedFormat":1},{"version":"2bc7aa4fba46df0bd495425a7c8201437a7d465f83854fac859df2d67f664df3","impliedFormat":1},{"version":"41d17e1ad9a002feb11c8cdd2777e5bbc0cdb1e3f595d237e4dded0b6949983b","impliedFormat":1},{"version":"1fede9296beac11ce8e6b425396a1791f64341f2be85deebb6286faf6e16306e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce697b6a251d9cad53998c7fd3098072df883b525ec45d83530e434dc6d80dc6","impliedFormat":1},{"version":"719412f054e6ecc35489462c9a21bab0323d173a7d04e55b0ace4b5d86fbeb07","impliedFormat":1},{"version":"0eb5d0cbf09de5d34542b977fd6a933bb2e0817bffe8e1a541b2f1ad1b9af1ff","impliedFormat":1},{"version":"fac3e88881b35d3a757ed891ac912b2674792c25e2a1a74e1f5fbc72d19a9792","impliedFormat":1},{"version":"2c2bdaa1d8ead9f68628d6d9d250e46ee8e81aa4898b4769a36956ae15e060fe","impliedFormat":1},{"version":"c32c840c62d8bd7aeb3147aa6754cd2d922b990a6b6634530cb2ebdce5adc8e9","impliedFormat":1},{"version":"5ff4433a2deae4f85ab1377e90a7554ce6b47ae51c69a84ca30a6e22fae85834","impliedFormat":1},{"version":"82b91e4e42e6c41bc7fc1b6c2dc5eba6a2ba98375eb1f210e6ff6bba2d54177e","impliedFormat":1},{"version":"c1fa52b3d014001e8662fa2669d90ea15373958a288e3b83a3b621733d25292a","affectsGlobalScope":true,"impliedFormat":1},{"version":"cbed824fec91efefc7bbdcb8b43d1a531fdbebd0e2ef19481501ff365a93cb70","impliedFormat":1},{"version":"d0716593b3f2b0451bcf0c24cfa86dec2235c325c89f201934248b7c742715fc","impliedFormat":1},{"version":"ec501101c2a96133a6c695f934c8f6642149cc728571b29cbb7b770984c1088e","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"2991bca2cc0f0628a278df2a2ccdb8d6cbcb700f3761abbed62bba137d5b1790","impliedFormat":1},{"version":"5e66972e83eb4dc7123939bf816e6cbd9ad81af5552db1cab84e6bd9c64d2ecc","affectsGlobalScope":true,"impliedFormat":1},{"version":"230763250f20449fa7b3c9273e1967adb0023dc890d4be1553faca658ee65971","impliedFormat":1},{"version":"c3e9078b60cb329d1221f5878e88cecfa3e74460550e605a58fcfb41a66029ff","impliedFormat":1},{"version":"8413d0641f293aed551c7464615b770d34a02dedede889b9591172287d68e773","impliedFormat":1},{"version":"0ea59f7d3e51440baa64f429253759b106cfcbaf51e474cae606e02265b37cf8","impliedFormat":1},{"version":"bc18a1991ba681f03e13285fa1d7b99b03b67ee671b7bc936254467177543890","impliedFormat":1},{"version":"1b241e24f3227d078c06aeda6e050187ad59a4e591f4467abed44d92b084e08d","impliedFormat":1},{"version":"fa94bbf532b7af8f394b95fa310980d6e20bd2d4c871c6a6cb9f70f03750a44b","impliedFormat":1},{"version":"7fde0e1be5c8be204ffbf428abfcf01da2eb0f130e1bc3f539eb7275f4fd1f58","impliedFormat":1},{"version":"e284328553df5f425a5d33d36a0c3fa66b46af9d097cad6f4d2e8696dfdeb0f1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7fa2214bb0d64701bc6f9ce8cde2fd2ff8c571e0b23065fa04a8a5a6beb91511","impliedFormat":1},{"version":"f36b3fbe2be150a9ca140da48593f21e6a8172004f92ddc549b43efec39f3e54","impliedFormat":1},{"version":"f1c93e046fb3d9b7f8249629f4b63dc068dd839b824dd0aa39a5e68476dc9420","impliedFormat":1},{"version":"016b29bf4926b80255a108c53a1451717350059da04fcae64d1075f5e93bbb39","impliedFormat":1},{"version":"841983e39bd4cbb463be385e92fda11057cab368bf27100a801c492f1d86cbaa","impliedFormat":1},{"version":"1c4f139ade4f6ebf45463505f8155173e5d7a5305e50e0aae0a5e712d6ff3b48","impliedFormat":1},{"version":"e16b319e5aca1031168de823c4946ff8e29629c4c8cc0ec0fcfe2a8ab2155043","impliedFormat":1},{"version":"e4156ddb25aa0e3b5303d372f26957b36778f0f6bbd4326359269873295e3058","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc1b433a84cae05ddc5672d4823170af78606ad21ecef60dbc4570190cbf1357","impliedFormat":1},{"version":"9d3821bc75c59577e52643324cec92fc2145642e8d17cf7ee07a3181f21d985d","impliedFormat":1},{"version":"7f78cfb2b343838612c192cb251746e3a7c62ac7675726a47e130d9b213f6580","impliedFormat":1},{"version":"201db9cf1687fab1adf5282fcba861f382b32303dc4f67c89d59655e78a25461","impliedFormat":1},{"version":"2c3c5c0f54055e87640f5d233716fd889f3034fc7911d603b642369b0dbeb2a7","impliedFormat":1},{"version":"0a20eaf2e4b1e3c1e1f87f7bccb0c936375b23b022baeea750519b7c9bc6ce83","impliedFormat":1},{"version":"b484ec11ba00e3a2235562a41898d55372ccabe607986c6fa4f4aba72093749f","impliedFormat":1},{"version":"a16b91b27bd6b706c687c88cbc8a7d4ee98e5ed6043026d6b84bda923c0aed67","impliedFormat":1},{"version":"1c9e5b1a17b1fc9b3711fb36e0690421261ab2880f15b145155b5b2ba2ab6c2d","impliedFormat":1},{"version":"99ab6d0d660ce4d21efb52288a39fd35bb3f556980ec5463b1ae8f304a3bbc85","impliedFormat":1},{"version":"6eeded8c7e352be6e0efb83f4935ec752513c4d22043b52522b90849a49a3a11","impliedFormat":1},{"version":"6c1ad90050ffbb151cacc68e2d06ea1a26a945659391e32651f5d42b86fd7f2c","impliedFormat":1},{"version":"afa1c49f8e559e413d57343339db857d2a8159435cf9cf7d4deb41718fff1b88","impliedFormat":1},{"version":"6953d7597831d0860c7034cf4f0419687d263b6b98a4b32e37ce6d49615c36e2","impliedFormat":1},{"version":"3a582c6e8906f5b094ccf0de6cc6f4f8a54b05a34f52517aba5c9c7f704f6b28","impliedFormat":99},{"version":"0528f6d21f7a02d4092895090d2dd86104bd5a3e79eced96d5a1a7dd90943d17","impliedFormat":99},{"version":"b5ce343886d23392be9c8280e9f24a87f1d7d3667f6672c2fe4aa61fa4ece7d4","impliedFormat":99},{"version":"72ce5b734c05da85c85a6f6dc05823b051d6aa41acaedeeb1d17c72f3b4efa72","impliedFormat":99},{"version":"b0857bb28fd5236ace84280f79a25093f919fd0eff13e47cc26ea03de60a7294","impliedFormat":99},{"version":"5e43e0824f10cd8c48e7a8c5c673638488925a12c31f0f9e0957965c290eb14c","impliedFormat":99},{"version":"ef13c73d6157a32933c612d476c1524dd674cf5b9a88571d7d6a0d147544d529","impliedFormat":99},{"version":"49ab4f1d153a252779958fc87b700743d32b5ffa42addd70ae23ad3f429daa5c","impliedFormat":99},{"version":"53cf4076f42b29b8d411259d168d51b3a0274c42c8814e5b44dfa8803a35d4fc","impliedFormat":99},{"version":"a39461ee1f27cf3e6cfd63d21045713d26d521da55ea4d8efccb705f689e6dbb","impliedFormat":99},{"version":"61bb64660ee150f3ab618340e15cca0a81664801bede7c966ca0eca3a952fe63","impliedFormat":99},{"version":"3b89216a7e38a454985ad17bb2ff85792837dc812f2a89fa5f60ad0a2e216fa7","impliedFormat":99},{"version":"16fe60bb544cfedfd2b5bb2f7d0b3957be7978706d57d9f06edc9c0c8dbdba23","impliedFormat":99},{"version":"de4a612aa8f1704af486f701e21993c786ba7d8cfed55fffa6684026aea2346e","impliedFormat":99},{"version":"4e003c868b0d8f8ad200b96cbc653e18e513fa23e1c19c4fe3cc25d4394efc47","impliedFormat":99},{"version":"8887e70871f697fa42ad7cdf32168db60ec2d6760c173c97973e35377fe5d83b","impliedFormat":99},{"version":"42a12f2faa483c9b48195ed794d22698162274e755f6e07219c2351c4f08d732","impliedFormat":99},{"version":"ec0c42bb0f465e4993f2bc68a6ce9df9a2dcbc7b83e21748f82f1b69561938e3","impliedFormat":99},{"version":"f50ff37a9cbbe74475f426474d9827083c7c2c138a954d28f1690df338f69291","impliedFormat":99},{"version":"61fd6c17235d530c40f543dd7c40afab091d91c1ef890baeed30db6d82b04b28","impliedFormat":99},{"version":"bcbd3becd08b4515225880abea0dbfbbf0d1181ce3af8f18f72f61edbe4febfb","impliedFormat":99},{"version":"091767bc841f937654ed597d49e023ed59850355e746ae1a6f20ab31076ee1fb","impliedFormat":99},{"version":"19c6d6135af59693698d384050b45a8a049493500add442f58e4bd7c8a255ab6","impliedFormat":99},{"version":"6a0dba12d55314638a8c51108b20fe2f68f1364a619d098918bda91c22dec154","impliedFormat":99},{"version":"c76c02846ba7d40b9b3488f0e8d75d02cbdee2f0bc5fcd55dd3bd2e1457646ea","impliedFormat":99},{"version":"4ead13a482c539b77394b2a97e3b877b809eac596390371cea490286f53b996a","impliedFormat":99},{"version":"06db2f8ba1d1dfacf04529cb731081ab23f133f29c7608ebdfbcab356996827c","impliedFormat":99},{"version":"bdd14f07b4eca0b4b5203b85b8dbc4d084c749fa590bee5ea613e1641dcd3b29","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"5c935b7fc4ddc1410ea1cd7cd4e35ed106a6e4920dd27a9480a40fd224359dc3","affectsGlobalScope":true,"impliedFormat":99},{"version":"2b39c6cf59088713babbfc3e20ee85f1375d40e66953156fa658346b8346f24f","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":99},{"version":"6987dfb4b0c4e02112cc4e548e7a77b3d9ddfeffa8c8a2db13ceac361a4567d9","impliedFormat":99},{"version":"4ffba3c5848b4fe62ee59b754fd5f256ad9656a0db6d37b9a2a8cb40dfc7ac21","impliedFormat":99},{"version":"c76c02846ba7d40b9b3488f0e8d75d02cbdee2f0bc5fcd55dd3bd2e1457646ea","impliedFormat":99},{"version":"5e2ba3d18d78aebbde1f34bde356e41e9c76eeaeaeee56a37036596a9eff4211","impliedFormat":99},{"version":"8280ae8ccc0493b32d1742d585357ab9f0a508ea050af25a5a20d64010d0a5cf","impliedFormat":99},{"version":"7adfd9f9056ecd4ae6c65fde2a98654960c662714c73f048478959d04c09e144","impliedFormat":99},{"version":"32b35cf0dc3a1b1a7118b61c34ce2ad1a29695851679f9ec34e0776f2ece2a69","impliedFormat":99},{"version":"b413fbc6658fe2774f8bf9a15cf4c53e586fc38a2d5256b3b9647da242c14389","impliedFormat":99},{"version":"59e5e964b84fdb2378e9455e4e59405030e4ed2b4c6f891ce395f17796af3cbb","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"90ba95a763101bb61b8a799731a2ed60b5016b8135c1a2d5186862d4b534d4a1","impliedFormat":99},{"version":"8d7cbeea0454e05a3cdf3370c5df267072c4f1dc6c48a45a9ad750d7890443d7","affectsGlobalScope":true,"impliedFormat":99}],"root":[[70,75]],"options":{"composite":true,"declaration":true,"declarationDir":"./@types","declarationMap":true,"emitDeclarationOnly":true,"erasableSyntaxOnly":true,"esModuleInterop":true,"module":199,"noUncheckedSideEffectImports":true,"outDir":"./","rootDir":"../src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9,"tsBuildInfoFile":"./.tsbuildinfo","verbatimModuleSyntax":true},"referencedMap":[[67,1],[69,2],[68,1],[66,3],[71,4],[73,5],[75,6],[74,3],[72,7],[70,8],[228,3],[231,9],[229,3],[139,10],[140,10],[141,11],[78,12],[142,13],[143,14],[144,15],[76,3],[145,16],[146,17],[147,18],[148,19],[149,20],[150,21],[151,21],[152,22],[153,23],[154,24],[155,25],[79,3],[77,3],[156,26],[157,27],[158,28],[200,29],[159,30],[160,31],[161,30],[162,32],[163,33],[164,34],[165,35],[166,35],[167,35],[168,36],[169,37],[170,38],[171,39],[172,40],[173,41],[174,41],[175,42],[176,3],[177,3],[178,43],[179,44],[180,45],[181,43],[182,46],[183,47],[184,48],[185,49],[186,50],[187,51],[188,52],[189,53],[190,54],[191,55],[192,56],[193,57],[194,58],[195,59],[196,60],[80,30],[81,3],[82,61],[83,62],[84,3],[85,63],[86,3],[130,64],[131,65],[132,66],[133,66],[134,67],[135,3],[136,13],[137,68],[138,65],[197,69],[198,70],[199,71],[232,72],[239,73],[240,74],[238,3],[201,3],[210,75],[209,76],[233,75],[217,77],[219,78],[218,79],[226,80],[225,3],[208,81],[202,82],[204,83],[206,84],[205,3],[207,82],[203,3],[230,3],[246,85],[248,86],[247,87],[245,88],[244,3],[234,3],[227,3],[63,3],[64,3],[12,3],[10,3],[11,3],[16,3],[15,3],[2,3],[17,3],[18,3],[19,3],[20,3],[21,3],[22,3],[23,3],[24,3],[3,3],[25,3],[26,3],[4,3],[27,3],[31,3],[28,3],[29,3],[30,3],[32,3],[33,3],[34,3],[5,3],[35,3],[36,3],[37,3],[38,3],[6,3],[42,3],[39,3],[40,3],[41,3],[43,3],[7,3],[44,3],[49,3],[50,3],[45,3],[46,3],[47,3],[48,3],[8,3],[54,3],[51,3],[52,3],[53,3],[55,3],[9,3],[56,3],[65,3],[57,3],[58,3],[60,3],[59,3],[61,3],[1,3],[62,3],[14,3],[13,3],[105,89],[118,90],[102,91],[119,92],[128,93],[93,94],[94,95],[92,96],[127,97],[122,98],[126,99],[96,100],[115,101],[95,102],[125,103],[90,104],[91,98],[97,105],[98,3],[104,106],[101,105],[88,107],[129,108],[120,109],[108,110],[107,105],[109,111],[112,112],[106,113],[110,114],[123,97],[99,115],[100,116],[113,117],[89,92],[117,118],[116,105],[103,116],[111,119],[114,120],[121,3],[87,3],[124,121],[213,122],[216,123],[214,122],[212,3],[215,124],[235,125],[224,126],[220,127],[221,77],[242,128],[236,129],[222,130],[241,131],[211,3],[223,132],[249,133],[243,134],[250,135],[237,3]],"latestChangedDtsFile":"./@types/index.d.ts","version":"6.0.3"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { BroadcastState, PatchMessage } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Result of applying a patch message to cached client state.
|
|
4
|
+
*/
|
|
5
|
+
export type ApplyResult<S extends BroadcastState = BroadcastState> = {
|
|
6
|
+
ok: true;
|
|
7
|
+
state: S;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
reason: "stale" | "behind";
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Apply a version-keyed patch message to the client's cached state.
|
|
14
|
+
*
|
|
15
|
+
* ## Version logic
|
|
16
|
+
*
|
|
17
|
+
* - All patches older than cached → "stale" (client already ahead)
|
|
18
|
+
* - Gap between cached version and first patch → "behind" (client missed versions, must resync)
|
|
19
|
+
* - Contiguous from cached version → apply in order
|
|
20
|
+
*
|
|
21
|
+
* ## Usage (React Query)
|
|
22
|
+
*
|
|
23
|
+
* ```typescript
|
|
24
|
+
* onData: (msg) => {
|
|
25
|
+
* const cached = utils.get_state.get_data({ streamId });
|
|
26
|
+
* const result = applyPatchMessage(msg, cached);
|
|
27
|
+
* if (result.ok) {
|
|
28
|
+
* utils.get_state.setData({ streamId }, result.state);
|
|
29
|
+
* } else if (result.reason === "behind") {
|
|
30
|
+
* utils.get_state.invalidate({ streamId }); // trigger full refetch
|
|
31
|
+
* }
|
|
32
|
+
* // "stale" → no-op, client already has newer state
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyPatchMessage<S extends BroadcastState>(msg: PatchMessage<S>, cached: S | null | undefined): ApplyResult<S>;
|
|
37
|
+
//# sourceMappingURL=apply-patch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-patch.d.ts","sourceRoot":"","sources":["../../src/apply-patch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAC7D;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACtB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAA;CAAE,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,cAAc,EACxD,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EACpB,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GAC3B,WAAW,CAAC,CAAC,CAAC,CAuBhB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { StateCache } from "./state-cache.js";
|
|
2
|
+
import type { BroadcastState, PatchMessage, Subscriber } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Server-side broadcast channel for incremental state sync over SSE.
|
|
5
|
+
*
|
|
6
|
+
* Manages per-stream subscriber sets and an LRU state cache. When state
|
|
7
|
+
* changes, forwards domain patches (from event handlers) to all subscribers
|
|
8
|
+
* as version-keyed messages.
|
|
9
|
+
*
|
|
10
|
+
* ## Usage
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const broadcast = new BroadcastChannel<MyState>();
|
|
14
|
+
*
|
|
15
|
+
* // After every app.do():
|
|
16
|
+
* const snaps = await app.do(...);
|
|
17
|
+
* const patches = snaps.map(s => s.patch).filter(Boolean);
|
|
18
|
+
* const state = deriveState(snaps.at(-1));
|
|
19
|
+
* broadcast.publish(streamId, state, patches);
|
|
20
|
+
*
|
|
21
|
+
* // In SSE subscription:
|
|
22
|
+
* const cleanup = broadcast.subscribe(streamId, (msg) => {
|
|
23
|
+
* pending = msg;
|
|
24
|
+
* resolve?.();
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // Initial state for reconnects:
|
|
28
|
+
* const cached = broadcast.get_state(streamId);
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* ## Version Contract
|
|
32
|
+
*
|
|
33
|
+
* The `_v` field on state MUST be set from `snap.event.version` (the event
|
|
34
|
+
* store's monotonic stream version) BEFORE calling `publish()`. This is the
|
|
35
|
+
* single source of truth for ordering — no separate version counters.
|
|
36
|
+
*/
|
|
37
|
+
export declare class BroadcastChannel<S extends BroadcastState = BroadcastState> {
|
|
38
|
+
private channels;
|
|
39
|
+
private state_cache;
|
|
40
|
+
constructor(options?: {
|
|
41
|
+
cache_size?: number;
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* Publish domain patches from a commit.
|
|
45
|
+
* patches[i] corresponds to version baseV + i + 1.
|
|
46
|
+
*
|
|
47
|
+
* @param streamId - The event store stream ID
|
|
48
|
+
* @param state - Full state with `_v` set from `snap.event.version`
|
|
49
|
+
* @param patches - Array of domain patches, one per emitted event
|
|
50
|
+
*/
|
|
51
|
+
publish(streamId: string, state: S, patches?: Partial<S>[]): PatchMessage<S>;
|
|
52
|
+
/**
|
|
53
|
+
* Publish a state update that doesn't change the event version
|
|
54
|
+
* (e.g. presence overlay, computed field refresh).
|
|
55
|
+
* Uses the same version as the cached state, single entry.
|
|
56
|
+
*/
|
|
57
|
+
publish_overlay(streamId: string, overlay_patch: Partial<S>): PatchMessage<S> | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Subscribe to broadcast messages for a stream.
|
|
60
|
+
* Returns a cleanup function that removes the subscription.
|
|
61
|
+
*/
|
|
62
|
+
subscribe(streamId: string, cb: Subscriber<S>): () => void;
|
|
63
|
+
/** Get the number of subscribers for a stream. */
|
|
64
|
+
get_subscriber_count(streamId: string): number;
|
|
65
|
+
/** Get the cached state for a stream (for reconnects / initial SSE yield). */
|
|
66
|
+
get_state(streamId: string): S | undefined;
|
|
67
|
+
/** Direct access to the state cache (for app-specific reads like presence). */
|
|
68
|
+
get cache(): StateCache<S>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=broadcast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../src/broadcast.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,gBAAgB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IACrE,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,WAAW,CAAgB;gBAEvB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAI7C;;;;;;;OAOG;IACH,OAAO,CACL,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,OAAO,CAAC,CAAC,CAAC,EAAO,GACzB,YAAY,CAAC,CAAC,CAAC;IAgBlB;;;;OAIG;IACH,eAAe,CACb,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,GACxB,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAe9B;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAW1D,kDAAkD;IAClD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI9C,8EAA8E;IAC9E,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI1C,+EAA+E;IAC/E,IAAI,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,CAEzB;CACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module act-sse
|
|
4
|
+
*
|
|
5
|
+
* Incremental state broadcast over SSE for act event-sourced apps.
|
|
6
|
+
*
|
|
7
|
+
* Provides server-side broadcast with domain patch forwarding,
|
|
8
|
+
* an LRU state cache, presence tracking, and a client-side
|
|
9
|
+
* patch applicator with version validation and resync detection.
|
|
10
|
+
*
|
|
11
|
+
* ## Architecture
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* app.do() → snapshots (each carries its domain patch)
|
|
15
|
+
* │
|
|
16
|
+
* ▼
|
|
17
|
+
* deriveState(snap) ← app-specific (overlay presence, deadlines, etc.)
|
|
18
|
+
* state._v = snap.event.version
|
|
19
|
+
* │
|
|
20
|
+
* ▼
|
|
21
|
+
* broadcast.publish(streamId, state, patches)
|
|
22
|
+
* │
|
|
23
|
+
* ├── version-key each patch: { [baseV+1]: patch1, [baseV+2]: patch2 }
|
|
24
|
+
* └── push to all SSE subscribers
|
|
25
|
+
* │
|
|
26
|
+
* ▼
|
|
27
|
+
* Client: applyPatchMessage(msg, cached)
|
|
28
|
+
* │
|
|
29
|
+
* ├── contiguous → deep-merge patches in version order
|
|
30
|
+
* ├── stale → skip (client already ahead)
|
|
31
|
+
* └── behind → resync (client missed versions)
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* ## Version Contract
|
|
35
|
+
*
|
|
36
|
+
* `_v` is always the event store stream version (`snap.event.version`).
|
|
37
|
+
* No separate version counters. The event store is the single source of truth.
|
|
38
|
+
*/
|
|
39
|
+
export { patch } from "@rotorsoft/act-patch";
|
|
40
|
+
export type { ApplyResult } from "./apply-patch.js";
|
|
41
|
+
export { applyPatchMessage } from "./apply-patch.js";
|
|
42
|
+
export { BroadcastChannel } from "./broadcast.js";
|
|
43
|
+
export { PresenceTracker } from "./presence.js";
|
|
44
|
+
export { StateCache } from "./state-cache.js";
|
|
45
|
+
export type { BroadcastState, PatchMessage, Subscriber } from "./types.js";
|
|
46
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic presence tracker — ref-counted online status per stream per identity.
|
|
3
|
+
*
|
|
4
|
+
* Supports multi-tab: each subscribe increments the ref count, each
|
|
5
|
+
* unsubscribe decrements it. An identity is considered online when
|
|
6
|
+
* ref count > 0.
|
|
7
|
+
*
|
|
8
|
+
* ## Usage
|
|
9
|
+
*
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const presence = new PresenceTracker();
|
|
12
|
+
*
|
|
13
|
+
* // On SSE connect:
|
|
14
|
+
* presence.add(game_id, player_id);
|
|
15
|
+
*
|
|
16
|
+
* // On SSE disconnect:
|
|
17
|
+
* presence.remove(game_id, player_id);
|
|
18
|
+
*
|
|
19
|
+
* // Query:
|
|
20
|
+
* presence.get_online(game_id); // Set<string>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class PresenceTracker {
|
|
24
|
+
private streams;
|
|
25
|
+
/** Increment ref count for an identity on a stream. */
|
|
26
|
+
add(streamId: string, identity_id: string): void;
|
|
27
|
+
/** Decrement ref count. Removes the identity when count reaches 0. */
|
|
28
|
+
remove(streamId: string, identity_id: string): void;
|
|
29
|
+
/** Get the set of online identity IDs for a stream. */
|
|
30
|
+
get_online(streamId: string): Set<string>;
|
|
31
|
+
/** Check if a specific identity is online for a stream. */
|
|
32
|
+
is_online(streamId: string, identity_id: string): boolean;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=presence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../src/presence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAA0C;IAEzD,uDAAuD;IACvD,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAMhD,sEAAsE;IACtE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IASnD,uDAAuD;IACvD,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAKzC,2DAA2D;IAC3D,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;CAG1D"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BroadcastState } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generic LRU cache for aggregate state objects.
|
|
4
|
+
*
|
|
5
|
+
* Keyed by stream ID. Each entry stores the full state (with `_v` from the
|
|
6
|
+
* event store). Used as the "previous state" baseline for computing patches,
|
|
7
|
+
* and as the fast path for reconnects.
|
|
8
|
+
*
|
|
9
|
+
* The cache is shared between the broadcast hot path and read queries.
|
|
10
|
+
* Projections should maintain their own cache to avoid double-apply bugs.
|
|
11
|
+
*/
|
|
12
|
+
export declare class StateCache<S extends BroadcastState = BroadcastState> {
|
|
13
|
+
private cache;
|
|
14
|
+
private maxSize;
|
|
15
|
+
constructor(maxSize?: number);
|
|
16
|
+
/** Get a cached state, promoting it to MRU position. */
|
|
17
|
+
get(key: string): S | undefined;
|
|
18
|
+
/** Set a cached state, evicting the LRU entry if at capacity. */
|
|
19
|
+
set(key: string, state: S): void;
|
|
20
|
+
/** Remove a cached entry. */
|
|
21
|
+
delete(key: string): void;
|
|
22
|
+
/** Check if a key exists in the cache. */
|
|
23
|
+
has(key: string): boolean;
|
|
24
|
+
/** Current number of cached entries. */
|
|
25
|
+
get size(): number;
|
|
26
|
+
/** Direct access to the underlying map (for iteration). */
|
|
27
|
+
entries(): IterableIterator<[string, S]>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=state-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-cache.d.ts","sourceRoot":"","sources":["../../src/state-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;GASG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IAC/D,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,SAAK;IAIxB,wDAAwD;IACxD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAU/B,iEAAiE;IACjE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAShC,6BAA6B;IAC7B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,0CAA0C;IAC1C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,wCAAwC;IACxC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,2DAA2D;IAC3D,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CAGzC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DeepPartial } from "@rotorsoft/act-patch";
|
|
2
|
+
/**
|
|
3
|
+
* Base constraint for state objects managed by the broadcast system.
|
|
4
|
+
* Apps extend this with their own domain state shape.
|
|
5
|
+
*/
|
|
6
|
+
export type BroadcastState = Record<string, unknown> & {
|
|
7
|
+
/** Event store stream version — set by the broadcast layer from snap.event.version */
|
|
8
|
+
_v: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* SSE message: version-keyed domain patches.
|
|
12
|
+
* Keys are stringified version numbers, values are domain patches (deep partials).
|
|
13
|
+
* Multi-event commits produce multiple version-keyed entries.
|
|
14
|
+
*/
|
|
15
|
+
export type PatchMessage<S extends BroadcastState = BroadcastState> = Record<number, DeepPartial<S>>;
|
|
16
|
+
/**
|
|
17
|
+
* Subscriber callback — receives version-keyed patch messages.
|
|
18
|
+
*/
|
|
19
|
+
export type Subscriber<S extends BroadcastState = BroadcastState> = (msg: PatchMessage<S>) => void;
|
|
20
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACrD,sFAAsF;IACtF,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAAI,MAAM,CAC1E,MAAM,EACN,WAAW,CAAC,CAAC,CAAC,CACf,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAAI,CAClE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,KACjB,IAAI,CAAC"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
BroadcastChannel: () => BroadcastChannel,
|
|
24
|
+
PresenceTracker: () => PresenceTracker,
|
|
25
|
+
StateCache: () => StateCache,
|
|
26
|
+
applyPatchMessage: () => applyPatchMessage,
|
|
27
|
+
patch: () => import_act_patch3.patch
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
var import_act_patch3 = require("@rotorsoft/act-patch");
|
|
31
|
+
|
|
32
|
+
// src/apply-patch.ts
|
|
33
|
+
var import_act_patch = require("@rotorsoft/act-patch");
|
|
34
|
+
function applyPatchMessage(msg, cached) {
|
|
35
|
+
const cachedV = cached?._v ?? 0;
|
|
36
|
+
const versions = Object.keys(msg).map(Number).sort((a, b) => a - b);
|
|
37
|
+
if (!versions.length) return { ok: false, reason: "stale" };
|
|
38
|
+
const minV = versions[0];
|
|
39
|
+
const maxV = versions[versions.length - 1];
|
|
40
|
+
if (maxV <= cachedV) return { ok: false, reason: "stale" };
|
|
41
|
+
if (!cached || minV > cachedV + 1) return { ok: false, reason: "behind" };
|
|
42
|
+
let state = cached;
|
|
43
|
+
for (const v of versions) {
|
|
44
|
+
if (v <= cachedV) continue;
|
|
45
|
+
state = { ...(0, import_act_patch.patch)(state, msg[v]), _v: v };
|
|
46
|
+
}
|
|
47
|
+
return { ok: true, state };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/broadcast.ts
|
|
51
|
+
var import_act_patch2 = require("@rotorsoft/act-patch");
|
|
52
|
+
|
|
53
|
+
// src/state-cache.ts
|
|
54
|
+
var StateCache = class {
|
|
55
|
+
cache = /* @__PURE__ */ new Map();
|
|
56
|
+
maxSize;
|
|
57
|
+
constructor(maxSize = 50) {
|
|
58
|
+
this.maxSize = maxSize;
|
|
59
|
+
}
|
|
60
|
+
/** Get a cached state, promoting it to MRU position. */
|
|
61
|
+
get(key) {
|
|
62
|
+
const s = this.cache.get(key);
|
|
63
|
+
if (s) {
|
|
64
|
+
this.cache.delete(key);
|
|
65
|
+
this.cache.set(key, s);
|
|
66
|
+
}
|
|
67
|
+
return s;
|
|
68
|
+
}
|
|
69
|
+
/** Set a cached state, evicting the LRU entry if at capacity. */
|
|
70
|
+
set(key, state) {
|
|
71
|
+
this.cache.delete(key);
|
|
72
|
+
this.cache.set(key, state);
|
|
73
|
+
if (this.cache.size > this.maxSize) {
|
|
74
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Remove a cached entry. */
|
|
78
|
+
delete(key) {
|
|
79
|
+
this.cache.delete(key);
|
|
80
|
+
}
|
|
81
|
+
/** Check if a key exists in the cache. */
|
|
82
|
+
has(key) {
|
|
83
|
+
return this.cache.has(key);
|
|
84
|
+
}
|
|
85
|
+
/** Current number of cached entries. */
|
|
86
|
+
get size() {
|
|
87
|
+
return this.cache.size;
|
|
88
|
+
}
|
|
89
|
+
/** Direct access to the underlying map (for iteration). */
|
|
90
|
+
entries() {
|
|
91
|
+
return this.cache.entries();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/broadcast.ts
|
|
96
|
+
var BroadcastChannel = class {
|
|
97
|
+
channels = /* @__PURE__ */ new Map();
|
|
98
|
+
state_cache;
|
|
99
|
+
constructor(options) {
|
|
100
|
+
this.state_cache = new StateCache(options?.cache_size ?? 50);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Publish domain patches from a commit.
|
|
104
|
+
* patches[i] corresponds to version baseV + i + 1.
|
|
105
|
+
*
|
|
106
|
+
* @param streamId - The event store stream ID
|
|
107
|
+
* @param state - Full state with `_v` set from `snap.event.version`
|
|
108
|
+
* @param patches - Array of domain patches, one per emitted event
|
|
109
|
+
*/
|
|
110
|
+
publish(streamId, state, patches = []) {
|
|
111
|
+
this.state_cache.set(streamId, state);
|
|
112
|
+
const baseV = state._v - patches.length;
|
|
113
|
+
const msg = {};
|
|
114
|
+
patches.forEach((p, i) => {
|
|
115
|
+
msg[baseV + i + 1] = p;
|
|
116
|
+
});
|
|
117
|
+
const subs = this.channels.get(streamId);
|
|
118
|
+
if (subs?.size) {
|
|
119
|
+
for (const cb of subs) cb(msg);
|
|
120
|
+
}
|
|
121
|
+
return msg;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Publish a state update that doesn't change the event version
|
|
125
|
+
* (e.g. presence overlay, computed field refresh).
|
|
126
|
+
* Uses the same version as the cached state, single entry.
|
|
127
|
+
*/
|
|
128
|
+
publish_overlay(streamId, overlay_patch) {
|
|
129
|
+
const prev = this.state_cache.get(streamId);
|
|
130
|
+
if (!prev) return void 0;
|
|
131
|
+
const state = (0, import_act_patch2.patch)(prev, overlay_patch);
|
|
132
|
+
this.state_cache.set(streamId, state);
|
|
133
|
+
const msg = { [state._v]: overlay_patch };
|
|
134
|
+
const subs = this.channels.get(streamId);
|
|
135
|
+
if (subs?.size) {
|
|
136
|
+
for (const cb of subs) cb(msg);
|
|
137
|
+
}
|
|
138
|
+
return msg;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Subscribe to broadcast messages for a stream.
|
|
142
|
+
* Returns a cleanup function that removes the subscription.
|
|
143
|
+
*/
|
|
144
|
+
subscribe(streamId, cb) {
|
|
145
|
+
if (!this.channels.has(streamId)) this.channels.set(streamId, /* @__PURE__ */ new Set());
|
|
146
|
+
this.channels.get(streamId).add(cb);
|
|
147
|
+
return () => {
|
|
148
|
+
this.channels.get(streamId)?.delete(cb);
|
|
149
|
+
if (this.channels.get(streamId)?.size === 0) {
|
|
150
|
+
this.channels.delete(streamId);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/** Get the number of subscribers for a stream. */
|
|
155
|
+
get_subscriber_count(streamId) {
|
|
156
|
+
return this.channels.get(streamId)?.size ?? 0;
|
|
157
|
+
}
|
|
158
|
+
/** Get the cached state for a stream (for reconnects / initial SSE yield). */
|
|
159
|
+
get_state(streamId) {
|
|
160
|
+
return this.state_cache.get(streamId);
|
|
161
|
+
}
|
|
162
|
+
/** Direct access to the state cache (for app-specific reads like presence). */
|
|
163
|
+
get cache() {
|
|
164
|
+
return this.state_cache;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// src/presence.ts
|
|
169
|
+
var PresenceTracker = class {
|
|
170
|
+
streams = /* @__PURE__ */ new Map();
|
|
171
|
+
/** Increment ref count for an identity on a stream. */
|
|
172
|
+
add(streamId, identity_id) {
|
|
173
|
+
if (!this.streams.has(streamId)) this.streams.set(streamId, /* @__PURE__ */ new Map());
|
|
174
|
+
const counts = this.streams.get(streamId);
|
|
175
|
+
counts.set(identity_id, (counts.get(identity_id) ?? 0) + 1);
|
|
176
|
+
}
|
|
177
|
+
/** Decrement ref count. Removes the identity when count reaches 0. */
|
|
178
|
+
remove(streamId, identity_id) {
|
|
179
|
+
const counts = this.streams.get(streamId);
|
|
180
|
+
if (!counts) return;
|
|
181
|
+
const n = (counts.get(identity_id) ?? 1) - 1;
|
|
182
|
+
if (n <= 0) counts.delete(identity_id);
|
|
183
|
+
else counts.set(identity_id, n);
|
|
184
|
+
if (counts.size === 0) this.streams.delete(streamId);
|
|
185
|
+
}
|
|
186
|
+
/** Get the set of online identity IDs for a stream. */
|
|
187
|
+
get_online(streamId) {
|
|
188
|
+
const counts = this.streams.get(streamId);
|
|
189
|
+
return counts ? new Set(counts.keys()) : /* @__PURE__ */ new Set();
|
|
190
|
+
}
|
|
191
|
+
/** Check if a specific identity is online for a stream. */
|
|
192
|
+
is_online(streamId, identity_id) {
|
|
193
|
+
return (this.streams.get(streamId)?.get(identity_id) ?? 0) > 0;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
197
|
+
0 && (module.exports = {
|
|
198
|
+
BroadcastChannel,
|
|
199
|
+
PresenceTracker,
|
|
200
|
+
StateCache,
|
|
201
|
+
applyPatchMessage,
|
|
202
|
+
patch
|
|
203
|
+
});
|
|
204
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/apply-patch.ts","../src/broadcast.ts","../src/state-cache.ts","../src/presence.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * @module act-sse\n *\n * Incremental state broadcast over SSE for act event-sourced apps.\n *\n * Provides server-side broadcast with domain patch forwarding,\n * an LRU state cache, presence tracking, and a client-side\n * patch applicator with version validation and resync detection.\n *\n * ## Architecture\n *\n * ```\n * app.do() → snapshots (each carries its domain patch)\n * │\n * ▼\n * deriveState(snap) ← app-specific (overlay presence, deadlines, etc.)\n * state._v = snap.event.version\n * │\n * ▼\n * broadcast.publish(streamId, state, patches)\n * │\n * ├── version-key each patch: { [baseV+1]: patch1, [baseV+2]: patch2 }\n * └── push to all SSE subscribers\n * │\n * ▼\n * Client: applyPatchMessage(msg, cached)\n * │\n * ├── contiguous → deep-merge patches in version order\n * ├── stale → skip (client already ahead)\n * └── behind → resync (client missed versions)\n * ```\n *\n * ## Version Contract\n *\n * `_v` is always the event store stream version (`snap.event.version`).\n * No separate version counters. The event store is the single source of truth.\n */\n\nexport { patch } from \"@rotorsoft/act-patch\";\nexport type { ApplyResult } from \"./apply-patch.js\";\nexport { applyPatchMessage } from \"./apply-patch.js\";\nexport { BroadcastChannel } from \"./broadcast.js\";\nexport { PresenceTracker } from \"./presence.js\";\nexport { StateCache } from \"./state-cache.js\";\nexport type { BroadcastState, PatchMessage, Subscriber } from \"./types.js\";\n","import { patch as deep_merge } from \"@rotorsoft/act-patch\";\nimport type { BroadcastState, PatchMessage } from \"./types.js\";\n\n/**\n * Result of applying a patch message to cached client state.\n */\nexport type ApplyResult<S extends BroadcastState = BroadcastState> =\n | { ok: true; state: S }\n | { ok: false; reason: \"stale\" | \"behind\" };\n\n/**\n * Apply a version-keyed patch message to the client's cached state.\n *\n * ## Version logic\n *\n * - All patches older than cached → \"stale\" (client already ahead)\n * - Gap between cached version and first patch → \"behind\" (client missed versions, must resync)\n * - Contiguous from cached version → apply in order\n *\n * ## Usage (React Query)\n *\n * ```typescript\n * onData: (msg) => {\n * const cached = utils.get_state.get_data({ streamId });\n * const result = applyPatchMessage(msg, cached);\n * if (result.ok) {\n * utils.get_state.setData({ streamId }, result.state);\n * } else if (result.reason === \"behind\") {\n * utils.get_state.invalidate({ streamId }); // trigger full refetch\n * }\n * // \"stale\" → no-op, client already has newer state\n * }\n * ```\n */\nexport function applyPatchMessage<S extends BroadcastState>(\n msg: PatchMessage<S>,\n cached: S | null | undefined\n): ApplyResult<S> {\n const cachedV = cached?._v ?? 0;\n const versions = Object.keys(msg)\n .map(Number)\n .sort((a, b) => a - b);\n\n if (!versions.length) return { ok: false, reason: \"stale\" };\n\n const minV = versions[0];\n const maxV = versions[versions.length - 1];\n\n // All patches are older than what we have\n if (maxV <= cachedV) return { ok: false, reason: \"stale\" };\n // Gap — we missed versions\n if (!cached || minV > cachedV + 1) return { ok: false, reason: \"behind\" };\n\n // Apply patches in version order, skipping any we already have\n let state = cached;\n for (const v of versions) {\n if (v <= cachedV) continue; // already applied\n state = { ...deep_merge(state, msg[v]), _v: v } as S;\n }\n return { ok: true, state };\n}\n","import { patch as apply_patch } from \"@rotorsoft/act-patch\";\nimport { StateCache } from \"./state-cache.js\";\nimport type { BroadcastState, PatchMessage, Subscriber } from \"./types.js\";\n\n/**\n * Server-side broadcast channel for incremental state sync over SSE.\n *\n * Manages per-stream subscriber sets and an LRU state cache. When state\n * changes, forwards domain patches (from event handlers) to all subscribers\n * as version-keyed messages.\n *\n * ## Usage\n *\n * ```typescript\n * const broadcast = new BroadcastChannel<MyState>();\n *\n * // After every app.do():\n * const snaps = await app.do(...);\n * const patches = snaps.map(s => s.patch).filter(Boolean);\n * const state = deriveState(snaps.at(-1));\n * broadcast.publish(streamId, state, patches);\n *\n * // In SSE subscription:\n * const cleanup = broadcast.subscribe(streamId, (msg) => {\n * pending = msg;\n * resolve?.();\n * });\n *\n * // Initial state for reconnects:\n * const cached = broadcast.get_state(streamId);\n * ```\n *\n * ## Version Contract\n *\n * The `_v` field on state MUST be set from `snap.event.version` (the event\n * store's monotonic stream version) BEFORE calling `publish()`. This is the\n * single source of truth for ordering — no separate version counters.\n */\nexport class BroadcastChannel<S extends BroadcastState = BroadcastState> {\n private channels = new Map<string, Set<Subscriber<S>>>();\n private state_cache: StateCache<S>;\n\n constructor(options?: { cache_size?: number }) {\n this.state_cache = new StateCache<S>(options?.cache_size ?? 50);\n }\n\n /**\n * Publish domain patches from a commit.\n * patches[i] corresponds to version baseV + i + 1.\n *\n * @param streamId - The event store stream ID\n * @param state - Full state with `_v` set from `snap.event.version`\n * @param patches - Array of domain patches, one per emitted event\n */\n publish(\n streamId: string,\n state: S,\n patches: Partial<S>[] = []\n ): PatchMessage<S> {\n this.state_cache.set(streamId, state);\n\n const baseV = state._v - patches.length;\n const msg: PatchMessage<S> = {};\n patches.forEach((p, i) => {\n msg[baseV + i + 1] = p;\n });\n\n const subs = this.channels.get(streamId);\n if (subs?.size) {\n for (const cb of subs) cb(msg);\n }\n return msg;\n }\n\n /**\n * Publish a state update that doesn't change the event version\n * (e.g. presence overlay, computed field refresh).\n * Uses the same version as the cached state, single entry.\n */\n publish_overlay(\n streamId: string,\n overlay_patch: Partial<S>\n ): PatchMessage<S> | undefined {\n const prev = this.state_cache.get(streamId);\n if (!prev) return undefined;\n\n const state = apply_patch(prev, overlay_patch) as S;\n this.state_cache.set(streamId, state);\n\n const msg: PatchMessage<S> = { [state._v]: overlay_patch };\n const subs = this.channels.get(streamId);\n if (subs?.size) {\n for (const cb of subs) cb(msg);\n }\n return msg;\n }\n\n /**\n * Subscribe to broadcast messages for a stream.\n * Returns a cleanup function that removes the subscription.\n */\n subscribe(streamId: string, cb: Subscriber<S>): () => void {\n if (!this.channels.has(streamId)) this.channels.set(streamId, new Set());\n this.channels.get(streamId)!.add(cb);\n return () => {\n this.channels.get(streamId)?.delete(cb);\n if (this.channels.get(streamId)?.size === 0) {\n this.channels.delete(streamId);\n }\n };\n }\n\n /** Get the number of subscribers for a stream. */\n get_subscriber_count(streamId: string): number {\n return this.channels.get(streamId)?.size ?? 0;\n }\n\n /** Get the cached state for a stream (for reconnects / initial SSE yield). */\n get_state(streamId: string): S | undefined {\n return this.state_cache.get(streamId);\n }\n\n /** Direct access to the state cache (for app-specific reads like presence). */\n get cache(): StateCache<S> {\n return this.state_cache;\n }\n}\n","import type { BroadcastState } from \"./types.js\";\n\n/**\n * Generic LRU cache for aggregate state objects.\n *\n * Keyed by stream ID. Each entry stores the full state (with `_v` from the\n * event store). Used as the \"previous state\" baseline for computing patches,\n * and as the fast path for reconnects.\n *\n * The cache is shared between the broadcast hot path and read queries.\n * Projections should maintain their own cache to avoid double-apply bugs.\n */\nexport class StateCache<S extends BroadcastState = BroadcastState> {\n private cache = new Map<string, S>();\n private maxSize: number;\n\n constructor(maxSize = 50) {\n this.maxSize = maxSize;\n }\n\n /** Get a cached state, promoting it to MRU position. */\n get(key: string): S | undefined {\n const s = this.cache.get(key);\n if (s) {\n // Move to end (MRU)\n this.cache.delete(key);\n this.cache.set(key, s);\n }\n return s;\n }\n\n /** Set a cached state, evicting the LRU entry if at capacity. */\n set(key: string, state: S): void {\n this.cache.delete(key);\n this.cache.set(key, state);\n if (this.cache.size > this.maxSize) {\n // Size > max guarantees at least one entry exists\n this.cache.delete(this.cache.keys().next().value!);\n }\n }\n\n /** Remove a cached entry. */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /** Check if a key exists in the cache. */\n has(key: string): boolean {\n return this.cache.has(key);\n }\n\n /** Current number of cached entries. */\n get size(): number {\n return this.cache.size;\n }\n\n /** Direct access to the underlying map (for iteration). */\n entries(): IterableIterator<[string, S]> {\n return this.cache.entries();\n }\n}\n","/**\n * Generic presence tracker — ref-counted online status per stream per identity.\n *\n * Supports multi-tab: each subscribe increments the ref count, each\n * unsubscribe decrements it. An identity is considered online when\n * ref count > 0.\n *\n * ## Usage\n *\n * ```typescript\n * const presence = new PresenceTracker();\n *\n * // On SSE connect:\n * presence.add(game_id, player_id);\n *\n * // On SSE disconnect:\n * presence.remove(game_id, player_id);\n *\n * // Query:\n * presence.get_online(game_id); // Set<string>\n * ```\n */\nexport class PresenceTracker {\n private streams = new Map<string, Map<string, number>>();\n\n /** Increment ref count for an identity on a stream. */\n add(streamId: string, identity_id: string): void {\n if (!this.streams.has(streamId)) this.streams.set(streamId, new Map());\n const counts = this.streams.get(streamId)!;\n counts.set(identity_id, (counts.get(identity_id) ?? 0) + 1);\n }\n\n /** Decrement ref count. Removes the identity when count reaches 0. */\n remove(streamId: string, identity_id: string): void {\n const counts = this.streams.get(streamId);\n if (!counts) return;\n const n = (counts.get(identity_id) ?? 1) - 1;\n if (n <= 0) counts.delete(identity_id);\n else counts.set(identity_id, n);\n if (counts.size === 0) this.streams.delete(streamId);\n }\n\n /** Get the set of online identity IDs for a stream. */\n get_online(streamId: string): Set<string> {\n const counts = this.streams.get(streamId);\n return counts ? new Set(counts.keys()) : new Set();\n }\n\n /** Check if a specific identity is online for a stream. */\n is_online(streamId: string, identity_id: string): boolean {\n return (this.streams.get(streamId)?.get(identity_id) ?? 0) > 0;\n }\n}\n"],"mappings":"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","names":["import_act_patch","deep_merge","import_act_patch","apply_patch"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { patch } from "@rotorsoft/act-patch";
|
|
3
|
+
|
|
4
|
+
// src/apply-patch.ts
|
|
5
|
+
import { patch as deep_merge } from "@rotorsoft/act-patch";
|
|
6
|
+
function applyPatchMessage(msg, cached) {
|
|
7
|
+
const cachedV = cached?._v ?? 0;
|
|
8
|
+
const versions = Object.keys(msg).map(Number).sort((a, b) => a - b);
|
|
9
|
+
if (!versions.length) return { ok: false, reason: "stale" };
|
|
10
|
+
const minV = versions[0];
|
|
11
|
+
const maxV = versions[versions.length - 1];
|
|
12
|
+
if (maxV <= cachedV) return { ok: false, reason: "stale" };
|
|
13
|
+
if (!cached || minV > cachedV + 1) return { ok: false, reason: "behind" };
|
|
14
|
+
let state = cached;
|
|
15
|
+
for (const v of versions) {
|
|
16
|
+
if (v <= cachedV) continue;
|
|
17
|
+
state = { ...deep_merge(state, msg[v]), _v: v };
|
|
18
|
+
}
|
|
19
|
+
return { ok: true, state };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/broadcast.ts
|
|
23
|
+
import { patch as apply_patch } from "@rotorsoft/act-patch";
|
|
24
|
+
|
|
25
|
+
// src/state-cache.ts
|
|
26
|
+
var StateCache = class {
|
|
27
|
+
cache = /* @__PURE__ */ new Map();
|
|
28
|
+
maxSize;
|
|
29
|
+
constructor(maxSize = 50) {
|
|
30
|
+
this.maxSize = maxSize;
|
|
31
|
+
}
|
|
32
|
+
/** Get a cached state, promoting it to MRU position. */
|
|
33
|
+
get(key) {
|
|
34
|
+
const s = this.cache.get(key);
|
|
35
|
+
if (s) {
|
|
36
|
+
this.cache.delete(key);
|
|
37
|
+
this.cache.set(key, s);
|
|
38
|
+
}
|
|
39
|
+
return s;
|
|
40
|
+
}
|
|
41
|
+
/** Set a cached state, evicting the LRU entry if at capacity. */
|
|
42
|
+
set(key, state) {
|
|
43
|
+
this.cache.delete(key);
|
|
44
|
+
this.cache.set(key, state);
|
|
45
|
+
if (this.cache.size > this.maxSize) {
|
|
46
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Remove a cached entry. */
|
|
50
|
+
delete(key) {
|
|
51
|
+
this.cache.delete(key);
|
|
52
|
+
}
|
|
53
|
+
/** Check if a key exists in the cache. */
|
|
54
|
+
has(key) {
|
|
55
|
+
return this.cache.has(key);
|
|
56
|
+
}
|
|
57
|
+
/** Current number of cached entries. */
|
|
58
|
+
get size() {
|
|
59
|
+
return this.cache.size;
|
|
60
|
+
}
|
|
61
|
+
/** Direct access to the underlying map (for iteration). */
|
|
62
|
+
entries() {
|
|
63
|
+
return this.cache.entries();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/broadcast.ts
|
|
68
|
+
var BroadcastChannel = class {
|
|
69
|
+
channels = /* @__PURE__ */ new Map();
|
|
70
|
+
state_cache;
|
|
71
|
+
constructor(options) {
|
|
72
|
+
this.state_cache = new StateCache(options?.cache_size ?? 50);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Publish domain patches from a commit.
|
|
76
|
+
* patches[i] corresponds to version baseV + i + 1.
|
|
77
|
+
*
|
|
78
|
+
* @param streamId - The event store stream ID
|
|
79
|
+
* @param state - Full state with `_v` set from `snap.event.version`
|
|
80
|
+
* @param patches - Array of domain patches, one per emitted event
|
|
81
|
+
*/
|
|
82
|
+
publish(streamId, state, patches = []) {
|
|
83
|
+
this.state_cache.set(streamId, state);
|
|
84
|
+
const baseV = state._v - patches.length;
|
|
85
|
+
const msg = {};
|
|
86
|
+
patches.forEach((p, i) => {
|
|
87
|
+
msg[baseV + i + 1] = p;
|
|
88
|
+
});
|
|
89
|
+
const subs = this.channels.get(streamId);
|
|
90
|
+
if (subs?.size) {
|
|
91
|
+
for (const cb of subs) cb(msg);
|
|
92
|
+
}
|
|
93
|
+
return msg;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Publish a state update that doesn't change the event version
|
|
97
|
+
* (e.g. presence overlay, computed field refresh).
|
|
98
|
+
* Uses the same version as the cached state, single entry.
|
|
99
|
+
*/
|
|
100
|
+
publish_overlay(streamId, overlay_patch) {
|
|
101
|
+
const prev = this.state_cache.get(streamId);
|
|
102
|
+
if (!prev) return void 0;
|
|
103
|
+
const state = apply_patch(prev, overlay_patch);
|
|
104
|
+
this.state_cache.set(streamId, state);
|
|
105
|
+
const msg = { [state._v]: overlay_patch };
|
|
106
|
+
const subs = this.channels.get(streamId);
|
|
107
|
+
if (subs?.size) {
|
|
108
|
+
for (const cb of subs) cb(msg);
|
|
109
|
+
}
|
|
110
|
+
return msg;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Subscribe to broadcast messages for a stream.
|
|
114
|
+
* Returns a cleanup function that removes the subscription.
|
|
115
|
+
*/
|
|
116
|
+
subscribe(streamId, cb) {
|
|
117
|
+
if (!this.channels.has(streamId)) this.channels.set(streamId, /* @__PURE__ */ new Set());
|
|
118
|
+
this.channels.get(streamId).add(cb);
|
|
119
|
+
return () => {
|
|
120
|
+
this.channels.get(streamId)?.delete(cb);
|
|
121
|
+
if (this.channels.get(streamId)?.size === 0) {
|
|
122
|
+
this.channels.delete(streamId);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Get the number of subscribers for a stream. */
|
|
127
|
+
get_subscriber_count(streamId) {
|
|
128
|
+
return this.channels.get(streamId)?.size ?? 0;
|
|
129
|
+
}
|
|
130
|
+
/** Get the cached state for a stream (for reconnects / initial SSE yield). */
|
|
131
|
+
get_state(streamId) {
|
|
132
|
+
return this.state_cache.get(streamId);
|
|
133
|
+
}
|
|
134
|
+
/** Direct access to the state cache (for app-specific reads like presence). */
|
|
135
|
+
get cache() {
|
|
136
|
+
return this.state_cache;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// src/presence.ts
|
|
141
|
+
var PresenceTracker = class {
|
|
142
|
+
streams = /* @__PURE__ */ new Map();
|
|
143
|
+
/** Increment ref count for an identity on a stream. */
|
|
144
|
+
add(streamId, identity_id) {
|
|
145
|
+
if (!this.streams.has(streamId)) this.streams.set(streamId, /* @__PURE__ */ new Map());
|
|
146
|
+
const counts = this.streams.get(streamId);
|
|
147
|
+
counts.set(identity_id, (counts.get(identity_id) ?? 0) + 1);
|
|
148
|
+
}
|
|
149
|
+
/** Decrement ref count. Removes the identity when count reaches 0. */
|
|
150
|
+
remove(streamId, identity_id) {
|
|
151
|
+
const counts = this.streams.get(streamId);
|
|
152
|
+
if (!counts) return;
|
|
153
|
+
const n = (counts.get(identity_id) ?? 1) - 1;
|
|
154
|
+
if (n <= 0) counts.delete(identity_id);
|
|
155
|
+
else counts.set(identity_id, n);
|
|
156
|
+
if (counts.size === 0) this.streams.delete(streamId);
|
|
157
|
+
}
|
|
158
|
+
/** Get the set of online identity IDs for a stream. */
|
|
159
|
+
get_online(streamId) {
|
|
160
|
+
const counts = this.streams.get(streamId);
|
|
161
|
+
return counts ? new Set(counts.keys()) : /* @__PURE__ */ new Set();
|
|
162
|
+
}
|
|
163
|
+
/** Check if a specific identity is online for a stream. */
|
|
164
|
+
is_online(streamId, identity_id) {
|
|
165
|
+
return (this.streams.get(streamId)?.get(identity_id) ?? 0) > 0;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
export {
|
|
169
|
+
BroadcastChannel,
|
|
170
|
+
PresenceTracker,
|
|
171
|
+
StateCache,
|
|
172
|
+
applyPatchMessage,
|
|
173
|
+
patch
|
|
174
|
+
};
|
|
175
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/apply-patch.ts","../src/broadcast.ts","../src/state-cache.ts","../src/presence.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * @module act-sse\n *\n * Incremental state broadcast over SSE for act event-sourced apps.\n *\n * Provides server-side broadcast with domain patch forwarding,\n * an LRU state cache, presence tracking, and a client-side\n * patch applicator with version validation and resync detection.\n *\n * ## Architecture\n *\n * ```\n * app.do() → snapshots (each carries its domain patch)\n * │\n * ▼\n * deriveState(snap) ← app-specific (overlay presence, deadlines, etc.)\n * state._v = snap.event.version\n * │\n * ▼\n * broadcast.publish(streamId, state, patches)\n * │\n * ├── version-key each patch: { [baseV+1]: patch1, [baseV+2]: patch2 }\n * └── push to all SSE subscribers\n * │\n * ▼\n * Client: applyPatchMessage(msg, cached)\n * │\n * ├── contiguous → deep-merge patches in version order\n * ├── stale → skip (client already ahead)\n * └── behind → resync (client missed versions)\n * ```\n *\n * ## Version Contract\n *\n * `_v` is always the event store stream version (`snap.event.version`).\n * No separate version counters. The event store is the single source of truth.\n */\n\nexport { patch } from \"@rotorsoft/act-patch\";\nexport type { ApplyResult } from \"./apply-patch.js\";\nexport { applyPatchMessage } from \"./apply-patch.js\";\nexport { BroadcastChannel } from \"./broadcast.js\";\nexport { PresenceTracker } from \"./presence.js\";\nexport { StateCache } from \"./state-cache.js\";\nexport type { BroadcastState, PatchMessage, Subscriber } from \"./types.js\";\n","import { patch as deep_merge } from \"@rotorsoft/act-patch\";\nimport type { BroadcastState, PatchMessage } from \"./types.js\";\n\n/**\n * Result of applying a patch message to cached client state.\n */\nexport type ApplyResult<S extends BroadcastState = BroadcastState> =\n | { ok: true; state: S }\n | { ok: false; reason: \"stale\" | \"behind\" };\n\n/**\n * Apply a version-keyed patch message to the client's cached state.\n *\n * ## Version logic\n *\n * - All patches older than cached → \"stale\" (client already ahead)\n * - Gap between cached version and first patch → \"behind\" (client missed versions, must resync)\n * - Contiguous from cached version → apply in order\n *\n * ## Usage (React Query)\n *\n * ```typescript\n * onData: (msg) => {\n * const cached = utils.get_state.get_data({ streamId });\n * const result = applyPatchMessage(msg, cached);\n * if (result.ok) {\n * utils.get_state.setData({ streamId }, result.state);\n * } else if (result.reason === \"behind\") {\n * utils.get_state.invalidate({ streamId }); // trigger full refetch\n * }\n * // \"stale\" → no-op, client already has newer state\n * }\n * ```\n */\nexport function applyPatchMessage<S extends BroadcastState>(\n msg: PatchMessage<S>,\n cached: S | null | undefined\n): ApplyResult<S> {\n const cachedV = cached?._v ?? 0;\n const versions = Object.keys(msg)\n .map(Number)\n .sort((a, b) => a - b);\n\n if (!versions.length) return { ok: false, reason: \"stale\" };\n\n const minV = versions[0];\n const maxV = versions[versions.length - 1];\n\n // All patches are older than what we have\n if (maxV <= cachedV) return { ok: false, reason: \"stale\" };\n // Gap — we missed versions\n if (!cached || minV > cachedV + 1) return { ok: false, reason: \"behind\" };\n\n // Apply patches in version order, skipping any we already have\n let state = cached;\n for (const v of versions) {\n if (v <= cachedV) continue; // already applied\n state = { ...deep_merge(state, msg[v]), _v: v } as S;\n }\n return { ok: true, state };\n}\n","import { patch as apply_patch } from \"@rotorsoft/act-patch\";\nimport { StateCache } from \"./state-cache.js\";\nimport type { BroadcastState, PatchMessage, Subscriber } from \"./types.js\";\n\n/**\n * Server-side broadcast channel for incremental state sync over SSE.\n *\n * Manages per-stream subscriber sets and an LRU state cache. When state\n * changes, forwards domain patches (from event handlers) to all subscribers\n * as version-keyed messages.\n *\n * ## Usage\n *\n * ```typescript\n * const broadcast = new BroadcastChannel<MyState>();\n *\n * // After every app.do():\n * const snaps = await app.do(...);\n * const patches = snaps.map(s => s.patch).filter(Boolean);\n * const state = deriveState(snaps.at(-1));\n * broadcast.publish(streamId, state, patches);\n *\n * // In SSE subscription:\n * const cleanup = broadcast.subscribe(streamId, (msg) => {\n * pending = msg;\n * resolve?.();\n * });\n *\n * // Initial state for reconnects:\n * const cached = broadcast.get_state(streamId);\n * ```\n *\n * ## Version Contract\n *\n * The `_v` field on state MUST be set from `snap.event.version` (the event\n * store's monotonic stream version) BEFORE calling `publish()`. This is the\n * single source of truth for ordering — no separate version counters.\n */\nexport class BroadcastChannel<S extends BroadcastState = BroadcastState> {\n private channels = new Map<string, Set<Subscriber<S>>>();\n private state_cache: StateCache<S>;\n\n constructor(options?: { cache_size?: number }) {\n this.state_cache = new StateCache<S>(options?.cache_size ?? 50);\n }\n\n /**\n * Publish domain patches from a commit.\n * patches[i] corresponds to version baseV + i + 1.\n *\n * @param streamId - The event store stream ID\n * @param state - Full state with `_v` set from `snap.event.version`\n * @param patches - Array of domain patches, one per emitted event\n */\n publish(\n streamId: string,\n state: S,\n patches: Partial<S>[] = []\n ): PatchMessage<S> {\n this.state_cache.set(streamId, state);\n\n const baseV = state._v - patches.length;\n const msg: PatchMessage<S> = {};\n patches.forEach((p, i) => {\n msg[baseV + i + 1] = p;\n });\n\n const subs = this.channels.get(streamId);\n if (subs?.size) {\n for (const cb of subs) cb(msg);\n }\n return msg;\n }\n\n /**\n * Publish a state update that doesn't change the event version\n * (e.g. presence overlay, computed field refresh).\n * Uses the same version as the cached state, single entry.\n */\n publish_overlay(\n streamId: string,\n overlay_patch: Partial<S>\n ): PatchMessage<S> | undefined {\n const prev = this.state_cache.get(streamId);\n if (!prev) return undefined;\n\n const state = apply_patch(prev, overlay_patch) as S;\n this.state_cache.set(streamId, state);\n\n const msg: PatchMessage<S> = { [state._v]: overlay_patch };\n const subs = this.channels.get(streamId);\n if (subs?.size) {\n for (const cb of subs) cb(msg);\n }\n return msg;\n }\n\n /**\n * Subscribe to broadcast messages for a stream.\n * Returns a cleanup function that removes the subscription.\n */\n subscribe(streamId: string, cb: Subscriber<S>): () => void {\n if (!this.channels.has(streamId)) this.channels.set(streamId, new Set());\n this.channels.get(streamId)!.add(cb);\n return () => {\n this.channels.get(streamId)?.delete(cb);\n if (this.channels.get(streamId)?.size === 0) {\n this.channels.delete(streamId);\n }\n };\n }\n\n /** Get the number of subscribers for a stream. */\n get_subscriber_count(streamId: string): number {\n return this.channels.get(streamId)?.size ?? 0;\n }\n\n /** Get the cached state for a stream (for reconnects / initial SSE yield). */\n get_state(streamId: string): S | undefined {\n return this.state_cache.get(streamId);\n }\n\n /** Direct access to the state cache (for app-specific reads like presence). */\n get cache(): StateCache<S> {\n return this.state_cache;\n }\n}\n","import type { BroadcastState } from \"./types.js\";\n\n/**\n * Generic LRU cache for aggregate state objects.\n *\n * Keyed by stream ID. Each entry stores the full state (with `_v` from the\n * event store). Used as the \"previous state\" baseline for computing patches,\n * and as the fast path for reconnects.\n *\n * The cache is shared between the broadcast hot path and read queries.\n * Projections should maintain their own cache to avoid double-apply bugs.\n */\nexport class StateCache<S extends BroadcastState = BroadcastState> {\n private cache = new Map<string, S>();\n private maxSize: number;\n\n constructor(maxSize = 50) {\n this.maxSize = maxSize;\n }\n\n /** Get a cached state, promoting it to MRU position. */\n get(key: string): S | undefined {\n const s = this.cache.get(key);\n if (s) {\n // Move to end (MRU)\n this.cache.delete(key);\n this.cache.set(key, s);\n }\n return s;\n }\n\n /** Set a cached state, evicting the LRU entry if at capacity. */\n set(key: string, state: S): void {\n this.cache.delete(key);\n this.cache.set(key, state);\n if (this.cache.size > this.maxSize) {\n // Size > max guarantees at least one entry exists\n this.cache.delete(this.cache.keys().next().value!);\n }\n }\n\n /** Remove a cached entry. */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /** Check if a key exists in the cache. */\n has(key: string): boolean {\n return this.cache.has(key);\n }\n\n /** Current number of cached entries. */\n get size(): number {\n return this.cache.size;\n }\n\n /** Direct access to the underlying map (for iteration). */\n entries(): IterableIterator<[string, S]> {\n return this.cache.entries();\n }\n}\n","/**\n * Generic presence tracker — ref-counted online status per stream per identity.\n *\n * Supports multi-tab: each subscribe increments the ref count, each\n * unsubscribe decrements it. An identity is considered online when\n * ref count > 0.\n *\n * ## Usage\n *\n * ```typescript\n * const presence = new PresenceTracker();\n *\n * // On SSE connect:\n * presence.add(game_id, player_id);\n *\n * // On SSE disconnect:\n * presence.remove(game_id, player_id);\n *\n * // Query:\n * presence.get_online(game_id); // Set<string>\n * ```\n */\nexport class PresenceTracker {\n private streams = new Map<string, Map<string, number>>();\n\n /** Increment ref count for an identity on a stream. */\n add(streamId: string, identity_id: string): void {\n if (!this.streams.has(streamId)) this.streams.set(streamId, new Map());\n const counts = this.streams.get(streamId)!;\n counts.set(identity_id, (counts.get(identity_id) ?? 0) + 1);\n }\n\n /** Decrement ref count. Removes the identity when count reaches 0. */\n remove(streamId: string, identity_id: string): void {\n const counts = this.streams.get(streamId);\n if (!counts) return;\n const n = (counts.get(identity_id) ?? 1) - 1;\n if (n <= 0) counts.delete(identity_id);\n else counts.set(identity_id, n);\n if (counts.size === 0) this.streams.delete(streamId);\n }\n\n /** Get the set of online identity IDs for a stream. */\n get_online(streamId: string): Set<string> {\n const counts = this.streams.get(streamId);\n return counts ? new Set(counts.keys()) : new Set();\n }\n\n /** Check if a specific identity is online for a stream. */\n is_online(streamId: string, identity_id: string): boolean {\n return (this.streams.get(streamId)?.get(identity_id) ?? 0) > 0;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rotorsoft/act-sse",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.4",
|
|
5
5
|
"description": "Incremental state broadcast over SSE for act apps",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"typescript",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"url": "git+https://github.com/rotorsoft/act-root.git",
|
|
18
18
|
"directory": "libs/act-sse"
|
|
19
19
|
},
|
|
20
|
+
"homepage": "https://github.com/rotorsoft/act-root/tree/master/libs/act-sse#readme",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/rotorsoft/act-root/issues"
|
|
23
|
+
},
|
|
20
24
|
"files": [
|
|
21
25
|
"dist"
|
|
22
26
|
],
|
|
@@ -32,13 +36,13 @@
|
|
|
32
36
|
},
|
|
33
37
|
"sideEffects": false,
|
|
34
38
|
"engines": {
|
|
35
|
-
"node": ">=22.
|
|
39
|
+
"node": ">=22.22.3"
|
|
36
40
|
},
|
|
37
41
|
"publishConfig": {
|
|
38
42
|
"access": "public"
|
|
39
43
|
},
|
|
40
44
|
"dependencies": {
|
|
41
|
-
"@rotorsoft/act-patch": "^1.2.
|
|
45
|
+
"@rotorsoft/act-patch": "^1.2.4"
|
|
42
46
|
},
|
|
43
47
|
"scripts": {
|
|
44
48
|
"clean": "rm -rf dist",
|