@treeseed/sdk 0.10.24 → 0.10.26

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 (39) 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/config-runtime.d.ts +24 -9
  9. package/dist/operations/services/config-runtime.js +60 -12
  10. package/dist/operations/services/deploy.js +6 -1
  11. package/dist/operations/services/hub-launch.js +1 -0
  12. package/dist/operations/services/hub-provider-launch.d.ts +11 -1
  13. package/dist/operations/services/hub-provider-launch.js +81 -8
  14. package/dist/operations/services/project-host-operations.d.ts +153 -0
  15. package/dist/operations/services/project-host-operations.js +365 -0
  16. package/dist/operations/services/project-platform.d.ts +198 -193
  17. package/dist/operations/services/project-platform.js +29 -14
  18. package/dist/operations/services/railway-deploy.d.ts +3 -0
  19. package/dist/operations/services/railway-deploy.js +74 -35
  20. package/dist/operations/services/release-candidate.js +8 -2
  21. package/dist/operations/services/template-host-bindings.d.ts +68 -0
  22. package/dist/operations/services/template-host-bindings.js +400 -0
  23. package/dist/operations/services/template-registry.d.ts +22 -2
  24. package/dist/operations/services/template-registry.js +60 -3
  25. package/dist/operations/services/template-secret-sync.d.ts +97 -0
  26. package/dist/operations/services/template-secret-sync.js +292 -0
  27. package/dist/platform/environment.d.ts +3 -0
  28. package/dist/project-workflow.d.ts +7 -1
  29. package/dist/scripts/scaffold-site.js +3 -2
  30. package/dist/scripts/test-scaffold.js +2 -1
  31. package/dist/sdk-types.d.ts +87 -0
  32. package/dist/sdk-types.js +29 -0
  33. package/dist/template-catalog.js +3 -1
  34. package/dist/template-launch-requirements.d.ts +118 -0
  35. package/dist/template-launch-requirements.js +759 -0
  36. package/dist/template-launch-ui.d.ts +85 -0
  37. package/dist/template-launch-ui.js +189 -0
  38. package/dist/treeseed/template-catalog/catalog.fixture.json +330 -3
  39. package/package.json +13 -1
@@ -87,6 +87,30 @@ function configuredEnvValue(env, name) {
87
87
  const value = env?.[name];
88
88
  return typeof value === "string" && value.trim() ? value.trim() : "";
89
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
+ }
90
114
  function parseRailwayJsonOutput(output) {
91
115
  const trimmed = typeof output === "string" ? output.trim() : "";
92
116
  if (!trimmed) {
@@ -1967,6 +1991,7 @@ async function deployRailwayService(tenantRoot, service, {
1967
1991
  prefix,
1968
1992
  env = process.env
1969
1993
  } = {}) {
1994
+ const timings = [];
1970
1995
  if (dryRun) {
1971
1996
  const plan2 = planRailwayServiceDeploy(service, { env });
1972
1997
  return {
@@ -1974,10 +1999,13 @@ async function deployRailwayService(tenantRoot, service, {
1974
1999
  status: "planned",
1975
2000
  command: [plan2.command, ...plan2.args].join(" "),
1976
2001
  cwd: plan2.cwd,
1977
- publicBaseUrl: service.publicBaseUrl
2002
+ publicBaseUrl: service.publicBaseUrl,
2003
+ timings
1978
2004
  };
1979
2005
  }
1980
- const deployService = await resolveRailwayDeployProjectContext(service, { env });
2006
+ const deployService = await timedRailwayPhase(timings, "railway:resolve-context", () => resolveRailwayDeployProjectContext(service, { env }), {
2007
+ service: service.key
2008
+ });
1981
2009
  const commandEnv = buildRailwayCommandEnv({ ...process.env, ...env });
1982
2010
  let railwayDeployEnv = buildRailwayDeployCommandEnv(commandEnv);
1983
2011
  const railway = resolveTreeseedToolCommand("railway", { env: commandEnv });
@@ -1990,9 +2018,9 @@ async function deployRailwayService(tenantRoot, service, {
1990
2018
  task: `${deployService.key}-railway-deploy`,
1991
2019
  stage: "deploy"
1992
2020
  };
1993
- const runtimeConfiguration = await syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, deployService, {
2021
+ const runtimeConfiguration = await timedRailwayPhase(timings, "railway:sync-runtime-config", () => syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, deployService, {
1994
2022
  env: commandEnv
1995
- });
2023
+ }), { service: deployService.key });
1996
2024
  const cliDeployService = {
1997
2025
  ...deployService,
1998
2026
  projectId: runtimeConfiguration?.projectId ?? deployService.projectId,
@@ -2002,14 +2030,19 @@ async function deployRailwayService(tenantRoot, service, {
2002
2030
  serviceName: runtimeConfiguration?.serviceName ?? deployService.serviceName,
2003
2031
  railwayEnvironment: runtimeConfiguration?.environmentName ?? runtimeConfiguration?.environmentId ?? deployService.railwayEnvironment
2004
2032
  };
2005
- await syncRailwayApiDeviceLoginVariables(cliDeployService, commandEnv, write, taskPrefix);
2033
+ await timedRailwayPhase(timings, "railway:device-login-vars", () => syncRailwayApiDeviceLoginVariables(cliDeployService, commandEnv, write, taskPrefix), {
2034
+ service: cliDeployService.key
2035
+ });
2006
2036
  railwayDeployEnv = buildRailwayCliContextEnv(railwayDeployEnv, cliDeployService);
2007
2037
  const hasCommandApiToken = Boolean(configuredEnvValue(commandEnv, "RAILWAY_API_TOKEN"));
2008
2038
  let usesProjectToken = Boolean(configuredEnvValue(railwayDeployEnv, "RAILWAY_TOKEN"));
2009
2039
  if (usesProjectToken) {
2010
2040
  railwayDeployEnv = { ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0 };
2011
2041
  }
2012
- if (!usesProjectToken && !hasCommandApiToken) {
2042
+ await timedRailwayPhase(timings, "railway:project-token", async () => {
2043
+ if (usesProjectToken || hasCommandApiToken) {
2044
+ return null;
2045
+ }
2013
2046
  const projectToken = await createRailwayCliProjectToken(cliDeployService, { env: commandEnv });
2014
2047
  if (projectToken) {
2015
2048
  railwayDeployEnv = buildRailwayCliContextEnv({ ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0, RAILWAY_TOKEN: projectToken }, cliDeployService);
@@ -2017,16 +2050,17 @@ async function deployRailwayService(tenantRoot, service, {
2017
2050
  } else if (configuredEnvValue(commandEnv, "CI") === "true") {
2018
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.`);
2019
2052
  }
2020
- }
2053
+ return null;
2054
+ }, { service: cliDeployService.key });
2021
2055
  const linkPlan = planRailwayServiceLink(cliDeployService, { env: commandEnv });
2022
2056
  const plan = planRailwayServiceDeploy(cliDeployService, { env, projectTokenMode: usesProjectToken });
2023
2057
  if (deployService.buildCommand && shouldRunRailwayPredeployBuild(commandEnv)) {
2024
- const buildResult = await runPrefixedCommand("bash", ["-lc", deployService.buildCommand], {
2058
+ const buildResult = await timedRailwayPhase(timings, "railway:predeploy-build", () => runPrefixedCommand("bash", ["-lc", deployService.buildCommand], {
2025
2059
  cwd: deployService.rootDir,
2026
2060
  env: commandEnv,
2027
2061
  write,
2028
2062
  prefix: { ...taskPrefix, stage: "build" }
2029
- });
2063
+ }), { service: deployService.key });
2030
2064
  if (buildResult.status !== 0) {
2031
2065
  throw new Error(`Railway ${deployService.key} build command failed.`);
2032
2066
  }
@@ -2035,9 +2069,11 @@ async function deployRailwayService(tenantRoot, service, {
2035
2069
  const cliConfig = configuredEnvValue(commandEnv, "CI") === "true" ? writeRailwayCliProjectConfig(cliDeployService, { env: railwayDeployEnv, cwd: plan.cwd }) : null;
2036
2070
  const effectiveLinkPlan = hasRailwayApiToken ? linkPlan : usesProjectToken ? planRailwayProjectEnvironmentLink(cliDeployService) : linkPlan;
2037
2071
  const railwayLinkEnv = hasRailwayApiToken ? buildRailwayLinkCommandEnv(commandEnv, cliDeployService) : railwayDeployEnv;
2038
- if (cliConfig) {
2039
- write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][link] Wrote Railway CLI project context for ${cliConfig.projectPath}.`, "stdout") : null;
2040
- } 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
+ }
2041
2077
  const linkResult = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...effectiveLinkPlan.args], {
2042
2078
  cwd: effectiveLinkPlan.cwd,
2043
2079
  env: railwayLinkEnv,
@@ -2047,37 +2083,40 @@ async function deployRailwayService(tenantRoot, service, {
2047
2083
  if (linkResult.status !== 0) {
2048
2084
  throw new Error(linkResult.stderr?.trim() || linkResult.stdout?.trim() || `railway ${effectiveLinkPlan.args.join(" ")} failed with exit code ${linkResult.status ?? "unknown"} in ${effectiveLinkPlan.cwd}`);
2049
2085
  }
2050
- }
2051
- let lastFailure = null;
2052
- for (let attempt = 1; attempt <= 5; attempt += 1) {
2053
- const result = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...plan.args], {
2054
- cwd: plan.cwd,
2055
- env: railwayDeployEnv,
2056
- write,
2057
- prefix: taskPrefix
2058
- });
2059
- if (result.status === 0) {
2060
- lastFailure = null;
2061
- 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);
2062
2108
  }
2063
- lastFailure = result;
2064
- if (!isRailwayTransientFailure(result) || attempt === 5) {
2065
- 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`);
2066
2111
  }
2067
- const backoffMs = 5e3 * attempt;
2068
- const warning = `Railway deploy for ${deployService.serviceName ?? deployService.serviceId ?? deployService.key} hit a transient failure; retrying in ${Math.round(backoffMs / 1e3)}s...`;
2069
- write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][retry] ${warning}`, "stderr") : console.warn(warning);
2070
- await sleep(backoffMs);
2071
- }
2072
- if (lastFailure) {
2073
- throw new Error(lastFailure.stderr?.trim() || lastFailure.stdout?.trim() || `railway ${plan.args.join(" ")} failed`);
2074
- }
2112
+ }, { service: cliDeployService.key });
2075
2113
  return {
2076
2114
  service: deployService.key,
2077
2115
  status: "deployed",
2078
2116
  command: [plan.command, ...plan.args].join(" "),
2079
2117
  cwd: plan.cwd,
2080
2118
  publicBaseUrl: deployService.publicBaseUrl,
2119
+ timings,
2081
2120
  runtimeConfiguration: runtimeConfiguration ? {
2082
2121
  updated: runtimeConfiguration.updated,
2083
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;