@scenetest/dashboard 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +87 -35
  2. package/dist/app.d.ts +10 -7
  3. package/dist/app.d.ts.map +1 -1
  4. package/dist/app.js +12 -130
  5. package/dist/app.js.map +1 -1
  6. package/dist/collections/index.d.ts +19 -0
  7. package/dist/collections/index.d.ts.map +1 -0
  8. package/dist/collections/index.js +18 -0
  9. package/dist/collections/index.js.map +1 -0
  10. package/dist/collections/options.d.ts +29 -0
  11. package/dist/collections/options.d.ts.map +1 -0
  12. package/dist/collections/options.js +68 -0
  13. package/dist/collections/options.js.map +1 -0
  14. package/dist/collections/projections.d.ts +117 -0
  15. package/dist/collections/projections.d.ts.map +1 -0
  16. package/dist/collections/projections.js +228 -0
  17. package/dist/collections/projections.js.map +1 -0
  18. package/dist/collections/source.d.ts +32 -0
  19. package/dist/collections/source.d.ts.map +1 -0
  20. package/dist/collections/source.js +84 -0
  21. package/dist/collections/source.js.map +1 -0
  22. package/dist/collections/types.d.ts +87 -0
  23. package/dist/collections/types.d.ts.map +1 -0
  24. package/dist/collections/types.js +2 -0
  25. package/dist/collections/types.js.map +1 -0
  26. package/dist/dashboard.d.ts +20 -0
  27. package/dist/dashboard.d.ts.map +1 -0
  28. package/dist/dashboard.js +114 -0
  29. package/dist/dashboard.js.map +1 -0
  30. package/dist/dev-transport.d.ts +3 -3
  31. package/dist/dev-transport.d.ts.map +1 -1
  32. package/dist/dev-transport.js +3 -7
  33. package/dist/dev-transport.js.map +1 -1
  34. package/dist/index.d.ts +6 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +4 -2
  37. package/dist/index.js.map +1 -1
  38. package/dist/runner.d.ts +8 -0
  39. package/dist/runner.d.ts.map +1 -0
  40. package/dist/runner.js +249 -0
  41. package/dist/runner.js.map +1 -0
  42. package/dist/select-helpers.d.ts +50 -0
  43. package/dist/select-helpers.d.ts.map +1 -0
  44. package/dist/select-helpers.js +48 -0
  45. package/dist/select-helpers.js.map +1 -0
  46. package/dist/select-runner.d.ts +55 -0
  47. package/dist/select-runner.d.ts.map +1 -0
  48. package/dist/select-runner.js +108 -0
  49. package/dist/select-runner.js.map +1 -0
  50. package/dist/select-waterfall.d.ts +12 -0
  51. package/dist/select-waterfall.d.ts.map +1 -0
  52. package/dist/select-waterfall.js +79 -0
  53. package/dist/select-waterfall.js.map +1 -0
  54. package/dist/style.css +878 -0
  55. package/dist/types.d.ts +6 -20
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/use-live-query.d.ts +28 -0
  58. package/dist/use-live-query.d.ts.map +1 -0
  59. package/dist/use-live-query.js +25 -0
  60. package/dist/use-live-query.js.map +1 -0
  61. package/dist/use-run-slice.d.ts +25 -0
  62. package/dist/use-run-slice.d.ts.map +1 -0
  63. package/dist/use-run-slice.js +48 -0
  64. package/dist/use-run-slice.js.map +1 -0
  65. package/package.json +10 -5
  66. package/dist/mount.d.ts +0 -14
  67. package/dist/mount.d.ts.map +0 -1
  68. package/dist/mount.js +0 -50
  69. package/dist/mount.js.map +0 -1
  70. package/dist/store.d.ts +0 -19
  71. package/dist/store.d.ts.map +0 -1
  72. package/dist/store.js +0 -164
  73. package/dist/store.js.map +0 -1
  74. package/dist/styles.d.ts +0 -10
  75. package/dist/styles.d.ts.map +0 -1
  76. package/dist/styles.js +0 -152
  77. package/dist/styles.js.map +0 -1
@@ -0,0 +1,117 @@
1
+ import type { TeamMeta } from '@scenetest/protocol';
2
+ import type { RunProjection } from './types.js';
3
+ /**
4
+ * Every event carries its own `runId` (producers stamp it; see
5
+ * `@scenetest/protocol`). Rows from every run of a PR live in one collection,
6
+ * partitioned by that id, so the picker / rollups / flaky detection are
7
+ * queries over the rows rather than separate fetches. A new `run:start` opens
8
+ * a new partition — it does **not** truncate (that was the single-run
9
+ * behaviour; see `docs/public/design/unified-console.md`). Because the id is
10
+ * on the event, projections are stateless and a collection can attach
11
+ * mid-stream without having seen the run's `run:start`.
12
+ */
13
+ /**
14
+ * Derived current-state of one scene, scoped to its run. Folded from a
15
+ * scene's `scene:start` / `scene:end` pair. The live timeline is
16
+ * `where runId = <latest>`.
17
+ */
18
+ export interface SceneRow {
19
+ /** `${runId}:${teamIndex}:${name}` — stable across the scene's start/end. */
20
+ id: string;
21
+ runId: string;
22
+ name: string;
23
+ file: string;
24
+ actors: string[];
25
+ status: 'running' | 'completed' | 'failed' | 'timeout' | string;
26
+ startTime: number;
27
+ endTime: number | null;
28
+ duration: number | null;
29
+ error: string | null;
30
+ team: TeamMeta;
31
+ teamIndex: number;
32
+ }
33
+ export declare function scenesProjection(): RunProjection<SceneRow, string>;
34
+ /**
35
+ * One row per inline assertion — the append-only end of the stream, scoped
36
+ * to its run. Keyed by `${runId}:${n}` (a per-projection monotonic index;
37
+ * the stream carries no assertion id).
38
+ *
39
+ * `sceneId` is the owning scene's {@link SceneRow.id} when the producer stamped
40
+ * `scene`/`teamIndex` on the event (the precise path); it's `null` for runs
41
+ * recorded before producers did so, where the consumer attributes by
42
+ * actor+time-window instead (see {@link attributeToScene}).
43
+ */
44
+ export interface AssertionRecord {
45
+ id: string;
46
+ runId: string;
47
+ actor: string | null;
48
+ description: string;
49
+ result: boolean;
50
+ timestamp: number;
51
+ sceneId: string | null;
52
+ }
53
+ export declare function assertionsProjection(): RunProjection<AssertionRecord, string>;
54
+ /**
55
+ * Attribute an event row to a scene. Prefers the stamped `sceneId` (precise,
56
+ * concurrency-safe); falls back to actor + time-window for rows from older
57
+ * producers: the scene of the same run whose `actors` include `actor` and
58
+ * whose `[startTime, endTime]` window contains `timestamp`. The window is
59
+ * open-ended while a scene is still running (`endTime === null`). Returns the
60
+ * matching scene's id, or `null` when nothing attributes (e.g. an actor-less
61
+ * inline assertion on an old run).
62
+ */
63
+ export declare function attributeToScene(row: {
64
+ sceneId: string | null;
65
+ runId: string;
66
+ actor: string | null;
67
+ timestamp: number;
68
+ }, scenes: Iterable<SceneRow>): string | null;
69
+ /**
70
+ * One row per DSL action, paired from its `action:start` / `action:end`. The
71
+ * projection mints an id on start and updates the same row on end, tracking
72
+ * open actions per `actor+action` (the stream carries no action id). `sceneId`
73
+ * comes from a stamped `scene`/`teamIndex` on the start event when present;
74
+ * otherwise the consumer attributes by actor+time-window like assertions.
75
+ */
76
+ export interface ActionRecord {
77
+ id: string;
78
+ runId: string;
79
+ actor: string;
80
+ action: string;
81
+ target: string | null;
82
+ startTime: number;
83
+ endTime: number | null;
84
+ duration: number | null;
85
+ error: string | null;
86
+ status: 'running' | 'success' | 'error';
87
+ sceneId: string | null;
88
+ /** Start timestamp — the time used for actor+time-window attribution. */
89
+ timestamp: number;
90
+ }
91
+ export declare function actionsProjection(): RunProjection<ActionRecord, string>;
92
+ /**
93
+ * One row per run — the picker, the "most recent" rollup, and (later) flaky
94
+ * detection are all live queries over this table. Folded from `run:start`
95
+ * (insert), `scene:end` (incremental pass/fail counts so the rollup is live),
96
+ * and `run:end` (authoritative counts + duration from the summary).
97
+ *
98
+ * `pr` / `branch` are stamped by the report loader from the filename
99
+ * (`pr-{num}-{timestamp}-…`), not the event stream, so they're absent for a
100
+ * live local run.
101
+ */
102
+ export interface RunRow {
103
+ /** runId — the `run:start` timestamp. */
104
+ id: string;
105
+ startTime: number;
106
+ endTime: number | null;
107
+ duration: number | null;
108
+ status: 'running' | 'finished' | string;
109
+ /** Expected scene count from `run:start`. */
110
+ sceneCount: number;
111
+ completed: number;
112
+ failed: number;
113
+ pr?: number;
114
+ branch?: string;
115
+ }
116
+ export declare function runsProjection(): RunProjection<RunRow, string>;
117
+ //# sourceMappingURL=projections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projections.d.ts","sourceRoot":"","sources":["../../src/collections/projections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,228 @@
1
+ function sceneKey(runId, teamIndex, name) {
2
+ return `${runId}:${teamIndex}:${name}`;
3
+ }
4
+ export function scenesProjection() {
5
+ return {
6
+ id: 'scenes',
7
+ getKey: (row) => row.id,
8
+ project(event, get) {
9
+ switch (event.type) {
10
+ case 'scene:start': {
11
+ const row = {
12
+ id: sceneKey(event.runId, event.teamIndex, event.name),
13
+ runId: event.runId,
14
+ name: event.name,
15
+ file: event.file,
16
+ actors: event.actors.slice(),
17
+ status: 'running',
18
+ startTime: event.timestamp,
19
+ endTime: null,
20
+ duration: null,
21
+ error: null,
22
+ team: event.team,
23
+ teamIndex: event.teamIndex,
24
+ };
25
+ return [{ type: 'insert', value: row }];
26
+ }
27
+ case 'scene:end': {
28
+ const prev = get(sceneKey(event.runId, event.teamIndex, event.name));
29
+ if (!prev)
30
+ return [];
31
+ return [
32
+ {
33
+ type: 'update',
34
+ value: {
35
+ ...prev,
36
+ status: event.status,
37
+ endTime: event.timestamp,
38
+ duration: event.duration,
39
+ error: event.error ?? null,
40
+ },
41
+ },
42
+ ];
43
+ }
44
+ default:
45
+ return [];
46
+ }
47
+ },
48
+ };
49
+ }
50
+ export function assertionsProjection() {
51
+ let next = 0;
52
+ return {
53
+ id: 'assertions',
54
+ getKey: (row) => row.id,
55
+ project(event) {
56
+ if (event.type === 'assertion') {
57
+ return [
58
+ {
59
+ type: 'insert',
60
+ value: {
61
+ id: `${event.runId}:${next++}`,
62
+ runId: event.runId,
63
+ actor: event.actor ?? null,
64
+ description: event.description,
65
+ result: event.result,
66
+ timestamp: event.timestamp,
67
+ sceneId: event.scene !== undefined && event.teamIndex !== undefined
68
+ ? sceneKey(event.runId, event.teamIndex, event.scene)
69
+ : null,
70
+ },
71
+ },
72
+ ];
73
+ }
74
+ return [];
75
+ },
76
+ };
77
+ }
78
+ /**
79
+ * Attribute an event row to a scene. Prefers the stamped `sceneId` (precise,
80
+ * concurrency-safe); falls back to actor + time-window for rows from older
81
+ * producers: the scene of the same run whose `actors` include `actor` and
82
+ * whose `[startTime, endTime]` window contains `timestamp`. The window is
83
+ * open-ended while a scene is still running (`endTime === null`). Returns the
84
+ * matching scene's id, or `null` when nothing attributes (e.g. an actor-less
85
+ * inline assertion on an old run).
86
+ */
87
+ export function attributeToScene(row, scenes) {
88
+ if (row.sceneId)
89
+ return row.sceneId;
90
+ if (!row.actor)
91
+ return null;
92
+ for (const scene of scenes) {
93
+ if (scene.runId !== row.runId)
94
+ continue;
95
+ if (!scene.actors.includes(row.actor))
96
+ continue;
97
+ if (row.timestamp < scene.startTime)
98
+ continue;
99
+ if (scene.endTime !== null && row.timestamp > scene.endTime)
100
+ continue;
101
+ return scene.id;
102
+ }
103
+ return null;
104
+ }
105
+ export function actionsProjection() {
106
+ let next = 0;
107
+ const open = new Map();
108
+ const openKey = (actor, action) => JSON.stringify([actor, action]);
109
+ return {
110
+ id: 'actions',
111
+ getKey: (row) => row.id,
112
+ project(event, get) {
113
+ if (event.type === 'action:start') {
114
+ const id = `${event.runId}:${next++}`;
115
+ open.set(openKey(event.actor, event.action), id);
116
+ const sceneId = event.scene !== undefined && event.teamIndex !== undefined
117
+ ? sceneKey(event.runId, event.teamIndex, event.scene)
118
+ : null;
119
+ return [
120
+ {
121
+ type: 'insert',
122
+ value: {
123
+ id,
124
+ runId: event.runId,
125
+ actor: event.actor,
126
+ action: event.action,
127
+ target: event.target ?? null,
128
+ startTime: event.timestamp,
129
+ endTime: null,
130
+ duration: null,
131
+ error: null,
132
+ status: 'running',
133
+ sceneId,
134
+ timestamp: event.timestamp,
135
+ },
136
+ },
137
+ ];
138
+ }
139
+ if (event.type === 'action:end') {
140
+ const key = openKey(event.actor, event.action);
141
+ const id = open.get(key);
142
+ if (id === undefined)
143
+ return [];
144
+ open.delete(key);
145
+ const prev = get(id);
146
+ if (!prev)
147
+ return [];
148
+ return [
149
+ {
150
+ type: 'update',
151
+ value: {
152
+ ...prev,
153
+ endTime: event.timestamp,
154
+ duration: event.duration,
155
+ error: event.error ?? null,
156
+ status: event.error ? 'error' : 'success',
157
+ },
158
+ },
159
+ ];
160
+ }
161
+ return [];
162
+ },
163
+ };
164
+ }
165
+ export function runsProjection() {
166
+ return {
167
+ id: 'runs',
168
+ getKey: (row) => row.id,
169
+ project(event, get) {
170
+ switch (event.type) {
171
+ case 'run:start': {
172
+ return [
173
+ {
174
+ type: 'insert',
175
+ value: {
176
+ id: event.runId,
177
+ startTime: event.timestamp,
178
+ endTime: null,
179
+ duration: null,
180
+ status: 'running',
181
+ sceneCount: event.sceneCount,
182
+ completed: 0,
183
+ failed: 0,
184
+ },
185
+ },
186
+ ];
187
+ }
188
+ case 'scene:end': {
189
+ const prev = get(event.runId);
190
+ if (!prev)
191
+ return [];
192
+ const passed = event.status === 'completed';
193
+ return [
194
+ {
195
+ type: 'update',
196
+ value: {
197
+ ...prev,
198
+ completed: prev.completed + (passed ? 1 : 0),
199
+ failed: prev.failed + (passed ? 0 : 1),
200
+ },
201
+ },
202
+ ];
203
+ }
204
+ case 'run:end': {
205
+ const prev = get(event.runId);
206
+ if (!prev)
207
+ return [];
208
+ return [
209
+ {
210
+ type: 'update',
211
+ value: {
212
+ ...prev,
213
+ status: 'finished',
214
+ endTime: event.timestamp,
215
+ duration: event.duration,
216
+ completed: event.summary?.completed ?? prev.completed,
217
+ failed: event.summary?.failed ?? prev.failed,
218
+ },
219
+ },
220
+ ];
221
+ }
222
+ default:
223
+ return [];
224
+ }
225
+ },
226
+ };
227
+ }
228
+ //# sourceMappingURL=projections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projections.js","sourceRoot":"","sources":["../../src/collections/projections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Transport } from '../types.js';
2
+ import type { RunSource } from './types.js';
3
+ /**
4
+ * Wrap a {@link Transport} as a shared {@link RunSource}: one
5
+ * `transport.subscribe` fanned out to many collections.
6
+ *
7
+ * Why a layer over the transport at all? Each `createDevTransport()`
8
+ * subscription opens its own `EventSource`; a per-collection subscription
9
+ * would mean N SSE/WebSocket connections for N tables of the same run. The
10
+ * source opens exactly one and multiplexes it, and buffers the current run
11
+ * so a collection created mid-run replays the events it missed — the same
12
+ * catch-up the transports give a fresh connection, but shared.
13
+ *
14
+ * The underlying transport subscription starts lazily on the first
15
+ * `subscribe` and stays open (it does not drop when the last collection
16
+ * detaches, since TanStack DB pauses sync when a collection has no active
17
+ * subscribers, and we want the run to keep accumulating across those gaps).
18
+ * Call {@link RunSource.close} to tear it down for good.
19
+ *
20
+ * The buffer holds **every** event of the connection — across runs — so a
21
+ * collection attaching mid-session replays the full history (the multi-run
22
+ * read model wants prior runs, not just the current one). `run:start` does
23
+ * not clear it; it just marks a new run partition downstream. Cap/eviction
24
+ * is a future concern; today a session's history is bounded.
25
+ *
26
+ * History/ordering/de-duplication are the transport's contract — both the
27
+ * dev (SSE) and cloud (WebSocket) adapters replay on connect and deliver
28
+ * events in order. The source does not re-derive `seq`; it consumes whatever
29
+ * the subscription delivers.
30
+ */
31
+ export declare function createRunSource(transport: Transport): RunSource;
32
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/collections/source.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,SAAS,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAK3C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,CAwD/D"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Wrap a {@link Transport} as a shared {@link RunSource}: one
3
+ * `transport.subscribe` fanned out to many collections.
4
+ *
5
+ * Why a layer over the transport at all? Each `createDevTransport()`
6
+ * subscription opens its own `EventSource`; a per-collection subscription
7
+ * would mean N SSE/WebSocket connections for N tables of the same run. The
8
+ * source opens exactly one and multiplexes it, and buffers the current run
9
+ * so a collection created mid-run replays the events it missed — the same
10
+ * catch-up the transports give a fresh connection, but shared.
11
+ *
12
+ * The underlying transport subscription starts lazily on the first
13
+ * `subscribe` and stays open (it does not drop when the last collection
14
+ * detaches, since TanStack DB pauses sync when a collection has no active
15
+ * subscribers, and we want the run to keep accumulating across those gaps).
16
+ * Call {@link RunSource.close} to tear it down for good.
17
+ *
18
+ * The buffer holds **every** event of the connection — across runs — so a
19
+ * collection attaching mid-session replays the full history (the multi-run
20
+ * read model wants prior runs, not just the current one). `run:start` does
21
+ * not clear it; it just marks a new run partition downstream. Cap/eviction
22
+ * is a future concern; today a session's history is bounded.
23
+ *
24
+ * History/ordering/de-duplication are the transport's contract — both the
25
+ * dev (SSE) and cloud (WebSocket) adapters replay on connect and deliver
26
+ * events in order. The source does not re-derive `seq`; it consumes whatever
27
+ * the subscription delivers.
28
+ */
29
+ export function createRunSource(transport) {
30
+ const eventListeners = new Set();
31
+ const statusListeners = new Set();
32
+ // Buffered events for the whole session, replayed to late subscribers.
33
+ let buffer = [];
34
+ let status = 'connecting';
35
+ let unsubscribeTransport = null;
36
+ let closed = false;
37
+ function onTransportEvent(event) {
38
+ buffer.push(event);
39
+ for (const listener of [...eventListeners])
40
+ listener(event);
41
+ }
42
+ function onTransportStatus(next) {
43
+ status = next;
44
+ for (const listener of [...statusListeners])
45
+ listener(next);
46
+ }
47
+ function ensureStarted() {
48
+ if (unsubscribeTransport || closed)
49
+ return;
50
+ unsubscribeTransport = transport.subscribe(onTransportEvent, onTransportStatus);
51
+ }
52
+ return {
53
+ get status() {
54
+ return status;
55
+ },
56
+ subscribe(onEvent, onStatus) {
57
+ if (closed)
58
+ return () => { };
59
+ eventListeners.add(onEvent);
60
+ if (onStatus)
61
+ statusListeners.add(onStatus);
62
+ // Replay the current run so a collection attaching mid-run catches up,
63
+ // then report the current liveness.
64
+ for (const event of buffer)
65
+ onEvent(event);
66
+ onStatus?.(status);
67
+ ensureStarted();
68
+ return () => {
69
+ eventListeners.delete(onEvent);
70
+ if (onStatus)
71
+ statusListeners.delete(onStatus);
72
+ };
73
+ },
74
+ close() {
75
+ closed = true;
76
+ unsubscribeTransport?.();
77
+ unsubscribeTransport = null;
78
+ eventListeners.clear();
79
+ statusListeners.clear();
80
+ buffer = [];
81
+ },
82
+ };
83
+ }
84
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/collections/source.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,eAAe,CAAC,SAAoB;IAClD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAiB,CAAA;IAC/C,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkB,CAAA;IACjD,uEAAuE;IACvE,IAAI,MAAM,GAAe,EAAE,CAAA;IAC3B,IAAI,MAAM,GAAqB,YAAY,CAAA;IAC3C,IAAI,oBAAoB,GAAwB,IAAI,CAAA;IACpD,IAAI,MAAM,GAAG,KAAK,CAAA;IAElB,SAAS,gBAAgB,CAAC,KAAe;QACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClB,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,cAAc,CAAC;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7D,CAAC;IAED,SAAS,iBAAiB,CAAC,IAAsB;QAC/C,MAAM,GAAG,IAAI,CAAA;QACb,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,eAAe,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC7D,CAAC;IAED,SAAS,aAAa;QACpB,IAAI,oBAAoB,IAAI,MAAM;YAAE,OAAM;QAC1C,oBAAoB,GAAG,SAAS,CAAC,SAAS,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAA;IACjF,CAAC;IAED,OAAO;QACL,IAAI,MAAM;YACR,OAAO,MAAM,CAAA;QACf,CAAC;QAED,SAAS,CAAC,OAAO,EAAE,QAAQ;YACzB,IAAI,MAAM;gBAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;YAC3B,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC3B,IAAI,QAAQ;gBAAE,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAE3C,uEAAuE;YACvE,oCAAoC;YACpC,KAAK,MAAM,KAAK,IAAI,MAAM;gBAAE,OAAO,CAAC,KAAK,CAAC,CAAA;YAC1C,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAA;YAElB,aAAa,EAAE,CAAA;YAEf,OAAO,GAAG,EAAE;gBACV,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;gBAC9B,IAAI,QAAQ;oBAAE,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YAChD,CAAC,CAAA;QACH,CAAC;QAED,KAAK;YACH,MAAM,GAAG,IAAI,CAAA;YACb,oBAAoB,EAAE,EAAE,CAAA;YACxB,oBAAoB,GAAG,IAAI,CAAA;YAC3B,cAAc,CAAC,KAAK,EAAE,CAAA;YACtB,eAAe,CAAC,KAAK,EAAE,CAAA;YACvB,MAAM,GAAG,EAAE,CAAA;QACb,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,87 @@
1
+ import type { RunEvent } from '@scenetest/protocol';
2
+ import type { ConnectionStatus, Transport } from '../types.js';
3
+ /**
4
+ * One row operation a projection emits for a single event. The collection
5
+ * options factory translates these into TanStack DB sync writes:
6
+ *
7
+ * - `insert` / `update` → `write({ type, value })` (key derived via `getKey`)
8
+ * - `delete` → `write({ type: 'delete', key })`
9
+ * - `reset` → `truncate()` (drop every row)
10
+ *
11
+ * The multi-run projections don't emit `reset` (a new `run:start` opens a new
12
+ * partition rather than wiping), but it stays in the vocabulary for projections
13
+ * that need a hard clear — e.g. switching the PR/context a collection tracks.
14
+ *
15
+ * Projections never touch TanStack DB directly; they speak this small,
16
+ * pure vocabulary, which keeps them trivially testable.
17
+ */
18
+ export type RowOp<T extends object, TKey extends string | number> = {
19
+ type: 'insert' | 'update';
20
+ value: T;
21
+ } | {
22
+ type: 'delete';
23
+ key: TKey;
24
+ } | {
25
+ type: 'reset';
26
+ };
27
+ /**
28
+ * A projection folds the read-only `RunEvent` stream into the rows of one
29
+ * collection — the "sync reducer" the proposal describes. It is the only
30
+ * writer for its table, and it is pure given the event and a reader for the
31
+ * rows it has already produced (`get`), so an `update` can be computed from
32
+ * the prior value.
33
+ *
34
+ * A projection may carry internal counter state (e.g. to mint ids for
35
+ * append-only rows), so create one per collection via a factory rather than
36
+ * sharing a singleton.
37
+ */
38
+ export interface RunProjection<T extends object, TKey extends string | number = string> {
39
+ /** Stable identifier, used as the collection's default `id`. */
40
+ readonly id: string;
41
+ /** Key extractor for rows of this collection. */
42
+ getKey(row: T): TKey;
43
+ /**
44
+ * Fold one event into row operations. `get` reads a row this projection
45
+ * has already emitted (the synced state), so updates merge onto it.
46
+ * Returns an empty array for events this collection does not care about.
47
+ */
48
+ project(event: RunEvent, get: (key: TKey) => T | undefined): Array<RowOp<T, TKey>>;
49
+ }
50
+ /**
51
+ * A shared, read-only handle on a single run's event stream. It wraps one
52
+ * `Transport.subscribe` and fans it out to any number of collections, so
53
+ * several collections can "attach to the same websocket, different table"
54
+ * off one underlying connection.
55
+ *
56
+ * Late subscribers are replayed the current run's buffered events on
57
+ * `subscribe`, so a collection created after the run started still catches
58
+ * up. The buffer resets on `run:start`.
59
+ */
60
+ export interface RunSource {
61
+ /**
62
+ * Attach a consumer. `onEvent` is first called synchronously for every
63
+ * buffered event of the current run, then for each live event.
64
+ * `onStatus`, if given, receives connection-liveness changes (and the
65
+ * current status immediately). Returns an unsubscribe function.
66
+ */
67
+ subscribe(onEvent: (event: RunEvent) => void, onStatus?: (status: ConnectionStatus) => void): () => void;
68
+ /** Latest connection liveness reported by the transport. */
69
+ readonly status: ConnectionStatus;
70
+ /** Tear down the underlying transport subscription and drop the buffer. */
71
+ close(): void;
72
+ }
73
+ /** Options for {@link runCollectionOptions}. */
74
+ export interface RunCollectionOptions<T extends object, TKey extends string | number> {
75
+ /** The shared stream this collection reads from. */
76
+ source: RunSource;
77
+ /** The projection that folds events into this collection's rows. */
78
+ projection: RunProjection<T, TKey>;
79
+ /**
80
+ * Whether to begin syncing on collection creation rather than on first
81
+ * query. Defaults to `true` so the read model captures the run from the
82
+ * moment it is created, not from the first `useLiveQuery`.
83
+ */
84
+ startSync?: boolean;
85
+ }
86
+ export type { Transport };
87
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/collections/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE9D;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,IAC5D;IAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAErB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM;IACpF,gEAAgE;IAChE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAA;IACpB;;;;OAIG;IACH,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,GAAG,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;CACnF;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IACH,SAAS,CACP,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,EAClC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAC5C,MAAM,IAAI,CAAA;IACb,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IACjC,2EAA2E;IAC3E,KAAK,IAAI,IAAI,CAAA;CACd;AAED,gDAAgD;AAChD,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM;IAClF,oDAAoD;IACpD,MAAM,EAAE,SAAS,CAAA;IACjB,oEAAoE;IACpE,UAAU,EAAE,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;IAClC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,YAAY,EAAE,SAAS,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/collections/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import type { DashboardTheme, Transport } from './types.js';
2
+ /**
3
+ * The Dashboard app — Home / Runner / Waterfall views over one read-only
4
+ * `@tanstack/db` read model, routed on `location.pathname`. A plain Preact
5
+ * component rendering into the light DOM under a single `.scenetest-dashboard`
6
+ * root class; the shipped stylesheet scopes everything to it. Dev and cloud
7
+ * render the same component — only the injected `transport` differs.
8
+ *
9
+ * /__scenetest → Home
10
+ * /__scenetest/runner → Runner (filterable scene log)
11
+ * /__scenetest/waterfall → Waterfall (live timeline)
12
+ *
13
+ * The collections are the single store: the component builds them from the run
14
+ * stream and every view reads from them (`selectWaterfall`, `selectSnapshot`).
15
+ */
16
+ export declare function Dashboard({ transport, theme, }: {
17
+ transport: Transport;
18
+ theme?: DashboardTheme;
19
+ }): import("preact").JSX.Element;
20
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAoB,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAiE7E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,KAAK,GACN,EAAE;IACD,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB,gCAyDA"}