@intentic/graph 1.18.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Artur Kurowski
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 ADDED
@@ -0,0 +1,29 @@
1
+ # @intentic/graph
2
+
3
+ The product-agnostic **desired-state IR** and its compiler — the data structure every other package is built around. A node's `type` is an opaque string here; the closed vocabulary lives in [`@intentic/resources`](../resources). This is the base of the dependency graph (depended on by every other package, depends on nothing internal).
4
+
5
+ ## Responsibilities
6
+
7
+ - Define the serializable graph types: `DesiredStateGraph`, `RawNode`/`ResourceNode`, `Ref`, `SecretRef`, `Readiness`.
8
+ - Compile a map of `RawNode`s into a validated, dependency-ordered `DesiredStateGraph` (`compile`).
9
+ - Provide the primitives others compose with: typed refs between nodes, env-sourced secrets, HTTP readiness gates, and ownership stamps.
10
+ - It does **not** know which resource kinds exist, how to reconcile them, or how to talk to infra — those belong to `resources`/`engine`/`providers`.
11
+
12
+ ## Key files
13
+
14
+ - [src/types.ts](src/types.ts) — the IR types (`DesiredStateGraph`, `RawNode`, `Ref`, `SecretRef`, `Readiness`).
15
+ - [src/compile.ts](src/compile.ts) — `compile`: RawNode map → graph (validates refs, fills order).
16
+ - [src/topo.ts](src/topo.ts) — `toNodeMap`, `linearize` (topological dependency order).
17
+ - [src/ref.ts](src/ref.ts) — `makeRef`/`refKey`/`isRef`, `env` (env-sourced secret), `httpOk` (readiness gate).
18
+ - [src/stamp.ts](src/stamp.ts) — `formatStamp`/`parseStamp` (resource ownership stamps).
19
+ - [src/serialize.ts](src/serialize.ts) — stable serialization of the graph.
20
+
21
+ ## How it fits
22
+
23
+ Foundational layer. `resources` constrains node `type`s on top of it; `need-resolver`, `state-resolver`, `engine`, and `sdk` all consume its types; authors import `env` from here (its true source) when writing a `deploy.config.ts`.
24
+
25
+ ## Conventions & gotchas
26
+
27
+ - Refs are typed pointers to another node's outputs — never inline a downstream value; emit a `Ref` so ordering and resolution stay correct.
28
+ - Secrets are `SecretRef`s with a `source` (`env` or `generated`); keep them as refs, never bake plaintext into a node.
29
+ - Co-located tests in [src/index.test.ts](src/index.test.ts). See [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full pipeline.
@@ -0,0 +1,3 @@
1
+ import type { DesiredStateGraph, RawNode } from "./types.js";
2
+ export declare const compile: (nodes: ReadonlyMap<string, RawNode>) => DesiredStateGraph;
3
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAiE,MAAM,YAAY,CAAC;AAY5H,eAAO,MAAM,OAAO,GAAI,OAAO,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,iBA6C7D,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { refKey } from "./ref.js";
2
+ import { collectRefs, serializeValue } from "./serialize.js";
3
+ import { topoSort } from "./topo.js";
4
+ const serializeReadiness = (readiness) => {
5
+ const url = typeof readiness.url === "string" ? readiness.url : { $ref: refKey(readiness.url.resourceId, readiness.url.output) };
6
+ return {
7
+ check: readiness.check,
8
+ url,
9
+ ...(readiness.timeout !== undefined ? { timeout: readiness.timeout } : {}),
10
+ ...(readiness.status !== undefined ? { status: readiness.status } : {}),
11
+ };
12
+ };
13
+ export const compile = (nodes) => {
14
+ const ids = [...nodes.keys()];
15
+ const known = new Set(ids);
16
+ const resources = {};
17
+ const dependsOnMap = new Map();
18
+ for (const node of nodes.values()) {
19
+ const inputs = {};
20
+ for (const [key, value] of Object.entries(node.inputs)) {
21
+ inputs[key] = serializeValue(value);
22
+ }
23
+ const referenced = [
24
+ ...node.explicitDependsOn,
25
+ ...Object.values(node.inputs).flatMap(collectRefs),
26
+ ...(node.readyWhen !== undefined ? collectRefs(node.readyWhen.url) : []),
27
+ ];
28
+ const dependsOn = [];
29
+ for (const dep of referenced) {
30
+ if (dep === node.id) {
31
+ continue;
32
+ }
33
+ if (!known.has(dep)) {
34
+ throw new Error(`resource "${node.id}" references unknown resource "${dep}"`);
35
+ }
36
+ if (!dependsOn.includes(dep)) {
37
+ dependsOn.push(dep);
38
+ }
39
+ }
40
+ const resourceNode = {
41
+ id: node.id,
42
+ type: node.type,
43
+ inputs,
44
+ dependsOn,
45
+ ...(node.readyWhen !== undefined ? { readyWhen: serializeReadiness(node.readyWhen) } : {}),
46
+ };
47
+ resources[node.id] = Object.freeze(resourceNode);
48
+ dependsOnMap.set(node.id, dependsOn);
49
+ }
50
+ topoSort(ids, dependsOnMap);
51
+ const graph = { version: 1, resources };
52
+ return Object.freeze(graph);
53
+ };
54
+ //# sourceMappingURL=compile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.js","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { DesiredStateGraph, RawNode, Readiness, Ref, SecretRef } from "./types.js";
2
+ export declare const env: (key: string) => SecretRef;
3
+ export declare const generated: (key: string) => SecretRef;
4
+ export declare const httpOk: (url: string | Ref<string>, options?: {
5
+ timeout?: string;
6
+ status?: number;
7
+ }) => Readiness;
8
+ export declare const linearize: (graph: DesiredStateGraph) => string[];
9
+ export declare const toNodeMap: (nodes: readonly RawNode[]) => Map<string, RawNode>;
10
+ export { compile } from "./compile.js";
11
+ export { isRef, makeRef, refKey } from "./ref.js";
12
+ export { formatStamp, parseStamp, STAMP_KEY } from "./stamp.js";
13
+ export type { DesiredStateGraph, Input, RawNode, Readiness, Ref, ResourceNode, SecretRef, SecretSource, SerializedReadiness, SerializedValue, } from "./types.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExF,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM,KAAG,SAAkE,CAAC;AAIrG,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,KAAG,SAAwE,CAAC;AAEjH,eAAO,MAAM,MAAM,GAAI,KAAK,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,SAO9F,CAAC;AAEP,eAAO,MAAM,SAAS,GAAI,OAAO,iBAAiB,KAAG,MAAM,EAO1D,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,OAAO,SAAS,OAAO,EAAE,KAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CASxE,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEhE,YAAY,EACR,iBAAiB,EACjB,KAAK,EACL,OAAO,EACP,SAAS,EACT,GAAG,EACH,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,eAAe,GAClB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ import { topoSort } from "./topo.js";
2
+ export const env = (key) => Object.freeze({ kind: "secret", source: "env", key });
3
+ export const generated = (key) => Object.freeze({ kind: "secret", source: "generated", key });
4
+ export const httpOk = (url, options) => Object.freeze({
5
+ kind: "readiness",
6
+ check: "httpOk",
7
+ url,
8
+ ...(options?.timeout !== undefined ? { timeout: options.timeout } : {}),
9
+ ...(options?.status !== undefined ? { status: options.status } : {}),
10
+ });
11
+ export const linearize = (graph) => {
12
+ const ids = Object.keys(graph.resources);
13
+ const dependsOn = new Map();
14
+ for (const id of ids) {
15
+ dependsOn.set(id, graph.resources[id]?.dependsOn ?? []);
16
+ }
17
+ return topoSort(ids, dependsOn);
18
+ };
19
+ export const toNodeMap = (nodes) => {
20
+ const map = new Map();
21
+ for (const node of nodes) {
22
+ if (map.has(node.id)) {
23
+ throw new Error(`duplicate resource id: "${node.id}"`);
24
+ }
25
+ map.set(node.id, node);
26
+ }
27
+ return map;
28
+ };
29
+ export { compile } from "./compile.js";
30
+ export { isRef, makeRef, refKey } from "./ref.js";
31
+ export { formatStamp, parseStamp, STAMP_KEY } from "./stamp.js";
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,GAAW,EAAa,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;AAIrG,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAa,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;AAEjH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,GAAyB,EAAE,OAA+C,EAAa,EAAE,CAC5G,MAAM,CAAC,MAAM,CAAC;IACV,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,QAAQ;IACf,GAAG;IACH,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CACvE,CAAC,CAAC;AAEP,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAwB,EAAY,EAAE;IAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,GAAG,EAA6B,CAAC;IACvD,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACnB,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AACpC,CAAC,CAAC;AAGF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAyB,EAAwB,EAAE;IACzE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmB,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3D,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
package/dist/ref.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { Ref, SecretRef } from "./types.js";
2
+ export declare const makeRef: <T = unknown>(resourceId: string, output?: string) => Ref<T>;
3
+ export declare const refKey: (resourceId: string, output?: string) => string;
4
+ export declare const isRef: (value: unknown) => value is Ref<unknown>;
5
+ export declare const isSecret: (value: unknown) => value is SecretRef;
6
+ //# sourceMappingURL=ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../src/ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,OAAO,GAAI,CAAC,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,SAAS,MAAM,KAAG,GAAG,CAAC,CAAC,CACqC,CAAC;AAItH,eAAO,MAAM,MAAM,GAAI,YAAY,MAAM,EAAE,SAAS,MAAM,KAAG,MAAyE,CAAC;AAEvI,eAAO,MAAM,KAAK,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,GAAG,CAAC,OAAO,CACoC,CAAC;AAEhG,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,SAC+C,CAAC"}
package/dist/ref.js ADDED
@@ -0,0 +1,5 @@
1
+ export const makeRef = (resourceId, output) => Object.freeze(output === undefined ? { kind: "ref", resourceId } : { kind: "ref", resourceId, output });
2
+ export const refKey = (resourceId, output) => (output === undefined ? resourceId : `${resourceId}.${output}`);
3
+ export const isRef = (value) => typeof value === "object" && value !== null && value.kind === "ref";
4
+ export const isSecret = (value) => typeof value === "object" && value !== null && value.kind === "secret";
5
+ //# sourceMappingURL=ref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref.js","sourceRoot":"","sources":["../src/ref.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAG,CAAc,UAAkB,EAAE,MAAe,EAAU,EAAE,CAChF,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAAW,CAAC;AAItH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAAkB,EAAE,MAAe,EAAU,EAAE,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,MAAM,EAAE,CAAC,CAAC;AAEvI,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAc,EAAyB,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAA4B,CAAC,IAAI,KAAK,KAAK,CAAC;AAEhG,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAsB,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAA4B,CAAC,IAAI,KAAK,QAAQ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { SerializedValue } from "./types.js";
2
+ export declare const serializeValue: (value: unknown) => SerializedValue;
3
+ export declare const collectRefs: (value: unknown) => string[];
4
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,eAqB/C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,MAAM,EAclD,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { isRef, isSecret, refKey } from "./ref.js";
2
+ export const serializeValue = (value) => {
3
+ if (isRef(value)) {
4
+ return { $ref: refKey(value.resourceId, value.output) };
5
+ }
6
+ if (isSecret(value)) {
7
+ return { $secret: { source: value.source, key: value.key } };
8
+ }
9
+ if (Array.isArray(value)) {
10
+ return value.map(serializeValue);
11
+ }
12
+ if (typeof value === "object" && value !== null) {
13
+ const result = {};
14
+ for (const [key, entry] of Object.entries(value)) {
15
+ result[key] = serializeValue(entry);
16
+ }
17
+ return result;
18
+ }
19
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
20
+ return value;
21
+ }
22
+ throw new Error(`cannot serialize value of type ${typeof value}`);
23
+ };
24
+ export const collectRefs = (value) => {
25
+ if (isRef(value)) {
26
+ return [value.resourceId];
27
+ }
28
+ if (isSecret(value)) {
29
+ return [];
30
+ }
31
+ if (Array.isArray(value)) {
32
+ return value.flatMap(collectRefs);
33
+ }
34
+ if (typeof value === "object" && value !== null) {
35
+ return Object.values(value).flatMap(collectRefs);
36
+ }
37
+ return [];
38
+ };
39
+ //# sourceMappingURL=serialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGnD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAc,EAAmB,EAAE;IAC9D,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAoC,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QACvF,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,OAAO,KAAK,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAc,EAAY,EAAE;IACpD,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAClB,OAAO,EAAE,CAAC;IACd,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC9C,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,EAAE,CAAC;AACd,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const STAMP_KEY = "intentic.id";
2
+ export declare const formatStamp: (id: string) => string;
3
+ export declare const parseStamp: (encoded: string) => string | undefined;
4
+ //# sourceMappingURL=stamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stamp.d.ts","sourceRoot":"","sources":["../src/stamp.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,SAAS,gBAAgB,CAAC;AAEvC,eAAO,MAAM,WAAW,GAAI,IAAI,MAAM,KAAG,MAA8B,CAAC;AAExE,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,SAGrD,CAAC"}
package/dist/stamp.js ADDED
@@ -0,0 +1,7 @@
1
+ export const STAMP_KEY = "intentic.id";
2
+ export const formatStamp = (id) => `${STAMP_KEY}=${id}`;
3
+ export const parseStamp = (encoded) => {
4
+ const prefix = `${STAMP_KEY}=`;
5
+ return encoded.startsWith(prefix) ? encoded.slice(prefix.length) : undefined;
6
+ };
7
+ //# sourceMappingURL=stamp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stamp.js","sourceRoot":"","sources":["../src/stamp.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,CAAC;AAEvC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,GAAG,SAAS,IAAI,EAAE,EAAE,CAAC;AAExE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAe,EAAsB,EAAE;IAC9D,MAAM,MAAM,GAAG,GAAG,SAAS,GAAG,CAAC;IAC/B,OAAO,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC,CAAC"}
package/dist/topo.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare const topoSort: (ids: readonly string[], dependsOn: ReadonlyMap<string, readonly string[]>) => string[];
2
+ //# sourceMappingURL=topo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topo.d.ts","sourceRoot":"","sources":["../src/topo.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,GAAI,KAAK,SAAS,MAAM,EAAE,EAAE,WAAW,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,KAAG,MAAM,EAoC1G,CAAC"}
package/dist/topo.js ADDED
@@ -0,0 +1,36 @@
1
+ export const topoSort = (ids, dependsOn) => {
2
+ const inDegree = new Map();
3
+ const dependents = new Map();
4
+ for (const id of ids) {
5
+ inDegree.set(id, 0);
6
+ dependents.set(id, []);
7
+ }
8
+ for (const id of ids) {
9
+ for (const dep of dependsOn.get(id) ?? []) {
10
+ inDegree.set(id, (inDegree.get(id) ?? 0) + 1);
11
+ dependents.get(dep)?.push(id);
12
+ }
13
+ }
14
+ const queue = ids.filter((id) => (inDegree.get(id) ?? 0) === 0);
15
+ const order = [];
16
+ while (queue.length > 0) {
17
+ const id = queue.shift();
18
+ if (id === undefined) {
19
+ break;
20
+ }
21
+ order.push(id);
22
+ for (const dependent of dependents.get(id) ?? []) {
23
+ const remaining = (inDegree.get(dependent) ?? 0) - 1;
24
+ inDegree.set(dependent, remaining);
25
+ if (remaining === 0) {
26
+ queue.push(dependent);
27
+ }
28
+ }
29
+ }
30
+ if (order.length !== ids.length) {
31
+ const cycle = ids.filter((id) => !order.includes(id));
32
+ throw new Error(`dependency cycle: ${cycle.join(" -> ")}`);
33
+ }
34
+ return order;
35
+ };
36
+ //# sourceMappingURL=topo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topo.js","sourceRoot":"","sources":["../src/topo.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAsB,EAAE,SAAiD,EAAY,EAAE;IAC5G,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC/C,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACnB,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACpB,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3B,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACnB,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YACxC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9C,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAChE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACnB,MAAM;QACV,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACrD,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACnC,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;gBAClB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACL,CAAC;IACL,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC"}
@@ -0,0 +1,57 @@
1
+ export interface Ref<T> {
2
+ readonly kind: "ref";
3
+ readonly resourceId: string;
4
+ readonly output?: string;
5
+ readonly __type?: T;
6
+ }
7
+ export type SecretSource = "env" | "generated";
8
+ export interface SecretRef {
9
+ readonly kind: "secret";
10
+ readonly source: SecretSource;
11
+ readonly key: string;
12
+ }
13
+ export interface Readiness {
14
+ readonly kind: "readiness";
15
+ readonly check: "httpOk";
16
+ readonly url: string | Ref<string>;
17
+ readonly timeout?: string;
18
+ readonly status?: number;
19
+ }
20
+ export type Input<T> = T | Ref<T> | (T extends string ? SecretRef : never);
21
+ export interface RawNode {
22
+ readonly id: string;
23
+ readonly type: string;
24
+ readonly inputs: Readonly<Record<string, unknown>>;
25
+ readonly explicitDependsOn: readonly string[];
26
+ readonly readyWhen?: Readiness;
27
+ }
28
+ export type SerializedValue = string | number | boolean | {
29
+ readonly $ref: string;
30
+ } | {
31
+ readonly $secret: {
32
+ readonly source: SecretSource;
33
+ readonly key: string;
34
+ };
35
+ } | readonly SerializedValue[] | {
36
+ readonly [key: string]: SerializedValue;
37
+ };
38
+ export interface SerializedReadiness {
39
+ readonly check: "httpOk";
40
+ readonly url: string | {
41
+ readonly $ref: string;
42
+ };
43
+ readonly timeout?: string;
44
+ readonly status?: number;
45
+ }
46
+ export interface ResourceNode {
47
+ readonly id: string;
48
+ readonly type: string;
49
+ readonly inputs: Readonly<Record<string, SerializedValue>>;
50
+ readonly dependsOn: readonly string[];
51
+ readonly readyWhen?: SerializedReadiness;
52
+ }
53
+ export interface DesiredStateGraph {
54
+ readonly version: 1;
55
+ readonly resources: Readonly<Record<string, ResourceNode>>;
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,GAAG,CAAC,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;CACvB;AAID,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,WAAW,CAAC;AAE/C,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;AAI3E,MAAM,WAAW,OAAO;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAClC;AAID,MAAM,MAAM,eAAe,GACrB,MAAM,GACN,MAAM,GACN,OAAO,GACP;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC7E,SAAS,eAAe,EAAE,GAC1B;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,CAAA;CAAE,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;CAC9D"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@intentic/graph",
3
+ "version": "1.18.0",
4
+ "description": "",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/radarsu/intentic.git",
10
+ "directory": "_libs/graph"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org/"
18
+ },
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": {
23
+ "@intentic/src": "./src/index.ts",
24
+ "default": "./dist/index.js"
25
+ },
26
+ "require": {
27
+ "@intentic/src": "./src/index.ts",
28
+ "default": "./dist/index.js"
29
+ }
30
+ }
31
+ },
32
+ "dependencies": {
33
+ "tslib": "2.8.1"
34
+ },
35
+ "devDependencies": {
36
+ "typescript": "5.9.3",
37
+ "vitest": "4.1.9",
38
+ "@intentic/tsconfig": "0.0.0"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "watch": "tsc --build --watch",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest"
45
+ }
46
+ }