@computesdk/railway 1.2.2 → 2.0.0
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 +57 -38
- package/dist/index.d.mts +9 -18
- package/dist/index.d.ts +9 -18
- package/dist/index.js +187 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +187 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @computesdk/railway
|
|
2
2
|
|
|
3
|
-
Railway provider for ComputeSDK
|
|
3
|
+
Railway provider for ComputeSDK - run commands in [Railway Sandboxes](https://docs.railway.com/sandboxes), ephemeral compute environments backed by the Railway platform.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,69 +8,88 @@ Railway provider for ComputeSDK that enables creating and managing containerized
|
|
|
8
8
|
npm install @computesdk/railway
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
> **Requires Node.js >= 22** — the underlying `railway` SDK depends on Node 22 APIs (e.g. global `WebSocket`).
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
1. Create a Railway API token at [railway.com/account/tokens](https://railway.com/account/tokens).
|
|
16
|
+
2. Find the environment ID you want sandboxes to run in (Railway project → environment settings).
|
|
17
|
+
3. Set the environment variables:
|
|
14
18
|
|
|
15
19
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
RAILWAY_ENVIRONMENT_ID=your_railway_environment_id
|
|
20
|
+
export RAILWAY_API_TOKEN=your_token_here
|
|
21
|
+
export RAILWAY_ENVIRONMENT_ID=your_environment_id_here
|
|
19
22
|
```
|
|
20
23
|
|
|
21
24
|
## Quick Start
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Use the gateway for zero-config auto-detection:
|
|
26
|
+
Configure `compute` with the Railway provider and create a sandbox:
|
|
26
27
|
|
|
27
28
|
```typescript
|
|
28
29
|
import { compute } from 'computesdk';
|
|
30
|
+
import { railway } from '@computesdk/railway';
|
|
31
|
+
|
|
32
|
+
compute.setConfig({
|
|
33
|
+
provider: railway({
|
|
34
|
+
token: process.env.RAILWAY_API_TOKEN,
|
|
35
|
+
environmentId: process.env.RAILWAY_ENVIRONMENT_ID,
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
29
38
|
|
|
30
|
-
// Auto-detects Railway from RAILWAY_API_KEY/RAILWAY_PROJECT_ID/RAILWAY_ENVIRONMENT_ID environment variables
|
|
31
39
|
const sandbox = await compute.sandbox.create();
|
|
32
|
-
|
|
40
|
+
|
|
41
|
+
const result = await sandbox.runCommand('echo "hello from Railway"');
|
|
42
|
+
console.log(result.stdout);
|
|
33
43
|
|
|
34
44
|
await sandbox.destroy();
|
|
35
45
|
```
|
|
36
46
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
For direct SDK usage without the gateway:
|
|
47
|
+
Alternatively, call the provider factory directly when you only need one provider:
|
|
40
48
|
|
|
41
49
|
```typescript
|
|
42
50
|
import { railway } from '@computesdk/railway';
|
|
43
51
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
environmentId: process.env.RAILWAY_ENVIRONMENT_ID
|
|
48
|
-
});
|
|
52
|
+
const sdk = railway({ token: process.env.RAILWAY_API_TOKEN });
|
|
53
|
+
const sandbox = await sdk.sandbox.create();
|
|
54
|
+
```
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
console.log(`Created sandbox: ${sandbox.sandboxId}`);
|
|
56
|
+
## Configuration
|
|
52
57
|
|
|
53
|
-
|
|
58
|
+
### Environment Variables
|
|
59
|
+
|
|
60
|
+
| Variable | Required | Description |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `RAILWAY_API_TOKEN` | Yes | Railway API token used to authenticate. |
|
|
63
|
+
| `RAILWAY_ENVIRONMENT_ID` | Recommended | Railway environment the sandbox runs in. |
|
|
64
|
+
|
|
65
|
+
### Config options
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
railway({
|
|
69
|
+
token: '...', // defaults to RAILWAY_API_TOKEN
|
|
70
|
+
environmentId: '...', // defaults to RAILWAY_ENVIRONMENT_ID
|
|
71
|
+
});
|
|
54
72
|
```
|
|
55
73
|
|
|
56
|
-
|
|
74
|
+
Per-command execution timeouts are supported via `runCommand`'s options (`{ timeout: ms }`), which maps to Railway's `timeoutSec`.
|
|
75
|
+
|
|
76
|
+
## Supported Features
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
78
|
+
| Feature | Supported | Notes |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| Command execution (`runCommand`) | ✅ | Backed by `sandbox.exec`. `timeout` is mapped to Railway's `timeoutSec`. |
|
|
81
|
+
| Filesystem (`filesystem.*`) | ✅ | Implemented over the shell (`cat`/`base64`/`mkdir`/`ls`/`rm`) since Railway has no dedicated filesystem API. |
|
|
82
|
+
| List sandboxes (`list`) | ✅ | Enumerates sandboxes in the configured environment. |
|
|
83
|
+
| Get / destroy by ID | ✅ | Via `Sandbox.connect` / `sandbox.destroy`. |
|
|
84
|
+
| Port exposure (`getUrl`) | ❌ | Railway sandboxes do not expose public per-port URLs. |
|
|
85
|
+
| Templates / snapshots | ❌ | Railway templates are a build-time builder (`Sandbox.template()`), not an ID-addressable resource, so they are not mapped to ComputeSDK templates/snapshots. |
|
|
61
86
|
|
|
62
|
-
|
|
63
|
-
- **node** - Uses `node:alpine` Docker image
|
|
64
|
-
- **python** - Uses `python:alpine` Docker image (default)
|
|
87
|
+
## Limitations
|
|
65
88
|
|
|
66
|
-
|
|
67
|
-
- **
|
|
68
|
-
- **
|
|
69
|
-
- **environmentId** - Railway environment identifier
|
|
89
|
+
- **No port exposure.** `getUrl` throws — Railway sandboxes don't publish public URLs per port.
|
|
90
|
+
- **Filesystem is shell-based.** File operations run shell commands inside the sandbox, so they require a POSIX shell with `base64`, `ls`, and the usual coreutils (present on Railway's default image).
|
|
91
|
+
- **Templates/snapshots are not exposed.** Use the underlying `railway` SDK's `Sandbox.template()` builder directly if you need custom base images.
|
|
70
92
|
|
|
71
|
-
##
|
|
93
|
+
## License
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
- Service names are generated with timestamp: `sandbox-{timestamp}`
|
|
75
|
-
- All operations use Railway's GraphQL API
|
|
76
|
-
- Environment variables take precedence over config options
|
|
95
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
|
+
import * as _computesdk_provider from '@computesdk/provider';
|
|
2
|
+
import { Sandbox } from 'railway';
|
|
3
|
+
export { Sandbox as RailwaySandbox } from 'railway';
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
|
-
* Railway
|
|
3
|
-
*
|
|
4
|
-
* Railway support previously depended on the hosted control-plane transport,
|
|
5
|
-
* which has been removed from computesdk.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Railway configuration (kept for compile-time compatibility of callers).
|
|
6
|
+
* Railway-specific configuration options
|
|
9
7
|
*/
|
|
10
8
|
interface RailwayConfig {
|
|
11
|
-
/** Railway API
|
|
12
|
-
|
|
13
|
-
/** Railway
|
|
14
|
-
projectId?: string;
|
|
15
|
-
/** Railway environment ID */
|
|
9
|
+
/** Railway API token - falls back to the RAILWAY_API_TOKEN environment variable */
|
|
10
|
+
token?: string;
|
|
11
|
+
/** Railway environment ID - falls back to the RAILWAY_ENVIRONMENT_ID environment variable */
|
|
16
12
|
environmentId?: string;
|
|
17
13
|
}
|
|
18
|
-
|
|
19
|
-
* Railway provider entrypoint.
|
|
20
|
-
*
|
|
21
|
-
* This package no longer provides a direct provider implementation.
|
|
22
|
-
*/
|
|
23
|
-
declare function railway(_config: RailwayConfig): never;
|
|
14
|
+
declare const railway: (config: RailwayConfig) => _computesdk_provider.Provider<Sandbox, any, any>;
|
|
24
15
|
|
|
25
16
|
export { type RailwayConfig, railway };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
|
+
import * as _computesdk_provider from '@computesdk/provider';
|
|
2
|
+
import { Sandbox } from 'railway';
|
|
3
|
+
export { Sandbox as RailwaySandbox } from 'railway';
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
|
-
* Railway
|
|
3
|
-
*
|
|
4
|
-
* Railway support previously depended on the hosted control-plane transport,
|
|
5
|
-
* which has been removed from computesdk.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Railway configuration (kept for compile-time compatibility of callers).
|
|
6
|
+
* Railway-specific configuration options
|
|
9
7
|
*/
|
|
10
8
|
interface RailwayConfig {
|
|
11
|
-
/** Railway API
|
|
12
|
-
|
|
13
|
-
/** Railway
|
|
14
|
-
projectId?: string;
|
|
15
|
-
/** Railway environment ID */
|
|
9
|
+
/** Railway API token - falls back to the RAILWAY_API_TOKEN environment variable */
|
|
10
|
+
token?: string;
|
|
11
|
+
/** Railway environment ID - falls back to the RAILWAY_ENVIRONMENT_ID environment variable */
|
|
16
12
|
environmentId?: string;
|
|
17
13
|
}
|
|
18
|
-
|
|
19
|
-
* Railway provider entrypoint.
|
|
20
|
-
*
|
|
21
|
-
* This package no longer provides a direct provider implementation.
|
|
22
|
-
*/
|
|
23
|
-
declare function railway(_config: RailwayConfig): never;
|
|
14
|
+
declare const railway: (config: RailwayConfig) => _computesdk_provider.Provider<Sandbox, any, any>;
|
|
24
15
|
|
|
25
16
|
export { type RailwayConfig, railway };
|
package/dist/index.js
CHANGED
|
@@ -23,11 +23,194 @@ __export(index_exports, {
|
|
|
23
23
|
railway: () => railway
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
var import_railway = require("railway");
|
|
27
|
+
var import_provider = require("@computesdk/provider");
|
|
28
|
+
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
29
|
+
function resolveClientOptions(config) {
|
|
30
|
+
const token = config.token || (typeof process !== "undefined" ? process.env?.RAILWAY_API_TOKEN : void 0);
|
|
31
|
+
if (!token) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"Missing Railway API token.\n\nCreate a token at https://railway.com/account/tokens\nThen pass it: railway({ token: 'xxx' })\nOr set RAILWAY_API_TOKEN in your environment."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
const environmentId = config.environmentId || (typeof process !== "undefined" ? process.env?.RAILWAY_ENVIRONMENT_ID : void 0);
|
|
37
|
+
return { token, environmentId };
|
|
38
|
+
}
|
|
39
|
+
function mapStatus(status) {
|
|
40
|
+
switch (status) {
|
|
41
|
+
case "RUNNING":
|
|
42
|
+
case "CREATING":
|
|
43
|
+
return "running";
|
|
44
|
+
case "DESTROYING":
|
|
45
|
+
case "DESTROYED":
|
|
46
|
+
return "stopped";
|
|
47
|
+
case "FAILED":
|
|
48
|
+
return "error";
|
|
49
|
+
default:
|
|
50
|
+
return "running";
|
|
51
|
+
}
|
|
30
52
|
}
|
|
53
|
+
var ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
54
|
+
function composeCommand(command, options) {
|
|
55
|
+
let fullCommand = command;
|
|
56
|
+
if (options?.env && Object.keys(options.env).length > 0) {
|
|
57
|
+
const envPrefix = Object.entries(options.env).map(([k, v]) => {
|
|
58
|
+
if (!ENV_KEY_PATTERN.test(k)) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Invalid environment variable name "${k}". Names must match ${ENV_KEY_PATTERN}.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return `${k}="${(0, import_provider.escapeShellArg)(String(v))}"`;
|
|
64
|
+
}).join(" ");
|
|
65
|
+
fullCommand = `${envPrefix} ${fullCommand}`;
|
|
66
|
+
}
|
|
67
|
+
if (options?.cwd) {
|
|
68
|
+
fullCommand = `cd "${(0, import_provider.escapeShellArg)(options.cwd)}" && ${fullCommand}`;
|
|
69
|
+
}
|
|
70
|
+
if (options?.background) {
|
|
71
|
+
fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
|
|
72
|
+
}
|
|
73
|
+
return fullCommand;
|
|
74
|
+
}
|
|
75
|
+
var railway = (0, import_provider.defineProvider)({
|
|
76
|
+
name: "railway",
|
|
77
|
+
methods: {
|
|
78
|
+
sandbox: {
|
|
79
|
+
create: async (config, options) => {
|
|
80
|
+
const client = resolveClientOptions(config);
|
|
81
|
+
try {
|
|
82
|
+
const sandbox = await import_railway.Sandbox.create({
|
|
83
|
+
token: client.token,
|
|
84
|
+
environmentId: client.environmentId,
|
|
85
|
+
...options?.envs ? { env: options.envs } : {},
|
|
86
|
+
...options?.idleTimeoutMinutes !== void 0 ? { idleTimeoutMinutes: options.idleTimeoutMinutes } : {},
|
|
87
|
+
...options?.networkIsolation !== void 0 ? { networkIsolation: options.networkIsolation } : {}
|
|
88
|
+
});
|
|
89
|
+
return { sandbox, sandboxId: sandbox.id };
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Failed to create Railway sandbox: ${error instanceof Error ? error.message : String(error)}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
getById: async (config, sandboxId) => {
|
|
97
|
+
const client = resolveClientOptions(config);
|
|
98
|
+
try {
|
|
99
|
+
const sandbox = await import_railway.Sandbox.connect(sandboxId, client);
|
|
100
|
+
return { sandbox, sandboxId };
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (error instanceof import_railway.SandboxNotFoundError) return null;
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
list: async (config) => {
|
|
107
|
+
const client = resolveClientOptions(config);
|
|
108
|
+
try {
|
|
109
|
+
const infos = await import_railway.Sandbox.list(client);
|
|
110
|
+
const connected = await Promise.allSettled(
|
|
111
|
+
infos.map(async (info) => {
|
|
112
|
+
const sandbox = await import_railway.Sandbox.connect(info.id, client);
|
|
113
|
+
return { sandbox, sandboxId: info.id };
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
return connected.filter(
|
|
117
|
+
(r) => r.status === "fulfilled"
|
|
118
|
+
).map((r) => r.value);
|
|
119
|
+
} catch {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
destroy: async (config, sandboxId) => {
|
|
124
|
+
const client = resolveClientOptions(config);
|
|
125
|
+
try {
|
|
126
|
+
const sandbox = await import_railway.Sandbox.connect(sandboxId, client);
|
|
127
|
+
await sandbox.destroy();
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
runCommand: async (sandbox, command, options) => {
|
|
132
|
+
const startTime = Date.now();
|
|
133
|
+
const fullCommand = composeCommand(command, options);
|
|
134
|
+
const timeoutSec = options?.timeout ? Math.ceil(options.timeout / 1e3) : void 0;
|
|
135
|
+
try {
|
|
136
|
+
const result = await sandbox.exec(
|
|
137
|
+
fullCommand,
|
|
138
|
+
timeoutSec ? { timeoutSec } : void 0
|
|
139
|
+
);
|
|
140
|
+
return {
|
|
141
|
+
stdout: result.stdout,
|
|
142
|
+
stderr: result.stderr,
|
|
143
|
+
// exitCode is null when a signal ended the command; surface as -1
|
|
144
|
+
exitCode: result.exitCode ?? -1,
|
|
145
|
+
durationMs: Date.now() - startTime
|
|
146
|
+
};
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return {
|
|
149
|
+
stdout: "",
|
|
150
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
151
|
+
exitCode: 127,
|
|
152
|
+
durationMs: Date.now() - startTime
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
getInfo: async (sandbox) => ({
|
|
157
|
+
id: sandbox.id,
|
|
158
|
+
provider: "railway",
|
|
159
|
+
status: mapStatus(sandbox.status),
|
|
160
|
+
createdAt: new Date(sandbox.createdAt),
|
|
161
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
162
|
+
metadata: { networkIsolation: sandbox.networkIsolation }
|
|
163
|
+
}),
|
|
164
|
+
getUrl: async (_sandbox, _options) => {
|
|
165
|
+
throw new Error(
|
|
166
|
+
"Railway sandboxes do not support exposing ports / public URLs. Use sandbox-to-sandbox networking within a Railway environment instead."
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
filesystem: {
|
|
170
|
+
readFile: async (sandbox, path, runCommand) => {
|
|
171
|
+
const arg = (0, import_provider.escapeShellArg)(path);
|
|
172
|
+
const result = await runCommand(sandbox, `test -f "${arg}" && base64 < "${arg}" | tr -d '\\n'`);
|
|
173
|
+
if (result.exitCode !== 0) throw new Error(`File not found or unreadable: ${path}`);
|
|
174
|
+
return Buffer.from(result.stdout, "base64").toString("utf8");
|
|
175
|
+
},
|
|
176
|
+
writeFile: async (sandbox, path, content, runCommand) => {
|
|
177
|
+
const arg = (0, import_provider.escapeShellArg)(path);
|
|
178
|
+
const encoded = Buffer.from(content).toString("base64");
|
|
179
|
+
const result = await runCommand(sandbox, `echo "${encoded}" | base64 -d > "${arg}"`);
|
|
180
|
+
if (result.exitCode !== 0) throw new Error(`Failed to write file ${path}: ${result.stderr}`);
|
|
181
|
+
},
|
|
182
|
+
mkdir: async (sandbox, path, runCommand) => {
|
|
183
|
+
const result = await runCommand(sandbox, `mkdir -p "${(0, import_provider.escapeShellArg)(path)}"`);
|
|
184
|
+
if (result.exitCode !== 0) throw new Error(`Failed to create directory ${path}: ${result.stderr}`);
|
|
185
|
+
},
|
|
186
|
+
readdir: async (sandbox, path, runCommand) => {
|
|
187
|
+
const result = await runCommand(sandbox, `ls -la "${(0, import_provider.escapeShellArg)(path)}"`);
|
|
188
|
+
if (result.exitCode !== 0) throw new Error(`Failed to list directory ${path}: ${result.stderr}`);
|
|
189
|
+
return (result.stdout || "").split("\n").filter((line) => line.trim() && !line.startsWith("total")).map((line) => {
|
|
190
|
+
const parts = line.trim().split(/\s+/);
|
|
191
|
+
const name = parts.slice(8).join(" ");
|
|
192
|
+
const isDirectory = line.startsWith("d");
|
|
193
|
+
return {
|
|
194
|
+
name,
|
|
195
|
+
type: isDirectory ? "directory" : "file",
|
|
196
|
+
size: parseInt(parts[4]) || 0,
|
|
197
|
+
modified: /* @__PURE__ */ new Date()
|
|
198
|
+
};
|
|
199
|
+
}).filter((entry) => entry.name && entry.name !== "." && entry.name !== "..");
|
|
200
|
+
},
|
|
201
|
+
exists: async (sandbox, path, runCommand) => {
|
|
202
|
+
const result = await runCommand(sandbox, `test -e "${(0, import_provider.escapeShellArg)(path)}"`);
|
|
203
|
+
return result.exitCode === 0;
|
|
204
|
+
},
|
|
205
|
+
remove: async (sandbox, path, runCommand) => {
|
|
206
|
+
const result = await runCommand(sandbox, `rm -rf "${(0, import_provider.escapeShellArg)(path)}"`);
|
|
207
|
+
if (result.exitCode !== 0) throw new Error(`Failed to remove ${path}: ${result.stderr}`);
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
getInstance: (sandbox) => sandbox
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
31
214
|
// Annotate the CommonJS export names for ESM import in node:
|
|
32
215
|
0 && (module.exports = {
|
|
33
216
|
railway
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Railway package placeholder.\n *\n * Railway support previously depended on the hosted control-plane transport,\n * which has been removed from computesdk.\n */\n\n/**\n * Railway configuration (kept for compile-time compatibility of callers).\n */\nexport interface RailwayConfig {\n /** Railway API key */\n apiKey?: string;\n /** Railway project ID */\n projectId?: string;\n /** Railway environment ID */\n environmentId?: string;\n}\n\n/**\n * Railway provider entrypoint.\n *\n * This package no longer provides a direct provider implementation.\n */\nexport function railway(_config: RailwayConfig): never {\n throw new Error(\n '@computesdk/railway is no longer supported after control-plane removal. ' +\n 'Use a direct provider package (for example @computesdk/e2b, @computesdk/modal, @computesdk/vercel, or @computesdk/daytona) with computesdk provider/providers config.'\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBO,SAAS,QAAQ,SAA+B;AACrD,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Railway Provider - Factory-based Implementation\n *\n * Wraps Railway Sandboxes (https://docs.railway.com/sandboxes) using the\n * ComputeSDK provider factory. Railway exposes command execution via\n * `sandbox.exec`; it has no dedicated filesystem or port-exposure API, so the\n * filesystem block is implemented over the shell and `getUrl` throws.\n */\n\nimport { Sandbox, SandboxNotFoundError } from 'railway';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\n\nimport type { CommandResult, RunCommandOptions, SandboxInfo } from '@computesdk/provider';\nimport type { CreateSandboxOptions, FileEntry } from 'computesdk';\n\ntype RailwaySandbox = Sandbox;\n\ntype CommandRunner = (\n sandbox: RailwaySandbox,\n command: string,\n options?: RunCommandOptions\n) => Promise<CommandResult>;\n\n/**\n * Railway-specific configuration options\n */\nexport interface RailwayConfig {\n /** Railway API token - falls back to the RAILWAY_API_TOKEN environment variable */\n token?: string;\n /** Railway environment ID - falls back to the RAILWAY_ENVIRONMENT_ID environment variable */\n environmentId?: string;\n}\n\n/** Options accepted by the Railway SDK's create/connect/list calls. */\ninterface RailwayClientOptions {\n token: string;\n environmentId?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 300000;\n\n/**\n * Resolve and validate credentials, falling back to environment variables.\n * Throws a helpful error when the token is missing.\n */\nfunction resolveClientOptions(config: RailwayConfig): RailwayClientOptions {\n const token =\n config.token || (typeof process !== 'undefined' ? process.env?.RAILWAY_API_TOKEN : undefined);\n\n if (!token) {\n throw new Error(\n 'Missing Railway API token.\\n\\n' +\n 'Create a token at https://railway.com/account/tokens\\n' +\n \"Then pass it: railway({ token: 'xxx' })\\n\" +\n 'Or set RAILWAY_API_TOKEN in your environment.'\n );\n }\n\n const environmentId =\n config.environmentId ||\n (typeof process !== 'undefined' ? process.env?.RAILWAY_ENVIRONMENT_ID : undefined);\n\n return { token, environmentId };\n}\n\n/** Map Railway's sandbox status onto the ComputeSDK status enum. */\nfunction mapStatus(status: string): SandboxInfo['status'] {\n switch (status) {\n case 'RUNNING':\n case 'CREATING':\n return 'running';\n case 'DESTROYING':\n case 'DESTROYED':\n return 'stopped';\n case 'FAILED':\n return 'error';\n default:\n return 'running';\n }\n}\n\n/** Valid POSIX shell environment variable name. Keys cannot be quoted in an\n * assignment prefix, so anything outside this set is rejected rather than escaped. */\nconst ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/** Apply env/cwd/background options by composing a single shell command string. */\nfunction composeCommand(command: string, options?: RunCommandOptions): string {\n let fullCommand = command;\n\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env)\n .map(([k, v]) => {\n if (!ENV_KEY_PATTERN.test(k)) {\n throw new Error(\n `Invalid environment variable name \"${k}\". Names must match ${ENV_KEY_PATTERN}.`\n );\n }\n return `${k}=\"${escapeShellArg(String(v))}\"`;\n })\n .join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n\n if (options?.cwd) {\n fullCommand = `cd \"${escapeShellArg(options.cwd)}\" && ${fullCommand}`;\n }\n\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n return fullCommand;\n}\n\nexport const railway = defineProvider<RailwaySandbox, RailwayConfig>({\n name: 'railway',\n methods: {\n sandbox: {\n create: async (config: RailwayConfig, options?: CreateSandboxOptions) => {\n const client = resolveClientOptions(config);\n\n try {\n const sandbox = await Sandbox.create({\n token: client.token,\n environmentId: client.environmentId,\n ...(options?.envs ? { env: options.envs } : {}),\n ...(options?.idleTimeoutMinutes !== undefined\n ? { idleTimeoutMinutes: options.idleTimeoutMinutes }\n : {}),\n ...(options?.networkIsolation !== undefined\n ? { networkIsolation: options.networkIsolation }\n : {}),\n });\n\n return { sandbox, sandboxId: sandbox.id };\n } catch (error) {\n throw new Error(\n `Failed to create Railway sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: RailwayConfig, sandboxId: string) => {\n const client = resolveClientOptions(config);\n try {\n const sandbox = await Sandbox.connect(sandboxId, client);\n return { sandbox, sandboxId };\n } catch (error) {\n // Only a missing sandbox maps to null; surface auth/network/config errors.\n if (error instanceof SandboxNotFoundError) return null;\n throw error;\n }\n },\n\n list: async (config: RailwayConfig) => {\n const client = resolveClientOptions(config);\n try {\n const infos = await Sandbox.list(client);\n const connected = await Promise.allSettled(\n infos.map(async (info) => {\n const sandbox = await Sandbox.connect(info.id, client);\n return { sandbox, sandboxId: info.id };\n })\n );\n return connected\n .filter(\n (r): r is PromiseFulfilledResult<{ sandbox: RailwaySandbox; sandboxId: string }> =>\n r.status === 'fulfilled'\n )\n .map((r) => r.value);\n } catch {\n return [];\n }\n },\n\n destroy: async (config: RailwayConfig, sandboxId: string) => {\n const client = resolveClientOptions(config);\n try {\n const sandbox = await Sandbox.connect(sandboxId, client);\n await sandbox.destroy();\n } catch {\n /* already destroyed or unreachable */\n }\n },\n\n runCommand: async (\n sandbox: RailwaySandbox,\n command: string,\n options?: RunCommandOptions\n ): Promise<CommandResult> => {\n const startTime = Date.now();\n const fullCommand = composeCommand(command, options);\n const timeoutSec = options?.timeout ? Math.ceil(options.timeout / 1000) : undefined;\n\n try {\n const result = await sandbox.exec(\n fullCommand,\n timeoutSec ? { timeoutSec } : undefined\n );\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n // exitCode is null when a signal ended the command; surface as -1\n exitCode: result.exitCode ?? -1,\n durationMs: Date.now() - startTime,\n };\n } catch (error) {\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127,\n durationMs: Date.now() - startTime,\n };\n }\n },\n\n getInfo: async (sandbox: RailwaySandbox): Promise<SandboxInfo> => ({\n id: sandbox.id,\n provider: 'railway',\n status: mapStatus(sandbox.status),\n createdAt: new Date(sandbox.createdAt),\n timeout: DEFAULT_TIMEOUT_MS,\n metadata: { networkIsolation: sandbox.networkIsolation },\n }),\n\n getUrl: async (_sandbox: RailwaySandbox, _options: { port: number; protocol?: string }): Promise<string> => {\n throw new Error(\n 'Railway sandboxes do not support exposing ports / public URLs. ' +\n 'Use sandbox-to-sandbox networking within a Railway environment instead.'\n );\n },\n\n filesystem: {\n readFile: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<string> => {\n const arg = escapeShellArg(path);\n const result = await runCommand(sandbox, `test -f \"${arg}\" && base64 < \"${arg}\" | tr -d '\\\\n'`);\n if (result.exitCode !== 0) throw new Error(`File not found or unreadable: ${path}`);\n return Buffer.from(result.stdout, 'base64').toString('utf8');\n },\n\n writeFile: async (sandbox: RailwaySandbox, path: string, content: string, runCommand: CommandRunner): Promise<void> => {\n const arg = escapeShellArg(path);\n const encoded = Buffer.from(content).toString('base64');\n const result = await runCommand(sandbox, `echo \"${encoded}\" | base64 -d > \"${arg}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to write file ${path}: ${result.stderr}`);\n },\n\n mkdir: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<void> => {\n const result = await runCommand(sandbox, `mkdir -p \"${escapeShellArg(path)}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to create directory ${path}: ${result.stderr}`);\n },\n\n readdir: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<FileEntry[]> => {\n const result = await runCommand(sandbox, `ls -la \"${escapeShellArg(path)}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to list directory ${path}: ${result.stderr}`);\n\n return (result.stdout || '')\n .split('\\n')\n .filter((line) => line.trim() && !line.startsWith('total'))\n .map((line) => {\n // `ls -la` columns: perms links owner group size month day time name…\n // The name is everything from the 9th column on, so it survives spaces.\n const parts = line.trim().split(/\\s+/);\n const name = parts.slice(8).join(' ');\n const isDirectory = line.startsWith('d');\n return {\n name,\n type: isDirectory ? ('directory' as const) : ('file' as const),\n size: parseInt(parts[4]) || 0,\n modified: new Date(),\n };\n })\n .filter((entry) => entry.name && entry.name !== '.' && entry.name !== '..');\n },\n\n exists: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<boolean> => {\n const result = await runCommand(sandbox, `test -e \"${escapeShellArg(path)}\"`);\n return result.exitCode === 0;\n },\n\n remove: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<void> => {\n const result = await runCommand(sandbox, `rm -rf \"${escapeShellArg(path)}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to remove ${path}: ${result.stderr}`);\n },\n },\n\n getInstance: (sandbox: RailwaySandbox): RailwaySandbox => sandbox,\n },\n },\n});\n\nexport type { Sandbox as RailwaySandbox } from 'railway';\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,192 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { Sandbox, SandboxNotFoundError } from "railway";
|
|
3
|
+
import { defineProvider, escapeShellArg } from "@computesdk/provider";
|
|
4
|
+
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
5
|
+
function resolveClientOptions(config) {
|
|
6
|
+
const token = config.token || (typeof process !== "undefined" ? process.env?.RAILWAY_API_TOKEN : void 0);
|
|
7
|
+
if (!token) {
|
|
8
|
+
throw new Error(
|
|
9
|
+
"Missing Railway API token.\n\nCreate a token at https://railway.com/account/tokens\nThen pass it: railway({ token: 'xxx' })\nOr set RAILWAY_API_TOKEN in your environment."
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
const environmentId = config.environmentId || (typeof process !== "undefined" ? process.env?.RAILWAY_ENVIRONMENT_ID : void 0);
|
|
13
|
+
return { token, environmentId };
|
|
6
14
|
}
|
|
15
|
+
function mapStatus(status) {
|
|
16
|
+
switch (status) {
|
|
17
|
+
case "RUNNING":
|
|
18
|
+
case "CREATING":
|
|
19
|
+
return "running";
|
|
20
|
+
case "DESTROYING":
|
|
21
|
+
case "DESTROYED":
|
|
22
|
+
return "stopped";
|
|
23
|
+
case "FAILED":
|
|
24
|
+
return "error";
|
|
25
|
+
default:
|
|
26
|
+
return "running";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
30
|
+
function composeCommand(command, options) {
|
|
31
|
+
let fullCommand = command;
|
|
32
|
+
if (options?.env && Object.keys(options.env).length > 0) {
|
|
33
|
+
const envPrefix = Object.entries(options.env).map(([k, v]) => {
|
|
34
|
+
if (!ENV_KEY_PATTERN.test(k)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Invalid environment variable name "${k}". Names must match ${ENV_KEY_PATTERN}.`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return `${k}="${escapeShellArg(String(v))}"`;
|
|
40
|
+
}).join(" ");
|
|
41
|
+
fullCommand = `${envPrefix} ${fullCommand}`;
|
|
42
|
+
}
|
|
43
|
+
if (options?.cwd) {
|
|
44
|
+
fullCommand = `cd "${escapeShellArg(options.cwd)}" && ${fullCommand}`;
|
|
45
|
+
}
|
|
46
|
+
if (options?.background) {
|
|
47
|
+
fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
|
|
48
|
+
}
|
|
49
|
+
return fullCommand;
|
|
50
|
+
}
|
|
51
|
+
var railway = defineProvider({
|
|
52
|
+
name: "railway",
|
|
53
|
+
methods: {
|
|
54
|
+
sandbox: {
|
|
55
|
+
create: async (config, options) => {
|
|
56
|
+
const client = resolveClientOptions(config);
|
|
57
|
+
try {
|
|
58
|
+
const sandbox = await Sandbox.create({
|
|
59
|
+
token: client.token,
|
|
60
|
+
environmentId: client.environmentId,
|
|
61
|
+
...options?.envs ? { env: options.envs } : {},
|
|
62
|
+
...options?.idleTimeoutMinutes !== void 0 ? { idleTimeoutMinutes: options.idleTimeoutMinutes } : {},
|
|
63
|
+
...options?.networkIsolation !== void 0 ? { networkIsolation: options.networkIsolation } : {}
|
|
64
|
+
});
|
|
65
|
+
return { sandbox, sandboxId: sandbox.id };
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Failed to create Railway sandbox: ${error instanceof Error ? error.message : String(error)}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
getById: async (config, sandboxId) => {
|
|
73
|
+
const client = resolveClientOptions(config);
|
|
74
|
+
try {
|
|
75
|
+
const sandbox = await Sandbox.connect(sandboxId, client);
|
|
76
|
+
return { sandbox, sandboxId };
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error instanceof SandboxNotFoundError) return null;
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
list: async (config) => {
|
|
83
|
+
const client = resolveClientOptions(config);
|
|
84
|
+
try {
|
|
85
|
+
const infos = await Sandbox.list(client);
|
|
86
|
+
const connected = await Promise.allSettled(
|
|
87
|
+
infos.map(async (info) => {
|
|
88
|
+
const sandbox = await Sandbox.connect(info.id, client);
|
|
89
|
+
return { sandbox, sandboxId: info.id };
|
|
90
|
+
})
|
|
91
|
+
);
|
|
92
|
+
return connected.filter(
|
|
93
|
+
(r) => r.status === "fulfilled"
|
|
94
|
+
).map((r) => r.value);
|
|
95
|
+
} catch {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
destroy: async (config, sandboxId) => {
|
|
100
|
+
const client = resolveClientOptions(config);
|
|
101
|
+
try {
|
|
102
|
+
const sandbox = await Sandbox.connect(sandboxId, client);
|
|
103
|
+
await sandbox.destroy();
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
runCommand: async (sandbox, command, options) => {
|
|
108
|
+
const startTime = Date.now();
|
|
109
|
+
const fullCommand = composeCommand(command, options);
|
|
110
|
+
const timeoutSec = options?.timeout ? Math.ceil(options.timeout / 1e3) : void 0;
|
|
111
|
+
try {
|
|
112
|
+
const result = await sandbox.exec(
|
|
113
|
+
fullCommand,
|
|
114
|
+
timeoutSec ? { timeoutSec } : void 0
|
|
115
|
+
);
|
|
116
|
+
return {
|
|
117
|
+
stdout: result.stdout,
|
|
118
|
+
stderr: result.stderr,
|
|
119
|
+
// exitCode is null when a signal ended the command; surface as -1
|
|
120
|
+
exitCode: result.exitCode ?? -1,
|
|
121
|
+
durationMs: Date.now() - startTime
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return {
|
|
125
|
+
stdout: "",
|
|
126
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
127
|
+
exitCode: 127,
|
|
128
|
+
durationMs: Date.now() - startTime
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
getInfo: async (sandbox) => ({
|
|
133
|
+
id: sandbox.id,
|
|
134
|
+
provider: "railway",
|
|
135
|
+
status: mapStatus(sandbox.status),
|
|
136
|
+
createdAt: new Date(sandbox.createdAt),
|
|
137
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
138
|
+
metadata: { networkIsolation: sandbox.networkIsolation }
|
|
139
|
+
}),
|
|
140
|
+
getUrl: async (_sandbox, _options) => {
|
|
141
|
+
throw new Error(
|
|
142
|
+
"Railway sandboxes do not support exposing ports / public URLs. Use sandbox-to-sandbox networking within a Railway environment instead."
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
filesystem: {
|
|
146
|
+
readFile: async (sandbox, path, runCommand) => {
|
|
147
|
+
const arg = escapeShellArg(path);
|
|
148
|
+
const result = await runCommand(sandbox, `test -f "${arg}" && base64 < "${arg}" | tr -d '\\n'`);
|
|
149
|
+
if (result.exitCode !== 0) throw new Error(`File not found or unreadable: ${path}`);
|
|
150
|
+
return Buffer.from(result.stdout, "base64").toString("utf8");
|
|
151
|
+
},
|
|
152
|
+
writeFile: async (sandbox, path, content, runCommand) => {
|
|
153
|
+
const arg = escapeShellArg(path);
|
|
154
|
+
const encoded = Buffer.from(content).toString("base64");
|
|
155
|
+
const result = await runCommand(sandbox, `echo "${encoded}" | base64 -d > "${arg}"`);
|
|
156
|
+
if (result.exitCode !== 0) throw new Error(`Failed to write file ${path}: ${result.stderr}`);
|
|
157
|
+
},
|
|
158
|
+
mkdir: async (sandbox, path, runCommand) => {
|
|
159
|
+
const result = await runCommand(sandbox, `mkdir -p "${escapeShellArg(path)}"`);
|
|
160
|
+
if (result.exitCode !== 0) throw new Error(`Failed to create directory ${path}: ${result.stderr}`);
|
|
161
|
+
},
|
|
162
|
+
readdir: async (sandbox, path, runCommand) => {
|
|
163
|
+
const result = await runCommand(sandbox, `ls -la "${escapeShellArg(path)}"`);
|
|
164
|
+
if (result.exitCode !== 0) throw new Error(`Failed to list directory ${path}: ${result.stderr}`);
|
|
165
|
+
return (result.stdout || "").split("\n").filter((line) => line.trim() && !line.startsWith("total")).map((line) => {
|
|
166
|
+
const parts = line.trim().split(/\s+/);
|
|
167
|
+
const name = parts.slice(8).join(" ");
|
|
168
|
+
const isDirectory = line.startsWith("d");
|
|
169
|
+
return {
|
|
170
|
+
name,
|
|
171
|
+
type: isDirectory ? "directory" : "file",
|
|
172
|
+
size: parseInt(parts[4]) || 0,
|
|
173
|
+
modified: /* @__PURE__ */ new Date()
|
|
174
|
+
};
|
|
175
|
+
}).filter((entry) => entry.name && entry.name !== "." && entry.name !== "..");
|
|
176
|
+
},
|
|
177
|
+
exists: async (sandbox, path, runCommand) => {
|
|
178
|
+
const result = await runCommand(sandbox, `test -e "${escapeShellArg(path)}"`);
|
|
179
|
+
return result.exitCode === 0;
|
|
180
|
+
},
|
|
181
|
+
remove: async (sandbox, path, runCommand) => {
|
|
182
|
+
const result = await runCommand(sandbox, `rm -rf "${escapeShellArg(path)}"`);
|
|
183
|
+
if (result.exitCode !== 0) throw new Error(`Failed to remove ${path}: ${result.stderr}`);
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
getInstance: (sandbox) => sandbox
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
7
190
|
export {
|
|
8
191
|
railway
|
|
9
192
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Railway package placeholder.\n *\n * Railway support previously depended on the hosted control-plane transport,\n * which has been removed from computesdk.\n */\n\n/**\n * Railway configuration (kept for compile-time compatibility of callers).\n */\nexport interface RailwayConfig {\n /** Railway API key */\n apiKey?: string;\n /** Railway project ID */\n projectId?: string;\n /** Railway environment ID */\n environmentId?: string;\n}\n\n/**\n * Railway provider entrypoint.\n *\n * This package no longer provides a direct provider implementation.\n */\nexport function railway(_config: RailwayConfig): never {\n throw new Error(\n '@computesdk/railway is no longer supported after control-plane removal. ' +\n 'Use a direct provider package (for example @computesdk/e2b, @computesdk/modal, @computesdk/vercel, or @computesdk/daytona) with computesdk provider/providers config.'\n );\n}\n"],"mappings":";AAwBO,SAAS,QAAQ,SAA+B;AACrD,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Railway Provider - Factory-based Implementation\n *\n * Wraps Railway Sandboxes (https://docs.railway.com/sandboxes) using the\n * ComputeSDK provider factory. Railway exposes command execution via\n * `sandbox.exec`; it has no dedicated filesystem or port-exposure API, so the\n * filesystem block is implemented over the shell and `getUrl` throws.\n */\n\nimport { Sandbox, SandboxNotFoundError } from 'railway';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\n\nimport type { CommandResult, RunCommandOptions, SandboxInfo } from '@computesdk/provider';\nimport type { CreateSandboxOptions, FileEntry } from 'computesdk';\n\ntype RailwaySandbox = Sandbox;\n\ntype CommandRunner = (\n sandbox: RailwaySandbox,\n command: string,\n options?: RunCommandOptions\n) => Promise<CommandResult>;\n\n/**\n * Railway-specific configuration options\n */\nexport interface RailwayConfig {\n /** Railway API token - falls back to the RAILWAY_API_TOKEN environment variable */\n token?: string;\n /** Railway environment ID - falls back to the RAILWAY_ENVIRONMENT_ID environment variable */\n environmentId?: string;\n}\n\n/** Options accepted by the Railway SDK's create/connect/list calls. */\ninterface RailwayClientOptions {\n token: string;\n environmentId?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 300000;\n\n/**\n * Resolve and validate credentials, falling back to environment variables.\n * Throws a helpful error when the token is missing.\n */\nfunction resolveClientOptions(config: RailwayConfig): RailwayClientOptions {\n const token =\n config.token || (typeof process !== 'undefined' ? process.env?.RAILWAY_API_TOKEN : undefined);\n\n if (!token) {\n throw new Error(\n 'Missing Railway API token.\\n\\n' +\n 'Create a token at https://railway.com/account/tokens\\n' +\n \"Then pass it: railway({ token: 'xxx' })\\n\" +\n 'Or set RAILWAY_API_TOKEN in your environment.'\n );\n }\n\n const environmentId =\n config.environmentId ||\n (typeof process !== 'undefined' ? process.env?.RAILWAY_ENVIRONMENT_ID : undefined);\n\n return { token, environmentId };\n}\n\n/** Map Railway's sandbox status onto the ComputeSDK status enum. */\nfunction mapStatus(status: string): SandboxInfo['status'] {\n switch (status) {\n case 'RUNNING':\n case 'CREATING':\n return 'running';\n case 'DESTROYING':\n case 'DESTROYED':\n return 'stopped';\n case 'FAILED':\n return 'error';\n default:\n return 'running';\n }\n}\n\n/** Valid POSIX shell environment variable name. Keys cannot be quoted in an\n * assignment prefix, so anything outside this set is rejected rather than escaped. */\nconst ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\n/** Apply env/cwd/background options by composing a single shell command string. */\nfunction composeCommand(command: string, options?: RunCommandOptions): string {\n let fullCommand = command;\n\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env)\n .map(([k, v]) => {\n if (!ENV_KEY_PATTERN.test(k)) {\n throw new Error(\n `Invalid environment variable name \"${k}\". Names must match ${ENV_KEY_PATTERN}.`\n );\n }\n return `${k}=\"${escapeShellArg(String(v))}\"`;\n })\n .join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n\n if (options?.cwd) {\n fullCommand = `cd \"${escapeShellArg(options.cwd)}\" && ${fullCommand}`;\n }\n\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n return fullCommand;\n}\n\nexport const railway = defineProvider<RailwaySandbox, RailwayConfig>({\n name: 'railway',\n methods: {\n sandbox: {\n create: async (config: RailwayConfig, options?: CreateSandboxOptions) => {\n const client = resolveClientOptions(config);\n\n try {\n const sandbox = await Sandbox.create({\n token: client.token,\n environmentId: client.environmentId,\n ...(options?.envs ? { env: options.envs } : {}),\n ...(options?.idleTimeoutMinutes !== undefined\n ? { idleTimeoutMinutes: options.idleTimeoutMinutes }\n : {}),\n ...(options?.networkIsolation !== undefined\n ? { networkIsolation: options.networkIsolation }\n : {}),\n });\n\n return { sandbox, sandboxId: sandbox.id };\n } catch (error) {\n throw new Error(\n `Failed to create Railway sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: RailwayConfig, sandboxId: string) => {\n const client = resolveClientOptions(config);\n try {\n const sandbox = await Sandbox.connect(sandboxId, client);\n return { sandbox, sandboxId };\n } catch (error) {\n // Only a missing sandbox maps to null; surface auth/network/config errors.\n if (error instanceof SandboxNotFoundError) return null;\n throw error;\n }\n },\n\n list: async (config: RailwayConfig) => {\n const client = resolveClientOptions(config);\n try {\n const infos = await Sandbox.list(client);\n const connected = await Promise.allSettled(\n infos.map(async (info) => {\n const sandbox = await Sandbox.connect(info.id, client);\n return { sandbox, sandboxId: info.id };\n })\n );\n return connected\n .filter(\n (r): r is PromiseFulfilledResult<{ sandbox: RailwaySandbox; sandboxId: string }> =>\n r.status === 'fulfilled'\n )\n .map((r) => r.value);\n } catch {\n return [];\n }\n },\n\n destroy: async (config: RailwayConfig, sandboxId: string) => {\n const client = resolveClientOptions(config);\n try {\n const sandbox = await Sandbox.connect(sandboxId, client);\n await sandbox.destroy();\n } catch {\n /* already destroyed or unreachable */\n }\n },\n\n runCommand: async (\n sandbox: RailwaySandbox,\n command: string,\n options?: RunCommandOptions\n ): Promise<CommandResult> => {\n const startTime = Date.now();\n const fullCommand = composeCommand(command, options);\n const timeoutSec = options?.timeout ? Math.ceil(options.timeout / 1000) : undefined;\n\n try {\n const result = await sandbox.exec(\n fullCommand,\n timeoutSec ? { timeoutSec } : undefined\n );\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n // exitCode is null when a signal ended the command; surface as -1\n exitCode: result.exitCode ?? -1,\n durationMs: Date.now() - startTime,\n };\n } catch (error) {\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127,\n durationMs: Date.now() - startTime,\n };\n }\n },\n\n getInfo: async (sandbox: RailwaySandbox): Promise<SandboxInfo> => ({\n id: sandbox.id,\n provider: 'railway',\n status: mapStatus(sandbox.status),\n createdAt: new Date(sandbox.createdAt),\n timeout: DEFAULT_TIMEOUT_MS,\n metadata: { networkIsolation: sandbox.networkIsolation },\n }),\n\n getUrl: async (_sandbox: RailwaySandbox, _options: { port: number; protocol?: string }): Promise<string> => {\n throw new Error(\n 'Railway sandboxes do not support exposing ports / public URLs. ' +\n 'Use sandbox-to-sandbox networking within a Railway environment instead.'\n );\n },\n\n filesystem: {\n readFile: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<string> => {\n const arg = escapeShellArg(path);\n const result = await runCommand(sandbox, `test -f \"${arg}\" && base64 < \"${arg}\" | tr -d '\\\\n'`);\n if (result.exitCode !== 0) throw new Error(`File not found or unreadable: ${path}`);\n return Buffer.from(result.stdout, 'base64').toString('utf8');\n },\n\n writeFile: async (sandbox: RailwaySandbox, path: string, content: string, runCommand: CommandRunner): Promise<void> => {\n const arg = escapeShellArg(path);\n const encoded = Buffer.from(content).toString('base64');\n const result = await runCommand(sandbox, `echo \"${encoded}\" | base64 -d > \"${arg}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to write file ${path}: ${result.stderr}`);\n },\n\n mkdir: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<void> => {\n const result = await runCommand(sandbox, `mkdir -p \"${escapeShellArg(path)}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to create directory ${path}: ${result.stderr}`);\n },\n\n readdir: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<FileEntry[]> => {\n const result = await runCommand(sandbox, `ls -la \"${escapeShellArg(path)}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to list directory ${path}: ${result.stderr}`);\n\n return (result.stdout || '')\n .split('\\n')\n .filter((line) => line.trim() && !line.startsWith('total'))\n .map((line) => {\n // `ls -la` columns: perms links owner group size month day time name…\n // The name is everything from the 9th column on, so it survives spaces.\n const parts = line.trim().split(/\\s+/);\n const name = parts.slice(8).join(' ');\n const isDirectory = line.startsWith('d');\n return {\n name,\n type: isDirectory ? ('directory' as const) : ('file' as const),\n size: parseInt(parts[4]) || 0,\n modified: new Date(),\n };\n })\n .filter((entry) => entry.name && entry.name !== '.' && entry.name !== '..');\n },\n\n exists: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<boolean> => {\n const result = await runCommand(sandbox, `test -e \"${escapeShellArg(path)}\"`);\n return result.exitCode === 0;\n },\n\n remove: async (sandbox: RailwaySandbox, path: string, runCommand: CommandRunner): Promise<void> => {\n const result = await runCommand(sandbox, `rm -rf \"${escapeShellArg(path)}\"`);\n if (result.exitCode !== 0) throw new Error(`Failed to remove ${path}: ${result.stderr}`);\n },\n },\n\n getInstance: (sandbox: RailwaySandbox): RailwaySandbox => sandbox,\n },\n },\n});\n\nexport type { Sandbox as RailwaySandbox } from 'railway';\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@computesdk/railway",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Railway provider for ComputeSDK -
|
|
5
|
-
"author": "ComputeSDK
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Railway Sandboxes provider for ComputeSDK - run commands in Railway-hosted sandboxes",
|
|
5
|
+
"author": "ComputeSDK",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
7
10
|
"main": "./dist/index.js",
|
|
8
11
|
"module": "./dist/index.mjs",
|
|
9
12
|
"types": "./dist/index.d.ts",
|
|
@@ -18,8 +21,9 @@
|
|
|
18
21
|
"dist"
|
|
19
22
|
],
|
|
20
23
|
"dependencies": {
|
|
21
|
-
"
|
|
22
|
-
"computesdk": "
|
|
24
|
+
"railway": "^3.1.1",
|
|
25
|
+
"@computesdk/provider": "2.1.3",
|
|
26
|
+
"computesdk": "4.1.3"
|
|
23
27
|
},
|
|
24
28
|
"keywords": [
|
|
25
29
|
"computesdk",
|
|
@@ -28,9 +32,7 @@
|
|
|
28
32
|
"code-execution",
|
|
29
33
|
"cloud",
|
|
30
34
|
"compute",
|
|
31
|
-
"
|
|
32
|
-
"provider",
|
|
33
|
-
"deployment"
|
|
35
|
+
"provider"
|
|
34
36
|
],
|
|
35
37
|
"repository": {
|
|
36
38
|
"type": "git",
|