@rlabs-inc/signals 1.12.0 → 1.13.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.
package/README.md CHANGED
@@ -85,6 +85,10 @@ flushSync() // Logs: "Count: 5, Doubled: 10"
85
85
  - [typedSlotArray](#typedslotarray)
86
86
  - [typedSlotArrayGroup](#typedslotarraygroup)
87
87
  - [reactiveProps](#reactiveprops)
88
+ - [Shared Memory](#shared-memory)
89
+ - [SharedSlotBuffer](#sharedslotbuffer)
90
+ - [Repeater](#repeater)
91
+ - [Notifier](#notifier)
88
92
  - [Deep Reactivity](#deep-reactivity)
89
93
  - [Utilities](#utilities)
90
94
  - [Reactive Collections](#reactive-collections)
@@ -720,6 +724,91 @@ MyComponent({ name: nameSignal, count: () => getCount(), active: activeSignal })
720
724
 
721
725
  ---
722
726
 
727
+ ## Shared Memory
728
+
729
+ Cross-language reactive shared memory primitives. Three layers that connect independent reactive graphs (e.g., TypeScript and Rust) through SharedArrayBuffer with zero serialization.
730
+
731
+ ### SharedSlotBuffer
732
+
733
+ Reactive typed arrays backed by shared memory. `get()` tracks dependencies, `set()` writes + notifies the reactive graph + notifies the other side.
734
+
735
+ ```typescript
736
+ import { sharedSlotBuffer, sharedSlotBufferGroup, NoopNotifier } from '@rlabs-inc/signals'
737
+
738
+ // Create a buffer backed by SharedArrayBuffer
739
+ const sab = new SharedArrayBuffer(4096 * 4)
740
+ const widths = sharedSlotBuffer({
741
+ buffer: new Float32Array(sab),
742
+ notifier: new NoopNotifier(), // or AtomicsNotifier for cross-thread
743
+ })
744
+
745
+ // Reactive read — tracks dependency in deriveds/effects
746
+ const w = widths.get(0)
747
+
748
+ // Write — updates shared memory + marks reactions dirty + notifies
749
+ widths.set(0, 150.0)
750
+
751
+ // Batch write — single notification at the end
752
+ widths.setBatch([[0, 100], [1, 200], [2, 300]])
753
+
754
+ // Direct TypedArray access for FFI
755
+ nativeEngine(widths.raw) // Float32Array on SharedArrayBuffer
756
+
757
+ // Create a group of buffers with shared dirty tracking
758
+ const layout = sharedSlotBufferGroup({
759
+ width: { buffer: new Float32Array(sab, 0, 4096), notifier },
760
+ height: { buffer: new Float32Array(sab, 4096 * 4, 4096), notifier },
761
+ })
762
+ ```
763
+
764
+ ### Repeater
765
+
766
+ A new reactive graph primitive — NOT an effect, NOT a derived. A purpose-built forwarding node that runs **inline during `markReactions`** with zero scheduling overhead. ~40-50 bytes per binding (vs ~200+ for Effect).
767
+
768
+ ```typescript
769
+ import { signal, repeat } from '@rlabs-inc/signals'
770
+
771
+ const myWidth = signal(100)
772
+
773
+ // Bind signal → buffer position
774
+ // When myWidth changes, the repeater forwards the value inline
775
+ const dispose = repeat(myWidth, widthBuffer, 0)
776
+
777
+ // That's it. No effect scheduling, no microtask delay.
778
+ // myWidth.value = 200 → buffer[0] is 200 during the same markReactions pass
779
+ ```
780
+
781
+ **How it works:**
782
+ ```
783
+ myWidth.value = 200
784
+ → markReactions(myWidth)
785
+ → encounters REPEATER node
786
+ → calls forward() INLINE (not scheduled)
787
+ → reads myWidth (already 200)
788
+ → writes buffer[0] = 200
789
+ → sets dirty flag
790
+ → notifier.notify() (batched)
791
+ → markReactions continues...
792
+ ```
793
+
794
+ ### Notifier
795
+
796
+ Pluggable cross-side notification. Decouples the reactive system from the transport layer.
797
+
798
+ ```typescript
799
+ import { AtomicsNotifier, NoopNotifier } from '@rlabs-inc/signals'
800
+
801
+ // For cross-thread/cross-language communication
802
+ const wakeFlag = new Int32Array(new SharedArrayBuffer(4))
803
+ const notifier = new AtomicsNotifier(wakeFlag)
804
+ // Multiple synchronous writes → single Atomics.notify via microtask batching
805
+
806
+ // For testing (no-op)
807
+ const silent = new NoopNotifier()
808
+ ```
809
+
810
+ ---
811
+
723
812
  ## Deep Reactivity
724
813
 
725
814
  ### proxy
@@ -34,6 +34,8 @@ export declare const UNOWNED: number;
34
34
  export declare const DISCONNECTED: number;
35
35
  /** Effect is an inspect effect (for $inspect) */
36
36
  export declare const INSPECT_EFFECT: number;
37
+ /** Reaction is a repeater (inline write-through forwarding node) */
38
+ export declare const REPEATER: number;
37
39
  /** Sentinel for uninitialized values (deleted properties, new deriveds) */
38
40
  export declare const UNINITIALIZED: unique symbol;
39
41
  /** Sentinel for stale reactions (aborted async work) */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AASA,2CAA2C;AAC3C,eAAO,MAAM,OAAO,QAAS,CAAA;AAE7B,0BAA0B;AAC1B,eAAO,MAAM,MAAM,QAAS,CAAA;AAE5B,wEAAwE;AACxE,eAAO,MAAM,aAAa,QAAS,CAAA;AAEnC,0DAA0D;AAC1D,eAAO,MAAM,WAAW,QAAS,CAAA;AAEjC,iDAAiD;AACjD,eAAO,MAAM,aAAa,QAAS,CAAA;AAEnC,wCAAwC;AACxC,eAAO,MAAM,WAAW,QAAS,CAAA;AAEjC,+BAA+B;AAC/B,eAAO,MAAM,YAAY,QAAS,CAAA;AAMlC,4CAA4C;AAC5C,eAAO,MAAM,KAAK,QAAU,CAAA;AAE5B,yDAAyD;AACzD,eAAO,MAAM,KAAK,QAAU,CAAA;AAE5B,mEAAmE;AACnE,eAAO,MAAM,WAAW,QAAU,CAAA;AAElC,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,QAAU,CAAA;AAE3C,gCAAgC;AAChC,eAAO,MAAM,SAAS,QAAU,CAAA;AAEhC,+BAA+B;AAC/B,eAAO,MAAM,KAAK,QAAU,CAAA;AAE5B,mCAAmC;AACnC,eAAO,MAAM,UAAU,QAAU,CAAA;AAEjC,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,QAAU,CAAA;AAMvC,oDAAoD;AACpD,eAAO,MAAM,OAAO,QAAS,CAAA;AAE7B,0DAA0D;AAC1D,eAAO,MAAM,YAAY,QAAS,CAAA;AAMlC,iDAAiD;AACjD,eAAO,MAAM,cAAc,QAAU,CAAA;AAMrC,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,OAAO,MAAkD,CAAA;AAErF,wDAAwD;AACxD,eAAO,MAAM,cAAc,EAAE,OAAO,MAAmD,CAAA;AAEvF,0CAA0C;AAC1C,eAAO,MAAM,YAAY,EAAE,OAAO,MAA0C,CAAA;AAE5E,sCAAsC;AACtC,eAAO,MAAM,eAAe,EAAE,OAAO,MAA6C,CAAA;AAElF,+DAA+D;AAC/D,eAAO,MAAM,cAAc,EAAE,OAAO,MAA4C,CAAA;AAEhF,8CAA8C;AAC9C,eAAO,MAAM,aAAa,EAAE,OAAO,MAA2C,CAAA;AAE9E,sCAAsC;AACtC,eAAO,MAAM,WAAW,EAAE,OAAO,MAAyC,CAAA;AAM1E,sCAAsC;AACtC,eAAO,MAAM,MAAM,QAAS,CAAA;AAM5B,gEAAgE;AAChE,eAAO,MAAM,WAAW,QAAiC,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AASA,2CAA2C;AAC3C,eAAO,MAAM,OAAO,QAAS,CAAA;AAE7B,0BAA0B;AAC1B,eAAO,MAAM,MAAM,QAAS,CAAA;AAE5B,wEAAwE;AACxE,eAAO,MAAM,aAAa,QAAS,CAAA;AAEnC,0DAA0D;AAC1D,eAAO,MAAM,WAAW,QAAS,CAAA;AAEjC,iDAAiD;AACjD,eAAO,MAAM,aAAa,QAAS,CAAA;AAEnC,wCAAwC;AACxC,eAAO,MAAM,WAAW,QAAS,CAAA;AAEjC,+BAA+B;AAC/B,eAAO,MAAM,YAAY,QAAS,CAAA;AAMlC,4CAA4C;AAC5C,eAAO,MAAM,KAAK,QAAU,CAAA;AAE5B,yDAAyD;AACzD,eAAO,MAAM,KAAK,QAAU,CAAA;AAE5B,mEAAmE;AACnE,eAAO,MAAM,WAAW,QAAU,CAAA;AAElC,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,QAAU,CAAA;AAE3C,gCAAgC;AAChC,eAAO,MAAM,SAAS,QAAU,CAAA;AAEhC,+BAA+B;AAC/B,eAAO,MAAM,KAAK,QAAU,CAAA;AAE5B,mCAAmC;AACnC,eAAO,MAAM,UAAU,QAAU,CAAA;AAEjC,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,QAAU,CAAA;AAMvC,oDAAoD;AACpD,eAAO,MAAM,OAAO,QAAS,CAAA;AAE7B,0DAA0D;AAC1D,eAAO,MAAM,YAAY,QAAS,CAAA;AAMlC,iDAAiD;AACjD,eAAO,MAAM,cAAc,QAAU,CAAA;AAErC,oEAAoE;AACpE,eAAO,MAAM,QAAQ,QAAU,CAAA;AAM/B,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,OAAO,MAAkD,CAAA;AAErF,wDAAwD;AACxD,eAAO,MAAM,cAAc,EAAE,OAAO,MAAmD,CAAA;AAEvF,0CAA0C;AAC1C,eAAO,MAAM,YAAY,EAAE,OAAO,MAA0C,CAAA;AAE5E,sCAAsC;AACtC,eAAO,MAAM,eAAe,EAAE,OAAO,MAA6C,CAAA;AAElF,+DAA+D;AAC/D,eAAO,MAAM,cAAc,EAAE,OAAO,MAA4C,CAAA;AAEhF,8CAA8C;AAC9C,eAAO,MAAM,aAAa,EAAE,OAAO,MAA2C,CAAA;AAE9E,sCAAsC;AACtC,eAAO,MAAM,WAAW,EAAE,OAAO,MAAyC,CAAA;AAM1E,sCAAsC;AACtC,eAAO,MAAM,MAAM,QAAS,CAAA;AAM5B,gEAAgE;AAChE,eAAO,MAAM,WAAW,QAAiC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -18,8 +18,13 @@ export { ReactiveSet } from './collections/set.js';
18
18
  export { ReactiveDate } from './collections/date.js';
19
19
  export { ReactiveSharedFloat32Array, ReactiveSharedUint8Array, ReactiveSharedInt32Array, ReactiveSharedUint32Array, createSharedBufferContext, notifyNative, scheduleNotify, } from './shared/reactive-shared-array.js';
20
20
  export type { SharedBufferContext, ReactiveSharedArrayOptions, } from './shared/reactive-shared-array.js';
21
+ export { sharedSlotBuffer, sharedSlotBufferGroup } from './shared/shared-slot-buffer.js';
22
+ export type { SharedSlotBuffer, SharedSlotBufferOptions, SharedSlotBufferGroupConfig } from './shared/shared-slot-buffer.js';
23
+ export { AtomicsNotifier, NoopNotifier } from './shared/notifier.js';
24
+ export type { Notifier } from './shared/notifier.js';
25
+ export { repeat } from './primitives/repeater.js';
21
26
  export { get, set, isDirty, setSignalStatus, markReactions, updateReaction, removeReactions, disconnectSource, } from './reactivity/tracking.js';
22
- export { DERIVED, EFFECT, RENDER_EFFECT, ROOT_EFFECT, BRANCH_EFFECT, USER_EFFECT, BLOCK_EFFECT, CLEAN, DIRTY, MAYBE_DIRTY, REACTION_IS_UPDATING, DESTROYED, INERT, EFFECT_RAN, EFFECT_PRESERVED, UNOWNED, DISCONNECTED, UNINITIALIZED, STALE_REACTION, STATE_SYMBOL, REACTIVE_MARKER, BINDING_SYMBOL, LINKED_SYMBOL, SLOT_SYMBOL, } from './core/constants.js';
27
+ export { DERIVED, EFFECT, RENDER_EFFECT, ROOT_EFFECT, BRANCH_EFFECT, USER_EFFECT, BLOCK_EFFECT, CLEAN, DIRTY, MAYBE_DIRTY, REACTION_IS_UPDATING, DESTROYED, INERT, EFFECT_RAN, EFFECT_PRESERVED, UNOWNED, DISCONNECTED, REPEATER, UNINITIALIZED, STALE_REACTION, STATE_SYMBOL, REACTIVE_MARKER, BINDING_SYMBOL, LINKED_SYMBOL, SLOT_SYMBOL, } from './core/constants.js';
23
28
  export { activeReaction, activeEffect, untracking, writeVersion, readVersion, batchDepth, setActiveReaction, setActiveEffect, setUntracking, incrementWriteVersion, incrementReadVersion, incrementBatchDepth, decrementBatchDepth, getReadVersion, getWriteVersion, getBatchDepth, } from './core/globals.js';
24
29
  export type { Signal, Source, Reaction, Derived, Effect, Value, ReadableSignal, WritableSignal, DerivedSignal, DisposeFn, CleanupFn, EffectFn, Equals, Uninitialized, ExtractInner, } from './core/types.js';
25
30
  export type { Binding, ReadonlyBinding } from './primitives/bind.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -47,6 +47,8 @@ __export(exports_src, {
47
47
  slot: () => slot,
48
48
  signals: () => signals,
49
49
  signal: () => signal,
50
+ sharedSlotBufferGroup: () => sharedSlotBufferGroup,
51
+ sharedSlotBuffer: () => sharedSlotBuffer,
50
52
  shallowEquals: () => shallowEquals,
51
53
  setUntracking: () => setUntracking,
52
54
  setSignalStatus: () => setSignalStatus,
@@ -56,6 +58,7 @@ __export(exports_src, {
56
58
  scheduleNotify: () => scheduleNotify,
57
59
  safeNotEqual: () => safeNotEqual,
58
60
  safeEquals: () => safeEquals,
61
+ repeat: () => repeat,
59
62
  removeReactions: () => removeReactions,
60
63
  readVersion: () => readVersion,
61
64
  reactiveProps: () => reactiveProps,
@@ -119,9 +122,11 @@ __export(exports_src, {
119
122
  ReactiveMap: () => ReactiveMap,
120
123
  ReactiveDate: () => ReactiveDate,
121
124
  ROOT_EFFECT: () => ROOT_EFFECT,
125
+ REPEATER: () => REPEATER,
122
126
  RENDER_EFFECT: () => RENDER_EFFECT,
123
127
  REACTIVE_MARKER: () => REACTIVE_MARKER,
124
128
  REACTION_IS_UPDATING: () => REACTION_IS_UPDATING,
129
+ NoopNotifier: () => NoopNotifier,
125
130
  MAYBE_DIRTY: () => MAYBE_DIRTY,
126
131
  LINKED_SYMBOL: () => LINKED_SYMBOL,
127
132
  INERT: () => INERT,
@@ -135,7 +140,8 @@ __export(exports_src, {
135
140
  CLEAN: () => CLEAN,
136
141
  BRANCH_EFFECT: () => BRANCH_EFFECT,
137
142
  BLOCK_EFFECT: () => BLOCK_EFFECT,
138
- BINDING_SYMBOL: () => BINDING_SYMBOL
143
+ BINDING_SYMBOL: () => BINDING_SYMBOL,
144
+ AtomicsNotifier: () => AtomicsNotifier
139
145
  });
140
146
  module.exports = __toCommonJS(exports_src);
141
147
 
@@ -201,6 +207,7 @@ var EFFECT_PRESERVED = 1 << 17;
201
207
  var UNOWNED = 1 << 8;
202
208
  var DISCONNECTED = 1 << 9;
203
209
  var INSPECT_EFFECT = 1 << 18;
210
+ var REPEATER = 1 << 19;
204
211
  var UNINITIALIZED = Symbol.for("rlabs.signals.uninitialized");
205
212
  var STALE_REACTION = Symbol.for("rlabs.signals.stale_reaction");
206
213
  var STATE_SYMBOL = Symbol.for("rlabs.signals.state");
@@ -415,6 +422,110 @@ async function tick() {
415
422
  flushSync();
416
423
  }
417
424
 
425
+ // src/primitives/repeater.ts
426
+ var SOURCE_SYMBOL = Symbol.for("signal.source");
427
+ function resolveSource(input) {
428
+ if (typeof input === "number") {
429
+ return null;
430
+ }
431
+ if (typeof input === "function") {
432
+ return null;
433
+ }
434
+ const maybeSource = input;
435
+ if (maybeSource && typeof maybeSource.f === "number" && "v" in maybeSource && "reactions" in maybeSource) {
436
+ return {
437
+ source: maybeSource,
438
+ readFn: () => get(maybeSource)
439
+ };
440
+ }
441
+ const src = input[SOURCE_SYMBOL];
442
+ if (src && typeof src.f === "number" && "reactions" in src) {
443
+ return { source: src, readFn: () => get(src) };
444
+ }
445
+ return null;
446
+ }
447
+ function repeat(input, target, index) {
448
+ if (typeof input === "number") {
449
+ target.set(index, input);
450
+ return () => {};
451
+ }
452
+ if (typeof input === "function") {
453
+ return repeatGetter(input, target, index);
454
+ }
455
+ const resolved = resolveSource(input);
456
+ if (resolved) {
457
+ return repeatSource(resolved.source, resolved.readFn, target, index);
458
+ }
459
+ if (typeof input.value !== "undefined") {
460
+ return repeatSignalWrapper(input, target, index);
461
+ }
462
+ throw new Error("repeat(): unsupported source type");
463
+ }
464
+ function repeatSource(src, readFn, target, index) {
465
+ const node = {
466
+ f: REPEATER | CLEAN,
467
+ wv: 0,
468
+ fn: null,
469
+ deps: [src],
470
+ _readFn: readFn,
471
+ _target: target,
472
+ _index: index
473
+ };
474
+ if (src.reactions === null) {
475
+ src.reactions = [node];
476
+ } else {
477
+ src.reactions.push(node);
478
+ }
479
+ target.set(index, readFn());
480
+ return () => {
481
+ node.f |= DESTROYED;
482
+ if (src.reactions) {
483
+ const idx = src.reactions.indexOf(node);
484
+ if (idx !== -1) {
485
+ const last = src.reactions.length - 1;
486
+ if (idx !== last)
487
+ src.reactions[idx] = src.reactions[last];
488
+ src.reactions.pop();
489
+ if (src.reactions.length === 0)
490
+ src.reactions = null;
491
+ }
492
+ }
493
+ };
494
+ }
495
+ function repeatGetter(getter, target, index) {
496
+ const node = {
497
+ f: REPEATER | CLEAN,
498
+ wv: 0,
499
+ fn: getter,
500
+ deps: null,
501
+ _readFn: getter,
502
+ _target: target,
503
+ _index: index
504
+ };
505
+ const initialValue = updateReaction(node);
506
+ target.set(index, initialValue);
507
+ return () => {
508
+ node.f |= DESTROYED;
509
+ removeReactions(node, 0);
510
+ node.deps = null;
511
+ };
512
+ }
513
+ function repeatSignalWrapper(sig, target, index) {
514
+ const src = sig[SOURCE_SYMBOL];
515
+ if (src && typeof src.f === "number" && "reactions" in src) {
516
+ return repeatSource(src, () => get(src), target, index);
517
+ }
518
+ return repeatGetter(() => sig.value, target, index);
519
+ }
520
+ function forwardRepeater(reaction) {
521
+ const r = reaction;
522
+ if ((r.f & DESTROYED) !== 0)
523
+ return false;
524
+ const val = r._readFn();
525
+ r._target.set(r._index, val);
526
+ return true;
527
+ }
528
+
418
529
  // src/reactivity/tracking.ts
419
530
  function get(signal) {
420
531
  if (activeReaction !== null && !untracking) {
@@ -533,6 +644,11 @@ function markReactions(signal, status) {
533
644
  }
534
645
  if ((flags & DERIVED) !== 0) {
535
646
  stack.push({ signal: reaction, status: MAYBE_DIRTY });
647
+ } else if ((flags & REPEATER) !== 0) {
648
+ if (notDirty) {
649
+ forwardRepeater(reaction);
650
+ setSignalStatus(reaction, CLEAN);
651
+ }
536
652
  } else if (notDirty) {
537
653
  scheduleEffect(reaction);
538
654
  }
@@ -729,7 +845,7 @@ function updateReaction(reaction) {
729
845
  }
730
846
 
731
847
  // src/primitives/signal.ts
732
- var SOURCE_SYMBOL = Symbol("signal.source");
848
+ var SOURCE_SYMBOL2 = Symbol.for("signal.source");
733
849
  function source(initialValue, options) {
734
850
  return {
735
851
  f: 0,
@@ -749,7 +865,7 @@ var signalCleanup = new FinalizationRegistry((src) => {
749
865
  function signal(initialValue, options) {
750
866
  const src = source(initialValue, options);
751
867
  const sig = {
752
- [SOURCE_SYMBOL]: src,
868
+ [SOURCE_SYMBOL2]: src,
753
869
  get value() {
754
870
  return get(src);
755
871
  },
@@ -761,7 +877,7 @@ function signal(initialValue, options) {
761
877
  return sig;
762
878
  }
763
879
  function getSource(sig) {
764
- return sig[SOURCE_SYMBOL];
880
+ return sig[SOURCE_SYMBOL2];
765
881
  }
766
882
  var proxyFn = null;
767
883
  function setProxyFn(fn) {
@@ -2926,6 +3042,181 @@ class ReactiveSharedUint32Array {
2926
3042
  return this.view.length;
2927
3043
  }
2928
3044
  }
3045
+ // src/shared/shared-slot-buffer.ts
3046
+ function sharedSlotBuffer(options) {
3047
+ let buffer;
3048
+ if (options.buffer) {
3049
+ buffer = options.buffer;
3050
+ } else if (options.type && options.capacity != null) {
3051
+ buffer = new options.type(options.capacity);
3052
+ } else {
3053
+ throw new Error("sharedSlotBuffer: provide either buffer or type+capacity");
3054
+ }
3055
+ const capacity = buffer.length;
3056
+ const defaultValue = options.defaultValue ?? 0;
3057
+ const notifier = options.notifier ?? null;
3058
+ const dirtyFlags = options.dirtyFlags ?? null;
3059
+ const source2 = {
3060
+ f: SOURCE | CLEAN,
3061
+ v: 0,
3062
+ wv: 0,
3063
+ rv: 0,
3064
+ reactions: null,
3065
+ equals: () => false
3066
+ };
3067
+ const indexSources = new Map;
3068
+ function _set(index, value) {
3069
+ if (buffer[index] === value)
3070
+ return;
3071
+ buffer[index] = value;
3072
+ if (dirtyFlags)
3073
+ dirtyFlags[index] = 1;
3074
+ source2.wv = incrementWriteVersion();
3075
+ markReactions(source2, DIRTY);
3076
+ const idx = indexSources.get(index);
3077
+ if (idx) {
3078
+ idx.v = value;
3079
+ idx.wv = source2.wv;
3080
+ markReactions(idx, DIRTY);
3081
+ }
3082
+ notifier?.notify();
3083
+ }
3084
+ return {
3085
+ get capacity() {
3086
+ return capacity;
3087
+ },
3088
+ get raw() {
3089
+ return buffer;
3090
+ },
3091
+ get(index) {
3092
+ get(source2);
3093
+ const idx = indexSources.get(index);
3094
+ if (idx)
3095
+ get(idx);
3096
+ return buffer[index];
3097
+ },
3098
+ peek(index) {
3099
+ return buffer[index];
3100
+ },
3101
+ set: _set,
3102
+ setBatch(updates) {
3103
+ let changed = false;
3104
+ const wv = incrementWriteVersion();
3105
+ for (let i = 0;i < updates.length; i++) {
3106
+ const [index, value] = updates[i];
3107
+ if (buffer[index] !== value) {
3108
+ buffer[index] = value;
3109
+ if (dirtyFlags)
3110
+ dirtyFlags[index] = 1;
3111
+ changed = true;
3112
+ const idx = indexSources.get(index);
3113
+ if (idx) {
3114
+ idx.v = value;
3115
+ idx.wv = wv;
3116
+ markReactions(idx, DIRTY);
3117
+ }
3118
+ }
3119
+ }
3120
+ if (changed) {
3121
+ source2.wv = wv;
3122
+ markReactions(source2, DIRTY);
3123
+ notifier?.notify();
3124
+ }
3125
+ },
3126
+ getIndexSource(index) {
3127
+ let src = indexSources.get(index);
3128
+ if (!src) {
3129
+ src = {
3130
+ f: SOURCE | CLEAN,
3131
+ v: buffer[index],
3132
+ wv: 0,
3133
+ rv: 0,
3134
+ reactions: null,
3135
+ equals: Object.is
3136
+ };
3137
+ indexSources.set(index, src);
3138
+ }
3139
+ return src;
3140
+ },
3141
+ notifyChanged() {
3142
+ source2.wv = incrementWriteVersion();
3143
+ markReactions(source2, DIRTY);
3144
+ },
3145
+ notifyIndicesChanged(indices) {
3146
+ const wv = incrementWriteVersion();
3147
+ for (let i = 0;i < indices.length; i++) {
3148
+ const idx = indexSources.get(indices[i]);
3149
+ if (idx) {
3150
+ idx.v = buffer[indices[i]];
3151
+ idx.wv = wv;
3152
+ markReactions(idx, DIRTY);
3153
+ }
3154
+ }
3155
+ source2.wv = wv;
3156
+ markReactions(source2, DIRTY);
3157
+ },
3158
+ clear(index) {
3159
+ _set(index, defaultValue);
3160
+ },
3161
+ dispose() {
3162
+ source2.reactions = null;
3163
+ indexSources.forEach((src) => {
3164
+ src.reactions = null;
3165
+ });
3166
+ indexSources.clear();
3167
+ }
3168
+ };
3169
+ }
3170
+ function sharedSlotBufferGroup(config, options) {
3171
+ const notifier = options?.notifier;
3172
+ const dirtyFlags = options?.dirtyFlags;
3173
+ const arrays = {};
3174
+ const buffers = [];
3175
+ for (const key in config) {
3176
+ const cfg = config[key];
3177
+ const buf = sharedSlotBuffer({
3178
+ type: cfg.type,
3179
+ capacity: cfg.capacity,
3180
+ defaultValue: cfg.defaultValue,
3181
+ notifier,
3182
+ dirtyFlags
3183
+ });
3184
+ arrays[key] = buf;
3185
+ buffers.push(buf);
3186
+ }
3187
+ return {
3188
+ arrays,
3189
+ dispose() {
3190
+ for (let i = 0;i < buffers.length; i++) {
3191
+ buffers[i].dispose();
3192
+ }
3193
+ }
3194
+ };
3195
+ }
3196
+ // src/shared/notifier.ts
3197
+ class AtomicsNotifier {
3198
+ wakeFlag;
3199
+ index;
3200
+ pending = false;
3201
+ constructor(wakeFlag, index = 0) {
3202
+ this.wakeFlag = wakeFlag;
3203
+ this.index = index;
3204
+ }
3205
+ notify() {
3206
+ if (!this.pending) {
3207
+ this.pending = true;
3208
+ queueMicrotask(() => {
3209
+ this.pending = false;
3210
+ Atomics.store(this.wakeFlag, this.index, 1);
3211
+ Atomics.notify(this.wakeFlag, this.index);
3212
+ });
3213
+ }
3214
+ }
3215
+ }
3216
+
3217
+ class NoopNotifier {
3218
+ notify() {}
3219
+ }
2929
3220
 
2930
3221
  // src/index.ts
2931
3222
  setProxyFn(proxy);
package/dist/index.mjs CHANGED
@@ -60,6 +60,7 @@ var EFFECT_PRESERVED = 1 << 17;
60
60
  var UNOWNED = 1 << 8;
61
61
  var DISCONNECTED = 1 << 9;
62
62
  var INSPECT_EFFECT = 1 << 18;
63
+ var REPEATER = 1 << 19;
63
64
  var UNINITIALIZED = Symbol.for("rlabs.signals.uninitialized");
64
65
  var STALE_REACTION = Symbol.for("rlabs.signals.stale_reaction");
65
66
  var STATE_SYMBOL = Symbol.for("rlabs.signals.state");
@@ -274,6 +275,110 @@ async function tick() {
274
275
  flushSync();
275
276
  }
276
277
 
278
+ // src/primitives/repeater.ts
279
+ var SOURCE_SYMBOL = Symbol.for("signal.source");
280
+ function resolveSource(input) {
281
+ if (typeof input === "number") {
282
+ return null;
283
+ }
284
+ if (typeof input === "function") {
285
+ return null;
286
+ }
287
+ const maybeSource = input;
288
+ if (maybeSource && typeof maybeSource.f === "number" && "v" in maybeSource && "reactions" in maybeSource) {
289
+ return {
290
+ source: maybeSource,
291
+ readFn: () => get(maybeSource)
292
+ };
293
+ }
294
+ const src = input[SOURCE_SYMBOL];
295
+ if (src && typeof src.f === "number" && "reactions" in src) {
296
+ return { source: src, readFn: () => get(src) };
297
+ }
298
+ return null;
299
+ }
300
+ function repeat(input, target, index) {
301
+ if (typeof input === "number") {
302
+ target.set(index, input);
303
+ return () => {};
304
+ }
305
+ if (typeof input === "function") {
306
+ return repeatGetter(input, target, index);
307
+ }
308
+ const resolved = resolveSource(input);
309
+ if (resolved) {
310
+ return repeatSource(resolved.source, resolved.readFn, target, index);
311
+ }
312
+ if (typeof input.value !== "undefined") {
313
+ return repeatSignalWrapper(input, target, index);
314
+ }
315
+ throw new Error("repeat(): unsupported source type");
316
+ }
317
+ function repeatSource(src, readFn, target, index) {
318
+ const node = {
319
+ f: REPEATER | CLEAN,
320
+ wv: 0,
321
+ fn: null,
322
+ deps: [src],
323
+ _readFn: readFn,
324
+ _target: target,
325
+ _index: index
326
+ };
327
+ if (src.reactions === null) {
328
+ src.reactions = [node];
329
+ } else {
330
+ src.reactions.push(node);
331
+ }
332
+ target.set(index, readFn());
333
+ return () => {
334
+ node.f |= DESTROYED;
335
+ if (src.reactions) {
336
+ const idx = src.reactions.indexOf(node);
337
+ if (idx !== -1) {
338
+ const last = src.reactions.length - 1;
339
+ if (idx !== last)
340
+ src.reactions[idx] = src.reactions[last];
341
+ src.reactions.pop();
342
+ if (src.reactions.length === 0)
343
+ src.reactions = null;
344
+ }
345
+ }
346
+ };
347
+ }
348
+ function repeatGetter(getter, target, index) {
349
+ const node = {
350
+ f: REPEATER | CLEAN,
351
+ wv: 0,
352
+ fn: getter,
353
+ deps: null,
354
+ _readFn: getter,
355
+ _target: target,
356
+ _index: index
357
+ };
358
+ const initialValue = updateReaction(node);
359
+ target.set(index, initialValue);
360
+ return () => {
361
+ node.f |= DESTROYED;
362
+ removeReactions(node, 0);
363
+ node.deps = null;
364
+ };
365
+ }
366
+ function repeatSignalWrapper(sig, target, index) {
367
+ const src = sig[SOURCE_SYMBOL];
368
+ if (src && typeof src.f === "number" && "reactions" in src) {
369
+ return repeatSource(src, () => get(src), target, index);
370
+ }
371
+ return repeatGetter(() => sig.value, target, index);
372
+ }
373
+ function forwardRepeater(reaction) {
374
+ const r = reaction;
375
+ if ((r.f & DESTROYED) !== 0)
376
+ return false;
377
+ const val = r._readFn();
378
+ r._target.set(r._index, val);
379
+ return true;
380
+ }
381
+
277
382
  // src/reactivity/tracking.ts
278
383
  function get(signal) {
279
384
  if (activeReaction !== null && !untracking) {
@@ -392,6 +497,11 @@ function markReactions(signal, status) {
392
497
  }
393
498
  if ((flags & DERIVED) !== 0) {
394
499
  stack.push({ signal: reaction, status: MAYBE_DIRTY });
500
+ } else if ((flags & REPEATER) !== 0) {
501
+ if (notDirty) {
502
+ forwardRepeater(reaction);
503
+ setSignalStatus(reaction, CLEAN);
504
+ }
395
505
  } else if (notDirty) {
396
506
  scheduleEffect(reaction);
397
507
  }
@@ -588,7 +698,7 @@ function updateReaction(reaction) {
588
698
  }
589
699
 
590
700
  // src/primitives/signal.ts
591
- var SOURCE_SYMBOL = Symbol("signal.source");
701
+ var SOURCE_SYMBOL2 = Symbol.for("signal.source");
592
702
  function source(initialValue, options) {
593
703
  return {
594
704
  f: 0,
@@ -608,7 +718,7 @@ var signalCleanup = new FinalizationRegistry((src) => {
608
718
  function signal(initialValue, options) {
609
719
  const src = source(initialValue, options);
610
720
  const sig = {
611
- [SOURCE_SYMBOL]: src,
721
+ [SOURCE_SYMBOL2]: src,
612
722
  get value() {
613
723
  return get(src);
614
724
  },
@@ -620,7 +730,7 @@ function signal(initialValue, options) {
620
730
  return sig;
621
731
  }
622
732
  function getSource(sig) {
623
- return sig[SOURCE_SYMBOL];
733
+ return sig[SOURCE_SYMBOL2];
624
734
  }
625
735
  var proxyFn = null;
626
736
  function setProxyFn(fn) {
@@ -2785,6 +2895,181 @@ class ReactiveSharedUint32Array {
2785
2895
  return this.view.length;
2786
2896
  }
2787
2897
  }
2898
+ // src/shared/shared-slot-buffer.ts
2899
+ function sharedSlotBuffer(options) {
2900
+ let buffer;
2901
+ if (options.buffer) {
2902
+ buffer = options.buffer;
2903
+ } else if (options.type && options.capacity != null) {
2904
+ buffer = new options.type(options.capacity);
2905
+ } else {
2906
+ throw new Error("sharedSlotBuffer: provide either buffer or type+capacity");
2907
+ }
2908
+ const capacity = buffer.length;
2909
+ const defaultValue = options.defaultValue ?? 0;
2910
+ const notifier = options.notifier ?? null;
2911
+ const dirtyFlags = options.dirtyFlags ?? null;
2912
+ const source2 = {
2913
+ f: SOURCE | CLEAN,
2914
+ v: 0,
2915
+ wv: 0,
2916
+ rv: 0,
2917
+ reactions: null,
2918
+ equals: () => false
2919
+ };
2920
+ const indexSources = new Map;
2921
+ function _set(index, value) {
2922
+ if (buffer[index] === value)
2923
+ return;
2924
+ buffer[index] = value;
2925
+ if (dirtyFlags)
2926
+ dirtyFlags[index] = 1;
2927
+ source2.wv = incrementWriteVersion();
2928
+ markReactions(source2, DIRTY);
2929
+ const idx = indexSources.get(index);
2930
+ if (idx) {
2931
+ idx.v = value;
2932
+ idx.wv = source2.wv;
2933
+ markReactions(idx, DIRTY);
2934
+ }
2935
+ notifier?.notify();
2936
+ }
2937
+ return {
2938
+ get capacity() {
2939
+ return capacity;
2940
+ },
2941
+ get raw() {
2942
+ return buffer;
2943
+ },
2944
+ get(index) {
2945
+ get(source2);
2946
+ const idx = indexSources.get(index);
2947
+ if (idx)
2948
+ get(idx);
2949
+ return buffer[index];
2950
+ },
2951
+ peek(index) {
2952
+ return buffer[index];
2953
+ },
2954
+ set: _set,
2955
+ setBatch(updates) {
2956
+ let changed = false;
2957
+ const wv = incrementWriteVersion();
2958
+ for (let i = 0;i < updates.length; i++) {
2959
+ const [index, value] = updates[i];
2960
+ if (buffer[index] !== value) {
2961
+ buffer[index] = value;
2962
+ if (dirtyFlags)
2963
+ dirtyFlags[index] = 1;
2964
+ changed = true;
2965
+ const idx = indexSources.get(index);
2966
+ if (idx) {
2967
+ idx.v = value;
2968
+ idx.wv = wv;
2969
+ markReactions(idx, DIRTY);
2970
+ }
2971
+ }
2972
+ }
2973
+ if (changed) {
2974
+ source2.wv = wv;
2975
+ markReactions(source2, DIRTY);
2976
+ notifier?.notify();
2977
+ }
2978
+ },
2979
+ getIndexSource(index) {
2980
+ let src = indexSources.get(index);
2981
+ if (!src) {
2982
+ src = {
2983
+ f: SOURCE | CLEAN,
2984
+ v: buffer[index],
2985
+ wv: 0,
2986
+ rv: 0,
2987
+ reactions: null,
2988
+ equals: Object.is
2989
+ };
2990
+ indexSources.set(index, src);
2991
+ }
2992
+ return src;
2993
+ },
2994
+ notifyChanged() {
2995
+ source2.wv = incrementWriteVersion();
2996
+ markReactions(source2, DIRTY);
2997
+ },
2998
+ notifyIndicesChanged(indices) {
2999
+ const wv = incrementWriteVersion();
3000
+ for (let i = 0;i < indices.length; i++) {
3001
+ const idx = indexSources.get(indices[i]);
3002
+ if (idx) {
3003
+ idx.v = buffer[indices[i]];
3004
+ idx.wv = wv;
3005
+ markReactions(idx, DIRTY);
3006
+ }
3007
+ }
3008
+ source2.wv = wv;
3009
+ markReactions(source2, DIRTY);
3010
+ },
3011
+ clear(index) {
3012
+ _set(index, defaultValue);
3013
+ },
3014
+ dispose() {
3015
+ source2.reactions = null;
3016
+ indexSources.forEach((src) => {
3017
+ src.reactions = null;
3018
+ });
3019
+ indexSources.clear();
3020
+ }
3021
+ };
3022
+ }
3023
+ function sharedSlotBufferGroup(config, options) {
3024
+ const notifier = options?.notifier;
3025
+ const dirtyFlags = options?.dirtyFlags;
3026
+ const arrays = {};
3027
+ const buffers = [];
3028
+ for (const key in config) {
3029
+ const cfg = config[key];
3030
+ const buf = sharedSlotBuffer({
3031
+ type: cfg.type,
3032
+ capacity: cfg.capacity,
3033
+ defaultValue: cfg.defaultValue,
3034
+ notifier,
3035
+ dirtyFlags
3036
+ });
3037
+ arrays[key] = buf;
3038
+ buffers.push(buf);
3039
+ }
3040
+ return {
3041
+ arrays,
3042
+ dispose() {
3043
+ for (let i = 0;i < buffers.length; i++) {
3044
+ buffers[i].dispose();
3045
+ }
3046
+ }
3047
+ };
3048
+ }
3049
+ // src/shared/notifier.ts
3050
+ class AtomicsNotifier {
3051
+ wakeFlag;
3052
+ index;
3053
+ pending = false;
3054
+ constructor(wakeFlag, index = 0) {
3055
+ this.wakeFlag = wakeFlag;
3056
+ this.index = index;
3057
+ }
3058
+ notify() {
3059
+ if (!this.pending) {
3060
+ this.pending = true;
3061
+ queueMicrotask(() => {
3062
+ this.pending = false;
3063
+ Atomics.store(this.wakeFlag, this.index, 1);
3064
+ Atomics.notify(this.wakeFlag, this.index);
3065
+ });
3066
+ }
3067
+ }
3068
+ }
3069
+
3070
+ class NoopNotifier {
3071
+ notify() {}
3072
+ }
2788
3073
 
2789
3074
  // src/index.ts
2790
3075
  setProxyFn(proxy);
@@ -2807,6 +3092,8 @@ export {
2807
3092
  slot,
2808
3093
  signals,
2809
3094
  signal,
3095
+ sharedSlotBufferGroup,
3096
+ sharedSlotBuffer,
2810
3097
  shallowEquals,
2811
3098
  setUntracking,
2812
3099
  setSignalStatus,
@@ -2816,6 +3103,7 @@ export {
2816
3103
  scheduleNotify,
2817
3104
  safeNotEqual,
2818
3105
  safeEquals,
3106
+ repeat,
2819
3107
  removeReactions,
2820
3108
  readVersion,
2821
3109
  reactiveProps,
@@ -2879,9 +3167,11 @@ export {
2879
3167
  ReactiveMap,
2880
3168
  ReactiveDate,
2881
3169
  ROOT_EFFECT,
3170
+ REPEATER,
2882
3171
  RENDER_EFFECT,
2883
3172
  REACTIVE_MARKER,
2884
3173
  REACTION_IS_UPDATING,
3174
+ NoopNotifier,
2885
3175
  MAYBE_DIRTY,
2886
3176
  LINKED_SYMBOL,
2887
3177
  INERT,
@@ -2895,5 +3185,6 @@ export {
2895
3185
  CLEAN,
2896
3186
  BRANCH_EFFECT,
2897
3187
  BLOCK_EFFECT,
2898
- BINDING_SYMBOL
3188
+ BINDING_SYMBOL,
3189
+ AtomicsNotifier
2899
3190
  };
@@ -0,0 +1,40 @@
1
+ import type { Reaction, ReadableSignal, WritableSignal, DerivedSignal } from '../core/types.js';
2
+ import type { SharedSlotBuffer } from '../shared/shared-slot-buffer.js';
3
+ /**
4
+ * A repeater node implements the Reaction interface but with the REPEATER flag.
5
+ * It has ONE permanent dependency (the source) and never re-wires deps.
6
+ *
7
+ * When markReactions encounters a REPEATER during traversal, it calls
8
+ * the repeater's readFn to get the current value and writes it to the target.
9
+ */
10
+ export interface RepeaterNode extends Reaction {
11
+ /** Read function - reads current value from the bound source */
12
+ _readFn: () => number;
13
+ /** Target buffer to write to */
14
+ _target: SharedSlotBuffer;
15
+ /** Index in target buffer */
16
+ _index: number;
17
+ }
18
+ type RepeaterSource = WritableSignal<number> | ReadableSignal<number> | DerivedSignal<number> | (() => number) | number;
19
+ /**
20
+ * Create a repeater: forwards a reactive source to a SharedSlotBuffer position.
21
+ *
22
+ * For static values: just calls target.set(index, value) — no repeater created.
23
+ * For reactive sources: creates a RepeaterNode, registers with source.reactions.
24
+ * Returns a dispose function.
25
+ *
26
+ * @param input - The value source: a signal, derived, getter, or static number
27
+ * @param target - The SharedSlotBuffer to write to
28
+ * @param index - Which position in the buffer
29
+ * @returns Dispose function (removes repeater from source.reactions)
30
+ */
31
+ export declare function repeat(input: RepeaterSource, target: SharedSlotBuffer, index: number): () => void;
32
+ /**
33
+ * Execute a repeater's forward operation.
34
+ * Called inline during markReactions when a REPEATER node is encountered.
35
+ *
36
+ * @returns true if the value was written to the target
37
+ */
38
+ export declare function forwardRepeater(reaction: Reaction): boolean;
39
+ export {};
40
+ //# sourceMappingURL=repeater.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repeater.d.ts","sourceRoot":"","sources":["../../src/primitives/repeater.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAU,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AASvE;;;;;;GAMG;AACH,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,gEAAgE;IAChE,OAAO,EAAE,MAAM,MAAM,CAAA;IACrB,gCAAgC;IAChC,OAAO,EAAE,gBAAgB,CAAA;IACzB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;CACf;AAMD,KAAK,cAAc,GACf,cAAc,CAAC,MAAM,CAAC,GACtB,cAAc,CAAC,MAAM,CAAC,GACtB,aAAa,CAAC,MAAM,CAAC,GACrB,CAAC,MAAM,MAAM,CAAC,GACd,MAAM,CAAA;AAqDV;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,GACZ,MAAM,IAAI,CAwBZ;AAuGD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAO3D"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../../src/reactivity/tracking.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAkCjE;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAiD3C;AAoGD;;GAEG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CA8BrD;AAMD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA8BlE;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE3E;AAMD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAoGnD;AAWD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEpD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAE3E;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAsBrD;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAOvE;AA8BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAmG1D"}
1
+ {"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../../src/reactivity/tracking.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAoCjE;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAiD3C;AAoGD;;GAEG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CA8BrD;AAMD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAoClE;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE3E;AAMD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAoGnD;AAWD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEpD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAE3E;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAsBrD;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAOvE;AA8BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAmG1D"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A notification mechanism for cross-side communication.
3
+ *
4
+ * When a SharedSlotBuffer is written to, the notifier is called to inform
5
+ * the other side (e.g., Rust) that changes are pending.
6
+ *
7
+ * Implementations can batch notifications (e.g., via microtask) to avoid
8
+ * redundant wake-ups during a synchronous update burst.
9
+ */
10
+ export interface Notifier {
11
+ /** Notify the other side that changes are pending. */
12
+ notify(): void;
13
+ }
14
+ /**
15
+ * Notifier that uses Atomics.store + Atomics.notify to wake a thread
16
+ * waiting on a shared memory location.
17
+ *
18
+ * Notifications are batched via microtask: multiple synchronous writes
19
+ * result in a single Atomics.notify call.
20
+ */
21
+ export declare class AtomicsNotifier implements Notifier {
22
+ private readonly wakeFlag;
23
+ private readonly index;
24
+ private pending;
25
+ constructor(wakeFlag: Int32Array, index?: number);
26
+ notify(): void;
27
+ }
28
+ /**
29
+ * A no-op notifier for testing or local-only usage.
30
+ */
31
+ export declare class NoopNotifier implements Notifier {
32
+ notify(): void;
33
+ }
34
+ //# sourceMappingURL=notifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifier.d.ts","sourceRoot":"","sources":["../../src/shared/notifier.ts"],"names":[],"mappings":"AAWA;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,sDAAsD;IACtD,MAAM,IAAI,IAAI,CAAA;CACf;AAMD;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,OAAO,CAAQ;gBAEX,QAAQ,EAAE,UAAU,EAAE,KAAK,SAAI;IAK3C,MAAM,IAAI,IAAI;CAUf;AAMD;;GAEG;AACH,qBAAa,YAAa,YAAW,QAAQ;IAC3C,MAAM,IAAI,IAAI;CAGf"}
@@ -0,0 +1,67 @@
1
+ import type { Source } from '../core/types.js';
2
+ import type { Notifier } from './notifier.js';
3
+ export type TypedArray = Float32Array | Float64Array | Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray;
4
+ export type TypedArrayConstructor = Float32ArrayConstructor | Float64ArrayConstructor | Int8ArrayConstructor | Int16ArrayConstructor | Int32ArrayConstructor | Uint8ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor | Uint8ClampedArrayConstructor;
5
+ export interface SharedSlotBuffer {
6
+ /** Maximum number of elements */
7
+ readonly capacity: number;
8
+ /** Direct access to underlying typed array (for FFI pointer passing) */
9
+ readonly raw: TypedArray;
10
+ /** Reactive read - tracks dependency */
11
+ get(index: number): number;
12
+ /** Non-reactive read */
13
+ peek(index: number): number;
14
+ /** Write + markReactions + dirty flag + notify */
15
+ set(index: number, value: number): void;
16
+ /** Batch write - single notification at end */
17
+ setBatch(updates: [number, number][]): void;
18
+ /** Get fine-grained per-index source for tracking */
19
+ getIndexSource(index: number): Source<number>;
20
+ /** Notify TS reactive graph that other side changed data */
21
+ notifyChanged(): void;
22
+ /** Notify specific indices changed from other side */
23
+ notifyIndicesChanged(indices: number[]): void;
24
+ /** Reset index to default value */
25
+ clear(index: number): void;
26
+ /** Clean up */
27
+ dispose(): void;
28
+ }
29
+ export interface SharedSlotBufferOptions {
30
+ /** External TypedArray view (fixed capacity, e.g., over SharedArrayBuffer) */
31
+ buffer?: TypedArray;
32
+ /** OR: allocate internally with this constructor */
33
+ type?: TypedArrayConstructor;
34
+ /** Capacity (required if type is provided, ignored if buffer is provided) */
35
+ capacity?: number;
36
+ /** Default value for clear() */
37
+ defaultValue?: number;
38
+ /** Cross-side notifier */
39
+ notifier?: Notifier;
40
+ /** Per-index dirty flags (external, e.g., from SharedArrayBuffer) */
41
+ dirtyFlags?: Uint8Array;
42
+ }
43
+ /**
44
+ * Create a reactive typed array backed by shared memory.
45
+ *
46
+ * The buffer is "just" a reactive read/write array - no source binding.
47
+ * Use `repeat()` from the repeater module to wire signals to buffer positions.
48
+ */
49
+ export declare function sharedSlotBuffer(options: SharedSlotBufferOptions): SharedSlotBuffer;
50
+ export type SharedSlotBufferGroupConfig = Record<string, {
51
+ type: TypedArrayConstructor;
52
+ capacity: number;
53
+ defaultValue?: number;
54
+ }>;
55
+ /**
56
+ * Create multiple SharedSlotBuffers sharing a single notifier and dirty flags.
57
+ */
58
+ export declare function sharedSlotBufferGroup<T extends SharedSlotBufferGroupConfig>(config: T, options?: {
59
+ notifier?: Notifier;
60
+ dirtyFlags?: Uint8Array;
61
+ }): {
62
+ arrays: {
63
+ [K in keyof T]: SharedSlotBuffer;
64
+ };
65
+ dispose(): void;
66
+ };
67
+ //# sourceMappingURL=shared-slot-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-slot-buffer.d.ts","sourceRoot":"","sources":["../../src/shared/shared-slot-buffer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAI9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAM7C,MAAM,MAAM,UAAU,GAClB,YAAY,GACZ,YAAY,GACZ,SAAS,GACT,UAAU,GACV,UAAU,GACV,UAAU,GACV,WAAW,GACX,WAAW,GACX,iBAAiB,CAAA;AAErB,MAAM,MAAM,qBAAqB,GAC7B,uBAAuB,GACvB,uBAAuB,GACvB,oBAAoB,GACpB,qBAAqB,GACrB,qBAAqB,GACrB,qBAAqB,GACrB,sBAAsB,GACtB,sBAAsB,GACtB,4BAA4B,CAAA;AAMhC,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,wEAAwE;IACxE,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;IACxB,wCAAwC;IACxC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,wBAAwB;IACxB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3B,kDAAkD;IAClD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,CAAA;IAC3C,qDAAqD;IACrD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IAC7C,4DAA4D;IAC5D,aAAa,IAAI,IAAI,CAAA;IACrB,sDAAsD;IACtD,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAC7C,mCAAmC;IACnC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,eAAe;IACf,OAAO,IAAI,IAAI,CAAA;CAChB;AAMD,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,oDAAoD;IACpD,IAAI,CAAC,EAAE,qBAAqB,CAAA;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gCAAgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,qEAAqE;IACrE,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAMD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,gBAAgB,CAuJnF;AAMD,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE;IACvD,IAAI,EAAE,qBAAqB,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAC,CAAA;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,2BAA2B,EACzE,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,gBAAgB;KAAE,CAAC;IAAC,OAAO,IAAI,IAAI,CAAA;CAAE,CA2BnE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rlabs-inc/signals",
3
- "version": "1.12.0",
3
+ "version": "1.13.1",
4
4
  "description": "Production-grade fine-grained reactivity for TypeScript. A complete standalone mirror of Svelte 5's reactivity system - signals, effects, derived values, deep reactivity, reactive collections, reactive bindings, and reactive slots.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",