@moku-labs/game 0.9.0 → 0.10.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.
Files changed (53) hide show
  1. package/README.md +81 -22
  2. package/bin/moku-game.mjs +4 -0
  3. package/dist/app/page.d.mts +41 -0
  4. package/dist/app/page.mjs +376 -0
  5. package/dist/app/system.d.mts +129 -0
  6. package/dist/app/system.mjs +307 -0
  7. package/dist/app.d.mts +37 -0
  8. package/dist/app.mjs +235 -0
  9. package/dist/assets-BHwTLVta.mjs +7391 -0
  10. package/dist/assets.d.mts +1 -1
  11. package/dist/assets.mjs +1 -7390
  12. package/dist/cli.d.mts +70 -0
  13. package/dist/cli.mjs +1650 -0
  14. package/dist/{commands-DuwCxK5t.d.mts → commands-C4QlqijJ.d.mts} +5 -5
  15. package/dist/config-CdARrrhU.mjs +81 -0
  16. package/dist/control.d.mts +11 -10
  17. package/dist/control.mjs +3 -3
  18. package/dist/{define-B6pHpdBi.d.mts → define-CCc0ozKe.d.mts} +2 -2
  19. package/dist/{dev-wKLgOw7c.mjs → dev-Cc50Dk7H.mjs} +1 -1
  20. package/dist/drafts-BawpSaVp.mjs +156 -0
  21. package/dist/fake-MpzwZhIZ.mjs +87 -0
  22. package/dist/{headless-SCQXJxQf.d.mts → headless-G4nuZ-xz.d.mts} +1 -1
  23. package/dist/hot.d.mts +4 -6
  24. package/dist/hot.mjs +8 -9
  25. package/dist/{index-BO9kZzY3.d.mts → index-xxSxKJJW.d.mts} +17 -17
  26. package/dist/index.d.mts +5 -5
  27. package/dist/index.mjs +1 -1
  28. package/dist/inspect-la_KkjCS.mjs +1 -0
  29. package/dist/inspect.d.mts +7 -7
  30. package/dist/inspect.mjs +3 -2
  31. package/dist/jsx-dev-runtime.d.mts +1 -1
  32. package/dist/jsx-runtime.d.mts +1 -1
  33. package/dist/lint.mjs +10 -6
  34. package/dist/memory-CWlqhS7l.mjs +136 -0
  35. package/dist/memory-DwDhfFWK.d.mts +50 -0
  36. package/dist/project.mjs +3 -3
  37. package/dist/{run-CofJEdYx.mjs → run-wYty_Lwo.mjs} +2 -2
  38. package/dist/{runtime-CdNJ0UBm.d.mts → runtime-DOBYM6g4.d.mts} +1 -1
  39. package/dist/{input-z_35Jwfn.mjs → session-DgukhR_7.mjs} +20 -20
  40. package/dist/{sources-DNnzyCYf.mjs → sources-Duzj6lhV.mjs} +2 -2
  41. package/dist/{src-536arXjV.mjs → src-DSl1eNB1.mjs} +14 -292
  42. package/dist/testing.d.mts +4 -50
  43. package/dist/testing.mjs +3 -87
  44. package/dist/{types-VZVWwqCg.d.mts → types-BM4shh8K.d.mts} +259 -259
  45. package/dist/{types-xXfyk56Q.d.mts → types-BUwDHKXm.d.mts} +1377 -1377
  46. package/dist/{types-CQueODzo.d.mts → types-CefgYzFt.d.mts} +2 -2
  47. package/dist/{types-DUMoYPYe.d.mts → types-DAdwEJMp.d.mts} +2 -2
  48. package/dist/{types-B0v5VVa3.d.mts → types-ZQLYXo5X.d.mts} +304 -304
  49. package/dist/types-hQgI_wrq.d.mts +544 -0
  50. package/dist/visual.d.mts +6 -6
  51. package/dist/visual.mjs +5 -5
  52. package/llms.txt +119 -43
  53. package/package.json +30 -2
@@ -1,11 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
+ import { r as systemSource, t as memory } from "./memory-CWlqhS7l.mjs";
3
+ import { a as finishDrafts, i as enableDraftPatches, n as deepFreeze, o as openDrafts, r as dropDrafts } from "./drafts-BawpSaVp.mjs";
2
4
  import { c as findNode, d as slotNames, f as compact, i as servePaused, l as framePath, n as captureFrame, o as collectFlows, p as pushEntry, r as serveCaptures, s as describeGraph, t as cancelCaptures, u as graphHash } from "./capture-fpd83Mi5.mjs";
3
5
  import { A as system, C as Exiting, D as component, E as Tree, T as Order, _ as Parent, a as visualOf$1, b as Transform, c as Text, g as NineSlice, h as Display, j as tag, k as resource, m as textFor, n as fitScaleOf, o as visualRectOf, p as readStyle, r as samePose, s as Countdown, t as CONTENT, u as builtInStyles, v as Shape, w as Layer, x as componentsFor, y as Sprite } from "./visual-dMW8iqAE.mjs";
4
- import { n as isDev } from "./dev-wKLgOw7c.mjs";
6
+ import { n as isDev } from "./dev-Cc50Dk7H.mjs";
5
7
  import { i as isComponentDefinition, n as flatten, r as defineComponent } from "./flatten-BkXuscAV.mjs";
6
8
  import { envPlugin, logPlugin } from "@moku-labs/common/browser";
7
9
  import { createCoreConfig } from "@moku-labs/core";
8
- import { applyPatches, createDraft, enablePatches, finishDraft } from "immer";
9
10
  /**
10
11
  * Core config of the engine: `log` and `env` on every plugin context.
11
12
  */
@@ -127,37 +128,6 @@ function createClockApi(ctx) {
127
128
  };
128
129
  }
129
130
  //#endregion
130
- //#region src/plugins/clock/system.ts
131
- /**
132
- * Tells whether a handle was produced by this source.
133
- *
134
- * @param handle - Handle given back to `clearTimer`.
135
- * @returns `true` when the handle carries a platform timer.
136
- * @example
137
- * ```ts
138
- * isSystemTimer({ timer: 7 }); // true
139
- * isSystemTimer(7); // false: a handle of another source is ignored
140
- * ```
141
- */
142
- function isSystemTimer(handle) {
143
- return typeof handle === "object" && handle !== null && "timer" in handle;
144
- }
145
- /**
146
- * Creates the system source: epoch milliseconds from the device clock and real timers.
147
- *
148
- * @returns A source reading `Date.now` and scheduling with `setTimeout`.
149
- */
150
- function systemSource() {
151
- return {
152
- now: () => Date.now(),
153
- setTimer: (callback, delayMs) => ({ timer: setTimeout(callback, delayMs) }),
154
- clearTimer: (handle) => {
155
- if (!isSystemTimer(handle)) return;
156
- clearTimeout(handle.timer);
157
- }
158
- };
159
- }
160
- //#endregion
161
131
  //#region src/plugins/clock/state.ts
162
132
  /**
163
133
  * @file clock plugin — state factory.
@@ -765,263 +735,6 @@ function createRngState() {
765
735
  return {};
766
736
  }
767
737
  //#endregion
768
- //#region src/plugins/model/store/drafts.ts
769
- /** Root order of a commit result, so two commits never report the same roots in another order. */
770
- const rootOrder = Object.freeze([
771
- "player",
772
- "session",
773
- "rng"
774
- ]);
775
- /**
776
- * Turns on Immer's patch recording. Idempotent, and called from the state factory rather than at
777
- * module scope: a module-scope call would run on import, even when no app is created.
778
- *
779
- */
780
- function enableDraftPatches() {
781
- enablePatches();
782
- }
783
- /**
784
- * Freezes a tree and every branch of it. Immer freezes what it produces; this covers the trees
785
- * that never went through a draft — the initial trees and the ones handed to `restore()`.
786
- *
787
- * @param tree - The tree to freeze, in place.
788
- * @returns The same reference, now frozen.
789
- * @example
790
- * ```ts
791
- * const tree = deepFreeze({ player: { bag: ["key"] } });
792
- * Object.isFrozen(tree.player.bag); // true
793
- * ```
794
- */
795
- function deepFreeze(tree) {
796
- if (!tree || typeof tree !== "object") return tree;
797
- for (const branch of Object.values(tree)) deepFreeze(branch);
798
- return Object.freeze(tree);
799
- }
800
- /**
801
- * Maps one Immer patch to our own structural patch, so no Immer type reaches a public type.
802
- * A removal carries no value, and `exactOptionalPropertyTypes` forbids an explicit `undefined`.
803
- *
804
- * @param patch - The Immer patch.
805
- * @param path - Path of the patch inside its own tree, without the container segment.
806
- * @returns The structural patch.
807
- * @example
808
- * ```ts
809
- * toPatch({ op: "remove", path: ["doc", "player", "key"] }, ["player", "key"]);
810
- * // { op: "remove", path: ["player", "key"] }
811
- * ```
812
- */
813
- function toPatch(patch, path) {
814
- if (patch.op === "remove") return {
815
- op: patch.op,
816
- path
817
- };
818
- return {
819
- op: patch.op,
820
- path,
821
- value: patch.value
822
- };
823
- }
824
- /**
825
- * Derives the touched roots from the patches of one commit, in a fixed order.
826
- *
827
- * @param docPatches - Patches of the save document.
828
- * @param sessionPatches - Patches of the session tree.
829
- * @returns The roots a listener has to reconcile.
830
- * @example
831
- * ```ts
832
- * rootsOf([{ op: "add", path: ["rng", "streams", "dice"], value: 7 }], []); // ["rng"]
833
- * rootsOf([], [{ op: "replace", path: ["rolls"], value: 1 }]); // ["session"]
834
- * ```
835
- */
836
- function rootsOf(docPatches, sessionPatches) {
837
- const touched = /* @__PURE__ */ new Set();
838
- for (const patch of docPatches) {
839
- const [head] = patch.path;
840
- if (head === "player" || head === "rng") touched.add(head);
841
- }
842
- if (sessionPatches.length > 0) touched.add("session");
843
- return rootOrder.filter((root) => touched.has(root));
844
- }
845
- /**
846
- * Opens mutable drafts of the frozen save document and session tree.
847
- * Both live in one draft container, so one `finishDraft` closes the transaction and the patches
848
- * arrive in one list, tagged by their container key.
849
- *
850
- * @param doc - Frozen save document.
851
- * @param session - Frozen session tree.
852
- * @returns The open drafts of one transaction.
853
- * @example
854
- * ```ts
855
- * const pair = openDrafts({ player: { coins: 1 }, rng: { seed: 7, streams: {} } }, { rolls: 0 });
856
- * pair.session; // a mutable draft of { rolls: 0 }: a write never reaches the frozen input
857
- * ```
858
- */
859
- function openDrafts(doc, session) {
860
- return createDraft({
861
- doc,
862
- session
863
- });
864
- }
865
- /**
866
- * Finishes the drafts: the new frozen trees, the patches per tree and the touched roots.
867
- * The drafts are revoked, so a draft that leaked into a view throws on the next touch instead of
868
- * corrupting the committed tree in silence.
869
- *
870
- * @param pair - Open drafts of one transaction.
871
- * @returns The frozen trees, the patches split by tree, and the touched roots.
872
- */
873
- function finishDrafts(pair) {
874
- const collected = [];
875
- const finished = finishDraft(pair, (patches) => {
876
- collected.push(...patches);
877
- });
878
- const docPatches = [];
879
- const sessionPatches = [];
880
- for (const patch of collected) {
881
- const [container, ...path] = patch.path;
882
- (container === "doc" ? docPatches : sessionPatches).push(toPatch(patch, path));
883
- }
884
- return {
885
- doc: finished.doc,
886
- session: finished.session,
887
- patches: {
888
- doc: docPatches,
889
- session: sessionPatches
890
- },
891
- roots: rootsOf(docPatches, sessionPatches)
892
- };
893
- }
894
- /**
895
- * Applies the patches of one commit to a document, the way a save seam stores what it was handed.
896
- * A whole-document patch carries the path `[]` and replaces the document. The input is left as it
897
- * is: the result is a new frozen document.
898
- *
899
- * @param document - The document the patches apply to.
900
- * @param patches - The patches of one commit, in order.
901
- * @returns The document after the patches.
902
- * @throws {Error} When a patch names a path the document does not have.
903
- * @example
904
- * ```ts
905
- * applyTo({ player: { coins: 0 } }, [{ op: "replace", path: ["player", "coins"], value: 4 }]);
906
- * // { player: { coins: 4 } }
907
- * ```
908
- */
909
- function applyTo(document, patches) {
910
- enablePatches();
911
- return applyPatches(document, patches);
912
- }
913
- /**
914
- * Drops the drafts without a result: the base trees stay as they are and the drafts are revoked.
915
- *
916
- * @param pair - Open drafts of one transaction.
917
- */
918
- function dropDrafts(pair) {
919
- finishDraft(pair);
920
- }
921
- //#endregion
922
- //#region src/plugins/model/store/providers/memory.ts
923
- /** Seed of a save built by `saveOf` when the caller does not pin one. */
924
- const defaultSeed = 1;
925
- /** The base a patch applies to when the provider was never handed a document. */
926
- const noDocument = {};
927
- /**
928
- * Creates an in-memory provider that keeps what it was committed and records every call.
929
- * It is the default when a game configures no `playerProvider`, and the double every test uses:
930
- * `provider.calls` is the whole persistence protocol of one run, in order. The document lives as
931
- * long as the provider does, so a second app over the same instance reads what the first one
932
- * wrote, and nothing survives the process.
933
- *
934
- * `load()` reads the fixture, or everything committed since; without either, the player is new.
935
- * `commitDurable()` resolves at once: there is no disk behind it.
936
- *
937
- * @param fixture - The save `load()` starts from. Omitted: a new player.
938
- * @param fixture.state - The saved document.
939
- * @param fixture.version - Schema version of the saved document.
940
- * @returns A provider that keeps its document and records its calls.
941
- * @example
942
- * ```ts
943
- * // A new player is saved at once. One roll reaches the provider at the next rest node.
944
- * const provider = memory();
945
- * const game = await createHeadless(createGame(provider));
946
- *
947
- * await game.walk([{ at: "home", intent: "roll" }]);
948
- * provider.calls.map(call => call.method); // ["load", "commit", "commit"]
949
- * ```
950
- */
951
- function memory(fixture) {
952
- const calls = [];
953
- const held = {
954
- document: fixture?.state,
955
- version: fixture?.version ?? 0
956
- };
957
- /**
958
- * Applies the patches of one commit to the held document.
959
- *
960
- * @param patches - Doc patches since the last commit.
961
- * @param version - Schema version this build writes.
962
- * @throws {Error} When a patch names a path the held document does not have.
963
- */
964
- const hold = (patches, version) => {
965
- held.document = applyTo(held.document ?? noDocument, patches);
966
- held.version = version;
967
- };
968
- return {
969
- calls,
970
- load: async () => {
971
- calls.push({ method: "load" });
972
- const document = held.document;
973
- if (document === void 0) return null;
974
- return {
975
- state: document,
976
- version: held.version
977
- };
978
- },
979
- commit: (patches, version) => {
980
- calls.push({
981
- method: "commit",
982
- patches,
983
- version
984
- });
985
- hold(patches, version);
986
- },
987
- commitDurable: async (patches, txId, version) => {
988
- calls.push({
989
- method: "commitDurable",
990
- patches,
991
- txId,
992
- version
993
- });
994
- hold(patches, version);
995
- },
996
- flush: async () => {
997
- calls.push({ method: "flush" });
998
- }
999
- };
1000
- }
1001
- /**
1002
- * Builds a save document from a player tree, with no rng streams drawn yet.
1003
- * Short fixtures in tests read as `saveOf({ coins: 5 })` instead of spelling out the rng branch.
1004
- *
1005
- * @param player - Player tree of the save.
1006
- * @param seed - Rng seed of the save.
1007
- * @returns The save document.
1008
- * @example
1009
- * ```ts
1010
- * // A returning player with 5 coins. The test starts from this save, not from `initialPlayer`.
1011
- * saveOf({ coins: 5 }, 42); // { player: { coins: 5 }, rng: { seed: 42, streams: {} } }
1012
- * const provider = memory({ state: saveOf({ coins: 5 }, 42), version: 1 });
1013
- * ```
1014
- */
1015
- function saveOf(player, seed = defaultSeed) {
1016
- return {
1017
- player,
1018
- rng: {
1019
- seed,
1020
- streams: {}
1021
- }
1022
- };
1023
- }
1024
- //#endregion
1025
738
  //#region src/plugins/model/store/state.ts
1026
739
  /** Seed of the trees that exist before `load()` ran. A save or a new player replaces it. */
1027
740
  const preloadSeed = 0;
@@ -34532,21 +34245,30 @@ function defineMotion(spec) {
34532
34245
  * | effects | maxPasses | 24, render passes per frame above which one dev warning fires per crossing |
34533
34246
  * | effects | phone | "auto", a coarse pointer and a short side of at most 820 CSS px |
34534
34247
  * | effects | blur | { quality: 2, phoneResolution: 0.5 }, what a Blur with quality 0 and resolution 0 resolves to; shallow merge: a game that sets `blur` gives both fields |
34535
- * | platform | provider | undefined, inert: no subscription, no haptic handler, `back()` answers "none" |
34248
+ * | platform | provider | undefined, inert: no subscription, no haptic handler, `back()` answers "none"; the engine page passes the system shell's provider |
34536
34249
  * | platform | keepAwake | false |
34537
34250
  *
34538
34251
  * Subpaths next to the root:
34539
34252
  *
34540
34253
  * | Subpath | What |
34541
34254
  * |---|---|
34255
+ * | `@moku-labs/game/app` | `defineGameApp`, the game as one data object with `headless()` and `screen()`; `startMoment`; the types of `index.ts` and `config.ts` (`GameConfig`) |
34256
+ * | `@moku-labs/game/app/page` | `startPage`, the page the generated `.moku/main.ts` calls: `?player=` scenarios, the system shell, the dev agents |
34257
+ * | `@moku-labs/game/app/system` | the system shell over the optional peer `@moku-labs/system`: `systemShell`, `fromSystem`, `storeSave`, `createSystemApp` |
34258
+ * | `@moku-labs/game/cli` | `runCli` of the bin `moku-game` and `preparePage` for the editor, node and bun only |
34542
34259
  * | `@moku-labs/game/testing` | headless play, repro runs, isolated feature tests (`isolate`, `stub`), the in-memory save, the fake clock |
34543
34260
  * | `@moku-labs/game/visual` | the visual tests, node and bun only |
34544
34261
  * | `@moku-labs/game/assets` | the build-time asset key scanner and the production packer (`packAssets`, `--pack <dir>`), node and bun only |
34545
34262
  * | `@moku-labs/game/inspect` | the editor's read door: `read`, `watch`, `defineSource`, the `sources` catalogue |
34546
34263
  * | `@moku-labs/game/control` | the editor's write door, dev builds only: `run`, `defineCommand`, the `commands` catalogue |
34264
+ * | `@moku-labs/game/hot` | the Bun plugin that hot swaps views; `moku-game dev` lists it in its bunfig |
34265
+ * | `@moku-labs/game/lint` | the oxlint JS plugin `moku-game` with the game lint rules |
34266
+ * | `@moku-labs/game/project` | the project index of a game's sources, node and bun only |
34547
34267
  * | `@moku-labs/game/jsx-runtime`, `/jsx-dev-runtime` | the JSX runtimes `jsxImportSource: "@moku-labs/game"` names |
34548
34268
  * | `@moku-labs/game/fonts/*` | the MSDF body font `font-body.fnt` + `.png` and its OFL licence; a game copies them into `features/ui/assets/` |
34269
+ * | bin `moku-game` | `dev`, `build`, `native <verb>`, `keys`, `pack`: serves, builds, packages and packs a game folder, bun only |
34549
34270
  * | bin `moku-game-assets` | the asset scanner CLI, bun only |
34271
+ * | bin `moku-game-index` | the project index CLI, bun only |
34550
34272
  *
34551
34273
  * @file The package root: the composed framework and its public exports.
34552
34274
  * @example
@@ -34641,4 +34363,4 @@ const screen = [
34641
34363
  uiPlugin
34642
34364
  ];
34643
34365
  //#endregion
34644
- export { sfx as $, types_exports$13 as A, defineFilter as At, defineStyle as B, flowPlugin as Bt, types_exports$6 as C, Alpha as Ct, types_exports$10 as D, Glow as Dt, types_exports$9 as E, Displacement as Et, resolve as F, AnimPlayer as Ft, external as G, modelPlugin as Gt, platformPlugin as H, slot as Ht, Box as I, Animation as It, mark as J, saveOf as Jt, frames as K, SaveUnreadableError as Kt, LocalWrite as L, Frames as Lt, types_exports$15 as M, scenesPlugin as Mt, types_exports$16 as N, assetsPlugin as Nt, types_exports$11 as O, Noise as Ot, uiPlugin as P, animPlugin as Pt, set as Q, popup as R, rendererPlugin as Rt, types_exports$5 as S, Emitter as St, types_exports$8 as T, ColorMatrix as Tt, HAPTIC_KINDS as U, to as Ut, textPlugin as V, exit as Vt, defineAnimation as W, type as Wt, play$1 as X, timePlugin as Xt, parallel as Y, lifecyclePlugin as Yt, sequence as Z, clockPlugin as Zt, types_exports as _, Touchable as _t, defineMotion as a, wait as at, types_exports$3 as b, i18nPlugin as bt, schedule as c, DropTarget as ct, tr as d, Pointer as dt, spawn as et, defineFeature as f, PointerOver as ft, load as g, Tappable as gt, defineBundles as h, Swipeable as ht, screen as i, use as it, types_exports$14 as j, audioPlugin as jt, types_exports$12 as k, Outline as kt, projection as l, Held as lt, music as m, Pressed as mt, createPlugin as n, stagger as nt, guide as o, inputPlugin as ot, defineEmitter as p, Pressable as pt, haptic as q, memory as qt, defineGame as r, tween as rt, hint as s, Draggable as st, createApp as t, spawned as tt, defineScene as u, Hovered as ut, types_exports$1 as v, Traceable as vt, types_exports$7 as w, Blur as wt, types_exports$4 as x, effectsPlugin as xt, types_exports$2 as y, Traced as yt, defineTokens as z, worldPlugin as zt };
34366
+ export { sfx as $, types_exports$13 as A, defineFilter as At, defineStyle as B, flowPlugin as Bt, types_exports$6 as C, Alpha as Ct, types_exports$10 as D, Glow as Dt, types_exports$9 as E, Displacement as Et, resolve as F, AnimPlayer as Ft, external as G, modelPlugin as Gt, platformPlugin as H, slot as Ht, Box as I, Animation as It, mark as J, timePlugin as Jt, frames as K, SaveUnreadableError as Kt, LocalWrite as L, Frames as Lt, types_exports$15 as M, scenesPlugin as Mt, types_exports$16 as N, assetsPlugin as Nt, types_exports$11 as O, Noise as Ot, uiPlugin as P, animPlugin as Pt, set as Q, popup as R, rendererPlugin as Rt, types_exports$5 as S, Emitter as St, types_exports$8 as T, ColorMatrix as Tt, HAPTIC_KINDS as U, to as Ut, textPlugin as V, exit as Vt, defineAnimation as W, type as Wt, play$1 as X, parallel as Y, clockPlugin as Yt, sequence as Z, types_exports as _, Touchable as _t, defineMotion as a, wait as at, types_exports$3 as b, i18nPlugin as bt, schedule as c, DropTarget as ct, tr as d, Pointer as dt, spawn as et, defineFeature as f, PointerOver as ft, load as g, Tappable as gt, defineBundles as h, Swipeable as ht, screen as i, use as it, types_exports$14 as j, audioPlugin as jt, types_exports$12 as k, Outline as kt, projection as l, Held as lt, music as m, Pressed as mt, createPlugin as n, stagger as nt, guide as o, inputPlugin as ot, defineEmitter as p, Pressable as pt, haptic as q, lifecyclePlugin as qt, defineGame as r, tween as rt, hint as s, Draggable as st, createApp as t, spawned as tt, defineScene as u, Hovered as ut, types_exports$1 as v, Traceable as vt, types_exports$7 as w, Blur as wt, types_exports$4 as x, effectsPlugin as xt, types_exports$2 as y, Traced as yt, defineTokens as z, worldPlugin as zt };
@@ -1,6 +1,7 @@
1
- import { $t as PlayerStateProvider, Et as AnyFlow, Jt as Json, Mt as NodeTable, en as ProviderCall, gn as FakeClock, mn as ClockSource, mt as FeaturePlugin, tn as SaveDoc } from "./types-B0v5VVa3.mjs";
2
- import { a as createHeadless, i as ReproResult, n as HeadlessGame, o as runRepro, r as Repro, s as stepFrames, t as HeadlessApp } from "./headless-SCQXJxQf.mjs";
3
- import { t as createApp } from "./index-BO9kZzY3.mjs";
1
+ import { Dt as AnyFlow, Ht as ClockSource, Nt as NodeTable, Wt as FakeClock, Xt as Json, ht as FeaturePlugin } from "./types-ZQLYXo5X.mjs";
2
+ import { t as createApp } from "./index-xxSxKJJW.mjs";
3
+ import { n as saveOf, t as memory } from "./memory-DwDhfFWK.mjs";
4
+ import { a as createHeadless, i as ReproResult, n as HeadlessGame, o as runRepro, r as Repro, s as stepFrames, t as HeadlessApp } from "./headless-G4nuZ-xz.mjs";
4
5
  import { AnyPluginInstance } from "@moku-labs/core";
5
6
 
6
7
  //#region src/plugins/clock/fake.d.ts
@@ -25,53 +26,6 @@ import { AnyPluginInstance } from "@moku-labs/core";
25
26
  */
26
27
  declare function fakeClock(start?: number): FakeClock;
27
28
  //#endregion
28
- //#region src/plugins/model/store/providers/memory.d.ts
29
- /**
30
- * Creates an in-memory provider that keeps what it was committed and records every call.
31
- * It is the default when a game configures no `playerProvider`, and the double every test uses:
32
- * `provider.calls` is the whole persistence protocol of one run, in order. The document lives as
33
- * long as the provider does, so a second app over the same instance reads what the first one
34
- * wrote, and nothing survives the process.
35
- *
36
- * `load()` reads the fixture, or everything committed since; without either, the player is new.
37
- * `commitDurable()` resolves at once: there is no disk behind it.
38
- *
39
- * @param fixture - The save `load()` starts from. Omitted: a new player.
40
- * @param fixture.state - The saved document.
41
- * @param fixture.version - Schema version of the saved document.
42
- * @returns A provider that keeps its document and records its calls.
43
- * @example
44
- * ```ts
45
- * // A new player is saved at once. One roll reaches the provider at the next rest node.
46
- * const provider = memory();
47
- * const game = await createHeadless(createGame(provider));
48
- *
49
- * await game.walk([{ at: "home", intent: "roll" }]);
50
- * provider.calls.map(call => call.method); // ["load", "commit", "commit"]
51
- * ```
52
- */
53
- declare function memory(fixture?: {
54
- state: SaveDoc;
55
- version: number;
56
- }): PlayerStateProvider & {
57
- calls: ProviderCall[];
58
- };
59
- /**
60
- * Builds a save document from a player tree, with no rng streams drawn yet.
61
- * Short fixtures in tests read as `saveOf({ coins: 5 })` instead of spelling out the rng branch.
62
- *
63
- * @param player - Player tree of the save.
64
- * @param seed - Rng seed of the save.
65
- * @returns The save document.
66
- * @example
67
- * ```ts
68
- * // A returning player with 5 coins. The test starts from this save, not from `initialPlayer`.
69
- * saveOf({ coins: 5 }, 42); // { player: { coins: 5 }, rng: { seed: 42, streams: {} } }
70
- * const provider = memory({ state: saveOf({ coins: 5 }, 42), version: 1 });
71
- * ```
72
- */
73
- declare function saveOf(player: Json, seed?: number): SaveDoc;
74
- //#endregion
75
29
  //#region src/testing/isolate.d.ts
76
30
  /**
77
31
  * A stub for one node or sub-flow of the isolated flow: the outcome it ends with, and its payload.
package/dist/testing.mjs CHANGED
@@ -1,91 +1,7 @@
1
- import { Jt as saveOf, Vt as exit, Wt as type, qt as memory, t as createApp } from "./src-536arXjV.mjs";
1
+ import { Vt as exit, Wt as type, t as createApp } from "./src-DSl1eNB1.mjs";
2
+ import { n as saveOf, t as memory } from "./memory-CWlqhS7l.mjs";
3
+ import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
2
4
  import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-BsNdJs9W.mjs";
3
- //#region src/plugins/clock/fake.ts
4
- /**
5
- * Removes and returns the timer that is due first, up to and including `until`.
6
- * Timers due at the same moment come out in the order they were scheduled.
7
- *
8
- * @param state - Innards of the fake clock.
9
- * @param until - Latest moment that counts as due.
10
- * @returns The timer to fire, or `undefined` when nothing is due.
11
- */
12
- function takeDue(state, until) {
13
- let earliest;
14
- for (const timer of state.timers) {
15
- if (timer.at > until) continue;
16
- if (earliest === void 0 || timer.at < earliest.at) earliest = timer;
17
- }
18
- if (earliest === void 0) return void 0;
19
- const due = earliest;
20
- state.timers = state.timers.filter((timer) => timer !== due);
21
- return due;
22
- }
23
- /**
24
- * Moves the clock to `until`, firing every timer that falls due on the way, in due order.
25
- * A timer scheduled inside a callback fires in the same run when it is due before `until`.
26
- *
27
- * @param state - Innards of the fake clock.
28
- * @param until - Moment to stop at.
29
- */
30
- function runDue(state, until) {
31
- let due = takeDue(state, until);
32
- while (due !== void 0) {
33
- state.now = Math.max(state.now, due.at);
34
- due.callback();
35
- due = takeDue(state, until);
36
- }
37
- state.now = Math.max(state.now, until);
38
- }
39
- /**
40
- * Creates a fake source for tests. Timers fire synchronously inside `advance`, in due order. A
41
- * negative delay counts as zero and an unknown handle is ignored.
42
- *
43
- * @param start - Starting moment in epoch milliseconds. Defaults to 0.
44
- * @returns A clock source with the test-only controls `advance` and `set`.
45
- * @example
46
- * ```ts
47
- * // An energy point refills 60 s after it was spent. The test moves the clock, not the minute.
48
- * const clock = fakeClock(1000);
49
- * const app = createApp({ pluginConfigs: { clock: { source: clock } } });
50
- * const seen: number[] = [];
51
- *
52
- * app.clock.onElapsed(({ now }) => seen.push(now));
53
- * app.clock.scheduleAt(61_000);
54
- * clock.advance(60_000); // the timer fires inside advance, nothing waits
55
- * seen; // [61000]
56
- * ```
57
- */
58
- function fakeClock(start = 0) {
59
- const state = {
60
- now: start,
61
- nextId: 1,
62
- timers: []
63
- };
64
- return {
65
- now: () => state.now,
66
- setTimer: (callback, delayMs) => {
67
- const id = state.nextId;
68
- state.nextId += 1;
69
- state.timers.push({
70
- id,
71
- at: state.now + Math.max(0, delayMs),
72
- callback
73
- });
74
- return id;
75
- },
76
- clearTimer: (handle) => {
77
- if (typeof handle !== "number") return;
78
- state.timers = state.timers.filter((timer) => timer.id !== handle);
79
- },
80
- advance: (ms) => {
81
- runDue(state, state.now + Math.max(0, ms));
82
- },
83
- set: (moment) => {
84
- state.now = moment;
85
- }
86
- };
87
- }
88
- //#endregion
89
5
  //#region src/testing/isolate.ts
90
6
  const noPayload = null;
91
7
  /** Id of the harness main flow. */