@computesdk/vercel 1.0.0 → 1.1.1

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/dist/index.d.ts CHANGED
@@ -1,21 +1,24 @@
1
- import { ComputeSpecification, SandboxConfig, Runtime, ExecutionResult, SandboxInfo } from 'computesdk';
1
+ import * as computesdk from 'computesdk';
2
+ import { Runtime } from 'computesdk';
2
3
 
3
- declare class VercelProvider implements ComputeSpecification {
4
- readonly specificationVersion: "v1";
5
- readonly provider = "vercel";
6
- readonly sandboxId: string;
7
- private sandbox;
8
- private readonly token;
9
- private readonly teamId;
10
- private readonly projectId;
11
- private readonly runtime;
12
- private readonly timeout;
13
- constructor(config: SandboxConfig);
14
- private ensureSandbox;
15
- doExecute(code: string, runtime?: Runtime): Promise<ExecutionResult>;
16
- doKill(): Promise<void>;
17
- doGetInfo(): Promise<SandboxInfo>;
4
+ /**
5
+ * Vercel-specific configuration options
6
+ */
7
+ interface VercelConfig {
8
+ /** Vercel API token - if not provided, will fallback to VERCEL_TOKEN environment variable */
9
+ token?: string;
10
+ /** Vercel team ID - if not provided, will fallback to VERCEL_TEAM_ID environment variable */
11
+ teamId?: string;
12
+ /** Vercel project ID - if not provided, will fallback to VERCEL_PROJECT_ID environment variable */
13
+ projectId?: string;
14
+ /** Default runtime environment */
15
+ runtime?: Runtime;
16
+ /** Execution timeout in milliseconds */
17
+ timeout?: number;
18
18
  }
19
- declare function vercel(config?: Partial<SandboxConfig>): VercelProvider;
19
+ /**
20
+ * Create a Vercel provider instance using the factory pattern
21
+ */
22
+ declare const vercel: (config: VercelConfig) => computesdk.Provider;
20
23
 
21
- export { VercelProvider, vercel };
24
+ export { type VercelConfig, vercel };
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,222 +15,331 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
31
21
  var index_exports = {};
32
22
  __export(index_exports, {
33
- VercelProvider: () => VercelProvider,
34
23
  vercel: () => vercel
35
24
  });
36
25
  module.exports = __toCommonJS(index_exports);
37
26
  var import_sandbox = require("@vercel/sandbox");
38
- var import_ms = __toESM(require("ms"));
39
- var VercelProvider = class {
40
- constructor(config) {
41
- this.specificationVersion = "v1";
42
- this.provider = "vercel";
43
- this.sandbox = null;
44
- this.sandboxId = `vercel-${Date.now()}-${Math.random().toString(36).substring(7)}`;
45
- this.timeout = config.timeout || 3e5;
46
- this.token = process.env.VERCEL_TOKEN || "";
47
- this.teamId = process.env.VERCEL_TEAM_ID || "";
48
- this.projectId = process.env.VERCEL_PROJECT_ID || "";
49
- if (!this.token) {
50
- throw new Error(
51
- `Missing Vercel token. Set VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`
52
- );
53
- }
54
- if (!this.teamId) {
55
- throw new Error(
56
- `Missing Vercel team ID. Set VERCEL_TEAM_ID environment variable.`
57
- );
58
- }
59
- if (!this.projectId) {
60
- throw new Error(
61
- `Missing Vercel project ID. Set VERCEL_PROJECT_ID environment variable.`
62
- );
63
- }
64
- if (config.runtime && !["node", "python"].includes(config.runtime)) {
65
- throw new Error("Vercel provider only supports Node.js and Python runtimes");
66
- }
67
- this.runtime = config.runtime || "node";
68
- }
69
- async ensureSandbox() {
70
- if (this.sandbox) {
71
- return this.sandbox;
72
- }
73
- try {
74
- const runtimeImage = this.runtime === "node" ? "node22" : "python3.13";
75
- this.sandbox = await import_sandbox.Sandbox.create({
76
- runtime: runtimeImage,
77
- timeout: (0, import_ms.default)(`${this.timeout}ms`),
78
- resources: { vcpus: 2 }
79
- // Default to 2 vCPUs
80
- });
81
- return this.sandbox;
82
- } catch (error) {
83
- if (error instanceof Error) {
84
- if (error.message.includes("unauthorized") || error.message.includes("token")) {
85
- throw new Error(
86
- `Vercel authentication failed. Please check your VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`
87
- );
27
+ var import_computesdk = require("computesdk");
28
+ var vercel = (0, import_computesdk.createProvider)({
29
+ name: "vercel",
30
+ methods: {
31
+ sandbox: {
32
+ // Collection operations (map to compute.sandbox.*)
33
+ create: async (config, options) => {
34
+ const oidcToken = typeof process !== "undefined" && process.env?.VERCEL_OIDC_TOKEN;
35
+ const token = config.token || typeof process !== "undefined" && process.env?.VERCEL_TOKEN || "";
36
+ const teamId = config.teamId || typeof process !== "undefined" && process.env?.VERCEL_TEAM_ID || "";
37
+ const projectId = config.projectId || typeof process !== "undefined" && process.env?.VERCEL_PROJECT_ID || "";
38
+ if (!oidcToken && (!token || !teamId || !projectId)) {
39
+ if (!oidcToken && !token) {
40
+ throw new Error(
41
+ `Missing Vercel authentication. Either:
42
+ 1. Use OIDC token: Run 'vercel env pull' to get VERCEL_OIDC_TOKEN, or
43
+ 2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`
44
+ );
45
+ }
46
+ if (!oidcToken && !teamId) {
47
+ throw new Error(
48
+ `Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID environment variable.`
49
+ );
50
+ }
51
+ if (!oidcToken && !projectId) {
52
+ throw new Error(
53
+ `Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID environment variable.`
54
+ );
55
+ }
88
56
  }
89
- if (error.message.includes("team") || error.message.includes("project")) {
57
+ const runtime = options?.runtime || config.runtime || "node";
58
+ const timeout = config.timeout || 3e5;
59
+ try {
60
+ let sandbox;
61
+ if (options?.sandboxId) {
62
+ throw new Error(
63
+ `Vercel provider does not support reconnecting to existing sandboxes. Vercel sandboxes are ephemeral and must be created fresh each time.`
64
+ );
65
+ } else {
66
+ if (oidcToken) {
67
+ sandbox = await import_sandbox.Sandbox.create();
68
+ } else {
69
+ sandbox = await import_sandbox.Sandbox.create({
70
+ token,
71
+ teamId,
72
+ projectId
73
+ });
74
+ }
75
+ }
76
+ return {
77
+ sandbox,
78
+ sandboxId: sandbox.sandboxId
79
+ };
80
+ } catch (error) {
81
+ if (error instanceof Error) {
82
+ if (error.message.includes("unauthorized") || error.message.includes("token")) {
83
+ throw new Error(
84
+ `Vercel authentication failed. Please check your VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`
85
+ );
86
+ }
87
+ if (error.message.includes("team") || error.message.includes("project")) {
88
+ throw new Error(
89
+ `Vercel team/project configuration failed. Please check your VERCEL_TEAM_ID and VERCEL_PROJECT_ID environment variables.`
90
+ );
91
+ }
92
+ }
90
93
  throw new Error(
91
- `Vercel team/project configuration error. Please check your VERCEL_TEAM_ID and VERCEL_PROJECT_ID environment variables.`
94
+ `Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`
92
95
  );
93
96
  }
94
- if (error.message.includes("Memory limit exceeded")) {
95
- throw new Error(
96
- `Vercel execution failed due to memory limits. Consider optimizing your code or using smaller data sets.`
97
- );
97
+ },
98
+ getById: async (config, sandboxId) => {
99
+ const oidcToken = typeof process !== "undefined" && process.env?.VERCEL_OIDC_TOKEN;
100
+ try {
101
+ let sandbox;
102
+ if (oidcToken) {
103
+ sandbox = await import_sandbox.Sandbox.get({ sandboxId });
104
+ } else {
105
+ const token = config.token || process.env.VERCEL_TOKEN;
106
+ const teamId = config.teamId || process.env.VERCEL_TEAM_ID;
107
+ const projectId = config.projectId || process.env.VERCEL_PROJECT_ID;
108
+ sandbox = await import_sandbox.Sandbox.get({
109
+ sandboxId,
110
+ token,
111
+ teamId,
112
+ projectId
113
+ });
114
+ }
115
+ return {
116
+ sandbox,
117
+ sandboxId
118
+ };
119
+ } catch (error) {
120
+ return null;
98
121
  }
99
- if (error.message.includes("quota") || error.message.includes("limit")) {
122
+ },
123
+ list: async (_config) => {
124
+ throw new Error(
125
+ `Vercel provider does not support listing sandboxes. Vercel sandboxes are ephemeral and designed for single-use execution.`
126
+ );
127
+ },
128
+ destroy: async (config, sandboxId) => {
129
+ const oidcToken = typeof process !== "undefined" && process.env?.VERCEL_OIDC_TOKEN;
130
+ try {
131
+ let sandbox;
132
+ if (oidcToken) {
133
+ sandbox = await import_sandbox.Sandbox.get({ sandboxId });
134
+ } else {
135
+ const token = config.token || process.env.VERCEL_TOKEN;
136
+ const teamId = config.teamId || process.env.VERCEL_TEAM_ID;
137
+ const projectId = config.projectId || process.env.VERCEL_PROJECT_ID;
138
+ sandbox = await import_sandbox.Sandbox.get({
139
+ sandboxId,
140
+ token,
141
+ teamId,
142
+ projectId
143
+ });
144
+ }
145
+ await sandbox.stop();
146
+ } catch (error) {
147
+ }
148
+ },
149
+ // Instance operations (map to individual Sandbox methods)
150
+ runCode: async (sandbox, code, runtime, config) => {
151
+ const startTime = Date.now();
152
+ try {
153
+ const effectiveRuntime = runtime || config?.runtime || // Strong Python indicators
154
+ (code.includes("print(") || code.includes("import ") || code.includes("def ") || code.includes("sys.") || code.includes("json.") || code.includes("__") || code.includes('f"') || code.includes("f'") ? "python" : "node");
155
+ const encoded = Buffer.from(code).toString("base64");
156
+ let command;
157
+ if (effectiveRuntime === "python") {
158
+ command = await sandbox.runCommand("sh", ["-c", `echo "${encoded}" | base64 -d | python3`]);
159
+ } else {
160
+ command = await sandbox.runCommand("sh", ["-c", `echo "${encoded}" | base64 -d | node`]);
161
+ }
162
+ const finishedCommand = await command.wait();
163
+ let stdout = "";
164
+ let stderr = "";
165
+ for await (const log of finishedCommand.logs()) {
166
+ if (log.stream === "stdout") {
167
+ stdout += log.data;
168
+ } else if (log.stream === "stderr") {
169
+ stderr += log.data;
170
+ }
171
+ }
172
+ if (finishedCommand.exitCode !== 0 && stderr) {
173
+ if (stderr.includes("SyntaxError") || stderr.includes("invalid syntax") || stderr.includes("Unexpected token") || stderr.includes("Unexpected identifier")) {
174
+ throw new Error(`Syntax error: ${stderr.trim()}`);
175
+ }
176
+ }
177
+ return {
178
+ stdout,
179
+ stderr,
180
+ exitCode: finishedCommand.exitCode,
181
+ executionTime: Date.now() - startTime,
182
+ sandboxId: sandbox.sandboxId,
183
+ provider: "vercel"
184
+ };
185
+ } catch (error) {
186
+ if (error instanceof Error && error.message.includes("Syntax error")) {
187
+ throw error;
188
+ }
100
189
  throw new Error(
101
- `Vercel quota exceeded. Please check your usage in the Vercel dashboard.`
190
+ `Vercel execution failed: ${error instanceof Error ? error.message : String(error)}`
102
191
  );
103
192
  }
104
- }
105
- throw new Error(
106
- `Failed to initialize Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`
107
- );
108
- }
109
- }
110
- async doExecute(code, runtime) {
111
- if (runtime && !["node", "python"].includes(runtime)) {
112
- throw new Error("Vercel provider only supports Node.js and Python runtimes");
113
- }
114
- const startTime = Date.now();
115
- const actualRuntime = runtime || this.runtime;
116
- try {
117
- const sandbox = await this.ensureSandbox();
118
- let command;
119
- let args = [];
120
- if (actualRuntime === "node") {
121
- command = "node";
122
- args = ["-e", code];
123
- } else if (actualRuntime === "python") {
124
- command = "python";
125
- args = ["-c", code];
126
- } else {
127
- throw new Error(`Unsupported runtime: ${actualRuntime}`);
128
- }
129
- const result = await sandbox.runCommand({
130
- cmd: command,
131
- args
132
- });
133
- let stdout = "";
134
- let stderr = "";
135
- let exitCode = 0;
136
- const stdoutPromise = new Promise((resolve) => {
137
- if (result.stdout) {
138
- result.stdout.on("data", (data) => {
139
- stdout += data.toString();
140
- });
141
- result.stdout.on("end", resolve);
142
- } else {
143
- resolve();
193
+ },
194
+ runCommand: async (sandbox, command, args = []) => {
195
+ const startTime = Date.now();
196
+ try {
197
+ const cmd = await sandbox.runCommand(command, args);
198
+ const finishedCommand = await cmd.wait();
199
+ let stdout = "";
200
+ let stderr = "";
201
+ for await (const log of finishedCommand.logs()) {
202
+ if (log.stream === "stdout") {
203
+ stdout += log.data;
204
+ } else if (log.stream === "stderr") {
205
+ stderr += log.data;
206
+ }
207
+ }
208
+ return {
209
+ stdout,
210
+ stderr,
211
+ exitCode: finishedCommand.exitCode,
212
+ executionTime: Date.now() - startTime,
213
+ sandboxId: sandbox.sandboxId,
214
+ provider: "vercel"
215
+ };
216
+ } catch (error) {
217
+ return {
218
+ stdout: "",
219
+ stderr: error instanceof Error ? error.message : String(error),
220
+ exitCode: 127,
221
+ // Standard "command not found" exit code
222
+ executionTime: Date.now() - startTime,
223
+ sandboxId: sandbox.sandboxId,
224
+ provider: "vercel"
225
+ };
144
226
  }
145
- });
146
- const stderrPromise = new Promise((resolve) => {
147
- if (result.stderr) {
148
- result.stderr.on("data", (data) => {
149
- stderr += data.toString();
227
+ },
228
+ getInfo: async (sandbox) => {
229
+ return {
230
+ id: "vercel-unknown",
231
+ provider: "vercel",
232
+ runtime: "node",
233
+ // Vercel default
234
+ status: "running",
235
+ createdAt: /* @__PURE__ */ new Date(),
236
+ timeout: 3e5,
237
+ metadata: {
238
+ vercelSandboxId: "vercel-unknown"
239
+ }
240
+ };
241
+ },
242
+ // Optional filesystem methods - Vercel has shell-based filesystem support
243
+ filesystem: {
244
+ readFile: async (sandbox, path) => {
245
+ const cmd = await sandbox.runCommand("cat", [path]);
246
+ const finishedCommand = await cmd.wait();
247
+ if (finishedCommand.exitCode !== 0) {
248
+ let stderr = "";
249
+ for await (const log of finishedCommand.logs()) {
250
+ if (log.stream === "stderr") {
251
+ stderr += log.data;
252
+ }
253
+ }
254
+ throw new Error(`Failed to read file ${path}: ${stderr}`);
255
+ }
256
+ let content = "";
257
+ for await (const log of finishedCommand.logs()) {
258
+ if (log.stream === "stdout") {
259
+ content += log.data;
260
+ }
261
+ }
262
+ return content.replace(/\n$/, "");
263
+ },
264
+ writeFile: async (sandbox, path, content) => {
265
+ const cmd = await sandbox.runCommand("sh", ["-c", `echo ${JSON.stringify(content)} > ${JSON.stringify(path)}`]);
266
+ const finishedCommand = await cmd.wait();
267
+ if (finishedCommand.exitCode !== 0) {
268
+ let stderr = "";
269
+ for await (const log of finishedCommand.logs()) {
270
+ if (log.stream === "stderr") {
271
+ stderr += log.data;
272
+ }
273
+ }
274
+ throw new Error(`Failed to write file ${path}: ${stderr}`);
275
+ }
276
+ },
277
+ mkdir: async (sandbox, path) => {
278
+ const cmd = await sandbox.runCommand("mkdir", ["-p", path]);
279
+ const finishedCommand = await cmd.wait();
280
+ if (finishedCommand.exitCode !== 0) {
281
+ let stderr = "";
282
+ for await (const log of finishedCommand.logs()) {
283
+ if (log.stream === "stderr") {
284
+ stderr += log.data;
285
+ }
286
+ }
287
+ throw new Error(`Failed to create directory ${path}: ${stderr}`);
288
+ }
289
+ },
290
+ readdir: async (sandbox, path) => {
291
+ const cmd = await sandbox.runCommand("ls", ["-la", path]);
292
+ const finishedCommand = await cmd.wait();
293
+ let stdout = "";
294
+ let stderr = "";
295
+ for await (const log of finishedCommand.logs()) {
296
+ if (log.stream === "stdout") {
297
+ stdout += log.data;
298
+ } else if (log.stream === "stderr") {
299
+ stderr += log.data;
300
+ }
301
+ }
302
+ if (finishedCommand.exitCode !== 0) {
303
+ throw new Error(`Failed to list directory ${path}: ${stderr}`);
304
+ }
305
+ const lines = (stdout || "").split("\n").filter((line) => line.trim() && !line.startsWith("total"));
306
+ return lines.map((line) => {
307
+ const parts = line.trim().split(/\s+/);
308
+ const name = parts[parts.length - 1];
309
+ const isDirectory = line.startsWith("d");
310
+ return {
311
+ name,
312
+ path: `${path}/${name}`,
313
+ isDirectory,
314
+ size: parseInt(parts[4]) || 0,
315
+ lastModified: /* @__PURE__ */ new Date()
316
+ };
150
317
  });
151
- result.stderr.on("end", resolve);
152
- } else {
153
- resolve();
154
- }
155
- });
156
- const exitPromise = new Promise((resolve, reject) => {
157
- result.on("exit", (code2) => {
158
- exitCode = code2;
159
- resolve(code2);
160
- });
161
- result.on("error", reject);
162
- });
163
- await Promise.all([stdoutPromise, stderrPromise, exitPromise]);
164
- return {
165
- stdout: stdout.trim(),
166
- stderr: stderr.trim(),
167
- exitCode,
168
- executionTime: Date.now() - startTime,
169
- sandboxId: this.sandboxId,
170
- provider: this.provider
171
- };
172
- } catch (error) {
173
- if (error instanceof Error) {
174
- if (error.message.includes("timeout")) {
175
- throw new Error(
176
- `Vercel execution timeout (${this.timeout}ms). Consider increasing the timeout or optimizing your code.`
177
- );
178
- }
179
- if (error.message.includes("memory") || error.message.includes("Memory")) {
180
- throw new Error(
181
- `Vercel execution failed due to memory limits. Consider optimizing your code or using smaller data sets.`
182
- );
318
+ },
319
+ exists: async (sandbox, path) => {
320
+ const cmd = await sandbox.runCommand("test", ["-e", path]);
321
+ const finishedCommand = await cmd.wait();
322
+ return finishedCommand.exitCode === 0;
323
+ },
324
+ remove: async (sandbox, path) => {
325
+ const cmd = await sandbox.runCommand("rm", ["-rf", path]);
326
+ const finishedCommand = await cmd.wait();
327
+ if (finishedCommand.exitCode !== 0) {
328
+ let stderr = "";
329
+ for await (const log of finishedCommand.logs()) {
330
+ if (log.stream === "stderr") {
331
+ stderr += log.data;
332
+ }
333
+ }
334
+ throw new Error(`Failed to remove ${path}: ${stderr}`);
335
+ }
183
336
  }
184
337
  }
185
- throw new Error(
186
- `Vercel execution failed: ${error instanceof Error ? error.message : String(error)}`
187
- );
188
338
  }
189
339
  }
190
- async doKill() {
191
- if (!this.sandbox) {
192
- return;
193
- }
194
- try {
195
- await this.sandbox.stop();
196
- this.sandbox = null;
197
- } catch (error) {
198
- throw new Error(
199
- `Failed to kill Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`
200
- );
201
- }
202
- }
203
- async doGetInfo() {
204
- await this.ensureSandbox();
205
- return {
206
- id: this.sandboxId,
207
- provider: this.provider,
208
- runtime: this.runtime,
209
- status: this.sandbox ? "running" : "stopped",
210
- createdAt: /* @__PURE__ */ new Date(),
211
- timeout: this.timeout,
212
- metadata: {
213
- vercelSandboxId: this.sandboxId,
214
- teamId: this.teamId,
215
- projectId: this.projectId,
216
- vcpus: 2,
217
- // Default vCPUs
218
- region: "global"
219
- // Vercel sandboxes can run globally
220
- }
221
- };
222
- }
223
- };
224
- function vercel(config) {
225
- const fullConfig = {
226
- provider: "vercel",
227
- runtime: "node",
228
- timeout: 3e5,
229
- ...config
230
- };
231
- return new VercelProvider(fullConfig);
232
- }
340
+ });
233
341
  // Annotate the CommonJS export names for ESM import in node:
234
342
  0 && (module.exports = {
235
- VercelProvider,
236
343
  vercel
237
344
  });
238
345
  //# sourceMappingURL=index.js.map