@treeseed/sdk 0.5.3 → 0.6.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/dist/index.d.ts +2 -0
- package/dist/index.js +46 -0
- package/dist/operations/providers/default.js +1 -1
- package/dist/operations/services/config-runtime.d.ts +49 -42
- package/dist/operations/services/config-runtime.js +449 -136
- package/dist/operations/services/deploy.d.ts +298 -0
- package/dist/operations/services/deploy.js +381 -137
- package/dist/operations/services/git-workflow.d.ts +9 -0
- package/dist/operations/services/git-workflow.js +32 -0
- package/dist/operations/services/github-api.d.ts +115 -0
- package/dist/operations/services/github-api.js +455 -0
- package/dist/operations/services/github-automation.d.ts +19 -33
- package/dist/operations/services/github-automation.js +44 -131
- package/dist/operations/services/key-agent.d.ts +20 -1
- package/dist/operations/services/key-agent.js +267 -102
- package/dist/operations/services/knowledge-coop-launch.d.ts +2 -3
- package/dist/operations/services/knowledge-coop-launch.js +26 -12
- package/dist/operations/services/project-platform.d.ts +157 -150
- package/dist/operations/services/project-platform.js +129 -26
- package/dist/operations/services/railway-api.d.ts +244 -0
- package/dist/operations/services/railway-api.js +882 -0
- package/dist/operations/services/railway-deploy.d.ts +171 -27
- package/dist/operations/services/railway-deploy.js +672 -172
- package/dist/operations/services/runtime-tools.d.ts +18 -0
- package/dist/operations/services/runtime-tools.js +19 -6
- package/dist/operations/services/workspace-preflight.js +2 -2
- package/dist/platform/contracts.d.ts +7 -0
- package/dist/platform/deploy-config.js +23 -0
- package/dist/platform/deploy-runtime.d.ts +1 -0
- package/dist/platform/deploy-runtime.js +7 -9
- package/dist/platform/env.yaml +10 -9
- package/dist/platform/environment.js +4 -0
- package/dist/platform/plugin.d.ts +6 -0
- package/dist/platform/plugins/constants.d.ts +1 -0
- package/dist/platform/plugins/constants.js +1 -0
- package/dist/platform/plugins/runtime.d.ts +4 -0
- package/dist/platform/plugins/runtime.js +8 -1
- package/dist/platform/published-content.js +27 -4
- package/dist/platform/tenant/runtime-config.js +33 -24
- package/dist/plugin-default.d.ts +1 -0
- package/dist/plugin-default.js +1 -0
- package/dist/reconcile/builtin-adapters.d.ts +3 -0
- package/dist/reconcile/builtin-adapters.js +2093 -0
- package/dist/reconcile/contracts.d.ts +155 -0
- package/dist/reconcile/contracts.js +0 -0
- package/dist/reconcile/desired-state.d.ts +179 -0
- package/dist/reconcile/desired-state.js +319 -0
- package/dist/reconcile/engine.d.ts +405 -0
- package/dist/reconcile/engine.js +356 -0
- package/dist/reconcile/errors.d.ts +5 -0
- package/dist/reconcile/errors.js +13 -0
- package/dist/reconcile/index.d.ts +7 -0
- package/dist/reconcile/index.js +7 -0
- package/dist/reconcile/registry.d.ts +7 -0
- package/dist/reconcile/registry.js +64 -0
- package/dist/reconcile/state.d.ts +7 -0
- package/dist/reconcile/state.js +303 -0
- package/dist/reconcile/units.d.ts +6 -0
- package/dist/reconcile/units.js +68 -0
- package/dist/scripts/config-treeseed.js +27 -19
- package/dist/scripts/tenant-deploy.js +35 -14
- package/dist/workflow/operations.js +127 -22
- package/dist/workflow-support.d.ts +3 -1
- package/dist/workflow-support.js +50 -0
- package/dist/workflow.d.ts +2 -0
- package/package.json +7 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { TreeseedDeployConfig } from '../platform/contracts.ts';
|
|
2
|
+
export type TreeseedReconcileProviderId = string;
|
|
3
|
+
export type TreeseedReconcileActionKind = 'noop' | 'create' | 'update' | 'reuse' | 'drift_correct' | 'destroy';
|
|
4
|
+
export type TreeseedReconcileStatusKind = 'pending' | 'ready' | 'drifted' | 'error';
|
|
5
|
+
export type TreeseedReconcileVerificationSource = 'cli' | 'api' | 'sdk' | 'derived';
|
|
6
|
+
export type TreeseedReconcileUnitType = 'web-ui' | 'api-runtime' | 'manager-runtime' | 'worker-runtime' | 'workday-start-runtime' | 'workday-report-runtime' | 'edge-worker' | 'content-store' | 'queue' | 'database' | 'kv-form-guard' | 'kv-session' | 'pages-project' | 'custom-domain:web' | 'custom-domain:api' | 'dns-record' | 'railway-service:api' | 'railway-service:manager' | 'railway-service:worker' | 'railway-service:workday-start' | 'railway-service:workday-report';
|
|
7
|
+
export type TreeseedReconcileTarget = {
|
|
8
|
+
kind: 'persistent';
|
|
9
|
+
scope: 'local' | 'staging' | 'prod';
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'branch';
|
|
12
|
+
branchName: string;
|
|
13
|
+
};
|
|
14
|
+
export type TreeseedReconcileUnitId = string;
|
|
15
|
+
export interface TreeseedReconcileIdentity {
|
|
16
|
+
teamId: string;
|
|
17
|
+
projectId: string;
|
|
18
|
+
slug: string;
|
|
19
|
+
environment: string;
|
|
20
|
+
deploymentKey: string;
|
|
21
|
+
environmentKey: string;
|
|
22
|
+
}
|
|
23
|
+
export interface TreeseedDesiredUnit {
|
|
24
|
+
unitId: TreeseedReconcileUnitId;
|
|
25
|
+
unitType: TreeseedReconcileUnitType;
|
|
26
|
+
provider: TreeseedReconcileProviderId;
|
|
27
|
+
identity: TreeseedReconcileIdentity;
|
|
28
|
+
target: TreeseedReconcileTarget;
|
|
29
|
+
logicalName: string;
|
|
30
|
+
dependencies: TreeseedReconcileUnitId[];
|
|
31
|
+
spec: Record<string, unknown>;
|
|
32
|
+
secrets: Record<string, string | null | undefined>;
|
|
33
|
+
metadata: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
export interface TreeseedObservedUnitState {
|
|
36
|
+
exists: boolean;
|
|
37
|
+
status: TreeseedReconcileStatusKind;
|
|
38
|
+
live: Record<string, unknown>;
|
|
39
|
+
locators: Record<string, string | null>;
|
|
40
|
+
warnings: string[];
|
|
41
|
+
}
|
|
42
|
+
export interface TreeseedUnitDiff {
|
|
43
|
+
action: TreeseedReconcileActionKind;
|
|
44
|
+
reasons: string[];
|
|
45
|
+
before: Record<string, unknown>;
|
|
46
|
+
after: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
export interface TreeseedUnitPersistedState {
|
|
49
|
+
unitId: TreeseedReconcileUnitId;
|
|
50
|
+
unitType: TreeseedReconcileUnitType;
|
|
51
|
+
provider: TreeseedReconcileProviderId;
|
|
52
|
+
identity: TreeseedReconcileIdentity;
|
|
53
|
+
target: TreeseedReconcileTarget;
|
|
54
|
+
logicalName: string;
|
|
55
|
+
desiredSpecHash: string;
|
|
56
|
+
lastObservedAt: string | null;
|
|
57
|
+
lastReconciledAt: string | null;
|
|
58
|
+
lastVerifiedAt: string | null;
|
|
59
|
+
lastStatus: TreeseedReconcileStatusKind;
|
|
60
|
+
lastObservedState: Record<string, unknown>;
|
|
61
|
+
lastReconciledState: Record<string, unknown>;
|
|
62
|
+
lastDiff: TreeseedUnitDiff | null;
|
|
63
|
+
lastVerification: TreeseedUnitVerificationResult | null;
|
|
64
|
+
lastAction: TreeseedReconcileActionKind | null;
|
|
65
|
+
resourceLocators: Record<string, string | null>;
|
|
66
|
+
warnings: string[];
|
|
67
|
+
error: string | null;
|
|
68
|
+
}
|
|
69
|
+
export interface TreeseedUnitPostcondition {
|
|
70
|
+
key: string;
|
|
71
|
+
description: string;
|
|
72
|
+
}
|
|
73
|
+
export interface TreeseedUnitVerificationCheck {
|
|
74
|
+
key: string;
|
|
75
|
+
description: string;
|
|
76
|
+
source: TreeseedReconcileVerificationSource;
|
|
77
|
+
exists: boolean;
|
|
78
|
+
configured: boolean;
|
|
79
|
+
ready: boolean;
|
|
80
|
+
verified: boolean;
|
|
81
|
+
expected?: unknown;
|
|
82
|
+
observed?: unknown;
|
|
83
|
+
issues: string[];
|
|
84
|
+
}
|
|
85
|
+
export interface TreeseedUnitVerificationResult {
|
|
86
|
+
unitId: TreeseedReconcileUnitId;
|
|
87
|
+
supported: boolean;
|
|
88
|
+
exists: boolean;
|
|
89
|
+
configured: boolean;
|
|
90
|
+
ready: boolean;
|
|
91
|
+
verified: boolean;
|
|
92
|
+
checks: TreeseedUnitVerificationCheck[];
|
|
93
|
+
missing: string[];
|
|
94
|
+
drifted: string[];
|
|
95
|
+
warnings: string[];
|
|
96
|
+
}
|
|
97
|
+
export interface TreeseedReconcilePlan {
|
|
98
|
+
unit: TreeseedDesiredUnit;
|
|
99
|
+
observed: TreeseedObservedUnitState;
|
|
100
|
+
diff: TreeseedUnitDiff;
|
|
101
|
+
persisted: TreeseedUnitPersistedState | null;
|
|
102
|
+
}
|
|
103
|
+
export interface TreeseedReconcileResult {
|
|
104
|
+
unit: TreeseedDesiredUnit;
|
|
105
|
+
observed: TreeseedObservedUnitState;
|
|
106
|
+
diff: TreeseedUnitDiff;
|
|
107
|
+
action: TreeseedReconcileActionKind;
|
|
108
|
+
warnings: string[];
|
|
109
|
+
resourceLocators: Record<string, string | null>;
|
|
110
|
+
state: Record<string, unknown>;
|
|
111
|
+
verification: TreeseedUnitVerificationResult | null;
|
|
112
|
+
}
|
|
113
|
+
export interface TreeseedReconcileRunContext {
|
|
114
|
+
tenantRoot: string;
|
|
115
|
+
target: TreeseedReconcileTarget;
|
|
116
|
+
deployConfig: TreeseedDeployConfig;
|
|
117
|
+
launchEnv: NodeJS.ProcessEnv;
|
|
118
|
+
write?: (line: string) => void;
|
|
119
|
+
session: Map<string, unknown>;
|
|
120
|
+
}
|
|
121
|
+
export interface TreeseedReconcileAdapterInput {
|
|
122
|
+
context: TreeseedReconcileRunContext;
|
|
123
|
+
unit: TreeseedDesiredUnit;
|
|
124
|
+
persistedState: TreeseedUnitPersistedState | null;
|
|
125
|
+
}
|
|
126
|
+
export interface TreeseedReconcileAdapter {
|
|
127
|
+
providerId: TreeseedReconcileProviderId;
|
|
128
|
+
unitTypes: TreeseedReconcileUnitType[];
|
|
129
|
+
supports(unitType: TreeseedReconcileUnitType, providerId: TreeseedReconcileProviderId): boolean;
|
|
130
|
+
validate?(input: TreeseedReconcileAdapterInput): Promise<void> | void;
|
|
131
|
+
requiredPostconditions?(input: TreeseedReconcileAdapterInput): Promise<TreeseedUnitPostcondition[]> | TreeseedUnitPostcondition[];
|
|
132
|
+
observe(input: TreeseedReconcileAdapterInput): Promise<TreeseedObservedUnitState> | TreeseedObservedUnitState;
|
|
133
|
+
plan(input: TreeseedReconcileAdapterInput & {
|
|
134
|
+
observed: TreeseedObservedUnitState;
|
|
135
|
+
}): Promise<TreeseedUnitDiff> | TreeseedUnitDiff;
|
|
136
|
+
reconcile(input: TreeseedReconcileAdapterInput & {
|
|
137
|
+
observed: TreeseedObservedUnitState;
|
|
138
|
+
diff: TreeseedUnitDiff;
|
|
139
|
+
}): Promise<TreeseedReconcileResult> | TreeseedReconcileResult;
|
|
140
|
+
verify(input: TreeseedReconcileAdapterInput & {
|
|
141
|
+
observed: TreeseedObservedUnitState;
|
|
142
|
+
diff: TreeseedUnitDiff;
|
|
143
|
+
result: TreeseedReconcileResult | null;
|
|
144
|
+
postconditions: TreeseedUnitPostcondition[];
|
|
145
|
+
}): Promise<TreeseedUnitVerificationResult> | TreeseedUnitVerificationResult;
|
|
146
|
+
destroy?(input: TreeseedReconcileAdapterInput & {
|
|
147
|
+
observed: TreeseedObservedUnitState;
|
|
148
|
+
}): Promise<TreeseedReconcileResult> | TreeseedReconcileResult;
|
|
149
|
+
}
|
|
150
|
+
export interface TreeseedReconcileStateRecord {
|
|
151
|
+
version: 1;
|
|
152
|
+
target: TreeseedReconcileTarget;
|
|
153
|
+
dependencyGraphVersion: number;
|
|
154
|
+
units: Record<TreeseedReconcileUnitId, TreeseedUnitPersistedState>;
|
|
155
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { TreeseedDesiredUnit, TreeseedReconcileTarget } from './contracts.ts';
|
|
2
|
+
export declare function deriveTreeseedDesiredUnits({ tenantRoot, target, }: {
|
|
3
|
+
tenantRoot: string;
|
|
4
|
+
target: TreeseedReconcileTarget;
|
|
5
|
+
}): {
|
|
6
|
+
deployConfig: {
|
|
7
|
+
name: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
siteUrl: string;
|
|
10
|
+
contactEmail: string;
|
|
11
|
+
hosting: {
|
|
12
|
+
kind: string;
|
|
13
|
+
registration: any;
|
|
14
|
+
marketBaseUrl: any;
|
|
15
|
+
teamId: any;
|
|
16
|
+
projectId: any;
|
|
17
|
+
};
|
|
18
|
+
hub: {
|
|
19
|
+
mode: string;
|
|
20
|
+
};
|
|
21
|
+
runtime: {
|
|
22
|
+
mode: string;
|
|
23
|
+
registration: any;
|
|
24
|
+
marketBaseUrl: any;
|
|
25
|
+
teamId: any;
|
|
26
|
+
projectId: any;
|
|
27
|
+
};
|
|
28
|
+
cloudflare: {
|
|
29
|
+
accountId: string;
|
|
30
|
+
zoneId: string | undefined;
|
|
31
|
+
workerName: string | undefined;
|
|
32
|
+
queueName: string | undefined;
|
|
33
|
+
dlqName: string | undefined;
|
|
34
|
+
d1Binding: string | undefined;
|
|
35
|
+
queueBinding: string | undefined;
|
|
36
|
+
pages: {
|
|
37
|
+
projectName: string | undefined;
|
|
38
|
+
previewProjectName: string | undefined;
|
|
39
|
+
productionBranch: string;
|
|
40
|
+
stagingBranch: string;
|
|
41
|
+
buildOutputDir: string | undefined;
|
|
42
|
+
} | undefined;
|
|
43
|
+
r2: {
|
|
44
|
+
binding: string | undefined;
|
|
45
|
+
bucketName: string | undefined;
|
|
46
|
+
publicBaseUrl: string | undefined;
|
|
47
|
+
manifestKeyTemplate: string;
|
|
48
|
+
previewRootTemplate: string;
|
|
49
|
+
previewTtlHours: number;
|
|
50
|
+
} | undefined;
|
|
51
|
+
};
|
|
52
|
+
plugins: {
|
|
53
|
+
package: string;
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
}[] | {
|
|
56
|
+
package: string;
|
|
57
|
+
enabled: boolean | undefined;
|
|
58
|
+
config: any;
|
|
59
|
+
}[];
|
|
60
|
+
providers: {
|
|
61
|
+
forms: string;
|
|
62
|
+
agents: {
|
|
63
|
+
execution: string;
|
|
64
|
+
mutation: string;
|
|
65
|
+
repository: string;
|
|
66
|
+
verification: string;
|
|
67
|
+
notification: string;
|
|
68
|
+
research: string;
|
|
69
|
+
};
|
|
70
|
+
deploy: string;
|
|
71
|
+
dns: string;
|
|
72
|
+
content: {
|
|
73
|
+
runtime: string;
|
|
74
|
+
publish: string;
|
|
75
|
+
docs: string;
|
|
76
|
+
serving: any;
|
|
77
|
+
};
|
|
78
|
+
site: string;
|
|
79
|
+
};
|
|
80
|
+
surfaces: {
|
|
81
|
+
[k: string]: {
|
|
82
|
+
enabled: boolean | undefined;
|
|
83
|
+
provider: string | undefined;
|
|
84
|
+
rootDir: string | undefined;
|
|
85
|
+
publicBaseUrl: string | undefined;
|
|
86
|
+
localBaseUrl: string | undefined;
|
|
87
|
+
environments: {
|
|
88
|
+
local: {
|
|
89
|
+
baseUrl: string | undefined;
|
|
90
|
+
domain: string | undefined;
|
|
91
|
+
railwayEnvironment: string | undefined;
|
|
92
|
+
};
|
|
93
|
+
staging: {
|
|
94
|
+
baseUrl: string | undefined;
|
|
95
|
+
domain: string | undefined;
|
|
96
|
+
railwayEnvironment: string | undefined;
|
|
97
|
+
};
|
|
98
|
+
prod: {
|
|
99
|
+
baseUrl: string | undefined;
|
|
100
|
+
domain: string | undefined;
|
|
101
|
+
railwayEnvironment: string | undefined;
|
|
102
|
+
};
|
|
103
|
+
} | undefined;
|
|
104
|
+
cache: {
|
|
105
|
+
sourcePages: {
|
|
106
|
+
browserTtlSeconds: number | undefined;
|
|
107
|
+
edgeTtlSeconds: number | undefined;
|
|
108
|
+
staleWhileRevalidateSeconds: number | undefined;
|
|
109
|
+
staleIfErrorSeconds: number | undefined;
|
|
110
|
+
} | {
|
|
111
|
+
paths: any[];
|
|
112
|
+
} | undefined;
|
|
113
|
+
contentPages: {
|
|
114
|
+
browserTtlSeconds: number | undefined;
|
|
115
|
+
edgeTtlSeconds: number | undefined;
|
|
116
|
+
staleWhileRevalidateSeconds: number | undefined;
|
|
117
|
+
staleIfErrorSeconds: number | undefined;
|
|
118
|
+
} | {
|
|
119
|
+
paths: any[];
|
|
120
|
+
} | undefined;
|
|
121
|
+
r2PublishedObjects: {
|
|
122
|
+
browserTtlSeconds: number | undefined;
|
|
123
|
+
edgeTtlSeconds: number | undefined;
|
|
124
|
+
staleWhileRevalidateSeconds: number | undefined;
|
|
125
|
+
staleIfErrorSeconds: number | undefined;
|
|
126
|
+
} | {
|
|
127
|
+
paths: any[];
|
|
128
|
+
} | undefined;
|
|
129
|
+
} | undefined;
|
|
130
|
+
} | undefined;
|
|
131
|
+
} | undefined;
|
|
132
|
+
services: {
|
|
133
|
+
[k: string]: {
|
|
134
|
+
enabled: boolean | undefined;
|
|
135
|
+
provider: string | undefined;
|
|
136
|
+
rootDir: string | undefined;
|
|
137
|
+
publicBaseUrl: string | undefined;
|
|
138
|
+
cloudflare: {
|
|
139
|
+
workerName: string | undefined;
|
|
140
|
+
};
|
|
141
|
+
railway: {
|
|
142
|
+
projectId: string | undefined;
|
|
143
|
+
projectName: string | undefined;
|
|
144
|
+
serviceId: string | undefined;
|
|
145
|
+
serviceName: string | undefined;
|
|
146
|
+
rootDir: string | undefined;
|
|
147
|
+
buildCommand: string | undefined;
|
|
148
|
+
startCommand: string | undefined;
|
|
149
|
+
schedule: any;
|
|
150
|
+
};
|
|
151
|
+
environments: {
|
|
152
|
+
local: {
|
|
153
|
+
baseUrl: string | undefined;
|
|
154
|
+
domain: string | undefined;
|
|
155
|
+
railwayEnvironment: string | undefined;
|
|
156
|
+
};
|
|
157
|
+
staging: {
|
|
158
|
+
baseUrl: string | undefined;
|
|
159
|
+
domain: string | undefined;
|
|
160
|
+
railwayEnvironment: string | undefined;
|
|
161
|
+
};
|
|
162
|
+
prod: {
|
|
163
|
+
baseUrl: string | undefined;
|
|
164
|
+
domain: string | undefined;
|
|
165
|
+
railwayEnvironment: string | undefined;
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
} | undefined;
|
|
169
|
+
} | undefined;
|
|
170
|
+
smtp: {
|
|
171
|
+
enabled: boolean | undefined;
|
|
172
|
+
};
|
|
173
|
+
turnstile: {
|
|
174
|
+
enabled: boolean;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
legacyState: any;
|
|
178
|
+
units: TreeseedDesiredUnit[];
|
|
179
|
+
};
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { loadCliDeployConfig } from "../operations/services/runtime-tools.js";
|
|
2
|
+
import {
|
|
3
|
+
loadDeployState,
|
|
4
|
+
resolveConfiguredSurfaceDomain,
|
|
5
|
+
resolveTreeseedResourceIdentity
|
|
6
|
+
} from "../operations/services/deploy.js";
|
|
7
|
+
import { configuredRailwayServices } from "../operations/services/railway-deploy.js";
|
|
8
|
+
import { normalizeRailwayEnvironmentName } from "../operations/services/railway-api.js";
|
|
9
|
+
import { createTreeseedReconcileUnitId } from "./units.js";
|
|
10
|
+
function railwayConcreteUnitTypeForServiceKey(serviceKey) {
|
|
11
|
+
switch (serviceKey) {
|
|
12
|
+
case "api":
|
|
13
|
+
return "railway-service:api";
|
|
14
|
+
case "manager":
|
|
15
|
+
return "railway-service:manager";
|
|
16
|
+
case "worker":
|
|
17
|
+
return "railway-service:worker";
|
|
18
|
+
case "workdayStart":
|
|
19
|
+
return "railway-service:workday-start";
|
|
20
|
+
case "workdayReport":
|
|
21
|
+
return "railway-service:workday-report";
|
|
22
|
+
default:
|
|
23
|
+
return "railway-service:api";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function deriveTreeseedDesiredUnits({
|
|
27
|
+
tenantRoot,
|
|
28
|
+
target
|
|
29
|
+
}) {
|
|
30
|
+
const deployConfig = loadCliDeployConfig(tenantRoot);
|
|
31
|
+
const legacyState = loadDeployState(tenantRoot, deployConfig, { target });
|
|
32
|
+
const identity = legacyState.identity ?? resolveTreeseedResourceIdentity(deployConfig, target);
|
|
33
|
+
const units = [];
|
|
34
|
+
const add = (unit) => {
|
|
35
|
+
units.push(unit);
|
|
36
|
+
return unit.unitId;
|
|
37
|
+
};
|
|
38
|
+
const queueId = add({
|
|
39
|
+
unitId: createTreeseedReconcileUnitId("queue", legacyState.queues.agentWork.name),
|
|
40
|
+
unitType: "queue",
|
|
41
|
+
provider: "cloudflare",
|
|
42
|
+
identity,
|
|
43
|
+
target,
|
|
44
|
+
logicalName: legacyState.queues.agentWork.name,
|
|
45
|
+
dependencies: [],
|
|
46
|
+
spec: {
|
|
47
|
+
name: legacyState.queues.agentWork.name,
|
|
48
|
+
dlqName: legacyState.queues.agentWork.dlqName,
|
|
49
|
+
binding: legacyState.queues.agentWork.binding
|
|
50
|
+
},
|
|
51
|
+
secrets: {},
|
|
52
|
+
metadata: {}
|
|
53
|
+
});
|
|
54
|
+
const databaseId = add({
|
|
55
|
+
unitId: createTreeseedReconcileUnitId("database", legacyState.d1Databases.SITE_DATA_DB.databaseName),
|
|
56
|
+
unitType: "database",
|
|
57
|
+
provider: "cloudflare",
|
|
58
|
+
identity,
|
|
59
|
+
target,
|
|
60
|
+
logicalName: legacyState.d1Databases.SITE_DATA_DB.databaseName,
|
|
61
|
+
dependencies: [],
|
|
62
|
+
spec: {
|
|
63
|
+
databaseName: legacyState.d1Databases.SITE_DATA_DB.databaseName,
|
|
64
|
+
binding: "SITE_DATA_DB"
|
|
65
|
+
},
|
|
66
|
+
secrets: {},
|
|
67
|
+
metadata: {}
|
|
68
|
+
});
|
|
69
|
+
const formGuardKvId = add({
|
|
70
|
+
unitId: createTreeseedReconcileUnitId("kv-form-guard", legacyState.kvNamespaces.FORM_GUARD_KV.name),
|
|
71
|
+
unitType: "kv-form-guard",
|
|
72
|
+
provider: "cloudflare",
|
|
73
|
+
identity,
|
|
74
|
+
target,
|
|
75
|
+
logicalName: legacyState.kvNamespaces.FORM_GUARD_KV.name,
|
|
76
|
+
dependencies: [],
|
|
77
|
+
spec: { binding: "FORM_GUARD_KV", name: legacyState.kvNamespaces.FORM_GUARD_KV.name },
|
|
78
|
+
secrets: {},
|
|
79
|
+
metadata: {}
|
|
80
|
+
});
|
|
81
|
+
const sessionKvId = add({
|
|
82
|
+
unitId: createTreeseedReconcileUnitId("kv-session", legacyState.kvNamespaces.SESSION.name),
|
|
83
|
+
unitType: "kv-session",
|
|
84
|
+
provider: "cloudflare",
|
|
85
|
+
identity,
|
|
86
|
+
target,
|
|
87
|
+
logicalName: legacyState.kvNamespaces.SESSION.name,
|
|
88
|
+
dependencies: [],
|
|
89
|
+
spec: { binding: "SESSION", name: legacyState.kvNamespaces.SESSION.name },
|
|
90
|
+
secrets: {},
|
|
91
|
+
metadata: {}
|
|
92
|
+
});
|
|
93
|
+
const contentStoreId = add({
|
|
94
|
+
unitId: createTreeseedReconcileUnitId("content-store", legacyState.content.bucketName ?? deployConfig.slug),
|
|
95
|
+
unitType: "content-store",
|
|
96
|
+
provider: "cloudflare",
|
|
97
|
+
identity,
|
|
98
|
+
target,
|
|
99
|
+
logicalName: legacyState.content.bucketName ?? deployConfig.slug,
|
|
100
|
+
dependencies: [],
|
|
101
|
+
spec: {
|
|
102
|
+
bucketName: legacyState.content.bucketName,
|
|
103
|
+
binding: legacyState.content.r2Binding,
|
|
104
|
+
publicBaseUrl: legacyState.content.publicBaseUrl,
|
|
105
|
+
manifestKeyTemplate: legacyState.content.manifestKeyTemplate,
|
|
106
|
+
previewRootTemplate: legacyState.content.previewRootTemplate
|
|
107
|
+
},
|
|
108
|
+
secrets: {},
|
|
109
|
+
metadata: { shared: true }
|
|
110
|
+
});
|
|
111
|
+
const pagesProjectId = add({
|
|
112
|
+
unitId: createTreeseedReconcileUnitId("pages-project", legacyState.pages.projectName),
|
|
113
|
+
unitType: "pages-project",
|
|
114
|
+
provider: "cloudflare",
|
|
115
|
+
identity,
|
|
116
|
+
target,
|
|
117
|
+
logicalName: legacyState.pages.projectName,
|
|
118
|
+
dependencies: [],
|
|
119
|
+
spec: {
|
|
120
|
+
projectName: legacyState.pages.projectName,
|
|
121
|
+
productionBranch: legacyState.pages.productionBranch,
|
|
122
|
+
stagingBranch: legacyState.pages.stagingBranch,
|
|
123
|
+
buildOutputDir: legacyState.pages.buildOutputDir
|
|
124
|
+
},
|
|
125
|
+
secrets: {},
|
|
126
|
+
metadata: {}
|
|
127
|
+
});
|
|
128
|
+
const edgeWorkerId = add({
|
|
129
|
+
unitId: createTreeseedReconcileUnitId("edge-worker", legacyState.workerName),
|
|
130
|
+
unitType: "edge-worker",
|
|
131
|
+
provider: "cloudflare",
|
|
132
|
+
identity,
|
|
133
|
+
target,
|
|
134
|
+
logicalName: legacyState.workerName,
|
|
135
|
+
dependencies: [queueId, databaseId, formGuardKvId, sessionKvId, contentStoreId, pagesProjectId],
|
|
136
|
+
spec: {
|
|
137
|
+
workerName: legacyState.workerName
|
|
138
|
+
},
|
|
139
|
+
secrets: {},
|
|
140
|
+
metadata: {}
|
|
141
|
+
});
|
|
142
|
+
if (deployConfig.surfaces?.web?.enabled !== false) {
|
|
143
|
+
const scope2 = target.kind === "persistent" ? target.scope : "staging";
|
|
144
|
+
const webDomain = target.kind === "persistent" ? resolveConfiguredSurfaceDomain(deployConfig, target, "web") : null;
|
|
145
|
+
const webDomainUnitId = webDomain ? add({
|
|
146
|
+
unitId: createTreeseedReconcileUnitId("custom-domain:web", webDomain),
|
|
147
|
+
unitType: "custom-domain:web",
|
|
148
|
+
provider: "cloudflare",
|
|
149
|
+
identity,
|
|
150
|
+
target,
|
|
151
|
+
logicalName: webDomain,
|
|
152
|
+
dependencies: [pagesProjectId],
|
|
153
|
+
spec: {
|
|
154
|
+
domain: webDomain,
|
|
155
|
+
projectName: legacyState.pages.projectName
|
|
156
|
+
},
|
|
157
|
+
secrets: {},
|
|
158
|
+
metadata: { surface: "web" }
|
|
159
|
+
}) : null;
|
|
160
|
+
const webDnsUnitId = webDomain ? add({
|
|
161
|
+
unitId: createTreeseedReconcileUnitId("dns-record", `web:${webDomain}`),
|
|
162
|
+
unitType: "dns-record",
|
|
163
|
+
provider: deployConfig.providers?.dns ?? "cloudflare-dns",
|
|
164
|
+
identity,
|
|
165
|
+
target,
|
|
166
|
+
logicalName: `web:${webDomain}`,
|
|
167
|
+
dependencies: webDomainUnitId ? [webDomainUnitId] : [],
|
|
168
|
+
spec: {
|
|
169
|
+
domain: webDomain,
|
|
170
|
+
zoneHost: webDomain,
|
|
171
|
+
recordName: webDomain,
|
|
172
|
+
recordType: "CNAME",
|
|
173
|
+
recordContent: scope2 === "prod" ? `${legacyState.pages.projectName}.pages.dev` : `${legacyState.pages.stagingBranch ?? "staging"}.${legacyState.pages.projectName}.pages.dev`,
|
|
174
|
+
proxied: true,
|
|
175
|
+
targetKind: "pages-project"
|
|
176
|
+
},
|
|
177
|
+
secrets: {},
|
|
178
|
+
metadata: { surface: "web" }
|
|
179
|
+
}) : null;
|
|
180
|
+
add({
|
|
181
|
+
unitId: createTreeseedReconcileUnitId("web-ui", "web-ui"),
|
|
182
|
+
unitType: "web-ui",
|
|
183
|
+
provider: "treeseed",
|
|
184
|
+
identity,
|
|
185
|
+
target,
|
|
186
|
+
logicalName: "web-ui",
|
|
187
|
+
dependencies: [
|
|
188
|
+
edgeWorkerId,
|
|
189
|
+
pagesProjectId,
|
|
190
|
+
contentStoreId,
|
|
191
|
+
...webDomainUnitId ? [webDomainUnitId] : [],
|
|
192
|
+
...webDnsUnitId ? [webDnsUnitId] : []
|
|
193
|
+
],
|
|
194
|
+
spec: {
|
|
195
|
+
publicBaseUrl: deployConfig.surfaces?.web?.publicBaseUrl ?? deployConfig.siteUrl,
|
|
196
|
+
localBaseUrl: deployConfig.surfaces?.web?.localBaseUrl ?? null
|
|
197
|
+
},
|
|
198
|
+
secrets: {},
|
|
199
|
+
metadata: {}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
const scope = target.kind === "persistent" ? target.scope : "staging";
|
|
203
|
+
for (const configuredService of configuredRailwayServices(tenantRoot, scope)) {
|
|
204
|
+
const serviceKey = configuredService.key;
|
|
205
|
+
const service = deployConfig.services?.[serviceKey];
|
|
206
|
+
const serviceState = legacyState.services?.[serviceKey];
|
|
207
|
+
if (!service || service.enabled === false || service.provider !== "railway") {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const concreteType = railwayConcreteUnitTypeForServiceKey(serviceKey);
|
|
211
|
+
const concreteId = add({
|
|
212
|
+
unitId: createTreeseedReconcileUnitId(concreteType, serviceState?.serviceName ?? configuredService.serviceName ?? serviceKey),
|
|
213
|
+
unitType: concreteType,
|
|
214
|
+
provider: "railway",
|
|
215
|
+
identity,
|
|
216
|
+
target,
|
|
217
|
+
logicalName: serviceState?.serviceName ?? configuredService.serviceName ?? serviceKey,
|
|
218
|
+
dependencies: [],
|
|
219
|
+
spec: {
|
|
220
|
+
projectId: serviceState?.projectId ?? configuredService.projectId,
|
|
221
|
+
projectName: serviceState?.projectName ?? configuredService.projectName,
|
|
222
|
+
serviceId: serviceState?.serviceId ?? configuredService.serviceId,
|
|
223
|
+
serviceName: serviceState?.serviceName ?? configuredService.serviceName,
|
|
224
|
+
rootDir: serviceState?.rootDir ?? configuredService.rootDir,
|
|
225
|
+
environment: normalizeRailwayEnvironmentName(serviceState?.environment ?? configuredService.railwayEnvironment),
|
|
226
|
+
buildCommand: configuredService.buildCommand,
|
|
227
|
+
startCommand: configuredService.startCommand,
|
|
228
|
+
healthcheckPath: configuredService.healthcheckPath,
|
|
229
|
+
healthcheckTimeoutSeconds: configuredService.healthcheckTimeoutSeconds,
|
|
230
|
+
healthcheckIntervalSeconds: configuredService.healthcheckIntervalSeconds,
|
|
231
|
+
restartPolicy: configuredService.restartPolicy,
|
|
232
|
+
runtimeMode: configuredService.runtimeMode,
|
|
233
|
+
schedule: serviceState?.schedule ?? configuredService.schedule,
|
|
234
|
+
publicBaseUrl: serviceState?.publicBaseUrl ?? configuredService.publicBaseUrl
|
|
235
|
+
},
|
|
236
|
+
secrets: {},
|
|
237
|
+
metadata: {
|
|
238
|
+
serviceKey,
|
|
239
|
+
scheduleManaged: Array.isArray(configuredService.schedule) && configuredService.schedule.length > 0,
|
|
240
|
+
scheduleBootstrap: false,
|
|
241
|
+
scheduleDeployScopes: ["prod"]
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
const apiDomain = serviceKey === "api" && target.kind === "persistent" ? resolveConfiguredSurfaceDomain(deployConfig, target, "api") : null;
|
|
245
|
+
const apiCustomDomainId = apiDomain ? add({
|
|
246
|
+
unitId: createTreeseedReconcileUnitId("custom-domain:api", apiDomain),
|
|
247
|
+
unitType: "custom-domain:api",
|
|
248
|
+
provider: "railway",
|
|
249
|
+
identity,
|
|
250
|
+
target,
|
|
251
|
+
logicalName: apiDomain,
|
|
252
|
+
dependencies: [concreteId],
|
|
253
|
+
spec: {
|
|
254
|
+
domain: apiDomain,
|
|
255
|
+
serviceName: serviceState?.serviceName ?? configuredService.serviceName,
|
|
256
|
+
projectName: serviceState?.projectName ?? configuredService.projectName,
|
|
257
|
+
environment: normalizeRailwayEnvironmentName(serviceState?.environment ?? configuredService.railwayEnvironment)
|
|
258
|
+
},
|
|
259
|
+
secrets: {},
|
|
260
|
+
metadata: { surface: "api", serviceKey }
|
|
261
|
+
}) : null;
|
|
262
|
+
const apiDnsUnitId = apiDomain ? add({
|
|
263
|
+
unitId: createTreeseedReconcileUnitId("dns-record", `api:${apiDomain}`),
|
|
264
|
+
unitType: "dns-record",
|
|
265
|
+
provider: deployConfig.providers?.dns ?? "cloudflare-dns",
|
|
266
|
+
identity,
|
|
267
|
+
target,
|
|
268
|
+
logicalName: `api:${apiDomain}`,
|
|
269
|
+
dependencies: apiCustomDomainId ? [apiCustomDomainId] : [concreteId],
|
|
270
|
+
spec: {
|
|
271
|
+
domain: apiDomain,
|
|
272
|
+
zoneHost: apiDomain,
|
|
273
|
+
targetKind: "railway-service",
|
|
274
|
+
serviceKey
|
|
275
|
+
},
|
|
276
|
+
secrets: {},
|
|
277
|
+
metadata: { surface: "api", serviceKey }
|
|
278
|
+
}) : null;
|
|
279
|
+
const runtimeUnitType = (() => {
|
|
280
|
+
switch (serviceKey) {
|
|
281
|
+
case "api":
|
|
282
|
+
return "api-runtime";
|
|
283
|
+
case "manager":
|
|
284
|
+
return "manager-runtime";
|
|
285
|
+
case "worker":
|
|
286
|
+
return "worker-runtime";
|
|
287
|
+
case "workdayStart":
|
|
288
|
+
return "workday-start-runtime";
|
|
289
|
+
case "workdayReport":
|
|
290
|
+
return "workday-report-runtime";
|
|
291
|
+
default:
|
|
292
|
+
return "api-runtime";
|
|
293
|
+
}
|
|
294
|
+
})();
|
|
295
|
+
add({
|
|
296
|
+
unitId: createTreeseedReconcileUnitId(runtimeUnitType, serviceKey),
|
|
297
|
+
unitType: runtimeUnitType,
|
|
298
|
+
provider: "treeseed",
|
|
299
|
+
identity,
|
|
300
|
+
target,
|
|
301
|
+
logicalName: serviceKey,
|
|
302
|
+
dependencies: [
|
|
303
|
+
concreteId,
|
|
304
|
+
...apiCustomDomainId ? [apiCustomDomainId] : [],
|
|
305
|
+
...apiDnsUnitId ? [apiDnsUnitId] : []
|
|
306
|
+
],
|
|
307
|
+
spec: {
|
|
308
|
+
serviceKey,
|
|
309
|
+
publicBaseUrl: serviceState?.publicBaseUrl ?? null
|
|
310
|
+
},
|
|
311
|
+
secrets: {},
|
|
312
|
+
metadata: {}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
return { deployConfig, legacyState, units };
|
|
316
|
+
}
|
|
317
|
+
export {
|
|
318
|
+
deriveTreeseedDesiredUnits
|
|
319
|
+
};
|