@ng-org/alien-deepsignals 0.1.2-alpha.6 → 0.1.2-alpha.7

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
@@ -4,20 +4,23 @@ Deep structural reactivity for plain objects / arrays / Sets built on top of `al
4
4
 
5
5
  Hooks for Svelte, Vue, and React.
6
6
 
7
- Core idea: wrap a data tree in a `Proxy` that lazily creates per-property signals the first time you read them. Deep mutations emit compact batched patch objects (in a JSON-patch inspired style) that you can track with `watch()`.
7
+ Core idea: wrap a data tree in a `Proxy` that lazily creates per-property signals the first time you read them. Deep mutations emit batched patch objects (in a JSON-patch inspired style) that you can track with `watch()`.
8
8
 
9
9
  ## Features
10
10
 
11
11
  - Lazy: signals & child proxies created only when touched.
12
12
  - Deep: nested objects, arrays, Sets proxied.
13
- - Per-property signals: fine‑grained invalidation without traversal on each change.
14
13
  - Patch stream: microtask‑batched granular mutations (paths + op) for syncing external stores / framework adapters.
15
14
  - Getter => computed: property getters become derived (readonly) signals automatically.
16
- - Sets: structural `add/delete/clear` emit patches; object entries get synthetic stable ids.
17
- - Configurable synthetic IDs: custom property generator - the synthetic id is used in the paths of patches to identify objects in sets.
15
+ - Sets: `add/delete/clear/...` methods emit patches; object entries get synthetic stable ids.
16
+ - Configurable synthetic IDs: custom property generator - the synthetic ID is used in the paths of patches to identify objects in sets. By default attached as `@id` property.
18
17
  - Read-only properties: protect specific properties from modification.
19
18
  - Shallow escape hatch: wrap sub-objects with `shallow(obj)` to track only reference replacement.
20
19
 
20
+ ## Reference documentation
21
+
22
+ [Reference documentation is available here on docs.nextgraph.org](https://docs.nextgraph.org/en/reference/alien-deepsignals/).
23
+
21
24
  ## Install
22
25
 
23
26
  ```bash
@@ -46,15 +49,37 @@ state.settings.add("beta");
46
49
 
47
50
  ## Frontend Hooks
48
51
 
49
- We provide hooks for Svelte 3/4, Svelte 5, Vue, and React so that you can use deepSignal objects in your frontend framework. Modifying the object within those components works as usual, just that the component will rerender automatically if the object changed (by an event in the component or a modification from elsewhere).
52
+ We provide hooks for Svelte 3/4, Svelte 5, Vue, and React so that you can use deepSignal objects in your frontend framework. Modifying the object within those components works as usual, just that the component will rerender automatically when the object changed (by a modification in the component or a modification from elsewhere).
53
+
54
+ Note that you can pass existing deepSignal objects to useDeepSignal (that you are using elsewhere too, for example as shared state) as well as plain JavaScript objects (which are then wrapped).
55
+
56
+ You can (and are often advised to) use deepSignals as a shared state (and sub objects thereof) across components.
50
57
 
51
- Note that you can pass existing deepSignal objects (that you are using elsewhere too, for example as shared state) as well as plain JavaScript objects (which are then wrapped).
58
+ ### React
52
59
 
53
60
  ```tsx
54
61
  import { useDeepSignal } from "@ng-org/alien-deepsignals/react";
62
+ import { DeepSignal } from "@ng-org/alien-deepsignals";
63
+ import UserComponent from "./User.tsx";
64
+ import type { User } from "./types.ts";
55
65
 
56
- const users = useDeepSignal([{ username: "Bob" }]);
57
- // Note: Instead of calling `setState`, you just need to modify a property. That will trigger the required re-render.
66
+ function UserManager() {
67
+ const users: DeepSignal<User[]> = useDeepSignal([{ username: "Bob" }]);
68
+
69
+ return users.map((user) => <UserComponent key={user.id} user={user} />);
70
+ }
71
+ ```
72
+
73
+ In child component `User.tsx`:
74
+
75
+ ```tsx
76
+ function UserComponent({ user }: { user: DeepSignal<User> }) {
77
+ // Modifications here will trigger a re-render in the parent component
78
+ // which updates this component.
79
+ // For performance reasons, you are advised to call `useDeepSignal`
80
+ // close to where its return value is used.
81
+ return <input type="text" value={user.name} />;
82
+ }
58
83
  ```
59
84
 
60
85
  ### Vue
@@ -63,12 +88,12 @@ In component `UserManager.vue`
63
88
 
64
89
  ```vue
65
90
  <script setup lang="ts">
66
- import { DeepSignal } from "@ng-org/alien-deepsignals";
67
91
  import { useDeepSignal } from "@ng-org/alien-deepsignals/vue";
92
+ import { DeepSignal } from "@ng-org/alien-deepsignals";
68
93
  import UserComponent from "./User.vue";
69
- import { User } from "./types.ts";
94
+ import type { User } from "./types.ts";
70
95
 
71
- const users: DeepSignal<User> = useDeepSignal([{ username: "Bob", id: 1 }]);
96
+ const users: DeepSignal<User[]> = useDeepSignal([{ username: "Bob", id: 1 }]);
72
97
  </script>
73
98
 
74
99
  <template>
@@ -80,14 +105,12 @@ In a child component, `User.vue`
80
105
 
81
106
  ```vue
82
107
  <script setup lang="ts">
83
- import { useDeepSignal } from "@ng-org/alien-deepsignals/vue";
84
-
85
108
  const props = defineProps<{
86
109
  user: DeepSignal<User>;
87
110
  }>();
88
111
 
89
112
  // The component only rerenders when user.name changes.
90
- // It behaves the same as an object called with `reactive()`
113
+ // It behaves the same as an object wrapped with `reactive()`
91
114
  const user = props.user;
92
115
  </script>
93
116
  <template>
@@ -113,332 +136,9 @@ import { useDeepSignal } from "@ng-org/alien-deepsignals/svelte";
113
136
  const users = useDeepSignal([{ username: "Bob" }]);
114
137
  ```
115
138
 
116
- ## Configuration options
117
-
118
- `deepSignal(obj, options?)` accepts an optional configuration object:
119
-
120
- ```ts
121
- type DeepSignalOptions = {
122
- propGenerator?: (props: {
123
- path: (string | number)[];
124
- inSet: boolean;
125
- object: any;
126
- }) => {
127
- syntheticId?: string;
128
- extraProps?: Record<string, unknown>;
129
- };
130
- syntheticIdPropertyName?: string;
131
- readOnlyProps?: string[];
132
- };
133
- ```
134
-
135
- ### Property generator function
136
-
137
- The `propGenerator` function is called when a new object is added to the deep signal tree. It receives:
138
-
139
- - `path`: The path of the newly added object
140
- - `inSet`: Whether the object is being added to a Set (true) or not (false)
141
- - `object`: The newly added object itself
142
-
143
- It can return:
144
-
145
- - `syntheticId`: A custom identifier for the object (used in Set entry paths and optionally as a property)
146
- - `extraProps`: Additional properties to be added to the object (overwriting existing ones).
147
-
148
- ```ts
149
- let counter = 0;
150
- const state = deepSignal(
151
- { items: new Set() },
152
- {
153
- propGenerator: ({ path, inSet, object }) => ({
154
- syntheticId: inSet
155
- ? `urn:item:${++counter}`
156
- : `urn:obj:${path.join("-")}`,
157
- extraProps: { createdAt: new Date().toISOString() },
158
- }),
159
- syntheticIdPropertyName: "@id",
160
- }
161
- );
162
-
163
- state.items.add({ name: "Item 1" }); // Gets @id: "urn:item:1" and createdAt property
164
- state.items.add({ name: "Item 2" }); // Gets @id: "urn:item:2"
165
- ```
166
-
167
- ### Synthetic ID property name
168
-
169
- When `syntheticIdPropertyName` is set (e.g., to `"@id"`), objects receive a readonly, enumerable property with the generated synthetic ID:
170
-
171
- ```ts
172
- const state = deepSignal(
173
- { data: {} },
174
- {
175
- propGenerator: ({ path, inSet, object }) => ({
176
- syntheticId: `urn:uuid:${crypto.randomUUID()}`,
177
- }),
178
- syntheticIdPropertyName: "@id",
179
- }
180
- );
181
-
182
- state.data.user = { name: "Ada" };
183
- console.log(state.data.user["@id"]); // e.g., "urn:uuid:550e8400-e29b-41d4-a716-446655440000"
184
- ```
185
-
186
- ### Read-only properties
187
-
188
- The `readOnlyProps` option lets you specify property names that cannot be modified:
189
-
190
- ```ts
191
- const state = deepSignal(
192
- { data: {} },
193
- {
194
- propGenerator: ({ path, inSet, object }) => ({
195
- syntheticId: `urn:uuid:${crypto.randomUUID()}`,
196
- }),
197
- syntheticIdPropertyName: "@id",
198
- readOnlyProps: ["@id", "@graph"],
199
- }
200
- );
201
-
202
- state.data.user = { name: "Ada" };
203
- state.data.user["@id"] = "new-id"; // TypeError: Cannot modify readonly property '@id'
204
- ```
205
-
206
- **Key behaviors:**
207
-
208
- - Synthetic IDs are assigned **before** the object is proxied, ensuring availability immediately
209
- - Properties specified in `readOnlyProps` are **readonly** and **enumerable**
210
- - Synthetic ID assignment emits a patch just like any other property
211
- - Objects with existing properties matching `syntheticIdPropertyName` keep their values (not overwritten)
212
- - Options propagate to all nested objects created after initialization
213
- - The `propGenerator` function is called for both Set entries (`inSet: true`) and regular objects (`inSet: false`)
214
-
215
- ## Watching patches
216
-
217
- `watch(root, cb, options?)` observes a deepSignal root and invokes your callback with microtask‑batched mutation patches plus snapshots.
218
-
219
- ```ts
220
- import { watch } from "alien-deepsignals";
221
-
222
- const stop = watch(state, ({ patches, oldValue, newValue }) => {
223
- for (const p of patches) {
224
- console.log(p.op, p.path.join("."), "value" in p ? p.value : p.type);
225
- }
226
- });
227
-
228
- state.user.name = "Lin";
229
- state.items[0].qty = 3;
230
- await Promise.resolve(); // flush microtask
231
- stop();
232
- ```
233
-
234
- ## Computed (derived) values
235
-
236
- Use the `computed()` function to create lazy derived signals that automatically track their dependencies and recompute only when needed.
237
-
238
- ```ts
239
- import { computed } from "@ng-org/alien-deepsignals";
240
-
241
- const state = deepSignal({
242
- firstName: "Ada",
243
- lastName: "Lovelace",
244
- items: [1, 2, 3],
245
- });
246
-
247
- // Create a computed signal that derives from reactive state
248
- const fullNaAdd documentationme = computed(() => `${state.firstName} ${state.lastName}`);
249
- const itemCount = computed(() => state.items.length);
250
-
251
- console.log(fullName()); // "Ada Lovelace" - computes on first access
252
- console.log(itemCount()); // 3
253
-
254
- state.firstName = "Grace";
255
- console.log(fullName()); // "Grace Lovelace" - recomputes automatically
256
- ```
257
-
258
- **Key benefits:**
259
-
260
- - **Lazy evaluation**: The computation runs only when you actually read the computed value. If you never access `fullName()`, the concatenation never happens—no wasted CPU cycles.
261
- - **Automatic caching**: Once computed, the result is cached until a dependency changes. Multiple reads return the cached value without re-running the getter.
262
- - **Fine-grained reactivity**: Only recomputes when its tracked dependencies change. Unrelated state mutations don't trigger unnecessary recalculation.
263
- - **Composable**: Computed signals can depend on other computed signals, forming efficient dependency chains.
264
-
265
- ```ts
266
- // Expensive computation only runs when accessed and dependencies change
267
- const expensiveResult = computed(() => {
268
- console.log("Computing...");
269
- return state.items.reduce((sum, n) => sum + n * n, 0);
270
- });
271
-
272
- // No computation happens yet!
273
- state.items.push(4);
274
- // Still no computation...
275
-
276
- console.log(expensiveResult()); // "Computing..." + result
277
- console.log(expensiveResult()); // Cached, no log
278
- state.items.push(5);
279
- console.log(expensiveResult()); // "Computing..." again (dependency changed)
280
- ```
281
-
282
- ### Callback event shape
283
-
284
- ```ts
285
- type WatchPatchEvent<T> = {
286
- patches: DeepPatch[]; // empty only on immediate
287
- oldValue: T | undefined; // deep-cloned snapshot before batch
288
- newValue: T; // live proxy (already mutated)
289
- registerCleanup(fn): void; // register disposer for next batch/stop
290
- stopListening(): void; // unsubscribe
291
- };
292
- ```
293
-
294
- ### Options
295
-
296
- | Option | Type | Default | Description |
297
- | ----------- | ------- | ------- | -------------------------------------------------- |
298
- | `immediate` | boolean | false | Fire once right away with `patches: []`. |
299
- | `once` | boolean | false | Auto stop after first callback (immediate counts). |
300
-
301
- `observe()` is an alias of `watch()`.
302
-
303
- ## DeepPatch format
304
-
305
- ```ts
306
- type DeepPatch = {
307
- root: symbol; // stable id per deepSignal root
308
- path: (string | number)[]; // root-relative segments
309
- } & (
310
- | { op: "add"; type: "object" } // assigned object/array/Set entry object
311
- | { op: "add"; value: string | number | boolean } // primitive write
312
- | { op: "remove" } // deletion
313
- | { op: "add"; type: "set"; value: [] } // Set.clear()
314
- | {
315
- op: "add";
316
- type: "set";
317
- value: (string | number | boolean)[] | { [id: string]: object };
318
- } // (reserved)
319
- );
320
- ```
321
-
322
- Notes:
323
-
324
- - `type:'object'` omits value to avoid deep cloning; read from `newValue` if needed.
325
- - `Set.add(entry)` emits object vs primitive form depending on entry type; path ends with synthetic id.
326
- - `Set.clear()` emits one structural patch and suppresses per‑entry removals in same batch.
327
-
328
- ## Sets & synthetic ids
329
-
330
- Object entries inside Sets need a stable key for patch paths. The synthetic ID resolution follows this priority:
331
-
332
- 1. Explicit custom ID via `setSetEntrySyntheticId(entry, 'myId')` (before `add`)
333
- 2. Custom ID property specified by `syntheticIdPropertyName` option (e.g., `entry['@id']`)
334
- 3. Auto-generated blank node ID (`_bN` format)
335
-
336
- ### Working with Sets
337
-
338
- ```ts
339
- import { addWithId, setSetEntrySyntheticId } from "@ng-org/alien-deepsignals";
340
-
341
- // Option 1: Use automatic ID generation via propGenerator
342
- const state = deepSignal(
343
- { items: new Set() },
344
- {
345
- propGenerator: ({ path, inSet, object }) => ({
346
- syntheticId: inSet ? `urn:uuid:${crypto.randomUUID()}` : undefined,
347
- }),
348
- syntheticIdPropertyName: "@id",
349
- }
350
- );
351
- const item = { name: "Item 1" };
352
- state.items.add(item); // Automatically gets @id before being added
353
- console.log(item["@id"]); // e.g., "urn:uuid:550e8400-..."
354
-
355
- // Option 2: Manually set synthetic ID
356
- const obj = { value: 42 };
357
- setSetEntrySyntheticId(obj, "urn:custom:my-id");
358
- state.items.add(obj);
359
-
360
- // Option 3: Use convenience helper
361
- addWithId(state.items as any, { value: 99 }, "urn:item:special");
362
-
363
- // Option 4: Pre-assign property matching syntheticIdPropertyName
364
- const preTagged = { "@id": "urn:explicit:123", data: "..." };
365
- state.items.add(preTagged); // Uses "urn:explicit:123" as synthetic ID
366
- ```
367
-
368
- ### Set entry patches and paths
369
-
370
- When objects are added to Sets, their **synthetic ID becomes part of the patch path**. This allows patches to uniquely identify which Set entry is being mutated.
371
-
372
- ```ts
373
- const state = deepSignal(
374
- { s: new Set() },
375
- {
376
- propGenerator: ({ inSet }) => ({
377
- syntheticId: inSet ? "urn:entry:set-entry-1" : undefined,
378
- }),
379
- syntheticIdPropertyName: "@id",
380
- }
381
- );
382
-
383
- watch(state, ({ patches }) => {
384
- console.log(JSON.stringify(patches));
385
- // [
386
- // {"path":["s","urn:entry:set-entry-1"],"op":"add","type":"object"},
387
- // {"path":["s","urn:entry:set-entry-1","@id"],"op":"add","value":"urn:entry:set-entry-1"},
388
- // {"path":["s","urn:entry:set-entry-1","data"],"op":"add","value":"test"}
389
- // ]
390
- });
391
-
392
- state.s.add({ data: "test" });
393
- ```
394
-
395
- **Path structure explained:**
396
-
397
- - `["s", "urn:entry:set-entry-1"]` - The structural Set patch; the IRI identifies the entry
398
- - `["s", "urn:entry:set-entry-1", "@id"]` - Patch for the @id property assignment
399
- - `["s", "urn:entry:set-entry-1", "data"]` - Nested property patch; the IRI identifies which Set entry
400
- - The synthetic ID (the IRI) is stable across mutations, allowing tracking of the same object
139
+ ### Other Frameworks
401
140
 
402
- **Mutating nested properties:**
403
-
404
- ```ts
405
- const state = deepSignal(
406
- { users: new Set() },
407
- {
408
- propGenerator: ({ path, inSet }) => ({
409
- syntheticId: inSet ? `urn:user:${crypto.randomUUID()}` : undefined,
410
- }),
411
- syntheticIdPropertyName: "@id",
412
- }
413
- );
414
- const user = { name: "Ada", age: 30 };
415
- state.users.add(user); // Gets @id, e.g., "urn:user:550e8400-..."
416
-
417
- watch(state, ({ patches }) => {
418
- console.log(JSON.stringify(patches));
419
- // [{"path":["users","urn:user:550e8400-...","age"],"op":"add","value":31}]
420
- });
421
-
422
- // Later mutation: synthetic ID identifies which Set entry changed
423
- user.age = 31;
424
- ```
425
-
426
- The path `["users", "urn:user:550e8400-...", "age"]` shows:
427
-
428
- 1. `users` - the Set container
429
- 2. `urn:user:550e8400-...` - the IRI identifying which object in the Set
430
- 3. `age` - the property being mutated
431
-
432
- This structure enables precise tracking of nested changes within Set entries, critical for syncing state changes or implementing undo/redo.
433
-
434
- ## Shallow
435
-
436
- Skip deep proxying of a subtree (only reference replacement tracked):
437
-
438
- ```ts
439
- import { shallow } from "alien-deepsignals";
440
- state.config = shallow({ huge: { blob: true } });
441
- ```
141
+ Integrating new frontend frameworks is fairly easy. Get in touch if you are interested.
442
142
 
443
143
  ## License
444
144
 
package/dist/core.d.ts CHANGED
@@ -1,16 +1,81 @@
1
- export { signal as alienSignal, computed as alienComputed, effect as alienEffect, } from "alien-signals";
1
+ import { computed as alienComputed, signal as alienSignal_, effect as alienEffect } from "alien-signals";
2
2
  /**
3
3
  * Execute multiple signal writes in a single batched update frame.
4
4
  * All downstream computed/effect re-evaluations are deferred until the function exits.
5
5
  *
6
- * IMPORTANT: The callback MUST be synchronous. If it returns a Promise the batch will
6
+ * IMPORTANT: The callback must be synchronous. If it returns a Promise the batch will
7
7
  * still end immediately after scheduling, possibly causing mid-async flushes.
8
8
  *
9
9
  * @example
10
+ * ```ts
10
11
  * batch(() => {
11
12
  * count(count() + 1);
12
13
  * other(other() + 2);
13
14
  * }); // effects observing both run only once
15
+ * ```
14
16
  */
15
17
  export declare function batch<T>(fn: () => T): T;
18
+ /**
19
+ * Re-export of alien-signals computed function.
20
+ *
21
+ * Use the `computed()` function to create lazy derived signals that automatically
22
+ * track their dependencies and recompute only when needed.
23
+ *
24
+ * Key features:
25
+ * - **Lazy evaluation**: The computation runs only when you actually read the computed value.
26
+ * If you never access `fullName()`, the concatenation never happens—no wasted CPU cycles.
27
+ * - **Automatic caching**: Once computed, the result is cached until a dependency changes.
28
+ * Multiple reads return the cached value without re-running the getter.
29
+ * - **Fine-grained reactivity**: Only recomputes when its tracked dependencies change.
30
+ * Unrelated state mutations don't trigger unnecessary recalculation.
31
+ * - **Composable**: Computed signals can depend on other computed signals,
32
+ * forming efficient dependency chains.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { computed } from "@ng-org/alien-deepsignals";
37
+ *
38
+ * const state = deepSignal({
39
+ * firstName: "Ada",
40
+ * lastName: "Lovelace",
41
+ * items: [1, 2, 3],
42
+ * });
43
+ *
44
+ * // Create a computed signal that derives from reactive state
45
+ * const fullName = computed(() => `${state.firstName} ${state.lastName}`);
46
+ *
47
+ * console.log(fullName()); // "Ada Lovelace" - computes on first access
48
+ *
49
+ * state.firstName = "Grace";
50
+ * console.log(fullName()); // "Grace Lovelace" - recomputes automatically
51
+ *
52
+ * // Expensive computation only runs when accessed and dependencies change
53
+ * const expensiveResult = computed(() => {
54
+ * console.log("Computing...");
55
+ * return state.items.reduce((sum, n) => sum + n * n, 0);
56
+ * });
57
+ *
58
+ * // No computation happens yet!
59
+ * state.items.push(4);
60
+ * // Still no computation...
61
+ *
62
+ * console.log(expensiveResult()); // "Computing..." + result
63
+ * console.log(expensiveResult()); // Cached, no log
64
+ * state.items.push(5);
65
+ * console.log(expensiveResult()); // "Computing..." again (dependency changed)
66
+ *
67
+ * ```
68
+ */
69
+ export declare const computed: typeof alienComputed;
70
+ /**
71
+ * Re-export of alien-signals `signal` function which creates a basic signal.
72
+ */
73
+ export declare const alienSignal: typeof alienSignal_;
74
+ /**
75
+ * Re-export of alien-signals effect function.
76
+ *
77
+ * Callback reruns on every signal modification that is used within its callback.
78
+ *
79
+ */
80
+ export declare const effect: typeof alienEffect;
16
81
  //# sourceMappingURL=core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAWA,OAAO,EACH,MAAM,IAAI,WAAW,EACrB,QAAQ,IAAI,aAAa,EACzB,MAAM,IAAI,WAAW,GACxB,MAAM,eAAe,CAAC;AAOvB;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAOvC"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAUA,OAAO,EAGH,QAAQ,IAAI,aAAa,EACzB,MAAM,IAAI,YAAY,EACtB,MAAM,IAAI,WAAW,EACxB,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAOvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,eAAO,MAAM,QAAQ,sBAAgB,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,WAAW,qBAAe,CAAC;AAExC;;;;;GAKG;AACH,eAAO,MAAM,MAAM,oBAAc,CAAC"}
package/dist/core.js CHANGED
@@ -9,33 +9,93 @@
9
9
  // according to those terms.
10
10
  // SPDX-License-Identifier: Apache-2.0 OR MIT
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.alienEffect = exports.alienComputed = exports.alienSignal = void 0;
12
+ exports.effect = exports.alienSignal = exports.computed = void 0;
13
13
  exports.batch = batch;
14
- // Native re-exports for advanced usage.
15
- var alien_signals_1 = require("alien-signals");
16
- Object.defineProperty(exports, "alienSignal", { enumerable: true, get: function () { return alien_signals_1.signal; } });
17
- Object.defineProperty(exports, "alienComputed", { enumerable: true, get: function () { return alien_signals_1.computed; } });
18
- Object.defineProperty(exports, "alienEffect", { enumerable: true, get: function () { return alien_signals_1.effect; } });
19
- const alien_signals_2 = require("alien-signals");
14
+ const alien_signals_1 = require("alien-signals");
20
15
  /**
21
16
  * Execute multiple signal writes in a single batched update frame.
22
17
  * All downstream computed/effect re-evaluations are deferred until the function exits.
23
18
  *
24
- * IMPORTANT: The callback MUST be synchronous. If it returns a Promise the batch will
19
+ * IMPORTANT: The callback must be synchronous. If it returns a Promise the batch will
25
20
  * still end immediately after scheduling, possibly causing mid-async flushes.
26
21
  *
27
22
  * @example
23
+ * ```ts
28
24
  * batch(() => {
29
25
  * count(count() + 1);
30
26
  * other(other() + 2);
31
27
  * }); // effects observing both run only once
28
+ * ```
32
29
  */
33
30
  function batch(fn) {
34
- (0, alien_signals_2.startBatch)();
31
+ (0, alien_signals_1.startBatch)();
35
32
  try {
36
33
  return fn();
37
34
  }
38
35
  finally {
39
- (0, alien_signals_2.endBatch)();
36
+ (0, alien_signals_1.endBatch)();
40
37
  }
41
38
  }
39
+ /**
40
+ * Re-export of alien-signals computed function.
41
+ *
42
+ * Use the `computed()` function to create lazy derived signals that automatically
43
+ * track their dependencies and recompute only when needed.
44
+ *
45
+ * Key features:
46
+ * - **Lazy evaluation**: The computation runs only when you actually read the computed value.
47
+ * If you never access `fullName()`, the concatenation never happens—no wasted CPU cycles.
48
+ * - **Automatic caching**: Once computed, the result is cached until a dependency changes.
49
+ * Multiple reads return the cached value without re-running the getter.
50
+ * - **Fine-grained reactivity**: Only recomputes when its tracked dependencies change.
51
+ * Unrelated state mutations don't trigger unnecessary recalculation.
52
+ * - **Composable**: Computed signals can depend on other computed signals,
53
+ * forming efficient dependency chains.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import { computed } from "@ng-org/alien-deepsignals";
58
+ *
59
+ * const state = deepSignal({
60
+ * firstName: "Ada",
61
+ * lastName: "Lovelace",
62
+ * items: [1, 2, 3],
63
+ * });
64
+ *
65
+ * // Create a computed signal that derives from reactive state
66
+ * const fullName = computed(() => `${state.firstName} ${state.lastName}`);
67
+ *
68
+ * console.log(fullName()); // "Ada Lovelace" - computes on first access
69
+ *
70
+ * state.firstName = "Grace";
71
+ * console.log(fullName()); // "Grace Lovelace" - recomputes automatically
72
+ *
73
+ * // Expensive computation only runs when accessed and dependencies change
74
+ * const expensiveResult = computed(() => {
75
+ * console.log("Computing...");
76
+ * return state.items.reduce((sum, n) => sum + n * n, 0);
77
+ * });
78
+ *
79
+ * // No computation happens yet!
80
+ * state.items.push(4);
81
+ * // Still no computation...
82
+ *
83
+ * console.log(expensiveResult()); // "Computing..." + result
84
+ * console.log(expensiveResult()); // Cached, no log
85
+ * state.items.push(5);
86
+ * console.log(expensiveResult()); // "Computing..." again (dependency changed)
87
+ *
88
+ * ```
89
+ */
90
+ exports.computed = alien_signals_1.computed;
91
+ /**
92
+ * Re-export of alien-signals `signal` function which creates a basic signal.
93
+ */
94
+ exports.alienSignal = alien_signals_1.signal;
95
+ /**
96
+ * Re-export of alien-signals effect function.
97
+ *
98
+ * Callback reruns on every signal modification that is used within its callback.
99
+ *
100
+ */
101
+ exports.effect = alien_signals_1.effect;
@@ -2,9 +2,14 @@ import { DeepPatchJITSubscriber, DeepPatchSubscriber, DeepSignal, DeepSignalOpti
2
2
  /** Runtime guard that checks whether a value is a deepSignal proxy. */
3
3
  export declare function isDeepSignal(value: unknown): value is DeepSignal<any>;
4
4
  /**
5
- * Create a deep reactive proxy for objects, arrays or Sets.
6
- * Returns the input itself, if it's a deepSignal already.
7
- * Throws if provided with unsupported input types.
5
+ * MAIN ENTRY POINT to create a deep reactive proxy for objects, arrays or Sets.
6
+ *
7
+ * If input is a deepSignal already and options are provided,
8
+ * the added subscriberFactories are joined with the existing ones
9
+ * and `replaceProxiesInBranchOnChange` is or-ed with the current value.
10
+ *
11
+ *
12
+ * @throws if provided with unsupported input types.
8
13
  */
9
14
  export declare function deepSignal<T extends object>(input: T, options?: DeepSignalOptions): DeepSignal<T>;
10
15
  /**
@@ -17,7 +22,14 @@ export declare function subscribeDeepMutations(root: object | symbol, cb: DeepPa
17
22
  export declare function getDeepSignalRootId(value: any): symbol | undefined;
18
23
  /** Retrieve the current patch version for a deepSignal root (if tracked). */
19
24
  export declare function getDeepSignalVersion(root: object | symbol): number | undefined;
20
- /** Mark an object so deepSignal skips proxying it (shallow boundary). */
25
+ /** Mark an object so deepSignal skips proxying it (shallow boundary).
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { shallow } from "alien-deepsignals";
30
+ * state.config = shallow({ huge: { blob: true } });
31
+ * ```
32
+ */
21
33
  export declare function shallow<T extends object>(obj: T): T;
22
34
  /** Force a specific synthetic ID to be used for a Set entry prior to insertion. */
23
35
  export declare function setSetEntrySyntheticId(obj: object, id: string | number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"deepSignal.d.ts","sourceRoot":"","sources":["../src/deepSignal.ts"],"names":[],"mappings":"AAWA,OAAO,EAGH,sBAAsB,EACtB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,EAOpB,MAAM,SAAS,CAAC;AA2wCjB,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC,CAErE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACvC,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAyCf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAClC,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,EAAE,EAAE,mBAAmB,GAAG,sBAAsB,EAChD,gBAAgB,GAAE,OAAe,GAClC,MAAM,IAAI,CAoBZ;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAElE;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,GAAG,SAAS,CAIpB;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAGnD;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,QAItE;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAa1E;AAED,oDAAoD;AACpD,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,OAEhE"}
1
+ {"version":3,"file":"deepSignal.d.ts","sourceRoot":"","sources":["../src/deepSignal.ts"],"names":[],"mappings":"AAWA,OAAO,EAGH,sBAAsB,EACtB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,EAMpB,MAAM,SAAS,CAAC;AAywCjB,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC,CAErE;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACvC,KAAK,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAwCf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAClC,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,EAAE,EAAE,mBAAmB,GAAG,sBAAsB,EAChD,gBAAgB,GAAE,OAAe,GAClC,MAAM,IAAI,CAoBZ;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAElE;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAGnD;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,QAItE;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAa1E;AAED,oDAAoD;AACpD,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,OAEhE"}
@@ -146,7 +146,7 @@ function ensureProxiedGetter(signals, target, key, receiver) {
146
146
  typeof Object.getOwnPropertyDescriptor(target, key)?.get === "function" // If we have a getter?
147
147
  ) {
148
148
  signals.set(key, {
149
- alienSignal: (0, core_1.alienComputed)(() => Reflect.get(target, key, receiver)),
149
+ alienSignal: (0, core_1.computed)(() => Reflect.get(target, key, receiver)),
150
150
  externalSubscribers: new Map(),
151
151
  });
152
152
  }
@@ -382,8 +382,8 @@ function ensureSetInfo(meta) {
382
382
  * Assign (or reuse) a synthetic identifier for a Set entry, respecting user options:
383
383
  * - Use user-provided propGenerator for synthetic ids and add add returned extra properties
384
384
  * - Check if the object has a property of `syntheticIdPropertyName` (default `@id`)
385
- * - Use a blank node id as a fallback.
386
- * - Add object and id to `idForObject` and `objectForId` maps.
385
+ * - Use a blank node ID as a fallback.
386
+ * - Add object and ID to `idForObject` and `objectForId` maps.
387
387
  */
388
388
  function assignSyntheticId(meta, entry, path, inSet) {
389
389
  const rawEntry = entry?.[RAW_KEY] ?? entry;
@@ -1013,15 +1013,19 @@ function isDeepSignal(value) {
1013
1013
  return !!value?.[RAW_KEY];
1014
1014
  }
1015
1015
  /**
1016
- * Create a deep reactive proxy for objects, arrays or Sets.
1017
- * Returns the input itself, if it's a deepSignal already.
1018
- * Throws if provided with unsupported input types.
1016
+ * MAIN ENTRY POINT to create a deep reactive proxy for objects, arrays or Sets.
1017
+ *
1018
+ * If input is a deepSignal already and options are provided,
1019
+ * the added subscriberFactories are joined with the existing ones
1020
+ * and `replaceProxiesInBranchOnChange` is or-ed with the current value.
1021
+ *
1022
+ *
1023
+ * @throws if provided with unsupported input types.
1019
1024
  */
1020
1025
  function deepSignal(input, options) {
1021
1026
  // Is the input already a signal?
1022
1027
  if (isDeepSignal(input)) {
1023
1028
  // Add possibly new external subscribers to existing ones.
1024
- // TODO: Document this behavior.
1025
1029
  const meta = rawToMeta.get(input[RAW_KEY]);
1026
1030
  meta.options.subscriberFactories =
1027
1031
  meta.options.subscriberFactories.union(options?.subscriberFactories ?? new Set());
@@ -1088,7 +1092,14 @@ function getDeepSignalVersion(root) {
1088
1092
  return undefined;
1089
1093
  return rootStates.get(rootId)?.version;
1090
1094
  }
1091
- /** Mark an object so deepSignal skips proxying it (shallow boundary). */
1095
+ /** Mark an object so deepSignal skips proxying it (shallow boundary).
1096
+ *
1097
+ * @example
1098
+ * ```ts
1099
+ * import { shallow } from "alien-deepsignals";
1100
+ * state.config = shallow({ huge: { blob: true } });
1101
+ * ```
1102
+ */
1092
1103
  function shallow(obj) {
1093
1104
  ignored.add(obj);
1094
1105
  return obj;
@@ -6,7 +6,7 @@ import { DeepSignalOptions } from "../..";
6
6
  * is rerendered as well.
7
7
  *
8
8
  * @param object The object that should become reactive
9
- * @param deepSignalOptions When the object is not a deepSignal already, options passed to `deepSignal`.
9
+ * @param options When the object is not a deepSignal already, options passed to {@link deepSignal}.
10
10
  * @returns The deepSignal object of the object param. On every change, the returned object will change (a new no-op proxy is created) around the deepSignal object.
11
11
  */
12
12
  declare const useSignal: <T extends object>(object: T, deepSignalOptions?: DeepSignalOptions) => import("../..").DeepSignal<T>;
@@ -19,7 +19,7 @@ const __1 = require("../..");
19
19
  * is rerendered as well.
20
20
  *
21
21
  * @param object The object that should become reactive
22
- * @param deepSignalOptions When the object is not a deepSignal already, options passed to `deepSignal`.
22
+ * @param options When the object is not a deepSignal already, options passed to {@link deepSignal}.
23
23
  * @returns The deepSignal object of the object param. On every change, the returned object will change (a new no-op proxy is created) around the deepSignal object.
24
24
  */
25
25
  const useSignal = (object, deepSignalOptions) => {
@@ -7,9 +7,9 @@ import { DeepSignalOptions, DeepSignal } from "../../index";
7
7
  * is rerendered as well.
8
8
  *
9
9
  * @param object The object that should become reactive
10
- * @param deepSignalObjects When the object is not a deepSignal already, options passed to `deepSignal`.
10
+ * @param options Options passed to {@link deepSignal}.
11
11
  * @returns A rune for using the deepSignal object in svelte.
12
12
  */
13
- export declare function useDeepSignal<T extends object>(object: T, options?: DeepSignalOptions): T extends DeepSignal<any> ? T : DeepSignal<T> | undefined;
13
+ export declare function useDeepSignal<T extends object>(object: T, options?: DeepSignalOptions): T extends DeepSignal<any> ? T : DeepSignal<T>;
14
14
  export default useDeepSignal;
15
15
  //# sourceMappingURL=useDeepSignal.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDeepSignal.svelte.d.ts","sourceRoot":"","sources":["../../../src/hooks/svelte/useDeepSignal.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,iBAAiB,EAAc,UAAU,EAAE,MAAM,aAAa,CAAC;AAExE;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,iBAAiB,GAab,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,CAC1E;AAyBD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"useDeepSignal.svelte.d.ts","sourceRoot":"","sources":["../../../src/hooks/svelte/useDeepSignal.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,iBAAiB,EAAc,UAAU,EAAE,MAAM,aAAa,CAAC;AAExE;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,iBAAiB,GAab,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAC9D;AAyBD,eAAe,aAAa,CAAC"}
@@ -20,7 +20,7 @@ const index_1 = require("../../index");
20
20
  * is rerendered as well.
21
21
  *
22
22
  * @param object The object that should become reactive
23
- * @param deepSignalObjects When the object is not a deepSignal already, options passed to `deepSignal`.
23
+ * @param options Options passed to {@link deepSignal}.
24
24
  * @returns A rune for using the deepSignal object in svelte.
25
25
  */
26
26
  function useDeepSignal(object, options) {
@@ -1,5 +1,5 @@
1
1
  import { type Readable } from "svelte/store";
2
- import { DeepSignalOptions, RevertDeepSignal } from "../../index";
2
+ import { DeepSignalOptions, UnwrapDeepSignal } from "../../index";
3
3
  /** Base result contract for a deepSignal-backed Svelte integration. */
4
4
  export interface UseDeepSignalResult<T> extends Readable<T> {
5
5
  /** Derive a nested selection; re-runs when the underlying tree version increments. */
@@ -12,16 +12,16 @@ export interface UseDeepSignalResult<T> extends Readable<T> {
12
12
  update(updater: (current: T) => T | void): void;
13
13
  }
14
14
  /**
15
- * Create a rune from a deepSignal object (creates one if it is just a regular object).
15
+ * Create a store from a deepSignal object (creates one if it is just a regular object).
16
16
  *
17
17
  * Modifications to the returned deepSignal object cause an immediate rerender.
18
18
  * If modifications of the object are made from somewhere else, the component
19
19
  * is rerendered as well.
20
20
  *
21
21
  * @param object The object that should become reactive
22
- * @param deepSignalObjects When the object is not a deepSignal already, options passed to `deepSignal`.
23
- * @returns A rune for using the deepSignal object in svelte.
22
+ * @param options Options passed to {@link deepSignal}.
23
+ * @returns A store for using the deepSignal object in svelte.
24
24
  */
25
- export declare function useDeepSignal<T extends object>(object: T | Promise<T>, options?: DeepSignalOptions): UseDeepSignalResult<RevertDeepSignal<T>>;
25
+ export declare function useDeepSignal<T extends object>(object: T | Promise<T>, options?: DeepSignalOptions): UseDeepSignalResult<UnwrapDeepSignal<T>>;
26
26
  export default useDeepSignal;
27
27
  //# sourceMappingURL=useDeepSignal.svelte.d.ts.map
@@ -15,15 +15,15 @@ const svelte_1 = require("svelte");
15
15
  const index_1 = require("../../index");
16
16
  const deepSignal_1 = require("../../deepSignal");
17
17
  /**
18
- * Create a rune from a deepSignal object (creates one if it is just a regular object).
18
+ * Create a store from a deepSignal object (creates one if it is just a regular object).
19
19
  *
20
20
  * Modifications to the returned deepSignal object cause an immediate rerender.
21
21
  * If modifications of the object are made from somewhere else, the component
22
22
  * is rerendered as well.
23
23
  *
24
24
  * @param object The object that should become reactive
25
- * @param deepSignalObjects When the object is not a deepSignal already, options passed to `deepSignal`.
26
- * @returns A rune for using the deepSignal object in svelte.
25
+ * @param options Options passed to {@link deepSignal}.
26
+ * @returns A store for using the deepSignal object in svelte.
27
27
  */
28
28
  function useDeepSignal(object, options) {
29
29
  const version = (0, store_1.writable)(-1);
@@ -7,7 +7,7 @@ import { DeepSignal, DeepSignalOptions } from "../../";
7
7
  * is rerendered as well.
8
8
  *
9
9
  * @param object The object that should become reactive (can be a ref or getter)
10
- * @param options When the object is not a deepSignal already, options passed to `deepSignal`.
10
+ * @param options Options passed to {@link deepSignal}.
11
11
  * @returns The deepSignal object of the object param.
12
12
  *
13
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"useDeepSignal.d.ts","sourceRoot":"","sources":["../../../src/hooks/vue/useDeepSignal.ts"],"names":[],"mappings":"AAUA,OAAO,EAGH,KAAK,gBAAgB,EAIxB,MAAM,KAAK,CAAC;AAEb,OAAO,EAAE,UAAU,EAAc,iBAAiB,EAAS,MAAM,QAAQ,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAaf;AAkBD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"useDeepSignal.d.ts","sourceRoot":"","sources":["../../../src/hooks/vue/useDeepSignal.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,gBAAgB,EAAsB,MAAM,KAAK,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAc,iBAAiB,EAAS,MAAM,QAAQ,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC1C,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,OAAO,CAAC,EAAE,iBAAiB,GAC5B,UAAU,CAAC,CAAC,CAAC,CAaf;AAkBD,eAAe,aAAa,CAAC"}
@@ -19,7 +19,7 @@ const __1 = require("../../");
19
19
  * is rerendered as well.
20
20
  *
21
21
  * @param object The object that should become reactive (can be a ref or getter)
22
- * @param options When the object is not a deepSignal already, options passed to `deepSignal`.
22
+ * @param options Options passed to {@link deepSignal}.
23
23
  * @returns The deepSignal object of the object param.
24
24
  *
25
25
  */
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export { addWithId, deepSignal, getRaw, isDeepSignal, shallow, subscribeDeepMutations, } from "./deepSignal";
2
2
  export * from "./core";
3
3
  export * from "./watch";
4
- export * from "./effect";
5
4
  export * from "./types";
6
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,SAAS,EACT,UAAU,EACV,MAAM,EACN,YAAY,EACZ,OAAO,EACP,sBAAsB,GACzB,MAAM,cAAc,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,SAAS,EACT,UAAU,EACV,MAAM,EACN,YAAY,EACZ,OAAO,EACP,sBAAsB,GACzB,MAAM,cAAc,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -24,5 +24,4 @@ Object.defineProperty(exports, "shallow", { enumerable: true, get: function () {
24
24
  Object.defineProperty(exports, "subscribeDeepMutations", { enumerable: true, get: function () { return deepSignal_1.subscribeDeepMutations; } });
25
25
  __exportStar(require("./core"), exports);
26
26
  __exportStar(require("./watch"), exports);
27
- __exportStar(require("./effect"), exports);
28
27
  __exportStar(require("./types"), exports);
@@ -15,12 +15,12 @@ exports.buildInitialState = buildInitialState;
15
15
  const buildDefaultObjectSetEntries = () => {
16
16
  const baseEntries = [
17
17
  {
18
- "@id": "urn:object:alpha",
18
+ "@id": "did:ng:x:alpha",
19
19
  label: "Alpha",
20
20
  count: 1,
21
21
  },
22
22
  {
23
- "@id": "urn:object:beta",
23
+ "@id": "did:ng:x:beta",
24
24
  label: "Beta",
25
25
  count: 3,
26
26
  },
@@ -28,7 +28,7 @@ const buildDefaultObjectSetEntries = () => {
28
28
  const extraEntries = Array.from({ length: 2 }, (_, index) => {
29
29
  const idNumber = (index + 1).toString().padStart(3, "0");
30
30
  return {
31
- "@id": `urn:object:item-${idNumber}`,
31
+ "@id": `did:ng:x:item-${idNumber}`,
32
32
  label: `Item ${idNumber}`,
33
33
  count: 5 + index,
34
34
  };
@@ -12,7 +12,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const vitest_1 = require("vitest");
13
13
  const __1 = require("../../");
14
14
  const watch_1 = require("../../watch");
15
- const effect_1 = require("../../effect");
16
15
  const deepSignal_1 = require("../../deepSignal");
17
16
  (0, vitest_1.describe)("watch", () => {
18
17
  (0, vitest_1.it)("watch immediate", () => {
@@ -84,15 +83,6 @@ const deepSignal_1 = require("../../deepSignal");
84
83
  (0, vitest_1.expect)(versions.length).toBe(1);
85
84
  (0, vitest_1.expect)(versions[0]).toBeGreaterThan(0);
86
85
  });
87
- (0, vitest_1.it)("effect runs and cleans up", () => {
88
- const calls = [];
89
- const dispose = (0, effect_1.effect)((registerCleanup) => {
90
- calls.push("run");
91
- registerCleanup?.(() => calls.push("cleanup"));
92
- });
93
- dispose();
94
- (0, vitest_1.expect)(calls).toEqual(["run", "cleanup"]);
95
- });
96
86
  });
97
87
  (0, vitest_1.describe)("watch (patch mode)", () => {
98
88
  (0, vitest_1.it)("emits set patches with correct paths and batching", async () => {
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { alienComputed, alienSignal } from "./core";
1
+ import { computed, alienSignal } from "./core";
2
2
  /** Deep mutation emitted from a deepSignal root. */
3
3
  export type DeepPatch = {
4
4
  path: (string | number)[];
@@ -16,20 +16,29 @@ export interface DeepPatchBatch {
16
16
  version: number;
17
17
  patches: DeepPatch[];
18
18
  }
19
- /** Batched patch payload for justInTime listeners. */
19
+ /** @ignore Batched patch payload for justInTime listeners. */
20
20
  export interface DeepPatchJITBatch {
21
21
  patches: DeepPatch[];
22
22
  }
23
+ /** @ignore */
23
24
  export type DeepPatchSubscriber = (batch: DeepPatchBatch) => void;
25
+ /** @ignore */
24
26
  export type DeepPatchJITSubscriber = (batch: DeepPatchJITBatch) => void;
25
- /** Options to pass to {@link deepSignal} */
27
+ /**
28
+ * Options to pass to {@link deepSignal}
29
+ * @internal
30
+ */
26
31
  export interface DeepSignalOptions {
27
- /** An optional function that is called when new objects are attached and that may return additional properties to be attached. */
32
+ /**
33
+ * An optional function that is called when new objects are attached and
34
+ * that may return additional properties to be attached.
35
+ */
28
36
  propGenerator?: DeepSignalPropGenFn;
29
37
  /**
30
38
  * The property name which should be used as an object identifier in sets.
31
39
  * You will see it when patches are generated with a path to an object in a set.
32
40
  * The `syntheticId` will be a patch element then.
41
+ * Objects with existing properties matching `syntheticIdPropertyName` keep their values (not overwritten).
33
42
  */
34
43
  syntheticIdPropertyName?: string;
35
44
  /**
@@ -50,14 +59,49 @@ export type ExternalSubscriberFactory<T = any> = () => {
50
59
  onGet: () => void;
51
60
  onSet: (newVal: T) => void;
52
61
  };
62
+ /**
63
+ * @internal
64
+ *
65
+ * The `propGenerator` function is called when a new object is added to the deep signal tree.
66
+ * @example
67
+ * ```ts
68
+ * let counter = 0;
69
+ * const state = deepSignal(
70
+ * { items: new Set() },
71
+ * {
72
+ * propGenerator: ({ path, inSet, object }) => ({
73
+ * syntheticId: inSet
74
+ * ? `urn:item:${++counter}`
75
+ * : `urn:obj:${path.join("-")}`,
76
+ * extraProps: { createdAt: new Date().toISOString() },
77
+ * }),
78
+ * syntheticIdPropertyName: "@id",
79
+ * }
80
+ * );
81
+ *
82
+ * state.items.add({ name: "Item 1" });
83
+ * // Attaches `{ name: "Item 1", `@id`: "urn:item:1", createdAt: <current date>`
84
+ *
85
+ * state.foo = {bar: 42};
86
+ * // Attaches `{bar: 42, "@id": "urn:obj:foo", createdAt: <current date>}`
87
+ * ```
88
+ */
53
89
  export type DeepSignalPropGenFn = (props: {
90
+ /**
91
+ * The path of the newly added object.
92
+ */
54
93
  path: (string | number)[];
94
+ /** Whether the object is being added to a Set (true) or not (false) */
55
95
  inSet: boolean;
96
+ /** The newly added object itself */
56
97
  object: any;
57
98
  }) => {
99
+ /** A custom identifier for the object (used in Set entry paths and optionally as a property). */
58
100
  syntheticId?: string | number;
101
+ /** Additional properties to be added to the object (overwriting existing ones). */
59
102
  extraProps?: Record<string, unknown>;
60
103
  };
104
+ /**@ignore*/
61
105
  export interface ProxyMeta {
62
106
  raw: object;
63
107
  parent?: ProxyMeta;
@@ -67,10 +111,12 @@ export interface ProxyMeta {
67
111
  options: DeepSignalOptions;
68
112
  setInfo?: SetMeta;
69
113
  }
114
+ /** @hidden */
70
115
  export interface SetMeta {
71
116
  idForObject: WeakMap<object, string>;
72
117
  objectForId: Map<string, object>;
73
118
  }
119
+ /**@ignore*/
74
120
  export interface RootState {
75
121
  options?: DeepSignalOptions;
76
122
  version: number;
@@ -78,12 +124,15 @@ export interface RootState {
78
124
  listeners: Set<DeepPatchSubscriber>;
79
125
  pendingPatches: DeepPatch[];
80
126
  }
127
+ /** @ignore */
81
128
  export type WritableSignal<T = any> = ReturnType<typeof alienSignal<T>>;
82
- export type ComputedSignal<T = any> = ReturnType<typeof alienComputed<T>>;
129
+ export type ComputedSignal<T = any> = ReturnType<typeof computed<T>>;
83
130
  export type SignalLike<T = any> = WritableSignal<T> | ComputedSignal<T>;
84
- /** Raw and meta key. */
131
+ /** @ignore Raw and meta key. */
85
132
  export type DeepSignalObjectProps<T> = {
133
+ /** The original raw object. */
86
134
  __raw__: T;
135
+ /** @ignore meta information */
87
136
  __meta__: ProxyMeta;
88
137
  };
89
138
  /** Utility functions for sets. */
@@ -99,13 +148,16 @@ export type DeepSignalSetProps<T> = {
99
148
  /**
100
149
  * Retrieve an object from the Set by its `@graph` and `@id`.
101
150
  *
102
- * @param graphIri - The `@graph` IRI of the object.
151
+ * @param graphIri - The `@graph` NURI of the object.
103
152
  * @param subjectIri - The `@subject` IRI of the object.
104
153
  * @returns The proxied entry if found, undefined otherwise.
105
154
  */
106
155
  getBy(graphIri: string, subjectIri: string): DeepSignal<T> | undefined;
107
156
  };
108
- /** Reactive Set wrapper that accepts raw or proxied entries. */
157
+ /**
158
+ * Type alias for `DeepSignal<Set<T>>` and reactive Set wrapper that accepts raw or proxied entries.
159
+ * Additionally it is decorated with {@link DeepSignalSetProps}.
160
+ */
109
161
  export interface DeepSignalSet<T> extends Set<DeepSignal<T>>, DeepSignalObjectProps<Set<T>>, SetIterator<DeepSignal<T>>, DeepSignalSetProps<T> {
110
162
  add(value: T | DeepSignal<T>): this;
111
163
  delete(value: T | DeepSignal<T>): boolean;
@@ -114,16 +166,15 @@ export interface DeepSignalSet<T> extends Set<DeepSignal<T>>, DeepSignalObjectPr
114
166
  forEach(callbackfn: (value: DeepSignal<T>, index: number) => void, thisArg?: any): void;
115
167
  }
116
168
  /**
117
- * The object returned by the @see deepSignal function.
118
- * It is decorated with utility functions for sets and a
119
- * `__raw__` prop to get the underlying non-reactive object
120
- * and `__meta__` prop, to get the internal metadata.
169
+ * The object returned by the {@link deepSignal} function.
170
+ * It is decorated with utility functions for sets, see {@link DeepSignalSetProps}
171
+ * and a `__raw__` prop to get the underlying non-reactive object.
121
172
  */
122
173
  export type DeepSignal<T> = T extends Function ? T : T extends string | number | boolean ? T : T extends DeepSignalObjectProps<any> | DeepSignalObjectProps<any>[] ? T : T extends Array<infer I> ? DeepSignal<I>[] : T extends Set<infer S> ? DeepSignalSet<S> : T extends object ? DeepSignalObject<T> : T;
123
174
  export type DeepSignalObject<T extends object> = {
124
175
  [K in keyof T]: DeepSignal<T[K]>;
125
176
  };
126
- export type RevertDeepSignal<T> = T extends DeepSignal<infer S> ? S : T;
177
+ export type UnwrapDeepSignal<T> = T extends DeepSignal<infer S> ? S : T;
127
178
  /** Union allowing a plain value or a writable signal wrapping that value. */
128
179
  export type MaybeSignal<T = any> = T | ReturnType<typeof alienSignal>;
129
180
  /** Union allowing value, writable signal, computed signal or plain getter function. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/watch.d.ts CHANGED
@@ -25,11 +25,37 @@ export type WatchPatchCallback<T extends object> = (event: WatchPatchEvent<T>) =
25
25
  /**
26
26
  * Watch for changes to a deepSignal.
27
27
  *
28
- * Whenever a change is made, `callback` with the patches describing the change and the current value.
28
+ * Whenever a change is made, `callback` is called with the patches describing the change and the new value.
29
29
  * If you set `triggerInstantly`, the callback is called on every property change.
30
30
  * If not, all changes are aggregated and `callback` is called in a microtask when
31
31
  * the current task finishes, e.g. `await` is called (meaning it supports batching).
32
32
  *
33
+ * When objects are added to Sets, their **synthetic ID (usually `@id`) becomes part of the patch path**. This allows patches to uniquely identify which Set entry is being mutated.
34
+ *
35
+ * ```ts
36
+ * const state = deepSignal(
37
+ * { s: new Set() },
38
+ * { ...}
39
+ * );
40
+ *
41
+ * watch(state, ({ patches }) => {
42
+ * console.log(JSON.stringify(patches));
43
+ * });
44
+ *
45
+ * state.s.add({ data: "test" });
46
+ * // Will log:
47
+ * // [
48
+ * // {"path":["s","did:ng:o:123"],"op":"add","type":"object"},
49
+ * // {"path":["s","did:ng:o:123","@id"],"op":"add","value":"did:ng:o:123"},
50
+ * // {"path":["s","did:ng:o:123","data"],"op":"add","value":"test"}
51
+ * // ]
52
+ *
53
+ * state.s.getById("did:ng:o:123")!.data = "new value"
54
+ * // Will log:
55
+ * // [
56
+ * // {"path":["s","did:ng:o:123","data"],"op":"add","value":"new value"}
57
+ * // ]
58
+ * ```
33
59
  */
34
60
  export declare function watch<T extends object>(source: DeepSignalSet<T> | DeepSignalObject<T> | DeepSignal<T>, callback: WatchPatchCallback<T>, options?: WatchOptions): {
35
61
  stopListening: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AAgBA,OAAO,EACH,SAAS,EAET,UAAU,EACV,gBAAgB,EAChB,aAAa,EAChB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAE9D,MAAM,WAAW,YAAY;IACzB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM;IAC7C,uBAAuB;IACvB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CAC3B;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,IAAI,CAC/C,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,KACxB,IAAI,CAAC;AAEV;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,EAClC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAC9D,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC/B,OAAO,GAAE,YAAiB;;;EAiE7B"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AAgBA,OAAO,EACH,SAAS,EAET,UAAU,EACV,gBAAgB,EAChB,aAAa,EAChB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAE9D,MAAM,WAAW,YAAY;IACzB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM;IAC7C,uBAAuB;IACvB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CAC3B;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,IAAI,CAC/C,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,KACxB,IAAI,CAAC;AAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,EAClC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAC9D,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC/B,OAAO,GAAE,YAAiB;;;EAiE7B"}
package/dist/watch.js CHANGED
@@ -14,11 +14,37 @@ const deepSignal_1 = require("./deepSignal");
14
14
  /**
15
15
  * Watch for changes to a deepSignal.
16
16
  *
17
- * Whenever a change is made, `callback` with the patches describing the change and the current value.
17
+ * Whenever a change is made, `callback` is called with the patches describing the change and the new value.
18
18
  * If you set `triggerInstantly`, the callback is called on every property change.
19
19
  * If not, all changes are aggregated and `callback` is called in a microtask when
20
20
  * the current task finishes, e.g. `await` is called (meaning it supports batching).
21
21
  *
22
+ * When objects are added to Sets, their **synthetic ID (usually `@id`) becomes part of the patch path**. This allows patches to uniquely identify which Set entry is being mutated.
23
+ *
24
+ * ```ts
25
+ * const state = deepSignal(
26
+ * { s: new Set() },
27
+ * { ...}
28
+ * );
29
+ *
30
+ * watch(state, ({ patches }) => {
31
+ * console.log(JSON.stringify(patches));
32
+ * });
33
+ *
34
+ * state.s.add({ data: "test" });
35
+ * // Will log:
36
+ * // [
37
+ * // {"path":["s","did:ng:o:123"],"op":"add","type":"object"},
38
+ * // {"path":["s","did:ng:o:123","@id"],"op":"add","value":"did:ng:o:123"},
39
+ * // {"path":["s","did:ng:o:123","data"],"op":"add","value":"test"}
40
+ * // ]
41
+ *
42
+ * state.s.getById("did:ng:o:123")!.data = "new value"
43
+ * // Will log:
44
+ * // [
45
+ * // {"path":["s","did:ng:o:123","data"],"op":"add","value":"new value"}
46
+ * // ]
47
+ * ```
22
48
  */
23
49
  function watch(source, callback, options = {}) {
24
50
  if (!(0, deepSignal_1.isDeepSignal)(source)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-org/alien-deepsignals",
3
- "version": "0.1.2-alpha.6",
3
+ "version": "0.1.2-alpha.7",
4
4
  "private": false,
5
5
  "authors": [
6
6
  "Laurin Weger",