@computesdk/vercel 1.7.25 → 1.7.27
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 +20 -65
- package/dist/index.d.mts +1 -14
- package/dist/index.d.ts +1 -14
- package/dist/index.js +54 -166
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +54 -166
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -37,39 +37,13 @@ Get your token from [Vercel Account Tokens](https://vercel.com/account/tokens)
|
|
|
37
37
|
|
|
38
38
|
## Quick Start
|
|
39
39
|
|
|
40
|
-
### Gateway Mode (Recommended)
|
|
41
|
-
|
|
42
|
-
Use the gateway for zero-config auto-detection:
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
import { compute } from 'computesdk';
|
|
46
|
-
|
|
47
|
-
// Auto-detects Vercel from VERCEL_OIDC_TOKEN or VERCEL_TOKEN environment variables
|
|
48
|
-
const sandbox = await compute.sandbox.create();
|
|
49
|
-
|
|
50
|
-
// Execute Node.js command
|
|
51
|
-
const result = await sandbox.runCommand('node -e "console.log(\"Hello from Vercel!\")"');
|
|
52
|
-
console.log(result.stdout); // "Hello from Vercel!"
|
|
53
|
-
|
|
54
|
-
// Execute Python command
|
|
55
|
-
const pythonResult = await sandbox.runCommand('python -c "print(\"Hello from Python!\")"');
|
|
56
|
-
console.log(pythonResult.stdout); // "Hello from Python!"
|
|
57
|
-
|
|
58
|
-
await sandbox.destroy();
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Direct Mode
|
|
62
|
-
|
|
63
|
-
For direct SDK usage without the gateway:
|
|
64
|
-
|
|
65
40
|
```typescript
|
|
66
41
|
import { vercel } from '@computesdk/vercel';
|
|
67
42
|
|
|
68
43
|
const compute = vercel({
|
|
69
44
|
token: process.env.VERCEL_TOKEN,
|
|
70
|
-
teamId: process.env.VERCEL_TEAM_ID,
|
|
45
|
+
teamId: process.env.VERCEL_TEAM_ID,
|
|
71
46
|
projectId: process.env.VERCEL_PROJECT_ID,
|
|
72
|
-
runtime: 'python',
|
|
73
47
|
timeout: 600000 // 10 minutes
|
|
74
48
|
});
|
|
75
49
|
|
|
@@ -81,6 +55,8 @@ console.log(result.stdout);
|
|
|
81
55
|
await sandbox.destroy();
|
|
82
56
|
```
|
|
83
57
|
|
|
58
|
+
OIDC tokens (`VERCEL_OIDC_TOKEN`) are auto-detected from the environment when no explicit credentials are provided in config.
|
|
59
|
+
|
|
84
60
|
## Configuration
|
|
85
61
|
|
|
86
62
|
### Environment Variables
|
|
@@ -105,19 +81,17 @@ interface VercelConfig {
|
|
|
105
81
|
teamId?: string;
|
|
106
82
|
/** Vercel project ID - if not provided, will use VERCEL_PROJECT_ID env var */
|
|
107
83
|
projectId?: string;
|
|
108
|
-
/** Default runtime environment */
|
|
109
|
-
runtime?: 'node' | 'python';
|
|
110
84
|
/** Execution timeout in milliseconds */
|
|
111
85
|
timeout?: number;
|
|
86
|
+
/** Ports to expose */
|
|
87
|
+
ports?: number[];
|
|
112
88
|
}
|
|
113
89
|
```
|
|
114
90
|
|
|
115
91
|
## Features
|
|
116
92
|
|
|
117
|
-
- ✅ **
|
|
118
|
-
- ✅ **Command Execution** - Run shell commands in sandbox
|
|
93
|
+
- ✅ **Command Execution** - Run shell commands in sandbox (Node.js 22, Python 3.13 available)
|
|
119
94
|
- ✅ **Filesystem Operations** - Full file system access via shell commands
|
|
120
|
-
- ✅ **Auto Runtime Detection** - Automatically detects Python vs Node.js
|
|
121
95
|
- ✅ **Long-running Tasks** - Up to 45 minutes execution time
|
|
122
96
|
- ✅ **Global Infrastructure** - Runs on Vercel's global network
|
|
123
97
|
- ❌ **Interactive Terminals** - Not supported by Vercel Sandbox
|
|
@@ -125,40 +99,33 @@ interface VercelConfig {
|
|
|
125
99
|
|
|
126
100
|
## API Reference
|
|
127
101
|
|
|
128
|
-
###
|
|
102
|
+
### Command Execution
|
|
129
103
|
|
|
130
104
|
```typescript
|
|
131
|
-
//
|
|
105
|
+
// Run Node.js code via heredoc
|
|
132
106
|
const result = await sandbox.runCommand(`node - <<'JS'
|
|
133
107
|
const data = { message: "Hello from Node.js" };
|
|
134
108
|
console.log(JSON.stringify(data));
|
|
135
109
|
JS`);
|
|
136
110
|
|
|
137
|
-
//
|
|
111
|
+
// Run Python code via heredoc
|
|
138
112
|
const result = await sandbox.runCommand(`python - <<'PY'
|
|
139
113
|
import json
|
|
140
114
|
data = {"message": "Hello from Python"}
|
|
141
115
|
print(json.dumps(data))
|
|
142
116
|
PY`);
|
|
143
117
|
|
|
144
|
-
// Auto-detection (based on code patterns)
|
|
145
|
-
const result = await sandbox.runCommand('python -c "print(\"Auto-detected as Python\")"');
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Command Execution
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
118
|
// List files
|
|
152
|
-
const result = await sandbox.runCommand('ls
|
|
119
|
+
const result = await sandbox.runCommand('ls -la');
|
|
153
120
|
|
|
154
121
|
// Install packages (Node.js)
|
|
155
|
-
const result = await sandbox.runCommand('npm
|
|
122
|
+
const result = await sandbox.runCommand('npm install lodash');
|
|
156
123
|
|
|
157
124
|
// Install packages (Python)
|
|
158
|
-
const result = await sandbox.runCommand('pip
|
|
125
|
+
const result = await sandbox.runCommand('pip install requests');
|
|
159
126
|
|
|
160
127
|
// Run scripts
|
|
161
|
-
const result = await sandbox.runCommand('node
|
|
128
|
+
const result = await sandbox.runCommand('node script.js');
|
|
162
129
|
```
|
|
163
130
|
|
|
164
131
|
### Filesystem Operations
|
|
@@ -191,27 +158,15 @@ const info = await sandbox.getInfo();
|
|
|
191
158
|
console.log(info.id, info.provider, info.status);
|
|
192
159
|
|
|
193
160
|
// Get existing sandbox
|
|
194
|
-
const existing = await compute.sandbox.getById(
|
|
161
|
+
const existing = await compute.sandbox.getById('sandbox-id');
|
|
195
162
|
|
|
196
163
|
// Destroy sandbox
|
|
197
|
-
await compute.sandbox.destroy(
|
|
164
|
+
await compute.sandbox.destroy('sandbox-id');
|
|
198
165
|
|
|
199
166
|
// Note: Vercel doesn't support listing all sandboxes
|
|
200
167
|
// Each sandbox is ephemeral and single-use
|
|
201
168
|
```
|
|
202
169
|
|
|
203
|
-
## Runtime Detection
|
|
204
|
-
|
|
205
|
-
The provider automatically detects the runtime based on code patterns:
|
|
206
|
-
|
|
207
|
-
**Python indicators:**
|
|
208
|
-
- `print(` statements
|
|
209
|
-
- `import` statements
|
|
210
|
-
- `def` function definitions
|
|
211
|
-
- Python-specific syntax (`f"`, `__`, etc.)
|
|
212
|
-
|
|
213
|
-
**Default:** Node.js for all other cases
|
|
214
|
-
|
|
215
170
|
## Error Handling
|
|
216
171
|
|
|
217
172
|
```typescript
|
|
@@ -246,7 +201,7 @@ try {
|
|
|
246
201
|
```typescript
|
|
247
202
|
import { vercel } from '@computesdk/vercel';
|
|
248
203
|
|
|
249
|
-
const compute = vercel({
|
|
204
|
+
const compute = vercel({});
|
|
250
205
|
const sandbox = await compute.sandbox.create();
|
|
251
206
|
|
|
252
207
|
const result = await sandbox.runCommand(`node - <<'JS'
|
|
@@ -283,7 +238,7 @@ await sandbox.destroy();
|
|
|
283
238
|
```typescript
|
|
284
239
|
import { vercel } from '@computesdk/vercel';
|
|
285
240
|
|
|
286
|
-
const compute = vercel({
|
|
241
|
+
const compute = vercel({});
|
|
287
242
|
const sandbox = await compute.sandbox.create();
|
|
288
243
|
|
|
289
244
|
const result = await sandbox.runCommand(`python - <<'PY'
|
|
@@ -328,7 +283,7 @@ await sandbox.destroy();
|
|
|
328
283
|
```typescript
|
|
329
284
|
import { vercel } from '@computesdk/vercel';
|
|
330
285
|
|
|
331
|
-
const compute = vercel({
|
|
286
|
+
const compute = vercel({});
|
|
332
287
|
const sandbox = await compute.sandbox.create();
|
|
333
288
|
|
|
334
289
|
// Create project structure
|
|
@@ -442,11 +397,11 @@ await sandbox.destroy();
|
|
|
442
397
|
```typescript
|
|
443
398
|
import { vercel } from '@computesdk/vercel';
|
|
444
399
|
|
|
445
|
-
const compute = vercel({
|
|
400
|
+
const compute = vercel({});
|
|
446
401
|
const sandbox = await compute.sandbox.create();
|
|
447
402
|
|
|
448
403
|
// Install lodash
|
|
449
|
-
const installResult = await sandbox.runCommand('npm
|
|
404
|
+
const installResult = await sandbox.runCommand('npm install lodash');
|
|
450
405
|
console.log('Install result:', installResult.stdout);
|
|
451
406
|
|
|
452
407
|
// Use lodash in code
|
package/dist/index.d.mts
CHANGED
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
import * as _computesdk_provider from '@computesdk/provider';
|
|
2
|
-
import { Runtime } from '@computesdk/provider';
|
|
3
2
|
import { Sandbox, Snapshot } from '@vercel/sandbox';
|
|
4
3
|
export { Sandbox as VercelSandbox, Snapshot as VercelSnapshot } from '@vercel/sandbox';
|
|
5
4
|
|
|
6
|
-
/**
|
|
7
|
-
* Vercel sandbox provider configuration
|
|
8
|
-
*/
|
|
9
5
|
interface VercelConfig {
|
|
10
|
-
/** Vercel API token */
|
|
11
6
|
token?: string;
|
|
12
|
-
/** Vercel team ID */
|
|
13
7
|
teamId?: string;
|
|
14
|
-
/** Vercel project ID */
|
|
15
8
|
projectId?: string;
|
|
16
|
-
/** Runtime environment for code execution */
|
|
17
|
-
runtime?: Runtime;
|
|
18
|
-
/** Execution timeout in milliseconds */
|
|
19
9
|
timeout?: number;
|
|
20
|
-
/** Ports to expose */
|
|
21
10
|
ports?: number[];
|
|
11
|
+
daemonSsePort?: number | false;
|
|
22
12
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Create a Vercel provider instance using the factory pattern
|
|
25
|
-
*/
|
|
26
13
|
declare const vercel: (config: VercelConfig) => _computesdk_provider.Provider<Sandbox, any, Snapshot>;
|
|
27
14
|
|
|
28
15
|
export { type VercelConfig, vercel };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
import * as _computesdk_provider from '@computesdk/provider';
|
|
2
|
-
import { Runtime } from '@computesdk/provider';
|
|
3
2
|
import { Sandbox, Snapshot } from '@vercel/sandbox';
|
|
4
3
|
export { Sandbox as VercelSandbox, Snapshot as VercelSnapshot } from '@vercel/sandbox';
|
|
5
4
|
|
|
6
|
-
/**
|
|
7
|
-
* Vercel sandbox provider configuration
|
|
8
|
-
*/
|
|
9
5
|
interface VercelConfig {
|
|
10
|
-
/** Vercel API token */
|
|
11
6
|
token?: string;
|
|
12
|
-
/** Vercel team ID */
|
|
13
7
|
teamId?: string;
|
|
14
|
-
/** Vercel project ID */
|
|
15
8
|
projectId?: string;
|
|
16
|
-
/** Runtime environment for code execution */
|
|
17
|
-
runtime?: Runtime;
|
|
18
|
-
/** Execution timeout in milliseconds */
|
|
19
9
|
timeout?: number;
|
|
20
|
-
/** Ports to expose */
|
|
21
10
|
ports?: number[];
|
|
11
|
+
daemonSsePort?: number | false;
|
|
22
12
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Create a Vercel provider instance using the factory pattern
|
|
25
|
-
*/
|
|
26
13
|
declare const vercel: (config: VercelConfig) => _computesdk_provider.Provider<Sandbox, any, Snapshot>;
|
|
27
14
|
|
|
28
15
|
export { type VercelConfig, vercel };
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,13 @@ module.exports = __toCommonJS(index_exports);
|
|
|
26
26
|
var import_sandbox = require("@vercel/sandbox");
|
|
27
27
|
var import_provider = require("@computesdk/provider");
|
|
28
28
|
var import_node_stream = require("stream");
|
|
29
|
+
var DEFAULT_DAEMON_SSE_PORT = 38989;
|
|
30
|
+
function mergeExposedPorts(primary, fallback, daemonSsePort) {
|
|
31
|
+
const daemonPort = daemonSsePort === false ? void 0 : daemonSsePort ?? DEFAULT_DAEMON_SSE_PORT;
|
|
32
|
+
const merged = [...primary ?? fallback ?? []];
|
|
33
|
+
if (typeof daemonPort === "number") merged.push(daemonPort);
|
|
34
|
+
return Array.from(new Set(merged.filter((port) => Number.isInteger(port) && port > 0 && port <= 65535)));
|
|
35
|
+
}
|
|
29
36
|
function resolveCredentials(config) {
|
|
30
37
|
const token = config.token || typeof process !== "undefined" && process.env?.VERCEL_TOKEN || "";
|
|
31
38
|
const teamId = config.teamId || typeof process !== "undefined" && process.env?.VERCEL_TEAM_ID || "";
|
|
@@ -36,26 +43,16 @@ function resolveCredentials(config) {
|
|
|
36
43
|
return { useOidc, token, teamId, projectId };
|
|
37
44
|
}
|
|
38
45
|
function validateCredentials(creds) {
|
|
39
|
-
if (creds.useOidc)
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
46
|
+
if (creds.useOidc) return;
|
|
42
47
|
if (!creds.token) {
|
|
43
48
|
throw new Error(
|
|
44
49
|
`Missing Vercel authentication. Either:
|
|
45
50
|
1. Use OIDC token: Run 'vercel env pull' to get VERCEL_OIDC_TOKEN, or
|
|
46
|
-
2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
if (!creds.teamId) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
`Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID environment variable.`
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
if (!creds.projectId) {
|
|
55
|
-
throw new Error(
|
|
56
|
-
`Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID environment variable.`
|
|
51
|
+
2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable.`
|
|
57
52
|
);
|
|
58
53
|
}
|
|
54
|
+
if (!creds.teamId) throw new Error(`Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID.`);
|
|
55
|
+
if (!creds.projectId) throw new Error(`Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID.`);
|
|
59
56
|
}
|
|
60
57
|
function getUtf8Sink() {
|
|
61
58
|
const chunks = [];
|
|
@@ -71,18 +68,14 @@ var vercel = (0, import_provider.defineProvider)({
|
|
|
71
68
|
name: "vercel",
|
|
72
69
|
methods: {
|
|
73
70
|
sandbox: {
|
|
74
|
-
// Collection operations (map to compute.sandbox.*)
|
|
75
71
|
create: async (config, options) => {
|
|
76
72
|
const creds = resolveCredentials(config);
|
|
77
73
|
validateCredentials(creds);
|
|
78
74
|
const timeout = options?.timeout ?? config.timeout ?? 3e5;
|
|
79
75
|
try {
|
|
80
|
-
let sandbox;
|
|
81
76
|
const {
|
|
82
|
-
runtime: optRuntime,
|
|
83
77
|
timeout: _timeout,
|
|
84
78
|
envs: _envs,
|
|
85
|
-
// Vercel SDK does not support envs at sandbox creation time
|
|
86
79
|
name: _name,
|
|
87
80
|
metadata: _metadata,
|
|
88
81
|
templateId,
|
|
@@ -90,29 +83,21 @@ var vercel = (0, import_provider.defineProvider)({
|
|
|
90
83
|
sandboxId: _sandboxId,
|
|
91
84
|
namespace: _namespace,
|
|
92
85
|
directory: _directory,
|
|
93
|
-
ports: optPorts,
|
|
94
|
-
source: optSource,
|
|
95
86
|
...providerOptions
|
|
96
87
|
} = options || {};
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const ports = optPorts ?? config.
|
|
103
|
-
if (ports && ports.length > 0)
|
|
104
|
-
params.ports = ports;
|
|
105
|
-
}
|
|
88
|
+
const optRuntime = options?.runtime;
|
|
89
|
+
const optPorts = options?.ports;
|
|
90
|
+
const optSource = options?.source;
|
|
91
|
+
const params = { timeout, ...providerOptions };
|
|
92
|
+
const optDaemonSsePort = options?.daemonSsePort;
|
|
93
|
+
const ports = mergeExposedPorts(optPorts, config.ports, optDaemonSsePort ?? config.daemonSsePort);
|
|
94
|
+
if (ports && ports.length > 0) params.ports = ports;
|
|
106
95
|
if (optRuntime) {
|
|
107
|
-
|
|
108
|
-
params.runtime = vercelRuntime;
|
|
96
|
+
params.runtime = optRuntime === "node" ? "node24" : optRuntime === "python" ? "python3.13" : optRuntime;
|
|
109
97
|
}
|
|
110
98
|
const snapshotId = optSnapshotId || templateId || optSource?.type === "snapshot" && optSource?.snapshotId;
|
|
111
99
|
if (snapshotId) {
|
|
112
|
-
params.source = {
|
|
113
|
-
type: "snapshot",
|
|
114
|
-
snapshotId
|
|
115
|
-
};
|
|
100
|
+
params.source = { type: "snapshot", snapshotId };
|
|
116
101
|
} else if (optSource) {
|
|
117
102
|
params.source = optSource;
|
|
118
103
|
}
|
|
@@ -121,75 +106,40 @@ var vercel = (0, import_provider.defineProvider)({
|
|
|
121
106
|
params.teamId = creds.teamId;
|
|
122
107
|
params.projectId = creds.projectId;
|
|
123
108
|
}
|
|
124
|
-
sandbox = await import_sandbox.Sandbox.create(params);
|
|
125
|
-
return {
|
|
126
|
-
sandbox,
|
|
127
|
-
sandboxId: sandbox.sandboxId
|
|
128
|
-
};
|
|
109
|
+
const sandbox = await import_sandbox.Sandbox.create(params);
|
|
110
|
+
return { sandbox, sandboxId: sandbox.sandboxId };
|
|
129
111
|
} catch (error) {
|
|
130
112
|
if (error instanceof Error) {
|
|
131
113
|
if (error.message.includes("unauthorized") || error.message.includes("token")) {
|
|
132
|
-
throw new Error(
|
|
133
|
-
`Vercel authentication failed. Please check your VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`
|
|
134
|
-
);
|
|
114
|
+
throw new Error(`Vercel authentication failed. Please check your VERCEL_TOKEN environment variable.`);
|
|
135
115
|
}
|
|
136
116
|
if (error.message.includes("team") || error.message.includes("project")) {
|
|
137
|
-
throw new Error(
|
|
138
|
-
`Vercel team/project configuration failed. Please check your VERCEL_TEAM_ID and VERCEL_PROJECT_ID environment variables.`
|
|
139
|
-
);
|
|
117
|
+
throw new Error(`Vercel team/project configuration failed. Check VERCEL_TEAM_ID and VERCEL_PROJECT_ID.`);
|
|
140
118
|
}
|
|
141
119
|
}
|
|
142
|
-
throw new Error(
|
|
143
|
-
`Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`
|
|
144
|
-
);
|
|
120
|
+
throw new Error(`Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`);
|
|
145
121
|
}
|
|
146
122
|
},
|
|
147
123
|
getById: async (config, sandboxId) => {
|
|
148
124
|
const creds = resolveCredentials(config);
|
|
149
125
|
try {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
} else {
|
|
154
|
-
sandbox = await import_sandbox.Sandbox.get({
|
|
155
|
-
sandboxId,
|
|
156
|
-
token: creds.token,
|
|
157
|
-
teamId: creds.teamId,
|
|
158
|
-
projectId: creds.projectId
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
return {
|
|
162
|
-
sandbox,
|
|
163
|
-
sandboxId
|
|
164
|
-
};
|
|
165
|
-
} catch (error) {
|
|
126
|
+
const sandbox = creds.useOidc ? await import_sandbox.Sandbox.get({ sandboxId }) : await import_sandbox.Sandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
127
|
+
return { sandbox, sandboxId };
|
|
128
|
+
} catch {
|
|
166
129
|
return null;
|
|
167
130
|
}
|
|
168
131
|
},
|
|
169
132
|
list: async (_config) => {
|
|
170
|
-
throw new Error(
|
|
171
|
-
`Vercel provider does not support listing sandboxes. Vercel sandboxes are ephemeral and designed for single-use execution.`
|
|
172
|
-
);
|
|
133
|
+
throw new Error(`Vercel provider does not support listing sandboxes.`);
|
|
173
134
|
},
|
|
174
135
|
destroy: async (config, sandboxId) => {
|
|
175
136
|
const creds = resolveCredentials(config);
|
|
176
137
|
try {
|
|
177
|
-
|
|
178
|
-
if (creds.useOidc) {
|
|
179
|
-
sandbox = await import_sandbox.Sandbox.get({ sandboxId });
|
|
180
|
-
} else {
|
|
181
|
-
sandbox = await import_sandbox.Sandbox.get({
|
|
182
|
-
sandboxId,
|
|
183
|
-
token: creds.token,
|
|
184
|
-
teamId: creds.teamId,
|
|
185
|
-
projectId: creds.projectId
|
|
186
|
-
});
|
|
187
|
-
}
|
|
138
|
+
const sandbox = creds.useOidc ? await import_sandbox.Sandbox.get({ sandboxId }) : await import_sandbox.Sandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
188
139
|
await sandbox.stop();
|
|
189
|
-
} catch
|
|
140
|
+
} catch {
|
|
190
141
|
}
|
|
191
142
|
},
|
|
192
|
-
// Instance operations (map to individual Sandbox methods)
|
|
193
143
|
runCommand: async (sandbox, command, options) => {
|
|
194
144
|
const startTime = Date.now();
|
|
195
145
|
try {
|
|
@@ -208,35 +158,19 @@ var vercel = (0, import_provider.defineProvider)({
|
|
|
208
158
|
stdout: stdout?.sink,
|
|
209
159
|
stderr: stderr?.sink
|
|
210
160
|
});
|
|
211
|
-
return {
|
|
212
|
-
stdout: stdout?.value() ?? "",
|
|
213
|
-
stderr: stderr?.value() ?? "",
|
|
214
|
-
exitCode: result.exitCode ?? 0,
|
|
215
|
-
durationMs: Date.now() - startTime
|
|
216
|
-
};
|
|
161
|
+
return { stdout: stdout?.value() ?? "", stderr: stderr?.value() ?? "", exitCode: result.exitCode ?? 0, durationMs: Date.now() - startTime };
|
|
217
162
|
} catch (error) {
|
|
218
|
-
return {
|
|
219
|
-
stdout: "",
|
|
220
|
-
stderr: error instanceof Error ? error.message : String(error),
|
|
221
|
-
exitCode: 127,
|
|
222
|
-
durationMs: Date.now() - startTime
|
|
223
|
-
};
|
|
163
|
+
return { stdout: "", stderr: error instanceof Error ? error.message : String(error), exitCode: 127, durationMs: Date.now() - startTime };
|
|
224
164
|
}
|
|
225
165
|
},
|
|
226
|
-
getInfo: async (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
timeout: 3e5,
|
|
235
|
-
metadata: {
|
|
236
|
-
vercelSandboxId: "vercel-unknown"
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
},
|
|
166
|
+
getInfo: async (_sandbox) => ({
|
|
167
|
+
id: "vercel-unknown",
|
|
168
|
+
provider: "vercel",
|
|
169
|
+
status: "running",
|
|
170
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
171
|
+
timeout: 3e5,
|
|
172
|
+
metadata: { vercelSandboxId: "vercel-unknown" }
|
|
173
|
+
}),
|
|
240
174
|
getUrl: async (sandbox, options) => {
|
|
241
175
|
try {
|
|
242
176
|
let url = sandbox.domain(options.port);
|
|
@@ -247,21 +181,15 @@ var vercel = (0, import_provider.defineProvider)({
|
|
|
247
181
|
}
|
|
248
182
|
return url;
|
|
249
183
|
} catch (error) {
|
|
250
|
-
throw new Error(
|
|
251
|
-
`Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}. Ensure the port has an associated route.`
|
|
252
|
-
);
|
|
184
|
+
throw new Error(`Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}.`);
|
|
253
185
|
}
|
|
254
186
|
},
|
|
255
187
|
filesystem: {
|
|
256
188
|
readFile: async (sandbox, path) => {
|
|
257
189
|
const stream = await sandbox.readFile({ path });
|
|
258
|
-
if (!stream) {
|
|
259
|
-
throw new Error(`File not found: ${path}`);
|
|
260
|
-
}
|
|
190
|
+
if (!stream) throw new Error(`File not found: ${path}`);
|
|
261
191
|
const chunks = [];
|
|
262
|
-
for await (const chunk of stream)
|
|
263
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
264
|
-
}
|
|
192
|
+
for await (const chunk of stream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
265
193
|
return Buffer.concat(chunks).toString("utf-8");
|
|
266
194
|
},
|
|
267
195
|
writeFile: async (sandbox, path, content) => {
|
|
@@ -271,82 +199,42 @@ var vercel = (0, import_provider.defineProvider)({
|
|
|
271
199
|
await sandbox.mkDir(path);
|
|
272
200
|
},
|
|
273
201
|
readdir: async (_sandbox, _path) => {
|
|
274
|
-
throw new Error("Vercel sandbox does not support readdir.
|
|
202
|
+
throw new Error("Vercel sandbox does not support readdir.");
|
|
275
203
|
},
|
|
276
204
|
exists: async (_sandbox, _path) => {
|
|
277
|
-
throw new Error("Vercel sandbox does not support exists.
|
|
205
|
+
throw new Error("Vercel sandbox does not support exists.");
|
|
278
206
|
},
|
|
279
207
|
remove: async (_sandbox, _path) => {
|
|
280
|
-
throw new Error("Vercel sandbox does not support remove.
|
|
208
|
+
throw new Error("Vercel sandbox does not support remove.");
|
|
281
209
|
}
|
|
282
210
|
},
|
|
283
|
-
|
|
284
|
-
getInstance: (sandbox) => {
|
|
285
|
-
return sandbox;
|
|
286
|
-
}
|
|
211
|
+
getInstance: (sandbox) => sandbox
|
|
287
212
|
},
|
|
288
213
|
snapshot: {
|
|
289
214
|
create: async (config, sandboxId) => {
|
|
290
215
|
const creds = resolveCredentials(config);
|
|
291
|
-
|
|
292
|
-
if (creds.useOidc) {
|
|
293
|
-
sandbox = await import_sandbox.Sandbox.get({ sandboxId });
|
|
294
|
-
} else {
|
|
295
|
-
sandbox = await import_sandbox.Sandbox.get({
|
|
296
|
-
sandboxId,
|
|
297
|
-
token: creds.token,
|
|
298
|
-
teamId: creds.teamId,
|
|
299
|
-
projectId: creds.projectId
|
|
300
|
-
});
|
|
301
|
-
}
|
|
216
|
+
const sandbox = creds.useOidc ? await import_sandbox.Sandbox.get({ sandboxId }) : await import_sandbox.Sandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
302
217
|
return await sandbox.snapshot();
|
|
303
218
|
},
|
|
304
219
|
list: async (_config) => {
|
|
305
|
-
throw new Error(
|
|
306
|
-
`Vercel provider does not support listing snapshots.`
|
|
307
|
-
);
|
|
220
|
+
throw new Error(`Vercel provider does not support listing snapshots.`);
|
|
308
221
|
},
|
|
309
222
|
delete: async (config, snapshotId) => {
|
|
310
223
|
const creds = resolveCredentials(config);
|
|
311
|
-
|
|
312
|
-
if (creds.useOidc) {
|
|
313
|
-
snapshot = await import_sandbox.Snapshot.get({ snapshotId });
|
|
314
|
-
} else {
|
|
315
|
-
snapshot = await import_sandbox.Snapshot.get({
|
|
316
|
-
snapshotId,
|
|
317
|
-
token: creds.token,
|
|
318
|
-
teamId: creds.teamId,
|
|
319
|
-
projectId: creds.projectId
|
|
320
|
-
});
|
|
321
|
-
}
|
|
224
|
+
const snapshot = creds.useOidc ? await import_sandbox.Snapshot.get({ snapshotId }) : await import_sandbox.Snapshot.get({ snapshotId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
322
225
|
await snapshot.delete();
|
|
323
226
|
}
|
|
324
227
|
},
|
|
325
|
-
// Vercel doesn't have a separate "template" concept - snapshots serve as templates
|
|
326
228
|
template: {
|
|
327
229
|
create: async (_config, _options) => {
|
|
328
|
-
throw new Error(
|
|
329
|
-
`Vercel does not support creating templates directly. Use snapshot.create() to create a snapshot from a running sandbox.`
|
|
330
|
-
);
|
|
230
|
+
throw new Error(`Vercel does not support creating templates directly. Use snapshot.create() instead.`);
|
|
331
231
|
},
|
|
332
232
|
list: async (_config) => {
|
|
333
|
-
throw new Error(
|
|
334
|
-
`Vercel provider does not support listing templates.`
|
|
335
|
-
);
|
|
233
|
+
throw new Error(`Vercel provider does not support listing templates.`);
|
|
336
234
|
},
|
|
337
235
|
delete: async (config, templateId) => {
|
|
338
236
|
const creds = resolveCredentials(config);
|
|
339
|
-
|
|
340
|
-
if (creds.useOidc) {
|
|
341
|
-
snapshot = await import_sandbox.Snapshot.get({ snapshotId: templateId });
|
|
342
|
-
} else {
|
|
343
|
-
snapshot = await import_sandbox.Snapshot.get({
|
|
344
|
-
snapshotId: templateId,
|
|
345
|
-
token: creds.token,
|
|
346
|
-
teamId: creds.teamId,
|
|
347
|
-
projectId: creds.projectId
|
|
348
|
-
});
|
|
349
|
-
}
|
|
237
|
+
const snapshot = creds.useOidc ? await import_sandbox.Snapshot.get({ snapshotId: templateId }) : await import_sandbox.Snapshot.get({ snapshotId: templateId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
350
238
|
await snapshot.delete();
|
|
351
239
|
}
|
|
352
240
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Vercel Provider - Factory-based Implementation\n * \n * Demonstrates the new defineProvider() factory pattern with ~50 lines\n * instead of the original ~350 lines of boilerplate.\n */\n\nimport { Sandbox as VercelSandbox, Snapshot as VercelSnapshot } from '@vercel/sandbox';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\nimport { Writable } from 'node:stream';\n\nexport type { VercelSandbox, VercelSnapshot };\n\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Vercel sandbox provider configuration\n */\nexport interface VercelConfig {\n /** Vercel API token */\n token?: string;\n /** Vercel team ID */\n teamId?: string;\n /** Vercel project ID */\n projectId?: string;\n /** Runtime environment for code execution */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Ports to expose */\n ports?: number[];\n}\n\n/**\n * Resolved Vercel credentials with the authentication method to use\n */\ninterface ResolvedCredentials {\n /** Whether to use OIDC authentication (no explicit credentials needed) */\n useOidc: boolean;\n /** Token for traditional auth (only used if useOidc is false) */\n token: string;\n /** Team ID for traditional auth (only used if useOidc is false) */\n teamId: string;\n /** Project ID for traditional auth (only used if useOidc is false) */\n projectId: string;\n}\n\n/**\n * Resolve Vercel credentials with proper precedence:\n * 1. Config values (from setConfig) always win\n * 2. Environment variables are used as fallback\n * 3. OIDC is only used when no config credentials are provided\n */\nfunction resolveCredentials(config: VercelConfig): ResolvedCredentials {\n // Get values from config first, then fall back to environment\n const token = config.token || (typeof process !== 'undefined' && process.env?.VERCEL_TOKEN) || '';\n const teamId = config.teamId || (typeof process !== 'undefined' && process.env?.VERCEL_TEAM_ID) || '';\n const projectId = config.projectId || (typeof process !== 'undefined' && process.env?.VERCEL_PROJECT_ID) || '';\n \n // Check if config explicitly provided credentials (config takes precedence)\n const hasConfigCredentials = !!(config.token || config.teamId || config.projectId);\n \n // Only use OIDC if:\n // 1. No config credentials were provided, AND\n // 2. OIDC token is available in environment\n const oidcToken = typeof process !== 'undefined' && process.env?.VERCEL_OIDC_TOKEN;\n const useOidc = !hasConfigCredentials && !!oidcToken;\n \n return { useOidc, token, teamId, projectId };\n}\n\n/**\n * Validate that we have sufficient credentials to authenticate\n */\nfunction validateCredentials(creds: ResolvedCredentials): void {\n if (creds.useOidc) {\n // OIDC auth - no additional validation needed\n return;\n }\n \n // Traditional auth - need all three\n if (!creds.token) {\n throw new Error(\n `Missing Vercel authentication. Either:\\n` +\n `1. Use OIDC token: Run 'vercel env pull' to get VERCEL_OIDC_TOKEN, or\\n` +\n `2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`\n );\n }\n if (!creds.teamId) {\n throw new Error(\n `Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID environment variable.`\n );\n }\n if (!creds.projectId) {\n throw new Error(\n `Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID environment variable.`\n );\n }\n}\n\n/**\n * Get a writable stream that collects UTF-8 string data and buffers it\n * in memory, returning the full concatenated string when done.\n */\nfunction getUtf8Sink() {\n const chunks: string[] = [];\n const sink = new Writable({\n write(chunk, _enc, cb) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk.toString(\"utf8\") :\n String(chunk));\n cb();\n },\n });\n return { sink, value: () => chunks.join(\"\") };\n}\n\n\n\n/**\n * Create a Vercel provider instance using the factory pattern\n */\nexport const vercel = defineProvider<VercelSandbox, VercelConfig, any, VercelSnapshot>({\n name: 'vercel',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: VercelConfig, options?: CreateSandboxOptions) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n validateCredentials(creds);\n\n // options.timeout takes precedence over config.timeout\n const timeout = options?.timeout ?? config.timeout ?? 300000;\n\n try {\n let sandbox: VercelSandbox;\n\n // Destructure known ComputeSDK fields, collect the rest for passthrough\n const {\n runtime: optRuntime,\n timeout: _timeout,\n envs: _envs, // Vercel SDK does not support envs at sandbox creation time\n name: _name,\n metadata: _metadata,\n templateId,\n snapshotId: optSnapshotId,\n sandboxId: _sandboxId,\n namespace: _namespace,\n directory: _directory,\n ports: optPorts,\n source: optSource,\n ...providerOptions\n } = options || {};\n\n // Construct base params, spreading provider-specific options\n const params: any = {\n timeout,\n ...providerOptions, // Spread provider-specific options (e.g., resources, networkPolicy, signal)\n };\n \n // Only add ports if explicitly configured (options.ports takes precedence)\n const ports = optPorts ?? config.ports;\n if (ports && ports.length > 0) {\n params.ports = ports;\n }\n\n // Pass runtime if specified (Vercel supports runtime selection).\n // Vercel only accepts specific versioned runtimes (node24, node22, python3.13),\n // so translate ComputeSDK's generic names to Vercel's expected format.\n if (optRuntime) {\n const vercelRuntime =\n optRuntime === 'node' ? 'node24' :\n optRuntime === 'python' ? 'python3.13' :\n optRuntime;\n params.runtime = vercelRuntime;\n }\n\n // Support both ComputeSDK format (snapshotId/templateId at top level) and \n // Vercel SDK format (source.snapshotId nested)\n const snapshotId = optSnapshotId || templateId ||\n (optSource?.type === 'snapshot' && optSource?.snapshotId);\n \n if (snapshotId) {\n params.source = {\n type: 'snapshot',\n snapshotId\n };\n } else if (optSource) {\n // Pass through source as-is (e.g., git or tarball sources)\n params.source = optSource;\n }\n\n // Add auth params if not using OIDC\n if (!creds.useOidc) {\n params.token = creds.token;\n params.teamId = creds.teamId;\n params.projectId = creds.projectId;\n }\n\n sandbox = await VercelSandbox.create(params);\n\n return {\n sandbox,\n sandboxId: sandbox.sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('token')) {\n throw new Error(\n `Vercel authentication failed. Please check your VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`\n );\n }\n if (error.message.includes('team') || error.message.includes('project')) {\n throw new Error(\n `Vercel team/project configuration failed. Please check your VERCEL_TEAM_ID and VERCEL_PROJECT_ID environment variables.`\n );\n }\n }\n throw new Error(\n `Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: VercelConfig, sandboxId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n try {\n let sandbox: VercelSandbox;\n\n if (creds.useOidc) {\n // Use OIDC token method\n sandbox = await VercelSandbox.get({ sandboxId });\n } else {\n // Use traditional method\n sandbox = await VercelSandbox.get({\n sandboxId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n return {\n sandbox,\n sandboxId\n };\n } catch (error) {\n // Sandbox doesn't exist or can't be accessed\n return null;\n }\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(\n `Vercel provider does not support listing sandboxes. Vercel sandboxes are ephemeral and designed for single-use execution.`\n );\n },\n\n destroy: async (config: VercelConfig, sandboxId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n try {\n let sandbox: VercelSandbox;\n\n if (creds.useOidc) {\n // Use OIDC token method\n sandbox = await VercelSandbox.get({ sandboxId });\n } else {\n // Use traditional method\n sandbox = await VercelSandbox.get({\n sandboxId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n await sandbox.stop();\n } catch (error) {\n // Sandbox 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\n runCommand: async (sandbox: VercelSandbox, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n const startTime = Date.now();\n\n try {\n // Build command with options\n let fullCommand = command;\n \n // Handle environment variables\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env)\n .map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`)\n .join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n\n // If running in the background, don't capture stdout/stderr\n const stdout = options?.background ? undefined : getUtf8Sink();\n const stderr = options?.background ? undefined : getUtf8Sink();\n\n const result = await sandbox.runCommand({\n cmd: 'sh',\n args: ['-c', fullCommand],\n cwd: options?.cwd,\n detached: options?.background,\n stdout: stdout?.sink,\n stderr: stderr?.sink,\n });\n\n return {\n stdout: stdout?.value() ?? '',\n stderr: stderr?.value() ?? '',\n exitCode: result.exitCode ?? 0,\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: VercelSandbox): Promise<SandboxInfo> => {\n return {\n id: 'vercel-unknown',\n provider: 'vercel',\n runtime: 'node', // Vercel default\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n vercelSandboxId: 'vercel-unknown'\n }\n };\n },\n\n getUrl: async (sandbox: VercelSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n // Use Vercel's built-in domain method to get the real domain\n let url = sandbox.domain(options.port);\n \n // If a specific protocol is requested, replace the URL's protocol\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}. Ensure the port has an associated route.`\n );\n }\n },\n\n filesystem: {\n readFile: async (sandbox: VercelSandbox, path: string): Promise<string> => {\n const stream = await sandbox.readFile({ path });\n if (!stream) {\n throw new Error(`File not found: ${path}`);\n }\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString('utf-8');\n },\n\n writeFile: async (sandbox: VercelSandbox, path: string, content: string): Promise<void> => {\n await sandbox.writeFiles([{ path, content: Buffer.from(content) }]);\n },\n\n mkdir: async (sandbox: VercelSandbox, path: string): Promise<void> => {\n await sandbox.mkDir(path);\n },\n\n readdir: async (_sandbox: VercelSandbox, _path: string): Promise<FileEntry[]> => {\n throw new Error('Vercel sandbox does not support readdir. Use runCommand to list directory contents.');\n },\n\n exists: async (_sandbox: VercelSandbox, _path: string): Promise<boolean> => {\n throw new Error('Vercel sandbox does not support exists. Use runCommand to check file existence.');\n },\n\n remove: async (_sandbox: VercelSandbox, _path: string): Promise<void> => {\n throw new Error('Vercel sandbox does not support remove. Use runCommand to delete files.');\n }\n },\n\n // Provider-specific typed getInstance method\n getInstance: (sandbox: VercelSandbox): VercelSandbox => {\n return sandbox;\n },\n\n },\n\n snapshot: {\n create: async (config: VercelConfig, sandboxId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n let sandbox: VercelSandbox;\n\n if (creds.useOidc) {\n // Use OIDC token method\n sandbox = await VercelSandbox.get({ sandboxId });\n } else {\n // Use traditional method\n sandbox = await VercelSandbox.get({\n sandboxId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n return await sandbox.snapshot();\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(\n `Vercel provider does not support listing snapshots.`\n );\n },\n\n delete: async (config: VercelConfig, snapshotId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n let snapshot: VercelSnapshot;\n\n if (creds.useOidc) {\n // Use OIDC token method\n snapshot = await VercelSnapshot.get({ snapshotId });\n } else {\n // Use traditional method\n snapshot = await VercelSnapshot.get({\n snapshotId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n await snapshot.delete();\n }\n },\n\n // Vercel doesn't have a separate \"template\" concept - snapshots serve as templates\n template: {\n create: async (_config: VercelConfig, _options: { name: string }) => {\n throw new Error(\n `Vercel does not support creating templates directly. Use snapshot.create() to create a snapshot from a running sandbox.`\n );\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(\n `Vercel provider does not support listing templates.`\n );\n },\n\n delete: async (config: VercelConfig, templateId: string) => {\n // Reuse snapshot.delete since Vercel doesn't have separate templates\n const creds = resolveCredentials(config);\n\n let snapshot: VercelSnapshot;\n\n if (creds.useOidc) {\n snapshot = await VercelSnapshot.get({ snapshotId: templateId });\n } else {\n snapshot = await VercelSnapshot.get({\n snapshotId: templateId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n await snapshot.delete();\n }\n }\n }\n});\n"],"mappings":"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","names":["VercelSandbox","VercelSnapshot"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Vercel Provider - Factory-based Implementation\n */\n\nimport { Sandbox as VercelSandbox, Snapshot as VercelSnapshot } from '@vercel/sandbox';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\nimport { Writable } from 'node:stream';\n\nexport type { VercelSandbox, VercelSnapshot };\n\nimport type { CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\nexport interface VercelConfig {\n token?: string;\n teamId?: string;\n projectId?: string;\n timeout?: number;\n ports?: number[];\n daemonSsePort?: number | false;\n}\n\nconst DEFAULT_DAEMON_SSE_PORT = 38989;\n\nfunction mergeExposedPorts(primary?: number[], fallback?: number[], daemonSsePort?: number | false): number[] {\n const daemonPort = daemonSsePort === false ? undefined : (daemonSsePort ?? DEFAULT_DAEMON_SSE_PORT);\n const merged = [...(primary ?? fallback ?? [])];\n if (typeof daemonPort === 'number') merged.push(daemonPort);\n return Array.from(new Set(merged.filter((port) => Number.isInteger(port) && port > 0 && port <= 65535)));\n}\n\ninterface ResolvedCredentials {\n useOidc: boolean;\n token: string;\n teamId: string;\n projectId: string;\n}\n\nfunction resolveCredentials(config: VercelConfig): ResolvedCredentials {\n const token = config.token || (typeof process !== 'undefined' && process.env?.VERCEL_TOKEN) || '';\n const teamId = config.teamId || (typeof process !== 'undefined' && process.env?.VERCEL_TEAM_ID) || '';\n const projectId = config.projectId || (typeof process !== 'undefined' && process.env?.VERCEL_PROJECT_ID) || '';\n const hasConfigCredentials = !!(config.token || config.teamId || config.projectId);\n const oidcToken = typeof process !== 'undefined' && process.env?.VERCEL_OIDC_TOKEN;\n const useOidc = !hasConfigCredentials && !!oidcToken;\n return { useOidc, token, teamId, projectId };\n}\n\nfunction validateCredentials(creds: ResolvedCredentials): void {\n if (creds.useOidc) return;\n if (!creds.token) {\n throw new Error(\n `Missing Vercel authentication. Either:\\n` +\n `1. Use OIDC token: Run 'vercel env pull' to get VERCEL_OIDC_TOKEN, or\\n` +\n `2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable.`\n );\n }\n if (!creds.teamId) throw new Error(`Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID.`);\n if (!creds.projectId) throw new Error(`Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID.`);\n}\n\nfunction getUtf8Sink() {\n const chunks: string[] = [];\n const sink = new Writable({\n write(chunk, _enc, cb) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk.toString(\"utf8\") : String(chunk));\n cb();\n },\n });\n return { sink, value: () => chunks.join(\"\") };\n}\n\nexport const vercel = defineProvider<VercelSandbox, VercelConfig, any, VercelSnapshot>({\n name: 'vercel',\n methods: {\n sandbox: {\n create: async (config: VercelConfig, options?: CreateSandboxOptions) => {\n const creds = resolveCredentials(config);\n validateCredentials(creds);\n const timeout = options?.timeout ?? config.timeout ?? 300000;\n try {\n const {\n timeout: _timeout, envs: _envs, name: _name, metadata: _metadata,\n templateId, snapshotId: optSnapshotId, sandboxId: _sandboxId,\n namespace: _namespace, directory: _directory,\n ...providerOptions\n } = options || {};\n const optRuntime = (options as any)?.runtime;\n const optPorts = (options as any)?.ports;\n const optSource = (options as any)?.source;\n\n const params: any = { timeout, ...providerOptions };\n const optDaemonSsePort = (options as any)?.daemonSsePort as number | false | undefined;\n const ports = mergeExposedPorts(optPorts, config.ports, optDaemonSsePort ?? config.daemonSsePort);\n if (ports && ports.length > 0) params.ports = ports;\n\n if (optRuntime) {\n params.runtime =\n optRuntime === 'node' ? 'node24' :\n optRuntime === 'python' ? 'python3.13' :\n optRuntime;\n }\n\n const snapshotId = optSnapshotId || templateId ||\n (optSource?.type === 'snapshot' && optSource?.snapshotId);\n if (snapshotId) {\n params.source = { type: 'snapshot', snapshotId };\n } else if (optSource) {\n params.source = optSource;\n }\n\n if (!creds.useOidc) {\n params.token = creds.token;\n params.teamId = creds.teamId;\n params.projectId = creds.projectId;\n }\n\n const sandbox = await VercelSandbox.create(params);\n return { sandbox, sandboxId: sandbox.sandboxId };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('token')) {\n throw new Error(`Vercel authentication failed. Please check your VERCEL_TOKEN environment variable.`);\n }\n if (error.message.includes('team') || error.message.includes('project')) {\n throw new Error(`Vercel team/project configuration failed. Check VERCEL_TEAM_ID and VERCEL_PROJECT_ID.`);\n }\n }\n throw new Error(`Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n getById: async (config: VercelConfig, sandboxId: string) => {\n const creds = resolveCredentials(config);\n try {\n const sandbox = creds.useOidc\n ? await VercelSandbox.get({ sandboxId })\n : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n return { sandbox, sandboxId };\n } catch { return null; }\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(`Vercel provider does not support listing sandboxes.`);\n },\n\n destroy: async (config: VercelConfig, sandboxId: string) => {\n const creds = resolveCredentials(config);\n try {\n const sandbox = creds.useOidc\n ? await VercelSandbox.get({ sandboxId })\n : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n await sandbox.stop();\n } catch { /* already destroyed or doesn't exist */ }\n },\n\n runCommand: async (sandbox: VercelSandbox, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n const startTime = Date.now();\n try {\n let fullCommand = command;\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env).map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`).join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n const stdout = options?.background ? undefined : getUtf8Sink();\n const stderr = options?.background ? undefined : getUtf8Sink();\n const result = await sandbox.runCommand({\n cmd: 'sh', args: ['-c', fullCommand],\n cwd: options?.cwd, detached: options?.background,\n stdout: stdout?.sink, stderr: stderr?.sink,\n });\n return { stdout: stdout?.value() ?? '', stderr: stderr?.value() ?? '', exitCode: result.exitCode ?? 0, durationMs: Date.now() - startTime };\n } catch (error) {\n return { stdout: '', stderr: error instanceof Error ? error.message : String(error), exitCode: 127, durationMs: Date.now() - startTime };\n }\n },\n\n getInfo: async (_sandbox: VercelSandbox): Promise<SandboxInfo> => ({\n id: 'vercel-unknown',\n provider: 'vercel',\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: { vercelSandboxId: 'vercel-unknown' }\n }),\n\n getUrl: async (sandbox: VercelSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n let url = sandbox.domain(options.port);\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n return url;\n } catch (error) {\n throw new Error(`Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}.`);\n }\n },\n\n filesystem: {\n readFile: async (sandbox: VercelSandbox, path: string): Promise<string> => {\n const stream = await sandbox.readFile({ path });\n if (!stream) throw new Error(`File not found: ${path}`);\n const chunks: Buffer[] = [];\n for await (const chunk of stream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return Buffer.concat(chunks).toString('utf-8');\n },\n writeFile: async (sandbox: VercelSandbox, path: string, content: string): Promise<void> => {\n await sandbox.writeFiles([{ path, content: Buffer.from(content) }]);\n },\n mkdir: async (sandbox: VercelSandbox, path: string): Promise<void> => { await sandbox.mkDir(path); },\n readdir: async (_sandbox: VercelSandbox, _path: string): Promise<FileEntry[]> => {\n throw new Error('Vercel sandbox does not support readdir.');\n },\n exists: async (_sandbox: VercelSandbox, _path: string): Promise<boolean> => {\n throw new Error('Vercel sandbox does not support exists.');\n },\n remove: async (_sandbox: VercelSandbox, _path: string): Promise<void> => {\n throw new Error('Vercel sandbox does not support remove.');\n }\n },\n\n getInstance: (sandbox: VercelSandbox): VercelSandbox => sandbox,\n },\n\n snapshot: {\n create: async (config: VercelConfig, sandboxId: string) => {\n const creds = resolveCredentials(config);\n const sandbox = creds.useOidc\n ? await VercelSandbox.get({ sandboxId })\n : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n return await sandbox.snapshot();\n },\n list: async (_config: VercelConfig) => { throw new Error(`Vercel provider does not support listing snapshots.`); },\n delete: async (config: VercelConfig, snapshotId: string) => {\n const creds = resolveCredentials(config);\n const snapshot = creds.useOidc\n ? await VercelSnapshot.get({ snapshotId })\n : await VercelSnapshot.get({ snapshotId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n await snapshot.delete();\n }\n },\n\n template: {\n create: async (_config: VercelConfig, _options: { name: string }) => {\n throw new Error(`Vercel does not support creating templates directly. Use snapshot.create() instead.`);\n },\n list: async (_config: VercelConfig) => { throw new Error(`Vercel provider does not support listing templates.`); },\n delete: async (config: VercelConfig, templateId: string) => {\n const creds = resolveCredentials(config);\n const snapshot = creds.useOidc\n ? await VercelSnapshot.get({ snapshotId: templateId })\n : await VercelSnapshot.get({ snapshotId: templateId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n await snapshot.delete();\n }\n }\n }\n});\n"],"mappings":"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","names":["VercelSandbox","VercelSnapshot"]}
|
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
import { Sandbox as VercelSandbox, Snapshot as VercelSnapshot } from "@vercel/sandbox";
|
|
3
3
|
import { defineProvider, escapeShellArg } from "@computesdk/provider";
|
|
4
4
|
import { Writable } from "stream";
|
|
5
|
+
var DEFAULT_DAEMON_SSE_PORT = 38989;
|
|
6
|
+
function mergeExposedPorts(primary, fallback, daemonSsePort) {
|
|
7
|
+
const daemonPort = daemonSsePort === false ? void 0 : daemonSsePort ?? DEFAULT_DAEMON_SSE_PORT;
|
|
8
|
+
const merged = [...primary ?? fallback ?? []];
|
|
9
|
+
if (typeof daemonPort === "number") merged.push(daemonPort);
|
|
10
|
+
return Array.from(new Set(merged.filter((port) => Number.isInteger(port) && port > 0 && port <= 65535)));
|
|
11
|
+
}
|
|
5
12
|
function resolveCredentials(config) {
|
|
6
13
|
const token = config.token || typeof process !== "undefined" && process.env?.VERCEL_TOKEN || "";
|
|
7
14
|
const teamId = config.teamId || typeof process !== "undefined" && process.env?.VERCEL_TEAM_ID || "";
|
|
@@ -12,26 +19,16 @@ function resolveCredentials(config) {
|
|
|
12
19
|
return { useOidc, token, teamId, projectId };
|
|
13
20
|
}
|
|
14
21
|
function validateCredentials(creds) {
|
|
15
|
-
if (creds.useOidc)
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
22
|
+
if (creds.useOidc) return;
|
|
18
23
|
if (!creds.token) {
|
|
19
24
|
throw new Error(
|
|
20
25
|
`Missing Vercel authentication. Either:
|
|
21
26
|
1. Use OIDC token: Run 'vercel env pull' to get VERCEL_OIDC_TOKEN, or
|
|
22
|
-
2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
if (!creds.teamId) {
|
|
26
|
-
throw new Error(
|
|
27
|
-
`Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID environment variable.`
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
if (!creds.projectId) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID environment variable.`
|
|
27
|
+
2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable.`
|
|
33
28
|
);
|
|
34
29
|
}
|
|
30
|
+
if (!creds.teamId) throw new Error(`Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID.`);
|
|
31
|
+
if (!creds.projectId) throw new Error(`Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID.`);
|
|
35
32
|
}
|
|
36
33
|
function getUtf8Sink() {
|
|
37
34
|
const chunks = [];
|
|
@@ -47,18 +44,14 @@ var vercel = defineProvider({
|
|
|
47
44
|
name: "vercel",
|
|
48
45
|
methods: {
|
|
49
46
|
sandbox: {
|
|
50
|
-
// Collection operations (map to compute.sandbox.*)
|
|
51
47
|
create: async (config, options) => {
|
|
52
48
|
const creds = resolveCredentials(config);
|
|
53
49
|
validateCredentials(creds);
|
|
54
50
|
const timeout = options?.timeout ?? config.timeout ?? 3e5;
|
|
55
51
|
try {
|
|
56
|
-
let sandbox;
|
|
57
52
|
const {
|
|
58
|
-
runtime: optRuntime,
|
|
59
53
|
timeout: _timeout,
|
|
60
54
|
envs: _envs,
|
|
61
|
-
// Vercel SDK does not support envs at sandbox creation time
|
|
62
55
|
name: _name,
|
|
63
56
|
metadata: _metadata,
|
|
64
57
|
templateId,
|
|
@@ -66,29 +59,21 @@ var vercel = defineProvider({
|
|
|
66
59
|
sandboxId: _sandboxId,
|
|
67
60
|
namespace: _namespace,
|
|
68
61
|
directory: _directory,
|
|
69
|
-
ports: optPorts,
|
|
70
|
-
source: optSource,
|
|
71
62
|
...providerOptions
|
|
72
63
|
} = options || {};
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const ports = optPorts ?? config.
|
|
79
|
-
if (ports && ports.length > 0)
|
|
80
|
-
params.ports = ports;
|
|
81
|
-
}
|
|
64
|
+
const optRuntime = options?.runtime;
|
|
65
|
+
const optPorts = options?.ports;
|
|
66
|
+
const optSource = options?.source;
|
|
67
|
+
const params = { timeout, ...providerOptions };
|
|
68
|
+
const optDaemonSsePort = options?.daemonSsePort;
|
|
69
|
+
const ports = mergeExposedPorts(optPorts, config.ports, optDaemonSsePort ?? config.daemonSsePort);
|
|
70
|
+
if (ports && ports.length > 0) params.ports = ports;
|
|
82
71
|
if (optRuntime) {
|
|
83
|
-
|
|
84
|
-
params.runtime = vercelRuntime;
|
|
72
|
+
params.runtime = optRuntime === "node" ? "node24" : optRuntime === "python" ? "python3.13" : optRuntime;
|
|
85
73
|
}
|
|
86
74
|
const snapshotId = optSnapshotId || templateId || optSource?.type === "snapshot" && optSource?.snapshotId;
|
|
87
75
|
if (snapshotId) {
|
|
88
|
-
params.source = {
|
|
89
|
-
type: "snapshot",
|
|
90
|
-
snapshotId
|
|
91
|
-
};
|
|
76
|
+
params.source = { type: "snapshot", snapshotId };
|
|
92
77
|
} else if (optSource) {
|
|
93
78
|
params.source = optSource;
|
|
94
79
|
}
|
|
@@ -97,75 +82,40 @@ var vercel = defineProvider({
|
|
|
97
82
|
params.teamId = creds.teamId;
|
|
98
83
|
params.projectId = creds.projectId;
|
|
99
84
|
}
|
|
100
|
-
sandbox = await VercelSandbox.create(params);
|
|
101
|
-
return {
|
|
102
|
-
sandbox,
|
|
103
|
-
sandboxId: sandbox.sandboxId
|
|
104
|
-
};
|
|
85
|
+
const sandbox = await VercelSandbox.create(params);
|
|
86
|
+
return { sandbox, sandboxId: sandbox.sandboxId };
|
|
105
87
|
} catch (error) {
|
|
106
88
|
if (error instanceof Error) {
|
|
107
89
|
if (error.message.includes("unauthorized") || error.message.includes("token")) {
|
|
108
|
-
throw new Error(
|
|
109
|
-
`Vercel authentication failed. Please check your VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`
|
|
110
|
-
);
|
|
90
|
+
throw new Error(`Vercel authentication failed. Please check your VERCEL_TOKEN environment variable.`);
|
|
111
91
|
}
|
|
112
92
|
if (error.message.includes("team") || error.message.includes("project")) {
|
|
113
|
-
throw new Error(
|
|
114
|
-
`Vercel team/project configuration failed. Please check your VERCEL_TEAM_ID and VERCEL_PROJECT_ID environment variables.`
|
|
115
|
-
);
|
|
93
|
+
throw new Error(`Vercel team/project configuration failed. Check VERCEL_TEAM_ID and VERCEL_PROJECT_ID.`);
|
|
116
94
|
}
|
|
117
95
|
}
|
|
118
|
-
throw new Error(
|
|
119
|
-
`Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`
|
|
120
|
-
);
|
|
96
|
+
throw new Error(`Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`);
|
|
121
97
|
}
|
|
122
98
|
},
|
|
123
99
|
getById: async (config, sandboxId) => {
|
|
124
100
|
const creds = resolveCredentials(config);
|
|
125
101
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
} else {
|
|
130
|
-
sandbox = await VercelSandbox.get({
|
|
131
|
-
sandboxId,
|
|
132
|
-
token: creds.token,
|
|
133
|
-
teamId: creds.teamId,
|
|
134
|
-
projectId: creds.projectId
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
sandbox,
|
|
139
|
-
sandboxId
|
|
140
|
-
};
|
|
141
|
-
} catch (error) {
|
|
102
|
+
const sandbox = creds.useOidc ? await VercelSandbox.get({ sandboxId }) : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
103
|
+
return { sandbox, sandboxId };
|
|
104
|
+
} catch {
|
|
142
105
|
return null;
|
|
143
106
|
}
|
|
144
107
|
},
|
|
145
108
|
list: async (_config) => {
|
|
146
|
-
throw new Error(
|
|
147
|
-
`Vercel provider does not support listing sandboxes. Vercel sandboxes are ephemeral and designed for single-use execution.`
|
|
148
|
-
);
|
|
109
|
+
throw new Error(`Vercel provider does not support listing sandboxes.`);
|
|
149
110
|
},
|
|
150
111
|
destroy: async (config, sandboxId) => {
|
|
151
112
|
const creds = resolveCredentials(config);
|
|
152
113
|
try {
|
|
153
|
-
|
|
154
|
-
if (creds.useOidc) {
|
|
155
|
-
sandbox = await VercelSandbox.get({ sandboxId });
|
|
156
|
-
} else {
|
|
157
|
-
sandbox = await VercelSandbox.get({
|
|
158
|
-
sandboxId,
|
|
159
|
-
token: creds.token,
|
|
160
|
-
teamId: creds.teamId,
|
|
161
|
-
projectId: creds.projectId
|
|
162
|
-
});
|
|
163
|
-
}
|
|
114
|
+
const sandbox = creds.useOidc ? await VercelSandbox.get({ sandboxId }) : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
164
115
|
await sandbox.stop();
|
|
165
|
-
} catch
|
|
116
|
+
} catch {
|
|
166
117
|
}
|
|
167
118
|
},
|
|
168
|
-
// Instance operations (map to individual Sandbox methods)
|
|
169
119
|
runCommand: async (sandbox, command, options) => {
|
|
170
120
|
const startTime = Date.now();
|
|
171
121
|
try {
|
|
@@ -184,35 +134,19 @@ var vercel = defineProvider({
|
|
|
184
134
|
stdout: stdout?.sink,
|
|
185
135
|
stderr: stderr?.sink
|
|
186
136
|
});
|
|
187
|
-
return {
|
|
188
|
-
stdout: stdout?.value() ?? "",
|
|
189
|
-
stderr: stderr?.value() ?? "",
|
|
190
|
-
exitCode: result.exitCode ?? 0,
|
|
191
|
-
durationMs: Date.now() - startTime
|
|
192
|
-
};
|
|
137
|
+
return { stdout: stdout?.value() ?? "", stderr: stderr?.value() ?? "", exitCode: result.exitCode ?? 0, durationMs: Date.now() - startTime };
|
|
193
138
|
} catch (error) {
|
|
194
|
-
return {
|
|
195
|
-
stdout: "",
|
|
196
|
-
stderr: error instanceof Error ? error.message : String(error),
|
|
197
|
-
exitCode: 127,
|
|
198
|
-
durationMs: Date.now() - startTime
|
|
199
|
-
};
|
|
139
|
+
return { stdout: "", stderr: error instanceof Error ? error.message : String(error), exitCode: 127, durationMs: Date.now() - startTime };
|
|
200
140
|
}
|
|
201
141
|
},
|
|
202
|
-
getInfo: async (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
timeout: 3e5,
|
|
211
|
-
metadata: {
|
|
212
|
-
vercelSandboxId: "vercel-unknown"
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
},
|
|
142
|
+
getInfo: async (_sandbox) => ({
|
|
143
|
+
id: "vercel-unknown",
|
|
144
|
+
provider: "vercel",
|
|
145
|
+
status: "running",
|
|
146
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
147
|
+
timeout: 3e5,
|
|
148
|
+
metadata: { vercelSandboxId: "vercel-unknown" }
|
|
149
|
+
}),
|
|
216
150
|
getUrl: async (sandbox, options) => {
|
|
217
151
|
try {
|
|
218
152
|
let url = sandbox.domain(options.port);
|
|
@@ -223,21 +157,15 @@ var vercel = defineProvider({
|
|
|
223
157
|
}
|
|
224
158
|
return url;
|
|
225
159
|
} catch (error) {
|
|
226
|
-
throw new Error(
|
|
227
|
-
`Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}. Ensure the port has an associated route.`
|
|
228
|
-
);
|
|
160
|
+
throw new Error(`Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}.`);
|
|
229
161
|
}
|
|
230
162
|
},
|
|
231
163
|
filesystem: {
|
|
232
164
|
readFile: async (sandbox, path) => {
|
|
233
165
|
const stream = await sandbox.readFile({ path });
|
|
234
|
-
if (!stream) {
|
|
235
|
-
throw new Error(`File not found: ${path}`);
|
|
236
|
-
}
|
|
166
|
+
if (!stream) throw new Error(`File not found: ${path}`);
|
|
237
167
|
const chunks = [];
|
|
238
|
-
for await (const chunk of stream)
|
|
239
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
240
|
-
}
|
|
168
|
+
for await (const chunk of stream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
241
169
|
return Buffer.concat(chunks).toString("utf-8");
|
|
242
170
|
},
|
|
243
171
|
writeFile: async (sandbox, path, content) => {
|
|
@@ -247,82 +175,42 @@ var vercel = defineProvider({
|
|
|
247
175
|
await sandbox.mkDir(path);
|
|
248
176
|
},
|
|
249
177
|
readdir: async (_sandbox, _path) => {
|
|
250
|
-
throw new Error("Vercel sandbox does not support readdir.
|
|
178
|
+
throw new Error("Vercel sandbox does not support readdir.");
|
|
251
179
|
},
|
|
252
180
|
exists: async (_sandbox, _path) => {
|
|
253
|
-
throw new Error("Vercel sandbox does not support exists.
|
|
181
|
+
throw new Error("Vercel sandbox does not support exists.");
|
|
254
182
|
},
|
|
255
183
|
remove: async (_sandbox, _path) => {
|
|
256
|
-
throw new Error("Vercel sandbox does not support remove.
|
|
184
|
+
throw new Error("Vercel sandbox does not support remove.");
|
|
257
185
|
}
|
|
258
186
|
},
|
|
259
|
-
|
|
260
|
-
getInstance: (sandbox) => {
|
|
261
|
-
return sandbox;
|
|
262
|
-
}
|
|
187
|
+
getInstance: (sandbox) => sandbox
|
|
263
188
|
},
|
|
264
189
|
snapshot: {
|
|
265
190
|
create: async (config, sandboxId) => {
|
|
266
191
|
const creds = resolveCredentials(config);
|
|
267
|
-
|
|
268
|
-
if (creds.useOidc) {
|
|
269
|
-
sandbox = await VercelSandbox.get({ sandboxId });
|
|
270
|
-
} else {
|
|
271
|
-
sandbox = await VercelSandbox.get({
|
|
272
|
-
sandboxId,
|
|
273
|
-
token: creds.token,
|
|
274
|
-
teamId: creds.teamId,
|
|
275
|
-
projectId: creds.projectId
|
|
276
|
-
});
|
|
277
|
-
}
|
|
192
|
+
const sandbox = creds.useOidc ? await VercelSandbox.get({ sandboxId }) : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
278
193
|
return await sandbox.snapshot();
|
|
279
194
|
},
|
|
280
195
|
list: async (_config) => {
|
|
281
|
-
throw new Error(
|
|
282
|
-
`Vercel provider does not support listing snapshots.`
|
|
283
|
-
);
|
|
196
|
+
throw new Error(`Vercel provider does not support listing snapshots.`);
|
|
284
197
|
},
|
|
285
198
|
delete: async (config, snapshotId) => {
|
|
286
199
|
const creds = resolveCredentials(config);
|
|
287
|
-
|
|
288
|
-
if (creds.useOidc) {
|
|
289
|
-
snapshot = await VercelSnapshot.get({ snapshotId });
|
|
290
|
-
} else {
|
|
291
|
-
snapshot = await VercelSnapshot.get({
|
|
292
|
-
snapshotId,
|
|
293
|
-
token: creds.token,
|
|
294
|
-
teamId: creds.teamId,
|
|
295
|
-
projectId: creds.projectId
|
|
296
|
-
});
|
|
297
|
-
}
|
|
200
|
+
const snapshot = creds.useOidc ? await VercelSnapshot.get({ snapshotId }) : await VercelSnapshot.get({ snapshotId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
298
201
|
await snapshot.delete();
|
|
299
202
|
}
|
|
300
203
|
},
|
|
301
|
-
// Vercel doesn't have a separate "template" concept - snapshots serve as templates
|
|
302
204
|
template: {
|
|
303
205
|
create: async (_config, _options) => {
|
|
304
|
-
throw new Error(
|
|
305
|
-
`Vercel does not support creating templates directly. Use snapshot.create() to create a snapshot from a running sandbox.`
|
|
306
|
-
);
|
|
206
|
+
throw new Error(`Vercel does not support creating templates directly. Use snapshot.create() instead.`);
|
|
307
207
|
},
|
|
308
208
|
list: async (_config) => {
|
|
309
|
-
throw new Error(
|
|
310
|
-
`Vercel provider does not support listing templates.`
|
|
311
|
-
);
|
|
209
|
+
throw new Error(`Vercel provider does not support listing templates.`);
|
|
312
210
|
},
|
|
313
211
|
delete: async (config, templateId) => {
|
|
314
212
|
const creds = resolveCredentials(config);
|
|
315
|
-
|
|
316
|
-
if (creds.useOidc) {
|
|
317
|
-
snapshot = await VercelSnapshot.get({ snapshotId: templateId });
|
|
318
|
-
} else {
|
|
319
|
-
snapshot = await VercelSnapshot.get({
|
|
320
|
-
snapshotId: templateId,
|
|
321
|
-
token: creds.token,
|
|
322
|
-
teamId: creds.teamId,
|
|
323
|
-
projectId: creds.projectId
|
|
324
|
-
});
|
|
325
|
-
}
|
|
213
|
+
const snapshot = creds.useOidc ? await VercelSnapshot.get({ snapshotId: templateId }) : await VercelSnapshot.get({ snapshotId: templateId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });
|
|
326
214
|
await snapshot.delete();
|
|
327
215
|
}
|
|
328
216
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Vercel Provider - Factory-based Implementation\n * \n * Demonstrates the new defineProvider() factory pattern with ~50 lines\n * instead of the original ~350 lines of boilerplate.\n */\n\nimport { Sandbox as VercelSandbox, Snapshot as VercelSnapshot } from '@vercel/sandbox';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\nimport { Writable } from 'node:stream';\n\nexport type { VercelSandbox, VercelSnapshot };\n\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\n/**\n * Vercel sandbox provider configuration\n */\nexport interface VercelConfig {\n /** Vercel API token */\n token?: string;\n /** Vercel team ID */\n teamId?: string;\n /** Vercel project ID */\n projectId?: string;\n /** Runtime environment for code execution */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Ports to expose */\n ports?: number[];\n}\n\n/**\n * Resolved Vercel credentials with the authentication method to use\n */\ninterface ResolvedCredentials {\n /** Whether to use OIDC authentication (no explicit credentials needed) */\n useOidc: boolean;\n /** Token for traditional auth (only used if useOidc is false) */\n token: string;\n /** Team ID for traditional auth (only used if useOidc is false) */\n teamId: string;\n /** Project ID for traditional auth (only used if useOidc is false) */\n projectId: string;\n}\n\n/**\n * Resolve Vercel credentials with proper precedence:\n * 1. Config values (from setConfig) always win\n * 2. Environment variables are used as fallback\n * 3. OIDC is only used when no config credentials are provided\n */\nfunction resolveCredentials(config: VercelConfig): ResolvedCredentials {\n // Get values from config first, then fall back to environment\n const token = config.token || (typeof process !== 'undefined' && process.env?.VERCEL_TOKEN) || '';\n const teamId = config.teamId || (typeof process !== 'undefined' && process.env?.VERCEL_TEAM_ID) || '';\n const projectId = config.projectId || (typeof process !== 'undefined' && process.env?.VERCEL_PROJECT_ID) || '';\n \n // Check if config explicitly provided credentials (config takes precedence)\n const hasConfigCredentials = !!(config.token || config.teamId || config.projectId);\n \n // Only use OIDC if:\n // 1. No config credentials were provided, AND\n // 2. OIDC token is available in environment\n const oidcToken = typeof process !== 'undefined' && process.env?.VERCEL_OIDC_TOKEN;\n const useOidc = !hasConfigCredentials && !!oidcToken;\n \n return { useOidc, token, teamId, projectId };\n}\n\n/**\n * Validate that we have sufficient credentials to authenticate\n */\nfunction validateCredentials(creds: ResolvedCredentials): void {\n if (creds.useOidc) {\n // OIDC auth - no additional validation needed\n return;\n }\n \n // Traditional auth - need all three\n if (!creds.token) {\n throw new Error(\n `Missing Vercel authentication. Either:\\n` +\n `1. Use OIDC token: Run 'vercel env pull' to get VERCEL_OIDC_TOKEN, or\\n` +\n `2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`\n );\n }\n if (!creds.teamId) {\n throw new Error(\n `Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID environment variable.`\n );\n }\n if (!creds.projectId) {\n throw new Error(\n `Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID environment variable.`\n );\n }\n}\n\n/**\n * Get a writable stream that collects UTF-8 string data and buffers it\n * in memory, returning the full concatenated string when done.\n */\nfunction getUtf8Sink() {\n const chunks: string[] = [];\n const sink = new Writable({\n write(chunk, _enc, cb) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk.toString(\"utf8\") :\n String(chunk));\n cb();\n },\n });\n return { sink, value: () => chunks.join(\"\") };\n}\n\n\n\n/**\n * Create a Vercel provider instance using the factory pattern\n */\nexport const vercel = defineProvider<VercelSandbox, VercelConfig, any, VercelSnapshot>({\n name: 'vercel',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: VercelConfig, options?: CreateSandboxOptions) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n validateCredentials(creds);\n\n // options.timeout takes precedence over config.timeout\n const timeout = options?.timeout ?? config.timeout ?? 300000;\n\n try {\n let sandbox: VercelSandbox;\n\n // Destructure known ComputeSDK fields, collect the rest for passthrough\n const {\n runtime: optRuntime,\n timeout: _timeout,\n envs: _envs, // Vercel SDK does not support envs at sandbox creation time\n name: _name,\n metadata: _metadata,\n templateId,\n snapshotId: optSnapshotId,\n sandboxId: _sandboxId,\n namespace: _namespace,\n directory: _directory,\n ports: optPorts,\n source: optSource,\n ...providerOptions\n } = options || {};\n\n // Construct base params, spreading provider-specific options\n const params: any = {\n timeout,\n ...providerOptions, // Spread provider-specific options (e.g., resources, networkPolicy, signal)\n };\n \n // Only add ports if explicitly configured (options.ports takes precedence)\n const ports = optPorts ?? config.ports;\n if (ports && ports.length > 0) {\n params.ports = ports;\n }\n\n // Pass runtime if specified (Vercel supports runtime selection).\n // Vercel only accepts specific versioned runtimes (node24, node22, python3.13),\n // so translate ComputeSDK's generic names to Vercel's expected format.\n if (optRuntime) {\n const vercelRuntime =\n optRuntime === 'node' ? 'node24' :\n optRuntime === 'python' ? 'python3.13' :\n optRuntime;\n params.runtime = vercelRuntime;\n }\n\n // Support both ComputeSDK format (snapshotId/templateId at top level) and \n // Vercel SDK format (source.snapshotId nested)\n const snapshotId = optSnapshotId || templateId ||\n (optSource?.type === 'snapshot' && optSource?.snapshotId);\n \n if (snapshotId) {\n params.source = {\n type: 'snapshot',\n snapshotId\n };\n } else if (optSource) {\n // Pass through source as-is (e.g., git or tarball sources)\n params.source = optSource;\n }\n\n // Add auth params if not using OIDC\n if (!creds.useOidc) {\n params.token = creds.token;\n params.teamId = creds.teamId;\n params.projectId = creds.projectId;\n }\n\n sandbox = await VercelSandbox.create(params);\n\n return {\n sandbox,\n sandboxId: sandbox.sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('token')) {\n throw new Error(\n `Vercel authentication failed. Please check your VERCEL_TOKEN environment variable. Get your token from https://vercel.com/account/tokens`\n );\n }\n if (error.message.includes('team') || error.message.includes('project')) {\n throw new Error(\n `Vercel team/project configuration failed. Please check your VERCEL_TEAM_ID and VERCEL_PROJECT_ID environment variables.`\n );\n }\n }\n throw new Error(\n `Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: VercelConfig, sandboxId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n try {\n let sandbox: VercelSandbox;\n\n if (creds.useOidc) {\n // Use OIDC token method\n sandbox = await VercelSandbox.get({ sandboxId });\n } else {\n // Use traditional method\n sandbox = await VercelSandbox.get({\n sandboxId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n return {\n sandbox,\n sandboxId\n };\n } catch (error) {\n // Sandbox doesn't exist or can't be accessed\n return null;\n }\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(\n `Vercel provider does not support listing sandboxes. Vercel sandboxes are ephemeral and designed for single-use execution.`\n );\n },\n\n destroy: async (config: VercelConfig, sandboxId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n try {\n let sandbox: VercelSandbox;\n\n if (creds.useOidc) {\n // Use OIDC token method\n sandbox = await VercelSandbox.get({ sandboxId });\n } else {\n // Use traditional method\n sandbox = await VercelSandbox.get({\n sandboxId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n await sandbox.stop();\n } catch (error) {\n // Sandbox 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\n runCommand: async (sandbox: VercelSandbox, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n const startTime = Date.now();\n\n try {\n // Build command with options\n let fullCommand = command;\n \n // Handle environment variables\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env)\n .map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`)\n .join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n\n // If running in the background, don't capture stdout/stderr\n const stdout = options?.background ? undefined : getUtf8Sink();\n const stderr = options?.background ? undefined : getUtf8Sink();\n\n const result = await sandbox.runCommand({\n cmd: 'sh',\n args: ['-c', fullCommand],\n cwd: options?.cwd,\n detached: options?.background,\n stdout: stdout?.sink,\n stderr: stderr?.sink,\n });\n\n return {\n stdout: stdout?.value() ?? '',\n stderr: stderr?.value() ?? '',\n exitCode: result.exitCode ?? 0,\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: VercelSandbox): Promise<SandboxInfo> => {\n return {\n id: 'vercel-unknown',\n provider: 'vercel',\n runtime: 'node', // Vercel default\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n vercelSandboxId: 'vercel-unknown'\n }\n };\n },\n\n getUrl: async (sandbox: VercelSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n // Use Vercel's built-in domain method to get the real domain\n let url = sandbox.domain(options.port);\n \n // If a specific protocol is requested, replace the URL's protocol\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}. Ensure the port has an associated route.`\n );\n }\n },\n\n filesystem: {\n readFile: async (sandbox: VercelSandbox, path: string): Promise<string> => {\n const stream = await sandbox.readFile({ path });\n if (!stream) {\n throw new Error(`File not found: ${path}`);\n }\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString('utf-8');\n },\n\n writeFile: async (sandbox: VercelSandbox, path: string, content: string): Promise<void> => {\n await sandbox.writeFiles([{ path, content: Buffer.from(content) }]);\n },\n\n mkdir: async (sandbox: VercelSandbox, path: string): Promise<void> => {\n await sandbox.mkDir(path);\n },\n\n readdir: async (_sandbox: VercelSandbox, _path: string): Promise<FileEntry[]> => {\n throw new Error('Vercel sandbox does not support readdir. Use runCommand to list directory contents.');\n },\n\n exists: async (_sandbox: VercelSandbox, _path: string): Promise<boolean> => {\n throw new Error('Vercel sandbox does not support exists. Use runCommand to check file existence.');\n },\n\n remove: async (_sandbox: VercelSandbox, _path: string): Promise<void> => {\n throw new Error('Vercel sandbox does not support remove. Use runCommand to delete files.');\n }\n },\n\n // Provider-specific typed getInstance method\n getInstance: (sandbox: VercelSandbox): VercelSandbox => {\n return sandbox;\n },\n\n },\n\n snapshot: {\n create: async (config: VercelConfig, sandboxId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n let sandbox: VercelSandbox;\n\n if (creds.useOidc) {\n // Use OIDC token method\n sandbox = await VercelSandbox.get({ sandboxId });\n } else {\n // Use traditional method\n sandbox = await VercelSandbox.get({\n sandboxId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n return await sandbox.snapshot();\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(\n `Vercel provider does not support listing snapshots.`\n );\n },\n\n delete: async (config: VercelConfig, snapshotId: string) => {\n // Resolve credentials with proper precedence (config wins over env)\n const creds = resolveCredentials(config);\n\n let snapshot: VercelSnapshot;\n\n if (creds.useOidc) {\n // Use OIDC token method\n snapshot = await VercelSnapshot.get({ snapshotId });\n } else {\n // Use traditional method\n snapshot = await VercelSnapshot.get({\n snapshotId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n await snapshot.delete();\n }\n },\n\n // Vercel doesn't have a separate \"template\" concept - snapshots serve as templates\n template: {\n create: async (_config: VercelConfig, _options: { name: string }) => {\n throw new Error(\n `Vercel does not support creating templates directly. Use snapshot.create() to create a snapshot from a running sandbox.`\n );\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(\n `Vercel provider does not support listing templates.`\n );\n },\n\n delete: async (config: VercelConfig, templateId: string) => {\n // Reuse snapshot.delete since Vercel doesn't have separate templates\n const creds = resolveCredentials(config);\n\n let snapshot: VercelSnapshot;\n\n if (creds.useOidc) {\n snapshot = await VercelSnapshot.get({ snapshotId: templateId });\n } else {\n snapshot = await VercelSnapshot.get({\n snapshotId: templateId,\n token: creds.token,\n teamId: creds.teamId,\n projectId: creds.projectId,\n });\n }\n\n await snapshot.delete();\n }\n }\n }\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Vercel Provider - Factory-based Implementation\n */\n\nimport { Sandbox as VercelSandbox, Snapshot as VercelSnapshot } from '@vercel/sandbox';\nimport { defineProvider, escapeShellArg } from '@computesdk/provider';\nimport { Writable } from 'node:stream';\n\nexport type { VercelSandbox, VercelSnapshot };\n\nimport type { CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\nexport interface VercelConfig {\n token?: string;\n teamId?: string;\n projectId?: string;\n timeout?: number;\n ports?: number[];\n daemonSsePort?: number | false;\n}\n\nconst DEFAULT_DAEMON_SSE_PORT = 38989;\n\nfunction mergeExposedPorts(primary?: number[], fallback?: number[], daemonSsePort?: number | false): number[] {\n const daemonPort = daemonSsePort === false ? undefined : (daemonSsePort ?? DEFAULT_DAEMON_SSE_PORT);\n const merged = [...(primary ?? fallback ?? [])];\n if (typeof daemonPort === 'number') merged.push(daemonPort);\n return Array.from(new Set(merged.filter((port) => Number.isInteger(port) && port > 0 && port <= 65535)));\n}\n\ninterface ResolvedCredentials {\n useOidc: boolean;\n token: string;\n teamId: string;\n projectId: string;\n}\n\nfunction resolveCredentials(config: VercelConfig): ResolvedCredentials {\n const token = config.token || (typeof process !== 'undefined' && process.env?.VERCEL_TOKEN) || '';\n const teamId = config.teamId || (typeof process !== 'undefined' && process.env?.VERCEL_TEAM_ID) || '';\n const projectId = config.projectId || (typeof process !== 'undefined' && process.env?.VERCEL_PROJECT_ID) || '';\n const hasConfigCredentials = !!(config.token || config.teamId || config.projectId);\n const oidcToken = typeof process !== 'undefined' && process.env?.VERCEL_OIDC_TOKEN;\n const useOidc = !hasConfigCredentials && !!oidcToken;\n return { useOidc, token, teamId, projectId };\n}\n\nfunction validateCredentials(creds: ResolvedCredentials): void {\n if (creds.useOidc) return;\n if (!creds.token) {\n throw new Error(\n `Missing Vercel authentication. Either:\\n` +\n `1. Use OIDC token: Run 'vercel env pull' to get VERCEL_OIDC_TOKEN, or\\n` +\n `2. Use traditional method: Provide 'token' in config or set VERCEL_TOKEN environment variable.`\n );\n }\n if (!creds.teamId) throw new Error(`Missing Vercel team ID. Provide 'teamId' in config or set VERCEL_TEAM_ID.`);\n if (!creds.projectId) throw new Error(`Missing Vercel project ID. Provide 'projectId' in config or set VERCEL_PROJECT_ID.`);\n}\n\nfunction getUtf8Sink() {\n const chunks: string[] = [];\n const sink = new Writable({\n write(chunk, _enc, cb) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk.toString(\"utf8\") : String(chunk));\n cb();\n },\n });\n return { sink, value: () => chunks.join(\"\") };\n}\n\nexport const vercel = defineProvider<VercelSandbox, VercelConfig, any, VercelSnapshot>({\n name: 'vercel',\n methods: {\n sandbox: {\n create: async (config: VercelConfig, options?: CreateSandboxOptions) => {\n const creds = resolveCredentials(config);\n validateCredentials(creds);\n const timeout = options?.timeout ?? config.timeout ?? 300000;\n try {\n const {\n timeout: _timeout, envs: _envs, name: _name, metadata: _metadata,\n templateId, snapshotId: optSnapshotId, sandboxId: _sandboxId,\n namespace: _namespace, directory: _directory,\n ...providerOptions\n } = options || {};\n const optRuntime = (options as any)?.runtime;\n const optPorts = (options as any)?.ports;\n const optSource = (options as any)?.source;\n\n const params: any = { timeout, ...providerOptions };\n const optDaemonSsePort = (options as any)?.daemonSsePort as number | false | undefined;\n const ports = mergeExposedPorts(optPorts, config.ports, optDaemonSsePort ?? config.daemonSsePort);\n if (ports && ports.length > 0) params.ports = ports;\n\n if (optRuntime) {\n params.runtime =\n optRuntime === 'node' ? 'node24' :\n optRuntime === 'python' ? 'python3.13' :\n optRuntime;\n }\n\n const snapshotId = optSnapshotId || templateId ||\n (optSource?.type === 'snapshot' && optSource?.snapshotId);\n if (snapshotId) {\n params.source = { type: 'snapshot', snapshotId };\n } else if (optSource) {\n params.source = optSource;\n }\n\n if (!creds.useOidc) {\n params.token = creds.token;\n params.teamId = creds.teamId;\n params.projectId = creds.projectId;\n }\n\n const sandbox = await VercelSandbox.create(params);\n return { sandbox, sandboxId: sandbox.sandboxId };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('token')) {\n throw new Error(`Vercel authentication failed. Please check your VERCEL_TOKEN environment variable.`);\n }\n if (error.message.includes('team') || error.message.includes('project')) {\n throw new Error(`Vercel team/project configuration failed. Check VERCEL_TEAM_ID and VERCEL_PROJECT_ID.`);\n }\n }\n throw new Error(`Failed to create Vercel sandbox: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n getById: async (config: VercelConfig, sandboxId: string) => {\n const creds = resolveCredentials(config);\n try {\n const sandbox = creds.useOidc\n ? await VercelSandbox.get({ sandboxId })\n : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n return { sandbox, sandboxId };\n } catch { return null; }\n },\n\n list: async (_config: VercelConfig) => {\n throw new Error(`Vercel provider does not support listing sandboxes.`);\n },\n\n destroy: async (config: VercelConfig, sandboxId: string) => {\n const creds = resolveCredentials(config);\n try {\n const sandbox = creds.useOidc\n ? await VercelSandbox.get({ sandboxId })\n : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n await sandbox.stop();\n } catch { /* already destroyed or doesn't exist */ }\n },\n\n runCommand: async (sandbox: VercelSandbox, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n const startTime = Date.now();\n try {\n let fullCommand = command;\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env).map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`).join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n const stdout = options?.background ? undefined : getUtf8Sink();\n const stderr = options?.background ? undefined : getUtf8Sink();\n const result = await sandbox.runCommand({\n cmd: 'sh', args: ['-c', fullCommand],\n cwd: options?.cwd, detached: options?.background,\n stdout: stdout?.sink, stderr: stderr?.sink,\n });\n return { stdout: stdout?.value() ?? '', stderr: stderr?.value() ?? '', exitCode: result.exitCode ?? 0, durationMs: Date.now() - startTime };\n } catch (error) {\n return { stdout: '', stderr: error instanceof Error ? error.message : String(error), exitCode: 127, durationMs: Date.now() - startTime };\n }\n },\n\n getInfo: async (_sandbox: VercelSandbox): Promise<SandboxInfo> => ({\n id: 'vercel-unknown',\n provider: 'vercel',\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: { vercelSandboxId: 'vercel-unknown' }\n }),\n\n getUrl: async (sandbox: VercelSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n let url = sandbox.domain(options.port);\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n return url;\n } catch (error) {\n throw new Error(`Failed to get Vercel domain for port ${options.port}: ${error instanceof Error ? error.message : String(error)}.`);\n }\n },\n\n filesystem: {\n readFile: async (sandbox: VercelSandbox, path: string): Promise<string> => {\n const stream = await sandbox.readFile({ path });\n if (!stream) throw new Error(`File not found: ${path}`);\n const chunks: Buffer[] = [];\n for await (const chunk of stream) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return Buffer.concat(chunks).toString('utf-8');\n },\n writeFile: async (sandbox: VercelSandbox, path: string, content: string): Promise<void> => {\n await sandbox.writeFiles([{ path, content: Buffer.from(content) }]);\n },\n mkdir: async (sandbox: VercelSandbox, path: string): Promise<void> => { await sandbox.mkDir(path); },\n readdir: async (_sandbox: VercelSandbox, _path: string): Promise<FileEntry[]> => {\n throw new Error('Vercel sandbox does not support readdir.');\n },\n exists: async (_sandbox: VercelSandbox, _path: string): Promise<boolean> => {\n throw new Error('Vercel sandbox does not support exists.');\n },\n remove: async (_sandbox: VercelSandbox, _path: string): Promise<void> => {\n throw new Error('Vercel sandbox does not support remove.');\n }\n },\n\n getInstance: (sandbox: VercelSandbox): VercelSandbox => sandbox,\n },\n\n snapshot: {\n create: async (config: VercelConfig, sandboxId: string) => {\n const creds = resolveCredentials(config);\n const sandbox = creds.useOidc\n ? await VercelSandbox.get({ sandboxId })\n : await VercelSandbox.get({ sandboxId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n return await sandbox.snapshot();\n },\n list: async (_config: VercelConfig) => { throw new Error(`Vercel provider does not support listing snapshots.`); },\n delete: async (config: VercelConfig, snapshotId: string) => {\n const creds = resolveCredentials(config);\n const snapshot = creds.useOidc\n ? await VercelSnapshot.get({ snapshotId })\n : await VercelSnapshot.get({ snapshotId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n await snapshot.delete();\n }\n },\n\n template: {\n create: async (_config: VercelConfig, _options: { name: string }) => {\n throw new Error(`Vercel does not support creating templates directly. Use snapshot.create() instead.`);\n },\n list: async (_config: VercelConfig) => { throw new Error(`Vercel provider does not support listing templates.`); },\n delete: async (config: VercelConfig, templateId: string) => {\n const creds = resolveCredentials(config);\n const snapshot = creds.useOidc\n ? await VercelSnapshot.get({ snapshotId: templateId })\n : await VercelSnapshot.get({ snapshotId: templateId, token: creds.token, teamId: creds.teamId, projectId: creds.projectId });\n await snapshot.delete();\n }\n }\n }\n});\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@computesdk/vercel",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.27",
|
|
4
4
|
"description": "Vercel Sandbox provider for ComputeSDK - serverless code execution for Python and Node.js on Vercel's edge network",
|
|
5
5
|
"author": "Garrison",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@vercel/sandbox": "^1.9.3",
|
|
22
22
|
"ms": "^2.1.3",
|
|
23
|
-
"@computesdk/provider": "1.
|
|
24
|
-
"computesdk": "
|
|
23
|
+
"@computesdk/provider": "2.1.0",
|
|
24
|
+
"computesdk": "4.1.0"
|
|
25
25
|
},
|
|
26
26
|
"keywords": [
|
|
27
27
|
"computesdk",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"tsup": "^8.0.0",
|
|
54
54
|
"typescript": "^5.0.0",
|
|
55
55
|
"vitest": "^1.0.0",
|
|
56
|
-
"@computesdk/test-utils": "
|
|
56
|
+
"@computesdk/test-utils": "2.0.0"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "tsup",
|