@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,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sharpee/channel-service — `ChannelService` class.
|
|
3
|
+
*
|
|
4
|
+
* Owner context: platform package — runs in-process wherever the engine
|
|
5
|
+
* runs (Node CLI, multi-user server, browser zifmia, platform-browser).
|
|
6
|
+
*
|
|
7
|
+
* Public interface (per ADR-163 §6, §13, §14):
|
|
8
|
+
*
|
|
9
|
+
* - `ChannelService` — concrete runtime. Constructor takes an
|
|
10
|
+
* `IChannelRegistry` plus the client's `ClientCapabilities`.
|
|
11
|
+
* - `buildManifest()` — returns a `CmgtPacket` listing the
|
|
12
|
+
* capability-filtered channel definitions.
|
|
13
|
+
* - `build({ world, events, blocks, turn })` — walks the registry,
|
|
14
|
+
* calls each `IOChannel.produce` closure, applies mode + emit-policy
|
|
15
|
+
* semantics, and returns a `TurnPacket`.
|
|
16
|
+
*
|
|
17
|
+
* Lifecycle (ADR-163 §13): instances are cheap. A new session (engine
|
|
18
|
+
* restart, story switch, RESTART command) creates a fresh
|
|
19
|
+
* `ChannelService`. There is no global session state — `prevValues`
|
|
20
|
+
* lives on the instance.
|
|
21
|
+
*
|
|
22
|
+
* Bootstrap-order invariants (engine-enforced, not service-enforced):
|
|
23
|
+
* the engine emits `channel:manifest` before any `channel:packet`
|
|
24
|
+
* because it calls `buildManifest()` once during `start()` before
|
|
25
|
+
* entering the turn loop. This service does not throw on
|
|
26
|
+
* out-of-order calls; engineers reading the engine code can trace the
|
|
27
|
+
* order from the engine's startup sequence.
|
|
28
|
+
*
|
|
29
|
+
* @see ADR-163 — Channel-Service Platform — §6, §11, §13, §14
|
|
30
|
+
* @see ADR-165 — Renderer Architecture (consumer side)
|
|
31
|
+
*/
|
|
32
|
+
import type { IChannelRegistry, ClientCapabilities, CmgtPacket, TurnPacket } from "../if-domain/index";
|
|
33
|
+
import type { ITextBlock } from "../text-blocks/index";
|
|
34
|
+
import type { ISemanticEvent } from "../core/index";
|
|
35
|
+
/**
|
|
36
|
+
* Wire-protocol version emitted in every CMGT manifest. Bumped on
|
|
37
|
+
* breaking shape changes to packet kinds or `ChannelDefinition` fields.
|
|
38
|
+
* Additive channels do not bump version.
|
|
39
|
+
*/
|
|
40
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
41
|
+
/**
|
|
42
|
+
* Input to {@link ChannelService.build}.
|
|
43
|
+
*
|
|
44
|
+
* `world` is typed `unknown` here for consistency with
|
|
45
|
+
* `ChannelProduceContext` (if-domain cannot import `IWorldModel`).
|
|
46
|
+
* Engine call sites pass an `IWorldModel`; closures cast at the
|
|
47
|
+
* boundary.
|
|
48
|
+
*/
|
|
49
|
+
export interface BuildInput {
|
|
50
|
+
readonly world: unknown;
|
|
51
|
+
readonly events: readonly ISemanticEvent[];
|
|
52
|
+
readonly blocks: readonly ITextBlock[];
|
|
53
|
+
/** Monotonic turn count supplied by the engine. Used for `turn_id`. */
|
|
54
|
+
readonly turn: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The channel-service runtime.
|
|
58
|
+
*
|
|
59
|
+
* One instance per session. Composes a channel registry (typically
|
|
60
|
+
* `@sharpee/stdlib`'s `channelRegistry`) with the negotiated client
|
|
61
|
+
* capabilities. Holds per-channel previous-value state for sparse-emit
|
|
62
|
+
* change detection and `always`-mode replace re-emission.
|
|
63
|
+
*/
|
|
64
|
+
export declare class ChannelService {
|
|
65
|
+
private readonly registry;
|
|
66
|
+
private readonly capabilities;
|
|
67
|
+
/**
|
|
68
|
+
* Per-channel previous emitted value. Replace-mode channels store the
|
|
69
|
+
* latest emitted value (used both for sparse change detection and for
|
|
70
|
+
* `always`-mode idle-turn re-emission). Append-mode channels store the
|
|
71
|
+
* total accumulated entry count (for diagnostics; the renderer owns
|
|
72
|
+
* accumulation per ADR-165 §5). Event-mode channels do not consult
|
|
73
|
+
* prevValue.
|
|
74
|
+
*/
|
|
75
|
+
private readonly prevValues;
|
|
76
|
+
constructor(registry: IChannelRegistry, capabilities: ClientCapabilities);
|
|
77
|
+
/**
|
|
78
|
+
* Build the per-client CMGT manifest (ADR-163 §11).
|
|
79
|
+
*
|
|
80
|
+
* Walks every registered channel. Capability-gated channels
|
|
81
|
+
* (`IOChannel.gatedBy`) are filtered out when the named capability is
|
|
82
|
+
* not declared `true` for this client. Returns a fresh manifest each
|
|
83
|
+
* call; safe to invoke multiple times (the engine calls it once
|
|
84
|
+
* during `start()`).
|
|
85
|
+
*/
|
|
86
|
+
buildManifest(): CmgtPacket;
|
|
87
|
+
/**
|
|
88
|
+
* Build the turn packet for the turn just executed (ADR-163 §1, §5).
|
|
89
|
+
*
|
|
90
|
+
* For each registered, non-gated channel:
|
|
91
|
+
* 1. Builds a {@link ChannelProduceContext} with the channel's
|
|
92
|
+
* `prevValue` from this instance's cache.
|
|
93
|
+
* 2. Calls `channel.produce(ctx)`.
|
|
94
|
+
* 3. Applies mode + emit-policy semantics to the return value to
|
|
95
|
+
* decide whether the channel appears in this turn's payload and
|
|
96
|
+
* what value it carries.
|
|
97
|
+
* 4. Updates the per-channel `prevValue` cache.
|
|
98
|
+
*
|
|
99
|
+
* Returns a `TurnPacket` whose `payload` contains only the channels
|
|
100
|
+
* that emitted this turn. Sparse channels stay quiet on no-change;
|
|
101
|
+
* always channels appear every turn.
|
|
102
|
+
*/
|
|
103
|
+
build(input: BuildInput): TurnPacket;
|
|
104
|
+
/**
|
|
105
|
+
* True if the channel's `gatedBy` flag is set and the client did not
|
|
106
|
+
* declare that capability as `true`. Gated-out channels appear neither
|
|
107
|
+
* in the manifest nor in turn packets.
|
|
108
|
+
*/
|
|
109
|
+
private isGatedOut;
|
|
110
|
+
/**
|
|
111
|
+
* Apply mode + emit-policy semantics to a closure's return value.
|
|
112
|
+
*
|
|
113
|
+
* Mutates `payload` (sets `payload[channel.id]` if the channel
|
|
114
|
+
* emits) and `this.prevValues` (records the new value for sparse
|
|
115
|
+
* compare and idle re-emission).
|
|
116
|
+
*
|
|
117
|
+
* Mode semantics (ADR-163 §4, §6):
|
|
118
|
+
*
|
|
119
|
+
* - `replace`:
|
|
120
|
+
* * `undefined` — `always` re-emits prevValue (idle turn);
|
|
121
|
+
* `sparse` skips.
|
|
122
|
+
* * `null` — emit `null` (hide / stop signal); cache `null`.
|
|
123
|
+
* * value — `always` emits unconditionally; `sparse` emits only
|
|
124
|
+
* on change. Cache the new value.
|
|
125
|
+
*
|
|
126
|
+
* - `append`:
|
|
127
|
+
* * `undefined` — skip (no new entries this turn).
|
|
128
|
+
* * `null` — treated as "no new entries"; skip.
|
|
129
|
+
* * scalar — wrapped into a single-element array (closure
|
|
130
|
+
* convenience: `produce: () => 'line'` works without `[]`).
|
|
131
|
+
* * array (possibly empty) — `always` emits the array as-is;
|
|
132
|
+
* `sparse` emits only when non-empty. The renderer owns
|
|
133
|
+
* accumulation per ADR-165 §5.
|
|
134
|
+
*
|
|
135
|
+
* - `event`:
|
|
136
|
+
* * `undefined` / `null` — skip (event channels emit only on
|
|
137
|
+
* fire). Emit policy is informative only — `event` mode is
|
|
138
|
+
* inherently sparse.
|
|
139
|
+
* * value — emit the value (transient signal).
|
|
140
|
+
*
|
|
141
|
+
* The closure return type `T | T[] | undefined | null` allows append
|
|
142
|
+
* mode to return entries directly while replace and event return a
|
|
143
|
+
* scalar. Append's scalar-as-shortcut is documented above.
|
|
144
|
+
*/
|
|
145
|
+
private applyEmission;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=channel-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-service.d.ts","sourceRoot":"","sources":["../../../../../repos/sharpee/packages/channel-service/src/channel-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAEhB,kBAAkB,EAGlB,UAAU,EACV,UAAU,EACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,qBAAa,cAAc;IAYvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAZ/B;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;gBAGtC,QAAQ,EAAE,gBAAgB,EAC1B,YAAY,EAAE,kBAAkB;IAGnD;;;;;;;;OAQG;IACH,aAAa,IAAI,UAAU;IAa3B;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU;IA0BpC;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAKlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH,OAAO,CAAC,aAAa;CAmDtB"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @sharpee/channel-service — `ChannelService` class.
|
|
4
|
+
*
|
|
5
|
+
* Owner context: platform package — runs in-process wherever the engine
|
|
6
|
+
* runs (Node CLI, multi-user server, browser zifmia, platform-browser).
|
|
7
|
+
*
|
|
8
|
+
* Public interface (per ADR-163 §6, §13, §14):
|
|
9
|
+
*
|
|
10
|
+
* - `ChannelService` — concrete runtime. Constructor takes an
|
|
11
|
+
* `IChannelRegistry` plus the client's `ClientCapabilities`.
|
|
12
|
+
* - `buildManifest()` — returns a `CmgtPacket` listing the
|
|
13
|
+
* capability-filtered channel definitions.
|
|
14
|
+
* - `build({ world, events, blocks, turn })` — walks the registry,
|
|
15
|
+
* calls each `IOChannel.produce` closure, applies mode + emit-policy
|
|
16
|
+
* semantics, and returns a `TurnPacket`.
|
|
17
|
+
*
|
|
18
|
+
* Lifecycle (ADR-163 §13): instances are cheap. A new session (engine
|
|
19
|
+
* restart, story switch, RESTART command) creates a fresh
|
|
20
|
+
* `ChannelService`. There is no global session state — `prevValues`
|
|
21
|
+
* lives on the instance.
|
|
22
|
+
*
|
|
23
|
+
* Bootstrap-order invariants (engine-enforced, not service-enforced):
|
|
24
|
+
* the engine emits `channel:manifest` before any `channel:packet`
|
|
25
|
+
* because it calls `buildManifest()` once during `start()` before
|
|
26
|
+
* entering the turn loop. This service does not throw on
|
|
27
|
+
* out-of-order calls; engineers reading the engine code can trace the
|
|
28
|
+
* order from the engine's startup sequence.
|
|
29
|
+
*
|
|
30
|
+
* @see ADR-163 — Channel-Service Platform — §6, §11, §13, §14
|
|
31
|
+
* @see ADR-165 — Renderer Architecture (consumer side)
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.ChannelService = exports.PROTOCOL_VERSION = void 0;
|
|
35
|
+
/**
|
|
36
|
+
* Wire-protocol version emitted in every CMGT manifest. Bumped on
|
|
37
|
+
* breaking shape changes to packet kinds or `ChannelDefinition` fields.
|
|
38
|
+
* Additive channels do not bump version.
|
|
39
|
+
*/
|
|
40
|
+
exports.PROTOCOL_VERSION = 1;
|
|
41
|
+
/**
|
|
42
|
+
* The channel-service runtime.
|
|
43
|
+
*
|
|
44
|
+
* One instance per session. Composes a channel registry (typically
|
|
45
|
+
* `@sharpee/stdlib`'s `channelRegistry`) with the negotiated client
|
|
46
|
+
* capabilities. Holds per-channel previous-value state for sparse-emit
|
|
47
|
+
* change detection and `always`-mode replace re-emission.
|
|
48
|
+
*/
|
|
49
|
+
class ChannelService {
|
|
50
|
+
registry;
|
|
51
|
+
capabilities;
|
|
52
|
+
/**
|
|
53
|
+
* Per-channel previous emitted value. Replace-mode channels store the
|
|
54
|
+
* latest emitted value (used both for sparse change detection and for
|
|
55
|
+
* `always`-mode idle-turn re-emission). Append-mode channels store the
|
|
56
|
+
* total accumulated entry count (for diagnostics; the renderer owns
|
|
57
|
+
* accumulation per ADR-165 §5). Event-mode channels do not consult
|
|
58
|
+
* prevValue.
|
|
59
|
+
*/
|
|
60
|
+
prevValues = new Map();
|
|
61
|
+
constructor(registry, capabilities) {
|
|
62
|
+
this.registry = registry;
|
|
63
|
+
this.capabilities = capabilities;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build the per-client CMGT manifest (ADR-163 §11).
|
|
67
|
+
*
|
|
68
|
+
* Walks every registered channel. Capability-gated channels
|
|
69
|
+
* (`IOChannel.gatedBy`) are filtered out when the named capability is
|
|
70
|
+
* not declared `true` for this client. Returns a fresh manifest each
|
|
71
|
+
* call; safe to invoke multiple times (the engine calls it once
|
|
72
|
+
* during `start()`).
|
|
73
|
+
*/
|
|
74
|
+
buildManifest() {
|
|
75
|
+
const channels = [];
|
|
76
|
+
for (const channel of this.registry.all()) {
|
|
77
|
+
if (this.isGatedOut(channel))
|
|
78
|
+
continue;
|
|
79
|
+
channels.push(toDefinition(channel));
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
kind: 'cmgt',
|
|
83
|
+
protocol_version: exports.PROTOCOL_VERSION,
|
|
84
|
+
channels,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Build the turn packet for the turn just executed (ADR-163 §1, §5).
|
|
89
|
+
*
|
|
90
|
+
* For each registered, non-gated channel:
|
|
91
|
+
* 1. Builds a {@link ChannelProduceContext} with the channel's
|
|
92
|
+
* `prevValue` from this instance's cache.
|
|
93
|
+
* 2. Calls `channel.produce(ctx)`.
|
|
94
|
+
* 3. Applies mode + emit-policy semantics to the return value to
|
|
95
|
+
* decide whether the channel appears in this turn's payload and
|
|
96
|
+
* what value it carries.
|
|
97
|
+
* 4. Updates the per-channel `prevValue` cache.
|
|
98
|
+
*
|
|
99
|
+
* Returns a `TurnPacket` whose `payload` contains only the channels
|
|
100
|
+
* that emitted this turn. Sparse channels stay quiet on no-change;
|
|
101
|
+
* always channels appear every turn.
|
|
102
|
+
*/
|
|
103
|
+
build(input) {
|
|
104
|
+
const payload = {};
|
|
105
|
+
for (const channel of this.registry.all()) {
|
|
106
|
+
if (this.isGatedOut(channel))
|
|
107
|
+
continue;
|
|
108
|
+
const prevValue = this.prevValues.get(channel.id);
|
|
109
|
+
const ctx = {
|
|
110
|
+
world: input.world,
|
|
111
|
+
events: input.events,
|
|
112
|
+
blocks: input.blocks,
|
|
113
|
+
turn: input.turn,
|
|
114
|
+
prevValue,
|
|
115
|
+
};
|
|
116
|
+
const produced = channel.produce(ctx);
|
|
117
|
+
this.applyEmission(channel, produced, prevValue, payload);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
kind: 'turn',
|
|
121
|
+
turn_id: `turn-${input.turn}`,
|
|
122
|
+
payload,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* True if the channel's `gatedBy` flag is set and the client did not
|
|
127
|
+
* declare that capability as `true`. Gated-out channels appear neither
|
|
128
|
+
* in the manifest nor in turn packets.
|
|
129
|
+
*/
|
|
130
|
+
isGatedOut(channel) {
|
|
131
|
+
if (channel.gatedBy === undefined)
|
|
132
|
+
return false;
|
|
133
|
+
return this.capabilities[channel.gatedBy] !== true;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Apply mode + emit-policy semantics to a closure's return value.
|
|
137
|
+
*
|
|
138
|
+
* Mutates `payload` (sets `payload[channel.id]` if the channel
|
|
139
|
+
* emits) and `this.prevValues` (records the new value for sparse
|
|
140
|
+
* compare and idle re-emission).
|
|
141
|
+
*
|
|
142
|
+
* Mode semantics (ADR-163 §4, §6):
|
|
143
|
+
*
|
|
144
|
+
* - `replace`:
|
|
145
|
+
* * `undefined` — `always` re-emits prevValue (idle turn);
|
|
146
|
+
* `sparse` skips.
|
|
147
|
+
* * `null` — emit `null` (hide / stop signal); cache `null`.
|
|
148
|
+
* * value — `always` emits unconditionally; `sparse` emits only
|
|
149
|
+
* on change. Cache the new value.
|
|
150
|
+
*
|
|
151
|
+
* - `append`:
|
|
152
|
+
* * `undefined` — skip (no new entries this turn).
|
|
153
|
+
* * `null` — treated as "no new entries"; skip.
|
|
154
|
+
* * scalar — wrapped into a single-element array (closure
|
|
155
|
+
* convenience: `produce: () => 'line'` works without `[]`).
|
|
156
|
+
* * array (possibly empty) — `always` emits the array as-is;
|
|
157
|
+
* `sparse` emits only when non-empty. The renderer owns
|
|
158
|
+
* accumulation per ADR-165 §5.
|
|
159
|
+
*
|
|
160
|
+
* - `event`:
|
|
161
|
+
* * `undefined` / `null` — skip (event channels emit only on
|
|
162
|
+
* fire). Emit policy is informative only — `event` mode is
|
|
163
|
+
* inherently sparse.
|
|
164
|
+
* * value — emit the value (transient signal).
|
|
165
|
+
*
|
|
166
|
+
* The closure return type `T | T[] | undefined | null` allows append
|
|
167
|
+
* mode to return entries directly while replace and event return a
|
|
168
|
+
* scalar. Append's scalar-as-shortcut is documented above.
|
|
169
|
+
*/
|
|
170
|
+
applyEmission(channel, produced, prevValue, payload) {
|
|
171
|
+
const emit = channel.emit;
|
|
172
|
+
switch (channel.mode) {
|
|
173
|
+
case 'replace': {
|
|
174
|
+
if (produced === undefined) {
|
|
175
|
+
if (emit === 'always' && prevValue !== undefined) {
|
|
176
|
+
payload[channel.id] = prevValue;
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// `produced` is either a real value or `null` (hide signal).
|
|
181
|
+
// Both go through the same change-detection path: sparse
|
|
182
|
+
// channels only emit on transition; always channels emit each
|
|
183
|
+
// turn. The cached prevValue tracks `null` so a subsequent
|
|
184
|
+
// null-return on a sparse channel is recognized as no-change.
|
|
185
|
+
if (emit === 'always' || !valueEquals(produced, prevValue)) {
|
|
186
|
+
payload[channel.id] = produced;
|
|
187
|
+
}
|
|
188
|
+
this.prevValues.set(channel.id, produced);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
case 'append': {
|
|
192
|
+
if (produced === undefined || produced === null)
|
|
193
|
+
return;
|
|
194
|
+
const entries = Array.isArray(produced) ? produced : [produced];
|
|
195
|
+
if (emit === 'always') {
|
|
196
|
+
payload[channel.id] = entries;
|
|
197
|
+
}
|
|
198
|
+
else if (entries.length > 0) {
|
|
199
|
+
payload[channel.id] = entries;
|
|
200
|
+
}
|
|
201
|
+
// Track entry count for diagnostics; renderer owns the buffer.
|
|
202
|
+
const prevCount = typeof prevValue === 'number' ? prevValue : 0;
|
|
203
|
+
this.prevValues.set(channel.id, prevCount + entries.length);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
case 'event': {
|
|
207
|
+
if (produced === undefined || produced === null)
|
|
208
|
+
return;
|
|
209
|
+
// Multi-firing in one turn collapses to the closure's last
|
|
210
|
+
// return value — the closure itself is the single fire site.
|
|
211
|
+
payload[channel.id] = produced;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
exports.ChannelService = ChannelService;
|
|
218
|
+
/**
|
|
219
|
+
* Project an `IOChannel` into a wire-shaped `ChannelDefinition`.
|
|
220
|
+
*
|
|
221
|
+
* The closure does not cross the wire; only identity and configuration.
|
|
222
|
+
*/
|
|
223
|
+
function toDefinition(channel) {
|
|
224
|
+
return {
|
|
225
|
+
id: channel.id,
|
|
226
|
+
contentType: channel.contentType,
|
|
227
|
+
mode: channel.mode,
|
|
228
|
+
emit: channel.emit,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Deep value equality for sparse-emit change detection.
|
|
233
|
+
*
|
|
234
|
+
* Uses `JSON.stringify` for object/array compares — adequate for the
|
|
235
|
+
* value shapes carried over the wire (scalars, plain objects, arrays
|
|
236
|
+
* of scalars or text content nodes). Not safe for cyclic graphs, but
|
|
237
|
+
* those cannot cross the JSON wire anyway.
|
|
238
|
+
*/
|
|
239
|
+
function valueEquals(a, b) {
|
|
240
|
+
if (a === b)
|
|
241
|
+
return true;
|
|
242
|
+
if (a === undefined || b === undefined)
|
|
243
|
+
return false;
|
|
244
|
+
if (a === null || b === null)
|
|
245
|
+
return a === b;
|
|
246
|
+
if (typeof a !== typeof b)
|
|
247
|
+
return false;
|
|
248
|
+
if (typeof a === 'object') {
|
|
249
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
250
|
+
}
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=channel-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-service.js","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/channel-service/src/channel-service.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;;;AAcH;;;;GAIG;AACU,QAAA,gBAAgB,GAAG,CAAC,CAAC;AAkBlC;;;;;;;GAOG;AACH,MAAa,cAAc;IAYN;IACA;IAZnB;;;;;;;OAOG;IACc,UAAU,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEzD,YACmB,QAA0B,EAC1B,YAAgC;QADhC,aAAQ,GAAR,QAAQ,CAAkB;QAC1B,iBAAY,GAAZ,YAAY,CAAoB;IAChD,CAAC;IAEJ;;;;;;;;OAQG;IACH,aAAa;QACX,MAAM,QAAQ,GAAwB,EAAE,CAAC;QACzC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;YAC1C,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,SAAS;YACvC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,gBAAgB,EAAE,wBAAgB;YAClC,QAAQ;SACT,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,KAAiB;QACrB,MAAM,OAAO,GAA4B,EAAE,CAAC;QAE5C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;YAC1C,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,SAAS;YAEvC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAClD,MAAM,GAAG,GAA0B;gBACjC,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,SAAS;aACV,CAAC;YAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,QAAQ,KAAK,CAAC,IAAI,EAAE;YAC7B,OAAO;SACR,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACK,UAAU,CAAC,OAAkB;QACnC,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAChD,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACrD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACK,aAAa,CACnB,OAAkB,EAClB,QAAiB,EACjB,SAAkB,EAClB,OAAgC;QAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC3B,IAAI,IAAI,KAAK,QAAQ,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;wBACjD,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;oBAClC,CAAC;oBACD,OAAO;gBACT,CAAC;gBACD,6DAA6D;gBAC7D,yDAAyD;gBACzD,8DAA8D;gBAC9D,2DAA2D;gBAC3D,8DAA8D;gBAC9D,IAAI,IAAI,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;oBAC3D,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC;gBACjC,CAAC;gBACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;gBAC1C,OAAO;YACT,CAAC;YAED,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI;oBAAE,OAAO;gBACxD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;gBAChE,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACtB,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;gBAChC,CAAC;qBAAM,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC9B,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;gBAChC,CAAC;gBACD,+DAA+D;gBAC/D,MAAM,SAAS,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC5D,OAAO;YACT,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI;oBAAE,OAAO;gBACxD,2DAA2D;gBAC3D,6DAA6D;gBAC7D,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC;gBAC/B,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAhLD,wCAgLC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,OAAkB;IACtC,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,CAAU,EAAE,CAAU;IACzC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sharpee/channel-service
|
|
3
|
+
*
|
|
4
|
+
* Channel-I/O wire producer for Sharpee surfaces (ADR-163,
|
|
5
|
+
* closure-per-channel model — 2026-05-02 rewrite + 2026-05-03 refinement).
|
|
6
|
+
*
|
|
7
|
+
* Owner context: platform package — runs in-process wherever the engine
|
|
8
|
+
* runs (Node CLI, multi-user server, browser zifmia, platform-browser).
|
|
9
|
+
*
|
|
10
|
+
* Public interface:
|
|
11
|
+
*
|
|
12
|
+
* - **`ChannelService`** — concrete runtime class. Constructor takes an
|
|
13
|
+
* `IChannelRegistry` plus the client's `ClientCapabilities`.
|
|
14
|
+
* - `buildManifest()` returns a `CmgtPacket` (capability-filtered).
|
|
15
|
+
* - `build({ world, events, blocks, turn })` walks the registry,
|
|
16
|
+
* calls each `IOChannel.produce`, and returns a `TurnPacket`.
|
|
17
|
+
* - **Channel + wire types** are re-exported from `@sharpee/if-domain`
|
|
18
|
+
* for caller convenience. `if-domain` is the single canonical home
|
|
19
|
+
* for these contracts (CLAUDE.md rule 7b).
|
|
20
|
+
* - **Wire decoder** ships here (`createDecoder`, `Decoder`,
|
|
21
|
+
* `DecoderState`) for clients that receive packets and need
|
|
22
|
+
* bootstrap-order enforcement.
|
|
23
|
+
* - **`flattenContent`** utility for projecting `TextContent` arrays
|
|
24
|
+
* to plain strings (used by closures and renderers).
|
|
25
|
+
*
|
|
26
|
+
* Standard channel definitions (`main`, `prompt`, `score`, `turn`,
|
|
27
|
+
* `location`, media channels, etc.) live in `@sharpee/stdlib` per
|
|
28
|
+
* ADR-163 §7, §14. This package is domain-agnostic — it does not know
|
|
29
|
+
* what `scoring` means or what `room.name` means.
|
|
30
|
+
*
|
|
31
|
+
* @see ADR-163 — Channel-Service Platform
|
|
32
|
+
* @see ADR-165 — Renderer Architecture (consumer side)
|
|
33
|
+
*/
|
|
34
|
+
export { ChannelService, PROTOCOL_VERSION } from './channel-service';
|
|
35
|
+
export type { BuildInput } from './channel-service';
|
|
36
|
+
export type { IOChannel, IChannelRegistry, ChannelProduceContext, ChannelContentType, ChannelMode, ChannelEmitPolicy, ClientCapabilities, CapabilityFlag, ChannelDefinition, HelloPacket, CmgtPacket, TurnPacket, CommandPacket, WirePacket, } from "../if-domain/index";
|
|
37
|
+
export { createDecoder, type Decoder, type DecoderState } from './wire';
|
|
38
|
+
export { flattenContent } from './utils/flatten';
|
|
39
|
+
export { renderToString, renderStatusLine } from './render-to-string';
|
|
40
|
+
export type { CLIRenderOptions } from './render-to-string';
|
|
41
|
+
export { Renderer, createRenderer, createJsonTreeFallbackFactory, type RendererOptions, type FallbackOutputSink, type FallbackWarningSink, } from './renderer';
|
|
42
|
+
export type { ChannelRenderer, IRenderer, ChannelStateStore, SlotHandle, } from './renderer';
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../repos/sharpee/packages/channel-service/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,UAAU,GACX,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAC;AAExE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAQjD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EACL,QAAQ,EACR,cAAc,EACd,6BAA6B,EAC7B,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @sharpee/channel-service
|
|
4
|
+
*
|
|
5
|
+
* Channel-I/O wire producer for Sharpee surfaces (ADR-163,
|
|
6
|
+
* closure-per-channel model — 2026-05-02 rewrite + 2026-05-03 refinement).
|
|
7
|
+
*
|
|
8
|
+
* Owner context: platform package — runs in-process wherever the engine
|
|
9
|
+
* runs (Node CLI, multi-user server, browser zifmia, platform-browser).
|
|
10
|
+
*
|
|
11
|
+
* Public interface:
|
|
12
|
+
*
|
|
13
|
+
* - **`ChannelService`** — concrete runtime class. Constructor takes an
|
|
14
|
+
* `IChannelRegistry` plus the client's `ClientCapabilities`.
|
|
15
|
+
* - `buildManifest()` returns a `CmgtPacket` (capability-filtered).
|
|
16
|
+
* - `build({ world, events, blocks, turn })` walks the registry,
|
|
17
|
+
* calls each `IOChannel.produce`, and returns a `TurnPacket`.
|
|
18
|
+
* - **Channel + wire types** are re-exported from `@sharpee/if-domain`
|
|
19
|
+
* for caller convenience. `if-domain` is the single canonical home
|
|
20
|
+
* for these contracts (CLAUDE.md rule 7b).
|
|
21
|
+
* - **Wire decoder** ships here (`createDecoder`, `Decoder`,
|
|
22
|
+
* `DecoderState`) for clients that receive packets and need
|
|
23
|
+
* bootstrap-order enforcement.
|
|
24
|
+
* - **`flattenContent`** utility for projecting `TextContent` arrays
|
|
25
|
+
* to plain strings (used by closures and renderers).
|
|
26
|
+
*
|
|
27
|
+
* Standard channel definitions (`main`, `prompt`, `score`, `turn`,
|
|
28
|
+
* `location`, media channels, etc.) live in `@sharpee/stdlib` per
|
|
29
|
+
* ADR-163 §7, §14. This package is domain-agnostic — it does not know
|
|
30
|
+
* what `scoring` means or what `room.name` means.
|
|
31
|
+
*
|
|
32
|
+
* @see ADR-163 — Channel-Service Platform
|
|
33
|
+
* @see ADR-165 — Renderer Architecture (consumer side)
|
|
34
|
+
*/
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createJsonTreeFallbackFactory = exports.createRenderer = exports.Renderer = exports.renderStatusLine = exports.renderToString = exports.flattenContent = exports.createDecoder = exports.PROTOCOL_VERSION = exports.ChannelService = void 0;
|
|
37
|
+
var channel_service_1 = require("./channel-service");
|
|
38
|
+
Object.defineProperty(exports, "ChannelService", { enumerable: true, get: function () { return channel_service_1.ChannelService; } });
|
|
39
|
+
Object.defineProperty(exports, "PROTOCOL_VERSION", { enumerable: true, get: function () { return channel_service_1.PROTOCOL_VERSION; } });
|
|
40
|
+
var wire_1 = require("./wire");
|
|
41
|
+
Object.defineProperty(exports, "createDecoder", { enumerable: true, get: function () { return wire_1.createDecoder; } });
|
|
42
|
+
var flatten_1 = require("./utils/flatten");
|
|
43
|
+
Object.defineProperty(exports, "flattenContent", { enumerable: true, get: function () { return flatten_1.flattenContent; } });
|
|
44
|
+
// Display flatteners (ADR-174 Phase 2 — `renderToString` / `renderStatusLine`
|
|
45
|
+
// migrated here from `@sharpee/text-service` per OQ-1 resolution).
|
|
46
|
+
// Used by transcript tooling, dev scripts, and chat overlays that need a
|
|
47
|
+
// single string projection of an `ITextBlock[]`. `flattenContent` (above)
|
|
48
|
+
// is the lower-level helper used inside producer closures; `renderToString`
|
|
49
|
+
// adds smart block-joining, ANSI translation, and status-block filtering.
|
|
50
|
+
var render_to_string_1 = require("./render-to-string");
|
|
51
|
+
Object.defineProperty(exports, "renderToString", { enumerable: true, get: function () { return render_to_string_1.renderToString; } });
|
|
52
|
+
Object.defineProperty(exports, "renderStatusLine", { enumerable: true, get: function () { return render_to_string_1.renderStatusLine; } });
|
|
53
|
+
// Consumer-side renderer (ADR-165) — see ./renderer.
|
|
54
|
+
var renderer_1 = require("./renderer");
|
|
55
|
+
Object.defineProperty(exports, "Renderer", { enumerable: true, get: function () { return renderer_1.Renderer; } });
|
|
56
|
+
Object.defineProperty(exports, "createRenderer", { enumerable: true, get: function () { return renderer_1.createRenderer; } });
|
|
57
|
+
Object.defineProperty(exports, "createJsonTreeFallbackFactory", { enumerable: true, get: function () { return renderer_1.createJsonTreeFallbackFactory; } });
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/channel-service/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;;AAEH,qDAAqE;AAA5D,iHAAA,cAAc,OAAA;AAAE,mHAAA,gBAAgB,OAAA;AAoBzC,+BAAwE;AAA/D,qGAAA,aAAa,OAAA;AAEtB,2CAAiD;AAAxC,yGAAA,cAAc,OAAA;AAEvB,8EAA8E;AAC9E,mEAAmE;AACnE,yEAAyE;AACzE,0EAA0E;AAC1E,4EAA4E;AAC5E,0EAA0E;AAC1E,uDAAsE;AAA7D,kHAAA,cAAc,OAAA;AAAE,oHAAA,gBAAgB,OAAA;AAGzC,qDAAqD;AACrD,uCAOoB;AANlB,oGAAA,QAAQ,OAAA;AACR,0GAAA,cAAc,OAAA;AACd,yHAAA,6BAA6B,OAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sharpee/channel-service",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Channel-service platform — universal channel-I/O wire producer (ADR-163)",
|
|
5
|
+
"main": "./index.js",
|
|
6
|
+
"types": "./index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"require": "./index.js",
|
|
11
|
+
"default": "./index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@sharpee/core": "^1.0.0",
|
|
16
|
+
"@sharpee/if-domain": "^1.0.0",
|
|
17
|
+
"@sharpee/text-blocks": "^1.0.0",
|
|
18
|
+
"@sharpee/world-model": "^1.0.0"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"interactive-fiction",
|
|
22
|
+
"if",
|
|
23
|
+
"text-adventure",
|
|
24
|
+
"sharpee",
|
|
25
|
+
"channel-service",
|
|
26
|
+
"channel-io",
|
|
27
|
+
"wire-protocol"
|
|
28
|
+
],
|
|
29
|
+
"author": "Sharpee Team",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/ChicagoDave/sharpee.git",
|
|
34
|
+
"directory": "packages/channel-service"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/ChicagoDave/sharpee#readme",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/ChicagoDave/sharpee/issues"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `renderToString` and `renderStatusLine` — flatten an `ITextBlock[]`
|
|
3
|
+
* to a single display string.
|
|
4
|
+
*
|
|
5
|
+
* Owner context: `@sharpee/channel-service`. Block-flattening helpers
|
|
6
|
+
* consumed by transcript tooling, chat overlays, and dev scripts.
|
|
7
|
+
* Channel-service is downstream of engine and upstream of clients —
|
|
8
|
+
* the right dependency position for a helper that walks ITextBlock[]
|
|
9
|
+
* for display.
|
|
10
|
+
*
|
|
11
|
+
* Public interface:
|
|
12
|
+
* - `renderToString(blocks, options?)` — flatten blocks to a joined
|
|
13
|
+
* string with smart separators between same-key vs different-key
|
|
14
|
+
* block transitions. Decorations translate to ANSI codes when
|
|
15
|
+
* `options.ansi === true`, or to bracket-stripped plain text
|
|
16
|
+
* otherwise.
|
|
17
|
+
* - `renderStatusLine(blocks, options?)` — render `status.*` blocks
|
|
18
|
+
* to a single pipe-separated line for status-bar display.
|
|
19
|
+
* - `CLIRenderOptions` — option shape (ansi, blockSeparator,
|
|
20
|
+
* colors, includeStatus). Name preserved from the prior
|
|
21
|
+
* `@sharpee/text-service` home; not CLI-specific in practice
|
|
22
|
+
* (zifmia uses `renderToString` for browser chat bubbles).
|
|
23
|
+
*
|
|
24
|
+
* Ported from `@sharpee/text-service/src/cli-renderer.ts` per ADR-174
|
|
25
|
+
* Phase 2 (OQ-1 resolution, 2026-05-10). The original file remains
|
|
26
|
+
* compilable in text-service through Phase 2 for zifmia's sake; Phase
|
|
27
|
+
* 3 deletes the package.
|
|
28
|
+
*
|
|
29
|
+
* @see ADR-174 — Decoration Architecture and Engine-Internal Prose Pipeline
|
|
30
|
+
* @see ADR-163 — Channel-Service Platform
|
|
31
|
+
*/
|
|
32
|
+
import type { ITextBlock } from "../text-blocks/index";
|
|
33
|
+
/**
|
|
34
|
+
* CLI render options
|
|
35
|
+
*/
|
|
36
|
+
export interface CLIRenderOptions {
|
|
37
|
+
/** Enable ANSI color codes (default: false) */
|
|
38
|
+
ansi?: boolean;
|
|
39
|
+
/** Separator between blocks (default: '\n\n') */
|
|
40
|
+
blockSeparator?: string;
|
|
41
|
+
/** Story-defined color mappings */
|
|
42
|
+
colors?: Record<string, string>;
|
|
43
|
+
/** Include status blocks in output (default: false) */
|
|
44
|
+
includeStatus?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Render `ITextBlock[]` to string for display.
|
|
48
|
+
*
|
|
49
|
+
* Uses smart joining: single newline between consecutive blocks of the
|
|
50
|
+
* same key, double newline (or `options.blockSeparator`) between blocks
|
|
51
|
+
* of different keys. This keeps related output together (e.g., multiple
|
|
52
|
+
* "Taken." messages) while separating distinct sections.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const output = renderToString(blocks, { ansi: true });
|
|
56
|
+
* console.log(output);
|
|
57
|
+
*/
|
|
58
|
+
export declare function renderToString(blocks: ITextBlock[], options?: CLIRenderOptions): string;
|
|
59
|
+
/**
|
|
60
|
+
* Render status blocks to a single line (for status bar display).
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const status = renderStatusLine(blocks);
|
|
64
|
+
* // "West of House | Score: 0 | Turns: 1"
|
|
65
|
+
*/
|
|
66
|
+
export declare function renderStatusLine(blocks: ITextBlock[], options?: CLIRenderOptions): string;
|
|
67
|
+
//# sourceMappingURL=render-to-string.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-to-string.d.ts","sourceRoot":"","sources":["../../../../../repos/sharpee/packages/channel-service/src/render-to-string.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAA4B,MAAM,sBAAsB,CAAC;AAGjF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC,uDAAuD;IACvD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAqJD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CA+BR;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CA6BR"}
|