@dxos/echo-atom 0.0.0 → 0.8.4-main.69d29f4
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/dist/lib/browser/index.mjs +178 -0
- package/dist/lib/browser/index.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -0
- package/dist/lib/node-esm/index.mjs +179 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/types/src/atom.d.ts +30 -0
- package/dist/types/src/atom.d.ts.map +1 -0
- package/dist/types/src/atom.test.d.ts +2 -0
- package/dist/types/src/atom.test.d.ts.map +1 -0
- package/dist/types/src/batching.test.d.ts +2 -0
- package/dist/types/src/batching.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/query-atom.d.ts +24 -0
- package/dist/types/src/query-atom.d.ts.map +1 -0
- package/dist/types/src/query-atom.test.d.ts +2 -0
- package/dist/types/src/query-atom.test.d.ts.map +1 -0
- package/dist/types/src/reactivity.test.d.ts +2 -0
- package/dist/types/src/reactivity.test.d.ts.map +1 -0
- package/dist/types/src/ref-atom.d.ts +13 -0
- package/dist/types/src/ref-atom.d.ts.map +1 -0
- package/dist/types/src/ref-atom.test.d.ts +2 -0
- package/dist/types/src/ref-atom.test.d.ts.map +1 -0
- package/dist/types/src/ref-utils.d.ts +14 -0
- package/dist/types/src/ref-utils.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +12 -9
- package/src/atom.test.ts +135 -1
- package/src/atom.ts +99 -55
- package/src/query-atom.test.ts +63 -1
- package/src/query-atom.ts +7 -4
- package/src/reactivity.test.ts +48 -0
- package/src/ref-atom.test.ts +209 -0
- package/src/ref-atom.ts +17 -9
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// src/atom.ts
|
|
8
|
+
var atom_exports = {};
|
|
9
|
+
__export(atom_exports, {
|
|
10
|
+
make: () => make2,
|
|
11
|
+
makeProperty: () => makeProperty
|
|
12
|
+
});
|
|
13
|
+
import * as Atom from "@effect-atom/atom/Atom";
|
|
14
|
+
import isEqual from "lodash.isequal";
|
|
15
|
+
import { Obj, Ref } from "@dxos/echo";
|
|
16
|
+
import { assertArgument } from "@dxos/invariant";
|
|
17
|
+
|
|
18
|
+
// src/ref-utils.ts
|
|
19
|
+
var loadRefTarget = (ref, get, onTargetAvailable) => {
|
|
20
|
+
const currentTarget = ref.target;
|
|
21
|
+
if (currentTarget) {
|
|
22
|
+
return onTargetAvailable(currentTarget);
|
|
23
|
+
}
|
|
24
|
+
void ref.load().then((loadedTarget) => {
|
|
25
|
+
get.setSelf(onTargetAvailable(loadedTarget));
|
|
26
|
+
}).catch(() => {
|
|
27
|
+
});
|
|
28
|
+
return void 0;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// src/atom.ts
|
|
32
|
+
var objectFamily = Atom.family((obj) => {
|
|
33
|
+
return Atom.make((get) => {
|
|
34
|
+
const unsubscribe = Obj.subscribe(obj, () => {
|
|
35
|
+
get.setSelf(Obj.getSnapshot(obj));
|
|
36
|
+
});
|
|
37
|
+
get.addFinalizer(() => unsubscribe());
|
|
38
|
+
return Obj.getSnapshot(obj);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
var refFamily = Atom.family((ref) => {
|
|
42
|
+
return Atom.make((get) => {
|
|
43
|
+
let unsubscribeTarget;
|
|
44
|
+
const setupTargetSubscription = (target) => {
|
|
45
|
+
unsubscribeTarget?.();
|
|
46
|
+
unsubscribeTarget = Obj.subscribe(target, () => {
|
|
47
|
+
get.setSelf(Obj.getSnapshot(target));
|
|
48
|
+
});
|
|
49
|
+
return Obj.getSnapshot(target);
|
|
50
|
+
};
|
|
51
|
+
get.addFinalizer(() => unsubscribeTarget?.());
|
|
52
|
+
return loadRefTarget(ref, get, setupTargetSubscription);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
var snapshotForComparison = (value) => {
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
return [
|
|
58
|
+
...value
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
if (value !== null && typeof value === "object") {
|
|
62
|
+
return {
|
|
63
|
+
...value
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
};
|
|
68
|
+
var propertyFamily = Atom.family((obj) => Atom.family((key) => {
|
|
69
|
+
return Atom.make((get) => {
|
|
70
|
+
let previousSnapshot = snapshotForComparison(obj[key]);
|
|
71
|
+
const unsubscribe = Obj.subscribe(obj, () => {
|
|
72
|
+
const newValue = obj[key];
|
|
73
|
+
if (!isEqual(previousSnapshot, newValue)) {
|
|
74
|
+
previousSnapshot = snapshotForComparison(newValue);
|
|
75
|
+
get.setSelf(snapshotForComparison(newValue));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
get.addFinalizer(() => unsubscribe());
|
|
79
|
+
return snapshotForComparison(obj[key]);
|
|
80
|
+
});
|
|
81
|
+
}));
|
|
82
|
+
function make2(objOrRef) {
|
|
83
|
+
if (objOrRef === void 0) {
|
|
84
|
+
return Atom.make(() => void 0);
|
|
85
|
+
}
|
|
86
|
+
if (Ref.isRef(objOrRef)) {
|
|
87
|
+
return refFamily(objOrRef);
|
|
88
|
+
}
|
|
89
|
+
const obj = objOrRef;
|
|
90
|
+
assertArgument(Obj.isObject(obj), "obj", "Object must be a reactive object");
|
|
91
|
+
return objectFamily(obj);
|
|
92
|
+
}
|
|
93
|
+
function makeProperty(obj, key) {
|
|
94
|
+
if (obj === void 0) {
|
|
95
|
+
return Atom.make(() => void 0);
|
|
96
|
+
}
|
|
97
|
+
assertArgument(Obj.isObject(obj), "obj", "Object must be a reactive object");
|
|
98
|
+
assertArgument(key in obj, "key", "Property must exist on object");
|
|
99
|
+
return propertyFamily(obj)(key);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/query-atom.ts
|
|
103
|
+
var query_atom_exports = {};
|
|
104
|
+
__export(query_atom_exports, {
|
|
105
|
+
fromQuery: () => fromQuery,
|
|
106
|
+
make: () => make3
|
|
107
|
+
});
|
|
108
|
+
import { Atom as Atom2 } from "@effect-atom/atom";
|
|
109
|
+
import { DXN, Database, Query } from "@dxos/echo";
|
|
110
|
+
import { WeakDictionary } from "@dxos/util";
|
|
111
|
+
var fromQuery = (queryResult) => Atom2.make((get) => {
|
|
112
|
+
const unsubscribe = queryResult.subscribe(() => {
|
|
113
|
+
get.setSelf(queryResult.results);
|
|
114
|
+
});
|
|
115
|
+
get.addFinalizer(unsubscribe);
|
|
116
|
+
return queryResult.results;
|
|
117
|
+
});
|
|
118
|
+
var queryableRegistry = new WeakDictionary();
|
|
119
|
+
var KEY_SEPARATOR = "~";
|
|
120
|
+
var queryFamily = Atom2.family((key) => {
|
|
121
|
+
const separatorIndex = key.indexOf(KEY_SEPARATOR);
|
|
122
|
+
const identifier = key.slice(0, separatorIndex);
|
|
123
|
+
const serializedAst = key.slice(separatorIndex + 1);
|
|
124
|
+
const queryable = queryableRegistry.get(identifier);
|
|
125
|
+
if (!queryable) {
|
|
126
|
+
return Atom2.make(() => []);
|
|
127
|
+
}
|
|
128
|
+
const ast = JSON.parse(serializedAst);
|
|
129
|
+
const queryResult = queryable.query(Query.fromAst(ast));
|
|
130
|
+
return Atom2.make((get) => {
|
|
131
|
+
const unsubscribe = queryResult.subscribe(() => {
|
|
132
|
+
get.setSelf(queryResult.results);
|
|
133
|
+
});
|
|
134
|
+
get.addFinalizer(unsubscribe);
|
|
135
|
+
return queryResult.results;
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
var getQueryableIdentifier = (queryable) => {
|
|
139
|
+
if (Database.isDatabase(queryable)) {
|
|
140
|
+
return queryable.spaceId;
|
|
141
|
+
}
|
|
142
|
+
if ("dxn" in queryable && queryable.dxn instanceof DXN) {
|
|
143
|
+
return queryable.dxn.toString();
|
|
144
|
+
}
|
|
145
|
+
if ("id" in queryable && typeof queryable.id === "string") {
|
|
146
|
+
return queryable.id;
|
|
147
|
+
}
|
|
148
|
+
throw new Error("Unable to derive identifier from queryable.");
|
|
149
|
+
};
|
|
150
|
+
var make3 = (queryable, queryOrFilter) => {
|
|
151
|
+
const identifier = getQueryableIdentifier(queryable);
|
|
152
|
+
return fromQueryable(queryable, identifier, queryOrFilter);
|
|
153
|
+
};
|
|
154
|
+
var fromQueryable = (queryable, identifier, queryOrFilter) => {
|
|
155
|
+
queryableRegistry.set(identifier, queryable);
|
|
156
|
+
const normalizedQuery = Query.is(queryOrFilter) ? queryOrFilter : Query.select(queryOrFilter);
|
|
157
|
+
const key = `${identifier}${KEY_SEPARATOR}${JSON.stringify(normalizedQuery.ast)}`;
|
|
158
|
+
return queryFamily(key);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// src/ref-atom.ts
|
|
162
|
+
var ref_atom_exports = {};
|
|
163
|
+
__export(ref_atom_exports, {
|
|
164
|
+
make: () => make5
|
|
165
|
+
});
|
|
166
|
+
import * as Atom3 from "@effect-atom/atom/Atom";
|
|
167
|
+
var refFamily2 = Atom3.family((ref) => {
|
|
168
|
+
return Atom3.make((get) => {
|
|
169
|
+
return loadRefTarget(ref, get, (target) => target);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
var make5 = refFamily2;
|
|
173
|
+
export {
|
|
174
|
+
atom_exports as AtomObj,
|
|
175
|
+
query_atom_exports as AtomQuery,
|
|
176
|
+
ref_atom_exports as AtomRef
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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 * Internal helper to create an atom from a Ref.\n * Handles async loading and subscribes to the target for reactive updates.\n * Uses Atom.family internally - same ref reference returns same atom instance.\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(() => unsubscribeTarget?.());\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"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"inputs":{"src/ref-utils.ts":{"bytes":3291,"imports":[],"format":"esm"},"src/atom.ts":{"bytes":14945,"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/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":18123},"dist/lib/browser/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":2313},"src/ref-utils.ts":{"bytesInOutput":301},"src/index.ts":{"bytesInOutput":0},"src/query-atom.ts":{"bytesInOutput":2044},"src/ref-atom.ts":{"bytesInOutput":291}},"bytes":5350}}}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// src/atom.ts
|
|
9
|
+
var atom_exports = {};
|
|
10
|
+
__export(atom_exports, {
|
|
11
|
+
make: () => make2,
|
|
12
|
+
makeProperty: () => makeProperty
|
|
13
|
+
});
|
|
14
|
+
import * as Atom from "@effect-atom/atom/Atom";
|
|
15
|
+
import isEqual from "lodash.isequal";
|
|
16
|
+
import { Obj, Ref } from "@dxos/echo";
|
|
17
|
+
import { assertArgument } from "@dxos/invariant";
|
|
18
|
+
|
|
19
|
+
// src/ref-utils.ts
|
|
20
|
+
var loadRefTarget = (ref, get, onTargetAvailable) => {
|
|
21
|
+
const currentTarget = ref.target;
|
|
22
|
+
if (currentTarget) {
|
|
23
|
+
return onTargetAvailable(currentTarget);
|
|
24
|
+
}
|
|
25
|
+
void ref.load().then((loadedTarget) => {
|
|
26
|
+
get.setSelf(onTargetAvailable(loadedTarget));
|
|
27
|
+
}).catch(() => {
|
|
28
|
+
});
|
|
29
|
+
return void 0;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/atom.ts
|
|
33
|
+
var objectFamily = Atom.family((obj) => {
|
|
34
|
+
return Atom.make((get) => {
|
|
35
|
+
const unsubscribe = Obj.subscribe(obj, () => {
|
|
36
|
+
get.setSelf(Obj.getSnapshot(obj));
|
|
37
|
+
});
|
|
38
|
+
get.addFinalizer(() => unsubscribe());
|
|
39
|
+
return Obj.getSnapshot(obj);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
var refFamily = Atom.family((ref) => {
|
|
43
|
+
return Atom.make((get) => {
|
|
44
|
+
let unsubscribeTarget;
|
|
45
|
+
const setupTargetSubscription = (target) => {
|
|
46
|
+
unsubscribeTarget?.();
|
|
47
|
+
unsubscribeTarget = Obj.subscribe(target, () => {
|
|
48
|
+
get.setSelf(Obj.getSnapshot(target));
|
|
49
|
+
});
|
|
50
|
+
return Obj.getSnapshot(target);
|
|
51
|
+
};
|
|
52
|
+
get.addFinalizer(() => unsubscribeTarget?.());
|
|
53
|
+
return loadRefTarget(ref, get, setupTargetSubscription);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
var snapshotForComparison = (value) => {
|
|
57
|
+
if (Array.isArray(value)) {
|
|
58
|
+
return [
|
|
59
|
+
...value
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
if (value !== null && typeof value === "object") {
|
|
63
|
+
return {
|
|
64
|
+
...value
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
};
|
|
69
|
+
var propertyFamily = Atom.family((obj) => Atom.family((key) => {
|
|
70
|
+
return Atom.make((get) => {
|
|
71
|
+
let previousSnapshot = snapshotForComparison(obj[key]);
|
|
72
|
+
const unsubscribe = Obj.subscribe(obj, () => {
|
|
73
|
+
const newValue = obj[key];
|
|
74
|
+
if (!isEqual(previousSnapshot, newValue)) {
|
|
75
|
+
previousSnapshot = snapshotForComparison(newValue);
|
|
76
|
+
get.setSelf(snapshotForComparison(newValue));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
get.addFinalizer(() => unsubscribe());
|
|
80
|
+
return snapshotForComparison(obj[key]);
|
|
81
|
+
});
|
|
82
|
+
}));
|
|
83
|
+
function make2(objOrRef) {
|
|
84
|
+
if (objOrRef === void 0) {
|
|
85
|
+
return Atom.make(() => void 0);
|
|
86
|
+
}
|
|
87
|
+
if (Ref.isRef(objOrRef)) {
|
|
88
|
+
return refFamily(objOrRef);
|
|
89
|
+
}
|
|
90
|
+
const obj = objOrRef;
|
|
91
|
+
assertArgument(Obj.isObject(obj), "obj", "Object must be a reactive object");
|
|
92
|
+
return objectFamily(obj);
|
|
93
|
+
}
|
|
94
|
+
function makeProperty(obj, key) {
|
|
95
|
+
if (obj === void 0) {
|
|
96
|
+
return Atom.make(() => void 0);
|
|
97
|
+
}
|
|
98
|
+
assertArgument(Obj.isObject(obj), "obj", "Object must be a reactive object");
|
|
99
|
+
assertArgument(key in obj, "key", "Property must exist on object");
|
|
100
|
+
return propertyFamily(obj)(key);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/query-atom.ts
|
|
104
|
+
var query_atom_exports = {};
|
|
105
|
+
__export(query_atom_exports, {
|
|
106
|
+
fromQuery: () => fromQuery,
|
|
107
|
+
make: () => make3
|
|
108
|
+
});
|
|
109
|
+
import { Atom as Atom2 } from "@effect-atom/atom";
|
|
110
|
+
import { DXN, Database, Query } from "@dxos/echo";
|
|
111
|
+
import { WeakDictionary } from "@dxos/util";
|
|
112
|
+
var fromQuery = (queryResult) => Atom2.make((get) => {
|
|
113
|
+
const unsubscribe = queryResult.subscribe(() => {
|
|
114
|
+
get.setSelf(queryResult.results);
|
|
115
|
+
});
|
|
116
|
+
get.addFinalizer(unsubscribe);
|
|
117
|
+
return queryResult.results;
|
|
118
|
+
});
|
|
119
|
+
var queryableRegistry = new WeakDictionary();
|
|
120
|
+
var KEY_SEPARATOR = "~";
|
|
121
|
+
var queryFamily = Atom2.family((key) => {
|
|
122
|
+
const separatorIndex = key.indexOf(KEY_SEPARATOR);
|
|
123
|
+
const identifier = key.slice(0, separatorIndex);
|
|
124
|
+
const serializedAst = key.slice(separatorIndex + 1);
|
|
125
|
+
const queryable = queryableRegistry.get(identifier);
|
|
126
|
+
if (!queryable) {
|
|
127
|
+
return Atom2.make(() => []);
|
|
128
|
+
}
|
|
129
|
+
const ast = JSON.parse(serializedAst);
|
|
130
|
+
const queryResult = queryable.query(Query.fromAst(ast));
|
|
131
|
+
return Atom2.make((get) => {
|
|
132
|
+
const unsubscribe = queryResult.subscribe(() => {
|
|
133
|
+
get.setSelf(queryResult.results);
|
|
134
|
+
});
|
|
135
|
+
get.addFinalizer(unsubscribe);
|
|
136
|
+
return queryResult.results;
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
var getQueryableIdentifier = (queryable) => {
|
|
140
|
+
if (Database.isDatabase(queryable)) {
|
|
141
|
+
return queryable.spaceId;
|
|
142
|
+
}
|
|
143
|
+
if ("dxn" in queryable && queryable.dxn instanceof DXN) {
|
|
144
|
+
return queryable.dxn.toString();
|
|
145
|
+
}
|
|
146
|
+
if ("id" in queryable && typeof queryable.id === "string") {
|
|
147
|
+
return queryable.id;
|
|
148
|
+
}
|
|
149
|
+
throw new Error("Unable to derive identifier from queryable.");
|
|
150
|
+
};
|
|
151
|
+
var make3 = (queryable, queryOrFilter) => {
|
|
152
|
+
const identifier = getQueryableIdentifier(queryable);
|
|
153
|
+
return fromQueryable(queryable, identifier, queryOrFilter);
|
|
154
|
+
};
|
|
155
|
+
var fromQueryable = (queryable, identifier, queryOrFilter) => {
|
|
156
|
+
queryableRegistry.set(identifier, queryable);
|
|
157
|
+
const normalizedQuery = Query.is(queryOrFilter) ? queryOrFilter : Query.select(queryOrFilter);
|
|
158
|
+
const key = `${identifier}${KEY_SEPARATOR}${JSON.stringify(normalizedQuery.ast)}`;
|
|
159
|
+
return queryFamily(key);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// src/ref-atom.ts
|
|
163
|
+
var ref_atom_exports = {};
|
|
164
|
+
__export(ref_atom_exports, {
|
|
165
|
+
make: () => make5
|
|
166
|
+
});
|
|
167
|
+
import * as Atom3 from "@effect-atom/atom/Atom";
|
|
168
|
+
var refFamily2 = Atom3.family((ref) => {
|
|
169
|
+
return Atom3.make((get) => {
|
|
170
|
+
return loadRefTarget(ref, get, (target) => target);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
var make5 = refFamily2;
|
|
174
|
+
export {
|
|
175
|
+
atom_exports as AtomObj,
|
|
176
|
+
query_atom_exports as AtomQuery,
|
|
177
|
+
ref_atom_exports as AtomRef
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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 * Internal helper to create an atom from a Ref.\n * Handles async loading and subscribes to the target for reactive updates.\n * Uses Atom.family internally - same ref reference returns same atom instance.\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(() => unsubscribeTarget?.());\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"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"inputs":{"src/ref-utils.ts":{"bytes":3291,"imports":[],"format":"esm"},"src/atom.ts":{"bytes":14945,"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/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":18124},"dist/lib/node-esm/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":2313},"src/ref-utils.ts":{"bytesInOutput":301},"src/index.ts":{"bytesInOutput":0},"src/query-atom.ts":{"bytesInOutput":2044},"src/ref-atom.ts":{"bytesInOutput":291}},"bytes":5442}}}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as Atom from '@effect-atom/atom/Atom';
|
|
2
|
+
import { Obj, Ref } from '@dxos/echo';
|
|
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).
|
|
7
|
+
* The atom updates automatically when the object is mutated.
|
|
8
|
+
* For refs, automatically handles async loading.
|
|
9
|
+
* Uses Atom.family internally - same object/ref reference returns same atom instance.
|
|
10
|
+
*
|
|
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.
|
|
13
|
+
*/
|
|
14
|
+
export declare function make<T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>>;
|
|
15
|
+
export declare function make<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined>;
|
|
16
|
+
export declare function make<T extends Obj.Unknown>(objOrRef: T | Ref.Ref<T> | undefined): Atom.Atom<Obj.Snapshot<T> | undefined>;
|
|
17
|
+
/**
|
|
18
|
+
* Create a read-only atom for a specific property of a reactive object.
|
|
19
|
+
* Works with both Echo objects (from createObject) and plain live objects (from Obj.make).
|
|
20
|
+
* The atom updates automatically when the property is mutated.
|
|
21
|
+
* Only fires updates when the property value actually changes.
|
|
22
|
+
* Uses Atom.family internally - same object+key combination returns same atom instance.
|
|
23
|
+
*
|
|
24
|
+
* @param obj - The reactive object to create an atom for, or undefined.
|
|
25
|
+
* @param key - The property key to subscribe to.
|
|
26
|
+
* @returns An atom that returns the property value, or undefined if obj is undefined.
|
|
27
|
+
*/
|
|
28
|
+
export declare function makeProperty<T extends Obj.Unknown, K extends keyof T>(obj: T, key: K): Atom.Atom<T[K]>;
|
|
29
|
+
export declare function makeProperty<T extends Obj.Unknown, K extends keyof T>(obj: T | undefined, key: K): Atom.Atom<T[K] | undefined>;
|
|
30
|
+
//# sourceMappingURL=atom.d.ts.map
|
|
@@ -0,0 +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;AAwFtC;;;;;;;;;;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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atom.test.d.ts","sourceRoot":"","sources":["../../../src/atom.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batching.test.d.ts","sourceRoot":"","sources":["../../../src/batching.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,OAAO,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Atom } from '@effect-atom/atom';
|
|
2
|
+
import { Database, type Entity, type Filter, Query, type QueryResult } from '@dxos/echo';
|
|
3
|
+
/**
|
|
4
|
+
* Create a self-updating atom from an existing QueryResult.
|
|
5
|
+
* Internally subscribes to queryResult and uses get.setSelf to update.
|
|
6
|
+
* Cleanup is handled via get.addFinalizer.
|
|
7
|
+
*
|
|
8
|
+
* Note: This creates a new atom each time. For memoization, use `make` instead.
|
|
9
|
+
*
|
|
10
|
+
* @param queryResult - The QueryResult to wrap.
|
|
11
|
+
* @returns An atom that automatically updates when query results change.
|
|
12
|
+
*/
|
|
13
|
+
export declare const fromQuery: <T extends Entity.Unknown>(queryResult: QueryResult.QueryResult<T>) => Atom.Atom<T[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Get a memoized query atom for any Queryable (Database, Queue, etc.).
|
|
16
|
+
* Uses a single Atom.family keyed by queryable identifier + serialized query AST.
|
|
17
|
+
* Same queryable + query/filter = same atom instance (proper memoization).
|
|
18
|
+
*
|
|
19
|
+
* @param queryable - The queryable to query (Database, Queue, etc.).
|
|
20
|
+
* @param queryOrFilter - A Query or Filter to execute.
|
|
21
|
+
* @returns A memoized atom that updates when query results change.
|
|
22
|
+
*/
|
|
23
|
+
export declare const make: <T extends Entity.Unknown>(queryable: Database.Queryable, queryOrFilter: Query.Query<T> | Filter.Filter<T>) => Atom.Atom<T[]>;
|
|
24
|
+
//# sourceMappingURL=query-atom.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-atom.test.d.ts","sourceRoot":"","sources":["../../../src/query-atom.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactivity.test.d.ts","sourceRoot":"","sources":["../../../src/reactivity.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Atom from '@effect-atom/atom/Atom';
|
|
2
|
+
import { type Ref } from '@dxos/echo';
|
|
3
|
+
/**
|
|
4
|
+
* Create a read-only atom for a reference target.
|
|
5
|
+
* Returns undefined if the target hasn't loaded yet.
|
|
6
|
+
* Updates when the ref loads but does NOT subscribe to target object changes.
|
|
7
|
+
* Use AtomObj.make with a ref if you need reactive snapshots of ECHO objects.
|
|
8
|
+
* Uses Atom.family internally - same ref reference returns same atom instance.
|
|
9
|
+
*
|
|
10
|
+
* Supports refs to any target type including ECHO objects and Queues.
|
|
11
|
+
*/
|
|
12
|
+
export declare const make: <T>(arg: Ref.Ref<T>) => Atom.Atom<T | undefined>;
|
|
13
|
+
//# sourceMappingURL=ref-atom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref-atom.d.ts","sourceRoot":"","sources":["../../../src/ref-atom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAE/C,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAgBtC;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,GAfc,CAAC,8CAeH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref-atom.test.d.ts","sourceRoot":"","sources":["../../../src/ref-atom.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type * as Atom from '@effect-atom/atom/Atom';
|
|
2
|
+
import type { Ref } from '@dxos/echo';
|
|
3
|
+
/**
|
|
4
|
+
* Internal helper for loading ref targets in atoms.
|
|
5
|
+
* Handles the common pattern of checking for loaded target and triggering async load.
|
|
6
|
+
*
|
|
7
|
+
* @param ref - The ref to load.
|
|
8
|
+
* @param get - The atom context for setSelf.
|
|
9
|
+
* @param onTargetAvailable - Callback invoked when target is available (sync or async).
|
|
10
|
+
* Should return the value to use for the atom.
|
|
11
|
+
* @returns The result of onTargetAvailable if target is already loaded, undefined otherwise.
|
|
12
|
+
*/
|
|
13
|
+
export declare const loadRefTarget: <T, R>(ref: Ref.Ref<T>, get: Atom.Context, onTargetAvailable: (target: T) => R) => R | undefined;
|
|
14
|
+
//# sourceMappingURL=ref-utils.d.ts.map
|
|
@@ -0,0 +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"}
|