@treeseed/sdk 0.10.6 → 0.10.8

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 (50) hide show
  1. package/dist/api/auth/d1-provider.d.ts +5 -0
  2. package/dist/api/auth/d1-provider.js +3 -0
  3. package/dist/api/auth/d1-store.d.ts +5 -0
  4. package/dist/api/auth/d1-store.js +62 -0
  5. package/dist/api/auth/memory-provider.d.ts +5 -0
  6. package/dist/api/auth/memory-provider.js +41 -0
  7. package/dist/api/types.d.ts +5 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +58 -0
  10. package/dist/market-client.d.ts +119 -0
  11. package/dist/market-client.js +79 -0
  12. package/dist/operations/repository-operations.d.ts +129 -0
  13. package/dist/operations/repository-operations.js +634 -0
  14. package/dist/operations/services/config-runtime.d.ts +7 -6
  15. package/dist/operations/services/config-runtime.js +45 -25
  16. package/dist/operations/services/deploy.d.ts +42 -0
  17. package/dist/operations/services/deploy.js +1 -1
  18. package/dist/operations/services/project-platform.d.ts +41 -1
  19. package/dist/operations/services/project-platform.js +14 -1
  20. package/dist/operations/services/railway-api.d.ts +35 -1
  21. package/dist/operations/services/railway-api.js +240 -35
  22. package/dist/operations/services/railway-deploy.d.ts +16 -234
  23. package/dist/operations/services/railway-deploy.js +177 -62
  24. package/dist/operations/services/release-candidate.js +1 -2
  25. package/dist/operations/services/runtime-tools.d.ts +14 -0
  26. package/dist/operations/services/runtime-tools.js +15 -1
  27. package/dist/operations/services/workspace-save.d.ts +24 -0
  28. package/dist/operations/services/workspace-save.js +143 -3
  29. package/dist/operations/services/workspace-tools.js +1 -1
  30. package/dist/platform/env.yaml +163 -2
  31. package/dist/platform/environment.d.ts +1 -0
  32. package/dist/platform/environment.js +9 -0
  33. package/dist/platform-operation-store.d.ts +90 -0
  34. package/dist/platform-operation-store.js +505 -0
  35. package/dist/platform-operations.d.ts +265 -0
  36. package/dist/platform-operations.js +421 -0
  37. package/dist/reconcile/bootstrap-systems.js +3 -3
  38. package/dist/reconcile/builtin-adapters.js +225 -29
  39. package/dist/reconcile/contracts.d.ts +1 -1
  40. package/dist/reconcile/desired-state.d.ts +14 -0
  41. package/dist/reconcile/desired-state.js +4 -0
  42. package/dist/reconcile/engine.d.ts +28 -0
  43. package/dist/reconcile/state.js +3 -0
  44. package/dist/reconcile/units.js +2 -0
  45. package/dist/workflow/operations.d.ts +13 -5
  46. package/dist/workflow/operations.js +69 -12
  47. package/dist/workflow-state.d.ts +2 -0
  48. package/dist/workflow-state.js +7 -2
  49. package/dist/workflow.d.ts +2 -0
  50. package/package.json +15 -2
@@ -1,6 +1,8 @@
1
1
  import { type TreeseedBootstrapTaskPrefix, type TreeseedBootstrapWriter } from './bootstrap-runner.ts';
2
2
  export declare function deriveRailwayWorkerRunnerServiceName(projectSlug: any, index?: number): string;
3
+ export declare function deriveRailwayMarketOperationsRunnerServiceName(baseServiceName: any, index?: number): string;
3
4
  export declare function deriveRailwayWorkerRunnerVolumeName(serviceName: any, environmentName?: string): string;
5
+ export declare function deriveRailwayMarketOperationsRunnerVolumeName(serviceName: any, environmentName?: string): string;
4
6
  export declare function railwayServiceRuntimeStartCommand(service: any): any;
5
7
  export declare function collectRailwayDeploymentStatusChecks(statusPayload: any, scope: any, services: any): any;
6
8
  export declare function isUsableRailwayToken(value: any): boolean;
@@ -17,30 +19,7 @@ export declare function runRailway(args: any, { cwd, capture, allowFailure, inpu
17
19
  allowFailure?: boolean | undefined;
18
20
  }): import("child_process").SpawnSyncReturns<string>;
19
21
  export declare function waitForRailwayManagedDeploymentsSettled(tenantRoot: any, scope: any, { services, env, timeoutMs, pollMs, onProgress, }?: {
20
- services?: ({
21
- key: string;
22
- scope: string;
23
- projectId: string | null;
24
- projectName: string;
25
- serviceId: string | null;
26
- serviceName: string;
27
- rootDir: string;
28
- publicBaseUrl: string | null;
29
- railwayEnvironment: string;
30
- buildCommand: string | null;
31
- startCommand: string | null;
32
- healthcheckPath: any;
33
- healthcheckTimeoutSeconds: any;
34
- healthcheckIntervalSeconds: any;
35
- restartPolicy: any;
36
- runtimeMode: any;
37
- schedule: string[];
38
- hostingKind: string;
39
- runnerPool: {
40
- bootstrapIndex: number;
41
- volumeMountPath: string;
42
- } | null;
43
- } | null)[] | undefined;
22
+ services?: unknown[] | undefined;
44
23
  env?: NodeJS.ProcessEnv | undefined;
45
24
  timeoutMs?: number | undefined;
46
25
  pollMs?: number | undefined;
@@ -75,135 +54,34 @@ export declare function ensureRailwayEnvironmentExists(service: any, { env }?: {
75
54
  export declare function ensureRailwayServiceExists(service: any, { env }?: {
76
55
  env?: NodeJS.ProcessEnv | undefined;
77
56
  }): import("child_process").SpawnSyncReturns<string>;
57
+ export declare function ensureRailwayDatabaseServiceExists(service: any, { database, env, }?: {
58
+ database?: string | undefined;
59
+ env?: NodeJS.ProcessEnv | undefined;
60
+ }): import("child_process").SpawnSyncReturns<string>;
78
61
  export declare function ensureRailwayProjectContext(service: any, { env, allowFailure, capture }?: {
79
62
  env?: NodeJS.ProcessEnv | undefined;
80
63
  allowFailure?: boolean | undefined;
81
64
  capture?: boolean | undefined;
82
65
  }): import("child_process").SpawnSyncReturns<string> | null;
83
- export declare function configuredRailwayServices(tenantRoot: any, scope: any): ({
84
- key: string;
85
- scope: string;
86
- projectId: string | null;
87
- projectName: string;
88
- serviceId: string | null;
89
- serviceName: string;
90
- rootDir: string;
91
- publicBaseUrl: string | null;
92
- railwayEnvironment: string;
93
- buildCommand: string | null;
94
- startCommand: string | null;
95
- healthcheckPath: any;
96
- healthcheckTimeoutSeconds: any;
97
- healthcheckIntervalSeconds: any;
98
- restartPolicy: any;
99
- runtimeMode: any;
100
- schedule: string[];
101
- hostingKind: string;
102
- runnerPool: {
103
- bootstrapIndex: number;
104
- volumeMountPath: string;
105
- } | null;
106
- } | null)[];
66
+ export declare function configuredRailwayServices(tenantRoot: any, scope: any): unknown[];
107
67
  export declare function configuredRailwayScheduledJobs(tenantRoot: any, scope: any, { phase }?: {
108
68
  phase?: string | undefined;
109
- }): {
110
- service: string;
111
- projectId: string | null;
112
- projectName: string;
113
- serviceId: string | null;
114
- serviceName: string;
115
- environment: string;
116
- environmentId: string | null;
117
- expression: string;
118
- command: string | null;
119
- enabled: boolean;
120
- logicalName: string;
121
- }[];
69
+ }): any[];
122
70
  export declare function resolveRailwayDeploymentProfile(tenantRoot: any): {
123
71
  hostingKind: string;
124
72
  managedTopology: string[];
125
73
  };
126
74
  export declare function validateRailwayServiceConfiguration(tenantRoot: any, scope: any): {
127
- services: ({
128
- key: string;
129
- scope: string;
130
- projectId: string | null;
131
- projectName: string;
132
- serviceId: string | null;
133
- serviceName: string;
134
- rootDir: string;
135
- publicBaseUrl: string | null;
136
- railwayEnvironment: string;
137
- buildCommand: string | null;
138
- startCommand: string | null;
139
- healthcheckPath: any;
140
- healthcheckTimeoutSeconds: any;
141
- healthcheckIntervalSeconds: any;
142
- restartPolicy: any;
143
- runtimeMode: any;
144
- schedule: string[];
145
- hostingKind: string;
146
- runnerPool: {
147
- bootstrapIndex: number;
148
- volumeMountPath: string;
149
- } | null;
150
- } | null)[];
151
- schedules: {
152
- service: string;
153
- projectId: string | null;
154
- projectName: string;
155
- serviceId: string | null;
156
- serviceName: string;
157
- environment: string;
158
- environmentId: string | null;
159
- expression: string;
160
- command: string | null;
161
- enabled: boolean;
162
- logicalName: string;
163
- }[];
75
+ services: unknown[];
76
+ schedules: any[];
164
77
  hostingKind: string;
165
78
  managedTopology: string[];
166
79
  };
167
80
  export declare function validateRailwayDeployPrerequisites(tenantRoot: any, scope: any, { env }?: {
168
81
  env?: NodeJS.ProcessEnv | undefined;
169
82
  }): {
170
- services: ({
171
- key: string;
172
- scope: string;
173
- projectId: string | null;
174
- projectName: string;
175
- serviceId: string | null;
176
- serviceName: string;
177
- rootDir: string;
178
- publicBaseUrl: string | null;
179
- railwayEnvironment: string;
180
- buildCommand: string | null;
181
- startCommand: string | null;
182
- healthcheckPath: any;
183
- healthcheckTimeoutSeconds: any;
184
- healthcheckIntervalSeconds: any;
185
- restartPolicy: any;
186
- runtimeMode: any;
187
- schedule: string[];
188
- hostingKind: string;
189
- runnerPool: {
190
- bootstrapIndex: number;
191
- volumeMountPath: string;
192
- } | null;
193
- } | null)[];
194
- schedules: {
195
- service: string;
196
- projectId: string | null;
197
- projectName: string;
198
- serviceId: string | null;
199
- serviceName: string;
200
- environment: string;
201
- environmentId: string | null;
202
- expression: string;
203
- command: string | null;
204
- enabled: boolean;
205
- logicalName: string;
206
- }[];
83
+ services: unknown[];
84
+ schedules: any[];
207
85
  hostingKind: string;
208
86
  managedTopology: string[];
209
87
  };
@@ -211,50 +89,7 @@ export declare function ensureRailwayScheduledJobs(tenantRoot: any, scope: any,
211
89
  dryRun?: boolean | undefined;
212
90
  fetchImpl?: typeof fetch | undefined;
213
91
  env?: NodeJS.ProcessEnv | undefined;
214
- }): Promise<{
215
- id: null;
216
- status: string;
217
- enabled: boolean;
218
- command: string | null;
219
- message: string;
220
- service: string;
221
- projectId: string | null;
222
- projectName: string;
223
- serviceId: string | null;
224
- serviceName: string;
225
- environment: string;
226
- environmentId: string | null;
227
- expression: string;
228
- logicalName: string;
229
- }[] | ({
230
- id: null;
231
- projectId: string | null;
232
- serviceId: string | null;
233
- environmentId: string | null;
234
- status: string;
235
- enabled: boolean;
236
- command: string | null;
237
- service: string;
238
- projectName: string;
239
- serviceName: string;
240
- environment: string;
241
- expression: string;
242
- logicalName: string;
243
- } | {
244
- projectId: string;
245
- id: string | null;
246
- status: string;
247
- enabled: boolean;
248
- command: string | null;
249
- serviceId: string;
250
- environmentId: string;
251
- service: string;
252
- projectName: string;
253
- serviceName: string;
254
- environment: string;
255
- expression: string;
256
- logicalName: string;
257
- })[]>;
92
+ }): Promise<any[]>;
258
93
  export declare function verifyRailwayScheduledJobs(tenantRoot: any, scope: any, { fetchImpl, apiToken, apiUrl, env }?: {
259
94
  fetchImpl?: typeof fetch | undefined;
260
95
  env?: NodeJS.ProcessEnv | undefined;
@@ -262,63 +97,10 @@ export declare function verifyRailwayScheduledJobs(tenantRoot: any, scope: any,
262
97
  ok: boolean;
263
98
  unsupported: boolean;
264
99
  message: string;
265
- checks: {
266
- id: null;
267
- ok: boolean;
268
- status: string;
269
- message: string;
270
- service: string;
271
- projectId: string | null;
272
- projectName: string;
273
- serviceId: string | null;
274
- serviceName: string;
275
- environment: string;
276
- environmentId: string | null;
277
- expression: string;
278
- command: string | null;
279
- enabled: boolean;
280
- logicalName: string;
281
- }[];
100
+ checks: any[];
282
101
  } | {
283
102
  ok: boolean;
284
- checks: ({
285
- id: null;
286
- ok: boolean;
287
- status: string;
288
- message: string;
289
- service: string;
290
- projectId: string | null;
291
- projectName: string;
292
- serviceId: string | null;
293
- serviceName: string;
294
- environment: string;
295
- environmentId: string | null;
296
- expression: string;
297
- command: string | null;
298
- enabled: boolean;
299
- logicalName: string;
300
- } | {
301
- id: string | null;
302
- projectId: string;
303
- serviceId: string;
304
- environmentId: string;
305
- ok: boolean;
306
- status: string;
307
- observed: {
308
- expression: string | null;
309
- command: string | null;
310
- enabled: boolean;
311
- } | null;
312
- message: string | undefined;
313
- service: string;
314
- projectName: string;
315
- serviceName: string;
316
- environment: string;
317
- expression: string;
318
- command: string | null;
319
- enabled: boolean;
320
- logicalName: string;
321
- })[];
103
+ checks: any[];
322
104
  unsupported?: undefined;
323
105
  message?: undefined;
324
106
  }>;
@@ -30,26 +30,38 @@ function normalizeScope(scope) {
30
30
  function resolveRailwayEnvironmentForScope(scope, configuredEnvironment) {
31
31
  return normalizeRailwayEnvironmentName(configuredEnvironment || normalizeScope(scope));
32
32
  }
33
- const RAILWAY_SERVICE_KEYS = ["api", "workdayManager", "workerRunner"];
34
- const HOSTED_PROJECT_SERVICE_KEYS = ["api", "workdayManager", "workerRunner"];
33
+ const RAILWAY_SERVICE_KEYS = ["api", "marketOperationsRunner"];
34
+ const HOSTED_PROJECT_SERVICE_KEYS = ["api"];
35
35
  const WORKER_RUNNER_BOOTSTRAP_INDEX = 1;
36
36
  const WORKER_RUNNER_VOLUME_MOUNT_PATH = "/data";
37
+ const MARKET_OPERATIONS_RUNNER_BOOTSTRAP_COUNT = 2;
37
38
  function shouldManageRailwaySchedules(scope, phase = "deploy") {
38
39
  const environment = normalizeRailwayEnvironmentName(scope);
39
40
  return phase === "deploy" && (environment === "staging" || environment === "production");
40
41
  }
41
42
  function railwayServiceNameSuffix(serviceKey) {
42
- return serviceKey === "workdayManager" ? "workday-manager" : serviceKey === "workerRunner" ? "worker-runner" : serviceKey;
43
+ return serviceKey === "workdayManager" ? "workday-manager" : serviceKey === "workerRunner" ? "worker-runner" : serviceKey === "marketOperationsRunner" ? "market-operations-runner" : serviceKey;
43
44
  }
44
45
  function deriveRailwayWorkerRunnerServiceName(projectSlug, index = WORKER_RUNNER_BOOTSTRAP_INDEX) {
45
46
  const normalizedIndex = Math.max(1, Number.parseInt(String(index), 10) || WORKER_RUNNER_BOOTSTRAP_INDEX);
46
47
  return `${projectSlug}-worker-runner-${String(normalizedIndex).padStart(2, "0")}`;
47
48
  }
49
+ function deriveRailwayMarketOperationsRunnerServiceName(baseServiceName, index = WORKER_RUNNER_BOOTSTRAP_INDEX) {
50
+ const normalizedIndex = Math.max(1, Number.parseInt(String(index), 10) || WORKER_RUNNER_BOOTSTRAP_INDEX);
51
+ const base = String(baseServiceName ?? "").trim().replace(/-\d+$/u, "") || "treeseed-market-operations-runner";
52
+ return `${base}-${String(normalizedIndex).padStart(2, "0")}`;
53
+ }
48
54
  function deriveRailwayWorkerRunnerVolumeName(serviceName, environmentName = "") {
49
55
  const environment = normalizeRailwayEnvironmentName(environmentName);
50
- const environmentSuffix = environment && environment !== "production" ? `-${environment}` : "";
56
+ const environmentSuffix = environment === "production" ? "-prod" : environment ? `-${environment}` : "";
51
57
  return `${serviceName}${environmentSuffix}-data`;
52
58
  }
59
+ function deriveRailwayMarketOperationsRunnerVolumeName(serviceName, environmentName = "") {
60
+ const environment = normalizeRailwayEnvironmentName(environmentName);
61
+ const environmentSuffix = environment === "production" ? "-prod" : environment ? `-${environment}` : "";
62
+ const index = String(serviceName ?? "").match(/-(\d+)$/u)?.[1] ?? "01";
63
+ return `market-ops-runner-${index}${environmentSuffix}-data`;
64
+ }
53
65
  function railwayServiceRuntimeStartCommand(service) {
54
66
  return service.startCommand;
55
67
  }
@@ -201,6 +213,7 @@ function normalizeRailwayCliVolume(value, { serviceId, environmentId, fallbackNa
201
213
  serviceId,
202
214
  environmentId,
203
215
  mountPath,
216
+ state: "READY",
204
217
  sizeGb: sizeMb === null ? null : sizeMb / 1e3,
205
218
  usedGb: currentSizeMb === null ? null : currentSizeMb / 1e3
206
219
  }]
@@ -668,6 +681,66 @@ function ensureRailwayServiceExists(service, { env = process.env } = {}) {
668
681
  }
669
682
  return refreshed;
670
683
  }
684
+ function ensureRailwayDatabaseServiceExists(service, {
685
+ database = "postgres",
686
+ env = process.env
687
+ } = {}) {
688
+ const serviceSelector = typeof (service?.serviceName ?? service?.serviceId) === "string" ? String(service.serviceName ?? service.serviceId).trim() : "";
689
+ if (!serviceSelector) {
690
+ throw new Error(`Railway database service ${service?.key ?? "(unknown)"} is missing a service selector.`);
691
+ }
692
+ const projectSelector = typeof service?.projectId === "string" && service.projectId.trim() ? service.projectId.trim() : typeof service?.projectName === "string" && service.projectName.trim() ? service.projectName.trim() : "";
693
+ if (!projectSelector) {
694
+ throw new Error(`Railway database service ${service?.key ?? serviceSelector} is missing a project selector.`);
695
+ }
696
+ const linkArgs = ["link", "--project", projectSelector];
697
+ const workspace = resolveRailwayWorkspace(env);
698
+ if (workspace) {
699
+ linkArgs.push("--workspace", workspace);
700
+ }
701
+ const environmentName = normalizeRailwayEnvironmentName(service?.railwayEnvironment);
702
+ if (environmentName) {
703
+ linkArgs.push("--environment", environmentName);
704
+ }
705
+ const linkResult = runRailway(linkArgs, {
706
+ cwd: service.rootDir,
707
+ capture: true,
708
+ allowFailure: true,
709
+ env
710
+ });
711
+ if ((linkResult.status ?? 1) !== 0) {
712
+ throw new Error(railwayMessage(linkResult) || `railway ${linkArgs.join(" ")} failed`);
713
+ }
714
+ const statusArgs = ["service", "status", "--service", serviceSelector, "--environment", service.railwayEnvironment, "--json"];
715
+ const statusResult = runRailway(statusArgs, {
716
+ cwd: service.rootDir,
717
+ capture: true,
718
+ allowFailure: true,
719
+ env
720
+ });
721
+ if (statusResult.status === 0) {
722
+ return statusResult;
723
+ }
724
+ const addResult = runRailway(["add", "--database", database, "--service", serviceSelector, "--json"], {
725
+ cwd: service.rootDir,
726
+ capture: true,
727
+ allowFailure: true,
728
+ env
729
+ });
730
+ if (addResult.status !== 0 && !isRailwayAlreadyExistsMessage(addResult)) {
731
+ throw new Error(railwayMessage(addResult) || `railway add --database ${database} --service ${serviceSelector} failed`);
732
+ }
733
+ const refreshed = runRailway(statusArgs, {
734
+ cwd: service.rootDir,
735
+ capture: true,
736
+ allowFailure: true,
737
+ env
738
+ });
739
+ if (refreshed.status !== 0) {
740
+ throw new Error(railwayMessage(refreshed) || `railway service status --service ${serviceSelector} failed`);
741
+ }
742
+ return refreshed;
743
+ }
671
744
  function ensureRailwayProjectContext(service, { env = process.env, allowFailure = false, capture = false } = {}) {
672
745
  ensureRailwayProjectExists(service, { env });
673
746
  let projectSelector = service?.projectId ?? "";
@@ -718,7 +791,12 @@ function ensureRailwayProjectContext(service, { env = process.env, allowFailure
718
791
  function configuredRailwayServices(tenantRoot, scope) {
719
792
  const deployConfig = loadCliDeployConfig(tenantRoot);
720
793
  const normalizedScope = normalizeScope(scope);
721
- const identity = resolveTreeseedResourceIdentity(deployConfig, createPersistentDeployTarget(normalizedScope));
794
+ let identity;
795
+ try {
796
+ identity = resolveTreeseedResourceIdentity(deployConfig, createPersistentDeployTarget(normalizedScope));
797
+ } catch {
798
+ identity = { deploymentKey: deployConfig.slug ?? deployConfig.name ?? "treeseed" };
799
+ }
722
800
  const managedRuntime = deployConfig.runtime?.mode === "treeseed_managed";
723
801
  const hostingKind = deployConfig.hosting?.kind ?? (managedRuntime ? "hosted_project" : "self_hosted_project");
724
802
  if (!managedRuntime) {
@@ -726,42 +804,58 @@ function configuredRailwayServices(tenantRoot, scope) {
726
804
  }
727
805
  const configuredOptionalServiceKeys = Object.keys(deployConfig.services ?? {}).filter((serviceKey) => RAILWAY_SERVICE_KEYS.includes(serviceKey));
728
806
  const serviceKeys = hostingKind === "hosted_project" ? [.../* @__PURE__ */ new Set([...HOSTED_PROJECT_SERVICE_KEYS, ...configuredOptionalServiceKeys])] : RAILWAY_SERVICE_KEYS;
729
- return serviceKeys.map((serviceKey) => {
807
+ return serviceKeys.flatMap((serviceKey) => {
730
808
  const service = deployConfig.services?.[serviceKey];
731
809
  if (!service || service.enabled === false || (service.provider ?? "railway") !== "railway") {
732
- return null;
810
+ return [];
733
811
  }
734
- const defaultRootDir = ["api", "workdayManager", "workerRunner"].includes(serviceKey) ? "." : "packages/core";
812
+ const defaultRootDir = ["api", "marketOperationsRunner"].includes(serviceKey) ? "." : "packages/core";
735
813
  const serviceRoot = resolve(tenantRoot, service.railway?.rootDir ?? service.rootDir ?? defaultRootDir);
736
814
  const railwayEnvironment = resolveRailwayEnvironmentForScope(
737
815
  normalizedScope,
738
816
  service.environments?.[normalizedScope]?.railwayEnvironment
739
817
  );
740
818
  const publicBaseUrl = service.environments?.[normalizedScope]?.baseUrl ?? service.publicBaseUrl ?? null;
741
- return {
742
- key: serviceKey,
743
- scope: normalizedScope,
744
- projectId: service.railway?.projectId ?? null,
745
- projectName: service.railway?.projectName ?? identity.deploymentKey,
746
- serviceId: service.railway?.serviceId ?? null,
747
- serviceName: service.railway?.serviceName ?? (serviceKey === "workerRunner" ? deriveRailwayWorkerRunnerServiceName(identity.deploymentKey) : `${identity.deploymentKey}-${railwayServiceNameSuffix(serviceKey)}`),
748
- rootDir: serviceRoot,
749
- publicBaseUrl,
750
- railwayEnvironment,
751
- buildCommand: service.railway?.buildCommand ?? null,
752
- startCommand: service.railway?.startCommand ?? null,
753
- healthcheckPath: service.railway?.healthcheckPath ?? null,
754
- healthcheckTimeoutSeconds: service.railway?.healthcheckTimeoutSeconds ?? null,
755
- healthcheckIntervalSeconds: service.railway?.healthcheckIntervalSeconds ?? null,
756
- restartPolicy: service.railway?.restartPolicy ?? null,
757
- runtimeMode: service.railway?.runtimeMode ?? null,
758
- schedule: normalizeScheduleExpressions(service.railway?.schedule),
759
- hostingKind,
760
- runnerPool: serviceKey === "workerRunner" ? {
761
- bootstrapIndex: WORKER_RUNNER_BOOTSTRAP_INDEX,
762
- volumeMountPath: WORKER_RUNNER_VOLUME_MOUNT_PATH
763
- } : null
764
- };
819
+ const configuredServiceName = service.railway?.serviceName ?? (serviceKey === "workerRunner" ? deriveRailwayWorkerRunnerServiceName(identity.deploymentKey) : `${identity.deploymentKey}-${railwayServiceNameSuffix(serviceKey)}`);
820
+ const configuredRunnerPool = service.railway?.runnerPool && typeof service.railway.runnerPool === "object" ? service.railway.runnerPool : null;
821
+ const runnerPool = serviceKey === "marketOperationsRunner" ? {
822
+ bootstrapCount: Math.max(1, Number.parseInt(String(configuredRunnerPool?.bootstrapCount ?? MARKET_OPERATIONS_RUNNER_BOOTSTRAP_COUNT), 10) || MARKET_OPERATIONS_RUNNER_BOOTSTRAP_COUNT),
823
+ maxRunners: Math.max(1, Number.parseInt(String(configuredRunnerPool?.maxRunners ?? configuredRunnerPool?.bootstrapCount ?? MARKET_OPERATIONS_RUNNER_BOOTSTRAP_COUNT), 10) || MARKET_OPERATIONS_RUNNER_BOOTSTRAP_COUNT),
824
+ volumeMountPath: service.railway?.volumeMountPath ?? configuredRunnerPool?.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH
825
+ } : serviceKey === "workerRunner" ? {
826
+ bootstrapIndex: WORKER_RUNNER_BOOTSTRAP_INDEX,
827
+ volumeMountPath: WORKER_RUNNER_VOLUME_MOUNT_PATH
828
+ } : null;
829
+ const instanceCount = serviceKey === "marketOperationsRunner" ? runnerPool.bootstrapCount : 1;
830
+ return Array.from({ length: instanceCount }, (_, offset) => {
831
+ const runnerIndex = offset + 1;
832
+ const serviceName = serviceKey === "marketOperationsRunner" ? deriveRailwayMarketOperationsRunnerServiceName(configuredServiceName, runnerIndex) : configuredServiceName;
833
+ return {
834
+ key: serviceKey,
835
+ instanceKey: serviceKey === "marketOperationsRunner" ? `${serviceKey}:${runnerIndex}` : serviceKey,
836
+ runnerIndex: serviceKey === "marketOperationsRunner" ? runnerIndex : null,
837
+ scope: normalizedScope,
838
+ projectId: service.railway?.projectId ?? null,
839
+ projectName: service.railway?.projectName ?? identity.deploymentKey,
840
+ serviceId: service.railway?.serviceId ?? null,
841
+ serviceName,
842
+ runnerId: serviceKey === "marketOperationsRunner" ? serviceName : null,
843
+ rootDir: serviceRoot,
844
+ publicBaseUrl,
845
+ railwayEnvironment,
846
+ buildCommand: service.railway?.buildCommand ?? null,
847
+ startCommand: service.railway?.startCommand ?? null,
848
+ healthcheckPath: service.railway?.healthcheckPath ?? null,
849
+ healthcheckTimeoutSeconds: service.railway?.healthcheckTimeoutSeconds ?? null,
850
+ healthcheckIntervalSeconds: service.railway?.healthcheckIntervalSeconds ?? null,
851
+ restartPolicy: service.railway?.restartPolicy ?? null,
852
+ runtimeMode: service.railway?.runtimeMode ?? null,
853
+ volumeMountPath: serviceKey === "marketOperationsRunner" ? runnerPool.volumeMountPath : service.railway?.volumeMountPath ?? null,
854
+ schedule: normalizeScheduleExpressions(service.railway?.schedule),
855
+ hostingKind,
856
+ runnerPool
857
+ };
858
+ });
765
859
  }).filter(Boolean);
766
860
  }
767
861
  function configuredRailwayScheduledJobs(tenantRoot, scope, { phase = "deploy" } = {}) {
@@ -1471,7 +1565,7 @@ async function resolveRailwayDeployProjectContext(service, { env = process.env }
1471
1565
  }
1472
1566
  async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, service, { env = process.env } = {}) {
1473
1567
  const wantsInstanceConfig = service.buildCommand || service.startCommand || service.rootDir || service.healthcheckPath || service.healthcheckTimeoutSeconds !== null || service.healthcheckTimeoutSeconds !== void 0 || service.healthcheckIntervalSeconds !== null || service.healthcheckIntervalSeconds !== void 0 || service.restartPolicy || service.runtimeMode;
1474
- const wantsRunnerVolume = service.key === "workerRunner";
1568
+ const wantsRunnerVolume = service.key === "workerRunner" || Boolean(service.volumeMountPath);
1475
1569
  if (!wantsInstanceConfig && !wantsRunnerVolume) {
1476
1570
  return null;
1477
1571
  }
@@ -1534,11 +1628,23 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1534
1628
  environmentId: environment.id,
1535
1629
  serviceId: railwayService.id,
1536
1630
  variables: {
1537
- TREESEED_SKIP_PACKAGE_PREPARE: "1"
1631
+ TREESEED_SKIP_PACKAGE_PREPARE: "1",
1632
+ ...service.key === "marketOperationsRunner" ? {
1633
+ NIXPACKS_APT_PKGS: "git",
1634
+ NIXPACKS_PKGS: "git",
1635
+ TREESEED_PLATFORM_RUNNER_ID: service.runnerId ?? railwayService.name,
1636
+ TREESEED_PLATFORM_RUNNER_DATA_DIR: service.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH,
1637
+ TREESEED_PLATFORM_RUNNER_ENVIRONMENT: normalizeScope(service.scope) === "prod" ? "production" : normalizeScope(service.scope),
1638
+ TREESEED_MARKET_ID: normalizeScope(service.scope),
1639
+ ...configuredEnvValue(env, "TREESEED_PLATFORM_RUNNER_SECRET") ? { TREESEED_PLATFORM_RUNNER_SECRET: configuredEnvValue(env, "TREESEED_PLATFORM_RUNNER_SECRET") } : {},
1640
+ ...configuredEnvValue(env, "TREESEED_MARKET_API_BASE_URL") || configuredEnvValue(env, "TREESEED_MARKET_URL") ? {
1641
+ TREESEED_MARKET_API_BASE_URL: configuredEnvValue(env, "TREESEED_MARKET_API_BASE_URL") || configuredEnvValue(env, "TREESEED_MARKET_URL")
1642
+ } : {}
1643
+ } : {}
1538
1644
  },
1539
1645
  env
1540
1646
  });
1541
- const volumeMountPath = service.runnerPool?.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH;
1647
+ const volumeMountPath = service.volumeMountPath ?? service.runnerPool?.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH;
1542
1648
  const volumeConfiguration = wantsRunnerVolume ? await ensureRailwayServiceVolumeWithCliFallback({
1543
1649
  tenantRoot,
1544
1650
  projectId: project.id,
@@ -1546,24 +1652,27 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1546
1652
  environmentName: environment.name,
1547
1653
  serviceId: railwayService.id,
1548
1654
  serviceName: railwayService.name,
1549
- name: deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
1655
+ name: service.key === "marketOperationsRunner" ? deriveRailwayMarketOperationsRunnerVolumeName(railwayService.name, environment.name) : deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
1550
1656
  mountPath: volumeMountPath,
1657
+ preferCli: service.key === "marketOperationsRunner",
1551
1658
  env
1552
1659
  }) : null;
1553
1660
  if (wantsRunnerVolume) {
1554
- await upsertRailwayVariables({
1555
- projectId: project.id,
1556
- environmentId: environment.id,
1557
- serviceId: railwayService.id,
1558
- variables: {
1559
- TREESEED_RUNNER_SERVICE_NAME: railwayService.name,
1560
- TREESEED_RUNNER_VOLUME_ROOT: volumeMountPath,
1561
- TREESEED_RUNNER_VOLUME_NAME: volumeConfiguration?.volume.name ?? deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
1562
- TREESEED_WORKER_IDLE_EXIT_MS: configuredEnvValue(env, "TREESEED_WORKER_IDLE_EXIT_MS") || "60000",
1563
- ...volumeConfiguration?.volume.id ? { TREESEED_RUNNER_VOLUME_ID: volumeConfiguration.volume.id } : {}
1564
- },
1565
- env
1566
- });
1661
+ if (service.key === "workerRunner") {
1662
+ await upsertRailwayVariables({
1663
+ projectId: project.id,
1664
+ environmentId: environment.id,
1665
+ serviceId: railwayService.id,
1666
+ variables: {
1667
+ TREESEED_RUNNER_SERVICE_NAME: railwayService.name,
1668
+ TREESEED_RUNNER_VOLUME_ROOT: volumeMountPath,
1669
+ TREESEED_RUNNER_VOLUME_NAME: volumeConfiguration?.volume.name ?? deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
1670
+ TREESEED_WORKER_IDLE_EXIT_MS: configuredEnvValue(env, "TREESEED_WORKER_IDLE_EXIT_MS") || "60000",
1671
+ ...volumeConfiguration?.volume.id ? { TREESEED_RUNNER_VOLUME_ID: volumeConfiguration.volume.id } : {}
1672
+ },
1673
+ env
1674
+ });
1675
+ }
1567
1676
  }
1568
1677
  return {
1569
1678
  projectId: project.id,
@@ -1592,21 +1701,24 @@ async function ensureRailwayServiceVolumeWithCliFallback({
1592
1701
  serviceName,
1593
1702
  name,
1594
1703
  mountPath,
1704
+ preferCli = false,
1595
1705
  env = process.env
1596
1706
  }) {
1597
- try {
1598
- return await ensureRailwayServiceVolume({
1599
- projectId,
1600
- environmentId,
1601
- serviceId,
1602
- name,
1603
- mountPath,
1604
- env
1605
- });
1606
- } catch (error) {
1607
- const message = error instanceof Error ? error.message : String(error);
1608
- if (!message.includes("Problem processing request")) {
1609
- throw error;
1707
+ if (!preferCli) {
1708
+ try {
1709
+ return await ensureRailwayServiceVolume({
1710
+ projectId,
1711
+ environmentId,
1712
+ serviceId,
1713
+ name,
1714
+ mountPath,
1715
+ env
1716
+ });
1717
+ } catch (error) {
1718
+ const message = error instanceof Error ? error.message : String(error);
1719
+ if (!message.includes("Problem processing request")) {
1720
+ throw error;
1721
+ }
1610
1722
  }
1611
1723
  }
1612
1724
  const cliOptions = {
@@ -1795,8 +1907,11 @@ export {
1795
1907
  configuredRailwayScheduledJobs,
1796
1908
  configuredRailwayServices,
1797
1909
  deployRailwayService,
1910
+ deriveRailwayMarketOperationsRunnerServiceName,
1911
+ deriveRailwayMarketOperationsRunnerVolumeName,
1798
1912
  deriveRailwayWorkerRunnerServiceName,
1799
1913
  deriveRailwayWorkerRunnerVolumeName,
1914
+ ensureRailwayDatabaseServiceExists,
1800
1915
  ensureRailwayEnvironmentExists,
1801
1916
  ensureRailwayProjectContext,
1802
1917
  ensureRailwayProjectExists,
@@ -365,12 +365,11 @@ function dependencyRehearsalChecks(root, plannedVersions, selectedPackageNames,
365
365
  });
366
366
  }
367
367
  }
368
- const selectedPackageSet = new Set(selectedPackageNames);
369
368
  const devReferenceIssues = collectInternalDevReferenceIssues(root);
370
369
  const unrehearsableDevReferences = devReferenceIssues.filter((issue) => {
371
370
  const dependencyName = issue.dependencyName ?? "";
372
371
  const planned = plannedVersions[dependencyName];
373
- return !selectedPackageSet.has(dependencyName) || !planned || !STABLE_SEMVER.test(planned);
372
+ return !planned || !STABLE_SEMVER.test(planned);
374
373
  });
375
374
  if (unrehearsableDevReferences.length > 0) {
376
375
  addFailure(failures, {