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
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/process-graph) [![Release](https://img.shields.io/github/v/release/ExaDev/process-graph)](https://github.com/ExaDev/process-graph/releases/latest) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions)
4
4
 
5
- The one install for the process-graph model: a layout-free description of a process, its projections into a flowchart, a swimlane, a state machine and a sequence diagram, and reasoning over a run (what is ready, what blocks what, what finishing something changes). It re-exports the building-block packages so a consumer depends on one package and imports from one place. `src/` imports nothing Node-only and runs unchanged in a browser or a Worker.
5
+ The one install for the process-graph model: a layout-free description of a process, its projections into a flowchart, a swimlane, a state machine and a sequence diagram, and reasoning over a run (what is ready, what blocks what, what finishing something changes). Layout, the GitHub issues source, the SQLite store for Node and the browser, the React UI and the command line each sit behind a subpath of their own, so an application loads only the parts it imports. ESM only.
6
6
 
7
7
  ```ts
8
8
  import {
@@ -36,26 +36,93 @@ toSwimlane(model).lanes; // one lane per actor, each with the elements it owns
36
36
  deriveStatuses(model, { submit: "done" }, facts); // Map { "submit" => "done", "pack" => "ready" }
37
37
  ```
38
38
 
39
- ## This package or a building block
39
+ ## Subpaths
40
+
41
+ The package is built from the repository's internal packages, which are bundled into it and not published on their own; each internal package's README documents its functions and rules. Each subpath loads only the code it reaches.
42
+
43
+ | Import | What it is | Runs in |
44
+ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
45
+ | `process-graph` | The model (`defineModel`, `parseModel`, `validate`), its projections and inverses, and the reasoning over a run (statuses, ready set, blocked-by, impact, what-if, critical path). | Browser, Worker, Node |
46
+ | `process-graph/layout` | `layout`: positions for a projected flowchart, swimlane or state machine, in the model's `views` shape, through elkjs. | Browser, Worker, Node |
47
+ | `process-graph/source/github` | The `GraphSource` port (contract, schemas, router, pagination and an in-memory fake) and the GitHub issues adapter, `createGitHubIssuesSource`. | Browser, Worker, Node |
48
+ | `process-graph/source/github/node` | `githubTokenFromEnvironment`: a token port reading `GITHUB_TOKEN` or the GitHub CLI's token. | Node |
49
+ | `process-graph/store` | The `GraphStore` port (contract, schemas, router, change feed, structural queries and an in-memory fake) and the SQLite store over any Drizzle SQLite database. | Browser, Worker, Node |
50
+ | `process-graph/store/node` | `openNodeGraphStore`: the SQLite store on Node's built-in `node:sqlite`. | Node |
51
+ | `process-graph/store/wasm` | `connectGraphStore`: connects a page to the store a dedicated worker serves. | Browser |
52
+ | `process-graph/store/wasm/worker` | `serveGraphStoreInWorker`: serves the store from a dedicated worker on SQLite wasm and OPFS, shared between tabs with no special headers. | Dedicated worker |
53
+ | `process-graph/react` | Headless React hooks and unstyled components: follow a stored model, derive its run, project, filter and select. | Browser |
54
+ | `process-graph/ui` | Styled components over `process-graph/react`, the SVG sequence diagram and the theme contract with light and dark themes. | Browser |
55
+ | `process-graph/ui/style.css` | The compiled styles for `process-graph/ui`. | Browser |
56
+ | `process-graph/react-flow` | React Flow views of a flowchart, swimlane or state machine, laid out by `process-graph/layout`. | Browser |
57
+ | `process-graph/react-flow/style.css` | The compiled styles for `process-graph/react-flow`, React Flow's own included. | Browser |
58
+ | `process-graph/cli` | The command line as a library: `runCli` over injected ports, `nodePorts` for a Node process, and each command's operation returning plain data. | Node |
59
+
60
+ `zod` and `trilean`, which the root entry needs, are dependencies. The libraries only other subpaths need are optional peer dependencies, so installing `process-graph` for its root entry pulls in nothing else; install the peers of each subpath you import beside it:
61
+
62
+ | Subpath | Peer dependencies |
63
+ | ------------------- | ---------------------------------------------------------------------------- |
64
+ | `layout` | `elkjs` |
65
+ | `source/github` | `@orpc/client`, `@orpc/contract`, `@orpc/server` |
66
+ | `store` | `@orpc/contract`, `@orpc/server`, `drizzle-orm` |
67
+ | `store/node` | `drizzle-orm` |
68
+ | `store/wasm` | `@orpc/client` |
69
+ | `store/wasm/worker` | `@orpc/contract`, `@orpc/server`, `drizzle-orm`, `@sqlite.org/sqlite-wasm` |
70
+ | `react` | `react` |
71
+ | `ui` | `react`, `@vanilla-extract/recipes`, `@vanilla-extract/css` (types) |
72
+ | `react-flow` | `react`, `react-dom`, `@xyflow/react`, `elkjs`, `@vanilla-extract/recipes` |
73
+ | `cli` and the bin | `commander`, `@orpc/client`, `@orpc/contract`, `@orpc/server`, `drizzle-orm` |
74
+
75
+ The versions are the ones `package.json` declares under `peerDependencies`.
76
+
77
+ With Vite, exclude `@sqlite.org/sqlite-wasm` from dependency pre-bundling (`optimizeDeps.exclude`), since it loads its `.wasm` file relative to itself. A worker module serving the browser store is one call:
40
78
 
41
- Install `process-graph` to author, load, project and reason about a model. Install a building-block package instead when only one layer is needed and the rest should stay out of the dependency tree, or when another package of this repository imports a layer directly.
79
+ ```ts
80
+ // store.worker.ts
81
+ import { serveGraphStoreInWorker } from "process-graph/store/wasm/worker";
82
+
83
+ serveGraphStoreInWorker({ name: "graph" });
84
+ ```
85
+
86
+ ```ts
87
+ // in the page
88
+ import { connectGraphStore } from "process-graph/store/wasm";
89
+
90
+ const store = connectGraphStore(
91
+ new Worker(new URL("./store.worker.ts", import.meta.url), { type: "module" }),
92
+ );
93
+ ```
42
94
 
43
- | Layer | Package | Exported by this package |
44
- | ---------- | ---------------------------------- | ------------------------ |
45
- | Model | `@exadev/process-graph-schema` | flat |
46
- | Projection | `@exadev/process-graph-projection` | flat |
47
- | Domain | `@exadev/process-graph-domain` | flat |
48
- | DAG | `@exadev/process-graph-dag` | namespaced as `dag` |
95
+ The styled components need their stylesheets imported once:
96
+
97
+ ```tsx
98
+ import "process-graph/ui/style.css";
99
+ import "process-graph/react-flow/style.css";
100
+ import { GraphTheme } from "process-graph/ui";
101
+ import { ProcessView } from "process-graph/react-flow";
102
+ ```
103
+
104
+ ## The command line
105
+
106
+ The package carries the `process-graph` bin: sync work from GitHub issues into a SQLite store, ask what is ready, blocked, affected, on the critical path or handed off, explain a status, and draw the model in Mermaid or Graphviz DOT. Its peers are installed beside it:
107
+
108
+ ```sh
109
+ npm install --global process-graph commander @orpc/client @orpc/contract @orpc/server drizzle-orm
110
+ process-graph sync github:ExaDev
111
+ process-graph ready
112
+ process-graph why github:ExaDev/process-graph#12
113
+ process-graph show --view swimlane --format mermaid
114
+ ```
49
115
 
50
- Each package's own README documents its functions and rules; this package adds no behaviour of its own.
116
+ Run without them, the bin starts nothing: it names the missing peers and the command that installs them with the package manager that ran it, and exits with status 6. Every command, its options and its exit statuses are in the [command line's README](../graph-cli/README.md). A program that mounts the command line as a subcommand, or wants each command's result as data, imports `process-graph/cli`.
51
117
 
52
118
  ## What is exported, and under which name
53
119
 
54
- The model, projection and domain packages are exported flat, under their own names. The DAG package is exported as the namespace `dag`, in its entirety: `dag.buildDag`, `dag.topologicalLayers`, `dag.criticalPath`, `dag.CycleError` and the rest. It is the only layer namespaced, because its `criticalPath` has the same name as the domain package's, which answers a different question (the heaviest chain through the work still ahead of a run, not through a bare node set). The whole layer is namespaced rather than only the colliding name, so a name added to a layer later cannot start colliding silently.
120
+ The root entry exports the model, projection and domain layers flat, under their own names, and the DAG layer as the namespace `dag`, in its entirety: `dag.buildDag`, `dag.topologicalLayers`, `dag.criticalPath`, `dag.CycleError` and the rest. The DAG layer is namespaced because its `criticalPath` has the same name as the domain's, which answers a different question (the heaviest chain through the work still ahead of a run, not through a bare node set). The whole layer is namespaced rather than only the colliding name, so a name added to a layer later cannot start colliding silently.
55
121
 
56
- - A name is never shadowed. Two flat layers exporting the same name is a compile error in this package, and its unit test also compares the runtime exports of each package against the entry point's.
122
+ - A name is never shadowed. Two layers exporting the same name on one entry point is a compile error, and the unit tests compare each entry point's runtime exports with the layers it carries.
57
123
  - Types follow the same rule as values: a model, projection or domain type is a flat import, a DAG type is `dag.Dag` and so on.
58
- - Errors thrown by the domain functions (`CycleError`, `UnknownNodeError`) are the DAG package's, so a handler imports them from `dag`.
124
+ - Errors thrown by the domain functions (`CycleError`, `UnknownNodeError`) are the DAG layer's, so a handler imports them from `dag`.
125
+ - The headless and styled components share names (`ElementCard`, `DetailPanel` and others), which is why `process-graph/react` and `process-graph/ui` are separate subpaths.
59
126
 
60
127
  ```ts
61
128
  import { criticalPath, dag } from "process-graph";
@@ -67,8 +134,9 @@ dag.criticalPath; // the DAG function: over a node set and a `needs` accessor
67
134
  ## Commands
68
135
 
69
136
  ```sh
70
- pnpm build # tsc -b -> dist/ (ESM + .d.ts)
71
- pnpm test # unit tests
72
- pnpm test:smoke # the built dist/ exercised as a real artefact
73
- pnpm test:mutation # Stryker
137
+ pnpm build # tsdown: the bundle in dist/, declarations included, with each internal package inlined
138
+ pnpm test # unit tests
139
+ pnpm test:smoke # packs the package, installs the tarball into a throwaway project, imports every subpath and runs the bin
140
+ pnpm test:integration # the bundled browser store in Chromium, against the store contract's conformance kit
141
+ pnpm test:mutation # Stryker
74
142
  ```
package/dist/bin.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {}
package/dist/bin.js ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ import { t as exitCodes } from "./exit-codes-0ultCqdS.js";
3
+ import { readFileSync } from "node:fs";
4
+ //#region src/missing-peers.ts
5
+ /**
6
+ * The optional peer dependencies the command line imports. `process-graph` declares them optional so that installing it for its root entry stays light, which means the bin can start without them; it checks for these first and says what to install rather than failing on the first missing import. The smoke test runs the packed bin where none is installed and expects exactly these to be named, so a peer the command line starts needing that is missing here fails that test.
7
+ */
8
+ const commandLinePeers = [
9
+ "@orpc/client",
10
+ "@orpc/contract",
11
+ "@orpc/server",
12
+ "commander",
13
+ "drizzle-orm"
14
+ ];
15
+ /**
16
+ * The peers that do not resolve.
17
+ * @param peers - The package names to look for.
18
+ * @param resolves - Whether a package name resolves from the bin's own location.
19
+ * @returns The names that do not, in the order given.
20
+ */
21
+ const missingPeers = (peers, resolves) => peers.filter((name) => !resolves(name));
22
+ /** The command each package manager installs a package with, keyed by the name its `npm_config_user_agent` starts with. */
23
+ const installCommands = /* @__PURE__ */ new Map([
24
+ ["npm", "npm install"],
25
+ ["pnpm", "pnpm add"],
26
+ ["yarn", "yarn add"],
27
+ ["bun", "bun add"]
28
+ ]);
29
+ /** npm's command, for a bin run directly or by a package manager not listed. */
30
+ const defaultInstallCommand = "npm install";
31
+ /**
32
+ * The command that installs packages with the package manager that ran the bin.
33
+ * @param userAgent - `npm_config_user_agent`, which every package manager sets for the processes it runs (`pnpm/12.4.1 npm/? node/v26.8.1 darwin arm64`), or `undefined` when the bin was run directly.
34
+ * @param packages - The `name@version` specifiers to install.
35
+ * @returns The command, with npm's when the package manager is not recognised.
36
+ */
37
+ const installCommand = (userAgent, packages) => {
38
+ const manager = userAgent?.split("/", 1)[0];
39
+ return [(manager === void 0 ? void 0 : installCommands.get(manager)) ?? defaultInstallCommand, ...packages].join(" ");
40
+ };
41
+ /**
42
+ * The one message the bin prints when peers are missing.
43
+ * @param missing - The missing package names.
44
+ * @param versions - The version `process-graph` declares for each peer, by name.
45
+ * @param userAgent - `npm_config_user_agent`, to pick the install command.
46
+ * @returns The message, ending in a newline.
47
+ * @throws Error when a missing package is not one of the declared peers, which is a packaging mistake rather than the user's.
48
+ */
49
+ const missingPeersMessage = (missing, versions, userAgent) => {
50
+ const specifiers = missing.map((name) => {
51
+ const version = versions.get(name);
52
+ if (version === void 0) throw new Error(`process-graph declares no peer dependency on ${name}`);
53
+ return `${name}@${version}`;
54
+ });
55
+ return [
56
+ `process-graph: the command line needs these optional peer dependencies, which are not installed: ${missing.join(", ")}.`,
57
+ `Install them beside process-graph: ${installCommand(userAgent, specifiers)}`,
58
+ ""
59
+ ].join("\n");
60
+ };
61
+ //#endregion
62
+ //#region src/bin.ts
63
+ /** This package's manifest, beside `dist/`. */
64
+ const manifest = new URL("../package.json", import.meta.url);
65
+ /** The peer dependency versions the manifest declares, by name. */
66
+ const declaredPeers = () => {
67
+ const parsed = JSON.parse(readFileSync(manifest, "utf8"));
68
+ if (typeof parsed !== "object" || parsed === null || !("peerDependencies" in parsed) || typeof parsed.peerDependencies !== "object" || parsed.peerDependencies === null) throw new Error(`${manifest.pathname} declares no peerDependencies`);
69
+ return new Map(Object.entries(parsed.peerDependencies).flatMap(([name, version]) => typeof version === "string" ? [[name, version]] : []));
70
+ };
71
+ /** Whether a package resolves from this bin's own location, as the command line's imports would. Only a package that is not installed counts as missing; any other resolution error is the import's to report. */
72
+ const resolves = (name) => {
73
+ try {
74
+ import.meta.resolve(name);
75
+ return true;
76
+ } catch (error) {
77
+ if (error instanceof Error && "code" in error && error.code === "ERR_MODULE_NOT_FOUND") return false;
78
+ throw error;
79
+ }
80
+ };
81
+ const missing = missingPeers(commandLinePeers, resolves);
82
+ if (missing.length > 0) {
83
+ process.stderr.write(missingPeersMessage(missing, declaredPeers(), process.env.npm_config_user_agent));
84
+ process.exitCode = exitCodes.missingPeers;
85
+ } else {
86
+ const { packageVersion, runProcess } = await import("./dist-IjrgWhHQ.js");
87
+ process.exitCode = await runProcess({
88
+ name: "process-graph",
89
+ version: packageVersion(manifest)
90
+ });
91
+ }
92
+ //#endregion