@dxos/app-graph 0.7.4 → 0.7.5-feature-compute.4d9d99a
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 +36 -11
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +35 -10
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +36 -11
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/graph-builder.d.ts +6 -3
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/node.d.ts +2 -2
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +16 -16
- package/src/graph-builder.ts +27 -9
- package/src/graph.ts +1 -2
- package/src/node.ts +3 -3
package/src/graph-builder.ts
CHANGED
|
@@ -8,11 +8,13 @@ import { Trigger, type UnsubscribeCallback } from '@dxos/async';
|
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
9
|
import { create } from '@dxos/live-object';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
|
-
import { isNode, type MaybePromise, nonNullable } from '@dxos/util';
|
|
11
|
+
import { byDisposition, type Disposition, isNode, type MaybePromise, nonNullable } from '@dxos/util';
|
|
12
12
|
|
|
13
13
|
import { ACTION_GROUP_TYPE, ACTION_TYPE, Graph, ROOT_ID, type GraphParams } from './graph';
|
|
14
14
|
import { type ActionData, actionGroupSymbol, type Node, type NodeArg, type Relation } from './node';
|
|
15
15
|
|
|
16
|
+
const NODE_RESOLVER_TIMEOUT = 1_000;
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* Graph builder extension for adding nodes to the graph based on just the node id.
|
|
18
20
|
* This is useful for creating the first node in a graph or for hydrating cached nodes with data.
|
|
@@ -50,6 +52,7 @@ type GuardedNodeType<T> = T extends (value: any) => value is infer N ? (N extend
|
|
|
50
52
|
* @param params.id The unique id of the extension.
|
|
51
53
|
* @param params.relation The relation the graph is being expanded from the existing node.
|
|
52
54
|
* @param params.type If provided, all nodes returned are expected to have this type.
|
|
55
|
+
* @param params.disposition Affects the order the extensions are processed in.
|
|
53
56
|
* @param params.filter A filter function to determine if an extension should act on a node.
|
|
54
57
|
* @param params.resolver A function to add nodes to the graph based on just the node id.
|
|
55
58
|
* @param params.connector A function to add nodes to the graph based on a connection to an existing node.
|
|
@@ -60,6 +63,7 @@ export type CreateExtensionOptions<T = any> = {
|
|
|
60
63
|
id: string;
|
|
61
64
|
relation?: Relation;
|
|
62
65
|
type?: string;
|
|
66
|
+
disposition?: Disposition;
|
|
63
67
|
filter?: (node: Node) => node is Node<T>;
|
|
64
68
|
resolver?: ResolverExtension;
|
|
65
69
|
connector?: ConnectorExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;
|
|
@@ -71,15 +75,16 @@ export type CreateExtensionOptions<T = any> = {
|
|
|
71
75
|
* Create a graph builder extension.
|
|
72
76
|
*/
|
|
73
77
|
export const createExtension = <T = any>(extension: CreateExtensionOptions<T>): BuilderExtension[] => {
|
|
74
|
-
const { id, resolver, connector, actions, actionGroups, ...rest } = extension;
|
|
78
|
+
const { id, disposition = 'static', resolver, connector, actions, actionGroups, ...rest } = extension;
|
|
75
79
|
const getId = (key: string) => `${id}/${key}`;
|
|
76
80
|
return [
|
|
77
|
-
resolver ? { id: getId('resolver'), resolver } : undefined,
|
|
78
|
-
connector ? { ...rest, id: getId('connector'), connector } : undefined,
|
|
81
|
+
resolver ? { id: getId('resolver'), disposition, resolver } : undefined,
|
|
82
|
+
connector ? { ...rest, id: getId('connector'), disposition, connector } : undefined,
|
|
79
83
|
actionGroups
|
|
80
84
|
? ({
|
|
81
85
|
...rest,
|
|
82
86
|
id: getId('actionGroups'),
|
|
87
|
+
disposition,
|
|
83
88
|
type: ACTION_GROUP_TYPE,
|
|
84
89
|
relation: 'outbound',
|
|
85
90
|
connector: ({ node }) =>
|
|
@@ -90,6 +95,7 @@ export const createExtension = <T = any>(extension: CreateExtensionOptions<T>):
|
|
|
90
95
|
? ({
|
|
91
96
|
...rest,
|
|
92
97
|
id: getId('actions'),
|
|
98
|
+
disposition,
|
|
93
99
|
type: ACTION_TYPE,
|
|
94
100
|
relation: 'outbound',
|
|
95
101
|
connector: ({ node }) => actions({ node })?.map((arg) => ({ ...arg, type: ACTION_TYPE })),
|
|
@@ -166,15 +172,16 @@ export const toSignal = <T>(
|
|
|
166
172
|
return thisSignal.value;
|
|
167
173
|
};
|
|
168
174
|
|
|
169
|
-
export type BuilderExtension = {
|
|
175
|
+
export type BuilderExtension = Readonly<{
|
|
170
176
|
id: string;
|
|
177
|
+
disposition: Disposition;
|
|
171
178
|
resolver?: ResolverExtension;
|
|
172
179
|
connector?: ConnectorExtension;
|
|
173
180
|
// Only for connector.
|
|
174
181
|
relation?: Relation;
|
|
175
182
|
type?: string;
|
|
176
183
|
filter?: (node: Node) => boolean;
|
|
177
|
-
}
|
|
184
|
+
}>;
|
|
178
185
|
|
|
179
186
|
type ExtensionArg = BuilderExtension | BuilderExtension[] | ExtensionArg[];
|
|
180
187
|
|
|
@@ -221,7 +228,16 @@ export class GraphBuilder {
|
|
|
221
228
|
.filter((id) => id !== ROOT_ID)
|
|
222
229
|
.forEach((id) => (this._initialized[id] = new Trigger()));
|
|
223
230
|
Object.keys(this._graph._nodes).forEach((id) => this._onInitialNode(id));
|
|
224
|
-
await Promise.all(
|
|
231
|
+
await Promise.all(
|
|
232
|
+
Object.entries(this._initialized).map(async ([id, trigger]) => {
|
|
233
|
+
try {
|
|
234
|
+
await trigger.wait({ timeout: NODE_RESOLVER_TIMEOUT });
|
|
235
|
+
} catch {
|
|
236
|
+
log.error('node resolver timeout', { id });
|
|
237
|
+
this.graph._removeNodes([id]);
|
|
238
|
+
}
|
|
239
|
+
}),
|
|
240
|
+
);
|
|
225
241
|
}
|
|
226
242
|
|
|
227
243
|
get graph() {
|
|
@@ -310,7 +326,8 @@ export class GraphBuilder {
|
|
|
310
326
|
this._resolverSubscriptions.set(
|
|
311
327
|
nodeId,
|
|
312
328
|
effect(() => {
|
|
313
|
-
|
|
329
|
+
const extensions = Object.values(this._extensions).toSorted(byDisposition);
|
|
330
|
+
for (const { id, resolver } of extensions) {
|
|
314
331
|
if (!resolver) {
|
|
315
332
|
continue;
|
|
316
333
|
}
|
|
@@ -367,7 +384,8 @@ export class GraphBuilder {
|
|
|
367
384
|
|
|
368
385
|
// TODO(wittjosiah): Consider allowing extensions to collaborate on the same node by merging their results.
|
|
369
386
|
const nodes: NodeArg<any>[] = [];
|
|
370
|
-
|
|
387
|
+
const extensions = Object.values(this._extensions).toSorted(byDisposition);
|
|
388
|
+
for (const { id, connector, filter, type, relation = 'outbound' } of extensions) {
|
|
371
389
|
if (
|
|
372
390
|
!connector ||
|
|
373
391
|
relation !== nodesRelation ||
|
package/src/graph.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { type MakeOptional, nonNullable, pick } from '@dxos/util';
|
|
|
13
13
|
import { type Node, type NodeArg, type NodeFilter, type Relation, actionGroupSymbol, isActionLike } from './node';
|
|
14
14
|
|
|
15
15
|
const graphSymbol = Symbol('graph');
|
|
16
|
-
type DeepWriteable<T> = { -readonly [K in keyof T]: DeepWriteable<T[K]> };
|
|
16
|
+
type DeepWriteable<T> = { -readonly [K in keyof T]: T[K] extends object ? DeepWriteable<T[K]> : T[K] };
|
|
17
17
|
type NodeInternal = DeepWriteable<Node> & { [graphSymbol]: Graph };
|
|
18
18
|
|
|
19
19
|
export const getGraph = (node: Node): Graph => {
|
|
@@ -319,7 +319,6 @@ export class Graph {
|
|
|
319
319
|
|
|
320
320
|
const nodes = this._getNodes({ node, relation, expansion });
|
|
321
321
|
const nodeSubscriptions = nodes.map((n) => this.subscribeTraverse({ node: n, visitor, expansion }, path));
|
|
322
|
-
|
|
323
322
|
return () => {
|
|
324
323
|
nodeSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
325
324
|
};
|
package/src/node.ts
CHANGED
|
@@ -87,9 +87,9 @@ export const isAction = (data: unknown): data is Action =>
|
|
|
87
87
|
|
|
88
88
|
export const actionGroupSymbol = Symbol('ActionGroup');
|
|
89
89
|
|
|
90
|
-
export type ActionGroup = Readonly<
|
|
91
|
-
Omit<Node<typeof actionGroupSymbol,
|
|
92
|
-
properties: Readonly<
|
|
90
|
+
export type ActionGroup<TProperties extends Record<string, any> = Record<string, any>> = Readonly<
|
|
91
|
+
Omit<Node<typeof actionGroupSymbol, TProperties>, 'properties'> & {
|
|
92
|
+
properties: Readonly<TProperties>;
|
|
93
93
|
}
|
|
94
94
|
>;
|
|
95
95
|
|