@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 +89 -0
- package/dist/core/constants.d.ts +2 -0
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +295 -4
- package/dist/index.mjs +295 -4
- package/dist/primitives/repeater.d.ts +40 -0
- package/dist/primitives/repeater.d.ts.map +1 -0
- package/dist/reactivity/tracking.d.ts.map +1 -1
- package/dist/shared/notifier.d.ts +34 -0
- package/dist/shared/notifier.d.ts.map +1 -0
- package/dist/shared/shared-slot-buffer.d.ts +67 -0
- package/dist/shared/shared-slot-buffer.d.ts.map +1 -0
- package/package.json +1 -1
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
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -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;
|
|
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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC1F,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAClI,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACpF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAMrD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAM1D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAM5D,OAAO,EACL,MAAM,EACN,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAMpD,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,YAAY,EACZ,cAAc,GACf,MAAM,mCAAmC,CAAA;AAE1C,YAAY,EACV,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,mCAAmC,CAAA;
|
|
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
|
|
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
|
-
[
|
|
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[
|
|
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
|
|
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
|
-
[
|
|
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[
|
|
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;
|
|
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.
|
|
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",
|