@graphrefly/graphrefly 0.17.0 → 0.19.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/dist/{chunk-R6OHUUYB.js → chunk-AHRKWMNI.js} +7 -7
- package/dist/chunk-AHRKWMNI.js.map +1 -0
- package/dist/{chunk-2PORF4RP.js → chunk-BER7UYLM.js} +27 -32
- package/dist/chunk-BER7UYLM.js.map +1 -0
- package/dist/{chunk-646OG3PO.js → chunk-IRZAGZUB.js} +51 -52
- package/dist/chunk-IRZAGZUB.js.map +1 -0
- package/dist/{chunk-IHJHBADD.js → chunk-JC2SN46B.js} +385 -197
- package/dist/chunk-JC2SN46B.js.map +1 -0
- package/dist/{chunk-XJ6EMQ22.js → chunk-OO5QOAXI.js} +4 -10
- package/dist/chunk-OO5QOAXI.js.map +1 -0
- package/dist/{chunk-YXROQFXZ.js → chunk-UW77D7SP.js} +3 -3
- package/dist/{chunk-F2ULI3Q3.js → chunk-XUOY3YKN.js} +7 -3
- package/dist/chunk-XUOY3YKN.js.map +1 -0
- package/dist/chunk-YLR5JUJZ.js +111 -0
- package/dist/chunk-YLR5JUJZ.js.map +1 -0
- package/dist/{chunk-BV3TPSBK.js → chunk-YXR3WW3Q.js} +740 -755
- package/dist/chunk-YXR3WW3Q.js.map +1 -0
- package/dist/compat/nestjs/index.cjs +1127 -983
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +4 -4
- package/dist/compat/nestjs/index.d.ts +4 -4
- package/dist/compat/nestjs/index.js +7 -13
- package/dist/core/index.cjs +653 -749
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +7 -7
- package/dist/extra/index.cjs +773 -795
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +4 -4
- package/dist/extra/index.d.ts +4 -4
- package/dist/extra/index.js +5 -11
- package/dist/graph/index.cjs +1036 -975
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +3 -3
- package/dist/graph/index.d.ts +3 -3
- package/dist/graph/index.js +8 -8
- package/dist/{graph-fCsaaVIa.d.cts → graph-KsTe57nI.d.cts} +127 -51
- package/dist/{graph-Dc-P9BVm.d.ts → graph-mILUUqW8.d.ts} +127 -51
- package/dist/{index-DhXznWyH.d.ts → index-8a605sg9.d.ts} +2 -2
- package/dist/{index-D7y9Q8W4.d.ts → index-B2SvPEbc.d.ts} +8 -69
- package/dist/{index-YlOH1Gw6.d.cts → index-BBUYZfJ1.d.cts} +122 -78
- package/dist/{index-ClaKZFPl.d.cts → index-Bjh5C1Tp.d.cts} +38 -35
- package/dist/{index-DWq0P9T6.d.ts → index-BjtlNirP.d.cts} +5 -7
- package/dist/{index-N704txAA.d.ts → index-BnkMgNNa.d.ts} +38 -35
- package/dist/{index-BBVBYPxr.d.cts → index-CgSiUouz.d.ts} +5 -7
- package/dist/{index-BmoUvOGN.d.ts → index-CvKzv0AW.d.ts} +122 -78
- package/dist/{index-4OIX-q0C.d.cts → index-UudxGnzc.d.cts} +8 -69
- package/dist/{index-DlGMf_Qe.d.cts → index-VHA43cGP.d.cts} +2 -2
- package/dist/index.cjs +6146 -5725
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +617 -383
- package/dist/index.d.ts +617 -383
- package/dist/index.js +4401 -4028
- package/dist/index.js.map +1 -1
- package/dist/{meta-BV4pj9ML.d.cts → meta-BnG7XAaE.d.cts} +395 -289
- package/dist/{meta-BV4pj9ML.d.ts → meta-BnG7XAaE.d.ts} +395 -289
- package/dist/observable-C8Kx_O6k.d.cts +36 -0
- package/dist/observable-DcBwQY7t.d.ts +36 -0
- package/dist/patterns/reactive-layout/index.cjs +1037 -857
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +3 -3
- package/dist/patterns/reactive-layout/index.d.ts +3 -3
- package/dist/patterns/reactive-layout/index.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-2PORF4RP.js.map +0 -1
- package/dist/chunk-646OG3PO.js.map +0 -1
- package/dist/chunk-BV3TPSBK.js.map +0 -1
- package/dist/chunk-EBNKJULL.js +0 -231
- package/dist/chunk-EBNKJULL.js.map +0 -1
- package/dist/chunk-F2ULI3Q3.js.map +0 -1
- package/dist/chunk-IHJHBADD.js.map +0 -1
- package/dist/chunk-R6OHUUYB.js.map +0 -1
- package/dist/chunk-XJ6EMQ22.js.map +0 -1
- package/dist/observable-Cz-AWhwR.d.cts +0 -42
- package/dist/observable-DCqlwGyl.d.ts +0 -42
- /package/dist/{chunk-YXROQFXZ.js.map → chunk-UW77D7SP.js.map} +0 -0
|
@@ -1,3 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphReFly message protocol — §1 `~/src/graphrefly/GRAPHREFLY-SPEC.md`.
|
|
3
|
+
* Emissions are always `[[Type, Data?], ...]` (no single-tuple shorthand).
|
|
4
|
+
*
|
|
5
|
+
* ## Canonical message ordering (within a composite batch)
|
|
6
|
+
*
|
|
7
|
+
* When multiple message types appear in a single `down()` call, the canonical
|
|
8
|
+
* delivery order is determined by **signal tier**:
|
|
9
|
+
*
|
|
10
|
+
* | Tier | Signals | Role | Batch behavior |
|
|
11
|
+
* |------|------------------------|-------------------|-------------------------------------|
|
|
12
|
+
* | 0 | START | Subscribe handshake | Immediate (never deferred) |
|
|
13
|
+
* | 1 | DIRTY, INVALIDATE | Notification | Immediate (never deferred) |
|
|
14
|
+
* | 2 | PAUSE, RESUME | Flow control | Immediate (never deferred) |
|
|
15
|
+
* | 3 | DATA, RESOLVED | Value settlement | Deferred inside `batch()` |
|
|
16
|
+
* | 4 | COMPLETE, ERROR | Terminal lifecycle | Deferred to after phase-2 |
|
|
17
|
+
* | 5 | TEARDOWN | Destruction | Immediate (usually sent alone) |
|
|
18
|
+
*
|
|
19
|
+
* **Rule:** Within `downWithBatch`, messages are partitioned by tier and delivered
|
|
20
|
+
* in tier order. This ensures phase-2 values (DATA/RESOLVED) reach sinks before
|
|
21
|
+
* terminal signals (COMPLETE/ERROR) mark the node as done, preventing the
|
|
22
|
+
* "COMPLETE-before-DATA" class of bugs. Sources that emit in canonical order
|
|
23
|
+
* naturally partition correctly with zero overhead.
|
|
24
|
+
*
|
|
25
|
+
* Unknown message types (forward-compat) are tier 1 (immediate).
|
|
26
|
+
*
|
|
27
|
+
* ## Meta node bypass rules (centralized — GRAPHREFLY-SPEC §2.3)
|
|
28
|
+
*
|
|
29
|
+
* - **INVALIDATE** via `graph.signal()` — no-op on meta nodes (cached values preserved).
|
|
30
|
+
* - **COMPLETE / ERROR** — not propagated from parent to meta (meta outlives terminal
|
|
31
|
+
* state for post-mortem writes like setting `meta.error` after ERROR).
|
|
32
|
+
* - **TEARDOWN** — propagated from parent to meta, releasing meta resources.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Subscribe-time handshake (`START`). Delivered to each new sink at the top of
|
|
36
|
+
* `subscribe()` — `[[START]]` for a SENTINEL (no cached value) node or
|
|
37
|
+
* `[[START], [DATA, cached]]` for a node with a cached value.
|
|
38
|
+
*
|
|
39
|
+
* Semantics: "upstream connected and ready to flow." A new sink receiving
|
|
40
|
+
* `[[START]]` alone knows the upstream is alive but has no current value; a
|
|
41
|
+
* sink receiving `[[START], [DATA, v]]` knows the upstream is ready
|
|
42
|
+
* with value `v`. Absence of `START` before any other message means the
|
|
43
|
+
* subscription was either never established or the node is terminal.
|
|
44
|
+
*
|
|
45
|
+
* Tier 0 — immediate, delivered before any DIRTY/DATA in the same batch.
|
|
46
|
+
* Not forwarded through nodes — each node emits its own `START` to its own
|
|
47
|
+
* new sinks.
|
|
48
|
+
*/
|
|
49
|
+
declare const START: unique symbol;
|
|
50
|
+
/** Value delivery (`DATA`, value). Tier 3 — deferred inside `batch()`. */
|
|
51
|
+
declare const DATA: unique symbol;
|
|
52
|
+
/** Phase 1: value about to change. Tier 1 — immediate. */
|
|
53
|
+
declare const DIRTY: unique symbol;
|
|
54
|
+
/** Phase 2: dirty pass completed, value unchanged. Tier 3 — deferred inside `batch()`. */
|
|
55
|
+
declare const RESOLVED: unique symbol;
|
|
56
|
+
/** Clear cached state; do not auto-emit. Tier 1 — immediate. */
|
|
57
|
+
declare const INVALIDATE: unique symbol;
|
|
58
|
+
/** Suspend activity. Tier 2 — immediate. */
|
|
59
|
+
declare const PAUSE: unique symbol;
|
|
60
|
+
/** Resume after pause. Tier 2 — immediate. */
|
|
61
|
+
declare const RESUME: unique symbol;
|
|
62
|
+
/** Permanent cleanup. Tier 5 — immediate (usually sent alone). */
|
|
63
|
+
declare const TEARDOWN: unique symbol;
|
|
64
|
+
/** Clean termination. Tier 4 — delivered after phase-2 in the same batch. */
|
|
65
|
+
declare const COMPLETE: unique symbol;
|
|
66
|
+
/** Error termination. Tier 4 — delivered after phase-2 in the same batch. */
|
|
67
|
+
declare const ERROR: unique symbol;
|
|
68
|
+
/** Known protocol type symbols (open set — other symbols are valid and forward). */
|
|
69
|
+
declare const knownMessageTypes: readonly symbol[];
|
|
70
|
+
/** One protocol tuple: `[Type, optional payload]`. */
|
|
71
|
+
type Message = readonly [symbol, unknown?];
|
|
72
|
+
/**
|
|
73
|
+
* A batch of tuples — the wire shape for `node.down()` / `node.up()`.
|
|
74
|
+
*/
|
|
75
|
+
type Messages = readonly Message[];
|
|
76
|
+
/**
|
|
77
|
+
* Whether `t` is one of the built-in protocol symbols in this module.
|
|
78
|
+
*
|
|
79
|
+
* @param t — Message type symbol (unknown types are still valid; they must forward).
|
|
80
|
+
* @returns `true` for `DATA`, `DIRTY`, `RESOLVED`, etc.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* import { DATA, DIRTY, isKnownMessageType } from "@graphrefly/graphrefly-ts";
|
|
85
|
+
*
|
|
86
|
+
* isKnownMessageType(DATA); // true
|
|
87
|
+
* isKnownMessageType(Symbol("custom")); // false
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function isKnownMessageType(t: symbol): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Returns the signal tier for a message type (see module-level ordering table).
|
|
93
|
+
*
|
|
94
|
+
* - 0: subscribe handshake (START) — immediate, first in canonical order
|
|
95
|
+
* - 1: notification (DIRTY, INVALIDATE) — immediate
|
|
96
|
+
* - 2: flow control (PAUSE, RESUME) — immediate
|
|
97
|
+
* - 3: value (DATA, RESOLVED) — deferred inside `batch()`
|
|
98
|
+
* - 4: terminal (COMPLETE, ERROR) — delivered after phase-3
|
|
99
|
+
* - 5: destruction (TEARDOWN) — immediate, usually alone
|
|
100
|
+
* - 1 for unknown types (forward-compat: immediate)
|
|
101
|
+
*
|
|
102
|
+
* @param t — Message type symbol.
|
|
103
|
+
* @returns Tier number (0–5).
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* import { DATA, DIRTY, COMPLETE, TEARDOWN, messageTier, START } from "@graphrefly/graphrefly-ts";
|
|
108
|
+
*
|
|
109
|
+
* messageTier(START); // 0
|
|
110
|
+
* messageTier(DIRTY); // 1
|
|
111
|
+
* messageTier(DATA); // 3
|
|
112
|
+
* messageTier(COMPLETE); // 4
|
|
113
|
+
* messageTier(TEARDOWN); // 5
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
declare function messageTier(t: symbol): number;
|
|
117
|
+
/**
|
|
118
|
+
* Returns whether this tuple is deferred by `batch()` (phase 2: `DATA` or `RESOLVED`).
|
|
119
|
+
*
|
|
120
|
+
* @param msg — Single message tuple.
|
|
121
|
+
* @returns `true` if `msg` is `DATA` or `RESOLVED`.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* import { DATA, RESOLVED, DIRTY, isPhase2Message } from "@graphrefly/graphrefly-ts";
|
|
126
|
+
*
|
|
127
|
+
* isPhase2Message([DATA, 42]); // true
|
|
128
|
+
* isPhase2Message([RESOLVED]); // true
|
|
129
|
+
* isPhase2Message([DIRTY]); // false
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
declare function isPhase2Message(msg: Message): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Returns whether this message type is terminal (COMPLETE or ERROR).
|
|
135
|
+
* Terminal messages are delivered after phase-2 in the same batch to prevent
|
|
136
|
+
* the node from becoming terminal before value messages reach sinks.
|
|
137
|
+
*
|
|
138
|
+
* @param t — Message type symbol.
|
|
139
|
+
* @returns `true` for `COMPLETE` or `ERROR`.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { COMPLETE, ERROR, DATA, isTerminalMessage } from "@graphrefly/graphrefly-ts";
|
|
144
|
+
*
|
|
145
|
+
* isTerminalMessage(COMPLETE); // true
|
|
146
|
+
* isTerminalMessage(ERROR); // true
|
|
147
|
+
* isTerminalMessage(DATA); // false
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
declare function isTerminalMessage(t: symbol): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Whether `t` is a graph-local signal that should NOT cross a wire/transport
|
|
153
|
+
* boundary (SSE, WebSocket, worker bridge, persistence sinks).
|
|
154
|
+
*
|
|
155
|
+
* Local-only signals (tier 0–2): START, DIRTY, INVALIDATE, PAUSE, RESUME.
|
|
156
|
+
* These are internal to the reactive graph — subscribe handshakes,
|
|
157
|
+
* notification phases, and flow control have no semantics for remote consumers.
|
|
158
|
+
*
|
|
159
|
+
* Wire-crossing signals (tier 3+): DATA, RESOLVED, COMPLETE, ERROR, TEARDOWN.
|
|
160
|
+
* Unknown message types (spec §1.3.6 forward-compat) also cross the wire.
|
|
161
|
+
*
|
|
162
|
+
* Individual adapters may further opt-in to local signals for observability
|
|
163
|
+
* (e.g. SSE `includeDirty`, `includeResolved` options). Storage/persistence
|
|
164
|
+
* adapters that need INVALIDATE for remote cache-clear should explicitly
|
|
165
|
+
* forward it despite `isLocalOnly(INVALIDATE) === true`. The default is to
|
|
166
|
+
* skip all local-only signals at the boundary.
|
|
167
|
+
*
|
|
168
|
+
* @param t — Message type symbol.
|
|
169
|
+
* @returns `true` if the message should be kept local (not sent over wire).
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* import { START, DIRTY, DATA, COMPLETE, isLocalOnly } from "@graphrefly/graphrefly-ts";
|
|
174
|
+
*
|
|
175
|
+
* isLocalOnly(START); // true — subscribe handshake
|
|
176
|
+
* isLocalOnly(DIRTY); // true — notification phase
|
|
177
|
+
* isLocalOnly(RESOLVED); // false — value settlement crosses wire
|
|
178
|
+
* isLocalOnly(DATA); // false — value crosses wire
|
|
179
|
+
* isLocalOnly(COMPLETE); // false — terminal crosses wire
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* @category core
|
|
183
|
+
*/
|
|
184
|
+
declare function isLocalOnly(t: symbol): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Whether `t` should be propagated from a parent node to its companion meta nodes.
|
|
187
|
+
* Only TEARDOWN propagates; COMPLETE/ERROR/INVALIDATE do not (meta outlives parent
|
|
188
|
+
* terminal state for post-mortem writes).
|
|
189
|
+
*
|
|
190
|
+
* @param t — Message type symbol.
|
|
191
|
+
* @returns `true` if the signal should reach meta nodes.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* import { TEARDOWN, COMPLETE, ERROR, propagatesToMeta } from "@graphrefly/graphrefly-ts";
|
|
196
|
+
*
|
|
197
|
+
* propagatesToMeta(TEARDOWN); // true
|
|
198
|
+
* propagatesToMeta(COMPLETE); // false
|
|
199
|
+
* propagatesToMeta(ERROR); // false
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
declare function propagatesToMeta(t: symbol): boolean;
|
|
203
|
+
|
|
1
204
|
/**
|
|
2
205
|
* Who is performing an operation (attribution + ABAC input).
|
|
3
206
|
*
|
|
@@ -131,156 +334,6 @@ declare function policyFromRules(rules: readonly PolicyRuleData[]): NodeGuard;
|
|
|
131
334
|
*/
|
|
132
335
|
declare function accessHintForGuard(guard: NodeGuard): string;
|
|
133
336
|
|
|
134
|
-
/**
|
|
135
|
-
* GraphReFly message protocol — §1 `~/src/graphrefly/GRAPHREFLY-SPEC.md`.
|
|
136
|
-
* Emissions are always `[[Type, Data?], ...]` (no single-tuple shorthand).
|
|
137
|
-
*
|
|
138
|
-
* ## Canonical message ordering (within a composite batch)
|
|
139
|
-
*
|
|
140
|
-
* When multiple message types appear in a single `down()` call, the canonical
|
|
141
|
-
* delivery order is determined by **signal tier**:
|
|
142
|
-
*
|
|
143
|
-
* | Tier | Signals | Role | Batch behavior |
|
|
144
|
-
* |------|------------------------|-------------------|-------------------------------------|
|
|
145
|
-
* | 0 | DIRTY, INVALIDATE | Notification | Immediate (never deferred) |
|
|
146
|
-
* | 1 | PAUSE, RESUME | Flow control | Immediate (never deferred) |
|
|
147
|
-
* | 2 | DATA, RESOLVED | Value settlement | Deferred inside `batch()` |
|
|
148
|
-
* | 3 | COMPLETE, ERROR | Terminal lifecycle | Deferred to after phase-2 |
|
|
149
|
-
* | 4 | TEARDOWN | Destruction | Immediate (usually sent alone) |
|
|
150
|
-
*
|
|
151
|
-
* **Rule:** Within `downWithBatch`, messages are partitioned by tier and delivered
|
|
152
|
-
* in tier order. This ensures phase-2 values (DATA/RESOLVED) reach sinks before
|
|
153
|
-
* terminal signals (COMPLETE/ERROR) mark the node as done, preventing the
|
|
154
|
-
* "COMPLETE-before-DATA" class of bugs. Sources that emit in canonical order
|
|
155
|
-
* naturally partition correctly with zero overhead.
|
|
156
|
-
*
|
|
157
|
-
* Unknown message types (forward-compat) are tier 0 (immediate).
|
|
158
|
-
*
|
|
159
|
-
* ## Meta node bypass rules (centralized — GRAPHREFLY-SPEC §2.3)
|
|
160
|
-
*
|
|
161
|
-
* - **INVALIDATE** via `graph.signal()` — no-op on meta nodes (cached values preserved).
|
|
162
|
-
* - **COMPLETE / ERROR** — not propagated from parent to meta (meta outlives terminal
|
|
163
|
-
* state for post-mortem writes like setting `meta.error` after ERROR).
|
|
164
|
-
* - **TEARDOWN** — propagated from parent to meta, releasing meta resources.
|
|
165
|
-
*/
|
|
166
|
-
/** Value delivery (`DATA`, value). Tier 2 — deferred inside `batch()`. */
|
|
167
|
-
declare const DATA: unique symbol;
|
|
168
|
-
/** Phase 1: value about to change. Tier 0 — immediate. */
|
|
169
|
-
declare const DIRTY: unique symbol;
|
|
170
|
-
/** Phase 2: dirty pass completed, value unchanged. Tier 2 — deferred inside `batch()`. */
|
|
171
|
-
declare const RESOLVED: unique symbol;
|
|
172
|
-
/** Clear cached state; do not auto-emit. Tier 0 — immediate. */
|
|
173
|
-
declare const INVALIDATE: unique symbol;
|
|
174
|
-
/** Suspend activity. Tier 1 — immediate. */
|
|
175
|
-
declare const PAUSE: unique symbol;
|
|
176
|
-
/** Resume after pause. Tier 1 — immediate. */
|
|
177
|
-
declare const RESUME: unique symbol;
|
|
178
|
-
/** Permanent cleanup. Tier 4 — immediate (usually sent alone). */
|
|
179
|
-
declare const TEARDOWN: unique symbol;
|
|
180
|
-
/** Clean termination. Tier 3 — delivered after phase-2 in the same batch. */
|
|
181
|
-
declare const COMPLETE: unique symbol;
|
|
182
|
-
/** Error termination. Tier 3 — delivered after phase-2 in the same batch. */
|
|
183
|
-
declare const ERROR: unique symbol;
|
|
184
|
-
/** Known protocol type symbols (open set — other symbols are valid and forward). */
|
|
185
|
-
declare const knownMessageTypes: readonly symbol[];
|
|
186
|
-
/** One protocol tuple: `[Type, optional payload]`. */
|
|
187
|
-
type Message = readonly [symbol, unknown?];
|
|
188
|
-
/**
|
|
189
|
-
* A batch of tuples — the wire shape for `node.down()` / `node.up()`.
|
|
190
|
-
*/
|
|
191
|
-
type Messages = readonly Message[];
|
|
192
|
-
/**
|
|
193
|
-
* Whether `t` is one of the built-in protocol symbols in this module.
|
|
194
|
-
*
|
|
195
|
-
* @param t — Message type symbol (unknown types are still valid; they must forward).
|
|
196
|
-
* @returns `true` for `DATA`, `DIRTY`, `RESOLVED`, etc.
|
|
197
|
-
*
|
|
198
|
-
* @example
|
|
199
|
-
* ```ts
|
|
200
|
-
* import { DATA, DIRTY, isKnownMessageType } from "@graphrefly/graphrefly-ts";
|
|
201
|
-
*
|
|
202
|
-
* isKnownMessageType(DATA); // true
|
|
203
|
-
* isKnownMessageType(Symbol("custom")); // false
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
declare function isKnownMessageType(t: symbol): boolean;
|
|
207
|
-
/**
|
|
208
|
-
* Returns the signal tier for a message type (see module-level ordering table).
|
|
209
|
-
*
|
|
210
|
-
* - 0: notification (DIRTY, INVALIDATE) — immediate
|
|
211
|
-
* - 1: flow control (PAUSE, RESUME) — immediate
|
|
212
|
-
* - 2: value (DATA, RESOLVED) — deferred inside `batch()`
|
|
213
|
-
* - 3: terminal (COMPLETE, ERROR) — delivered after phase-2
|
|
214
|
-
* - 4: destruction (TEARDOWN) — immediate, usually alone
|
|
215
|
-
* - 0 for unknown types (forward-compat: immediate)
|
|
216
|
-
*
|
|
217
|
-
* @param t — Message type symbol.
|
|
218
|
-
* @returns Tier number (0–4).
|
|
219
|
-
*
|
|
220
|
-
* @example
|
|
221
|
-
* ```ts
|
|
222
|
-
* import { DATA, DIRTY, COMPLETE, TEARDOWN, messageTier } from "@graphrefly/graphrefly-ts";
|
|
223
|
-
*
|
|
224
|
-
* messageTier(DIRTY); // 0
|
|
225
|
-
* messageTier(DATA); // 2
|
|
226
|
-
* messageTier(COMPLETE); // 3
|
|
227
|
-
* messageTier(TEARDOWN); // 4
|
|
228
|
-
* ```
|
|
229
|
-
*/
|
|
230
|
-
declare function messageTier(t: symbol): number;
|
|
231
|
-
/**
|
|
232
|
-
* Returns whether this tuple is deferred by `batch()` (phase 2: `DATA` or `RESOLVED`).
|
|
233
|
-
*
|
|
234
|
-
* @param msg — Single message tuple.
|
|
235
|
-
* @returns `true` if `msg` is `DATA` or `RESOLVED`.
|
|
236
|
-
*
|
|
237
|
-
* @example
|
|
238
|
-
* ```ts
|
|
239
|
-
* import { DATA, RESOLVED, DIRTY, isPhase2Message } from "@graphrefly/graphrefly-ts";
|
|
240
|
-
*
|
|
241
|
-
* isPhase2Message([DATA, 42]); // true
|
|
242
|
-
* isPhase2Message([RESOLVED]); // true
|
|
243
|
-
* isPhase2Message([DIRTY]); // false
|
|
244
|
-
* ```
|
|
245
|
-
*/
|
|
246
|
-
declare function isPhase2Message(msg: Message): boolean;
|
|
247
|
-
/**
|
|
248
|
-
* Returns whether this message type is terminal (COMPLETE or ERROR).
|
|
249
|
-
* Terminal messages are delivered after phase-2 in the same batch to prevent
|
|
250
|
-
* the node from becoming terminal before value messages reach sinks.
|
|
251
|
-
*
|
|
252
|
-
* @param t — Message type symbol.
|
|
253
|
-
* @returns `true` for `COMPLETE` or `ERROR`.
|
|
254
|
-
*
|
|
255
|
-
* @example
|
|
256
|
-
* ```ts
|
|
257
|
-
* import { COMPLETE, ERROR, DATA, isTerminalMessage } from "@graphrefly/graphrefly-ts";
|
|
258
|
-
*
|
|
259
|
-
* isTerminalMessage(COMPLETE); // true
|
|
260
|
-
* isTerminalMessage(ERROR); // true
|
|
261
|
-
* isTerminalMessage(DATA); // false
|
|
262
|
-
* ```
|
|
263
|
-
*/
|
|
264
|
-
declare function isTerminalMessage(t: symbol): boolean;
|
|
265
|
-
/**
|
|
266
|
-
* Whether `t` should be propagated from a parent node to its companion meta nodes.
|
|
267
|
-
* Only TEARDOWN propagates; COMPLETE/ERROR/INVALIDATE do not (meta outlives parent
|
|
268
|
-
* terminal state for post-mortem writes).
|
|
269
|
-
*
|
|
270
|
-
* @param t — Message type symbol.
|
|
271
|
-
* @returns `true` if the signal should reach meta nodes.
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* ```ts
|
|
275
|
-
* import { TEARDOWN, COMPLETE, ERROR, propagatesToMeta } from "@graphrefly/graphrefly-ts";
|
|
276
|
-
*
|
|
277
|
-
* propagatesToMeta(TEARDOWN); // true
|
|
278
|
-
* propagatesToMeta(COMPLETE); // false
|
|
279
|
-
* propagatesToMeta(ERROR); // false
|
|
280
|
-
* ```
|
|
281
|
-
*/
|
|
282
|
-
declare function propagatesToMeta(t: symbol): boolean;
|
|
283
|
-
|
|
284
337
|
/**
|
|
285
338
|
* Node versioning — GRAPHREFLY-SPEC §7.
|
|
286
339
|
*
|
|
@@ -346,23 +399,44 @@ declare function advanceVersion(info: NodeVersionInfo, newValue: unknown, hashFn
|
|
|
346
399
|
declare function isV1(info: NodeVersionInfo): info is V1;
|
|
347
400
|
|
|
348
401
|
/**
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
402
|
+
* `NodeBase` — abstract class implementing the {@link Node} protocol with
|
|
403
|
+
* lifecycle machinery shared between {@link NodeImpl} (static deps) and
|
|
404
|
+
* {@link DynamicNodeImpl} (runtime-tracked deps).
|
|
405
|
+
*
|
|
406
|
+
* **Responsibilities (shared):**
|
|
407
|
+
* - Identity (name, describeKind, meta, guard, versioning)
|
|
408
|
+
* - Cache + status lifecycle (`_cached`, `_status`, `_terminal`)
|
|
409
|
+
* - Sink storage (null / single / Set fast paths)
|
|
410
|
+
* - `subscribe()` with START handshake + first-subscriber activation
|
|
411
|
+
* - `_downInternal` → `_downToSinks` delivery pipeline (via `downWithBatch`)
|
|
412
|
+
* - `_downAutoValue` (value → protocol framing with equals)
|
|
413
|
+
* - `_handleLocalLifecycle` (cached/status/terminal updates + meta propagation)
|
|
414
|
+
*
|
|
415
|
+
* **Subclass hooks (abstract):**
|
|
416
|
+
* - `_onActivate()` — called when sinkCount transitions 0 → 1
|
|
417
|
+
* - `_doDeactivate()` — cleanup on deactivation (at-most-once, guarded by `_onDeactivate`)
|
|
418
|
+
* - `up()` / `unsubscribe()` / `_upInternal()` — dep-iteration specifics
|
|
419
|
+
* - `_createMetaNode()` — meta companion factory (avoids circular imports)
|
|
420
|
+
*
|
|
421
|
+
* See GRAPHREFLY-SPEC §2 and COMPOSITION-GUIDE §1 for protocol contracts.
|
|
422
|
+
*/
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Internal sentinel value: "no cached value has been set or emitted."
|
|
426
|
+
* Used instead of `undefined` so that `undefined` can be a valid emitted value.
|
|
427
|
+
*/
|
|
428
|
+
declare const NO_VALUE: unique symbol;
|
|
429
|
+
/**
|
|
430
|
+
* Branded symbol that marks a {@link CleanupResult} wrapper — prevents
|
|
431
|
+
* duck-type collisions with domain objects that happen to have a `cleanup`
|
|
432
|
+
* property.
|
|
352
433
|
*/
|
|
353
434
|
declare const CLEANUP_RESULT: unique symbol;
|
|
354
|
-
/** Lifecycle status of a node. */
|
|
355
|
-
type NodeStatus = "disconnected" | "dirty" | "settled" | "resolved" | "completed" | "errored";
|
|
435
|
+
/** Lifecycle status of a node (GRAPHREFLY-SPEC §2.2). */
|
|
436
|
+
type NodeStatus = "disconnected" | "pending" | "dirty" | "settled" | "resolved" | "completed" | "errored";
|
|
356
437
|
/** Callback that receives downstream message batches. */
|
|
357
438
|
type NodeSink = (messages: Messages) => void;
|
|
358
|
-
/**
|
|
359
|
-
* Compute function passed to `node()`.
|
|
360
|
-
*
|
|
361
|
-
* @returns A value to emit, `undefined` to skip emission, or a cleanup
|
|
362
|
-
* function invoked before the next run or on teardown.
|
|
363
|
-
*/
|
|
364
|
-
type NodeFn<T = unknown> = (deps: readonly unknown[], actions: NodeActions) => T | undefined | (() => void);
|
|
365
|
-
/** Imperative actions available inside a {@link NodeFn}. */
|
|
439
|
+
/** Imperative actions available inside a node's compute function. */
|
|
366
440
|
interface NodeActions {
|
|
367
441
|
/** Emit raw messages downstream. */
|
|
368
442
|
down(messages: Messages): void;
|
|
@@ -372,14 +446,10 @@ interface NodeActions {
|
|
|
372
446
|
up(messages: Messages): void;
|
|
373
447
|
}
|
|
374
448
|
/**
|
|
375
|
-
* Callback for intercepting messages before the default dispatch.
|
|
376
|
-
*
|
|
377
|
-
* Called for every message from every dep. Return `true` to consume the
|
|
378
|
-
* message (skip default handling), or `false` to let default dispatch run.
|
|
449
|
+
* Callback for intercepting messages before the default dispatch (§2.6).
|
|
379
450
|
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
* @param actions — `{ down(), emit(), up() }` — same as `NodeFn` receives.
|
|
451
|
+
* Called for every message from every dep. Return `true` to consume
|
|
452
|
+
* (skip default handling), or `false` to let default dispatch run.
|
|
383
453
|
*/
|
|
384
454
|
type OnMessageHandler = (msg: Message, depIndex: number, actions: NodeActions) => boolean;
|
|
385
455
|
/**
|
|
@@ -395,9 +465,9 @@ type NodeInspectorHookEvent = {
|
|
|
395
465
|
depValues: readonly unknown[];
|
|
396
466
|
};
|
|
397
467
|
type NodeInspectorHook = (event: NodeInspectorHookEvent) => void;
|
|
398
|
-
/** Explicit describe `type` for {@link Graph.describe}
|
|
468
|
+
/** Explicit describe `type` for {@link Graph.describe} (GRAPHREFLY-SPEC Appendix B). */
|
|
399
469
|
type NodeDescribeKind = "state" | "derived" | "producer" | "operator" | "effect";
|
|
400
|
-
/** Options
|
|
470
|
+
/** Options accepted by every node constructor. */
|
|
401
471
|
interface NodeOptions {
|
|
402
472
|
name?: string;
|
|
403
473
|
/**
|
|
@@ -411,7 +481,7 @@ interface NodeOptions {
|
|
|
411
481
|
/**
|
|
412
482
|
* Each key becomes an independently subscribable companion node.
|
|
413
483
|
* Meta nodes outlive the parent's subscription lifecycle: when all sinks
|
|
414
|
-
* unsubscribe the parent
|
|
484
|
+
* unsubscribe the parent deactivates but meta nodes stay alive.
|
|
415
485
|
* Send `[[TEARDOWN]]` to the parent to release meta node resources.
|
|
416
486
|
*/
|
|
417
487
|
meta?: Record<string, unknown>;
|
|
@@ -442,20 +512,14 @@ interface NodeOptions {
|
|
|
442
512
|
* Companion {@link NodeOptions.meta | meta} nodes inherit this guard from the primary.
|
|
443
513
|
*/
|
|
444
514
|
guard?: NodeGuard;
|
|
445
|
-
/**
|
|
446
|
-
* Opt-in versioning level (GRAPHREFLY-SPEC §7).
|
|
447
|
-
* - `0` (V0): `id` + `version` — identity & change detection.
|
|
448
|
-
* - `1` (V1): + `cid` + `prev` — content addressing & linked history.
|
|
449
|
-
*/
|
|
515
|
+
/** Opt-in versioning level (GRAPHREFLY-SPEC §7). */
|
|
450
516
|
versioning?: VersioningLevel;
|
|
451
517
|
/** Override auto-generated versioning id. */
|
|
452
518
|
versioningId?: string;
|
|
453
519
|
/** Custom hash function for V1 cid computation. */
|
|
454
520
|
versioningHash?: HashFn;
|
|
455
521
|
}
|
|
456
|
-
/**
|
|
457
|
-
* Options for {@link Node.down} / {@link Node.up} (actor context, graph delivery mode, internal bypass).
|
|
458
|
-
*/
|
|
522
|
+
/** Actor/delivery context for {@link Node.down} and {@link Node.up}. */
|
|
459
523
|
type NodeTransportOptions = {
|
|
460
524
|
actor?: Actor;
|
|
461
525
|
/**
|
|
@@ -464,25 +528,23 @@ type NodeTransportOptions = {
|
|
|
464
528
|
*/
|
|
465
529
|
internal?: boolean;
|
|
466
530
|
/**
|
|
467
|
-
* `signal` for {@link Graph.signal} deliveries; default `write` for {@link Graph.set}
|
|
531
|
+
* `signal` for {@link Graph.signal} deliveries; default `write` for {@link Graph.set}
|
|
532
|
+
* and direct `down`.
|
|
468
533
|
*/
|
|
469
534
|
delivery?: "write" | "signal";
|
|
470
535
|
};
|
|
471
|
-
/**
|
|
472
|
-
* Optional hints passed to {@link Node.subscribe} to enable per-sink
|
|
473
|
-
* optimizations.
|
|
474
|
-
*/
|
|
536
|
+
/** Optional hints passed to {@link Node.subscribe}. */
|
|
475
537
|
interface SubscribeHints {
|
|
476
538
|
/**
|
|
477
539
|
* Subscriber has exactly one dep with `fn` — the source may skip DIRTY
|
|
478
540
|
* dispatch when this is the sole subscriber. The subscriber synthesizes
|
|
479
|
-
* dirty state locally
|
|
541
|
+
* dirty state locally.
|
|
480
542
|
*/
|
|
481
543
|
singleDep?: boolean;
|
|
482
544
|
/**
|
|
483
|
-
* Actor to check against the node's `observe` guard.
|
|
484
|
-
*
|
|
485
|
-
*
|
|
545
|
+
* Actor to check against the node's `observe` guard. When set,
|
|
546
|
+
* `subscribe()` throws {@link GuardDenied} if the actor is not permitted
|
|
547
|
+
* to observe this node.
|
|
486
548
|
*/
|
|
487
549
|
actor?: Actor;
|
|
488
550
|
}
|
|
@@ -512,7 +574,7 @@ interface Node<T = unknown> {
|
|
|
512
574
|
actor: Actor;
|
|
513
575
|
timestamp_ns: number;
|
|
514
576
|
}>;
|
|
515
|
-
/** Whether
|
|
577
|
+
/** Whether `actor` may {@link Graph.observe} this node. */
|
|
516
578
|
allowsObserve(actor: Actor): boolean;
|
|
517
579
|
/** Whether a {@link NodeOptions.guard | guard} is installed. */
|
|
518
580
|
hasGuard(): boolean;
|
|
@@ -524,60 +586,154 @@ interface Node<T = unknown> {
|
|
|
524
586
|
* `cleanup` is registered as the teardown/recompute cleanup and `value`
|
|
525
587
|
* (if present) is emitted as data. This avoids the ambiguity where returning
|
|
526
588
|
* a plain function is silently consumed as cleanup instead of emitted as data.
|
|
527
|
-
*
|
|
528
|
-
* Use the {@link cleanupResult} factory to create instances — it stamps the
|
|
529
|
-
* branded {@link CLEANUP_RESULT} symbol so that domain objects with a `cleanup`
|
|
530
|
-
* property are never misinterpreted.
|
|
531
|
-
*
|
|
532
|
-
* Plain function returns are still treated as cleanup for backward compatibility.
|
|
533
589
|
*/
|
|
534
590
|
type CleanupResult<T = unknown> = {
|
|
535
591
|
readonly [CLEANUP_RESULT]: true;
|
|
536
592
|
cleanup: () => void;
|
|
537
593
|
value?: T;
|
|
538
594
|
};
|
|
539
|
-
/**
|
|
540
|
-
* Create a branded {@link CleanupResult}.
|
|
541
|
-
*
|
|
542
|
-
* ```ts
|
|
543
|
-
* node([dep], () => cleanupResult(() => release(), computedValue))
|
|
544
|
-
* ```
|
|
545
|
-
*/
|
|
595
|
+
/** Create a branded {@link CleanupResult}. */
|
|
546
596
|
declare function cleanupResult<T>(cleanup: () => void): CleanupResult<T>;
|
|
547
597
|
declare function cleanupResult<T>(cleanup: () => void, value: T): CleanupResult<T>;
|
|
548
598
|
/**
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
599
|
+
* Abstract base class for every node in the graph. Both {@link NodeImpl}
|
|
600
|
+
* (static deps) and {@link DynamicNodeImpl} (runtime-tracked deps) extend
|
|
601
|
+
* this to share subscribe/sink/lifecycle machinery.
|
|
602
|
+
*
|
|
603
|
+
* Invariants (see GRAPHREFLY-SPEC §2.2):
|
|
604
|
+
* - `_sinkCount` always reflects the size of `_sinks`.
|
|
605
|
+
* - `_cached === NO_VALUE` iff the node has never produced a value (SENTINEL).
|
|
606
|
+
* - `_terminal` is set exactly once (per subscription cycle for resubscribable).
|
|
607
|
+
* - `_onActivate` runs exactly once per activation cycle; `_doDeactivate`
|
|
608
|
+
* runs at most once per deactivation (guarded by `_active` flag).
|
|
609
|
+
*
|
|
610
|
+
* ROM/RAM rule (GRAPHREFLY-SPEC §2.2): state nodes (no fn) preserve `_cached`
|
|
611
|
+
* across disconnect — intrinsic, non-volatile. Compute nodes (derived,
|
|
612
|
+
* producer, dynamic) clear `_cached` on disconnect in their subclass
|
|
613
|
+
* `_doDeactivate` — their value is a function of live subscriptions.
|
|
614
|
+
*/
|
|
615
|
+
declare abstract class NodeBase<T = unknown> implements Node<T> {
|
|
616
|
+
protected readonly _optsName: string | undefined;
|
|
617
|
+
private _registryName;
|
|
618
|
+
/** @internal Read by `describeNode` before inference. */
|
|
619
|
+
readonly _describeKind: NodeDescribeKind | undefined;
|
|
620
|
+
readonly meta: Record<string, Node>;
|
|
621
|
+
protected readonly _equals: (a: unknown, b: unknown) => boolean;
|
|
622
|
+
protected readonly _resubscribable: boolean;
|
|
623
|
+
protected readonly _resetOnTeardown: boolean;
|
|
624
|
+
protected readonly _onResubscribe: (() => void) | undefined;
|
|
625
|
+
protected readonly _onMessage: OnMessageHandler | undefined;
|
|
626
|
+
/** @internal Read by `describeNode` for `accessHintForGuard`. */
|
|
627
|
+
readonly _guard: NodeGuard | undefined;
|
|
628
|
+
/** @internal Subclasses update this through {@link _recordMutation}. */
|
|
629
|
+
protected _lastMutation: {
|
|
630
|
+
actor: Actor;
|
|
631
|
+
timestamp_ns: number;
|
|
632
|
+
} | undefined;
|
|
633
|
+
protected _hashFn: HashFn;
|
|
634
|
+
private _versioning;
|
|
635
|
+
/** @internal Read by `describeNode` and `graph.ts`. */
|
|
636
|
+
_cached: T | typeof NO_VALUE;
|
|
637
|
+
/** @internal Read externally via `get status()`. */
|
|
638
|
+
_status: NodeStatus;
|
|
639
|
+
protected _terminal: boolean;
|
|
640
|
+
private _active;
|
|
641
|
+
/** @internal Read by `graph/profile.ts` for subscriber counts. */
|
|
642
|
+
_sinkCount: number;
|
|
643
|
+
protected _singleDepSinkCount: number;
|
|
644
|
+
protected _singleDepSinks: WeakSet<NodeSink>;
|
|
645
|
+
protected _sinks: NodeSink | Set<NodeSink> | null;
|
|
646
|
+
protected readonly _actions: NodeActions;
|
|
647
|
+
protected readonly _boundDownToSinks: (messages: Messages) => void;
|
|
648
|
+
private _inspectorHook;
|
|
649
|
+
constructor(opts: NodeOptions);
|
|
650
|
+
/**
|
|
651
|
+
* Subclass hook invoked by `actions.down` / `actions.emit`. Default no-op;
|
|
652
|
+
* {@link NodeImpl} overrides to set `_manualEmitUsed`.
|
|
653
|
+
*/
|
|
654
|
+
protected _onManualEmit(): void;
|
|
655
|
+
/**
|
|
656
|
+
* Create a companion meta node. Called from the base constructor; must
|
|
657
|
+
* not touch subclass fields that haven't been initialized yet (safe to
|
|
658
|
+
* read from `opts`).
|
|
659
|
+
*/
|
|
660
|
+
protected abstract _createMetaNode(key: string, initialValue: unknown, opts: NodeOptions): Node;
|
|
661
|
+
get name(): string | undefined;
|
|
662
|
+
/** @internal Assigned by `Graph.add` when registered without an options `name`. */
|
|
663
|
+
_assignRegistryName(localName: string): void;
|
|
664
|
+
/**
|
|
665
|
+
* @internal Attach/remove inspector hook for graph-level observability.
|
|
666
|
+
* Returns a disposer that restores the previous hook.
|
|
667
|
+
*/
|
|
668
|
+
_setInspectorHook(hook?: NodeInspectorHook): () => void;
|
|
669
|
+
/** @internal Used by subclasses to surface inspector events. */
|
|
670
|
+
protected _emitInspectorHook(event: NodeInspectorHookEvent): void;
|
|
671
|
+
get status(): NodeStatus;
|
|
672
|
+
get lastMutation(): Readonly<{
|
|
673
|
+
actor: Actor;
|
|
674
|
+
timestamp_ns: number;
|
|
675
|
+
}> | undefined;
|
|
676
|
+
get v(): Readonly<NodeVersionInfo> | undefined;
|
|
677
|
+
/** @internal Used by `Graph.setVersioning` to retroactively apply versioning. */
|
|
678
|
+
_applyVersioning(level: VersioningLevel, opts?: {
|
|
679
|
+
id?: string;
|
|
680
|
+
hash?: HashFn;
|
|
681
|
+
}): void;
|
|
682
|
+
hasGuard(): boolean;
|
|
683
|
+
allowsObserve(actor: Actor): boolean;
|
|
684
|
+
get(): T | undefined;
|
|
685
|
+
down(messages: Messages, options?: NodeTransportOptions): void;
|
|
686
|
+
/** @internal Record a successful guarded mutation (called by `down` and subclass `up`). */
|
|
687
|
+
protected _recordMutation(actor: Actor): void;
|
|
688
|
+
/** Abstract — subclasses forward messages to dependencies (or no-op for sources). */
|
|
689
|
+
abstract up(messages: Messages, options?: NodeTransportOptions): void;
|
|
690
|
+
/** Abstract — subclasses release upstream subscriptions (or no-op for sources). */
|
|
691
|
+
abstract unsubscribe(): void;
|
|
692
|
+
/** Internal upstream-send used by `actions.up`. */
|
|
693
|
+
protected abstract _upInternal(messages: Messages): void;
|
|
694
|
+
/** Called when `_sinkCount` transitions 0 → 1. */
|
|
695
|
+
protected abstract _onActivate(): void;
|
|
696
|
+
/**
|
|
697
|
+
* At-most-once deactivation guard. Both TEARDOWN (eager) and
|
|
698
|
+
* unsubscribe-body (lazy) call this. The `_active` flag ensures
|
|
699
|
+
* `_doDeactivate` runs exactly once per activation cycle.
|
|
700
|
+
*/
|
|
701
|
+
protected _onDeactivate(): void;
|
|
702
|
+
/** Subclass hook: cleanup on deactivation (called at most once). */
|
|
703
|
+
protected abstract _doDeactivate(): void;
|
|
704
|
+
subscribe(sink: NodeSink, hints?: SubscribeHints): () => void;
|
|
705
|
+
/**
|
|
706
|
+
* Core outgoing dispatch. Applies terminal filter + local lifecycle
|
|
707
|
+
* update, then hands messages to `downWithBatch` for tier-aware delivery.
|
|
708
|
+
*/
|
|
709
|
+
protected _downInternal(messages: Messages): void;
|
|
710
|
+
protected _canSkipDirty(): boolean;
|
|
711
|
+
protected _downToSinks(messages: Messages): void;
|
|
712
|
+
/**
|
|
713
|
+
* Update `_cached`, `_status`, `_terminal` from message batch before
|
|
714
|
+
* delivery. Subclass hooks `_onInvalidate` / `_onTeardown` let
|
|
715
|
+
* {@link NodeImpl} clear `_lastDepValues` and invoke cleanup fns.
|
|
716
|
+
*/
|
|
717
|
+
protected _handleLocalLifecycle(messages: Messages): void;
|
|
718
|
+
/**
|
|
719
|
+
* Subclass hook: invoked when INVALIDATE arrives (before `_cached` is
|
|
720
|
+
* cleared). {@link NodeImpl} uses this to run the fn cleanup fn and
|
|
721
|
+
* drop `_lastDepValues` so the next wave re-runs fn.
|
|
722
|
+
*/
|
|
723
|
+
protected _onInvalidate(): void;
|
|
724
|
+
/**
|
|
725
|
+
* Subclass hook: invoked when TEARDOWN arrives, before `_onDeactivate`.
|
|
726
|
+
* {@link NodeImpl} uses this to run any pending cleanup fn.
|
|
727
|
+
*/
|
|
728
|
+
protected _onTeardown(): void;
|
|
729
|
+
/** Forward a signal to all companion meta nodes (best-effort). */
|
|
730
|
+
protected _propagateToMeta(t: symbol): void;
|
|
731
|
+
/**
|
|
732
|
+
* Frame a computed value into the right protocol messages and dispatch
|
|
733
|
+
* via `_downInternal`. Used by `_runFn` and `actions.emit`.
|
|
734
|
+
*/
|
|
735
|
+
protected _downAutoValue(value: unknown): void;
|
|
736
|
+
}
|
|
581
737
|
|
|
582
738
|
/** JSON-shaped slice of a node for Phase 1 `Graph.describe()` (GRAPHREFLY-SPEC §3.6, Appendix B). */
|
|
583
739
|
type DescribeNodeOutput = {
|
|
@@ -587,6 +743,8 @@ type DescribeNodeOutput = {
|
|
|
587
743
|
meta?: Record<string, unknown>;
|
|
588
744
|
name?: string;
|
|
589
745
|
value?: unknown;
|
|
746
|
+
/** True when the node has never received or been initialized with a value (cache holds SENTINEL). */
|
|
747
|
+
sentinel?: boolean;
|
|
590
748
|
/** Node versioning info (GRAPHREFLY-SPEC §7). Present only when versioning is enabled. */
|
|
591
749
|
v?: {
|
|
592
750
|
id: string;
|
|
@@ -616,57 +774,5 @@ type DescribeDetail = "minimal" | "standard" | "full";
|
|
|
616
774
|
type DescribeField = "type" | "status" | "value" | "deps" | "meta" | "v" | "guard" | "lastMutation" | `meta.${string}`;
|
|
617
775
|
/** Resolve which fields to include based on detail level or explicit field list. */
|
|
618
776
|
declare function resolveDescribeFields(detail?: DescribeDetail, fields?: readonly DescribeField[]): Set<string> | null;
|
|
619
|
-
/**
|
|
620
|
-
* Reads the current cached value of every companion meta field on a node,
|
|
621
|
-
* suitable for merging into `describe()`-style JSON (GRAPHREFLY-SPEC §2.3, §3.6).
|
|
622
|
-
*
|
|
623
|
-
* @remarks
|
|
624
|
-
* Values come from {@link Node.get}, which returns the **last settled** cache.
|
|
625
|
-
* If a meta field is in `"dirty"` status (DIRTY received, DATA pending), the
|
|
626
|
-
* snapshot contains the *previous* value — check `node.meta[key].status` when
|
|
627
|
-
* freshness matters. Avoid calling mid-batch for the same reason.
|
|
628
|
-
*
|
|
629
|
-
* Meta nodes are **not** terminated when their parent receives COMPLETE or
|
|
630
|
-
* ERROR — they remain writable so callers can record post-mortem metadata
|
|
631
|
-
* (e.g. `meta.error`). They *are* torn down when the parent receives TEARDOWN.
|
|
632
|
-
*
|
|
633
|
-
* @param node - The node whose meta fields to snapshot.
|
|
634
|
-
* @returns Plain object of `{ key: value }` pairs (empty if no meta defined).
|
|
635
|
-
* Keys whose companion node's {@link Node.get} throws are omitted.
|
|
636
|
-
*
|
|
637
|
-
* @example
|
|
638
|
-
* ```ts
|
|
639
|
-
* import { core } from "@graphrefly/graphrefly-ts";
|
|
640
|
-
*
|
|
641
|
-
* const n = core.node({ initial: 0, meta: { tag: "a" } });
|
|
642
|
-
* core.metaSnapshot(n); // { tag: "a" }
|
|
643
|
-
* ```
|
|
644
|
-
*/
|
|
645
|
-
declare function metaSnapshot(node: Node): Record<string, unknown>;
|
|
646
|
-
/**
|
|
647
|
-
* Builds a single-node slice of `Graph.describe()` JSON (structure + `meta` snapshot).
|
|
648
|
-
* Parity with graphrefly-py `describe_node`.
|
|
649
|
-
*
|
|
650
|
-
* `type` is inferred from factory configuration, optional `describeKind` in node options,
|
|
651
|
-
* and the last `manualEmitUsed` hint (operator vs derived). {@link effect} sets
|
|
652
|
-
* `describeKind: "effect"`. Nodes not created by {@link node} fall back to `type: "state"` and empty `deps`.
|
|
653
|
-
*
|
|
654
|
-
* @param node - Any `Node` to introspect.
|
|
655
|
-
* @returns `DescribeNodeOutput` suitable for merging into graph describe maps.
|
|
656
|
-
*
|
|
657
|
-
* @example
|
|
658
|
-
* ```ts
|
|
659
|
-
* import { describeNode, state } from "@graphrefly/graphrefly-ts";
|
|
660
|
-
*
|
|
661
|
-
* describeNode(state(0));
|
|
662
|
-
* ```
|
|
663
|
-
*/
|
|
664
|
-
/**
|
|
665
|
-
* Builds a single-node slice for `Graph.describe()`.
|
|
666
|
-
*
|
|
667
|
-
* @param node - Node to introspect.
|
|
668
|
-
* @param includeFields - Set of fields to include, or `null` for all. When omitted, all fields are included (legacy behavior).
|
|
669
|
-
*/
|
|
670
|
-
declare function describeNode(node: Node, includeFields?: Set<string> | null): DescribeNodeOutput;
|
|
671
777
|
|
|
672
|
-
export {
|
|
778
|
+
export { normalizeActor as $, type Actor as A, accessHintForGuard as B, CLEANUP_RESULT as C, DATA as D, ERROR as E, advanceVersion as F, type GuardAction as G, type HashFn as H, INVALIDATE as I, cleanupResult as J, createVersioning as K, defaultHash as L, type Message as M, type Node as N, type OnMessageHandler as O, PAUSE as P, isKnownMessageType as Q, RESOLVED as R, START as S, TEARDOWN as T, isLocalOnly as U, type V0 as V, isPhase2Message as W, isTerminalMessage as X, isV1 as Y, knownMessageTypes as Z, messageTier as _, type NodeOptions as a, policy as a0, policyFromRules as a1, propagatesToMeta as a2, resolveDescribeFields as a3, NodeBase as a4, type NodeActions as b, COMPLETE as c, type CleanupResult as d, DEFAULT_ACTOR as e, DIRTY as f, type DescribeDetail as g, type DescribeField as h, type DescribeNodeOutput as i, GuardDenied as j, type GuardDeniedDetails as k, type Messages as l, type NodeDescribeKind as m, type NodeGuard as n, type NodeSink as o, type NodeStatus as p, type NodeTransportOptions as q, type NodeVersionInfo as r, type PolicyAllow as s, type PolicyDeny as t, type PolicyRuleData as u, RESUME as v, type SubscribeHints as w, type V1 as x, type VersioningLevel as y, type VersioningOptions as z };
|