@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
@@ -24,6 +24,7 @@ import {
24
24
  resolveRailwayWorkspaceContext,
25
25
  upsertRailwayVariables
26
26
  } from "./railway-api.js";
27
+ import { elapsedMs, formatDurationMs } from "../../timing.js";
27
28
  function normalizeScope(scope) {
28
29
  return scope === "prod" ? "prod" : scope === "staging" ? "staging" : "local";
29
30
  }
@@ -86,6 +87,30 @@ function configuredEnvValue(env, name) {
86
87
  const value = env?.[name];
87
88
  return typeof value === "string" && value.trim() ? value.trim() : "";
88
89
  }
90
+ async function timedRailwayPhase(timings, name, run, metadata) {
91
+ const startMs = performance.now();
92
+ try {
93
+ const result = await Promise.resolve(run());
94
+ timings.push({
95
+ name,
96
+ durationMs: elapsedMs(startMs),
97
+ status: "success",
98
+ ...metadata ? { metadata } : {}
99
+ });
100
+ return result;
101
+ } catch (error) {
102
+ timings.push({
103
+ name,
104
+ durationMs: elapsedMs(startMs),
105
+ status: "failed",
106
+ metadata: {
107
+ ...metadata ?? {},
108
+ error: error instanceof Error ? error.name || "Error" : "Error"
109
+ }
110
+ });
111
+ throw error;
112
+ }
113
+ }
89
114
  function parseRailwayJsonOutput(output) {
90
115
  const trimmed = typeof output === "string" ? output.trim() : "";
91
116
  if (!trimmed) {
@@ -171,6 +196,26 @@ function collectRailwayDeploymentStatusChecks(statusPayload, scope, services) {
171
196
  };
172
197
  }
173
198
  const deployment = instance.latestDeployment ?? null;
199
+ if (!deployment) {
200
+ return {
201
+ type: "deployment-status",
202
+ service: service.key,
203
+ serviceName: service.serviceName,
204
+ environment: normalizeRailwayEnvironmentName(environment.name),
205
+ ok: true,
206
+ skipped: true,
207
+ status: "no_active_deployment",
208
+ observed: {
209
+ status: null,
210
+ deploymentId: null,
211
+ deploymentCreatedAt: null,
212
+ deploymentStopped: null,
213
+ instanceStatuses: [],
214
+ volumeMounts: []
215
+ },
216
+ message: `Railway service ${service.serviceName} has no active deployment to wait for.`
217
+ };
218
+ }
174
219
  const status = String(deployment?.status ?? "").trim().toUpperCase();
175
220
  const instanceStatuses = Array.isArray(deployment?.instances) ? deployment.instances.map((entry) => String(entry?.status ?? "").trim()).filter(Boolean) : [];
176
221
  const ok = railwayStatusDeploymentSettled(status);
@@ -183,6 +228,8 @@ function collectRailwayDeploymentStatusChecks(statusPayload, scope, services) {
183
228
  status: status || "missing_deployment",
184
229
  observed: {
185
230
  status: status || null,
231
+ deploymentId: deployment?.id ?? null,
232
+ deploymentCreatedAt: deployment?.createdAt ?? null,
186
233
  deploymentStopped: deployment?.deploymentStopped ?? null,
187
234
  instanceStatuses,
188
235
  volumeMounts: Array.isArray(deployment?.meta?.volumeMounts) ? deployment.meta.volumeMounts : []
@@ -474,8 +521,10 @@ async function waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
474
521
  env = process.env,
475
522
  timeoutMs = 6e5,
476
523
  pollMs = 15e3,
524
+ fetchImpl = fetch,
477
525
  onProgress
478
526
  } = {}) {
527
+ const startMs = performance.now();
479
528
  const deadline = Date.now() + timeoutMs;
480
529
  const projectId = services.find((service) => typeof service.projectId === "string" && service.projectId.trim())?.projectId ?? null;
481
530
  if (!projectId) {
@@ -488,6 +537,11 @@ async function waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
488
537
  environment: resolveRailwayEnvironmentForScope(scope),
489
538
  ok: false,
490
539
  status: "missing_project",
540
+ settle: {
541
+ durationMs: elapsedMs(startMs),
542
+ pollCount: 0,
543
+ finalStatus: "missing_project"
544
+ },
491
545
  message: `Railway deployment status for ${service.serviceName} cannot be checked without a project id.`
492
546
  }))
493
547
  };
@@ -495,12 +549,15 @@ async function waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
495
549
  let checks = [];
496
550
  let lastError = null;
497
551
  let lastSummary = "";
552
+ let pollCount = 0;
498
553
  for (; ; ) {
499
554
  lastError = null;
555
+ pollCount += 1;
500
556
  try {
501
557
  const statusPayload = await fetchRailwayProjectDeploymentStatus({
502
558
  projectId,
503
- env
559
+ env,
560
+ fetchImpl
504
561
  });
505
562
  checks = collectRailwayDeploymentStatusChecks(statusPayload, scope, services);
506
563
  } catch (error) {
@@ -512,28 +569,63 @@ async function waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
512
569
  environment: resolveRailwayEnvironmentForScope(scope),
513
570
  ok: false,
514
571
  status: "status_error",
572
+ settle: {
573
+ durationMs: elapsedMs(startMs),
574
+ pollCount,
575
+ finalStatus: "status_error"
576
+ },
515
577
  message: error instanceof Error ? error.message : String(error)
516
578
  }));
517
579
  }
518
580
  const summary = formatRailwayDeploymentStatusSummary(scope, checks);
519
- if (summary !== lastSummary || !checks.every((entry) => entry.ok === true)) {
520
- onProgress?.(summary, "stdout");
521
- lastSummary = summary;
581
+ const progress = `${summary} poll=${pollCount} elapsed=${formatDurationMs(elapsedMs(startMs))}`;
582
+ if (progress !== lastSummary || !checks.every((entry) => entry.ok === true || entry.skipped === true)) {
583
+ onProgress?.(progress, "stdout");
584
+ lastSummary = progress;
522
585
  }
523
- if (checks.every((entry) => entry.ok === true)) {
524
- return { ok: true, checks };
586
+ if (checks.every((entry) => entry.ok === true || entry.skipped === true)) {
587
+ return {
588
+ ok: true,
589
+ checks: checks.map((check) => ({
590
+ ...check,
591
+ settle: {
592
+ durationMs: elapsedMs(startMs),
593
+ pollCount,
594
+ finalStatus: check.status,
595
+ fastSkipped: check.skipped === true
596
+ }
597
+ })),
598
+ settle: {
599
+ durationMs: elapsedMs(startMs),
600
+ pollCount,
601
+ status: checks.every((entry) => entry.skipped === true) ? "skipped" : "settled"
602
+ }
603
+ };
525
604
  }
526
605
  if (Date.now() >= deadline) {
527
606
  return {
528
607
  ok: false,
529
- checks,
608
+ checks: checks.map((check) => ({
609
+ ...check,
610
+ settle: {
611
+ durationMs: elapsedMs(startMs),
612
+ pollCount,
613
+ finalStatus: check.status,
614
+ timeout: true
615
+ }
616
+ })),
617
+ settle: {
618
+ durationMs: elapsedMs(startMs),
619
+ pollCount,
620
+ status: "timeout"
621
+ },
530
622
  message: lastError instanceof Error ? lastError.message : "Railway deployments did not settle before the monitor timeout."
531
623
  };
532
624
  }
533
625
  await sleep(pollMs);
534
626
  }
535
627
  }
536
- async function fetchRailwayProjectDeploymentStatus({ projectId, env = process.env }) {
628
+ async function fetchRailwayProjectDeploymentStatus({ projectId, env = process.env, fetchImpl = fetch }) {
537
629
  const payload = await railwayGraphqlRequest({
538
630
  query: `
539
631
  query TreeseedRailwayDeploymentStatus($projectId: String!) {
@@ -571,7 +663,8 @@ query TreeseedRailwayDeploymentStatus($projectId: String!) {
571
663
  }
572
664
  `.trim(),
573
665
  variables: { projectId },
574
- env
666
+ env,
667
+ fetchImpl
575
668
  });
576
669
  return payload.data?.project ?? null;
577
670
  }
@@ -1300,6 +1393,7 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
1300
1393
  const settled = await waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
1301
1394
  services: deploymentStatusServices.length > 0 ? deploymentStatusServices : services,
1302
1395
  env: effectiveEnv,
1396
+ fetchImpl,
1303
1397
  timeoutMs: settleTimeoutMs,
1304
1398
  pollMs: settlePollMs,
1305
1399
  onProgress
@@ -1897,6 +1991,7 @@ async function deployRailwayService(tenantRoot, service, {
1897
1991
  prefix,
1898
1992
  env = process.env
1899
1993
  } = {}) {
1994
+ const timings = [];
1900
1995
  if (dryRun) {
1901
1996
  const plan2 = planRailwayServiceDeploy(service, { env });
1902
1997
  return {
@@ -1904,10 +1999,13 @@ async function deployRailwayService(tenantRoot, service, {
1904
1999
  status: "planned",
1905
2000
  command: [plan2.command, ...plan2.args].join(" "),
1906
2001
  cwd: plan2.cwd,
1907
- publicBaseUrl: service.publicBaseUrl
2002
+ publicBaseUrl: service.publicBaseUrl,
2003
+ timings
1908
2004
  };
1909
2005
  }
1910
- const deployService = await resolveRailwayDeployProjectContext(service, { env });
2006
+ const deployService = await timedRailwayPhase(timings, "railway:resolve-context", () => resolveRailwayDeployProjectContext(service, { env }), {
2007
+ service: service.key
2008
+ });
1911
2009
  const commandEnv = buildRailwayCommandEnv({ ...process.env, ...env });
1912
2010
  let railwayDeployEnv = buildRailwayDeployCommandEnv(commandEnv);
1913
2011
  const railway = resolveTreeseedToolCommand("railway", { env: commandEnv });
@@ -1920,9 +2018,9 @@ async function deployRailwayService(tenantRoot, service, {
1920
2018
  task: `${deployService.key}-railway-deploy`,
1921
2019
  stage: "deploy"
1922
2020
  };
1923
- const runtimeConfiguration = await syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, deployService, {
2021
+ const runtimeConfiguration = await timedRailwayPhase(timings, "railway:sync-runtime-config", () => syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, deployService, {
1924
2022
  env: commandEnv
1925
- });
2023
+ }), { service: deployService.key });
1926
2024
  const cliDeployService = {
1927
2025
  ...deployService,
1928
2026
  projectId: runtimeConfiguration?.projectId ?? deployService.projectId,
@@ -1932,14 +2030,19 @@ async function deployRailwayService(tenantRoot, service, {
1932
2030
  serviceName: runtimeConfiguration?.serviceName ?? deployService.serviceName,
1933
2031
  railwayEnvironment: runtimeConfiguration?.environmentName ?? runtimeConfiguration?.environmentId ?? deployService.railwayEnvironment
1934
2032
  };
1935
- await syncRailwayApiDeviceLoginVariables(cliDeployService, commandEnv, write, taskPrefix);
2033
+ await timedRailwayPhase(timings, "railway:device-login-vars", () => syncRailwayApiDeviceLoginVariables(cliDeployService, commandEnv, write, taskPrefix), {
2034
+ service: cliDeployService.key
2035
+ });
1936
2036
  railwayDeployEnv = buildRailwayCliContextEnv(railwayDeployEnv, cliDeployService);
1937
2037
  const hasCommandApiToken = Boolean(configuredEnvValue(commandEnv, "RAILWAY_API_TOKEN"));
1938
2038
  let usesProjectToken = Boolean(configuredEnvValue(railwayDeployEnv, "RAILWAY_TOKEN"));
1939
2039
  if (usesProjectToken) {
1940
2040
  railwayDeployEnv = { ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0 };
1941
2041
  }
1942
- if (!usesProjectToken && !hasCommandApiToken) {
2042
+ await timedRailwayPhase(timings, "railway:project-token", async () => {
2043
+ if (usesProjectToken || hasCommandApiToken) {
2044
+ return null;
2045
+ }
1943
2046
  const projectToken = await createRailwayCliProjectToken(cliDeployService, { env: commandEnv });
1944
2047
  if (projectToken) {
1945
2048
  railwayDeployEnv = buildRailwayCliContextEnv({ ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0, RAILWAY_TOKEN: projectToken }, cliDeployService);
@@ -1947,16 +2050,17 @@ async function deployRailwayService(tenantRoot, service, {
1947
2050
  } else if (configuredEnvValue(commandEnv, "CI") === "true") {
1948
2051
  throw new Error(`Railway CI deploy requires a project token for ${cliDeployService.serviceName ?? cliDeployService.key}. Automatic project token creation did not return a token.`);
1949
2052
  }
1950
- }
2053
+ return null;
2054
+ }, { service: cliDeployService.key });
1951
2055
  const linkPlan = planRailwayServiceLink(cliDeployService, { env: commandEnv });
1952
2056
  const plan = planRailwayServiceDeploy(cliDeployService, { env, projectTokenMode: usesProjectToken });
1953
2057
  if (deployService.buildCommand && shouldRunRailwayPredeployBuild(commandEnv)) {
1954
- const buildResult = await runPrefixedCommand("bash", ["-lc", deployService.buildCommand], {
2058
+ const buildResult = await timedRailwayPhase(timings, "railway:predeploy-build", () => runPrefixedCommand("bash", ["-lc", deployService.buildCommand], {
1955
2059
  cwd: deployService.rootDir,
1956
2060
  env: commandEnv,
1957
2061
  write,
1958
2062
  prefix: { ...taskPrefix, stage: "build" }
1959
- });
2063
+ }), { service: deployService.key });
1960
2064
  if (buildResult.status !== 0) {
1961
2065
  throw new Error(`Railway ${deployService.key} build command failed.`);
1962
2066
  }
@@ -1965,9 +2069,11 @@ async function deployRailwayService(tenantRoot, service, {
1965
2069
  const cliConfig = configuredEnvValue(commandEnv, "CI") === "true" ? writeRailwayCliProjectConfig(cliDeployService, { env: railwayDeployEnv, cwd: plan.cwd }) : null;
1966
2070
  const effectiveLinkPlan = hasRailwayApiToken ? linkPlan : usesProjectToken ? planRailwayProjectEnvironmentLink(cliDeployService) : linkPlan;
1967
2071
  const railwayLinkEnv = hasRailwayApiToken ? buildRailwayLinkCommandEnv(commandEnv, cliDeployService) : railwayDeployEnv;
1968
- if (cliConfig) {
1969
- write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][link] Wrote Railway CLI project context for ${cliConfig.projectPath}.`, "stdout") : null;
1970
- } else {
2072
+ await timedRailwayPhase(timings, "railway:link", async () => {
2073
+ if (cliConfig) {
2074
+ write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][link] Wrote Railway CLI project context for ${cliConfig.projectPath}.`, "stdout") : null;
2075
+ return;
2076
+ }
1971
2077
  const linkResult = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...effectiveLinkPlan.args], {
1972
2078
  cwd: effectiveLinkPlan.cwd,
1973
2079
  env: railwayLinkEnv,
@@ -1977,37 +2083,40 @@ async function deployRailwayService(tenantRoot, service, {
1977
2083
  if (linkResult.status !== 0) {
1978
2084
  throw new Error(linkResult.stderr?.trim() || linkResult.stdout?.trim() || `railway ${effectiveLinkPlan.args.join(" ")} failed with exit code ${linkResult.status ?? "unknown"} in ${effectiveLinkPlan.cwd}`);
1979
2085
  }
1980
- }
1981
- let lastFailure = null;
1982
- for (let attempt = 1; attempt <= 5; attempt += 1) {
1983
- const result = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...plan.args], {
1984
- cwd: plan.cwd,
1985
- env: railwayDeployEnv,
1986
- write,
1987
- prefix: taskPrefix
1988
- });
1989
- if (result.status === 0) {
1990
- lastFailure = null;
1991
- break;
2086
+ }, { service: cliDeployService.key });
2087
+ await timedRailwayPhase(timings, "railway:deploy", async () => {
2088
+ let lastFailure = null;
2089
+ for (let attempt = 1; attempt <= 5; attempt += 1) {
2090
+ const result = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...plan.args], {
2091
+ cwd: plan.cwd,
2092
+ env: railwayDeployEnv,
2093
+ write,
2094
+ prefix: taskPrefix
2095
+ });
2096
+ if (result.status === 0) {
2097
+ lastFailure = null;
2098
+ break;
2099
+ }
2100
+ lastFailure = result;
2101
+ if (!isRailwayTransientFailure(result) || attempt === 5) {
2102
+ throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${plan.args.join(" ")} failed with exit code ${result.status ?? "unknown"} in ${plan.cwd}`);
2103
+ }
2104
+ const backoffMs = 5e3 * attempt;
2105
+ const warning = `Railway deploy for ${deployService.serviceName ?? deployService.serviceId ?? deployService.key} hit a transient failure; retrying in ${Math.round(backoffMs / 1e3)}s...`;
2106
+ write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][retry] ${warning}`, "stderr") : console.warn(warning);
2107
+ await sleep(backoffMs);
1992
2108
  }
1993
- lastFailure = result;
1994
- if (!isRailwayTransientFailure(result) || attempt === 5) {
1995
- throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${plan.args.join(" ")} failed with exit code ${result.status ?? "unknown"} in ${plan.cwd}`);
2109
+ if (lastFailure) {
2110
+ throw new Error(lastFailure.stderr?.trim() || lastFailure.stdout?.trim() || `railway ${plan.args.join(" ")} failed`);
1996
2111
  }
1997
- const backoffMs = 5e3 * attempt;
1998
- const warning = `Railway deploy for ${deployService.serviceName ?? deployService.serviceId ?? deployService.key} hit a transient failure; retrying in ${Math.round(backoffMs / 1e3)}s...`;
1999
- write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][retry] ${warning}`, "stderr") : console.warn(warning);
2000
- await sleep(backoffMs);
2001
- }
2002
- if (lastFailure) {
2003
- throw new Error(lastFailure.stderr?.trim() || lastFailure.stdout?.trim() || `railway ${plan.args.join(" ")} failed`);
2004
- }
2112
+ }, { service: cliDeployService.key });
2005
2113
  return {
2006
2114
  service: deployService.key,
2007
2115
  status: "deployed",
2008
2116
  command: [plan.command, ...plan.args].join(" "),
2009
2117
  cwd: plan.cwd,
2010
2118
  publicBaseUrl: deployService.publicBaseUrl,
2119
+ timings,
2011
2120
  runtimeConfiguration: runtimeConfiguration ? {
2012
2121
  updated: runtimeConfiguration.updated,
2013
2122
  healthcheckPath: runtimeConfiguration.instance?.healthcheckPath ?? null,
@@ -244,7 +244,7 @@ function rehearsalVerifyScript(root) {
244
244
  function runNpmRehearsalCommand(args, options) {
245
245
  const result = spawnSync("npm", args, {
246
246
  cwd: options.cwd,
247
- env: process.env,
247
+ env: options.env ?? process.env,
248
248
  stdio: "pipe",
249
249
  encoding: "utf8",
250
250
  timeout: options.timeoutMs
@@ -320,7 +320,13 @@ function runProductionDependencyRehearsal(root, plannedVersions, selectedPackage
320
320
  buildRehearsalWorkspacePackageArtifacts(copied.tempRoot);
321
321
  const scriptName = rehearsalVerifyScript(copied.tempRoot);
322
322
  if (scriptName) {
323
- runNpmRehearsalCommand(["run", scriptName], { cwd: copied.tempRoot, timeoutMs: 9e5 });
323
+ const packageJson = safePackageJson(resolve(copied.tempRoot, "package.json"));
324
+ const parallelMarketVerify = packageJson?.name === "@treeseed/market" && (scriptName === "verify:direct" || scriptName === "verify:local" || scriptName === "verify");
325
+ runNpmRehearsalCommand(["run", scriptName], {
326
+ cwd: copied.tempRoot,
327
+ timeoutMs: 9e5,
328
+ env: parallelMarketVerify ? { ...process.env, TREESEED_VERIFY_PARALLEL: "1" } : process.env
329
+ });
324
330
  }
325
331
  const postInstallIssues = collectInternalDevReferenceIssues(copied.tempRoot, selectedPackageSet);
326
332
  if (postInstallIssues.length > 0) {
@@ -0,0 +1,68 @@
1
+ import { type ProjectEnvironmentName, type TemplateConfigMergeStrategy, type TemplateConfigWriteTarget, type TemplateSecretSensitivity } from '../../sdk-types.ts';
2
+ import type { ProjectLaunchConfigWritePlanItem, ProjectLaunchResolvedHostBinding, ProjectLaunchSecretDeploymentPlanItem } from '../../template-launch-requirements.ts';
3
+ export interface ApplyProjectLaunchHostBindingConfigOptions {
4
+ projectRoot: string;
5
+ hostBindings?: Record<string, ProjectLaunchResolvedHostBinding> | null;
6
+ hostBindingPlans?: {
7
+ configWrites?: ProjectLaunchConfigWritePlanItem[];
8
+ secretDeployment?: {
9
+ items?: ProjectLaunchSecretDeploymentPlanItem[];
10
+ };
11
+ } | null;
12
+ launchInput?: {
13
+ projectSlug?: string | null;
14
+ projectName?: string | null;
15
+ repoName?: string | null;
16
+ domains?: Record<string, unknown> | null;
17
+ } | null;
18
+ derived?: {
19
+ projectSlug?: string | null;
20
+ projectName?: string | null;
21
+ repositoryName?: string | null;
22
+ } | null;
23
+ }
24
+ export interface ProjectLaunchHostBindingConfigWriteSummary {
25
+ target: TemplateConfigWriteTarget;
26
+ path: string;
27
+ requirementKey: string;
28
+ requirementKind: string;
29
+ provider: string;
30
+ operation: TemplateConfigMergeStrategy;
31
+ valuePreview: string | number | boolean | null;
32
+ }
33
+ export interface ProjectLaunchHostBindingEnvironmentWriteSummary {
34
+ env: string;
35
+ requirementKey: string;
36
+ requirementKind: string;
37
+ sourceHostType?: string | null;
38
+ sourceProvider?: string | null;
39
+ sensitivity: TemplateSecretSensitivity | string;
40
+ targets: string[];
41
+ scopes: ProjectEnvironmentName[];
42
+ }
43
+ export interface ProjectLaunchHostBindingConfigApplyResult {
44
+ configWrites: ProjectLaunchHostBindingConfigWriteSummary[];
45
+ environmentWrites: ProjectLaunchHostBindingEnvironmentWriteSummary[];
46
+ targets: string[];
47
+ }
48
+ export interface ProjectLaunchHostBindingConfigAuditDiagnostic {
49
+ code: 'missing_config_target' | 'stale_config_target' | 'invalid_config_target';
50
+ status: 'ok' | 'warning' | 'blocked';
51
+ target: TemplateConfigWriteTarget;
52
+ message: string;
53
+ }
54
+ export interface ProjectLaunchHostBindingConfigAuditResult {
55
+ status: 'ok' | 'warning' | 'blocked';
56
+ checkedTargets: TemplateConfigWriteTarget[];
57
+ changedTargets: TemplateConfigWriteTarget[];
58
+ diagnostics: ProjectLaunchHostBindingConfigAuditDiagnostic[];
59
+ expected: ProjectLaunchHostBindingConfigApplyResult;
60
+ }
61
+ export declare function applyProjectLaunchHostBindingConfig(options: ApplyProjectLaunchHostBindingConfigOptions): ProjectLaunchHostBindingConfigApplyResult;
62
+ export declare function auditProjectLaunchHostBindingConfig(options: ApplyProjectLaunchHostBindingConfigOptions): ProjectLaunchHostBindingConfigAuditResult;
63
+ export declare function preserveProjectLaunchHostBindingConfigOverlay(options: {
64
+ target: TemplateConfigWriteTarget;
65
+ currentContent: string;
66
+ nextContent: string;
67
+ hostBindingPlans?: ApplyProjectLaunchHostBindingConfigOptions['hostBindingPlans'];
68
+ }): string;