lanka 1.2.0 → 1.3.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 (60) hide show
  1. package/README.md +3 -1
  2. package/dist/{ALankaGateway-CkW1LbKE.d.ts → ALankaGateway-BrVPaZN5.d.ts} +1 -1
  3. package/dist/ILankaFieldError-D5931-vT.d.ts +34 -0
  4. package/dist/{ILankaScenarioMetadata-GoWWNEQL.d.ts → ILankaScenarioMetadata-Dj4GCqmX.d.ts} +1 -1
  5. package/dist/{ILankaScenarioVM-DUsI-fSc.d.ts → ILankaScenarioVM-DpKFL3iE.d.ts} +5 -4
  6. package/dist/{LankaError-xpI-qj35.d.ts → LankaError-D6RWNyLM.d.ts} +18 -0
  7. package/dist/{LankaScenarioLocator-D86TIwiu.d.ts → LankaScenarioLocator-CAENLhDO.d.ts} +3 -3
  8. package/dist/_extend/index.d.ts +6 -5
  9. package/dist/_internal/index.d.ts +61 -8
  10. package/dist/_internal/index.js +25 -0
  11. package/dist/_internal/index.js.map +1 -1
  12. package/dist/{activeRuntime-B336NU5I.d.ts → activeRuntime-BYd2D6Lx.d.ts} +2 -2
  13. package/dist/bootstrap/index.d.ts +9 -8
  14. package/dist/bootstrap/index.js +2 -2
  15. package/dist/cache/index.d.ts +99 -0
  16. package/dist/cache/index.js +1 -0
  17. package/dist/cache/index.js.map +1 -0
  18. package/dist/{chunk-UGXSGQPW.js → chunk-B7EYIAW7.js} +39 -3
  19. package/dist/chunk-B7EYIAW7.js.map +1 -0
  20. package/dist/chunk-CRIRTOLB.js +27 -0
  21. package/dist/chunk-CRIRTOLB.js.map +1 -0
  22. package/dist/{chunk-Q7QESSYF.js → chunk-G32H73QY.js} +10 -1
  23. package/dist/chunk-G32H73QY.js.map +1 -0
  24. package/dist/chunk-HVSQOMRE.js +69 -0
  25. package/dist/chunk-HVSQOMRE.js.map +1 -0
  26. package/dist/{chunk-73IVH3C6.js → chunk-NDCJBO47.js} +2 -2
  27. package/dist/{chunk-G3I7QIZR.js → chunk-UBGXDTXC.js} +14 -5
  28. package/dist/chunk-UBGXDTXC.js.map +1 -0
  29. package/dist/{createLanka-DI1CSy2Q.d.ts → createLanka-NrlvN-WQ.d.ts} +1 -1
  30. package/dist/errors/index.d.ts +22 -3
  31. package/dist/errors/index.js +8 -3
  32. package/dist/errors/index.js.map +1 -1
  33. package/dist/gateway/index.d.ts +4 -3
  34. package/dist/gateway/index.js +6 -5
  35. package/dist/gateway/index.js.map +1 -1
  36. package/dist/index.d.ts +9 -8
  37. package/dist/index.js +3 -3
  38. package/dist/{lankaStandardValidator-CL-r-zEV.d.ts → lankaStandardValidator-BUFnysK0.d.ts} +10 -0
  39. package/dist/locator/index.d.ts +3 -2
  40. package/dist/scenario/index.d.ts +56 -6
  41. package/dist/scenario/index.js +1 -1
  42. package/dist/storage/index.d.ts +120 -0
  43. package/dist/storage/index.js +1 -0
  44. package/dist/storage/index.js.map +1 -0
  45. package/dist/stream/index.d.ts +8 -7
  46. package/dist/validation/index.d.ts +7 -4
  47. package/dist/validation/index.js +5 -3
  48. package/dist/viewmodel/index.d.ts +51 -5
  49. package/dist/viewmodel/index.js +75 -47
  50. package/dist/viewmodel/index.js.map +1 -1
  51. package/package.json +11 -3
  52. package/skills/lanka-core/SKILL.md +59 -1
  53. package/skills/lanka-core/reference.md +312 -6
  54. package/skills/lanka-packages/SKILL.md +1 -1
  55. package/dist/chunk-G3I7QIZR.js.map +0 -1
  56. package/dist/chunk-GV5DUYST.js +0 -64
  57. package/dist/chunk-GV5DUYST.js.map +0 -1
  58. package/dist/chunk-Q7QESSYF.js.map +0 -1
  59. package/dist/chunk-UGXSGQPW.js.map +0 -1
  60. /package/dist/{chunk-73IVH3C6.js.map → chunk-NDCJBO47.js.map} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { StoreApi, StateCreator, UseBoundStore } from 'zustand';
2
- import { a as ILankaScenario, T as TLankaReplayRequest, I as ILankaScenarioVM } from '../ILankaScenarioVM-DUsI-fSc.js';
2
+ import { a as ILankaScenario, T as TLankaReplayRequest, I as ILankaScenarioVM } from '../ILankaScenarioVM-DpKFL3iE.js';
3
3
  import { A as ALankaSharedStore } from '../ALankaSharedStore-B7uepuuk.js';
4
4
  import { StoreApi as StoreApi$1 } from 'zustand/vanilla';
5
5
 
@@ -257,6 +257,19 @@ declare function createLazySharedStoreLankaVM<StoreState extends object, Actions
257
257
  declare function createLazySharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Record<string, never>>): TLazySharedStoreReturn<StoreState, Actions, Store, TGateways, Record<string, never>>;
258
258
  declare function createLazySharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object, Services extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Services>): TLazySharedStoreReturn<StoreState, Actions, Store, TGateways, Services>;
259
259
 
260
+ /**
261
+ * The lifecycle moments a ViewModel took, as the scenario binder receives them.
262
+ *
263
+ * A hook is present only when the ViewModel DECLARED it — overrode the method,
264
+ * or passed it in config. Bootstrap registers a ViewModel for the sake of these
265
+ * calls, so "declared" is what decides registration; a default no-op must not
266
+ * count, or every ViewModel would sit in the scenario registry for nothing.
267
+ */
268
+ interface ILankaVMLifecycleHooks {
269
+ onInit?: () => void;
270
+ onReset?: () => void;
271
+ }
272
+
260
273
  /**
261
274
  * What every ViewModel is given, and the two moments it is told about.
262
275
  *
@@ -281,10 +294,36 @@ declare abstract class ALankaVMEnvironment<TGateways extends object = Record<str
281
294
  protected createGateways(): TGateways;
282
295
  /** Non-gateway collaborators, built once per ViewModel. */
283
296
  protected createServices(): Services;
284
- /** Runs after the scenarios are bound. */
297
+ /**
298
+ * Runs once the scenarios are bound: inside `startLanka()` for a ViewModel built
299
+ * at module level, inside `build()` for one built after bootstrap — in both
300
+ * cases before any screen has read the hook the build returns.
301
+ */
285
302
  protected onInit(): void;
286
- /** Runs when the screen goes away, before the scenarios are unbound. */
303
+ /**
304
+ * Runs when the ViewModel is released — the framework instance disposed, or a
305
+ * lazy ViewModel's `dispose()` — after its scenario subscriptions are gone.
306
+ */
287
307
  protected onReset(): void;
308
+ /**
309
+ * The two moments above as the scenario binder receives them: present only
310
+ * where this ViewModel took them.
311
+ *
312
+ * Framework plumbing, not an extension point — a ViewModel overrides `onInit`
313
+ * and `onReset`, never this. Protected because the three bases call it, and
314
+ * named after `toStyleContext` for the same reason: a derived view of the
315
+ * protected surface, assembled by the framework.
316
+ *
317
+ * Why "took them" decides anything: `onInit` runs inside `initializeScenario`,
318
+ * which bootstrap alone calls, on the ViewModels registered with it.
319
+ * Registration used to follow scenario bindings only, so a ViewModel that
320
+ * overrode `onInit` and bound nothing was never initialised — silently. Now a
321
+ * declared hook registers the ViewModel too, and a default no-op must not
322
+ * count, or every ViewModel would sit in the scenario registry for nothing.
323
+ * The functional bridges declare theirs as own properties over these methods,
324
+ * which is what this comparison sees.
325
+ */
326
+ protected toLifecycleHooks(): ILankaVMLifecycleHooks;
288
327
  }
289
328
 
290
329
  /**
@@ -300,7 +339,9 @@ declare abstract class ALankaVMEnvironment<TGateways extends object = Record<str
300
339
  * value or a thunk, the class supplies by overriding a method of the same name —
301
340
  * `states`, `scenarioHandlers`, `enhancers`, `onInit`, `onReset` — with the two
302
341
  * dependency suppliers named `createGateways` and `createServices`, because
303
- * `gateways` and `services` already name what they answer.
342
+ * `gateways` and `services` already name what they answer. `toLifecycleHooks`
343
+ * is protected too and is not one of these: it is how the framework reads the
344
+ * two hooks, and a ViewModel overrides the hooks, never it.
304
345
  *
305
346
  * ```ts
306
347
  * class TodoVM extends ALankaVM<ITodoState, ITodoActions, ITodoGateways> {
@@ -389,6 +430,9 @@ declare abstract class ALankaVM<State extends object, Actions extends object, TG
389
430
  * or a thunk, the class supplies by overriding a method of the same name, with
390
431
  * the two dependency suppliers named `createGateways` and `createServices`
391
432
  * because `gateways` and `services` already name what they answer.
433
+ * `toLifecycleHooks` is protected too and is not one of these: it is how the
434
+ * framework reads `onInit` and `onReset`, and a ViewModel overrides those,
435
+ * never it.
392
436
  *
393
437
  * ```ts
394
438
  * class SessionVM extends ALankaStatelessVM<ISessionActions, ISessionGateways> {
@@ -469,7 +513,9 @@ declare abstract class ALankaStatelessVM<Actions extends object, TGateways exten
469
513
  * implementation: the store, the tracked hook and the two memoised state
470
514
  * references are the factory's, and duplicating them here would be the second
471
515
  * implementation the parity canon exists to prevent. What it gives a class-style
472
- * consumer is the same protected surface under the same names.
516
+ * consumer is the same protected surface under the same names — plus
517
+ * `toLifecycleHooks`, the framework's reading of `onInit`/`onReset`, which is
518
+ * not an extension point.
473
519
  *
474
520
  * Canon: `skills/parity/SKILL.md`.
475
521
  */
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  lankaScenarioBootstrap
4
- } from "../chunk-UGXSGQPW.js";
4
+ } from "../chunk-B7EYIAW7.js";
5
5
  import "../chunk-O5ROO7QF.js";
6
6
  import {
7
7
  lankaLogger
@@ -12,7 +12,7 @@ import {
12
12
  import "../chunk-BGVDPDX4.js";
13
13
 
14
14
  // src/viewmodel/_abstractions/lanka-vm-environment/ALankaVMEnvironment.ts
15
- var ALankaVMEnvironment = class {
15
+ var ALankaVMEnvironment = class _ALankaVMEnvironment {
16
16
  /** What `createGateways` answered: the data layer, kept apart from services. */
17
17
  gateways;
18
18
  /** What `createServices` answered: everything that is not a gateway. */
@@ -25,12 +25,44 @@ var ALankaVMEnvironment = class {
25
25
  createServices() {
26
26
  return {};
27
27
  }
28
- /** Runs after the scenarios are bound. */
28
+ /**
29
+ * Runs once the scenarios are bound: inside `startLanka()` for a ViewModel built
30
+ * at module level, inside `build()` for one built after bootstrap — in both
31
+ * cases before any screen has read the hook the build returns.
32
+ */
29
33
  onInit() {
30
34
  }
31
- /** Runs when the screen goes away, before the scenarios are unbound. */
35
+ /**
36
+ * Runs when the ViewModel is released — the framework instance disposed, or a
37
+ * lazy ViewModel's `dispose()` — after its scenario subscriptions are gone.
38
+ */
32
39
  onReset() {
33
40
  }
41
+ /**
42
+ * The two moments above as the scenario binder receives them: present only
43
+ * where this ViewModel took them.
44
+ *
45
+ * Framework plumbing, not an extension point — a ViewModel overrides `onInit`
46
+ * and `onReset`, never this. Protected because the three bases call it, and
47
+ * named after `toStyleContext` for the same reason: a derived view of the
48
+ * protected surface, assembled by the framework.
49
+ *
50
+ * Why "took them" decides anything: `onInit` runs inside `initializeScenario`,
51
+ * which bootstrap alone calls, on the ViewModels registered with it.
52
+ * Registration used to follow scenario bindings only, so a ViewModel that
53
+ * overrode `onInit` and bound nothing was never initialised — silently. Now a
54
+ * declared hook registers the ViewModel too, and a default no-op must not
55
+ * count, or every ViewModel would sit in the scenario registry for nothing.
56
+ * The functional bridges declare theirs as own properties over these methods,
57
+ * which is what this comparison sees.
58
+ */
59
+ toLifecycleHooks() {
60
+ const defaults = _ALankaVMEnvironment.prototype;
61
+ const hooks = {};
62
+ if (this.onInit !== defaults.onInit) hooks.onInit = () => this.onInit();
63
+ if (this.onReset !== defaults.onReset) hooks.onReset = () => this.onReset();
64
+ return hooks;
65
+ }
34
66
  };
35
67
 
36
68
  // src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
@@ -106,10 +138,12 @@ var createLankaBlindSpotTrap = (viewModelName, isArmed) => {
106
138
 
107
139
  // src/viewmodel/_internal/create-lanka-scenario-binder/createLankaScenarioBinder.ts
108
140
  var readBindings = (declared) => typeof declared === "function" ? declared() : declared ?? [];
141
+ var needsBootstrap = (config) => typeof config.bindings === "function" || config.bindings !== void 0 && config.bindings.length > 0 || config.onInit !== void 0 || config.onReset !== void 0;
109
142
  var createLankaScenarioBinder = (config) => {
110
143
  const subscriptions = /* @__PURE__ */ new Map();
111
144
  let isInitialized = false;
112
145
  return {
146
+ needsBootstrap: needsBootstrap(config),
113
147
  get isInitialized() {
114
148
  return isInitialized;
115
149
  },
@@ -259,25 +293,20 @@ var ALankaVM = class extends ALankaVMEnvironment {
259
293
  this.name,
260
294
  getLankaFlags().isDevelopment === true
261
295
  );
262
- const bindings = this.scenarioHandlers();
263
- const hasBindings = typeof bindings === "function" || bindings.length > 0;
296
+ const hooks = this.toLifecycleHooks();
297
+ const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
298
+ name: this.name,
299
+ bindings: this.scenarioHandlers(),
300
+ context: () => this.toStyleContext(),
301
+ onInit: hooks.onInit,
302
+ onReset: hooks.onReset
303
+ });
264
304
  const stateCreator = (set, get) => {
265
305
  this.set = set;
266
306
  this.get = blindSpot.observeGet(get);
267
307
  this.gateways = this.createGateways();
268
308
  this.services = this.createServices();
269
309
  const actions = blindSpot.observeActions(this.createActions());
270
- const { initializeScenario, resetScenario } = createLankaScenarioBinder({
271
- name: this.name,
272
- bindings,
273
- context: () => this.toStyleContext(),
274
- onInit: () => {
275
- this.onInit();
276
- },
277
- onReset: () => {
278
- this.onReset();
279
- }
280
- });
281
310
  return {
282
311
  ...this.states(),
283
312
  ...actions,
@@ -291,7 +320,7 @@ var ALankaVM = class extends ALankaVMEnvironment {
291
320
  );
292
321
  const store = create()(enhancedCreator);
293
322
  const registerScenarioViewModel = (viewModel) => {
294
- if (hasBindings) {
323
+ if (needsBootstrap2) {
295
324
  lankaScenarioBootstrap.registerViewModel(viewModel, this.name);
296
325
  }
297
326
  };
@@ -344,11 +373,16 @@ function createLankaVM(config) {
344
373
  createActions() {
345
374
  return config.createActions(this.toStyleContext());
346
375
  }
347
- onInit() {
348
- config.onInit?.(this.toStyleContext());
349
- }
350
- onReset() {
351
- config.onReset?.(this.toStyleContext());
376
+ // The config's hooks become this instance's OWN `onInit`/`onReset`, assigned
377
+ // only when declared. An unconditional method override would make the base
378
+ // read every functional ViewModel as taking both hooks and register it with
379
+ // bootstrap for nothing; an own property is seen by the same test a class
380
+ // override is, and `this.onInit()` means the same thing in both styles.
381
+ constructor() {
382
+ super();
383
+ const { onInit, onReset } = config;
384
+ if (onInit) this.onInit = () => onInit(this.toStyleContext());
385
+ if (onReset) this.onReset = () => onReset(this.toStyleContext());
352
386
  }
353
387
  }
354
388
  return new FunctionalVM().build();
@@ -461,20 +495,16 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
461
495
  this.gateways = this.createGateways();
462
496
  this.services = this.createServices();
463
497
  const actions = this.createActions();
464
- const bindings = this.scenarioHandlers();
465
- const { initializeScenario, resetScenario } = createLankaScenarioBinder({
498
+ const hooks = this.toLifecycleHooks();
499
+ const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
466
500
  name: this.name,
467
- bindings,
501
+ bindings: this.scenarioHandlers(),
468
502
  context: () => this.toStyleContext(),
469
- onInit: () => {
470
- this.onInit();
471
- },
472
- onReset: () => {
473
- this.onReset();
474
- }
503
+ onInit: hooks.onInit,
504
+ onReset: hooks.onReset
475
505
  });
476
506
  state = { ...state, ...actions, initializeScenario, resetScenario };
477
- if (typeof bindings === "function" || bindings.length > 0) {
507
+ if (needsBootstrap2) {
478
508
  lankaScenarioBootstrap.registerViewModel(state, this.name);
479
509
  }
480
510
  const useStatelessViewModel = ((selector) => selector ? selector(state) : state);
@@ -500,11 +530,13 @@ function createStatelessLankaVM(config) {
500
530
  createActions() {
501
531
  return config.createActions(this.toStyleContext());
502
532
  }
503
- onInit() {
504
- config.onInit?.(this.toStyleContext());
505
- }
506
- onReset() {
507
- config.onReset?.(this.toStyleContext());
533
+ // Own properties, assigned only when declared — see the same constructor in
534
+ // `createLankaVM` for why not a method override.
535
+ constructor() {
536
+ super();
537
+ const { onInit, onReset } = config;
538
+ if (onInit) this.onInit = () => onInit(this.toStyleContext());
539
+ if (onReset) this.onReset = () => onReset(this.toStyleContext());
508
540
  }
509
541
  }
510
542
  return new FunctionalStatelessVM().build();
@@ -551,7 +583,7 @@ function createSharedStoreLankaVM(config) {
551
583
  services,
552
584
  trigger: (scenario, data) => scenario.trigger(data)
553
585
  };
554
- const { initializeScenario, resetScenario } = createLankaScenarioBinder({
586
+ const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
555
587
  name: config.name,
556
588
  bindings: config.scenarioHandlers,
557
589
  context: () => ctx,
@@ -578,8 +610,7 @@ function createSharedStoreLankaVM(config) {
578
610
  const useSharedStoreViewModel = isAccessTrackingEnabled ? useTrackedSharedStoreViewModel : useUntrackedSharedStoreViewModel;
579
611
  useSharedStoreViewModel.getState = () => getFullState();
580
612
  useSharedStoreViewModel.getStoreState = () => config.store.getState();
581
- const declaredBindings = config.scenarioHandlers;
582
- if (typeof declaredBindings === "function" || declaredBindings !== void 0 && declaredBindings.length > 0) {
613
+ if (needsBootstrap2) {
583
614
  const scenarioViewModel = {
584
615
  initializeScenario,
585
616
  resetScenario
@@ -626,6 +657,7 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
626
657
  }
627
658
  /** Builds the hook a screen calls. One ViewModel per call. */
628
659
  build() {
660
+ const hooks = this.toLifecycleHooks();
629
661
  return createSharedStoreLankaVM({
630
662
  name: this.name,
631
663
  store: this.store,
@@ -642,12 +674,8 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
642
674
  this.trigger = context.trigger;
643
675
  return this.createActions();
644
676
  },
645
- onInit: () => {
646
- this.onInit();
647
- },
648
- onReset: () => {
649
- this.onReset();
650
- }
677
+ onInit: hooks.onInit,
678
+ onReset: hooks.onReset
651
679
  });
652
680
  }
653
681
  };