@computesdk/runloop 1.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/LICENSE +21 -0
- package/dist/index.d.mts +59 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +385 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +360 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 computesdk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as computesdk from 'computesdk';
|
|
2
|
+
import { Runloop } from '@runloop/api-client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Runloop-specific configuration options
|
|
6
|
+
*/
|
|
7
|
+
interface RunloopConfig {
|
|
8
|
+
/** Runloop API key - if not provided, will fallback to RUNLOOP_API_KEY environment variable */
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
/** Execution timeout in milliseconds */
|
|
11
|
+
timeout?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Runloop-specific blueprint creation options
|
|
15
|
+
*/
|
|
16
|
+
interface CreateBlueprintTemplateOptions {
|
|
17
|
+
/** Name of the blueprint template */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Custom Dockerfile content */
|
|
20
|
+
dockerfile?: string;
|
|
21
|
+
/** System setup commands to run during blueprint creation */
|
|
22
|
+
systemSetupCommands?: string[];
|
|
23
|
+
/** Launch commands to run when starting a devbox from this blueprint */
|
|
24
|
+
launchCommands?: string[];
|
|
25
|
+
/** File mounts as key-value pairs (path -> content) */
|
|
26
|
+
fileMounts?: Record<string, string>;
|
|
27
|
+
/** Code repository mounts */
|
|
28
|
+
codeMounts?: Array<{
|
|
29
|
+
repoName: string;
|
|
30
|
+
repoOwner: string;
|
|
31
|
+
token?: string;
|
|
32
|
+
installCommand?: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** Resource size for devboxes created from this blueprint */
|
|
35
|
+
resourceSize?: "X_SMALL" | "SMALL" | "MEDIUM" | "LARGE" | "X_LARGE" | "XX_LARGE" | "CUSTOM_SIZE";
|
|
36
|
+
/** CPU architecture */
|
|
37
|
+
architecture?: "x86_64" | "arm64";
|
|
38
|
+
/** Custom CPU cores (requires CUSTOM_SIZE) */
|
|
39
|
+
customCpuCores?: number;
|
|
40
|
+
/** Custom memory in GB (requires CUSTOM_SIZE) */
|
|
41
|
+
customMemoryGb?: number;
|
|
42
|
+
/** Custom disk size (requires CUSTOM_SIZE) */
|
|
43
|
+
customDiskSize?: number;
|
|
44
|
+
/** Available ports for the devbox */
|
|
45
|
+
availablePorts?: number[];
|
|
46
|
+
/** Action to take when devbox is idle */
|
|
47
|
+
afterIdle?: {
|
|
48
|
+
action: string;
|
|
49
|
+
timeSeconds: number;
|
|
50
|
+
};
|
|
51
|
+
/** Keep alive time in seconds */
|
|
52
|
+
keepAliveTimeSeconds?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create a Runloop provider instance using the factory pattern
|
|
56
|
+
*/
|
|
57
|
+
declare const runloop: (config: RunloopConfig) => computesdk.Provider<Runloop.Devboxes.DevboxView, Runloop.Blueprints.BlueprintView, Runloop.Devboxes.DevboxSnapshotView>;
|
|
58
|
+
|
|
59
|
+
export { type CreateBlueprintTemplateOptions, type RunloopConfig, runloop };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as computesdk from 'computesdk';
|
|
2
|
+
import { Runloop } from '@runloop/api-client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Runloop-specific configuration options
|
|
6
|
+
*/
|
|
7
|
+
interface RunloopConfig {
|
|
8
|
+
/** Runloop API key - if not provided, will fallback to RUNLOOP_API_KEY environment variable */
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
/** Execution timeout in milliseconds */
|
|
11
|
+
timeout?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Runloop-specific blueprint creation options
|
|
15
|
+
*/
|
|
16
|
+
interface CreateBlueprintTemplateOptions {
|
|
17
|
+
/** Name of the blueprint template */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Custom Dockerfile content */
|
|
20
|
+
dockerfile?: string;
|
|
21
|
+
/** System setup commands to run during blueprint creation */
|
|
22
|
+
systemSetupCommands?: string[];
|
|
23
|
+
/** Launch commands to run when starting a devbox from this blueprint */
|
|
24
|
+
launchCommands?: string[];
|
|
25
|
+
/** File mounts as key-value pairs (path -> content) */
|
|
26
|
+
fileMounts?: Record<string, string>;
|
|
27
|
+
/** Code repository mounts */
|
|
28
|
+
codeMounts?: Array<{
|
|
29
|
+
repoName: string;
|
|
30
|
+
repoOwner: string;
|
|
31
|
+
token?: string;
|
|
32
|
+
installCommand?: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** Resource size for devboxes created from this blueprint */
|
|
35
|
+
resourceSize?: "X_SMALL" | "SMALL" | "MEDIUM" | "LARGE" | "X_LARGE" | "XX_LARGE" | "CUSTOM_SIZE";
|
|
36
|
+
/** CPU architecture */
|
|
37
|
+
architecture?: "x86_64" | "arm64";
|
|
38
|
+
/** Custom CPU cores (requires CUSTOM_SIZE) */
|
|
39
|
+
customCpuCores?: number;
|
|
40
|
+
/** Custom memory in GB (requires CUSTOM_SIZE) */
|
|
41
|
+
customMemoryGb?: number;
|
|
42
|
+
/** Custom disk size (requires CUSTOM_SIZE) */
|
|
43
|
+
customDiskSize?: number;
|
|
44
|
+
/** Available ports for the devbox */
|
|
45
|
+
availablePorts?: number[];
|
|
46
|
+
/** Action to take when devbox is idle */
|
|
47
|
+
afterIdle?: {
|
|
48
|
+
action: string;
|
|
49
|
+
timeSeconds: number;
|
|
50
|
+
};
|
|
51
|
+
/** Keep alive time in seconds */
|
|
52
|
+
keepAliveTimeSeconds?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create a Runloop provider instance using the factory pattern
|
|
56
|
+
*/
|
|
57
|
+
declare const runloop: (config: RunloopConfig) => computesdk.Provider<Runloop.Devboxes.DevboxView, Runloop.Blueprints.BlueprintView, Runloop.Devboxes.DevboxSnapshotView>;
|
|
58
|
+
|
|
59
|
+
export { type CreateBlueprintTemplateOptions, type RunloopConfig, runloop };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
runloop: () => runloop
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var import_api_client = require("@runloop/api-client");
|
|
27
|
+
var import_computesdk = require("computesdk");
|
|
28
|
+
var runloop = (0, import_computesdk.createProvider)({
|
|
29
|
+
name: "runloop",
|
|
30
|
+
methods: {
|
|
31
|
+
sandbox: {
|
|
32
|
+
// Collection operations (map to compute.sandbox.*)
|
|
33
|
+
create: async (config, options) => {
|
|
34
|
+
const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.RUNLOOP_API_KEY || "";
|
|
35
|
+
if (!apiKey) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Missing Runloop API key. Provide 'apiKey' in config or set RUNLOOP_API_KEY environment variable. Get your API key from https://runloop.ai/`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
const timeout = config.timeout;
|
|
41
|
+
try {
|
|
42
|
+
const client = new import_api_client.Runloop({
|
|
43
|
+
bearerToken: apiKey
|
|
44
|
+
});
|
|
45
|
+
let devboxParams = {
|
|
46
|
+
launch_parameters: {
|
|
47
|
+
keep_alive_time_seconds: timeout || options?.timeout || 3e5
|
|
48
|
+
},
|
|
49
|
+
name: options?.sandboxId,
|
|
50
|
+
metadata: options?.metadata,
|
|
51
|
+
environment_variables: options?.envs
|
|
52
|
+
};
|
|
53
|
+
if (options?.templateId) {
|
|
54
|
+
const templateId = options?.templateId;
|
|
55
|
+
if (templateId?.startsWith("bpt_")) {
|
|
56
|
+
devboxParams.blueprint_id = templateId;
|
|
57
|
+
} else if (templateId?.startsWith("snp_")) {
|
|
58
|
+
devboxParams.snapshot_id = templateId;
|
|
59
|
+
} else {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const dbx = await client.devboxes.createAndAwaitRunning(devboxParams);
|
|
63
|
+
return {
|
|
64
|
+
sandbox: dbx,
|
|
65
|
+
sandboxId: dbx.id
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Failed to create Runloop devbox: ${error instanceof Error ? error.message : String(error)}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
getById: async (config, sandboxId) => {
|
|
74
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
75
|
+
try {
|
|
76
|
+
const client = new import_api_client.Runloop({
|
|
77
|
+
bearerToken: apiKey
|
|
78
|
+
});
|
|
79
|
+
const devbox = await client.devboxes.retrieve(sandboxId);
|
|
80
|
+
return {
|
|
81
|
+
sandbox: devbox,
|
|
82
|
+
sandboxId
|
|
83
|
+
};
|
|
84
|
+
} catch (error) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
list: async (config) => {
|
|
89
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
90
|
+
try {
|
|
91
|
+
const client = new import_api_client.Runloop({
|
|
92
|
+
bearerToken: apiKey
|
|
93
|
+
});
|
|
94
|
+
const response = await client.devboxes.list();
|
|
95
|
+
const devboxes = response.devboxes || [];
|
|
96
|
+
return devboxes.map((devbox) => ({
|
|
97
|
+
sandbox: devbox,
|
|
98
|
+
sandboxId: devbox.id
|
|
99
|
+
}));
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
destroy: async (config, sandboxId) => {
|
|
105
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
106
|
+
try {
|
|
107
|
+
const client = new import_api_client.Runloop({
|
|
108
|
+
bearerToken: apiKey
|
|
109
|
+
});
|
|
110
|
+
await client.devboxes.shutdown(sandboxId);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
// Instance operations (map to individual Sandbox methods)
|
|
115
|
+
runCode: async (_sandbox, _code) => {
|
|
116
|
+
throw new Error("Please use runCommand instead");
|
|
117
|
+
},
|
|
118
|
+
runCommand: async (sandbox, command, args = []) => {
|
|
119
|
+
const startTime = Date.now();
|
|
120
|
+
const { devbox, client } = sandbox;
|
|
121
|
+
try {
|
|
122
|
+
const execution = await client.devboxes.executeAsync(devbox.id, {
|
|
123
|
+
command: `${command} ${args.join(" ")}`
|
|
124
|
+
});
|
|
125
|
+
const executionResult = await client.devboxes.executions.awaitCompleted(
|
|
126
|
+
devbox.id,
|
|
127
|
+
execution.execution_id
|
|
128
|
+
);
|
|
129
|
+
return {
|
|
130
|
+
stdout: executionResult.stdout || "",
|
|
131
|
+
stderr: executionResult.stderr || "",
|
|
132
|
+
exitCode: executionResult.exit_status || 0,
|
|
133
|
+
executionTime: Date.now() - startTime,
|
|
134
|
+
sandboxId: devbox.id || "runloop-unknown",
|
|
135
|
+
provider: "runloop"
|
|
136
|
+
};
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (error instanceof Error && error.message.includes("Syntax error")) {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Runloop execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
getInfo: async (sandbox) => {
|
|
147
|
+
const devbox = sandbox;
|
|
148
|
+
return {
|
|
149
|
+
id: devbox.id || "runloop-unknown",
|
|
150
|
+
provider: "runloop",
|
|
151
|
+
runtime: "node",
|
|
152
|
+
// Runloop supports multiple runtimes, defaulting to node
|
|
153
|
+
status: devbox.status,
|
|
154
|
+
createdAt: new Date(devbox.create_time_ms || Date.now()),
|
|
155
|
+
timeout: devbox.launch_parameters.keep_alive_time_seconds || 3e5,
|
|
156
|
+
metadata: {
|
|
157
|
+
runloopDevboxId: devbox.id,
|
|
158
|
+
templateId: devbox.blueprint_id || devbox.snapshot_id,
|
|
159
|
+
...devbox.metadata
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
getUrl: async (sandbox, options) => {
|
|
164
|
+
const { devbox, client } = sandbox;
|
|
165
|
+
try {
|
|
166
|
+
const tunnel = await client.devboxes.createTunnel(devbox.id, {
|
|
167
|
+
port: options.port
|
|
168
|
+
});
|
|
169
|
+
return tunnel.url;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`Failed to get Runloop URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
// Optional filesystem methods - using Runloop's file operations
|
|
177
|
+
filesystem: {
|
|
178
|
+
readFile: async (sandbox, path) => {
|
|
179
|
+
const { devbox, client } = sandbox;
|
|
180
|
+
try {
|
|
181
|
+
const result = await client.devboxes.readFileContents(devbox.id, {
|
|
182
|
+
path
|
|
183
|
+
});
|
|
184
|
+
return result.content || "";
|
|
185
|
+
} catch (error) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
writeFile: async (sandbox, path, content) => {
|
|
192
|
+
const { devbox, client } = sandbox;
|
|
193
|
+
try {
|
|
194
|
+
await client.devboxes.writeFileContents(devbox.id, {
|
|
195
|
+
path,
|
|
196
|
+
content
|
|
197
|
+
});
|
|
198
|
+
} catch (error) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
mkdir: async (sandbox, path, runCommand) => {
|
|
205
|
+
const result = await runCommand(sandbox, "mkdir", ["-p", path]);
|
|
206
|
+
if (result.exitCode !== 0) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`Failed to create directory ${path}: ${result.stderr}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
readdir: async (sandbox, path, runCommand) => {
|
|
213
|
+
const result = await runCommand(sandbox, "ls", ["-la", path]);
|
|
214
|
+
if (result.exitCode !== 0) {
|
|
215
|
+
throw new Error(
|
|
216
|
+
`Failed to list directory ${path}: ${result.stderr}`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const lines = (result.stdout || "").split("\n").filter((line) => line.trim() && !line.startsWith("total"));
|
|
220
|
+
return lines.map((line) => {
|
|
221
|
+
const parts = line.trim().split(/\s+/);
|
|
222
|
+
const name = parts[parts.length - 1];
|
|
223
|
+
const isDirectory = line.startsWith("d");
|
|
224
|
+
return {
|
|
225
|
+
name,
|
|
226
|
+
path: `${path}/${name}`,
|
|
227
|
+
isDirectory,
|
|
228
|
+
size: parseInt(parts[4]) || 0,
|
|
229
|
+
lastModified: /* @__PURE__ */ new Date()
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
},
|
|
233
|
+
exists: async (sandbox, path, runCommand) => {
|
|
234
|
+
const result = await runCommand(sandbox, "test", ["-e", path]);
|
|
235
|
+
return result.exitCode === 0;
|
|
236
|
+
},
|
|
237
|
+
remove: async (sandbox, path, runCommand) => {
|
|
238
|
+
const result = await runCommand(sandbox, "rm", ["-rf", path]);
|
|
239
|
+
if (result.exitCode !== 0) {
|
|
240
|
+
throw new Error(`Failed to remove ${path}: ${result.stderr}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
// Provider-specific typed getInstance method
|
|
245
|
+
getInstance: (sandbox) => {
|
|
246
|
+
return sandbox;
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
// Template management methods using the new factory pattern
|
|
250
|
+
template: {
|
|
251
|
+
create: async (config, options) => {
|
|
252
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
253
|
+
if (!apiKey) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
"Missing Runloop API key for blueprint template creation"
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const client = new import_api_client.Runloop({
|
|
260
|
+
bearerToken: apiKey
|
|
261
|
+
});
|
|
262
|
+
const blueprint = await client.blueprints.create(options);
|
|
263
|
+
return blueprint;
|
|
264
|
+
} catch (error) {
|
|
265
|
+
throw new Error(
|
|
266
|
+
`Failed to create blueprint template: ${error instanceof Error ? error.message : String(error)}`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
list: async (config, options) => {
|
|
271
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
272
|
+
if (!apiKey) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
"Missing Runloop API key for listing blueprint templates"
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
const client = new import_api_client.Runloop({
|
|
279
|
+
bearerToken: apiKey
|
|
280
|
+
});
|
|
281
|
+
const listParams = {};
|
|
282
|
+
if (options?.limit) {
|
|
283
|
+
listParams.limit = options.limit;
|
|
284
|
+
}
|
|
285
|
+
const response = await client.blueprints.list(listParams);
|
|
286
|
+
return response.blueprints || [];
|
|
287
|
+
} catch (error) {
|
|
288
|
+
throw new Error(
|
|
289
|
+
`Failed to list blueprint templates: ${error instanceof Error ? error.message : String(error)}`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
delete: async (config, blueprintId) => {
|
|
294
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
295
|
+
if (!apiKey) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
"Missing Runloop API key for blueprint template deletion"
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
try {
|
|
301
|
+
const client = new import_api_client.Runloop({
|
|
302
|
+
bearerToken: apiKey
|
|
303
|
+
});
|
|
304
|
+
await client.blueprints.delete(blueprintId);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
throw new Error(
|
|
307
|
+
`Failed to delete blueprint template ${blueprintId}: ${error instanceof Error ? error.message : String(error)}`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
// Snapshot management methods using the new factory pattern
|
|
313
|
+
snapshot: {
|
|
314
|
+
create: async (config, sandboxId, options) => {
|
|
315
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
316
|
+
if (!apiKey) {
|
|
317
|
+
throw new Error("Missing Runloop API key for snapshot creation");
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
const client = new import_api_client.Runloop({
|
|
321
|
+
bearerToken: apiKey
|
|
322
|
+
});
|
|
323
|
+
const snapshotParams = {};
|
|
324
|
+
if (options?.name) {
|
|
325
|
+
snapshotParams.name = options.name;
|
|
326
|
+
}
|
|
327
|
+
if (options?.metadata) {
|
|
328
|
+
snapshotParams.metadata = options.metadata;
|
|
329
|
+
}
|
|
330
|
+
const snapshot = await client.devboxes.snapshotDisk(
|
|
331
|
+
sandboxId,
|
|
332
|
+
snapshotParams
|
|
333
|
+
);
|
|
334
|
+
return snapshot;
|
|
335
|
+
} catch (error) {
|
|
336
|
+
throw new Error(
|
|
337
|
+
`Failed to create snapshot for sandbox ${sandboxId}: ${error instanceof Error ? error.message : String(error)}`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
list: async (config, options) => {
|
|
342
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
343
|
+
if (!apiKey) {
|
|
344
|
+
throw new Error("Missing Runloop API key for listing snapshots");
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
347
|
+
const client = new import_api_client.Runloop({
|
|
348
|
+
bearerToken: apiKey
|
|
349
|
+
});
|
|
350
|
+
const listParams = {};
|
|
351
|
+
if (options?.limit) {
|
|
352
|
+
listParams.limit = options.limit;
|
|
353
|
+
}
|
|
354
|
+
const response = await client.devboxes.listDiskSnapshots(listParams);
|
|
355
|
+
return response.snapshots || [];
|
|
356
|
+
} catch (error) {
|
|
357
|
+
throw new Error(
|
|
358
|
+
`Failed to list snapshots: ${error instanceof Error ? error.message : String(error)}`
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
delete: async (config, snapshotId) => {
|
|
363
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
364
|
+
if (!apiKey) {
|
|
365
|
+
throw new Error("Missing Runloop API key for snapshot deletion");
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
const client = new import_api_client.Runloop({
|
|
369
|
+
bearerToken: apiKey
|
|
370
|
+
});
|
|
371
|
+
await client.devboxes.deleteDiskSnapshot(snapshotId);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
throw new Error(
|
|
374
|
+
`Failed to delete snapshot ${snapshotId}: ${error instanceof Error ? error.message : String(error)}`
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
382
|
+
0 && (module.exports = {
|
|
383
|
+
runloop
|
|
384
|
+
});
|
|
385
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Runloop Provider - Factory-based Implementation\n *\n * Full-featured provider with filesystem support using the factory pattern.\n * Reduces ~400 lines of boilerplate to ~100 lines of core logic.\n */\n\nimport { Runloop } from \"@runloop/api-client\";\nimport { createProvider } from \"computesdk\";\nimport type {\n ExecutionResult,\n SandboxInfo,\n CreateSandboxOptions,\n FileEntry,\n CreateSnapshotOptions,\n ListSnapshotsOptions,\n Runtime,\n SandboxStatus,\n Sandbox,\n} from \"computesdk\";\n\n// Define Runloop-specific types\ntype RunloopSnapshot = Runloop.DevboxSnapshotView;\ntype RunloopTemplate = Runloop.BlueprintView;\n\n/**\n * Runloop-specific configuration options\n */\nexport interface RunloopConfig {\n /** Runloop API key - if not provided, will fallback to RUNLOOP_API_KEY environment variable */\n apiKey?: string;\n /** Execution timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * Runloop-specific blueprint creation options\n */\nexport interface CreateBlueprintTemplateOptions {\n /** Name of the blueprint template */\n name: string;\n /** Custom Dockerfile content */\n dockerfile?: string;\n /** System setup commands to run during blueprint creation */\n systemSetupCommands?: string[];\n /** Launch commands to run when starting a devbox from this blueprint */\n launchCommands?: string[];\n /** File mounts as key-value pairs (path -> content) */\n fileMounts?: Record<string, string>;\n /** Code repository mounts */\n codeMounts?: Array<{\n repoName: string;\n repoOwner: string;\n token?: string;\n installCommand?: string;\n }>;\n /** Resource size for devboxes created from this blueprint */\n resourceSize?:\n | \"X_SMALL\"\n | \"SMALL\"\n | \"MEDIUM\"\n | \"LARGE\"\n | \"X_LARGE\"\n | \"XX_LARGE\"\n | \"CUSTOM_SIZE\";\n /** CPU architecture */\n architecture?: \"x86_64\" | \"arm64\";\n /** Custom CPU cores (requires CUSTOM_SIZE) */\n customCpuCores?: number;\n /** Custom memory in GB (requires CUSTOM_SIZE) */\n customMemoryGb?: number;\n /** Custom disk size (requires CUSTOM_SIZE) */\n customDiskSize?: number;\n /** Available ports for the devbox */\n availablePorts?: number[];\n /** Action to take when devbox is idle */\n afterIdle?: { action: string; timeSeconds: number };\n /** Keep alive time in seconds */\n keepAliveTimeSeconds?: number;\n}\n\n/**\n * Create a Runloop provider instance using the factory pattern\n */\nexport const runloop = createProvider<\n Runloop.DevboxView, // TSandbox\n RunloopConfig, // TConfig\n RunloopTemplate, // TTemplate \n RunloopSnapshot // TSnapshot\n>({\n name: \"runloop\",\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: RunloopConfig, options?: CreateSandboxOptions) => {\n // Validate API key\n const apiKey =\n config.apiKey ||\n (typeof process !== \"undefined\" && process.env?.RUNLOOP_API_KEY) ||\n \"\";\n\n if (!apiKey) {\n throw new Error(\n `Missing Runloop API key. Provide 'apiKey' in config or set RUNLOOP_API_KEY environment variable. Get your API key from https://runloop.ai/`\n );\n }\n\n const timeout = config.timeout;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n let devboxParams: Runloop.DevboxCreateParams = {\n launch_parameters: {\n keep_alive_time_seconds: timeout || options?.timeout || 300000,\n },\n name: options?.sandboxId,\n metadata: options?.metadata,\n environment_variables: options?.envs,\n };\n\n // Use blueprint if specified\n if (options?.templateId) {\n const templateId = options?.templateId;\n // Check template prefix to determine parameter type\n if (templateId?.startsWith(\"bpt_\")) {\n devboxParams.blueprint_id = templateId;\n } else if (templateId?.startsWith(\"snp_\")) {\n devboxParams.snapshot_id = templateId;\n } else {\n // empty\n }\n }\n\n const dbx = await client.devboxes.createAndAwaitRunning(devboxParams);\n\n return {\n sandbox: dbx, \n sandboxId: dbx.id,\n };\n } catch (error) {\n throw new Error(\n `Failed to create Runloop devbox: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n getById: async (config: RunloopConfig, sandboxId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const devbox = await client.devboxes.retrieve(sandboxId);\n\n return {\n sandbox: devbox,\n sandboxId,\n };\n } catch (error) {\n // Devbox doesn't exist or can't be accessed\n return null;\n }\n },\n\n list: async (config: RunloopConfig) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const response = await client.devboxes.list();\n const devboxes = response.devboxes || [];\n\n return devboxes.map((devbox) => ({\n sandbox: devbox,\n sandboxId: devbox.id,\n }));\n } catch (error) {\n // Return empty array if listing fails\n return [];\n }\n },\n\n destroy: async (config: RunloopConfig, sandboxId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n await client.devboxes.shutdown(sandboxId);\n } catch (error) {\n // Devbox might already be destroyed or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (_sandbox: any, _code: string): Promise<ExecutionResult> => {\n throw new Error(\"Please use runCommand instead\");\n },\n\n runCommand: async (\n sandbox: any,\n command: string,\n args: string[] = []\n ): Promise<ExecutionResult> => {\n const startTime = Date.now();\n const { devbox, client } = sandbox;\n\n try {\n // Execute code using Runloop's executeAsync\n // Runloop supports all runtimes\n\n const execution = await client.devboxes.executeAsync(devbox.id, {\n command: `${command} ${args.join(\" \")}`,\n });\n\n const executionResult =\n await client.devboxes.executions.awaitCompleted(\n devbox.id,\n execution.execution_id\n );\n\n return {\n stdout: executionResult.stdout || \"\",\n stderr: executionResult.stderr || \"\",\n exitCode: executionResult.exit_status || 0,\n executionTime: Date.now() - startTime,\n sandboxId: devbox.id || \"runloop-unknown\",\n provider: \"runloop\",\n };\n } catch (error) {\n // Re-throw syntax errors\n if (\n error instanceof Error &&\n error.message.includes(\"Syntax error\")\n ) {\n throw error;\n }\n throw new Error(\n `Runloop execution failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n getInfo: async (sandbox): Promise<SandboxInfo> => {\n const devbox = sandbox;\n\n return {\n id: devbox.id || \"runloop-unknown\",\n provider: \"runloop\",\n runtime: \"node\" as Runtime, // Runloop supports multiple runtimes, defaulting to node\n status: devbox.status as SandboxStatus,\n createdAt: new Date(devbox.create_time_ms || Date.now()),\n timeout: devbox.launch_parameters.keep_alive_time_seconds || 300000,\n metadata: {\n runloopDevboxId: devbox.id,\n templateId: devbox.blueprint_id || devbox.snapshot_id,\n ...devbox.metadata,\n },\n };\n },\n\n getUrl: async (\n sandbox: any,\n options: { port: number }\n ): Promise<string> => {\n const { devbox, client } = sandbox;\n\n try {\n const tunnel = await client.devboxes.createTunnel(devbox.id, {\n port: options.port,\n });\n\n return tunnel.url;\n } catch (error) {\n throw new Error(\n `Failed to get Runloop URL for port ${options.port}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n // Optional filesystem methods - using Runloop's file operations\n filesystem: {\n readFile: async (sandbox: any, path: string): Promise<string> => {\n const { devbox, client } = sandbox;\n\n try {\n const result = await client.devboxes.readFileContents(devbox.id, {\n path: path,\n });\n return result.content || \"\";\n } catch (error) {\n throw new Error(\n `Failed to read file ${path}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n writeFile: async (\n sandbox: any,\n path: string,\n content: string\n ): Promise<void> => {\n const { devbox, client } = sandbox;\n\n try {\n await client.devboxes.writeFileContents(devbox.id, {\n path: path,\n content: content,\n });\n } catch (error) {\n throw new Error(\n `Failed to write file ${path}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n mkdir: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<void> => {\n const result = await runCommand(sandbox, \"mkdir\", [\"-p\", path]);\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to create directory ${path}: ${result.stderr}`\n );\n }\n },\n\n readdir: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<FileEntry[]> => {\n const result = await runCommand(sandbox, \"ls\", [\"-la\", path]);\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to list directory ${path}: ${result.stderr}`\n );\n }\n\n const lines = (result.stdout || \"\")\n .split(\"\\n\")\n .filter((line: string) => line.trim() && !line.startsWith(\"total\"));\n\n return lines.map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const name = parts[parts.length - 1];\n const isDirectory = line.startsWith(\"d\");\n\n return {\n name,\n path: `${path}/${name}`,\n isDirectory,\n size: parseInt(parts[4]) || 0,\n lastModified: new Date(),\n };\n });\n },\n\n exists: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<boolean> => {\n const result = await runCommand(sandbox, \"test\", [\"-e\", path]);\n return result.exitCode === 0;\n },\n\n remove: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<void> => {\n const result = await runCommand(sandbox, \"rm\", [\"-rf\", path]);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to remove ${path}: ${result.stderr}`);\n }\n },\n },\n \n // Provider-specific typed getInstance method\n getInstance: (sandbox): Runloop.DevboxView => {\n return sandbox;\n },\n },\n\n // Template management methods using the new factory pattern\n template: {\n create: async (\n config: RunloopConfig,\n options: CreateBlueprintTemplateOptions | Runloop.BlueprintCreateParams\n ) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\n \"Missing Runloop API key for blueprint template creation\"\n );\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const blueprint = await client.blueprints.create(options);\n return blueprint;\n } catch (error) {\n throw new Error(\n `Failed to create blueprint template: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n list: async (config: RunloopConfig, options?: { limit?: number }) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\n \"Missing Runloop API key for listing blueprint templates\"\n );\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const listParams: any = {};\n if (options?.limit) {\n listParams.limit = options.limit;\n }\n\n const response = await client.blueprints.list(listParams);\n return response.blueprints || [];\n } catch (error) {\n throw new Error(\n `Failed to list blueprint templates: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n delete: async (config: RunloopConfig, blueprintId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\n \"Missing Runloop API key for blueprint template deletion\"\n );\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n await client.blueprints.delete(blueprintId);\n } catch (error) {\n throw new Error(\n `Failed to delete blueprint template ${blueprintId}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n },\n\n // Snapshot management methods using the new factory pattern\n snapshot: {\n create: async (\n config: RunloopConfig,\n sandboxId: string,\n options?: CreateSnapshotOptions\n ) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\"Missing Runloop API key for snapshot creation\");\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const snapshotParams: any = {};\n if (options?.name) {\n snapshotParams.name = options.name;\n }\n if (options?.metadata) {\n snapshotParams.metadata = options.metadata;\n }\n\n const snapshot = await client.devboxes.snapshotDisk(\n sandboxId,\n snapshotParams\n );\n return snapshot;\n } catch (error) {\n throw new Error(\n `Failed to create snapshot for sandbox ${sandboxId}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n list: async (\n config: RunloopConfig,\n options?: ListSnapshotsOptions\n ) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\"Missing Runloop API key for listing snapshots\");\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const listParams: any = {};\n if (options?.limit) {\n listParams.limit = options.limit;\n }\n\n const response = await client.devboxes.listDiskSnapshots(listParams);\n return response.snapshots || [];\n } catch (error) {\n throw new Error(\n `Failed to list snapshots: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n delete: async (config: RunloopConfig, snapshotId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\"Missing Runloop API key for snapshot deletion\");\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n await client.devboxes.deleteDiskSnapshot(snapshotId);\n } catch (error) {\n throw new Error(\n `Failed to delete snapshot ${snapshotId}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n },\n },\n});"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { Runloop } from "@runloop/api-client";
|
|
3
|
+
import { createProvider } from "computesdk";
|
|
4
|
+
var runloop = createProvider({
|
|
5
|
+
name: "runloop",
|
|
6
|
+
methods: {
|
|
7
|
+
sandbox: {
|
|
8
|
+
// Collection operations (map to compute.sandbox.*)
|
|
9
|
+
create: async (config, options) => {
|
|
10
|
+
const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.RUNLOOP_API_KEY || "";
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`Missing Runloop API key. Provide 'apiKey' in config or set RUNLOOP_API_KEY environment variable. Get your API key from https://runloop.ai/`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
const timeout = config.timeout;
|
|
17
|
+
try {
|
|
18
|
+
const client = new Runloop({
|
|
19
|
+
bearerToken: apiKey
|
|
20
|
+
});
|
|
21
|
+
let devboxParams = {
|
|
22
|
+
launch_parameters: {
|
|
23
|
+
keep_alive_time_seconds: timeout || options?.timeout || 3e5
|
|
24
|
+
},
|
|
25
|
+
name: options?.sandboxId,
|
|
26
|
+
metadata: options?.metadata,
|
|
27
|
+
environment_variables: options?.envs
|
|
28
|
+
};
|
|
29
|
+
if (options?.templateId) {
|
|
30
|
+
const templateId = options?.templateId;
|
|
31
|
+
if (templateId?.startsWith("bpt_")) {
|
|
32
|
+
devboxParams.blueprint_id = templateId;
|
|
33
|
+
} else if (templateId?.startsWith("snp_")) {
|
|
34
|
+
devboxParams.snapshot_id = templateId;
|
|
35
|
+
} else {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const dbx = await client.devboxes.createAndAwaitRunning(devboxParams);
|
|
39
|
+
return {
|
|
40
|
+
sandbox: dbx,
|
|
41
|
+
sandboxId: dbx.id
|
|
42
|
+
};
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Failed to create Runloop devbox: ${error instanceof Error ? error.message : String(error)}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
getById: async (config, sandboxId) => {
|
|
50
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
51
|
+
try {
|
|
52
|
+
const client = new Runloop({
|
|
53
|
+
bearerToken: apiKey
|
|
54
|
+
});
|
|
55
|
+
const devbox = await client.devboxes.retrieve(sandboxId);
|
|
56
|
+
return {
|
|
57
|
+
sandbox: devbox,
|
|
58
|
+
sandboxId
|
|
59
|
+
};
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
list: async (config) => {
|
|
65
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
66
|
+
try {
|
|
67
|
+
const client = new Runloop({
|
|
68
|
+
bearerToken: apiKey
|
|
69
|
+
});
|
|
70
|
+
const response = await client.devboxes.list();
|
|
71
|
+
const devboxes = response.devboxes || [];
|
|
72
|
+
return devboxes.map((devbox) => ({
|
|
73
|
+
sandbox: devbox,
|
|
74
|
+
sandboxId: devbox.id
|
|
75
|
+
}));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
destroy: async (config, sandboxId) => {
|
|
81
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
82
|
+
try {
|
|
83
|
+
const client = new Runloop({
|
|
84
|
+
bearerToken: apiKey
|
|
85
|
+
});
|
|
86
|
+
await client.devboxes.shutdown(sandboxId);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
// Instance operations (map to individual Sandbox methods)
|
|
91
|
+
runCode: async (_sandbox, _code) => {
|
|
92
|
+
throw new Error("Please use runCommand instead");
|
|
93
|
+
},
|
|
94
|
+
runCommand: async (sandbox, command, args = []) => {
|
|
95
|
+
const startTime = Date.now();
|
|
96
|
+
const { devbox, client } = sandbox;
|
|
97
|
+
try {
|
|
98
|
+
const execution = await client.devboxes.executeAsync(devbox.id, {
|
|
99
|
+
command: `${command} ${args.join(" ")}`
|
|
100
|
+
});
|
|
101
|
+
const executionResult = await client.devboxes.executions.awaitCompleted(
|
|
102
|
+
devbox.id,
|
|
103
|
+
execution.execution_id
|
|
104
|
+
);
|
|
105
|
+
return {
|
|
106
|
+
stdout: executionResult.stdout || "",
|
|
107
|
+
stderr: executionResult.stderr || "",
|
|
108
|
+
exitCode: executionResult.exit_status || 0,
|
|
109
|
+
executionTime: Date.now() - startTime,
|
|
110
|
+
sandboxId: devbox.id || "runloop-unknown",
|
|
111
|
+
provider: "runloop"
|
|
112
|
+
};
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error instanceof Error && error.message.includes("Syntax error")) {
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Runloop execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
getInfo: async (sandbox) => {
|
|
123
|
+
const devbox = sandbox;
|
|
124
|
+
return {
|
|
125
|
+
id: devbox.id || "runloop-unknown",
|
|
126
|
+
provider: "runloop",
|
|
127
|
+
runtime: "node",
|
|
128
|
+
// Runloop supports multiple runtimes, defaulting to node
|
|
129
|
+
status: devbox.status,
|
|
130
|
+
createdAt: new Date(devbox.create_time_ms || Date.now()),
|
|
131
|
+
timeout: devbox.launch_parameters.keep_alive_time_seconds || 3e5,
|
|
132
|
+
metadata: {
|
|
133
|
+
runloopDevboxId: devbox.id,
|
|
134
|
+
templateId: devbox.blueprint_id || devbox.snapshot_id,
|
|
135
|
+
...devbox.metadata
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
getUrl: async (sandbox, options) => {
|
|
140
|
+
const { devbox, client } = sandbox;
|
|
141
|
+
try {
|
|
142
|
+
const tunnel = await client.devboxes.createTunnel(devbox.id, {
|
|
143
|
+
port: options.port
|
|
144
|
+
});
|
|
145
|
+
return tunnel.url;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`Failed to get Runloop URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
// Optional filesystem methods - using Runloop's file operations
|
|
153
|
+
filesystem: {
|
|
154
|
+
readFile: async (sandbox, path) => {
|
|
155
|
+
const { devbox, client } = sandbox;
|
|
156
|
+
try {
|
|
157
|
+
const result = await client.devboxes.readFileContents(devbox.id, {
|
|
158
|
+
path
|
|
159
|
+
});
|
|
160
|
+
return result.content || "";
|
|
161
|
+
} catch (error) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
writeFile: async (sandbox, path, content) => {
|
|
168
|
+
const { devbox, client } = sandbox;
|
|
169
|
+
try {
|
|
170
|
+
await client.devboxes.writeFileContents(devbox.id, {
|
|
171
|
+
path,
|
|
172
|
+
content
|
|
173
|
+
});
|
|
174
|
+
} catch (error) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
mkdir: async (sandbox, path, runCommand) => {
|
|
181
|
+
const result = await runCommand(sandbox, "mkdir", ["-p", path]);
|
|
182
|
+
if (result.exitCode !== 0) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Failed to create directory ${path}: ${result.stderr}`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
readdir: async (sandbox, path, runCommand) => {
|
|
189
|
+
const result = await runCommand(sandbox, "ls", ["-la", path]);
|
|
190
|
+
if (result.exitCode !== 0) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`Failed to list directory ${path}: ${result.stderr}`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
const lines = (result.stdout || "").split("\n").filter((line) => line.trim() && !line.startsWith("total"));
|
|
196
|
+
return lines.map((line) => {
|
|
197
|
+
const parts = line.trim().split(/\s+/);
|
|
198
|
+
const name = parts[parts.length - 1];
|
|
199
|
+
const isDirectory = line.startsWith("d");
|
|
200
|
+
return {
|
|
201
|
+
name,
|
|
202
|
+
path: `${path}/${name}`,
|
|
203
|
+
isDirectory,
|
|
204
|
+
size: parseInt(parts[4]) || 0,
|
|
205
|
+
lastModified: /* @__PURE__ */ new Date()
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
exists: async (sandbox, path, runCommand) => {
|
|
210
|
+
const result = await runCommand(sandbox, "test", ["-e", path]);
|
|
211
|
+
return result.exitCode === 0;
|
|
212
|
+
},
|
|
213
|
+
remove: async (sandbox, path, runCommand) => {
|
|
214
|
+
const result = await runCommand(sandbox, "rm", ["-rf", path]);
|
|
215
|
+
if (result.exitCode !== 0) {
|
|
216
|
+
throw new Error(`Failed to remove ${path}: ${result.stderr}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
// Provider-specific typed getInstance method
|
|
221
|
+
getInstance: (sandbox) => {
|
|
222
|
+
return sandbox;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
// Template management methods using the new factory pattern
|
|
226
|
+
template: {
|
|
227
|
+
create: async (config, options) => {
|
|
228
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
229
|
+
if (!apiKey) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
"Missing Runloop API key for blueprint template creation"
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const client = new Runloop({
|
|
236
|
+
bearerToken: apiKey
|
|
237
|
+
});
|
|
238
|
+
const blueprint = await client.blueprints.create(options);
|
|
239
|
+
return blueprint;
|
|
240
|
+
} catch (error) {
|
|
241
|
+
throw new Error(
|
|
242
|
+
`Failed to create blueprint template: ${error instanceof Error ? error.message : String(error)}`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
list: async (config, options) => {
|
|
247
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
248
|
+
if (!apiKey) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
"Missing Runloop API key for listing blueprint templates"
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const client = new Runloop({
|
|
255
|
+
bearerToken: apiKey
|
|
256
|
+
});
|
|
257
|
+
const listParams = {};
|
|
258
|
+
if (options?.limit) {
|
|
259
|
+
listParams.limit = options.limit;
|
|
260
|
+
}
|
|
261
|
+
const response = await client.blueprints.list(listParams);
|
|
262
|
+
return response.blueprints || [];
|
|
263
|
+
} catch (error) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
`Failed to list blueprint templates: ${error instanceof Error ? error.message : String(error)}`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
delete: async (config, blueprintId) => {
|
|
270
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
271
|
+
if (!apiKey) {
|
|
272
|
+
throw new Error(
|
|
273
|
+
"Missing Runloop API key for blueprint template deletion"
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
const client = new Runloop({
|
|
278
|
+
bearerToken: apiKey
|
|
279
|
+
});
|
|
280
|
+
await client.blueprints.delete(blueprintId);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
throw new Error(
|
|
283
|
+
`Failed to delete blueprint template ${blueprintId}: ${error instanceof Error ? error.message : String(error)}`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
// Snapshot management methods using the new factory pattern
|
|
289
|
+
snapshot: {
|
|
290
|
+
create: async (config, sandboxId, options) => {
|
|
291
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
292
|
+
if (!apiKey) {
|
|
293
|
+
throw new Error("Missing Runloop API key for snapshot creation");
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const client = new Runloop({
|
|
297
|
+
bearerToken: apiKey
|
|
298
|
+
});
|
|
299
|
+
const snapshotParams = {};
|
|
300
|
+
if (options?.name) {
|
|
301
|
+
snapshotParams.name = options.name;
|
|
302
|
+
}
|
|
303
|
+
if (options?.metadata) {
|
|
304
|
+
snapshotParams.metadata = options.metadata;
|
|
305
|
+
}
|
|
306
|
+
const snapshot = await client.devboxes.snapshotDisk(
|
|
307
|
+
sandboxId,
|
|
308
|
+
snapshotParams
|
|
309
|
+
);
|
|
310
|
+
return snapshot;
|
|
311
|
+
} catch (error) {
|
|
312
|
+
throw new Error(
|
|
313
|
+
`Failed to create snapshot for sandbox ${sandboxId}: ${error instanceof Error ? error.message : String(error)}`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
list: async (config, options) => {
|
|
318
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
319
|
+
if (!apiKey) {
|
|
320
|
+
throw new Error("Missing Runloop API key for listing snapshots");
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
const client = new Runloop({
|
|
324
|
+
bearerToken: apiKey
|
|
325
|
+
});
|
|
326
|
+
const listParams = {};
|
|
327
|
+
if (options?.limit) {
|
|
328
|
+
listParams.limit = options.limit;
|
|
329
|
+
}
|
|
330
|
+
const response = await client.devboxes.listDiskSnapshots(listParams);
|
|
331
|
+
return response.snapshots || [];
|
|
332
|
+
} catch (error) {
|
|
333
|
+
throw new Error(
|
|
334
|
+
`Failed to list snapshots: ${error instanceof Error ? error.message : String(error)}`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
delete: async (config, snapshotId) => {
|
|
339
|
+
const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY;
|
|
340
|
+
if (!apiKey) {
|
|
341
|
+
throw new Error("Missing Runloop API key for snapshot deletion");
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
const client = new Runloop({
|
|
345
|
+
bearerToken: apiKey
|
|
346
|
+
});
|
|
347
|
+
await client.devboxes.deleteDiskSnapshot(snapshotId);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
throw new Error(
|
|
350
|
+
`Failed to delete snapshot ${snapshotId}: ${error instanceof Error ? error.message : String(error)}`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
export {
|
|
358
|
+
runloop
|
|
359
|
+
};
|
|
360
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Runloop Provider - Factory-based Implementation\n *\n * Full-featured provider with filesystem support using the factory pattern.\n * Reduces ~400 lines of boilerplate to ~100 lines of core logic.\n */\n\nimport { Runloop } from \"@runloop/api-client\";\nimport { createProvider } from \"computesdk\";\nimport type {\n ExecutionResult,\n SandboxInfo,\n CreateSandboxOptions,\n FileEntry,\n CreateSnapshotOptions,\n ListSnapshotsOptions,\n Runtime,\n SandboxStatus,\n Sandbox,\n} from \"computesdk\";\n\n// Define Runloop-specific types\ntype RunloopSnapshot = Runloop.DevboxSnapshotView;\ntype RunloopTemplate = Runloop.BlueprintView;\n\n/**\n * Runloop-specific configuration options\n */\nexport interface RunloopConfig {\n /** Runloop API key - if not provided, will fallback to RUNLOOP_API_KEY environment variable */\n apiKey?: string;\n /** Execution timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * Runloop-specific blueprint creation options\n */\nexport interface CreateBlueprintTemplateOptions {\n /** Name of the blueprint template */\n name: string;\n /** Custom Dockerfile content */\n dockerfile?: string;\n /** System setup commands to run during blueprint creation */\n systemSetupCommands?: string[];\n /** Launch commands to run when starting a devbox from this blueprint */\n launchCommands?: string[];\n /** File mounts as key-value pairs (path -> content) */\n fileMounts?: Record<string, string>;\n /** Code repository mounts */\n codeMounts?: Array<{\n repoName: string;\n repoOwner: string;\n token?: string;\n installCommand?: string;\n }>;\n /** Resource size for devboxes created from this blueprint */\n resourceSize?:\n | \"X_SMALL\"\n | \"SMALL\"\n | \"MEDIUM\"\n | \"LARGE\"\n | \"X_LARGE\"\n | \"XX_LARGE\"\n | \"CUSTOM_SIZE\";\n /** CPU architecture */\n architecture?: \"x86_64\" | \"arm64\";\n /** Custom CPU cores (requires CUSTOM_SIZE) */\n customCpuCores?: number;\n /** Custom memory in GB (requires CUSTOM_SIZE) */\n customMemoryGb?: number;\n /** Custom disk size (requires CUSTOM_SIZE) */\n customDiskSize?: number;\n /** Available ports for the devbox */\n availablePorts?: number[];\n /** Action to take when devbox is idle */\n afterIdle?: { action: string; timeSeconds: number };\n /** Keep alive time in seconds */\n keepAliveTimeSeconds?: number;\n}\n\n/**\n * Create a Runloop provider instance using the factory pattern\n */\nexport const runloop = createProvider<\n Runloop.DevboxView, // TSandbox\n RunloopConfig, // TConfig\n RunloopTemplate, // TTemplate \n RunloopSnapshot // TSnapshot\n>({\n name: \"runloop\",\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: RunloopConfig, options?: CreateSandboxOptions) => {\n // Validate API key\n const apiKey =\n config.apiKey ||\n (typeof process !== \"undefined\" && process.env?.RUNLOOP_API_KEY) ||\n \"\";\n\n if (!apiKey) {\n throw new Error(\n `Missing Runloop API key. Provide 'apiKey' in config or set RUNLOOP_API_KEY environment variable. Get your API key from https://runloop.ai/`\n );\n }\n\n const timeout = config.timeout;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n let devboxParams: Runloop.DevboxCreateParams = {\n launch_parameters: {\n keep_alive_time_seconds: timeout || options?.timeout || 300000,\n },\n name: options?.sandboxId,\n metadata: options?.metadata,\n environment_variables: options?.envs,\n };\n\n // Use blueprint if specified\n if (options?.templateId) {\n const templateId = options?.templateId;\n // Check template prefix to determine parameter type\n if (templateId?.startsWith(\"bpt_\")) {\n devboxParams.blueprint_id = templateId;\n } else if (templateId?.startsWith(\"snp_\")) {\n devboxParams.snapshot_id = templateId;\n } else {\n // empty\n }\n }\n\n const dbx = await client.devboxes.createAndAwaitRunning(devboxParams);\n\n return {\n sandbox: dbx, \n sandboxId: dbx.id,\n };\n } catch (error) {\n throw new Error(\n `Failed to create Runloop devbox: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n getById: async (config: RunloopConfig, sandboxId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const devbox = await client.devboxes.retrieve(sandboxId);\n\n return {\n sandbox: devbox,\n sandboxId,\n };\n } catch (error) {\n // Devbox doesn't exist or can't be accessed\n return null;\n }\n },\n\n list: async (config: RunloopConfig) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const response = await client.devboxes.list();\n const devboxes = response.devboxes || [];\n\n return devboxes.map((devbox) => ({\n sandbox: devbox,\n sandboxId: devbox.id,\n }));\n } catch (error) {\n // Return empty array if listing fails\n return [];\n }\n },\n\n destroy: async (config: RunloopConfig, sandboxId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n await client.devboxes.shutdown(sandboxId);\n } catch (error) {\n // Devbox might already be destroyed or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (_sandbox: any, _code: string): Promise<ExecutionResult> => {\n throw new Error(\"Please use runCommand instead\");\n },\n\n runCommand: async (\n sandbox: any,\n command: string,\n args: string[] = []\n ): Promise<ExecutionResult> => {\n const startTime = Date.now();\n const { devbox, client } = sandbox;\n\n try {\n // Execute code using Runloop's executeAsync\n // Runloop supports all runtimes\n\n const execution = await client.devboxes.executeAsync(devbox.id, {\n command: `${command} ${args.join(\" \")}`,\n });\n\n const executionResult =\n await client.devboxes.executions.awaitCompleted(\n devbox.id,\n execution.execution_id\n );\n\n return {\n stdout: executionResult.stdout || \"\",\n stderr: executionResult.stderr || \"\",\n exitCode: executionResult.exit_status || 0,\n executionTime: Date.now() - startTime,\n sandboxId: devbox.id || \"runloop-unknown\",\n provider: \"runloop\",\n };\n } catch (error) {\n // Re-throw syntax errors\n if (\n error instanceof Error &&\n error.message.includes(\"Syntax error\")\n ) {\n throw error;\n }\n throw new Error(\n `Runloop execution failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n getInfo: async (sandbox): Promise<SandboxInfo> => {\n const devbox = sandbox;\n\n return {\n id: devbox.id || \"runloop-unknown\",\n provider: \"runloop\",\n runtime: \"node\" as Runtime, // Runloop supports multiple runtimes, defaulting to node\n status: devbox.status as SandboxStatus,\n createdAt: new Date(devbox.create_time_ms || Date.now()),\n timeout: devbox.launch_parameters.keep_alive_time_seconds || 300000,\n metadata: {\n runloopDevboxId: devbox.id,\n templateId: devbox.blueprint_id || devbox.snapshot_id,\n ...devbox.metadata,\n },\n };\n },\n\n getUrl: async (\n sandbox: any,\n options: { port: number }\n ): Promise<string> => {\n const { devbox, client } = sandbox;\n\n try {\n const tunnel = await client.devboxes.createTunnel(devbox.id, {\n port: options.port,\n });\n\n return tunnel.url;\n } catch (error) {\n throw new Error(\n `Failed to get Runloop URL for port ${options.port}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n // Optional filesystem methods - using Runloop's file operations\n filesystem: {\n readFile: async (sandbox: any, path: string): Promise<string> => {\n const { devbox, client } = sandbox;\n\n try {\n const result = await client.devboxes.readFileContents(devbox.id, {\n path: path,\n });\n return result.content || \"\";\n } catch (error) {\n throw new Error(\n `Failed to read file ${path}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n writeFile: async (\n sandbox: any,\n path: string,\n content: string\n ): Promise<void> => {\n const { devbox, client } = sandbox;\n\n try {\n await client.devboxes.writeFileContents(devbox.id, {\n path: path,\n content: content,\n });\n } catch (error) {\n throw new Error(\n `Failed to write file ${path}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n mkdir: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<void> => {\n const result = await runCommand(sandbox, \"mkdir\", [\"-p\", path]);\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to create directory ${path}: ${result.stderr}`\n );\n }\n },\n\n readdir: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<FileEntry[]> => {\n const result = await runCommand(sandbox, \"ls\", [\"-la\", path]);\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to list directory ${path}: ${result.stderr}`\n );\n }\n\n const lines = (result.stdout || \"\")\n .split(\"\\n\")\n .filter((line: string) => line.trim() && !line.startsWith(\"total\"));\n\n return lines.map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const name = parts[parts.length - 1];\n const isDirectory = line.startsWith(\"d\");\n\n return {\n name,\n path: `${path}/${name}`,\n isDirectory,\n size: parseInt(parts[4]) || 0,\n lastModified: new Date(),\n };\n });\n },\n\n exists: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<boolean> => {\n const result = await runCommand(sandbox, \"test\", [\"-e\", path]);\n return result.exitCode === 0;\n },\n\n remove: async (\n sandbox: any,\n path: string,\n runCommand: any\n ): Promise<void> => {\n const result = await runCommand(sandbox, \"rm\", [\"-rf\", path]);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to remove ${path}: ${result.stderr}`);\n }\n },\n },\n \n // Provider-specific typed getInstance method\n getInstance: (sandbox): Runloop.DevboxView => {\n return sandbox;\n },\n },\n\n // Template management methods using the new factory pattern\n template: {\n create: async (\n config: RunloopConfig,\n options: CreateBlueprintTemplateOptions | Runloop.BlueprintCreateParams\n ) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\n \"Missing Runloop API key for blueprint template creation\"\n );\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const blueprint = await client.blueprints.create(options);\n return blueprint;\n } catch (error) {\n throw new Error(\n `Failed to create blueprint template: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n list: async (config: RunloopConfig, options?: { limit?: number }) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\n \"Missing Runloop API key for listing blueprint templates\"\n );\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const listParams: any = {};\n if (options?.limit) {\n listParams.limit = options.limit;\n }\n\n const response = await client.blueprints.list(listParams);\n return response.blueprints || [];\n } catch (error) {\n throw new Error(\n `Failed to list blueprint templates: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n delete: async (config: RunloopConfig, blueprintId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\n \"Missing Runloop API key for blueprint template deletion\"\n );\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n await client.blueprints.delete(blueprintId);\n } catch (error) {\n throw new Error(\n `Failed to delete blueprint template ${blueprintId}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n },\n\n // Snapshot management methods using the new factory pattern\n snapshot: {\n create: async (\n config: RunloopConfig,\n sandboxId: string,\n options?: CreateSnapshotOptions\n ) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\"Missing Runloop API key for snapshot creation\");\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const snapshotParams: any = {};\n if (options?.name) {\n snapshotParams.name = options.name;\n }\n if (options?.metadata) {\n snapshotParams.metadata = options.metadata;\n }\n\n const snapshot = await client.devboxes.snapshotDisk(\n sandboxId,\n snapshotParams\n );\n return snapshot;\n } catch (error) {\n throw new Error(\n `Failed to create snapshot for sandbox ${sandboxId}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n list: async (\n config: RunloopConfig,\n options?: ListSnapshotsOptions\n ) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\"Missing Runloop API key for listing snapshots\");\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n const listParams: any = {};\n if (options?.limit) {\n listParams.limit = options.limit;\n }\n\n const response = await client.devboxes.listDiskSnapshots(listParams);\n return response.snapshots || [];\n } catch (error) {\n throw new Error(\n `Failed to list snapshots: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n\n delete: async (config: RunloopConfig, snapshotId: string) => {\n const apiKey = config.apiKey || process.env.RUNLOOP_API_KEY!;\n\n if (!apiKey) {\n throw new Error(\"Missing Runloop API key for snapshot deletion\");\n }\n\n try {\n const client = new Runloop({\n bearerToken: apiKey,\n });\n\n await client.devboxes.deleteDiskSnapshot(snapshotId);\n } catch (error) {\n throw new Error(\n `Failed to delete snapshot ${snapshotId}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n },\n },\n },\n});"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@computesdk/runloop",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Runloop provider for ComputeSDK",
|
|
5
|
+
"author": "Runloop",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.mjs",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.mjs",
|
|
14
|
+
"require": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@runloop/api-client": "^0.44.0",
|
|
22
|
+
"computesdk": "1.7.0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"runloop",
|
|
26
|
+
"sandbox",
|
|
27
|
+
"code-execution",
|
|
28
|
+
"python",
|
|
29
|
+
"node",
|
|
30
|
+
"ai",
|
|
31
|
+
"compute"
|
|
32
|
+
],
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/computesdk/computesdk.git",
|
|
36
|
+
"directory": "packages/runloop"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/computesdk/computesdk/tree/main/packages/runloop",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/computesdk/computesdk/issues"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.0.0",
|
|
44
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
45
|
+
"eslint": "^8.37.0",
|
|
46
|
+
"rimraf": "^5.0.0",
|
|
47
|
+
"tsup": "^8.0.0",
|
|
48
|
+
"typescript": "^5.0.0",
|
|
49
|
+
"vitest": "^1.0.0",
|
|
50
|
+
"@computesdk/test-utils": "1.3.1"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsup",
|
|
54
|
+
"clean": "rimraf dist",
|
|
55
|
+
"dev": "tsup --watch",
|
|
56
|
+
"test": "vitest run",
|
|
57
|
+
"test:watch": "vitest watch",
|
|
58
|
+
"test:coverage": "vitest run --coverage",
|
|
59
|
+
"typecheck": "tsc --noEmit",
|
|
60
|
+
"lint": "eslint"
|
|
61
|
+
}
|
|
62
|
+
}
|