@treeseed/sdk 0.4.8 → 0.4.10
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 +1 -1
- package/dist/control-plane-client.d.ts +45 -0
- package/dist/control-plane-client.js +229 -0
- package/dist/control-plane.d.ts +94 -0
- package/dist/control-plane.js +125 -0
- package/dist/d1-store.d.ts +56 -1
- package/dist/d1-store.js +132 -0
- package/dist/dispatch.d.ts +4 -0
- package/dist/dispatch.js +180 -0
- package/dist/index.d.ts +14 -2
- package/dist/index.js +94 -4
- package/dist/operations/services/config-runtime.d.ts +10 -0
- package/dist/operations/services/config-runtime.js +62 -4
- package/dist/operations/services/deploy.d.ts +95 -3
- package/dist/operations/services/deploy.js +351 -10
- package/dist/operations/services/github-automation.d.ts +37 -1
- package/dist/operations/services/github-automation.js +71 -14
- package/dist/operations/services/project-platform.d.ts +835 -0
- package/dist/operations/services/project-platform.js +782 -0
- package/dist/operations/services/railway-deploy.d.ts +113 -18
- package/dist/operations/services/railway-deploy.js +357 -8
- package/dist/operations/services/runtime-tools.d.ts +25 -1
- package/dist/operations/services/runtime-tools.js +66 -5
- package/dist/operations/services/template-registry.d.ts +1 -1
- package/dist/operations/services/template-registry.js +17 -3
- package/dist/platform/books-data.d.ts +3 -4
- package/dist/platform/books-data.js +30 -4
- package/dist/platform/contracts.d.ts +56 -4
- package/dist/platform/deploy-config.js +109 -4
- package/dist/platform/deploy-runtime.d.ts +2 -0
- package/dist/platform/deploy-runtime.js +9 -1
- package/dist/platform/env.yaml +677 -0
- package/dist/platform/environment.js +57 -2
- package/dist/platform/plugin.d.ts +8 -0
- package/dist/platform/plugins/constants.d.ts +2 -0
- package/dist/platform/plugins/constants.js +2 -0
- package/dist/platform/plugins/runtime.d.ts +2 -0
- package/dist/platform/plugins/runtime.js +9 -1
- package/dist/platform/plugins.d.ts +1 -1
- package/dist/platform/plugins.js +4 -0
- package/dist/platform/published-content-pipeline.d.ts +84 -0
- package/dist/platform/published-content-pipeline.js +543 -0
- package/dist/platform/published-content.d.ts +223 -0
- package/dist/platform/published-content.js +588 -0
- package/dist/platform/tenant/runtime-config.d.ts +1 -1
- package/dist/platform/tenant/runtime-config.js +34 -1
- package/dist/platform/tenant-config.d.ts +2 -1
- package/dist/platform/tenant-config.js +17 -1
- package/dist/platform/utils/site-config-schema.js +104 -0
- package/dist/plugin-default.d.ts +2 -0
- package/dist/plugin-default.js +2 -0
- package/dist/remote.d.ts +65 -9
- package/dist/remote.js +104 -28
- package/dist/scripts/check-build-warnings.js +50 -0
- package/dist/scripts/config-treeseed.js +7 -0
- package/dist/scripts/tenant-workflow-action.js +71 -0
- package/dist/sdk-dispatch.d.ts +12 -0
- package/dist/sdk-dispatch.js +142 -0
- package/dist/sdk-types.d.ts +579 -7
- package/dist/sdk-types.js +53 -1
- package/dist/sdk.d.ts +17 -1
- package/dist/sdk.js +109 -0
- package/dist/stores/operational-store.d.ts +22 -2
- package/dist/stores/operational-store.js +235 -0
- package/dist/template-catalog.js +8 -1
- package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +20 -0
- package/dist/types/cloudflare.d.ts +23 -0
- package/dist/workflow/operations.d.ts +12 -3
- package/dist/workflow/policy.d.ts +1 -1
- package/dist/workflow-state.js +2 -1
- package/package.json +7 -2
- package/templates/github/deploy.workflow.yml +442 -0
- package/templates/github/hosted-project.workflow.yml +77 -0
|
@@ -10,7 +10,7 @@ const DEFAULT_COMPATIBILITY_FLAGS = ["nodejs_compat"];
|
|
|
10
10
|
const GENERATED_ROOT = ".treeseed/generated";
|
|
11
11
|
const STATE_ROOT = ".treeseed/state";
|
|
12
12
|
const PERSISTENT_SCOPES = /* @__PURE__ */ new Set(["local", "staging", "prod"]);
|
|
13
|
-
const MANAGED_SERVICE_KEYS = ["api", "agents", "
|
|
13
|
+
const MANAGED_SERVICE_KEYS = ["api", "agents", "manager", "worker", "runner", "workdayStart", "workdayReport"];
|
|
14
14
|
const TRESEED_ENVELOPE_SCHEMA_GENERATION = "runtime-envelopes-v1";
|
|
15
15
|
const TRESEED_MIGRATION_WAVE_ID = "0005_runtime_envelopes";
|
|
16
16
|
const TRESEED_SUPPORTED_PAYLOAD_RANGE = { min: 1, max: 1 };
|
|
@@ -128,17 +128,57 @@ function relativeFromGeneratedRoot(targetPath, generatedRoot) {
|
|
|
128
128
|
return relative(generatedRoot, targetPath).replaceAll("\\", "/");
|
|
129
129
|
}
|
|
130
130
|
function buildPublicVars(deployConfig) {
|
|
131
|
+
const contentRuntimeProvider = deployConfig.providers?.content?.runtime ?? "team_scoped_r2_overlay";
|
|
132
|
+
const contentPublishProvider = deployConfig.providers?.content?.publish ?? contentRuntimeProvider;
|
|
133
|
+
const contentDefaultTeamId = deployConfig.hosting?.teamId ?? deployConfig.slug;
|
|
134
|
+
const contentManifestKeyTemplate = deployConfig.cloudflare.r2?.manifestKeyTemplate ?? "teams/{teamId}/published/common.json";
|
|
135
|
+
const contentPreviewRootTemplate = deployConfig.cloudflare.r2?.previewRootTemplate ?? "teams/{teamId}/previews";
|
|
136
|
+
const contentManifestKey = contentManifestKeyTemplate.replaceAll("{teamId}", contentDefaultTeamId);
|
|
137
|
+
const hostedProject = (deployConfig.hosting?.kind ?? "self_hosted_project") === "hosted_project";
|
|
138
|
+
const workerRailway = deployConfig.services?.worker?.railway ?? {};
|
|
131
139
|
return {
|
|
140
|
+
TREESEED_HOSTING_KIND: deployConfig.hosting?.kind ?? "self_hosted_project",
|
|
141
|
+
TREESEED_HOSTING_REGISTRATION: deployConfig.hosting?.registration ?? "none",
|
|
142
|
+
TREESEED_MARKET_API_BASE_URL: deployConfig.hosting?.marketBaseUrl ?? "",
|
|
143
|
+
TREESEED_HOSTING_TEAM_ID: deployConfig.hosting?.teamId ?? contentDefaultTeamId,
|
|
144
|
+
TREESEED_PROJECT_ID: deployConfig.hosting?.projectId ?? deployConfig.slug,
|
|
132
145
|
TREESEED_AGENT_EXECUTION_PROVIDER: deployConfig.providers?.agents?.execution ?? "stub",
|
|
133
146
|
TREESEED_AGENT_REPOSITORY_PROVIDER: deployConfig.providers?.agents?.repository ?? "stub",
|
|
134
147
|
TREESEED_AGENT_VERIFICATION_PROVIDER: deployConfig.providers?.agents?.verification ?? "stub",
|
|
148
|
+
TREESEED_CONTENT_RUNTIME_PROVIDER: contentRuntimeProvider,
|
|
149
|
+
TREESEED_CONTENT_PUBLISH_PROVIDER: contentPublishProvider,
|
|
150
|
+
TREESEED_CONTENT_DEFAULT_TEAM_ID: contentDefaultTeamId,
|
|
151
|
+
TREESEED_CONTENT_MANIFEST_KEY: contentManifestKey,
|
|
152
|
+
TREESEED_CONTENT_MANIFEST_KEY_TEMPLATE: contentManifestKeyTemplate,
|
|
153
|
+
TREESEED_CONTENT_PREVIEW_ROOT_TEMPLATE: contentPreviewRootTemplate,
|
|
154
|
+
TREESEED_EDITORIAL_PREVIEW_ROOT: contentPreviewRootTemplate.replaceAll("{teamId}", contentDefaultTeamId),
|
|
155
|
+
TREESEED_EDITORIAL_PREVIEW_TTL_HOURS: String(deployConfig.cloudflare.r2?.previewTtlHours ?? 168),
|
|
156
|
+
TREESEED_CONTENT_BUCKET_NAME: deployConfig.cloudflare.r2?.bucketName ?? "",
|
|
157
|
+
TREESEED_CONTENT_PUBLIC_BASE_URL: deployConfig.cloudflare.r2?.publicBaseUrl ?? "",
|
|
158
|
+
TREESEED_WORKER_POOL_SCALER: envOrNull("TREESEED_WORKER_POOL_SCALER") ?? (hostedProject ? "railway" : ""),
|
|
159
|
+
TREESEED_WORKDAY_TIMEZONE: envOrNull("TREESEED_WORKDAY_TIMEZONE") ?? "",
|
|
160
|
+
TREESEED_WORKDAY_WINDOWS_JSON: envOrNull("TREESEED_WORKDAY_WINDOWS_JSON") ?? "",
|
|
161
|
+
TREESEED_WORKDAY_TASK_CREDIT_BUDGET: envOrNull("TREESEED_WORKDAY_TASK_CREDIT_BUDGET") ?? "",
|
|
162
|
+
TREESEED_MANAGER_MAX_QUEUED_TASKS: envOrNull("TREESEED_MANAGER_MAX_QUEUED_TASKS") ?? "",
|
|
163
|
+
TREESEED_MANAGER_MAX_QUEUED_CREDITS: envOrNull("TREESEED_MANAGER_MAX_QUEUED_CREDITS") ?? "",
|
|
164
|
+
TREESEED_MANAGER_PRIORITY_MODELS: envOrNull("TREESEED_MANAGER_PRIORITY_MODELS") ?? "",
|
|
165
|
+
TREESEED_TASK_CREDIT_WEIGHTS_JSON: envOrNull("TREESEED_TASK_CREDIT_WEIGHTS_JSON") ?? "",
|
|
166
|
+
TREESEED_AGENT_POOL_MIN_WORKERS: envOrNull("TREESEED_AGENT_POOL_MIN_WORKERS") ?? "",
|
|
167
|
+
TREESEED_AGENT_POOL_MAX_WORKERS: envOrNull("TREESEED_AGENT_POOL_MAX_WORKERS") ?? "",
|
|
168
|
+
TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH: envOrNull("TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH") ?? "",
|
|
169
|
+
TREESEED_AGENT_POOL_COOLDOWN_SECONDS: envOrNull("TREESEED_AGENT_POOL_COOLDOWN_SECONDS") ?? "",
|
|
170
|
+
TREESEED_RAILWAY_PROJECT_ID: envOrNull("TREESEED_RAILWAY_PROJECT_ID") ?? workerRailway.projectId ?? "",
|
|
171
|
+
TREESEED_RAILWAY_ENVIRONMENT_ID: envOrNull("TREESEED_RAILWAY_ENVIRONMENT_ID") ?? "",
|
|
172
|
+
TREESEED_RAILWAY_WORKER_SERVICE_ID: envOrNull("TREESEED_RAILWAY_WORKER_SERVICE_ID") ?? workerRailway.serviceId ?? "",
|
|
135
173
|
TREESEED_PUBLIC_TURNSTILE_SITE_KEY: envOrNull("TREESEED_PUBLIC_TURNSTILE_SITE_KEY") ?? ""
|
|
136
174
|
};
|
|
137
175
|
}
|
|
138
176
|
function buildSecretMap(deployConfig, state) {
|
|
139
177
|
const generatedSecret = state.generatedSecrets?.TREESEED_FORM_TOKEN_SECRET ?? randomBytes(24).toString("hex");
|
|
178
|
+
const previewSecret = state.generatedSecrets?.TREESEED_EDITORIAL_PREVIEW_SECRET ?? randomBytes(24).toString("hex");
|
|
140
179
|
return {
|
|
141
180
|
TREESEED_FORM_TOKEN_SECRET: envOrNull("TREESEED_FORM_TOKEN_SECRET") ?? generatedSecret,
|
|
181
|
+
TREESEED_EDITORIAL_PREVIEW_SECRET: envOrNull("TREESEED_EDITORIAL_PREVIEW_SECRET") ?? previewSecret,
|
|
142
182
|
TREESEED_TURNSTILE_SECRET_KEY: envOrNull("TREESEED_TURNSTILE_SECRET_KEY"),
|
|
143
183
|
TREESEED_SMTP_HOST: deployConfig.smtp?.enabled ? envOrNull("TREESEED_SMTP_HOST") : null,
|
|
144
184
|
TREESEED_SMTP_PORT: deployConfig.smtp?.enabled ? envOrNull("TREESEED_SMTP_PORT") : null,
|
|
@@ -151,6 +191,10 @@ function buildSecretMap(deployConfig, state) {
|
|
|
151
191
|
function defaultStateFromConfig(deployConfig, target) {
|
|
152
192
|
const workerName = targetWorkerName(deployConfig, target);
|
|
153
193
|
const suffix = target.kind === "persistent" ? target.scope : sanitizeSegment(target.branchName);
|
|
194
|
+
const contentManifestKeyTemplate = deployConfig.cloudflare.r2?.manifestKeyTemplate ?? "teams/{teamId}/published/common.json";
|
|
195
|
+
const contentPreviewRootTemplate = deployConfig.cloudflare.r2?.previewRootTemplate ?? "teams/{teamId}/previews";
|
|
196
|
+
const contentDefaultTeamId = deployConfig.hosting?.teamId ?? deployConfig.slug;
|
|
197
|
+
const contentManifestKey = contentManifestKeyTemplate.replaceAll("{teamId}", contentDefaultTeamId);
|
|
154
198
|
return {
|
|
155
199
|
version: 2,
|
|
156
200
|
target,
|
|
@@ -179,15 +223,49 @@ function defaultStateFromConfig(deployConfig, target) {
|
|
|
179
223
|
agentWork: {
|
|
180
224
|
name: deployConfig.cloudflare.queueName ?? "agent-work",
|
|
181
225
|
dlqName: deployConfig.cloudflare.dlqName ?? "agent-work-dlq",
|
|
182
|
-
binding: deployConfig.cloudflare.queueBinding ?? "AGENT_WORK_QUEUE"
|
|
226
|
+
binding: deployConfig.cloudflare.queueBinding ?? "AGENT_WORK_QUEUE",
|
|
227
|
+
queueId: null,
|
|
228
|
+
dlqId: null
|
|
183
229
|
}
|
|
184
230
|
},
|
|
231
|
+
pages: {
|
|
232
|
+
projectName: target.kind === "persistent" ? target.scope === "prod" ? deployConfig.cloudflare.pages?.projectName ?? deployConfig.slug : deployConfig.cloudflare.pages?.previewProjectName ?? `${deployConfig.cloudflare.pages?.projectName ?? deployConfig.slug}-staging` : deployConfig.cloudflare.pages?.previewProjectName ?? `${deployConfig.cloudflare.pages?.projectName ?? deployConfig.slug}-preview`,
|
|
233
|
+
productionBranch: deployConfig.cloudflare.pages?.productionBranch ?? "main",
|
|
234
|
+
stagingBranch: deployConfig.cloudflare.pages?.stagingBranch ?? "staging",
|
|
235
|
+
buildOutputDir: deployConfig.cloudflare.pages?.buildOutputDir ?? "dist",
|
|
236
|
+
url: null
|
|
237
|
+
},
|
|
238
|
+
content: {
|
|
239
|
+
runtimeProvider: deployConfig.providers?.content?.runtime ?? "team_scoped_r2_overlay",
|
|
240
|
+
publishProvider: deployConfig.providers?.content?.publish ?? deployConfig.providers?.content?.runtime ?? "team_scoped_r2_overlay",
|
|
241
|
+
defaultTeamId: contentDefaultTeamId,
|
|
242
|
+
r2Binding: deployConfig.cloudflare.r2?.binding ?? null,
|
|
243
|
+
bucketName: deployConfig.cloudflare.r2?.bucketName ?? null,
|
|
244
|
+
publicBaseUrl: deployConfig.cloudflare.r2?.publicBaseUrl ?? null,
|
|
245
|
+
manifestKeyTemplate: contentManifestKeyTemplate,
|
|
246
|
+
previewRootTemplate: contentPreviewRootTemplate,
|
|
247
|
+
previewTtlHours: deployConfig.cloudflare.r2?.previewTtlHours ?? 168,
|
|
248
|
+
manifestKey: contentManifestKey,
|
|
249
|
+
lastPublishedManifestRevision: null,
|
|
250
|
+
lastPublishedManifestSha256: null
|
|
251
|
+
},
|
|
252
|
+
hosting: {
|
|
253
|
+
kind: deployConfig.hosting?.kind ?? "self_hosted_project",
|
|
254
|
+
registration: deployConfig.hosting?.registration ?? "none",
|
|
255
|
+
marketBaseUrl: deployConfig.hosting?.marketBaseUrl ?? null,
|
|
256
|
+
teamId: deployConfig.hosting?.teamId ?? contentDefaultTeamId,
|
|
257
|
+
projectId: deployConfig.hosting?.projectId ?? deployConfig.slug
|
|
258
|
+
},
|
|
185
259
|
generatedSecrets: {},
|
|
186
260
|
readiness: {
|
|
261
|
+
configured: false,
|
|
262
|
+
provisioned: false,
|
|
263
|
+
deployable: false,
|
|
187
264
|
initialized: false,
|
|
188
265
|
initializedAt: null,
|
|
189
266
|
lastValidatedAt: null,
|
|
190
|
-
lastConfigFingerprint: null
|
|
267
|
+
lastConfigFingerprint: null,
|
|
268
|
+
lastValidationSummary: null
|
|
191
269
|
},
|
|
192
270
|
lastDeployedUrl: target.kind === "branch" ? targetWorkersDevUrl(workerName) : null,
|
|
193
271
|
lastManifestFingerprint: null,
|
|
@@ -210,15 +288,18 @@ function defaultStateFromConfig(deployConfig, target) {
|
|
|
210
288
|
workerName: serviceConfig?.cloudflare?.workerName ?? null,
|
|
211
289
|
rootDir: serviceConfig?.railway?.rootDir ?? serviceConfig?.rootDir ?? null,
|
|
212
290
|
environment: serviceConfig?.environments?.[scope]?.railwayEnvironment ?? scope,
|
|
291
|
+
schedule: serviceConfig?.railway?.schedule ?? null,
|
|
213
292
|
publicBaseUrl: baseUrl,
|
|
214
293
|
initialized: false,
|
|
215
294
|
lastDeploymentTimestamp: null,
|
|
216
295
|
lastDeployedUrl: baseUrl,
|
|
217
|
-
lastDeploymentCommand: null
|
|
296
|
+
lastDeploymentCommand: null,
|
|
297
|
+
lastScheduleSyncAt: null
|
|
218
298
|
}
|
|
219
299
|
];
|
|
220
300
|
})
|
|
221
301
|
),
|
|
302
|
+
railwaySchedules: {},
|
|
222
303
|
runtimeCompatibility: {
|
|
223
304
|
envelopeSchemaGeneration: TRESEED_ENVELOPE_SCHEMA_GENERATION,
|
|
224
305
|
migrationWaveId: TRESEED_MIGRATION_WAVE_ID,
|
|
@@ -270,13 +351,49 @@ function loadDeployState(tenantRoot, deployConfig, options = {}) {
|
|
|
270
351
|
...persisted.queues?.agentWork ?? {},
|
|
271
352
|
name: defaults.queues?.agentWork?.name ?? persisted.queues?.agentWork?.name ?? "agent-work",
|
|
272
353
|
dlqName: defaults.queues?.agentWork?.dlqName ?? persisted.queues?.agentWork?.dlqName ?? "agent-work-dlq",
|
|
273
|
-
binding: defaults.queues?.agentWork?.binding ?? persisted.queues?.agentWork?.binding ?? "AGENT_WORK_QUEUE"
|
|
354
|
+
binding: defaults.queues?.agentWork?.binding ?? persisted.queues?.agentWork?.binding ?? "AGENT_WORK_QUEUE",
|
|
355
|
+
queueId: persisted.queues?.agentWork?.queueId ?? defaults.queues?.agentWork?.queueId ?? null,
|
|
356
|
+
dlqId: persisted.queues?.agentWork?.dlqId ?? defaults.queues?.agentWork?.dlqId ?? null
|
|
274
357
|
}
|
|
275
358
|
},
|
|
276
359
|
generatedSecrets: {
|
|
277
360
|
...defaults.generatedSecrets ?? {},
|
|
278
361
|
...persisted.generatedSecrets ?? {}
|
|
279
362
|
},
|
|
363
|
+
content: {
|
|
364
|
+
...defaults.content ?? {},
|
|
365
|
+
...persisted.content ?? {},
|
|
366
|
+
runtimeProvider: defaults.content?.runtimeProvider ?? persisted.content?.runtimeProvider ?? "team_scoped_r2_overlay",
|
|
367
|
+
publishProvider: defaults.content?.publishProvider ?? persisted.content?.publishProvider ?? "team_scoped_r2_overlay",
|
|
368
|
+
defaultTeamId: defaults.content?.defaultTeamId ?? persisted.content?.defaultTeamId ?? deployConfig.slug,
|
|
369
|
+
r2Binding: defaults.content?.r2Binding ?? persisted.content?.r2Binding ?? null,
|
|
370
|
+
bucketName: defaults.content?.bucketName ?? persisted.content?.bucketName ?? null,
|
|
371
|
+
publicBaseUrl: defaults.content?.publicBaseUrl ?? persisted.content?.publicBaseUrl ?? null,
|
|
372
|
+
manifestKeyTemplate: defaults.content?.manifestKeyTemplate ?? persisted.content?.manifestKeyTemplate ?? "teams/{teamId}/published/common.json",
|
|
373
|
+
previewRootTemplate: defaults.content?.previewRootTemplate ?? persisted.content?.previewRootTemplate ?? "teams/{teamId}/previews",
|
|
374
|
+
previewTtlHours: defaults.content?.previewTtlHours ?? persisted.content?.previewTtlHours ?? 168,
|
|
375
|
+
manifestKey: defaults.content?.manifestKey ?? persisted.content?.manifestKey ?? `teams/${deployConfig.slug}/published/common.json`,
|
|
376
|
+
lastPublishedManifestRevision: persisted.content?.lastPublishedManifestRevision ?? defaults.content?.lastPublishedManifestRevision ?? null,
|
|
377
|
+
lastPublishedManifestSha256: persisted.content?.lastPublishedManifestSha256 ?? defaults.content?.lastPublishedManifestSha256 ?? null
|
|
378
|
+
},
|
|
379
|
+
hosting: {
|
|
380
|
+
...defaults.hosting ?? {},
|
|
381
|
+
...persisted.hosting ?? {},
|
|
382
|
+
kind: defaults.hosting?.kind ?? persisted.hosting?.kind ?? "self_hosted_project",
|
|
383
|
+
registration: defaults.hosting?.registration ?? persisted.hosting?.registration ?? "none",
|
|
384
|
+
marketBaseUrl: defaults.hosting?.marketBaseUrl ?? persisted.hosting?.marketBaseUrl ?? null,
|
|
385
|
+
teamId: defaults.hosting?.teamId ?? persisted.hosting?.teamId ?? deployConfig.slug,
|
|
386
|
+
projectId: defaults.hosting?.projectId ?? persisted.hosting?.projectId ?? deployConfig.slug
|
|
387
|
+
},
|
|
388
|
+
pages: {
|
|
389
|
+
...defaults.pages ?? {},
|
|
390
|
+
...persisted.pages ?? {},
|
|
391
|
+
projectName: defaults.pages?.projectName ?? persisted.pages?.projectName ?? null,
|
|
392
|
+
productionBranch: defaults.pages?.productionBranch ?? persisted.pages?.productionBranch ?? "main",
|
|
393
|
+
stagingBranch: defaults.pages?.stagingBranch ?? persisted.pages?.stagingBranch ?? "staging",
|
|
394
|
+
buildOutputDir: defaults.pages?.buildOutputDir ?? persisted.pages?.buildOutputDir ?? "dist",
|
|
395
|
+
url: persisted.pages?.url ?? defaults.pages?.url ?? null
|
|
396
|
+
},
|
|
280
397
|
readiness: {
|
|
281
398
|
...defaults.readiness,
|
|
282
399
|
...persisted.readiness ?? {}
|
|
@@ -299,12 +416,17 @@ function loadDeployState(tenantRoot, deployConfig, options = {}) {
|
|
|
299
416
|
workerName: defaultService.workerName ?? persistedService.workerName ?? null,
|
|
300
417
|
rootDir: defaultService.rootDir ?? persistedService.rootDir ?? null,
|
|
301
418
|
environment: defaultService.environment ?? persistedService.environment ?? null,
|
|
419
|
+
schedule: defaultService.schedule ?? persistedService.schedule ?? null,
|
|
302
420
|
publicBaseUrl: defaultService.publicBaseUrl ?? persistedService.publicBaseUrl ?? null,
|
|
303
|
-
lastDeployedUrl: persistedService.lastDeployedUrl ?? defaultService.publicBaseUrl ?? null
|
|
421
|
+
lastDeployedUrl: persistedService.lastDeployedUrl ?? defaultService.publicBaseUrl ?? null,
|
|
422
|
+
lastScheduleSyncAt: persistedService.lastScheduleSyncAt ?? defaultService.lastScheduleSyncAt ?? null
|
|
304
423
|
}
|
|
305
424
|
];
|
|
306
425
|
})
|
|
307
|
-
)
|
|
426
|
+
),
|
|
427
|
+
railwaySchedules: {
|
|
428
|
+
...persisted.railwaySchedules ?? {}
|
|
429
|
+
}
|
|
308
430
|
};
|
|
309
431
|
if (target.kind === "branch" && !merged.lastDeployedUrl) {
|
|
310
432
|
merged.lastDeployedUrl = targetWorkersDevUrl(merged.workerName);
|
|
@@ -330,6 +452,9 @@ function buildWranglerConfigContents(tenantRoot, deployConfig, state, options =
|
|
|
330
452
|
const assetsDirectory = relativeFromGeneratedRoot(resolve(tenantRoot, "dist"), generatedRoot);
|
|
331
453
|
const migrationsDir = relativeFromGeneratedRoot(resolve(tenantRoot, "migrations"), generatedRoot);
|
|
332
454
|
const vars = buildPublicVars(deployConfig);
|
|
455
|
+
const r2Config = deployConfig.cloudflare.r2;
|
|
456
|
+
const r2Binding = r2Config?.binding ?? "TREESEED_CONTENT_BUCKET";
|
|
457
|
+
const r2BucketName = r2Config?.bucketName ?? `${deployConfig.slug}-content`;
|
|
333
458
|
return [
|
|
334
459
|
`name = ${renderTomlString(workerName)}`,
|
|
335
460
|
`compatibility_date = ${renderTomlString(DEFAULT_COMPATIBILITY_DATE)}`,
|
|
@@ -360,7 +485,13 @@ function buildWranglerConfigContents(tenantRoot, deployConfig, state, options =
|
|
|
360
485
|
`database_id = ${renderTomlString(state.d1Databases.SITE_DATA_DB.databaseId)}`,
|
|
361
486
|
`preview_database_id = ${renderTomlString(state.d1Databases.SITE_DATA_DB.previewDatabaseId ?? state.d1Databases.SITE_DATA_DB.databaseId)}`,
|
|
362
487
|
`migrations_dir = ${renderTomlString(migrationsDir)}`,
|
|
363
|
-
""
|
|
488
|
+
"",
|
|
489
|
+
...r2Config ? [
|
|
490
|
+
"[[r2_buckets]]",
|
|
491
|
+
`binding = ${renderTomlString(r2Binding)}`,
|
|
492
|
+
`bucket_name = ${renderTomlString(r2BucketName)}`,
|
|
493
|
+
""
|
|
494
|
+
] : []
|
|
364
495
|
].join("\n");
|
|
365
496
|
}
|
|
366
497
|
function ensureGeneratedWranglerConfig(tenantRoot, options = {}) {
|
|
@@ -379,6 +510,7 @@ function ensureGeneratedWranglerConfig(tenantRoot, options = {}) {
|
|
|
379
510
|
}
|
|
380
511
|
const secretMap = buildSecretMap(deployConfig, state);
|
|
381
512
|
state.generatedSecrets.TREESEED_FORM_TOKEN_SECRET = secretMap.TREESEED_FORM_TOKEN_SECRET;
|
|
513
|
+
state.generatedSecrets.TREESEED_EDITORIAL_PREVIEW_SECRET = secretMap.TREESEED_EDITORIAL_PREVIEW_SECRET;
|
|
382
514
|
writeDeployState(tenantRoot, state, { target });
|
|
383
515
|
return { wranglerPath, deployConfig, state, manifestFingerprint, target };
|
|
384
516
|
}
|
|
@@ -429,6 +561,33 @@ function listD1Databases(tenantRoot, env) {
|
|
|
429
561
|
});
|
|
430
562
|
return parseWranglerJsonOutput(result, "D1 list");
|
|
431
563
|
}
|
|
564
|
+
function listQueues(tenantRoot, env) {
|
|
565
|
+
const result = runWrangler(["queues", "list", "--json"], {
|
|
566
|
+
cwd: tenantRoot,
|
|
567
|
+
capture: true,
|
|
568
|
+
env,
|
|
569
|
+
allowFailure: true
|
|
570
|
+
});
|
|
571
|
+
return result.status === 0 ? parseWranglerJsonOutput(result, "Queues list") : [];
|
|
572
|
+
}
|
|
573
|
+
function listR2Buckets(tenantRoot, env) {
|
|
574
|
+
const result = runWrangler(["r2", "bucket", "list", "--json"], {
|
|
575
|
+
cwd: tenantRoot,
|
|
576
|
+
capture: true,
|
|
577
|
+
env,
|
|
578
|
+
allowFailure: true
|
|
579
|
+
});
|
|
580
|
+
return result.status === 0 ? parseWranglerJsonOutput(result, "R2 bucket list") : [];
|
|
581
|
+
}
|
|
582
|
+
function listPagesProjects(tenantRoot, env) {
|
|
583
|
+
const result = runWrangler(["pages", "project", "list", "--json"], {
|
|
584
|
+
cwd: tenantRoot,
|
|
585
|
+
capture: true,
|
|
586
|
+
env,
|
|
587
|
+
allowFailure: true
|
|
588
|
+
});
|
|
589
|
+
return result.status === 0 ? parseWranglerJsonOutput(result, "Pages project list") : [];
|
|
590
|
+
}
|
|
432
591
|
function isPlaceholderResourceId(value) {
|
|
433
592
|
if (!value || typeof value !== "string") {
|
|
434
593
|
return true;
|
|
@@ -441,11 +600,25 @@ function buildProvisioningSummary(deployConfig, state, target) {
|
|
|
441
600
|
workerName: state.workerName ?? targetWorkerName(deployConfig, target),
|
|
442
601
|
siteUrl: target.kind === "branch" ? targetWorkersDevUrl(state.workerName) : deployConfig.siteUrl,
|
|
443
602
|
accountId: deployConfig.cloudflare.accountId,
|
|
603
|
+
pages: state.pages ?? null,
|
|
444
604
|
formGuardKv: state.kvNamespaces.FORM_GUARD_KV,
|
|
445
605
|
sessionKv: state.kvNamespaces.SESSION,
|
|
446
|
-
siteDataDb: state.d1Databases.SITE_DATA_DB
|
|
606
|
+
siteDataDb: state.d1Databases.SITE_DATA_DB,
|
|
607
|
+
queue: state.queues?.agentWork ?? null,
|
|
608
|
+
content: state.content ?? null
|
|
447
609
|
};
|
|
448
610
|
}
|
|
611
|
+
function queueName(entry) {
|
|
612
|
+
return entry?.queue_name ?? entry?.queueName ?? entry?.name ?? null;
|
|
613
|
+
}
|
|
614
|
+
function queueId(entry) {
|
|
615
|
+
return entry?.queue_id ?? entry?.queueId ?? entry?.id ?? entry?.uuid ?? null;
|
|
616
|
+
}
|
|
617
|
+
function hasProvisionedCloudflareResources(state) {
|
|
618
|
+
return Boolean(
|
|
619
|
+
state?.pages?.projectName && state?.pages?.url && state?.d1Databases?.SITE_DATA_DB?.databaseId && state?.kvNamespaces?.FORM_GUARD_KV?.id && state?.kvNamespaces?.SESSION?.id && state?.queues?.agentWork?.name && state?.content?.bucketName
|
|
620
|
+
);
|
|
621
|
+
}
|
|
449
622
|
function buildDestroySummary(deployConfig, state, target) {
|
|
450
623
|
return buildProvisioningSummary(deployConfig, state, target);
|
|
451
624
|
}
|
|
@@ -462,6 +635,18 @@ function missingTurnstileRequirements() {
|
|
|
462
635
|
}
|
|
463
636
|
return issues;
|
|
464
637
|
}
|
|
638
|
+
function missingContentRuntimeRequirements(deployConfig) {
|
|
639
|
+
const issues = [];
|
|
640
|
+
if (deployConfig.providers?.content?.runtime === "team_scoped_r2_overlay") {
|
|
641
|
+
if (!deployConfig.cloudflare.r2?.bucketName) {
|
|
642
|
+
issues.push("Set cloudflare.r2.bucketName before deploying team-scoped hosted content.");
|
|
643
|
+
}
|
|
644
|
+
if (!envOrNull("TREESEED_EDITORIAL_PREVIEW_SECRET")) {
|
|
645
|
+
issues.push("Set TREESEED_EDITORIAL_PREVIEW_SECRET before deploying team-scoped hosted content.");
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return issues;
|
|
649
|
+
}
|
|
465
650
|
function collectMissingDeployInputs(tenantRoot) {
|
|
466
651
|
const deployConfig = loadTenantDeployConfig(tenantRoot);
|
|
467
652
|
const missing = [];
|
|
@@ -486,6 +671,13 @@ function collectMissingDeployInputs(tenantRoot) {
|
|
|
486
671
|
message: "Turnstile secret key is missing for deploy."
|
|
487
672
|
});
|
|
488
673
|
}
|
|
674
|
+
if (deployConfig.providers?.content?.runtime === "team_scoped_r2_overlay" && !envOrNull("TREESEED_EDITORIAL_PREVIEW_SECRET")) {
|
|
675
|
+
missing.push({
|
|
676
|
+
key: "TREESEED_EDITORIAL_PREVIEW_SECRET",
|
|
677
|
+
label: "Editorial preview signing secret",
|
|
678
|
+
message: "Editorial preview signing secret is missing for deploy."
|
|
679
|
+
});
|
|
680
|
+
}
|
|
489
681
|
return missing;
|
|
490
682
|
}
|
|
491
683
|
async function promptForMissingDeployInputs(tenantRoot) {
|
|
@@ -525,6 +717,7 @@ function validateDeployPrerequisites(tenantRoot, { requireRemote = true } = {})
|
|
|
525
717
|
}
|
|
526
718
|
if (requireRemote) {
|
|
527
719
|
issues.push(...missingTurnstileRequirements());
|
|
720
|
+
issues.push(...missingContentRuntimeRequirements(deployConfig));
|
|
528
721
|
const result = runWrangler(["whoami"], {
|
|
529
722
|
cwd: tenantRoot,
|
|
530
723
|
allowFailure: true,
|
|
@@ -731,6 +924,9 @@ function provisionCloudflareResources(tenantRoot, options = {}) {
|
|
|
731
924
|
const dryRun = options.dryRun ?? false;
|
|
732
925
|
const kvNamespaces = dryRun ? [] : listKvNamespaces(tenantRoot, env);
|
|
733
926
|
const d1Databases = dryRun ? [] : listD1Databases(tenantRoot, env);
|
|
927
|
+
const queues = dryRun ? [] : listQueues(tenantRoot, env);
|
|
928
|
+
const buckets = dryRun ? [] : listR2Buckets(tenantRoot, env);
|
|
929
|
+
const pagesProjects = dryRun ? [] : listPagesProjects(tenantRoot, env);
|
|
734
930
|
const ensureKv = (binding) => {
|
|
735
931
|
const current = state.kvNamespaces[binding];
|
|
736
932
|
if (current?.id && !isPlaceholderResourceId(current.id)) {
|
|
@@ -786,12 +982,103 @@ function provisionCloudflareResources(tenantRoot, options = {}) {
|
|
|
786
982
|
current.databaseId = created.uuid;
|
|
787
983
|
current.previewDatabaseId = created.previewDatabaseUuid ?? created.uuid;
|
|
788
984
|
};
|
|
985
|
+
const ensureQueue = () => {
|
|
986
|
+
const current = state.queues?.agentWork;
|
|
987
|
+
if (!current?.name) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
const exists = queues.find((entry) => queueName(entry) === current.name);
|
|
991
|
+
if (exists) {
|
|
992
|
+
current.queueId = queueId(exists);
|
|
993
|
+
const currentDlq = current.dlqName ? queues.find((entry) => queueName(entry) === current.dlqName) : null;
|
|
994
|
+
current.dlqId = queueId(currentDlq);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (dryRun) {
|
|
998
|
+
current.queueId = `dryrun-${current.name}`;
|
|
999
|
+
current.dlqId = current.dlqName ? `dryrun-${current.dlqName}` : null;
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
runWrangler(["queues", "create", current.name], {
|
|
1003
|
+
cwd: tenantRoot,
|
|
1004
|
+
capture: true,
|
|
1005
|
+
env
|
|
1006
|
+
});
|
|
1007
|
+
if (current.dlqName && !queues.find((entry) => queueName(entry) === current.dlqName)) {
|
|
1008
|
+
runWrangler(["queues", "create", current.dlqName], {
|
|
1009
|
+
cwd: tenantRoot,
|
|
1010
|
+
capture: true,
|
|
1011
|
+
env
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
const refreshed = listQueues(tenantRoot, env);
|
|
1015
|
+
const created = refreshed.find((entry) => queueName(entry) === current.name);
|
|
1016
|
+
current.queueId = queueId(created);
|
|
1017
|
+
const createdDlq = current.dlqName ? refreshed.find((entry) => queueName(entry) === current.dlqName) : null;
|
|
1018
|
+
current.dlqId = queueId(createdDlq);
|
|
1019
|
+
};
|
|
1020
|
+
const ensureR2Bucket = () => {
|
|
1021
|
+
const bucketName = state.content?.bucketName;
|
|
1022
|
+
if (!bucketName) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
const exists = buckets.find((entry) => entry?.name === bucketName);
|
|
1026
|
+
if (exists) {
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (dryRun) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
runWrangler(["r2", "bucket", "create", bucketName], {
|
|
1033
|
+
cwd: tenantRoot,
|
|
1034
|
+
capture: true,
|
|
1035
|
+
env
|
|
1036
|
+
});
|
|
1037
|
+
};
|
|
1038
|
+
const ensurePagesProject = () => {
|
|
1039
|
+
const current = state.pages;
|
|
1040
|
+
if (!current?.projectName) {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
const exists = pagesProjects.find((entry) => entry?.name === current.projectName);
|
|
1044
|
+
if (exists) {
|
|
1045
|
+
current.url = exists.subdomain ? `https://${exists.subdomain}` : current.url ?? `https://${current.projectName}.pages.dev`;
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
if (dryRun) {
|
|
1049
|
+
current.url = `https://${current.projectName}.pages.dev`;
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
runWrangler([
|
|
1053
|
+
"pages",
|
|
1054
|
+
"project",
|
|
1055
|
+
"create",
|
|
1056
|
+
current.projectName,
|
|
1057
|
+
"--production-branch",
|
|
1058
|
+
target.kind === "persistent" && target.scope === "prod" ? current.productionBranch ?? "main" : current.stagingBranch ?? "staging"
|
|
1059
|
+
], {
|
|
1060
|
+
cwd: tenantRoot,
|
|
1061
|
+
capture: true,
|
|
1062
|
+
env
|
|
1063
|
+
});
|
|
1064
|
+
current.url = `https://${current.projectName}.pages.dev`;
|
|
1065
|
+
};
|
|
789
1066
|
ensureKv("FORM_GUARD_KV");
|
|
790
1067
|
ensureKv("SESSION");
|
|
791
1068
|
ensureD1();
|
|
1069
|
+
ensureQueue();
|
|
1070
|
+
ensureR2Bucket();
|
|
1071
|
+
ensurePagesProject();
|
|
1072
|
+
state.readiness.configured = true;
|
|
1073
|
+
state.readiness.provisioned = hasProvisionedCloudflareResources(state);
|
|
1074
|
+
state.readiness.deployable = state.readiness.provisioned === true;
|
|
792
1075
|
state.readiness.initialized = true;
|
|
793
1076
|
state.readiness.initializedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
794
1077
|
state.readiness.lastValidatedAt = state.readiness.initializedAt;
|
|
1078
|
+
state.readiness.lastValidationSummary = {
|
|
1079
|
+
cloudflare: state.readiness.provisioned === true ? "ready" : "incomplete",
|
|
1080
|
+
railway: "configured"
|
|
1081
|
+
};
|
|
795
1082
|
writeDeployState(tenantRoot, state, { target });
|
|
796
1083
|
return buildProvisioningSummary(deployConfig, state, target);
|
|
797
1084
|
}
|
|
@@ -827,11 +1114,58 @@ function syncCloudflareSecrets(tenantRoot, options = {}) {
|
|
|
827
1114
|
}
|
|
828
1115
|
state.generatedSecrets = {
|
|
829
1116
|
...state.generatedSecrets ?? {},
|
|
830
|
-
TREESEED_FORM_TOKEN_SECRET: secrets.TREESEED_FORM_TOKEN_SECRET ?? state.generatedSecrets?.TREESEED_FORM_TOKEN_SECRET
|
|
1117
|
+
TREESEED_FORM_TOKEN_SECRET: secrets.TREESEED_FORM_TOKEN_SECRET ?? state.generatedSecrets?.TREESEED_FORM_TOKEN_SECRET,
|
|
1118
|
+
TREESEED_EDITORIAL_PREVIEW_SECRET: secrets.TREESEED_EDITORIAL_PREVIEW_SECRET ?? state.generatedSecrets?.TREESEED_EDITORIAL_PREVIEW_SECRET
|
|
831
1119
|
};
|
|
832
1120
|
writeDeployState(tenantRoot, state, { target });
|
|
833
1121
|
return synced;
|
|
834
1122
|
}
|
|
1123
|
+
function verifyProvisionedCloudflareResources(tenantRoot, options = {}) {
|
|
1124
|
+
const target = normalizeTarget(options.scope ?? options.target ?? "prod");
|
|
1125
|
+
const deployConfig = loadTenantDeployConfig(tenantRoot);
|
|
1126
|
+
const state = loadDeployState(tenantRoot, deployConfig, { target });
|
|
1127
|
+
const env = {
|
|
1128
|
+
CLOUDFLARE_ACCOUNT_ID: deployConfig.cloudflare.accountId
|
|
1129
|
+
};
|
|
1130
|
+
const dryRun = options.dryRun ?? false;
|
|
1131
|
+
const kvNamespaces = dryRun ? [] : listKvNamespaces(tenantRoot, env);
|
|
1132
|
+
const d1Databases = dryRun ? [] : listD1Databases(tenantRoot, env);
|
|
1133
|
+
const queues = dryRun ? [] : listQueues(tenantRoot, env);
|
|
1134
|
+
const buckets = dryRun ? [] : listR2Buckets(tenantRoot, env);
|
|
1135
|
+
const pagesProjects = dryRun ? [] : listPagesProjects(tenantRoot, env);
|
|
1136
|
+
const checks = {
|
|
1137
|
+
pages: Boolean(state.pages?.projectName && pagesProjects.find((entry) => entry?.name === state.pages.projectName)),
|
|
1138
|
+
formGuardKv: Boolean(state.kvNamespaces?.FORM_GUARD_KV?.name && kvNamespaces.find((entry) => entry?.title === state.kvNamespaces.FORM_GUARD_KV.name)),
|
|
1139
|
+
sessionKv: Boolean(state.kvNamespaces?.SESSION?.name && kvNamespaces.find((entry) => entry?.title === state.kvNamespaces.SESSION.name)),
|
|
1140
|
+
d1: Boolean(state.d1Databases?.SITE_DATA_DB?.databaseName && d1Databases.find((entry) => entry?.name === state.d1Databases.SITE_DATA_DB.databaseName)),
|
|
1141
|
+
queue: Boolean(state.queues?.agentWork?.name && queues.find((entry) => queueName(entry) === state.queues.agentWork.name)),
|
|
1142
|
+
dlq: !state.queues?.agentWork?.dlqName || Boolean(queues.find((entry) => queueName(entry) === state.queues.agentWork.dlqName)),
|
|
1143
|
+
r2: Boolean(state.content?.bucketName && buckets.find((entry) => entry?.name === state.content.bucketName))
|
|
1144
|
+
};
|
|
1145
|
+
const ok = dryRun ? true : Object.values(checks).every(Boolean);
|
|
1146
|
+
state.readiness.configured = true;
|
|
1147
|
+
state.readiness.provisioned = ok;
|
|
1148
|
+
state.readiness.deployable = ok;
|
|
1149
|
+
state.readiness.lastValidatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1150
|
+
state.readiness.lastValidationSummary = checks;
|
|
1151
|
+
const liveQueue = queues.find((entry) => queueName(entry) === state.queues?.agentWork?.name);
|
|
1152
|
+
if (state.queues?.agentWork) {
|
|
1153
|
+
state.queues.agentWork.queueId = queueId(liveQueue) ?? state.queues.agentWork.queueId ?? null;
|
|
1154
|
+
const liveDlq = queues.find((entry) => queueName(entry) === state.queues.agentWork.dlqName);
|
|
1155
|
+
state.queues.agentWork.dlqId = queueId(liveDlq) ?? state.queues.agentWork.dlqId ?? null;
|
|
1156
|
+
}
|
|
1157
|
+
const livePages = pagesProjects.find((entry) => entry?.name === state.pages?.projectName);
|
|
1158
|
+
if (state.pages && livePages?.subdomain) {
|
|
1159
|
+
state.pages.url = `https://${livePages.subdomain}`;
|
|
1160
|
+
}
|
|
1161
|
+
writeDeployState(tenantRoot, state, { target });
|
|
1162
|
+
return {
|
|
1163
|
+
ok,
|
|
1164
|
+
target: deployTargetLabel(target),
|
|
1165
|
+
checks,
|
|
1166
|
+
state
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
835
1169
|
function runRemoteD1Migrations(tenantRoot, options = {}) {
|
|
836
1170
|
const target = normalizeTarget(options.scope ?? options.target ?? "prod");
|
|
837
1171
|
const { wranglerPath, deployConfig, state } = ensureGeneratedWranglerConfig(tenantRoot, { target });
|
|
@@ -853,6 +1187,9 @@ function markDeploymentInitialized(tenantRoot, options = {}) {
|
|
|
853
1187
|
const state = loadDeployState(tenantRoot, deployConfig, { target });
|
|
854
1188
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
855
1189
|
state.readiness.initialized = true;
|
|
1190
|
+
state.readiness.configured = true;
|
|
1191
|
+
state.readiness.provisioned = hasProvisionedCloudflareResources(state);
|
|
1192
|
+
state.readiness.deployable = state.readiness.provisioned === true;
|
|
856
1193
|
state.readiness.initializedAt = state.readiness.initializedAt ?? timestamp;
|
|
857
1194
|
state.readiness.lastValidatedAt = timestamp;
|
|
858
1195
|
state.readiness.lastConfigFingerprint = state.lastManifestFingerprint ?? state.readiness.lastConfigFingerprint;
|
|
@@ -912,6 +1249,9 @@ function finalizeDeploymentState(tenantRoot, options = {}) {
|
|
|
912
1249
|
const history = Array.isArray(state.deploymentHistory) ? state.deploymentHistory : [];
|
|
913
1250
|
state.deploymentHistory = [...history, nextHistoryEntry].slice(-20);
|
|
914
1251
|
state.readiness.initialized = true;
|
|
1252
|
+
state.readiness.configured = true;
|
|
1253
|
+
state.readiness.provisioned = hasProvisionedCloudflareResources(state);
|
|
1254
|
+
state.readiness.deployable = state.readiness.provisioned === true;
|
|
915
1255
|
state.readiness.lastValidatedAt = state.lastDeploymentTimestamp;
|
|
916
1256
|
for (const result of options.serviceResults ?? []) {
|
|
917
1257
|
if (!result?.service || !state.services?.[result.service]) {
|
|
@@ -977,5 +1317,6 @@ export {
|
|
|
977
1317
|
syncCloudflareSecrets,
|
|
978
1318
|
validateDeployPrerequisites,
|
|
979
1319
|
validateDestroyPrerequisites,
|
|
1320
|
+
verifyProvisionedCloudflareResources,
|
|
980
1321
|
writeDeployState
|
|
981
1322
|
};
|
|
@@ -14,17 +14,42 @@ export declare function requiredGitHubSecrets(tenantRoot: any): string[];
|
|
|
14
14
|
export declare function renderDeployWorkflow({ workingDirectory }: {
|
|
15
15
|
workingDirectory: any;
|
|
16
16
|
}): string;
|
|
17
|
+
export declare function renderHostedProjectWorkflow({ workingDirectory }: {
|
|
18
|
+
workingDirectory: any;
|
|
19
|
+
}): string;
|
|
17
20
|
export declare function ensureDeployWorkflow(tenantRoot: any): {
|
|
18
21
|
workflowPath: string;
|
|
19
22
|
changed: boolean;
|
|
20
23
|
workingDirectory: string;
|
|
21
24
|
mode: string;
|
|
22
25
|
} | {
|
|
26
|
+
workingDirectory: string;
|
|
27
|
+
workflowPath: string;
|
|
28
|
+
changed: boolean;
|
|
29
|
+
mode?: undefined;
|
|
30
|
+
};
|
|
31
|
+
export declare function ensureHostedProjectWorkflow(tenantRoot: any): {
|
|
23
32
|
workflowPath: string;
|
|
24
33
|
changed: boolean;
|
|
25
34
|
workingDirectory: string;
|
|
35
|
+
mode: string;
|
|
36
|
+
} | {
|
|
37
|
+
workingDirectory: string;
|
|
38
|
+
workflowPath: string;
|
|
39
|
+
changed: boolean;
|
|
26
40
|
mode?: undefined;
|
|
27
41
|
};
|
|
42
|
+
export declare function ensureStandardizedGitHubWorkflows(tenantRoot: any): ({
|
|
43
|
+
workflowPath: string;
|
|
44
|
+
changed: boolean;
|
|
45
|
+
workingDirectory: string;
|
|
46
|
+
mode: string;
|
|
47
|
+
} | {
|
|
48
|
+
workingDirectory: string;
|
|
49
|
+
workflowPath: string;
|
|
50
|
+
changed: boolean;
|
|
51
|
+
mode?: undefined;
|
|
52
|
+
})[];
|
|
28
53
|
export declare function listGitHubSecretNames(repository: any, tenantRoot: any): Set<unknown>;
|
|
29
54
|
export declare function listGitHubVariableNames(repository: any, tenantRoot: any): Set<unknown>;
|
|
30
55
|
export declare function formatMissingSecretsReport(repository: any, missingSecrets: any, reason?: string): string;
|
|
@@ -91,11 +116,22 @@ export declare function ensureGitHubDeployAutomation(tenantRoot: any, { dryRun }
|
|
|
91
116
|
workingDirectory: string;
|
|
92
117
|
mode: string;
|
|
93
118
|
} | {
|
|
119
|
+
workingDirectory: string;
|
|
94
120
|
workflowPath: string;
|
|
95
121
|
changed: boolean;
|
|
96
|
-
workingDirectory: string;
|
|
97
122
|
mode?: undefined;
|
|
98
123
|
};
|
|
124
|
+
workflows: ({
|
|
125
|
+
workflowPath: string;
|
|
126
|
+
changed: boolean;
|
|
127
|
+
workingDirectory: string;
|
|
128
|
+
mode: string;
|
|
129
|
+
} | {
|
|
130
|
+
workingDirectory: string;
|
|
131
|
+
workflowPath: string;
|
|
132
|
+
changed: boolean;
|
|
133
|
+
mode?: undefined;
|
|
134
|
+
})[];
|
|
99
135
|
secrets: {
|
|
100
136
|
existing: never[];
|
|
101
137
|
created: never[];
|