@dxos/echo-atom 0.8.4-main.ef1bc66f44 → 0.8.4-main.effb148878

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/LICENSE CHANGED
@@ -1,8 +1,105 @@
1
- MIT License
2
- Copyright (c) 2025 DXOS
1
+ # Functional Source License, Version 1.1, ALv2 Future License
3
2
 
4
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
+ ## Abbreviation
5
4
 
6
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5
+ FSL-1.1-Apache-2.0
7
6
 
8
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ ## Notice
8
+
9
+ Copyright 2026 DXOS
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
package/README.md CHANGED
@@ -28,9 +28,9 @@ Atoms wrap Echo objects and their properties, storing metadata about the object
28
28
 
29
29
  ```typescript
30
30
  interface AtomValue<T> {
31
- readonly obj: Entity.Unknown; // The Echo object being watched
32
- readonly path: KeyPath; // Property path (empty for entire object)
33
- readonly value: T; // Current value
31
+ readonly obj: Entity.Unknown; // The Echo object being watched
32
+ readonly path: KeyPath; // Property path (empty for entire object)
33
+ readonly value: T; // Current value
34
34
  }
35
35
  ```
36
36
 
@@ -58,7 +58,7 @@ const registry = Registry.make();
58
58
  // Create an Echo object
59
59
  const person = Obj.make(TestSchema.Person, {
60
60
  name: 'Alice',
61
- email: 'alice@example.com'
61
+ email: 'alice@example.com',
62
62
  });
63
63
 
64
64
  // Create an atom for the entire object
@@ -72,10 +72,14 @@ const currentPerson = registry.get(personAtom).value;
72
72
  const currentName = registry.get(nameAtom).value;
73
73
 
74
74
  // Subscribe to updates using the registry
75
- const unsubscribe = registry.subscribe(nameAtom, () => {
76
- const newName = registry.get(nameAtom).value;
77
- console.log('Name changed:', newName);
78
- }, { immediate: true });
75
+ const unsubscribe = registry.subscribe(
76
+ nameAtom,
77
+ () => {
78
+ const newName = registry.get(nameAtom).value;
79
+ console.log('Name changed:', newName);
80
+ },
81
+ { immediate: true },
82
+ );
79
83
 
80
84
  // Update the object directly - the atom will automatically update
81
85
  person.name = 'Bob';
@@ -115,11 +119,14 @@ function PersonView({ person }: { person: Person }) {
115
119
 
116
120
  return (
117
121
  <div>
118
- <input
119
- value={name}
120
- onChange={(e) => updateName(e.target.value)}
121
- />
122
- <button onClick={() => updatePerson(p => { p.email = 'new@example.com'; })}>
122
+ <input value={name} onChange={(e) => updateName(e.target.value)} />
123
+ <button
124
+ onClick={() =>
125
+ updatePerson((p) => {
126
+ p.email = 'new@example.com';
127
+ })
128
+ }
129
+ >
123
130
  Update Email
124
131
  </button>
125
132
  </div>
@@ -157,11 +164,14 @@ function PersonView(props: { person: Person }) {
157
164
 
158
165
  return (
159
166
  <div>
160
- <input
161
- value={name()}
162
- onInput={(e) => updateName(e.target.value)}
163
- />
164
- <button onClick={() => updatePerson(p => { p.email = 'new@example.com'; })}>
167
+ <input value={name()} onInput={(e) => updateName(e.target.value)} />
168
+ <button
169
+ onClick={() =>
170
+ updatePerson((p) => {
171
+ p.email = 'new@example.com';
172
+ })
173
+ }
174
+ >
165
175
  Update Email
166
176
  </button>
167
177
  </div>
@@ -8,11 +8,15 @@ var __export = (target, all) => {
8
8
  var atom_exports = {};
9
9
  __export(atom_exports, {
10
10
  make: () => make2,
11
- makeProperty: () => makeProperty
11
+ makeProperty: () => makeProperty,
12
+ makeWithReactive: () => makeWithReactive
12
13
  });
13
14
  import * as Atom from "@effect-atom/atom/Atom";
14
- import isEqual from "lodash.isequal";
15
- import { Obj, Ref } from "@dxos/echo";
15
+ import * as Result from "@effect-atom/atom/Result";
16
+ import * as Effect from "effect/Effect";
17
+ import * as Function from "effect/Function";
18
+ import * as Option from "effect/Option";
19
+ import { Entity, Obj, Ref } from "@dxos/echo";
16
20
  import { assertArgument } from "@dxos/invariant";
17
21
 
18
22
  // src/ref-utils.ts
@@ -21,6 +25,13 @@ var loadRefTarget = (ref, get, onTargetAvailable) => {
21
25
  if (currentTarget) {
22
26
  return onTargetAvailable(currentTarget);
23
27
  }
28
+ const unsubscribe = ref.onResolved(() => {
29
+ const target = ref.target;
30
+ if (target) {
31
+ get.setSelf(onTargetAvailable(target));
32
+ }
33
+ });
34
+ get.addFinalizer(unsubscribe);
24
35
  void ref.load().then((loadedTarget) => {
25
36
  get.setSelf(onTargetAvailable(loadedTarget));
26
37
  }).catch(() => {
@@ -36,7 +47,7 @@ var objectFamily = Atom.family((obj) => {
36
47
  });
37
48
  get.addFinalizer(() => unsubscribe());
38
49
  return Obj.getSnapshot(obj);
39
- });
50
+ }).pipe(Atom.keepAlive);
40
51
  });
41
52
  var refFamily = Atom.family((ref) => {
42
53
  return Atom.make((get) => {
@@ -52,7 +63,7 @@ var refFamily = Atom.family((ref) => {
52
63
  unsubscribeTarget?.();
53
64
  });
54
65
  return loadRefTarget(ref, get, setupTargetSubscription);
55
- });
66
+ }).pipe(Atom.keepAlive);
56
67
  });
57
68
  var snapshotForComparison = (value) => {
58
69
  if (Array.isArray(value)) {
@@ -72,14 +83,14 @@ var propertyFamily = Atom.family((obj) => Atom.family((key) => {
72
83
  let previousSnapshot = snapshotForComparison(obj[key]);
73
84
  const unsubscribe = Obj.subscribe(obj, () => {
74
85
  const newValue = obj[key];
75
- if (!isEqual(previousSnapshot, newValue)) {
86
+ if (previousSnapshot !== newValue) {
76
87
  previousSnapshot = snapshotForComparison(newValue);
77
88
  get.setSelf(snapshotForComparison(newValue));
78
89
  }
79
90
  });
80
91
  get.addFinalizer(() => unsubscribe());
81
92
  return snapshotForComparison(obj[key]);
82
- });
93
+ }).pipe(Atom.keepAlive);
83
94
  }));
84
95
  function make2(objOrRef) {
85
96
  if (objOrRef === void 0) {
@@ -89,7 +100,7 @@ function make2(objOrRef) {
89
100
  return refFamily(objOrRef);
90
101
  }
91
102
  const obj = objOrRef;
92
- assertArgument(Obj.isObject(obj), "obj", "Object must be a reactive object");
103
+ assertArgument(Entity.isEntity(obj), "obj", "Object must be a reactive object");
93
104
  return objectFamily(obj);
94
105
  }
95
106
  function makeProperty(obj, key) {
@@ -97,9 +108,39 @@ function makeProperty(obj, key) {
97
108
  return Atom.make(() => void 0);
98
109
  }
99
110
  assertArgument(Obj.isObject(obj), "obj", "Object must be a reactive object");
100
- assertArgument(key in obj, "key", "Property must exist on object");
101
111
  return propertyFamily(obj)(key);
102
112
  }
113
+ var objectWithReactiveFamily = Atom.family((obj) => {
114
+ return Atom.make((get) => {
115
+ const unsubscribe = Obj.subscribe(obj, () => {
116
+ get.setSelf(obj);
117
+ });
118
+ get.addFinalizer(() => unsubscribe());
119
+ return obj;
120
+ }).pipe(Atom.keepAlive);
121
+ });
122
+ var refWithReactiveFamily = Atom.family((ref) => {
123
+ const effect = (get) => Effect.gen(function* () {
124
+ const snapshot = get(make2(ref));
125
+ if (snapshot == null) {
126
+ return void 0;
127
+ }
128
+ const option = yield* Obj.getReactiveOption(snapshot);
129
+ return Option.getOrElse(option, () => void 0);
130
+ });
131
+ return Function.pipe(Atom.make(effect), Atom.map((result) => Result.getOrElse(result, () => void 0)));
132
+ });
133
+ function makeWithReactive(objOrRef) {
134
+ if (objOrRef === void 0) {
135
+ return Atom.make(() => void 0);
136
+ }
137
+ if (Ref.isRef(objOrRef)) {
138
+ return refWithReactiveFamily(objOrRef);
139
+ }
140
+ const obj = objOrRef;
141
+ assertArgument(Obj.isObject(obj), "obj", "Object must be a reactive object");
142
+ return objectWithReactiveFamily(obj);
143
+ }
103
144
 
104
145
  // src/query-atom.ts
105
146
  var query_atom_exports = {};
@@ -108,14 +149,14 @@ __export(query_atom_exports, {
108
149
  make: () => make3
109
150
  });
110
151
  import { Atom as Atom2 } from "@effect-atom/atom";
111
- import { DXN, Database, Query } from "@dxos/echo";
152
+ import { Database, Key, Query } from "@dxos/echo";
112
153
  import { WeakDictionary } from "@dxos/util";
113
154
  var fromQuery = (queryResult) => Atom2.make((get) => {
114
155
  const unsubscribe = queryResult.subscribe(() => {
115
- get.setSelf(queryResult.results);
156
+ get.setSelf(queryResult.runSync());
116
157
  });
117
158
  get.addFinalizer(unsubscribe);
118
- return queryResult.results;
159
+ return queryResult.runSync();
119
160
  });
120
161
  var queryableRegistry = new WeakDictionary();
121
162
  var KEY_SEPARATOR = "~";
@@ -141,8 +182,8 @@ var getQueryableIdentifier = (queryable) => {
141
182
  if (Database.isDatabase(queryable)) {
142
183
  return queryable.spaceId;
143
184
  }
144
- if ("dxn" in queryable && queryable.dxn instanceof DXN) {
145
- return queryable.dxn.toString();
185
+ if ("uri" in queryable && Key.URI.isURI(queryable.uri)) {
186
+ return queryable.uri;
146
187
  }
147
188
  if ("id" in queryable && typeof queryable.id === "string") {
148
189
  return queryable.id;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/atom.ts", "../../../src/ref-utils.ts", "../../../src/query-atom.ts", "../../../src/ref-atom.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Atom from '@effect-atom/atom/Atom';\nimport isEqual from 'lodash.isequal';\n\nimport { Obj, Ref } from '@dxos/echo';\nimport { assertArgument } from '@dxos/invariant';\n\nimport { loadRefTarget } from './ref-utils';\n\n/**\n * Atom family for ECHO objects.\n * Uses object reference as key - same object returns same atom.\n */\nconst objectFamily = Atom.family(<T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>> => {\n return Atom.make<Obj.Snapshot<T>>((get) => {\n const unsubscribe = Obj.subscribe(obj, () => {\n get.setSelf(Obj.getSnapshot(obj));\n });\n\n get.addFinalizer(() => unsubscribe());\n\n return Obj.getSnapshot(obj);\n });\n});\n\n/**\n * Atom family for ECHO refs.\n * RefImpl implements Effect's Hash/Equal traits using DXN, so different Ref instances\n * pointing to the same object resolve to the same atom.\n */\nconst refFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined> => {\n return Atom.make<Obj.Snapshot<T> | undefined>((get) => {\n let unsubscribeTarget: (() => void) | undefined;\n\n const setupTargetSubscription = (target: T): Obj.Snapshot<T> => {\n unsubscribeTarget?.();\n unsubscribeTarget = Obj.subscribe(target, () => {\n get.setSelf(Obj.getSnapshot(target));\n });\n return Obj.getSnapshot(target);\n };\n\n get.addFinalizer(() => {\n unsubscribeTarget?.();\n });\n\n return loadRefTarget(ref, get, setupTargetSubscription);\n });\n});\n\n/**\n * Snapshot a value to create a new reference for comparison and React dependency tracking.\n * Arrays and plain objects are shallow-copied so that:\n * 1. The snapshot is isolated from mutations to the original value.\n * 2. React's shallow comparison (Object.is) detects changes via new reference identity.\n */\nconst snapshotForComparison = <V>(value: V): V => {\n if (Array.isArray(value)) {\n return [...value] as V;\n }\n if (value !== null && typeof value === 'object') {\n return { ...value } as V;\n }\n return value;\n};\n\n/**\n * Atom family for ECHO object properties.\n * Uses nested families: outer keyed by object, inner keyed by property key.\n * Same object+key combination returns same atom instance.\n */\nconst propertyFamily = Atom.family(<T extends Obj.Unknown>(obj: T) =>\n Atom.family(<K extends keyof T>(key: K): Atom.Atom<T[K]> => {\n return Atom.make<T[K]>((get) => {\n // Snapshot the initial value for comparison (arrays/objects need copying).\n let previousSnapshot = snapshotForComparison(obj[key]);\n\n const unsubscribe = Obj.subscribe(obj, () => {\n const newValue = obj[key];\n if (!isEqual(previousSnapshot, newValue)) {\n previousSnapshot = snapshotForComparison(newValue);\n // Return a snapshot copy so React sees a new reference.\n get.setSelf(snapshotForComparison(newValue));\n }\n });\n\n get.addFinalizer(() => unsubscribe());\n\n // Return a snapshot copy so React sees a new reference.\n return snapshotForComparison(obj[key]);\n });\n }),\n);\n\n/**\n * Create a read-only atom for a reactive object or ref.\n * Works with Echo objects, plain reactive objects (from Obj.make), and Refs.\n * Returns immutable snapshots of the object data (branded with SnapshotKindId).\n * The atom updates automatically when the object is mutated.\n * For refs, automatically handles async loading.\n * Uses Atom.family internally - same object/ref reference returns same atom instance.\n *\n * @param objOrRef - The reactive object or ref to create an atom for, or undefined.\n * @returns An atom that returns the object snapshot. Returns undefined only for refs (async loading) or undefined input.\n */\nexport function make<T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>>;\nexport function make<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined>;\nexport function make<T extends Obj.Unknown>(\n objOrRef: T | Ref.Ref<T> | undefined,\n): Atom.Atom<Obj.Snapshot<T> | undefined>;\nexport function make<T extends Obj.Unknown>(\n objOrRef: T | Ref.Ref<T> | undefined,\n): Atom.Atom<Obj.Snapshot<T> | undefined> {\n if (objOrRef === undefined) {\n return Atom.make<Obj.Snapshot<T> | undefined>(() => undefined);\n }\n\n // Handle Ref inputs.\n if (Ref.isRef(objOrRef)) {\n return refFamily(objOrRef as Ref.Ref<T>);\n }\n\n // At this point, objOrRef is definitely T (not a Ref).\n const obj = objOrRef as T;\n assertArgument(Obj.isObject(obj), 'obj', 'Object must be a reactive object');\n\n return objectFamily(obj);\n}\n\n/**\n * Create a read-only atom for a specific property of a reactive object.\n * Works with both Echo objects (from createObject) and plain live objects (from Obj.make).\n * The atom updates automatically when the property is mutated.\n * Only fires updates when the property value actually changes.\n * Uses Atom.family internally - same object+key combination returns same atom instance.\n *\n * @param obj - The reactive object to create an atom for, or undefined.\n * @param key - The property key to subscribe to.\n * @returns An atom that returns the property value, or undefined if obj is undefined.\n */\nexport function makeProperty<T extends Obj.Unknown, K extends keyof T>(obj: T, key: K): Atom.Atom<T[K]>;\nexport function makeProperty<T extends Obj.Unknown, K extends keyof T>(\n obj: T | undefined,\n key: K,\n): Atom.Atom<T[K] | undefined>;\nexport function makeProperty<T extends Obj.Unknown, K extends keyof T>(\n obj: T | undefined,\n key: K,\n): Atom.Atom<T[K] | undefined> {\n if (obj === undefined) {\n return Atom.make<T[K] | undefined>(() => undefined);\n }\n\n assertArgument(Obj.isObject(obj), 'obj', 'Object must be a reactive object');\n assertArgument(key in obj, 'key', 'Property must exist on object');\n return propertyFamily(obj)(key);\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport type * as Atom from '@effect-atom/atom/Atom';\n\nimport type { Ref } from '@dxos/echo';\n\n/**\n * Internal helper for loading ref targets in atoms.\n * Handles the common pattern of checking for loaded target and triggering async load.\n *\n * @param ref - The ref to load.\n * @param get - The atom context for setSelf.\n * @param onTargetAvailable - Callback invoked when target is available (sync or async).\n * Should return the value to use for the atom.\n * @returns The result of onTargetAvailable if target is already loaded, undefined otherwise.\n */\nexport const loadRefTarget = <T, R>(\n ref: Ref.Ref<T>,\n get: Atom.Context,\n onTargetAvailable: (target: T) => R,\n): R | undefined => {\n const currentTarget = ref.target;\n if (currentTarget) {\n return onTargetAvailable(currentTarget);\n }\n\n // Target not loaded yet - trigger async load.\n void ref\n .load()\n .then((loadedTarget) => {\n get.setSelf(onTargetAvailable(loadedTarget));\n })\n .catch(() => {\n // Loading failed, keep target as undefined.\n });\n\n return undefined;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom';\n\nimport { DXN, Database, type Entity, type Filter, Query, type QueryResult } from '@dxos/echo';\nimport { WeakDictionary } from '@dxos/util';\n\n/**\n * Create a self-updating atom from an existing QueryResult.\n * Internally subscribes to queryResult and uses get.setSelf to update.\n * Cleanup is handled via get.addFinalizer.\n *\n * Note: This creates a new atom each time. For memoization, use `make` instead.\n *\n * @param queryResult - The QueryResult to wrap.\n * @returns An atom that automatically updates when query results change.\n */\nexport const fromQuery = <T extends Entity.Unknown>(queryResult: QueryResult.QueryResult<T>): Atom.Atom<T[]> =>\n Atom.make((get) => {\n // TODO(wittjosiah): Consider subscribing to individual objects here as well, and grabbing their snapshots.\n // Subscribe to QueryResult changes.\n const unsubscribe = queryResult.subscribe(() => {\n get.setSelf(queryResult.results);\n });\n\n // Register cleanup for when atom is no longer used.\n get.addFinalizer(unsubscribe);\n\n return queryResult.results;\n });\n\n// Registry: key → Queryable (WeakRef with auto-cleanup when GC'd).\nconst queryableRegistry = new WeakDictionary<string, Database.Queryable>();\n\n// Key separator that won't appear in identifiers (DXN strings use colons).\nconst KEY_SEPARATOR = '~';\n\n// Atom.family keyed by \"identifier\\0serializedAST\".\nconst queryFamily = Atom.family((key: string) => {\n // Parse key outside Atom.make - runs once per key.\n const separatorIndex = key.indexOf(KEY_SEPARATOR);\n const identifier = key.slice(0, separatorIndex);\n const serializedAst = key.slice(separatorIndex + 1);\n\n // Get queryable outside Atom.make - keeps Queryable alive via closure.\n const queryable = queryableRegistry.get(identifier);\n if (!queryable) {\n return Atom.make(() => [] as Entity.Unknown[]);\n }\n\n // Create query outside Atom.make - runs once, not on every recompute.\n const ast = JSON.parse(serializedAst);\n const queryResult = queryable.query(Query.fromAst(ast)) as QueryResult.QueryResult<Entity.Unknown>;\n\n return Atom.make((get) => {\n const unsubscribe = queryResult.subscribe(() => {\n get.setSelf(queryResult.results);\n });\n get.addFinalizer(unsubscribe);\n\n return queryResult.results;\n });\n});\n\n/**\n * Derive a stable identifier from a Queryable.\n * Supports Database (spaceId), Queue (dxn), and objects with id.\n */\nconst getQueryableIdentifier = (queryable: Database.Queryable): string => {\n // Database: use spaceId.\n if (Database.isDatabase(queryable)) {\n return queryable.spaceId;\n }\n // Queue or similar: use dxn if it's a DXN instance.\n if ('dxn' in queryable && queryable.dxn instanceof DXN) {\n return queryable.dxn.toString();\n }\n // Fallback: use id if it's a string.\n if ('id' in queryable && typeof queryable.id === 'string') {\n return queryable.id;\n }\n throw new Error('Unable to derive identifier from queryable.');\n};\n\n/**\n * Get a memoized query atom for any Queryable (Database, Queue, etc.).\n * Uses a single Atom.family keyed by queryable identifier + serialized query AST.\n * Same queryable + query/filter = same atom instance (proper memoization).\n *\n * @param queryable - The queryable to query (Database, Queue, etc.).\n * @param queryOrFilter - A Query or Filter to execute.\n * @returns A memoized atom that updates when query results change.\n */\nexport const make = <T extends Entity.Unknown>(\n queryable: Database.Queryable,\n queryOrFilter: Query.Query<T> | Filter.Filter<T>,\n): Atom.Atom<T[]> => {\n const identifier = getQueryableIdentifier(queryable);\n return fromQueryable(queryable, identifier, queryOrFilter);\n};\n\n/**\n * Internal: Get a memoized query atom for any Queryable with a custom identifier.\n */\nconst fromQueryable = <T extends Entity.Unknown>(\n queryable: Database.Queryable,\n identifier: string,\n queryOrFilter: Query.Query<T> | Filter.Filter<T>,\n): Atom.Atom<T[]> => {\n // Register queryable in registry (WeakDictionary handles cleanup automatically).\n queryableRegistry.set(identifier, queryable);\n\n // Normalize to Query.\n const normalizedQuery: Query.Any = Query.is(queryOrFilter)\n ? queryOrFilter\n : Query.select(queryOrFilter as Filter.Filter<T>);\n\n // Build key: identifier\\0serializedAST (using null char as separator to avoid DXN colon conflicts).\n const key = `${identifier}${KEY_SEPARATOR}${JSON.stringify(normalizedQuery.ast)}`;\n\n return queryFamily(key) as Atom.Atom<T[]>;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Atom from '@effect-atom/atom/Atom';\n\nimport { type Ref } from '@dxos/echo';\n\nimport { loadRefTarget } from './ref-utils';\n\n/**\n * Atom family for ECHO refs.\n * Uses ref reference as key - same ref returns same atom.\n * This atom only updates once when the ref loads - it does not subscribe to object changes.\n * Use AtomObj.make with a ref if you need reactive snapshots of ECHO objects.\n */\nconst refFamily = Atom.family(<T>(ref: Ref.Ref<T>): Atom.Atom<T | undefined> => {\n return Atom.make<T | undefined>((get) => {\n return loadRefTarget(ref, get, (target) => target);\n });\n});\n\n/**\n * Create a read-only atom for a reference target.\n * Returns undefined if the target hasn't loaded yet.\n * Updates when the ref loads but does NOT subscribe to target object changes.\n * Use AtomObj.make with a ref if you need reactive snapshots of ECHO objects.\n * Uses Atom.family internally - same ref reference returns same atom instance.\n *\n * Supports refs to any target type including ECHO objects and Queues.\n */\nexport const make = refFamily;\n"],
5
- "mappings": "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",
6
- "names": ["make", "Atom", "isEqual", "Obj", "Ref", "assertArgument", "loadRefTarget", "ref", "get", "onTargetAvailable", "currentTarget", "target", "load", "then", "loadedTarget", "setSelf", "catch", "undefined", "objectFamily", "family", "obj", "make", "get", "unsubscribe", "Obj", "subscribe", "setSelf", "getSnapshot", "addFinalizer", "refFamily", "ref", "unsubscribeTarget", "setupTargetSubscription", "target", "loadRefTarget", "snapshotForComparison", "value", "Array", "isArray", "propertyFamily", "key", "previousSnapshot", "newValue", "isEqual", "objOrRef", "undefined", "Ref", "isRef", "assertArgument", "isObject", "makeProperty", "make", "Atom", "DXN", "Database", "Query", "WeakDictionary", "fromQuery", "queryResult", "Atom", "make", "get", "unsubscribe", "subscribe", "setSelf", "results", "addFinalizer", "queryableRegistry", "WeakDictionary", "KEY_SEPARATOR", "queryFamily", "family", "key", "separatorIndex", "indexOf", "identifier", "slice", "serializedAst", "queryable", "ast", "JSON", "parse", "query", "Query", "fromAst", "getQueryableIdentifier", "Database", "isDatabase", "spaceId", "dxn", "DXN", "toString", "id", "Error", "queryOrFilter", "fromQueryable", "set", "normalizedQuery", "is", "select", "stringify", "make", "Atom", "refFamily", "family", "ref", "make", "get", "loadRefTarget", "target"]
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Atom from '@effect-atom/atom/Atom';\nimport * as Result from '@effect-atom/atom/Result';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Option from 'effect/Option';\n\nimport { Entity, Obj, Ref, Relation } from '@dxos/echo';\nimport { assertArgument } from '@dxos/invariant';\n\nimport { loadRefTarget } from './ref-utils';\n\n/**\n * Atom family for ECHO objects.\n * Uses object reference as key - same object returns same atom.\n */\nconst objectFamily = Atom.family(<T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>> => {\n return Atom.make<Obj.Snapshot<T>>((get) => {\n const unsubscribe = Obj.subscribe(obj, () => {\n get.setSelf(Obj.getSnapshot(obj));\n });\n\n get.addFinalizer(() => unsubscribe());\n\n return Obj.getSnapshot(obj);\n }).pipe(Atom.keepAlive);\n});\n\n/**\n * Atom family for ECHO refs.\n * RefImpl implements Effect's Hash/Equal traits using DXN, so different Ref instances\n * pointing to the same object resolve to the same atom.\n */\nconst refFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined> => {\n return Atom.make<Obj.Snapshot<T> | undefined>((get) => {\n let unsubscribeTarget: (() => void) | undefined;\n\n const setupTargetSubscription = (target: T): Obj.Snapshot<T> => {\n unsubscribeTarget?.();\n unsubscribeTarget = Obj.subscribe(target, () => {\n get.setSelf(Obj.getSnapshot(target));\n });\n return Obj.getSnapshot(target);\n };\n\n get.addFinalizer(() => {\n unsubscribeTarget?.();\n });\n\n return loadRefTarget(ref, get, setupTargetSubscription);\n }).pipe(Atom.keepAlive);\n});\n\n/**\n * Snapshot a value to create a new reference for comparison and React dependency tracking.\n * Arrays and plain objects are shallow-copied so that:\n * 1. The snapshot is isolated from mutations to the original value.\n * 2. React's shallow comparison (Object.is) detects changes via new reference identity.\n */\nconst snapshotForComparison = <V>(value: V): V => {\n if (Array.isArray(value)) {\n return [...value] as V;\n }\n if (value !== null && typeof value === 'object') {\n return { ...value } as V;\n }\n return value;\n};\n\n/**\n * Atom family for ECHO object properties.\n * Uses nested families: outer keyed by object, inner keyed by property key.\n * Same object+key combination returns same atom instance.\n */\nconst propertyFamily = Atom.family(<T extends Obj.Unknown>(obj: T) =>\n Atom.family(<K extends keyof T>(key: K): Atom.Atom<T[K]> => {\n return Atom.make<T[K]>((get) => {\n // Snapshot the initial value for comparison (arrays/objects need copying).\n let previousSnapshot = snapshotForComparison(obj[key]);\n\n const unsubscribe = Obj.subscribe(obj, () => {\n const newValue = obj[key];\n if (previousSnapshot !== newValue) {\n previousSnapshot = snapshotForComparison(newValue);\n // Return a snapshot copy so React sees a new reference.\n get.setSelf(snapshotForComparison(newValue));\n }\n });\n\n get.addFinalizer(() => unsubscribe());\n\n // Return a snapshot copy so React sees a new reference.\n return snapshotForComparison(obj[key]);\n }).pipe(Atom.keepAlive);\n }),\n);\n\n/**\n * Create a read-only atom for a single reactive object or ref.\n * Returns {@link Obj.Snapshot} (immutable plain data), not the live reactive object.\n * Use this when you need one object's data for display or React dependency tracking.\n * The atom updates automatically when the object is mutated.\n * For refs, automatically handles async loading.\n * Uses Atom.family internally - same object/ref returns same atom instance.\n *\n * @param objOrRef - The reactive object or ref to create an atom for, or undefined.\n * @returns An atom that returns the object snapshot (plain data). Returns undefined only for refs (async loading) or undefined input.\n */\nexport function make<T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>>;\nexport function make<T extends Relation.Unknown>(relation: T): Atom.Atom<Relation.Snapshot<T>>;\nexport function make<T extends Entity.Unknown>(entity: T): Atom.Atom<Entity.Snapshot>;\nexport function make<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined>;\nexport function make<T extends Obj.Unknown>(\n objOrRef: T | Ref.Ref<T> | undefined,\n): Atom.Atom<Obj.Snapshot<T> | undefined>;\nexport function make<T extends Entity.Unknown>(\n objOrRef: T | Ref.Ref<T> | undefined,\n): Atom.Atom<Entity.Snapshot | undefined> {\n if (objOrRef === undefined) {\n return Atom.make<Entity.Snapshot | undefined>(() => undefined);\n }\n\n // Handle Ref inputs.\n if (Ref.isRef(objOrRef)) {\n return refFamily(objOrRef as any);\n }\n\n // At this point, objOrRef is definitely T (not a Ref).\n const obj = objOrRef as T;\n // Accept any kind of entity (Obj, Relation, or persisted Type) — the\n // reactive subscription only needs `[KindId]` to be set; the proxy machinery\n // is kind-agnostic. Narrowing to Obj/Relation here used to throw for type\n // entities returned by the schema registry (e.g. persisted RoastLog), which\n // broke the schema-node connector in plugin-space.\n assertArgument(Entity.isEntity(obj), 'obj', 'Object must be a reactive object');\n\n // TODO(dmaretskyi): Fix echo types during review.\n return objectFamily(obj as any);\n}\n\n/**\n * Create a read-only atom for a specific property of a reactive object.\n * Works with both Echo objects (from createObject) and plain live objects (from Obj.make).\n * The atom updates automatically when the property is mutated.\n * Only fires updates when the property value actually changes.\n * Uses Atom.family internally - same object+key combination returns same atom instance.\n *\n * @param obj - The reactive object to create an atom for, or undefined.\n * @param key - The property key to subscribe to.\n * @returns An atom that returns the property value, or undefined if obj is undefined.\n */\nexport function makeProperty<T extends Obj.Unknown, K extends keyof T>(obj: T, key: K): Atom.Atom<T[K]>;\nexport function makeProperty<T extends Obj.Unknown, K extends keyof T>(\n obj: T | undefined,\n key: K,\n): Atom.Atom<T[K] | undefined>;\nexport function makeProperty<T extends Obj.Unknown, K extends keyof T>(\n obj: T | undefined,\n key: K,\n): Atom.Atom<T[K] | undefined> {\n if (obj === undefined) {\n return Atom.make<T[K] | undefined>(() => undefined);\n }\n\n assertArgument(Obj.isObject(obj), 'obj', 'Object must be a reactive object');\n return propertyFamily(obj)(key);\n}\n\n/**\n * Atom family for ECHO objects - returns the live object, not a snapshot.\n * Same as objectFamily but returns T instead of Obj.Snapshot<T>.\n */\nconst objectWithReactiveFamily = Atom.family(<T extends Obj.Unknown>(obj: T): Atom.Atom<T> => {\n return Atom.make<T>((get) => {\n const unsubscribe = Obj.subscribe(obj, () => {\n get.setSelf(obj);\n });\n\n get.addFinalizer(() => unsubscribe());\n\n return obj;\n }).pipe(Atom.keepAlive);\n});\n\n/**\n * Atom family for ECHO refs - returns the live reactive object, not a snapshot.\n * Resolves the ref via the database; returns undefined while loading or if unresolved.\n */\nconst refWithReactiveFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<T | undefined> => {\n const effect = (get: Atom.Context) =>\n Effect.gen(function* () {\n const snapshot = get(make(ref));\n if (snapshot == null) {\n return undefined;\n }\n const option = yield* Obj.getReactiveOption(snapshot);\n return Option.getOrElse(option, () => undefined);\n });\n\n return Function.pipe(\n Atom.make(effect),\n Atom.map((result) => Result.getOrElse(result, () => undefined)),\n );\n});\n\n/**\n * Like {@link make} but returns the live reactive object instead of a snapshot.\n * Same input: Obj or Ref.Ref. Same output shape: Atom that updates when the object mutates.\n * Prefer {@link make} (snapshot) unless you need the live Obj.Obj for generic mutations (e.g. Obj.update).\n *\n * @param objOrRef - The reactive object or ref.\n * @returns An atom that returns the live object. Returns undefined for refs (async loading) or undefined input.\n */\nexport function makeWithReactive<T extends Obj.Unknown>(obj: T): Atom.Atom<T>;\nexport function makeWithReactive<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<T | undefined>;\nexport function makeWithReactive<T extends Obj.Unknown>(objOrRef: T | Ref.Ref<T> | undefined): Atom.Atom<T | undefined>;\nexport function makeWithReactive<T extends Obj.Unknown>(\n objOrRef: T | Ref.Ref<T> | undefined,\n): Atom.Atom<T | undefined> {\n if (objOrRef === undefined) {\n return Atom.make<T | undefined>(() => undefined);\n }\n\n if (Ref.isRef(objOrRef)) {\n return refWithReactiveFamily(objOrRef as Ref.Ref<T>);\n }\n\n const obj = objOrRef as T;\n assertArgument(Obj.isObject(obj), 'obj', 'Object must be a reactive object');\n return objectWithReactiveFamily(obj);\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport type * as Atom from '@effect-atom/atom/Atom';\n\nimport type { Ref } from '@dxos/echo';\n\n/**\n * Internal helper for loading ref targets in atoms.\n * Handles the common pattern of checking for loaded target and triggering async load.\n *\n * @param ref - The ref to load.\n * @param get - The atom context for setSelf.\n * @param onTargetAvailable - Callback invoked when target is available (sync or async).\n * Should return the value to use for the atom.\n * @returns The result of onTargetAvailable if target is already loaded, undefined otherwise.\n */\nexport const loadRefTarget = <T, R>(\n ref: Ref.Ref<T>,\n get: Atom.Context,\n onTargetAvailable: (target: T) => R,\n): R | undefined => {\n // Accessing `ref.target` registers a resolution callback when the target is\n // not yet loaded, so resolution can be observed via `ref.onResolved` below.\n const currentTarget = ref.target;\n if (currentTarget) {\n return onTargetAvailable(currentTarget);\n }\n\n // Subscribe to the ref's resolution event in case the target loads later\n // (e.g. when a sibling client creates the linked object). Without this,\n // a one-shot async load that fails because the document hasn't propagated\n // would leave the atom permanently undefined.\n const unsubscribe = ref.onResolved(() => {\n const target = ref.target;\n if (target) {\n get.setSelf(onTargetAvailable(target));\n }\n });\n get.addFinalizer(unsubscribe);\n\n // Also try async load (e.g. for objects that need disk loading).\n void ref\n .load()\n .then((loadedTarget) => {\n get.setSelf(onTargetAvailable(loadedTarget));\n })\n .catch(() => {\n // Loading failed; the resolution subscription above will pick up\n // cross-client updates when they arrive.\n });\n\n return undefined;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom';\n\nimport { Database, type Entity, type Filter, Key, Query, type QueryResult } from '@dxos/echo';\nimport { WeakDictionary } from '@dxos/util';\n\n/**\n * Create a self-updating atom from any QueryResult (e.g. schema registry queries).\n * Internally subscribes to queryResult and uses get.setSelf to update.\n * Cleanup is handled via get.addFinalizer.\n *\n * Note: This creates a new atom each time. For memoization, use `make` instead.\n *\n * @param queryResult - The QueryResult to wrap.\n * @returns An atom that automatically updates when query results change.\n */\nexport const fromQuery = <T>(queryResult: QueryResult.QueryResult<T>): Atom.Atom<T[]> =>\n Atom.make((get) => {\n const unsubscribe = queryResult.subscribe(() => {\n get.setSelf(queryResult.runSync());\n });\n get.addFinalizer(unsubscribe);\n return queryResult.runSync();\n });\n\n// Registry: key → Queryable (WeakRef with auto-cleanup when GC'd).\nconst queryableRegistry = new WeakDictionary<string, Database.Queryable>();\n\n// Key separator that won't appear in identifiers (DXN strings use colons).\nconst KEY_SEPARATOR = '~';\n\n// Atom.family keyed by \"identifier~serializedAST\".\nconst queryFamily = Atom.family((key: string) => {\n // Parse key outside Atom.make - runs once per key.\n const separatorIndex = key.indexOf(KEY_SEPARATOR);\n const identifier = key.slice(0, separatorIndex);\n const serializedAst = key.slice(separatorIndex + 1);\n\n // Get queryable outside Atom.make - keeps Queryable alive via closure.\n const queryable = queryableRegistry.get(identifier);\n if (!queryable) {\n return Atom.make(() => [] as Entity.Unknown[]);\n }\n\n // Create query outside Atom.make - runs once, not on every recompute.\n const ast = JSON.parse(serializedAst);\n const queryResult = queryable.query(Query.fromAst(ast)) as QueryResult.QueryResult<Entity.Unknown>;\n\n return Atom.make((get) => {\n const unsubscribe = queryResult.subscribe(() => {\n get.setSelf(queryResult.results);\n });\n get.addFinalizer(unsubscribe);\n\n return queryResult.results;\n });\n});\n\n/**\n * Derive a stable identifier from a Queryable.\n * Supports Database (spaceId), Queue (dxn), and objects with id.\n */\nconst getQueryableIdentifier = (queryable: Database.Queryable): string => {\n // Database: use spaceId.\n if (Database.isDatabase(queryable)) {\n return queryable.spaceId;\n }\n // Queue or similar: use uri if it's a URI (EchoURI or DXN).\n if ('uri' in queryable && Key.URI.isURI(queryable.uri)) {\n return queryable.uri;\n }\n // Fallback: use id if it's a string.\n if ('id' in queryable && typeof queryable.id === 'string') {\n return queryable.id;\n }\n throw new Error('Unable to derive identifier from queryable.');\n};\n\n/**\n * Get a memoized query atom for any Queryable (Database, Queue, etc.).\n * Uses a single Atom.family keyed by queryable identifier + serialized query AST.\n * Same queryable + query/filter = same atom instance (proper memoization).\n *\n * @param queryable - The queryable to query (Database, Queue, etc.).\n * @param queryOrFilter - A Query or Filter to execute.\n * @returns A memoized atom that updates when query results change.\n */\nexport const make = <T extends Entity.Unknown>(\n queryable: Database.Queryable,\n queryOrFilter: Query.Query<T> | Filter.Filter<T>,\n): Atom.Atom<T[]> => {\n const identifier = getQueryableIdentifier(queryable);\n return fromQueryable(queryable, identifier, queryOrFilter);\n};\n\n/**\n * Internal: Get a memoized query atom for any Queryable with a custom identifier.\n */\nconst fromQueryable = <T extends Entity.Unknown>(\n queryable: Database.Queryable,\n identifier: string,\n queryOrFilter: Query.Query<T> | Filter.Filter<T>,\n): Atom.Atom<T[]> => {\n // Register queryable in registry (WeakDictionary handles cleanup automatically).\n queryableRegistry.set(identifier, queryable);\n\n // Normalize to Query.\n const normalizedQuery: Query.Any = Query.is(queryOrFilter)\n ? queryOrFilter\n : Query.select(queryOrFilter as Filter.Filter<T>);\n\n // Build key: identifier\\0serializedAST (using null char as separator to avoid DXN colon conflicts).\n const key = `${identifier}${KEY_SEPARATOR}${JSON.stringify(normalizedQuery.ast)}`;\n\n return queryFamily(key) as Atom.Atom<T[]>;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Atom from '@effect-atom/atom/Atom';\n\nimport { type Ref } from '@dxos/echo';\n\nimport { loadRefTarget } from './ref-utils';\n\n/**\n * Atom family for ECHO refs.\n * Uses ref reference as key - same ref returns same atom.\n * This atom only updates once when the ref loads - it does not subscribe to object changes.\n * Use AtomObj.make with a ref if you need reactive snapshots of ECHO objects.\n */\nconst refFamily = Atom.family(<T>(ref: Ref.Ref<T>): Atom.Atom<T | undefined> => {\n return Atom.make<T | undefined>((get) => {\n return loadRefTarget(ref, get, (target) => target);\n });\n});\n\n/**\n * Create a read-only atom for a reference target.\n * Returns undefined if the target hasn't loaded yet.\n * Updates when the ref loads but does NOT subscribe to target object changes.\n * Use AtomObj.make with a ref if you need reactive snapshots of ECHO objects.\n * Uses Atom.family internally - same ref reference returns same atom instance.\n *\n * Supports refs to any target type including ECHO objects and Queues.\n */\nexport const make = refFamily;\n"],
5
+ "mappings": "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",
6
+ "names": ["make", "Atom", "Result", "Effect", "Function", "Option", "Entity", "Obj", "Ref", "assertArgument", "loadRefTarget", "ref", "get", "onTargetAvailable", "currentTarget", "target", "unsubscribe", "onResolved", "setSelf", "addFinalizer", "load", "then", "loadedTarget", "catch", "undefined", "objectFamily", "family", "obj", "make", "get", "unsubscribe", "Obj", "subscribe", "setSelf", "getSnapshot", "addFinalizer", "pipe", "keepAlive", "refFamily", "ref", "unsubscribeTarget", "setupTargetSubscription", "target", "loadRefTarget", "snapshotForComparison", "value", "Array", "isArray", "propertyFamily", "key", "previousSnapshot", "newValue", "objOrRef", "undefined", "Ref", "isRef", "assertArgument", "Entity", "isEntity", "makeProperty", "isObject", "objectWithReactiveFamily", "refWithReactiveFamily", "effect", "gen", "snapshot", "option", "getReactiveOption", "getOrElse", "map", "result", "makeWithReactive", "make", "Atom", "Database", "Key", "Query", "WeakDictionary", "fromQuery", "queryResult", "get", "unsubscribe", "subscribe", "setSelf", "runSync", "addFinalizer", "queryableRegistry", "KEY_SEPARATOR", "queryFamily", "family", "key", "separatorIndex", "indexOf", "identifier", "slice", "serializedAst", "queryable", "ast", "JSON", "parse", "query", "fromAst", "results", "getQueryableIdentifier", "isDatabase", "spaceId", "URI", "isURI", "uri", "id", "Error", "queryOrFilter", "fromQueryable", "set", "normalizedQuery", "is", "select", "stringify", "make", "Atom", "refFamily", "family", "ref", "make", "get", "loadRefTarget", "target"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"src/ref-utils.ts":{"bytes":3291,"imports":[],"format":"esm"},"src/atom.ts":{"bytes":14923,"imports":[{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true},{"path":"lodash.isequal","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"src/ref-utils.ts","kind":"import-statement","original":"./ref-utils"}],"format":"esm"},"src/query-atom.ts":{"bytes":13559,"imports":[{"path":"@effect-atom/atom","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"src/ref-atom.ts":{"bytes":3183,"imports":[{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true},{"path":"src/ref-utils.ts","kind":"import-statement","original":"./ref-utils"}],"format":"esm"},"src/index.ts":{"bytes":816,"imports":[{"path":"src/atom.ts","kind":"import-statement","original":"./atom"},{"path":"src/query-atom.ts","kind":"import-statement","original":"./query-atom"},{"path":"src/ref-atom.ts","kind":"import-statement","original":"./ref-atom"}],"format":"esm"}},"outputs":{"dist/lib/neutral/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":18117},"dist/lib/neutral/index.mjs":{"imports":[{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true},{"path":"lodash.isequal","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@effect-atom/atom","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true}],"exports":["AtomObj","AtomQuery","AtomRef"],"entryPoint":"src/index.ts","inputs":{"src/atom.ts":{"bytesInOutput":2328},"src/ref-utils.ts":{"bytesInOutput":301},"src/index.ts":{"bytesInOutput":0},"src/query-atom.ts":{"bytesInOutput":2044},"src/ref-atom.ts":{"bytesInOutput":291}},"bytes":5365}}}
1
+ {"inputs":{"src/ref-utils.ts":{"bytes":5284,"imports":[],"format":"esm"},"src/atom.ts":{"bytes":22908,"imports":[{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true},{"path":"@effect-atom/atom/Result","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Function","kind":"import-statement","external":true},{"path":"effect/Option","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"src/ref-utils.ts","kind":"import-statement","original":"./ref-utils"}],"format":"esm"},"src/query-atom.ts":{"bytes":12968,"imports":[{"path":"@effect-atom/atom","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"src/ref-atom.ts":{"bytes":3101,"imports":[{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true},{"path":"src/ref-utils.ts","kind":"import-statement","original":"./ref-utils"}],"format":"esm"},"src/index.ts":{"bytes":733,"imports":[{"path":"src/atom.ts","kind":"import-statement","original":"./atom"},{"path":"src/query-atom.ts","kind":"import-statement","original":"./query-atom"},{"path":"src/ref-atom.ts","kind":"import-statement","original":"./ref-atom"}],"format":"esm"}},"outputs":{"dist/lib/neutral/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":23170},"dist/lib/neutral/index.mjs":{"imports":[{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true},{"path":"@effect-atom/atom/Result","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Function","kind":"import-statement","external":true},{"path":"effect/Option","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@effect-atom/atom","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@effect-atom/atom/Atom","kind":"import-statement","external":true}],"exports":["AtomObj","AtomQuery","AtomRef"],"entryPoint":"src/index.ts","inputs":{"src/atom.ts":{"bytesInOutput":3518},"src/ref-utils.ts":{"bytesInOutput":486},"src/index.ts":{"bytesInOutput":0},"src/query-atom.ts":{"bytesInOutput":2037},"src/ref-atom.ts":{"bytesInOutput":291}},"bytes":6733}}}
@@ -1,17 +1,19 @@
1
1
  import * as Atom from '@effect-atom/atom/Atom';
2
- import { Obj, Ref } from '@dxos/echo';
2
+ import { Entity, Obj, Ref, Relation } from '@dxos/echo';
3
3
  /**
4
- * Create a read-only atom for a reactive object or ref.
5
- * Works with Echo objects, plain reactive objects (from Obj.make), and Refs.
6
- * Returns immutable snapshots of the object data (branded with SnapshotKindId).
4
+ * Create a read-only atom for a single reactive object or ref.
5
+ * Returns {@link Obj.Snapshot} (immutable plain data), not the live reactive object.
6
+ * Use this when you need one object's data for display or React dependency tracking.
7
7
  * The atom updates automatically when the object is mutated.
8
8
  * For refs, automatically handles async loading.
9
- * Uses Atom.family internally - same object/ref reference returns same atom instance.
9
+ * Uses Atom.family internally - same object/ref returns same atom instance.
10
10
  *
11
11
  * @param objOrRef - The reactive object or ref to create an atom for, or undefined.
12
- * @returns An atom that returns the object snapshot. Returns undefined only for refs (async loading) or undefined input.
12
+ * @returns An atom that returns the object snapshot (plain data). Returns undefined only for refs (async loading) or undefined input.
13
13
  */
14
14
  export declare function make<T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>>;
15
+ export declare function make<T extends Relation.Unknown>(relation: T): Atom.Atom<Relation.Snapshot<T>>;
16
+ export declare function make<T extends Entity.Unknown>(entity: T): Atom.Atom<Entity.Snapshot>;
15
17
  export declare function make<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined>;
16
18
  export declare function make<T extends Obj.Unknown>(objOrRef: T | Ref.Ref<T> | undefined): Atom.Atom<Obj.Snapshot<T> | undefined>;
17
19
  /**
@@ -27,4 +29,15 @@ export declare function make<T extends Obj.Unknown>(objOrRef: T | Ref.Ref<T> | u
27
29
  */
28
30
  export declare function makeProperty<T extends Obj.Unknown, K extends keyof T>(obj: T, key: K): Atom.Atom<T[K]>;
29
31
  export declare function makeProperty<T extends Obj.Unknown, K extends keyof T>(obj: T | undefined, key: K): Atom.Atom<T[K] | undefined>;
32
+ /**
33
+ * Like {@link make} but returns the live reactive object instead of a snapshot.
34
+ * Same input: Obj or Ref.Ref. Same output shape: Atom that updates when the object mutates.
35
+ * Prefer {@link make} (snapshot) unless you need the live Obj.Obj for generic mutations (e.g. Obj.update).
36
+ *
37
+ * @param objOrRef - The reactive object or ref.
38
+ * @returns An atom that returns the live object. Returns undefined for refs (async loading) or undefined input.
39
+ */
40
+ export declare function makeWithReactive<T extends Obj.Unknown>(obj: T): Atom.Atom<T>;
41
+ export declare function makeWithReactive<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<T | undefined>;
42
+ export declare function makeWithReactive<T extends Obj.Unknown>(objOrRef: T | Ref.Ref<T> | undefined): Atom.Atom<T | undefined>;
30
43
  //# sourceMappingURL=atom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"atom.d.ts","sourceRoot":"","sources":["../../../src/atom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAG/C,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AA0FtC;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,wBAAgB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AACrG,wBAAgB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EACxC,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,GACnC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AAoB1C;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxG,wBAAgB,YAAY,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,CAAC,SAAS,MAAM,CAAC,EACnE,GAAG,EAAE,CAAC,GAAG,SAAS,EAClB,GAAG,EAAE,CAAC,GACL,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"atom.d.ts","sourceRoot":"","sources":["../../../src/atom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAM/C,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA0FxD;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/F,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACtF,wBAAgB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AACrG,wBAAgB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EACxC,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,GACnC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AA0B1C;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxG,wBAAgB,YAAY,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,CAAC,SAAS,MAAM,CAAC,EACnE,GAAG,EAAE,CAAC,GAAG,SAAS,EAClB,GAAG,EAAE,CAAC,GACL,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AAkD/B;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9E,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AACnG,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { Atom } from '@effect-atom/atom';
2
2
  import { Database, type Entity, type Filter, Query, type QueryResult } from '@dxos/echo';
3
3
  /**
4
- * Create a self-updating atom from an existing QueryResult.
4
+ * Create a self-updating atom from any QueryResult (e.g. schema registry queries).
5
5
  * Internally subscribes to queryResult and uses get.setSelf to update.
6
6
  * Cleanup is handled via get.addFinalizer.
7
7
  *
@@ -10,7 +10,7 @@ import { Database, type Entity, type Filter, Query, type QueryResult } from '@dx
10
10
  * @param queryResult - The QueryResult to wrap.
11
11
  * @returns An atom that automatically updates when query results change.
12
12
  */
13
- export declare const fromQuery: <T extends Entity.Unknown>(queryResult: QueryResult.QueryResult<T>) => Atom.Atom<T[]>;
13
+ export declare const fromQuery: <T>(queryResult: QueryResult.QueryResult<T>) => Atom.Atom<T[]>;
14
14
  /**
15
15
  * Get a memoized query atom for any Queryable (Database, Queue, etc.).
16
16
  * Uses a single Atom.family keyed by queryable identifier + serialized query AST.
@@ -1 +1 @@
1
- {"version":3,"file":"query-atom.d.ts","sourceRoot":"","sources":["../../../src/query-atom.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAO,QAAQ,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9F;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,MAAM,CAAC,OAAO,EAAE,aAAa,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,KAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAYvG,CAAC;AAuDL;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,SAAS,MAAM,CAAC,OAAO,EAC3C,WAAW,QAAQ,CAAC,SAAS,EAC7B,eAAe,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAC/C,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAGf,CAAC"}
1
+ {"version":3,"file":"query-atom.d.ts","sourceRoot":"","sources":["../../../src/query-atom.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAO,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9F;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,eAAe,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,KAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAOhF,CAAC;AAuDL;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,SAAS,MAAM,CAAC,OAAO,aAChC,QAAQ,CAAC,SAAS,iBACd,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAC/C,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAGf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ref-utils.d.ts","sourceRoot":"","sources":["../../../src/ref-utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAEpD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,EAChC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EACf,KAAK,IAAI,CAAC,OAAO,EACjB,mBAAmB,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,KAClC,CAAC,GAAG,SAiBN,CAAC"}
1
+ {"version":3,"file":"ref-utils.d.ts","sourceRoot":"","sources":["../../../src/ref-utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAEpD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,OAC3B,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OACV,IAAI,CAAC,OAAO,qBACE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,KAClC,CAAC,GAAG,SAgCN,CAAC"}