@dxos/app-graph 0.8.4-main.f9ba587 → 0.8.4-main.fffef41

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/src/graph.ts CHANGED
@@ -2,19 +2,23 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Registry, Rx } from '@effect-rx/rx-react';
6
- import { Option, pipe, Record } from 'effect';
5
+ import { Atom, Registry } from '@effect-atom/atom-react';
6
+ import * as Function from 'effect/Function';
7
+ import * as Option from 'effect/Option';
8
+ import * as Record from 'effect/Record';
7
9
 
8
10
  import { Event, Trigger } from '@dxos/async';
9
11
  import { todo } from '@dxos/debug';
10
12
  import { invariant } from '@dxos/invariant';
11
13
  import { log } from '@dxos/log';
12
- import { isNonNullable, type MakeOptional } from '@dxos/util';
14
+ import { type MakeOptional, isNonNullable } from '@dxos/util';
13
15
 
14
- import { type NodeArg, type Node, type Relation, type Action, type ActionGroup } from './node';
16
+ import { type Action, type ActionGroup, type Node, type NodeArg, type Relation } from './node';
15
17
 
16
18
  const graphSymbol = Symbol('graph');
17
- type DeepWriteable<T> = { -readonly [K in keyof T]: T[K] extends object ? DeepWriteable<T[K]> : T[K] };
19
+ type DeepWriteable<T> = {
20
+ -readonly [K in keyof T]: T[K] extends object ? DeepWriteable<T[K]> : T[K];
21
+ };
18
22
  type NodeInternal = DeepWriteable<Node> & { [graphSymbol]: Graph };
19
23
 
20
24
  /**
@@ -59,8 +63,7 @@ export type GraphParams = {
59
63
  nodes?: MakeOptional<Node, 'data' | 'cacheable'>[];
60
64
  edges?: Record<string, Edges>;
61
65
  onExpand?: Graph['_onExpand'];
62
- // TODO(wittjosiah): On initialize to restore state from cache.
63
- // onInitialize?: Graph['_onInitialize'];
66
+ onInitialize?: Graph['_onInitialize'];
64
67
  onRemoveNode?: Graph['_onRemoveNode'];
65
68
  };
66
69
 
@@ -78,32 +81,32 @@ export interface ReadableGraph {
78
81
  */
79
82
  toJSON(id?: string): object;
80
83
 
81
- json(id?: string): Rx.Rx<any>;
84
+ json(id?: string): Atom.Atom<any>;
82
85
 
83
86
  /**
84
- * Get the rx key for the node with the given id.
87
+ * Get the atom key for the node with the given id.
85
88
  */
86
- node(id: string): Rx.Rx<Option.Option<Node>>;
89
+ node(id: string): Atom.Atom<Option.Option<Node>>;
87
90
 
88
91
  /**
89
- * Get the rx key for the node with the given id.
92
+ * Get the atom key for the node with the given id.
90
93
  */
91
- nodeOrThrow(id: string): Rx.Rx<Node>;
94
+ nodeOrThrow(id: string): Atom.Atom<Node>;
92
95
 
93
96
  /**
94
- * Get the rx key for the connections of the node with the given id.
97
+ * Get the atom key for the connections of the node with the given id.
95
98
  */
96
- connections(id: string, relation?: Relation): Rx.Rx<Node[]>;
99
+ connections(id: string, relation?: Relation): Atom.Atom<Node[]>;
97
100
 
98
101
  /**
99
- * Get the rx key for the actions of the node with the given id.
102
+ * Get the atom key for the actions of the node with the given id.
100
103
  */
101
- actions(id: string): Rx.Rx<(Action | ActionGroup)[]>;
104
+ actions(id: string): Atom.Atom<(Action | ActionGroup)[]>;
102
105
 
103
106
  /**
104
- * Get the rx key for the edges of the node with the given id.
107
+ * Get the atom key for the edges of the node with the given id.
105
108
  */
106
- edges(id: string): Rx.Rx<Edges>;
109
+ edges(id: string): Atom.Atom<Edges>;
107
110
 
108
111
  /**
109
112
  * Alias for `getNodeOrThrow(ROOT_ID)`.
@@ -166,7 +169,7 @@ export interface ExpandableGraph extends ReadableGraph {
166
169
  *
167
170
  * Fires the `onInitialize` callback to provide initial data for a node.
168
171
  */
169
- // initialize(id: string): Promise<void>;
172
+ initialize(id: string): Promise<void>;
170
173
 
171
174
  /**
172
175
  * Expand a node in the graph.
@@ -227,10 +230,13 @@ export interface WritableGraph extends ExpandableGraph {
227
230
  * The Graph represents the user interface information architecture of the application constructed via plugins.
228
231
  */
229
232
  export class Graph implements WritableGraph {
230
- readonly onNodeChanged = new Event<{ id: string; node: Option.Option<Node> }>();
233
+ readonly onNodeChanged = new Event<{
234
+ id: string;
235
+ node: Option.Option<Node>;
236
+ }>();
231
237
 
232
238
  private readonly _onExpand?: (id: string, relation: Relation) => void;
233
- // private readonly _onInitialize?: (id: string) => Promise<void>;
239
+ private readonly _onInitialize?: (id: string) => Promise<void>;
234
240
  private readonly _onRemoveNode?: (id: string) => void;
235
241
 
236
242
  private readonly _registry: Registry.Registry;
@@ -238,55 +244,63 @@ export class Graph implements WritableGraph {
238
244
  private readonly _initialized = Record.empty<string, boolean>();
239
245
  private readonly _initialEdges = Record.empty<string, Edges>();
240
246
  private readonly _initialNodes = Record.fromEntries([
241
- [ROOT_ID, this._constructNode({ id: ROOT_ID, type: ROOT_TYPE, data: null, properties: {} })],
247
+ [
248
+ ROOT_ID,
249
+ this._constructNode({
250
+ id: ROOT_ID,
251
+ type: ROOT_TYPE,
252
+ data: null,
253
+ properties: {},
254
+ }),
255
+ ],
242
256
  ]);
243
257
 
244
258
  /** @internal */
245
- readonly _node = Rx.family<string, Rx.Writable<Option.Option<Node>>>((id) => {
259
+ readonly _node = Atom.family<string, Atom.Writable<Option.Option<Node>>>((id) => {
246
260
  const initial = Option.flatten(Record.get(this._initialNodes, id));
247
- return Rx.make<Option.Option<Node>>(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
261
+ return Atom.make<Option.Option<Node>>(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:node:${id}`));
248
262
  });
249
263
 
250
- private readonly _nodeOrThrow = Rx.family<string, Rx.Rx<Node>>((id) => {
251
- return Rx.make((get) => {
264
+ private readonly _nodeOrThrow = Atom.family<string, Atom.Atom<Node>>((id) => {
265
+ return Atom.make((get) => {
252
266
  const node = get(this._node(id));
253
267
  invariant(Option.isSome(node), `Node not available: ${id}`);
254
268
  return node.value;
255
269
  });
256
270
  });
257
271
 
258
- private readonly _edges = Rx.family<string, Rx.Writable<Edges>>((id) => {
272
+ private readonly _edges = Atom.family<string, Atom.Writable<Edges>>((id) => {
259
273
  const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({ inbound: [], outbound: [] })));
260
- return Rx.make<Edges>(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
274
+ return Atom.make<Edges>(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:edges:${id}`));
261
275
  });
262
276
 
263
- // NOTE: Currently the argument to the family needs to be referentially stable for the rx to be referentially stable.
264
- // TODO(wittjosiah): Rx feature request, support for something akin to `ComplexMap` to allow for complex arguments.
265
- private readonly _connections = Rx.family<string, Rx.Rx<Node[]>>((key) => {
266
- return Rx.make((get) => {
277
+ // NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
278
+ // TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
279
+ private readonly _connections = Atom.family<string, Atom.Atom<Node[]>>((key) => {
280
+ return Atom.make((get) => {
267
281
  const [id, relation] = key.split('$');
268
282
  const edges = get(this._edges(id));
269
283
  return edges[relation as Relation]
270
284
  .map((id) => get(this._node(id)))
271
285
  .filter(Option.isSome)
272
286
  .map((o) => o.value);
273
- }).pipe(Rx.withLabel(`graph:connections:${key}`));
287
+ }).pipe(Atom.withLabel(`graph:connections:${key}`));
274
288
  });
275
289
 
276
- private readonly _actions = Rx.family<string, Rx.Rx<(Action | ActionGroup)[]>>((id) => {
277
- return Rx.make((get) => {
290
+ private readonly _actions = Atom.family<string, Atom.Atom<(Action | ActionGroup)[]>>((id) => {
291
+ return Atom.make((get) => {
278
292
  return get(this._connections(`${id}$outbound`)).filter(
279
293
  (node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE,
280
294
  );
281
- }).pipe(Rx.withLabel(`graph:actions:${id}`));
295
+ }).pipe(Atom.withLabel(`graph:actions:${id}`));
282
296
  });
283
297
 
284
- private readonly _json = Rx.family<string, Rx.Rx<any>>((id) => {
285
- return Rx.make((get) => {
298
+ private readonly _json = Atom.family<string, Atom.Atom<any>>((id) => {
299
+ return Atom.make((get) => {
286
300
  const toJSON = (node: Node, seen: string[] = []): any => {
287
301
  const nodes = get(this.connections(node.id));
288
302
  const obj: Record<string, any> = {
289
- id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
303
+ id: node.id,
290
304
  type: node.type,
291
305
  };
292
306
  if (node.properties.label) {
@@ -306,11 +320,12 @@ export class Graph implements WritableGraph {
306
320
 
307
321
  const root = get(this.nodeOrThrow(id));
308
322
  return toJSON(root);
309
- }).pipe(Rx.withLabel(`graph:json:${id}`));
323
+ }).pipe(Atom.withLabel(`graph:json:${id}`));
310
324
  });
311
325
 
312
- constructor({ registry, nodes, edges, onExpand, onRemoveNode }: GraphParams = {}) {
326
+ constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode }: GraphParams = {}) {
313
327
  this._registry = registry ?? Registry.make();
328
+ this._onInitialize = onInitialize;
314
329
  this._onExpand = onExpand;
315
330
  this._onRemoveNode = onRemoveNode;
316
331
 
@@ -335,15 +350,15 @@ export class Graph implements WritableGraph {
335
350
  return this._json(id);
336
351
  }
337
352
 
338
- node(id: string): Rx.Rx<Option.Option<Node>> {
353
+ node(id: string): Atom.Atom<Option.Option<Node>> {
339
354
  return this._node(id);
340
355
  }
341
356
 
342
- nodeOrThrow(id: string): Rx.Rx<Node> {
357
+ nodeOrThrow(id: string): Atom.Atom<Node> {
343
358
  return this._nodeOrThrow(id);
344
359
  }
345
360
 
346
- connections(id: string, relation: Relation = 'outbound'): Rx.Rx<Node[]> {
361
+ connections(id: string, relation: Relation = 'outbound'): Atom.Atom<Node[]> {
347
362
  return this._connections(`${id}$${relation}`);
348
363
  }
349
364
 
@@ -351,7 +366,7 @@ export class Graph implements WritableGraph {
351
366
  return this._actions(id);
352
367
  }
353
368
 
354
- edges(id: string): Rx.Rx<Edges> {
369
+ edges(id: string): Atom.Atom<Edges> {
355
370
  return this._edges(id);
356
371
  }
357
372
 
@@ -379,15 +394,14 @@ export class Graph implements WritableGraph {
379
394
  return this._registry.get(this.edges(id));
380
395
  }
381
396
 
382
- // TODO(wittjosiah): On initialize to restore state from cache.
383
- // async initialize(id: string) {
384
- // const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
385
- // log('initialize', { id, initialized });
386
- // if (!initialized) {
387
- // await this._onInitialize?.(id);
388
- // Record.set(this._initialized, id, true);
389
- // }
390
- // }
397
+ async initialize(id: string) {
398
+ const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
399
+ log('initialize', { id, initialized });
400
+ if (!initialized) {
401
+ await this._onInitialize?.(id);
402
+ Record.set(this._initialized, id, true);
403
+ }
404
+ }
391
405
 
392
406
  expand(id: string, relation: Relation = 'outbound'): void {
393
407
  const key = `${id}$${relation}`;
@@ -400,38 +414,48 @@ export class Graph implements WritableGraph {
400
414
  }
401
415
 
402
416
  addNodes(nodes: NodeArg<any, Record<string, any>>[]): void {
403
- Rx.batch(() => {
417
+ Atom.batch(() => {
404
418
  nodes.map((node) => this.addNode(node));
405
419
  });
406
420
  }
407
421
 
408
422
  addNode({ nodes, edges, ...nodeArg }: NodeArg<any, Record<string, any>>): void {
409
423
  const { id, type, data = null, properties = {} } = nodeArg;
410
- const nodeRx = this._node(id);
411
- const node = this._registry.get(nodeRx);
424
+ const nodeAtom = this._node(id);
425
+ const node = this._registry.get(nodeAtom);
412
426
  Option.match(node, {
413
427
  onSome: (node) => {
414
428
  const typeChanged = node.type !== type;
415
429
  const dataChanged = node.data !== data;
416
430
  const propertiesChanged = Object.keys(properties).some((key) => node.properties[key] !== properties[key]);
417
- log('existing node', { id, typeChanged, dataChanged, propertiesChanged });
431
+ log('existing node', {
432
+ id,
433
+ typeChanged,
434
+ dataChanged,
435
+ propertiesChanged,
436
+ });
418
437
  if (typeChanged || dataChanged || propertiesChanged) {
419
438
  log('updating node', { id, type, data, properties });
420
- const newNode = Option.some({ ...node, type, data, properties: { ...node.properties, ...properties } });
421
- this._registry.set(nodeRx, newNode);
439
+ const newNode = Option.some({
440
+ ...node,
441
+ type,
442
+ data,
443
+ properties: { ...node.properties, ...properties },
444
+ });
445
+ this._registry.set(nodeAtom, newNode);
422
446
  this.onNodeChanged.emit({ id, node: newNode });
423
447
  }
424
448
  },
425
449
  onNone: () => {
426
450
  log('new node', { id, type, data, properties });
427
451
  const newNode = this._constructNode({ id, type, data, properties });
428
- this._registry.set(nodeRx, newNode);
452
+ this._registry.set(nodeAtom, newNode);
429
453
  this.onNodeChanged.emit({ id, node: newNode });
430
454
  },
431
455
  });
432
456
 
433
457
  if (nodes) {
434
- // Rx.batch(() => {
458
+ // Atom.batch(() => {
435
459
  this.addNodes(nodes);
436
460
  const _edges = nodes.map((node) => ({ source: id, target: node.id }));
437
461
  this.addEdges(_edges);
@@ -444,15 +468,15 @@ export class Graph implements WritableGraph {
444
468
  }
445
469
 
446
470
  removeNodes(ids: string[], edges = false): void {
447
- Rx.batch(() => {
471
+ Atom.batch(() => {
448
472
  ids.map((id) => this.removeNode(id, edges));
449
473
  });
450
474
  }
451
475
 
452
476
  removeNode(id: string, edges = false): void {
453
- const nodeRx = this._node(id);
454
- // TODO(wittjosiah): Is there a way to mark these rx values for garbage collection?
455
- this._registry.set(nodeRx, Option.none());
477
+ const nodeAtom = this._node(id);
478
+ // TODO(wittjosiah): Is there a way to mark these atom values for garbage collection?
479
+ this._registry.set(nodeAtom, Option.none());
456
480
  this.onNodeChanged.emit({ id, node: Option.none() });
457
481
  // TODO(wittjosiah): Reset expanded and initialized flags?
458
482
 
@@ -469,55 +493,67 @@ export class Graph implements WritableGraph {
469
493
  }
470
494
 
471
495
  addEdges(edges: Edge[]): void {
472
- Rx.batch(() => {
496
+ Atom.batch(() => {
473
497
  edges.map((edge) => this.addEdge(edge));
474
498
  });
475
499
  }
476
500
 
477
501
  addEdge(edgeArg: Edge): void {
478
- const sourceRx = this._edges(edgeArg.source);
479
- const source = this._registry.get(sourceRx);
502
+ const sourceAtom = this._edges(edgeArg.source);
503
+ const source = this._registry.get(sourceAtom);
480
504
  if (!source.outbound.includes(edgeArg.target)) {
481
- log('add outbound edge', { source: edgeArg.source, target: edgeArg.target });
482
- this._registry.set(sourceRx, { inbound: source.inbound, outbound: [...source.outbound, edgeArg.target] });
505
+ log('add outbound edge', {
506
+ source: edgeArg.source,
507
+ target: edgeArg.target,
508
+ });
509
+ this._registry.set(sourceAtom, {
510
+ inbound: source.inbound,
511
+ outbound: [...source.outbound, edgeArg.target],
512
+ });
483
513
  }
484
514
 
485
- const targetRx = this._edges(edgeArg.target);
486
- const target = this._registry.get(targetRx);
515
+ const targetAtom = this._edges(edgeArg.target);
516
+ const target = this._registry.get(targetAtom);
487
517
  if (!target.inbound.includes(edgeArg.source)) {
488
- log('add inbound edge', { source: edgeArg.source, target: edgeArg.target });
489
- this._registry.set(targetRx, { inbound: [...target.inbound, edgeArg.source], outbound: target.outbound });
518
+ log('add inbound edge', {
519
+ source: edgeArg.source,
520
+ target: edgeArg.target,
521
+ });
522
+ this._registry.set(targetAtom, {
523
+ inbound: [...target.inbound, edgeArg.source],
524
+ outbound: target.outbound,
525
+ });
490
526
  }
491
527
  }
492
528
 
493
529
  removeEdges(edges: Edge[], removeOrphans = false): void {
494
- Rx.batch(() => {
530
+ Atom.batch(() => {
495
531
  edges.map((edge) => this.removeEdge(edge, removeOrphans));
496
532
  });
497
533
  }
498
534
 
499
535
  removeEdge(edgeArg: Edge, removeOrphans = false): void {
500
- const sourceRx = this._edges(edgeArg.source);
501
- const source = this._registry.get(sourceRx);
536
+ const sourceAtom = this._edges(edgeArg.source);
537
+ const source = this._registry.get(sourceAtom);
502
538
  if (source.outbound.includes(edgeArg.target)) {
503
- this._registry.set(sourceRx, {
539
+ this._registry.set(sourceAtom, {
504
540
  inbound: source.inbound,
505
541
  outbound: source.outbound.filter((id) => id !== edgeArg.target),
506
542
  });
507
543
  }
508
544
 
509
- const targetRx = this._edges(edgeArg.target);
510
- const target = this._registry.get(targetRx);
545
+ const targetAtom = this._edges(edgeArg.target);
546
+ const target = this._registry.get(targetAtom);
511
547
  if (target.inbound.includes(edgeArg.source)) {
512
- this._registry.set(targetRx, {
548
+ this._registry.set(targetAtom, {
513
549
  inbound: target.inbound.filter((id) => id !== edgeArg.source),
514
550
  outbound: target.outbound,
515
551
  });
516
552
  }
517
553
 
518
554
  if (removeOrphans) {
519
- const source = this._registry.get(sourceRx);
520
- const target = this._registry.get(targetRx);
555
+ const source = this._registry.get(sourceAtom);
556
+ const target = this._registry.get(targetAtom);
521
557
  if (source.outbound.length === 0 && source.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
522
558
  this.removeNodes([edgeArg.source]);
523
559
  }
@@ -528,12 +564,12 @@ export class Graph implements WritableGraph {
528
564
  }
529
565
 
530
566
  sortEdges(id: string, relation: Relation, order: string[]): void {
531
- const edgesRx = this._edges(id);
532
- const edges = this._registry.get(edgesRx);
567
+ const edgesAtom = this._edges(id);
568
+ const edges = this._registry.get(edgesAtom);
533
569
  const unsorted = edges[relation].filter((id) => !order.includes(id)) ?? [];
534
570
  const sorted = order.filter((id) => edges[relation].includes(id)) ?? [];
535
571
  edges[relation].splice(0, edges[relation].length, ...[...sorted, ...unsorted]);
536
- this._registry.set(edgesRx, edges);
572
+ this._registry.set(edgesAtom, edges);
537
573
  }
538
574
 
539
575
  traverse({ visitor, source = ROOT_ID, relation = 'outbound' }: GraphTraversalOptions, path: string[] = []): void {
@@ -554,7 +590,7 @@ export class Graph implements WritableGraph {
554
590
  }
555
591
 
556
592
  getPath({ source = 'root', target }: { source?: string; target: string }): Option.Option<string[]> {
557
- return pipe(
593
+ return Function.pipe(
558
594
  this.getNode(source),
559
595
  Option.flatMap((node) => {
560
596
  let found: Option.Option<string[]> = Option.none();
@@ -598,6 +634,11 @@ export class Graph implements WritableGraph {
598
634
 
599
635
  /** @internal */
600
636
  _constructNode(node: NodeArg<any>): Option.Option<Node> {
601
- return Option.some({ [graphSymbol]: this, data: null, properties: {}, ...node });
637
+ return Option.some({
638
+ [graphSymbol]: this,
639
+ data: null,
640
+ properties: {},
641
+ ...node,
642
+ });
602
643
  }
603
644
  }
package/src/node.ts CHANGED
@@ -2,7 +2,9 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type MaybePromise, type MakeOptional } from '@dxos/util';
5
+ import { type MakeOptional, type MaybePromise } from '@dxos/util';
6
+
7
+ import { ACTION_GROUP_TYPE, ACTION_TYPE } from './graph';
6
8
 
7
9
  /**
8
10
  * Represents a node in the graph.
@@ -84,7 +86,7 @@ export type Action<TProperties extends Record<string, any> = Record<string, any>
84
86
  >;
85
87
 
86
88
  export const isAction = (data: unknown): data is Action =>
87
- isGraphNode(data) ? typeof data.data === 'function' : false;
89
+ isGraphNode(data) ? typeof data.data === 'function' && data.type === ACTION_TYPE : false;
88
90
 
89
91
  export const actionGroupSymbol = Symbol('ActionGroup');
90
92
 
@@ -95,7 +97,7 @@ export type ActionGroup<TProperties extends Record<string, any> = Record<string,
95
97
  >;
96
98
 
97
99
  export const isActionGroup = (data: unknown): data is ActionGroup =>
98
- isGraphNode(data) ? data.data === actionGroupSymbol : false;
100
+ isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ACTION_GROUP_TYPE : false;
99
101
 
100
102
  export type ActionLike = Action | ActionGroup;
101
103
 
@@ -2,37 +2,37 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Registry, Rx } from '@effect-rx/rx-react';
5
+ import { Atom, Registry } from '@effect-atom/atom-react';
6
6
  import { signal } from '@preact/signals-core';
7
7
  import { afterEach, beforeEach, describe, expect, onTestFinished, test } from 'vitest';
8
8
 
9
9
  import { Trigger } from '@dxos/async';
10
+ import { Obj, Type } from '@dxos/echo';
11
+ import { Ref } from '@dxos/echo/internal';
10
12
  import { Filter } from '@dxos/echo-db';
11
13
  import { EchoTestBuilder } from '@dxos/echo-db/testing';
12
- import { Expando, Ref } from '@dxos/echo-schema';
13
14
  import { registerSignalsRuntime } from '@dxos/echo-signals';
14
- import { live } from '@dxos/live-object';
15
15
 
16
16
  import { ROOT_ID } from './graph';
17
- import { createExtension, GraphBuilder, rxFromSignal } from './graph-builder';
18
- import { rxFromQuery } from './testing';
17
+ import { GraphBuilder, atomFromSignal, createExtension } from './graph-builder';
18
+ import { atomFromQuery } from './testing';
19
19
 
20
20
  registerSignalsRuntime();
21
21
 
22
22
  const EXAMPLE_TYPE = 'dxos.org/type/example';
23
23
 
24
24
  describe('signals integration', () => {
25
- test('creating rx from signal', () => {
25
+ test('creating atom from signal', () => {
26
26
  const registry = Registry.make();
27
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.
28
+ const value = atomFromSignal(() => state.value);
29
+ const inline = Atom.make((get) => {
30
+ // NOTE: This will create a new atom instance each time.
31
+ // This test is verifying that this behaves the same as using a stable atom instance.
32
32
  // The parent will remain subscribed to one instance until the new one is created.
33
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);
34
+ const atom = atomFromSignal(() => get(value));
35
+ return get(atom);
36
36
  });
37
37
 
38
38
  let count = 0;
@@ -72,7 +72,7 @@ describe('signals integration', () => {
72
72
  await dbBuilder.close();
73
73
  });
74
74
 
75
- test('rx references are loaded lazily and receive signal notifications', async () => {
75
+ test('atom references are loaded lazily and receive signal notifications', async () => {
76
76
  const registry = Registry.make();
77
77
  await using peer = await dbBuilder.createPeer();
78
78
 
@@ -89,23 +89,24 @@ describe('signals integration', () => {
89
89
  {
90
90
  await using db = await peer.openLastDatabase();
91
91
  const outer = (await db.query(Filter.ids(outerId)).first()) as any;
92
- const innerRx = rxFromSignal(() => outer.inner.target);
93
-
92
+ const innerAtom = atomFromSignal(() => outer.inner.target);
94
93
  const loaded = new Trigger();
94
+
95
95
  let count = 0;
96
- const cancel = registry.subscribe(innerRx, (inner) => {
96
+ const cancel = registry.subscribe(innerAtom, (inner) => {
97
97
  count++;
98
98
  if (inner) {
99
99
  loaded.wake();
100
100
  }
101
101
  });
102
+
102
103
  onTestFinished(() => cancel());
103
104
 
104
- expect(registry.get(innerRx)).to.eq(undefined);
105
+ expect(registry.get(innerAtom)).to.eq(undefined);
105
106
  expect(count).to.eq(1);
106
107
 
107
108
  await loaded.wait();
108
- expect(registry.get(innerRx)).to.include({ name: 'inner' });
109
+ expect(registry.get(innerAtom)).to.include({ name: 'inner' });
109
110
  expect(count).to.eq(2);
110
111
  }
111
112
  });
@@ -129,8 +130,8 @@ describe('signals integration', () => {
129
130
  {
130
131
  await using db = await peer.openLastDatabase();
131
132
  const outer = (await db.query(Filter.ids(outerId)).first()) as any;
132
- const innerRx = rxFromSignal(() => outer.inner.target);
133
- const inner = registry.get(innerRx);
133
+ const innerAtom = atomFromSignal(() => outer.inner.target);
134
+ const inner = registry.get(innerAtom);
134
135
  expect(inner).to.eq(undefined);
135
136
 
136
137
  const builder = new GraphBuilder({ registry });
@@ -138,8 +139,8 @@ describe('signals integration', () => {
138
139
  createExtension({
139
140
  id: 'outbound-connector',
140
141
  connector: () =>
141
- Rx.make((get) => {
142
- const inner = get(innerRx) as any;
142
+ Atom.make((get) => {
143
+ const inner = get(innerAtom) as any;
143
144
  return inner ? [{ id: inner.id, type: EXAMPLE_TYPE, data: inner.name }] : [];
144
145
  }),
145
146
  }),
@@ -174,18 +175,18 @@ describe('signals integration', () => {
174
175
  const registry = Registry.make();
175
176
  await using peer = await dbBuilder.createPeer();
176
177
  await using db = await peer.createDatabase();
177
- db.add(live(Expando, { name: 'a' }));
178
- db.add(live(Expando, { name: 'b' }));
178
+ db.add(Obj.make(Type.Expando, { name: 'a' }));
179
+ db.add(Obj.make(Type.Expando, { name: 'b' }));
179
180
 
180
181
  const builder = new GraphBuilder({ registry });
181
182
  builder.addExtension(
182
183
  createExtension({
183
184
  id: 'expando',
184
185
  connector: () => {
185
- const query = db.query(Filter.type(Expando));
186
+ const query = db.query(Filter.type(Type.Expando));
186
187
 
187
- return Rx.make((get) => {
188
- const objects = get(rxFromQuery(query));
188
+ return Atom.make((get) => {
189
+ const objects = get(atomFromQuery(query));
189
190
  return objects.map((object) => ({ id: object.id, type: EXAMPLE_TYPE, data: object.name }));
190
191
  });
191
192
  },
@@ -205,7 +206,7 @@ describe('signals integration', () => {
205
206
  graph.expand(ROOT_ID);
206
207
  expect(count).to.eq(2);
207
208
 
208
- const object = db.add(live(Expando, { name: 'c' }));
209
+ const object = db.add(Obj.make(Type.Expando, { name: 'c' }));
209
210
  await db.flush();
210
211
  expect(count).to.eq(3);
211
212