@moku-labs/game 0.14.12 → 0.14.13

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 (56) hide show
  1. package/README.md +13 -12
  2. package/dist/app/page.d.mts +8 -3
  3. package/dist/app/page.mjs +57 -12
  4. package/dist/app/system.d.mts +5 -3
  5. package/dist/app/system.mjs +2 -0
  6. package/dist/app.d.mts +15 -7
  7. package/dist/app.mjs +131 -27
  8. package/dist/{assets-BrKSg1O6.mjs → assets-CEMfBogh.mjs} +471 -120
  9. package/dist/assets.d.mts +30 -13
  10. package/dist/assets.mjs +1 -1
  11. package/dist/cli.d.mts +105 -8
  12. package/dist/cli.mjs +1036 -128
  13. package/dist/{commands-BaCx2B9j.d.mts → commands-DAETmK86.d.mts} +43 -7
  14. package/dist/{config-CdARrrhU.mjs → config-B87aFTW-.mjs} +25 -4
  15. package/dist/control.d.mts +130 -17
  16. package/dist/control.mjs +4 -4
  17. package/dist/{define-Ce8SVEN-.d.mts → define-BASd9ZUh.d.mts} +32 -4
  18. package/dist/dev-DbHgx-R-.mjs +89 -0
  19. package/dist/{fake-MpzwZhIZ.mjs → fake-6mazmHK3.mjs} +20 -2
  20. package/dist/features-DowEilZm.mjs +266 -0
  21. package/dist/{headless-CMHNsKjW.d.mts → headless-cFveciuY.d.mts} +1 -1
  22. package/dist/hot.d.mts +4 -2
  23. package/dist/hot.mjs +7 -4
  24. package/dist/{index-CLQ8NOTw.d.mts → index-DedbED3T.d.mts} +317 -69
  25. package/dist/index.d.mts +5 -6
  26. package/dist/index.mjs +3 -3
  27. package/dist/inspect.d.mts +12 -7
  28. package/dist/inspect.mjs +2 -2
  29. package/dist/jsx-dev-runtime.d.mts +1 -1
  30. package/dist/jsx-runtime.d.mts +1 -1
  31. package/dist/lint.d.mts +8 -3
  32. package/dist/lint.mjs +432 -20
  33. package/dist/project.d.mts +15 -1
  34. package/dist/project.mjs +1 -1
  35. package/dist/{run-Bf2hKyjZ.mjs → run-BbipFRc6.mjs} +250 -51
  36. package/dist/{runtime-BCnKn0xf.d.mts → runtime-DoSlRx8X.d.mts} +1 -1
  37. package/dist/{session-DgukhR_7.mjs → session-CeKgO2hy.mjs} +30 -2
  38. package/dist/{sources-Duzj6lhV.mjs → sources-Cdvb0rOS.mjs} +33 -6
  39. package/dist/{src-CtC8w3_z.mjs → src-BEbJ_sSx.mjs} +35536 -17789
  40. package/dist/testing.d.mts +23 -13
  41. package/dist/testing.mjs +10 -6
  42. package/dist/{types-DOlpeuGx.d.mts → types-7GXcXxxv.d.mts} +174 -242
  43. package/dist/{types-BjTtGSFb.d.mts → types-BGcda5Le.d.mts} +4459 -732
  44. package/dist/{types-gisvSHoC.d.mts → types-C73hbmxi.d.mts} +129 -17
  45. package/dist/{types-CAPv9l29.d.mts → types-DngFQJro.d.mts} +43 -5
  46. package/dist/{types-Y_rCuXtj.d.mts → types-GHE4J5Uf.d.mts} +1025 -191
  47. package/dist/{visual-dMW8iqAE.mjs → visual-2m4wJL_z.mjs} +111 -7
  48. package/dist/visual-_XhoGeIC.d.mts +345 -0
  49. package/dist/visual.d.mts +1 -332
  50. package/dist/visual.mjs +130 -20
  51. package/dist/{watch-CWI_on4T.mjs → watch-BEdrp80i.mjs} +149 -30
  52. package/llms.txt +99 -48
  53. package/package.json +8 -6
  54. package/dist/dev-Cc50Dk7H.mjs +0 -47
  55. package/dist/memory-pUQ7YZWC.d.mts +0 -50
  56. package/dist/types-BX4Ge_j5.d.mts +0 -656
@@ -1,7 +1,7 @@
1
- import { Bt as NodeFx, Dt as AnyFlow, Gt as FakeClock, Lt as Descriptor, Nt as NodeTable, Ut as ClockSource, Zt as Json, ht as FeaturePlugin, zt as Hint } from "./types-BjTtGSFb.mjs";
2
- import { t as createApp } from "./index-CLQ8NOTw.mjs";
3
- import { n as saveOf, t as memory } from "./memory-pUQ7YZWC.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-CMHNsKjW.mjs";
1
+ import { $n as NodeFx, In as FeaturePlugin, Jn as Descriptor, Qn as Hint, Rn as AnyFlow, Wn as NodeTable, ir as FakeClock, nr as ClockSource, ur as Json } from "./types-BGcda5Le.mjs";
2
+ import { t as createApp } from "./index-DedbED3T.mjs";
3
+ import { b as saveOf, v as WithGameState, y as memory } from "./types-C73hbmxi.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-cFveciuY.mjs";
5
5
  import { AnyPluginInstance } from "@moku-labs/core";
6
6
 
7
7
  //#region src/plugins/clock/fake.d.ts
@@ -160,12 +160,12 @@ type StubsOf<Nodes extends NodeTable> = { readonly [Name in keyof Nodes & string
160
160
  *
161
161
  * @example
162
162
  * ```ts
163
- * const options: IsolateOptions<typeof boardFlow.nodes> = {
163
+ * const options: IsolateOptions<typeof boardFlow.nodes, Player> = {
164
164
  * flow: boardFlow, shared: sharedLayer, stubs: { settings: stub("closed") }, player: fresh
165
165
  * };
166
166
  * ```
167
167
  */
168
- type IsolateOptions<Nodes extends NodeTable> = {
168
+ type IsolateOptions<Nodes extends NodeTable, Player extends Json = Json, Session extends Json = Json> = {
169
169
  /** The feature's flow. It becomes the one node of the harness main flow, named by `as`. */flow: AnyFlow & {
170
170
  readonly nodes: Nodes;
171
171
  };
@@ -182,9 +182,9 @@ type IsolateOptions<Nodes extends NodeTable> = {
182
182
  as?: string; /** The shared layer, composed as `logicOnly` before the feature. */
183
183
  shared?: FeaturePlugin; /** Node name of `flow` to the stub that replaces it. A node not listed runs for real. */
184
184
  stubs?: StubsOf<Nodes>; /** More plugins the feature needs headless, for example a feature-own plugin. */
185
- plugins?: readonly AnyPluginInstance[]; /** The player a new save starts from. */
186
- player: Json; /** The session at start. `{}` by default. */
187
- session?: Json; /** The rng seed. `1` by default. */
185
+ plugins?: readonly AnyPluginInstance[]; /** The player a new save starts from. Its type types `model.store.snapshot().player`. */
186
+ player: Player; /** The session at start. `{}` by default. Its type types `model.store.snapshot().session`. */
187
+ session?: Session; /** The rng seed. `1` by default. */
188
188
  seed?: number;
189
189
  };
190
190
  /**
@@ -206,6 +206,12 @@ type IsolateSeams = {
206
206
  * plugins on it.
207
207
  */
208
208
  type IsolatedApp = ReturnType<typeof createApp>;
209
+ /**
210
+ * The app of an isolated feature with `model.store.snapshot()` typed by the player and session
211
+ * of the `isolate` call, as `WithGameState` types `game.headless()`. A call whose player and
212
+ * session are `Model.Json` reads a `Model.Json` snapshot, as before. Only the type.
213
+ */
214
+ type IsolatedAppOf<Player, Session> = WithGameState<IsolatedApp, Player, Session>;
209
215
  /**
210
216
  * A stub: the replaced node or sub-flow ends at once with this outcome. Written as a sub-flow of
211
217
  * one transit node, so a route can still substitute it for one visit:
@@ -223,14 +229,16 @@ type IsolatedApp = ReturnType<typeof createApp>;
223
229
  declare function stub<const Name extends string>(outcome: Name, payload?: Json): Stub<Name>;
224
230
  /**
225
231
  * Composes one feature without the rest of the game: the shared layer and the feature as
226
- * `logicOnly`, the feature's flow inside a harness main flow `isolated`, and every stubbed node
232
+ * `logicOnly` (a parent feature is composed with its sub-features), the feature's flow inside a
233
+ * harness main flow `isolated`, and every stubbed node
227
234
  * replaced by a sub-flow that ends with the stub's outcome. Every exit of the flow lands on the
228
235
  * rest node `exited`, whose intent `again` enters the flow once more. Paths read as in the game:
229
236
  * the harness holds the flow under `options.as`, its id by default. A node that is not stubbed
230
237
  * runs for real, even when it belongs to a feature that is not composed.
231
238
  *
232
239
  * @param feature - The feature under test.
233
- * @param options - Its flow, the shared layer, the stubs, the starting state.
240
+ * @param options - Its flow, the shared layer, the stubs, the starting state. The types of
241
+ * `player` and `session` type the app's `model.store.snapshot()`.
234
242
  * @returns A factory of apps, not started; pass one to `createHeadless`.
235
243
  * @throws {Error} For a stub key that is not a node of the flow, or an outcome the node does not declare.
236
244
  * @example
@@ -239,11 +247,13 @@ declare function stub<const Name extends string>(outcome: Name, payload?: Json):
239
247
  * const homeOnly = isolate(homeFeature, {
240
248
  * flow: mainFlow, stubs: { info: stub("ok") }, player: startingPlayer, session: startingSession
241
249
  * });
242
- * const game = await createHeadless(homeOnly());
250
+ * const app = homeOnly();
251
+ * const game = await createHeadless(app);
243
252
  * const state = await game.walk([{ at: "main/home", intent: "info" }]);
244
253
  * state.path; // "main/home"
254
+ * app.model.store.snapshot().player.count; // 0, typed number: startingPlayer types the snapshot
245
255
  * ```
246
256
  */
247
- declare function isolate<Nodes extends NodeTable>(feature: FeaturePlugin, options: IsolateOptions<Nodes>): (seams?: IsolateSeams) => IsolatedApp;
257
+ declare function isolate<Nodes extends NodeTable, Player extends Json = Json, Session extends Json = Json>(feature: FeaturePlugin, options: IsolateOptions<Nodes, Player, Session>): (seams?: IsolateSeams) => IsolatedAppOf<Player, Session>;
248
258
  //#endregion
249
259
  export { type FakeFx, type FakeFxOptions, type HeadlessApp, type HeadlessGame, type IsolateOptions, type IsolateSeams, type Repro, type ReproResult, type Stub, type StubsOf, createHeadless, fakeClock, fakeFx, isolate, memory, runRepro, saveOf, stepFrames, stub };
package/dist/testing.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { Ut as refuseStart, Wt as exit, qt as type, t as createApp } from "./src-CtC8w3_z.mjs";
1
+ import { $t as refuseStart, en as exit, p as flattenFeatures, rn as type, t as createApp } from "./src-BEbJ_sSx.mjs";
2
2
  import { n as saveOf, t as memory } from "./memory-CWlqhS7l.mjs";
3
- import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
3
+ import { t as fakeClock } from "./fake-6mazmHK3.mjs";
4
4
  import { i as stepFrames, r as runRepro, t as createHeadless } from "./headless-BA6ffzqD.mjs";
5
5
  //#region src/testing/fake-fx.ts
6
6
  /** The node path a refused `fx.start` names when the test gives none. */
@@ -235,14 +235,16 @@ function harnessOf(flow, name = flow.id) {
235
235
  }
236
236
  /**
237
237
  * Composes one feature without the rest of the game: the shared layer and the feature as
238
- * `logicOnly`, the feature's flow inside a harness main flow `isolated`, and every stubbed node
238
+ * `logicOnly` (a parent feature is composed with its sub-features), the feature's flow inside a
239
+ * harness main flow `isolated`, and every stubbed node
239
240
  * replaced by a sub-flow that ends with the stub's outcome. Every exit of the flow lands on the
240
241
  * rest node `exited`, whose intent `again` enters the flow once more. Paths read as in the game:
241
242
  * the harness holds the flow under `options.as`, its id by default. A node that is not stubbed
242
243
  * runs for real, even when it belongs to a feature that is not composed.
243
244
  *
244
245
  * @param feature - The feature under test.
245
- * @param options - Its flow, the shared layer, the stubs, the starting state.
246
+ * @param options - Its flow, the shared layer, the stubs, the starting state. The types of
247
+ * `player` and `session` type the app's `model.store.snapshot()`.
246
248
  * @returns A factory of apps, not started; pass one to `createHeadless`.
247
249
  * @throws {Error} For a stub key that is not a node of the flow, or an outcome the node does not declare.
248
250
  * @example
@@ -251,16 +253,18 @@ function harnessOf(flow, name = flow.id) {
251
253
  * const homeOnly = isolate(homeFeature, {
252
254
  * flow: mainFlow, stubs: { info: stub("ok") }, player: startingPlayer, session: startingSession
253
255
  * });
254
- * const game = await createHeadless(homeOnly());
256
+ * const app = homeOnly();
257
+ * const game = await createHeadless(app);
255
258
  * const state = await game.walk([{ at: "main/home", intent: "info" }]);
256
259
  * state.path; // "main/home"
260
+ * app.model.store.snapshot().player.count; // 0, typed number: startingPlayer types the snapshot
257
261
  * ```
258
262
  */
259
263
  function isolate(feature, options) {
260
264
  const mainFlow = harnessOf(withStubs(options.flow, options.stubs ?? {}), options.as);
261
265
  const plugins = [
262
266
  ...options.shared === void 0 ? [] : [options.shared.logicOnly],
263
- feature.logicOnly,
267
+ ...flattenFeatures([feature.logicOnly]),
264
268
  ...options.plugins ?? []
265
269
  ];
266
270
  return (seams = {}) => createApp({