lanka 1.3.0 → 2.0.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 (63) hide show
  1. package/README.md +1 -1
  2. package/dist/ILankaReadableVM-BoPzHEPV.d.ts +72 -0
  3. package/dist/{LankaScenarioLocator-CAENLhDO.d.ts → LankaScenarioLocator-Dki2Es3O.d.ts} +2 -2
  4. package/dist/{LankaSharedStoreLocator-zS2kLu-S.d.ts → LankaSharedStoreLocator-jsz_gnUm.d.ts} +1 -1
  5. package/dist/_extend/index.d.ts +228 -5
  6. package/dist/_extend/index.js +137 -8
  7. package/dist/_extend/index.js.map +1 -1
  8. package/dist/_internal/index.d.ts +3 -3
  9. package/dist/_internal/index.js +9 -3
  10. package/dist/_internal/index.js.map +1 -1
  11. package/dist/{activeRuntime-BYd2D6Lx.d.ts → activeRuntime-BO-qY0yY.d.ts} +50 -3
  12. package/dist/bootstrap/index.d.ts +6 -6
  13. package/dist/bootstrap/index.js +7 -8
  14. package/dist/{chunk-D27MREPB.js → chunk-7DQUF2QR.js} +2 -2
  15. package/dist/{chunk-UJEC7H6K.js → chunk-BHQ2SQ7P.js} +2 -2
  16. package/dist/chunk-EYDMBI5T.js +550 -0
  17. package/dist/chunk-EYDMBI5T.js.map +1 -0
  18. package/dist/{chunk-C2HP7CRD.js → chunk-FII3PW2G.js} +2 -2
  19. package/dist/{chunk-DTO27QFR.js → chunk-H5TIUKRK.js} +2 -2
  20. package/dist/{chunk-NDCJBO47.js → chunk-O5EUTNR6.js} +2 -2
  21. package/dist/{chunk-RKYKK6MN.js → chunk-RUMUFHSL.js} +2 -2
  22. package/dist/{chunk-UBGXDTXC.js → chunk-SZVNPK24.js} +11 -13
  23. package/dist/chunk-SZVNPK24.js.map +1 -0
  24. package/dist/chunk-UDP6IXDS.js +17 -0
  25. package/dist/chunk-UDP6IXDS.js.map +1 -0
  26. package/dist/{chunk-5MAQVBI2.js → chunk-UMPSR4US.js} +3 -3
  27. package/dist/{chunk-BGVDPDX4.js → chunk-XGMXT4XZ.js} +20 -3
  28. package/dist/chunk-XGMXT4XZ.js.map +1 -0
  29. package/dist/config/index.js +3 -3
  30. package/dist/{createLanka-NrlvN-WQ.d.ts → createLanka-x4oSMs7P.d.ts} +2 -2
  31. package/dist/{createLankaScope-BiFxNQgl.d.ts → createLankaScope-DomNbEvb.d.ts} +1 -1
  32. package/dist/errors/index.js +3 -3
  33. package/dist/gateway/index.js +9 -9
  34. package/dist/index.d.ts +5 -5
  35. package/dist/index.js +8 -9
  36. package/dist/locator/index.d.ts +2 -2
  37. package/dist/locator/index.js +2 -2
  38. package/dist/logger/index.js +3 -3
  39. package/dist/mock/index.js +3 -3
  40. package/dist/scenario/index.d.ts +25 -0
  41. package/dist/scenario/index.js +6 -8
  42. package/dist/scenario/index.js.map +1 -1
  43. package/dist/stream/index.d.ts +5 -5
  44. package/dist/viewmodel/index.d.ts +137 -27
  45. package/dist/viewmodel/index.js +94 -126
  46. package/dist/viewmodel/index.js.map +1 -1
  47. package/package.json +3 -4
  48. package/skills/lanka-core/SKILL.md +18 -16
  49. package/skills/lanka-core/reference.md +135 -58
  50. package/skills/lanka-packages/SKILL.md +94 -22
  51. package/dist/chunk-B7EYIAW7.js +0 -216
  52. package/dist/chunk-B7EYIAW7.js.map +0 -1
  53. package/dist/chunk-BGVDPDX4.js.map +0 -1
  54. package/dist/chunk-O5ROO7QF.js +0 -315
  55. package/dist/chunk-O5ROO7QF.js.map +0 -1
  56. package/dist/chunk-UBGXDTXC.js.map +0 -1
  57. /package/dist/{chunk-D27MREPB.js.map → chunk-7DQUF2QR.js.map} +0 -0
  58. /package/dist/{chunk-UJEC7H6K.js.map → chunk-BHQ2SQ7P.js.map} +0 -0
  59. /package/dist/{chunk-C2HP7CRD.js.map → chunk-FII3PW2G.js.map} +0 -0
  60. /package/dist/{chunk-DTO27QFR.js.map → chunk-H5TIUKRK.js.map} +0 -0
  61. /package/dist/{chunk-NDCJBO47.js.map → chunk-O5EUTNR6.js.map} +0 -0
  62. /package/dist/{chunk-RKYKK6MN.js.map → chunk-RUMUFHSL.js.map} +0 -0
  63. /package/dist/{chunk-5MAQVBI2.js.map → chunk-UMPSR4US.js.map} +0 -0
@@ -1,15 +1,16 @@
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-EYDMBI5T.js";
6
7
  import {
7
8
  lankaLogger
8
- } from "../chunk-C2HP7CRD.js";
9
+ } from "../chunk-FII3PW2G.js";
9
10
  import {
10
11
  getLankaFlags
11
- } from "../chunk-D27MREPB.js";
12
- import "../chunk-BGVDPDX4.js";
12
+ } from "../chunk-7DQUF2QR.js";
13
+ import "../chunk-XGMXT4XZ.js";
13
14
 
14
15
  // src/viewmodel/_abstractions/lanka-vm-environment/ALankaVMEnvironment.ts
15
16
  var ALankaVMEnvironment = class _ALankaVMEnvironment {
@@ -66,7 +67,7 @@ var ALankaVMEnvironment = class _ALankaVMEnvironment {
66
67
  };
67
68
 
68
69
  // src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
69
- import { create } from "zustand";
70
+ import { createStore } from "zustand/vanilla";
70
71
 
71
72
  // src/viewmodel/_internal/create-lanka-blind-spot-trap/createLankaBlindSpotTrap.ts
72
73
  var createLankaBlindSpotTrap = (viewModelName, isArmed) => {
@@ -173,69 +174,6 @@ var createLankaScenarioBinder = (config) => {
173
174
  };
174
175
  };
175
176
 
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
177
  // src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
240
178
  var ALankaVM = class extends ALankaVMEnvironment {
241
179
  /**
@@ -286,7 +224,15 @@ var ALankaVM = class extends ALankaVMEnvironment {
286
224
  trigger: this.trigger
287
225
  };
288
226
  }
289
- /** Builds the hook a screen calls. One store per call. */
227
+ /**
228
+ * Builds the ViewModel a screen reads. One store per call.
229
+ *
230
+ * What comes back is a STORE, not a hook: `getState`, `subscribe`, `setState`,
231
+ * plus the name and the tracking flag. A screen reaches it through its
232
+ * framework's binding — `useLankaVM(todoVM)` from `@lankajs/react`,
233
+ * `@lankajs/vue` and the rest of the shelf — and a program with no framework
234
+ * at all reads `getState()` and `subscribe()` directly.
235
+ */
290
236
  build() {
291
237
  lankaLogger.printViewModelLog("START Create VM", this.name);
292
238
  const blindSpot = createLankaBlindSpotTrap(
@@ -318,29 +264,21 @@ var ALankaVM = class extends ALankaVMEnvironment {
318
264
  (creator, enhance) => enhance(creator),
319
265
  stateCreator
320
266
  );
321
- const store = create()(enhancedCreator);
322
- const registerScenarioViewModel = (viewModel) => {
323
- if (needsBootstrap2) {
324
- lankaScenarioBootstrap.registerViewModel(viewModel, this.name);
267
+ const store = createStore()(enhancedCreator);
268
+ const viewModel = Object.defineProperties(store, {
269
+ name: { value: this.name, enumerable: false, configurable: true },
270
+ isAccessTracked: {
271
+ value: this.enableAccessTrackingOptimization,
272
+ enumerable: false,
273
+ configurable: true
325
274
  }
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
275
  });
337
- useOptimizedViewModel.setState = store.setState;
338
- useOptimizedViewModel.getState = store.getState;
339
- useOptimizedViewModel.getInitialState = store.getInitialState;
340
- useOptimizedViewModel.subscribe = store.subscribe;
341
- registerScenarioViewModel(useOptimizedViewModel.getState());
276
+ lankaBlindSpotRegistry.remember(viewModel, blindSpot);
277
+ if (needsBootstrap2) {
278
+ lankaScenarioBootstrap.registerViewModel(store.getState(), this.name);
279
+ }
342
280
  lankaLogger.printViewModelLog("FINISH Create VM", this.name);
343
- return useOptimizedViewModel;
281
+ return viewModel;
344
282
  }
345
283
  };
346
284
 
@@ -388,7 +326,7 @@ function createLankaVM(config) {
388
326
  return new FunctionalVM().build();
389
327
  }
390
328
 
391
- // src/viewmodel/_internal/create-lazy-lanka-hook/createLazyLankaHook.ts
329
+ // src/viewmodel/_internal/create-lazy-lanka-vm-proxy/createLazyLankaVMProxy.ts
392
330
  var lazySlot = (config) => {
393
331
  let store = null;
394
332
  return {
@@ -422,29 +360,31 @@ var lazySlot = (config) => {
422
360
  };
423
361
  };
424
362
  var PROMISE_MEMBERS = /* @__PURE__ */ new Set(["then", "catch", "finally"]);
425
- var forwardEveryMember = (slot) => (_target, property) => {
363
+ var forwardEveryMember = (slot, config) => (_target, property) => {
426
364
  if (property === "dispose") return slot.release;
427
365
  if (PROMISE_MEMBERS.has(property)) return void 0;
366
+ if (property === "name") return config.name;
367
+ if (property === "isAccessTracked") return config.isAccessTracked;
428
368
  return (...args) => {
429
369
  const built = slot.get();
430
370
  const member = built[property];
431
371
  return typeof member === "function" ? member.apply(built, args) : member;
432
372
  };
433
373
  };
434
- var createLazyLankaHook = (config) => {
374
+ var createLazyLankaVMProxy = (config) => {
435
375
  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) });
376
+ return new Proxy(
377
+ {},
378
+ { get: forwardEveryMember(slot, config) }
379
+ );
441
380
  };
442
381
 
443
382
  // src/viewmodel/_factories/create-lazy-lanka-vm/createLazyLankaVM.ts
444
383
  function createLazyLankaVM(config) {
445
- return createLazyLankaHook({
384
+ return createLazyLankaVMProxy({
446
385
  name: config.name,
447
386
  kind: "VM",
387
+ isAccessTracked: config.enableAccessTrackingOptimization ?? true,
448
388
  create: () => createLankaVM(config)
449
389
  });
450
390
  }
@@ -483,7 +423,12 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
483
423
  trigger: this.trigger
484
424
  };
485
425
  }
486
- /** Builds the hook a screen calls. One ViewModel per call. */
426
+ /**
427
+ * Builds the ViewModel a screen reads. One per call.
428
+ *
429
+ * What comes back answers the read half of the port and nothing more: there
430
+ * is no store to write to from outside, because there is no state to write.
431
+ */
487
432
  build() {
488
433
  lankaLogger.printViewModelLog("START Create slVM", this.name);
489
434
  let state = {};
@@ -507,10 +452,14 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
507
452
  if (needsBootstrap2) {
508
453
  lankaScenarioBootstrap.registerViewModel(state, this.name);
509
454
  }
510
- const useStatelessViewModel = ((selector) => selector ? selector(state) : state);
511
- useStatelessViewModel.getState = () => state;
455
+ const statelessViewModel = {
456
+ name: this.name,
457
+ getState: () => state,
458
+ subscribe: () => () => void 0,
459
+ isAccessTracked: false
460
+ };
512
461
  lankaLogger.printViewModelLog("FINISH Create slVM", this.name);
513
- return useStatelessViewModel;
462
+ return statelessViewModel;
514
463
  }
515
464
  };
516
465
 
@@ -544,15 +493,17 @@ function createStatelessLankaVM(config) {
544
493
 
545
494
  // src/viewmodel/_factories/create-lazy-stateless-lanka-vm/createLazyStatelessLankaVM.ts
546
495
  function createLazyStatelessLankaVM(config) {
547
- return createLazyLankaHook({
496
+ return createLazyLankaVMProxy({
548
497
  name: config.name,
549
498
  kind: "slVM",
499
+ // A stateless ViewModel has no reactive fields, so there is nothing whose
500
+ // reads could be worth recording — the eager one answers false too.
501
+ isAccessTracked: false,
550
502
  create: () => createStatelessLankaVM(config)
551
503
  });
552
504
  }
553
505
 
554
506
  // src/viewmodel/_factories/create-shared-store-lanka-vm/createSharedStoreLankaVM.ts
555
- import { useStore } from "zustand";
556
507
  function createSharedStoreLankaVM(config) {
557
508
  lankaLogger.printViewModelLog("START Create ssVM", config.name);
558
509
  let actions = {};
@@ -594,22 +545,15 @@ function createSharedStoreLankaVM(config) {
594
545
  lastStoreStateRef = null;
595
546
  lastFullStateRef = null;
596
547
  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();
548
+ const sharedStoreViewModel = {
549
+ name: config.name,
550
+ getState: getFullState,
551
+ getStoreState: () => config.store.getState(),
552
+ isAccessTracked: isAccessTrackingEnabled,
553
+ subscribe: (listener) => config.store.subscribe((storeState, prevStoreState) => {
554
+ listener(buildFullState(storeState), buildFullState(prevStoreState));
555
+ })
556
+ };
613
557
  if (needsBootstrap2) {
614
558
  const scenarioViewModel = {
615
559
  initializeScenario,
@@ -618,14 +562,15 @@ function createSharedStoreLankaVM(config) {
618
562
  lankaScenarioBootstrap.registerViewModel(scenarioViewModel, config.name);
619
563
  }
620
564
  lankaLogger.printViewModelLog("FINISH Create ssVM", config.name);
621
- return useSharedStoreViewModel;
565
+ return sharedStoreViewModel;
622
566
  }
623
567
 
624
568
  // src/viewmodel/_factories/create-lazy-shared-store-lanka-vm/createLazySharedStoreLankaVM.ts
625
569
  function createLazySharedStoreLankaVM(config) {
626
- return createLazyLankaHook({
570
+ return createLazyLankaVMProxy({
627
571
  name: config.name,
628
572
  kind: "ssVM",
573
+ isAccessTracked: config.enableAccessTrackingOptimization ?? true,
629
574
  create: () => createSharedStoreLankaVM(config)
630
575
  });
631
576
  }
@@ -681,13 +626,13 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
681
626
  };
682
627
 
683
628
  // src/viewmodel/_abstractions/lanka-shared-store/ALankaSharedStore.ts
684
- import { createStore } from "zustand/vanilla";
629
+ import { createStore as createStore2 } from "zustand/vanilla";
685
630
  var ALankaSharedStore = class {
686
631
  api;
687
632
  createInitialState;
688
633
  constructor(createInitialState) {
689
634
  this.createInitialState = createInitialState;
690
- this.api = createStore()(() => this.createInitialState());
635
+ this.api = createStore2()(() => this.createInitialState());
691
636
  }
692
637
  getApi() {
693
638
  return this.api;
@@ -729,11 +674,34 @@ var createLankaSharedStore = (createInitialState) => {
729
674
  }
730
675
  return new FunctionalSharedStore();
731
676
  };
677
+
678
+ // src/viewmodel/_factories/create-lanka-shallow-hold/createLankaShallowHold.ts
679
+ var isShallowEqual = (a, b) => {
680
+ if (Object.is(a, b)) return true;
681
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
682
+ const left = Object.keys(a);
683
+ const right = Object.keys(b);
684
+ if (left.length !== right.length) return false;
685
+ return left.every(
686
+ (key) => Object.hasOwn(b, key) && Object.is(a[key], b[key])
687
+ );
688
+ };
689
+ var createLankaShallowHold = () => {
690
+ let held;
691
+ let holding = false;
692
+ return (next) => {
693
+ if (holding && isShallowEqual(held, next)) return held;
694
+ holding = true;
695
+ held = next;
696
+ return next;
697
+ };
698
+ };
732
699
  export {
733
700
  ALankaSharedStore,
734
701
  ALankaSharedStoreVM,
735
702
  ALankaStatelessVM,
736
703
  ALankaVM,
704
+ createLankaShallowHold,
737
705
  createLankaSharedStore,
738
706
  createLankaVM,
739
707
  createLazyLankaVM,