@graphrefly/graphrefly 0.1.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/LICENSE +21 -0
- package/README.md +234 -0
- package/dist/chunk-5X3LAO3B.js +1571 -0
- package/dist/chunk-5X3LAO3B.js.map +1 -0
- package/dist/chunk-6W5SGIGB.js +1793 -0
- package/dist/chunk-6W5SGIGB.js.map +1 -0
- package/dist/chunk-CP6MNKAA.js +97 -0
- package/dist/chunk-CP6MNKAA.js.map +1 -0
- package/dist/chunk-HP7OKEOE.js +107 -0
- package/dist/chunk-HP7OKEOE.js.map +1 -0
- package/dist/chunk-KWXPDASV.js +781 -0
- package/dist/chunk-KWXPDASV.js.map +1 -0
- package/dist/chunk-O3PI7W45.js +68 -0
- package/dist/chunk-O3PI7W45.js.map +1 -0
- package/dist/chunk-QW7H3ICI.js +1372 -0
- package/dist/chunk-QW7H3ICI.js.map +1 -0
- package/dist/chunk-VPS7L64N.js +4785 -0
- package/dist/chunk-VPS7L64N.js.map +1 -0
- package/dist/chunk-Z4Y4FMQN.js +1097 -0
- package/dist/chunk-Z4Y4FMQN.js.map +1 -0
- package/dist/compat/nestjs/index.cjs +4883 -0
- package/dist/compat/nestjs/index.cjs.map +1 -0
- package/dist/compat/nestjs/index.d.cts +7 -0
- package/dist/compat/nestjs/index.d.ts +7 -0
- package/dist/compat/nestjs/index.js +84 -0
- package/dist/compat/nestjs/index.js.map +1 -0
- package/dist/core/index.cjs +1632 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +2 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +90 -0
- package/dist/core/index.js.map +1 -0
- package/dist/extra/index.cjs +6885 -0
- package/dist/extra/index.cjs.map +1 -0
- package/dist/extra/index.d.cts +5 -0
- package/dist/extra/index.d.ts +5 -0
- package/dist/extra/index.js +290 -0
- package/dist/extra/index.js.map +1 -0
- package/dist/graph/index.cjs +3225 -0
- package/dist/graph/index.cjs.map +1 -0
- package/dist/graph/index.d.cts +3 -0
- package/dist/graph/index.d.ts +3 -0
- package/dist/graph/index.js +25 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph-CL_ZDAj9.d.cts +605 -0
- package/dist/graph-D18qmsNm.d.ts +605 -0
- package/dist/index-B6SsZs2h.d.cts +3463 -0
- package/dist/index-B7eOdgEx.d.ts +449 -0
- package/dist/index-BHUvlQ3v.d.ts +3463 -0
- package/dist/index-BtK55IE2.d.ts +231 -0
- package/dist/index-BvhgZRHK.d.cts +231 -0
- package/dist/index-Bvy_6CaN.d.ts +452 -0
- package/dist/index-C3BMRmmp.d.cts +449 -0
- package/dist/index-C5mqLhMX.d.cts +452 -0
- package/dist/index-CP_QvbWu.d.ts +940 -0
- package/dist/index-D_geH2Bm.d.cts +940 -0
- package/dist/index.cjs +14843 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1517 -0
- package/dist/index.d.ts +1517 -0
- package/dist/index.js +3649 -0
- package/dist/index.js.map +1 -0
- package/dist/meta-BsF6Sag9.d.cts +607 -0
- package/dist/meta-BsF6Sag9.d.ts +607 -0
- package/dist/patterns/reactive-layout/index.cjs +4143 -0
- package/dist/patterns/reactive-layout/index.cjs.map +1 -0
- package/dist/patterns/reactive-layout/index.d.cts +3 -0
- package/dist/patterns/reactive-layout/index.d.ts +3 -0
- package/dist/patterns/reactive-layout/index.js +38 -0
- package/dist/patterns/reactive-layout/index.js.map +1 -0
- package/dist/reactive-log-BfvfNWQh.d.cts +137 -0
- package/dist/reactive-log-ohLmTXoZ.d.ts +137 -0
- package/package.json +256 -0
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who is performing an operation (attribution + ABAC input).
|
|
3
|
+
*
|
|
4
|
+
* @see GRAPHREFLY-SPEC — roadmap Phase 1.5 (Actor & Guard).
|
|
5
|
+
*/
|
|
6
|
+
type Actor = {
|
|
7
|
+
type: "human" | "llm" | "wallet" | "system" | string;
|
|
8
|
+
id: string;
|
|
9
|
+
} & Record<string, unknown>;
|
|
10
|
+
/** Default actor when none is passed ({@link normalizeActor}). */
|
|
11
|
+
declare const DEFAULT_ACTOR: Actor;
|
|
12
|
+
/**
|
|
13
|
+
* Fills missing `type` / `id` on an actor and returns {@link DEFAULT_ACTOR} when input is undefined.
|
|
14
|
+
*
|
|
15
|
+
* @param actor - Optional partial actor from a transport hint.
|
|
16
|
+
* @returns A normalized `Actor` safe to pass to guards and graph APIs.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { normalizeActor } from "@graphrefly/graphrefly-ts";
|
|
21
|
+
*
|
|
22
|
+
* normalizeActor({ type: "human", id: "u1" });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare function normalizeActor(actor?: Actor): Actor;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Actions checked by {@link NodeGuard}. `write` covers both {@link Node.down} and
|
|
29
|
+
* {@link Node.up} today; finer-grained strings may be added later (e.g. `"write.data"`).
|
|
30
|
+
*/
|
|
31
|
+
type GuardAction = "write" | "signal" | "observe" | (string & {});
|
|
32
|
+
type NodeGuard = (actor: Actor, action: GuardAction) => boolean;
|
|
33
|
+
type GuardDeniedDetails = {
|
|
34
|
+
actor: Actor;
|
|
35
|
+
action: GuardAction;
|
|
36
|
+
/** Registry or options name when known */
|
|
37
|
+
nodeName?: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Thrown when a {@link NodeGuard} denies an action for a given actor.
|
|
41
|
+
*
|
|
42
|
+
* Carries the rejected `actor`, `action`, and optional `nodeName` for diagnostic
|
|
43
|
+
* messages and middleware error handling.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { GuardDenied, policy } from "@graphrefly/graphrefly-ts";
|
|
48
|
+
*
|
|
49
|
+
* const guard = policy((allow) => { allow("observe"); });
|
|
50
|
+
* try {
|
|
51
|
+
* if (!guard({ type: "llm", id: "agent-1" }, "write")) {
|
|
52
|
+
* throw new GuardDenied(
|
|
53
|
+
* { actor: { type: "llm", id: "agent-1" }, action: "write", nodeName: "userInput" },
|
|
54
|
+
* );
|
|
55
|
+
* }
|
|
56
|
+
* } catch (e) {
|
|
57
|
+
* if (e instanceof GuardDenied) console.error(e.action, e.actor.type); // "write" "llm"
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare class GuardDenied extends Error {
|
|
62
|
+
readonly actor: Actor;
|
|
63
|
+
readonly action: GuardAction;
|
|
64
|
+
readonly nodeName?: string;
|
|
65
|
+
/**
|
|
66
|
+
* @param details - Actor, action, and optional node name for the denial.
|
|
67
|
+
* @param message - Optional override for the default error message.
|
|
68
|
+
*/
|
|
69
|
+
constructor(details: GuardDeniedDetails, message?: string);
|
|
70
|
+
/** Qualified registry path when known (roadmap diagnostics: same as {@link nodeName}). */
|
|
71
|
+
get node(): string | undefined;
|
|
72
|
+
}
|
|
73
|
+
type Where = (actor: Actor) => boolean;
|
|
74
|
+
type PolicyAllow = (action: GuardAction | readonly GuardAction[], opts?: {
|
|
75
|
+
where?: Where;
|
|
76
|
+
}) => void;
|
|
77
|
+
type PolicyDeny = (action: GuardAction | readonly GuardAction[], opts?: {
|
|
78
|
+
where?: Where;
|
|
79
|
+
}) => void;
|
|
80
|
+
type PolicyRuleData = {
|
|
81
|
+
effect: "allow" | "deny";
|
|
82
|
+
action: GuardAction | readonly GuardAction[];
|
|
83
|
+
actorType?: string | readonly string[];
|
|
84
|
+
actorId?: string | readonly string[];
|
|
85
|
+
claims?: Record<string, unknown>;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Declarative guard builder. Precedence: any matching **deny** blocks even if an allow also matches.
|
|
89
|
+
* If no rule matches, the guard returns `false` (deny-by-default). Aligned with graphrefly-py `policy()`.
|
|
90
|
+
*
|
|
91
|
+
* @param build - Callback that registers `allow(...)` / `deny(...)` rules in order.
|
|
92
|
+
* @returns A `NodeGuard` for use as `node({ guard })`.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const guard = policy((allow, deny) => {
|
|
97
|
+
* allow("observe");
|
|
98
|
+
* deny("write", { where: (a) => a.type === "llm" });
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function policy(build: (allow: PolicyAllow, deny: PolicyDeny) => void): NodeGuard;
|
|
103
|
+
/**
|
|
104
|
+
* Rebuild a declarative guard from persisted policy data (snapshot-safe).
|
|
105
|
+
*
|
|
106
|
+
* Rules are deny-overrides, same semantics as {@link policy}.
|
|
107
|
+
*/
|
|
108
|
+
declare function policyFromRules(rules: readonly PolicyRuleData[]): NodeGuard;
|
|
109
|
+
/**
|
|
110
|
+
* Derives a best-effort `meta.access` hint string by probing `guard` with the
|
|
111
|
+
* standard actor types `human`, `llm`, `wallet`, `system` for the `"write"` action
|
|
112
|
+
* (roadmap 1.5). Aligned with graphrefly-py `access_hint_for_guard`.
|
|
113
|
+
*
|
|
114
|
+
* @param guard - Guard function to probe (typically from {@link policy}).
|
|
115
|
+
* @returns `"restricted"` when no standard type is allowed; `"both"` when both
|
|
116
|
+
* `human` and `llm` are allowed (plus optionally `system`); the single allowed
|
|
117
|
+
* type name when only one passes; or a `"+"` joined list otherwise.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* import { policy, accessHintForGuard } from "@graphrefly/graphrefly-ts";
|
|
122
|
+
*
|
|
123
|
+
* const guardBoth = policy((allow) => { allow("write"); });
|
|
124
|
+
* accessHintForGuard(guardBoth); // "both"
|
|
125
|
+
*
|
|
126
|
+
* const guardHuman = policy((allow) => {
|
|
127
|
+
* allow("write", { where: (a) => a.type === "human" });
|
|
128
|
+
* });
|
|
129
|
+
* accessHintForGuard(guardHuman); // "human"
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
declare function accessHintForGuard(guard: NodeGuard): string;
|
|
133
|
+
|
|
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 `emitWithBatch`, 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
|
+
/**
|
|
285
|
+
* Node versioning — GRAPHREFLY-SPEC §7.
|
|
286
|
+
*
|
|
287
|
+
* Progressive, optional versioning for node identity and change tracking.
|
|
288
|
+
*
|
|
289
|
+
* - **V0**: `id` + `version` — identity & change detection (~16 bytes overhead)
|
|
290
|
+
* - **V1**: + `cid` + `prev` — content addressing & linked history (~60 bytes overhead)
|
|
291
|
+
*
|
|
292
|
+
* **Lifecycle notes:**
|
|
293
|
+
* - Version advances only on DATA (not RESOLVED, INVALIDATE, or TEARDOWN).
|
|
294
|
+
* - `resetOnTeardown` clears the cached value but does NOT reset versioning state.
|
|
295
|
+
* After teardown, `v.cid` still reflects the last DATA value, not the cleared cache.
|
|
296
|
+
* The invariant `hash(node.get()) === v.cid` only holds in `settled`/`resolved` status.
|
|
297
|
+
* - Resubscribable nodes preserve versioning across subscription lifetimes (monotonic counter).
|
|
298
|
+
*/
|
|
299
|
+
/** V0: identity + monotonic version counter. */
|
|
300
|
+
type V0 = {
|
|
301
|
+
readonly id: string;
|
|
302
|
+
version: number;
|
|
303
|
+
};
|
|
304
|
+
/** V1: V0 + content-addressed identifier + previous cid link. */
|
|
305
|
+
type V1 = V0 & {
|
|
306
|
+
cid: string;
|
|
307
|
+
prev: string | null;
|
|
308
|
+
};
|
|
309
|
+
/** Union of all versioning info shapes. */
|
|
310
|
+
type NodeVersionInfo = V0 | V1;
|
|
311
|
+
/** Supported versioning levels (extensible to 2, 3 later). */
|
|
312
|
+
type VersioningLevel = 0 | 1;
|
|
313
|
+
/** Function that hashes a value to a hex string (for V1 cid). */
|
|
314
|
+
type HashFn = (value: unknown) => string;
|
|
315
|
+
interface VersioningOptions {
|
|
316
|
+
/** Override auto-generated id. */
|
|
317
|
+
id?: string;
|
|
318
|
+
/** Custom hash function for V1 cid (default: SHA-256 truncated to 16 hex chars). */
|
|
319
|
+
hash?: HashFn;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Default content hash: SHA-256 of deterministic JSON, truncated to 16 hex chars (~64-bit).
|
|
323
|
+
* Uses {@link canonicalizeForHash} for cross-language parity with Python `default_hash`.
|
|
324
|
+
*/
|
|
325
|
+
declare function defaultHash(value: unknown): string;
|
|
326
|
+
/**
|
|
327
|
+
* Create initial versioning state for a node.
|
|
328
|
+
*
|
|
329
|
+
* @param level - 0 for V0, 1 for V1.
|
|
330
|
+
* @param initialValue - The node's initial cached value (used for V1 cid).
|
|
331
|
+
* @param opts - Optional overrides (id, hash).
|
|
332
|
+
*/
|
|
333
|
+
declare function createVersioning(level: VersioningLevel, initialValue: unknown, opts?: VersioningOptions): NodeVersionInfo;
|
|
334
|
+
/**
|
|
335
|
+
* Advance versioning state after a DATA emission (value changed).
|
|
336
|
+
*
|
|
337
|
+
* Mutates `info` in place for performance (called on every DATA).
|
|
338
|
+
* Only call when the cached value has actually changed (not on RESOLVED).
|
|
339
|
+
*
|
|
340
|
+
* @param info - The node's current versioning state.
|
|
341
|
+
* @param newValue - The new cached value.
|
|
342
|
+
* @param hashFn - Hash function (only used for V1).
|
|
343
|
+
*/
|
|
344
|
+
declare function advanceVersion(info: NodeVersionInfo, newValue: unknown, hashFn: HashFn): void;
|
|
345
|
+
/** Type guard: is this V1 versioning info? */
|
|
346
|
+
declare function isV1(info: NodeVersionInfo): info is V1;
|
|
347
|
+
|
|
348
|
+
/** Lifecycle status of a node. */
|
|
349
|
+
type NodeStatus = "disconnected" | "dirty" | "settled" | "resolved" | "completed" | "errored";
|
|
350
|
+
/** Callback that receives downstream message batches. */
|
|
351
|
+
type NodeSink = (messages: Messages) => void;
|
|
352
|
+
/**
|
|
353
|
+
* Compute function passed to `node()`.
|
|
354
|
+
*
|
|
355
|
+
* @returns A value to emit, `undefined` to skip emission, or a cleanup
|
|
356
|
+
* function invoked before the next run or on teardown.
|
|
357
|
+
*/
|
|
358
|
+
type NodeFn<T = unknown> = (deps: readonly unknown[], actions: NodeActions) => T | undefined | (() => void);
|
|
359
|
+
/** Imperative actions available inside a {@link NodeFn}. */
|
|
360
|
+
interface NodeActions {
|
|
361
|
+
/** Emit raw messages downstream. */
|
|
362
|
+
down(messages: Messages): void;
|
|
363
|
+
/** Emit a single value (auto-wraps in DIRTY/DATA or DIRTY/RESOLVED). */
|
|
364
|
+
emit(value: unknown): void;
|
|
365
|
+
/** Send messages upstream toward sources. */
|
|
366
|
+
up(messages: Messages): void;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Callback for intercepting messages before the default dispatch.
|
|
370
|
+
*
|
|
371
|
+
* Called for every message from every dep. Return `true` to consume the
|
|
372
|
+
* message (skip default handling), or `false` to let default dispatch run.
|
|
373
|
+
*
|
|
374
|
+
* @param msg — The message tuple `[Type, Data?]`.
|
|
375
|
+
* @param depIndex — Which dep sent it (index into the deps array).
|
|
376
|
+
* @param actions — `{ down(), emit(), up() }` — same as `NodeFn` receives.
|
|
377
|
+
*/
|
|
378
|
+
type OnMessageHandler = (msg: Message, depIndex: number, actions: NodeActions) => boolean;
|
|
379
|
+
/**
|
|
380
|
+
* Internal inspector hook (opt-in): emits dependency message and run events
|
|
381
|
+
* for graph-level observability features (`observe(..., { causal|derived })`).
|
|
382
|
+
*/
|
|
383
|
+
type NodeInspectorHookEvent = {
|
|
384
|
+
kind: "dep_message";
|
|
385
|
+
depIndex: number;
|
|
386
|
+
message: Message;
|
|
387
|
+
} | {
|
|
388
|
+
kind: "run";
|
|
389
|
+
depValues: readonly unknown[];
|
|
390
|
+
};
|
|
391
|
+
type NodeInspectorHook = (event: NodeInspectorHookEvent) => void;
|
|
392
|
+
/** Explicit describe `type` for {@link Graph.describe} / {@link describeNode} (GRAPHREFLY-SPEC Appendix B). */
|
|
393
|
+
type NodeDescribeKind = "state" | "derived" | "producer" | "operator" | "effect";
|
|
394
|
+
/** Options for {@link node}. */
|
|
395
|
+
interface NodeOptions {
|
|
396
|
+
name?: string;
|
|
397
|
+
/**
|
|
398
|
+
* Overrides inferred `type` in describe output. Sugar constructors set this;
|
|
399
|
+
* omit to infer from deps / fn / manual emit usage.
|
|
400
|
+
*/
|
|
401
|
+
describeKind?: NodeDescribeKind;
|
|
402
|
+
/** Equality check for RESOLVED detection. Defaults to `Object.is`. */
|
|
403
|
+
equals?: (a: unknown, b: unknown) => boolean;
|
|
404
|
+
initial?: unknown;
|
|
405
|
+
/**
|
|
406
|
+
* Each key becomes an independently subscribable companion node.
|
|
407
|
+
* Meta nodes outlive the parent's subscription lifecycle: when all sinks
|
|
408
|
+
* unsubscribe the parent disconnects upstream but meta nodes stay alive.
|
|
409
|
+
* Send `[[TEARDOWN]]` to the parent to release meta node resources.
|
|
410
|
+
*/
|
|
411
|
+
meta?: Record<string, unknown>;
|
|
412
|
+
/** Allow fresh subscriptions after COMPLETE/ERROR. */
|
|
413
|
+
resubscribable?: boolean;
|
|
414
|
+
/**
|
|
415
|
+
* Invoked when a new {@link Node.subscribe} clears a terminal state on a
|
|
416
|
+
* resubscribable node — reset operator-local counters/accumulators here.
|
|
417
|
+
*/
|
|
418
|
+
onResubscribe?: () => void;
|
|
419
|
+
/** Clear cached value on TEARDOWN. */
|
|
420
|
+
resetOnTeardown?: boolean;
|
|
421
|
+
/**
|
|
422
|
+
* When `true` (default), auto-emit `[[COMPLETE]]` when all deps complete
|
|
423
|
+
* (spec §1.3.5). Set `false` for derived/operator nodes that should not
|
|
424
|
+
* auto-complete.
|
|
425
|
+
*/
|
|
426
|
+
completeWhenDepsComplete?: boolean;
|
|
427
|
+
/**
|
|
428
|
+
* Intercept messages before the default dispatch (spec §2.6).
|
|
429
|
+
*
|
|
430
|
+
* Return `true` to consume the message (skip default handling),
|
|
431
|
+
* or `false` to let the default dispatch run.
|
|
432
|
+
*/
|
|
433
|
+
onMessage?: OnMessageHandler;
|
|
434
|
+
/**
|
|
435
|
+
* ABAC: `(actor, action) => boolean`. `write` applies to both {@link Node.down} and {@link Node.up}.
|
|
436
|
+
* Companion {@link NodeOptions.meta | meta} nodes inherit this guard from the primary.
|
|
437
|
+
*/
|
|
438
|
+
guard?: NodeGuard;
|
|
439
|
+
/**
|
|
440
|
+
* Opt-in versioning level (GRAPHREFLY-SPEC §7).
|
|
441
|
+
* - `0` (V0): `id` + `version` — identity & change detection.
|
|
442
|
+
* - `1` (V1): + `cid` + `prev` — content addressing & linked history.
|
|
443
|
+
*/
|
|
444
|
+
versioning?: VersioningLevel;
|
|
445
|
+
/** Override auto-generated versioning id. */
|
|
446
|
+
versioningId?: string;
|
|
447
|
+
/** Custom hash function for V1 cid computation. */
|
|
448
|
+
versioningHash?: HashFn;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Options for {@link Node.down} / {@link Node.up} (actor context, graph delivery mode, internal bypass).
|
|
452
|
+
*/
|
|
453
|
+
type NodeTransportOptions = {
|
|
454
|
+
actor?: Actor;
|
|
455
|
+
/**
|
|
456
|
+
* When `true`, skips guard checks (reactive internals, graph lifecycle TEARDOWN, etc.).
|
|
457
|
+
* Not for untrusted call sites.
|
|
458
|
+
*/
|
|
459
|
+
internal?: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* `signal` for {@link Graph.signal} deliveries; default `write` for {@link Graph.set} and direct `down`.
|
|
462
|
+
*/
|
|
463
|
+
delivery?: "write" | "signal";
|
|
464
|
+
};
|
|
465
|
+
/**
|
|
466
|
+
* Optional hints passed to {@link Node.subscribe} to enable per-sink
|
|
467
|
+
* optimizations.
|
|
468
|
+
*/
|
|
469
|
+
interface SubscribeHints {
|
|
470
|
+
/**
|
|
471
|
+
* Subscriber has exactly one dep with `fn` — the source may skip DIRTY
|
|
472
|
+
* dispatch when this is the sole subscriber. The subscriber synthesizes
|
|
473
|
+
* dirty state locally via `onDepSettled`.
|
|
474
|
+
*/
|
|
475
|
+
singleDep?: boolean;
|
|
476
|
+
/**
|
|
477
|
+
* Actor to check against the node's `observe` guard.
|
|
478
|
+
* When set, `subscribe()` throws {@link GuardDenied} if the actor is not
|
|
479
|
+
* permitted to observe this node. Aligned with graphrefly-py `subscribe(actor=)`.
|
|
480
|
+
*/
|
|
481
|
+
actor?: Actor;
|
|
482
|
+
}
|
|
483
|
+
/** A reactive node in the GraphReFly protocol. */
|
|
484
|
+
interface Node<T = unknown> {
|
|
485
|
+
readonly name?: string;
|
|
486
|
+
readonly status: NodeStatus;
|
|
487
|
+
readonly meta: Record<string, Node>;
|
|
488
|
+
/** Returns the current cached value. */
|
|
489
|
+
get(): T | undefined;
|
|
490
|
+
/** Push messages downstream. */
|
|
491
|
+
down(messages: Messages, options?: NodeTransportOptions): void;
|
|
492
|
+
/**
|
|
493
|
+
* Registers a sink to receive downstream messages.
|
|
494
|
+
*
|
|
495
|
+
* @param sink - Callback receiving message batches.
|
|
496
|
+
* @param hints - Optional optimization hints (e.g. `{ singleDep: true }`).
|
|
497
|
+
* @returns An unsubscribe function (idempotent).
|
|
498
|
+
*/
|
|
499
|
+
subscribe(sink: NodeSink, hints?: SubscribeHints): () => void;
|
|
500
|
+
/** Send messages upstream (present on nodes with deps). */
|
|
501
|
+
up?: (messages: Messages, options?: NodeTransportOptions) => void;
|
|
502
|
+
/** Disconnect from upstream deps (present on nodes with deps). */
|
|
503
|
+
unsubscribe?: () => void;
|
|
504
|
+
/** Last successful guarded `down` / `up` (not set for `internal` deliveries). */
|
|
505
|
+
readonly lastMutation?: Readonly<{
|
|
506
|
+
actor: Actor;
|
|
507
|
+
timestamp_ns: number;
|
|
508
|
+
}>;
|
|
509
|
+
/** Whether {@link NodeTransportOptions.actor | actor} may {@link Graph.observe | observe} this node. */
|
|
510
|
+
allowsObserve(actor: Actor): boolean;
|
|
511
|
+
/** Whether a {@link NodeOptions.guard | guard} is installed. */
|
|
512
|
+
hasGuard(): boolean;
|
|
513
|
+
/** Versioning info (GRAPHREFLY-SPEC §7). `undefined` when versioning is not enabled. */
|
|
514
|
+
readonly v: Readonly<NodeVersionInfo> | undefined;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Creates a reactive {@link Node} — the single GraphReFly primitive (GRAPHREFLY-SPEC §2).
|
|
518
|
+
*
|
|
519
|
+
* Typical shapes: `node([])` / `node([], opts)` for a manual source; `node(producerFn, opts)` for a
|
|
520
|
+
* producer; `node(deps, computeFn, opts)` for derived nodes and operators.
|
|
521
|
+
*
|
|
522
|
+
* @param depsOrFn - Dependency nodes, a {@link NodeFn} (producer), or {@link NodeOptions} alone.
|
|
523
|
+
* @param fnOrOpts - With deps: compute function or options. Omitted for producer-only form.
|
|
524
|
+
* @param optsArg - Options when both `deps` and `fn` are provided.
|
|
525
|
+
* @returns `Node<T>` - Configured node instance (lazy until subscribed).
|
|
526
|
+
*
|
|
527
|
+
* @remarks
|
|
528
|
+
* **Protocol:** DIRTY / DATA / RESOLVED ordering, completion, and batch deferral follow `~/src/graphrefly/GRAPHREFLY-SPEC.md`.
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* ```ts
|
|
532
|
+
* import { node, state } from "@graphrefly/graphrefly-ts";
|
|
533
|
+
*
|
|
534
|
+
* const a = state(1);
|
|
535
|
+
* const b = node([a], ([x]) => (x as number) + 1);
|
|
536
|
+
* ```
|
|
537
|
+
*
|
|
538
|
+
* @seeAlso [Specification](/spec)
|
|
539
|
+
*
|
|
540
|
+
* @category core
|
|
541
|
+
*/
|
|
542
|
+
declare function node<T = unknown>(depsOrFn?: readonly Node[] | NodeFn<T> | NodeOptions, fnOrOpts?: NodeFn<T> | NodeOptions, optsArg?: NodeOptions): Node<T>;
|
|
543
|
+
|
|
544
|
+
/** JSON-shaped slice of a node for Phase 1 `Graph.describe()` (GRAPHREFLY-SPEC §3.6, Appendix B). */
|
|
545
|
+
type DescribeNodeOutput = {
|
|
546
|
+
type: "state" | "derived" | "producer" | "operator" | "effect";
|
|
547
|
+
status: Node["status"];
|
|
548
|
+
deps: string[];
|
|
549
|
+
meta: Record<string, unknown>;
|
|
550
|
+
name?: string;
|
|
551
|
+
value?: unknown;
|
|
552
|
+
/** Node versioning info (GRAPHREFLY-SPEC §7). Present only when versioning is enabled. */
|
|
553
|
+
v?: {
|
|
554
|
+
id: string;
|
|
555
|
+
version: number;
|
|
556
|
+
cid?: string;
|
|
557
|
+
prev?: string | null;
|
|
558
|
+
};
|
|
559
|
+
};
|
|
560
|
+
/**
|
|
561
|
+
* Reads the current cached value of every companion meta field on a node,
|
|
562
|
+
* suitable for merging into `describe()`-style JSON (GRAPHREFLY-SPEC §2.3, §3.6).
|
|
563
|
+
*
|
|
564
|
+
* @remarks
|
|
565
|
+
* Values come from {@link Node.get}, which returns the **last settled** cache.
|
|
566
|
+
* If a meta field is in `"dirty"` status (DIRTY received, DATA pending), the
|
|
567
|
+
* snapshot contains the *previous* value — check `node.meta[key].status` when
|
|
568
|
+
* freshness matters. Avoid calling mid-batch for the same reason.
|
|
569
|
+
*
|
|
570
|
+
* Meta nodes are **not** terminated when their parent receives COMPLETE or
|
|
571
|
+
* ERROR — they remain writable so callers can record post-mortem metadata
|
|
572
|
+
* (e.g. `meta.error`). They *are* torn down when the parent receives TEARDOWN.
|
|
573
|
+
*
|
|
574
|
+
* @param node - The node whose meta fields to snapshot.
|
|
575
|
+
* @returns Plain object of `{ key: value }` pairs (empty if no meta defined).
|
|
576
|
+
* Keys whose companion node's {@link Node.get} throws are omitted.
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```ts
|
|
580
|
+
* import { core } from "@graphrefly/graphrefly-ts";
|
|
581
|
+
*
|
|
582
|
+
* const n = core.node({ initial: 0, meta: { tag: "a" } });
|
|
583
|
+
* core.metaSnapshot(n); // { tag: "a" }
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
declare function metaSnapshot(node: Node): Record<string, unknown>;
|
|
587
|
+
/**
|
|
588
|
+
* Builds a single-node slice of `Graph.describe()` JSON (structure + `meta` snapshot).
|
|
589
|
+
* Parity with graphrefly-py `describe_node`.
|
|
590
|
+
*
|
|
591
|
+
* `type` is inferred from factory configuration, optional `describeKind` in node options,
|
|
592
|
+
* and the last `manualEmitUsed` hint (operator vs derived). {@link effect} sets
|
|
593
|
+
* `describeKind: "effect"`. Nodes not created by {@link node} fall back to `type: "state"` and empty `deps`.
|
|
594
|
+
*
|
|
595
|
+
* @param node - Any `Node` to introspect.
|
|
596
|
+
* @returns `DescribeNodeOutput` suitable for merging into graph describe maps.
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```ts
|
|
600
|
+
* import { describeNode, state } from "@graphrefly/graphrefly-ts";
|
|
601
|
+
*
|
|
602
|
+
* describeNode(state(0));
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
605
|
+
declare function describeNode(node: Node): DescribeNodeOutput;
|
|
606
|
+
|
|
607
|
+
export { propagatesToMeta as $, type Actor as A, describeNode as B, COMPLETE as C, DATA as D, ERROR as E, isKnownMessageType as F, type GuardAction as G, type HashFn as H, INVALIDATE as I, isPhase2Message as J, isTerminalMessage as K, isV1 as L, type Message as M, type Node as N, type OnMessageHandler as O, PAUSE as P, knownMessageTypes as Q, RESOLVED as R, type SubscribeHints as S, TEARDOWN as T, messageTier as U, type V0 as V, metaSnapshot as W, node as X, normalizeActor as Y, policy as Z, policyFromRules as _, type NodeOptions as a, type NodeInspectorHook as a0, type NodeActions as b, type NodeFn as c, DEFAULT_ACTOR as d, DIRTY as e, type DescribeNodeOutput as f, GuardDenied as g, type GuardDeniedDetails as h, type Messages as i, type NodeDescribeKind as j, type NodeGuard as k, type NodeSink as l, type NodeStatus as m, type NodeTransportOptions as n, type NodeVersionInfo as o, type PolicyAllow as p, type PolicyDeny as q, type PolicyRuleData as r, RESUME as s, type V1 as t, type VersioningLevel as u, type VersioningOptions as v, accessHintForGuard as w, advanceVersion as x, createVersioning as y, defaultHash as z };
|