@mmstack/primitives 21.0.20 → 21.0.21

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.
package/README.md CHANGED
@@ -29,6 +29,7 @@ This library provides the following primitives:
29
29
  - `toWritable` - Converts a read-only signal to writable using custom write logic.
30
30
  - `derived` - Creates a signal with two-way binding to a source signal.
31
31
  - `chunked` - Creates a signal that time-slices an array into chunked values & emits thats array based on the provided options.
32
+ - `pooled` / `pooledArray` / `pooledMap` / `pooledSet` - Double-buffered object pools for `computed` signals; recycle the output container to remove allocation pressure in high-frequency recomputation.
32
33
  - `tabSync` - Low level primitive to "share" the value of a WritableSignal accross tabs via the BroadcastChannel api.
33
34
  - `sensor` - A facade function to create various reactive sensor signals (e.g., mouse position, network status, page visibility, dark mode preference)." (This was the suggestion from before; it just reads a little smoother and more accurately reflects what the facade creates directly).
34
35
  - `mediaQuery` - A generic primitive that tracks a CSS media query (forms the basis for `prefersDarkMode` and `prefersReducedMotion`).
@@ -94,7 +95,6 @@ import { JsonPipe } from '@angular/common';
94
95
 
95
96
  @Component({
96
97
  selector: 'app-throttle-demo',
97
- standalone: true,
98
98
  imports: [JsonPipe],
99
99
  template: `
100
100
  <div (mousemove)="onMouseMove($event)" style="width: 300px; height: 200px; border: 1px solid black; padding: 10px; user-select: none;">Move mouse here to see updates...</div>
@@ -196,7 +196,6 @@ import { stored } from '@mmstack/primitives';
196
196
 
197
197
  @Component({
198
198
  selector: 'app-theme-selector',
199
- standalone: true,
200
199
  // imports: [FormsModule], // Import if using ngModel
201
200
  template: `
202
201
  Theme:
@@ -274,7 +273,6 @@ import { JsonPipe } from '@angular/common';
274
273
 
275
274
  @Component({
276
275
  selector: 'app-store-demo',
277
- standalone: true,
278
276
  imports: [FormsModule, JsonPipe],
279
277
  template: `
280
278
  <h3>User Profile</h3>
@@ -658,6 +656,75 @@ export class HeavyListComponent {
658
656
  }
659
657
  ```
660
658
 
659
+ ### pooled / pooledArray / pooledMap / pooledSet
660
+
661
+ A double-buffered object pool for `computed` signal outputs. After a brief warm-up the pool reaches steady state with **zero allocations per recomputation** — two buffers are swapped on every read, with `reset` invoked before each `computation`. Each read returns a different identity from the previous read, so default `Object.is` equality still flags changes correctly. Most users will reach for the preset helpers (`pooledArray`, `pooledMap`, `pooledSet`); drop down to `pooled` only when you need a custom buffer type.
662
+
663
+ > **Retention contract:** the value returned from a pooled signal is only valid until the next read of that signal. The container is reused on the second-next read and will be `reset` first, mutating any reference you still hold. Do not store the result in component state, async closures, or anywhere outside the same reactive tick. Treat it as scratch output consumed synchronously.
664
+
665
+ Use these when a computed is recomputed at high frequency and produces a large allocation (filter/map outputs over big arrays, lookup indices, RAF-driven computeds). For typical UI computeds over small data, just use `computed` — the docs cost and footgun aren't worth saving an allocation that doesn't show up in a profile.
666
+
667
+ ```typescript
668
+ import { Component, signal } from '@angular/core';
669
+ import { pooledArray, pooledMap, pooledSet } from '@mmstack/primitives';
670
+
671
+ @Component({
672
+ selector: 'app-pooled-demo',
673
+ template: `<p>Active: {{ activeIds().length }} / {{ items().length }}</p>`,
674
+ })
675
+ export class PooledDemoComponent {
676
+ readonly items = signal(Array.from({ length: 10_000 }, (_, i) => ({ id: i, active: i % 2 === 0 })));
677
+
678
+ // Recycles a single number[] across recomputations.
679
+ readonly activeIds = pooledArray<number[]>((buf) => {
680
+ for (const item of this.items()) {
681
+ if (item.active) buf.push(item.id);
682
+ }
683
+ return buf;
684
+ });
685
+
686
+ // Recycles a Map for fast id → item lookups.
687
+ readonly byId = pooledMap<Map<number, { id: number; active: boolean }>>((buf) => {
688
+ for (const item of this.items()) buf.set(item.id, item);
689
+ return buf;
690
+ });
691
+
692
+ // Recycles a Set of distinct values.
693
+ readonly distinctFlags = pooledSet<Set<boolean>>((buf) => {
694
+ for (const item of this.items()) buf.add(item.active);
695
+ return buf;
696
+ });
697
+ }
698
+ ```
699
+
700
+ Need a custom buffer type (typed array, your own struct)? Use `pooled` directly:
701
+
702
+ ```typescript
703
+ import { signal } from '@angular/core';
704
+ import { pooled } from '@mmstack/primitives';
705
+
706
+ const source = signal<{ active: boolean }[]>([]);
707
+
708
+ // Pre-allocate both slots at construction (eager) — useful when create() is expensive.
709
+ const counters = pooled<{ total: number; active: number }>({
710
+ create: () => ({ total: 0, active: 0 }),
711
+ reset: (c) => {
712
+ c.total = 0;
713
+ c.active = 0;
714
+ },
715
+ computation: (c) => {
716
+ for (const item of source()) {
717
+ c.total++;
718
+ if (item.active) c.active++;
719
+ }
720
+ return c;
721
+ },
722
+ eager: true,
723
+ });
724
+ ```
725
+
726
+ Complementary to `linkedSignal` (which carries previous *state* forward, not the *container*) and `chunked` (which time-slices large outputs across frames).
727
+
661
728
  ### tabSync
662
729
 
663
730
  A low-level primitive that synchronizes a WritableSignal across multiple browser tabs or windows of the same application using the BroadcastChannel API. Used by the cache in @mmstack/resource & the stored signal.
@@ -681,7 +748,7 @@ import { tabSync } from '@mmstack/primitives';
681
748
  template: `
682
749
  <p>Open this page in two tabs!</p>
683
750
 
684
- <button (click)="counter.update(n => n + 1)">Count: {{ counter() }}</button>
751
+ <button (click)="counter.update((n) => n + 1)">Count: {{ counter() }}</button>
685
752
 
686
753
  <select [ngModel]="theme()" (ngModelChange)="theme.set($event)">
687
754
  <option value="light">Light</option>
@@ -714,7 +781,6 @@ import { Component, signal, effect } from '@angular/core';
714
781
 
715
782
  @Component({
716
783
  selector: 'app-history-demo',
717
- standalone: true,
718
784
  imports: [FormsModule, JsonPipe],
719
785
  template: `
720
786
  <h4>Simple Text Editor</h4>
@@ -781,7 +847,6 @@ import { JsonPipe } from '@angular/common';
781
847
 
782
848
  @Component({
783
849
  selector: 'app-mouse-tracker',
784
- standalone: true,
785
850
  imports: [JsonPipe],
786
851
  template: `
787
852
  <div (mousemove)="onMouseMove($event)" style="width: 300px; height: 200px; border: 1px solid black; padding: 10px; user-select: none;">Move mouse here...</div>
@@ -819,7 +884,6 @@ import { DatePipe } from '@angular/common';
819
884
 
820
885
  @Component({
821
886
  selector: 'app-network-info',
822
- standalone: true,
823
887
  imports: [DatePipe],
824
888
  template: `
825
889
  @if (netStatus()) {
@@ -850,7 +914,6 @@ import { sensor } from '@mmstack/primitives'; // Or import { pageVisibility }
850
914
 
851
915
  @Component({
852
916
  selector: 'app-visibility-logger',
853
- standalone: true,
854
917
  template: `<p>Page is currently: {{ visibility() }}</p>`,
855
918
  })
856
919
  export class VisibilityLoggerComponent {
@@ -877,7 +940,6 @@ import { sensor } from '@mmstack/primitives'; // Or import { windowSize }
877
940
 
878
941
  @Component({
879
942
  selector: 'app-responsive-display',
880
- standalone: true,
881
943
  template: `
882
944
  <p>Current Window Size: {{ winSize().width }}px x {{ winSize().height }}px</p>
883
945
  <p>Unthrottled: W: {{ winSize.unthrottled().width }} H: {{ winSize.unthrottled().height }}</p>
@@ -911,7 +973,6 @@ import { JsonPipe } from '@angular/common';
911
973
 
912
974
  @Component({
913
975
  selector: 'app-scroll-indicator',
914
- standalone: true,
915
976
  imports: [JsonPipe],
916
977
  template: `
917
978
  <div style="height: 100px; border-bottom: 2px solid red; position: fixed; top: 0; left: 0; width: 100%; background: white; z-index: 10;">
@@ -945,7 +1006,6 @@ import { mediaQuery, prefersDarkMode, prefersReducedMotion } from '@mmstack/prim
945
1006
 
946
1007
  @Component({
947
1008
  selector: 'app-layout-checker',
948
- standalone: true,
949
1009
  template: `
950
1010
  @if (isLargeScreen()) {
951
1011
  <p>Using large screen layout.</p>
@@ -1007,7 +1067,6 @@ import { elementVisibility } from '@mmstack/primitives';
1007
1067
 
1008
1068
  @Component({
1009
1069
  selector: 'app-lazy-load-item',
1010
- standalone: true,
1011
1070
  template: `
1012
1071
  <div #itemToObserve style="height: 300px; margin-top: 100vh; border: 2px solid green;">
1013
1072
  @if (intersectionEntry.visible()) {
@@ -197,7 +197,7 @@ function chunked(source, options) {
197
197
  return () => clearTimeout(num);
198
198
  };
199
199
  }
200
- const internal = linkedSignal({ ...(ngDevMode ? { debugName: "internal" } : {}), source,
200
+ const internal = linkedSignal({ ...(ngDevMode ? { debugName: "internal" } : /* istanbul ignore next */ {}), source,
201
201
  computation: (items) => items.slice(0, chunkSize),
202
202
  equal });
203
203
  nestedEffect((cleanup) => {
@@ -311,7 +311,7 @@ function debounced(initial, opt) {
311
311
  */
312
312
  function debounce(source, opt) {
313
313
  const ms = opt?.ms ?? 0;
314
- const trigger = signal(false, ...(ngDevMode ? [{ debugName: "trigger" }] : []));
314
+ const trigger = signal(false, ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
315
315
  let timeout;
316
316
  try {
317
317
  const destroyRef = opt?.destroyRef ?? inject(DestroyRef, { optional: true });
@@ -540,7 +540,7 @@ function createItemSignal(source, index, setter, opt) {
540
540
  }
541
541
  function indexArray(source, map, opt = {}) {
542
542
  const data = isSignal(source) ? source : computed(source);
543
- const len = computed(() => data().length, ...(ngDevMode ? [{ debugName: "len" }] : []));
543
+ const len = computed(() => data().length, ...(ngDevMode ? [{ debugName: "len" }] : /* istanbul ignore next */ []));
544
544
  const setter = createSetter(data);
545
545
  const writableData = isWritableSignal(data)
546
546
  ? data
@@ -643,7 +643,7 @@ function keyArray(source, mapFn, options = {}) {
643
643
  for (j = 0; j < newLen; j++) {
644
644
  item = newItems[j];
645
645
  items[j] = item;
646
- const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : []));
646
+ const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : /* istanbul ignore next */ []));
647
647
  newIndexes[j] = indexSignal;
648
648
  newMapped[j] = mapFn(item, indexSignal);
649
649
  }
@@ -693,7 +693,7 @@ function keyArray(source, mapFn, options = {}) {
693
693
  newIndexes[j].set(j);
694
694
  }
695
695
  else {
696
- const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : []));
696
+ const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : /* istanbul ignore next */ []));
697
697
  newIndexes[j] = indexSignal;
698
698
  newMapped[j] = mapFn(newItems[j], indexSignal);
699
699
  }
@@ -840,6 +840,102 @@ function piped(initial, opt) {
840
840
  return pipeable(signal(initial, opt));
841
841
  }
842
842
 
843
+ /**
844
+ * A `Signal<U>` backed by a two-slot object pool: `create` is called at most
845
+ * twice over the pool's lifetime, and the two `T` instances are swapped on
846
+ * every recomputation with `reset` invoked on the dirty one before
847
+ * `computation` writes into it. Consecutive reads return different identities,
848
+ * so the default `Object.is` equality still flags changes.
849
+ *
850
+ * **Retention contract:** the returned value is only valid until the next
851
+ * recomputation of this signal. The container is recycled and `reset`,
852
+ * mutating any reference you still hold — do not store the result, pass it to
853
+ * async code, or hand it to consumers that outlive the current reactive tick.
854
+ *
855
+ * For collection buffers prefer the presets: {@link pooledArray},
856
+ * {@link pooledMap}, {@link pooledSet}.
857
+ *
858
+ * @see [Angular `linkedSignal`](https://angular.dev/api/core/linkedSignal) — carries previous *state* forward; complementary, not a substitute.
859
+ *
860
+ * @example
861
+ * ```ts
862
+ * const source = signal<{ active: boolean }[]>([]);
863
+ *
864
+ * const counters = pooled<{ total: number; active: number }>({
865
+ * create: () => ({ total: 0, active: 0 }),
866
+ * reset: (c) => { c.total = 0; c.active = 0; },
867
+ * computation: (c) => {
868
+ * for (const item of source()) { c.total++; if (item.active) c.active++; }
869
+ * return c;
870
+ * },
871
+ * });
872
+ * ```
873
+ */
874
+ function pooled({ create, reset, computation, ...opt }) {
875
+ let other = opt.eager ? create() : undefined;
876
+ let current = opt.eager ? create() : undefined;
877
+ let otherFresh = opt.eager;
878
+ let currentFresh = opt.eager;
879
+ return computed(() => {
880
+ let next;
881
+ let nextFresh;
882
+ if (other !== undefined) {
883
+ next = other;
884
+ nextFresh = !!otherFresh;
885
+ }
886
+ else {
887
+ next = untracked(() => create());
888
+ nextFresh = true;
889
+ }
890
+ if (current !== undefined) {
891
+ other = current;
892
+ otherFresh = currentFresh;
893
+ }
894
+ current = next;
895
+ // the buffer is about to be mutated by `computation`, so it's no longer fresh
896
+ currentFresh = false;
897
+ const clean = nextFresh ? next : (untracked(() => reset(next)) ?? next);
898
+ return computation(clean);
899
+ }, opt);
900
+ }
901
+
902
+ function toPooledOptions(optOrComputation, create, reset, signalOpt) {
903
+ const opt = typeof optOrComputation === 'object' ? optOrComputation : signalOpt;
904
+ const computation = typeof optOrComputation === 'function'
905
+ ? optOrComputation
906
+ : optOrComputation.computation;
907
+ return {
908
+ create,
909
+ reset,
910
+ computation,
911
+ ...opt,
912
+ };
913
+ }
914
+ function createEmptyArray() {
915
+ return [];
916
+ }
917
+ function resetArray(arr) {
918
+ arr.length = 0;
919
+ }
920
+ function pooledArray(optOrComputation, signalOpt) {
921
+ return pooled(toPooledOptions(optOrComputation, createEmptyArray, resetArray, signalOpt));
922
+ }
923
+ function createEmptySet() {
924
+ return new Set();
925
+ }
926
+ function resetClearable(clearable) {
927
+ clearable.clear();
928
+ }
929
+ function pooledSet(optOrComputation, signalOpt) {
930
+ return pooled(toPooledOptions(optOrComputation, createEmptySet, resetClearable, signalOpt));
931
+ }
932
+ function createEmptyMap() {
933
+ return new Map();
934
+ }
935
+ function pooledMap(optOrComputation, signalOpt) {
936
+ return pooled(toPooledOptions(optOrComputation, createEmptyMap, resetClearable, signalOpt));
937
+ }
938
+
843
939
  function observerSupported$1() {
844
940
  return typeof ResizeObserver !== 'undefined';
845
941
  }
@@ -999,7 +1095,7 @@ function elementVisibility(target = inject(ElementRef), opt) {
999
1095
  const base = computed(() => undefined, {
1000
1096
  debugName: opt?.debugName,
1001
1097
  });
1002
- base.visible = computed(() => false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
1098
+ base.visible = computed(() => false, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
1003
1099
  return base;
1004
1100
  }
1005
1101
  const state = signal(undefined, {
@@ -1036,7 +1132,7 @@ function elementVisibility(target = inject(ElementRef), opt) {
1036
1132
  if (!s)
1037
1133
  return false;
1038
1134
  return s.isIntersecting;
1039
- }, ...(ngDevMode ? [{ debugName: "visible" }] : []));
1135
+ }, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
1040
1136
  return base;
1041
1137
  }
1042
1138
 
@@ -1201,7 +1297,7 @@ function throttled(initial, opt) {
1201
1297
  */
1202
1298
  function throttle(source, opt) {
1203
1299
  const ms = opt?.ms ?? 0;
1204
- const trigger = signal(false, ...(ngDevMode ? [{ debugName: "trigger" }] : []));
1300
+ const trigger = signal(false, ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
1205
1301
  let timeout;
1206
1302
  try {
1207
1303
  const destroyRef = opt?.destroyRef ?? inject(DestroyRef, { optional: true });
@@ -1347,11 +1443,11 @@ function networkStatus(debugName = 'networkStatus') {
1347
1443
  const sig = computed(() => true, {
1348
1444
  debugName,
1349
1445
  });
1350
- sig.since = computed(() => serverDate, ...(ngDevMode ? [{ debugName: "since" }] : []));
1446
+ sig.since = computed(() => serverDate, ...(ngDevMode ? [{ debugName: "since" }] : /* istanbul ignore next */ []));
1351
1447
  return sig;
1352
1448
  }
1353
- const state = signal(navigator.onLine, { ...(ngDevMode ? { debugName: "state" } : {}), debugName });
1354
- const since = signal(new Date(), ...(ngDevMode ? [{ debugName: "since" }] : []));
1449
+ const state = signal(navigator.onLine, { ...(ngDevMode ? { debugName: "state" } : /* istanbul ignore next */ {}), debugName });
1450
+ const since = signal(new Date(), ...(ngDevMode ? [{ debugName: "since" }] : /* istanbul ignore next */ []));
1355
1451
  const goOnline = () => {
1356
1452
  state.set(true);
1357
1453
  since.set(new Date());
@@ -1411,7 +1507,7 @@ function pageVisibility(debugName = 'pageVisibility') {
1411
1507
  if (isPlatformServer(inject(PLATFORM_ID))) {
1412
1508
  return computed(() => 'visible', { debugName });
1413
1509
  }
1414
- const visibility = signal(document.visibilityState, { ...(ngDevMode ? { debugName: "visibility" } : {}), debugName });
1510
+ const visibility = signal(document.visibilityState, { ...(ngDevMode ? { debugName: "visibility" } : /* istanbul ignore next */ {}), debugName });
1415
1511
  const onVisibilityChange = () => visibility.set(document.visibilityState);
1416
1512
  document.addEventListener('visibilitychange', onVisibilityChange);
1417
1513
  inject(DestroyRef).onDestroy(() => document.removeEventListener('visibilitychange', onVisibilityChange));
@@ -1675,7 +1771,7 @@ function toArrayStore(source, injector) {
1675
1771
  if (!Array.isArray(v))
1676
1772
  return 0;
1677
1773
  return v.length;
1678
- }, ...(ngDevMode ? [{ debugName: "lengthSignal" }] : []));
1774
+ }, ...(ngDevMode ? [{ debugName: "lengthSignal" }] : /* istanbul ignore next */ []));
1679
1775
  return new Proxy(source, {
1680
1776
  has(_, prop) {
1681
1777
  if (prop === 'length')
@@ -1940,7 +2036,6 @@ const noopStore = {
1940
2036
  *
1941
2037
  * @Component({
1942
2038
  * selector: 'app-settings',
1943
- * standalone: true,
1944
2039
  * template: `
1945
2040
  * Theme:
1946
2041
  * <select [ngModel]="theme()" (ngModelChange)="theme.set($event)">
@@ -1998,7 +2093,7 @@ function stored(fallback, { key, store: providedStore, serialize = JSON.stringif
1998
2093
  equal,
1999
2094
  };
2000
2095
  const initialKey = untracked(keySig);
2001
- const internal = signal(getValue(initialKey), { ...(ngDevMode ? { debugName: "internal" } : {}), ...opt,
2096
+ const internal = signal(getValue(initialKey), { ...(ngDevMode ? { debugName: "internal" } : /* istanbul ignore next */ {}), ...opt,
2002
2097
  equal: (a, b) => {
2003
2098
  if (a === null && b === null)
2004
2099
  return true;
@@ -2083,10 +2178,10 @@ class MessageBus {
2083
2178
  this.channel.removeEventListener('message', listener);
2084
2179
  this.listeners.delete(id);
2085
2180
  }
2086
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: MessageBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2087
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: MessageBus, providedIn: 'root' });
2181
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: MessageBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2182
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: MessageBus, providedIn: 'root' });
2088
2183
  }
2089
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: MessageBus, decorators: [{
2184
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: MessageBus, decorators: [{
2090
2185
  type: Injectable,
2091
2186
  args: [{
2092
2187
  providedIn: 'root',
@@ -2163,7 +2258,7 @@ function tabSync(sig, opt) {
2163
2258
  return;
2164
2259
  }
2165
2260
  post(val);
2166
- }, ...(ngDevMode ? [{ debugName: "effectRef" }] : []));
2261
+ }, ...(ngDevMode ? [{ debugName: "effectRef" }] : /* istanbul ignore next */ []));
2167
2262
  inject(DestroyRef).onDestroy(() => {
2168
2263
  effectRef.destroy();
2169
2264
  unsub();
@@ -2359,9 +2454,9 @@ function withHistory(source, opt) {
2359
2454
  history.set([]);
2360
2455
  redoArray.set([]);
2361
2456
  };
2362
- internal.canUndo = computed(() => history().length > 0, ...(ngDevMode ? [{ debugName: "canUndo" }] : []));
2363
- internal.canRedo = computed(() => redoArray().length > 0, ...(ngDevMode ? [{ debugName: "canRedo" }] : []));
2364
- internal.canClear = computed(() => internal.canUndo() || internal.canRedo(), ...(ngDevMode ? [{ debugName: "canClear" }] : []));
2457
+ internal.canUndo = computed(() => history().length > 0, ...(ngDevMode ? [{ debugName: "canUndo" }] : /* istanbul ignore next */ []));
2458
+ internal.canRedo = computed(() => redoArray().length > 0, ...(ngDevMode ? [{ debugName: "canRedo" }] : /* istanbul ignore next */ []));
2459
+ internal.canClear = computed(() => internal.canUndo() || internal.canRedo(), ...(ngDevMode ? [{ debugName: "canClear" }] : /* istanbul ignore next */ []));
2365
2460
  return internal;
2366
2461
  }
2367
2462
 
@@ -2369,5 +2464,5 @@ function withHistory(source, opt) {
2369
2464
  * Generated bundle index. Do not edit.
2370
2465
  */
2371
2466
 
2372
- export { chunked, combineWith, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, indexArray, isDerivation, isMutable, isStore, keyArray, map, mapArray, mapObject, mediaQuery, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, pageVisibility, pipeable, piped, prefersDarkMode, prefersReducedMotion, scrollPosition, select, sensor, sensors, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
2467
+ export { chunked, combineWith, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, indexArray, isDerivation, isMutable, isStore, keyArray, map, mapArray, mapObject, mediaQuery, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, pageVisibility, pipeable, piped, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, scrollPosition, select, sensor, sensors, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
2373
2468
  //# sourceMappingURL=mmstack-primitives.mjs.map