@treeseed/sdk 0.10.23 → 0.10.25

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.
Files changed (49) hide show
  1. package/dist/index.d.ts +12 -2
  2. package/dist/index.js +42 -1
  3. package/dist/market-client.d.ts +23 -0
  4. package/dist/market-client.js +30 -0
  5. package/dist/operations/providers/default.js +103 -10
  6. package/dist/operations/repository-operations.d.ts +6 -1
  7. package/dist/operations/repository-operations.js +44 -0
  8. package/dist/operations/services/bootstrap-runner.d.ts +5 -1
  9. package/dist/operations/services/bootstrap-runner.js +34 -5
  10. package/dist/operations/services/config-runtime.d.ts +25 -9
  11. package/dist/operations/services/config-runtime.js +60 -12
  12. package/dist/operations/services/deploy.js +6 -1
  13. package/dist/operations/services/hub-launch.js +1 -0
  14. package/dist/operations/services/hub-provider-launch.d.ts +11 -1
  15. package/dist/operations/services/hub-provider-launch.js +81 -8
  16. package/dist/operations/services/project-host-operations.d.ts +153 -0
  17. package/dist/operations/services/project-host-operations.js +365 -0
  18. package/dist/operations/services/project-platform.d.ts +207 -177
  19. package/dist/operations/services/project-platform.js +96 -29
  20. package/dist/operations/services/railway-deploy.d.ts +33 -1
  21. package/dist/operations/services/railway-deploy.js +153 -44
  22. package/dist/operations/services/release-candidate.js +8 -2
  23. package/dist/operations/services/template-host-bindings.d.ts +68 -0
  24. package/dist/operations/services/template-host-bindings.js +400 -0
  25. package/dist/operations/services/template-registry.d.ts +22 -2
  26. package/dist/operations/services/template-registry.js +93 -6
  27. package/dist/operations/services/template-secret-sync.d.ts +97 -0
  28. package/dist/operations/services/template-secret-sync.js +292 -0
  29. package/dist/platform/contracts.d.ts +1 -0
  30. package/dist/platform/deploy-config.js +8 -1
  31. package/dist/platform/deploy-runtime.js +1 -0
  32. package/dist/platform/environment.d.ts +3 -0
  33. package/dist/project-workflow.d.ts +7 -1
  34. package/dist/reconcile/engine.d.ts +2 -0
  35. package/dist/reconcile/engine.js +58 -3
  36. package/dist/scripts/scaffold-site.js +3 -2
  37. package/dist/scripts/test-scaffold.js +2 -1
  38. package/dist/sdk-types.d.ts +87 -0
  39. package/dist/sdk-types.js +29 -0
  40. package/dist/template-catalog.js +3 -1
  41. package/dist/template-launch-requirements.d.ts +118 -0
  42. package/dist/template-launch-requirements.js +759 -0
  43. package/dist/template-launch-ui.d.ts +85 -0
  44. package/dist/template-launch-ui.js +189 -0
  45. package/dist/timing.d.ts +20 -0
  46. package/dist/timing.js +73 -0
  47. package/dist/treeseed/template-catalog/catalog.fixture.json +477 -0
  48. package/package.json +13 -1
  49. package/templates/github/deploy-web.workflow.yml +4 -0
@@ -3,6 +3,7 @@ import { spawnSync } from "node:child_process";
3
3
  import { mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
4
4
  import { tmpdir } from "node:os";
5
5
  import { basename, extname, join, resolve } from "node:path";
6
+ import { elapsedMs, formatTimingMarkdown, formatTimingSummary } from "../../timing.js";
6
7
  import {
7
8
  createControlPlaneReporter
8
9
  } from "../../control-plane.js";
@@ -52,6 +53,39 @@ const PROCESSING_PLATFORM_BOOTSTRAP_SYSTEMS = ["api", "agents"];
52
53
  function stableHash(value) {
53
54
  return createHash("sha256").update(value).digest("hex");
54
55
  }
56
+ function recordTiming(timings, name, startMs, status = "success", metadata) {
57
+ const entry = {
58
+ name,
59
+ durationMs: elapsedMs(startMs),
60
+ status,
61
+ ...metadata ? { metadata } : {}
62
+ };
63
+ timings.push(entry);
64
+ return entry;
65
+ }
66
+ async function timedPhase(timings, name, run, metadata) {
67
+ const startMs = performance.now();
68
+ try {
69
+ const result = await Promise.resolve(run());
70
+ recordTiming(timings, name, startMs, "success", metadata);
71
+ return result;
72
+ } catch (error) {
73
+ recordTiming(timings, name, startMs, "failed", {
74
+ ...metadata ?? {},
75
+ error: error instanceof Error ? error.message : String(error)
76
+ });
77
+ throw error;
78
+ }
79
+ }
80
+ function writeProviderTimingSummary(options, timings) {
81
+ const text = formatTimingSummary(timings);
82
+ options.write?.(text);
83
+ const summaryPath = String(options.env?.TREESEED_PROVIDER_TIMING_SUMMARY_PATH ?? process.env.TREESEED_PROVIDER_TIMING_SUMMARY_PATH ?? "").trim();
84
+ if (!summaryPath) {
85
+ return;
86
+ }
87
+ writeFileSync(summaryPath, formatTimingMarkdown(timings), { flag: "a" });
88
+ }
55
89
  function inferEnvironmentFromBranch(tenantRoot) {
56
90
  const branch = currentManagedBranch(tenantRoot);
57
91
  if (branch === STAGING_BRANCH) {
@@ -1024,25 +1058,30 @@ async function publishContent(options, reporter, publishOptions = {}) {
1024
1058
  }
1025
1059
  }
1026
1060
  async function provisionProjectPlatform(options) {
1061
+ const timings = [];
1027
1062
  const reporter = resolveReporter(options.tenantRoot, options.reporter);
1028
1063
  const target = createPersistentDeployTarget(options.scope === "local" ? "staging" : options.scope);
1029
1064
  const siteConfig = loadCliDeployConfig(options.tenantRoot);
1030
1065
  const bootstrapSystems = resolveProjectPlatformBootstrapSystems(options, siteConfig);
1031
1066
  const selectedSystems = new Set(bootstrapSystems);
1032
1067
  const env = { ...process.env, ...options.env ?? {} };
1033
- const summary = await reconcileTreeseedTarget({
1068
+ const summary = await timedPhase(timings, "provision:reconcile", () => reconcileTreeseedTarget({
1034
1069
  tenantRoot: options.tenantRoot,
1035
1070
  target,
1036
1071
  env,
1037
- systems: bootstrapSystems
1038
- });
1039
- const verification = await collectTreeseedReconcileStatus({
1072
+ systems: bootstrapSystems,
1073
+ write: options.write
1074
+ }));
1075
+ timings.push(...summary.timings ?? []);
1076
+ const verification = await timedPhase(timings, "provision:collect-reconcile-status", () => collectTreeseedReconcileStatus({
1040
1077
  tenantRoot: options.tenantRoot,
1041
1078
  target,
1042
1079
  env,
1043
1080
  systems: bootstrapSystems
1081
+ }));
1082
+ await timedPhase(timings, "provision:ensure-wrangler-config", () => {
1083
+ ensureGeneratedWranglerConfig(options.tenantRoot, { target });
1044
1084
  });
1045
- ensureGeneratedWranglerConfig(options.tenantRoot, { target });
1046
1085
  const shouldValidateRailway = selectedSystems.has("api") || selectedSystems.has("agents");
1047
1086
  const railwayValidation = shouldValidateRailway ? options.scope === "local" ? validateRailwayServiceConfiguration(options.tenantRoot, options.scope) : validateRailwayDeployPrerequisites(options.tenantRoot, options.scope, { env }) : { services: [] };
1048
1087
  const railwaySchedules = [];
@@ -1173,6 +1212,7 @@ async function provisionProjectPlatform(options) {
1173
1212
  target: deployTargetLabel(target),
1174
1213
  summary,
1175
1214
  verification,
1215
+ timings,
1176
1216
  reconcileActions: summary.results.map((result) => ({
1177
1217
  unitId: result.unit.unitId,
1178
1218
  action: result.action,
@@ -1190,6 +1230,7 @@ async function provisionProjectPlatform(options) {
1190
1230
  target: deployTargetLabel(target),
1191
1231
  summary,
1192
1232
  verification,
1233
+ timings,
1193
1234
  railway: {
1194
1235
  services: railwayValidation.services.map((service) => service.key),
1195
1236
  schedules: railwaySchedules,
@@ -1198,6 +1239,8 @@ async function provisionProjectPlatform(options) {
1198
1239
  };
1199
1240
  }
1200
1241
  async function deployProjectPlatform(options) {
1242
+ const timings = [];
1243
+ const deployStartMs = performance.now();
1201
1244
  const reporter = resolveReporter(options.tenantRoot, options.reporter);
1202
1245
  const commitSha = currentCommit(options.tenantRoot);
1203
1246
  const branchName = currentRef(options.tenantRoot);
@@ -1216,7 +1259,8 @@ async function deployProjectPlatform(options) {
1216
1259
  metadata: { scope: options.scope }
1217
1260
  });
1218
1261
  if (!options.skipProvision) {
1219
- await provisionProjectPlatform({ ...options, reporter, bootstrapSystems });
1262
+ const provision = await timedPhase(timings, "deploy:provision", () => provisionProjectPlatform({ ...options, reporter, bootstrapSystems }));
1263
+ timings.push(...provision.timings ?? []);
1220
1264
  }
1221
1265
  const nodes = [];
1222
1266
  let cloudflareContext = null;
@@ -1276,6 +1320,7 @@ async function deployProjectPlatform(options) {
1276
1320
  const selectedServices = validation.services.filter(
1277
1321
  (service) => service.key === "api" ? selectedSystems.has("api") : selectedSystems.has("agents")
1278
1322
  );
1323
+ const sequentialRailwayDeploys = String(env.TREESEED_RAILWAY_DEPLOY_SEQUENTIAL ?? "").trim() === "1";
1279
1324
  let previousRailwayDeployNodeId = null;
1280
1325
  for (const service of selectedServices) {
1281
1326
  const system = service.key === "api" ? "api" : "agents";
@@ -1285,7 +1330,8 @@ async function deployProjectPlatform(options) {
1285
1330
  id: nodeId,
1286
1331
  dependencies: resolveRailwayServiceDeployDependencies({
1287
1332
  includeDataDependency: selectedSystems.has("data"),
1288
- previousRailwayDeployNodeId
1333
+ previousRailwayDeployNodeId,
1334
+ sequentialRailwayDeploys
1289
1335
  }),
1290
1336
  run: async () => {
1291
1337
  const result = await deployRailwayService(options.tenantRoot, service, {
@@ -1303,7 +1349,9 @@ async function deployProjectPlatform(options) {
1303
1349
  return result;
1304
1350
  }
1305
1351
  });
1306
- previousRailwayDeployNodeId = nodeId;
1352
+ if (sequentialRailwayDeploys) {
1353
+ previousRailwayDeployNodeId = nodeId;
1354
+ }
1307
1355
  }
1308
1356
  }
1309
1357
  const managesRailwaySchedules = options.scope === "staging" || options.scope === "prod";
@@ -1335,8 +1383,11 @@ async function deployProjectPlatform(options) {
1335
1383
  }
1336
1384
  });
1337
1385
  }
1338
- await runTreeseedBootstrapDag({ nodes, execution });
1386
+ await runTreeseedBootstrapDag({ nodes, execution, write, timings });
1339
1387
  const serviceResults = selectedRailwayServiceKeys.map((serviceKey) => serviceResultsByKey.get(serviceKey)).filter(Boolean);
1388
+ for (const result of serviceResults) {
1389
+ timings.push(...result.timings ?? []);
1390
+ }
1340
1391
  if (options.scope !== "local" && !options.dryRun && (selectedSystems.has("web") || serviceResults.length > 0)) {
1341
1392
  finalizeDeploymentState(options.tenantRoot, {
1342
1393
  target: createPersistentDeployTarget(options.scope),
@@ -1358,8 +1409,11 @@ async function deployProjectPlatform(options) {
1358
1409
  scheduleVerification: railwayScheduleVerification
1359
1410
  });
1360
1411
  }
1361
- const monitor = await monitorProjectPlatform({ ...options, reporter, bootstrapSystems });
1362
- const hostingRepair = await repairHostingAfterSuccessfulDeploy(options, bootstrapSystems);
1412
+ const monitor = await timedPhase(timings, "deploy:monitor", () => monitorProjectPlatform({ ...options, reporter, bootstrapSystems }));
1413
+ timings.push(...monitor.timings ?? []);
1414
+ const hostingRepair = await timedPhase(timings, "deploy:hosting-repair", () => repairHostingAfterSuccessfulDeploy(options, bootstrapSystems));
1415
+ recordTiming(timings, "deploy:total", deployStartMs);
1416
+ writeProviderTimingSummary(options, timings);
1363
1417
  await reportDeployment(reporter, {
1364
1418
  environment: options.scope,
1365
1419
  deploymentKind: "code",
@@ -1371,7 +1425,8 @@ async function deployProjectPlatform(options) {
1371
1425
  scope: options.scope,
1372
1426
  railway: options.scope === "local" ? [] : configuredRailwayServices(options.tenantRoot, options.scope).map((service) => service.key).filter((serviceKey) => serviceKey === "api" ? selectedSystems.has("api") : selectedSystems.has("agents")),
1373
1427
  monitor,
1374
- hostingRepair
1428
+ hostingRepair,
1429
+ timings
1375
1430
  },
1376
1431
  finishedAt: (/* @__PURE__ */ new Date()).toISOString()
1377
1432
  });
@@ -1380,16 +1435,18 @@ async function deployProjectPlatform(options) {
1380
1435
  scope: options.scope,
1381
1436
  monitor,
1382
1437
  hostingRepair,
1383
- serviceResults
1438
+ serviceResults,
1439
+ timings
1384
1440
  };
1385
1441
  }
1386
1442
  function resolveRailwayServiceDeployDependencies({
1387
1443
  includeDataDependency,
1388
- previousRailwayDeployNodeId
1444
+ previousRailwayDeployNodeId,
1445
+ sequentialRailwayDeploys = false
1389
1446
  }) {
1390
1447
  return [
1391
1448
  ...includeDataDependency ? ["data:d1-migrate"] : [],
1392
- ...previousRailwayDeployNodeId ? [previousRailwayDeployNodeId] : []
1449
+ ...sequentialRailwayDeploys && previousRailwayDeployNodeId ? [previousRailwayDeployNodeId] : []
1393
1450
  ];
1394
1451
  }
1395
1452
  async function publishProjectContent(options) {
@@ -1397,6 +1454,7 @@ async function publishProjectContent(options) {
1397
1454
  return publishContent(options, reporter);
1398
1455
  }
1399
1456
  async function monitorProjectPlatform(options) {
1457
+ const timings = [];
1400
1458
  const reporter = resolveReporter(options.tenantRoot, options.reporter);
1401
1459
  const env = { ...process.env, ...options.env ?? {} };
1402
1460
  const target = createPersistentDeployTarget(options.scope === "local" ? "staging" : options.scope);
@@ -1408,24 +1466,24 @@ async function monitorProjectPlatform(options) {
1408
1466
  const webProbeUrl = resolveImmediatePagesProbeUrl(siteConfig, state, target);
1409
1467
  const apiBaseUrl = resolveImmediateApiProbeUrl(siteConfig, state, target);
1410
1468
  const apiMonitorEndpoints = resolveApiMonitorEndpoints(siteConfig, apiBaseUrl);
1411
- const railwayResources = options.scope === "local" || !apiSelected && !agentsSelected ? { ok: true, skipped: true, reason: options.scope === "local" ? "local_scope" : "railway_not_selected" } : await verifyRailwayManagedResources(options.tenantRoot, options.scope, {
1469
+ const railwayResourcesPromise = options.scope === "local" || !apiSelected && !agentsSelected ? { ok: true, skipped: true, reason: options.scope === "local" ? "local_scope" : "railway_not_selected" } : timedPhase(timings, "monitor:railway-resources", () => verifyRailwayManagedResources(options.tenantRoot, options.scope, {
1412
1470
  env,
1413
1471
  settleDeployments: true,
1414
1472
  onProgress: options.write
1415
- });
1473
+ }));
1416
1474
  const skippedApiCheck = apiSelected ? { ok: false, skipped: true, reason: "api_url_unconfigured" } : { ok: true, skipped: true, reason: "api_not_selected" };
1417
1475
  const skippedAgentCheck = agentsSelected ? { ok: false, skipped: true, reason: "api_url_unconfigured" } : { ok: true, skipped: true, reason: "agents_not_selected" };
1418
1476
  const skippedD1Check = apiMonitorEndpoints.processingAgentApi ? { ok: true, skipped: true, reason: "processing_agent_api" } : skippedApiCheck;
1419
1477
  const checks = {
1420
- pages: await probeHttp(webProbeUrl, { attempts: 3, delayMs: 5e3 }),
1421
- apiHealth: apiSelected && apiMonitorEndpoints.apiHealth ? await probeHttp(apiMonitorEndpoints.apiHealth, { attempts: 8, delayMs: 1e4 }) : skippedApiCheck,
1422
- apiReady: apiSelected && apiMonitorEndpoints.apiReady ? await probeHttp(apiMonitorEndpoints.apiReady, { attempts: 8, delayMs: 1e4 }) : skippedApiCheck,
1423
- d1Health: apiSelected && apiMonitorEndpoints.d1Health ? await probeHttp(apiMonitorEndpoints.d1Health, { attempts: 8, delayMs: 1e4 }) : skippedD1Check,
1424
- agentHealth: agentsSelected && apiMonitorEndpoints.agentHealth ? await probeHttp(apiMonitorEndpoints.agentHealth, { attempts: 8, delayMs: 1e4 }) : skippedAgentCheck,
1425
- r2: options.dryRun ? { ok: true, skipped: true, reason: "dry_run" } : probeR2(options.tenantRoot, siteConfig, state, target),
1426
- queue: options.dryRun ? Promise.resolve({ ok: true, skipped: true, reason: "dry_run" }) : probeQueue(siteConfig, state),
1427
- scaleProbe: probeScaleConfiguration(siteConfig, state),
1428
- railwayResources,
1478
+ pages: timedPhase(timings, "monitor:probe-pages", () => probeHttp(webProbeUrl, { attempts: 3, delayMs: 5e3 })),
1479
+ apiHealth: apiSelected && apiMonitorEndpoints.apiHealth ? timedPhase(timings, "monitor:probe-api-health", () => probeHttp(apiMonitorEndpoints.apiHealth, { attempts: 8, delayMs: 1e4 })) : Promise.resolve(skippedApiCheck),
1480
+ apiReady: apiSelected && apiMonitorEndpoints.apiReady ? timedPhase(timings, "monitor:probe-api-ready", () => probeHttp(apiMonitorEndpoints.apiReady, { attempts: 8, delayMs: 1e4 })) : Promise.resolve(skippedApiCheck),
1481
+ d1Health: apiSelected && apiMonitorEndpoints.d1Health ? timedPhase(timings, "monitor:probe-d1-health", () => probeHttp(apiMonitorEndpoints.d1Health, { attempts: 8, delayMs: 1e4 })) : Promise.resolve(skippedD1Check),
1482
+ agentHealth: agentsSelected && apiMonitorEndpoints.agentHealth ? timedPhase(timings, "monitor:probe-agent-health", () => probeHttp(apiMonitorEndpoints.agentHealth, { attempts: 8, delayMs: 1e4 })) : Promise.resolve(skippedAgentCheck),
1483
+ r2: options.dryRun ? Promise.resolve({ ok: true, skipped: true, reason: "dry_run" }) : timedPhase(timings, "monitor:probe-r2", () => probeR2(options.tenantRoot, siteConfig, state, target)),
1484
+ queue: options.dryRun ? Promise.resolve({ ok: true, skipped: true, reason: "dry_run" }) : timedPhase(timings, "monitor:probe-queue", () => probeQueue(siteConfig, state)),
1485
+ scaleProbe: timedPhase(timings, "monitor:probe-scale", () => probeScaleConfiguration(siteConfig, state)),
1486
+ railwayResources: Promise.resolve(railwayResourcesPromise),
1429
1487
  readiness: state.readiness,
1430
1488
  apiMonitor: {
1431
1489
  ok: true,
@@ -1435,8 +1493,15 @@ async function monitorProjectPlatform(options) {
1435
1493
  };
1436
1494
  const resolvedChecks = {
1437
1495
  ...checks,
1496
+ pages: await checks.pages,
1497
+ apiHealth: await checks.apiHealth,
1498
+ apiReady: await checks.apiReady,
1499
+ d1Health: await checks.d1Health,
1500
+ agentHealth: await checks.agentHealth,
1438
1501
  r2: await checks.r2,
1439
- queue: await checks.queue
1502
+ queue: await checks.queue,
1503
+ scaleProbe: await checks.scaleProbe,
1504
+ railwayResources: await checks.railwayResources
1440
1505
  };
1441
1506
  const ok = [
1442
1507
  resolvedChecks.pages,
@@ -1464,14 +1529,16 @@ ${failedChecks.join("\n")}`);
1464
1529
  metadata: {
1465
1530
  mode: "monitor",
1466
1531
  target: deployTargetLabel(target),
1467
- checks: resolvedChecks
1532
+ checks: resolvedChecks,
1533
+ timings
1468
1534
  },
1469
1535
  finishedAt: (/* @__PURE__ */ new Date()).toISOString()
1470
1536
  });
1471
1537
  return {
1472
1538
  ok,
1473
1539
  target: deployTargetLabel(target),
1474
- checks: resolvedChecks
1540
+ checks: resolvedChecks,
1541
+ timings
1475
1542
  };
1476
1543
  }
1477
1544
  async function syncControlPlaneState(options) {
@@ -1,4 +1,5 @@
1
1
  import { type TreeseedBootstrapTaskPrefix, type TreeseedBootstrapWriter } from './bootstrap-runner.ts';
2
+ import { type TreeseedTimingEntry } from '../../timing.ts';
2
3
  export declare function deriveRailwayWorkerRunnerServiceName(projectSlug: any, index?: number): string;
3
4
  export declare function deriveRailwayMarketOperationsRunnerServiceName(baseServiceName: any, index?: number): string;
4
5
  export declare function deriveRailwayWorkerRunnerVolumeName(serviceName: any, environmentName?: string): string;
@@ -31,18 +32,47 @@ export declare function runRailway(args: any, { cwd, capture, allowFailure, inpu
31
32
  retryAttempts?: number | undefined;
32
33
  retryDelayMs?: number | undefined;
33
34
  }): import("child_process").SpawnSyncReturns<string> | null;
34
- export declare function waitForRailwayManagedDeploymentsSettled(tenantRoot: any, scope: any, { services, env, timeoutMs, pollMs, onProgress, }?: {
35
+ export declare function waitForRailwayManagedDeploymentsSettled(tenantRoot: any, scope: any, { services, env, timeoutMs, pollMs, fetchImpl, onProgress, }?: {
35
36
  services?: unknown[] | undefined;
36
37
  env?: NodeJS.ProcessEnv | undefined;
37
38
  timeoutMs?: number | undefined;
38
39
  pollMs?: number | undefined;
40
+ fetchImpl?: typeof fetch | undefined;
39
41
  }): Promise<{
42
+ ok: boolean;
43
+ checks: {
44
+ type: string;
45
+ service: any;
46
+ serviceName: any;
47
+ environment: string;
48
+ ok: boolean;
49
+ status: string;
50
+ settle: {
51
+ durationMs: number;
52
+ pollCount: number;
53
+ finalStatus: string;
54
+ };
55
+ message: string;
56
+ }[];
57
+ settle?: undefined;
58
+ message?: undefined;
59
+ } | {
40
60
  ok: boolean;
41
61
  checks: any;
62
+ settle: {
63
+ durationMs: number;
64
+ pollCount: number;
65
+ status: string;
66
+ };
42
67
  message?: undefined;
43
68
  } | {
44
69
  ok: boolean;
45
70
  checks: any;
71
+ settle: {
72
+ durationMs: number;
73
+ pollCount: number;
74
+ status: string;
75
+ };
46
76
  message: string;
47
77
  }>;
48
78
  export declare function setRailwaySecretVariable({ cwd, service, environment, key, value, env, capture, allowFailure }: {
@@ -182,6 +212,7 @@ export declare function deployRailwayService(tenantRoot: any, service: any, { dr
182
212
  command: string;
183
213
  cwd: any;
184
214
  publicBaseUrl: any;
215
+ timings: TreeseedTimingEntry[];
185
216
  runtimeConfiguration?: undefined;
186
217
  } | {
187
218
  service: any;
@@ -189,6 +220,7 @@ export declare function deployRailwayService(tenantRoot: any, service: any, { dr
189
220
  command: string;
190
221
  cwd: any;
191
222
  publicBaseUrl: any;
223
+ timings: TreeseedTimingEntry[];
192
224
  runtimeConfiguration: {
193
225
  updated: boolean;
194
226
  healthcheckPath: string | null;