@montra-interactive/deepstate 0.2.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@ Proxy-based reactive state management powered by RxJS. Each property is its own
9
9
  - **Type-safe**: Full TypeScript support with inferred types
10
10
  - **RxJS native**: Every node is an Observable - use `pipe()`, `combineLatest`, etc.
11
11
  - **Batched updates**: Group multiple changes into a single emission
12
- - **Immutable reads**: Values are deeply frozen to prevent accidental mutations
12
+ - **Mutable snapshots**: Reads return plain values; use `.set()` to update state
13
13
  - **Nullable objects**: First-class support for `T | null` properties with deep subscription
14
14
  - **Debug mode**: Optional logging for development
15
15
 
@@ -301,14 +301,13 @@ store.selectedId.get(); // string | null
301
301
  ### Type Exports
302
302
 
303
303
  ```ts
304
- import type { RxState, Draft, DeepReadonly } from "@montra-interactive/deepstate";
304
+ import type { RxState, Draft } from "@montra-interactive/deepstate";
305
305
  ```
306
306
 
307
307
  | Type | Description |
308
308
  |------|-------------|
309
309
  | `RxState<T>` | The reactive state type returned by `state()` |
310
310
  | `Draft<T>` | Type alias for values in update callbacks |
311
- | `DeepReadonly<T>` | Deep readonly type for returned values |
312
311
 
313
312
  ## Architecture
314
313
 
@@ -21,12 +21,9 @@ type IsNullish<T> = HasNull<T> extends true ? true : HasUndefined<T>;
21
21
  type NonNullPartIsObject<T> = NonNullablePart<T> extends object ? NonNullablePart<T> extends Array<unknown> ? false : true : false;
22
22
  type IsNullableObject<T> = IsNullish<T> extends true ? NonNullPartIsObject<T> : false;
23
23
  /**
24
- * Deep readonly type - makes all nested properties readonly.
25
- * Used for return types of get() and subscribe() to prevent accidental mutations.
24
+ * Type alias for values returned by get() and subscribe().
26
25
  */
27
- export type DeepReadonly<T> = [T] extends [Primitive] ? T : [T] extends [Array<infer U>] ? ReadonlyArray<DeepReadonly<U>> : [T] extends [object] ? {
28
- readonly [K in keyof T]: DeepReadonly<T[K]>;
29
- } : T;
26
+ export type DeepReadonly<T> = T;
30
27
  /**
31
28
  * A mutable draft of state T for use in update callbacks.
32
29
  */
@@ -38,20 +35,20 @@ interface NodeCore<T> {
38
35
  subscribeOnce?(callback: (value: T) => void): Subscription;
39
36
  }
40
37
  declare const NODE: unique symbol;
41
- type RxLeaf<T> = Observable<DeepReadonly<T>> & {
38
+ type RxLeaf<T> = Observable<T> & {
42
39
  /** Get current value synchronously */
43
- get(): DeepReadonly<T>;
40
+ get(): T;
44
41
  /** Set value */
45
42
  set(value: T): void;
46
43
  /** Subscribe to a single emission, then automatically unsubscribe */
47
- subscribeOnce(callback: (value: DeepReadonly<T>) => void): Subscription;
44
+ subscribeOnce(callback: (value: T) => void): Subscription;
48
45
  [NODE]: NodeCore<T>;
49
46
  };
50
47
  type RxObject<T extends object> = {
51
48
  [K in keyof T]: RxNodeFor<T[K]>;
52
- } & Observable<DeepReadonly<T>> & {
49
+ } & Observable<T> & {
53
50
  /** Get current value synchronously */
54
- get(): DeepReadonly<T>;
51
+ get(): T;
55
52
  /** Set value */
56
53
  set(value: T): void;
57
54
  /**
@@ -64,14 +61,14 @@ type RxObject<T extends object> = {
64
61
  * draft.age.set(31);
65
62
  * });
66
63
  */
67
- update(callback: (draft: RxObject<T>) => void): DeepReadonly<T>;
64
+ update(callback: (draft: RxObject<T>) => void): T;
68
65
  /** Subscribe to a single emission, then automatically unsubscribe */
69
- subscribeOnce(callback: (value: DeepReadonly<T>) => void): Subscription;
66
+ subscribeOnce(callback: (value: T) => void): Subscription;
70
67
  [NODE]: NodeCore<T>;
71
68
  };
72
- type RxArray<T> = Observable<DeepReadonly<T[]>> & {
69
+ type RxArray<T> = Observable<T[]> & {
73
70
  /** Get current value synchronously */
74
- get(): DeepReadonly<T[]>;
71
+ get(): T[];
75
72
  /** Set value */
76
73
  set(value: T[]): void;
77
74
  /**
@@ -84,9 +81,9 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
84
81
  * draft.push({ id: 2, name: "New" });
85
82
  * });
86
83
  */
87
- update(callback: (draft: RxArray<T>) => void): DeepReadonly<T[]>;
84
+ update(callback: (draft: RxArray<T>) => void): T[];
88
85
  /** Subscribe to a single emission, then automatically unsubscribe */
89
- subscribeOnce(callback: (value: DeepReadonly<T[]>) => void): Subscription;
86
+ subscribeOnce(callback: (value: T[]) => void): Subscription;
90
87
  /** Get reactive node for array element at index */
91
88
  at(index: number): RxNodeFor<T> | undefined;
92
89
  /** Get current length (also observable) */
@@ -96,11 +93,11 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
96
93
  /** Push items and return new length */
97
94
  push(...items: T[]): number;
98
95
  /** Pop last item */
99
- pop(): DeepReadonly<T> | undefined;
96
+ pop(): T | undefined;
100
97
  /** Map over current values (non-reactive, use .subscribe for reactive) */
101
- map<U>(fn: (item: DeepReadonly<T>, index: number) => U): U[];
98
+ map<U>(fn: (item: T, index: number) => U): U[];
102
99
  /** Filter current values */
103
- filter(fn: (item: DeepReadonly<T>, index: number) => boolean): DeepReadonly<T>[];
100
+ filter(fn: (item: T, index: number) => boolean): T[];
104
101
  [NODE]: NodeCore<T[]>;
105
102
  };
106
103
  /**
@@ -124,13 +121,13 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
124
121
  * store.user.name.get(); // "Alice"
125
122
  * store.user.name.set("Bob"); // Works!
126
123
  */
127
- type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<DeepReadonly<T>> & {
124
+ type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<T> & {
128
125
  /** Get current value (may be null/undefined) */
129
- get(): DeepReadonly<T>;
126
+ get(): T;
130
127
  /** Set value (can be null/undefined or the full object) */
131
128
  set(value: T): void;
132
129
  /** Subscribe to a single emission, then automatically unsubscribe */
133
- subscribeOnce(callback: (value: DeepReadonly<T>) => void): Subscription;
130
+ subscribeOnce(callback: (value: T) => void): Subscription;
134
131
  /**
135
132
  * Update multiple properties in a single emission.
136
133
  * @example
@@ -139,7 +136,7 @@ type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Obse
139
136
  * user.age.set(31);
140
137
  * });
141
138
  */
142
- update(callback: (draft: RxObject<TNonNull>) => void): DeepReadonly<T>;
139
+ update(callback: (draft: RxObject<TNonNull>) => void): T;
143
140
  [NODE]: NodeCore<T>;
144
141
  } & {
145
142
  [K in keyof TNonNull]: RxNullableChild<TNonNull[K]>;
@@ -156,10 +153,10 @@ type RxNullableChild<T> = IsNullableObject<T> extends true ? RxNullable<T> : [T]
156
153
  * The object itself might be undefined (if parent is null), but if present
157
154
  * it has all the normal object methods and children.
158
155
  */
159
- type RxNullableChildObject<T extends object> = Observable<DeepReadonly<T> | undefined> & {
160
- get(): DeepReadonly<T> | undefined;
156
+ type RxNullableChildObject<T extends object> = Observable<T | undefined> & {
157
+ get(): T | undefined;
161
158
  set(value: T): void;
162
- subscribeOnce(callback: (value: DeepReadonly<T> | undefined) => void): Subscription;
159
+ subscribeOnce(callback: (value: T | undefined) => void): Subscription;
163
160
  [NODE]: NodeCore<T | undefined>;
164
161
  } & {
165
162
  [K in keyof T]: RxNullableChild<T[K]>;
@@ -1 +1 @@
1
- {"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deepstate.d.ts","sourceRoot":"","sources":["../src/deepstate.ts"],"names":[],"mappings":"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"}
package/dist/helpers.d.ts CHANGED
@@ -56,6 +56,6 @@ export declare function select<T extends Record<string, Observable<unknown>>>(ob
56
56
  * @param selector - A function that extracts/derives a value from each item
57
57
  * @returns An Observable that emits an array of selected values
58
58
  */
59
- export declare function selectFromEach<T, U>(arrayNode: Observable<ReadonlyArray<T>>, selector: (item: T, index: number) => U): Observable<U[]>;
59
+ export declare function selectFromEach<T, U>(arrayNode: Observable<T[]>, selector: (item: T, index: number) => U): Observable<U[]>;
60
60
  export {};
61
61
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAiB,MAAM,MAAM,CAAC;AA+CjD,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAGpE,KAAK,gBAAgB,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI;KACtD,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAGF,KAAK,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI;KAC1E,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,EACpD,GAAG,WAAW,EAAE,CAAC,GAChB,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAClE,WAAW,EAAE,CAAC,GACb,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;AAyBzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EACjC,SAAS,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EACvC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,GACtC,UAAU,CAAC,CAAC,EAAE,CAAC,CAOjB"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAiB,MAAM,MAAM,CAAC;AA+CjD,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAGpE,KAAK,gBAAgB,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI;KACtD,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAGF,KAAK,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI;KAC1E,CAAC,IAAI,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,EACpD,GAAG,WAAW,EAAE,CAAC,GAChB,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAClE,WAAW,EAAE,CAAC,GACb,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;AAyBzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EACjC,SAAS,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,EAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,GACtC,UAAU,CAAC,CAAC,EAAE,CAAC,CAOjB"}
package/dist/index.js CHANGED
@@ -91,27 +91,6 @@ function countedDistinctUntilChanged(compareFn) {
91
91
  return a === b;
92
92
  });
93
93
  }
94
- function deepFreezeImpl(obj, seen) {
95
- if (obj === null || typeof obj !== "object")
96
- return obj;
97
- if (Object.isFrozen(obj))
98
- return obj;
99
- if (seen.has(obj))
100
- return obj;
101
- seen.add(obj);
102
- Object.freeze(obj);
103
- if (Array.isArray(obj)) {
104
- obj.forEach((item) => deepFreezeImpl(item, seen));
105
- } else {
106
- Object.keys(obj).forEach((key) => {
107
- deepFreezeImpl(obj[key], seen);
108
- });
109
- }
110
- return obj;
111
- }
112
- function deepFreeze(obj) {
113
- return deepFreezeImpl(obj, new WeakSet);
114
- }
115
94
  var NODE = Symbol("node");
116
95
  function createLeafNode(value) {
117
96
  const subject$ = new BehaviorSubject(value);
@@ -160,11 +139,10 @@ function createObjectNode(value) {
160
139
  return result;
161
140
  }), shareReplay(1));
162
141
  $.subscribe();
163
- const frozen$ = $.pipe(map2(deepFreeze));
164
142
  return {
165
- $: frozen$,
143
+ $,
166
144
  children,
167
- get: () => deepFreeze(getCurrentValue()),
145
+ get: () => getCurrentValue(),
168
146
  set: (v) => {
169
147
  for (const [key, child] of children) {
170
148
  child.set(v[key]);
@@ -173,7 +151,7 @@ function createObjectNode(value) {
173
151
  lock: () => lock$.next(false),
174
152
  unlock: () => lock$.next(true),
175
153
  subscribeOnce: (callback) => {
176
- return frozen$.pipe(take(1)).subscribe(callback);
154
+ return $.pipe(take(1)).subscribe(callback);
177
155
  }
178
156
  };
179
157
  }
@@ -202,7 +180,7 @@ function createArrayNode(value, comparator) {
202
180
  };
203
181
  const lock$ = new BehaviorSubject(true);
204
182
  const baseLocked$ = combineLatest2([subject$, lock$]).pipe(filter(([_, unlocked]) => unlocked), map2(([arr, _]) => arr));
205
- const locked$ = (comparator ? baseLocked$.pipe(distinctUntilChanged2(comparator)) : baseLocked$).pipe(map2(deepFreeze), shareReplay(1));
183
+ const locked$ = (comparator ? baseLocked$.pipe(distinctUntilChanged2(comparator)) : baseLocked$).pipe(map2((arr) => [...arr]), shareReplay(1));
206
184
  locked$.subscribe();
207
185
  const length$ = locked$.pipe(map2((arr) => arr.length), distinctUntilChanged2(), shareReplay(1));
208
186
  length$.subscribe();
@@ -212,7 +190,7 @@ function createArrayNode(value, comparator) {
212
190
  return {
213
191
  $: locked$,
214
192
  childCache,
215
- get: () => deepFreeze([...subject$.getValue()]),
193
+ get: () => [...subject$.getValue()],
216
194
  set: (v) => {
217
195
  if (hasCircularReference(v)) {
218
196
  throw new Error("Circular reference detected in array value. " + "Deepstate does not support circular references. " + "Please flatten your data structure or remove the circular reference.");
@@ -246,13 +224,13 @@ function createArrayNode(value, comparator) {
246
224
  const last = current[current.length - 1];
247
225
  childCache.delete(current.length - 1);
248
226
  subject$.next(current.slice(0, -1));
249
- return deepFreeze(last);
227
+ return last;
250
228
  },
251
229
  mapItems: (fn) => {
252
- return subject$.getValue().map((item, i) => fn(deepFreeze(item), i));
230
+ return subject$.getValue().map((item, i) => fn(item, i));
253
231
  },
254
232
  filterItems: (fn) => {
255
- return deepFreeze(subject$.getValue().filter((item, i) => fn(deepFreeze(item), i)));
233
+ return subject$.getValue().filter((item, i) => fn(item, i));
256
234
  },
257
235
  lock: () => lock$.next(false),
258
236
  unlock: () => lock$.next(true)
@@ -300,7 +278,7 @@ function createNullableObjectNode(initialValue) {
300
278
  if (b === null || b === undefined)
301
279
  return false;
302
280
  return JSON.stringify(a) === JSON.stringify(b);
303
- }), map2(deepFreeze), shareReplay(1));
281
+ }), shareReplay(1));
304
282
  $.subscribe();
305
283
  const nodeState = { children };
306
284
  const updateChildrenRef = () => {
@@ -329,7 +307,7 @@ function createNullableObjectNode(initialValue) {
329
307
  get children() {
330
308
  return nodeState.children;
331
309
  },
332
- get: () => deepFreeze(getCurrentValue()),
310
+ get: () => getCurrentValue(),
333
311
  set: (value) => {
334
312
  if (value === null || value === undefined) {
335
313
  subject$.next(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@montra-interactive/deepstate",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "description": "Proxy-based reactive state management with RxJS. Deep nested state observation with full TypeScript support.",
5
5
  "keywords": [
6
6
  "state",
@@ -19,7 +19,7 @@
19
19
  "homepage": "https://github.com/Montra-Interactive/deepstate/tree/main/packages/core",
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "https://github.com/Montra-Interactive/deepstate",
22
+ "url": "git+https://github.com/Montra-Interactive/deepstate.git",
23
23
  "directory": "packages/core"
24
24
  },
25
25
  "module": "dist/index.js",
package/src/deepstate.ts CHANGED
@@ -75,35 +75,6 @@ function countedDistinctUntilChanged<T>(compareFn?: (a: T, b: T) => boolean) {
75
75
  });
76
76
  }
77
77
 
78
- // =============================================================================
79
- // Deep Freeze
80
- // =============================================================================
81
-
82
- function deepFreezeImpl<T>(obj: T, seen: WeakSet<object>): T {
83
- if (obj === null || typeof obj !== "object") return obj;
84
- if (Object.isFrozen(obj)) return obj;
85
-
86
- // Circular reference protection
87
- if (seen.has(obj as object)) return obj;
88
- seen.add(obj as object);
89
-
90
- Object.freeze(obj);
91
-
92
- if (Array.isArray(obj)) {
93
- obj.forEach((item) => deepFreezeImpl(item, seen));
94
- } else {
95
- Object.keys(obj).forEach((key) => {
96
- deepFreezeImpl((obj as Record<string, unknown>)[key], seen);
97
- });
98
- }
99
-
100
- return obj;
101
- }
102
-
103
- function deepFreeze<T>(obj: T): T {
104
- return deepFreezeImpl(obj, new WeakSet<object>());
105
- }
106
-
107
78
  // =============================================================================
108
79
  // Types
109
80
  // =============================================================================
@@ -131,16 +102,9 @@ type IsNullableObject<T> = IsNullish<T> extends true
131
102
  : false;
132
103
 
133
104
  /**
134
- * Deep readonly type - makes all nested properties readonly.
135
- * Used for return types of get() and subscribe() to prevent accidental mutations.
105
+ * Type alias for values returned by get() and subscribe().
136
106
  */
137
- export type DeepReadonly<T> = [T] extends [Primitive]
138
- ? T
139
- : [T] extends [Array<infer U>]
140
- ? ReadonlyArray<DeepReadonly<U>>
141
- : [T] extends [object]
142
- ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
143
- : T;
107
+ export type DeepReadonly<T> = T;
144
108
 
145
109
  /**
146
110
  * A mutable draft of state T for use in update callbacks.
@@ -159,21 +123,21 @@ interface NodeCore<T> {
159
123
  const NODE = Symbol("node");
160
124
 
161
125
  // External API types
162
- type RxLeaf<T> = Observable<DeepReadonly<T>> & {
126
+ type RxLeaf<T> = Observable<T> & {
163
127
  /** Get current value synchronously */
164
- get(): DeepReadonly<T>;
128
+ get(): T;
165
129
  /** Set value */
166
130
  set(value: T): void;
167
131
  /** Subscribe to a single emission, then automatically unsubscribe */
168
- subscribeOnce(callback: (value: DeepReadonly<T>) => void): Subscription;
132
+ subscribeOnce(callback: (value: T) => void): Subscription;
169
133
  [NODE]: NodeCore<T>;
170
134
  };
171
135
 
172
136
  type RxObject<T extends object> = {
173
137
  [K in keyof T]: RxNodeFor<T[K]>;
174
- } & Observable<DeepReadonly<T>> & {
138
+ } & Observable<T> & {
175
139
  /** Get current value synchronously */
176
- get(): DeepReadonly<T>;
140
+ get(): T;
177
141
  /** Set value */
178
142
  set(value: T): void;
179
143
  /**
@@ -186,15 +150,15 @@ type RxObject<T extends object> = {
186
150
  * draft.age.set(31);
187
151
  * });
188
152
  */
189
- update(callback: (draft: RxObject<T>) => void): DeepReadonly<T>;
153
+ update(callback: (draft: RxObject<T>) => void): T;
190
154
  /** Subscribe to a single emission, then automatically unsubscribe */
191
- subscribeOnce(callback: (value: DeepReadonly<T>) => void): Subscription;
155
+ subscribeOnce(callback: (value: T) => void): Subscription;
192
156
  [NODE]: NodeCore<T>;
193
157
  };
194
158
 
195
- type RxArray<T> = Observable<DeepReadonly<T[]>> & {
159
+ type RxArray<T> = Observable<T[]> & {
196
160
  /** Get current value synchronously */
197
- get(): DeepReadonly<T[]>;
161
+ get(): T[];
198
162
  /** Set value */
199
163
  set(value: T[]): void;
200
164
  /**
@@ -207,9 +171,9 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
207
171
  * draft.push({ id: 2, name: "New" });
208
172
  * });
209
173
  */
210
- update(callback: (draft: RxArray<T>) => void): DeepReadonly<T[]>;
174
+ update(callback: (draft: RxArray<T>) => void): T[];
211
175
  /** Subscribe to a single emission, then automatically unsubscribe */
212
- subscribeOnce(callback: (value: DeepReadonly<T[]>) => void): Subscription;
176
+ subscribeOnce(callback: (value: T[]) => void): Subscription;
213
177
  /** Get reactive node for array element at index */
214
178
  at(index: number): RxNodeFor<T> | undefined;
215
179
  /** Get current length (also observable) */
@@ -217,11 +181,11 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
217
181
  /** Push items and return new length */
218
182
  push(...items: T[]): number;
219
183
  /** Pop last item */
220
- pop(): DeepReadonly<T> | undefined;
184
+ pop(): T | undefined;
221
185
  /** Map over current values (non-reactive, use .subscribe for reactive) */
222
- map<U>(fn: (item: DeepReadonly<T>, index: number) => U): U[];
186
+ map<U>(fn: (item: T, index: number) => U): U[];
223
187
  /** Filter current values */
224
- filter(fn: (item: DeepReadonly<T>, index: number) => boolean): DeepReadonly<T>[];
188
+ filter(fn: (item: T, index: number) => boolean): T[];
225
189
  [NODE]: NodeCore<T[]>;
226
190
  };
227
191
 
@@ -246,13 +210,13 @@ type RxArray<T> = Observable<DeepReadonly<T[]>> & {
246
210
  * store.user.name.get(); // "Alice"
247
211
  * store.user.name.set("Bob"); // Works!
248
212
  */
249
- type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<DeepReadonly<T>> & {
213
+ type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Observable<T> & {
250
214
  /** Get current value (may be null/undefined) */
251
- get(): DeepReadonly<T>;
215
+ get(): T;
252
216
  /** Set value (can be null/undefined or the full object) */
253
217
  set(value: T): void;
254
218
  /** Subscribe to a single emission, then automatically unsubscribe */
255
- subscribeOnce(callback: (value: DeepReadonly<T>) => void): Subscription;
219
+ subscribeOnce(callback: (value: T) => void): Subscription;
256
220
  /**
257
221
  * Update multiple properties in a single emission.
258
222
  * @example
@@ -261,7 +225,7 @@ type RxNullable<T, TNonNull extends object = NonNullablePart<T> & object> = Obse
261
225
  * user.age.set(31);
262
226
  * });
263
227
  */
264
- update(callback: (draft: RxObject<TNonNull>) => void): DeepReadonly<T>;
228
+ update(callback: (draft: RxObject<TNonNull>) => void): T;
265
229
  [NODE]: NodeCore<T>;
266
230
  } & {
267
231
  /**
@@ -299,10 +263,10 @@ type RxNullableChild<T> =
299
263
  * The object itself might be undefined (if parent is null), but if present
300
264
  * it has all the normal object methods and children.
301
265
  */
302
- type RxNullableChildObject<T extends object> = Observable<DeepReadonly<T> | undefined> & {
303
- get(): DeepReadonly<T> | undefined;
266
+ type RxNullableChildObject<T extends object> = Observable<T | undefined> & {
267
+ get(): T | undefined;
304
268
  set(value: T): void;
305
- subscribeOnce(callback: (value: DeepReadonly<T> | undefined) => void): Subscription;
269
+ subscribeOnce(callback: (value: T | undefined) => void): Subscription;
306
270
  [NODE]: NodeCore<T | undefined>;
307
271
  } & {
308
272
  [K in keyof T]: RxNullableChild<T[K]>;
@@ -411,13 +375,10 @@ function createObjectNode<T extends object>(value: T): NodeCore<T> & {
411
375
  // Force subscription to make it hot (so emissions work even before external subscribers)
412
376
  $.subscribe();
413
377
 
414
- // Create a version that freezes on emission
415
- const frozen$ = $.pipe(map(deepFreeze));
416
-
417
378
  return {
418
- $: frozen$,
379
+ $,
419
380
  children: children as Map<string, NodeCore<unknown>>,
420
- get: () => deepFreeze(getCurrentValue()),
381
+ get: () => getCurrentValue(),
421
382
  set: (v: T) => {
422
383
  for (const [key, child] of children) {
423
384
  child.set(v[key]);
@@ -427,7 +388,7 @@ function createObjectNode<T extends object>(value: T): NodeCore<T> & {
427
388
  unlock: () => lock$.next(true),
428
389
  // Note: update() is implemented in wrapWithProxy since it needs the proxy reference
429
390
  subscribeOnce: (callback: (value: T) => void): Subscription => {
430
- return frozen$.pipe(take(1)).subscribe(callback);
391
+ return $.pipe(take(1)).subscribe(callback);
431
392
  },
432
393
  };
433
394
  }
@@ -496,11 +457,11 @@ function createArrayNode<T>(
496
457
  );
497
458
 
498
459
  // Apply distinct comparison if provided
499
- const locked$ = (comparator
460
+ const locked$ = (comparator
500
461
  ? baseLocked$.pipe(distinctUntilChanged(comparator))
501
462
  : baseLocked$
502
463
  ).pipe(
503
- map(deepFreeze),
464
+ map((arr) => [...arr]),
504
465
  shareReplay(1)
505
466
  );
506
467
  locked$.subscribe(); // Keep hot
@@ -520,7 +481,7 @@ function createArrayNode<T>(
520
481
  return {
521
482
  $: locked$ as Observable<T[]>,
522
483
  childCache,
523
- get: () => deepFreeze([...subject$.getValue()]) as T[],
484
+ get: () => [...subject$.getValue()] as T[],
524
485
  set: (v: T[]) => {
525
486
  // Check for circular references in array items
526
487
  if (hasCircularReference(v)) {
@@ -560,13 +521,13 @@ function createArrayNode<T>(
560
521
  // Clear cached node for popped index
561
522
  childCache.delete(current.length - 1);
562
523
  subject$.next(current.slice(0, -1));
563
- return deepFreeze(last) as T;
524
+ return last as T;
564
525
  },
565
526
  mapItems: <U>(fn: (item: T, index: number) => U): U[] => {
566
- return subject$.getValue().map((item, i) => fn(deepFreeze(item) as T, i));
527
+ return subject$.getValue().map((item, i) => fn(item as T, i));
567
528
  },
568
529
  filterItems: (fn: (item: T, index: number) => boolean): T[] => {
569
- return deepFreeze(subject$.getValue().filter((item, i) => fn(deepFreeze(item) as T, i))) as T[];
530
+ return subject$.getValue().filter((item, i) => fn(item as T, i)) as T[];
570
531
  },
571
532
  lock: () => lock$.next(false),
572
533
  unlock: () => lock$.next(true),
@@ -668,7 +629,6 @@ function createNullableObjectNode<T>(
668
629
  if (b === null || b === undefined) return false;
669
630
  return JSON.stringify(a) === JSON.stringify(b);
670
631
  }),
671
- map(deepFreeze),
672
632
  shareReplay(1)
673
633
  );
674
634
  $.subscribe(); // Keep hot
@@ -711,7 +671,7 @@ function createNullableObjectNode<T>(
711
671
  $,
712
672
  get children() { return nodeState.children; },
713
673
 
714
- get: () => deepFreeze(getCurrentValue()),
674
+ get: () => getCurrentValue(),
715
675
 
716
676
  set: (value: T) => {
717
677
  if (value === null || value === undefined) {
package/src/helpers.ts CHANGED
@@ -137,7 +137,7 @@ export function select(
137
137
  * @returns An Observable that emits an array of selected values
138
138
  */
139
139
  export function selectFromEach<T, U>(
140
- arrayNode: Observable<ReadonlyArray<T>>,
140
+ arrayNode: Observable<T[]>,
141
141
  selector: (item: T, index: number) => U
142
142
  ): Observable<U[]> {
143
143
  return arrayNode.pipe(