process-graph 1.0.6 → 1.1.1

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 (58) hide show
  1. package/README.md +85 -17
  2. package/dist/bin.d.ts +1 -0
  3. package/dist/bin.js +92 -0
  4. package/dist/cli.d.ts +512 -0
  5. package/dist/cli.js +3 -0
  6. package/dist/control-aDk9560d.js +294 -0
  7. package/dist/detail-panel-B1ZmMuJT.js +341 -0
  8. package/dist/dist-BpCBmnMl.js +582 -0
  9. package/dist/dist-HLlW8vgT.js +1388 -0
  10. package/dist/dist-IjrgWhHQ.js +3 -0
  11. package/dist/errors-BZe5WzCn.js +19 -0
  12. package/dist/exit-codes-0ultCqdS.js +23 -0
  13. package/dist/graphql-C1j5wQFz.d.ts +631 -0
  14. package/dist/index-CCfe0csl.d.ts +353 -0
  15. package/dist/index-CmZOswkx.d.ts +512 -0
  16. package/dist/index-CoA6vXqe.d.ts +404 -0
  17. package/dist/index-CptUHq6F.d.ts +58 -0
  18. package/dist/index-CrM5qWUA.d.ts +110 -0
  19. package/dist/index-DhbvDgK4.d.ts +1582 -0
  20. package/dist/index-DricKcyl.d.ts +421 -0
  21. package/dist/index.d.ts +111 -4
  22. package/dist/index.js +929 -5
  23. package/dist/layout-CCM-KBdp.js +307 -0
  24. package/dist/layout.d.ts +8 -0
  25. package/dist/layout.js +2 -0
  26. package/dist/node-AchI1T-K.js +40 -0
  27. package/dist/open-CyRXJ4bt.js +29 -0
  28. package/dist/parse-CuipC_2K.js +41 -0
  29. package/dist/queries-CCexJAE2.js +2202 -0
  30. package/dist/react-flow/style.css +658 -0
  31. package/dist/react-flow.d.ts +173 -0
  32. package/dist/react-flow.js +450 -0
  33. package/dist/react.d.ts +2 -0
  34. package/dist/react.js +107 -0
  35. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  36. package/dist/router-D4gtTlXm.js +188 -0
  37. package/dist/schema-CVnS6HiX.js +234 -0
  38. package/dist/selection-BW_xXWOy.js +314 -0
  39. package/dist/source/github/node.d.ts +16 -0
  40. package/dist/source/github/node.js +2 -0
  41. package/dist/source/github.d.ts +49 -0
  42. package/dist/source/github.js +201 -0
  43. package/dist/source-DRDpEA8Q.js +1316 -0
  44. package/dist/status-Bm1CGu9C.js +11 -0
  45. package/dist/store/node.d.ts +24 -0
  46. package/dist/store/node.js +2 -0
  47. package/dist/store/wasm/worker.d.ts +16 -0
  48. package/dist/store/wasm/worker.js +98 -0
  49. package/dist/store/wasm.d.ts +9 -0
  50. package/dist/store/wasm.js +11 -0
  51. package/dist/store-BcR70CaO.js +1287 -0
  52. package/dist/store.d.ts +1328 -0
  53. package/dist/store.js +238 -0
  54. package/dist/ui/style.css +351 -0
  55. package/dist/ui.d.ts +235 -0
  56. package/dist/ui.js +2 -0
  57. package/dist/validate-DF3mQZww.js +125 -0
  58. package/package.json +150 -15
@@ -0,0 +1,1287 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { a as validateOverlay, c as fragmentOperators, d as overlayStatuses, f as participantKinds, l as messageModes, p as pseudoRoles, r as overlaySchema, s as elementKinds, t as modelSchema, u as notations } from "./schema-CVnS6HiX.js";
3
+ import { t as validate } from "./validate-DF3mQZww.js";
4
+ import { r as loopTransitions } from "./control-aDk9560d.js";
5
+ import { z } from "zod";
6
+ import { and, asc, eq, inArray, sql } from "drizzle-orm";
7
+ import { index, integer, primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core";
8
+ //#region ../../core/graph/store-contract/dist/schema.js
9
+ /**
10
+ * The model's own record schemas, taken from `modelSchema` rather than restated, so what the store accepts is exactly a model or a slice of one and can never drift from it.
11
+ */
12
+ const modelShape = modelSchema.unwrap().shape;
13
+ /** The model's `activity` element: the first variant of its element union. A type test pins the order, so reordering the union is a compile error. */
14
+ const [activityElementSchema] = modelShape.elements.unwrap().element.options;
15
+ /** The name a store files a model under. Any non-empty string; the store gives it no structure. */
16
+ const modelIdSchema = z.string().min(1);
17
+ /**
18
+ * A position in the store's history. Every change to any model takes the next revision from one store-wide sequence, so revisions only grow, a model's revision is the revision of its last change, and a model deleted and saved again never reuses an earlier one.
19
+ */
20
+ const revisionSchema = z.int().positive();
21
+ /**
22
+ * An activity bound to the external record it stands for. `source` is required here, where the model leaves it optional: a bound item's identity is its source record, and the source-qualified identifier is its element id.
23
+ */
24
+ const boundActivitySchema = activityElementSchema.unwrap().extend({ source: z.string().min(1) }).refine((activity) => activity.id === activity.source, {
25
+ message: "a bound activity's id must equal its source",
26
+ path: ["id"]
27
+ }).readonly();
28
+ /** The relation kinds a store keeps beside a model, the same kinds a source reports. */
29
+ const relationKinds = [
30
+ "child-of",
31
+ "assigned-to",
32
+ "part-of"
33
+ ];
34
+ /**
35
+ * A structural link the model has no field for, kept beside it: `child-of` from a sub-task element to its parent element, `assigned-to` from an element to a person participant, `part-of` from one participant to the participant that contains it (a repository to its organisation). A relation is identified by its kind and its two ends. Relations carry no ordering, so the structural queries never treat a parent as waiting on its children.
36
+ */
37
+ const relationSchema = z.strictObject({
38
+ kind: z.enum(relationKinds),
39
+ from: z.string().min(1),
40
+ to: z.string().min(1)
41
+ }).readonly();
42
+ /**
43
+ * Items read from a source, to be merged into a stored model by identifier. Each participant, activity and transition replaces the one with the same id or is appended after the existing ones; the overlay's entries replace the run state of the elements they name; each relation not already stored is appended. Everything else in the model is left as it is.
44
+ */
45
+ const boundItemsSchema = z.strictObject({
46
+ participants: z.array(modelShape.participants.unwrap().element).readonly(),
47
+ activities: z.array(boundActivitySchema).readonly(),
48
+ transitions: z.array(modelShape.transitions.unwrap().element).readonly(),
49
+ overlay: overlaySchema,
50
+ relations: z.array(relationSchema).readonly().exactOptional()
51
+ }).readonly();
52
+ /** One stored model and the run state laid over it, at the revision of its last change. */
53
+ const storedModelSchema = z.strictObject({
54
+ modelId: modelIdSchema,
55
+ revision: revisionSchema,
56
+ model: modelSchema,
57
+ overlay: overlaySchema
58
+ }).readonly();
59
+ /** A stored model's name and the revision of its last change. */
60
+ const modelSummarySchema = z.strictObject({
61
+ modelId: modelIdSchema,
62
+ revision: revisionSchema
63
+ }).readonly();
64
+ /** An element reached by a traversal and its distance from the start, in transitions. */
65
+ const reachSchema = z.strictObject({
66
+ element: z.string(),
67
+ distance: z.int().positive()
68
+ }).readonly();
69
+ /** The kinds of change a store reports. */
70
+ const changeKinds = [
71
+ "saved",
72
+ "overlay",
73
+ "items",
74
+ "deleted"
75
+ ];
76
+ /**
77
+ * A change to a model. `revision` is the revision the change took. `missed` says the subscriber missed one or more changes and should load the model again: it is sent at the start of a subscription that names a revision the model is no longer at (the model changed, or has gone), and in place of the changes a subscriber that reads too slowly has let pile up beyond its subscription's capacity.
78
+ */
79
+ const storeChangeSchema = z.union([z.strictObject({
80
+ modelId: modelIdSchema,
81
+ kind: z.enum(changeKinds),
82
+ revision: revisionSchema
83
+ }).readonly(), z.strictObject({
84
+ modelId: modelIdSchema,
85
+ kind: z.literal("missed")
86
+ }).readonly()]);
87
+ /** A structural issue in a model or overlay, as `validate` and `validateOverlay` report it. */
88
+ const issueSchema = z.strictObject({
89
+ code: z.string(),
90
+ message: z.string()
91
+ }).readonly();
92
+ //#endregion
93
+ //#region ../../core/graph/store-contract/dist/errors.js
94
+ /**
95
+ * The one error a `GraphStore` implementation throws for an expected failure. `createGraphStoreRouter` turns it into the contract's typed oRPC error, so every store reports failures the same way over every transport.
96
+ */
97
+ var GraphStoreError = class extends Error {
98
+ /** What went wrong. */
99
+ failure;
100
+ /**
101
+ * @param failure - What went wrong.
102
+ */
103
+ constructor(failure) {
104
+ super(failure.kind === "not-found" ? failure.element === void 0 ? `No model "${failure.modelId}"` : `Model "${failure.modelId}" has no element "${failure.element}"` : `Invalid change: ${failure.issues.map((issue) => issue.message).join("; ")}`);
105
+ this.name = "GraphStoreError";
106
+ this.failure = failure;
107
+ }
108
+ };
109
+ //#endregion
110
+ //#region ../../core/graph/store-contract/dist/feed.js
111
+ /**
112
+ * How many undelivered changes a subscription holds by default before it collapses them into `missed`.
113
+ *
114
+ * A change tells a subscriber only that its model has moved on to a later revision, and the one thing a subscriber can do about it is read the model again. A subscriber that has not yet taken one pending change will read the model after that change, and the model it reads already reflects every later one, so a second pending change gives it nothing it could act on: one held change is all a lagging subscriber can use. A subscriber that is waiting when a change commits receives it directly and never touches the buffer, so a subscriber that keeps reading misses nothing at this capacity.
115
+ */
116
+ const defaultSubscriptionCapacity = 1;
117
+ /** Checks a capacity is a positive integer, since a subscription must be able to hold the `missed` it reports. */
118
+ const checkedCapacity = (capacity) => {
119
+ if (!Number.isInteger(capacity) || capacity < 1) throw new RangeError(`A subscription capacity must be a positive integer, not ${capacity}`);
120
+ return capacity;
121
+ };
122
+ /**
123
+ * Fans the changes one store makes out to every subscriber of the model they touch. A store publishes after each committed write; the router reads a subscription for `changes`.
124
+ *
125
+ * A subscription is registered the moment `subscribe` returns, so a caller can subscribe first and then read the current revision without missing a change made in between. A change that arrives while the subscriber is waiting is handed straight to it; one that arrives while it is busy is held, up to the subscription's capacity. Past that, the held changes are replaced by a single `missed` event: memory stays bounded however slowly a subscriber reads, and a subscriber is never left unaware that it fell behind.
126
+ *
127
+ * A feed only sees the writes made through the store that owns it. Several processes or tabs writing to one database each need their own bridge (a `BroadcastChannel`, a database notification) that publishes the others' changes into their feed.
128
+ */
129
+ var ChangeFeed = class {
130
+ #listeners = /* @__PURE__ */ new Map();
131
+ #capacity;
132
+ /**
133
+ * @param options - The capacity every subscription gets unless it sets its own.
134
+ * @throws RangeError when the capacity is not a positive integer.
135
+ */
136
+ constructor(options = {}) {
137
+ this.#capacity = checkedCapacity(options.capacity ?? 1);
138
+ }
139
+ /**
140
+ * Delivers a change to every current subscriber of its model.
141
+ * @param change - The change, after it is committed.
142
+ */
143
+ publish(change) {
144
+ for (const listener of this.#listeners.get(change.modelId) ?? []) listener(change);
145
+ }
146
+ /**
147
+ * Subscribes to one model's changes from now on.
148
+ * @param modelId - The model to follow.
149
+ * @param options - The signal that ends it, and a capacity overriding the feed's.
150
+ * @returns The live subscription.
151
+ * @throws RangeError when the capacity is not a positive integer.
152
+ */
153
+ subscribe(modelId, options = {}) {
154
+ const { signal } = options;
155
+ const capacity = checkedCapacity(options.capacity ?? this.#capacity);
156
+ let buffered = [];
157
+ let waiting;
158
+ let closed = false;
159
+ const listeners = this.#listeners.get(modelId) ?? /* @__PURE__ */ new Set();
160
+ this.#listeners.set(modelId, listeners);
161
+ const finished = {
162
+ done: true,
163
+ value: void 0
164
+ };
165
+ const listener = (change) => {
166
+ if (waiting === void 0) buffered = buffered.length < capacity ? [...buffered, change] : [{
167
+ modelId,
168
+ kind: "missed"
169
+ }];
170
+ else {
171
+ waiting({
172
+ done: false,
173
+ value: change
174
+ });
175
+ waiting = void 0;
176
+ }
177
+ };
178
+ const close = () => {
179
+ if (closed) return;
180
+ closed = true;
181
+ listeners.delete(listener);
182
+ if (listeners.size === 0) this.#listeners.delete(modelId);
183
+ signal?.removeEventListener("abort", close);
184
+ waiting?.(finished);
185
+ waiting = void 0;
186
+ };
187
+ listeners.add(listener);
188
+ signal?.addEventListener("abort", close);
189
+ if (signal?.aborted === true) close();
190
+ const iterator = {
191
+ next: async () => {
192
+ const [change, ...rest] = buffered;
193
+ buffered = rest;
194
+ if (change !== void 0) return {
195
+ done: false,
196
+ value: change
197
+ };
198
+ if (closed) return finished;
199
+ return new Promise((resolve) => {
200
+ waiting = resolve;
201
+ });
202
+ },
203
+ return: async () => {
204
+ close();
205
+ return Promise.resolve(finished);
206
+ }
207
+ };
208
+ return {
209
+ close,
210
+ [Symbol.asyncIterator]: () => iterator
211
+ };
212
+ }
213
+ };
214
+ //#endregion
215
+ //#region ../../core/graph/store-contract/dist/merge.js
216
+ /** A model with nothing in it, which `items.upsert` starts from when the model does not exist yet. */
217
+ const emptyModel = {
218
+ participants: [],
219
+ events: [],
220
+ actions: [],
221
+ artefacts: [],
222
+ elements: [],
223
+ transitions: [],
224
+ fragments: [],
225
+ projections: []
226
+ };
227
+ /** Replaces each record of `current` that an incoming record shares an id with, in place, and appends the rest in their incoming order. */
228
+ const upsertById = (current, incoming) => {
229
+ const replacements = new Map(incoming.map((record) => [record.id, record]));
230
+ const known = new Set(current.map(({ id }) => id));
231
+ return [...current.map((record) => replacements.get(record.id) ?? record), ...incoming.filter(({ id }) => !known.has(id))];
232
+ };
233
+ /**
234
+ * Merges items read from a source into a model and its overlay: participants, activities and transitions by id, replacing a record in its place or appending a new one; overlay entries replace the run state of the elements they name. The result is not checked; see `checkStored`.
235
+ * @param model - The stored model.
236
+ * @param overlay - The stored overlay.
237
+ * @param items - The items to merge.
238
+ * @returns The merged model and overlay.
239
+ */
240
+ const mergeBoundItems = (model, overlay, items) => ({
241
+ model: {
242
+ ...model,
243
+ participants: upsertById(model.participants, items.participants),
244
+ elements: upsertById(model.elements, items.activities),
245
+ transitions: upsertById(model.transitions, items.transitions)
246
+ },
247
+ overlay: {
248
+ ...overlay,
249
+ ...items.overlay
250
+ }
251
+ });
252
+ /**
253
+ * Keeps only the overlay entries that name an element of the model, so replacing a model drops the run state of elements it no longer declares.
254
+ * @param model - The model the overlay is for.
255
+ * @param overlay - The overlay to narrow.
256
+ * @returns The entries whose key is an element of `model`.
257
+ */
258
+ const overlayWithin = (model, overlay) => {
259
+ const elements = new Set(model.elements.map(({ id }) => id));
260
+ return Object.fromEntries(Object.entries(overlay).filter(([id]) => elements.has(id)));
261
+ };
262
+ /**
263
+ * Checks a model and overlay a write is about to store. Every store runs this before committing, so a store never holds a model `validate` rejects or an overlay entry for an element the model does not declare.
264
+ * @param model - The model to store.
265
+ * @param overlay - The overlay to store with it.
266
+ * @throws GraphStoreError with `invalid` and every issue found, when there is any.
267
+ */
268
+ const checkStored = (model, overlay) => {
269
+ const issues = [...validate(model), ...validateOverlay(model, overlay)];
270
+ if (issues.length > 0) throw new GraphStoreError({
271
+ kind: "invalid",
272
+ issues
273
+ });
274
+ };
275
+ //#endregion
276
+ //#region ../../core/graph/store-contract/dist/hierarchy.js
277
+ /** Which identifier space each end of a relation of each kind names: a sub-task and its parent are elements, an assignee and a containing organisation are participants. */
278
+ const endpoints = {
279
+ "child-of": {
280
+ from: "element",
281
+ to: "element"
282
+ },
283
+ "assigned-to": {
284
+ from: "element",
285
+ to: "participant"
286
+ },
287
+ "part-of": {
288
+ from: "participant",
289
+ to: "participant"
290
+ }
291
+ };
292
+ /** The identity of a relation: one relation of a kind between two identifiers, however often it is reported. */
293
+ const relationKey = (relation) => JSON.stringify([
294
+ relation.kind,
295
+ relation.from,
296
+ relation.to
297
+ ]);
298
+ /**
299
+ * Adds relations to a stored list: one already there is kept in its place, and a new one is appended in its incoming order, each distinct relation once.
300
+ * @param current - The stored relations.
301
+ * @param incoming - The relations to add.
302
+ * @returns The merged relations.
303
+ */
304
+ const mergeRelations = (current, incoming) => {
305
+ return [...new Map([...current, ...incoming].map((relation) => [relationKey(relation), relation])).values()];
306
+ };
307
+ /** The identifiers a model declares in each space a relation can name. */
308
+ const spacesOf = (model) => ({
309
+ element: new Set(model.elements.map(({ id }) => id)),
310
+ participant: new Set(model.participants.map(({ id }) => id))
311
+ });
312
+ /**
313
+ * Keeps only the relations both of whose ends the model still declares, in the space their kind names, so replacing a model drops the relations of what it no longer has.
314
+ * @param model - The model the relations are for.
315
+ * @param relations - The relations to narrow.
316
+ * @returns The relations whose ends are both declared.
317
+ */
318
+ const relationsWithin = (model, relations) => {
319
+ const spaces = spacesOf(model);
320
+ return relations.filter((relation) => spaces[endpoints[relation.kind].from].has(relation.from) && spaces[endpoints[relation.kind].to].has(relation.to));
321
+ };
322
+ /**
323
+ * The issues with a model's relations: an end that names nothing the model declares in the space its kind requires is an `unknown-reference`, as an unknown reference anywhere else in a model is.
324
+ * @param model - The model the relations are for.
325
+ * @param relations - The relations to check.
326
+ * @returns One issue per end that names nothing, empty when every end resolves.
327
+ */
328
+ const relationIssues = (model, relations) => {
329
+ const spaces = spacesOf(model);
330
+ return relations.flatMap((relation) => ["from", "to"].flatMap((end) => {
331
+ const space = endpoints[relation.kind][end];
332
+ const id = relation[end];
333
+ return spaces[space].has(id) ? [] : [{
334
+ code: "unknown-reference",
335
+ message: `${relation.kind} relation ${end} refers to unknown ${space} id "${id}"`
336
+ }];
337
+ }));
338
+ };
339
+ /**
340
+ * Orders elements by their position in the model. Every element a hierarchy query reports is the end of a stored `child-of` relation, which `relationIssues` has checked the model declares.
341
+ * @throws Error for an element the model does not declare, which only a store that skipped that check can cause.
342
+ */
343
+ const byModelOrder = (model) => {
344
+ const order = new Map(model.elements.map(({ id }, index) => [id, index]));
345
+ const positionOf = (element) => {
346
+ const position = order.get(element);
347
+ if (position === void 0) throw new Error(`No element "${element}" in the model`);
348
+ return position;
349
+ };
350
+ return (left, right) => positionOf(left) - positionOf(right);
351
+ };
352
+ /**
353
+ * Breadth-first walk along `child-of` relations from `start`, with the fewest steps it takes to reach each element, by that distance and then model order. `start` itself is never reported, so a cycle of `child-of` relations through it ends the walk.
354
+ */
355
+ const walk$1 = (model, relations, start, direction) => {
356
+ const next = /* @__PURE__ */ new Map();
357
+ for (const { kind, from, to } of relations) if (kind === "child-of") {
358
+ const [key, value] = direction === "down" ? [to, from] : [from, to];
359
+ next.set(key, [...next.get(key) ?? [], value]);
360
+ }
361
+ const compare = byModelOrder(model);
362
+ const distance = /* @__PURE__ */ new Map([[start, 0]]);
363
+ let frontier = [start];
364
+ for (let depth = 1; frontier.length > 0; depth += 1) {
365
+ const reached = [...new Set(frontier.flatMap((element) => next.get(element) ?? []))].filter((element) => !distance.has(element));
366
+ for (const element of reached) distance.set(element, depth);
367
+ frontier = reached;
368
+ }
369
+ distance.delete(start);
370
+ return [...distance].map(([element, steps]) => ({
371
+ element,
372
+ distance: steps
373
+ })).sort((left, right) => left.distance - right.distance || compare(left.element, right.element));
374
+ };
375
+ /**
376
+ * The direct children of an element: every element related to it by `child-of`.
377
+ * @param model - The model, which declares `element`.
378
+ * @param relations - The model's relations.
379
+ * @param element - The parent.
380
+ * @returns The children, in model order.
381
+ */
382
+ const childrenOf = (model, relations, element) => [...new Set(relations.filter(({ kind, to }) => kind === "child-of" && to === element).map(({ from }) => from))].filter((child) => child !== element).sort(byModelOrder(model));
383
+ /**
384
+ * Everything beneath an element: its children, their children and so on, each with the fewest `child-of` steps between them.
385
+ * @param model - The model, which declares `element`.
386
+ * @param relations - The model's relations.
387
+ * @param element - The element at the top.
388
+ * @returns The descendants, by distance and then model order.
389
+ */
390
+ const descendantsOf = (model, relations, element) => walk$1(model, relations, element, "down");
391
+ /**
392
+ * Everything above an element: its parents, their parents and so on, nearest first.
393
+ * @param model - The model, which declares `element`.
394
+ * @param relations - The model's relations.
395
+ * @param element - The element at the bottom.
396
+ * @returns The ancestors, by distance and then model order.
397
+ */
398
+ const ancestorsOf = (model, relations, element) => walk$1(model, relations, element, "up");
399
+ //#endregion
400
+ //#region ../../adapters/graph/store-sqlite/dist/database.js
401
+ /**
402
+ * Runs steps one after another, each starting once the one before has finished: the statements of one transaction, which must not overlap on a connection.
403
+ * @param steps - The steps, in order.
404
+ */
405
+ const sequentially = async (steps) => {
406
+ await steps.reduce(async (previous, step) => {
407
+ await previous;
408
+ return step();
409
+ }, Promise.resolve());
410
+ };
411
+ /**
412
+ * Runs work inside one immediate transaction: committed when the work resolves, rolled back when it throws, and the error rethrown.
413
+ *
414
+ * The transaction is opened with plain statements rather than Drizzle's `transaction`, whose callback must be synchronous on a synchronous driver and asynchronous on an async one. The caller must hold the connection exclusively for the duration, so no other work interleaves between the statements.
415
+ * @param db - The database.
416
+ * @param work - The work to run.
417
+ * @returns What the work returns.
418
+ */
419
+ const inTransaction = async (db, work) => {
420
+ await db.run(sql`BEGIN IMMEDIATE`);
421
+ try {
422
+ const result = await work();
423
+ await db.run(sql`COMMIT`);
424
+ return result;
425
+ } catch (error) {
426
+ await db.run(sql`ROLLBACK`);
427
+ throw error;
428
+ }
429
+ };
430
+ /**
431
+ * An `Exclusive` for one process: operations wait for the one before to settle, in call order.
432
+ * @returns The serialiser.
433
+ */
434
+ const serialised = () => {
435
+ let tail = Promise.resolve();
436
+ return async (operation) => {
437
+ const result = tail.then(operation);
438
+ tail = result.then(() => void 0, () => void 0);
439
+ return result;
440
+ };
441
+ };
442
+ //#endregion
443
+ //#region ../../adapters/graph/store-sqlite/dist/generated/migrations.js
444
+ const migrations = [{
445
+ "sql": [
446
+ "CREATE TABLE `actions` (\n `model_id` text NOT NULL,\n `id` text NOT NULL,\n `position` integer NOT NULL,\n `name` text NOT NULL,\n CONSTRAINT `actions_pk` PRIMARY KEY(`model_id`, `id`)\n);\n",
447
+ "\nCREATE TABLE `artefacts` (\n `model_id` text NOT NULL,\n `id` text NOT NULL,\n `position` integer NOT NULL,\n `name` text NOT NULL,\n `deliverable` integer,\n CONSTRAINT `artefacts_pk` PRIMARY KEY(`model_id`, `id`)\n);\n",
448
+ "\nCREATE TABLE `elements` (\n `model_id` text NOT NULL,\n `id` text NOT NULL,\n `position` integer NOT NULL,\n `kind` text NOT NULL,\n `label` text,\n `actor` text,\n `action` text,\n `source` text,\n `affects` text,\n `consumes` text,\n `produces` text,\n `parent` text,\n `entry` text,\n `exit` text,\n `role` text,\n `from_actor` text,\n `to_actor` text,\n `mode` text,\n `event` text,\n `extensions` text,\n CONSTRAINT `elements_pk` PRIMARY KEY(`model_id`, `id`)\n);\n",
449
+ "\nCREATE TABLE `events` (\n `model_id` text NOT NULL,\n `id` text NOT NULL,\n `position` integer NOT NULL,\n `name` text NOT NULL,\n `payload` text,\n CONSTRAINT `events_pk` PRIMARY KEY(`model_id`, `id`)\n);\n",
450
+ "\nCREATE TABLE `fragments` (\n `model_id` text NOT NULL,\n `id` text NOT NULL,\n `position` integer NOT NULL,\n `operator` text NOT NULL,\n `operands` text NOT NULL,\n CONSTRAINT `fragments_pk` PRIMARY KEY(`model_id`, `id`)\n);\n",
451
+ "\nCREATE TABLE `models` (\n `id` text PRIMARY KEY,\n `revision` integer NOT NULL,\n `views` text\n);\n",
452
+ "\nCREATE TABLE `overlay` (\n `model_id` text NOT NULL,\n `element` text NOT NULL,\n `status` text NOT NULL,\n CONSTRAINT `overlay_pk` PRIMARY KEY(`model_id`, `element`)\n);\n",
453
+ "\nCREATE TABLE `participants` (\n `model_id` text NOT NULL,\n `id` text NOT NULL,\n `position` integer NOT NULL,\n `label` text NOT NULL,\n `kind` text NOT NULL,\n CONSTRAINT `participants_pk` PRIMARY KEY(`model_id`, `id`)\n);\n",
454
+ "\nCREATE TABLE `projections` (\n `model_id` text NOT NULL,\n `position` integer NOT NULL,\n `id` text NOT NULL,\n `notation` text NOT NULL,\n `subject` text,\n `scenario` text,\n CONSTRAINT `projections_pk` PRIMARY KEY(`model_id`, `position`)\n);\n",
455
+ "\nCREATE TABLE `sequences` (\n `name` text PRIMARY KEY,\n `value` integer NOT NULL\n);\n",
456
+ "\nCREATE TABLE `transitions` (\n `model_id` text NOT NULL,\n `id` text NOT NULL,\n `position` integer NOT NULL,\n `source` text NOT NULL,\n `target` text NOT NULL,\n `trigger` text,\n `guard` text,\n `condition` text,\n `effect` text,\n `loop` integer NOT NULL,\n CONSTRAINT `transitions_pk` PRIMARY KEY(`model_id`, `id`)\n);\n",
457
+ "\nCREATE INDEX `transitions_by_target` ON `transitions` (`model_id`,`target`);",
458
+ "\nCREATE INDEX `transitions_by_source` ON `transitions` (`model_id`,`source`);"
459
+ ],
460
+ "bps": true,
461
+ "folderMillis": 1791646949e3,
462
+ "hash": "78b8523685396fc94dd78dccb22bc64697fc985a1be4e398b34e86af9f2b9bd3",
463
+ "name": "20261010154229_init"
464
+ }, {
465
+ "sql": ["CREATE TABLE `relations` (\n `model_id` text NOT NULL,\n `kind` text NOT NULL,\n `from_id` text NOT NULL,\n `to_id` text NOT NULL,\n `position` integer NOT NULL,\n CONSTRAINT `relations_pk` PRIMARY KEY(`model_id`, `kind`, `from_id`, `to_id`)\n);\n", "\nCREATE INDEX `relations_by_to` ON `relations` (`model_id`,`kind`,`to_id`);"],
466
+ "bps": true,
467
+ "folderMillis": 1791685834e3,
468
+ "hash": "441d05be00056c89f041364a03d9068c26d7a277538cf0561ae0fe198daecafc",
469
+ "name": "20261011023034_relations"
470
+ }];
471
+ //#endregion
472
+ //#region ../../adapters/graph/store-sqlite/dist/migrate.js
473
+ /** The journal table drizzle's own migrators keep, so a database migrated here is one drizzle-kit recognises, and the reverse. */
474
+ const journal = "__drizzle_migrations";
475
+ const appliedRow = z.tuple([z.string().nullable()]);
476
+ /**
477
+ * Brings a database up to the package's schema by applying, in one transaction, every embedded drizzle-kit migration its journal does not name, and recording each in drizzle's `__drizzle_migrations` journal with the name, hash and folder time drizzle's own migrators record. A migration is matched by name, as drizzle's `getMigrationsToRun` matches it.
478
+ *
479
+ * Drizzle's migrators cannot serve every runtime: `drizzle-orm/migrator` reads the migrations folder through `node:fs`, and `migrateAsync` reads its journal in object mode, which the `sqlite-proxy` session refuses. This one reads the journal through `values`, which every async SQLite driver answers, and takes the migrations from the package itself, so a Node process and a browser worker apply exactly the same statements.
480
+ * @param db - The database to migrate. The caller holds it exclusively for the duration.
481
+ * @param options - What to apply and how to stamp it.
482
+ */
483
+ const migrate = async (db, options = {}) => {
484
+ const { migrations: available = migrations, now = () => /* @__PURE__ */ new Date() } = options;
485
+ await db.run(sql`CREATE TABLE IF NOT EXISTS ${sql.identifier(journal)} (id INTEGER PRIMARY KEY, hash text NOT NULL, created_at numeric, name text, applied_at TEXT)`);
486
+ const applied = new Set((await db.values(sql`SELECT name FROM ${sql.identifier(journal)}`)).map((row) => appliedRow.parse(row)[0]));
487
+ const pending = available.filter(({ name }) => !applied.has(name));
488
+ if (pending.length === 0) return;
489
+ await inTransaction(db, async () => sequentially(pending.flatMap((migration) => [...migration.sql.map((statement) => sql.raw(statement)), sql`INSERT INTO ${sql.identifier(journal)} ("hash", "created_at", "name", "applied_at") VALUES (${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${now().toISOString()})`]).map((statement) => async () => {
490
+ await db.run(statement);
491
+ })));
492
+ };
493
+ //#endregion
494
+ //#region ../../adapters/graph/store-sqlite/dist/queries.js
495
+ /** The element kinds the queries pass through and never report. */
496
+ const control = sql`('decision', 'pseudo')`;
497
+ /** Whether the overlay records `element` (an SQL expression) as done in `modelId`. */
498
+ const isDone = (modelId, element) => sql`EXISTS (SELECT 1 FROM overlay o WHERE o.model_id = ${modelId} AND o.element = ${element} AND o.status = 'done')`;
499
+ const reachRow = z.tuple([z.string(), z.number().int().positive()]);
500
+ const idRow = z.tuple([z.string()]);
501
+ const upstream = {
502
+ from: sql.raw("target"),
503
+ to: sql.raw("source")
504
+ };
505
+ const downstream = {
506
+ from: sql.raw("source"),
507
+ to: sql.raw("target")
508
+ };
509
+ /**
510
+ * Every element not done and not a control element reachable from `element` along non-loop transitions in one direction, expanding only elements that are not done, with the fewest transitions it takes, by that distance and then model order.
511
+ *
512
+ * Distances are capped at the model's element count: no shortest path is longer, and the cap ends the recursion on a model whose transitions cycle without a decision.
513
+ */
514
+ const walk = async (db, { modelId, element }, { from, to }) => {
515
+ return (await db.values(sql`
516
+ WITH RECURSIVE
517
+ bound(n) AS (SELECT count(*) FROM elements WHERE model_id = ${modelId}),
518
+ walk(element, distance) AS (
519
+ SELECT t.${to}, 1 FROM transitions t
520
+ WHERE t.model_id = ${modelId} AND t.${from} = ${element} AND t.loop = 0
521
+ UNION
522
+ SELECT t.${to}, w.distance + 1 FROM walk w
523
+ JOIN transitions t ON t.model_id = ${modelId} AND t.${from} = w.element AND t.loop = 0
524
+ WHERE w.distance < (SELECT n FROM bound)
525
+ AND NOT ${isDone(modelId, sql`w.element`)}
526
+ )
527
+ SELECT w.element, min(w.distance) AS distance
528
+ FROM walk w
529
+ JOIN elements e ON e.model_id = ${modelId} AND e.id = w.element
530
+ WHERE w.element <> ${element}
531
+ AND e.kind NOT IN ${control}
532
+ AND NOT ${isDone(modelId, sql`w.element`)}
533
+ GROUP BY w.element, e.position
534
+ ORDER BY distance, e.position
535
+ `)).map((row) => {
536
+ const [reached, distance] = reachRow.parse(row);
537
+ return {
538
+ element: reached,
539
+ distance
540
+ };
541
+ });
542
+ };
543
+ /**
544
+ * The unfinished work upstream of an element; nothing when the element is done.
545
+ * @param db - The database.
546
+ * @param request - The model and the element, which the caller has checked exist.
547
+ * @returns The chain, by distance and then model order.
548
+ */
549
+ const blockedChain = async (db, request) => {
550
+ const [done] = await db.values(sql`SELECT ${isDone(request.modelId, sql`${request.element}`)}`);
551
+ return z.tuple([z.number()]).parse(done)[0] === 1 ? [] : walk(db, request, upstream);
552
+ };
553
+ /**
554
+ * The unfinished work downstream of an element, whatever its own state.
555
+ * @param db - The database.
556
+ * @param request - The model and the element, which the caller has checked exist.
557
+ * @returns The impacted elements, by distance and then model order.
558
+ */
559
+ const impact = async (db, request) => walk(db, request, downstream);
560
+ /**
561
+ * The work that can start now: every element that is not a control element, whose run state is absent or `open`, and from which no unfinished work is reachable upstream through control elements that are not done. That is exactly "its blocked chain is empty": the first unfinished work on any upstream path is reached through control elements alone.
562
+ * @param db - The database.
563
+ * @param modelId - The model, which the caller has checked exists.
564
+ * @returns The ready elements, in model order.
565
+ */
566
+ const ready = async (db, modelId) => {
567
+ return (await db.values(sql`
568
+ WITH RECURSIVE
569
+ behind(start, element) AS (
570
+ SELECT t.target, t.source FROM transitions t
571
+ WHERE t.model_id = ${modelId} AND t.loop = 0
572
+ UNION
573
+ SELECT b.start, t.source FROM behind b
574
+ JOIN elements c ON c.model_id = ${modelId} AND c.id = b.element AND c.kind IN ${control}
575
+ JOIN transitions t ON t.model_id = ${modelId} AND t.target = b.element AND t.loop = 0
576
+ WHERE NOT ${isDone(modelId, sql`b.element`)}
577
+ )
578
+ SELECT e.id FROM elements e
579
+ WHERE e.model_id = ${modelId}
580
+ AND e.kind NOT IN ${control}
581
+ AND NOT EXISTS (
582
+ SELECT 1 FROM overlay o
583
+ WHERE o.model_id = ${modelId} AND o.element = e.id AND o.status IN ('done', 'unknown')
584
+ )
585
+ AND NOT EXISTS (
586
+ SELECT 1 FROM behind b
587
+ JOIN elements p ON p.model_id = ${modelId} AND p.id = b.element
588
+ WHERE b.start = e.id
589
+ AND p.kind NOT IN ${control}
590
+ AND NOT ${isDone(modelId, sql`b.element`)}
591
+ )
592
+ ORDER BY e.position
593
+ `)).map((row) => idRow.parse(row)[0]);
594
+ };
595
+ /** Which way a hierarchy walk follows `child-of` relations: from a parent (`to_id`) to its children (`from_id`), or from a child to its parents. */
596
+ const down = {
597
+ from: sql.raw("to_id"),
598
+ to: sql.raw("from_id")
599
+ };
600
+ const up = {
601
+ from: sql.raw("from_id"),
602
+ to: sql.raw("to_id")
603
+ };
604
+ /**
605
+ * Every element reachable from `element` along `child-of` relations in one direction, with the fewest relations it takes, by that distance and then model order. The element itself is never reported.
606
+ *
607
+ * Distances are capped at the model's element count: no shortest path is longer, and the cap ends the recursion on a cycle of `child-of` relations.
608
+ */
609
+ const hierarchyWalk = async (db, { modelId, element }, { from, to }) => {
610
+ return (await db.values(sql`
611
+ WITH RECURSIVE
612
+ bound(n) AS (SELECT count(*) FROM elements WHERE model_id = ${modelId}),
613
+ walk(element, distance) AS (
614
+ SELECT r.${to}, 1 FROM relations r
615
+ WHERE r.model_id = ${modelId} AND r.kind = 'child-of' AND r.${from} = ${element}
616
+ UNION
617
+ SELECT r.${to}, w.distance + 1 FROM walk w
618
+ JOIN relations r ON r.model_id = ${modelId} AND r.kind = 'child-of' AND r.${from} = w.element
619
+ WHERE w.distance < (SELECT n FROM bound)
620
+ )
621
+ SELECT w.element, min(w.distance) AS distance
622
+ FROM walk w
623
+ JOIN elements e ON e.model_id = ${modelId} AND e.id = w.element
624
+ WHERE w.element <> ${element}
625
+ GROUP BY w.element, e.position
626
+ ORDER BY distance, e.position
627
+ `)).map((row) => {
628
+ const [reached, distance] = reachRow.parse(row);
629
+ return {
630
+ element: reached,
631
+ distance
632
+ };
633
+ });
634
+ };
635
+ /**
636
+ * The direct children of an element: every element related to it by `child-of`, other than itself.
637
+ * @param db - The database.
638
+ * @param request - The model and the element, which the caller has checked exist.
639
+ * @returns The children, in model order.
640
+ */
641
+ const children = async (db, request) => {
642
+ const { modelId, element } = request;
643
+ return (await db.values(sql`
644
+ SELECT r.from_id FROM relations r
645
+ JOIN elements e ON e.model_id = ${modelId} AND e.id = r.from_id
646
+ WHERE r.model_id = ${modelId} AND r.kind = 'child-of' AND r.to_id = ${element}
647
+ AND r.from_id <> ${element}
648
+ ORDER BY e.position
649
+ `)).map((row) => idRow.parse(row)[0]);
650
+ };
651
+ /**
652
+ * Everything beneath an element along `child-of` relations.
653
+ * @param db - The database.
654
+ * @param request - The model and the element, which the caller has checked exist.
655
+ * @returns The descendants, by distance and then model order.
656
+ */
657
+ const descendants = async (db, request) => hierarchyWalk(db, request, down);
658
+ /**
659
+ * Everything above an element along `child-of` relations.
660
+ * @param db - The database.
661
+ * @param request - The model and the element, which the caller has checked exist.
662
+ * @returns The ancestors, by distance and then model order.
663
+ */
664
+ const ancestors = async (db, request) => hierarchyWalk(db, request, up);
665
+ //#endregion
666
+ //#region ../../adapters/graph/store-sqlite/dist/rows.js
667
+ /** A field that is present only when its column holds a value. Its type is loose on purpose: `fromRows` hands everything to `modelSchema`, which is the check. */
668
+ const present = (key, value) => value === null ? {} : Object.fromEntries([[key, value]]);
669
+ /**
670
+ * Flattens a model into rows.
671
+ * @param modelId - The model's id in the store.
672
+ * @param model - A valid model.
673
+ * @param revision - The revision this write takes.
674
+ * @param loops - The ids of the transitions graph-domain counts as loop edges.
675
+ * @returns The rows to insert.
676
+ */
677
+ const toRows = (modelId, model, revision, loops) => ({
678
+ model: {
679
+ id: modelId,
680
+ revision,
681
+ views: model.views ?? null
682
+ },
683
+ participants: model.participants.map(({ id, label, kind }, position) => ({
684
+ modelId,
685
+ id,
686
+ position,
687
+ label,
688
+ kind
689
+ })),
690
+ events: model.events.map(({ id, name, payload }, position) => ({
691
+ modelId,
692
+ id,
693
+ position,
694
+ name,
695
+ payload: payload ?? null
696
+ })),
697
+ actions: model.actions.map(({ id, name }, position) => ({
698
+ modelId,
699
+ id,
700
+ position,
701
+ name
702
+ })),
703
+ artefacts: model.artefacts.map(({ id, name, deliverable }, position) => ({
704
+ modelId,
705
+ id,
706
+ position,
707
+ name,
708
+ deliverable: deliverable ?? null
709
+ })),
710
+ elements: model.elements.map((element, position) => {
711
+ const common = {
712
+ modelId,
713
+ id: element.id,
714
+ position,
715
+ kind: element.kind,
716
+ extensions: element.extensions ?? null
717
+ };
718
+ if (element.kind === "activity") return {
719
+ ...common,
720
+ label: element.label,
721
+ actor: element.actor ?? null,
722
+ action: element.action ?? null,
723
+ source: element.source ?? null,
724
+ affects: element.affects ?? null,
725
+ consumes: element.consumes ?? null,
726
+ produces: element.produces ?? null
727
+ };
728
+ if (element.kind === "decision") return {
729
+ ...common,
730
+ label: element.label,
731
+ actor: element.actor ?? null
732
+ };
733
+ if (element.kind === "state") return {
734
+ ...common,
735
+ label: element.label,
736
+ parent: element.parent ?? null,
737
+ entry: element.entry ?? null,
738
+ exit: element.exit ?? null
739
+ };
740
+ if (element.kind === "pseudo") return {
741
+ ...common,
742
+ role: element.role,
743
+ parent: element.parent ?? null
744
+ };
745
+ return {
746
+ ...common,
747
+ label: element.label,
748
+ from: element.from,
749
+ to: element.to,
750
+ mode: element.mode,
751
+ event: element.event ?? null
752
+ };
753
+ }),
754
+ transitions: model.transitions.map((transition, position) => ({
755
+ modelId,
756
+ id: transition.id,
757
+ position,
758
+ source: transition.source,
759
+ target: transition.target,
760
+ trigger: transition.trigger ?? null,
761
+ guard: transition.guard ?? null,
762
+ condition: transition.condition ?? null,
763
+ effect: transition.effect ?? null,
764
+ loop: loops.has(transition.id)
765
+ })),
766
+ fragments: model.fragments.map(({ id, operator, operands }, position) => ({
767
+ modelId,
768
+ id,
769
+ position,
770
+ operator,
771
+ operands
772
+ })),
773
+ projections: model.projections.map((projection, position) => ({
774
+ modelId,
775
+ position,
776
+ id: projection.id,
777
+ notation: projection.notation,
778
+ subject: "subject" in projection ? projection.subject : null,
779
+ scenario: "scenario" in projection ? projection.scenario : null
780
+ }))
781
+ });
782
+ /** The fields each element kind takes from its row, beyond the kind, id and extensions every element has. Keyed by every kind, so a new kind is a compile error here until it is mapped. */
783
+ const kindFields = {
784
+ activity: (row) => ({
785
+ label: row.label,
786
+ ...present("actor", row.actor),
787
+ ...present("action", row.action),
788
+ ...present("source", row.source),
789
+ ...present("affects", row.affects),
790
+ ...present("consumes", row.consumes),
791
+ ...present("produces", row.produces)
792
+ }),
793
+ decision: (row) => ({
794
+ label: row.label,
795
+ ...present("actor", row.actor)
796
+ }),
797
+ state: (row) => ({
798
+ label: row.label,
799
+ ...present("parent", row.parent),
800
+ ...present("entry", row.entry),
801
+ ...present("exit", row.exit)
802
+ }),
803
+ pseudo: (row) => ({
804
+ role: row.role,
805
+ ...present("parent", row.parent)
806
+ }),
807
+ message: (row) => ({
808
+ label: row.label,
809
+ from: row.from,
810
+ to: row.to,
811
+ mode: row.mode,
812
+ ...present("event", row.event)
813
+ })
814
+ };
815
+ /** Puts back the fields of one element row that belong to its kind. */
816
+ const elementOf = (row) => ({
817
+ kind: row.kind,
818
+ id: row.id,
819
+ ...present("extensions", row.extensions),
820
+ ...kindFields[row.kind](row)
821
+ });
822
+ /**
823
+ * Reassembles a model from its rows.
824
+ * @param rows - Every row of the model, each table in position order.
825
+ * @returns The model.
826
+ * @throws ZodError when the rows do not make a model, which only a database changed outside the store can cause.
827
+ */
828
+ const fromRows = (rows) => modelSchema.parse({
829
+ participants: rows.participants.map(({ id, label, kind }) => ({
830
+ id,
831
+ label,
832
+ kind
833
+ })),
834
+ events: rows.events.map(({ id, name, payload }) => ({
835
+ id,
836
+ name,
837
+ ...present("payload", payload)
838
+ })),
839
+ actions: rows.actions.map(({ id, name }) => ({
840
+ id,
841
+ name
842
+ })),
843
+ artefacts: rows.artefacts.map(({ id, name, deliverable }) => ({
844
+ id,
845
+ name,
846
+ ...present("deliverable", deliverable)
847
+ })),
848
+ elements: rows.elements.map(elementOf),
849
+ transitions: rows.transitions.map((row) => ({
850
+ id: row.id,
851
+ source: row.source,
852
+ target: row.target,
853
+ ...present("trigger", row.trigger),
854
+ ...present("guard", row.guard),
855
+ ...present("condition", row.condition),
856
+ ...present("effect", row.effect)
857
+ })),
858
+ fragments: rows.fragments.map(({ id, operator, operands }) => ({
859
+ id,
860
+ operator,
861
+ operands
862
+ })),
863
+ projections: rows.projections.map((row) => ({
864
+ id: row.id,
865
+ notation: row.notation,
866
+ ...present("subject", row.subject),
867
+ ...present("scenario", row.scenario)
868
+ })),
869
+ ...present("views", rows.model.views)
870
+ });
871
+ /**
872
+ * Reassembles an overlay from its rows.
873
+ * @param rows - The model's overlay rows.
874
+ * @returns The overlay.
875
+ */
876
+ const overlayFromRows = (rows) => overlaySchema.parse(Object.fromEntries(rows.map(({ element, status }) => [element, status])));
877
+ //#endregion
878
+ //#region ../../adapters/graph/store-sqlite/dist/tables.js
879
+ var tables_exports = /* @__PURE__ */ __exportAll({
880
+ actions: () => actions,
881
+ artefacts: () => artefacts,
882
+ elements: () => elements,
883
+ events: () => events,
884
+ fragments: () => fragments,
885
+ models: () => models,
886
+ overlay: () => overlay,
887
+ participants: () => participants,
888
+ projections: () => projections,
889
+ relations: () => relations,
890
+ sequences: () => sequences,
891
+ transitions: () => transitions
892
+ });
893
+ /**
894
+ * The storage projection of the process model. Every record a model declares is one row keyed by its model and its id, with `position` keeping the model's declared order, so a model loads back exactly as it was saved. Enumerated columns take their values from graph-schema's own vocabulary, and nested values (lists, extensions, conditions) are JSON text, typed `unknown` here because `rows.ts` checks them with the model schema on every read. Rows are never the contract's shape: `rows.ts` maps them to the model and back.
895
+ *
896
+ * No foreign keys are declared: SQLite enforces them only on connections that enable them, which a store cannot assume of the driver it is given, so the store keeps a model's rows together itself by writing and deleting them in one transaction.
897
+ */
898
+ /** The store-wide revision sequence: one row, named so it reads as what it is. */
899
+ const sequences = sqliteTable("sequences", {
900
+ name: text("name").primaryKey(),
901
+ value: integer("value").notNull()
902
+ });
903
+ /** One row per stored model: its revision and its layout. */
904
+ const models = sqliteTable("models", {
905
+ id: text("id").primaryKey(),
906
+ revision: integer("revision").notNull(),
907
+ views: text("views", { mode: "json" })
908
+ });
909
+ const participants = sqliteTable("participants", {
910
+ modelId: text("model_id").notNull(),
911
+ id: text("id").notNull(),
912
+ position: integer("position").notNull(),
913
+ label: text("label").notNull(),
914
+ kind: text("kind", { enum: participantKinds }).notNull()
915
+ }, (table) => [primaryKey({ columns: [table.modelId, table.id] })]);
916
+ const events = sqliteTable("events", {
917
+ modelId: text("model_id").notNull(),
918
+ id: text("id").notNull(),
919
+ position: integer("position").notNull(),
920
+ name: text("name").notNull(),
921
+ payload: text("payload", { mode: "json" })
922
+ }, (table) => [primaryKey({ columns: [table.modelId, table.id] })]);
923
+ const actions = sqliteTable("actions", {
924
+ modelId: text("model_id").notNull(),
925
+ id: text("id").notNull(),
926
+ position: integer("position").notNull(),
927
+ name: text("name").notNull()
928
+ }, (table) => [primaryKey({ columns: [table.modelId, table.id] })]);
929
+ const artefacts = sqliteTable("artefacts", {
930
+ modelId: text("model_id").notNull(),
931
+ id: text("id").notNull(),
932
+ position: integer("position").notNull(),
933
+ name: text("name").notNull(),
934
+ deliverable: integer("deliverable", { mode: "boolean" })
935
+ }, (table) => [primaryKey({ columns: [table.modelId, table.id] })]);
936
+ /**
937
+ * Every element kind in one table, so the structural queries traverse a single relation. A column a kind does not have is null on its rows; `rows.ts` reads only the columns of the row's kind.
938
+ */
939
+ const elements = sqliteTable("elements", {
940
+ modelId: text("model_id").notNull(),
941
+ id: text("id").notNull(),
942
+ position: integer("position").notNull(),
943
+ kind: text("kind", { enum: elementKinds }).notNull(),
944
+ label: text("label"),
945
+ actor: text("actor"),
946
+ action: text("action"),
947
+ source: text("source"),
948
+ affects: text("affects", { mode: "json" }),
949
+ consumes: text("consumes", { mode: "json" }),
950
+ produces: text("produces", { mode: "json" }),
951
+ parent: text("parent"),
952
+ entry: text("entry"),
953
+ exit: text("exit"),
954
+ role: text("role", { enum: pseudoRoles }),
955
+ from: text("from_actor"),
956
+ to: text("to_actor"),
957
+ mode: text("mode", { enum: messageModes }),
958
+ event: text("event"),
959
+ extensions: text("extensions", { mode: "json" })
960
+ }, (table) => [primaryKey({ columns: [table.modelId, table.id] })]);
961
+ /** Transitions, with `loop` recording whether graph-domain counts the transition as a decision's loop edge, so the recursive queries can leave it out without loading the model. */
962
+ const transitions = sqliteTable("transitions", {
963
+ modelId: text("model_id").notNull(),
964
+ id: text("id").notNull(),
965
+ position: integer("position").notNull(),
966
+ source: text("source").notNull(),
967
+ target: text("target").notNull(),
968
+ trigger: text("trigger"),
969
+ guard: text("guard"),
970
+ condition: text("condition", { mode: "json" }),
971
+ effect: text("effect"),
972
+ loop: integer("loop", { mode: "boolean" }).notNull()
973
+ }, (table) => [
974
+ primaryKey({ columns: [table.modelId, table.id] }),
975
+ index("transitions_by_target").on(table.modelId, table.target),
976
+ index("transitions_by_source").on(table.modelId, table.source)
977
+ ]);
978
+ const fragments = sqliteTable("fragments", {
979
+ modelId: text("model_id").notNull(),
980
+ id: text("id").notNull(),
981
+ position: integer("position").notNull(),
982
+ operator: text("operator", { enum: fragmentOperators }).notNull(),
983
+ operands: text("operands", { mode: "json" }).notNull()
984
+ }, (table) => [primaryKey({ columns: [table.modelId, table.id] })]);
985
+ /** Projections, keyed by position because the model does not require their ids to be unique. */
986
+ const projections = sqliteTable("projections", {
987
+ modelId: text("model_id").notNull(),
988
+ position: integer("position").notNull(),
989
+ id: text("id").notNull(),
990
+ notation: text("notation", { enum: notations }).notNull(),
991
+ subject: text("subject"),
992
+ scenario: text("scenario", { mode: "json" })
993
+ }, (table) => [primaryKey({ columns: [table.modelId, table.position] })]);
994
+ /** Run state, one row per element that has any. */
995
+ const overlay = sqliteTable("overlay", {
996
+ modelId: text("model_id").notNull(),
997
+ element: text("element").notNull(),
998
+ status: text("status", { enum: overlayStatuses }).notNull()
999
+ }, (table) => [primaryKey({ columns: [table.modelId, table.element] })]);
1000
+ /**
1001
+ * Relations kept beside a model, one row per kind and pair of ends, so a relation sent twice is stored once, with `position` keeping the order relations were first stored. The ends are identifiers of the model's elements or participants, by kind.
1002
+ */
1003
+ const relations = sqliteTable("relations", {
1004
+ modelId: text("model_id").notNull(),
1005
+ kind: text("kind", { enum: relationKinds }).notNull(),
1006
+ from: text("from_id").notNull(),
1007
+ to: text("to_id").notNull(),
1008
+ position: integer("position").notNull()
1009
+ }, (table) => [primaryKey({ columns: [
1010
+ table.modelId,
1011
+ table.kind,
1012
+ table.from,
1013
+ table.to
1014
+ ] }), index("relations_by_to").on(table.modelId, table.kind, table.to)]);
1015
+ //#endregion
1016
+ //#region ../../adapters/graph/store-sqlite/dist/store.js
1017
+ /** The tables that hold a model's own records and the relations kept beside it, every one keyed by `modelId`. */
1018
+ const recordTables = [
1019
+ participants,
1020
+ events,
1021
+ actions,
1022
+ artefacts,
1023
+ elements,
1024
+ transitions,
1025
+ fragments,
1026
+ projections,
1027
+ relations
1028
+ ];
1029
+ /** The name of the store-wide revision sequence's row in `sequences`. */
1030
+ const revisionSequence = "revision";
1031
+ /**
1032
+ * A `GraphStore` over SQLite through Drizzle. It migrates the database on its first operation, keeps every model as rows (see `tables.ts` and `rows.ts`), checks every write with the contract's `checkStored` before committing it, and answers the structural queries with recursive SQL.
1033
+ *
1034
+ * Writes rewrite the model's rows inside one transaction, so a failed check or an aborted signal leaves the previous rows in place.
1035
+ * @param options - The database, and optionally the exclusivity and feed a host provides.
1036
+ * @returns The store, ready to serve with `createGraphStoreRouter`.
1037
+ */
1038
+ const createSqliteGraphStore = (options) => {
1039
+ const { db, exclusive = serialised(), feed = new ChangeFeed() } = options;
1040
+ let migrated;
1041
+ /** Runs an operation exclusively on a migrated database. */
1042
+ const operation = async (work) => exclusive(async () => {
1043
+ migrated ??= migrate(db);
1044
+ await migrated;
1045
+ return work();
1046
+ });
1047
+ const nextRevision = async () => {
1048
+ const [row] = await db.insert(sequences).values({
1049
+ name: revisionSequence,
1050
+ value: 1
1051
+ }).onConflictDoUpdate({
1052
+ target: sequences.name,
1053
+ set: { value: sql`${sequences.value} + 1` }
1054
+ }).returning({ value: sequences.value });
1055
+ return z.object({ value: z.number() }).parse(row).value;
1056
+ };
1057
+ const revisionOf = async (modelId) => {
1058
+ const [row] = await db.select({ revision: models.revision }).from(models).where(eq(models.id, modelId));
1059
+ return row?.revision;
1060
+ };
1061
+ const requireModel = async (modelId) => {
1062
+ if (await revisionOf(modelId) === void 0) throw new GraphStoreError({
1063
+ kind: "not-found",
1064
+ modelId
1065
+ });
1066
+ };
1067
+ const requireElement = async (modelId, element) => {
1068
+ await requireModel(modelId);
1069
+ const [row] = await db.select({ id: elements.id }).from(elements).where(and(eq(elements.modelId, modelId), eq(elements.id, element)));
1070
+ if (row === void 0) throw new GraphStoreError({
1071
+ kind: "not-found",
1072
+ modelId,
1073
+ element
1074
+ });
1075
+ };
1076
+ const readOverlay = async (modelId) => overlayFromRows(await db.select().from(overlay).where(eq(overlay.modelId, modelId)));
1077
+ const readRelations = async (modelId) => db.select({
1078
+ kind: relations.kind,
1079
+ from: relations.from,
1080
+ to: relations.to
1081
+ }).from(relations).where(eq(relations.modelId, modelId)).orderBy(asc(relations.position));
1082
+ const read = async (modelId) => {
1083
+ const [model] = await db.select().from(models).where(eq(models.id, modelId));
1084
+ if (model === void 0) throw new GraphStoreError({
1085
+ kind: "not-found",
1086
+ modelId
1087
+ });
1088
+ const rows = {
1089
+ model,
1090
+ participants: await db.select().from(participants).where(eq(participants.modelId, modelId)).orderBy(asc(participants.position)),
1091
+ events: await db.select().from(events).where(eq(events.modelId, modelId)).orderBy(asc(events.position)),
1092
+ actions: await db.select().from(actions).where(eq(actions.modelId, modelId)).orderBy(asc(actions.position)),
1093
+ artefacts: await db.select().from(artefacts).where(eq(artefacts.modelId, modelId)).orderBy(asc(artefacts.position)),
1094
+ elements: await db.select().from(elements).where(eq(elements.modelId, modelId)).orderBy(asc(elements.position)),
1095
+ transitions: await db.select().from(transitions).where(eq(transitions.modelId, modelId)).orderBy(asc(transitions.position)),
1096
+ fragments: await db.select().from(fragments).where(eq(fragments.modelId, modelId)).orderBy(asc(fragments.position)),
1097
+ projections: await db.select().from(projections).where(eq(projections.modelId, modelId)).orderBy(asc(projections.position))
1098
+ };
1099
+ return {
1100
+ modelId,
1101
+ revision: model.revision,
1102
+ model: fromRows(rows),
1103
+ overlay: await readOverlay(modelId)
1104
+ };
1105
+ };
1106
+ const removeRecords = async (modelId) => sequentially(recordTables.map((table) => async () => db.delete(table).where(eq(table.modelId, modelId))));
1107
+ /** Inserts a model's record rows, skipping the tables it has no records for (an insert needs at least one row). */
1108
+ const insertAll = async (rows) => sequentially([
1109
+ ...rows.participants.length > 0 ? [async () => db.insert(participants).values([...rows.participants])] : [],
1110
+ ...rows.events.length > 0 ? [async () => db.insert(events).values([...rows.events])] : [],
1111
+ ...rows.actions.length > 0 ? [async () => db.insert(actions).values([...rows.actions])] : [],
1112
+ ...rows.artefacts.length > 0 ? [async () => db.insert(artefacts).values([...rows.artefacts])] : [],
1113
+ ...rows.elements.length > 0 ? [async () => db.insert(elements).values([...rows.elements])] : [],
1114
+ ...rows.transitions.length > 0 ? [async () => db.insert(transitions).values([...rows.transitions])] : [],
1115
+ ...rows.fragments.length > 0 ? [async () => db.insert(fragments).values([...rows.fragments])] : [],
1116
+ ...rows.projections.length > 0 ? [async () => db.insert(projections).values([...rows.projections])] : []
1117
+ ]);
1118
+ /** Replaces a model's rows, overlay and relations in one transaction and publishes the change once it commits. */
1119
+ const write = async ({ modelId, kind, model, overlay: overlay$1, relations: relations$1, signal }) => {
1120
+ checkStored(model, overlay$1);
1121
+ const issues = relationIssues(model, relations$1);
1122
+ if (issues.length > 0) throw new GraphStoreError({
1123
+ kind: "invalid",
1124
+ issues
1125
+ });
1126
+ const revision = await inTransaction(db, async () => {
1127
+ const taken = await nextRevision();
1128
+ const rows = toRows(modelId, model, taken, new Set(loopTransitions(model)));
1129
+ await removeRecords(modelId);
1130
+ await db.delete(overlay).where(eq(overlay.modelId, modelId));
1131
+ await db.insert(models).values(rows.model).onConflictDoUpdate({
1132
+ target: models.id,
1133
+ set: {
1134
+ revision: rows.model.revision,
1135
+ views: rows.model.views
1136
+ }
1137
+ });
1138
+ await insertAll(rows);
1139
+ const entries = Object.entries(overlay$1).flatMap(([element, status]) => status === void 0 ? [] : [{
1140
+ modelId,
1141
+ element,
1142
+ status
1143
+ }]);
1144
+ if (entries.length > 0) await db.insert(overlay).values(entries);
1145
+ if (relations$1.length > 0) await db.insert(relations).values(relations$1.map((relation, position) => ({
1146
+ modelId,
1147
+ ...relation,
1148
+ position
1149
+ })));
1150
+ signal?.throwIfAborted();
1151
+ return taken;
1152
+ });
1153
+ feed.publish({
1154
+ modelId,
1155
+ kind,
1156
+ revision
1157
+ });
1158
+ return revision;
1159
+ };
1160
+ return {
1161
+ feed,
1162
+ listModels: async () => operation(async () => db.select({
1163
+ modelId: models.id,
1164
+ revision: models.revision
1165
+ }).from(models).orderBy(asc(models.id))),
1166
+ saveModel: async ({ modelId, model, signal }) => operation(async () => {
1167
+ const stored = await revisionOf(modelId) !== void 0;
1168
+ return write({
1169
+ modelId,
1170
+ kind: "saved",
1171
+ model,
1172
+ overlay: overlayWithin(model, stored ? await readOverlay(modelId) : {}),
1173
+ relations: relationsWithin(model, stored ? await readRelations(modelId) : []),
1174
+ signal
1175
+ });
1176
+ }),
1177
+ loadModel: async ({ modelId }) => operation(async () => read(modelId)),
1178
+ deleteModel: async ({ modelId, signal }) => operation(async () => {
1179
+ if (await revisionOf(modelId) === void 0) return;
1180
+ const revision = await inTransaction(db, async () => {
1181
+ const taken = await nextRevision();
1182
+ await removeRecords(modelId);
1183
+ await db.delete(overlay).where(eq(overlay.modelId, modelId));
1184
+ await db.delete(models).where(eq(models.id, modelId));
1185
+ signal?.throwIfAborted();
1186
+ return taken;
1187
+ });
1188
+ feed.publish({
1189
+ modelId,
1190
+ kind: "deleted",
1191
+ revision
1192
+ });
1193
+ return revision;
1194
+ }),
1195
+ applyOverlay: async ({ modelId, overlay: overlay$2, signal }) => operation(async () => {
1196
+ const stored = await read(modelId);
1197
+ const merged = {
1198
+ ...stored.overlay,
1199
+ ...overlay$2
1200
+ };
1201
+ checkStored(stored.model, merged);
1202
+ const named = Object.keys(overlay$2);
1203
+ const revision = await inTransaction(db, async () => {
1204
+ const taken = await nextRevision();
1205
+ await db.update(models).set({ revision: taken }).where(eq(models.id, modelId));
1206
+ await db.delete(overlay).where(and(eq(overlay.modelId, modelId), inArray(overlay.element, named)));
1207
+ const entries = Object.entries(overlay$2).flatMap(([element, status]) => status === void 0 ? [] : [{
1208
+ modelId,
1209
+ element,
1210
+ status
1211
+ }]);
1212
+ if (entries.length > 0) await db.insert(overlay).values(entries);
1213
+ signal?.throwIfAborted();
1214
+ return taken;
1215
+ });
1216
+ feed.publish({
1217
+ modelId,
1218
+ kind: "overlay",
1219
+ revision
1220
+ });
1221
+ return revision;
1222
+ }),
1223
+ upsertItems: async ({ modelId, items, signal }) => operation(async () => {
1224
+ const stored = await revisionOf(modelId) === void 0 ? {
1225
+ model: emptyModel,
1226
+ overlay: {},
1227
+ relations: []
1228
+ } : {
1229
+ ...await read(modelId),
1230
+ relations: await readRelations(modelId)
1231
+ };
1232
+ return write({
1233
+ modelId,
1234
+ kind: "items",
1235
+ ...mergeBoundItems(stored.model, stored.overlay, items),
1236
+ relations: mergeRelations(stored.relations, items.relations ?? []),
1237
+ signal
1238
+ });
1239
+ }),
1240
+ relations: async ({ modelId }) => operation(async () => {
1241
+ await requireModel(modelId);
1242
+ return readRelations(modelId);
1243
+ }),
1244
+ children: async ({ modelId, element }) => operation(async () => {
1245
+ await requireElement(modelId, element);
1246
+ return children(db, {
1247
+ modelId,
1248
+ element
1249
+ });
1250
+ }),
1251
+ descendants: async ({ modelId, element }) => operation(async () => {
1252
+ await requireElement(modelId, element);
1253
+ return descendants(db, {
1254
+ modelId,
1255
+ element
1256
+ });
1257
+ }),
1258
+ ancestors: async ({ modelId, element }) => operation(async () => {
1259
+ await requireElement(modelId, element);
1260
+ return ancestors(db, {
1261
+ modelId,
1262
+ element
1263
+ });
1264
+ }),
1265
+ ready: async ({ modelId }) => operation(async () => {
1266
+ await requireModel(modelId);
1267
+ return ready(db, modelId);
1268
+ }),
1269
+ blockedChain: async ({ modelId, element }) => operation(async () => {
1270
+ await requireElement(modelId, element);
1271
+ return blockedChain(db, {
1272
+ modelId,
1273
+ element
1274
+ });
1275
+ }),
1276
+ impact: async ({ modelId, element }) => operation(async () => {
1277
+ await requireElement(modelId, element);
1278
+ return impact(db, {
1279
+ modelId,
1280
+ element
1281
+ });
1282
+ }),
1283
+ revisionOf: async ({ modelId }) => operation(async () => revisionOf(modelId))
1284
+ };
1285
+ };
1286
+ //#endregion
1287
+ export { modelSummarySchema as C, revisionSchema as D, relationSchema as E, storeChangeSchema as O, modelIdSchema as S, relationKinds as T, GraphStoreError as _, ancestorsOf as a, changeKinds as b, mergeRelations as c, checkStored as d, emptyModel as f, defaultSubscriptionCapacity as g, ChangeFeed as h, serialised as i, storedModelSchema as k, relationIssues as l, overlayWithin as m, tables_exports as n, childrenOf as o, mergeBoundItems as p, migrate as r, descendantsOf as s, createSqliteGraphStore as t, relationsWithin as u, boundActivitySchema as v, reachSchema as w, issueSchema as x, boundItemsSchema as y };