@treeseed/sdk 0.10.27 → 0.11.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/README.md +207 -6
- package/dist/capacity-provider.d.ts +3 -1
- package/dist/capacity-provider.js +25 -5
- package/dist/control-plane.d.ts +1 -0
- package/dist/control-plane.js +38 -13
- package/dist/db/market-schema.d.ts +8860 -6172
- package/dist/db/market-schema.js +108 -0
- package/dist/db/node-sqlite.js +7 -2
- package/dist/hosting/apps.d.ts +12 -0
- package/dist/hosting/apps.js +107 -0
- package/dist/hosting/builtins.d.ts +25 -0
- package/dist/hosting/builtins.js +791 -0
- package/dist/hosting/contracts.d.ts +207 -0
- package/dist/hosting/contracts.js +0 -0
- package/dist/hosting/graph.d.ts +192 -0
- package/dist/hosting/graph.js +1106 -0
- package/dist/hosting/index.d.ts +4 -0
- package/dist/hosting/index.js +4 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.js +71 -7
- package/dist/managed-dependencies.js +1 -2
- package/dist/market-client.d.ts +63 -3
- package/dist/market-client.js +83 -11
- package/dist/operations/services/bootstrap-runner.d.ts +3 -1
- package/dist/operations/services/bootstrap-runner.js +22 -2
- package/dist/operations/services/config-runtime.d.ts +10 -5
- package/dist/operations/services/config-runtime.js +209 -66
- package/dist/operations/services/deploy.d.ts +70 -7
- package/dist/operations/services/deploy.js +579 -64
- package/dist/operations/services/deployment-readiness.d.ts +30 -0
- package/dist/operations/services/deployment-readiness.js +175 -0
- package/dist/operations/services/git-workflow.d.ts +2 -1
- package/dist/operations/services/git-workflow.js +9 -3
- package/dist/operations/services/github-actions-verification.d.ts +1 -0
- package/dist/operations/services/github-actions-verification.js +1 -0
- package/dist/operations/services/github-api.js +1 -1
- package/dist/operations/services/github-automation.d.ts +1 -1
- package/dist/operations/services/github-automation.js +4 -3
- package/dist/operations/services/github-credentials.d.ts +13 -0
- package/dist/operations/services/github-credentials.js +58 -0
- package/dist/operations/services/hosted-service-checks.d.ts +63 -0
- package/dist/operations/services/hosted-service-checks.js +327 -0
- package/dist/operations/services/hub-provider-launch.js +3 -3
- package/dist/operations/services/live-hosted-service-checks.d.ts +25 -0
- package/dist/operations/services/live-hosted-service-checks.js +350 -0
- package/dist/operations/services/managed-host-security.js +1 -1
- package/dist/operations/services/operations-runner-smoke.d.ts +30 -0
- package/dist/operations/services/operations-runner-smoke.js +180 -0
- package/dist/operations/services/package-adapters.d.ts +95 -0
- package/dist/operations/services/package-adapters.js +288 -0
- package/dist/operations/services/package-reference-policy.d.ts +1 -0
- package/dist/operations/services/package-reference-policy.js +15 -2
- package/dist/operations/services/project-platform.d.ts +80 -22
- package/dist/operations/services/project-platform.js +49 -8
- package/dist/operations/services/project-web-monitor.js +26 -4
- package/dist/operations/services/railway-api.d.ts +88 -5
- package/dist/operations/services/railway-api.js +626 -35
- package/dist/operations/services/railway-deploy.d.ts +46 -40
- package/dist/operations/services/railway-deploy.js +261 -293
- package/dist/operations/services/release-candidate.d.ts +19 -0
- package/dist/operations/services/release-candidate.js +375 -38
- package/dist/operations/services/repository-save-orchestrator.d.ts +3 -1
- package/dist/operations/services/repository-save-orchestrator.js +279 -66
- package/dist/operations/services/runtime-tools.d.ts +1 -0
- package/dist/operations/services/runtime-tools.js +10 -9
- package/dist/operations/services/template-registry.js +14 -7
- package/dist/operations/services/verification-cache.d.ts +25 -0
- package/dist/operations/services/verification-cache.js +71 -0
- package/dist/operations/services/workspace-dependency-mode.js +9 -1
- package/dist/operations/services/workspace-save.js +1 -1
- package/dist/operations/services/workspace-tools.js +2 -1
- package/dist/platform/contracts.d.ts +32 -1
- package/dist/platform/deploy-config.js +73 -8
- package/dist/platform/env.yaml +163 -35
- package/dist/platform/environment.d.ts +1 -0
- package/dist/platform/environment.js +74 -5
- package/dist/platform/plugin.d.ts +9 -0
- package/dist/platform-operation-store.js +2 -2
- package/dist/platform-operations.js +1 -1
- package/dist/reconcile/bootstrap-systems.js +2 -2
- package/dist/reconcile/builtin-adapters.js +372 -189
- package/dist/reconcile/contracts.d.ts +9 -5
- package/dist/reconcile/desired-state.d.ts +1 -0
- package/dist/reconcile/desired-state.js +5 -5
- package/dist/reconcile/engine.d.ts +5 -2
- package/dist/reconcile/engine.js +53 -32
- package/dist/reconcile/index.d.ts +2 -0
- package/dist/reconcile/index.js +2 -0
- package/dist/reconcile/live-acceptance.d.ts +79 -0
- package/dist/reconcile/live-acceptance.js +1615 -0
- package/dist/reconcile/platform.d.ts +104 -0
- package/dist/reconcile/platform.js +100 -0
- package/dist/reconcile/state.js +4 -4
- package/dist/reconcile/units.js +2 -2
- package/dist/scripts/deployment-readiness.js +20 -0
- package/dist/scripts/generate-treedx-openapi-types.js +186 -0
- package/dist/scripts/operations-runner-smoke.js +16 -0
- package/dist/scripts/release-verify.js +4 -1
- package/dist/scripts/template-catalog.test.js +7 -7
- package/dist/scripts/tenant-workflow-action.js +10 -1
- package/dist/sdk-types.d.ts +172 -5
- package/dist/sdk-types.js +28 -3
- package/dist/sdk.d.ts +35 -24
- package/dist/sdk.js +186 -17
- package/dist/template-launch-requirements.js +9 -0
- package/dist/treedx/adapters.d.ts +6 -0
- package/dist/treedx/adapters.js +36 -0
- package/dist/treedx/client.d.ts +222 -0
- package/dist/treedx/client.js +871 -0
- package/dist/treedx/errors.d.ts +13 -0
- package/dist/treedx/errors.js +17 -0
- package/dist/treedx/federated-client.d.ts +27 -0
- package/dist/treedx/federated-client.js +158 -0
- package/dist/treedx/generated/openapi-types.d.ts +3558 -0
- package/dist/treedx/generated/openapi-types.js +0 -0
- package/dist/treedx/graph-adapter.d.ts +33 -0
- package/dist/treedx/graph-adapter.js +156 -0
- package/dist/treedx/index.d.ts +14 -0
- package/dist/treedx/index.js +48 -0
- package/dist/treedx/market-integration.d.ts +27 -0
- package/dist/treedx/market-integration.js +131 -0
- package/dist/treedx/ports.d.ts +166 -0
- package/dist/treedx/ports.js +231 -0
- package/dist/treedx/query-adapter.d.ts +19 -0
- package/dist/treedx/query-adapter.js +62 -0
- package/dist/treedx/registry-client.d.ts +11 -0
- package/dist/treedx/registry-client.js +19 -0
- package/dist/treedx/repository-adapter.d.ts +45 -0
- package/dist/treedx/repository-adapter.js +308 -0
- package/dist/treedx/sdk-integration.d.ts +27 -0
- package/dist/treedx/sdk-integration.js +63 -0
- package/dist/treedx/types.d.ts +1084 -0
- package/dist/treedx/types.js +8 -0
- package/dist/treedx/workspace-adapter.d.ts +27 -0
- package/dist/treedx/workspace-adapter.js +65 -0
- package/dist/treedx-backends.d.ts +218 -0
- package/dist/treedx-backends.js +632 -0
- package/dist/treedx-client.d.ts +86 -0
- package/dist/treedx-client.js +175 -0
- package/dist/treeseed/template-catalog/catalog.fixture.json +497 -138
- package/dist/workflow/operations.d.ts +119 -13
- package/dist/workflow/operations.js +309 -53
- package/dist/workflow-state.d.ts +13 -0
- package/dist/workflow-state.js +43 -26
- package/dist/workflow-support.d.ts +11 -3
- package/dist/workflow-support.js +67 -3
- package/dist/workflow.d.ts +5 -0
- package/drizzle/market/0004_treedx_market_integration.sql +99 -0
- package/package.json +34 -3
- package/templates/github/deploy-web.workflow.yml +39 -6
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +0 -3
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +0 -6
- package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +0 -35
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +0 -4
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +0 -65
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +0 -22
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +0 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +0 -11
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +0 -11
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +0 -11
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +0 -17
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +0 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +0 -3
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +0 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +0 -26
- package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +0 -74
- package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +0 -9
- package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +0 -103
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export declare const TREESEED_RECONCILE_RUN_MODEL: readonly ["refresh", "plan", "validate", "apply", "refresh", "verify", "persist"];
|
|
2
|
+
export declare const TREESEED_RECONCILE_ACTION_KINDS: readonly ["noop", "create", "update", "replace", "delete", "adopt", "rename", "reattach", "retain", "taint", "blocked"];
|
|
3
|
+
export type TreeseedCanonicalReconcilePhase = typeof TREESEED_RECONCILE_RUN_MODEL[number];
|
|
4
|
+
export type TreeseedCanonicalReconcileActionKind = typeof TREESEED_RECONCILE_ACTION_KINDS[number];
|
|
5
|
+
export interface TreeseedCanonicalGraphNode {
|
|
6
|
+
id: string;
|
|
7
|
+
provider?: string | null;
|
|
8
|
+
type?: string | null;
|
|
9
|
+
owner?: string | null;
|
|
10
|
+
environment?: string | null;
|
|
11
|
+
spec?: unknown;
|
|
12
|
+
state?: unknown;
|
|
13
|
+
locators?: Record<string, unknown>;
|
|
14
|
+
metadata?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
export interface TreeseedCanonicalDrift {
|
|
17
|
+
id: string;
|
|
18
|
+
resourceId?: string | null;
|
|
19
|
+
severity?: 'info' | 'warning' | 'blocking';
|
|
20
|
+
reason: string;
|
|
21
|
+
expected?: unknown;
|
|
22
|
+
observed?: unknown;
|
|
23
|
+
provider?: string | null;
|
|
24
|
+
type?: string | null;
|
|
25
|
+
}
|
|
26
|
+
export interface TreeseedCanonicalAction {
|
|
27
|
+
id: string;
|
|
28
|
+
kind: TreeseedCanonicalReconcileActionKind;
|
|
29
|
+
resourceId: string;
|
|
30
|
+
reason: string;
|
|
31
|
+
provider?: string | null;
|
|
32
|
+
type?: string | null;
|
|
33
|
+
before?: unknown;
|
|
34
|
+
after?: unknown;
|
|
35
|
+
}
|
|
36
|
+
export interface TreeseedCanonicalPostcondition {
|
|
37
|
+
id: string;
|
|
38
|
+
resourceId: string;
|
|
39
|
+
description: string;
|
|
40
|
+
source?: 'api' | 'cli' | 'sdk' | 'http' | 'local' | 'derived';
|
|
41
|
+
required?: boolean;
|
|
42
|
+
ok: boolean;
|
|
43
|
+
issues: string[];
|
|
44
|
+
expected?: unknown;
|
|
45
|
+
observed?: unknown;
|
|
46
|
+
}
|
|
47
|
+
export interface TreeseedCanonicalLiveVerification {
|
|
48
|
+
ok: boolean;
|
|
49
|
+
source?: string;
|
|
50
|
+
checkedAt?: string | null;
|
|
51
|
+
issues: string[];
|
|
52
|
+
checks?: unknown[];
|
|
53
|
+
}
|
|
54
|
+
export interface TreeseedCanonicalReconcileReport {
|
|
55
|
+
desiredGraph: TreeseedCanonicalGraphNode[];
|
|
56
|
+
observedGraph: TreeseedCanonicalGraphNode[];
|
|
57
|
+
stateGraph: TreeseedCanonicalGraphNode[];
|
|
58
|
+
diff: TreeseedCanonicalDrift[];
|
|
59
|
+
actions: TreeseedCanonicalAction[];
|
|
60
|
+
postconditions: TreeseedCanonicalPostcondition[];
|
|
61
|
+
selectedResources: string[];
|
|
62
|
+
skippedResources: Array<{
|
|
63
|
+
id: string;
|
|
64
|
+
reason: string;
|
|
65
|
+
}>;
|
|
66
|
+
blockedDrift: TreeseedCanonicalDrift[];
|
|
67
|
+
providerLimitations: TreeseedCanonicalDrift[];
|
|
68
|
+
retainedResources: TreeseedCanonicalGraphNode[];
|
|
69
|
+
destroyedResources: TreeseedCanonicalGraphNode[];
|
|
70
|
+
liveVerification: TreeseedCanonicalLiveVerification;
|
|
71
|
+
ok: boolean;
|
|
72
|
+
}
|
|
73
|
+
export interface CreateTreeseedCanonicalReconcileReportInput {
|
|
74
|
+
desiredGraph?: TreeseedCanonicalGraphNode[];
|
|
75
|
+
observedGraph?: TreeseedCanonicalGraphNode[];
|
|
76
|
+
stateGraph?: TreeseedCanonicalGraphNode[];
|
|
77
|
+
diff?: TreeseedCanonicalDrift[];
|
|
78
|
+
actions?: TreeseedCanonicalAction[];
|
|
79
|
+
postconditions?: TreeseedCanonicalPostcondition[];
|
|
80
|
+
selectedResources?: string[];
|
|
81
|
+
skippedResources?: Array<{
|
|
82
|
+
id: string;
|
|
83
|
+
reason: string;
|
|
84
|
+
}>;
|
|
85
|
+
blockedDrift?: TreeseedCanonicalDrift[];
|
|
86
|
+
providerLimitations?: TreeseedCanonicalDrift[];
|
|
87
|
+
retainedResources?: TreeseedCanonicalGraphNode[];
|
|
88
|
+
destroyedResources?: TreeseedCanonicalGraphNode[];
|
|
89
|
+
liveVerification?: Partial<TreeseedCanonicalLiveVerification>;
|
|
90
|
+
}
|
|
91
|
+
export declare function createTreeseedCanonicalReconcileReport(input?: CreateTreeseedCanonicalReconcileReportInput): TreeseedCanonicalReconcileReport;
|
|
92
|
+
export declare function assertTreeseedCanonicalReconcileSuccess(report: TreeseedCanonicalReconcileReport): void;
|
|
93
|
+
export declare function summarizeTreeseedCanonicalReconcileReport(report: TreeseedCanonicalReconcileReport): {
|
|
94
|
+
ok: boolean;
|
|
95
|
+
desired: number;
|
|
96
|
+
observed: number;
|
|
97
|
+
actions: number;
|
|
98
|
+
postconditions: number;
|
|
99
|
+
blockedDrift: number;
|
|
100
|
+
providerLimitations: number;
|
|
101
|
+
retainedResources: number;
|
|
102
|
+
destroyedResources: number;
|
|
103
|
+
liveVerificationOk: boolean;
|
|
104
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const TREESEED_RECONCILE_RUN_MODEL = [
|
|
2
|
+
"refresh",
|
|
3
|
+
"plan",
|
|
4
|
+
"validate",
|
|
5
|
+
"apply",
|
|
6
|
+
"refresh",
|
|
7
|
+
"verify",
|
|
8
|
+
"persist"
|
|
9
|
+
];
|
|
10
|
+
const TREESEED_RECONCILE_ACTION_KINDS = [
|
|
11
|
+
"noop",
|
|
12
|
+
"create",
|
|
13
|
+
"update",
|
|
14
|
+
"replace",
|
|
15
|
+
"delete",
|
|
16
|
+
"adopt",
|
|
17
|
+
"rename",
|
|
18
|
+
"reattach",
|
|
19
|
+
"retain",
|
|
20
|
+
"taint",
|
|
21
|
+
"blocked"
|
|
22
|
+
];
|
|
23
|
+
function hasBlockingAction(actions) {
|
|
24
|
+
return actions.some((action) => action.kind === "blocked");
|
|
25
|
+
}
|
|
26
|
+
function liveVerificationOk(input, postconditions) {
|
|
27
|
+
if (input?.ok === false) return false;
|
|
28
|
+
if ((input?.issues ?? []).length > 0) return false;
|
|
29
|
+
return postconditions.every((postcondition) => postcondition.required === false || postcondition.ok);
|
|
30
|
+
}
|
|
31
|
+
function createTreeseedCanonicalReconcileReport(input = {}) {
|
|
32
|
+
const desiredGraph = input.desiredGraph ?? [];
|
|
33
|
+
const observedGraph = input.observedGraph ?? [];
|
|
34
|
+
const stateGraph = input.stateGraph ?? [];
|
|
35
|
+
const diff = input.diff ?? [];
|
|
36
|
+
const actions = input.actions ?? [];
|
|
37
|
+
const postconditions = input.postconditions ?? [];
|
|
38
|
+
const selectedResources = input.selectedResources ?? desiredGraph.map((node) => node.id);
|
|
39
|
+
const skippedResources = input.skippedResources ?? [];
|
|
40
|
+
const blockedDrift = input.blockedDrift ?? diff.filter((entry) => entry.severity === "blocking");
|
|
41
|
+
const providerLimitations = input.providerLimitations ?? [];
|
|
42
|
+
const retainedResources = input.retainedResources ?? [];
|
|
43
|
+
const destroyedResources = input.destroyedResources ?? [];
|
|
44
|
+
const liveVerification = {
|
|
45
|
+
ok: input.liveVerification?.ok ?? liveVerificationOk(input.liveVerification, postconditions),
|
|
46
|
+
source: input.liveVerification?.source ?? "sdk",
|
|
47
|
+
checkedAt: input.liveVerification?.checkedAt ?? null,
|
|
48
|
+
issues: input.liveVerification?.issues ?? [],
|
|
49
|
+
checks: input.liveVerification?.checks ?? []
|
|
50
|
+
};
|
|
51
|
+
const ok = liveVerification.ok && blockedDrift.length === 0 && providerLimitations.length === 0 && !hasBlockingAction(actions) && postconditions.every((postcondition) => postcondition.required === false || postcondition.ok);
|
|
52
|
+
return {
|
|
53
|
+
desiredGraph,
|
|
54
|
+
observedGraph,
|
|
55
|
+
stateGraph,
|
|
56
|
+
diff,
|
|
57
|
+
actions,
|
|
58
|
+
postconditions,
|
|
59
|
+
selectedResources,
|
|
60
|
+
skippedResources,
|
|
61
|
+
blockedDrift,
|
|
62
|
+
providerLimitations,
|
|
63
|
+
retainedResources,
|
|
64
|
+
destroyedResources,
|
|
65
|
+
liveVerification,
|
|
66
|
+
ok
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function assertTreeseedCanonicalReconcileSuccess(report) {
|
|
70
|
+
if (report.ok) return;
|
|
71
|
+
const reasons = [
|
|
72
|
+
...report.blockedDrift.map((entry) => `blocked drift ${entry.id}: ${entry.reason}`),
|
|
73
|
+
...report.providerLimitations.map((entry) => `provider limitation ${entry.id}: ${entry.reason}`),
|
|
74
|
+
...report.actions.filter((action) => action.kind === "blocked").map((action) => `blocked action ${action.id}: ${action.reason}`),
|
|
75
|
+
...report.postconditions.filter((postcondition) => postcondition.required !== false && !postcondition.ok).map((postcondition) => `postcondition ${postcondition.id}: ${postcondition.issues.join("; ") || "failed"}`),
|
|
76
|
+
...report.liveVerification.issues.map((issue) => `live verification: ${issue}`)
|
|
77
|
+
];
|
|
78
|
+
throw new Error(`Treeseed reconciliation did not converge: ${reasons.join(" | ") || "unknown drift remained"}`);
|
|
79
|
+
}
|
|
80
|
+
function summarizeTreeseedCanonicalReconcileReport(report) {
|
|
81
|
+
return {
|
|
82
|
+
ok: report.ok,
|
|
83
|
+
desired: report.desiredGraph.length,
|
|
84
|
+
observed: report.observedGraph.length,
|
|
85
|
+
actions: report.actions.length,
|
|
86
|
+
postconditions: report.postconditions.length,
|
|
87
|
+
blockedDrift: report.blockedDrift.length,
|
|
88
|
+
providerLimitations: report.providerLimitations.length,
|
|
89
|
+
retainedResources: report.retainedResources.length,
|
|
90
|
+
destroyedResources: report.destroyedResources.length,
|
|
91
|
+
liveVerificationOk: report.liveVerification.ok
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
TREESEED_RECONCILE_ACTION_KINDS,
|
|
96
|
+
TREESEED_RECONCILE_RUN_MODEL,
|
|
97
|
+
assertTreeseedCanonicalReconcileSuccess,
|
|
98
|
+
createTreeseedCanonicalReconcileReport,
|
|
99
|
+
summarizeTreeseedCanonicalReconcileReport
|
|
100
|
+
};
|
package/dist/reconcile/state.js
CHANGED
|
@@ -6,8 +6,8 @@ function stableHash(value) {
|
|
|
6
6
|
return createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
7
7
|
}
|
|
8
8
|
function railwayUnitTypeForServiceKey(serviceKey) {
|
|
9
|
-
if (serviceKey === "
|
|
10
|
-
return "railway-service:
|
|
9
|
+
if (serviceKey === "operationsRunner") {
|
|
10
|
+
return "railway-service:operations-runner";
|
|
11
11
|
}
|
|
12
12
|
if (serviceKey === "workdayManager") {
|
|
13
13
|
return "railway-service:workday-manager";
|
|
@@ -271,7 +271,7 @@ function loadTreeseedReconcileState(tenantRoot, target) {
|
|
|
271
271
|
return {
|
|
272
272
|
version: 1,
|
|
273
273
|
target,
|
|
274
|
-
dependencyGraphVersion: legacyState.
|
|
274
|
+
dependencyGraphVersion: legacyState.reconciliation?.dependencyGraphVersion ?? 1,
|
|
275
275
|
units: { ...persistedUnits }
|
|
276
276
|
};
|
|
277
277
|
}
|
|
@@ -280,7 +280,7 @@ function writeTreeseedReconcileState(tenantRoot, reconcileState) {
|
|
|
280
280
|
const legacyState = loadDeployState(tenantRoot, deployConfig, { target: reconcileState.target });
|
|
281
281
|
writeDeployState(tenantRoot, {
|
|
282
282
|
...legacyState,
|
|
283
|
-
|
|
283
|
+
reconciliation: {
|
|
284
284
|
version: reconcileState.version,
|
|
285
285
|
dependencyGraphVersion: reconcileState.dependencyGraphVersion,
|
|
286
286
|
targetKey: targetKey(reconcileState.target)
|
package/dist/reconcile/units.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const TRESEED_RECONCILE_UNIT_TYPES = [
|
|
2
2
|
"web-ui",
|
|
3
3
|
"api-runtime",
|
|
4
|
-
"
|
|
4
|
+
"operations-runner-runtime",
|
|
5
5
|
"workday-manager-runtime",
|
|
6
6
|
"worker-runner-runtime",
|
|
7
7
|
"edge-worker",
|
|
@@ -15,7 +15,7 @@ const TRESEED_RECONCILE_UNIT_TYPES = [
|
|
|
15
15
|
"custom-domain:api",
|
|
16
16
|
"dns-record",
|
|
17
17
|
"railway-service:api",
|
|
18
|
-
"railway-service:
|
|
18
|
+
"railway-service:operations-runner",
|
|
19
19
|
"railway-service:workday-manager",
|
|
20
20
|
"railway-service:worker-runner"
|
|
21
21
|
];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { collectTreeseedDeploymentReadiness, formatTreeseedReadinessReport } from '../operations/services/deployment-readiness.js';
|
|
2
|
+
function arg(name) {
|
|
3
|
+
const index = process.argv.indexOf(name);
|
|
4
|
+
return index >= 0 ? process.argv[index + 1] : null;
|
|
5
|
+
}
|
|
6
|
+
const environment = (arg('--environment') ?? 'staging');
|
|
7
|
+
const strict = process.argv.includes('--strict');
|
|
8
|
+
const report = collectTreeseedDeploymentReadiness({
|
|
9
|
+
tenantRoot: process.cwd(),
|
|
10
|
+
environment,
|
|
11
|
+
});
|
|
12
|
+
if (process.argv.includes('--json')) {
|
|
13
|
+
console.log(JSON.stringify(report, null, 2));
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
console.log(formatTreeseedReadinessReport(report));
|
|
17
|
+
}
|
|
18
|
+
if (strict && !report.ok) {
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, relative, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { parse, stringify } from 'yaml';
|
|
5
|
+
const check = process.argv.includes('--check');
|
|
6
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
7
|
+
const workspaceRoot = resolve(packageRoot, '../..');
|
|
8
|
+
const workspaceOpenApiPath = resolve(workspaceRoot, 'docs/api/openapi.yaml');
|
|
9
|
+
const packageOpenApiPath = resolve(packageRoot, 'docs/api/openapi.yaml');
|
|
10
|
+
const openApiPath = existsSync(workspaceOpenApiPath) ? workspaceOpenApiPath : packageOpenApiPath;
|
|
11
|
+
const workspaceOpenApiJsonPath = resolve(workspaceRoot, 'docs/api/openapi.json');
|
|
12
|
+
const packageOpenApiJsonPath = resolve(packageRoot, 'docs/api/openapi.json');
|
|
13
|
+
const outPath = resolve(packageRoot, 'src/treedx/generated/openapi-types.ts');
|
|
14
|
+
const openApi = parse(readFileSync(openApiPath, 'utf8'));
|
|
15
|
+
function refName(ref) {
|
|
16
|
+
return ref.split('/').pop() ?? ref;
|
|
17
|
+
}
|
|
18
|
+
function schemaRefType(ref) {
|
|
19
|
+
return `components['schemas']['${refName(ref)}']`;
|
|
20
|
+
}
|
|
21
|
+
function literal(value) {
|
|
22
|
+
return JSON.stringify(value);
|
|
23
|
+
}
|
|
24
|
+
function key(name) {
|
|
25
|
+
return /^[A-Za-z_$][\w$]*$/u.test(name) ? name : JSON.stringify(name);
|
|
26
|
+
}
|
|
27
|
+
function typeForSchema(schema) {
|
|
28
|
+
if (!schema || typeof schema !== 'object')
|
|
29
|
+
return 'unknown';
|
|
30
|
+
const s = schema;
|
|
31
|
+
if (typeof s.$ref === 'string')
|
|
32
|
+
return schemaRefType(s.$ref);
|
|
33
|
+
if ('const' in s)
|
|
34
|
+
return literal(s.const);
|
|
35
|
+
if (Array.isArray(s.enum))
|
|
36
|
+
return s.enum.map(literal).join(' | ') || 'never';
|
|
37
|
+
if (Array.isArray(s.oneOf))
|
|
38
|
+
return s.oneOf.map(typeForSchema).join(' | ') || 'unknown';
|
|
39
|
+
if (Array.isArray(s.anyOf))
|
|
40
|
+
return s.anyOf.map(typeForSchema).join(' | ') || 'unknown';
|
|
41
|
+
if (Array.isArray(s.allOf))
|
|
42
|
+
return s.allOf.map(typeForSchema).join(' & ') || 'unknown';
|
|
43
|
+
if (s.nullable === true)
|
|
44
|
+
return `${typeForSchema({ ...s, nullable: undefined })} | null`;
|
|
45
|
+
if (s.type === 'string')
|
|
46
|
+
return 'string';
|
|
47
|
+
if (s.type === 'integer' || s.type === 'number')
|
|
48
|
+
return 'number';
|
|
49
|
+
if (s.type === 'boolean')
|
|
50
|
+
return 'boolean';
|
|
51
|
+
if (s.type === 'null')
|
|
52
|
+
return 'null';
|
|
53
|
+
if (s.type === 'array')
|
|
54
|
+
return `${typeForSchema(s.items)}[]`;
|
|
55
|
+
if (s.type === 'object' || s.properties || s.additionalProperties !== undefined) {
|
|
56
|
+
const properties = (s.properties ?? {});
|
|
57
|
+
const required = new Set(Array.isArray(s.required) ? s.required.map(String) : []);
|
|
58
|
+
const parts = Object.entries(properties).map(([name, prop]) => {
|
|
59
|
+
const optional = required.has(name) ? '' : '?';
|
|
60
|
+
return `${key(name)}${optional}: ${typeForSchema(prop)};`;
|
|
61
|
+
});
|
|
62
|
+
if (s.additionalProperties === true) {
|
|
63
|
+
parts.push('[key: string]: unknown;');
|
|
64
|
+
}
|
|
65
|
+
else if (s.additionalProperties && typeof s.additionalProperties === 'object') {
|
|
66
|
+
parts.push(`[key: string]: ${typeForSchema(s.additionalProperties)};`);
|
|
67
|
+
}
|
|
68
|
+
return parts.length > 0 ? `{ ${parts.join(' ')} }` : 'Record<string, never>';
|
|
69
|
+
}
|
|
70
|
+
return 'unknown';
|
|
71
|
+
}
|
|
72
|
+
function parametersFor(operation, location) {
|
|
73
|
+
const params = Array.isArray(operation.parameters) ? operation.parameters : [];
|
|
74
|
+
const entries = params
|
|
75
|
+
.filter((param) => typeof param === 'object' && param !== null && param.in === location)
|
|
76
|
+
.map((param) => {
|
|
77
|
+
const name = String(param.name);
|
|
78
|
+
const optional = param.required === true ? '' : '?';
|
|
79
|
+
return `${key(name)}${optional}: ${typeForSchema(param.schema)};`;
|
|
80
|
+
});
|
|
81
|
+
return entries.length > 0 ? `{ ${entries.join(' ')} }` : 'never';
|
|
82
|
+
}
|
|
83
|
+
function requestBodyFor(operation) {
|
|
84
|
+
const body = operation.requestBody;
|
|
85
|
+
const content = body?.content ?? {};
|
|
86
|
+
const json = content['application/json']?.schema;
|
|
87
|
+
if (json)
|
|
88
|
+
return typeForSchema(json);
|
|
89
|
+
const octets = content['application/octet-stream']?.schema;
|
|
90
|
+
if (octets)
|
|
91
|
+
return 'ArrayBuffer | Uint8Array | Blob';
|
|
92
|
+
return 'never';
|
|
93
|
+
}
|
|
94
|
+
function responseFor(response) {
|
|
95
|
+
if (!response || typeof response !== 'object')
|
|
96
|
+
return 'unknown';
|
|
97
|
+
if (typeof response.$ref === 'string') {
|
|
98
|
+
const name = refName(response.$ref);
|
|
99
|
+
if (name === 'Error')
|
|
100
|
+
return "components['schemas']['TreeDxErrorEnvelope']";
|
|
101
|
+
if (name === 'Ok')
|
|
102
|
+
return "components['schemas']['TreeDxOkEnvelope']";
|
|
103
|
+
}
|
|
104
|
+
const r = response;
|
|
105
|
+
const content = r.content ?? {};
|
|
106
|
+
const json = content['application/json']?.schema;
|
|
107
|
+
if (json)
|
|
108
|
+
return typeForSchema(json);
|
|
109
|
+
const octets = content['application/octet-stream']?.schema;
|
|
110
|
+
if (octets)
|
|
111
|
+
return 'ArrayBuffer';
|
|
112
|
+
return 'unknown';
|
|
113
|
+
}
|
|
114
|
+
function operationType(operation) {
|
|
115
|
+
const responses = operation.responses ?? {};
|
|
116
|
+
const responseEntries = Object.entries(responses).map(([status, response]) => `${JSON.stringify(status)}: ${responseFor(response)};`);
|
|
117
|
+
return [
|
|
118
|
+
'{',
|
|
119
|
+
`parameters: { path: ${parametersFor(operation, 'path')}; query: ${parametersFor(operation, 'query')}; header: ${parametersFor(operation, 'header')}; };`,
|
|
120
|
+
`requestBody: ${requestBodyFor(operation)};`,
|
|
121
|
+
`responses: { ${responseEntries.join(' ')} };`,
|
|
122
|
+
'}',
|
|
123
|
+
].join(' ');
|
|
124
|
+
}
|
|
125
|
+
const schemas = openApi.components?.schemas ?? {};
|
|
126
|
+
const schemaLines = Object.entries(schemas)
|
|
127
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
128
|
+
.map(([name, schema]) => `${key(name)}: ${typeForSchema(schema)};`);
|
|
129
|
+
const operationEntries = [];
|
|
130
|
+
const pathLines = [];
|
|
131
|
+
for (const [path, methods] of Object.entries(openApi.paths ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
|
|
132
|
+
const methodLines = [];
|
|
133
|
+
for (const [method, operation] of Object.entries(methods).sort(([a], [b]) => a.localeCompare(b))) {
|
|
134
|
+
if (!operation?.operationId)
|
|
135
|
+
continue;
|
|
136
|
+
operationEntries.push([operation.operationId, operation]);
|
|
137
|
+
methodLines.push(`${method}: operations['${operation.operationId}'];`);
|
|
138
|
+
}
|
|
139
|
+
pathLines.push(`${JSON.stringify(path)}: { ${methodLines.join(' ')} };`);
|
|
140
|
+
}
|
|
141
|
+
const operationLines = operationEntries
|
|
142
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
143
|
+
.map(([id, operation]) => `${key(id)}: ${operationType(operation)};`);
|
|
144
|
+
const generated = `// Generated from docs/api/openapi.yaml. Do not edit by hand.
|
|
145
|
+
|
|
146
|
+
export interface paths {
|
|
147
|
+
${pathLines.map((line) => `\t${line}`).join('\n')}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface components {
|
|
151
|
+
\tschemas: {
|
|
152
|
+
${schemaLines.map((line) => `\t\t${line}`).join('\n')}
|
|
153
|
+
\t};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface operations {
|
|
157
|
+
${operationLines.map((line) => `\t${line}`).join('\n')}
|
|
158
|
+
}
|
|
159
|
+
`;
|
|
160
|
+
const current = (() => {
|
|
161
|
+
try {
|
|
162
|
+
return readFileSync(outPath, 'utf8');
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
})();
|
|
168
|
+
if (check && current !== generated) {
|
|
169
|
+
console.error(`${relative(process.cwd(), outPath)} is not up to date. Run npm run treedx:generate-types.`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
if (!check) {
|
|
173
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
174
|
+
writeFileSync(outPath, generated, 'utf8');
|
|
175
|
+
for (const target of [workspaceOpenApiJsonPath, packageOpenApiJsonPath]) {
|
|
176
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
177
|
+
writeFileSync(target, `${JSON.stringify(openApi, null, 2)}\n`, 'utf8');
|
|
178
|
+
}
|
|
179
|
+
if (openApiPath === workspaceOpenApiPath) {
|
|
180
|
+
mkdirSync(dirname(packageOpenApiPath), { recursive: true });
|
|
181
|
+
writeFileSync(packageOpenApiPath, stringify(openApi), 'utf8');
|
|
182
|
+
}
|
|
183
|
+
console.log(`Wrote ${relative(process.cwd(), outPath)}`);
|
|
184
|
+
console.log(`Wrote ${relative(process.cwd(), workspaceOpenApiJsonPath)}`);
|
|
185
|
+
console.log(`Wrote ${relative(process.cwd(), packageOpenApiJsonPath)}`);
|
|
186
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { runTreeseedOperationsRunnerSmoke } from '../operations/services/operations-runner-smoke.js';
|
|
2
|
+
function arg(name) {
|
|
3
|
+
const index = process.argv.indexOf(name);
|
|
4
|
+
return index >= 0 ? process.argv[index + 1] : null;
|
|
5
|
+
}
|
|
6
|
+
const environment = (arg('--environment') ?? 'staging') === 'prod' ? 'prod' : 'staging';
|
|
7
|
+
const report = await runTreeseedOperationsRunnerSmoke({
|
|
8
|
+
tenantRoot: process.cwd(),
|
|
9
|
+
environment,
|
|
10
|
+
baseUrl: arg('--base-url'),
|
|
11
|
+
timeoutMs: arg('--timeout-ms') ? Number(arg('--timeout-ms')) : undefined,
|
|
12
|
+
});
|
|
13
|
+
console.log(JSON.stringify(report, null, 2));
|
|
14
|
+
if (!report.ok) {
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
}
|
|
@@ -101,5 +101,8 @@ assertNoLocalDependencyLinks();
|
|
|
101
101
|
run('npm', ['run', 'lint']);
|
|
102
102
|
scanDirectory(resolve(packageRoot, 'dist'));
|
|
103
103
|
assertCleanDistArtifacts();
|
|
104
|
-
run('npm', ['run', 'test:
|
|
104
|
+
run('npm', ['run', 'test:release']);
|
|
105
|
+
if (process.env.TREESEED_SDK_VERIFY_WORKFLOW_LIFECYCLE === '1') {
|
|
106
|
+
run('npm', ['run', 'test:workflow:lifecycle']);
|
|
107
|
+
}
|
|
105
108
|
run('npm', ['run', 'test:smoke']);
|
|
@@ -36,8 +36,8 @@ function writeCatalogCache(root, endpoint, items) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const starterTemplate = {
|
|
39
|
-
id: '
|
|
40
|
-
displayName: '
|
|
39
|
+
id: 'fixture-template',
|
|
40
|
+
displayName: 'Fixture Template',
|
|
41
41
|
description: 'Starter',
|
|
42
42
|
summary: 'Starter summary',
|
|
43
43
|
status: 'live',
|
|
@@ -53,7 +53,7 @@ const starterTemplate = {
|
|
|
53
53
|
fulfillment: {
|
|
54
54
|
source: {
|
|
55
55
|
repoUrl: 'https://example.com/repo.git',
|
|
56
|
-
directory: 'templates/
|
|
56
|
+
directory: 'templates/fixture-template',
|
|
57
57
|
ref: 'main',
|
|
58
58
|
},
|
|
59
59
|
hooksPolicy: 'builtin_only',
|
|
@@ -69,7 +69,7 @@ test('template registry reads the remote catalog from a configured file endpoint
|
|
|
69
69
|
|
|
70
70
|
const remoteProducts = await listTemplateProducts({ cwd, env: {} });
|
|
71
71
|
assert.equal(remoteProducts.length, 1);
|
|
72
|
-
assert.equal(remoteProducts[0]?.id, '
|
|
72
|
+
assert.equal(remoteProducts[0]?.id, 'fixture-template');
|
|
73
73
|
|
|
74
74
|
writeCatalogCache(cwd, fallbackEndpoint, [starterTemplate]);
|
|
75
75
|
|
|
@@ -83,7 +83,7 @@ test('template registry reads the remote catalog from a configured file endpoint
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
assert.equal(cachedProducts.length, 1);
|
|
86
|
-
assert.equal(cachedProducts[0]?.id, '
|
|
86
|
+
assert.equal(cachedProducts[0]?.id, 'fixture-template');
|
|
87
87
|
assert.equal(warnings.length, 1);
|
|
88
88
|
assert.match(warnings[0], /Using cached template catalog/);
|
|
89
89
|
});
|
|
@@ -94,7 +94,7 @@ test('template definition resolution rejects templates missing from the remote c
|
|
|
94
94
|
const cwd = makeMachineConfigRoot(`file:${fixturePath}`);
|
|
95
95
|
|
|
96
96
|
await assert.rejects(
|
|
97
|
-
() => resolveTemplateDefinition('
|
|
98
|
-
/Unable to resolve remote template product "
|
|
97
|
+
() => resolveTemplateDefinition('fixture-template', { cwd, env: {} }),
|
|
98
|
+
/Unable to resolve remote template product "fixture-template"\./,
|
|
99
99
|
);
|
|
100
100
|
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
|
-
import { resolveScope, runProjectPlatformAction, } from '../operations/services/project-platform.js';
|
|
4
3
|
const tenantRoot = process.cwd();
|
|
4
|
+
function writeStatus(message) {
|
|
5
|
+
process.stderr.write(`[tenant-workflow-action] ${message}\n`);
|
|
6
|
+
}
|
|
5
7
|
function parseArgs(argv) {
|
|
6
8
|
const parsed = {
|
|
7
9
|
action: 'deploy_web',
|
|
@@ -65,17 +67,24 @@ async function main() {
|
|
|
65
67
|
const options = parseArgs(process.argv.slice(2));
|
|
66
68
|
process.env.TREESEED_WORKFLOW_ACTION = options.action;
|
|
67
69
|
process.env.TREESEED_WORKFLOW_PLANE ||= 'web';
|
|
70
|
+
writeStatus(`start action=${options.action} environment=${options.environment ?? '(auto)'}`);
|
|
71
|
+
writeStatus('loading project platform module...');
|
|
72
|
+
const { resolveScope, runProjectPlatformAction } = await import('../operations/services/project-platform.js');
|
|
73
|
+
writeStatus('project platform module loaded.');
|
|
68
74
|
const scope = resolveScope(options.environment);
|
|
75
|
+
writeStatus(`resolved scope=${scope}; running action...`);
|
|
69
76
|
const result = await runProjectPlatformAction(options.action, {
|
|
70
77
|
tenantRoot,
|
|
71
78
|
scope,
|
|
72
79
|
projectId: options.projectId ?? process.env.TREESEED_PROJECT_ID ?? null,
|
|
73
80
|
previewId: options.previewId,
|
|
74
81
|
dryRun: options.dryRun,
|
|
82
|
+
write: (line) => writeStatus(line),
|
|
75
83
|
});
|
|
76
84
|
if (result !== undefined) {
|
|
77
85
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
78
86
|
}
|
|
87
|
+
writeStatus('complete.');
|
|
79
88
|
}
|
|
80
89
|
function isCliEntrypoint() {
|
|
81
90
|
if (!process.argv[1]) {
|