@ng-org/alien-deepsignals 0.1.2-alpha.3 → 0.1.2-alpha.5

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 (57) hide show
  1. package/dist/deepSignal.d.ts.map +1 -1
  2. package/dist/deepSignal.js +168 -16
  3. package/dist/hooks/svelte/useDeepSignal.svelte.d.ts +3 -7
  4. package/dist/hooks/svelte/useDeepSignal.svelte.d.ts.map +1 -1
  5. package/dist/hooks/svelte/useDeepSignal.svelte.js +34 -18
  6. package/dist/hooks/vue/useDeepSignal.d.ts +4 -3
  7. package/dist/hooks/vue/useDeepSignal.d.ts.map +1 -1
  8. package/dist/hooks/vue/useDeepSignal.js +52 -24
  9. package/dist/test/frontend/astro-app/src/components/PerfSuiteClient.d.ts +4 -0
  10. package/dist/test/frontend/astro-app/src/components/PerfSuiteClient.d.ts.map +1 -0
  11. package/dist/test/frontend/astro-app/src/components/PerfSuiteClient.js +225 -0
  12. package/dist/test/frontend/astro-app/src/components/ReactPanel.d.ts +4 -0
  13. package/dist/test/frontend/astro-app/src/components/ReactPanel.d.ts.map +1 -0
  14. package/dist/test/frontend/astro-app/src/components/ReactPanel.js +227 -0
  15. package/dist/test/frontend/astro-app/src/components/perf/react/ReactPerfDeep.d.ts +4 -0
  16. package/dist/test/frontend/astro-app/src/components/perf/react/ReactPerfDeep.d.ts.map +1 -0
  17. package/dist/test/frontend/astro-app/src/components/perf/react/ReactPerfDeep.js +150 -0
  18. package/dist/test/frontend/astro-app/src/components/perf/react/ReactPerfNative.d.ts +4 -0
  19. package/dist/test/frontend/astro-app/src/components/perf/react/ReactPerfNative.d.ts.map +1 -0
  20. package/dist/test/frontend/astro-app/src/components/perf/react/ReactPerfNative.js +184 -0
  21. package/dist/test/frontend/playwright/crossFrameworkHooks.spec.d.ts +2 -0
  22. package/dist/test/frontend/playwright/crossFrameworkHooks.spec.d.ts.map +1 -0
  23. package/dist/test/frontend/playwright/crossFrameworkHooks.spec.js +171 -0
  24. package/dist/test/frontend/playwright/perfSuite.spec.d.ts +2 -0
  25. package/dist/test/frontend/playwright/perfSuite.spec.d.ts.map +1 -0
  26. package/dist/test/frontend/playwright/perfSuite.spec.js +128 -0
  27. package/dist/test/frontend/utils/mockData.d.ts +53 -0
  28. package/dist/test/frontend/utils/mockData.d.ts.map +1 -0
  29. package/dist/test/frontend/utils/mockData.js +78 -0
  30. package/dist/test/frontend/utils/paths.d.ts +4 -0
  31. package/dist/test/frontend/utils/paths.d.ts.map +1 -0
  32. package/dist/test/frontend/utils/paths.js +28 -0
  33. package/dist/test/frontend/utils/perfScenarios.d.ts +15 -0
  34. package/dist/test/frontend/utils/perfScenarios.d.ts.map +1 -0
  35. package/dist/test/frontend/utils/perfScenarios.js +287 -0
  36. package/dist/test/frontend/utils/renderMetrics.d.ts +13 -0
  37. package/dist/test/frontend/utils/renderMetrics.d.ts.map +1 -0
  38. package/dist/test/frontend/utils/renderMetrics.js +45 -0
  39. package/dist/test/frontend/utils/state.d.ts +57 -0
  40. package/dist/test/frontend/utils/state.d.ts.map +1 -0
  41. package/dist/test/frontend/utils/state.js +79 -0
  42. package/dist/test/lib/core.test.d.ts +2 -0
  43. package/dist/test/lib/core.test.d.ts.map +1 -0
  44. package/dist/test/lib/core.test.js +53 -0
  45. package/dist/test/lib/deepSignalOptions.test.d.ts +2 -0
  46. package/dist/test/lib/deepSignalOptions.test.d.ts.map +1 -0
  47. package/dist/test/lib/deepSignalOptions.test.js +230 -0
  48. package/dist/test/lib/index.test.d.ts +2 -0
  49. package/dist/test/lib/index.test.d.ts.map +1 -0
  50. package/dist/test/lib/index.test.js +807 -0
  51. package/dist/test/lib/misc.test.d.ts +2 -0
  52. package/dist/test/lib/misc.test.d.ts.map +1 -0
  53. package/dist/test/lib/misc.test.js +140 -0
  54. package/dist/test/lib/watch.test.d.ts +2 -0
  55. package/dist/test/lib/watch.test.d.ts.map +1 -0
  56. package/dist/test/lib/watch.test.js +1280 -0
  57. package/package.json +1 -2
@@ -1 +1 @@
1
- {"version":3,"file":"deepSignal.d.ts","sourceRoot":"","sources":["../src/deepSignal.ts"],"names":[],"mappings":"AAWA,OAAO,EAGH,sBAAsB,EACtB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,EAMpB,MAAM,SAAS,CAAC;AAo/BjB,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACvC,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAwBf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAClC,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,EAAE,EAAE,mBAAmB,GAAG,sBAAsB,EAChD,gBAAgB,GAAE,OAAe,GAClC,MAAM,IAAI,CAoBZ;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAElE;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,GAAG,SAAS,CAIpB;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAGnD;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,QAItE;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAa1E"}
1
+ {"version":3,"file":"deepSignal.d.ts","sourceRoot":"","sources":["../src/deepSignal.ts"],"names":[],"mappings":"AAWA,OAAO,EAGH,sBAAsB,EACtB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,EAMpB,MAAM,SAAS,CAAC;AA+qCjB,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACvC,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAwBf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAClC,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,EAAE,EAAE,mBAAmB,GAAG,sBAAsB,EAChD,gBAAgB,GAAE,OAAe,GAClC,MAAM,IAAI,CAoBZ;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAElE;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,GAAG,SAAS,CAIpB;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAGnD;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,QAItE;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAa1E"}
@@ -31,6 +31,7 @@ const pendingRoots = new Set();
31
31
  const supported = new Set([Object, Array, Set]);
32
32
  const descriptor = Object.getOwnPropertyDescriptor;
33
33
  let blankNodeCounter = 0;
34
+ let tmpIdCounter = 0;
34
35
  const wellKnownSymbols = new Set([
35
36
  Symbol.asyncDispose,
36
37
  Symbol.asyncIterator,
@@ -414,12 +415,6 @@ function createProxy(target, root, options, parentMeta, key, isSyntheticId) {
414
415
  rawToProxy.set(target, proxy);
415
416
  return proxy;
416
417
  }
417
- /** Normalize a value prior to writes, ensuring nested objects are proxied. */
418
- function ensureValueForWrite(value, receiver, key) {
419
- const rawValue = rawToMeta.get(value) ?? value;
420
- const proxied = ensureChildProxy(rawValue, receiver, key);
421
- return { raw: rawValue, proxied };
422
- }
423
418
  /** Return primitive literals (string/number/boolean) for patch serialization. */
424
419
  function snapshotLiteral(value) {
425
420
  if (typeof value === "string" ||
@@ -452,8 +447,8 @@ function emitPatchesForNew(value, meta, basePath, inSet = false) {
452
447
  {
453
448
  path: basePath,
454
449
  op: "add",
455
- type: value instanceof Set ? "set" : "object",
456
- value: value instanceof Set ? [] : undefined,
450
+ value: value instanceof Set || Array.isArray(value) ? [] : {},
451
+ type: value instanceof Set ? "set" : undefined,
457
452
  },
458
453
  ];
459
454
  // The id property name, usually `@id`
@@ -507,6 +502,128 @@ function emitPatchesForNew(value, meta, basePath, inSet = false) {
507
502
  }
508
503
  return patches;
509
504
  }
505
+ /**
506
+ * Refresh numeric index signals for an array target so reads return current items
507
+ * and dependent effects are notified. Recreates/proxies values for indices < length
508
+ * and clears signals for indices >= length.
509
+ */
510
+ function refreshNumericIndexSignals(target, receiver) {
511
+ const sigs = propertiesToSignals.get(target);
512
+ if (!sigs)
513
+ return;
514
+ for (const k of Array.from(sigs.keys())) {
515
+ if (typeof k === "string" && /^\d+$/.test(k)) {
516
+ const idx = Number(k);
517
+ if (idx >= target.length) {
518
+ const existing = sigs.get(k);
519
+ if (existing &&
520
+ typeof existing.set === "function") {
521
+ existing.set(undefined);
522
+ }
523
+ sigs.delete(k);
524
+ }
525
+ else {
526
+ const val = target[idx];
527
+ const proxied = ensureChildProxy(val, receiver, idx);
528
+ setSignalValue(sigs, k, proxied);
529
+ }
530
+ }
531
+ }
532
+ }
533
+ let hasWarnedAboutMissingSupportForReverse = false;
534
+ let hasWarnedAboutMissingSupportForSort = false;
535
+ /** Returns proxy function for array-mutating functions. */
536
+ const getArrayMutationProxy = (target, key, receiver) => {
537
+ const meta = rawToMeta.get(target);
538
+ if (key === "reverse") {
539
+ if (!hasWarnedAboutMissingSupportForReverse) {
540
+ console.warn(".reverse() was called on deepSignal array. In place modifications with .sort() and .reverse() are not supported. `toReversed` will be called instead.");
541
+ hasWarnedAboutMissingSupportForReverse = true;
542
+ }
543
+ return target.toReversed;
544
+ }
545
+ else if (key === "sort") {
546
+ if (!hasWarnedAboutMissingSupportForSort) {
547
+ console.warn(".sort() was called on deepSignal array. In place modifications with .sort() and .reverse() are not supported. `toSorted` will be called instead.");
548
+ hasWarnedAboutMissingSupportForSort = true;
549
+ }
550
+ return target.toSorted;
551
+ }
552
+ else if (key === "shift") {
553
+ return () => {
554
+ target.shift();
555
+ schedulePatch(meta, () => ({
556
+ op: "remove",
557
+ path: buildPath(meta, "0"),
558
+ }));
559
+ // Update length of proxy explicitly.
560
+ receiver.length = target.length;
561
+ // Refresh numeric index signals so shifted indices don't return stale values.
562
+ refreshNumericIndexSignals(target, receiver);
563
+ };
564
+ }
565
+ else if (key === "splice") {
566
+ return (start, deleteCount, ...items) => {
567
+ // Call splice on (non-proxied) target.
568
+ const deletedItems = target.splice(start, deleteCount, ...items);
569
+ // Manually schedule patches.
570
+ schedulePatch(meta, () => {
571
+ const patches = [];
572
+ // All items can be deleted at the same path / index.
573
+ for (let i = 0; i < deleteCount; i++) {
574
+ patches.push({
575
+ op: "remove",
576
+ path: buildPath(meta, String(start)),
577
+ });
578
+ }
579
+ // All items can be inserted at same path / index, by adding items in reverse order.
580
+ for (const newItem of items.toReversed()) {
581
+ patches.push({
582
+ op: "add",
583
+ path: buildPath(meta, String(start)),
584
+ value: newItem,
585
+ });
586
+ }
587
+ return patches;
588
+ });
589
+ // Ensure newly added items are proxied.
590
+ for (let i = 0; i < items.length; i++) {
591
+ ensureChildProxy(items[i], target, start + i);
592
+ }
593
+ // Refresh numeric index signals so shifted indices don't return stale values.
594
+ refreshNumericIndexSignals(target, receiver);
595
+ // Update length of proxy explicitly.
596
+ receiver.length = target.length;
597
+ return deletedItems;
598
+ };
599
+ }
600
+ else if (key === "unshift") {
601
+ return (...items) => {
602
+ const deletedItems = target.unshift(...items);
603
+ schedulePatch(meta, () => {
604
+ const patches = [];
605
+ // All items can be inserted at index 0, by adding items in reverse order.
606
+ for (const newItem of items.toReversed()) {
607
+ patches.push({
608
+ op: "add",
609
+ path: buildPath(meta, "0"),
610
+ value: newItem,
611
+ });
612
+ }
613
+ return patches;
614
+ });
615
+ // Ensure newly added items are proxied.
616
+ for (let i = 0; i < items.length; i++) {
617
+ ensureChildProxy(items[i], target, i);
618
+ }
619
+ // Update length of proxy explicitly.
620
+ receiver.length = target.length;
621
+ // Refresh numeric index signals so shifted indices don't return stale values.
622
+ refreshNumericIndexSignals(target, receiver);
623
+ return deletedItems;
624
+ };
625
+ }
626
+ };
510
627
  /** Proxy handler driving reactivity for plain objects and arrays. */
511
628
  const objectHandlers = {
512
629
  get(target, key, receiver) {
@@ -524,6 +641,14 @@ const objectHandlers = {
524
641
  if (!isReactiveSymbol(key))
525
642
  return Reflect.get(target, key, receiver);
526
643
  }
644
+ // Array helper handling. We need that because otherwise, every array position change would go as a separate operation through the proxy.
645
+ // Thus, we need to schedule the patches manually for mutating array functions.
646
+ if (Array.isArray(target)) {
647
+ const mutationProxy = getArrayMutationProxy(target, key, receiver);
648
+ if (mutationProxy) {
649
+ return mutationProxy;
650
+ }
651
+ }
527
652
  // Get object map from key to signal.
528
653
  const signals = ensureSignalMap(target);
529
654
  // Ensure that target object is signal.
@@ -552,29 +677,56 @@ const objectHandlers = {
552
677
  const desc = descriptor(target, key);
553
678
  const hasAccessor = !!desc &&
554
679
  (typeof desc.get === "function" || typeof desc.set === "function");
555
- const { raw, proxied } = ensureValueForWrite(value, receiver, key);
680
+ const proxied = ensureChildProxy(value, target, key);
681
+ const rawValue = value?.[RAW_KEY] ?? value;
556
682
  const hadKey = Object.prototype.hasOwnProperty.call(target, key);
557
- const result = Reflect.set(target, key, raw, receiver);
683
+ const shouldManuallyTrimLength = Array.isArray(target) && key === "length" && value < target.length;
684
+ // If `length` is used to reduce the size of the array, delete the overflowing slots
685
+ // manually so that existing delete reactivity emits the patches and clears signals.
686
+ if (shouldManuallyTrimLength) {
687
+ for (let i = target.length - 1; i >= value; i -= 1) {
688
+ delete receiver[i];
689
+ }
690
+ }
691
+ // === Set value on actual target ===
692
+ const result = Reflect.set(target, key, rawValue, receiver);
558
693
  if (!hasAccessor) {
559
694
  const signals = ensureSignalMap(target);
560
695
  setSignalValue(signals, key, proxied);
561
696
  }
562
697
  if (!hadKey)
563
698
  touchIterable(target);
564
- if (meta && path && typeof raw === "object") {
565
- initializeObjectTreeIfNoListeners(meta, path, raw, false);
699
+ if (meta && path && typeof rawValue === "object") {
700
+ initializeObjectTreeIfNoListeners(meta, path, rawValue, false);
701
+ }
702
+ // Modifications to the length should not emit patches
703
+ if (Array.isArray(target) && key === "length") {
704
+ return result;
566
705
  }
567
706
  schedulePatch(meta, () => {
568
707
  const resolvedPath = path ?? buildPath(meta, key);
569
- if (!hadKey || typeof raw === "object") {
570
- return emitPatchesForNew(raw, meta, resolvedPath);
708
+ if (!hadKey || typeof rawValue === "object") {
709
+ const patches = emitPatchesForNew(rawValue, meta, resolvedPath);
710
+ // TODO: Document
711
+ // If an object is added to an array (this happens in discrete CRDTs), we will eventually receive an @id back.
712
+ // However, the @id is not available from the beginning but frontend frameworks might depend on @id.
713
+ // Thus, we set a temporary @id which will be replaced once we are called back with the real @id.
714
+ // Also, we don't emit a patch for this.
715
+ if (Array.isArray(target) &&
716
+ !isNaN(Number(key)) &&
717
+ value &&
718
+ typeof value === "object" &&
719
+ meta?.options.syntheticIdPropertyName !== "@id") {
720
+ rawValue["@id"] = `tmp-${++tmpIdCounter}`;
721
+ }
722
+ return patches;
571
723
  }
572
- if (snapshotLiteral(raw) === undefined)
724
+ if (snapshotLiteral(rawValue) === undefined)
573
725
  return undefined;
574
726
  return {
575
727
  path: resolvedPath,
576
728
  op: "add",
577
- value: raw,
729
+ value: rawValue,
578
730
  };
579
731
  });
580
732
  return result;
@@ -1,11 +1,7 @@
1
1
  import { type Readable } from "svelte/store";
2
- import { type DeepPatchBatch, DeepSignalOptions, RevertDeepSignal } from "../../index";
2
+ import { DeepSignalOptions, RevertDeepSignal } from "../../index";
3
3
  /** Base result contract for a deepSignal-backed Svelte integration. */
4
- export interface UseDeepSignalResult<T extends object> extends Readable<T> {
5
- /** Store of the full deep proxy tree (also accessible via `subscribe` directly on this result). */
6
- deep: Readable<T>;
7
- /** Last batch of deep mutation patches for this root (empties only on next non-empty batch). */
8
- patches: Readable<DeepPatchBatch | null>;
4
+ export interface UseDeepSignalResult<T> extends Readable<T> {
9
5
  /** Derive a nested selection; re-runs when the underlying tree version increments. */
10
6
  select<U>(selector: (tree: T) => U): Readable<U>;
11
7
  /** Stop receiving further updates (invoked automatically on component destroy). */
@@ -26,6 +22,6 @@ export interface UseDeepSignalResult<T extends object> extends Readable<T> {
26
22
  * @param deepSignalObjects When the object is not a deepSignal already, options passed to `deepSignal`.
27
23
  * @returns A rune for using the deepSignal object in svelte.
28
24
  */
29
- export declare function useDeepSignal<T extends object>(object: T, options?: DeepSignalOptions): UseDeepSignalResult<RevertDeepSignal<T>>;
25
+ export declare function useDeepSignal<T extends object>(object: T | Promise<T>, options?: DeepSignalOptions): UseDeepSignalResult<RevertDeepSignal<T>>;
30
26
  export default useDeepSignal;
31
27
  //# sourceMappingURL=useDeepSignal.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDeepSignal.svelte.d.ts","sourceRoot":"","sources":["../../../src/hooks/svelte/useDeepSignal.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAGH,KAAK,cAAc,EACnB,iBAAiB,EAEjB,gBAAgB,EAEnB,MAAM,aAAa,CAAC;AAErB,uEAAuE;AACvE,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IACtE,mGAAmG;IACnG,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClB,gGAAgG;IAChG,OAAO,EAAE,QAAQ,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACzC,sFAAsF;IACtF,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjD,mFAAmF;IACnF,OAAO,IAAI,IAAI,CAAC;IAChB,sGAAsG;IACtG,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAChC,4DAA4D;IAC5D,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;CACnD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,iBAAiB,GAC5B,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAiD1C;AAED,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"useDeepSignal.svelte.d.ts","sourceRoot":"","sources":["../../../src/hooks/svelte/useDeepSignal.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAIH,iBAAiB,EAEjB,gBAAgB,EAEnB,MAAM,aAAa,CAAC;AAErB,uEAAuE;AACvE,MAAM,WAAW,mBAAmB,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IACvD,sFAAsF;IACtF,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjD,mFAAmF;IACnF,OAAO,IAAI,IAAI,CAAC;IAChB,sGAAsG;IACtG,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAChC,4DAA4D;IAC5D,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;CACnD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC5B,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAkE1C;AAED,eAAe,aAAa,CAAC"}
@@ -25,26 +25,42 @@ const index_1 = require("../../index");
25
25
  * @returns A rune for using the deepSignal object in svelte.
26
26
  */
27
27
  function useDeepSignal(object, options) {
28
- const deepProxy = (0, index_1.deepSignal)(object, options);
29
- const rootId = (0, index_1.getDeepSignalRootId)(deepProxy);
30
- const initialVersion = (0, index_1.getDeepSignalVersion)(deepProxy) ?? 0;
31
- const version = (0, store_1.writable)(initialVersion);
32
- const patchesStore = (0, store_1.writable)(null);
33
- const unsubscribe = (0, index_1.subscribeDeepMutations)(deepProxy, (batch) => {
34
- if (!rootId)
28
+ const version = (0, store_1.writable)(-1);
29
+ let deepProxy;
30
+ let unsubscribe;
31
+ let isDestroyed = false;
32
+ const init = (obj) => {
33
+ if (isDestroyed)
35
34
  return;
36
- if (batch.patches.length) {
37
- patchesStore.set(batch);
38
- version.set(batch.version);
39
- }
40
- });
41
- const deep = (0, store_1.derived)(version, () => deepProxy);
42
- const select = (selector) => (0, store_1.derived)(deep, (t) => selector(t));
43
- const dispose = () => unsubscribe();
35
+ deepProxy = (0, index_1.deepSignal)(obj, options);
36
+ const rootId = (0, index_1.getDeepSignalRootId)(deepProxy);
37
+ const initialVersion = (0, index_1.getDeepSignalVersion)(deepProxy) ?? 0;
38
+ unsubscribe = (0, index_1.subscribeDeepMutations)(deepProxy, (batch) => {
39
+ if (!rootId)
40
+ return;
41
+ if (batch.patches.length) {
42
+ version.set(batch.version);
43
+ }
44
+ });
45
+ version.set(initialVersion);
46
+ };
47
+ if (object instanceof Promise) {
48
+ object.then(init);
49
+ }
50
+ else {
51
+ init(object);
52
+ }
53
+ const dispose = () => {
54
+ isDestroyed = true;
55
+ if (unsubscribe)
56
+ unsubscribe();
57
+ };
44
58
  (0, svelte_1.onDestroy)(dispose);
59
+ const deep = (0, store_1.derived)(version, () => deepProxy);
60
+ const select = (selector) => (0, store_1.derived)(deep, (t) => (t ? selector(t) : undefined));
45
61
  // Expose Svelte store contract by delegating subscribe to deep store.
46
62
  const applyReplacement = (next) => {
47
- if (!next || typeof next !== "object")
63
+ if (!deepProxy || !next || typeof next !== "object")
48
64
  return;
49
65
  // Remove keys absent in next
50
66
  for (const k of Object.keys(deepProxy)) {
@@ -55,8 +71,6 @@ function useDeepSignal(object, options) {
55
71
  Object.assign(deepProxy, next);
56
72
  };
57
73
  const store = {
58
- deep,
59
- patches: patchesStore,
60
74
  select,
61
75
  dispose,
62
76
  subscribe: deep.subscribe,
@@ -64,6 +78,8 @@ function useDeepSignal(object, options) {
64
78
  applyReplacement(next);
65
79
  },
66
80
  update(updater) {
81
+ if (!deepProxy)
82
+ return;
67
83
  const result = updater(deepProxy);
68
84
  if (result && typeof result === "object")
69
85
  applyReplacement(result);
@@ -1,3 +1,4 @@
1
+ import { type MaybeRefOrGetter } from "vue";
1
2
  import { DeepSignal, DeepSignalOptions } from "../../";
2
3
  /**
3
4
  * Create or use an existing deepSignal object in your component.
@@ -5,11 +6,11 @@ import { DeepSignal, DeepSignalOptions } from "../../";
5
6
  * If modifications of the object are made from somewhere else, the component
6
7
  * is rerendered as well.
7
8
  *
8
- * @param object The object that should become reactive
9
- * @param deepSignalObjects When the object is not a deepSignal already, options passed to `deepSignal`.
9
+ * @param object The object that should become reactive (can be a ref or getter)
10
+ * @param options When the object is not a deepSignal already, options passed to `deepSignal`.
10
11
  * @returns The deepSignal object of the object param.
11
12
  *
12
13
  */
13
- export declare function useDeepSignal<T extends object>(object: T, options?: DeepSignalOptions): DeepSignal<T>;
14
+ export declare function useDeepSignal<T extends object>(object: MaybeRefOrGetter<T>, options?: DeepSignalOptions): DeepSignal<T>;
14
15
  export default useDeepSignal;
15
16
  //# sourceMappingURL=useDeepSignal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDeepSignal.d.ts","sourceRoot":"","sources":["../../../src/hooks/vue/useDeepSignal.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,UAAU,EAAc,iBAAiB,EAAS,MAAM,QAAQ,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAgDf;AAED,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"useDeepSignal.d.ts","sourceRoot":"","sources":["../../../src/hooks/vue/useDeepSignal.ts"],"names":[],"mappings":"AAUA,OAAO,EAGH,KAAK,gBAAgB,EAGxB,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,UAAU,EAAc,iBAAiB,EAAS,MAAM,QAAQ,CAAC;AAE1E;;;;;;;;;;GAUG;AAEH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAkFf;AAED,eAAe,aAAa,CAAC"}
@@ -18,54 +18,82 @@ const __1 = require("../../");
18
18
  * If modifications of the object are made from somewhere else, the component
19
19
  * is rerendered as well.
20
20
  *
21
- * @param object The object that should become reactive
22
- * @param deepSignalObjects When the object is not a deepSignal already, options passed to `deepSignal`.
21
+ * @param object The object that should become reactive (can be a ref or getter)
22
+ * @param options When the object is not a deepSignal already, options passed to `deepSignal`.
23
23
  * @returns The deepSignal object of the object param.
24
24
  *
25
25
  */
26
+ // Note partly written with the help of Gemini 3.
26
27
  function useDeepSignal(object, options) {
27
28
  const version = (0, vue_1.ref)(0);
28
- const signalObject = (0, __1.deepSignal)(object, options);
29
- const stopHandle = (0, __1.watch)(signalObject, ({ patches }) => {
30
- if (patches.length > 0) {
31
- version.value++;
29
+ // Holds the current reactive signal object.
30
+ let currentSignal;
31
+ let stopHandle;
32
+ // Watch the input object for changes.
33
+ const stopWatchingSource = (0, vue_1.watch)(() => (0, vue_1.toValue)(object), (newObj) => {
34
+ if (stopHandle) {
35
+ stopHandle.stopListening();
36
+ stopHandle = undefined;
32
37
  }
33
- });
34
- // Proxy that creates Vue dependency on version for any access
35
- const proxy = new Proxy(signalObject, {
38
+ if (newObj) {
39
+ currentSignal = (0, __1.deepSignal)(newObj, options);
40
+ stopHandle = (0, __1.watch)(currentSignal, ({ patches }) => {
41
+ if (patches.length > 0)
42
+ version.value++;
43
+ });
44
+ }
45
+ // Trigger Vue update.
46
+ version.value++;
47
+ }, { immediate: true });
48
+ // Determines the initial target for the Proxy (array vs object).
49
+ const initialVal = (0, vue_1.toValue)(object);
50
+ const proxyTarget = (Array.isArray(initialVal) ? [] : {});
51
+ // Proxy that creates Vue dependency on version for any access.
52
+ const proxy = new Proxy(proxyTarget, {
36
53
  get(target, key) {
37
54
  if (key === "__raw")
38
- return target;
39
- // Track version to create reactive dependency
55
+ return currentSignal;
56
+ // Track version to create reactive dependency.
40
57
  version.value;
41
- const value = target[key];
42
- // Bind methods to maintain correct `this` context
43
- return typeof value === "function" ? value.bind(target) : value;
58
+ // Delegate to current signal.
59
+ const actualTarget = currentSignal || target;
60
+ const value = Reflect.get(actualTarget, key);
61
+ // Bind methods to maintain correct `this` context.
62
+ return typeof value === "function"
63
+ ? value.bind(actualTarget)
64
+ : value;
44
65
  },
45
66
  set(target, key, value) {
46
- // Directly forward writes to the deep signal root so other frameworks observe the change.
47
- return Reflect.set(target, key, value);
67
+ // Delegate to current signal.
68
+ const actualTarget = currentSignal || target;
69
+ return Reflect.set(actualTarget, key, value);
48
70
  },
49
71
  has(target, key) {
50
72
  version.value;
51
- return key in target;
73
+ const actualTarget = currentSignal || target;
74
+ return Reflect.has(actualTarget, key);
52
75
  },
53
76
  ownKeys(target) {
54
77
  version.value;
55
- return Reflect.ownKeys(target);
78
+ const actualTarget = currentSignal || target;
79
+ return Reflect.ownKeys(actualTarget);
56
80
  },
57
81
  getOwnPropertyDescriptor(target, key) {
58
82
  version.value;
59
- const desc = Object.getOwnPropertyDescriptor(target, key);
83
+ const actualTarget = currentSignal || target;
84
+ const desc = Reflect.getOwnPropertyDescriptor(actualTarget, key);
60
85
  return desc ? { ...desc, configurable: true } : undefined;
61
86
  },
62
87
  });
63
88
  (0, vue_1.onBeforeUnmount)(() => {
64
- try {
65
- stopHandle.stopListening();
66
- }
67
- catch {
68
- // ignore
89
+ stopWatchingSource();
90
+ if (stopHandle) {
91
+ try {
92
+ stopHandle.stopListening();
93
+ }
94
+ catch {
95
+ // ignore
96
+ }
69
97
  }
70
98
  });
71
99
  return proxy;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ declare const PerfSuiteClient: React.FC;
3
+ export default PerfSuiteClient;
4
+ //# sourceMappingURL=PerfSuiteClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PerfSuiteClient.d.ts","sourceRoot":"","sources":["../../../../../../src/test/frontend/astro-app/src/components/PerfSuiteClient.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AA+C5D,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAkL5B,CAAC;AAEF,eAAe,eAAe,CAAC"}