@tachyon-gg/railway-deploy 0.2.8 → 0.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/index.js +115 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -122,16 +122,19 @@ registry_credentials: # For private container registries
|
|
|
122
122
|
#### Build
|
|
123
123
|
|
|
124
124
|
```yaml
|
|
125
|
-
builder: NIXPACKS # RAILPACK (default),
|
|
125
|
+
builder: NIXPACKS # RAILPACK (default), NIXPACKS, HEROKU, PAKETO
|
|
126
126
|
build_command: npm run build # Custom build command
|
|
127
|
-
dockerfile_path: Dockerfile.prod # Path to Dockerfile (
|
|
127
|
+
dockerfile_path: Dockerfile.prod # Path to Dockerfile (uses Railpack with Dockerfile)
|
|
128
128
|
root_directory: /packages/api # Root directory (monorepo support)
|
|
129
129
|
watch_patterns: # File patterns that trigger deploys
|
|
130
130
|
- /packages/api/src/**
|
|
131
131
|
- /packages/shared/**
|
|
132
132
|
railway_config_file: railway.toml # Path to railway.json/toml for config-as-code
|
|
133
|
+
metal: true # Enable Railway Metal builds (service-level, see note below)
|
|
133
134
|
```
|
|
134
135
|
|
|
136
|
+
**Note:** Some settings are **service-level** in Railway (applied globally, not per-environment): `metal`, service creation, and service deletion. If you manage multiple environments for the same project, these settings will affect all environments regardless of which YAML file sets them.
|
|
137
|
+
|
|
135
138
|
#### Deploy
|
|
136
139
|
|
|
137
140
|
```yaml
|
package/dist/index.js
CHANGED
|
@@ -37508,7 +37508,8 @@ var ServiceTemplateSchema = exports_external.object({
|
|
|
37508
37508
|
tcp_proxies: exports_external.array(exports_external.number().int().positive()).optional(),
|
|
37509
37509
|
limits: LimitsConfigSchema,
|
|
37510
37510
|
railway_config_file: exports_external.string().optional(),
|
|
37511
|
-
static_outbound_ips: exports_external.boolean().optional()
|
|
37511
|
+
static_outbound_ips: exports_external.boolean().optional(),
|
|
37512
|
+
metal: exports_external.boolean().optional()
|
|
37512
37513
|
}).strict();
|
|
37513
37514
|
var ServiceEntrySchema = exports_external.object({
|
|
37514
37515
|
template: exports_external.string().optional(),
|
|
@@ -37540,7 +37541,8 @@ var ServiceEntrySchema = exports_external.object({
|
|
|
37540
37541
|
tcp_proxies: exports_external.array(exports_external.number().int().positive()).optional(),
|
|
37541
37542
|
limits: LimitsConfigSchema,
|
|
37542
37543
|
railway_config_file: exports_external.string().optional(),
|
|
37543
|
-
static_outbound_ips: exports_external.boolean().optional()
|
|
37544
|
+
static_outbound_ips: exports_external.boolean().optional(),
|
|
37545
|
+
metal: exports_external.boolean().optional()
|
|
37544
37546
|
}).strict();
|
|
37545
37547
|
var EnvironmentConfigSchema = exports_external.object({
|
|
37546
37548
|
project: exports_external.string().min(1, "project name is required"),
|
|
@@ -37574,7 +37576,7 @@ ${issues}`);
|
|
|
37574
37576
|
}
|
|
37575
37577
|
}
|
|
37576
37578
|
var VALID_RESTART_POLICIES = ["ALWAYS", "NEVER", "ON_FAILURE"];
|
|
37577
|
-
var VALID_BUILDERS = ["RAILPACK", "
|
|
37579
|
+
var VALID_BUILDERS = ["RAILPACK", "NIXPACKS", "HEROKU", "PAKETO"];
|
|
37578
37580
|
var CRON_FIELD_PATTERN = /^(\*|[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*)(\/[0-9]+)?$/;
|
|
37579
37581
|
var DOMAIN_PATTERN = /^(\*\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
37580
37582
|
function validateResolvedService(name, service) {
|
|
@@ -37761,6 +37763,7 @@ function resolveService(name, entry, envDir, lenient = false) {
|
|
|
37761
37763
|
const limits = template?.limits ?? entry.limits;
|
|
37762
37764
|
const railwayConfigFile = template?.railway_config_file ? expandParamsDeep(template.railway_config_file, params) : entry.railway_config_file;
|
|
37763
37765
|
const staticOutboundIps = template?.static_outbound_ips ?? entry.static_outbound_ips;
|
|
37766
|
+
const metal = template?.metal ?? entry.metal;
|
|
37764
37767
|
let templateDomains = [];
|
|
37765
37768
|
if (template?.domains) {
|
|
37766
37769
|
templateDomains = normalizeDomains(expandParamsDeep(template.domains, params));
|
|
@@ -37866,6 +37869,8 @@ function resolveService(name, entry, envDir, lenient = false) {
|
|
|
37866
37869
|
service.railwayConfigFile = railwayConfigFile;
|
|
37867
37870
|
if (staticOutboundIps !== undefined)
|
|
37868
37871
|
service.staticOutboundIps = staticOutboundIps;
|
|
37872
|
+
if (metal !== undefined)
|
|
37873
|
+
service.metal = metal;
|
|
37869
37874
|
validateResolvedService(name, service);
|
|
37870
37875
|
return { service, deleted };
|
|
37871
37876
|
}
|
|
@@ -38440,11 +38445,13 @@ function createClient(token) {
|
|
|
38440
38445
|
const baseClient = new GraphQLClient(RAILWAY_API, {
|
|
38441
38446
|
headers: {
|
|
38442
38447
|
Authorization: `Bearer ${token}`
|
|
38443
|
-
}
|
|
38444
|
-
signal: AbortSignal.timeout(30000)
|
|
38448
|
+
}
|
|
38445
38449
|
});
|
|
38446
38450
|
const originalRequest = baseClient.request.bind(baseClient);
|
|
38447
|
-
baseClient.request = (...args) => withRetry(() =>
|
|
38451
|
+
baseClient.request = (...args) => withRetry(() => {
|
|
38452
|
+
baseClient.requestConfig.signal = AbortSignal.timeout(120000);
|
|
38453
|
+
return originalRequest(...args);
|
|
38454
|
+
});
|
|
38448
38455
|
return baseClient;
|
|
38449
38456
|
}
|
|
38450
38457
|
|
|
@@ -38467,8 +38474,10 @@ var ServiceInstanceLimitsUpdateDocument = { kind: "Document", definitions: [{ ki
|
|
|
38467
38474
|
var DeploymentTriggerUpdateDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "mutation", name: { kind: "Name", value: "DeploymentTriggerUpdate" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "id" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }, { kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "input" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "DeploymentTriggerUpdateInput" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "deploymentTriggerUpdate" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "id" }, value: { kind: "Variable", name: { kind: "Name", value: "id" } } }, { kind: "Argument", name: { kind: "Name", value: "input" }, value: { kind: "Variable", name: { kind: "Name", value: "input" } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "branch" } }] } }] } }] };
|
|
38468
38475
|
var EgressGatewayAssociationCreateDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "mutation", name: { kind: "Name", value: "EgressGatewayAssociationCreate" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "input" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "EgressGatewayCreateInput" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "egressGatewayAssociationCreate" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "input" }, value: { kind: "Variable", name: { kind: "Name", value: "input" } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "ipv4" } }, { kind: "Field", name: { kind: "Name", value: "region" } }] } }] } }] };
|
|
38469
38476
|
var EgressGatewayAssociationsClearDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "mutation", name: { kind: "Name", value: "EgressGatewayAssociationsClear" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "input" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "EgressGatewayServiceTargetInput" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "egressGatewayAssociationsClear" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "input" }, value: { kind: "Variable", name: { kind: "Name", value: "input" } } }] }] } }] };
|
|
38477
|
+
var ServiceFeatureFlagAddDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "mutation", name: { kind: "Name", value: "ServiceFeatureFlagAdd" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "input" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "ServiceFeatureFlagToggleInput" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "serviceFeatureFlagAdd" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "input" }, value: { kind: "Variable", name: { kind: "Name", value: "input" } } }] }] } }] };
|
|
38478
|
+
var ServiceFeatureFlagRemoveDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "mutation", name: { kind: "Name", value: "ServiceFeatureFlagRemove" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "input" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "ServiceFeatureFlagToggleInput" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "serviceFeatureFlagRemove" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "input" }, value: { kind: "Variable", name: { kind: "Name", value: "input" } } }] }] } }] };
|
|
38470
38479
|
var ListProjectsDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "query", name: { kind: "Name", value: "ListProjects" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "projects" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }] } }] } }] } }] } }] };
|
|
38471
|
-
var GetProjectDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "query", name: { kind: "Name", value: "GetProject" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "id" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "project" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "id" }, value: { kind: "Variable", name: { kind: "Name", value: "id" } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "environments" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "deploymentTriggers" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "branch" } }, { kind: "Field", name: { kind: "Name", value: "checkSuites" } }, { kind: "Field", name: { kind: "Name", value: "serviceId" } }, { kind: "Field", name: { kind: "Name", value: "repository" } }] } }] } }] } }] } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "services" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "serviceInstances" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "environmentId" } }, { kind: "Field", name: { kind: "Name", value: "source" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "image" } }, { kind: "Field", name: { kind: "Name", value: "repo" } }] } }, { kind: "Field", name: { kind: "Name", value: "domains" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "customDomains" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "domain" } }, { kind: "Field", name: { kind: "Name", value: "targetPort" } }] } }, { kind: "Field", name: { kind: "Name", value: "serviceDomains" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "domain" } }, { kind: "Field", name: { kind: "Name", value: "targetPort" } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "region" } }, { kind: "Field", name: { kind: "Name", value: "numReplicas" } }, { kind: "Field", name: { kind: "Name", value: "restartPolicyType" } }, { kind: "Field", name: { kind: "Name", value: "restartPolicyMaxRetries" } }, { kind: "Field", name: { kind: "Name", value: "healthcheckPath" } }, { kind: "Field", name: { kind: "Name", value: "healthcheckTimeout" } }, { kind: "Field", name: { kind: "Name", value: "cronSchedule" } }, { kind: "Field", name: { kind: "Name", value: "startCommand" } }, { kind: "Field", name: { kind: "Name", value: "buildCommand" } }, { kind: "Field", name: { kind: "Name", value: "rootDirectory" } }, { kind: "Field", name: { kind: "Name", value: "dockerfilePath" } }, { kind: "Field", name: { kind: "Name", value: "preDeployCommand" } }, { kind: "Field", name: { kind: "Name", value: "sleepApplication" } }, { kind: "Field", name: { kind: "Name", value: "builder" } }, { kind: "Field", name: { kind: "Name", value: "watchPatterns" } }, { kind: "Field", name: { kind: "Name", value: "drainingSeconds" } }, { kind: "Field", name: { kind: "Name", value: "overlapSeconds" } }, { kind: "Field", name: { kind: "Name", value: "ipv6EgressEnabled" } }, { kind: "Field", name: { kind: "Name", value: "railwayConfigFile" } }] } }] } }] } }] } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "buckets" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }] } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "volumes" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "volumeInstances" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "mountPath" } }, { kind: "Field", name: { kind: "Name", value: "environmentId" } }, { kind: "Field", name: { kind: "Name", value: "serviceId" } }] } }] } }] } }] } }] } }] } }] } }] } }] };
|
|
38480
|
+
var GetProjectDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "query", name: { kind: "Name", value: "GetProject" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "id" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "project" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "id" }, value: { kind: "Variable", name: { kind: "Name", value: "id" } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "environments" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "deploymentTriggers" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "branch" } }, { kind: "Field", name: { kind: "Name", value: "checkSuites" } }, { kind: "Field", name: { kind: "Name", value: "serviceId" } }, { kind: "Field", name: { kind: "Name", value: "repository" } }] } }] } }] } }] } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "services" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "featureFlags" } }, { kind: "Field", name: { kind: "Name", value: "serviceInstances" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "environmentId" } }, { kind: "Field", name: { kind: "Name", value: "source" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "image" } }, { kind: "Field", name: { kind: "Name", value: "repo" } }] } }, { kind: "Field", name: { kind: "Name", value: "domains" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "customDomains" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "domain" } }, { kind: "Field", name: { kind: "Name", value: "targetPort" } }] } }, { kind: "Field", name: { kind: "Name", value: "serviceDomains" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "domain" } }, { kind: "Field", name: { kind: "Name", value: "targetPort" } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "region" } }, { kind: "Field", name: { kind: "Name", value: "numReplicas" } }, { kind: "Field", name: { kind: "Name", value: "restartPolicyType" } }, { kind: "Field", name: { kind: "Name", value: "restartPolicyMaxRetries" } }, { kind: "Field", name: { kind: "Name", value: "healthcheckPath" } }, { kind: "Field", name: { kind: "Name", value: "healthcheckTimeout" } }, { kind: "Field", name: { kind: "Name", value: "cronSchedule" } }, { kind: "Field", name: { kind: "Name", value: "startCommand" } }, { kind: "Field", name: { kind: "Name", value: "buildCommand" } }, { kind: "Field", name: { kind: "Name", value: "rootDirectory" } }, { kind: "Field", name: { kind: "Name", value: "dockerfilePath" } }, { kind: "Field", name: { kind: "Name", value: "preDeployCommand" } }, { kind: "Field", name: { kind: "Name", value: "sleepApplication" } }, { kind: "Field", name: { kind: "Name", value: "builder" } }, { kind: "Field", name: { kind: "Name", value: "watchPatterns" } }, { kind: "Field", name: { kind: "Name", value: "drainingSeconds" } }, { kind: "Field", name: { kind: "Name", value: "overlapSeconds" } }, { kind: "Field", name: { kind: "Name", value: "ipv6EgressEnabled" } }, { kind: "Field", name: { kind: "Name", value: "railwayConfigFile" } }] } }] } }] } }] } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "buckets" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }] } }] } }] } }, { kind: "Field", name: { kind: "Name", value: "volumes" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "name" } }, { kind: "Field", name: { kind: "Name", value: "volumeInstances" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "edges" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "node" }, selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "mountPath" } }, { kind: "Field", name: { kind: "Name", value: "environmentId" } }, { kind: "Field", name: { kind: "Name", value: "serviceId" } }] } }] } }] } }] } }] } }] } }] } }] } }] };
|
|
38472
38481
|
var GetVariablesDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "query", name: { kind: "Name", value: "GetVariables" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "projectId" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }, { kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "environmentId" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }, { kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "serviceId" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "variables" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "projectId" }, value: { kind: "Variable", name: { kind: "Name", value: "projectId" } } }, { kind: "Argument", name: { kind: "Name", value: "environmentId" }, value: { kind: "Variable", name: { kind: "Name", value: "environmentId" } } }, { kind: "Argument", name: { kind: "Name", value: "serviceId" }, value: { kind: "Variable", name: { kind: "Name", value: "serviceId" } } }, { kind: "Argument", name: { kind: "Name", value: "unrendered" }, value: { kind: "BooleanValue", value: true } }] }] } }] };
|
|
38473
38482
|
var GetSharedVariablesDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "query", name: { kind: "Name", value: "GetSharedVariables" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "projectId" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }, { kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "environmentId" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "variables" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "projectId" }, value: { kind: "Variable", name: { kind: "Name", value: "projectId" } } }, { kind: "Argument", name: { kind: "Name", value: "environmentId" }, value: { kind: "Variable", name: { kind: "Name", value: "environmentId" } } }, { kind: "Argument", name: { kind: "Name", value: "unrendered" }, value: { kind: "BooleanValue", value: true } }] }] } }] };
|
|
38474
38483
|
var GetTcpProxiesDocument = { kind: "Document", definitions: [{ kind: "OperationDefinition", operation: "query", name: { kind: "Name", value: "GetTcpProxies" }, variableDefinitions: [{ kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "serviceId" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }, { kind: "VariableDefinition", variable: { kind: "Variable", name: { kind: "Name", value: "environmentId" } }, type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "String" } } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "tcpProxies" }, arguments: [{ kind: "Argument", name: { kind: "Name", value: "serviceId" }, value: { kind: "Variable", name: { kind: "Name", value: "serviceId" } } }, { kind: "Argument", name: { kind: "Name", value: "environmentId" }, value: { kind: "Variable", name: { kind: "Name", value: "environmentId" } } }], selectionSet: { kind: "SelectionSet", selections: [{ kind: "Field", name: { kind: "Name", value: "id" } }, { kind: "Field", name: { kind: "Name", value: "applicationPort" } }, { kind: "Field", name: { kind: "Name", value: "proxyPort" } }, { kind: "Field", name: { kind: "Name", value: "domain" } }] } }] } }] };
|
|
@@ -38636,6 +38645,9 @@ async function fetchCurrentState(client, projectId, environmentId) {
|
|
|
38636
38645
|
if (egressLookup.get(svc.id)) {
|
|
38637
38646
|
services[svc.name].staticOutboundIps = true;
|
|
38638
38647
|
}
|
|
38648
|
+
if (svc.featureFlags.includes("USE_VM_RUNTIME")) {
|
|
38649
|
+
services[svc.name].metal = true;
|
|
38650
|
+
}
|
|
38639
38651
|
if (vol) {
|
|
38640
38652
|
volumeMap[svc.name] = vol;
|
|
38641
38653
|
}
|
|
@@ -38893,6 +38905,16 @@ async function clearEgressGateways(client, serviceId, environmentId) {
|
|
|
38893
38905
|
input: { serviceId, environmentId }
|
|
38894
38906
|
});
|
|
38895
38907
|
}
|
|
38908
|
+
async function addServiceFeatureFlag(client, serviceId, flag) {
|
|
38909
|
+
await client.request(ServiceFeatureFlagAddDocument, {
|
|
38910
|
+
input: { serviceId, flag }
|
|
38911
|
+
});
|
|
38912
|
+
}
|
|
38913
|
+
async function removeServiceFeatureFlag(client, serviceId, flag) {
|
|
38914
|
+
await client.request(ServiceFeatureFlagRemoveDocument, {
|
|
38915
|
+
input: { serviceId, flag }
|
|
38916
|
+
});
|
|
38917
|
+
}
|
|
38896
38918
|
async function createBucket(client, projectId, name) {
|
|
38897
38919
|
const data = await client.request(BucketCreateDocument, {
|
|
38898
38920
|
input: { projectId, name }
|
|
@@ -39093,6 +39115,24 @@ function describeChange(change) {
|
|
|
39093
39115
|
serviceName: change.serviceName,
|
|
39094
39116
|
summary: "static outbound IPs: disable"
|
|
39095
39117
|
};
|
|
39118
|
+
case "enable-service-feature-flag": {
|
|
39119
|
+
const flagName = change.flag === "USE_VM_RUNTIME" ? "metal" : change.flag;
|
|
39120
|
+
return {
|
|
39121
|
+
category: "Feature flags",
|
|
39122
|
+
action: "create",
|
|
39123
|
+
serviceName: change.serviceName,
|
|
39124
|
+
summary: `${flagName}: enable`
|
|
39125
|
+
};
|
|
39126
|
+
}
|
|
39127
|
+
case "disable-service-feature-flag": {
|
|
39128
|
+
const flagName = change.flag === "USE_VM_RUNTIME" ? "metal" : change.flag;
|
|
39129
|
+
return {
|
|
39130
|
+
category: "Feature flags",
|
|
39131
|
+
action: "delete",
|
|
39132
|
+
serviceName: change.serviceName,
|
|
39133
|
+
summary: `${flagName}: disable`
|
|
39134
|
+
};
|
|
39135
|
+
}
|
|
39096
39136
|
case "create-bucket":
|
|
39097
39137
|
return {
|
|
39098
39138
|
category: "Buckets",
|
|
@@ -39234,6 +39274,25 @@ Apply results:`);
|
|
|
39234
39274
|
}
|
|
39235
39275
|
|
|
39236
39276
|
// src/reconcile/apply.ts
|
|
39277
|
+
function extractErrorMessage(err) {
|
|
39278
|
+
if (!(err instanceof Error))
|
|
39279
|
+
return String(err);
|
|
39280
|
+
const msg = err.message;
|
|
39281
|
+
try {
|
|
39282
|
+
const parsed = "response" in err ? err.response : undefined;
|
|
39283
|
+
if (parsed && typeof parsed === "object" && parsed !== null) {
|
|
39284
|
+
const resp = parsed;
|
|
39285
|
+
const gqlMessage = resp.errors?.[0]?.message;
|
|
39286
|
+
if (gqlMessage && gqlMessage !== "Problem processing request") {
|
|
39287
|
+
return gqlMessage;
|
|
39288
|
+
}
|
|
39289
|
+
}
|
|
39290
|
+
} catch {}
|
|
39291
|
+
const match = msg.match(/"message":"([^"]+)"/);
|
|
39292
|
+
if (match)
|
|
39293
|
+
return match[1];
|
|
39294
|
+
return msg;
|
|
39295
|
+
}
|
|
39237
39296
|
function green2(text, noColor) {
|
|
39238
39297
|
return noColor ? text : `\x1B[32m${text}\x1B[0m`;
|
|
39239
39298
|
}
|
|
@@ -39263,7 +39322,7 @@ async function applyChangeset(client, changeset, projectId, environmentId, optio
|
|
|
39263
39322
|
applied.push(change);
|
|
39264
39323
|
console.log(` ${green2("✓", noColor)} ${changeLabel(change)}`);
|
|
39265
39324
|
} catch (err) {
|
|
39266
|
-
const message =
|
|
39325
|
+
const message = extractErrorMessage(err);
|
|
39267
39326
|
failed.push({ change, error: message });
|
|
39268
39327
|
console.log(` ${red2("✗", noColor)} ${changeLabel(change)} — ${message}`);
|
|
39269
39328
|
}
|
|
@@ -39458,6 +39517,22 @@ async function applyChange(client, change, projectId, environmentId, createdServ
|
|
|
39458
39517
|
await clearEgressGateways(client, serviceId, environmentId);
|
|
39459
39518
|
break;
|
|
39460
39519
|
}
|
|
39520
|
+
case "enable-service-feature-flag": {
|
|
39521
|
+
const serviceId = change.serviceId || createdServiceIds.get(change.serviceName);
|
|
39522
|
+
if (!serviceId) {
|
|
39523
|
+
throw new Error(`No service ID for "${change.serviceName}"`);
|
|
39524
|
+
}
|
|
39525
|
+
await addServiceFeatureFlag(client, serviceId, change.flag);
|
|
39526
|
+
break;
|
|
39527
|
+
}
|
|
39528
|
+
case "disable-service-feature-flag": {
|
|
39529
|
+
const serviceId = change.serviceId || createdServiceIds.get(change.serviceName);
|
|
39530
|
+
if (!serviceId) {
|
|
39531
|
+
throw new Error(`No service ID for "${change.serviceName}"`);
|
|
39532
|
+
}
|
|
39533
|
+
await removeServiceFeatureFlag(client, serviceId, change.flag);
|
|
39534
|
+
break;
|
|
39535
|
+
}
|
|
39461
39536
|
case "delete-bucket":
|
|
39462
39537
|
throw new Error("Bucket deletion is not supported by the Railway API — delete manually");
|
|
39463
39538
|
default: {
|
|
@@ -39575,6 +39650,15 @@ function computeChangeset(desired, current, deletedVars, deletedSharedVars, doma
|
|
|
39575
39650
|
serviceId: ""
|
|
39576
39651
|
});
|
|
39577
39652
|
}
|
|
39653
|
+
if (desiredSvc.metal) {
|
|
39654
|
+
console.warn(` Warning: "${name}" metal flag is service-level — applies across all Railway environments`);
|
|
39655
|
+
changes.push({
|
|
39656
|
+
type: "enable-service-feature-flag",
|
|
39657
|
+
serviceName: name,
|
|
39658
|
+
serviceId: "",
|
|
39659
|
+
flag: "USE_VM_RUNTIME"
|
|
39660
|
+
});
|
|
39661
|
+
}
|
|
39578
39662
|
if (Object.keys(newSvcSettings).length > 0) {
|
|
39579
39663
|
changes.push({
|
|
39580
39664
|
type: "update-service-settings",
|
|
@@ -39606,6 +39690,7 @@ function computeChangeset(desired, current, deletedVars, deletedSharedVars, doma
|
|
|
39606
39690
|
}
|
|
39607
39691
|
}
|
|
39608
39692
|
diffStaticOutboundIps(name, desiredSvc, currentSvc, changes);
|
|
39693
|
+
diffMetal(name, desiredSvc, currentSvc, changes);
|
|
39609
39694
|
}
|
|
39610
39695
|
}
|
|
39611
39696
|
for (const name of currentNames) {
|
|
@@ -39915,6 +40000,27 @@ function diffServiceLimits(serviceName, desired, current, changes) {
|
|
|
39915
40000
|
});
|
|
39916
40001
|
}
|
|
39917
40002
|
}
|
|
40003
|
+
function diffMetal(serviceName, desired, current, changes) {
|
|
40004
|
+
if (!current.id)
|
|
40005
|
+
return;
|
|
40006
|
+
if (desired.metal === true && !current.metal) {
|
|
40007
|
+
console.warn(` Warning: "${serviceName}" metal flag is service-level — applies across all Railway environments`);
|
|
40008
|
+
changes.push({
|
|
40009
|
+
type: "enable-service-feature-flag",
|
|
40010
|
+
serviceName,
|
|
40011
|
+
serviceId: current.id,
|
|
40012
|
+
flag: "USE_VM_RUNTIME"
|
|
40013
|
+
});
|
|
40014
|
+
} else if (desired.metal === false && current.metal) {
|
|
40015
|
+
console.warn(` Warning: "${serviceName}" metal flag is service-level — applies across all Railway environments`);
|
|
40016
|
+
changes.push({
|
|
40017
|
+
type: "disable-service-feature-flag",
|
|
40018
|
+
serviceName,
|
|
40019
|
+
serviceId: current.id,
|
|
40020
|
+
flag: "USE_VM_RUNTIME"
|
|
40021
|
+
});
|
|
40022
|
+
}
|
|
40023
|
+
}
|
|
39918
40024
|
function diffStaticOutboundIps(serviceName, desired, current, changes) {
|
|
39919
40025
|
if (!current.id)
|
|
39920
40026
|
return;
|
|
@@ -40033,7 +40139,7 @@ Fetching current state from Railway...`);
|
|
|
40033
40139
|
console.log("Nothing to apply.");
|
|
40034
40140
|
process.exit(0);
|
|
40035
40141
|
}
|
|
40036
|
-
const hasDestructive = changeset.changes.some((c) => c.type === "delete-service" || c.type === "delete-volume" || c.type === "delete-bucket" || c.type === "delete-domain" || c.type === "delete-variables" || c.type === "delete-shared-variables" || c.type === "delete-service-domain" || c.type === "delete-tcp-proxy" || c.type === "disable-static-ips");
|
|
40142
|
+
const hasDestructive = changeset.changes.some((c) => c.type === "delete-service" || c.type === "delete-volume" || c.type === "delete-bucket" || c.type === "delete-domain" || c.type === "delete-variables" || c.type === "delete-shared-variables" || c.type === "delete-service-domain" || c.type === "delete-tcp-proxy" || c.type === "disable-static-ips" || c.type === "disable-service-feature-flag");
|
|
40037
40143
|
if (hasDestructive && !opts.yes) {
|
|
40038
40144
|
const ok = await confirm("This changeset includes destructive operations (deletions). Continue?");
|
|
40039
40145
|
if (!ok) {
|