@procedures/dag 0.0.0-stage → 0.1.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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +498 -2
- package/README_NEW.md +736 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/dag/builder.d.ts +25 -0
- package/dist/dag/builder.d.ts.map +1 -0
- package/dist/dag/builder.js +95 -0
- package/dist/dag/builder.js.map +1 -0
- package/dist/dag/executor.d.ts +28 -0
- package/dist/dag/executor.d.ts.map +1 -0
- package/dist/dag/executor.js +147 -0
- package/dist/dag/executor.js.map +1 -0
- package/dist/dag/index.d.ts +7 -0
- package/dist/dag/index.d.ts.map +1 -0
- package/dist/dag/index.js +7 -0
- package/dist/dag/index.js.map +1 -0
- package/dist/dag/traversal.d.ts +28 -0
- package/dist/dag/traversal.d.ts.map +1 -0
- package/dist/dag/traversal.js +103 -0
- package/dist/dag/traversal.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -3
- package/src/dag/builder.ts +124 -0
- package/src/dag/executor.ts +190 -0
- package/src/dag/index.ts +23 -0
- package/src/dag/traversal.ts +129 -0
- package/src/index.ts +64 -0
- package/src/types.ts +87 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Mark Russell
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,499 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @procedures/dag
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@procedures/dag)
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install @procedures/dag
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](https://nodejs.org/)
|
|
12
|
+
|
|
13
|
+
> Generic DAG (Directed Acyclic Graph) utilities for dependency ordering and parallel execution. Powers the ecosystem's build system.
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Overview](#overview)
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Architecture](#architecture)
|
|
20
|
+
- [Quick Start](#quick-start)
|
|
21
|
+
- [API Reference](#api-reference)
|
|
22
|
+
- [Types](#types)
|
|
23
|
+
- [Functions](#functions)
|
|
24
|
+
- [buildDAG](#builddag)
|
|
25
|
+
- [executeDAG](#executedag)
|
|
26
|
+
- [Use Cases](#use-cases)
|
|
27
|
+
- [Integration](#integration)
|
|
28
|
+
- [Requirements](#requirements)
|
|
29
|
+
- [License](#license)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Overview
|
|
34
|
+
|
|
35
|
+
**client-dag** provides utilities for working with Directed Acyclic Graphs:
|
|
36
|
+
|
|
37
|
+
- **DAG Building** - Topological sorting using Kahn's algorithm
|
|
38
|
+
- **Parallel Execution** - Process nodes level-by-level with configurable concurrency
|
|
39
|
+
- **Traversal Utilities** - Find roots, leaves, dependents, and dependencies
|
|
40
|
+
- **Progress Tracking** - Callbacks for node start/complete events
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install github:mark1russell7/client-dag#main
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
### System Overview
|
|
55
|
+
|
|
56
|
+
```mermaid
|
|
57
|
+
graph TB
|
|
58
|
+
subgraph "Input"
|
|
59
|
+
Nodes[DAGNode Array<br/>id + dependencies]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
subgraph "client-dag"
|
|
63
|
+
subgraph "DAG Builder"
|
|
64
|
+
Kahn[Kahn's Algorithm]
|
|
65
|
+
Topo[Topological Sort]
|
|
66
|
+
Level[Level Assignment]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
subgraph "DAG Executor"
|
|
70
|
+
Queue[Level Queue]
|
|
71
|
+
Pool[Concurrency Pool]
|
|
72
|
+
Process[Node Processor]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
subgraph "Traversal"
|
|
76
|
+
Roots[getRoots]
|
|
77
|
+
Leaves[getLeaves]
|
|
78
|
+
Deps[getDependents]
|
|
79
|
+
Reqs[getDependencies]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
subgraph "Output"
|
|
84
|
+
DAG[DependencyDAG<br/>nodes + levels]
|
|
85
|
+
Result[DAGResult<br/>success + results]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
Nodes --> Kahn
|
|
89
|
+
Kahn --> Topo
|
|
90
|
+
Topo --> Level
|
|
91
|
+
Level --> DAG
|
|
92
|
+
|
|
93
|
+
DAG --> Queue
|
|
94
|
+
Queue --> Pool
|
|
95
|
+
Pool --> Process
|
|
96
|
+
Process --> Result
|
|
97
|
+
|
|
98
|
+
DAG --> Roots
|
|
99
|
+
DAG --> Leaves
|
|
100
|
+
DAG --> Deps
|
|
101
|
+
DAG --> Reqs
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Execution Flow
|
|
105
|
+
|
|
106
|
+
```mermaid
|
|
107
|
+
sequenceDiagram
|
|
108
|
+
participant App as Application
|
|
109
|
+
participant DAG as client-dag
|
|
110
|
+
participant Build as buildDAG
|
|
111
|
+
participant Exec as executeDAG
|
|
112
|
+
participant Proc as NodeProcessor
|
|
113
|
+
|
|
114
|
+
App->>Build: buildDAG(nodes)
|
|
115
|
+
Build->>Build: Kahn's algorithm
|
|
116
|
+
Build->>Build: Assign levels
|
|
117
|
+
Build-->>App: DependencyDAG
|
|
118
|
+
|
|
119
|
+
App->>Exec: executeDAG(dag, processor, options)
|
|
120
|
+
|
|
121
|
+
loop For each level
|
|
122
|
+
Exec->>Exec: Get nodes at level
|
|
123
|
+
par Parallel execution (concurrency)
|
|
124
|
+
Exec->>Proc: process(node1)
|
|
125
|
+
Proc-->>Exec: NodeResult
|
|
126
|
+
Exec->>Proc: process(node2)
|
|
127
|
+
Proc-->>Exec: NodeResult
|
|
128
|
+
end
|
|
129
|
+
Exec->>Exec: Check failFast
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
Exec-->>App: DAGResult
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Topological Sorting (Kahn's Algorithm)
|
|
136
|
+
|
|
137
|
+
```mermaid
|
|
138
|
+
graph LR
|
|
139
|
+
subgraph "Input Graph"
|
|
140
|
+
A1[A depends on B,C]
|
|
141
|
+
B1[B depends on D]
|
|
142
|
+
C1[C depends on D]
|
|
143
|
+
D1[D no deps]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
subgraph "Processing"
|
|
147
|
+
K[Kahn's Algorithm]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
subgraph "Output Levels"
|
|
151
|
+
L0[Level 0: D]
|
|
152
|
+
L1[Level 1: B, C]
|
|
153
|
+
L2[Level 2: A]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
A1 --> K
|
|
157
|
+
B1 --> K
|
|
158
|
+
C1 --> K
|
|
159
|
+
D1 --> K
|
|
160
|
+
K --> L0
|
|
161
|
+
K --> L1
|
|
162
|
+
K --> L2
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### DAG Structure Visualization
|
|
166
|
+
|
|
167
|
+
```mermaid
|
|
168
|
+
graph TB
|
|
169
|
+
subgraph "Level 2 (Roots)"
|
|
170
|
+
App[app]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
subgraph "Level 1"
|
|
174
|
+
LibA[lib-a]
|
|
175
|
+
LibB[lib-b]
|
|
176
|
+
LibC[lib-c]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
subgraph "Level 0 (Leaves)"
|
|
180
|
+
Core[core]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
App --> LibA
|
|
184
|
+
App --> LibB
|
|
185
|
+
App --> LibC
|
|
186
|
+
LibA --> Core
|
|
187
|
+
LibB --> Core
|
|
188
|
+
LibC --> Core
|
|
189
|
+
|
|
190
|
+
style App fill:#f9f,stroke:#333
|
|
191
|
+
style Core fill:#9f9,stroke:#333
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Quick Start
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import {
|
|
200
|
+
buildDAG,
|
|
201
|
+
executeDAG,
|
|
202
|
+
type DAGNode,
|
|
203
|
+
type NodeProcessor,
|
|
204
|
+
} from "@procedures/dag";
|
|
205
|
+
|
|
206
|
+
// Define nodes
|
|
207
|
+
const nodes: DAGNode[] = [
|
|
208
|
+
{ id: "app", dependencies: ["lib-a", "lib-b"] },
|
|
209
|
+
{ id: "lib-a", dependencies: ["core"] },
|
|
210
|
+
{ id: "lib-b", dependencies: ["core"] },
|
|
211
|
+
{ id: "core", dependencies: [] },
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
// Build the DAG
|
|
215
|
+
const dag = buildDAG(nodes);
|
|
216
|
+
// Levels: [["core"], ["lib-a", "lib-b"], ["app"]]
|
|
217
|
+
|
|
218
|
+
// Define a processor
|
|
219
|
+
const processor: NodeProcessor = async (node) => {
|
|
220
|
+
console.log(`Processing ${node.id}`);
|
|
221
|
+
// Do work...
|
|
222
|
+
return {
|
|
223
|
+
node,
|
|
224
|
+
success: true,
|
|
225
|
+
duration: 100,
|
|
226
|
+
logs: [`Built ${node.id}`],
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Execute with parallel processing per level
|
|
231
|
+
const result = await executeDAG(dag, processor, {
|
|
232
|
+
concurrency: 4,
|
|
233
|
+
failFast: true,
|
|
234
|
+
onNodeStart: (node) => console.log(`Starting: ${node.id}`),
|
|
235
|
+
onNodeComplete: (result) => console.log(`Done: ${result.node.id}`),
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## API Reference
|
|
242
|
+
|
|
243
|
+
### Types
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
interface DAGNode<TData = unknown> {
|
|
247
|
+
id: string; // Unique identifier
|
|
248
|
+
dependencies: string[]; // IDs of dependencies
|
|
249
|
+
level?: number; // Topological level (computed)
|
|
250
|
+
data?: TData; // Optional user data
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
interface DependencyDAG<TNode extends DAGNode = DAGNode> {
|
|
254
|
+
nodes: Map<string, TNode>; // All nodes
|
|
255
|
+
levels: TNode[][]; // Nodes by level
|
|
256
|
+
roots: string[]; // No dependents (end nodes)
|
|
257
|
+
leaves: string[]; // No dependencies (start nodes)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
interface DAGExecutionOptions<TNode extends DAGNode = DAGNode> {
|
|
261
|
+
concurrency?: number; // Max parallel per level (default: 4)
|
|
262
|
+
failFast?: boolean; // Stop on first error (default: true)
|
|
263
|
+
onNodeStart?: (node: TNode) => void;
|
|
264
|
+
onNodeComplete?: (result: NodeResult<TNode>) => void;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
interface NodeResult<TNode extends DAGNode = DAGNode> {
|
|
268
|
+
node: TNode;
|
|
269
|
+
success: boolean;
|
|
270
|
+
error?: Error;
|
|
271
|
+
duration: number; // ms
|
|
272
|
+
logs: string[];
|
|
273
|
+
output?: unknown;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
interface DAGResult<TNode extends DAGNode = DAGNode> {
|
|
277
|
+
success: boolean;
|
|
278
|
+
results: Map<string, NodeResult<TNode>>;
|
|
279
|
+
failedNodes: string[];
|
|
280
|
+
totalDuration: number;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
type NodeProcessor<TNode extends DAGNode = DAGNode> = (
|
|
284
|
+
node: TNode
|
|
285
|
+
) => Promise<NodeResult<TNode>>;
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Functions
|
|
289
|
+
|
|
290
|
+
| Function | Description |
|
|
291
|
+
|----------|-------------|
|
|
292
|
+
| `buildDAG(nodes)` | Build a DAG from nodes with dependencies |
|
|
293
|
+
| `executeDAG(dag, processor, options)` | Execute DAG with parallel processing |
|
|
294
|
+
| `getRoots(dag)` | Get nodes with no dependents |
|
|
295
|
+
| `getLeaves(dag)` | Get nodes with no dependencies |
|
|
296
|
+
| `getDependents(dag, id)` | Get nodes that depend on this node |
|
|
297
|
+
| `getDependencies(dag, id)` | Get this node's dependencies |
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
### buildDAG
|
|
302
|
+
|
|
303
|
+
Build a leveled DAG using Kahn's algorithm.
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { buildDAG } from "@procedures/dag";
|
|
307
|
+
|
|
308
|
+
const nodes = [
|
|
309
|
+
{ id: "a", dependencies: ["b", "c"] },
|
|
310
|
+
{ id: "b", dependencies: ["d"] },
|
|
311
|
+
{ id: "c", dependencies: ["d"] },
|
|
312
|
+
{ id: "d", dependencies: [] },
|
|
313
|
+
];
|
|
314
|
+
|
|
315
|
+
const dag = buildDAG(nodes);
|
|
316
|
+
// dag.levels = [
|
|
317
|
+
// [{ id: "d", ... }], // Level 0: process first
|
|
318
|
+
// [{ id: "b" }, { id: "c" }], // Level 1: parallel
|
|
319
|
+
// [{ id: "a", ... }], // Level 2: process last
|
|
320
|
+
// ]
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Cycle Detection:**
|
|
324
|
+
```typescript
|
|
325
|
+
// Throws if cycles detected
|
|
326
|
+
const cyclic = [
|
|
327
|
+
{ id: "a", dependencies: ["b"] },
|
|
328
|
+
{ id: "b", dependencies: ["a"] }, // Cycle!
|
|
329
|
+
];
|
|
330
|
+
buildDAG(cyclic); // Error: Cycle detected
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### executeDAG
|
|
336
|
+
|
|
337
|
+
Execute nodes level by level with configurable parallelism.
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
import { executeDAG } from "@procedures/dag";
|
|
341
|
+
|
|
342
|
+
const result = await executeDAG(dag, processor, {
|
|
343
|
+
concurrency: 4, // Process up to 4 nodes in parallel per level
|
|
344
|
+
failFast: true, // Stop immediately on first failure
|
|
345
|
+
onNodeStart: (node) => console.log(`Starting: ${node.id}`),
|
|
346
|
+
onNodeComplete: (r) => console.log(`${r.node.id}: ${r.success ? "OK" : "FAIL"}`),
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
if (result.success) {
|
|
350
|
+
console.log("All nodes processed successfully");
|
|
351
|
+
} else {
|
|
352
|
+
console.log("Failed nodes:", result.failedNodes);
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Execution Order:**
|
|
357
|
+
|
|
358
|
+
```mermaid
|
|
359
|
+
graph LR
|
|
360
|
+
subgraph "Level 0"
|
|
361
|
+
D[core]
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
subgraph "Level 1 (parallel)"
|
|
365
|
+
B[lib-a]
|
|
366
|
+
C[lib-b]
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
subgraph "Level 2"
|
|
370
|
+
A[app]
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
D -->|then| B
|
|
374
|
+
D -->|then| C
|
|
375
|
+
B -->|then| A
|
|
376
|
+
C -->|then| A
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Use Cases
|
|
382
|
+
|
|
383
|
+
### Package Build Order
|
|
384
|
+
|
|
385
|
+
Build packages in dependency order (`dag.traverse` of `client-lib` does this):
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
const packages = [
|
|
389
|
+
{ id: "app", dependencies: ["@org/lib-ui", "@org/lib-core"] },
|
|
390
|
+
{ id: "@org/lib-ui", dependencies: ["@org/lib-core"] },
|
|
391
|
+
{ id: "@org/lib-core", dependencies: [] },
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
const dag = buildDAG(packages);
|
|
395
|
+
await executeDAG(dag, async (pkg) => {
|
|
396
|
+
await runBuild(pkg.id);
|
|
397
|
+
return { node: pkg, success: true, duration: 0, logs: [] };
|
|
398
|
+
});
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Task Scheduling
|
|
402
|
+
|
|
403
|
+
Execute dependent tasks:
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
const tasks = [
|
|
407
|
+
{ id: "deploy", dependencies: ["test", "build"] },
|
|
408
|
+
{ id: "test", dependencies: ["build"] },
|
|
409
|
+
{ id: "build", dependencies: [] },
|
|
410
|
+
];
|
|
411
|
+
|
|
412
|
+
const dag = buildDAG(tasks);
|
|
413
|
+
await executeDAG(dag, async (task) => {
|
|
414
|
+
await runTask(task.id);
|
|
415
|
+
return { node: task, success: true, duration: 0, logs: [] };
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Module Loading
|
|
420
|
+
|
|
421
|
+
Load modules respecting dependencies:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const modules = [
|
|
425
|
+
{ id: "app", dependencies: ["router", "store"] },
|
|
426
|
+
{ id: "router", dependencies: ["utils"] },
|
|
427
|
+
{ id: "store", dependencies: ["utils"] },
|
|
428
|
+
{ id: "utils", dependencies: [] },
|
|
429
|
+
];
|
|
430
|
+
|
|
431
|
+
const dag = buildDAG(modules);
|
|
432
|
+
await executeDAG(dag, async (mod) => {
|
|
433
|
+
await import(mod.id);
|
|
434
|
+
return { node: mod, success: true, duration: 0, logs: [] };
|
|
435
|
+
});
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Integration
|
|
441
|
+
|
|
442
|
+
### With client-lib
|
|
443
|
+
|
|
444
|
+
`client-lib` uses `client-dag` for ecosystem package management:
|
|
445
|
+
|
|
446
|
+
```mermaid
|
|
447
|
+
graph TB
|
|
448
|
+
subgraph "client-lib"
|
|
449
|
+
Scan[lib.scan<br/>Discover packages]
|
|
450
|
+
Traverse[dag.traverse<br/>Visit in dependency order]
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
subgraph "client-dag"
|
|
454
|
+
Build[buildDAG]
|
|
455
|
+
Execute[executeDAG]
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
subgraph "Packages"
|
|
459
|
+
P1[Package A]
|
|
460
|
+
P2[Package B]
|
|
461
|
+
P3[Package C]
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
Scan --> Build
|
|
465
|
+
Build --> Execute
|
|
466
|
+
Traverse --> Execute
|
|
467
|
+
Execute --> P1
|
|
468
|
+
Execute --> P2
|
|
469
|
+
Execute --> P3
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### dag.traverse Procedure
|
|
473
|
+
|
|
474
|
+
The `dag.traverse` procedure in `client-lib` wraps this functionality:
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
// Via procedure
|
|
478
|
+
await client.exec(["dag", "traverse"], {
|
|
479
|
+
visit: ["pnpm", "install"],
|
|
480
|
+
concurrency: 4,
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// Internally uses
|
|
484
|
+
const dag = buildDAG(packages);
|
|
485
|
+
await executeDAG(dag, processor);
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## Requirements
|
|
491
|
+
|
|
492
|
+
- **Node.js** >= 22
|
|
493
|
+
- **Dependencies:** none
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## License
|
|
498
|
+
|
|
499
|
+
MIT
|