@smthrs/plan 0.0.0-stage → 1.0.0-rc.3
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 +183 -0
- package/LICENSE +21 -0
- package/README.md +228 -2
- package/dist/cjs/CachePolicy.d.ts +131 -0
- package/dist/cjs/CachePolicy.d.ts.map +1 -0
- package/dist/cjs/CachePolicy.js +50 -0
- package/dist/cjs/CachePolicy.js.map +7 -0
- package/dist/cjs/Effects.d.ts +240 -0
- package/dist/cjs/Effects.d.ts.map +1 -0
- package/dist/cjs/Effects.js +76 -0
- package/dist/cjs/Effects.js.map +7 -0
- package/dist/cjs/FileSet.d.ts +288 -0
- package/dist/cjs/FileSet.d.ts.map +1 -0
- package/dist/cjs/FileSet.js +191 -0
- package/dist/cjs/FileSet.js.map +7 -0
- package/dist/cjs/GraphBuildError.d.ts +122 -0
- package/dist/cjs/GraphBuildError.d.ts.map +1 -0
- package/dist/cjs/GraphBuildError.js +71 -0
- package/dist/cjs/GraphBuildError.js.map +7 -0
- package/dist/cjs/KeyMaterial.d.ts +102 -0
- package/dist/cjs/KeyMaterial.d.ts.map +1 -0
- package/dist/cjs/KeyMaterial.js +64 -0
- package/dist/cjs/KeyMaterial.js.map +7 -0
- package/dist/cjs/Node.d.ts +606 -0
- package/dist/cjs/Node.d.ts.map +1 -0
- package/dist/cjs/Node.js +207 -0
- package/dist/cjs/Node.js.map +7 -0
- package/dist/cjs/Placement.d.ts +117 -0
- package/dist/cjs/Placement.d.ts.map +1 -0
- package/dist/cjs/Placement.js +46 -0
- package/dist/cjs/Placement.js.map +7 -0
- package/dist/cjs/Plan.d.ts +440 -0
- package/dist/cjs/Plan.d.ts.map +1 -0
- package/dist/cjs/Plan.js +508 -0
- package/dist/cjs/Plan.js.map +7 -0
- package/dist/cjs/PlanDiff.d.ts +58 -0
- package/dist/cjs/PlanDiff.d.ts.map +1 -0
- package/dist/cjs/PlanDiff.js +124 -0
- package/dist/cjs/PlanDiff.js.map +7 -0
- package/dist/cjs/Planned.d.ts +121 -0
- package/dist/cjs/Planned.d.ts.map +1 -0
- package/dist/cjs/Planned.js +72 -0
- package/dist/cjs/Planned.js.map +7 -0
- package/dist/cjs/Repetition.d.ts +31 -0
- package/dist/cjs/Repetition.d.ts.map +1 -0
- package/dist/cjs/Repetition.js +36 -0
- package/dist/cjs/Repetition.js.map +7 -0
- package/dist/cjs/Scheduling.d.ts +89 -0
- package/dist/cjs/Scheduling.d.ts.map +1 -0
- package/dist/cjs/Scheduling.js +76 -0
- package/dist/cjs/Scheduling.js.map +7 -0
- package/dist/cjs/StepKey.d.ts +333 -0
- package/dist/cjs/StepKey.d.ts.map +1 -0
- package/dist/cjs/StepKey.js +311 -0
- package/dist/cjs/StepKey.js.map +7 -0
- package/dist/cjs/index.d.ts +91 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +59 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/ConflictAnnotation.d.ts +59 -0
- package/dist/cjs/internal/ConflictAnnotation.d.ts.map +1 -0
- package/dist/cjs/internal/ConflictAnnotation.js +247 -0
- package/dist/cjs/internal/ConflictAnnotation.js.map +7 -0
- package/dist/cjs/internal/EffectCandidates.d.ts +19 -0
- package/dist/cjs/internal/EffectCandidates.d.ts.map +1 -0
- package/dist/cjs/internal/EffectCandidates.js +92 -0
- package/dist/cjs/internal/EffectCandidates.js.map +7 -0
- package/dist/cjs/internal/JsonMirror.d.ts +34 -0
- package/dist/cjs/internal/JsonMirror.d.ts.map +1 -0
- package/dist/cjs/internal/JsonMirror.js +195 -0
- package/dist/cjs/internal/JsonMirror.js.map +7 -0
- package/dist/cjs/internal/effects.d.ts +245 -0
- package/dist/cjs/internal/effects.d.ts.map +1 -0
- package/dist/cjs/internal/effects.js +290 -0
- package/dist/cjs/internal/effects.js.map +7 -0
- package/dist/cjs/internal/node.d.ts +526 -0
- package/dist/cjs/internal/node.d.ts.map +1 -0
- package/dist/cjs/internal/node.js +312 -0
- package/dist/cjs/internal/node.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/test/PlanFixtures.d.ts +127 -0
- package/dist/cjs/test/PlanFixtures.d.ts.map +1 -0
- package/dist/cjs/test/PlanFixtures.js +59 -0
- package/dist/cjs/test/PlanFixtures.js.map +7 -0
- package/dist/esm/CachePolicy.d.ts +131 -0
- package/dist/esm/CachePolicy.d.ts.map +1 -0
- package/dist/esm/CachePolicy.js +117 -0
- package/dist/esm/CachePolicy.js.map +1 -0
- package/dist/esm/Effects.d.ts +240 -0
- package/dist/esm/Effects.d.ts.map +1 -0
- package/dist/esm/Effects.js +167 -0
- package/dist/esm/Effects.js.map +1 -0
- package/dist/esm/FileSet.d.ts +288 -0
- package/dist/esm/FileSet.d.ts.map +1 -0
- package/dist/esm/FileSet.js +324 -0
- package/dist/esm/FileSet.js.map +1 -0
- package/dist/esm/GraphBuildError.d.ts +122 -0
- package/dist/esm/GraphBuildError.d.ts.map +1 -0
- package/dist/esm/GraphBuildError.js +146 -0
- package/dist/esm/GraphBuildError.js.map +1 -0
- package/dist/esm/KeyMaterial.d.ts +102 -0
- package/dist/esm/KeyMaterial.d.ts.map +1 -0
- package/dist/esm/KeyMaterial.js +85 -0
- package/dist/esm/KeyMaterial.js.map +1 -0
- package/dist/esm/Node.d.ts +606 -0
- package/dist/esm/Node.d.ts.map +1 -0
- package/dist/esm/Node.js +521 -0
- package/dist/esm/Node.js.map +1 -0
- package/dist/esm/Placement.d.ts +117 -0
- package/dist/esm/Placement.d.ts.map +1 -0
- package/dist/esm/Placement.js +65 -0
- package/dist/esm/Placement.js.map +1 -0
- package/dist/esm/Plan.d.ts +440 -0
- package/dist/esm/Plan.d.ts.map +1 -0
- package/dist/esm/Plan.js +673 -0
- package/dist/esm/Plan.js.map +1 -0
- package/dist/esm/PlanDiff.d.ts +58 -0
- package/dist/esm/PlanDiff.d.ts.map +1 -0
- package/dist/esm/PlanDiff.js +159 -0
- package/dist/esm/PlanDiff.js.map +1 -0
- package/dist/esm/Planned.d.ts +121 -0
- package/dist/esm/Planned.d.ts.map +1 -0
- package/dist/esm/Planned.js +147 -0
- package/dist/esm/Planned.js.map +1 -0
- package/dist/esm/Repetition.d.ts +31 -0
- package/dist/esm/Repetition.d.ts.map +1 -0
- package/dist/esm/Repetition.js +24 -0
- package/dist/esm/Repetition.js.map +1 -0
- package/dist/esm/Scheduling.d.ts +89 -0
- package/dist/esm/Scheduling.d.ts.map +1 -0
- package/dist/esm/Scheduling.js +82 -0
- package/dist/esm/Scheduling.js.map +1 -0
- package/dist/esm/StepKey.d.ts +333 -0
- package/dist/esm/StepKey.d.ts.map +1 -0
- package/dist/esm/StepKey.js +478 -0
- package/dist/esm/StepKey.js.map +1 -0
- package/dist/esm/index.d.ts +91 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +91 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/ConflictAnnotation.d.ts +59 -0
- package/dist/esm/internal/ConflictAnnotation.d.ts.map +1 -0
- package/dist/esm/internal/ConflictAnnotation.js +332 -0
- package/dist/esm/internal/ConflictAnnotation.js.map +1 -0
- package/dist/esm/internal/EffectCandidates.d.ts +19 -0
- package/dist/esm/internal/EffectCandidates.d.ts.map +1 -0
- package/dist/esm/internal/EffectCandidates.js +86 -0
- package/dist/esm/internal/EffectCandidates.js.map +1 -0
- package/dist/esm/internal/JsonMirror.d.ts +34 -0
- package/dist/esm/internal/JsonMirror.d.ts.map +1 -0
- package/dist/esm/internal/JsonMirror.js +204 -0
- package/dist/esm/internal/JsonMirror.js.map +1 -0
- package/dist/esm/internal/effects.d.ts +245 -0
- package/dist/esm/internal/effects.d.ts.map +1 -0
- package/dist/esm/internal/effects.js +459 -0
- package/dist/esm/internal/effects.js.map +1 -0
- package/dist/esm/internal/node.d.ts +526 -0
- package/dist/esm/internal/node.d.ts.map +1 -0
- package/dist/esm/internal/node.js +564 -0
- package/dist/esm/internal/node.js.map +1 -0
- package/dist/esm/test/PlanFixtures.d.ts +127 -0
- package/dist/esm/test/PlanFixtures.d.ts.map +1 -0
- package/dist/esm/test/PlanFixtures.js +60 -0
- package/dist/esm/test/PlanFixtures.js.map +1 -0
- package/docs/README.md +165 -0
- package/docs/api.md +1475 -0
- package/docs/concepts/authoring-ast.md +203 -0
- package/docs/concepts/effects-and-conflicts.md +135 -0
- package/docs/concepts/plan-value.md +168 -0
- package/docs/concepts/step-keys.md +179 -0
- package/docs/guides/author-a-node-graph.md +182 -0
- package/docs/guides/compile-a-plan.md +146 -0
- package/docs/guides/declare-file-effects.md +143 -0
- package/docs/guides/diff-two-plans.md +101 -0
- package/docs/installation.md +71 -0
- package/docs/quickstart.md +128 -0
- package/docs/testing.md +73 -0
- package/docs/troubleshooting.md +314 -0
- package/package.json +254 -3
- package/src/CachePolicy.ts +143 -0
- package/src/Effects.ts +284 -0
- package/src/FileSet.ts +411 -0
- package/src/GraphBuildError.ts +158 -0
- package/src/KeyMaterial.ts +106 -0
- package/src/Node.ts +871 -0
- package/src/Placement.ts +99 -0
- package/src/Plan.ts +868 -0
- package/src/PlanDiff.ts +199 -0
- package/src/Planned.ts +208 -0
- package/src/Repetition.ts +33 -0
- package/src/Scheduling.ts +154 -0
- package/src/StepKey.ts +710 -0
- package/src/index.ts +103 -0
- package/src/internal/ConflictAnnotation.ts +374 -0
- package/src/internal/EffectCandidates.ts +89 -0
- package/src/internal/JsonMirror.ts +255 -0
- package/src/internal/effects.ts +543 -0
- package/src/internal/node.ts +858 -0
- package/src/test/PlanFixtures.ts +76 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph fixtures shared by every suite that needs a compiled plan.
|
|
3
|
+
*
|
|
4
|
+
* These live outside a `*.test.ts` file on purpose. `PlanStore.test.ts` used to
|
|
5
|
+
* import `compile` and `draft` from `Plan.test.ts`, and importing a test module
|
|
6
|
+
* REGISTERS ITS SUITES in the importer: every case in `Plan.test.ts` ran a
|
|
7
|
+
* second time under `PlanStore.test.ts`, including the 10,000-node chain, which
|
|
8
|
+
* is the most expensive case in the package. CI reported it as
|
|
9
|
+
* `PlanStore.test.ts > Plan.compile > compiles a 10,000-node Ref chain` and it
|
|
10
|
+
* timed out there, on a slower runner, for work `PlanStore` never asked for.
|
|
11
|
+
*
|
|
12
|
+
* They ship from `src/test` rather than `test/` because `@smthrs/plan-store`
|
|
13
|
+
* drives the same fixtures against the persisted form, the way
|
|
14
|
+
* `@smthrs/database` ships `test/TestDatabase` and `@smthrs/engine-store`
|
|
15
|
+
* ships `test/TestStores`. One definition, two packages.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
*/
|
|
19
|
+
import * as KeyMaterial from "../KeyMaterial.ts";
|
|
20
|
+
import * as Plan from "../Plan.ts";
|
|
21
|
+
/**
|
|
22
|
+
* A hard-boundary effect declaration over plain path lists.
|
|
23
|
+
*
|
|
24
|
+
* @category models
|
|
25
|
+
* @since 0.1.0
|
|
26
|
+
*/
|
|
27
|
+
export declare const effects: (reads: ReadonlyArray<string>, writes: ReadonlyArray<string>) => Plan.NodeEffects;
|
|
28
|
+
/**
|
|
29
|
+
* A sealed node draft whose body defaults to `{ action: id }`.
|
|
30
|
+
*
|
|
31
|
+
* @category constructors
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export declare const draft: (id: string, options?: {
|
|
35
|
+
readonly body?: unknown;
|
|
36
|
+
readonly inputs?: ReadonlyArray<KeyMaterial.InputRef>;
|
|
37
|
+
readonly reads?: ReadonlyArray<string>;
|
|
38
|
+
readonly writes?: ReadonlyArray<string>;
|
|
39
|
+
readonly removes?: ReadonlyArray<string>;
|
|
40
|
+
} & Omit<Plan.NodeDraft, "id" | "material" | "effects">) => Plan.NodeDraft;
|
|
41
|
+
/**
|
|
42
|
+
* Compiles drafts into a plan under the `example/Build` flow.
|
|
43
|
+
*
|
|
44
|
+
* @category constructors
|
|
45
|
+
* @since 0.1.0
|
|
46
|
+
*/
|
|
47
|
+
export declare const compile: (nodes: ReadonlyArray<Plan.NodeDraft>, planId?: string) => import("effect/Effect").Effect<{
|
|
48
|
+
readonly planId: string;
|
|
49
|
+
readonly flow: string;
|
|
50
|
+
readonly generation: number;
|
|
51
|
+
readonly baseDigest: string & import("effect/Brand").Brand<"@smthrs/keys/Key">;
|
|
52
|
+
readonly digest: string & import("effect/Brand").Brand<"@smthrs/keys/Key">;
|
|
53
|
+
readonly nodes: readonly {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly kind: "step" | "agent" | "merge";
|
|
56
|
+
readonly key: string & import("effect/Brand").Brand<"@smthrs/keys/Key">;
|
|
57
|
+
readonly material: {
|
|
58
|
+
readonly version: "flows/key-material/v2";
|
|
59
|
+
readonly inputs: readonly ({
|
|
60
|
+
readonly _tag: "Literal";
|
|
61
|
+
readonly value: unknown;
|
|
62
|
+
} | {
|
|
63
|
+
readonly _tag: "Ref";
|
|
64
|
+
readonly from: string;
|
|
65
|
+
readonly path: readonly string[];
|
|
66
|
+
} | {
|
|
67
|
+
readonly _tag: "Pending";
|
|
68
|
+
readonly from: string;
|
|
69
|
+
})[];
|
|
70
|
+
readonly layers: readonly string[];
|
|
71
|
+
readonly capabilities: readonly string[];
|
|
72
|
+
readonly kind: "sealed" | "compensable" | "irreversible";
|
|
73
|
+
readonly body: unknown;
|
|
74
|
+
readonly nondeterministic?: true | undefined;
|
|
75
|
+
readonly effects?: unknown;
|
|
76
|
+
readonly placement?: unknown;
|
|
77
|
+
};
|
|
78
|
+
readonly effects: {
|
|
79
|
+
readonly reads: readonly (string | {
|
|
80
|
+
readonly include: readonly [string, ...string[]];
|
|
81
|
+
readonly _tag: "Glob";
|
|
82
|
+
readonly exclude?: readonly string[] | undefined;
|
|
83
|
+
} | {
|
|
84
|
+
readonly _tag: "Filegroup";
|
|
85
|
+
readonly name: string;
|
|
86
|
+
readonly entries: readonly (string | {
|
|
87
|
+
readonly include: readonly [string, ...string[]];
|
|
88
|
+
readonly _tag: "Glob";
|
|
89
|
+
readonly exclude?: readonly string[] | undefined;
|
|
90
|
+
})[];
|
|
91
|
+
})[];
|
|
92
|
+
readonly writes: readonly (string | {
|
|
93
|
+
readonly include: readonly [string, ...string[]];
|
|
94
|
+
readonly _tag: "Glob";
|
|
95
|
+
readonly exclude?: readonly string[] | undefined;
|
|
96
|
+
} | {
|
|
97
|
+
readonly _tag: "TreeArtifact";
|
|
98
|
+
readonly path: string;
|
|
99
|
+
} | {
|
|
100
|
+
readonly _tag: "Filegroup";
|
|
101
|
+
readonly name: string;
|
|
102
|
+
readonly entries: readonly (string | {
|
|
103
|
+
readonly include: readonly [string, ...string[]];
|
|
104
|
+
readonly _tag: "Glob";
|
|
105
|
+
readonly exclude?: readonly string[] | undefined;
|
|
106
|
+
} | {
|
|
107
|
+
readonly _tag: "TreeArtifact";
|
|
108
|
+
readonly path: string;
|
|
109
|
+
})[];
|
|
110
|
+
})[];
|
|
111
|
+
readonly boundaryMode: "expected" | "hard";
|
|
112
|
+
readonly removes?: readonly string[] | undefined;
|
|
113
|
+
};
|
|
114
|
+
readonly dependsOn: readonly string[];
|
|
115
|
+
readonly conflicts: readonly {
|
|
116
|
+
readonly with: string;
|
|
117
|
+
readonly paths: readonly string[];
|
|
118
|
+
readonly strategy: "serialize" | "lane" | "fail";
|
|
119
|
+
readonly runtime: "delay-rebase" | "stop-merge";
|
|
120
|
+
}[];
|
|
121
|
+
readonly strategy: "serialize" | "lane" | "fail";
|
|
122
|
+
readonly runtime: "delay-rebase" | "stop-merge";
|
|
123
|
+
readonly priority: number;
|
|
124
|
+
readonly generation: number;
|
|
125
|
+
}[];
|
|
126
|
+
}, import("effect/Schema").SchemaError | import("../StepKey.ts").KeyMaterialError | Plan.PlanError, import("effect/Crypto").Crypto>;
|
|
127
|
+
//# sourceMappingURL=PlanFixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlanFixtures.d.ts","sourceRoot":"","sources":["../../../src/test/PlanFixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,IAAI,MAAM,YAAY,CAAA;AAElC;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAClB,OAAO,aAAa,CAAC,MAAM,CAAC,EAC5B,QAAQ,aAAa,CAAC,MAAM,CAAC,KAC5B,IAAI,CAAC,WAAwD,CAAA;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAChB,IAAI,MAAM,EACV,UAAS;IACP,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;IACrD,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACzC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,UAAU,GAAG,SAAS,CAAM,KAC3D,IAAI,CAAC,SAkBN,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,eAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mIACvB,CAAA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph fixtures shared by every suite that needs a compiled plan.
|
|
3
|
+
*
|
|
4
|
+
* These live outside a `*.test.ts` file on purpose. `PlanStore.test.ts` used to
|
|
5
|
+
* import `compile` and `draft` from `Plan.test.ts`, and importing a test module
|
|
6
|
+
* REGISTERS ITS SUITES in the importer: every case in `Plan.test.ts` ran a
|
|
7
|
+
* second time under `PlanStore.test.ts`, including the 10,000-node chain, which
|
|
8
|
+
* is the most expensive case in the package. CI reported it as
|
|
9
|
+
* `PlanStore.test.ts > Plan.compile > compiles a 10,000-node Ref chain` and it
|
|
10
|
+
* timed out there, on a slower runner, for work `PlanStore` never asked for.
|
|
11
|
+
*
|
|
12
|
+
* They ship from `src/test` rather than `test/` because `@smthrs/plan-store`
|
|
13
|
+
* drives the same fixtures against the persisted form, the way
|
|
14
|
+
* `@smthrs/database` ships `test/TestDatabase` and `@smthrs/engine-store`
|
|
15
|
+
* ships `test/TestStores`. One definition, two packages.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
*/
|
|
19
|
+
import * as KeyMaterial from "../KeyMaterial.js";
|
|
20
|
+
import * as Plan from "../Plan.js";
|
|
21
|
+
/**
|
|
22
|
+
* A hard-boundary effect declaration over plain path lists.
|
|
23
|
+
*
|
|
24
|
+
* @category models
|
|
25
|
+
* @since 0.1.0
|
|
26
|
+
*/
|
|
27
|
+
export const effects = (reads, writes) => ({ reads, writes, boundaryMode: "hard" });
|
|
28
|
+
/**
|
|
29
|
+
* A sealed node draft whose body defaults to `{ action: id }`.
|
|
30
|
+
*
|
|
31
|
+
* @category constructors
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export const draft = (id, options = {}) => ({
|
|
35
|
+
id,
|
|
36
|
+
material: {
|
|
37
|
+
version: KeyMaterial.version,
|
|
38
|
+
kind: "sealed",
|
|
39
|
+
body: options.body ?? { action: id },
|
|
40
|
+
inputs: options.inputs ?? [],
|
|
41
|
+
layers: [],
|
|
42
|
+
capabilities: []
|
|
43
|
+
},
|
|
44
|
+
effects: {
|
|
45
|
+
...effects(options.reads ?? [], options.writes ?? []),
|
|
46
|
+
...(options.removes === undefined ? {} : { removes: options.removes })
|
|
47
|
+
},
|
|
48
|
+
...(options.kind === undefined ? {} : { kind: options.kind }),
|
|
49
|
+
...(options.priority === undefined ? {} : { priority: options.priority }),
|
|
50
|
+
...(options.conflictStrategy === undefined ? {} : { conflictStrategy: options.conflictStrategy }),
|
|
51
|
+
...(options.runtimeStrategy === undefined ? {} : { runtimeStrategy: options.runtimeStrategy })
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Compiles drafts into a plan under the `example/Build` flow.
|
|
55
|
+
*
|
|
56
|
+
* @category constructors
|
|
57
|
+
* @since 0.1.0
|
|
58
|
+
*/
|
|
59
|
+
export const compile = (nodes, planId = "plan-1") => Plan.compile({ planId, flow: "example/Build", nodes });
|
|
60
|
+
//# sourceMappingURL=PlanFixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlanFixtures.js","sourceRoot":"","sources":["../../../src/test/PlanFixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,IAAI,MAAM,YAAY,CAAA;AAElC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,KAA4B,EAC5B,MAA6B,EACX,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAA;AAEhE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,EAAU,EACV,UAM0D,EAAE,EAC5C,EAAE,CAAC,CAAC;IACpB,EAAE;IACF,QAAQ,EAAE;QACR,OAAO,EAAE,WAAW,CAAC,OAAO;QAC5B,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;QAC5B,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,EAAE;KACjB;IACD,OAAO,EAAE;QACP,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;QACrD,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;KACvE;IACD,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;IAC7D,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;IACzE,GAAG,CAAC,OAAO,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC;IACjG,GAAG,CAAC,OAAO,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC;CAC/F,CAAC,CAAA;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,KAAoC,EAAE,MAAM,GAAG,QAAQ,EAAE,EAAE,CACjF,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAA","sourcesContent":["/**\n * Graph fixtures shared by every suite that needs a compiled plan.\n *\n * These live outside a `*.test.ts` file on purpose. `PlanStore.test.ts` used to\n * import `compile` and `draft` from `Plan.test.ts`, and importing a test module\n * REGISTERS ITS SUITES in the importer: every case in `Plan.test.ts` ran a\n * second time under `PlanStore.test.ts`, including the 10,000-node chain, which\n * is the most expensive case in the package. CI reported it as\n * `PlanStore.test.ts > Plan.compile > compiles a 10,000-node Ref chain` and it\n * timed out there, on a slower runner, for work `PlanStore` never asked for.\n *\n * They ship from `src/test` rather than `test/` because `@smthrs/plan-store`\n * drives the same fixtures against the persisted form, the way\n * `@smthrs/database` ships `test/TestDatabase` and `@smthrs/engine-store`\n * ships `test/TestStores`. One definition, two packages.\n *\n * @since 0.1.0\n */\n\nimport * as KeyMaterial from \"../KeyMaterial.ts\"\nimport * as Plan from \"../Plan.ts\"\n\n/**\n * A hard-boundary effect declaration over plain path lists.\n *\n * @category models\n * @since 0.1.0\n */\nexport const effects = (\n reads: ReadonlyArray<string>,\n writes: ReadonlyArray<string>\n): Plan.NodeEffects => ({ reads, writes, boundaryMode: \"hard\" })\n\n/**\n * A sealed node draft whose body defaults to `{ action: id }`.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const draft = (\n id: string,\n options: {\n readonly body?: unknown\n readonly inputs?: ReadonlyArray<KeyMaterial.InputRef>\n readonly reads?: ReadonlyArray<string>\n readonly writes?: ReadonlyArray<string>\n readonly removes?: ReadonlyArray<string>\n } & Omit<Plan.NodeDraft, \"id\" | \"material\" | \"effects\"> = {}\n): Plan.NodeDraft => ({\n id,\n material: {\n version: KeyMaterial.version,\n kind: \"sealed\",\n body: options.body ?? { action: id },\n inputs: options.inputs ?? [],\n layers: [],\n capabilities: []\n },\n effects: {\n ...effects(options.reads ?? [], options.writes ?? []),\n ...(options.removes === undefined ? {} : { removes: options.removes })\n },\n ...(options.kind === undefined ? {} : { kind: options.kind }),\n ...(options.priority === undefined ? {} : { priority: options.priority }),\n ...(options.conflictStrategy === undefined ? {} : { conflictStrategy: options.conflictStrategy }),\n ...(options.runtimeStrategy === undefined ? {} : { runtimeStrategy: options.runtimeStrategy })\n})\n\n/**\n * Compiles drafts into a plan under the `example/Build` flow.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const compile = (nodes: ReadonlyArray<Plan.NodeDraft>, planId = \"plan-1\") =>\n Plan.compile({ planId, flow: \"example/Build\", nodes })\n"]}
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "@smthrs/plan"
|
|
3
|
+
description: "Compile what a run intends to do into one keyed, content-addressed graph, grow it later without rewriting a node, and diff two graphs to say exactly what changed."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`@smthrs/plan` turns a description of work into one durable value. It compiles a
|
|
7
|
+
list of declared steps into a graph in which every node carries a content key
|
|
8
|
+
derived from what that node declares, grows that graph a generation at a time
|
|
9
|
+
without rewriting a node, and compares two graphs to say exactly what changed.
|
|
10
|
+
It runs nothing itself and performs no I/O at all.
|
|
11
|
+
|
|
12
|
+
## What it solves
|
|
13
|
+
|
|
14
|
+
A long run that calls models, builds code, and touches files has to answer two
|
|
15
|
+
questions that are awkward to answer after the fact.
|
|
16
|
+
|
|
17
|
+
The first is which work is the same work as last time. If identity is a name or
|
|
18
|
+
a position in a list, a harmless edit invalidates everything downstream and a
|
|
19
|
+
meaningful edit sometimes invalidates nothing. This package makes identity
|
|
20
|
+
computable: a node's key is a hash of its payload, its declared dependencies,
|
|
21
|
+
its layers, and its capabilities, so an edit re-keys that node and the nodes
|
|
22
|
+
that depend on it, and leaves every other key untouched. Renaming a node changes
|
|
23
|
+
no key at all, because ids are lookup addresses rather than identity.
|
|
24
|
+
|
|
25
|
+
The second is whether what executed is what somebody approved. A plan carries
|
|
26
|
+
two digests: `digest`, which moves as the plan elaborates, and `baseDigest`,
|
|
27
|
+
which still names the shape a reviewer signed off on. `Plan.append` is the only
|
|
28
|
+
way a plan changes, and it leaves every earlier node byte for byte.
|
|
29
|
+
[`@smthrs/plan-store`](/api/plan-store) keeps that honest in SQL rather than by
|
|
30
|
+
convention, with triggers that refuse a rewritten node.
|
|
31
|
+
|
|
32
|
+
Reach for this package when you are building a scheduler, a cache, or an
|
|
33
|
+
approval flow over declared work and you need step identity, declared file
|
|
34
|
+
effects, and an auditable history as values you can hold, hash, and store.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
Not on npm yet; see [Installation](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/flow/docs/installation.md#use-the-libraries).
|
|
39
|
+
|
|
40
|
+
Compiling asks Effect for its `Crypto` service, which a platform package
|
|
41
|
+
supplies:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm add @effect/platform-node@4.0.0-rc.115 @effect/platform-node-shared@4.0.0-rc.115
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
[Installation](./installation.md) covers the import forms, the package
|
|
48
|
+
persistence lives in, and browser support.
|
|
49
|
+
|
|
50
|
+
## Compile a plan
|
|
51
|
+
|
|
52
|
+
Two steps, where the second consumes the first's result and reads the file the
|
|
53
|
+
first writes:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import * as NodeCrypto from "@effect/platform-node/NodeCrypto"
|
|
57
|
+
import * as KeyMaterial from "@smthrs/plan/KeyMaterial"
|
|
58
|
+
import * as Plan from "@smthrs/plan/Plan"
|
|
59
|
+
import * as Effect from "effect/Effect"
|
|
60
|
+
|
|
61
|
+
/** Everything hashed about one node. `sealed` is work whose result may be reused across runs. */
|
|
62
|
+
const sealed = (body: unknown, inputs: ReadonlyArray<KeyMaterial.InputRef> = []): KeyMaterial.KeyMaterial => ({
|
|
63
|
+
version: KeyMaterial.version,
|
|
64
|
+
kind: "sealed",
|
|
65
|
+
body,
|
|
66
|
+
inputs,
|
|
67
|
+
layers: [],
|
|
68
|
+
capabilities: []
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const drafts: ReadonlyArray<Plan.NodeDraft> = [
|
|
72
|
+
{
|
|
73
|
+
id: "run-tests",
|
|
74
|
+
material: sealed({ action: "run-tests" }, [{ _tag: "Ref", from: "read-pr", path: [] }]),
|
|
75
|
+
effects: { reads: ["pr.json"], writes: ["report.json"], boundaryMode: "hard" }
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "read-pr",
|
|
79
|
+
material: sealed({ action: "read-pr", pr: 4821 }),
|
|
80
|
+
effects: { reads: [], writes: ["pr.json"], boundaryMode: "hard" }
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
const plan = await Effect.runPromise(
|
|
85
|
+
Plan.compile({ planId: "review-4821", flow: "example/Review", nodes: drafts }).pipe(
|
|
86
|
+
Effect.provide(NodeCrypto.layer),
|
|
87
|
+
Effect.orDie
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
console.log(plan.digest)
|
|
92
|
+
for (const node of plan.nodes) console.log(node.id, node.key, node.dependsOn)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`layers` and `capabilities` are empty here. They name the composition a node
|
|
96
|
+
runs under and the authority it claims, and both are hashed into the node's
|
|
97
|
+
key. `boundaryMode` is `hard` or `expected`: the plan carries it through to
|
|
98
|
+
whatever measures the boundary at run time and never interprets it itself.
|
|
99
|
+
[Step keys](./concepts/step-keys.md) tables every field.
|
|
100
|
+
|
|
101
|
+
The digests on your machine match these, because a plan is a pure function of
|
|
102
|
+
its declarations. Compiling reads no file, no clock, and no network:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
key1_61edccc875ff69b798e0c3874d167f65ff0a250b9fe67d27558b854fa2832302
|
|
106
|
+
read-pr key1_6353326ab2a03804d6acfe916debc4f04f09f9deb8f0e93c1ebea3cdd983db18 []
|
|
107
|
+
run-tests key1_e58229e3be2f6abf6f818baf8577fe7045edba6f5e88097b633898478da93985 [ 'read-pr' ]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The drafts went in out of order and came back topologically sorted.
|
|
111
|
+
`run-tests` names `read-pr` once, in its key material, and that single
|
|
112
|
+
declaration became both the hashed dependency and the graph edge, so an edge and
|
|
113
|
+
a key can never disagree about what a node consumes. Change `pr: 4821` to
|
|
114
|
+
another number and both keys move; rename `read-pr` to `fetch-pr` and neither
|
|
115
|
+
does.
|
|
116
|
+
|
|
117
|
+
## What is in the package
|
|
118
|
+
|
|
119
|
+
| Module | Role |
|
|
120
|
+
| ------------- | ------------------------------------------------------------------------------- |
|
|
121
|
+
| `Node` | The pure authoring AST: `succeed`, `all`, `map`, `andThen`, `branch`, `catch`. |
|
|
122
|
+
| `Planned` | The placeholder a body sees where a step result will be. |
|
|
123
|
+
| `KeyMaterial` | What a planner declares about a node: body, inputs, layers, capabilities. |
|
|
124
|
+
| `StepKey` | The compiler that turns material and resolved dependencies into a key. |
|
|
125
|
+
| `FileSet` | Patterns, globs, tree artifacts, and filegroups: the vocabulary `effects` uses. |
|
|
126
|
+
| `Plan` | `compile`, `append`, the node schemas, and the digest an approval binds to. |
|
|
127
|
+
| `PlanDiff` | A comparison of two plans as a value, with each re-key attributed to a field. |
|
|
128
|
+
| `Placement` | Where a node runs: four directives, their host detail, and the annotation key. |
|
|
129
|
+
|
|
130
|
+
The [API reference](./api.md) documents every export.
|
|
131
|
+
|
|
132
|
+
## Where this sits
|
|
133
|
+
|
|
134
|
+
`@smthrs/plan` is one package of the Smithers durable flow engine, and it owns
|
|
135
|
+
the plan phase: step identity, graph compilation, and declared file effects.
|
|
136
|
+
Storing a plan is [`@smthrs/plan-store`](/api/plan-store), which is a separate
|
|
137
|
+
package so that compiling does not drag a database in.
|
|
138
|
+
[`@smthrs/flows`](/api/flows) is the whole engine as a single dependency, and it
|
|
139
|
+
re-exports this package as its `Plan` namespace, so `Plan.compile` there is
|
|
140
|
+
`Plan.Plan.compile`. If you are writing an application rather than a scheduler,
|
|
141
|
+
install `@smthrs/flows` and reach for this package's names through it; install
|
|
142
|
+
`@smthrs/plan` on its own when you want the plan value without the engine that
|
|
143
|
+
executes it.
|
|
144
|
+
|
|
145
|
+
Nothing here executes a node. A compiled plan is inert until a scheduler drives
|
|
146
|
+
it, which is [`@smthrs/engine-store`](/api/engine-store)'s `PlanScheduler`.
|
|
147
|
+
Above this layer, [`@smthrs/flow`](/api/flow) is the authoring API most flow
|
|
148
|
+
authors write against, and it produces the drafts that arrive here. Above all of
|
|
149
|
+
it, [`@smthrs/cli`](/api/cli) is the `smthrs` command line that plans, approves,
|
|
150
|
+
runs, and inspects flows for someone who never imports a package at all.
|
|
151
|
+
|
|
152
|
+
## Next
|
|
153
|
+
|
|
154
|
+
- [Quickstart](./quickstart.md): compile a plan, append a generation, and diff
|
|
155
|
+
the two graphs.
|
|
156
|
+
- [The plan value](./concepts/plan-value.md): generations, the two digests, and
|
|
157
|
+
why a plan grows instead of being rewritten.
|
|
158
|
+
- [Step keys](./concepts/step-keys.md): what goes into a key, what deliberately
|
|
159
|
+
stays out, and why invalidation is re-keying.
|
|
160
|
+
- [Declared effects and conflicts](./concepts/effects-and-conflicts.md): how
|
|
161
|
+
reads and writes become ordering edges.
|
|
162
|
+
- [Persist a plan](https://plan-store.smithers.sh/guides/persist-a-plan/): the
|
|
163
|
+
store composition and every outcome `record` can answer with.
|
|
164
|
+
- [Troubleshooting](./troubleshooting.md): every refusal this package raises and
|
|
165
|
+
what to change.
|