footprintjs 9.44.3 → 9.46.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/CLAUDE.md +9 -8
- package/dist/esm/lib/memory/DiagnosticCollector.js +2 -2
- package/dist/esm/lib/memory/RecordFrame.d.ts +197 -0
- package/dist/esm/lib/memory/RecordFrame.js +265 -0
- package/dist/esm/lib/memory/SharedMemory.d.ts +11 -10
- package/dist/esm/lib/memory/SharedMemory.js +19 -20
- package/dist/esm/lib/memory/StageContext.d.ts +52 -137
- package/dist/esm/lib/memory/StageContext.js +111 -215
- package/dist/esm/lib/memory/TransactionBuffer.d.ts +6 -5
- package/dist/esm/lib/memory/TransactionBuffer.js +7 -6
- package/dist/esm/lib/memory/utils.d.ts +11 -7
- package/dist/esm/lib/memory/utils.js +46 -28
- package/dist/esm/lib/reactive/structuralWrite.d.ts +1 -1
- package/dist/esm/lib/reactive/structuralWrite.js +2 -2
- package/dist/lib/memory/DiagnosticCollector.js +2 -2
- package/dist/lib/memory/RecordFrame.js +269 -0
- package/dist/lib/memory/SharedMemory.js +19 -20
- package/dist/lib/memory/StageContext.js +111 -215
- package/dist/lib/memory/TransactionBuffer.js +7 -6
- package/dist/lib/memory/utils.js +46 -28
- package/dist/lib/reactive/structuralWrite.js +2 -2
- package/dist/types/lib/memory/RecordFrame.d.ts +197 -0
- package/dist/types/lib/memory/SharedMemory.d.ts +11 -10
- package/dist/types/lib/memory/StageContext.d.ts +52 -137
- package/dist/types/lib/memory/TransactionBuffer.d.ts +6 -5
- package/dist/types/lib/memory/utils.d.ts +11 -7
- package/dist/types/lib/reactive/structuralWrite.d.ts +1 -1
- package/package.json +1 -1
|
@@ -2,35 +2,33 @@
|
|
|
2
2
|
* StageContext — Execution context for a single stage in a flowchart run
|
|
3
3
|
*
|
|
4
4
|
* Like a stack frame in a compiler/runtime:
|
|
5
|
-
* -
|
|
6
|
-
*
|
|
5
|
+
* - A RecordFrame — the record half (C3): the heap, the address, the
|
|
6
|
+
* first-touch base, the lazy transaction buffer, the readKeys list
|
|
7
7
|
* - Links to parent/child/next contexts (call stack frames)
|
|
8
|
+
* - What belongs to a stage inside a run: retention of reads and writes, the
|
|
9
|
+
* redaction verdict per write, the dev-mode warnings, the commit observer
|
|
8
10
|
* - DiagnosticCollector for logs, errors, metrics
|
|
9
11
|
*/
|
|
10
12
|
import { type DiagnosticChannel, DiagnosticCollector } from './DiagnosticCollector.js';
|
|
11
|
-
import { EventLog } from './EventLog.js';
|
|
13
|
+
import type { EventLog } from './EventLog.js';
|
|
12
14
|
import type { EmitSourcePosition } from './eventPosition.js';
|
|
13
15
|
import type { RedactionVerdict } from './redaction.js';
|
|
14
16
|
import { RedactionRule } from './redaction.js';
|
|
15
17
|
import type { RunPolicy } from './runPolicy.js';
|
|
16
|
-
import { SharedMemory } from './SharedMemory.js';
|
|
17
|
-
import { TransactionBuffer } from './TransactionBuffer.js';
|
|
18
|
+
import type { SharedMemory } from './SharedMemory.js';
|
|
18
19
|
import type { CommitPhase, FlowControlType, StageSnapshot, UntrackedSource } from './types.js';
|
|
19
20
|
export declare class StageContext {
|
|
20
|
-
private sharedMemory;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* — consumers share the redacted view externally without leaking raw PII
|
|
31
|
-
* through `sharedState`.
|
|
22
|
+
* The record half of this frame (`RecordFrame.ts`, L3, C3): the heap and,
|
|
23
|
+
* when the run keeps them, the redacted mirror and the log; the address;
|
|
24
|
+
* the first-touch base; the lazy transaction buffer; the readKeys list.
|
|
25
|
+
* Every state read of this frame goes through it, and so does every
|
|
26
|
+
* commit. The mirror is present **only** when the run's policy keeps a
|
|
27
|
+
* redacted view (a `RedactionPolicy` is configured) — read via
|
|
28
|
+
* `FlowChartExecutor.getSnapshot({ redact: true })`, the foundation for
|
|
29
|
+
* sharing a trace without leaking raw PII through `sharedState`.
|
|
32
30
|
*/
|
|
33
|
-
private
|
|
31
|
+
private readonly record;
|
|
34
32
|
/**
|
|
35
33
|
* The run's policy — the four dials, the redaction rule, the mirror flag
|
|
36
34
|
* (`runPolicy.ts`, F5). Held BY REFERENCE: one frozen object per run (and
|
|
@@ -40,15 +38,6 @@ export declare class StageContext {
|
|
|
40
38
|
* ({@link usePolicy}). Never edited; a change is a new object.
|
|
41
39
|
*/
|
|
42
40
|
private policy;
|
|
43
|
-
private buffer?;
|
|
44
|
-
/**
|
|
45
|
-
* Committed-state view captured at this stage's FIRST touch (first read OR
|
|
46
|
-
* first write) — held by REFERENCE, never cloned. See
|
|
47
|
-
* {@link firstTouchState} for the algorithm and the immutability invariant
|
|
48
|
-
* that makes a bare reference safe.
|
|
49
|
-
*/
|
|
50
|
-
private stateView?;
|
|
51
|
-
private eventLog?;
|
|
52
41
|
/** The emitting frame's logical leg, never the mutable executor's current leg. */
|
|
53
42
|
private emitRunId?;
|
|
54
43
|
stageName: string;
|
|
@@ -65,7 +54,13 @@ export declare class StageContext {
|
|
|
65
54
|
* none — the same once-per-execution law `_untrackedSources` keeps.
|
|
66
55
|
*/
|
|
67
56
|
tags?: readonly string[];
|
|
68
|
-
|
|
57
|
+
/**
|
|
58
|
+
* The run this frame belongs to — its identity on every event, and the run
|
|
59
|
+
* namespace it reads and writes in ({@link runAddress}), read once, when the
|
|
60
|
+
* frame is built (C3). Only {@link useAddressOf} moves the address after
|
|
61
|
+
* that, and only before the first write.
|
|
62
|
+
*/
|
|
63
|
+
readonly runId: string;
|
|
69
64
|
/**
|
|
70
65
|
* The run namespace this frame writes and reads in when that is not its own
|
|
71
66
|
* `runId` — set once, before the frame's first write, by
|
|
@@ -128,11 +123,6 @@ export declare class StageContext {
|
|
|
128
123
|
* tier (`ScopeFacade`, one per stage execution), not here.
|
|
129
124
|
*/
|
|
130
125
|
private _committed;
|
|
131
|
-
/** Lazily-allocated ordered registry of keys tracked-read in THIS stage —
|
|
132
|
-
* the source of the per-write prefix. Only allocated under the
|
|
133
|
-
* `'reads-prefix'` dial; insertion-ordered (a Set) and monotonic, which
|
|
134
|
-
* is what makes "last write's prefix == union" hold in delta mode. */
|
|
135
|
-
private _provenanceReads?;
|
|
136
126
|
/** Tracked reads of a selected value ({@link selectedReads}). */
|
|
137
127
|
private _selectedReads;
|
|
138
128
|
/** Each object this frame read under a selected name → that read's verdict (`stageWrite` hands it on). */
|
|
@@ -159,7 +149,7 @@ export declare class StageContext {
|
|
|
159
149
|
/**
|
|
160
150
|
* Install a parallel redacted mirror. Subsequent `commit()` calls apply
|
|
161
151
|
* the already-computed redacted patches — the ones the log records — to
|
|
162
|
-
* this mirror, beside the raw patches on
|
|
152
|
+
* this mirror, beside the raw patches on the heap (`recordCommit`).
|
|
163
153
|
* Child / next contexts inherit the mirror via `createNext` / `createChild`.
|
|
164
154
|
*
|
|
165
155
|
* Called on a runtime's root frame by `ExecutionRuntime` when the run's policy keeps a mirror.
|
|
@@ -198,6 +188,12 @@ export declare class StageContext {
|
|
|
198
188
|
* {@link createChild} both call it, and it names no dial.
|
|
199
189
|
*/
|
|
200
190
|
private inheritRun;
|
|
191
|
+
/**
|
|
192
|
+
* The ONE place this frame's policy changes: the frame holds it, and its
|
|
193
|
+
* record frame encodes under the same reference (`commitValues`,
|
|
194
|
+
* `writeProvenance` — `RecordFrame · useEncoding`), so the two never differ.
|
|
195
|
+
*/
|
|
196
|
+
private adoptPolicy;
|
|
201
197
|
/**
|
|
202
198
|
* Record a tracked user-level write, policy-gated (#13c-A) — the single
|
|
203
199
|
* bookkeeping path for {@link setObject} and {@link updateObject}. Holds
|
|
@@ -257,64 +253,6 @@ export declare class StageContext {
|
|
|
257
253
|
* the verdict so the caller retains and reports under the same decision.
|
|
258
254
|
*/
|
|
259
255
|
private stageWrite;
|
|
260
|
-
/**
|
|
261
|
-
* ── The first-touch state view (#13) ────────────────────────────────────
|
|
262
|
-
*
|
|
263
|
-
* WHAT: returns the committed shared state as it was at this stage's FIRST
|
|
264
|
-
* touch (first read or first write), capturing the reference on first call.
|
|
265
|
-
* Serves two consumers: reads before the first write ({@link readState})
|
|
266
|
-
* and the transaction buffer's diff base ({@link getTransactionBuffer}).
|
|
267
|
-
*
|
|
268
|
-
* WHY A BARE REFERENCE IS SAFE — the invariant this rests on: committed
|
|
269
|
-
* state is immutable-after-swap. Every write to `SharedMemory` builds the
|
|
270
|
-
* NEXT generation and swaps it in (copy-on-write, 9.29.0: `applyPatch` via
|
|
271
|
-
* `nextGeneration`, and `setValue`/`updateValue` too) — it copies the root
|
|
272
|
-
* and the containers on each written path, shares the rest, and never
|
|
273
|
-
* edits a container of the generation a stage captured here. Holding the
|
|
274
|
-
* reference therefore gives this stage a stable snapshot at zero cost — no
|
|
275
|
-
* clone, which is the entire point of #13. The transaction buffer's
|
|
276
|
-
* net-change diff base rests on the same guarantee: it IS this view.
|
|
277
|
-
*
|
|
278
|
-
* WHY FIRST TOUCH, not first write: the pre-#13 eager engine cloned the
|
|
279
|
-
* state into the buffer at the stage's first ACCESS, anchoring both its
|
|
280
|
-
* snapshot reads and its commit baseline (the net-change diff base) there.
|
|
281
|
-
* #13's first cut anchored the lazy buffer at first WRITE — observably
|
|
282
|
-
* different when something else commits in the gap between this stage's
|
|
283
|
-
* first read and its first write. That gap is REACHABLE: fork siblings are
|
|
284
|
-
* namespace-isolated for run-scoped keys (each child writes under
|
|
285
|
-
* `runs/<childId>/`), but ROOT-level keys are shared — written via
|
|
286
|
-
* `setGlobal` from consumer scope code and, critically, by
|
|
287
|
-
* `SubflowInputMapper`'s output mapping (`parentContext.setGlobal`), which
|
|
288
|
-
* is exactly what runs when a subflow is a fork branch. A sibling's
|
|
289
|
-
* root-key commit landing in the gap would shift this stage's diff base,
|
|
290
|
-
* making its CommitBundle record a phantom change (or swallow a real one)
|
|
291
|
-
* relative to the eager engine. Anchoring the view at first touch restores
|
|
292
|
-
* the EXACT eager semantics — sequential AND parallel — at zero clone cost.
|
|
293
|
-
*
|
|
294
|
-
* Read visibility is two-tier, matching eager byte-for-byte: keys present
|
|
295
|
-
* in the view at first touch read repeatably from it; keys ABSENT from it
|
|
296
|
-
* fall back to LIVE state (the eager engine's exact fallback — a
|
|
297
|
-
* mid-flight sibling root-key write was always visible to reads, and
|
|
298
|
-
* stays visible; only the DIFF BASE is pinned).
|
|
299
|
-
*/
|
|
300
|
-
private firstTouchState;
|
|
301
|
-
/** Lazily creates the transaction buffer on the stage's FIRST WRITE (#13).
|
|
302
|
-
*
|
|
303
|
-
* Reads NEVER construct it: read-your-writes only matters once a staged
|
|
304
|
-
* write exists, so before that {@link getValue}/{@link getValueDirect}
|
|
305
|
-
* serve from the first-touch state view and {@link commit} records an
|
|
306
|
-
* empty bundle — all with ZERO `structuredClone`s of the shared state.
|
|
307
|
-
*
|
|
308
|
-
* The buffer's base is the FIRST-TOUCH view, NOT the live state at write
|
|
309
|
-
* time: under parallel forks a sibling may have committed between this
|
|
310
|
-
* stage's first read and this write, and the net-change diff base must
|
|
311
|
-
* stay anchored at first touch to match the eager engine — see
|
|
312
|
-
* {@link firstTouchState}. */
|
|
313
|
-
getTransactionBuffer(): TransactionBuffer;
|
|
314
|
-
/** Builds an absolute path inside the shared memory (run namespace). */
|
|
315
|
-
private withNamespace;
|
|
316
|
-
/** The run namespace writes and reads go to: {@link addressRunId}, else `runId`. */
|
|
317
|
-
private get namespaceId();
|
|
318
256
|
/**
|
|
319
257
|
* Write and read at ANOTHER frame's address (its run namespace) while this
|
|
320
258
|
* frame keeps its own identity on the record — `stage`, `stageId`,
|
|
@@ -322,9 +260,13 @@ export declare class StageContext {
|
|
|
322
260
|
* (`SubflowExecutor · executeSubflow`, R13): the mount frame of a branch or
|
|
323
261
|
* fork child lands its values where its parent writes, as before, and its
|
|
324
262
|
* bundle now names the mount instead of the stage before it. Refused once
|
|
325
|
-
* the frame has staged anything — its buffer's address is fixed then.
|
|
263
|
+
* the frame has staged anything — its buffer's address is fixed then. The
|
|
264
|
+
* decision is the engine's (namespace ids, as since R13); the record frame
|
|
265
|
+
* takes the address it comes to (`RecordFrame · useAddress`).
|
|
326
266
|
*/
|
|
327
267
|
useAddressOf(frame: StageContext): void;
|
|
268
|
+
/** The run namespace writes and reads go to: {@link addressRunId}, else `runId`. */
|
|
269
|
+
private get namespaceId();
|
|
328
270
|
patch(path: string[], key: string, value: unknown, shouldRedact?: boolean): RedactionVerdict;
|
|
329
271
|
set(path: string[], key: string, value: unknown): void;
|
|
330
272
|
merge(path: string[], key: string, value: unknown, shouldRedact?: boolean): RedactionVerdict;
|
|
@@ -336,26 +278,6 @@ export declare class StageContext {
|
|
|
336
278
|
updateGlobalContext(key: string, value: unknown): void;
|
|
337
279
|
appendToArray(path: string[], key: string, items: unknown[], description?: string): void;
|
|
338
280
|
mergeObject(path: string[], key: string, obj: Record<string, unknown>, description?: string): void;
|
|
339
|
-
/** Buffer-aware read, mirroring the eager engine's read order byte-for-byte:
|
|
340
|
-
*
|
|
341
|
-
* 1. staged writes + first-touch snapshot — `buffer.get` over its
|
|
342
|
-
* workingCopy when the buffer exists, else `nativeGet` over the
|
|
343
|
-
* zero-clone state view (the buffer's base IS that view, so the two
|
|
344
|
-
* tiers agree on content);
|
|
345
|
-
* 2. LIVE state via `sharedMemory.getValue` for keys absent from the
|
|
346
|
-
* snapshot — including its run→global namespace fallback. The eager
|
|
347
|
-
* engine had this exact live fallback for snapshot-missing keys;
|
|
348
|
-
* byte-identity over purity. After the stage's first write such a
|
|
349
|
-
* value can be the very container the buffer's diff base holds at
|
|
350
|
-
* the path (the stage deleted or unset it, or replaced a container
|
|
351
|
-
* above it), so the base is detached there first
|
|
352
|
-
* (`TransactionBuffer · detachBase`): an in-place edit of the value
|
|
353
|
-
* (out of contract) written back is recorded, as on 9.28.0, whose
|
|
354
|
-
* base was a clone taken at the first write.
|
|
355
|
-
*
|
|
356
|
-
* Reads never construct the buffer (#13): a stage that never writes
|
|
357
|
-
* performs zero clones of the shared state. */
|
|
358
|
-
private readState;
|
|
359
281
|
/**
|
|
360
282
|
* Tracked read. The returned value is BORROWED — see the contract on
|
|
361
283
|
* `ScopeFacade.getValue`. Read-tracking cost is policy-gated (#14):
|
|
@@ -414,8 +336,8 @@ export declare class StageContext {
|
|
|
414
336
|
* those are engine reads (the subflow merge-back), not user reads.
|
|
415
337
|
*
|
|
416
338
|
* It also only looks at keys served from the PINNED source — the first-touch
|
|
417
|
-
* view or this stage's own buffer. A key absent from both was served by
|
|
418
|
-
*
|
|
339
|
+
* view or this stage's own buffer. A key absent from both was served by the
|
|
340
|
+
* read's live fallback (`RecordFrame · read`, tier 2), which a parallel sibling's root-key commit can
|
|
419
341
|
* legitimately move; accusing the stage there would be a false alarm. For
|
|
420
342
|
* the same reason it runs on the frame's FIRST commit only: the reads belong
|
|
421
343
|
* to that round, and by the engine's second round (a fork double-commit, a
|
|
@@ -447,21 +369,16 @@ export declare class StageContext {
|
|
|
447
369
|
* `outputMapper` (a lazy mount, every `parallelForEach` branch), whose exit
|
|
448
370
|
* is its only bundle, records that bundle as its own, tags and all.
|
|
449
371
|
*
|
|
450
|
-
* Commit is the stage's lifecycle end:
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
* O(N²) before copy-on-write (9.29.0), when each generation and each
|
|
457
|
-
* buffer was a whole-state clone: 563.8MB at N=200 on an agent-style
|
|
458
|
-
* chart; a 500-iteration agent OOMed a default Node heap (backlog #18).
|
|
459
|
-
* Generations now share every unchanged subtree, but a pinned one still
|
|
460
|
-
* keeps the containers later commits replaced alive.
|
|
372
|
+
* Commit is the stage's lifecycle end: the record frame's buffer and
|
|
373
|
+
* first-touch base are only needed DURING execution, as the read snapshot +
|
|
374
|
+
* net-change diff base, so the record frame releases them once the commit
|
|
375
|
+
* has landed and the observer has seen it (`RecordFrame · release` — why a
|
|
376
|
+
* frame that kept them would retain one state generation per executed
|
|
377
|
+
* stage, and why a re-used frame re-anchors on current state, is there).
|
|
461
378
|
*
|
|
462
|
-
* RE-USE AFTER COMMIT stays correct because both
|
|
463
|
-
* - a later READ re-anchors
|
|
464
|
-
*
|
|
379
|
+
* RE-USE AFTER COMMIT stays correct because both re-create lazily:
|
|
380
|
+
* - a later READ re-anchors on the CURRENT committed state (which includes
|
|
381
|
+
* this stage's own flushed writes);
|
|
465
382
|
* - a later WRITE constructs a fresh buffer on that re-anchored view, so a
|
|
466
383
|
* second commit diffs against post-first-commit state. The pre-release
|
|
467
384
|
* buffer behaved the same for VALUES (its `workingCopy` was reset on
|
|
@@ -492,20 +409,18 @@ export declare class StageContext {
|
|
|
492
409
|
* (M1: the transaction buffer holds writes until `commit()` flushes them).
|
|
493
410
|
*
|
|
494
411
|
* What is released, and why each one matters for the next attempt:
|
|
495
|
-
* -
|
|
496
|
-
* with nothing staged
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
*
|
|
412
|
+
* - the record frame's staged state (`RecordFrame · discard`) — the buffer
|
|
413
|
+
* (the next attempt starts with nothing staged), the
|
|
414
|
+
* first-touch base (it re-anchors on committed state as
|
|
415
|
+
* it stands NOW — a sibling fork branch may legitimately
|
|
416
|
+
* have committed in between) and the readKeys list (#P1:
|
|
417
|
+
* a discarded attempt's reads must never reach the next
|
|
418
|
+
* attempt's `TraceEntry.readKeys`);
|
|
500
419
|
* - `_stageWrites` / `_pendingWrites` / `_stageReads` — the snapshot
|
|
501
420
|
* payload; without the reset the execution tree would
|
|
502
421
|
* report writes that were discarded, which is the exact
|
|
503
422
|
* lie this feature exists to prevent (the pending map
|
|
504
423
|
* holds bare references — dropping it un-clones nothing);
|
|
505
|
-
* - `_provenanceReads` — the per-write read prefix (#P1); a discarded
|
|
506
|
-
* attempt's reads must never appear in the next attempt's
|
|
507
|
-
* `TraceEntry.readKeys`, or a backward slice would follow
|
|
508
|
-
* an edge that no committed write ever had;
|
|
509
424
|
* - `_untrackedSources` — the D2 honesty markers, released with the rest.
|
|
510
425
|
*
|
|
511
426
|
* What is deliberately KEPT: `debug` (logs, metrics, errors, flow messages).
|
|
@@ -128,8 +128,9 @@ export declare class TransactionBuffer {
|
|
|
128
128
|
*/
|
|
129
129
|
private detachedBase?;
|
|
130
130
|
/**
|
|
131
|
-
* Where the stage writes (9.30.0):
|
|
132
|
-
*
|
|
131
|
+
* Where the stage writes (9.30.0): a path prefix its frame computed and
|
|
132
|
+
* hands over as data (C2 — for the engine, the frame's run namespace, or
|
|
133
|
+
* `[]` for the root). Its containers are the stage's ADDRESS, not a value
|
|
133
134
|
* the stage reads (every read it makes is a key below it), so a shell a
|
|
134
135
|
* write leaves there is no part of the read-back the record must hold.
|
|
135
136
|
*/
|
|
@@ -234,8 +235,8 @@ export declare class TransactionBuffer {
|
|
|
234
235
|
* Keep the diff base exact under a read the working copy cannot answer.
|
|
235
236
|
*
|
|
236
237
|
* When `workingCopy` holds nothing at `path` — the stage deleted or unset
|
|
237
|
-
* it, or a write replaced a container above it — `
|
|
238
|
-
*
|
|
238
|
+
* it, or a write replaced a container above it — `RecordFrame · read`
|
|
239
|
+
* serves the read from LIVE committed state, exactly as 9.28.0
|
|
239
240
|
* did, so the value it hands out is committed state itself. On 9.28.0 the
|
|
240
241
|
* diff base was a whole-state clone taken at the stage's first write, and
|
|
241
242
|
* an in-place edit of that value (out of contract — reads are borrowed)
|
|
@@ -275,7 +276,7 @@ export declare class TransactionBuffer {
|
|
|
275
276
|
* - a container still SHARED with committed state at the same position is
|
|
276
277
|
* replaced by a private deep copy when it is the value read, or by a
|
|
277
278
|
* shallow copy when it is a container on the way to it (so a read of
|
|
278
|
-
* `
|
|
279
|
+
* `k` under a fork child's address copies `k`, not every child's namespace);
|
|
279
280
|
* - a container the stage STAGED (or anything else the buffer did not
|
|
280
281
|
* take from committed state) is handed back by reference, as before;
|
|
281
282
|
* - a container the buffer owns is walked on — and when it is the value
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* (`merge.ts`) at L0, and the verb law (`verbs.ts`) at L1 — `applySmartMerge`,
|
|
11
11
|
* `nextGeneration`, `applySmartMergeInto`, `dryFold`, `supersededByNextSet`.
|
|
12
12
|
* The log's scrub, `redactPatch`, moved to its owner `redaction.ts` in 9.33.0.
|
|
13
|
+
* The writers take an ADDRESS, a path prefix their caller computed, and never
|
|
14
|
+
* name one (C2: the engine decides where a stage writes, `StageContext.ts · runAddress`).
|
|
13
15
|
* Zero external dependencies.
|
|
14
16
|
*/
|
|
15
17
|
export { deepEqual } from './equality.js';
|
|
@@ -20,24 +22,26 @@ type NestedObject = {
|
|
|
20
22
|
[key: string]: any;
|
|
21
23
|
};
|
|
22
24
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* The two places a value at `path` can sit: under `address` (`runPath`, absent
|
|
26
|
+
* for the root address `[]`) and at the root (`globalPath`). `address` is a
|
|
27
|
+
* path prefix the caller computed — for the engine, a frame's run namespace
|
|
28
|
+
* (`StageContext.ts · runAddress`, C2), held by its record frame (`RecordFrame · address`, C3).
|
|
25
29
|
*/
|
|
26
|
-
export declare function getRunAndGlobalPaths(
|
|
30
|
+
export declare function getRunAndGlobalPaths(address?: readonly string[], path?: (string | number)[]): {
|
|
27
31
|
runPath: (string | number)[] | undefined;
|
|
28
32
|
globalPath: (string | number)[];
|
|
29
33
|
};
|
|
30
34
|
/**
|
|
31
|
-
* Sets a value at a nested path
|
|
35
|
+
* Sets a value at a nested path under `address`, creating intermediate objects as needed.
|
|
32
36
|
*/
|
|
33
|
-
export declare function setNestedValue<T>(obj: NestedObject,
|
|
37
|
+
export declare function setNestedValue<T>(obj: NestedObject, address: readonly string[], path: string[], field: string, value: T, defaultValues?: unknown): NestedObject;
|
|
34
38
|
/**
|
|
35
|
-
* Deep-merges a value into the object at
|
|
39
|
+
* Deep-merges a value into the object at a nested path under `address`.
|
|
36
40
|
* - Arrays: concatenate
|
|
37
41
|
* - Objects: shallow merge at each level
|
|
38
42
|
* - Primitives: replace
|
|
39
43
|
*/
|
|
40
|
-
export declare function updateNestedValue<T>(obj: any,
|
|
44
|
+
export declare function updateNestedValue<T>(obj: any, address: readonly string[], path: (string | number)[], field: string | number, value: T, defaultValues?: unknown): any;
|
|
41
45
|
/**
|
|
42
46
|
* In-place value update with merge semantics.
|
|
43
47
|
* - Arrays (non-empty): concatenate onto existing
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* path inside the value I read, put this". The value it read is BORROWED —
|
|
6
6
|
* before a stage's first staged write it is a bare reference into committed
|
|
7
7
|
* shared memory, and committed state is immutable-after-swap (see
|
|
8
|
-
* `
|
|
8
|
+
* `RecordFrame · firstTouch`). Editing it in place would corrupt every
|
|
9
9
|
* in-flight stage AND leave the commit log with nothing to record.
|
|
10
10
|
*
|
|
11
11
|
* So the write path never mutates. It COPIES the containers along the path
|
package/package.json
CHANGED