@dxos/app-graph 0.10.0 → 0.11.0
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/chunk-graph-builder.mjs +1901 -0
- package/dist/lib/chunk-graph-builder.mjs.map +1 -0
- package/dist/lib/index.mjs +281 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/scheduler.browser.mjs +2 -0
- package/dist/lib/scheduler.mjs +12 -0
- package/dist/lib/scheduler.mjs.map +1 -0
- package/dist/lib/testing.mjs +28 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/types/src/atoms.d.ts +1 -1
- package/dist/types/src/atoms.d.ts.map +1 -1
- package/dist/types/src/graph-builder.d.ts +128 -9
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +4 -1
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/node-matcher.d.ts +1 -1
- package/dist/types/src/node-matcher.d.ts.map +1 -1
- package/dist/types/src/node.d.ts +14 -2
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/path-resolution.d.ts +69 -0
- package/dist/types/src/path-resolution.d.ts.map +1 -0
- package/dist/types/src/path-resolution.test.d.ts +2 -0
- package/dist/types/src/path-resolution.test.d.ts.map +1 -0
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/src/testing/setup-graph-builder.d.ts +1 -1
- package/dist/types/src/testing/setup-graph-builder.d.ts.map +1 -1
- package/dist/types/src/util.test.d.ts +2 -0
- package/dist/types/src/util.test.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +22 -21
- package/src/atoms.ts +1 -1
- package/src/graph-builder.test.ts +21 -1
- package/src/graph-builder.ts +327 -58
- package/src/graph.test.ts +1 -1
- package/src/graph.ts +22 -16
- package/src/index.ts +1 -0
- package/src/node-matcher.test.ts +1 -1
- package/src/node-matcher.ts +1 -1
- package/src/node.ts +19 -2
- package/src/path-resolution.test.ts +520 -0
- package/src/path-resolution.ts +355 -0
- package/src/stories/EchoGraph.stories.tsx +97 -121
- package/src/testing/setup-graph-builder.ts +1 -1
- package/src/util.test.ts +85 -0
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YMTZ7MPW.mjs +0 -1509
- package/dist/lib/neutral/chunk-YMTZ7MPW.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -40
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/scheduler.mjs +0 -15
- package/dist/lib/neutral/scheduler.mjs.map +0 -7
- package/dist/lib/neutral/testing/index.mjs +0 -40
- package/dist/lib/neutral/testing/index.mjs.map +0 -7
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { a as urlRepresentation, c as getConnections, d as getParentId, f as getSegmentId, g as __exportAll, h as node_exports, l as getNode, m as RootId, n as flush, o as node_matcher_exports, p as qualifyId, r as graph_builder_exports, s as expand, u as graph_exports } from "./chunk-graph-builder.mjs";
|
|
2
|
+
import { Atom } from "@effect-atom/atom";
|
|
3
|
+
import * as Function from "effect/Function";
|
|
4
|
+
import * as Option from "effect/Option";
|
|
5
|
+
import { log } from "@dxos/log";
|
|
6
|
+
import { Position } from "@dxos/util";
|
|
7
|
+
import * as Array from "effect/Array";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Record from "effect/Record";
|
|
10
|
+
import { EffectEx } from "@dxos/effect";
|
|
11
|
+
import { EntityId, SpaceId } from "@dxos/keys";
|
|
12
|
+
//#region src/atoms.ts
|
|
13
|
+
var atoms_exports = /* @__PURE__ */ __exportAll({ fromObservable: () => fromObservable });
|
|
14
|
+
var observableFamily = Atom.family((observable) => {
|
|
15
|
+
return Atom.make((get) => {
|
|
16
|
+
const subscription = observable.subscribe((value) => get.setSelf(value));
|
|
17
|
+
get.addFinalizer(() => subscription.unsubscribe());
|
|
18
|
+
return observable.get();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Creates an Atom.Atom<T> from a MulticastObservable<T>
|
|
23
|
+
* Will return the same atom instance for the same observable.
|
|
24
|
+
*/
|
|
25
|
+
var fromObservable = (observable) => {
|
|
26
|
+
return observableFamily(observable);
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/path-resolution.ts
|
|
30
|
+
var path_resolution_exports = /* @__PURE__ */ __exportAll({
|
|
31
|
+
buildUrlKeyTable: () => buildUrlKeyTable,
|
|
32
|
+
representNode: () => representNode,
|
|
33
|
+
resolveUrl: () => resolveUrl
|
|
34
|
+
});
|
|
35
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/path-resolution.ts";
|
|
36
|
+
/** Reserved words that can never be registered as a `urlKey`, duplicated from `UrlPath.isReservedKey`
|
|
37
|
+
* (rather than imported) to keep app-graph free of an app-toolkit dependency. A key declared by a
|
|
38
|
+
* binding — including the `anchor` and `linked` tiers — is never reserved. */
|
|
39
|
+
var RESERVED_URL_KEYS = /* @__PURE__ */ new Set([
|
|
40
|
+
"reset",
|
|
41
|
+
"redirect",
|
|
42
|
+
"not-found"
|
|
43
|
+
]);
|
|
44
|
+
var isReservedUrlKey = (key) => RESERVED_URL_KEYS.has(key) || SpaceId.isValid(key) || EntityId.isValid(key);
|
|
45
|
+
/** Narrows to an extension that declared a URL binding, so callers need no non-null assertion. */
|
|
46
|
+
var isUrlKeyed = (extension) => !!extension.url?.key;
|
|
47
|
+
var getKeyedExtensions = (builder) => {
|
|
48
|
+
const extensions = Function.pipe(Record.values(builder.getExtensions()), Array.sortBy(Position.compare));
|
|
49
|
+
const keyed = [];
|
|
50
|
+
for (const extension of extensions) {
|
|
51
|
+
if (!isUrlKeyed(extension)) continue;
|
|
52
|
+
if (isReservedUrlKey(extension.url.key)) {
|
|
53
|
+
log.warn("reserved URL prefix key", {
|
|
54
|
+
key: extension.url.key,
|
|
55
|
+
extension: extension.id
|
|
56
|
+
}, {
|
|
57
|
+
"~LogMeta": "~LogMeta",
|
|
58
|
+
F: __dxlog_file,
|
|
59
|
+
L: 80,
|
|
60
|
+
S: void 0
|
|
61
|
+
});
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
keyed.push(extension);
|
|
65
|
+
}
|
|
66
|
+
return keyed;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Build the global `urlKey -> extensionIds` table from the builder's current extensions. Recomputed
|
|
70
|
+
* on every call — cheap (a synchronous scan of already-registered extensions) and always current, so
|
|
71
|
+
* activating/deactivating plugins can never leave a stale table around. A key maps to the ordered list
|
|
72
|
+
* of every extension that declared it (usually one); forward resolution treats a node produced by any
|
|
73
|
+
* of them as a match for the key.
|
|
74
|
+
*/
|
|
75
|
+
var buildKeyTable = (builder) => {
|
|
76
|
+
const table = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const extension of getKeyedExtensions(builder)) {
|
|
78
|
+
const key = extension.url.key;
|
|
79
|
+
const existing = table.get(key);
|
|
80
|
+
if (existing) existing.push(extension.id);
|
|
81
|
+
else table.set(key, [extension.id]);
|
|
82
|
+
}
|
|
83
|
+
return table;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Build the `urlKey -> { key, hasId }` table consumed by `UrlPath.parse`, straight from the
|
|
87
|
+
* builder's current `urlKey`/`urlKeyHasId` declarations — the "registration, not parser" property
|
|
88
|
+
* the URL grammar requires. Callers (the layout url-handler) pass this to `UrlPath.parse`
|
|
89
|
+
* to tokenize a pathname into a pair chain.
|
|
90
|
+
*/
|
|
91
|
+
var buildUrlKeyTable = (builder) => {
|
|
92
|
+
const table = /* @__PURE__ */ new Map();
|
|
93
|
+
const { anchorKey, linkedKey } = builder.urlGrammar;
|
|
94
|
+
if (anchorKey) table.set(anchorKey, {
|
|
95
|
+
key: anchorKey,
|
|
96
|
+
hasId: true,
|
|
97
|
+
anchor: true
|
|
98
|
+
});
|
|
99
|
+
if (linkedKey) table.set(linkedKey, {
|
|
100
|
+
key: linkedKey,
|
|
101
|
+
hasId: true,
|
|
102
|
+
anchor: false
|
|
103
|
+
});
|
|
104
|
+
for (const extension of getKeyedExtensions(builder)) {
|
|
105
|
+
const key = extension.url.key;
|
|
106
|
+
const hasId = extension.url.kind !== "singleton";
|
|
107
|
+
const anchor = false;
|
|
108
|
+
const existing = table.get(key);
|
|
109
|
+
if (existing && existing.hasId !== hasId) {
|
|
110
|
+
log.warn("conflicting kind for shared URL prefix key", {
|
|
111
|
+
key,
|
|
112
|
+
extension: extension.id
|
|
113
|
+
}, {
|
|
114
|
+
"~LogMeta": "~LogMeta",
|
|
115
|
+
F: __dxlog_file,
|
|
116
|
+
L: 142,
|
|
117
|
+
S: void 0
|
|
118
|
+
});
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
table.set(key, {
|
|
122
|
+
key,
|
|
123
|
+
hasId,
|
|
124
|
+
anchor
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return table;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Expand every ancestor prefix of a qualified node id (including the id itself), then flush once.
|
|
131
|
+
* Mirrors `@dxos/app-toolkit`'s `NotFound.expandPath` technique, reimplemented locally so app-graph
|
|
132
|
+
* doesn't depend on app-toolkit.
|
|
133
|
+
*/
|
|
134
|
+
var expandAncestors = async (builder, qualifiedId) => {
|
|
135
|
+
const segments = qualifiedId.split("/");
|
|
136
|
+
for (let index = 1; index <= segments.length; index++) expand(builder.graph, segments.slice(0, index).join("/"), "child");
|
|
137
|
+
await flush(builder);
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Materialize a candidate qualified node id and confirm it exists: expand its ancestors, then check
|
|
141
|
+
* the node is known. Returns the id on success, `null` otherwise.
|
|
142
|
+
*/
|
|
143
|
+
var materializeCandidate = async (builder, candidateId) => {
|
|
144
|
+
await expandAncestors(builder, candidateId);
|
|
145
|
+
return Option.isSome(getNode(builder.graph, candidateId)) ? candidateId : null;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Resolve a single `(key, id)` pair to a qualified node id, anchored at the workspace base. Resolution
|
|
149
|
+
* is fully explicit — no search. Each keyed extension's `path` is one of:
|
|
150
|
+
* 1. Static segments (`string[]`, the preferred deterministic case): the id is the `+`-joined node
|
|
151
|
+
* segments *after* the path, so a fixed-depth nested shape (e.g. `db/<slug>+<id>`) resolves with
|
|
152
|
+
* no resolver — split the id back into segments and expand the exact path.
|
|
153
|
+
* 2. A dynamic {@link GraphBuilder.PathResolver} (recursive/mutable shapes, i.e. nested collections),
|
|
154
|
+
* whose candidate is materialized and verified the same way.
|
|
155
|
+
* Static paths are tried before resolvers; an unmatched pair yields `null`.
|
|
156
|
+
*/
|
|
157
|
+
var resolveKeyId = async (builder, workspaceBaseId, workspace, extensions, id) => {
|
|
158
|
+
const idSegments = id.split(builder.urlGrammar.tailSeparator);
|
|
159
|
+
for (const extension of extensions) if (Array.isArray(extension.path)) {
|
|
160
|
+
const resolved = await materializeCandidate(builder, [
|
|
161
|
+
workspaceBaseId,
|
|
162
|
+
...extension.path,
|
|
163
|
+
...idSegments
|
|
164
|
+
].join("/"));
|
|
165
|
+
if (resolved) return resolved;
|
|
166
|
+
}
|
|
167
|
+
for (const extension of extensions) if (typeof extension.path === "function") {
|
|
168
|
+
const candidateId = await EffectEx.runPromise(extension.path({
|
|
169
|
+
id,
|
|
170
|
+
workspace,
|
|
171
|
+
workspaceBaseId
|
|
172
|
+
}).pipe(Effect.catchAllDefect(() => Effect.succeed(null))));
|
|
173
|
+
if (candidateId) {
|
|
174
|
+
const resolved = await materializeCandidate(builder, candidateId);
|
|
175
|
+
if (resolved) return resolved;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Resolve a linked pair (`<key>/<variant>`) against the item it attaches to: the linked-segment child
|
|
182
|
+
* (`<precedingNodeId>/~<variant>`) of `precedingNodeId`. A single expand, no BFS — a linked node is
|
|
183
|
+
* always a direct child of the item it attaches to. Matched by the variant (the `~`-stripped last
|
|
184
|
+
* segment), so it works regardless of which extension produced the node.
|
|
185
|
+
*/
|
|
186
|
+
var resolveLinked = async (builder, precedingNodeId, variant) => {
|
|
187
|
+
expand(builder.graph, precedingNodeId, "child");
|
|
188
|
+
await flush(builder);
|
|
189
|
+
const linkedSegment = `${builder.urlGrammar.linkedPrefix}${variant}`;
|
|
190
|
+
return getConnections(builder.graph, precedingNodeId, "child").find((child) => child.id.slice(child.id.lastIndexOf("/") + 1) === linkedSegment)?.id ?? null;
|
|
191
|
+
};
|
|
192
|
+
var resolveUrlAsync = async (builder, parsed) => {
|
|
193
|
+
const keyTable = buildKeyTable(builder);
|
|
194
|
+
const allExtensions = builder.getExtensions();
|
|
195
|
+
const results = [];
|
|
196
|
+
let lastItemNodeId;
|
|
197
|
+
for (let pairIndex = 0; pairIndex < parsed.pairs.length; pairIndex++) {
|
|
198
|
+
const pair = parsed.pairs[pairIndex];
|
|
199
|
+
if (pair.key === builder.urlGrammar.linkedKey) {
|
|
200
|
+
const nodeId = lastItemNodeId && pair.id ? await resolveLinked(builder, lastItemNodeId, pair.id) : null;
|
|
201
|
+
results.push(nodeId ? {
|
|
202
|
+
pairIndex,
|
|
203
|
+
nodeId
|
|
204
|
+
} : null);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const extensionIdList = keyTable.get(pair.key);
|
|
208
|
+
if (!extensionIdList || extensionIdList.length === 0) {
|
|
209
|
+
log.warn("unknown URL prefix key", { key: pair.key }, {
|
|
210
|
+
"~LogMeta": "~LogMeta",
|
|
211
|
+
F: __dxlog_file,
|
|
212
|
+
L: 274,
|
|
213
|
+
S: void 0
|
|
214
|
+
});
|
|
215
|
+
results.push(null);
|
|
216
|
+
if (pair.id !== void 0) lastItemNodeId = void 0;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const workspaceBaseId = `${RootId}/${pair.workspace}`;
|
|
220
|
+
const extensions = [];
|
|
221
|
+
for (const extensionId of extensionIdList) {
|
|
222
|
+
const url = allExtensions[extensionId]?.url;
|
|
223
|
+
if (url) extensions.push({
|
|
224
|
+
id: extensionId,
|
|
225
|
+
path: url.path
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
const nodeId = await resolveKeyId(builder, workspaceBaseId, pair.workspace, extensions, pair.id ?? pair.key);
|
|
229
|
+
results.push(nodeId ? {
|
|
230
|
+
pairIndex,
|
|
231
|
+
nodeId
|
|
232
|
+
} : null);
|
|
233
|
+
lastItemNodeId = nodeId ?? void 0;
|
|
234
|
+
}
|
|
235
|
+
return results;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Resolve a parsed URL's pair chain to graph node ids, walking left to right. Resolution is fully
|
|
239
|
+
* explicit — each keyed extension declares either a static `urlPath` template (preferred) or a dynamic
|
|
240
|
+
* `resolve` Effect (data-dependent shapes); there is no generic search. Reverse mapping still uses the
|
|
241
|
+
* provenance the builder tracks (see `GraphBuilder.getNodeExtensionId`).
|
|
242
|
+
*
|
|
243
|
+
* An unknown key, or a key whose extension produces no matching node, yields `null` at that index;
|
|
244
|
+
* how a `null` is surfaced is the caller's concern. A linked pair resolves against the *preceding
|
|
245
|
+
* item's* node, not the raw preceding pair.
|
|
246
|
+
*/
|
|
247
|
+
var resolveUrl = (builder, parsed) => Effect.promise(() => resolveUrlAsync(builder, parsed));
|
|
248
|
+
/**
|
|
249
|
+
* Reverse-map a graph node id back to its `(key, id?, workspace)` representation, the inverse of
|
|
250
|
+
* `resolveUrl`. A linked node (a `~<variant>` segment) maps to the declared `linked` key
|
|
251
|
+
* with the variant as its id — independent of the producing extension, so every linked node is
|
|
252
|
+
* addressable. Any other node maps via its producing extension's `urlKey` (`getNodeExtensionId`);
|
|
253
|
+
* a node with no key-declaring producer returns `Option.none()` (unmapped — serialization skips it
|
|
254
|
+
* with a dev-time warning one layer up, per the design's "unmapped nodes" rule).
|
|
255
|
+
*/
|
|
256
|
+
var representNode = (builder, nodeId) => {
|
|
257
|
+
const segments = nodeId.split("/");
|
|
258
|
+
const workspace = segments[1];
|
|
259
|
+
if (!workspace) return Option.none();
|
|
260
|
+
const lastSegment = segments[segments.length - 1];
|
|
261
|
+
if (lastSegment.startsWith(builder.urlGrammar.linkedPrefix)) {
|
|
262
|
+
const linkedKey = builder.urlGrammar.linkedKey;
|
|
263
|
+
if (linkedKey) return Option.some({
|
|
264
|
+
key: linkedKey,
|
|
265
|
+
id: lastSegment.slice(builder.urlGrammar.linkedPrefix.length),
|
|
266
|
+
workspace
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const extensionId = builder.getNodeExtensionId(nodeId);
|
|
270
|
+
if (!extensionId) return Option.none();
|
|
271
|
+
const url = builder.getExtensions()[extensionId]?.url;
|
|
272
|
+
if (!url) return Option.none();
|
|
273
|
+
return Option.some({
|
|
274
|
+
...urlRepresentation(nodeId, url, builder.urlGrammar.tailSeparator),
|
|
275
|
+
workspace
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
//#endregion
|
|
279
|
+
export { atoms_exports as CreateAtom, graph_exports as Graph, graph_builder_exports as GraphBuilder, node_exports as Node, node_matcher_exports as NodeMatcher, path_resolution_exports as PathResolution, getParentId, getSegmentId, qualifyId };
|
|
280
|
+
|
|
281
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/atoms.ts","../../src/path-resolution.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom';\n\nimport { type MulticastObservable } from '@dxos/async';\n\nconst observableFamily = Atom.family((observable: MulticastObservable<any>) => {\n return Atom.make((get) => {\n const subscription = observable.subscribe((value) => get.setSelf(value));\n\n get.addFinalizer(() => subscription.unsubscribe());\n\n return observable.get();\n });\n});\n\n/**\n * Creates an Atom.Atom<T> from a MulticastObservable<T>\n * Will return the same atom instance for the same observable.\n */\nexport const fromObservable = <T>(observable: MulticastObservable<T>): Atom.Atom<T> => {\n return observableFamily(observable) as Atom.Atom<T>;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Array from 'effect/Array';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Option from 'effect/Option';\nimport * as Record from 'effect/Record';\n\nimport { EffectEx } from '@dxos/effect';\nimport { EntityId, SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { Position } from '@dxos/util';\n\nimport * as Graph from './graph';\nimport * as GraphBuilder from './graph-builder';\nimport * as Node from './node';\n\n/**\n * A single `(prefix, id?)` pair as parsed by `@dxos/app-toolkit`'s `UrlPath.parse`. Kept as a\n * plain structural type here (rather than importing `UrlPath.Pair`) because app-graph must not\n * depend on app-toolkit.\n */\nexport type UrlPair = {\n key: string;\n id?: string;\n workspace: string;\n};\n\n/**\n * A resolved pair: the index it occupied in the parsed chain, and the qualified graph node id it\n * resolved to. `null` in the caller's result array means the pair didn't resolve (unknown key or\n * no matching node); how an unresolved pair is surfaced is the caller's concern.\n */\nexport type ResolvedPair = {\n pairIndex: number;\n nodeId: string;\n};\n\n/** The graph-path representation of a node, the reverse of a `UrlPair` (`id` is absent for singleton keys). */\nexport type RepresentedNode = {\n key: string;\n id?: string;\n workspace: string;\n};\n\n/** Reserved words that can never be registered as a `urlKey`, duplicated from `UrlPath.isReservedKey`\n * (rather than imported) to keep app-graph free of an app-toolkit dependency. A key declared by a\n * binding — including the `anchor` and `linked` tiers — is never reserved. */\nconst RESERVED_URL_KEYS = new Set(['reset', 'redirect', 'not-found']);\n\nconst isReservedUrlKey = (key: string): boolean =>\n RESERVED_URL_KEYS.has(key) || SpaceId.isValid(key) || EntityId.isValid(key);\n\n/**\n * Ordered `urlKey`-declaring extensions: sorted by Position then insertion order (matching\n * connector-ordering semantics elsewhere in this package), with reserved-word keys dropped (each with\n * a `log.warn`). A single key may legitimately be shared by more than one extension (e.g. plugin-space\n * declares `collection` on both the root-collection children connector and the nested-collection\n * children connector, which together address any object reachable through a space's collection tree),\n * so keys are NOT deduped here — {@link buildKeyTable} groups the sharers under one key and forward\n * resolution matches a node produced by any of them. Shared with {@link buildUrlKeyTable} so the\n * reservation rule is expressed exactly once.\n */\ntype UrlKeyedExtension = GraphBuilder.BuilderExtension & { url: GraphBuilder.UrlBinding };\n\n/** Narrows to an extension that declared a URL binding, so callers need no non-null assertion. */\nconst isUrlKeyed = (extension: GraphBuilder.BuilderExtension): extension is UrlKeyedExtension => !!extension.url?.key;\n\nconst getKeyedExtensions = (builder: GraphBuilder.GraphBuilder): UrlKeyedExtension[] => {\n const extensions = Function.pipe(Record.values(builder.getExtensions()), Array.sortBy(Position.compare));\n\n const keyed: UrlKeyedExtension[] = [];\n for (const extension of extensions) {\n if (!isUrlKeyed(extension)) {\n continue;\n }\n if (isReservedUrlKey(extension.url.key)) {\n log.warn('reserved URL prefix key', { key: extension.url.key, extension: extension.id });\n continue;\n }\n keyed.push(extension);\n }\n return keyed;\n};\n\n/**\n * Build the global `urlKey -> extensionIds` table from the builder's current extensions. Recomputed\n * on every call — cheap (a synchronous scan of already-registered extensions) and always current, so\n * activating/deactivating plugins can never leave a stale table around. A key maps to the ordered list\n * of every extension that declared it (usually one); forward resolution treats a node produced by any\n * of them as a match for the key.\n */\nconst buildKeyTable = (builder: GraphBuilder.GraphBuilder): Map<string, string[]> => {\n const table = new Map<string, string[]>();\n for (const extension of getKeyedExtensions(builder)) {\n const key = extension.url.key;\n const existing = table.get(key);\n if (existing) {\n existing.push(extension.id);\n } else {\n table.set(key, [extension.id]);\n }\n }\n return table;\n};\n\n/**\n * A single registered URL prefix key, in the shape `UrlPath.parse` expects. Kept as a plain\n * structural type here (rather than importing `UrlPath.KeyTableEntry`) because app-graph must not\n * depend on app-toolkit.\n */\nexport type UrlKeyTableEntry = { key: string; hasId: boolean; anchor: boolean };\n\n/**\n * Build the `urlKey -> { key, hasId }` table consumed by `UrlPath.parse`, straight from the\n * builder's current `urlKey`/`urlKeyHasId` declarations — the \"registration, not parser\" property\n * the URL grammar requires. Callers (the layout url-handler) pass this to `UrlPath.parse`\n * to tokenize a pathname into a pair chain.\n */\nexport const buildUrlKeyTable = (builder: GraphBuilder.GraphBuilder): Map<string, UrlKeyTableEntry> => {\n const table = new Map<string, UrlKeyTableEntry>();\n // The grammar's fixed tiers are configured on the builder, not declared by any extension: the anchor\n // rebases the chain, and the linked key addresses a `~<variant>` child of the preceding item.\n const { anchorKey, linkedKey } = builder.urlGrammar;\n if (anchorKey) {\n table.set(anchorKey, { key: anchorKey, hasId: true, anchor: true });\n }\n if (linkedKey) {\n table.set(linkedKey, { key: linkedKey, hasId: true, anchor: false });\n }\n for (const extension of getKeyedExtensions(builder)) {\n const key = extension.url.key;\n // The tokenizer's flat lookup is derived from `kind`: a singleton has no id.\n const hasId = extension.url.kind !== 'singleton';\n const anchor = false;\n const existing = table.get(key);\n if (existing && existing.hasId !== hasId) {\n // Extensions that share a key must agree on their kind — the parse table has one entry per key.\n // A mismatch is a declaration bug; keep the first and warn.\n log.warn('conflicting kind for shared URL prefix key', { key, extension: extension.id });\n continue;\n }\n table.set(key, { key, hasId, anchor });\n }\n return table;\n};\n\n/**\n * Expand every ancestor prefix of a qualified node id (including the id itself), then flush once.\n * Mirrors `@dxos/app-toolkit`'s `NotFound.expandPath` technique, reimplemented locally so app-graph\n * doesn't depend on app-toolkit.\n */\nconst expandAncestors = async (builder: GraphBuilder.GraphBuilder, qualifiedId: string): Promise<void> => {\n const segments = qualifiedId.split('/');\n for (let index = 1; index <= segments.length; index++) {\n Graph.expand(builder.graph, segments.slice(0, index).join('/'), 'child');\n }\n await GraphBuilder.flush(builder);\n};\n\n/** An extension registered for a URL key: its path (static segments or a dynamic resolver). */\ntype KeyedExtension = { id: string; path: string[] | GraphBuilder.PathResolver };\n\n/**\n * Materialize a candidate qualified node id and confirm it exists: expand its ancestors, then check\n * the node is known. Returns the id on success, `null` otherwise.\n */\nconst materializeCandidate = async (\n builder: GraphBuilder.GraphBuilder,\n candidateId: string,\n): Promise<string | null> => {\n await expandAncestors(builder, candidateId);\n return Option.isSome(Graph.getNode(builder.graph, candidateId)) ? candidateId : null;\n};\n\n/**\n * Resolve a single `(key, id)` pair to a qualified node id, anchored at the workspace base. Resolution\n * is fully explicit — no search. Each keyed extension's `path` is one of:\n * 1. Static segments (`string[]`, the preferred deterministic case): the id is the `+`-joined node\n * segments *after* the path, so a fixed-depth nested shape (e.g. `db/<slug>+<id>`) resolves with\n * no resolver — split the id back into segments and expand the exact path.\n * 2. A dynamic {@link GraphBuilder.PathResolver} (recursive/mutable shapes, i.e. nested collections),\n * whose candidate is materialized and verified the same way.\n * Static paths are tried before resolvers; an unmatched pair yields `null`.\n */\nconst resolveKeyId = async (\n builder: GraphBuilder.GraphBuilder,\n workspaceBaseId: string,\n workspace: string,\n extensions: ReadonlyArray<KeyedExtension>,\n id: string,\n): Promise<string | null> => {\n // 1. Static segments: an exact candidate, no search (type sections, database/inbox objects, etc.).\n const idSegments = id.split(builder.urlGrammar.tailSeparator);\n for (const extension of extensions) {\n if (Array.isArray(extension.path)) {\n const resolved = await materializeCandidate(\n builder,\n [workspaceBaseId, ...extension.path, ...idSegments].join('/'),\n );\n if (resolved) {\n return resolved;\n }\n }\n }\n\n // 2. Dynamic resolver: the extension computes the candidate id from runtime data (self-contained\n // Effect; a defect degrades to no candidate rather than crashing resolution).\n for (const extension of extensions) {\n if (typeof extension.path === 'function') {\n const candidateId = await EffectEx.runPromise(\n extension.path({ id, workspace, workspaceBaseId }).pipe(Effect.catchAllDefect(() => Effect.succeed(null))),\n );\n if (candidateId) {\n const resolved = await materializeCandidate(builder, candidateId);\n if (resolved) {\n return resolved;\n }\n }\n }\n }\n\n return null;\n};\n\n/**\n * Resolve a linked pair (`<key>/<variant>`) against the item it attaches to: the linked-segment child\n * (`<precedingNodeId>/~<variant>`) of `precedingNodeId`. A single expand, no BFS — a linked node is\n * always a direct child of the item it attaches to. Matched by the variant (the `~`-stripped last\n * segment), so it works regardless of which extension produced the node.\n */\nconst resolveLinked = async (\n builder: GraphBuilder.GraphBuilder,\n precedingNodeId: string,\n variant: string,\n): Promise<string | null> => {\n Graph.expand(builder.graph, precedingNodeId, 'child');\n await GraphBuilder.flush(builder);\n\n const linkedSegment = `${builder.urlGrammar.linkedPrefix}${variant}`;\n const match = Graph.getConnections(builder.graph, precedingNodeId, 'child').find(\n (child) => child.id.slice(child.id.lastIndexOf('/') + 1) === linkedSegment,\n );\n return match?.id ?? null;\n};\n\nconst resolveUrlAsync = async (\n builder: GraphBuilder.GraphBuilder,\n parsed: { workspace: string; pairs: ReadonlyArray<UrlPair> },\n): Promise<Array<ResolvedPair | null>> => {\n const keyTable = buildKeyTable(builder);\n const allExtensions = builder.getExtensions();\n const results: Array<ResolvedPair | null> = [];\n // Tracks the most recently resolved *item* node, the base for `linked` pairs — a linked pair\n // always attaches to the preceding item, never to another linked pair.\n let lastItemNodeId: string | undefined;\n\n for (let pairIndex = 0; pairIndex < parsed.pairs.length; pairIndex++) {\n const pair = parsed.pairs[pairIndex];\n\n // Linked pair: resolves against the preceding item by variant, not the workspace base — the linked\n // resolution tier. Produced by no extension (it is a grammar key), so it is matched before the key\n // table, and it is not itself an item, so it does not become the base for a following linked pair.\n if (pair.key === builder.urlGrammar.linkedKey) {\n const nodeId = lastItemNodeId && pair.id ? await resolveLinked(builder, lastItemNodeId, pair.id) : null;\n results.push(nodeId ? { pairIndex, nodeId } : null);\n continue;\n }\n\n const extensionIdList = keyTable.get(pair.key);\n if (!extensionIdList || extensionIdList.length === 0) {\n log.warn('unknown URL prefix key', { key: pair.key });\n results.push(null);\n if (pair.id !== undefined) {\n lastItemNodeId = undefined;\n }\n continue;\n }\n\n const workspaceBaseId = `${Node.RootId}/${pair.workspace}`;\n const extensions: KeyedExtension[] = [];\n for (const extensionId of extensionIdList) {\n const url = allExtensions[extensionId]?.url;\n if (url) {\n extensions.push({ id: extensionId, path: url.path });\n }\n }\n // A normal key addresses a node by id; an id-less singleton key (e.g. `home`) addresses a fixed node\n // whose terminal segment IS the key — resolve it the same way with the key standing in for the id\n // (`root/<ws>/<...path>/<key>`).\n const nodeId = await resolveKeyId(builder, workspaceBaseId, pair.workspace, extensions, pair.id ?? pair.key);\n results.push(nodeId ? { pairIndex, nodeId } : null);\n lastItemNodeId = nodeId ?? undefined;\n }\n\n return results;\n};\n\n/**\n * Resolve a parsed URL's pair chain to graph node ids, walking left to right. Resolution is fully\n * explicit — each keyed extension declares either a static `urlPath` template (preferred) or a dynamic\n * `resolve` Effect (data-dependent shapes); there is no generic search. Reverse mapping still uses the\n * provenance the builder tracks (see `GraphBuilder.getNodeExtensionId`).\n *\n * An unknown key, or a key whose extension produces no matching node, yields `null` at that index;\n * how a `null` is surfaced is the caller's concern. A linked pair resolves against the *preceding\n * item's* node, not the raw preceding pair.\n */\nexport const resolveUrl = (\n builder: GraphBuilder.GraphBuilder,\n parsed: { workspace: string; pairs: ReadonlyArray<UrlPair> },\n): Effect.Effect<Array<ResolvedPair | null>> => Effect.promise(() => resolveUrlAsync(builder, parsed));\n\n/**\n * Reverse-map a graph node id back to its `(key, id?, workspace)` representation, the inverse of\n * `resolveUrl`. A linked node (a `~<variant>` segment) maps to the declared `linked` key\n * with the variant as its id — independent of the producing extension, so every linked node is\n * addressable. Any other node maps via its producing extension's `urlKey` (`getNodeExtensionId`);\n * a node with no key-declaring producer returns `Option.none()` (unmapped — serialization skips it\n * with a dev-time warning one layer up, per the design's \"unmapped nodes\" rule).\n */\nexport const representNode = (builder: GraphBuilder.GraphBuilder, nodeId: string): Option.Option<RepresentedNode> => {\n const segments = nodeId.split('/');\n // Canonical node ids are `root/<workspace>/...`; the workspace is always the second segment.\n const workspace = segments[1];\n if (!workspace) {\n return Option.none();\n }\n\n const lastSegment = segments[segments.length - 1];\n if (lastSegment.startsWith(builder.urlGrammar.linkedPrefix)) {\n // Linked node: keyed by the grammar's `linked` key, with the variant (the `~`-stripped segment) as\n // its id — matched by the convention, independent of the producing extension.\n const linkedKey = builder.urlGrammar.linkedKey;\n if (linkedKey) {\n return Option.some({ key: linkedKey, id: lastSegment.slice(builder.urlGrammar.linkedPrefix.length), workspace });\n }\n }\n\n const extensionId = builder.getNodeExtensionId(nodeId);\n if (!extensionId) {\n return Option.none();\n }\n const url = builder.getExtensions()[extensionId]?.url;\n if (!url) {\n return Option.none();\n }\n\n // The (key, id?) representation is derived from the node id + binding (a singleton has no id; a\n // resolver-backed key keeps just the object id; a static path `+`-joins the segments after the path) —\n // the same derivation the builder uses to stamp `urlSegment`.\n return Option.some({ ...GraphBuilder.urlRepresentation(nodeId, url, builder.urlGrammar.tailSeparator), workspace });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/scheduler.ts
|
|
2
|
+
var scheduleTask = async (callback, _options) => {
|
|
3
|
+
await Promise.resolve();
|
|
4
|
+
return callback();
|
|
5
|
+
};
|
|
6
|
+
var yieldOrContinue = async (_priority) => {
|
|
7
|
+
await Promise.resolve();
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { scheduleTask, yieldOrContinue };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=scheduler.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.mjs","names":[],"sources":["../../src/scheduler.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// CF Workers / Node fallback: there is no main thread to yield to.\n// scheduleTask runs the callback on the next microtask; yieldOrContinue is a microtask hop.\n\ntype ScheduleOptions = { strategy?: 'smooth' | 'interactive' | 'idle'; signal?: AbortSignal };\n\nexport const scheduleTask = async <T>(callback: () => T | Promise<T>, _options?: ScheduleOptions): Promise<T> => {\n await Promise.resolve();\n return callback();\n};\n\nexport const yieldOrContinue = async (_priority: 'smooth' | 'interactive' | 'idle'): Promise<void> => {\n await Promise.resolve();\n};\n"],"mappings":";AASA,IAAa,eAAe,OAAU,UAAgC,aAA2C;CAC/G,MAAM,QAAQ,QAAQ;CACtB,OAAO,SAAS;AAClB;AAEA,IAAa,kBAAkB,OAAO,cAAgE;CACpG,MAAM,QAAQ,QAAQ;AACxB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { i as make, l as getNode, n as flush, s as expand, t as addExtension } from "./chunk-graph-builder.mjs";
|
|
2
|
+
import { Registry } from "@effect-atom/atom";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
4
|
+
//#region src/testing/setup-graph-builder.ts
|
|
5
|
+
var setupGraphBuilder = ({ registry = Registry.make(), extensions } = {}) => {
|
|
6
|
+
const builder = make({ registry });
|
|
7
|
+
const graph = builder.graph;
|
|
8
|
+
if (extensions) addExtension(builder, extensions);
|
|
9
|
+
return {
|
|
10
|
+
registry,
|
|
11
|
+
builder,
|
|
12
|
+
graph,
|
|
13
|
+
addExtensions: (nextExtensions) => {
|
|
14
|
+
addExtension(builder, nextExtensions);
|
|
15
|
+
},
|
|
16
|
+
expand: async (id, relation = "child") => {
|
|
17
|
+
expand(graph, id, relation);
|
|
18
|
+
await flush(builder);
|
|
19
|
+
},
|
|
20
|
+
flush: () => flush(builder),
|
|
21
|
+
getConnections: (id, relation = "child") => registry.get(graph.connections(id, relation)),
|
|
22
|
+
getNode: (id) => getNode(graph, id).pipe(Option.getOrNull)
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { setupGraphBuilder };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.mjs","names":[],"sources":["../../src/testing/setup-graph-builder.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Registry } from '@effect-atom/atom';\nimport * as Option from 'effect/Option';\n\nimport * as Graph from '../graph';\nimport * as GraphBuilder from '../graph-builder';\nimport * as Node from '../node';\n\nexport type SetupGraphBuilderOptions = {\n registry?: Registry.Registry;\n extensions?: GraphBuilder.BuilderExtensions;\n};\n\nexport const setupGraphBuilder = ({ registry = Registry.make(), extensions }: SetupGraphBuilderOptions = {}) => {\n const builder = GraphBuilder.make({ registry });\n const graph = builder.graph;\n\n if (extensions) {\n GraphBuilder.addExtension(builder, extensions);\n }\n\n return {\n registry,\n builder,\n graph,\n addExtensions: (nextExtensions: GraphBuilder.BuilderExtensions) => {\n GraphBuilder.addExtension(builder, nextExtensions);\n },\n expand: async (id: string, relation: Node.RelationInput = 'child') => {\n Graph.expand(graph, id, relation);\n await GraphBuilder.flush(builder);\n },\n flush: () => GraphBuilder.flush(builder),\n getConnections: (id: string, relation: Node.RelationInput = 'child') =>\n registry.get(graph.connections(id, relation)),\n getNode: (id: string) => Graph.getNode(graph, id).pipe(Option.getOrNull),\n };\n};\n"],"mappings":";;;;AAgBA,IAAa,qBAAqB,EAAE,WAAW,SAAS,KAAK,GAAG,eAAyC,CAAC,MAAM;CAC9G,MAAM,UAAU,KAAkB,EAAE,SAAS,CAAC;CAC9C,MAAM,QAAQ,QAAQ;CAEtB,IAAI,YACF,aAA0B,SAAS,UAAU;CAG/C,OAAO;EACL;EACA;EACA;EACA,gBAAgB,mBAAmD;GACjE,aAA0B,SAAS,cAAc;EACnD;EACA,QAAQ,OAAO,IAAY,WAA+B,YAAY;GACpE,OAAa,OAAO,IAAI,QAAQ;GAChC,MAAM,MAAmB,OAAO;EAClC;EACA,aAAa,MAAmB,OAAO;EACvC,iBAAiB,IAAY,WAA+B,YAC1D,SAAS,IAAI,MAAM,YAAY,IAAI,QAAQ,CAAC;EAC9C,UAAU,OAAe,QAAc,OAAO,EAAE,CAAC,CAAC,KAAK,OAAO,SAAS;CACzE;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atoms.d.ts","sourceRoot":"","sources":["../../../src/atoms.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"atoms.d.ts","sourceRoot":"","sources":["../../../src/atoms.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAYvD;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,cAAc,mBAAmB,CAAC,CAAC,CAAC,KAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAEjF,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Atom, Registry } from '@effect-atom/atom
|
|
1
|
+
import { Atom, Registry } from '@effect-atom/atom';
|
|
2
2
|
import * as Effect from 'effect/Effect';
|
|
3
3
|
import * as Option from 'effect/Option';
|
|
4
4
|
import * as Pipeable from 'effect/Pipeable';
|
|
@@ -6,10 +6,6 @@ import { type Type } from '@dxos/echo';
|
|
|
6
6
|
import { type MaybePromise, Position } from '@dxos/util';
|
|
7
7
|
import * as Graph from './graph';
|
|
8
8
|
import * as Node from './node';
|
|
9
|
-
/**
|
|
10
|
-
* Graph builder extension for adding nodes to the graph based on a node id.
|
|
11
|
-
*/
|
|
12
|
-
export type ResolverExtension = (id: string) => Atom.Atom<Node.NodeArg<any> | null>;
|
|
13
9
|
/**
|
|
14
10
|
* Graph builder extension for adding nodes to the graph based on a connection to an existing node.
|
|
15
11
|
*
|
|
@@ -24,14 +20,116 @@ export type ActionsExtension = (node: Atom.Atom<Option.Option<Node.Node>>) => At
|
|
|
24
20
|
* Constrained case of the connector extension for more easily adding action groups to the graph.
|
|
25
21
|
*/
|
|
26
22
|
export type ActionGroupsExtension = (node: Atom.Atom<Option.Option<Node.Node>>) => Atom.Atom<Omit<Node.NodeArg<typeof Node.actionGroupSymbol>, 'type' | 'data' | 'nodes' | 'edges'>[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Graph builder extension for adding nodes to the graph based on a node id.
|
|
25
|
+
*
|
|
26
|
+
* TODO(wittjosiah): Remove? Superseded by the declared `url` binding — URL resolution no longer
|
|
27
|
+
* materializes a node from a bare id. Retained alongside `Graph.initialize`, which fires it.
|
|
28
|
+
*/
|
|
29
|
+
export type ResolverExtension = (id: string) => Atom.Atom<Node.NodeArg<any> | null>;
|
|
27
30
|
export type BuilderExtension = Readonly<{
|
|
28
31
|
id: string;
|
|
29
32
|
position?: Position.Position;
|
|
30
33
|
relation?: Node.RelationInput;
|
|
34
|
+
/**
|
|
35
|
+
* URL binding for the nodes this extension's connector produces: the registered prefix key plus how
|
|
36
|
+
* it resolves. Omitted when the extension's nodes are not URL-addressable. See {@link UrlBinding} and
|
|
37
|
+
* `path-resolution.ts` for how the key table is derived and used.
|
|
38
|
+
*/
|
|
39
|
+
url?: UrlBinding;
|
|
31
40
|
resolver?: ResolverExtension;
|
|
32
41
|
connector?: (node: Atom.Atom<Option.Option<Node.Node>>) => Atom.Atom<Node.NodeArg<any>[]>;
|
|
33
42
|
}>;
|
|
43
|
+
/**
|
|
44
|
+
* How an extension's nodes map to (and from) the URL pair chain — one binding per extension, holding
|
|
45
|
+
* the whole URL contract for the nodes it produces. The `kind` is the *resolution tier*: what a pair
|
|
46
|
+
* with this key resolves against.
|
|
47
|
+
*
|
|
48
|
+
* - `'item'` — Resolves against the current anchor (workspace) base, addressed by a variable id.
|
|
49
|
+
* The default addressable node; may itself have children (e.g. a mailbox). (`doc/<id>`).
|
|
50
|
+
* - `'singleton'` — Resolves against the current anchor base, but is a single fixed node per anchor, so
|
|
51
|
+
* it carries no id — its terminal node-id segment is the key itself. (`settings`).
|
|
52
|
+
*
|
|
53
|
+
* The anchor and linked tiers are not declared per extension: they are fixed keys of the URL grammar,
|
|
54
|
+
* configured once on the builder as {@link UrlGrammar}.
|
|
55
|
+
*
|
|
56
|
+
* `path` is how the node is located, in one of two forms:
|
|
57
|
+
* - `string[]` — fixed ancestor node-id segments between the workspace base and the node (the common,
|
|
58
|
+
* deterministic case): the node is `${Node.RootId}/<workspace>/<...segments>/<id>`. Fixed-depth
|
|
59
|
+
* dynamic tails beyond the segments are `+`-encoded into the id.
|
|
60
|
+
* - {@link PathResolver} — a dynamic resolver, for data-dependent shapes (e.g. nested collections at
|
|
61
|
+
* arbitrary depth) that cannot declare static segments.
|
|
62
|
+
*
|
|
63
|
+
* Read by `path-resolution.ts` (which derives the parse table's `hasId`/`anchor` from `kind`) and
|
|
64
|
+
* consumed by `UrlPath.parse`.
|
|
65
|
+
*/
|
|
66
|
+
export type UrlBinding = {
|
|
67
|
+
key: string;
|
|
68
|
+
kind: 'item' | 'singleton';
|
|
69
|
+
path: string[] | PathResolver;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* The URL grammar the builder resolves and stamps against, configured once at construction.
|
|
73
|
+
*
|
|
74
|
+
* The two keys are fixed tiers no extension declares (no connector produces their nodes): `anchorKey`
|
|
75
|
+
* establishes the base that following pairs resolve against and is consumed as a rebase
|
|
76
|
+
* (`w/<workspace>`); `linkedKey` addresses the linked-segment child of the preceding item
|
|
77
|
+
* (`companion/<variant>`), resolved structurally. The separators are the id-encoding conventions:
|
|
78
|
+
* `linkedPrefix` marks a linked segment (`<parent>/~<variant>`), and `tailSeparator` joins the
|
|
79
|
+
* fixed-depth node-id segments between a key's static `path` and the object id into one URL id
|
|
80
|
+
* (`db/<slug>+<id>`) so a fixed-depth nested shape needs no resolver.
|
|
81
|
+
*/
|
|
82
|
+
export type UrlGrammar = {
|
|
83
|
+
anchorKey?: string;
|
|
84
|
+
linkedKey?: string;
|
|
85
|
+
linkedPrefix: string;
|
|
86
|
+
tailSeparator: string;
|
|
87
|
+
};
|
|
88
|
+
/** {@link UrlGrammar} as supplied at construction: the separators fall back to their defaults. */
|
|
89
|
+
export type UrlGrammarProps = Partial<UrlGrammar>;
|
|
90
|
+
/** Params passed to a {@link PathResolver} for a single `(key, id)` URL pair. */
|
|
91
|
+
export type PathResolveParams = {
|
|
92
|
+
/** The id segment from the `(key, id)` pair. */
|
|
93
|
+
id: string;
|
|
94
|
+
/** The workspace segment from the URL. */
|
|
95
|
+
workspace: string;
|
|
96
|
+
/** Qualified id of the workspace base node (`${Node.RootId}/<workspace>`). */
|
|
97
|
+
workspaceBaseId: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Dynamic forward URL resolver for an extension whose node-id shape is data-dependent and so cannot
|
|
101
|
+
* declare a static {@link UrlBinding.path}. Returns the candidate qualified node id —
|
|
102
|
+
* `path-resolution.ts` then materializes its ancestors and verifies it — or `null` if the id can't be
|
|
103
|
+
* located. Must be self-contained (the declaring plugin closes over any services it needs), so
|
|
104
|
+
* `@dxos/app-graph` stays free of service dependencies.
|
|
105
|
+
*/
|
|
106
|
+
export type PathResolver = (params: PathResolveParams) => Effect.Effect<string | null>;
|
|
34
107
|
export type BuilderExtensions = BuilderExtension | BuilderExtension[] | BuilderExtensions[];
|
|
108
|
+
/**
|
|
109
|
+
* The `(key, id?)` URL representation of a node under a given {@link UrlBinding} — the reverse of forward
|
|
110
|
+
* resolution, minus the workspace (always the node id's second segment). A singleton has no id; a
|
|
111
|
+
* resolver-backed key keeps just the object id; a static path encodes the segments between the path and
|
|
112
|
+
* the id, `+`-joined (empty when the node sits at the path — a container whose children are the items).
|
|
113
|
+
*/
|
|
114
|
+
export declare const urlRepresentation: (nodeId: string, url: UrlBinding, tailSeparator?: string) => {
|
|
115
|
+
key: string;
|
|
116
|
+
id?: string;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* A node's own URL pair segment — `/<key>[/<id>]`, with no workspace/anchor prefix — or `undefined` when
|
|
120
|
+
* the node is not addressable in its own right (a container node sitting at the binding's `path`, whose
|
|
121
|
+
* children are the addressable items). A full URL is composed by prefixing `/w/<workspace>`.
|
|
122
|
+
*/
|
|
123
|
+
export declare const nodeUrlSegment: (nodeId: string, url: UrlBinding, tailSeparator?: string) => string | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* A graph node with its computed {@link nodeUrlSegment} attached at `properties.urlSegment` when the node
|
|
126
|
+
* is URL-addressable. The core {@link Node.Node} stays URL-agnostic; this is the typed view for reading
|
|
127
|
+
* the segment — an open properties record with an explicit `urlSegment` field — mirroring how
|
|
128
|
+
* `@dxos/react-ui-menu` wraps `Node` for menu items.
|
|
129
|
+
*/
|
|
130
|
+
export type BuilderNode<TData = any> = Node.Node<TData, {
|
|
131
|
+
urlSegment?: string;
|
|
132
|
+
} & Record<string, any>>;
|
|
35
133
|
export type GraphBuilderTraverseOptions = {
|
|
36
134
|
visitor: (node: Node.Node, path: string[]) => MaybePromise<boolean | void>;
|
|
37
135
|
registry?: Registry.Registry;
|
|
@@ -50,15 +148,29 @@ export interface GraphBuilder extends Pipeable.Pipeable {
|
|
|
50
148
|
readonly [GraphBuilderTypeId]: GraphBuilderTypeId;
|
|
51
149
|
readonly graph: Graph.ExpandableGraph;
|
|
52
150
|
readonly extensions: Atom.Atom<Record<string, BuilderExtension>>;
|
|
151
|
+
/** The URL grammar this builder resolves and stamps against (separators always resolved). */
|
|
152
|
+
readonly urlGrammar: UrlGrammar;
|
|
153
|
+
/** Read the currently registered extensions synchronously (used for URL key-table derivation). */
|
|
154
|
+
getExtensions(): Record<string, BuilderExtension>;
|
|
155
|
+
/**
|
|
156
|
+
* The id of the extension whose connector produced the given node, if known. Populated as
|
|
157
|
+
* connectors materialize nodes and cleared on removal; used by `path-resolution.ts` for
|
|
158
|
+
* reverse (node → URL) mapping.
|
|
159
|
+
*/
|
|
160
|
+
getNodeExtensionId(nodeId: string): string | undefined;
|
|
53
161
|
}
|
|
162
|
+
/** Construction params: the backing graph's props plus the URL grammar's fixed keys. */
|
|
163
|
+
export type GraphBuilderProps = Pick<Graph.GraphProps, 'registry' | 'nodes' | 'edges'> & {
|
|
164
|
+
urlGrammar?: UrlGrammarProps;
|
|
165
|
+
};
|
|
54
166
|
/**
|
|
55
167
|
* Creates a new GraphBuilder instance.
|
|
56
168
|
*/
|
|
57
|
-
export declare const make: (params?:
|
|
169
|
+
export declare const make: (params?: GraphBuilderProps) => GraphBuilder;
|
|
58
170
|
/**
|
|
59
171
|
* Creates a GraphBuilder from a serialized pickle string.
|
|
60
172
|
*/
|
|
61
|
-
export declare const from: (pickle?: string, registry?: Registry.Registry) => GraphBuilder;
|
|
173
|
+
export declare const from: (pickle?: string, registry?: Registry.Registry, urlGrammar?: UrlGrammarProps) => GraphBuilder;
|
|
62
174
|
/**
|
|
63
175
|
* Add extensions to the graph builder.
|
|
64
176
|
*/
|
|
@@ -89,7 +201,7 @@ export declare const flush: (builder: GraphBuilder) => Promise<void>;
|
|
|
89
201
|
* @param params.id The unique id of the extension.
|
|
90
202
|
* @param params.relation The relation the graph is being expanded from the existing node.
|
|
91
203
|
* @param params.position Affects the order the extensions are processed in.
|
|
92
|
-
* @param params.
|
|
204
|
+
* @param params.url URL binding for the nodes this extension produces (key + resolution); see {@link UrlBinding}.
|
|
93
205
|
* @param params.connector A function to add nodes to the graph based on a connection to an existing node.
|
|
94
206
|
* @param params.actions A function to add actions to the graph based on a connection to an existing node.
|
|
95
207
|
* @param params.actionGroups A function to add action groups to the graph based on a connection to an existing node.
|
|
@@ -98,6 +210,7 @@ export type CreateExtensionRawOptions = {
|
|
|
98
210
|
id: string;
|
|
99
211
|
relation?: Node.RelationInput;
|
|
100
212
|
position?: Position.Position;
|
|
213
|
+
url?: UrlBinding;
|
|
101
214
|
resolver?: ResolverExtension;
|
|
102
215
|
connector?: ConnectorExtension;
|
|
103
216
|
actions?: ActionsExtension;
|
|
@@ -117,10 +230,15 @@ export type CreateExtensionOptions<TMatched = Node.Node, R = never> = {
|
|
|
117
230
|
id: string;
|
|
118
231
|
match: (node: Node.Node, get: Atom.Context) => Option.Option<TMatched>;
|
|
119
232
|
actions?: (matched: TMatched, get: Atom.Context) => Effect.Effect<Omit<Node.NodeArg<Node.ActionData<any>, any>, 'type'>[], never, R>;
|
|
120
|
-
|
|
233
|
+
/** Contribute dropdown action groups (each with nested `actions`) to the matched node; the group's
|
|
234
|
+
* `type`/`data` are set automatically, so returning `Node.makeActionGroup(...)` output is fine. */
|
|
235
|
+
actionGroups?: (matched: TMatched, get: Atom.Context) => Effect.Effect<Omit<Node.NodeArg<typeof Node.actionGroupSymbol>, 'type' | 'data'>[], never, R>;
|
|
121
236
|
resolver?: (id: string, get: Atom.Context) => Effect.Effect<Node.NodeArg<any, any> | null, never, R>;
|
|
237
|
+
connector?: (matched: TMatched, get: Atom.Context) => Effect.Effect<Node.NodeArg<any, any>[], never, R>;
|
|
122
238
|
relation?: Node.RelationInput;
|
|
123
239
|
position?: Position.Position;
|
|
240
|
+
/** URL binding for the nodes this extension produces (key + resolution); see {@link UrlBinding}. */
|
|
241
|
+
url?: UrlBinding;
|
|
124
242
|
};
|
|
125
243
|
/**
|
|
126
244
|
* Create a graph builder extension with simplified API.
|
|
@@ -141,6 +259,7 @@ export type CreateTypeExtensionOptions<T extends Type.AnyEntity = Type.AnyEntity
|
|
|
141
259
|
id: string;
|
|
142
260
|
type: T;
|
|
143
261
|
actions?: (object: Type.InstanceType<T>, get: Atom.Context) => Effect.Effect<Omit<Node.NodeArg<Node.ActionData<any>>, 'type'>[], never, R>;
|
|
262
|
+
actionGroups?: (object: Type.InstanceType<T>, get: Atom.Context) => Effect.Effect<Omit<Node.NodeArg<typeof Node.actionGroupSymbol>, 'type' | 'data'>[], never, R>;
|
|
144
263
|
connector?: (object: Type.InstanceType<T>, get: Atom.Context) => Effect.Effect<Node.NodeArg<any>[], never, R>;
|
|
145
264
|
relation?: Node.RelationInput;
|
|
146
265
|
position?: Position.Position;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-builder.d.ts","sourceRoot":"","sources":["../../../src/graph-builder.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"graph-builder.d.ts","sourceRoot":"","sources":["../../../src/graph-builder.ts"],"names":[],"mappings":"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"}
|