@dxos/app-graph 0.8.4-main.ae835ea → 0.8.4-main.bc674ce
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 +1014 -553
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1013 -553
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/atoms.d.ts +8 -0
- package/dist/types/src/atoms.d.ts.map +1 -0
- package/dist/types/src/graph-builder.d.ts +108 -66
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +182 -212
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +6 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/node-matcher.d.ts +218 -0
- package/dist/types/src/node-matcher.d.ts.map +1 -0
- package/dist/types/src/node-matcher.test.d.ts +2 -0
- package/dist/types/src/node-matcher.test.d.ts.map +1 -0
- package/dist/types/src/node.d.ts +32 -3
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +35 -33
- package/src/atoms.ts +25 -0
- package/src/graph-builder.test.ts +520 -104
- package/src/graph-builder.ts +550 -255
- package/src/graph.test.ts +299 -106
- package/src/graph.ts +964 -394
- package/src/index.ts +9 -3
- package/src/node-matcher.test.ts +301 -0
- package/src/node-matcher.ts +284 -0
- package/src/node.ts +39 -6
- package/src/stories/EchoGraph.stories.tsx +104 -95
- package/src/stories/Tree.tsx +2 -2
- package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
- package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
- package/dist/types/src/signals-integration.test.d.ts +0 -2
- package/dist/types/src/signals-integration.test.d.ts.map +0 -1
- package/dist/types/src/testing.d.ts +0 -5
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/experimental/graph-projections.test.ts +0 -56
- package/src/signals-integration.test.ts +0 -218
- package/src/testing.ts +0 -20
|
@@ -2,37 +2,29 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Registry, RegistryContext,
|
|
5
|
+
import { Atom, type Registry, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
|
|
6
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
7
|
import * as Function from 'effect/Function';
|
|
8
8
|
import * as Option from 'effect/Option';
|
|
9
|
-
import React, { type PropsWithChildren, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Query,
|
|
16
|
-
type QueryResult,
|
|
17
|
-
type Space,
|
|
18
|
-
SpaceState,
|
|
19
|
-
isSpace,
|
|
20
|
-
live,
|
|
21
|
-
} from '@dxos/client/echo';
|
|
22
|
-
import { Obj, Type } from '@dxos/echo';
|
|
9
|
+
import React, { type PropsWithChildren, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
import { Filter, type Space, SpaceState, isSpace } from '@dxos/client/echo';
|
|
12
|
+
import { Obj, Query } from '@dxos/echo';
|
|
13
|
+
import { TestSchema } from '@dxos/echo/testing';
|
|
14
|
+
import { AtomObj, AtomQuery } from '@dxos/echo-atom';
|
|
23
15
|
import { faker } from '@dxos/random';
|
|
24
16
|
import { type Client, useClient } from '@dxos/react-client';
|
|
25
17
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
26
18
|
import { Icon, IconButton, Input, Select } from '@dxos/react-ui';
|
|
27
19
|
import { withTheme } from '@dxos/react-ui/testing';
|
|
28
20
|
import { Path, Tree } from '@dxos/react-ui-list';
|
|
29
|
-
import { getSize, mx } from '@dxos/
|
|
21
|
+
import { getSize, mx } from '@dxos/ui-theme';
|
|
30
22
|
import { byPosition, isNonNullable, safeParseInt } from '@dxos/util';
|
|
31
23
|
|
|
32
|
-
import
|
|
33
|
-
import
|
|
34
|
-
import
|
|
35
|
-
import
|
|
24
|
+
import * as CreateAtom from '../atoms';
|
|
25
|
+
import * as Graph from '../graph';
|
|
26
|
+
import * as GraphBuilder from '../graph-builder';
|
|
27
|
+
import * as Node from '../node';
|
|
36
28
|
|
|
37
29
|
import { JsonTree } from './Tree';
|
|
38
30
|
|
|
@@ -56,43 +48,44 @@ const actionWeights = {
|
|
|
56
48
|
[Action.RENAME_OBJECT]: 4,
|
|
57
49
|
};
|
|
58
50
|
|
|
59
|
-
const createGraph = (client: Client, registry: Registry.Registry): ExpandableGraph => {
|
|
60
|
-
const spaceBuilderExtension =
|
|
51
|
+
const createGraph = (client: Client, registry: Registry.Registry): Graph.ExpandableGraph => {
|
|
52
|
+
const spaceBuilderExtension = GraphBuilder.createExtensionRaw({
|
|
61
53
|
id: 'space',
|
|
62
54
|
connector: (node) =>
|
|
63
|
-
|
|
55
|
+
Atom.make((get) =>
|
|
64
56
|
Function.pipe(
|
|
65
57
|
get(node),
|
|
66
|
-
Option.flatMap((node) => (node.id ===
|
|
58
|
+
Option.flatMap((node) => (node.id === Node.RootId ? Option.some(node) : Option.none())),
|
|
67
59
|
Option.map(() => {
|
|
68
|
-
const spaces = get(
|
|
60
|
+
const spaces = get(CreateAtom.fromObservable(client.spaces)) ?? [];
|
|
69
61
|
return spaces
|
|
70
|
-
.filter((space) => get(
|
|
71
|
-
.map((space) =>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
62
|
+
.filter((space: any) => get(CreateAtom.fromObservable(space.state)) === SpaceState.SPACE_READY)
|
|
63
|
+
.map((space) => {
|
|
64
|
+
const propertiesSnapshot = get(AtomObj.make(space.properties));
|
|
65
|
+
return {
|
|
66
|
+
id: space.id,
|
|
67
|
+
type: 'dxos.org/type/Space',
|
|
68
|
+
properties: {
|
|
69
|
+
label: propertiesSnapshot.name,
|
|
70
|
+
},
|
|
71
|
+
data: space,
|
|
72
|
+
};
|
|
73
|
+
});
|
|
77
74
|
}),
|
|
78
75
|
Option.getOrElse(() => []),
|
|
79
76
|
),
|
|
80
77
|
),
|
|
81
78
|
});
|
|
82
79
|
|
|
83
|
-
const objectBuilderExtension =
|
|
80
|
+
const objectBuilderExtension = GraphBuilder.createExtensionRaw({
|
|
84
81
|
id: 'object',
|
|
85
82
|
connector: (node) => {
|
|
86
|
-
|
|
87
|
-
return Rx.make((get) =>
|
|
83
|
+
return Atom.make((get) =>
|
|
88
84
|
Function.pipe(
|
|
89
85
|
get(node),
|
|
90
86
|
Option.flatMap((node) => (isSpace(node.data) ? Option.some(node.data) : Option.none())),
|
|
91
87
|
Option.map((space) => {
|
|
92
|
-
|
|
93
|
-
query = space.db.query(Query.type(Expando, { type: 'test' }));
|
|
94
|
-
}
|
|
95
|
-
const objects = get(rxFromQuery(query));
|
|
88
|
+
const objects = get(AtomQuery.make(space.db, Query.type(TestSchema.Expando, { type: 'test' })));
|
|
96
89
|
return objects.map((object) => ({
|
|
97
90
|
id: object.id,
|
|
98
91
|
type: 'dxos.org/type/test',
|
|
@@ -106,15 +99,15 @@ const createGraph = (client: Client, registry: Registry.Registry): ExpandableGra
|
|
|
106
99
|
},
|
|
107
100
|
});
|
|
108
101
|
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
const builder = GraphBuilder.make({ registry });
|
|
103
|
+
GraphBuilder.addExtension(builder, spaceBuilderExtension);
|
|
104
|
+
GraphBuilder.addExtension(builder, objectBuilderExtension);
|
|
105
|
+
const graph = builder.graph;
|
|
112
106
|
graph.onNodeChanged.on(({ id }) => {
|
|
113
|
-
|
|
107
|
+
Graph.expand(graph, id);
|
|
114
108
|
});
|
|
115
|
-
|
|
109
|
+
Graph.expand(graph, Node.RootId);
|
|
116
110
|
(window as any).graph = graph;
|
|
117
|
-
|
|
118
111
|
return graph;
|
|
119
112
|
};
|
|
120
113
|
|
|
@@ -134,9 +127,9 @@ const getRandomSpace = (client: Client): Space | undefined => {
|
|
|
134
127
|
const getSpaceWithObjects = async (client: Client): Promise<Space | undefined> => {
|
|
135
128
|
const readySpaces = client.spaces.get().filter((space) => space.state.get() === SpaceState.SPACE_READY);
|
|
136
129
|
const spaceQueries = await Promise.all(
|
|
137
|
-
readySpaces.map((space) => space.db.query(Filter.type(Expando, { type: 'test' })).run()),
|
|
130
|
+
readySpaces.map((space) => space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run()),
|
|
138
131
|
);
|
|
139
|
-
const spaces = readySpaces.filter((space, index) => spaceQueries[index].
|
|
132
|
+
const spaces = readySpaces.filter((space, index) => spaceQueries[index].length > 0);
|
|
140
133
|
return spaces[Math.floor(Math.random() * spaces.length)];
|
|
141
134
|
};
|
|
142
135
|
|
|
@@ -153,19 +146,26 @@ const runAction = async (client: Client, action: Action) => {
|
|
|
153
146
|
case Action.RENAME_SPACE: {
|
|
154
147
|
const space = getRandomSpace(client);
|
|
155
148
|
if (space) {
|
|
156
|
-
space.properties
|
|
149
|
+
Obj.change(space.properties, (p) => {
|
|
150
|
+
p.name = faker.commerce.productName();
|
|
151
|
+
});
|
|
157
152
|
}
|
|
158
153
|
break;
|
|
159
154
|
}
|
|
160
155
|
|
|
161
156
|
case Action.ADD_OBJECT:
|
|
162
|
-
getRandomSpace(client)?.db.add(
|
|
157
|
+
getRandomSpace(client)?.db.add(
|
|
158
|
+
Obj.make(TestSchema.Expando, {
|
|
159
|
+
type: 'test',
|
|
160
|
+
name: faker.commerce.productName(),
|
|
161
|
+
}),
|
|
162
|
+
);
|
|
163
163
|
break;
|
|
164
164
|
|
|
165
165
|
case Action.REMOVE_OBJECT: {
|
|
166
166
|
const space = await getSpaceWithObjects(client);
|
|
167
167
|
if (space) {
|
|
168
|
-
const
|
|
168
|
+
const objects = await space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run();
|
|
169
169
|
space.db.remove(objects[Math.floor(Math.random() * objects.length)]);
|
|
170
170
|
}
|
|
171
171
|
break;
|
|
@@ -174,8 +174,11 @@ const runAction = async (client: Client, action: Action) => {
|
|
|
174
174
|
case Action.RENAME_OBJECT: {
|
|
175
175
|
const space = await getSpaceWithObjects(client);
|
|
176
176
|
if (space) {
|
|
177
|
-
const
|
|
178
|
-
objects[Math.floor(Math.random() * objects.length)]
|
|
177
|
+
const objects = await space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run();
|
|
178
|
+
const object = objects[Math.floor(Math.random() * objects.length)];
|
|
179
|
+
Obj.change(object, (o) => {
|
|
180
|
+
o.name = faker.commerce.productName();
|
|
181
|
+
});
|
|
179
182
|
}
|
|
180
183
|
break;
|
|
181
184
|
}
|
|
@@ -214,7 +217,7 @@ const Controls = ({ children }: PropsWithChildren) => {
|
|
|
214
217
|
<Input.TextInput
|
|
215
218
|
autoComplete='off'
|
|
216
219
|
size={5}
|
|
217
|
-
classNames='
|
|
220
|
+
classNames='is-[100px] text-right pie-[22px]'
|
|
218
221
|
placeholder='Interval'
|
|
219
222
|
value={actionInterval}
|
|
220
223
|
onChange={({ target: { value } }) => setActionInterval(value)}
|
|
@@ -258,7 +261,7 @@ const meta = {
|
|
|
258
261
|
},
|
|
259
262
|
}),
|
|
260
263
|
],
|
|
261
|
-
} satisfies Meta
|
|
264
|
+
} satisfies Meta;
|
|
262
265
|
|
|
263
266
|
export default meta;
|
|
264
267
|
|
|
@@ -269,7 +272,7 @@ export const JsonView: Story = {
|
|
|
269
272
|
const client = useClient();
|
|
270
273
|
const registry = useContext(RegistryContext);
|
|
271
274
|
const graph = useMemo(() => createGraph(client, registry), [client, registry]);
|
|
272
|
-
const data =
|
|
275
|
+
const data = useAtomValue(graph.json());
|
|
273
276
|
|
|
274
277
|
return (
|
|
275
278
|
<>
|
|
@@ -285,26 +288,37 @@ export const TreeView: Story = {
|
|
|
285
288
|
const client = useClient();
|
|
286
289
|
const registry = useContext(RegistryContext);
|
|
287
290
|
const graph = useMemo(() => createGraph(client, registry), [client, registry]);
|
|
288
|
-
const
|
|
291
|
+
const stateRef = useRef(new Map<string, Atom.Writable<{ open: boolean; current: boolean }>>());
|
|
292
|
+
|
|
293
|
+
const getOrCreateState = useMemo(
|
|
294
|
+
() => (path: string) => {
|
|
295
|
+
let atom = stateRef.current.get(path);
|
|
296
|
+
if (!atom) {
|
|
297
|
+
atom = Atom.make({ open: true, current: false }).pipe(Atom.keepAlive);
|
|
298
|
+
stateRef.current.set(path, atom);
|
|
299
|
+
}
|
|
300
|
+
return atom;
|
|
301
|
+
},
|
|
302
|
+
[],
|
|
303
|
+
);
|
|
289
304
|
|
|
290
305
|
const useItems = useCallback(
|
|
291
|
-
(node?: Node, options?: { disposition?: string; sort?: boolean }) => {
|
|
292
|
-
const connections =
|
|
306
|
+
(node?: Node.Node, options?: { disposition?: string; sort?: boolean }) => {
|
|
307
|
+
const connections = useAtomValue(graph.connections(node?.id ?? Node.RootId));
|
|
293
308
|
return options?.sort ? connections.toSorted((a, b) => byPosition(a.properties, b.properties)) : connections;
|
|
294
309
|
},
|
|
295
310
|
[graph],
|
|
296
311
|
);
|
|
297
312
|
|
|
298
313
|
const getProps = useCallback(
|
|
299
|
-
(node: Node, path: string[]) => {
|
|
300
|
-
const children = graph
|
|
301
|
-
.getConnections(node.id, 'outbound')
|
|
314
|
+
(node: Node.Node, path: string[]) => {
|
|
315
|
+
const children = Graph.getConnections(graph, node.id, 'outbound')
|
|
302
316
|
.map((n) => {
|
|
303
317
|
// Break cycles.
|
|
304
318
|
const nextPath = [...path, node.id];
|
|
305
|
-
return nextPath.includes(n.id) ? undefined : (n as Node);
|
|
319
|
+
return nextPath.includes(n.id) ? undefined : (n as Node.Node);
|
|
306
320
|
})
|
|
307
|
-
.filter(isNonNullable) as Node[];
|
|
321
|
+
.filter(isNonNullable) as Node.Node[];
|
|
308
322
|
const parentOf =
|
|
309
323
|
children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
|
|
310
324
|
return {
|
|
@@ -317,59 +331,54 @@ export const TreeView: Story = {
|
|
|
317
331
|
[graph],
|
|
318
332
|
);
|
|
319
333
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
334
|
+
// Hook that subscribes to item state via Atom.
|
|
335
|
+
const useItemState = (_path: string[]) => {
|
|
336
|
+
const path = useMemo(() => Path.create(..._path), [_path.join('~')]);
|
|
337
|
+
const atom = getOrCreateState(path);
|
|
338
|
+
return useAtomValue(atom);
|
|
339
|
+
};
|
|
327
340
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
);
|
|
332
|
-
|
|
333
|
-
const isCurrent = useCallback(
|
|
334
|
-
(_path: string[]) => {
|
|
335
|
-
const path = Path.create(..._path);
|
|
336
|
-
const object = state.get(path) ?? live({ open: false, current: false });
|
|
337
|
-
if (!state.has(path)) {
|
|
338
|
-
state.set(path, object);
|
|
339
|
-
}
|
|
341
|
+
const useIsOpen = (_path: string[]) => {
|
|
342
|
+
return useItemState(_path).open;
|
|
343
|
+
};
|
|
340
344
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
);
|
|
345
|
+
const useIsCurrent = (_path: string[]) => {
|
|
346
|
+
return useItemState(_path).current;
|
|
347
|
+
};
|
|
345
348
|
|
|
346
349
|
const onOpenChange = useCallback(
|
|
347
350
|
({ path: _path, open }: { path: string[]; open: boolean }) => {
|
|
348
351
|
const path = Path.create(..._path);
|
|
349
|
-
const
|
|
350
|
-
|
|
352
|
+
const atom = stateRef.current.get(path);
|
|
353
|
+
if (atom) {
|
|
354
|
+
const prev = registry.get(atom);
|
|
355
|
+
registry.set(atom, { ...prev, open });
|
|
356
|
+
}
|
|
351
357
|
},
|
|
352
|
-
[
|
|
358
|
+
[registry],
|
|
353
359
|
);
|
|
354
360
|
|
|
355
361
|
const onSelect = useCallback(
|
|
356
362
|
({ path: _path, current }: { path: string[]; current: boolean }) => {
|
|
357
363
|
const path = Path.create(..._path);
|
|
358
|
-
const
|
|
359
|
-
|
|
364
|
+
const atom = stateRef.current.get(path);
|
|
365
|
+
if (atom) {
|
|
366
|
+
const prev = registry.get(atom);
|
|
367
|
+
registry.set(atom, { ...prev, current });
|
|
368
|
+
}
|
|
360
369
|
},
|
|
361
|
-
[
|
|
370
|
+
[registry],
|
|
362
371
|
);
|
|
363
372
|
|
|
364
373
|
return (
|
|
365
374
|
<>
|
|
366
375
|
<Controls />
|
|
367
376
|
<Tree
|
|
368
|
-
id={
|
|
377
|
+
id={Node.RootId}
|
|
369
378
|
useItems={useItems}
|
|
370
379
|
getProps={getProps}
|
|
371
|
-
|
|
372
|
-
|
|
380
|
+
useIsOpen={useIsOpen}
|
|
381
|
+
useIsCurrent={useIsCurrent}
|
|
373
382
|
onOpenChange={onOpenChange}
|
|
374
383
|
onSelect={onSelect}
|
|
375
384
|
/>
|
package/src/stories/Tree.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { type FC, type HTMLAttributes, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import { mx } from '@dxos/
|
|
7
|
+
import { mx } from '@dxos/ui-theme';
|
|
8
8
|
|
|
9
9
|
// TODO(burdon): Copied form devtools.
|
|
10
10
|
|
|
@@ -72,7 +72,7 @@ const Scalar: FC<{ value: any }> = ({ value }) => {
|
|
|
72
72
|
|
|
73
73
|
const Box: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...props }) => {
|
|
74
74
|
return (
|
|
75
|
-
<div className={mx('flex
|
|
75
|
+
<div className={mx('flex pli-2 border border-l-0 font-mono truncate', className)} {...props}>
|
|
76
76
|
{children}
|
|
77
77
|
</div>
|
|
78
78
|
);
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
type Cb = () => void;
|
|
2
|
-
interface Query {
|
|
3
|
-
id?: string[];
|
|
4
|
-
typename?: string[];
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Lazy query result that can be executed.
|
|
8
|
-
* Does not run without the run function being called.
|
|
9
|
-
*/
|
|
10
|
-
interface QueryResult<T> {
|
|
11
|
-
/**
|
|
12
|
-
* Execute the query and subscribe to the result.
|
|
13
|
-
* @param next Called at least once with the first value (maybe synchronously) and then for every subsequent update.
|
|
14
|
-
* @param error Called on error. `next` is never called after that.
|
|
15
|
-
* @returns Function to dispose the query and unsubscribe.
|
|
16
|
-
*/
|
|
17
|
-
run(onData: (value?: T[]) => void, onError: (err: Error) => void): Cb;
|
|
18
|
-
}
|
|
19
|
-
declare const QueryResult: Readonly<{
|
|
20
|
-
fromPromise: <T>(run: (onDispose: (cb: Cb) => void) => Promise<T[]>) => QueryResult<T>;
|
|
21
|
-
}>;
|
|
22
|
-
interface _Resolver<T> {
|
|
23
|
-
query(query: Query): QueryResult<T>;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=graph-projections.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"graph-projections.test.d.ts","sourceRoot":"","sources":["../../../../src/experimental/graph-projections.test.ts"],"names":[],"mappings":"AAIA,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC;AAErB,UAAU,KAAK;IACb,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,UAAU,WAAW,CAAC,CAAC;IACrB;;;;;OAKG;IACH,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,GAAG,EAAE,CAAC;CACvE;AAED,QAAA,MAAM,WAAW;kBACD,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,KAAG,WAAW,CAAC,CAAC,CAAC;EAyBpF,CAAC;AAEH,UAAU,SAAS,CAAC,CAAC;IACnB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;CACrC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signals-integration.test.d.ts","sourceRoot":"","sources":["../../../src/signals-integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { Rx } from '@effect-rx/rx-react';
|
|
2
|
-
import { type AnyEchoObject } from '@dxos/echo/internal';
|
|
3
|
-
import { type QueryResult } from '@dxos/echo-db';
|
|
4
|
-
export declare const rxFromQuery: <T extends AnyEchoObject>(query: QueryResult<T>) => Rx.Rx<T[]>;
|
|
5
|
-
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../src/testing.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAEzC,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,aAAa,EAAE,OAAO,WAAW,CAAC,CAAC,CAAC,KAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAUrF,CAAC"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
type Cb = () => void;
|
|
6
|
-
|
|
7
|
-
interface Query {
|
|
8
|
-
id?: string[];
|
|
9
|
-
typename?: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Lazy query result that can be executed.
|
|
14
|
-
* Does not run without the run function being called.
|
|
15
|
-
*/
|
|
16
|
-
interface QueryResult<T> {
|
|
17
|
-
/**
|
|
18
|
-
* Execute the query and subscribe to the result.
|
|
19
|
-
* @param next Called at least once with the first value (maybe synchronously) and then for every subsequent update.
|
|
20
|
-
* @param error Called on error. `next` is never called after that.
|
|
21
|
-
* @returns Function to dispose the query and unsubscribe.
|
|
22
|
-
*/
|
|
23
|
-
run(onData: (value?: T[]) => void, onError: (err: Error) => void): Cb;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const QueryResult = Object.freeze({
|
|
27
|
-
fromPromise: <T>(run: (onDispose: (cb: Cb) => void) => Promise<T[]>): QueryResult<T> => {
|
|
28
|
-
return {
|
|
29
|
-
run: (onData, onError) => {
|
|
30
|
-
const cbs: Cb[] = [];
|
|
31
|
-
let disposed = false;
|
|
32
|
-
const dispose = () => {
|
|
33
|
-
cbs.forEach((cb) => cb());
|
|
34
|
-
disposed = true;
|
|
35
|
-
};
|
|
36
|
-
run((cb) => (disposed ? cb() : cbs.push(cb))).then(
|
|
37
|
-
(data) => {
|
|
38
|
-
if (disposed) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
onData(data);
|
|
42
|
-
},
|
|
43
|
-
(err) => {
|
|
44
|
-
dispose();
|
|
45
|
-
onError(err);
|
|
46
|
-
},
|
|
47
|
-
);
|
|
48
|
-
return dispose;
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
interface _Resolver<T> {
|
|
55
|
-
query(query: Query): QueryResult<T>;
|
|
56
|
-
}
|