@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @computesdk/railway
2
2
 
3
- Railway provider for ComputeSDK that enables creating and managing containerized sandboxes on Railway's infrastructure.
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
- ## Configuration
11
+ > **Requires Node.js >= 22** — the underlying `railway` SDK depends on Node 22 APIs (e.g. global `WebSocket`).
12
+
13
+ ## Setup
12
14
 
13
- The Railway provider requires the following environment variables:
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
- RAILWAY_API_KEY=your_railway_api_key
17
- RAILWAY_PROJECT_ID=your_railway_project_id
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
- ### Gateway Mode (Recommended)
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
- console.log(`Created sandbox: ${sandbox.sandboxId}`);
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
- ### Direct Mode
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 compute = railway({
45
- apiKey: process.env.RAILWAY_API_KEY,
46
- projectId: process.env.RAILWAY_PROJECT_ID,
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
- const sandbox = await compute.sandbox.create();
51
- console.log(`Created sandbox: ${sandbox.sandboxId}`);
56
+ ## Configuration
52
57
 
53
- await sandbox.destroy();
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
- ## Currently Implemented
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
- ### Sandbox Operations
59
- - **create()** - Creates a new Railway service with Docker container deployment
60
- - **destroy()** - Deletes a Railway service
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
- ### Supported Runtimes
63
- - **node** - Uses `node:alpine` Docker image
64
- - **python** - Uses `python:alpine` Docker image (default)
87
+ ## Limitations
65
88
 
66
- ### Configuration Options
67
- - **apiKey** - Railway API authentication token
68
- - **projectId** - Railway project identifier
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
- ## Notes
93
+ ## License
72
94
 
73
- - Services are automatically deployed upon creation
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 package placeholder.
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 key */
12
- apiKey?: string;
13
- /** Railway project ID */
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 package placeholder.
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 key */
12
- apiKey?: string;
13
- /** Railway project ID */
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
- function railway(_config) {
27
- throw new Error(
28
- "@computesdk/railway is no longer supported after control-plane removal. Use a direct provider package (for example @computesdk/e2b, @computesdk/modal, @computesdk/vercel, or @computesdk/daytona) with computesdk provider/providers config."
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
- function railway(_config) {
3
- throw new Error(
4
- "@computesdk/railway is no longer supported after control-plane removal. Use a direct provider package (for example @computesdk/e2b, @computesdk/modal, @computesdk/vercel, or @computesdk/daytona) with computesdk provider/providers config."
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
  };
@@ -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": "1.2.2",
4
- "description": "Railway provider for ComputeSDK - simple cloud deployment for containerized sandboxes",
5
- "author": "ComputeSDK Team",
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
- "@computesdk/provider": "2.0.0",
22
- "computesdk": "4.0.0"
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
- "containers",
32
- "provider",
33
- "deployment"
35
+ "provider"
34
36
  ],
35
37
  "repository": {
36
38
  "type": "git",