lanka 1.3.0 → 2.0.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.
Files changed (91) hide show
  1. package/README.md +1 -1
  2. package/dist/{LankaSharedStoreLocator-zS2kLu-S.d.ts → ALankaLocator-BUCCz0Q5.d.ts} +1 -47
  3. package/dist/ILankaReadableVM-BoPzHEPV.d.ts +72 -0
  4. package/dist/{ILankaScenarioVM-DpKFL3iE.d.ts → ILankaScenario-DQd9ZfUw.d.ts} +1 -30
  5. package/dist/{ILankaScenarioMetadata-Dj4GCqmX.d.ts → ILankaScenarioMetadata-BsDp0Bzm.d.ts} +1 -1
  6. package/dist/ILankaScenarioVM-DKwjbIRq.d.ts +30 -0
  7. package/dist/{LankaScenarioLocator-CAENLhDO.d.ts → LankaScenarioVMRegistry-DySAOaj2.d.ts} +4 -37
  8. package/dist/_extend/index.d.ts +235 -7
  9. package/dist/_extend/index.js +152 -12
  10. package/dist/_extend/index.js.map +1 -1
  11. package/dist/_internal/index.d.ts +13 -8
  12. package/dist/_internal/index.js +9 -3
  13. package/dist/_internal/index.js.map +1 -1
  14. package/dist/{activeRuntime-BYd2D6Lx.d.ts → activeRuntime-ByucLPhj.d.ts} +55 -4
  15. package/dist/bootstrap/index.d.ts +15 -10
  16. package/dist/bootstrap/index.js +14 -9
  17. package/dist/chunk-24MUFFHF.js +43 -0
  18. package/dist/chunk-24MUFFHF.js.map +1 -0
  19. package/dist/chunk-3R2NO47A.js +35 -0
  20. package/dist/chunk-3R2NO47A.js.map +1 -0
  21. package/dist/{chunk-5MAQVBI2.js → chunk-42CWYVZJ.js} +44 -61
  22. package/dist/chunk-42CWYVZJ.js.map +1 -0
  23. package/dist/{chunk-D27MREPB.js → chunk-7DQUF2QR.js} +2 -2
  24. package/dist/{chunk-UJEC7H6K.js → chunk-BHQ2SQ7P.js} +2 -2
  25. package/dist/chunk-BMF4TM2Z.js +22 -0
  26. package/dist/chunk-BMF4TM2Z.js.map +1 -0
  27. package/dist/{chunk-C2HP7CRD.js → chunk-FII3PW2G.js} +2 -2
  28. package/dist/{chunk-DTO27QFR.js → chunk-H5TIUKRK.js} +2 -2
  29. package/dist/chunk-JZJ6GXX3.js +12 -0
  30. package/dist/chunk-JZJ6GXX3.js.map +1 -0
  31. package/dist/{chunk-B7EYIAW7.js → chunk-MKKMTLOY.js} +47 -13
  32. package/dist/chunk-MKKMTLOY.js.map +1 -0
  33. package/dist/{chunk-UE2C76OR.js → chunk-N3275IPH.js} +2 -69
  34. package/dist/chunk-N3275IPH.js.map +1 -0
  35. package/dist/{chunk-O5ROO7QF.js → chunk-NWEHOMTS.js} +3 -3
  36. package/dist/{chunk-NDCJBO47.js → chunk-O5EUTNR6.js} +2 -2
  37. package/dist/{chunk-RKYKK6MN.js → chunk-RUMUFHSL.js} +2 -2
  38. package/dist/chunk-SBITVBF7.js +49 -0
  39. package/dist/chunk-SBITVBF7.js.map +1 -0
  40. package/dist/{chunk-UBGXDTXC.js → chunk-SO7D5E7O.js} +22 -16
  41. package/dist/chunk-SO7D5E7O.js.map +1 -0
  42. package/dist/chunk-UDP6IXDS.js +17 -0
  43. package/dist/chunk-UDP6IXDS.js.map +1 -0
  44. package/dist/{chunk-BGVDPDX4.js → chunk-XGMXT4XZ.js} +20 -3
  45. package/dist/chunk-XGMXT4XZ.js.map +1 -0
  46. package/dist/config/index.js +3 -3
  47. package/dist/{createLanka-NrlvN-WQ.d.ts → createLanka-DvUGu9Hl.d.ts} +2 -2
  48. package/dist/{createLankaScope-BiFxNQgl.d.ts → createLankaScope-CVoV0EwO.d.ts} +1 -1
  49. package/dist/errors/index.js +3 -3
  50. package/dist/gateway/index.js +6 -6
  51. package/dist/index.d.ts +14 -9
  52. package/dist/index.js +15 -10
  53. package/dist/locator/gateway/lanka-gateway-locator/LankaGatewayLocator.d.ts +18 -0
  54. package/dist/locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js +9 -0
  55. package/dist/locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js.map +1 -0
  56. package/dist/locator/index.d.ts +4 -2
  57. package/dist/locator/index.js +6 -3
  58. package/dist/locator/index.js.map +1 -1
  59. package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.d.ts +60 -0
  60. package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js +12 -0
  61. package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js.map +1 -0
  62. package/dist/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.d.ts +22 -0
  63. package/dist/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js +9 -0
  64. package/dist/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js.map +1 -0
  65. package/dist/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.d.ts +30 -0
  66. package/dist/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js +9 -0
  67. package/dist/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js.map +1 -0
  68. package/dist/logger/index.js +3 -3
  69. package/dist/mock/index.js +3 -3
  70. package/dist/scenario/index.d.ts +29 -3
  71. package/dist/scenario/index.js +5 -5
  72. package/dist/stream/index.d.ts +17 -12
  73. package/dist/viewmodel/index.d.ts +139 -28
  74. package/dist/viewmodel/index.js +95 -126
  75. package/dist/viewmodel/index.js.map +1 -1
  76. package/package.json +3 -4
  77. package/skills/lanka-core/SKILL.md +18 -16
  78. package/skills/lanka-core/reference.md +135 -58
  79. package/skills/lanka-packages/SKILL.md +94 -22
  80. package/dist/chunk-5MAQVBI2.js.map +0 -1
  81. package/dist/chunk-B7EYIAW7.js.map +0 -1
  82. package/dist/chunk-BGVDPDX4.js.map +0 -1
  83. package/dist/chunk-UBGXDTXC.js.map +0 -1
  84. package/dist/chunk-UE2C76OR.js.map +0 -1
  85. /package/dist/{chunk-D27MREPB.js.map → chunk-7DQUF2QR.js.map} +0 -0
  86. /package/dist/{chunk-UJEC7H6K.js.map → chunk-BHQ2SQ7P.js.map} +0 -0
  87. /package/dist/{chunk-C2HP7CRD.js.map → chunk-FII3PW2G.js.map} +0 -0
  88. /package/dist/{chunk-DTO27QFR.js.map → chunk-H5TIUKRK.js.map} +0 -0
  89. /package/dist/{chunk-O5ROO7QF.js.map → chunk-NWEHOMTS.js.map} +0 -0
  90. /package/dist/{chunk-NDCJBO47.js.map → chunk-O5EUTNR6.js.map} +0 -0
  91. /package/dist/{chunk-RKYKK6MN.js.map → chunk-RUMUFHSL.js.map} +0 -0
@@ -1,15 +1,17 @@
1
- "use client";
1
+ import {
2
+ lankaBlindSpotRegistry
3
+ } from "../chunk-UDP6IXDS.js";
2
4
  import {
3
5
  lankaScenarioBootstrap
4
- } from "../chunk-B7EYIAW7.js";
5
- import "../chunk-O5ROO7QF.js";
6
+ } from "../chunk-MKKMTLOY.js";
7
+ import "../chunk-NWEHOMTS.js";
6
8
  import {
7
9
  lankaLogger
8
- } from "../chunk-C2HP7CRD.js";
10
+ } from "../chunk-FII3PW2G.js";
9
11
  import {
10
12
  getLankaFlags
11
- } from "../chunk-D27MREPB.js";
12
- import "../chunk-BGVDPDX4.js";
13
+ } from "../chunk-7DQUF2QR.js";
14
+ import "../chunk-XGMXT4XZ.js";
13
15
 
14
16
  // src/viewmodel/_abstractions/lanka-vm-environment/ALankaVMEnvironment.ts
15
17
  var ALankaVMEnvironment = class _ALankaVMEnvironment {
@@ -66,7 +68,7 @@ var ALankaVMEnvironment = class _ALankaVMEnvironment {
66
68
  };
67
69
 
68
70
  // src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
69
- import { create } from "zustand";
71
+ import { createStore } from "zustand/vanilla";
70
72
 
71
73
  // src/viewmodel/_internal/create-lanka-blind-spot-trap/createLankaBlindSpotTrap.ts
72
74
  var createLankaBlindSpotTrap = (viewModelName, isArmed) => {
@@ -173,69 +175,6 @@ var createLankaScenarioBinder = (config) => {
173
175
  };
174
176
  };
175
177
 
176
- // src/viewmodel/_internal/create-lanka-tracked-hook/createLankaTrackedHook.ts
177
- import { useCallback, useRef, useSyncExternalStore } from "react";
178
- var asRecord = (state) => state;
179
- var createLankaTrackedHook = (config) => {
180
- return (selector) => {
181
- const selectorRef = useRef(selector);
182
- selectorRef.current = selector;
183
- const trackedKeysRef = useRef(/* @__PURE__ */ new Set());
184
- const trackedStateRef = useRef(null);
185
- const trackedProxyRef = useRef(null);
186
- const subscribe = useCallback(
187
- (onStoreChange) => config.subscribe((nextState, prevState) => {
188
- if (selectorRef.current) {
189
- onStoreChange();
190
- return;
191
- }
192
- const trackedKeys = trackedKeysRef.current;
193
- if (trackedKeys.size === 0) {
194
- onStoreChange();
195
- return;
196
- }
197
- const next = asRecord(nextState);
198
- const prev = asRecord(prevState);
199
- for (const key of trackedKeys) {
200
- if (!Object.is(next[key], prev[key])) {
201
- onStoreChange();
202
- return;
203
- }
204
- }
205
- config.onUntrackedChange?.(trackedKeys, next, prev);
206
- }),
207
- []
208
- );
209
- return useSyncExternalStore(subscribe, readTracked, readUntracked);
210
- function readTracked() {
211
- const state = config.readState();
212
- const activeSelector = selectorRef.current;
213
- if (activeSelector) return activeSelector(state);
214
- if (trackedStateRef.current === state && trackedProxyRef.current) {
215
- return trackedProxyRef.current;
216
- }
217
- const trackedKeys = /* @__PURE__ */ new Set();
218
- const proxyState = new Proxy(state, {
219
- get(target, prop, receiver) {
220
- if (typeof prop === "string") {
221
- trackedKeys.add(prop);
222
- }
223
- return Reflect.get(target, prop, receiver);
224
- }
225
- });
226
- trackedKeysRef.current = trackedKeys;
227
- trackedStateRef.current = state;
228
- trackedProxyRef.current = proxyState;
229
- return proxyState;
230
- }
231
- function readUntracked() {
232
- const state = config.readState();
233
- const activeSelector = selectorRef.current;
234
- return activeSelector ? activeSelector(state) : state;
235
- }
236
- };
237
- };
238
-
239
178
  // src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
240
179
  var ALankaVM = class extends ALankaVMEnvironment {
241
180
  /**
@@ -286,7 +225,15 @@ var ALankaVM = class extends ALankaVMEnvironment {
286
225
  trigger: this.trigger
287
226
  };
288
227
  }
289
- /** Builds the hook a screen calls. One store per call. */
228
+ /**
229
+ * Builds the ViewModel a screen reads. One store per call.
230
+ *
231
+ * What comes back is a STORE, not a hook: `getState`, `subscribe`, `setState`,
232
+ * plus the name and the tracking flag. A screen reaches it through its
233
+ * framework's binding — `useLankaVM(todoVM)` from `@lankajs/react`,
234
+ * `@lankajs/vue` and the rest of the shelf — and a program with no framework
235
+ * at all reads `getState()` and `subscribe()` directly.
236
+ */
290
237
  build() {
291
238
  lankaLogger.printViewModelLog("START Create VM", this.name);
292
239
  const blindSpot = createLankaBlindSpotTrap(
@@ -318,29 +265,21 @@ var ALankaVM = class extends ALankaVMEnvironment {
318
265
  (creator, enhance) => enhance(creator),
319
266
  stateCreator
320
267
  );
321
- const store = create()(enhancedCreator);
322
- const registerScenarioViewModel = (viewModel) => {
323
- if (needsBootstrap2) {
324
- lankaScenarioBootstrap.registerViewModel(viewModel, this.name);
268
+ const store = createStore()(enhancedCreator);
269
+ const viewModel = Object.defineProperties(store, {
270
+ name: { value: this.name, enumerable: false, configurable: true },
271
+ isAccessTracked: {
272
+ value: this.enableAccessTrackingOptimization,
273
+ enumerable: false,
274
+ configurable: true
325
275
  }
326
- };
327
- if (!this.enableAccessTrackingOptimization) {
328
- registerScenarioViewModel(store.getState());
329
- lankaLogger.printViewModelLog("FINISH Create VM", this.name);
330
- return store;
331
- }
332
- const useOptimizedViewModel = createLankaTrackedHook({
333
- subscribe: (onChange) => store.subscribe(onChange),
334
- readState: () => store.getState(),
335
- onUntrackedChange: blindSpot.isArmed ? blindSpot.report : void 0
336
276
  });
337
- useOptimizedViewModel.setState = store.setState;
338
- useOptimizedViewModel.getState = store.getState;
339
- useOptimizedViewModel.getInitialState = store.getInitialState;
340
- useOptimizedViewModel.subscribe = store.subscribe;
341
- registerScenarioViewModel(useOptimizedViewModel.getState());
277
+ lankaBlindSpotRegistry.remember(viewModel, blindSpot);
278
+ if (needsBootstrap2) {
279
+ lankaScenarioBootstrap.registerViewModel(store.getState(), this.name);
280
+ }
342
281
  lankaLogger.printViewModelLog("FINISH Create VM", this.name);
343
- return useOptimizedViewModel;
282
+ return viewModel;
344
283
  }
345
284
  };
346
285
 
@@ -388,7 +327,7 @@ function createLankaVM(config) {
388
327
  return new FunctionalVM().build();
389
328
  }
390
329
 
391
- // src/viewmodel/_internal/create-lazy-lanka-hook/createLazyLankaHook.ts
330
+ // src/viewmodel/_internal/create-lazy-lanka-vm-proxy/createLazyLankaVMProxy.ts
392
331
  var lazySlot = (config) => {
393
332
  let store = null;
394
333
  return {
@@ -422,29 +361,31 @@ var lazySlot = (config) => {
422
361
  };
423
362
  };
424
363
  var PROMISE_MEMBERS = /* @__PURE__ */ new Set(["then", "catch", "finally"]);
425
- var forwardEveryMember = (slot) => (_target, property) => {
364
+ var forwardEveryMember = (slot, config) => (_target, property) => {
426
365
  if (property === "dispose") return slot.release;
427
366
  if (PROMISE_MEMBERS.has(property)) return void 0;
367
+ if (property === "name") return config.name;
368
+ if (property === "isAccessTracked") return config.isAccessTracked;
428
369
  return (...args) => {
429
370
  const built = slot.get();
430
371
  const member = built[property];
431
372
  return typeof member === "function" ? member.apply(built, args) : member;
432
373
  };
433
374
  };
434
- var createLazyLankaHook = (config) => {
375
+ var createLazyLankaVMProxy = (config) => {
435
376
  const slot = lazySlot(config);
436
- const hook = (selector) => {
437
- const built = slot.get();
438
- return selector ? built(selector) : built();
439
- };
440
- return new Proxy(hook, { get: forwardEveryMember(slot) });
377
+ return new Proxy(
378
+ {},
379
+ { get: forwardEveryMember(slot, config) }
380
+ );
441
381
  };
442
382
 
443
383
  // src/viewmodel/_factories/create-lazy-lanka-vm/createLazyLankaVM.ts
444
384
  function createLazyLankaVM(config) {
445
- return createLazyLankaHook({
385
+ return createLazyLankaVMProxy({
446
386
  name: config.name,
447
387
  kind: "VM",
388
+ isAccessTracked: config.enableAccessTrackingOptimization ?? true,
448
389
  create: () => createLankaVM(config)
449
390
  });
450
391
  }
@@ -483,7 +424,12 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
483
424
  trigger: this.trigger
484
425
  };
485
426
  }
486
- /** Builds the hook a screen calls. One ViewModel per call. */
427
+ /**
428
+ * Builds the ViewModel a screen reads. One per call.
429
+ *
430
+ * What comes back answers the read half of the port and nothing more: there
431
+ * is no store to write to from outside, because there is no state to write.
432
+ */
487
433
  build() {
488
434
  lankaLogger.printViewModelLog("START Create slVM", this.name);
489
435
  let state = {};
@@ -507,10 +453,14 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
507
453
  if (needsBootstrap2) {
508
454
  lankaScenarioBootstrap.registerViewModel(state, this.name);
509
455
  }
510
- const useStatelessViewModel = ((selector) => selector ? selector(state) : state);
511
- useStatelessViewModel.getState = () => state;
456
+ const statelessViewModel = {
457
+ name: this.name,
458
+ getState: () => state,
459
+ subscribe: () => () => void 0,
460
+ isAccessTracked: false
461
+ };
512
462
  lankaLogger.printViewModelLog("FINISH Create slVM", this.name);
513
- return useStatelessViewModel;
463
+ return statelessViewModel;
514
464
  }
515
465
  };
516
466
 
@@ -544,15 +494,17 @@ function createStatelessLankaVM(config) {
544
494
 
545
495
  // src/viewmodel/_factories/create-lazy-stateless-lanka-vm/createLazyStatelessLankaVM.ts
546
496
  function createLazyStatelessLankaVM(config) {
547
- return createLazyLankaHook({
497
+ return createLazyLankaVMProxy({
548
498
  name: config.name,
549
499
  kind: "slVM",
500
+ // A stateless ViewModel has no reactive fields, so there is nothing whose
501
+ // reads could be worth recording — the eager one answers false too.
502
+ isAccessTracked: false,
550
503
  create: () => createStatelessLankaVM(config)
551
504
  });
552
505
  }
553
506
 
554
507
  // src/viewmodel/_factories/create-shared-store-lanka-vm/createSharedStoreLankaVM.ts
555
- import { useStore } from "zustand";
556
508
  function createSharedStoreLankaVM(config) {
557
509
  lankaLogger.printViewModelLog("START Create ssVM", config.name);
558
510
  let actions = {};
@@ -594,22 +546,15 @@ function createSharedStoreLankaVM(config) {
594
546
  lastStoreStateRef = null;
595
547
  lastFullStateRef = null;
596
548
  const isAccessTrackingEnabled = config.enableAccessTrackingOptimization ?? true;
597
- const useTrackedSharedStoreViewModel = createLankaTrackedHook({
598
- subscribe: (onChange) => config.store.subscribe((storeState, prevStoreState) => {
599
- onChange(buildFullState(storeState), buildFullState(prevStoreState));
600
- }),
601
- readState: getFullState
602
- });
603
- const useUntrackedSharedStoreViewModel = ((selector) => useStore(config.store.getApi(), (storeState) => {
604
- const fullState = buildFullState(storeState);
605
- if (selector) {
606
- return selector(fullState);
607
- }
608
- return fullState;
609
- }));
610
- const useSharedStoreViewModel = isAccessTrackingEnabled ? useTrackedSharedStoreViewModel : useUntrackedSharedStoreViewModel;
611
- useSharedStoreViewModel.getState = () => getFullState();
612
- useSharedStoreViewModel.getStoreState = () => config.store.getState();
549
+ const sharedStoreViewModel = {
550
+ name: config.name,
551
+ getState: getFullState,
552
+ getStoreState: () => config.store.getState(),
553
+ isAccessTracked: isAccessTrackingEnabled,
554
+ subscribe: (listener) => config.store.subscribe((storeState, prevStoreState) => {
555
+ listener(buildFullState(storeState), buildFullState(prevStoreState));
556
+ })
557
+ };
613
558
  if (needsBootstrap2) {
614
559
  const scenarioViewModel = {
615
560
  initializeScenario,
@@ -618,14 +563,15 @@ function createSharedStoreLankaVM(config) {
618
563
  lankaScenarioBootstrap.registerViewModel(scenarioViewModel, config.name);
619
564
  }
620
565
  lankaLogger.printViewModelLog("FINISH Create ssVM", config.name);
621
- return useSharedStoreViewModel;
566
+ return sharedStoreViewModel;
622
567
  }
623
568
 
624
569
  // src/viewmodel/_factories/create-lazy-shared-store-lanka-vm/createLazySharedStoreLankaVM.ts
625
570
  function createLazySharedStoreLankaVM(config) {
626
- return createLazyLankaHook({
571
+ return createLazyLankaVMProxy({
627
572
  name: config.name,
628
573
  kind: "ssVM",
574
+ isAccessTracked: config.enableAccessTrackingOptimization ?? true,
629
575
  create: () => createSharedStoreLankaVM(config)
630
576
  });
631
577
  }
@@ -681,13 +627,13 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
681
627
  };
682
628
 
683
629
  // src/viewmodel/_abstractions/lanka-shared-store/ALankaSharedStore.ts
684
- import { createStore } from "zustand/vanilla";
630
+ import { createStore as createStore2 } from "zustand/vanilla";
685
631
  var ALankaSharedStore = class {
686
632
  api;
687
633
  createInitialState;
688
634
  constructor(createInitialState) {
689
635
  this.createInitialState = createInitialState;
690
- this.api = createStore()(() => this.createInitialState());
636
+ this.api = createStore2()(() => this.createInitialState());
691
637
  }
692
638
  getApi() {
693
639
  return this.api;
@@ -729,11 +675,34 @@ var createLankaSharedStore = (createInitialState) => {
729
675
  }
730
676
  return new FunctionalSharedStore();
731
677
  };
678
+
679
+ // src/viewmodel/_factories/create-lanka-shallow-hold/createLankaShallowHold.ts
680
+ var isShallowEqual = (a, b) => {
681
+ if (Object.is(a, b)) return true;
682
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
683
+ const left = Object.keys(a);
684
+ const right = Object.keys(b);
685
+ if (left.length !== right.length) return false;
686
+ return left.every(
687
+ (key) => Object.hasOwn(b, key) && Object.is(a[key], b[key])
688
+ );
689
+ };
690
+ var createLankaShallowHold = () => {
691
+ let held;
692
+ let holding = false;
693
+ return (next) => {
694
+ if (holding && isShallowEqual(held, next)) return held;
695
+ holding = true;
696
+ held = next;
697
+ return next;
698
+ };
699
+ };
732
700
  export {
733
701
  ALankaSharedStore,
734
702
  ALankaSharedStoreVM,
735
703
  ALankaStatelessVM,
736
704
  ALankaVM,
705
+ createLankaShallowHold,
737
706
  createLankaSharedStore,
738
707
  createLankaVM,
739
708
  createLazyLankaVM,