@sharpee/channel-service 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/channel-service.d.ts +147 -0
- package/channel-service.d.ts.map +1 -0
- package/channel-service.js +253 -0
- package/channel-service.js.map +1 -0
- package/index.d.ts +43 -0
- package/index.d.ts.map +1 -0
- package/index.js +58 -0
- package/index.js.map +1 -0
- package/package.json +46 -0
- package/render-to-string.d.ts +67 -0
- package/render-to-string.d.ts.map +1 -0
- package/render-to-string.js +243 -0
- package/render-to-string.js.map +1 -0
- package/renderer/index.d.ts +12 -0
- package/renderer/index.d.ts.map +1 -0
- package/renderer/index.js +17 -0
- package/renderer/index.js.map +1 -0
- package/renderer/json-tree-fallback.d.ts +45 -0
- package/renderer/json-tree-fallback.d.ts.map +1 -0
- package/renderer/json-tree-fallback.js +71 -0
- package/renderer/json-tree-fallback.js.map +1 -0
- package/renderer/renderer.d.ts +139 -0
- package/renderer/renderer.d.ts.map +1 -0
- package/renderer/renderer.js +262 -0
- package/renderer/renderer.js.map +1 -0
- package/renderer/types.d.ts +179 -0
- package/renderer/types.d.ts.map +1 -0
- package/renderer/types.js +27 -0
- package/renderer/types.js.map +1 -0
- package/utils/flatten.d.ts +27 -0
- package/utils/flatten.d.ts.map +1 -0
- package/utils/flatten.js +40 -0
- package/utils/flatten.js.map +1 -0
- package/wire/decoder.d.ts +61 -0
- package/wire/decoder.d.ts.map +1 -0
- package/wire/decoder.js +74 -0
- package/wire/decoder.js.map +1 -0
- package/wire/index.d.ts +19 -0
- package/wire/index.d.ts.map +1 -0
- package/wire/index.js +22 -0
- package/wire/index.js.map +1 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @sharpee/channel-service/renderer — `Renderer` host implementation.
|
|
4
|
+
*
|
|
5
|
+
* Owner context: consumer-side dispatcher. Drives `CmgtPacket` and
|
|
6
|
+
* `TurnPacket` instances into registered `ChannelRenderer` plug-ins,
|
|
7
|
+
* holds the channel state store, and pumps commands back to the
|
|
8
|
+
* engine.
|
|
9
|
+
*
|
|
10
|
+
* Public interface (per ADR-165 §2, §3, §4, §5, §7):
|
|
11
|
+
* - `Renderer` class implementing the same-named interface.
|
|
12
|
+
* - `createRenderer(opts)` factory for ergonomic instantiation.
|
|
13
|
+
*
|
|
14
|
+
* @see ADR-165 — Renderer Architecture
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Renderer = void 0;
|
|
18
|
+
exports.createRenderer = createRenderer;
|
|
19
|
+
const json_tree_fallback_1 = require("./json-tree-fallback");
|
|
20
|
+
/**
|
|
21
|
+
* Concrete `Renderer` host (ADR-165 §2).
|
|
22
|
+
*
|
|
23
|
+
* One instance per session. Holds:
|
|
24
|
+
* - the registered `ChannelRenderer`s (last-write-wins per channel id),
|
|
25
|
+
* - the channel state store (replace-latest, append-accumulating,
|
|
26
|
+
* event-no-entry — ADR-165 §5),
|
|
27
|
+
* - the slot handles (`getSlot` / `registerSlot` per §7),
|
|
28
|
+
* - the current `CmgtPacket` (so `onValue` can pass the matching
|
|
29
|
+
* `ChannelDefinition` to the renderer),
|
|
30
|
+
* - the command-handler subscriber list.
|
|
31
|
+
*
|
|
32
|
+
* No DOM, no transport, no engine. Concrete consumers compose this
|
|
33
|
+
* with their host platform.
|
|
34
|
+
*/
|
|
35
|
+
class Renderer {
|
|
36
|
+
renderers = new Map();
|
|
37
|
+
fallbackRenderers = new Map();
|
|
38
|
+
state = {};
|
|
39
|
+
slots = new Map();
|
|
40
|
+
commandHandlers = new Set();
|
|
41
|
+
currentManifest;
|
|
42
|
+
warn;
|
|
43
|
+
buildFallback;
|
|
44
|
+
constructor(opts = {}) {
|
|
45
|
+
this.warn = opts.warn ?? ((m) => {
|
|
46
|
+
// eslint-disable-next-line no-console
|
|
47
|
+
console.warn(m);
|
|
48
|
+
});
|
|
49
|
+
this.buildFallback = (0, json_tree_fallback_1.createJsonTreeFallbackFactory)({
|
|
50
|
+
warn: opts.fallbackWarn ?? this.warn,
|
|
51
|
+
output: opts.fallbackOutput,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// ────────────────────────────────────────────────────────────────
|
|
55
|
+
// Registration
|
|
56
|
+
// ────────────────────────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Register a `ChannelRenderer` (ADR-165 §3). Last-write-wins —
|
|
59
|
+
* re-registering replaces the prior renderer for that id.
|
|
60
|
+
*/
|
|
61
|
+
registerRenderer(channelId, renderer) {
|
|
62
|
+
this.renderers.set(channelId, renderer);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Register a slot (ADR-165 §7). Stories that replace the
|
|
66
|
+
* platform-default layout call this for each region.
|
|
67
|
+
*/
|
|
68
|
+
registerSlot(name, handle) {
|
|
69
|
+
this.slots.set(name, handle);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve a slot handle, or `null` if not registered.
|
|
73
|
+
*/
|
|
74
|
+
getSlot(name) {
|
|
75
|
+
return this.slots.has(name) ? this.slots.get(name) : null;
|
|
76
|
+
}
|
|
77
|
+
// ────────────────────────────────────────────────────────────────
|
|
78
|
+
// Command pump
|
|
79
|
+
// ────────────────────────────────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* Subscribe to commands emitted by channel renderers.
|
|
82
|
+
*/
|
|
83
|
+
onCommand(handler) {
|
|
84
|
+
this.commandHandlers.add(handler);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Emit a command from a `ChannelRenderer` (UI-gesture origin).
|
|
88
|
+
* All registered handlers receive the packet synchronously.
|
|
89
|
+
*/
|
|
90
|
+
emitCommand(text) {
|
|
91
|
+
const packet = { kind: 'command', text };
|
|
92
|
+
for (const handler of this.commandHandlers) {
|
|
93
|
+
handler(packet);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ────────────────────────────────────────────────────────────────
|
|
97
|
+
// Lifecycle
|
|
98
|
+
// ────────────────────────────────────────────────────────────────
|
|
99
|
+
/**
|
|
100
|
+
* Apply a CMGT packet (ADR-165 §4 lifecycle).
|
|
101
|
+
*
|
|
102
|
+
* 1. If a prior manifest exists, run `onDestroy` for each of its
|
|
103
|
+
* renderers (in registration order for determinism).
|
|
104
|
+
* 2. Reset the state store.
|
|
105
|
+
* 3. Update the current manifest.
|
|
106
|
+
* 4. Run `onCmgt` for each new-manifest renderer in registration
|
|
107
|
+
* order.
|
|
108
|
+
*/
|
|
109
|
+
applyCmgt(packet) {
|
|
110
|
+
if (this.currentManifest) {
|
|
111
|
+
for (const channel of this.currentManifest.channels) {
|
|
112
|
+
const r = this.renderers.get(channel.id) ?? this.fallbackRenderers.get(channel.id);
|
|
113
|
+
r?.onDestroy?.();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
this.state = {};
|
|
117
|
+
this.currentManifest = packet;
|
|
118
|
+
// Reset fallback cache so a re-mounted session re-issues the
|
|
119
|
+
// one-time warning if a channel still lacks a renderer.
|
|
120
|
+
this.fallbackRenderers.clear();
|
|
121
|
+
for (const channel of packet.channels) {
|
|
122
|
+
const r = this.resolveRenderer(channel.id);
|
|
123
|
+
r.onCmgt?.(channel, packet);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Dispatch a turn packet (ADR-165 §4 dispatch contract).
|
|
128
|
+
*
|
|
129
|
+
* Iterates the current manifest in registration order. For each
|
|
130
|
+
* manifest entry that has a payload value, updates the state
|
|
131
|
+
* store per mode and invokes `onValue`. Handles the `clear`
|
|
132
|
+
* channel specially — empties append-mode state stores and fires
|
|
133
|
+
* `onClear` hooks.
|
|
134
|
+
*/
|
|
135
|
+
applyTurnPacket(packet) {
|
|
136
|
+
if (!this.currentManifest) {
|
|
137
|
+
this.warn('[channel-service] applyTurnPacket called before applyCmgt; ' +
|
|
138
|
+
'turn packet ignored. Bootstrap order: cmgt before turn (ADR-163 §11).');
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
// Check for a `clear` event in this turn packet — handle it
|
|
142
|
+
// first so subsequent main/append channel emissions land in an
|
|
143
|
+
// emptied store.
|
|
144
|
+
const clearValue = packet.payload['clear'];
|
|
145
|
+
if (clearValue !== undefined) {
|
|
146
|
+
this.handleClear(clearValue);
|
|
147
|
+
}
|
|
148
|
+
// Walk the manifest in registration order. The payload's own
|
|
149
|
+
// key order is irrelevant — manifest order is the contract.
|
|
150
|
+
for (const channel of this.currentManifest.channels) {
|
|
151
|
+
// The clear channel itself was already handled above; let
|
|
152
|
+
// its renderer fire normally too (visual side-effects).
|
|
153
|
+
if (!Object.prototype.hasOwnProperty.call(packet.payload, channel.id)) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const value = packet.payload[channel.id];
|
|
157
|
+
this.applyChannelValue(channel, value);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Snapshot of the channel state store (deep-cloned) — for tests
|
|
162
|
+
* and ADR-163 AC-12 round-trip.
|
|
163
|
+
*/
|
|
164
|
+
getStateSnapshot() {
|
|
165
|
+
return deepClone(this.state);
|
|
166
|
+
}
|
|
167
|
+
// ────────────────────────────────────────────────────────────────
|
|
168
|
+
// Private — dispatch helpers
|
|
169
|
+
// ────────────────────────────────────────────────────────────────
|
|
170
|
+
/**
|
|
171
|
+
* Update the state store per mode and invoke the renderer's
|
|
172
|
+
* `onValue`.
|
|
173
|
+
*/
|
|
174
|
+
applyChannelValue(channel, value) {
|
|
175
|
+
switch (channel.mode) {
|
|
176
|
+
case 'replace': {
|
|
177
|
+
this.state[channel.id] = value;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case 'append': {
|
|
181
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
182
|
+
const existing = this.state[channel.id];
|
|
183
|
+
const accumulator = Array.isArray(existing) ? existing : [];
|
|
184
|
+
this.state[channel.id] = accumulator.concat(entries);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case 'event': {
|
|
188
|
+
// Event channels do NOT write to the state store (ADR-165 §5).
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const renderer = this.resolveRenderer(channel.id);
|
|
193
|
+
renderer.onValue(value, channel);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Handle a `clear` channel emission (ADR-165 §4 step 2).
|
|
197
|
+
*
|
|
198
|
+
* `value.target` (when set) names a specific append-mode channel
|
|
199
|
+
* to clear; an empty / missing target clears every append-mode
|
|
200
|
+
* channel currently registered in the manifest.
|
|
201
|
+
*/
|
|
202
|
+
handleClear(value) {
|
|
203
|
+
if (!this.currentManifest)
|
|
204
|
+
return;
|
|
205
|
+
const target = value && typeof value === 'object' && 'target' in value
|
|
206
|
+
? value.target
|
|
207
|
+
: undefined;
|
|
208
|
+
for (const channel of this.currentManifest.channels) {
|
|
209
|
+
if (channel.mode !== 'append')
|
|
210
|
+
continue;
|
|
211
|
+
if (target !== undefined && target !== '' && channel.id !== target)
|
|
212
|
+
continue;
|
|
213
|
+
// Reset state store entry first (ADR-165 §4 says state is
|
|
214
|
+
// reset BEFORE onClear runs).
|
|
215
|
+
delete this.state[channel.id];
|
|
216
|
+
const renderer = this.renderers.get(channel.id);
|
|
217
|
+
renderer?.onClear?.(target ?? channel.id);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Resolve the renderer for a channel id. Returns the registered
|
|
222
|
+
* renderer when present; otherwise lazily creates and caches a
|
|
223
|
+
* JSON-tree fallback (so the one-time warning fires once per
|
|
224
|
+
* channel id, not once per emission).
|
|
225
|
+
*/
|
|
226
|
+
resolveRenderer(channelId) {
|
|
227
|
+
const registered = this.renderers.get(channelId);
|
|
228
|
+
if (registered)
|
|
229
|
+
return registered;
|
|
230
|
+
let fallback = this.fallbackRenderers.get(channelId);
|
|
231
|
+
if (!fallback) {
|
|
232
|
+
fallback = this.buildFallback(channelId);
|
|
233
|
+
this.fallbackRenderers.set(channelId, fallback);
|
|
234
|
+
}
|
|
235
|
+
return fallback;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
exports.Renderer = Renderer;
|
|
239
|
+
/**
|
|
240
|
+
* Convenience factory for `new Renderer(opts)`.
|
|
241
|
+
*/
|
|
242
|
+
function createRenderer(opts = {}) {
|
|
243
|
+
return new Renderer(opts);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Deep-clone helper for `getStateSnapshot`. Uses `structuredClone`
|
|
247
|
+
* when available; falls back to `JSON.parse(JSON.stringify(...))`
|
|
248
|
+
* for compatibility with older runtimes.
|
|
249
|
+
*/
|
|
250
|
+
function deepClone(value) {
|
|
251
|
+
if (typeof globalThis.structuredClone === 'function') {
|
|
252
|
+
return globalThis.structuredClone(value);
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
return JSON.parse(JSON.stringify(value));
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Last resort — return shallow copy if value cannot round-trip.
|
|
259
|
+
return Array.isArray(value) ? [...value] : { ...value };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/channel-service/src/renderer/renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sharpee/channel-service/renderer — consumer-side type contracts.
|
|
3
|
+
*
|
|
4
|
+
* Owner context: consumer side of channel-I/O. Defines the
|
|
5
|
+
* `ChannelRenderer` plug-in shape, the `Renderer` host that drives
|
|
6
|
+
* packets into renderers, and the small `SlotHandle` abstraction the
|
|
7
|
+
* default layouts use to address output regions.
|
|
8
|
+
*
|
|
9
|
+
* Public interface (per ADR-165 §1, §2, §5, §7):
|
|
10
|
+
* - `ChannelRenderer` — per-channel rendering contract; only
|
|
11
|
+
* `onValue` is required.
|
|
12
|
+
* - `Renderer` — top-level host the consumer drives.
|
|
13
|
+
* - `ChannelStateStore` — in-memory state per channel id (replace
|
|
14
|
+
* keeps latest, append accumulates, event has no entry).
|
|
15
|
+
* - `SlotHandle` — opaque handle the default layouts use; concrete
|
|
16
|
+
* consumers narrow to `HTMLElement` (DOM), terminal region (CLI),
|
|
17
|
+
* or whatever their output medium uses.
|
|
18
|
+
*
|
|
19
|
+
* No implementation lives here. Pure types so renderer-host packages
|
|
20
|
+
* (browser, CLI, multi-user) and channel-renderer authors share a
|
|
21
|
+
* single contract.
|
|
22
|
+
*
|
|
23
|
+
* @see ADR-165 — Renderer Architecture
|
|
24
|
+
*/
|
|
25
|
+
import type { ChannelDefinition, CmgtPacket, CommandPacket, TurnPacket } from "../../if-domain/index";
|
|
26
|
+
/**
|
|
27
|
+
* Per-channel rendering logic (ADR-165 §1).
|
|
28
|
+
*
|
|
29
|
+
* A `ChannelRenderer` is registered against a channel id via
|
|
30
|
+
* `Renderer.registerRenderer(channelId, renderer)`. The dispatcher
|
|
31
|
+
* invokes `onValue` once per emission of that channel in a turn
|
|
32
|
+
* packet; optional hooks fire on lifecycle transitions.
|
|
33
|
+
*
|
|
34
|
+
* The interface is deliberately small. Cross-channel logic (a
|
|
35
|
+
* status-bar renderer reading both `location` and `score`) lives in
|
|
36
|
+
* the host module, not inside individual `ChannelRenderer` instances.
|
|
37
|
+
*/
|
|
38
|
+
export interface ChannelRenderer {
|
|
39
|
+
/**
|
|
40
|
+
* Required. Called once per emission of this channel in a turn
|
|
41
|
+
* packet. The shape of `value` mirrors the channel's mode:
|
|
42
|
+
*
|
|
43
|
+
* - **replace-mode** — the latest scalar value (or `null` for
|
|
44
|
+
* hide / stop signals per ADR-163 §6).
|
|
45
|
+
* - **append-mode** — an array of new entries this turn (per
|
|
46
|
+
* ADR-163 §5; the renderer accumulates across turns).
|
|
47
|
+
* - **event-mode** — the event payload.
|
|
48
|
+
*
|
|
49
|
+
* `channel` is the manifest entry — useful for renderers that
|
|
50
|
+
* decide formatting based on `contentType`.
|
|
51
|
+
*/
|
|
52
|
+
onValue(value: unknown, channel: ChannelDefinition): void;
|
|
53
|
+
/**
|
|
54
|
+
* Optional. Append-mode only. Invoked by the dispatcher when a
|
|
55
|
+
* `clear` event with a matching `target` arrives. The renderer
|
|
56
|
+
* is responsible for clearing its rendered output (DOM container,
|
|
57
|
+
* terminal region). The state store is reset by the dispatcher
|
|
58
|
+
* before this hook fires.
|
|
59
|
+
*/
|
|
60
|
+
onClear?(target: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Optional. Invoked when CMGT is applied. Use for one-time setup
|
|
63
|
+
* (DOM scaffolding, asset preload, audio context init). NOT for
|
|
64
|
+
* state restoration — that comes via `applyTurnPacket` replays.
|
|
65
|
+
*
|
|
66
|
+
* On the first `applyCmgt` of a `Renderer`'s lifetime this is the
|
|
67
|
+
* only setup hook called. On subsequent invocations, `onDestroy`
|
|
68
|
+
* is called first, then `onCmgt` is called again to set up a
|
|
69
|
+
* fresh session.
|
|
70
|
+
*/
|
|
71
|
+
onCmgt?(channel: ChannelDefinition, manifest: CmgtPacket): void;
|
|
72
|
+
/**
|
|
73
|
+
* Optional. Invoked when a fresh `applyCmgt` is about to reset
|
|
74
|
+
* this `Renderer`. Releases resources allocated in `onCmgt` (Web
|
|
75
|
+
* Audio context, IntersectionObserver, etc.). Symmetric with
|
|
76
|
+
* `onCmgt`. Not called when the host platform itself is shutting
|
|
77
|
+
* down (process exit, page unload) — the platform handles that.
|
|
78
|
+
*/
|
|
79
|
+
onDestroy?(): void;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Channel state store shape (ADR-165 §5).
|
|
83
|
+
*
|
|
84
|
+
* Replace channels store the latest scalar (or `null`); append
|
|
85
|
+
* channels store an accumulated `unknown[]`; event channels and
|
|
86
|
+
* never-emitted channels have no entry.
|
|
87
|
+
*
|
|
88
|
+
* The dispatcher owns mutation. Renderers read; they do not write.
|
|
89
|
+
*/
|
|
90
|
+
export interface ChannelStateStore {
|
|
91
|
+
[channelId: string]: unknown | unknown[] | undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Opaque handle to a layout slot (ADR-165 §7).
|
|
95
|
+
*
|
|
96
|
+
* Concrete renderer hosts narrow to their output medium:
|
|
97
|
+
* - browser: `HTMLElement`
|
|
98
|
+
* - CLI: a small `{ write, clear }` adapter
|
|
99
|
+
* - canvas: a draw-group reference
|
|
100
|
+
*
|
|
101
|
+
* The `Renderer` itself is medium-agnostic — it stores and returns
|
|
102
|
+
* whatever the host registers.
|
|
103
|
+
*/
|
|
104
|
+
export type SlotHandle = unknown;
|
|
105
|
+
/**
|
|
106
|
+
* Top-level renderer handle the consumer drives (ADR-165 §2).
|
|
107
|
+
*
|
|
108
|
+
* One instance per session. The consumer:
|
|
109
|
+
* 1. Constructs a `Renderer`.
|
|
110
|
+
* 2. Calls `registerRenderer(channelId, renderer)` for each
|
|
111
|
+
* channel it wants to display (platform defaults register
|
|
112
|
+
* during platform boot; stories register during story init).
|
|
113
|
+
* 3. Calls `applyCmgt(cmgt)` once when the engine emits the
|
|
114
|
+
* manifest.
|
|
115
|
+
* 4. Calls `applyTurnPacket(packet)` per turn the engine emits.
|
|
116
|
+
* 5. Subscribes to `onCommand(handler)` to feed commands back.
|
|
117
|
+
*/
|
|
118
|
+
export interface Renderer {
|
|
119
|
+
/**
|
|
120
|
+
* Apply a CMGT packet (ADR-165 §4).
|
|
121
|
+
*
|
|
122
|
+
* On second-and-subsequent invocations:
|
|
123
|
+
* 1. Runs `onDestroy` for every renderer in the prior manifest.
|
|
124
|
+
* 2. Resets every channel state store.
|
|
125
|
+
* 3. Updates the current manifest.
|
|
126
|
+
* 4. Runs `onCmgt` for every renderer in the new manifest, in
|
|
127
|
+
* manifest order.
|
|
128
|
+
*
|
|
129
|
+
* On the first invocation, step 1 is skipped.
|
|
130
|
+
*/
|
|
131
|
+
applyCmgt(packet: CmgtPacket): void;
|
|
132
|
+
/**
|
|
133
|
+
* Dispatch a turn packet (ADR-165 §4). Iterates the current
|
|
134
|
+
* manifest in registration order; for each manifest entry that
|
|
135
|
+
* has a payload value, updates the state store and invokes the
|
|
136
|
+
* registered renderer's `onValue`. `clear` events trigger the
|
|
137
|
+
* append-channel truncation path.
|
|
138
|
+
*
|
|
139
|
+
* Synchronous: every dispatched callback completes before the
|
|
140
|
+
* call returns.
|
|
141
|
+
*/
|
|
142
|
+
applyTurnPacket(packet: TurnPacket): void;
|
|
143
|
+
/**
|
|
144
|
+
* Register a `ChannelRenderer` against a channel id. Last-write-
|
|
145
|
+
* wins per ADR-165 §3 — re-registering with the same id replaces
|
|
146
|
+
* the prior renderer. Platform-default renderers register first;
|
|
147
|
+
* story overrides replace them.
|
|
148
|
+
*/
|
|
149
|
+
registerRenderer(channelId: string, renderer: ChannelRenderer): void;
|
|
150
|
+
/**
|
|
151
|
+
* Subscribe to `CommandPacket`s emitted by channel renderers.
|
|
152
|
+
* The consumer's host loop pumps these back to the engine.
|
|
153
|
+
* Multiple subscribers all receive each emission.
|
|
154
|
+
*/
|
|
155
|
+
onCommand(handler: (cmd: CommandPacket) => void): void;
|
|
156
|
+
/**
|
|
157
|
+
* Emit a `CommandPacket`. Channel renderers call this when a UI
|
|
158
|
+
* gesture (hotspot click, drag-drop, custom widget) should
|
|
159
|
+
* advance the engine (ADR-163 §10).
|
|
160
|
+
*/
|
|
161
|
+
emitCommand(text: string): void;
|
|
162
|
+
/**
|
|
163
|
+
* Register a slot (ADR-165 §7). Stories that replace the
|
|
164
|
+
* platform-default layout call this for each region of their
|
|
165
|
+
* custom layout.
|
|
166
|
+
*/
|
|
167
|
+
registerSlot(name: string, handle: SlotHandle): void;
|
|
168
|
+
/**
|
|
169
|
+
* Resolve a slot handle, or `null` if the slot is not registered.
|
|
170
|
+
*/
|
|
171
|
+
getSlot(name: string): SlotHandle | null;
|
|
172
|
+
/**
|
|
173
|
+
* Snapshot of the channel state store for testing and AC-7
|
|
174
|
+
* (re-emission identity round-trip). Returns a deep-cloned copy;
|
|
175
|
+
* the caller may mutate freely.
|
|
176
|
+
*/
|
|
177
|
+
getStateSnapshot(): ChannelStateStore;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/channel-service/src/renderer/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,UAAU,EACX,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE1D;;;;;;OAMG;IACH,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B;;;;;;;;;OASG;IACH,MAAM,CAAC,CAAC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IAEhE;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,IAAI,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,CAAC;CACtD;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC;AAEjC;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAEpC;;;;;;;;;OASG;IACH,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAE1C;;;;;OAKG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAErE;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI,CAAC;IAEvD;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAErD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IAEzC;;;;OAIG;IACH,gBAAgB,IAAI,iBAAiB,CAAC;CACvC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @sharpee/channel-service/renderer — consumer-side type contracts.
|
|
4
|
+
*
|
|
5
|
+
* Owner context: consumer side of channel-I/O. Defines the
|
|
6
|
+
* `ChannelRenderer` plug-in shape, the `Renderer` host that drives
|
|
7
|
+
* packets into renderers, and the small `SlotHandle` abstraction the
|
|
8
|
+
* default layouts use to address output regions.
|
|
9
|
+
*
|
|
10
|
+
* Public interface (per ADR-165 §1, §2, §5, §7):
|
|
11
|
+
* - `ChannelRenderer` — per-channel rendering contract; only
|
|
12
|
+
* `onValue` is required.
|
|
13
|
+
* - `Renderer` — top-level host the consumer drives.
|
|
14
|
+
* - `ChannelStateStore` — in-memory state per channel id (replace
|
|
15
|
+
* keeps latest, append accumulates, event has no entry).
|
|
16
|
+
* - `SlotHandle` — opaque handle the default layouts use; concrete
|
|
17
|
+
* consumers narrow to `HTMLElement` (DOM), terminal region (CLI),
|
|
18
|
+
* or whatever their output medium uses.
|
|
19
|
+
*
|
|
20
|
+
* No implementation lives here. Pure types so renderer-host packages
|
|
21
|
+
* (browser, CLI, multi-user) and channel-renderer authors share a
|
|
22
|
+
* single contract.
|
|
23
|
+
*
|
|
24
|
+
* @see ADR-165 — Renderer Architecture
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/channel-service/src/renderer/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sharpee/channel-service/utils — text-content flattening helper.
|
|
3
|
+
*
|
|
4
|
+
* Owner context: platform package. Small utility used by consumers
|
|
5
|
+
* (renderers, debug logs, custom extractors) that need to project an
|
|
6
|
+
* `ITextBlock`'s decorated content tree into a plain string.
|
|
7
|
+
*
|
|
8
|
+
* Public interface:
|
|
9
|
+
* - `flattenContent(content)` — recursive concat of string nodes,
|
|
10
|
+
* stripping decoration wrappers (preserving their inner content).
|
|
11
|
+
*
|
|
12
|
+
* Originally lived inside `platform-rules.ts`; extracted here as part
|
|
13
|
+
* of the ADR-163 R1 rewrite (rule machinery removed; this helper kept
|
|
14
|
+
* because consumers may still want a one-liner string projection).
|
|
15
|
+
*
|
|
16
|
+
* @see ADR-163 — Channel-Service Platform — §6, §14
|
|
17
|
+
*/
|
|
18
|
+
import type { TextContent } from "../../text-blocks/index";
|
|
19
|
+
/**
|
|
20
|
+
* Flatten a `TextContent` array to a plain string.
|
|
21
|
+
*
|
|
22
|
+
* Recursively concatenates string nodes and strips decoration wrappers
|
|
23
|
+
* (preserving their inner content). Side-effect-free; safe to call
|
|
24
|
+
* inside producer closures.
|
|
25
|
+
*/
|
|
26
|
+
export declare function flattenContent(content: ReadonlyArray<TextContent>): string;
|
|
27
|
+
//# sourceMappingURL=flatten.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flatten.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/channel-service/src/utils/flatten.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,MAAM,CAU1E"}
|
package/utils/flatten.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @sharpee/channel-service/utils — text-content flattening helper.
|
|
4
|
+
*
|
|
5
|
+
* Owner context: platform package. Small utility used by consumers
|
|
6
|
+
* (renderers, debug logs, custom extractors) that need to project an
|
|
7
|
+
* `ITextBlock`'s decorated content tree into a plain string.
|
|
8
|
+
*
|
|
9
|
+
* Public interface:
|
|
10
|
+
* - `flattenContent(content)` — recursive concat of string nodes,
|
|
11
|
+
* stripping decoration wrappers (preserving their inner content).
|
|
12
|
+
*
|
|
13
|
+
* Originally lived inside `platform-rules.ts`; extracted here as part
|
|
14
|
+
* of the ADR-163 R1 rewrite (rule machinery removed; this helper kept
|
|
15
|
+
* because consumers may still want a one-liner string projection).
|
|
16
|
+
*
|
|
17
|
+
* @see ADR-163 — Channel-Service Platform — §6, §14
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.flattenContent = flattenContent;
|
|
21
|
+
/**
|
|
22
|
+
* Flatten a `TextContent` array to a plain string.
|
|
23
|
+
*
|
|
24
|
+
* Recursively concatenates string nodes and strips decoration wrappers
|
|
25
|
+
* (preserving their inner content). Side-effect-free; safe to call
|
|
26
|
+
* inside producer closures.
|
|
27
|
+
*/
|
|
28
|
+
function flattenContent(content) {
|
|
29
|
+
let out = '';
|
|
30
|
+
for (const node of content) {
|
|
31
|
+
if (typeof node === 'string') {
|
|
32
|
+
out += node;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
out += flattenContent(node.content);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=flatten.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flatten.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/channel-service/src/utils/flatten.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;AAWH,wCAUC;AAjBD;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,OAAmC;IAChE,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,GAAG,IAAI,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sharpee/channel-service/wire — client-side decoder
|
|
3
|
+
*
|
|
4
|
+
* Owner context: wire-protocol module. A small state machine the
|
|
5
|
+
* consumer feeds incoming packets through. Enforces the ordering
|
|
6
|
+
* invariants from ADR-163 §11 / AC-11:
|
|
7
|
+
*
|
|
8
|
+
* 1. The first server-bound packet a consumer accepts is `cmgt`.
|
|
9
|
+
* 2. `turn` packets are accepted only after `cmgt`.
|
|
10
|
+
* 3. `hello` and `command` are not server-bound — receiving one is a
|
|
11
|
+
* protocol error.
|
|
12
|
+
*
|
|
13
|
+
* The decoder does NOT render — it only validates ordering and exposes
|
|
14
|
+
* the negotiated manifest. Renderer dispatch is the consumer's
|
|
15
|
+
* concern (per ADR-165).
|
|
16
|
+
*
|
|
17
|
+
* @see ADR-163 §11 — bootstrap order invariants
|
|
18
|
+
*/
|
|
19
|
+
import type { CmgtPacket, TurnPacket, WirePacket } from "../../if-domain/index";
|
|
20
|
+
/**
|
|
21
|
+
* State exposed by the decoder after each `ingest` call.
|
|
22
|
+
*
|
|
23
|
+
* - `'awaiting-cmgt'` — initial state. Consumer has dispatched a hello
|
|
24
|
+
* and is awaiting the server's CMGT manifest.
|
|
25
|
+
* - `'live'` — CMGT received; turn packets are now accepted.
|
|
26
|
+
* - `'error'` — protocol violation. The decoder does not recover; the
|
|
27
|
+
* consumer must drop the connection (or, in single-bundle, surface
|
|
28
|
+
* the error and reset the producer).
|
|
29
|
+
*/
|
|
30
|
+
export type DecoderState = {
|
|
31
|
+
readonly status: 'awaiting-cmgt';
|
|
32
|
+
} | {
|
|
33
|
+
readonly status: 'live';
|
|
34
|
+
readonly cmgt: CmgtPacket;
|
|
35
|
+
} | {
|
|
36
|
+
readonly status: 'error';
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Decoder handle. The consumer reads `state` after each `ingest`.
|
|
41
|
+
* `lastTurn` is set when a turn is accepted and cleared when the
|
|
42
|
+
* decoder transitions to `error`.
|
|
43
|
+
*/
|
|
44
|
+
export interface Decoder {
|
|
45
|
+
readonly state: DecoderState;
|
|
46
|
+
/**
|
|
47
|
+
* Most recently accepted `turn` packet, or `null` if none has been
|
|
48
|
+
* accepted in the current session. Reset on every `ingest`.
|
|
49
|
+
*/
|
|
50
|
+
readonly lastTurn: TurnPacket | null;
|
|
51
|
+
/**
|
|
52
|
+
* Feed a packet to the decoder. After this returns, `state` reflects
|
|
53
|
+
* the new state. Returns the same handle for chaining.
|
|
54
|
+
*/
|
|
55
|
+
ingest(packet: WirePacket): Decoder;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create a fresh client-side decoder in the `awaiting-cmgt` state.
|
|
59
|
+
*/
|
|
60
|
+
export declare function createDecoder(): Decoder;
|
|
61
|
+
//# sourceMappingURL=decoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/channel-service/src/wire/decoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE7E;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAA;CAAE,GACpC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;CACrC;AAoDD;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC"}
|