@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.
Files changed (43) hide show
  1. package/dist/lib/browser/index.mjs +1014 -553
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +1013 -553
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/atoms.d.ts +8 -0
  8. package/dist/types/src/atoms.d.ts.map +1 -0
  9. package/dist/types/src/graph-builder.d.ts +108 -66
  10. package/dist/types/src/graph-builder.d.ts.map +1 -1
  11. package/dist/types/src/graph.d.ts +182 -212
  12. package/dist/types/src/graph.d.ts.map +1 -1
  13. package/dist/types/src/index.d.ts +6 -3
  14. package/dist/types/src/index.d.ts.map +1 -1
  15. package/dist/types/src/node-matcher.d.ts +218 -0
  16. package/dist/types/src/node-matcher.d.ts.map +1 -0
  17. package/dist/types/src/node-matcher.test.d.ts +2 -0
  18. package/dist/types/src/node-matcher.test.d.ts.map +1 -0
  19. package/dist/types/src/node.d.ts +32 -3
  20. package/dist/types/src/node.d.ts.map +1 -1
  21. package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
  22. package/dist/types/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +35 -33
  24. package/src/atoms.ts +25 -0
  25. package/src/graph-builder.test.ts +520 -104
  26. package/src/graph-builder.ts +550 -255
  27. package/src/graph.test.ts +299 -106
  28. package/src/graph.ts +964 -394
  29. package/src/index.ts +9 -3
  30. package/src/node-matcher.test.ts +301 -0
  31. package/src/node-matcher.ts +284 -0
  32. package/src/node.ts +39 -6
  33. package/src/stories/EchoGraph.stories.tsx +104 -95
  34. package/src/stories/Tree.tsx +2 -2
  35. package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
  36. package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
  37. package/dist/types/src/signals-integration.test.d.ts +0 -2
  38. package/dist/types/src/signals-integration.test.d.ts.map +0 -1
  39. package/dist/types/src/testing.d.ts +0 -5
  40. package/dist/types/src/testing.d.ts.map +0 -1
  41. package/src/experimental/graph-projections.test.ts +0 -56
  42. package/src/signals-integration.test.ts +0 -218
  43. package/src/testing.ts +0 -20
@@ -1,218 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Registry, Rx } from '@effect-rx/rx-react';
6
- import { signal } from '@preact/signals-core';
7
- import { afterEach, beforeEach, describe, expect, onTestFinished, test } from 'vitest';
8
-
9
- import { Trigger } from '@dxos/async';
10
- import { Obj, Type } from '@dxos/echo';
11
- import { Ref } from '@dxos/echo/internal';
12
- import { Filter } from '@dxos/echo-db';
13
- import { EchoTestBuilder } from '@dxos/echo-db/testing';
14
- import { registerSignalsRuntime } from '@dxos/echo-signals';
15
-
16
- import { ROOT_ID } from './graph';
17
- import { GraphBuilder, createExtension, rxFromSignal } from './graph-builder';
18
- import { rxFromQuery } from './testing';
19
-
20
- registerSignalsRuntime();
21
-
22
- const EXAMPLE_TYPE = 'dxos.org/type/example';
23
-
24
- describe('signals integration', () => {
25
- test('creating rx from signal', () => {
26
- const registry = Registry.make();
27
- const state = signal<number>(0);
28
- const value = rxFromSignal(() => state.value);
29
- const inline = Rx.make((get) => {
30
- // NOTE: This will create a new rx instance each time.
31
- // This test is verifying that this behaves the same as using a stable rx instance.
32
- // The parent will remain subscribed to one instance until the new one is created.
33
- // The old one will then be garbage collected because it is no longer referenced.
34
- const rx = rxFromSignal(() => get(value));
35
- return get(rx);
36
- });
37
-
38
- let count = 0;
39
- const cancel = registry.subscribe(value, (value) => {
40
- count = value;
41
- });
42
- onTestFinished(() => cancel());
43
-
44
- let inlineCount = 0;
45
- const inlineCancel = registry.subscribe(inline, (value) => {
46
- inlineCount = value;
47
- });
48
- onTestFinished(() => inlineCancel());
49
-
50
- registry.get(value);
51
- registry.get(inline);
52
- expect(count).to.eq(0);
53
- expect(inlineCount).to.eq(0);
54
-
55
- state.value = 1;
56
- expect(count).to.eq(1);
57
- expect(inlineCount).to.eq(1);
58
-
59
- state.value = 2;
60
- expect(count).to.eq(2);
61
- expect(inlineCount).to.eq(2);
62
- });
63
-
64
- describe('echo', () => {
65
- let dbBuilder: EchoTestBuilder;
66
-
67
- beforeEach(async () => {
68
- dbBuilder = await new EchoTestBuilder().open();
69
- });
70
-
71
- afterEach(async () => {
72
- await dbBuilder.close();
73
- });
74
-
75
- test('rx references are loaded lazily and receive signal notifications', async () => {
76
- const registry = Registry.make();
77
- await using peer = await dbBuilder.createPeer();
78
-
79
- let outerId: string;
80
- {
81
- await using db = await peer.createDatabase();
82
- const inner = db.add({ name: 'inner' });
83
- const outer = db.add({ inner: Ref.make(inner) });
84
- outerId = outer.id;
85
- await db.flush();
86
- }
87
-
88
- await peer.reload();
89
- {
90
- await using db = await peer.openLastDatabase();
91
- const outer = (await db.query(Filter.ids(outerId)).first()) as any;
92
- const innerRx = rxFromSignal(() => outer.inner.target);
93
-
94
- const loaded = new Trigger();
95
- let count = 0;
96
- const cancel = registry.subscribe(innerRx, (inner) => {
97
- count++;
98
- if (inner) {
99
- loaded.wake();
100
- }
101
- });
102
- onTestFinished(() => cancel());
103
-
104
- expect(registry.get(innerRx)).to.eq(undefined);
105
- expect(count).to.eq(1);
106
-
107
- await loaded.wait();
108
- expect(registry.get(innerRx)).to.include({ name: 'inner' });
109
- expect(count).to.eq(2);
110
- }
111
- });
112
-
113
- test('references graph builder', async () => {
114
- const registry = Registry.make();
115
- await using peer = await dbBuilder.createPeer();
116
-
117
- let outerId, innerId: string;
118
- {
119
- await using db = await peer.createDatabase();
120
- const inner = db.add({ name: 'inner' });
121
- const outer = db.add({ inner: Ref.make(inner) });
122
- innerId = inner.id;
123
- outerId = outer.id;
124
- await db.flush();
125
- }
126
-
127
- await peer.reload();
128
-
129
- {
130
- await using db = await peer.openLastDatabase();
131
- const outer = (await db.query(Filter.ids(outerId)).first()) as any;
132
- const innerRx = rxFromSignal(() => outer.inner.target);
133
- const inner = registry.get(innerRx);
134
- expect(inner).to.eq(undefined);
135
-
136
- const builder = new GraphBuilder({ registry });
137
- builder.addExtension(
138
- createExtension({
139
- id: 'outbound-connector',
140
- connector: () =>
141
- Rx.make((get) => {
142
- const inner = get(innerRx) as any;
143
- return inner ? [{ id: inner.id, type: EXAMPLE_TYPE, data: inner.name }] : [];
144
- }),
145
- }),
146
- );
147
-
148
- const graph = builder.graph;
149
-
150
- const loaded = new Trigger();
151
- let count = 0;
152
- const cancel = registry.subscribe(graph.connections(ROOT_ID), (nodes) => {
153
- count++;
154
- if (nodes.length > 0) {
155
- loaded.wake();
156
- }
157
- });
158
- onTestFinished(() => cancel());
159
- registry.get(graph.connections(ROOT_ID));
160
- expect(count).to.eq(1);
161
-
162
- graph.expand(ROOT_ID);
163
- await loaded.wait();
164
- expect(count).to.eq(2);
165
-
166
- const nodes = registry.get(graph.connections(ROOT_ID));
167
- expect(nodes).has.length(1);
168
- expect(nodes[0].id).to.eq(innerId);
169
- expect(nodes[0].data).to.eq('inner');
170
- }
171
- });
172
-
173
- test('query graph builder', async () => {
174
- const registry = Registry.make();
175
- await using peer = await dbBuilder.createPeer();
176
- await using db = await peer.createDatabase();
177
- db.add(Obj.make(Type.Expando, { name: 'a' }));
178
- db.add(Obj.make(Type.Expando, { name: 'b' }));
179
-
180
- const builder = new GraphBuilder({ registry });
181
- builder.addExtension(
182
- createExtension({
183
- id: 'expando',
184
- connector: () => {
185
- const query = db.query(Filter.type(Type.Expando));
186
-
187
- return Rx.make((get) => {
188
- const objects = get(rxFromQuery(query));
189
- return objects.map((object) => ({ id: object.id, type: EXAMPLE_TYPE, data: object.name }));
190
- });
191
- },
192
- }),
193
- );
194
-
195
- const graph = builder.graph;
196
- let count = 0;
197
- const cancel = registry.subscribe(graph.connections(ROOT_ID), (nodes) => {
198
- count = nodes.length;
199
- });
200
- onTestFinished(() => cancel());
201
-
202
- registry.get(graph.connections(ROOT_ID));
203
- expect(count).to.eq(0);
204
-
205
- graph.expand(ROOT_ID);
206
- expect(count).to.eq(2);
207
-
208
- const object = db.add(Obj.make(Type.Expando, { name: 'c' }));
209
- await db.flush();
210
- expect(count).to.eq(3);
211
-
212
- // NOTE: This graph builder is not reactive to the object update.
213
- object.name = 'updated';
214
- await db.flush();
215
- expect(count).to.eq(3);
216
- });
217
- });
218
- });
package/src/testing.ts DELETED
@@ -1,20 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Rx } from '@effect-rx/rx-react';
6
-
7
- import { type AnyEchoObject } from '@dxos/echo/internal';
8
- import { type QueryResult } from '@dxos/echo-db';
9
-
10
- export const rxFromQuery = <T extends AnyEchoObject>(query: QueryResult<T>): Rx.Rx<T[]> => {
11
- return Rx.make((get) => {
12
- const unsubscribe = query.subscribe((result) => {
13
- get.setSelf(result.objects);
14
- });
15
-
16
- get.addFinalizer(() => unsubscribe());
17
-
18
- return query.objects;
19
- });
20
- };