@graphrefly/graphrefly 0.6.0 → 0.8.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/README.md +30 -14
- package/dist/{chunk-HP7OKEOE.js → chunk-A2AJJOSJ.js} +3 -3
- package/dist/chunk-A2AJJOSJ.js.map +1 -0
- package/dist/{chunk-CP6MNKAA.js → chunk-E7OH6ZAZ.js} +10 -4
- package/dist/{chunk-CP6MNKAA.js.map → chunk-E7OH6ZAZ.js.map} +1 -1
- package/dist/chunk-LR2CLSEF.js +106 -0
- package/dist/chunk-LR2CLSEF.js.map +1 -0
- package/dist/{chunk-5X3LAO3B.js → chunk-QTZSBQGJ.js} +79 -20
- package/dist/chunk-QTZSBQGJ.js.map +1 -0
- package/dist/{chunk-V3UACY6A.js → chunk-TZLX4KIT.js} +790 -203
- package/dist/chunk-TZLX4KIT.js.map +1 -0
- package/dist/{chunk-QW7H3ICI.js → chunk-UCW3VWMN.js} +4 -4
- package/dist/{chunk-6W5SGIGB.js → chunk-WYI7YW54.js} +142 -30
- package/dist/chunk-WYI7YW54.js.map +1 -0
- package/dist/chunk-WZ2Z2CRV.js +32 -0
- package/dist/chunk-WZ2Z2CRV.js.map +1 -0
- package/dist/{chunk-Z4Y4FMQN.js → chunk-XCZPGOVP.js} +7 -7
- package/dist/{chunk-KWXPDASV.js → chunk-YWTP2XRJ.js} +2 -2
- package/dist/compat/nestjs/index.cjs +268 -61
- 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 +8 -7
- package/dist/core/index.cjs +163 -35
- 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 +10 -4
- package/dist/extra/index.cjs +892 -221
- 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 +22 -3
- package/dist/graph/index.cjs +268 -61
- 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 +4 -4
- package/dist/{graph-CL_ZDAj9.d.cts → graph-DqTICAY2.d.cts} +69 -12
- package/dist/{graph-D18qmsNm.d.ts → graph-X9uwnD_z.d.ts} +69 -12
- package/dist/{index-C3BMRmmp.d.cts → index-3U0WxdD-.d.cts} +3 -3
- package/dist/{index-Bk_idZm1.d.cts → index-BP1t_38S.d.cts} +406 -61
- package/dist/{index-BtK55IE2.d.ts → index-BPCeYDS4.d.ts} +4 -2
- package/dist/{index-Bvy_6CaN.d.ts → index-BVG5pjin.d.ts} +50 -5
- package/dist/{index-C5mqLhMX.d.cts → index-BYEgosAX.d.cts} +50 -5
- package/dist/{index-D_geH2Bm.d.cts → index-BYa2YMat.d.cts} +3 -3
- package/dist/{index-CP_QvbWu.d.ts → index-DLO8wnYU.d.ts} +3 -3
- package/dist/{index-B7eOdgEx.d.ts → index-DMv1Etbi.d.ts} +3 -3
- package/dist/{index-BvhgZRHK.d.cts → index-DbwgQ4Cw.d.cts} +4 -2
- package/dist/{index-B2jmzVxL.d.ts → index-a5gHmH5b.d.ts} +406 -61
- package/dist/index.cjs +2966 -1790
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -14
- package/dist/index.d.ts +112 -14
- package/dist/index.js +385 -20
- package/dist/index.js.map +1 -1
- package/dist/{meta-BsF6Sag9.d.cts → meta-BJEU8fYz.d.cts} +31 -4
- package/dist/{meta-BsF6Sag9.d.ts → meta-BJEU8fYz.d.ts} +31 -4
- package/dist/patterns/reactive-layout/index.cjs +268 -61
- 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/dist/{reactive-log-BfvfNWQh.d.cts → reactive-log-BfX6bOSZ.d.cts} +2 -2
- package/dist/{reactive-log-ohLmTXoZ.d.ts → reactive-log-RhgIog2Z.d.ts} +2 -2
- package/package.json +29 -18
- package/dist/chunk-5X3LAO3B.js.map +0 -1
- package/dist/chunk-6W5SGIGB.js.map +0 -1
- package/dist/chunk-HP7OKEOE.js.map +0 -1
- package/dist/chunk-O3PI7W45.js +0 -68
- package/dist/chunk-O3PI7W45.js.map +0 -1
- package/dist/chunk-V3UACY6A.js.map +0 -1
- /package/dist/{chunk-QW7H3ICI.js.map → chunk-UCW3VWMN.js.map} +0 -0
- /package/dist/{chunk-Z4Y4FMQN.js.map → chunk-XCZPGOVP.js.map} +0 -0
- /package/dist/{chunk-KWXPDASV.js.map → chunk-YWTP2XRJ.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# GraphReFly
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Describe what matters. It watches, filters, and explains — persistently.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
You're buried under emails, alerts, feeds, and messages. You can't process it all. GraphReFly lets you describe automations in plain language, review them visually, run them persistently, and trace every decision back to its source.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@graphrefly/graphrefly)
|
|
8
8
|
[](./LICENSE)
|
|
@@ -11,6 +11,18 @@ One primitive. Zero dependencies. Composable nodes with glitch-free diamond reso
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
<!-- TODO: Demo 0 GIF/video — NL → flow view → running → "why was this flagged?" -->
|
|
15
|
+
|
|
16
|
+
## What can you do with it?
|
|
17
|
+
|
|
18
|
+
**Email triage** — "Watch my inbox. Urgent emails from my team go to a priority list. Newsletters get summarized weekly. Everything else, count by sender." It watches, classifies, and alerts — and when you ask "why was this flagged?", it walks you through the reasoning.
|
|
19
|
+
|
|
20
|
+
**Spending alerts** — Connect bank transactions to budget categories. Get a push notification when monthly dining exceeds your target. No polling, no manual checks — changes propagate the moment data arrives.
|
|
21
|
+
|
|
22
|
+
**Knowledge management** — Notes, bookmarks, highlights flow in. Contradictions surface automatically. Related ideas link themselves. Your second brain stays current without you maintaining it.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
14
26
|
## Quick start
|
|
15
27
|
|
|
16
28
|
```bash
|
|
@@ -30,20 +42,24 @@ count.set(3);
|
|
|
30
42
|
// → doubled: 6
|
|
31
43
|
```
|
|
32
44
|
|
|
45
|
+
## How it works
|
|
46
|
+
|
|
47
|
+
You describe what you need — an LLM composes a reactive graph (like SQL for data flows). The graph runs persistently, checkpoints its state, and traces every decision through a causal chain. Ask "why?" at any point and get a human-readable explanation from source to conclusion.
|
|
48
|
+
|
|
33
49
|
## Why GraphReFly?
|
|
34
50
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
|
38
|
-
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
| Framework adapters | React | Angular | React / Vue | varies | **React / Vue / Svelte / Solid / NestJS** |
|
|
46
|
-
| Dependencies | 0 | 0 | 0 | n/a | **0** |
|
|
51
|
+
| | Zustand / Jotai | RxJS | XState | LangGraph | TC39 Signals | **GraphReFly** |
|
|
52
|
+
|--|-----------------|------|--------|-----------|-------------|---------------|
|
|
53
|
+
| Simple store API | yes | no | no | no | yes | **yes** |
|
|
54
|
+
| Streaming operators | no | yes | no | no | no | **yes** |
|
|
55
|
+
| Diamond resolution | no | n/a | n/a | n/a | partial | **glitch-free** |
|
|
56
|
+
| Graph introspection | no | no | visual | checkpoints | no | **describe / observe / diagram** |
|
|
57
|
+
| Causal tracing | no | no | no | no | no | **explain every decision** |
|
|
58
|
+
| Durable checkpoints | no | no | persistence | yes | no | **file / SQLite / IndexedDB** |
|
|
59
|
+
| LLM orchestration | no | no | no | yes | no | **agentLoop / chatStream / toolRegistry** |
|
|
60
|
+
| NL → graph composition | no | no | no | no | no | **graphFromSpec / llmCompose** |
|
|
61
|
+
| Framework adapters | React | Angular | React / Vue | n/a | varies | **React / Vue / Svelte / Solid / NestJS** |
|
|
62
|
+
| Dependencies | 0 | 0 | 0 | many | n/a | **0** |
|
|
47
63
|
|
|
48
64
|
## One primitive
|
|
49
65
|
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
GRAPH_META_SEGMENT,
|
|
3
3
|
Graph,
|
|
4
4
|
reachable
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-WYI7YW54.js";
|
|
6
6
|
import {
|
|
7
7
|
__export
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QTZSBQGJ.js";
|
|
9
9
|
|
|
10
10
|
// src/graph/index.ts
|
|
11
11
|
var graph_exports = {};
|
|
@@ -104,4 +104,4 @@ export {
|
|
|
104
104
|
replayWAL,
|
|
105
105
|
graph_exports
|
|
106
106
|
};
|
|
107
|
-
//# sourceMappingURL=chunk-
|
|
107
|
+
//# sourceMappingURL=chunk-A2AJJOSJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/graph/index.ts","../src/graph/codec.ts"],"sourcesContent":["/**\n * Graph container: registry, wiring, introspection (Phase 1).\n */\n\nexport {\n\tcreateDagCborCodec,\n\tcreateDagCborZstdCodec,\n\ttype DeltaCheckpoint,\n\ttype EvictedSubgraphInfo,\n\ttype EvictionPolicy,\n\ttype GraphCodec,\n\tJsonCodec,\n\ttype LazyGraphCodec,\n\tnegotiateCodec,\n\treplayWAL,\n\ttype WALEntry,\n} from \"./codec.js\";\nexport {\n\ttype AutoCheckpointAdapter,\n\ttype DescribeFilter,\n\tGRAPH_META_SEGMENT,\n\tGraph,\n\ttype GraphActorOptions,\n\ttype GraphAutoCheckpointHandle,\n\ttype GraphAutoCheckpointOptions,\n\ttype GraphCheckpointRecord,\n\ttype GraphDescribeOptions,\n\ttype GraphDescribeOutput,\n\ttype GraphDiagramDirection,\n\ttype GraphDiagramOptions,\n\ttype GraphDiffChange,\n\ttype GraphDiffResult,\n\ttype GraphDumpOptions,\n\ttype GraphFactoryContext,\n\ttype GraphNodeFactory,\n\ttype GraphObserveAll,\n\ttype GraphObserveOne,\n\ttype GraphOptions,\n\ttype GraphPersistSnapshot,\n\ttype GraphSpyHandle,\n\ttype GraphSpyOptions,\n\ttype GraphSpyTheme,\n\ttype GraphSpyThemeName,\n\ttype ObserveDetail,\n\ttype ObserveEvent,\n\ttype ObserveOptions,\n\ttype ObserveResult,\n\ttype ReachableDirection,\n\ttype ReachableOptions,\n\treachable,\n\ttype TraceEntry,\n} from \"./graph.js\";\n","/**\n * GraphCodec — pluggable serialization for graph snapshots (Phase 8.6).\n *\n * Design reference: `archive/docs/SESSION-serialization-memory-footprint.md`\n *\n * The codec interface decouples snapshot format from graph internals.\n * Default is JSON (current behavior). DAG-CBOR and compressed variants\n * ship as optional codecs. FlatBuffers/Arrow for advanced tiers.\n *\n * Tiered representation:\n * HOT — JS objects (live propagation, no codec involved)\n * WARM — DAG-CBOR in-memory buffer (lazy hydration, delta checkpoints)\n * COLD — Arrow/Parquet (bulk storage, ML pipelines, archival)\n * PEEK — FlatBuffers (zero-copy read from dormant graph)\n */\n\nimport type { GraphPersistSnapshot } from \"./graph.js\";\n\n// ---------------------------------------------------------------------------\n// Core codec interface\n// ---------------------------------------------------------------------------\n\n/**\n * Encode/decode graph snapshots to/from binary.\n *\n * Implementations must be deterministic: `encode(x)` always produces the\n * same bytes for the same input. This is critical for CID computation (V1)\n * and snapshot hash-comparison.\n */\nexport interface GraphCodec {\n\t/** MIME-like content type identifier (e.g. \"application/dag-cbor+zstd\"). */\n\treadonly contentType: string;\n\n\t/** Human-readable name for diagnostics. */\n\treadonly name: string;\n\n\t/** Encode a snapshot to binary. */\n\tencode(snapshot: GraphPersistSnapshot): Uint8Array;\n\n\t/**\n\t * Decode binary back to a snapshot.\n\t *\n\t * For lazy codecs, this may return a proxy that decodes nodes on access\n\t * (see {@link LazyGraphCodec}).\n\t */\n\tdecode(buffer: Uint8Array): GraphPersistSnapshot;\n}\n\n/**\n * Extended codec that supports lazy (on-demand) node decoding.\n *\n * `decodeLazy` returns a snapshot where `nodes` is a Proxy — individual\n * nodes are decoded only when accessed. This enables near-zero cold-start\n * for large graphs (decode envelope + topology, skip node values until read).\n */\nexport interface LazyGraphCodec extends GraphCodec {\n\t/** Decode envelope and topology; defer node value decoding to access time. */\n\tdecodeLazy(buffer: Uint8Array): GraphPersistSnapshot;\n}\n\n// ---------------------------------------------------------------------------\n// Delta checkpoint types (requires V0 — Phase 6.0)\n// ---------------------------------------------------------------------------\n\n/**\n * A delta checkpoint: only the nodes that changed since last checkpoint.\n *\n * Append-only: each delta is identified by `seq` (monotonic). A full\n * snapshot is taken every `compactEvery` deltas for WAL compaction.\n */\nexport interface DeltaCheckpoint {\n\t/** Monotonic sequence number. */\n\tseq: number;\n\t/** Graph name. */\n\tname: string;\n\t/** Base snapshot seq this delta applies to (0 = initial full snapshot). */\n\tbaseSec: number;\n\t/** Only nodes with version > lastCheckpoint. Keyed by node name. */\n\tnodes: Record<\n\t\tstring,\n\t\t{\n\t\t\t/** V0 version at time of checkpoint. */\n\t\t\tversion: number;\n\t\t\t/** Serialized node value (codec-dependent). */\n\t\t\tvalue: unknown;\n\t\t\t/** Meta snapshot (only if materialized). */\n\t\t\tmeta?: Record<string, unknown>;\n\t\t}\n\t>;\n\t/** Nodes removed since last checkpoint. */\n\tremoved: string[];\n\t/** Edges added since last checkpoint. */\n\tedgesAdded: ReadonlyArray<{ from: string; to: string }>;\n\t/** Edges removed since last checkpoint. */\n\tedgesRemoved: ReadonlyArray<{ from: string; to: string }>;\n\t/** Timestamp (wall-clock ns) of this checkpoint. */\n\ttimestampNs: bigint;\n}\n\n/**\n * WAL entry: either a full snapshot or a delta.\n */\nexport type WALEntry =\n\t| { type: \"full\"; snapshot: GraphPersistSnapshot; seq: number }\n\t| { type: \"delta\"; delta: DeltaCheckpoint };\n\n// ---------------------------------------------------------------------------\n// Eviction policy (dormant subgraph management)\n// ---------------------------------------------------------------------------\n\n/**\n * Policy for evicting dormant subgraphs to reduce memory.\n *\n * When a subgraph hasn't propagated for `idleTimeoutMs`, it is serialized\n * using the graph's codec and JS objects are released. Re-hydrated on next\n * access (read, propagation, describe).\n */\nexport interface EvictionPolicy {\n\t/** Milliseconds of inactivity before eviction. */\n\tidleTimeoutMs: number;\n\t/** Codec to use for serializing evicted subgraphs (default: graph's codec). */\n\tcodec?: GraphCodec;\n}\n\n/** Metadata about an evicted subgraph, exposed via describe(). */\nexport interface EvictedSubgraphInfo {\n\t/** True if currently evicted (serialized, JS objects released). */\n\tevicted: true;\n\t/** Wall-clock ns of last propagation before eviction. */\n\tlastActiveNs: bigint;\n\t/** Size of serialized buffer in bytes. */\n\tserializedBytes: number;\n\t/** Codec used for serialization. */\n\tcodecName: string;\n}\n\n// ---------------------------------------------------------------------------\n// JSON codec (default — wraps current behavior)\n// ---------------------------------------------------------------------------\n\n/**\n * Default JSON codec. Wraps `JSON.stringify`/`JSON.parse` with deterministic\n * key ordering (matching current `snapshot()` behavior).\n */\nexport const JsonCodec: GraphCodec = {\n\tcontentType: \"application/json\",\n\tname: \"json\",\n\n\tencode(snapshot: GraphPersistSnapshot): Uint8Array {\n\t\t// Deterministic: snapshot() already sorts keys.\n\t\tconst json = JSON.stringify(snapshot);\n\t\treturn new TextEncoder().encode(json);\n\t},\n\n\tdecode(buffer: Uint8Array): GraphPersistSnapshot {\n\t\tconst json = new TextDecoder().decode(buffer);\n\t\treturn JSON.parse(json) as GraphPersistSnapshot;\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// DAG-CBOR codec (stub — requires @ipld/dag-cbor)\n// ---------------------------------------------------------------------------\n\n/**\n * Create a DAG-CBOR codec.\n *\n * Requires `@ipld/dag-cbor` as a peer dependency. ~40-50% smaller than JSON,\n * deterministic encoding (required for V1 CID), CID links as native type.\n *\n * @example\n * ```ts\n * import * as dagCbor from \"@ipld/dag-cbor\";\n * const codec = createDagCborCodec(dagCbor);\n * const bytes = codec.encode(graph.snapshot());\n * ```\n */\nexport function createDagCborCodec(dagCbor: {\n\tencode: (value: unknown) => Uint8Array;\n\tdecode: (bytes: Uint8Array) => unknown;\n}): GraphCodec {\n\treturn {\n\t\tcontentType: \"application/dag-cbor\",\n\t\tname: \"dag-cbor\",\n\t\tencode: (snapshot) => dagCbor.encode(snapshot),\n\t\tdecode: (buffer) => dagCbor.decode(buffer) as GraphPersistSnapshot,\n\t};\n}\n\n/**\n * Create a DAG-CBOR + zstd codec. ~80-90% smaller than JSON.\n *\n * Requires `@ipld/dag-cbor` and a zstd implementation (e.g. `fzstd` for\n * browser, `node:zlib` for Node.js).\n *\n * @example\n * ```ts\n * import * as dagCbor from \"@ipld/dag-cbor\";\n * import { compressSync, decompressSync } from \"fzstd\";\n * const codec = createDagCborZstdCodec(dagCbor, { compressSync, decompressSync });\n * ```\n */\nexport function createDagCborZstdCodec(\n\tdagCbor: {\n\t\tencode: (value: unknown) => Uint8Array;\n\t\tdecode: (bytes: Uint8Array) => unknown;\n\t},\n\tzstd: {\n\t\tcompressSync: (data: Uint8Array) => Uint8Array;\n\t\tdecompressSync: (data: Uint8Array) => Uint8Array;\n\t},\n): GraphCodec {\n\treturn {\n\t\tcontentType: \"application/dag-cbor+zstd\",\n\t\tname: \"dag-cbor-zstd\",\n\t\tencode: (snapshot) => zstd.compressSync(dagCbor.encode(snapshot)),\n\t\tdecode: (buffer) => dagCbor.decode(zstd.decompressSync(buffer)) as GraphPersistSnapshot,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Codec negotiation (for peerGraph)\n// ---------------------------------------------------------------------------\n\n/**\n * Negotiate a common codec between two peers.\n *\n * Each peer advertises its supported codecs (ordered by preference).\n * Returns the first codec supported by both, or null if none.\n */\nexport function negotiateCodec(\n\tlocalPreference: readonly GraphCodec[],\n\tremoteContentTypes: readonly string[],\n): GraphCodec | null {\n\tconst remoteSet = new Set(remoteContentTypes);\n\tfor (const codec of localPreference) {\n\t\tif (remoteSet.has(codec.contentType)) return codec;\n\t}\n\treturn null;\n}\n\n// ---------------------------------------------------------------------------\n// WAL helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Reconstruct a snapshot from a WAL (full snapshot + sequence of deltas).\n *\n * Applies deltas in order on top of the base snapshot. Validates that\n * delta `baseSec` chains correctly.\n */\nexport function replayWAL(entries: readonly WALEntry[]): GraphPersistSnapshot {\n\tif (entries.length === 0) {\n\t\tthrow new Error(\"WAL is empty — need at least one full snapshot\");\n\t}\n\n\tconst first = entries[0]!;\n\tif (first.type !== \"full\") {\n\t\tthrow new Error(\"WAL must start with a full snapshot\");\n\t}\n\n\t// Deep clone the base snapshot so we can mutate it.\n\tconst result: GraphPersistSnapshot = JSON.parse(JSON.stringify(first.snapshot));\n\n\tfor (let i = 1; i < entries.length; i++) {\n\t\tconst entry = entries[i]!;\n\t\tif (entry.type === \"full\") {\n\t\t\t// A compaction point — replace the entire result.\n\t\t\tObject.assign(result, JSON.parse(JSON.stringify(entry.snapshot)));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst delta = entry.delta;\n\n\t\t// Apply node changes.\n\t\tfor (const [name, patch] of Object.entries(delta.nodes)) {\n\t\t\tif (result.nodes[name]) {\n\t\t\t\tresult.nodes[name]!.value = patch.value;\n\t\t\t\tif (patch.meta) {\n\t\t\t\t\tresult.nodes[name]!.meta = patch.meta;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Apply removals.\n\t\tfor (const name of delta.removed) {\n\t\t\tdelete result.nodes[name];\n\t\t}\n\n\t\t// Apply edge changes.\n\t\tconst edges = [...result.edges];\n\t\tfor (const edge of delta.edgesRemoved) {\n\t\t\tconst idx = edges.findIndex((e) => e.from === edge.from && e.to === edge.to);\n\t\t\tif (idx !== -1) edges.splice(idx, 1);\n\t\t}\n\t\tfor (const edge of delta.edgesAdded) {\n\t\t\tedges.push(edge);\n\t\t}\n\t\t(result as unknown as { edges: typeof edges }).edges = edges;\n\t}\n\n\treturn result;\n}\n"],"mappings":";;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgJO,IAAM,YAAwB;AAAA,EACpC,aAAa;AAAA,EACb,MAAM;AAAA,EAEN,OAAO,UAA4C;AAElD,UAAM,OAAO,KAAK,UAAU,QAAQ;AACpC,WAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AAAA,EACrC;AAAA,EAEA,OAAO,QAA0C;AAChD,UAAM,OAAO,IAAI,YAAY,EAAE,OAAO,MAAM;AAC5C,WAAO,KAAK,MAAM,IAAI;AAAA,EACvB;AACD;AAmBO,SAAS,mBAAmB,SAGpB;AACd,SAAO;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,QAAQ,CAAC,aAAa,QAAQ,OAAO,QAAQ;AAAA,IAC7C,QAAQ,CAAC,WAAW,QAAQ,OAAO,MAAM;AAAA,EAC1C;AACD;AAeO,SAAS,uBACf,SAIA,MAIa;AACb,SAAO;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,QAAQ,CAAC,aAAa,KAAK,aAAa,QAAQ,OAAO,QAAQ,CAAC;AAAA,IAChE,QAAQ,CAAC,WAAW,QAAQ,OAAO,KAAK,eAAe,MAAM,CAAC;AAAA,EAC/D;AACD;AAYO,SAAS,eACf,iBACA,oBACoB;AACpB,QAAM,YAAY,IAAI,IAAI,kBAAkB;AAC5C,aAAW,SAAS,iBAAiB;AACpC,QAAI,UAAU,IAAI,MAAM,WAAW,EAAG,QAAO;AAAA,EAC9C;AACA,SAAO;AACR;AAYO,SAAS,UAAU,SAAoD;AAC7E,MAAI,QAAQ,WAAW,GAAG;AACzB,UAAM,IAAI,MAAM,qDAAgD;AAAA,EACjE;AAEA,QAAM,QAAQ,QAAQ,CAAC;AACvB,MAAI,MAAM,SAAS,QAAQ;AAC1B,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACtD;AAGA,QAAM,SAA+B,KAAK,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC;AAE9E,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACxC,UAAM,QAAQ,QAAQ,CAAC;AACvB,QAAI,MAAM,SAAS,QAAQ;AAE1B,aAAO,OAAO,QAAQ,KAAK,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC;AAChE;AAAA,IACD;AAEA,UAAM,QAAQ,MAAM;AAGpB,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,KAAK,GAAG;AACxD,UAAI,OAAO,MAAM,IAAI,GAAG;AACvB,eAAO,MAAM,IAAI,EAAG,QAAQ,MAAM;AAClC,YAAI,MAAM,MAAM;AACf,iBAAO,MAAM,IAAI,EAAG,OAAO,MAAM;AAAA,QAClC;AAAA,MACD;AAAA,IACD;AAGA,eAAW,QAAQ,MAAM,SAAS;AACjC,aAAO,OAAO,MAAM,IAAI;AAAA,IACzB;AAGA,UAAM,QAAQ,CAAC,GAAG,OAAO,KAAK;AAC9B,eAAW,QAAQ,MAAM,cAAc;AACtC,YAAM,MAAM,MAAM,UAAU,CAAC,MAAM,EAAE,SAAS,KAAK,QAAQ,EAAE,OAAO,KAAK,EAAE;AAC3E,UAAI,QAAQ,GAAI,OAAM,OAAO,KAAK,CAAC;AAAA,IACpC;AACA,eAAW,QAAQ,MAAM,YAAY;AACpC,YAAM,KAAK,IAAI;AAAA,IAChB;AACA,IAAC,OAA8C,QAAQ;AAAA,EACxD;AAEA,SAAO;AACR;","names":[]}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ResettableTimer
|
|
3
|
+
} from "./chunk-WZ2Z2CRV.js";
|
|
1
4
|
import {
|
|
2
5
|
describeNode,
|
|
3
|
-
metaSnapshot
|
|
4
|
-
|
|
6
|
+
metaSnapshot,
|
|
7
|
+
resolveDescribeFields
|
|
8
|
+
} from "./chunk-LR2CLSEF.js";
|
|
5
9
|
import {
|
|
6
10
|
COMPLETE,
|
|
7
11
|
DATA,
|
|
@@ -43,7 +47,7 @@ import {
|
|
|
43
47
|
propagatesToMeta,
|
|
44
48
|
state,
|
|
45
49
|
wallClockNs
|
|
46
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-QTZSBQGJ.js";
|
|
47
51
|
|
|
48
52
|
// src/core/index.ts
|
|
49
53
|
var core_exports = {};
|
|
@@ -59,6 +63,7 @@ __export(core_exports, {
|
|
|
59
63
|
PAUSE: () => PAUSE,
|
|
60
64
|
RESOLVED: () => RESOLVED,
|
|
61
65
|
RESUME: () => RESUME,
|
|
66
|
+
ResettableTimer: () => ResettableTimer,
|
|
62
67
|
TEARDOWN: () => TEARDOWN,
|
|
63
68
|
accessHintForGuard: () => accessHintForGuard,
|
|
64
69
|
advanceVersion: () => advanceVersion,
|
|
@@ -87,6 +92,7 @@ __export(core_exports, {
|
|
|
87
92
|
policyFromRules: () => policyFromRules,
|
|
88
93
|
producer: () => producer,
|
|
89
94
|
propagatesToMeta: () => propagatesToMeta,
|
|
95
|
+
resolveDescribeFields: () => resolveDescribeFields,
|
|
90
96
|
state: () => state,
|
|
91
97
|
wallClockNs: () => wallClockNs
|
|
92
98
|
});
|
|
@@ -94,4 +100,4 @@ __export(core_exports, {
|
|
|
94
100
|
export {
|
|
95
101
|
core_exports
|
|
96
102
|
};
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
103
|
+
//# sourceMappingURL=chunk-E7OH6ZAZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/index.ts"],"sourcesContent":["/**\n * Core layer: message protocol, node primitive, lifecycle (Phase 0).\n */\nexport * from \"./actor.js\";\nexport * from \"./batch.js\";\nexport { monotonicNs, wallClockNs } from \"./clock.js\";\nexport * from \"./dynamic-node.js\";\nexport * from \"./guard.js\";\nexport * from \"./messages.js\";\nexport * from \"./meta.js\";\nexport {\n\ttype Node,\n\ttype NodeActions,\n\ttype NodeDescribeKind,\n\ttype NodeFn,\n\ttype NodeOptions,\n\ttype NodeSink,\n\ttype NodeStatus,\n\ttype NodeTransportOptions,\n\tnode,\n\ttype OnMessageHandler,\n\ttype SubscribeHints,\n} from \"./node.js\";\nexport * from \"./sugar.js\";\nexport {\n\tadvanceVersion,\n\tcreateVersioning,\n\tdefaultHash,\n\ttype HashFn,\n\tisV1,\n\ttype NodeVersionInfo,\n\ttype V0,\n\ttype V1,\n\ttype VersioningLevel,\n\ttype VersioningOptions,\n} from \"./versioning.js\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/core/index.ts"],"sourcesContent":["/**\n * Core layer: message protocol, node primitive, lifecycle (Phase 0).\n */\nexport * from \"./actor.js\";\nexport * from \"./batch.js\";\nexport { monotonicNs, wallClockNs } from \"./clock.js\";\nexport * from \"./dynamic-node.js\";\nexport * from \"./guard.js\";\nexport * from \"./messages.js\";\nexport * from \"./meta.js\";\nexport {\n\ttype Node,\n\ttype NodeActions,\n\ttype NodeDescribeKind,\n\ttype NodeFn,\n\ttype NodeOptions,\n\ttype NodeSink,\n\ttype NodeStatus,\n\ttype NodeTransportOptions,\n\tnode,\n\ttype OnMessageHandler,\n\ttype SubscribeHints,\n} from \"./node.js\";\nexport * from \"./sugar.js\";\nexport { ResettableTimer } from \"./timer.js\";\nexport {\n\tadvanceVersion,\n\tcreateVersioning,\n\tdefaultHash,\n\ttype HashFn,\n\tisV1,\n\ttype NodeVersionInfo,\n\ttype V0,\n\ttype V1,\n\ttype VersioningLevel,\n\ttype VersioningOptions,\n} from \"./versioning.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;","names":[]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DynamicNodeImpl,
|
|
3
|
+
NodeImpl,
|
|
4
|
+
accessHintForGuard
|
|
5
|
+
} from "./chunk-QTZSBQGJ.js";
|
|
6
|
+
|
|
7
|
+
// src/core/meta.ts
|
|
8
|
+
function resolveDescribeFields(detail, fields) {
|
|
9
|
+
if (fields != null && fields.length > 0) return new Set(fields);
|
|
10
|
+
switch (detail) {
|
|
11
|
+
case "standard":
|
|
12
|
+
return /* @__PURE__ */ new Set(["type", "status", "value", "deps", "meta", "v"]);
|
|
13
|
+
case "full":
|
|
14
|
+
return null;
|
|
15
|
+
// null = include everything
|
|
16
|
+
case "minimal":
|
|
17
|
+
default:
|
|
18
|
+
return /* @__PURE__ */ new Set(["type", "deps"]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function inferDescribeType(n) {
|
|
22
|
+
if (n._describeKind != null) return n._describeKind;
|
|
23
|
+
if (!n._hasDeps) return n._fn != null ? "producer" : "state";
|
|
24
|
+
if (n._fn == null) return "derived";
|
|
25
|
+
if (n._manualEmitUsed) return "operator";
|
|
26
|
+
return "derived";
|
|
27
|
+
}
|
|
28
|
+
function metaSnapshot(node) {
|
|
29
|
+
const out = {};
|
|
30
|
+
for (const [key, child] of Object.entries(node.meta)) {
|
|
31
|
+
try {
|
|
32
|
+
out[key] = child.get();
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
function describeNode(node, includeFields) {
|
|
39
|
+
const all = includeFields == null;
|
|
40
|
+
const metaKeys = !all && includeFields != null ? [...includeFields].filter((f) => f.startsWith("meta.")).map((f) => f.slice(5)) : null;
|
|
41
|
+
const wantsMeta = all || includeFields.has("meta") || metaKeys != null && metaKeys.length > 0;
|
|
42
|
+
let type = "state";
|
|
43
|
+
let deps = [];
|
|
44
|
+
if (node instanceof NodeImpl) {
|
|
45
|
+
type = inferDescribeType(node);
|
|
46
|
+
deps = node._deps.map((d) => d.name ?? "");
|
|
47
|
+
} else if (node instanceof DynamicNodeImpl) {
|
|
48
|
+
type = node._describeKind ?? "derived";
|
|
49
|
+
deps = [];
|
|
50
|
+
}
|
|
51
|
+
const out = { type, deps };
|
|
52
|
+
if (all || includeFields.has("status")) {
|
|
53
|
+
out.status = node.status;
|
|
54
|
+
}
|
|
55
|
+
const guard = node instanceof NodeImpl && node._guard || node instanceof DynamicNodeImpl && node._guard || void 0;
|
|
56
|
+
if (wantsMeta) {
|
|
57
|
+
const rawMeta = { ...metaSnapshot(node) };
|
|
58
|
+
if (guard != null && rawMeta.access === void 0) {
|
|
59
|
+
rawMeta.access = accessHintForGuard(guard);
|
|
60
|
+
}
|
|
61
|
+
if (metaKeys != null && metaKeys.length > 0 && !includeFields.has("meta")) {
|
|
62
|
+
const filtered = {};
|
|
63
|
+
for (const k of metaKeys) {
|
|
64
|
+
if (k in rawMeta) filtered[k] = rawMeta[k];
|
|
65
|
+
}
|
|
66
|
+
out.meta = filtered;
|
|
67
|
+
} else {
|
|
68
|
+
out.meta = rawMeta;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (node.name != null) {
|
|
72
|
+
out.name = node.name;
|
|
73
|
+
}
|
|
74
|
+
if (all || includeFields.has("value")) {
|
|
75
|
+
try {
|
|
76
|
+
out.value = node.get();
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if ((all || includeFields.has("v")) && node.v != null) {
|
|
81
|
+
const vInfo = { id: node.v.id, version: node.v.version };
|
|
82
|
+
if ("cid" in node.v) {
|
|
83
|
+
vInfo.cid = node.v.cid;
|
|
84
|
+
vInfo.prev = node.v.prev;
|
|
85
|
+
}
|
|
86
|
+
out.v = vInfo;
|
|
87
|
+
}
|
|
88
|
+
if (all || includeFields.has("guard")) {
|
|
89
|
+
if (guard != null) {
|
|
90
|
+
out.guard = accessHintForGuard(guard);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (all || includeFields.has("lastMutation")) {
|
|
94
|
+
if (node.lastMutation != null) {
|
|
95
|
+
out.lastMutation = node.lastMutation;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export {
|
|
102
|
+
resolveDescribeFields,
|
|
103
|
+
metaSnapshot,
|
|
104
|
+
describeNode
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=chunk-LR2CLSEF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/meta.ts"],"sourcesContent":["import type { Actor } from \"./actor.js\";\nimport { DynamicNodeImpl } from \"./dynamic-node.js\";\nimport { accessHintForGuard } from \"./guard.js\";\nimport { type Node, NodeImpl } from \"./node.js\";\n\n/** JSON-shaped slice of a node for Phase 1 `Graph.describe()` (GRAPHREFLY-SPEC §3.6, Appendix B). */\nexport type DescribeNodeOutput = {\n\ttype: \"state\" | \"derived\" | \"producer\" | \"operator\" | \"effect\";\n\tstatus?: Node[\"status\"];\n\tdeps: string[];\n\tmeta?: Record<string, unknown>;\n\tname?: string;\n\tvalue?: unknown;\n\t/** Node versioning info (GRAPHREFLY-SPEC §7). Present only when versioning is enabled. */\n\tv?: { id: string; version: number; cid?: string; prev?: string | null };\n\t/** Guard info (full detail). */\n\tguard?: string;\n\t/** Last mutation attribution (full detail). */\n\tlastMutation?: Readonly<{ actor: Actor; timestamp_ns: number }>;\n};\n\n/**\n * Detail level for `describe()` progressive disclosure (Phase 3.3b).\n * - `\"minimal\"` — type + deps only (default). LLM-friendly.\n * - `\"standard\"` — type, status, value, deps, meta, versioning (`v`).\n * - `\"full\"` — standard + guard, lastMutation.\n */\nexport type DescribeDetail = \"minimal\" | \"standard\" | \"full\";\n\n/**\n * Valid field names for `describe({ fields: [...] })` (Phase 3.3b).\n * Dotted paths like `\"meta.label\"` select specific meta keys.\n */\nexport type DescribeField =\n\t| \"type\"\n\t| \"status\"\n\t| \"value\"\n\t| \"deps\"\n\t| \"meta\"\n\t| \"v\"\n\t| \"guard\"\n\t| \"lastMutation\"\n\t| `meta.${string}`;\n\n/** Resolve which fields to include based on detail level or explicit field list. */\nexport function resolveDescribeFields(\n\tdetail?: DescribeDetail,\n\tfields?: readonly DescribeField[],\n): Set<string> | null {\n\t// Explicit fields override detail level\n\tif (fields != null && fields.length > 0) return new Set(fields);\n\tswitch (detail) {\n\t\tcase \"standard\":\n\t\t\treturn new Set([\"type\", \"status\", \"value\", \"deps\", \"meta\", \"v\"]);\n\t\tcase \"full\":\n\t\t\treturn null; // null = include everything\n\t\tcase \"minimal\":\n\t\tdefault:\n\t\t\treturn new Set([\"type\", \"deps\"]);\n\t}\n}\n\nfunction inferDescribeType(n: NodeImpl): DescribeNodeOutput[\"type\"] {\n\tif (n._describeKind != null) return n._describeKind;\n\tif (!n._hasDeps) return n._fn != null ? \"producer\" : \"state\";\n\tif (n._fn == null) return \"derived\";\n\tif (n._manualEmitUsed) return \"operator\";\n\treturn \"derived\";\n}\n\n/**\n * Reads the current cached value of every companion meta field on a node,\n * suitable for merging into `describe()`-style JSON (GRAPHREFLY-SPEC §2.3, §3.6).\n *\n * @remarks\n * Values come from {@link Node.get}, which returns the **last settled** cache.\n * If a meta field is in `\"dirty\"` status (DIRTY received, DATA pending), the\n * snapshot contains the *previous* value — check `node.meta[key].status` when\n * freshness matters. Avoid calling mid-batch for the same reason.\n *\n * Meta nodes are **not** terminated when their parent receives COMPLETE or\n * ERROR — they remain writable so callers can record post-mortem metadata\n * (e.g. `meta.error`). They *are* torn down when the parent receives TEARDOWN.\n *\n * @param node - The node whose meta fields to snapshot.\n * @returns Plain object of `{ key: value }` pairs (empty if no meta defined).\n * Keys whose companion node's {@link Node.get} throws are omitted.\n *\n * @example\n * ```ts\n * import { core } from \"@graphrefly/graphrefly-ts\";\n *\n * const n = core.node({ initial: 0, meta: { tag: \"a\" } });\n * core.metaSnapshot(n); // { tag: \"a\" }\n * ```\n */\nexport function metaSnapshot(node: Node): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [key, child] of Object.entries(node.meta)) {\n\t\ttry {\n\t\t\tout[key] = child.get();\n\t\t} catch {\n\t\t\t/* omit key — describe tooling still gets other fields */\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * Builds a single-node slice of `Graph.describe()` JSON (structure + `meta` snapshot).\n * Parity with graphrefly-py `describe_node`.\n *\n * `type` is inferred from factory configuration, optional `describeKind` in node options,\n * and the last `manualEmitUsed` hint (operator vs derived). {@link effect} sets\n * `describeKind: \"effect\"`. Nodes not created by {@link node} fall back to `type: \"state\"` and empty `deps`.\n *\n * @param node - Any `Node` to introspect.\n * @returns `DescribeNodeOutput` suitable for merging into graph describe maps.\n *\n * @example\n * ```ts\n * import { describeNode, state } from \"@graphrefly/graphrefly-ts\";\n *\n * describeNode(state(0));\n * ```\n */\n/**\n * Builds a single-node slice for `Graph.describe()`.\n *\n * @param node - Node to introspect.\n * @param includeFields - Set of fields to include, or `null` for all. When omitted, all fields are included (legacy behavior).\n */\nexport function describeNode(node: Node, includeFields?: Set<string> | null): DescribeNodeOutput {\n\tconst all = includeFields == null; // null or undefined → include everything\n\n\t// Specific meta keys requested via dotted paths (e.g. \"meta.label\")\n\tconst metaKeys: string[] | null =\n\t\t!all && includeFields != null\n\t\t\t? [...includeFields].filter((f) => f.startsWith(\"meta.\")).map((f) => f.slice(5))\n\t\t\t: null;\n\tconst wantsMeta = all || includeFields!.has(\"meta\") || (metaKeys != null && metaKeys.length > 0);\n\n\tlet type: DescribeNodeOutput[\"type\"] = \"state\";\n\tlet deps: string[] = [];\n\n\tif (node instanceof NodeImpl) {\n\t\ttype = inferDescribeType(node);\n\t\tdeps = node._deps.map((d) => d.name ?? \"\");\n\t} else if (node instanceof DynamicNodeImpl) {\n\t\ttype = node._describeKind ?? \"derived\";\n\t\tdeps = [];\n\t}\n\n\tconst out: DescribeNodeOutput = { type, deps };\n\n\t// status\n\tif (all || includeFields!.has(\"status\")) {\n\t\tout.status = node.status;\n\t}\n\n\t// Resolve guard once — used by both meta.access hint and standalone guard field\n\tconst guard =\n\t\t(node instanceof NodeImpl && node._guard) ||\n\t\t(node instanceof DynamicNodeImpl && node._guard) ||\n\t\tundefined;\n\n\t// meta\n\tif (wantsMeta) {\n\t\tconst rawMeta: Record<string, unknown> = { ...metaSnapshot(node) };\n\t\tif (guard != null && rawMeta.access === undefined) {\n\t\t\trawMeta.access = accessHintForGuard(guard);\n\t\t}\n\n\t\tif (metaKeys != null && metaKeys.length > 0 && !includeFields!.has(\"meta\")) {\n\t\t\t// Only specific meta keys\n\t\t\tconst filtered: Record<string, unknown> = {};\n\t\t\tfor (const k of metaKeys) {\n\t\t\t\tif (k in rawMeta) filtered[k] = rawMeta[k];\n\t\t\t}\n\t\t\tout.meta = filtered;\n\t\t} else {\n\t\t\tout.meta = rawMeta;\n\t\t}\n\t}\n\n\t// name (always include when present — it's identity, not detail)\n\tif (node.name != null) {\n\t\tout.name = node.name;\n\t}\n\n\t// value\n\tif (all || includeFields!.has(\"value\")) {\n\t\ttry {\n\t\t\tout.value = node.get();\n\t\t} catch {\n\t\t\t/* omit value */\n\t\t}\n\t}\n\n\t// Versioning (GRAPHREFLY-SPEC §7)\n\tif ((all || includeFields!.has(\"v\")) && node.v != null) {\n\t\tconst vInfo: DescribeNodeOutput[\"v\"] = { id: node.v.id, version: node.v.version };\n\t\tif (\"cid\" in node.v) {\n\t\t\tvInfo!.cid = (node.v as { cid: string }).cid;\n\t\t\tvInfo!.prev = (node.v as { prev: string | null }).prev;\n\t\t}\n\t\tout.v = vInfo;\n\t}\n\n\t// Guard info (full detail)\n\tif (all || includeFields!.has(\"guard\")) {\n\t\tif (guard != null) {\n\t\t\tout.guard = accessHintForGuard(guard);\n\t\t}\n\t}\n\n\t// Last mutation attribution (full detail)\n\tif (all || includeFields!.has(\"lastMutation\")) {\n\t\tif (node.lastMutation != null) {\n\t\t\tout.lastMutation = node.lastMutation;\n\t\t}\n\t}\n\n\treturn out;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -219,10 +219,14 @@ function partitionForBatch(messages) {
|
|
|
219
219
|
}
|
|
220
220
|
return { immediate, deferred, terminal };
|
|
221
221
|
}
|
|
222
|
-
function emitWithBatch(emit, messages, phase = 2) {
|
|
222
|
+
function emitWithBatch(emit, messages, phase = 2, options) {
|
|
223
223
|
if (messages.length === 0) {
|
|
224
224
|
return;
|
|
225
225
|
}
|
|
226
|
+
if (options?.strategy === "sequential") {
|
|
227
|
+
_emitSequential(emit, messages, phase);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
226
230
|
const queue = phase === 3 ? pendingPhase3 : pendingPhase2;
|
|
227
231
|
if (messages.length === 1) {
|
|
228
232
|
const t = messages[0][0];
|
|
@@ -263,6 +267,29 @@ function emitWithBatch(emit, messages, phase = 2) {
|
|
|
263
267
|
}
|
|
264
268
|
}
|
|
265
269
|
}
|
|
270
|
+
function _emitSequential(emit, messages, phase = 2) {
|
|
271
|
+
const dataQueue = phase === 3 ? pendingPhase3 : pendingPhase2;
|
|
272
|
+
for (const msg of messages) {
|
|
273
|
+
const tier = messageTier(msg[0]);
|
|
274
|
+
if (tier === 2) {
|
|
275
|
+
if (isBatching()) {
|
|
276
|
+
const m = msg;
|
|
277
|
+
dataQueue.push(() => emit([m]));
|
|
278
|
+
} else {
|
|
279
|
+
emit([msg]);
|
|
280
|
+
}
|
|
281
|
+
} else if (tier >= 3) {
|
|
282
|
+
if (isBatching()) {
|
|
283
|
+
const m = msg;
|
|
284
|
+
pendingPhase3.push(() => emit([m]));
|
|
285
|
+
} else {
|
|
286
|
+
emit([msg]);
|
|
287
|
+
}
|
|
288
|
+
} else {
|
|
289
|
+
emit([msg]);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
266
293
|
|
|
267
294
|
// src/core/clock.ts
|
|
268
295
|
function monotonicNs() {
|
|
@@ -426,6 +453,7 @@ function isV1(info) {
|
|
|
426
453
|
}
|
|
427
454
|
|
|
428
455
|
// src/core/node.ts
|
|
456
|
+
var NO_VALUE = /* @__PURE__ */ Symbol.for("graphrefly/NO_VALUE");
|
|
429
457
|
function createIntBitSet() {
|
|
430
458
|
let bits = 0;
|
|
431
459
|
return {
|
|
@@ -555,10 +583,10 @@ var NodeImpl = class {
|
|
|
555
583
|
this._hasDeps = deps.length > 0;
|
|
556
584
|
this._autoComplete = opts.completeWhenDepsComplete ?? true;
|
|
557
585
|
this._isSingleDep = deps.length === 1 && fn != null;
|
|
558
|
-
this._cached = opts.initial;
|
|
586
|
+
this._cached = "initial" in opts ? opts.initial : NO_VALUE;
|
|
559
587
|
this._status = this._hasDeps ? "disconnected" : "settled";
|
|
560
588
|
this._hashFn = opts.versioningHash ?? defaultHash;
|
|
561
|
-
this._versioning = opts.versioning != null ? createVersioning(opts.versioning, this._cached, {
|
|
589
|
+
this._versioning = opts.versioning != null ? createVersioning(opts.versioning, this._cached === NO_VALUE ? void 0 : this._cached, {
|
|
562
590
|
id: opts.versioningId,
|
|
563
591
|
hash: this._hashFn
|
|
564
592
|
}) : void 0;
|
|
@@ -642,10 +670,14 @@ var NodeImpl = class {
|
|
|
642
670
|
_applyVersioning(level, opts) {
|
|
643
671
|
if (this._versioning != null) return;
|
|
644
672
|
this._hashFn = opts?.hash ?? this._hashFn;
|
|
645
|
-
this._versioning = createVersioning(
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
673
|
+
this._versioning = createVersioning(
|
|
674
|
+
level,
|
|
675
|
+
this._cached === NO_VALUE ? void 0 : this._cached,
|
|
676
|
+
{
|
|
677
|
+
id: opts?.id,
|
|
678
|
+
hash: this._hashFn
|
|
679
|
+
}
|
|
680
|
+
);
|
|
649
681
|
}
|
|
650
682
|
hasGuard() {
|
|
651
683
|
return this._guard != null;
|
|
@@ -655,7 +687,7 @@ var NodeImpl = class {
|
|
|
655
687
|
return this._guard(normalizeActor(actor), "observe");
|
|
656
688
|
}
|
|
657
689
|
get() {
|
|
658
|
-
return this._cached;
|
|
690
|
+
return this._cached === NO_VALUE ? void 0 : this._cached;
|
|
659
691
|
}
|
|
660
692
|
down(messages, options) {
|
|
661
693
|
if (messages.length === 0) return;
|
|
@@ -712,6 +744,7 @@ var NodeImpl = class {
|
|
|
712
744
|
}
|
|
713
745
|
if (this._terminal && this._opts.resubscribable) {
|
|
714
746
|
this._terminal = false;
|
|
747
|
+
this._cached = NO_VALUE;
|
|
715
748
|
this._status = this._hasDeps ? "disconnected" : "settled";
|
|
716
749
|
this._opts.onResubscribe?.();
|
|
717
750
|
}
|
|
@@ -811,7 +844,7 @@ var NodeImpl = class {
|
|
|
811
844
|
const cleanupFn = this._cleanup;
|
|
812
845
|
this._cleanup = void 0;
|
|
813
846
|
cleanupFn?.();
|
|
814
|
-
this._cached =
|
|
847
|
+
this._cached = NO_VALUE;
|
|
815
848
|
this._lastDepValues = void 0;
|
|
816
849
|
}
|
|
817
850
|
this._status = statusAfterMessage(this._status, m);
|
|
@@ -820,7 +853,7 @@ var NodeImpl = class {
|
|
|
820
853
|
}
|
|
821
854
|
if (t === TEARDOWN) {
|
|
822
855
|
if (this._opts.resetOnTeardown) {
|
|
823
|
-
this._cached =
|
|
856
|
+
this._cached = NO_VALUE;
|
|
824
857
|
}
|
|
825
858
|
const teardownCleanup = this._cleanup;
|
|
826
859
|
this._cleanup = void 0;
|
|
@@ -851,7 +884,15 @@ var NodeImpl = class {
|
|
|
851
884
|
}
|
|
852
885
|
_emitAutoValue(value) {
|
|
853
886
|
const wasDirty = this._status === "dirty";
|
|
854
|
-
|
|
887
|
+
let unchanged;
|
|
888
|
+
try {
|
|
889
|
+
unchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);
|
|
890
|
+
} catch (eqErr) {
|
|
891
|
+
const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
|
|
892
|
+
const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, { cause: eqErr });
|
|
893
|
+
this._downInternal([[ERROR, wrapped]]);
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
855
896
|
if (unchanged) {
|
|
856
897
|
this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
|
|
857
898
|
return;
|
|
@@ -898,7 +939,9 @@ var NodeImpl = class {
|
|
|
898
939
|
if (out === void 0) return;
|
|
899
940
|
this._emitAutoValue(out);
|
|
900
941
|
} catch (err) {
|
|
901
|
-
|
|
942
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
943
|
+
const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, { cause: err });
|
|
944
|
+
this._downInternal([[ERROR, wrapped]]);
|
|
902
945
|
}
|
|
903
946
|
}
|
|
904
947
|
_onDepDirty(index) {
|
|
@@ -933,7 +976,11 @@ var NodeImpl = class {
|
|
|
933
976
|
try {
|
|
934
977
|
if (this._onMessage(msg, index, this._actions)) continue;
|
|
935
978
|
} catch (err) {
|
|
936
|
-
|
|
979
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
980
|
+
const wrapped = new Error(`Node "${this.name}": onMessage threw: ${errMsg}`, {
|
|
981
|
+
cause: err
|
|
982
|
+
});
|
|
983
|
+
this._downInternal([[ERROR, wrapped]]);
|
|
937
984
|
return;
|
|
938
985
|
}
|
|
939
986
|
}
|
|
@@ -1069,7 +1116,7 @@ var DynamicNodeImpl = class {
|
|
|
1069
1116
|
_actions;
|
|
1070
1117
|
_boundEmitToSinks;
|
|
1071
1118
|
// Mutable state
|
|
1072
|
-
_cached;
|
|
1119
|
+
_cached = NO_VALUE;
|
|
1073
1120
|
_status = "disconnected";
|
|
1074
1121
|
_terminal = false;
|
|
1075
1122
|
_connected = false;
|
|
@@ -1163,7 +1210,7 @@ var DynamicNodeImpl = class {
|
|
|
1163
1210
|
return this._guard(normalizeActor(actor), "observe");
|
|
1164
1211
|
}
|
|
1165
1212
|
get() {
|
|
1166
|
-
return this._cached;
|
|
1213
|
+
return this._cached === NO_VALUE ? void 0 : this._cached;
|
|
1167
1214
|
}
|
|
1168
1215
|
down(messages, options) {
|
|
1169
1216
|
if (messages.length === 0) return;
|
|
@@ -1221,6 +1268,7 @@ var DynamicNodeImpl = class {
|
|
|
1221
1268
|
}
|
|
1222
1269
|
if (this._terminal && this._resubscribable) {
|
|
1223
1270
|
this._terminal = false;
|
|
1271
|
+
this._cached = NO_VALUE;
|
|
1224
1272
|
this._status = "disconnected";
|
|
1225
1273
|
this._onResubscribe?.();
|
|
1226
1274
|
}
|
|
@@ -1298,10 +1346,13 @@ var DynamicNodeImpl = class {
|
|
|
1298
1346
|
const t = m[0];
|
|
1299
1347
|
if (t === DATA) this._cached = m[1];
|
|
1300
1348
|
if (t === INVALIDATE) {
|
|
1301
|
-
this._cached =
|
|
1349
|
+
this._cached = NO_VALUE;
|
|
1350
|
+
this._status = "dirty";
|
|
1302
1351
|
}
|
|
1303
|
-
if (t === DATA
|
|
1352
|
+
if (t === DATA) {
|
|
1304
1353
|
this._status = "settled";
|
|
1354
|
+
} else if (t === RESOLVED) {
|
|
1355
|
+
this._status = "resolved";
|
|
1305
1356
|
} else if (t === DIRTY) {
|
|
1306
1357
|
this._status = "dirty";
|
|
1307
1358
|
} else if (t === COMPLETE) {
|
|
@@ -1312,7 +1363,7 @@ var DynamicNodeImpl = class {
|
|
|
1312
1363
|
this._terminal = true;
|
|
1313
1364
|
}
|
|
1314
1365
|
if (t === TEARDOWN) {
|
|
1315
|
-
if (this._resetOnTeardown) this._cached =
|
|
1366
|
+
if (this._resetOnTeardown) this._cached = NO_VALUE;
|
|
1316
1367
|
try {
|
|
1317
1368
|
this._propagateToMeta(t);
|
|
1318
1369
|
} finally {
|
|
@@ -1335,7 +1386,15 @@ var DynamicNodeImpl = class {
|
|
|
1335
1386
|
}
|
|
1336
1387
|
_emitAutoValue(value) {
|
|
1337
1388
|
const wasDirty = this._status === "dirty";
|
|
1338
|
-
|
|
1389
|
+
let unchanged;
|
|
1390
|
+
try {
|
|
1391
|
+
unchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);
|
|
1392
|
+
} catch (eqErr) {
|
|
1393
|
+
const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
|
|
1394
|
+
const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, { cause: eqErr });
|
|
1395
|
+
this._downInternal([[ERROR, wrapped]]);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1339
1398
|
if (unchanged) {
|
|
1340
1399
|
this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
|
|
1341
1400
|
return;
|
|
@@ -1568,4 +1627,4 @@ export {
|
|
|
1568
1627
|
effect,
|
|
1569
1628
|
pipe
|
|
1570
1629
|
};
|
|
1571
|
-
//# sourceMappingURL=chunk-
|
|
1630
|
+
//# sourceMappingURL=chunk-QTZSBQGJ.js.map
|