@storylet-studio/runtime 0.7.0 → 0.8.1
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 +10 -0
- package/dist/index.cjs +689 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -19
- package/dist/index.d.ts +117 -19
- package/dist/index.js +689 -57
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ScalarValue, ScopeResolver, ExprNode } from '@wildwinter/expr';
|
|
1
|
+
import { ScalarValue, ScopeResolver, ExprNode, EvalContext } from '@wildwinter/expr';
|
|
2
2
|
export { Prng, makePrng, shuffleInPlace } from '@wildwinter/expr';
|
|
3
|
-
import { Bundle, FlowSave, LoadReport, Card, Expression, Deck, Box, Hand, HandTemplate, TagGroup, PropertyDecl, SaveEnvelope, PropertyType, ScalarValue as ScalarValue$1 } from '@storylet-studio/model';
|
|
4
|
-
import { PropertyBag, PropertyRow } from '@wildwinter/scoperegistry';
|
|
3
|
+
import { Bundle, FlowSave, LoadReport, Card, Expression, Deck, Box, Hand, HandTemplate, TagGroup, PropertyDecl, SaveEnvelope, SaveEnvelopeV1, PropertyType, ScalarValue as ScalarValue$1 } from '@storylet-studio/model';
|
|
4
|
+
import { PropertyBag, ScopeRegistry, PropertyRow } from '@wildwinter/scoperegistry';
|
|
5
5
|
export { PropertyRow } from '@wildwinter/scoperegistry';
|
|
6
6
|
|
|
7
7
|
interface EngineOptions {
|
|
@@ -18,12 +18,25 @@ interface EngineOptions {
|
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* The host's resolver for @world - the values the game owns and the
|
|
21
|
-
* story reads (and, where `set` is offered, writes).
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* story reads (and, where `set` is offered, writes). Engine-level, shared
|
|
22
|
+
* by all flows, never saved: the game keeps these values. Omit it and a
|
|
23
|
+
* standalone engine self-backs @world from the declared defaults, as a
|
|
24
|
+
* property its registry stores and saves. A game running several engines
|
|
25
|
+
* registers @world in its registry itself instead.
|
|
25
26
|
*/
|
|
26
27
|
world?: ScopeResolver;
|
|
28
|
+
/**
|
|
29
|
+
* The game's registry: ONE per game, holding every engine's properties
|
|
30
|
+
* except those the game keeps itself, saved once. Given one, the engine
|
|
31
|
+
* registers its own scopes in it (@story under `story`, every other bag
|
|
32
|
+
* under a key starting `storylets/`, and @world if `world` is passed),
|
|
33
|
+
* reads every other scope from it, and `saveGame()` leaves the property
|
|
34
|
+
* values to the game. @world is then the game's to register: owned if the
|
|
35
|
+
* registry should store it, foreign if the game keeps it. Omit it and the
|
|
36
|
+
* engine makes its own registry and acts as its own game: it self-backs
|
|
37
|
+
* @world, and `saveGame()` carries the registry's values too.
|
|
38
|
+
*/
|
|
39
|
+
registry?: ScopeRegistry;
|
|
27
40
|
/**
|
|
28
41
|
* Diagnostics hook (opt-in, dev tooling only): fired when `openFlow` REPLACES
|
|
29
42
|
* a flow that still had cards dealt, with the flow id and how many. The
|
|
@@ -313,9 +326,24 @@ interface Internals {
|
|
|
313
326
|
* what the shared side WOULD hold without building a bag, which is what
|
|
314
327
|
* makes previewLoad pure. */
|
|
315
328
|
sharedDecls: DeclSet;
|
|
316
|
-
/** The shared stores
|
|
329
|
+
/** The shared stores, registered in the registry for the engine's life.
|
|
330
|
+
* Reseeded in place by reset and by a load that carries values. */
|
|
317
331
|
shared: Partition;
|
|
318
|
-
/**
|
|
332
|
+
/** The game's one registry (or the engine's own, when it is standalone). */
|
|
333
|
+
registry: ScopeRegistry;
|
|
334
|
+
/** True when the engine made the registry: `saveGame()` then carries its values. */
|
|
335
|
+
ownsRegistry: boolean;
|
|
336
|
+
/** True when the engine self-backed @world (standalone, no resolver bound). */
|
|
337
|
+
selfWorld: boolean;
|
|
338
|
+
/** Every OTHER scope in the registry, as an eval context sees it (instance
|
|
339
|
+
* keys left out), rebuilt only when the registry's set of scopes moves. */
|
|
340
|
+
registryView: () => {
|
|
341
|
+
scopes: EvalContext["scopes"];
|
|
342
|
+
qualities: EvalContext["qualities"];
|
|
343
|
+
};
|
|
344
|
+
/** @world, read through the registry by name (the scope's own normalisation),
|
|
345
|
+
* so a @world the game registered folded to lower case still answers the
|
|
346
|
+
* names as authored. */
|
|
319
347
|
worldResolver: ScopeResolver;
|
|
320
348
|
/** The @world WRITE seam. `host` says the caller is the GAME's own surface -
|
|
321
349
|
* setProperty, the coverage harness, the CLI's --set - which the shared
|
|
@@ -348,10 +376,19 @@ declare class Engine {
|
|
|
348
376
|
* outlives reset/loadGame (the host's container is the host's). The
|
|
349
377
|
* self-backed resolver is rebuilt instead. */
|
|
350
378
|
private readonly hostWorld?;
|
|
379
|
+
/** The options this engine was built with: hotSwap builds its replacement from them. */
|
|
380
|
+
private readonly creationOptions;
|
|
381
|
+
/** How to register each shared scope again, in registration order: a failed
|
|
382
|
+
* hotSwap puts this engine back exactly as it was. */
|
|
383
|
+
private readonly sharedMounts;
|
|
351
384
|
constructor(bundle: Bundle, opts?: EngineOptions);
|
|
352
|
-
/** Build the shared stores and
|
|
353
|
-
* engine's
|
|
385
|
+
/** Build the shared stores, register them and @world, and set up the @world
|
|
386
|
+
* seam. Once, for the engine's life: reset and loads reseed the bags in
|
|
387
|
+
* place, so the registry never sees them come and go. */
|
|
354
388
|
private initShared;
|
|
389
|
+
/** Every shared bag back to its declared defaults, in place (the registry
|
|
390
|
+
* keeps them registered), the self-backed @world included. */
|
|
391
|
+
private reseedShared;
|
|
355
392
|
/** Quality ladders by scope for the eval channel (design/quality.md):
|
|
356
393
|
* world/story keyed by name; box/deck/value keyed by owner id then name.
|
|
357
394
|
* Built once - a bundle's declarations never change. Ladders are
|
|
@@ -362,6 +399,10 @@ declare class Engine {
|
|
|
362
399
|
* state; shared state is untouched. There is no default flow: "main" is
|
|
363
400
|
* a caller convention, not an engine rule. */
|
|
364
401
|
openFlow(id: string, opts?: OpenFlowOptions): Flow;
|
|
402
|
+
/** openFlow, and loadGame's rebuild. `claim` says the new flow's bags take
|
|
403
|
+
* the values the registry holds for them (a load); a fresh open is a reset
|
|
404
|
+
* of that name, so anything waiting for it is discarded first. */
|
|
405
|
+
private open;
|
|
365
406
|
getFlow(id: string): Flow | undefined;
|
|
366
407
|
/** Every live flow, open order. */
|
|
367
408
|
flows(): Flow[];
|
|
@@ -376,6 +417,11 @@ declare class Engine {
|
|
|
376
417
|
* self-backed @world included; a host-bound @world is the host's and is
|
|
377
418
|
* not touched). */
|
|
378
419
|
reset(): void;
|
|
420
|
+
/** End the run: clear the log, close every flow, forget spent cards. Each
|
|
421
|
+
* flow's bags leave the registry; `keepFlows` names the flows whose values
|
|
422
|
+
* are kept there for the flow that replaces them (a load into the game's
|
|
423
|
+
* registry). */
|
|
424
|
+
private dropRun;
|
|
379
425
|
/** Cards a shared `redraw: "never"` has taken out of the world, by card id.
|
|
380
426
|
* The claim ledger is DERIVED from live boards and so needs no storage;
|
|
381
427
|
* this one is durable, so it rides the save's shared half. */
|
|
@@ -418,6 +464,12 @@ declare class Engine {
|
|
|
418
464
|
* carries no flow. It reaches the run log and the engine tap; there is
|
|
419
465
|
* nowhere else for it to go, and it fires only on a legacy address. */
|
|
420
466
|
private diagnose;
|
|
467
|
+
/** Content that names another engine's scope (`@patter.visits`) runs only
|
|
468
|
+
* where that engine is on this registry: without it every read would answer
|
|
469
|
+
* false and every write fail, so the flow is refused as it opens, before
|
|
470
|
+
* anything changes. By then a game has built all of its engines, whatever
|
|
471
|
+
* order it built them in. The same message on every runtime. */
|
|
472
|
+
private assertExternalScopes;
|
|
421
473
|
/** The shared surface as examiner rows: @world (read through the
|
|
422
474
|
* resolver) then the shared partitions. Per-flow rows live on each Flow. */
|
|
423
475
|
listProperties(): PropertyRow[];
|
|
@@ -427,9 +479,33 @@ declare class Engine {
|
|
|
427
479
|
listBags(): BagMount[];
|
|
428
480
|
/** Every flow's trace, one stream, each event tagged with its flow id. */
|
|
429
481
|
subscribeTrace(handler: EngineTraceHandler): () => void;
|
|
430
|
-
/**
|
|
431
|
-
*
|
|
432
|
-
*
|
|
482
|
+
/**
|
|
483
|
+
* Live bundle refresh: rebuild on an edited bundle with the whole run carried
|
|
484
|
+
* over, and return the replacement with the report its load produced.
|
|
485
|
+
*
|
|
486
|
+
* Standalone, that is a save and a load into a new engine, and this one is left
|
|
487
|
+
* untouched (discard it). With the game's registry the two cannot both hold the
|
|
488
|
+
* same keys, so this engine is spent afterwards (its flows closed, the
|
|
489
|
+
* replacement holding everything on the same registry): it carries its
|
|
490
|
+
* own values into the snapshot, steps out of the registry, and the replacement
|
|
491
|
+
* loads them the way a standalone save loads: so the report covers the
|
|
492
|
+
* properties the edit dropped, defaulted, or retyped, and a dropped property
|
|
493
|
+
* is dropped rather than kept. Values the game loaded that were still waiting
|
|
494
|
+
* for a flow of this engine carry across as they were, and nothing belonging
|
|
495
|
+
* to any other engine is touched. A save for another project is refused before
|
|
496
|
+
* anything moves; if the rebuild fails for any other reason, this engine takes
|
|
497
|
+
* its registrations back and is left exactly as it was.
|
|
498
|
+
*/
|
|
499
|
+
hotSwap(bundle: Bundle, opts?: EngineOptions): {
|
|
500
|
+
engine: Engine;
|
|
501
|
+
report: LoadReport;
|
|
502
|
+
};
|
|
503
|
+
/** The whole engine's NON-property state, one envelope: the spent cards
|
|
504
|
+
* once, then every live flow (board, clocks, cooldowns, PRNG, play log)
|
|
505
|
+
* keyed by its id. The property values are the registry's: a standalone
|
|
506
|
+
* engine (one that made its own registry) carries them here under
|
|
507
|
+
* `registry`, self-backed @world included; a game that passed a registry
|
|
508
|
+
* saves it once itself, beside each engine's envelope. */
|
|
433
509
|
saveGame(): SaveEnvelope;
|
|
434
510
|
/** ONE flow's blob, to park a visit that is walking away: the same shape
|
|
435
511
|
* the envelope carries per flow, and the same shape `openFlow`'s `restore`
|
|
@@ -442,7 +518,7 @@ declare class Engine {
|
|
|
442
518
|
* doing any of it (design/engine-server.md 4.9). Pure: nothing on this
|
|
443
519
|
* engine moves. A project mismatch is refused here exactly as `loadGame`
|
|
444
520
|
* refuses it - it is the one thing neither call will tolerate. */
|
|
445
|
-
previewLoad(envelope: SaveEnvelope): LoadReport;
|
|
521
|
+
previewLoad(envelope: SaveEnvelope | SaveEnvelopeV1): LoadReport;
|
|
446
522
|
/** What `openFlow(id, { restore: saved })` would do to a flow of that name,
|
|
447
523
|
* without doing it: the same report shape, since a visit parked under one
|
|
448
524
|
* build and resumed under the next raises the same questions. Pure. */
|
|
@@ -451,10 +527,18 @@ declare class Engine {
|
|
|
451
527
|
* Handles held from before the load are closed and inert (Patter's
|
|
452
528
|
* rule); take fresh ones from getFlow()/flows().
|
|
453
529
|
*
|
|
530
|
+
* Property values come from the registry. An envelope that carries them
|
|
531
|
+
* (a standalone engine's, or a version 1 envelope) has them walked, cleaned,
|
|
532
|
+
* and moved into the registry here, over fresh defaults. Otherwise the game
|
|
533
|
+
* loads its registry itself, before or after this call: each flow's bags
|
|
534
|
+
* are handed back to the registry with their values, and the restored
|
|
535
|
+
* flows claim them. The report then covers only what this envelope holds;
|
|
536
|
+
* the registry's own load rule applies to the values.
|
|
537
|
+
*
|
|
454
538
|
* Returns the report `previewLoad` would have given for this envelope: the
|
|
455
539
|
* drift tolerance that makes a load forgiving is what hides its cost, so
|
|
456
540
|
* the cost comes back with the load whether or not anybody looked first. */
|
|
457
|
-
loadGame(envelope: SaveEnvelope): LoadReport;
|
|
541
|
+
loadGame(envelope: SaveEnvelope | SaveEnvelopeV1): LoadReport;
|
|
458
542
|
private assertSameProject;
|
|
459
543
|
/** The whole-envelope walk: the report, and the cleaned state the apply
|
|
460
544
|
* half writes. Nothing here touches the engine, which is what lets
|
|
@@ -482,8 +566,12 @@ declare class Flow {
|
|
|
482
566
|
private lastPlayOf;
|
|
483
567
|
private tagPlayCount;
|
|
484
568
|
private lastPlayInTag;
|
|
485
|
-
/** The per-flow property partitions (the not-shared halves)
|
|
569
|
+
/** The per-flow property partitions (the not-shared halves), each bag
|
|
570
|
+
* that declares something registered under this flow's keys. */
|
|
486
571
|
private stores;
|
|
572
|
+
private readonly registered;
|
|
573
|
+
/** This flow's bags that declare something, under their registry keys. */
|
|
574
|
+
private readonly bagKeys;
|
|
487
575
|
private traceHandlers;
|
|
488
576
|
private logEntries;
|
|
489
577
|
private logSeq;
|
|
@@ -501,6 +589,15 @@ declare class Flow {
|
|
|
501
589
|
close(): void;
|
|
502
590
|
/** @internal */
|
|
503
591
|
markClosed(): void;
|
|
592
|
+
/** @internal - take this flow's bags out of the registry; with `keep`, their
|
|
593
|
+
* values wait there for the flow that replaces this one (a load into the
|
|
594
|
+
* game's registry). Idempotent. */
|
|
595
|
+
releaseBags(keep: boolean): void;
|
|
596
|
+
/** @internal - the registry keys this flow holds right now. */
|
|
597
|
+
registeredKeys(): string[];
|
|
598
|
+
/** @internal - register this flow's bags (again): at construction, and when a
|
|
599
|
+
* failed hotSwap hands them back. Each claims what the registry holds for it. */
|
|
600
|
+
mountBags(): void;
|
|
504
601
|
private assertOpen;
|
|
505
602
|
/** A box's current turn (schema 3.4), on THIS flow's clock. */
|
|
506
603
|
turn(boxRef: string): number;
|
|
@@ -709,8 +806,9 @@ declare class Flow {
|
|
|
709
806
|
getProperty(path: string): ScalarValue;
|
|
710
807
|
setProperty(path: string, value: ScalarValue): void;
|
|
711
808
|
private resolvePath;
|
|
712
|
-
/** @internal - this flow's blob inside the engine's envelope
|
|
713
|
-
|
|
809
|
+
/** @internal - this flow's blob: inside the engine's envelope without its
|
|
810
|
+
* properties (the registry has them), or parked whole by saveFlow. */
|
|
811
|
+
snapshot(withProps: boolean): FlowSave;
|
|
714
812
|
/** @internal - restore a freshly opened flow from its blob (loadGame).
|
|
715
813
|
* Orphaned keys (deleted entities) drop; new declarations keep defaults. */
|
|
716
814
|
restore(saved: FlowSave): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ScalarValue, ScopeResolver, ExprNode } from '@wildwinter/expr';
|
|
1
|
+
import { ScalarValue, ScopeResolver, ExprNode, EvalContext } from '@wildwinter/expr';
|
|
2
2
|
export { Prng, makePrng, shuffleInPlace } from '@wildwinter/expr';
|
|
3
|
-
import { Bundle, FlowSave, LoadReport, Card, Expression, Deck, Box, Hand, HandTemplate, TagGroup, PropertyDecl, SaveEnvelope, PropertyType, ScalarValue as ScalarValue$1 } from '@storylet-studio/model';
|
|
4
|
-
import { PropertyBag, PropertyRow } from '@wildwinter/scoperegistry';
|
|
3
|
+
import { Bundle, FlowSave, LoadReport, Card, Expression, Deck, Box, Hand, HandTemplate, TagGroup, PropertyDecl, SaveEnvelope, SaveEnvelopeV1, PropertyType, ScalarValue as ScalarValue$1 } from '@storylet-studio/model';
|
|
4
|
+
import { PropertyBag, ScopeRegistry, PropertyRow } from '@wildwinter/scoperegistry';
|
|
5
5
|
export { PropertyRow } from '@wildwinter/scoperegistry';
|
|
6
6
|
|
|
7
7
|
interface EngineOptions {
|
|
@@ -18,12 +18,25 @@ interface EngineOptions {
|
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* The host's resolver for @world - the values the game owns and the
|
|
21
|
-
* story reads (and, where `set` is offered, writes).
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* story reads (and, where `set` is offered, writes). Engine-level, shared
|
|
22
|
+
* by all flows, never saved: the game keeps these values. Omit it and a
|
|
23
|
+
* standalone engine self-backs @world from the declared defaults, as a
|
|
24
|
+
* property its registry stores and saves. A game running several engines
|
|
25
|
+
* registers @world in its registry itself instead.
|
|
25
26
|
*/
|
|
26
27
|
world?: ScopeResolver;
|
|
28
|
+
/**
|
|
29
|
+
* The game's registry: ONE per game, holding every engine's properties
|
|
30
|
+
* except those the game keeps itself, saved once. Given one, the engine
|
|
31
|
+
* registers its own scopes in it (@story under `story`, every other bag
|
|
32
|
+
* under a key starting `storylets/`, and @world if `world` is passed),
|
|
33
|
+
* reads every other scope from it, and `saveGame()` leaves the property
|
|
34
|
+
* values to the game. @world is then the game's to register: owned if the
|
|
35
|
+
* registry should store it, foreign if the game keeps it. Omit it and the
|
|
36
|
+
* engine makes its own registry and acts as its own game: it self-backs
|
|
37
|
+
* @world, and `saveGame()` carries the registry's values too.
|
|
38
|
+
*/
|
|
39
|
+
registry?: ScopeRegistry;
|
|
27
40
|
/**
|
|
28
41
|
* Diagnostics hook (opt-in, dev tooling only): fired when `openFlow` REPLACES
|
|
29
42
|
* a flow that still had cards dealt, with the flow id and how many. The
|
|
@@ -313,9 +326,24 @@ interface Internals {
|
|
|
313
326
|
* what the shared side WOULD hold without building a bag, which is what
|
|
314
327
|
* makes previewLoad pure. */
|
|
315
328
|
sharedDecls: DeclSet;
|
|
316
|
-
/** The shared stores
|
|
329
|
+
/** The shared stores, registered in the registry for the engine's life.
|
|
330
|
+
* Reseeded in place by reset and by a load that carries values. */
|
|
317
331
|
shared: Partition;
|
|
318
|
-
/**
|
|
332
|
+
/** The game's one registry (or the engine's own, when it is standalone). */
|
|
333
|
+
registry: ScopeRegistry;
|
|
334
|
+
/** True when the engine made the registry: `saveGame()` then carries its values. */
|
|
335
|
+
ownsRegistry: boolean;
|
|
336
|
+
/** True when the engine self-backed @world (standalone, no resolver bound). */
|
|
337
|
+
selfWorld: boolean;
|
|
338
|
+
/** Every OTHER scope in the registry, as an eval context sees it (instance
|
|
339
|
+
* keys left out), rebuilt only when the registry's set of scopes moves. */
|
|
340
|
+
registryView: () => {
|
|
341
|
+
scopes: EvalContext["scopes"];
|
|
342
|
+
qualities: EvalContext["qualities"];
|
|
343
|
+
};
|
|
344
|
+
/** @world, read through the registry by name (the scope's own normalisation),
|
|
345
|
+
* so a @world the game registered folded to lower case still answers the
|
|
346
|
+
* names as authored. */
|
|
319
347
|
worldResolver: ScopeResolver;
|
|
320
348
|
/** The @world WRITE seam. `host` says the caller is the GAME's own surface -
|
|
321
349
|
* setProperty, the coverage harness, the CLI's --set - which the shared
|
|
@@ -348,10 +376,19 @@ declare class Engine {
|
|
|
348
376
|
* outlives reset/loadGame (the host's container is the host's). The
|
|
349
377
|
* self-backed resolver is rebuilt instead. */
|
|
350
378
|
private readonly hostWorld?;
|
|
379
|
+
/** The options this engine was built with: hotSwap builds its replacement from them. */
|
|
380
|
+
private readonly creationOptions;
|
|
381
|
+
/** How to register each shared scope again, in registration order: a failed
|
|
382
|
+
* hotSwap puts this engine back exactly as it was. */
|
|
383
|
+
private readonly sharedMounts;
|
|
351
384
|
constructor(bundle: Bundle, opts?: EngineOptions);
|
|
352
|
-
/** Build the shared stores and
|
|
353
|
-
* engine's
|
|
385
|
+
/** Build the shared stores, register them and @world, and set up the @world
|
|
386
|
+
* seam. Once, for the engine's life: reset and loads reseed the bags in
|
|
387
|
+
* place, so the registry never sees them come and go. */
|
|
354
388
|
private initShared;
|
|
389
|
+
/** Every shared bag back to its declared defaults, in place (the registry
|
|
390
|
+
* keeps them registered), the self-backed @world included. */
|
|
391
|
+
private reseedShared;
|
|
355
392
|
/** Quality ladders by scope for the eval channel (design/quality.md):
|
|
356
393
|
* world/story keyed by name; box/deck/value keyed by owner id then name.
|
|
357
394
|
* Built once - a bundle's declarations never change. Ladders are
|
|
@@ -362,6 +399,10 @@ declare class Engine {
|
|
|
362
399
|
* state; shared state is untouched. There is no default flow: "main" is
|
|
363
400
|
* a caller convention, not an engine rule. */
|
|
364
401
|
openFlow(id: string, opts?: OpenFlowOptions): Flow;
|
|
402
|
+
/** openFlow, and loadGame's rebuild. `claim` says the new flow's bags take
|
|
403
|
+
* the values the registry holds for them (a load); a fresh open is a reset
|
|
404
|
+
* of that name, so anything waiting for it is discarded first. */
|
|
405
|
+
private open;
|
|
365
406
|
getFlow(id: string): Flow | undefined;
|
|
366
407
|
/** Every live flow, open order. */
|
|
367
408
|
flows(): Flow[];
|
|
@@ -376,6 +417,11 @@ declare class Engine {
|
|
|
376
417
|
* self-backed @world included; a host-bound @world is the host's and is
|
|
377
418
|
* not touched). */
|
|
378
419
|
reset(): void;
|
|
420
|
+
/** End the run: clear the log, close every flow, forget spent cards. Each
|
|
421
|
+
* flow's bags leave the registry; `keepFlows` names the flows whose values
|
|
422
|
+
* are kept there for the flow that replaces them (a load into the game's
|
|
423
|
+
* registry). */
|
|
424
|
+
private dropRun;
|
|
379
425
|
/** Cards a shared `redraw: "never"` has taken out of the world, by card id.
|
|
380
426
|
* The claim ledger is DERIVED from live boards and so needs no storage;
|
|
381
427
|
* this one is durable, so it rides the save's shared half. */
|
|
@@ -418,6 +464,12 @@ declare class Engine {
|
|
|
418
464
|
* carries no flow. It reaches the run log and the engine tap; there is
|
|
419
465
|
* nowhere else for it to go, and it fires only on a legacy address. */
|
|
420
466
|
private diagnose;
|
|
467
|
+
/** Content that names another engine's scope (`@patter.visits`) runs only
|
|
468
|
+
* where that engine is on this registry: without it every read would answer
|
|
469
|
+
* false and every write fail, so the flow is refused as it opens, before
|
|
470
|
+
* anything changes. By then a game has built all of its engines, whatever
|
|
471
|
+
* order it built them in. The same message on every runtime. */
|
|
472
|
+
private assertExternalScopes;
|
|
421
473
|
/** The shared surface as examiner rows: @world (read through the
|
|
422
474
|
* resolver) then the shared partitions. Per-flow rows live on each Flow. */
|
|
423
475
|
listProperties(): PropertyRow[];
|
|
@@ -427,9 +479,33 @@ declare class Engine {
|
|
|
427
479
|
listBags(): BagMount[];
|
|
428
480
|
/** Every flow's trace, one stream, each event tagged with its flow id. */
|
|
429
481
|
subscribeTrace(handler: EngineTraceHandler): () => void;
|
|
430
|
-
/**
|
|
431
|
-
*
|
|
432
|
-
*
|
|
482
|
+
/**
|
|
483
|
+
* Live bundle refresh: rebuild on an edited bundle with the whole run carried
|
|
484
|
+
* over, and return the replacement with the report its load produced.
|
|
485
|
+
*
|
|
486
|
+
* Standalone, that is a save and a load into a new engine, and this one is left
|
|
487
|
+
* untouched (discard it). With the game's registry the two cannot both hold the
|
|
488
|
+
* same keys, so this engine is spent afterwards (its flows closed, the
|
|
489
|
+
* replacement holding everything on the same registry): it carries its
|
|
490
|
+
* own values into the snapshot, steps out of the registry, and the replacement
|
|
491
|
+
* loads them the way a standalone save loads: so the report covers the
|
|
492
|
+
* properties the edit dropped, defaulted, or retyped, and a dropped property
|
|
493
|
+
* is dropped rather than kept. Values the game loaded that were still waiting
|
|
494
|
+
* for a flow of this engine carry across as they were, and nothing belonging
|
|
495
|
+
* to any other engine is touched. A save for another project is refused before
|
|
496
|
+
* anything moves; if the rebuild fails for any other reason, this engine takes
|
|
497
|
+
* its registrations back and is left exactly as it was.
|
|
498
|
+
*/
|
|
499
|
+
hotSwap(bundle: Bundle, opts?: EngineOptions): {
|
|
500
|
+
engine: Engine;
|
|
501
|
+
report: LoadReport;
|
|
502
|
+
};
|
|
503
|
+
/** The whole engine's NON-property state, one envelope: the spent cards
|
|
504
|
+
* once, then every live flow (board, clocks, cooldowns, PRNG, play log)
|
|
505
|
+
* keyed by its id. The property values are the registry's: a standalone
|
|
506
|
+
* engine (one that made its own registry) carries them here under
|
|
507
|
+
* `registry`, self-backed @world included; a game that passed a registry
|
|
508
|
+
* saves it once itself, beside each engine's envelope. */
|
|
433
509
|
saveGame(): SaveEnvelope;
|
|
434
510
|
/** ONE flow's blob, to park a visit that is walking away: the same shape
|
|
435
511
|
* the envelope carries per flow, and the same shape `openFlow`'s `restore`
|
|
@@ -442,7 +518,7 @@ declare class Engine {
|
|
|
442
518
|
* doing any of it (design/engine-server.md 4.9). Pure: nothing on this
|
|
443
519
|
* engine moves. A project mismatch is refused here exactly as `loadGame`
|
|
444
520
|
* refuses it - it is the one thing neither call will tolerate. */
|
|
445
|
-
previewLoad(envelope: SaveEnvelope): LoadReport;
|
|
521
|
+
previewLoad(envelope: SaveEnvelope | SaveEnvelopeV1): LoadReport;
|
|
446
522
|
/** What `openFlow(id, { restore: saved })` would do to a flow of that name,
|
|
447
523
|
* without doing it: the same report shape, since a visit parked under one
|
|
448
524
|
* build and resumed under the next raises the same questions. Pure. */
|
|
@@ -451,10 +527,18 @@ declare class Engine {
|
|
|
451
527
|
* Handles held from before the load are closed and inert (Patter's
|
|
452
528
|
* rule); take fresh ones from getFlow()/flows().
|
|
453
529
|
*
|
|
530
|
+
* Property values come from the registry. An envelope that carries them
|
|
531
|
+
* (a standalone engine's, or a version 1 envelope) has them walked, cleaned,
|
|
532
|
+
* and moved into the registry here, over fresh defaults. Otherwise the game
|
|
533
|
+
* loads its registry itself, before or after this call: each flow's bags
|
|
534
|
+
* are handed back to the registry with their values, and the restored
|
|
535
|
+
* flows claim them. The report then covers only what this envelope holds;
|
|
536
|
+
* the registry's own load rule applies to the values.
|
|
537
|
+
*
|
|
454
538
|
* Returns the report `previewLoad` would have given for this envelope: the
|
|
455
539
|
* drift tolerance that makes a load forgiving is what hides its cost, so
|
|
456
540
|
* the cost comes back with the load whether or not anybody looked first. */
|
|
457
|
-
loadGame(envelope: SaveEnvelope): LoadReport;
|
|
541
|
+
loadGame(envelope: SaveEnvelope | SaveEnvelopeV1): LoadReport;
|
|
458
542
|
private assertSameProject;
|
|
459
543
|
/** The whole-envelope walk: the report, and the cleaned state the apply
|
|
460
544
|
* half writes. Nothing here touches the engine, which is what lets
|
|
@@ -482,8 +566,12 @@ declare class Flow {
|
|
|
482
566
|
private lastPlayOf;
|
|
483
567
|
private tagPlayCount;
|
|
484
568
|
private lastPlayInTag;
|
|
485
|
-
/** The per-flow property partitions (the not-shared halves)
|
|
569
|
+
/** The per-flow property partitions (the not-shared halves), each bag
|
|
570
|
+
* that declares something registered under this flow's keys. */
|
|
486
571
|
private stores;
|
|
572
|
+
private readonly registered;
|
|
573
|
+
/** This flow's bags that declare something, under their registry keys. */
|
|
574
|
+
private readonly bagKeys;
|
|
487
575
|
private traceHandlers;
|
|
488
576
|
private logEntries;
|
|
489
577
|
private logSeq;
|
|
@@ -501,6 +589,15 @@ declare class Flow {
|
|
|
501
589
|
close(): void;
|
|
502
590
|
/** @internal */
|
|
503
591
|
markClosed(): void;
|
|
592
|
+
/** @internal - take this flow's bags out of the registry; with `keep`, their
|
|
593
|
+
* values wait there for the flow that replaces this one (a load into the
|
|
594
|
+
* game's registry). Idempotent. */
|
|
595
|
+
releaseBags(keep: boolean): void;
|
|
596
|
+
/** @internal - the registry keys this flow holds right now. */
|
|
597
|
+
registeredKeys(): string[];
|
|
598
|
+
/** @internal - register this flow's bags (again): at construction, and when a
|
|
599
|
+
* failed hotSwap hands them back. Each claims what the registry holds for it. */
|
|
600
|
+
mountBags(): void;
|
|
504
601
|
private assertOpen;
|
|
505
602
|
/** A box's current turn (schema 3.4), on THIS flow's clock. */
|
|
506
603
|
turn(boxRef: string): number;
|
|
@@ -709,8 +806,9 @@ declare class Flow {
|
|
|
709
806
|
getProperty(path: string): ScalarValue;
|
|
710
807
|
setProperty(path: string, value: ScalarValue): void;
|
|
711
808
|
private resolvePath;
|
|
712
|
-
/** @internal - this flow's blob inside the engine's envelope
|
|
713
|
-
|
|
809
|
+
/** @internal - this flow's blob: inside the engine's envelope without its
|
|
810
|
+
* properties (the registry has them), or parked whole by saveFlow. */
|
|
811
|
+
snapshot(withProps: boolean): FlowSave;
|
|
714
812
|
/** @internal - restore a freshly opened flow from its blob (loadGame).
|
|
715
813
|
* Orphaned keys (deleted entities) drop; new declarations keep defaults. */
|
|
716
814
|
restore(saved: FlowSave): void;
|