@ai-sdk/sandbox-vercel 1.0.133 → 1.0.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,1187 +1,898 @@
1
- // src/vercel-legacy-sandbox-provider.ts
2
- import { Sandbox as Sandbox2 } from "@vercel/sandbox";
3
-
4
- // src/vercel-network-sandbox-session.ts
5
- import {
6
- HarnessCapabilityUnsupportedError as HarnessCapabilityUnsupportedError2
7
- } from "@ai-sdk/harness";
8
-
9
- // src/vercel-network-policy-manager.ts
10
- import {
11
- HarnessCapabilityUnsupportedError
12
- } from "@ai-sdk/harness";
13
- var VERCEL_PROVIDER_ID = "vercel-sandbox";
1
+ import { Sandbox } from "@vercel/sandbox";
2
+ import { HarnessCapabilityUnsupportedError, HarnessSandboxAuthenticationError } from "@ai-sdk/harness";
3
+ import { posix } from "node:path";
4
+ import { extractLines } from "@ai-sdk/provider-utils";
5
+ //#region src/vercel-network-policy-manager.ts
6
+ const VERCEL_PROVIDER_ID$2 = "vercel-sandbox";
7
+ /**
8
+ * Owns the complete Vercel Sandbox network-policy value for one live session.
9
+ * Vercel combines network access, request transformations, and forwarding in a
10
+ * single structure, so every mutation must be composed here before replacing
11
+ * that structure through `sandbox.update()`.
12
+ */
14
13
  var VercelNetworkPolicyManager = class {
15
- #sandbox;
16
- #state;
17
- #mutationQueue = Promise.resolve();
18
- constructor({ sandbox }) {
19
- this.#sandbox = sandbox;
20
- }
21
- setNetworkPolicy(policy) {
22
- return this.#enqueueMutation(async () => {
23
- const inspection = this.#inspectPolicy();
24
- if (this.#state == null && inspection.requestTransformationHosts.length > 0) {
25
- throw createPolicyConflictError(
26
- "Cannot set the network policy because the current Vercel Sandbox policy contains request transformations whose redacted values cannot be preserved safely. Replace them explicitly with setRequestTransformations() or rehydrate them with addRequestTransformations() first."
27
- );
28
- }
29
- await this.#applyState({
30
- accessPolicy: toNetworkAccessPolicy(policy),
31
- requestTransformations: this.#state?.requestTransformations.map(cloneRequestTransformation) ?? [],
32
- forwardRules: inspection.forwardRules.map(cloneForwardRule),
33
- currentPolicy: inspection.currentPolicy
34
- });
35
- });
36
- }
37
- setRequestTransformations(transformations) {
38
- return this.#enqueueMutation(async () => {
39
- const inspection = this.#inspectPolicy();
40
- await this.#applyState({
41
- accessPolicy: inspection.accessPolicy,
42
- requestTransformations: transformations.map(cloneRequestTransformation),
43
- forwardRules: inspection.forwardRules.map(cloneForwardRule),
44
- currentPolicy: inspection.currentPolicy
45
- });
46
- });
47
- }
48
- addRequestTransformations(transformations) {
49
- return this.#enqueueMutation(async () => {
50
- const inspection = this.#inspectPolicy();
51
- const incomingTransformations = transformations.map(
52
- cloneRequestTransformation
53
- );
54
- if (this.#state == null) {
55
- const incomingPolicy = composeNetworkPolicy({
56
- accessPolicy: inspection.accessPolicy,
57
- requestTransformations: incomingTransformations,
58
- forwardRules: inspection.forwardRules
59
- });
60
- const incomingHosts = getRequestTransformationHosts(incomingPolicy);
61
- if (!isHostSetSubset({
62
- subset: inspection.requestTransformationHosts,
63
- superset: incomingHosts
64
- })) {
65
- throw createPolicyConflictError(
66
- "Cannot add request transformations because the current Vercel Sandbox policy contains request transformations that cannot be attributed to this call. Their header values are redacted, so preserving them safely is not possible."
67
- );
68
- }
69
- }
70
- await this.#applyState({
71
- accessPolicy: inspection.accessPolicy,
72
- requestTransformations: this.#state == null ? incomingTransformations : mergeRequestTransformations({
73
- existing: this.#state.requestTransformations,
74
- incoming: incomingTransformations
75
- }),
76
- forwardRules: inspection.forwardRules.map(cloneForwardRule),
77
- currentPolicy: inspection.currentPolicy
78
- });
79
- });
80
- }
81
- #enqueueMutation(operation) {
82
- const result = this.#mutationQueue.then(operation);
83
- this.#mutationQueue = result.then(
84
- () => void 0,
85
- () => void 0
86
- );
87
- return result;
88
- }
89
- #inspectPolicy() {
90
- if (this.#state != null) {
91
- return {
92
- accessPolicy: this.#state.accessPolicy,
93
- forwardRules: this.#state.forwardRules,
94
- requestTransformationHosts: [],
95
- currentPolicy: this.#state.effectivePolicy
96
- };
97
- }
98
- return inspectCurrentPolicy(
99
- this.#sandbox.currentSession().networkPolicy ?? "allow-all"
100
- );
101
- }
102
- async #applyState({
103
- accessPolicy,
104
- requestTransformations,
105
- forwardRules,
106
- currentPolicy
107
- }) {
108
- const effectivePolicy = composeNetworkPolicy({
109
- accessPolicy,
110
- requestTransformations,
111
- forwardRules
112
- });
113
- if (!areNetworkPoliciesEqual({
114
- first: currentPolicy,
115
- second: effectivePolicy
116
- })) {
117
- await this.#sandbox.update({ networkPolicy: effectivePolicy });
118
- }
119
- this.#state = {
120
- accessPolicy: cloneNetworkAccessPolicy(accessPolicy),
121
- requestTransformations: requestTransformations.map(
122
- cloneRequestTransformation
123
- ),
124
- forwardRules: forwardRules.map(cloneForwardRule),
125
- effectivePolicy
126
- };
127
- }
14
+ #sandbox;
15
+ #state;
16
+ #mutationQueue = Promise.resolve();
17
+ constructor({ sandbox }) {
18
+ this.#sandbox = sandbox;
19
+ }
20
+ setNetworkPolicy(policy) {
21
+ return this.#enqueueMutation(async () => {
22
+ const inspection = this.#inspectPolicy();
23
+ if (this.#state == null && inspection.requestTransformationHosts.length > 0) throw createPolicyConflictError("Cannot set the network policy because the current Vercel Sandbox policy contains request transformations whose redacted values cannot be preserved safely. Replace them explicitly with setRequestTransformations() or rehydrate them with addRequestTransformations() first.");
24
+ await this.#applyState({
25
+ accessPolicy: toNetworkAccessPolicy(policy),
26
+ requestTransformations: this.#state?.requestTransformations.map(cloneRequestTransformation) ?? [],
27
+ forwardRules: inspection.forwardRules.map(cloneForwardRule),
28
+ currentPolicy: inspection.currentPolicy
29
+ });
30
+ });
31
+ }
32
+ setRequestTransformations(transformations) {
33
+ return this.#enqueueMutation(async () => {
34
+ const inspection = this.#inspectPolicy();
35
+ await this.#applyState({
36
+ accessPolicy: inspection.accessPolicy,
37
+ requestTransformations: transformations.map(cloneRequestTransformation),
38
+ forwardRules: inspection.forwardRules.map(cloneForwardRule),
39
+ currentPolicy: inspection.currentPolicy
40
+ });
41
+ });
42
+ }
43
+ addRequestTransformations(transformations) {
44
+ return this.#enqueueMutation(async () => {
45
+ const inspection = this.#inspectPolicy();
46
+ const incomingTransformations = transformations.map(cloneRequestTransformation);
47
+ if (this.#state == null) {
48
+ const incomingHosts = getRequestTransformationHosts(composeNetworkPolicy({
49
+ accessPolicy: inspection.accessPolicy,
50
+ requestTransformations: incomingTransformations,
51
+ forwardRules: inspection.forwardRules
52
+ }));
53
+ if (!isHostSetSubset({
54
+ subset: inspection.requestTransformationHosts,
55
+ superset: incomingHosts
56
+ })) throw createPolicyConflictError("Cannot add request transformations because the current Vercel Sandbox policy contains request transformations that cannot be attributed to this call. Their header values are redacted, so preserving them safely is not possible.");
57
+ }
58
+ await this.#applyState({
59
+ accessPolicy: inspection.accessPolicy,
60
+ requestTransformations: this.#state == null ? incomingTransformations : mergeRequestTransformations({
61
+ existing: this.#state.requestTransformations,
62
+ incoming: incomingTransformations
63
+ }),
64
+ forwardRules: inspection.forwardRules.map(cloneForwardRule),
65
+ currentPolicy: inspection.currentPolicy
66
+ });
67
+ });
68
+ }
69
+ #enqueueMutation(operation) {
70
+ const result = this.#mutationQueue.then(operation);
71
+ this.#mutationQueue = result.then(() => void 0, () => void 0);
72
+ return result;
73
+ }
74
+ #inspectPolicy() {
75
+ if (this.#state != null) return {
76
+ accessPolicy: this.#state.accessPolicy,
77
+ forwardRules: this.#state.forwardRules,
78
+ requestTransformationHosts: [],
79
+ currentPolicy: this.#state.effectivePolicy
80
+ };
81
+ return inspectCurrentPolicy(this.#sandbox.currentSession().networkPolicy ?? "allow-all");
82
+ }
83
+ async #applyState({ accessPolicy, requestTransformations, forwardRules, currentPolicy }) {
84
+ const effectivePolicy = composeNetworkPolicy({
85
+ accessPolicy,
86
+ requestTransformations,
87
+ forwardRules
88
+ });
89
+ if (!areNetworkPoliciesEqual({
90
+ first: currentPolicy,
91
+ second: effectivePolicy
92
+ })) await this.#sandbox.update({ networkPolicy: effectivePolicy });
93
+ this.#state = {
94
+ accessPolicy: cloneNetworkAccessPolicy(accessPolicy),
95
+ requestTransformations: requestTransformations.map(cloneRequestTransformation),
96
+ forwardRules: forwardRules.map(cloneForwardRule),
97
+ effectivePolicy
98
+ };
99
+ }
128
100
  };
129
101
  function inspectCurrentPolicy(policy) {
130
- if (policy === "allow-all" || policy === "deny-all") {
131
- return {
132
- accessPolicy: { mode: policy },
133
- forwardRules: [],
134
- requestTransformationHosts: [],
135
- currentPolicy: policy
136
- };
137
- }
138
- const allowedHosts = Array.isArray(policy.allow) ? [...policy.allow] : Object.keys(policy.allow ?? {});
139
- const forwardRules = [];
140
- const requestTransformationHosts = /* @__PURE__ */ new Set();
141
- if (policy.allow != null && !Array.isArray(policy.allow)) {
142
- for (const [host, rules] of Object.entries(policy.allow)) {
143
- for (const rule of rules) {
144
- if (hasRequestTransformation(rule)) {
145
- requestTransformationHosts.add(host.toLowerCase());
146
- }
147
- if (rule.forwardURL != null) {
148
- forwardRules.push({
149
- host,
150
- ...rule.match == null ? {} : { match: cloneMatch(rule.match) },
151
- forwardURL: rule.forwardURL
152
- });
153
- }
154
- }
155
- }
156
- }
157
- return {
158
- accessPolicy: {
159
- mode: "custom",
160
- allowedHosts: minimizeHostPatterns(allowedHosts),
161
- allowedCIDRs: [...policy.subnets?.allow ?? []],
162
- deniedCIDRs: [...policy.subnets?.deny ?? []]
163
- },
164
- forwardRules,
165
- requestTransformationHosts: [...requestTransformationHosts],
166
- currentPolicy: cloneNetworkPolicy(policy)
167
- };
102
+ if (policy === "allow-all" || policy === "deny-all") return {
103
+ accessPolicy: { mode: policy },
104
+ forwardRules: [],
105
+ requestTransformationHosts: [],
106
+ currentPolicy: policy
107
+ };
108
+ const allowedHosts = Array.isArray(policy.allow) ? [...policy.allow] : Object.keys(policy.allow ?? {});
109
+ const forwardRules = [];
110
+ const requestTransformationHosts = /* @__PURE__ */ new Set();
111
+ if (policy.allow != null && !Array.isArray(policy.allow)) for (const [host, rules] of Object.entries(policy.allow)) for (const rule of rules) {
112
+ if (hasRequestTransformation(rule)) requestTransformationHosts.add(host.toLowerCase());
113
+ if (rule.forwardURL != null) forwardRules.push({
114
+ host,
115
+ ...rule.match == null ? {} : { match: cloneMatch(rule.match) },
116
+ forwardURL: rule.forwardURL
117
+ });
118
+ }
119
+ return {
120
+ accessPolicy: {
121
+ mode: "custom",
122
+ allowedHosts: minimizeHostPatterns(allowedHosts),
123
+ allowedCIDRs: [...policy.subnets?.allow ?? []],
124
+ deniedCIDRs: [...policy.subnets?.deny ?? []]
125
+ },
126
+ forwardRules,
127
+ requestTransformationHosts: [...requestTransformationHosts],
128
+ currentPolicy: cloneNetworkPolicy(policy)
129
+ };
168
130
  }
169
131
  function toNetworkAccessPolicy(policy) {
170
- switch (policy.mode) {
171
- case "allow-all":
172
- return { mode: "allow-all" };
173
- case "deny-all":
174
- return { mode: "deny-all" };
175
- case "custom": {
176
- const allowedHosts = [...policy.allowedHosts ?? []];
177
- const allowedCIDRs = [...policy.allowedCIDRs ?? []];
178
- const deniedCIDRs = [...policy.deniedCIDRs ?? []];
179
- if (allowedHosts.length === 0 && allowedCIDRs.length === 0 && deniedCIDRs.length === 0) {
180
- throw createPolicyConflictError(
181
- "Custom network policy requires at least one of allowedHosts, allowedCIDRs, or deniedCIDRs to be non-empty."
182
- );
183
- }
184
- return {
185
- mode: "custom",
186
- allowedHosts,
187
- allowedCIDRs,
188
- deniedCIDRs
189
- };
190
- }
191
- }
192
- }
193
- function composeNetworkPolicy({
194
- accessPolicy,
195
- requestTransformations,
196
- forwardRules
197
- }) {
198
- if (accessPolicy.mode === "deny-all") {
199
- return "deny-all";
200
- }
201
- const rulesByHost = /* @__PURE__ */ new Map();
202
- const allowedHosts = accessPolicy.mode === "allow-all" ? ["*"] : accessPolicy.allowedHosts;
203
- for (const host of allowedHosts) {
204
- rulesByHost.set(host, []);
205
- }
206
- for (const transformation of requestTransformations) {
207
- for (const host of getActiveHostPatterns({
208
- allowedHosts,
209
- ruleHost: transformation.match.host
210
- })) {
211
- appendRule({
212
- rulesByHost,
213
- host,
214
- rule: toVercelRequestTransformationRule(transformation)
215
- });
216
- }
217
- }
218
- for (const forwardRule of forwardRules) {
219
- for (const host of getActiveHostPatterns({
220
- allowedHosts,
221
- ruleHost: forwardRule.host
222
- })) {
223
- appendRule({
224
- rulesByHost,
225
- host,
226
- rule: {
227
- ...forwardRule.match == null ? {} : { match: cloneMatch(forwardRule.match) },
228
- forwardURL: forwardRule.forwardURL
229
- }
230
- });
231
- }
232
- }
233
- const hasActiveRules = [...rulesByHost.values()].some(
234
- (rules) => rules.length > 0
235
- );
236
- if (!hasActiveRules) {
237
- return toVercelAccessPolicy(accessPolicy);
238
- }
239
- return {
240
- allow: Object.fromEntries(rulesByHost),
241
- ...accessPolicy.mode !== "custom" ? {} : toVercelSubnets(accessPolicy)
242
- };
132
+ switch (policy.mode) {
133
+ case "allow-all": return { mode: "allow-all" };
134
+ case "deny-all": return { mode: "deny-all" };
135
+ case "custom": {
136
+ const allowedHosts = [...policy.allowedHosts ?? []];
137
+ const allowedCIDRs = [...policy.allowedCIDRs ?? []];
138
+ const deniedCIDRs = [...policy.deniedCIDRs ?? []];
139
+ if (allowedHosts.length === 0 && allowedCIDRs.length === 0 && deniedCIDRs.length === 0) throw createPolicyConflictError("Custom network policy requires at least one of allowedHosts, allowedCIDRs, or deniedCIDRs to be non-empty.");
140
+ return {
141
+ mode: "custom",
142
+ allowedHosts,
143
+ allowedCIDRs,
144
+ deniedCIDRs
145
+ };
146
+ }
147
+ }
148
+ }
149
+ function composeNetworkPolicy({ accessPolicy, requestTransformations, forwardRules }) {
150
+ if (accessPolicy.mode === "deny-all") return "deny-all";
151
+ const rulesByHost = /* @__PURE__ */ new Map();
152
+ const allowedHosts = accessPolicy.mode === "allow-all" ? ["*"] : accessPolicy.allowedHosts;
153
+ for (const host of allowedHosts) rulesByHost.set(host, []);
154
+ for (const transformation of requestTransformations) for (const host of getActiveHostPatterns({
155
+ allowedHosts,
156
+ ruleHost: transformation.match.host
157
+ })) appendRule({
158
+ rulesByHost,
159
+ host,
160
+ rule: toVercelRequestTransformationRule(transformation)
161
+ });
162
+ for (const forwardRule of forwardRules) for (const host of getActiveHostPatterns({
163
+ allowedHosts,
164
+ ruleHost: forwardRule.host
165
+ })) appendRule({
166
+ rulesByHost,
167
+ host,
168
+ rule: {
169
+ ...forwardRule.match == null ? {} : { match: cloneMatch(forwardRule.match) },
170
+ forwardURL: forwardRule.forwardURL
171
+ }
172
+ });
173
+ if (![...rulesByHost.values()].some((rules) => rules.length > 0)) return toVercelAccessPolicy(accessPolicy);
174
+ return {
175
+ allow: Object.fromEntries(rulesByHost),
176
+ ...accessPolicy.mode !== "custom" ? {} : toVercelSubnets(accessPolicy)
177
+ };
243
178
  }
244
179
  function toVercelAccessPolicy(accessPolicy) {
245
- if (accessPolicy.mode === "allow-all" || accessPolicy.mode === "deny-all") {
246
- return accessPolicy.mode;
247
- }
248
- return {
249
- ...accessPolicy.allowedHosts.length === 0 ? {} : { allow: [...accessPolicy.allowedHosts] },
250
- ...toVercelSubnets(accessPolicy)
251
- };
180
+ if (accessPolicy.mode === "allow-all" || accessPolicy.mode === "deny-all") return accessPolicy.mode;
181
+ return {
182
+ ...accessPolicy.allowedHosts.length === 0 ? {} : { allow: [...accessPolicy.allowedHosts] },
183
+ ...toVercelSubnets(accessPolicy)
184
+ };
252
185
  }
253
186
  function toVercelSubnets(accessPolicy) {
254
- if (accessPolicy.allowedCIDRs.length === 0 && accessPolicy.deniedCIDRs.length === 0) {
255
- return {};
256
- }
257
- return {
258
- subnets: {
259
- ...accessPolicy.allowedCIDRs.length === 0 ? {} : { allow: [...accessPolicy.allowedCIDRs] },
260
- ...accessPolicy.deniedCIDRs.length === 0 ? {} : { deny: [...accessPolicy.deniedCIDRs] }
261
- }
262
- };
263
- }
264
- function getActiveHostPatterns({
265
- allowedHosts,
266
- ruleHost
267
- }) {
268
- return minimizeHostPatterns(
269
- allowedHosts.flatMap((allowedHost) => {
270
- const intersection = intersectHostPatterns({
271
- first: allowedHost,
272
- second: ruleHost
273
- });
274
- return intersection == null ? [] : [intersection];
275
- })
276
- );
277
- }
278
- function intersectHostPatterns({
279
- first,
280
- second
281
- }) {
282
- if (isHostPatternSubset({ candidate: first, container: second })) {
283
- return first;
284
- }
285
- if (isHostPatternSubset({ candidate: second, container: first })) {
286
- return second;
287
- }
288
- }
289
- function isHostPatternSubset({
290
- candidate,
291
- container
292
- }) {
293
- const normalizedCandidate = candidate.toLowerCase();
294
- const normalizedContainer = container.toLowerCase();
295
- if (normalizedCandidate === normalizedContainer || normalizedContainer === "*") {
296
- return true;
297
- }
298
- if (normalizedCandidate === "*" || !normalizedContainer.startsWith("*")) {
299
- return false;
300
- }
301
- const containerSuffix = normalizedContainer.slice(1);
302
- return normalizedCandidate.startsWith("*") ? normalizedCandidate.slice(1).endsWith(containerSuffix) : normalizedCandidate.endsWith(containerSuffix);
187
+ if (accessPolicy.allowedCIDRs.length === 0 && accessPolicy.deniedCIDRs.length === 0) return {};
188
+ return { subnets: {
189
+ ...accessPolicy.allowedCIDRs.length === 0 ? {} : { allow: [...accessPolicy.allowedCIDRs] },
190
+ ...accessPolicy.deniedCIDRs.length === 0 ? {} : { deny: [...accessPolicy.deniedCIDRs] }
191
+ } };
192
+ }
193
+ function getActiveHostPatterns({ allowedHosts, ruleHost }) {
194
+ return minimizeHostPatterns(allowedHosts.flatMap((allowedHost) => {
195
+ const intersection = intersectHostPatterns({
196
+ first: allowedHost,
197
+ second: ruleHost
198
+ });
199
+ return intersection == null ? [] : [intersection];
200
+ }));
201
+ }
202
+ function intersectHostPatterns({ first, second }) {
203
+ if (isHostPatternSubset({
204
+ candidate: first,
205
+ container: second
206
+ })) return first;
207
+ if (isHostPatternSubset({
208
+ candidate: second,
209
+ container: first
210
+ })) return second;
211
+ }
212
+ function isHostPatternSubset({ candidate, container }) {
213
+ const normalizedCandidate = candidate.toLowerCase();
214
+ const normalizedContainer = container.toLowerCase();
215
+ if (normalizedCandidate === normalizedContainer || normalizedContainer === "*") return true;
216
+ if (normalizedCandidate === "*" || !normalizedContainer.startsWith("*")) return false;
217
+ const containerSuffix = normalizedContainer.slice(1);
218
+ return normalizedCandidate.startsWith("*") ? normalizedCandidate.slice(1).endsWith(containerSuffix) : normalizedCandidate.endsWith(containerSuffix);
303
219
  }
304
220
  function minimizeHostPatterns(patterns) {
305
- const uniquePatterns = [...new Set(patterns)];
306
- return uniquePatterns.filter(
307
- (pattern) => !uniquePatterns.some(
308
- (other) => other !== pattern && isHostPatternSubset({ candidate: pattern, container: other })
309
- )
310
- );
221
+ const uniquePatterns = [...new Set(patterns)];
222
+ return uniquePatterns.filter((pattern) => !uniquePatterns.some((other) => other !== pattern && isHostPatternSubset({
223
+ candidate: pattern,
224
+ container: other
225
+ })));
311
226
  }
312
- function appendRule({
313
- rulesByHost,
314
- host,
315
- rule
316
- }) {
317
- const rules = rulesByHost.get(host) ?? [];
318
- rules.push(rule);
319
- rulesByHost.set(host, rules);
227
+ function appendRule({ rulesByHost, host, rule }) {
228
+ const rules = rulesByHost.get(host) ?? [];
229
+ rules.push(rule);
230
+ rulesByHost.set(host, rules);
320
231
  }
321
232
  function toVercelRequestTransformationRule(transformation) {
322
- const {
323
- host: _host,
324
- method,
325
- path,
326
- queryString,
327
- headers
328
- } = transformation.match;
329
- const match = {
330
- ...path == null ? {} : { path: cloneMatcher(path) },
331
- ...method == null ? {} : { method: [...method] },
332
- ...queryString == null ? {} : { queryString: queryString.map(cloneKeyValueMatcher) },
333
- ...headers == null ? {} : { headers: headers.map(cloneKeyValueMatcher) }
334
- };
335
- return {
336
- ...Object.keys(match).length === 0 ? {} : { match },
337
- transform: [{ headers: { ...transformation.transform.headers } }]
338
- };
233
+ const { host: _host, method, path, queryString, headers } = transformation.match;
234
+ const match = {
235
+ ...path == null ? {} : { path: cloneMatcher(path) },
236
+ ...method == null ? {} : { method: [...method] },
237
+ ...queryString == null ? {} : { queryString: queryString.map(cloneKeyValueMatcher) },
238
+ ...headers == null ? {} : { headers: headers.map(cloneKeyValueMatcher) }
239
+ };
240
+ return {
241
+ ...Object.keys(match).length === 0 ? {} : { match },
242
+ transform: [{ headers: { ...transformation.transform.headers } }]
243
+ };
339
244
  }
340
245
  function hasRequestTransformation(rule) {
341
- return rule.transform?.some(
342
- (transformation) => transformation.headers != null && Object.keys(transformation.headers).length > 0
343
- ) ?? false;
246
+ return rule.transform?.some((transformation) => transformation.headers != null && Object.keys(transformation.headers).length > 0) ?? false;
344
247
  }
345
248
  function getRequestTransformationHosts(policy) {
346
- if (policy === "allow-all" || policy === "deny-all" || policy.allow == null || Array.isArray(policy.allow)) {
347
- return [];
348
- }
349
- const hosts = /* @__PURE__ */ new Set();
350
- for (const [host, rules] of Object.entries(policy.allow)) {
351
- for (const rule of rules) {
352
- if (hasRequestTransformation(rule)) {
353
- hosts.add(host.toLowerCase());
354
- }
355
- }
356
- }
357
- return [...hosts];
358
- }
359
- function isHostSetSubset({
360
- subset,
361
- superset
362
- }) {
363
- const allowedHosts = new Set(superset.map((host) => host.toLowerCase()));
364
- return subset.every((host) => allowedHosts.has(host.toLowerCase()));
365
- }
366
- function areNetworkPoliciesEqual({
367
- first,
368
- second
369
- }) {
370
- return stableSerialize(first) === stableSerialize(second);
371
- }
372
- function mergeRequestTransformations({
373
- existing,
374
- incoming
375
- }) {
376
- const merged = existing.map(cloneRequestTransformation);
377
- const identities = new Map(
378
- merged.map((transformation, index) => [
379
- getRequestTransformationIdentity(transformation),
380
- index
381
- ])
382
- );
383
- for (const transformation of incoming) {
384
- const clonedTransformation = cloneRequestTransformation(transformation);
385
- const identity = getRequestTransformationIdentity(clonedTransformation);
386
- const existingIndex = identities.get(identity);
387
- if (existingIndex == null) {
388
- identities.set(identity, merged.length);
389
- merged.push(clonedTransformation);
390
- } else {
391
- merged[existingIndex] = clonedTransformation;
392
- }
393
- }
394
- return merged;
249
+ if (policy === "allow-all" || policy === "deny-all" || policy.allow == null || Array.isArray(policy.allow)) return [];
250
+ const hosts = /* @__PURE__ */ new Set();
251
+ for (const [host, rules] of Object.entries(policy.allow)) for (const rule of rules) if (hasRequestTransformation(rule)) hosts.add(host.toLowerCase());
252
+ return [...hosts];
253
+ }
254
+ function isHostSetSubset({ subset, superset }) {
255
+ const allowedHosts = new Set(superset.map((host) => host.toLowerCase()));
256
+ return subset.every((host) => allowedHosts.has(host.toLowerCase()));
257
+ }
258
+ function areNetworkPoliciesEqual({ first, second }) {
259
+ return stableSerialize(first) === stableSerialize(second);
260
+ }
261
+ function mergeRequestTransformations({ existing, incoming }) {
262
+ const merged = existing.map(cloneRequestTransformation);
263
+ const identities = new Map(merged.map((transformation, index) => [getRequestTransformationIdentity(transformation), index]));
264
+ for (const transformation of incoming) {
265
+ const clonedTransformation = cloneRequestTransformation(transformation);
266
+ const identity = getRequestTransformationIdentity(clonedTransformation);
267
+ const existingIndex = identities.get(identity);
268
+ if (existingIndex == null) {
269
+ identities.set(identity, merged.length);
270
+ merged.push(clonedTransformation);
271
+ } else merged[existingIndex] = clonedTransformation;
272
+ }
273
+ return merged;
395
274
  }
396
275
  function getRequestTransformationIdentity(transformation) {
397
- return stableSerialize({
398
- match: transformation.match,
399
- transformedHeaderNames: Object.keys(transformation.transform.headers).map((name) => name.toLowerCase()).sort()
400
- });
276
+ return stableSerialize({
277
+ match: transformation.match,
278
+ transformedHeaderNames: Object.keys(transformation.transform.headers).map((name) => name.toLowerCase()).sort()
279
+ });
401
280
  }
402
281
  function stableSerialize(value) {
403
- if (Array.isArray(value)) {
404
- return `[${value.map(stableSerialize).join(",")}]`;
405
- }
406
- if (value != null && typeof value === "object") {
407
- return `{${Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([firstKey], [secondKey]) => firstKey.localeCompare(secondKey)).map(
408
- ([key, entryValue]) => `${JSON.stringify(key)}:${stableSerialize(entryValue)}`
409
- ).join(",")}}`;
410
- }
411
- return JSON.stringify(value);
282
+ if (Array.isArray(value)) return `[${value.map(stableSerialize).join(",")}]`;
283
+ if (value != null && typeof value === "object") return `{${Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([firstKey], [secondKey]) => firstKey.localeCompare(secondKey)).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableSerialize(entryValue)}`).join(",")}}`;
284
+ return JSON.stringify(value);
412
285
  }
413
286
  function cloneRequestTransformation(transformation) {
414
- return {
415
- match: {
416
- host: transformation.match.host,
417
- ...transformation.match.path == null ? {} : { path: cloneHarnessMatcher(transformation.match.path) },
418
- ...transformation.match.method == null ? {} : { method: [...transformation.match.method] },
419
- ...transformation.match.queryString == null ? {} : {
420
- queryString: transformation.match.queryString.map(
421
- cloneHarnessKeyValueMatcher
422
- )
423
- },
424
- ...transformation.match.headers == null ? {} : {
425
- headers: transformation.match.headers.map(
426
- cloneHarnessKeyValueMatcher
427
- )
428
- }
429
- },
430
- transform: { headers: { ...transformation.transform.headers } }
431
- };
287
+ return {
288
+ match: {
289
+ host: transformation.match.host,
290
+ ...transformation.match.path == null ? {} : { path: cloneHarnessMatcher(transformation.match.path) },
291
+ ...transformation.match.method == null ? {} : { method: [...transformation.match.method] },
292
+ ...transformation.match.queryString == null ? {} : { queryString: transformation.match.queryString.map(cloneHarnessKeyValueMatcher) },
293
+ ...transformation.match.headers == null ? {} : { headers: transformation.match.headers.map(cloneHarnessKeyValueMatcher) }
294
+ },
295
+ transform: { headers: { ...transformation.transform.headers } }
296
+ };
432
297
  }
433
298
  function cloneForwardRule(rule) {
434
- return {
435
- host: rule.host,
436
- ...rule.match == null ? {} : { match: cloneMatch(rule.match) },
437
- forwardURL: rule.forwardURL
438
- };
299
+ return {
300
+ host: rule.host,
301
+ ...rule.match == null ? {} : { match: cloneMatch(rule.match) },
302
+ forwardURL: rule.forwardURL
303
+ };
439
304
  }
440
305
  function cloneNetworkAccessPolicy(policy) {
441
- if (policy.mode === "allow-all" || policy.mode === "deny-all") {
442
- return { mode: policy.mode };
443
- }
444
- return {
445
- mode: "custom",
446
- allowedHosts: [...policy.allowedHosts],
447
- allowedCIDRs: [...policy.allowedCIDRs],
448
- deniedCIDRs: [...policy.deniedCIDRs]
449
- };
306
+ if (policy.mode === "allow-all" || policy.mode === "deny-all") return { mode: policy.mode };
307
+ return {
308
+ mode: "custom",
309
+ allowedHosts: [...policy.allowedHosts],
310
+ allowedCIDRs: [...policy.allowedCIDRs],
311
+ deniedCIDRs: [...policy.deniedCIDRs]
312
+ };
450
313
  }
451
314
  function cloneNetworkPolicy(policy) {
452
- return structuredClone(policy);
315
+ return structuredClone(policy);
453
316
  }
454
317
  function cloneMatch(match) {
455
- return {
456
- ...match.path == null ? {} : { path: cloneMatcher(match.path) },
457
- ...match.method == null ? {} : { method: [...match.method] },
458
- ...match.queryString == null ? {} : { queryString: match.queryString.map(cloneKeyValueMatcher) },
459
- ...match.headers == null ? {} : { headers: match.headers.map(cloneKeyValueMatcher) }
460
- };
318
+ return {
319
+ ...match.path == null ? {} : { path: cloneMatcher(match.path) },
320
+ ...match.method == null ? {} : { method: [...match.method] },
321
+ ...match.queryString == null ? {} : { queryString: match.queryString.map(cloneKeyValueMatcher) },
322
+ ...match.headers == null ? {} : { headers: match.headers.map(cloneKeyValueMatcher) }
323
+ };
461
324
  }
462
325
  function cloneKeyValueMatcher(matcher) {
463
- return {
464
- ...matcher.key == null ? {} : { key: cloneMatcher(matcher.key) },
465
- ...matcher.value == null ? {} : { value: cloneMatcher(matcher.value) }
466
- };
326
+ return {
327
+ ...matcher.key == null ? {} : { key: cloneMatcher(matcher.key) },
328
+ ...matcher.value == null ? {} : { value: cloneMatcher(matcher.value) }
329
+ };
467
330
  }
468
331
  function cloneMatcher(matcher) {
469
- return { ...matcher };
332
+ return { ...matcher };
470
333
  }
471
334
  function cloneHarnessKeyValueMatcher(matcher) {
472
- return {
473
- ...matcher.key == null ? {} : { key: cloneHarnessMatcher(matcher.key) },
474
- ...matcher.value == null ? {} : { value: cloneHarnessMatcher(matcher.value) }
475
- };
335
+ return {
336
+ ...matcher.key == null ? {} : { key: cloneHarnessMatcher(matcher.key) },
337
+ ...matcher.value == null ? {} : { value: cloneHarnessMatcher(matcher.value) }
338
+ };
476
339
  }
477
340
  function cloneHarnessMatcher(matcher) {
478
- if ("exact" in matcher) {
479
- return { exact: matcher.exact };
480
- }
481
- if ("startsWith" in matcher) {
482
- return { startsWith: matcher.startsWith };
483
- }
484
- return { regex: matcher.regex };
341
+ if ("exact" in matcher) return { exact: matcher.exact };
342
+ if ("startsWith" in matcher) return { startsWith: matcher.startsWith };
343
+ return { regex: matcher.regex };
485
344
  }
486
345
  function createPolicyConflictError(message) {
487
- return new HarnessCapabilityUnsupportedError({
488
- harnessId: VERCEL_PROVIDER_ID,
489
- message
490
- });
491
- }
492
-
493
- // src/vercel-sandbox-session.ts
494
- import { posix } from "path";
495
- import {
496
- extractLines
497
- } from "@ai-sdk/provider-utils";
346
+ return new HarnessCapabilityUnsupportedError({
347
+ harnessId: VERCEL_PROVIDER_ID$2,
348
+ message
349
+ });
350
+ }
351
+ //#endregion
352
+ //#region src/vercel-sandbox-session.ts
353
+ /**
354
+ * `Experimental_SandboxSession` implementation backed by a `@vercel/sandbox`
355
+ * `Sandbox` instance. This is the tool-safe surface (file I/O, exec, spawn);
356
+ * it is what `VercelNetworkSandboxSession.restricted()` returns and is not
357
+ * constructed directly by consumers. The network sandbox session owns the
358
+ * lifetime of the underlying sandbox.
359
+ */
498
360
  var VercelSandboxSession = class {
499
- constructor(sandbox) {
500
- this.sandbox = sandbox;
501
- }
502
- get description() {
503
- return [
504
- `Vercel Sandbox (name: ${this.sandbox.name}).`,
505
- "Filesystem changes persist for the lifetime of the sandbox."
506
- ].join("\n");
507
- }
508
- async run({
509
- command,
510
- workingDirectory,
511
- env,
512
- abortSignal
513
- }) {
514
- abortSignal?.throwIfAborted();
515
- const finished = await this.sandbox.runCommand({
516
- cmd: "bash",
517
- args: ["-c", command],
518
- ...workingDirectory !== void 0 ? { cwd: workingDirectory } : {},
519
- ...env !== void 0 ? { env } : {},
520
- ...abortSignal !== void 0 ? { signal: abortSignal } : {}
521
- });
522
- const [stdout, stderr] = await Promise.all([
523
- finished.stdout(),
524
- finished.stderr()
525
- ]);
526
- return {
527
- exitCode: finished.exitCode,
528
- stdout,
529
- stderr
530
- };
531
- }
532
- async spawn({
533
- command,
534
- workingDirectory,
535
- env,
536
- abortSignal
537
- }) {
538
- abortSignal?.throwIfAborted();
539
- const live = await this.sandbox.runCommand({
540
- cmd: "bash",
541
- args: ["-c", command],
542
- detached: true,
543
- ...workingDirectory !== void 0 ? { cwd: workingDirectory } : {},
544
- ...env !== void 0 ? { env } : {},
545
- ...abortSignal !== void 0 ? { signal: abortSignal } : {}
546
- });
547
- return createSandboxProcess(live, abortSignal);
548
- }
549
- async readFile({
550
- path,
551
- abortSignal
552
- }) {
553
- const bytes = await this.readBinaryFile({ path, abortSignal });
554
- if (bytes == null) return null;
555
- return bytesToStream(bytes);
556
- }
557
- async readBinaryFile({
558
- path,
559
- abortSignal
560
- }) {
561
- abortSignal?.throwIfAborted();
562
- try {
563
- const buffer = await this.sandbox.readFileToBuffer(
564
- { path },
565
- abortSignal ? { signal: abortSignal } : void 0
566
- );
567
- if (buffer == null) return null;
568
- return new Uint8Array(
569
- buffer.buffer,
570
- buffer.byteOffset,
571
- buffer.byteLength
572
- );
573
- } catch (error) {
574
- if (isFileNotFoundError(error)) return null;
575
- throw error;
576
- }
577
- }
578
- async readTextFile({
579
- path,
580
- encoding = "utf-8",
581
- startLine,
582
- endLine,
583
- abortSignal
584
- }) {
585
- const bytes = await this.readBinaryFile({ path, abortSignal });
586
- if (bytes == null) return null;
587
- const text = Buffer.from(bytes).toString(encoding);
588
- return extractLines({ text, startLine, endLine });
589
- }
590
- async writeFile({
591
- path,
592
- content,
593
- abortSignal
594
- }) {
595
- const bytes = await collectStream(content);
596
- await this.writeBinaryFile({ path, content: bytes, abortSignal });
597
- }
598
- async writeBinaryFile({
599
- path,
600
- content,
601
- abortSignal
602
- }) {
603
- abortSignal?.throwIfAborted();
604
- const parent = posix.dirname(path);
605
- if (parent && parent !== "." && parent !== "/") {
606
- await this.sandbox.runCommand({
607
- cmd: "mkdir",
608
- args: ["-p", parent],
609
- ...abortSignal !== void 0 ? { signal: abortSignal } : {}
610
- });
611
- }
612
- await this.sandbox.writeFiles(
613
- [{ path, content }],
614
- abortSignal ? { signal: abortSignal } : void 0
615
- );
616
- }
617
- async writeTextFile({
618
- path,
619
- content,
620
- encoding = "utf-8",
621
- abortSignal
622
- }) {
623
- const buffer = Buffer.from(content, encoding);
624
- await this.writeBinaryFile({
625
- path,
626
- content: new Uint8Array(
627
- buffer.buffer,
628
- buffer.byteOffset,
629
- buffer.byteLength
630
- ),
631
- abortSignal
632
- });
633
- }
361
+ constructor(sandbox) {
362
+ this.sandbox = sandbox;
363
+ }
364
+ get description() {
365
+ return [`Vercel Sandbox (name: ${this.sandbox.name}).`, "Filesystem changes persist for the lifetime of the sandbox."].join("\n");
366
+ }
367
+ async run({ command, workingDirectory, env, abortSignal }) {
368
+ abortSignal?.throwIfAborted();
369
+ const finished = await this.sandbox.runCommand({
370
+ cmd: "bash",
371
+ args: ["-c", command],
372
+ ...workingDirectory !== void 0 ? { cwd: workingDirectory } : {},
373
+ ...env !== void 0 ? { env } : {},
374
+ ...abortSignal !== void 0 ? { signal: abortSignal } : {}
375
+ });
376
+ const [stdout, stderr] = await Promise.all([finished.stdout(), finished.stderr()]);
377
+ return {
378
+ exitCode: finished.exitCode,
379
+ stdout,
380
+ stderr
381
+ };
382
+ }
383
+ async spawn({ command, workingDirectory, env, abortSignal }) {
384
+ abortSignal?.throwIfAborted();
385
+ return createSandboxProcess(await this.sandbox.runCommand({
386
+ cmd: "bash",
387
+ args: ["-c", command],
388
+ detached: true,
389
+ ...workingDirectory !== void 0 ? { cwd: workingDirectory } : {},
390
+ ...env !== void 0 ? { env } : {},
391
+ ...abortSignal !== void 0 ? { signal: abortSignal } : {}
392
+ }), abortSignal);
393
+ }
394
+ async readFile({ path, abortSignal }) {
395
+ const bytes = await this.readBinaryFile({
396
+ path,
397
+ abortSignal
398
+ });
399
+ if (bytes == null) return null;
400
+ return bytesToStream(bytes);
401
+ }
402
+ async readBinaryFile({ path, abortSignal }) {
403
+ abortSignal?.throwIfAborted();
404
+ try {
405
+ const buffer = await this.sandbox.readFileToBuffer({ path }, abortSignal ? { signal: abortSignal } : void 0);
406
+ if (buffer == null) return null;
407
+ return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
408
+ } catch (error) {
409
+ if (isFileNotFoundError(error)) return null;
410
+ throw error;
411
+ }
412
+ }
413
+ async readTextFile({ path, encoding = "utf-8", startLine, endLine, abortSignal }) {
414
+ const bytes = await this.readBinaryFile({
415
+ path,
416
+ abortSignal
417
+ });
418
+ if (bytes == null) return null;
419
+ const text = Buffer.from(bytes).toString(encoding);
420
+ return extractLines({
421
+ text,
422
+ startLine,
423
+ endLine
424
+ });
425
+ }
426
+ async writeFile({ path, content, abortSignal }) {
427
+ const bytes = await collectStream(content);
428
+ await this.writeBinaryFile({
429
+ path,
430
+ content: bytes,
431
+ abortSignal
432
+ });
433
+ }
434
+ async writeBinaryFile({ path, content, abortSignal }) {
435
+ abortSignal?.throwIfAborted();
436
+ const parent = posix.dirname(path);
437
+ if (parent && parent !== "." && parent !== "/") await this.sandbox.runCommand({
438
+ cmd: "mkdir",
439
+ args: ["-p", parent],
440
+ ...abortSignal !== void 0 ? { signal: abortSignal } : {}
441
+ });
442
+ await this.sandbox.writeFiles([{
443
+ path,
444
+ content
445
+ }], abortSignal ? { signal: abortSignal } : void 0);
446
+ }
447
+ async writeTextFile({ path, content, encoding = "utf-8", abortSignal }) {
448
+ const buffer = Buffer.from(content, encoding);
449
+ await this.writeBinaryFile({
450
+ path,
451
+ content: new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength),
452
+ abortSignal
453
+ });
454
+ }
634
455
  };
635
456
  function createSandboxProcess(command, abortSignal) {
636
- const encoder = new TextEncoder();
637
- const controllers = {};
638
- const stdout = new ReadableStream({
639
- start(controller) {
640
- controllers.stdout = controller;
641
- }
642
- });
643
- const stderr = new ReadableStream({
644
- start(controller) {
645
- controllers.stderr = controller;
646
- }
647
- });
648
- const drained = (async () => {
649
- try {
650
- const iterator = abortSignal ? command.logs({ signal: abortSignal }) : command.logs();
651
- for await (const message of iterator) {
652
- const target = message.stream === "stdout" ? controllers.stdout : controllers.stderr;
653
- target?.enqueue(encoder.encode(message.data));
654
- }
655
- controllers.stdout?.close();
656
- controllers.stderr?.close();
657
- } catch (error) {
658
- controllers.stdout?.error(error);
659
- controllers.stderr?.error(error);
660
- }
661
- })();
662
- return {
663
- stdout,
664
- stderr,
665
- async wait() {
666
- const finished = await command.wait();
667
- await drained;
668
- if (abortSignal?.aborted) {
669
- throw abortSignal.reason ?? new DOMException("Aborted", "AbortError");
670
- }
671
- return { exitCode: finished.exitCode };
672
- },
673
- async kill() {
674
- await command.kill();
675
- }
676
- };
457
+ const encoder = new TextEncoder();
458
+ const controllers = {};
459
+ const stdout = new ReadableStream({ start(controller) {
460
+ controllers.stdout = controller;
461
+ } });
462
+ const stderr = new ReadableStream({ start(controller) {
463
+ controllers.stderr = controller;
464
+ } });
465
+ const drained = (async () => {
466
+ try {
467
+ const iterator = abortSignal ? command.logs({ signal: abortSignal }) : command.logs();
468
+ for await (const message of iterator) (message.stream === "stdout" ? controllers.stdout : controllers.stderr)?.enqueue(encoder.encode(message.data));
469
+ controllers.stdout?.close();
470
+ controllers.stderr?.close();
471
+ } catch (error) {
472
+ controllers.stdout?.error(error);
473
+ controllers.stderr?.error(error);
474
+ }
475
+ })();
476
+ return {
477
+ stdout,
478
+ stderr,
479
+ async wait() {
480
+ const finished = await command.wait();
481
+ await drained;
482
+ if (abortSignal?.aborted) throw abortSignal.reason ?? new DOMException("Aborted", "AbortError");
483
+ return { exitCode: finished.exitCode };
484
+ },
485
+ async kill() {
486
+ await command.kill();
487
+ }
488
+ };
677
489
  }
678
490
  function bytesToStream(bytes) {
679
- return new ReadableStream({
680
- start(controller) {
681
- controller.enqueue(bytes);
682
- controller.close();
683
- }
684
- });
491
+ return new ReadableStream({ start(controller) {
492
+ controller.enqueue(bytes);
493
+ controller.close();
494
+ } });
685
495
  }
686
496
  async function collectStream(stream) {
687
- const reader = stream.getReader();
688
- const chunks = [];
689
- let total = 0;
690
- while (true) {
691
- const { value, done } = await reader.read();
692
- if (done) break;
693
- if (value) {
694
- chunks.push(value);
695
- total += value.byteLength;
696
- }
697
- }
698
- const out = new Uint8Array(total);
699
- let offset = 0;
700
- for (const chunk of chunks) {
701
- out.set(chunk, offset);
702
- offset += chunk.byteLength;
703
- }
704
- return out;
497
+ const reader = stream.getReader();
498
+ const chunks = [];
499
+ let total = 0;
500
+ while (true) {
501
+ const { value, done } = await reader.read();
502
+ if (done) break;
503
+ if (value) {
504
+ chunks.push(value);
505
+ total += value.byteLength;
506
+ }
507
+ }
508
+ const out = new Uint8Array(total);
509
+ let offset = 0;
510
+ for (const chunk of chunks) {
511
+ out.set(chunk, offset);
512
+ offset += chunk.byteLength;
513
+ }
514
+ return out;
705
515
  }
706
516
  function isFileNotFoundError(error) {
707
- if (error == null || typeof error !== "object") return false;
708
- const code = error.code;
709
- if (code === "ENOENT") return true;
710
- const message = error.message;
711
- return typeof message === "string" && /no such file|not found|does not exist|ENOENT/i.test(message);
712
- }
713
-
714
- // src/vercel-network-sandbox-session.ts
715
- var VERCEL_PROVIDER_ID2 = "vercel-sandbox";
517
+ if (error == null || typeof error !== "object") return false;
518
+ if (error.code === "ENOENT") return true;
519
+ const message = error.message;
520
+ return typeof message === "string" && /no such file|not found|does not exist|ENOENT/i.test(message);
521
+ }
522
+ //#endregion
523
+ //#region src/vercel-network-sandbox-session.ts
524
+ const VERCEL_PROVIDER_ID$1 = "vercel-sandbox";
525
+ /**
526
+ * `HarnessV1NetworkSandboxSession` backed by a `@vercel/sandbox` `Sandbox`. The
527
+ * native adaptation and sandbox creation functions return one of these. It
528
+ * extends {@link VercelSandboxSession} with ports, lifecycle, and network
529
+ * policy. Explicit `stop()` and `destroy()` calls delegate to the native
530
+ * sandbox unless the session was wrapped through the compatibility provider's
531
+ * existing-sandbox path, where those calls are intentionally no-ops.
532
+ */
716
533
  var VercelNetworkSandboxSession = class extends VercelSandboxSession {
717
- constructor(input) {
718
- super(input.sandbox);
719
- this.getPortEndpoint = async (options) => {
720
- const exposedPorts = this.ports;
721
- if (!exposedPorts.includes(options.port)) {
722
- throw new HarnessCapabilityUnsupportedError2({
723
- harnessId: VERCEL_PROVIDER_ID2,
724
- message: `Port ${options.port} is not exposed on this sandbox. Exposed ports: [${exposedPorts.join(", ")}].`
725
- });
726
- }
727
- const protocol = options.protocol ?? "https";
728
- const url = new URL(this.sandbox.domain(options.port));
729
- const isSecure = url.protocol === "https:";
730
- switch (protocol) {
731
- case "http":
732
- url.protocol = isSecure ? "https:" : "http:";
733
- break;
734
- case "https":
735
- url.protocol = "https:";
736
- break;
737
- case "ws":
738
- url.protocol = isSecure ? "wss:" : "ws:";
739
- break;
740
- }
741
- return { url: url.toString() };
742
- };
743
- /**
744
- * @deprecated Use `getPortEndpoint` instead.
745
- */
746
- this.getPortUrl = async (options) => {
747
- return (await this.getPortEndpoint(options)).url;
748
- };
749
- this.setNetworkPolicy = async (policy) => {
750
- await this.#networkPolicyManager.setNetworkPolicy(policy);
751
- };
752
- this.setRequestTransformations = async (transformations) => {
753
- await this.#networkPolicyManager.setRequestTransformations(transformations);
754
- };
755
- this.addRequestTransformations = async (transformations) => {
756
- await this.#networkPolicyManager.addRequestTransformations(transformations);
757
- };
758
- this.setPorts = async (ports, options) => {
759
- await this.sandbox.update(
760
- { ports: [...ports] },
761
- options?.abortSignal ? { signal: options.abortSignal } : void 0
762
- );
763
- };
764
- this.stop = async () => {
765
- if (!this.ownsLifecycle) return;
766
- await this.sandbox.stop();
767
- };
768
- this.destroy = async () => {
769
- if (!this.ownsLifecycle) return;
770
- await this.sandbox.stop().catch(() => {
771
- });
772
- await this.sandbox.delete();
773
- };
774
- this.ownsLifecycle = input.ownsLifecycle;
775
- this.id = input.sandbox.name;
776
- this.defaultWorkingDirectory = input.sandbox.currentSession().cwd;
777
- this.#networkPolicyManager = new VercelNetworkPolicyManager({
778
- sandbox: input.sandbox
779
- });
780
- }
781
- #networkPolicyManager;
782
- get ports() {
783
- return this.sandbox.routes.map((route) => route.port);
784
- }
785
- restricted() {
786
- return new VercelSandboxSession(this.sandbox);
787
- }
534
+ #networkPolicyManager;
535
+ constructor(input) {
536
+ super(input.sandbox);
537
+ this.getPortEndpoint = async (options) => {
538
+ const exposedPorts = this.ports;
539
+ if (!exposedPorts.includes(options.port)) throw new HarnessCapabilityUnsupportedError({
540
+ harnessId: VERCEL_PROVIDER_ID$1,
541
+ message: `Port ${options.port} is not exposed on this sandbox. Exposed ports: [${exposedPorts.join(", ")}].`
542
+ });
543
+ const protocol = options.protocol ?? "https";
544
+ const url = new URL(this.sandbox.domain(options.port));
545
+ const isSecure = url.protocol === "https:";
546
+ switch (protocol) {
547
+ case "http":
548
+ url.protocol = isSecure ? "https:" : "http:";
549
+ break;
550
+ case "https":
551
+ url.protocol = "https:";
552
+ break;
553
+ case "ws": url.protocol = isSecure ? "wss:" : "ws:";
554
+ }
555
+ return { url: url.toString() };
556
+ };
557
+ this.getPortUrl = async (options) => {
558
+ return (await this.getPortEndpoint(options)).url;
559
+ };
560
+ this.setNetworkPolicy = async (policy) => {
561
+ await this.#networkPolicyManager.setNetworkPolicy(policy);
562
+ };
563
+ this.setRequestTransformations = async (transformations) => {
564
+ await this.#networkPolicyManager.setRequestTransformations(transformations);
565
+ };
566
+ this.addRequestTransformations = async (transformations) => {
567
+ await this.#networkPolicyManager.addRequestTransformations(transformations);
568
+ };
569
+ this.setPorts = async (ports, options) => {
570
+ await this.sandbox.update({ ports: [...ports] }, options?.abortSignal ? { signal: options.abortSignal } : void 0);
571
+ };
572
+ this.stop = async () => {
573
+ if (!this.ownsLifecycle) return;
574
+ await this.sandbox.stop();
575
+ };
576
+ this.destroy = async () => {
577
+ if (!this.ownsLifecycle) return;
578
+ await this.sandbox.stop().catch(() => {});
579
+ await this.sandbox.delete();
580
+ };
581
+ this.ownsLifecycle = input.ownsLifecycle;
582
+ this.id = input.sandbox.name;
583
+ this.defaultWorkingDirectory = input.sandbox.currentSession().cwd;
584
+ this.#networkPolicyManager = new VercelNetworkPolicyManager({ sandbox: input.sandbox });
585
+ }
586
+ get ports() {
587
+ return this.sandbox.routes.map((route) => route.port);
588
+ }
589
+ restricted() {
590
+ return new VercelSandboxSession(this.sandbox);
591
+ }
788
592
  };
789
-
790
- // src/utils.ts
791
- import { HarnessSandboxAuthenticationError } from "@ai-sdk/harness";
792
- import { Sandbox } from "@vercel/sandbox";
793
- var VERCEL_PROVIDER_ID3 = "vercel-sandbox";
794
- var DEFAULT_SANDBOX_TIMEOUT_MS = 30 * 60 * 1e3;
795
- var DEFAULT_SANDBOX_RUNTIME = "node24";
796
- var SNAPSHOT_POLL_INTERVAL_MS = 500;
797
- var SNAPSHOT_POLL_TIMEOUT_MS = 3e4;
593
+ //#endregion
594
+ //#region src/utils.ts
595
+ const VERCEL_PROVIDER_ID = "vercel-sandbox";
596
+ const DEFAULT_SANDBOX_RUNTIME = "node24";
597
+ const SNAPSHOT_POLL_INTERVAL_MS = 500;
598
+ const SNAPSHOT_POLL_TIMEOUT_MS = 3e4;
798
599
  function getSandboxLookupParams(settings) {
799
- if ("sandbox" in settings && settings.sandbox != null) {
800
- return {};
801
- }
802
- const { fetch, projectId, teamId, token } = settings;
803
- return {
804
- ...fetch ? { fetch } : {},
805
- ...projectId ? { projectId } : {},
806
- ...teamId ? { teamId } : {},
807
- ...token ? { token } : {}
808
- };
809
- }
810
- var VERCEL_SANDBOX_AUTHENTICATION_MESSAGE = "Vercel Sandbox authentication failed. Set VERCEL_OIDC_TOKEN, or pass token, teamId, and projectId to createVercelSandbox(), then verify that they can access Vercel Sandbox.";
811
- async function withVercelSandboxAuthenticationError({
812
- settings,
813
- operation
814
- }) {
815
- try {
816
- return await operation();
817
- } catch (error) {
818
- if (!isVercelSandboxAuthenticationFailure({
819
- error,
820
- hasConfiguredCredentials: hasConfiguredCredentials(settings)
821
- })) {
822
- throw error;
823
- }
824
- throw new HarnessSandboxAuthenticationError({
825
- message: VERCEL_SANDBOX_AUTHENTICATION_MESSAGE,
826
- sandboxProviderId: VERCEL_PROVIDER_ID3,
827
- cause: error
828
- });
829
- }
600
+ if ("sandbox" in settings && settings.sandbox != null) return {};
601
+ const { fetch, projectId, teamId, token } = settings;
602
+ return {
603
+ ...fetch ? { fetch } : {},
604
+ ...projectId ? { projectId } : {},
605
+ ...teamId ? { teamId } : {},
606
+ ...token ? { token } : {}
607
+ };
608
+ }
609
+ const VERCEL_SANDBOX_AUTHENTICATION_MESSAGE = "Vercel Sandbox authentication failed. Set VERCEL_OIDC_TOKEN, or pass token, teamId, and projectId to createVercelSandbox(), then verify that they can access Vercel Sandbox.";
610
+ async function withVercelSandboxAuthenticationError({ settings, operation }) {
611
+ try {
612
+ return await operation();
613
+ } catch (error) {
614
+ if (!isVercelSandboxAuthenticationFailure({
615
+ error,
616
+ hasConfiguredCredentials: hasConfiguredCredentials(settings)
617
+ })) throw error;
618
+ throw new HarnessSandboxAuthenticationError({
619
+ message: VERCEL_SANDBOX_AUTHENTICATION_MESSAGE,
620
+ sandboxProviderId: VERCEL_PROVIDER_ID,
621
+ cause: error
622
+ });
623
+ }
830
624
  }
831
625
  function hasConfiguredCredentials(settings) {
832
- if (process.env.VERCEL_OIDC_TOKEN) return true;
833
- if ("sandbox" in settings && settings.sandbox != null) return true;
834
- const { token, teamId, projectId } = getSandboxLookupParams(settings);
835
- return Boolean(token && teamId && projectId);
836
- }
837
- function isVercelSandboxAuthenticationFailure({
838
- error,
839
- hasConfiguredCredentials: hasConfiguredCredentials2
840
- }) {
841
- const seen = /* @__PURE__ */ new Set();
842
- let current = error;
843
- while (current != null && !seen.has(current)) {
844
- seen.add(current);
845
- if (typeof current === "object") {
846
- const candidate = current;
847
- if (candidate.response?.status === 401 || candidate.response?.status === 403 || candidate.response?.statusCode === 401 || candidate.response?.statusCode === 403) {
848
- return true;
849
- }
850
- if (typeof candidate.name === "string" && VERCEL_AUTHENTICATION_ERROR_NAMES.has(candidate.name)) {
851
- return true;
852
- }
853
- if (typeof candidate.message === "string" && VERCEL_AUTHENTICATION_ERROR_MESSAGE.test(candidate.message)) {
854
- return true;
855
- }
856
- if (!hasConfiguredCredentials2 && candidate.code === "ERR_INVALID_ARG_TYPE" && typeof candidate.message === "string" && candidate.message.includes('"path" argument') && candidate.message.includes("Received undefined")) {
857
- return true;
858
- }
859
- current = candidate.cause;
860
- continue;
861
- }
862
- break;
863
- }
864
- return false;
865
- }
866
- var VERCEL_AUTHENTICATION_ERROR_NAMES = /* @__PURE__ */ new Set([
867
- "AccessTokenMissingError",
868
- "LocalOidcContextError",
869
- "OAuthError",
870
- "RefreshAccessTokenFailedError",
871
- "VercelOidcContextError",
872
- "VercelOidcTokenError"
626
+ if (process.env.VERCEL_OIDC_TOKEN) return true;
627
+ if ("sandbox" in settings && settings.sandbox != null) return true;
628
+ const { token, teamId, projectId } = getSandboxLookupParams(settings);
629
+ return Boolean(token && teamId && projectId);
630
+ }
631
+ function isVercelSandboxAuthenticationFailure({ error, hasConfiguredCredentials }) {
632
+ const seen = /* @__PURE__ */ new Set();
633
+ let current = error;
634
+ while (current != null && !seen.has(current)) {
635
+ seen.add(current);
636
+ if (typeof current === "object") {
637
+ const candidate = current;
638
+ if (candidate.response?.status === 401 || candidate.response?.status === 403 || candidate.response?.statusCode === 401 || candidate.response?.statusCode === 403) return true;
639
+ if (typeof candidate.name === "string" && VERCEL_AUTHENTICATION_ERROR_NAMES.has(candidate.name)) return true;
640
+ if (typeof candidate.message === "string" && VERCEL_AUTHENTICATION_ERROR_MESSAGE.test(candidate.message)) return true;
641
+ if (!hasConfiguredCredentials && candidate.code === "ERR_INVALID_ARG_TYPE" && typeof candidate.message === "string" && candidate.message.includes("\"path\" argument") && candidate.message.includes("Received undefined")) return true;
642
+ current = candidate.cause;
643
+ continue;
644
+ }
645
+ break;
646
+ }
647
+ return false;
648
+ }
649
+ const VERCEL_AUTHENTICATION_ERROR_NAMES = /* @__PURE__ */ new Set([
650
+ "AccessTokenMissingError",
651
+ "LocalOidcContextError",
652
+ "OAuthError",
653
+ "RefreshAccessTokenFailedError",
654
+ "VercelOidcContextError",
655
+ "VercelOidcTokenError"
873
656
  ]);
874
- var VERCEL_AUTHENTICATION_ERROR_MESSAGE = /Could not get credentials from OIDC context|No authentication found|Failed to (?:retrieve|refresh) authentication token|Missing credentials parameters to access the Vercel API|Authentication failed/i;
657
+ const VERCEL_AUTHENTICATION_ERROR_MESSAGE = /Could not get credentials from OIDC context|No authentication found|Failed to (?:retrieve|refresh) authentication token|Missing credentials parameters to access the Vercel API|Authentication failed/i;
875
658
  function hasExplicitSandboxEnvironment(params) {
876
- return "runtime" in params && params.runtime != null || "image" in params && params.image != null || "source" in params && typeof params.source === "object" && params.source != null && "type" in params.source && params.source.type === "snapshot";
659
+ return "runtime" in params && params.runtime != null || "image" in params && params.image != null || "source" in params && typeof params.source === "object" && params.source != null && "type" in params.source && params.source.type === "snapshot";
877
660
  }
878
661
  function withDefaultSandboxSettings(createParams) {
879
- return {
880
- ...hasExplicitSandboxEnvironment(createParams) ? {} : { runtime: DEFAULT_SANDBOX_RUNTIME },
881
- ...createParams,
882
- timeout: createParams.timeout ?? DEFAULT_SANDBOX_TIMEOUT_MS
883
- };
884
- }
885
- async function ensureTemplateSnapshot({
886
- baseParams,
887
- templateName,
888
- onCreate,
889
- lookupParams,
890
- abortSignal,
891
- snapshotCache
892
- }) {
893
- const cachedSnapshotId = snapshotCache?.get(templateName);
894
- if (cachedSnapshotId != null) {
895
- return cachedSnapshotId;
896
- }
897
- const prepared = await Sandbox.getOrCreate({
898
- ...baseParams,
899
- name: templateName,
900
- persistent: true,
901
- snapshotExpiration: baseParams.snapshotExpiration ?? 0,
902
- onCreate,
903
- ...abortSignal ? { signal: abortSignal } : {}
904
- });
905
- let snapshotId = prepared.currentSnapshotId;
906
- if (snapshotId == null) {
907
- const stopped = await prepared.stop(
908
- abortSignal ? { signal: abortSignal } : void 0
909
- );
910
- snapshotId = stopped.snapshot?.id ?? await pollForTemplateSnapshot({
911
- name: templateName,
912
- lookupParams,
913
- abortSignal
914
- });
915
- }
916
- snapshotCache?.set(templateName, snapshotId);
917
- return snapshotId;
918
- }
919
- function createLiveSandboxFromSnapshot({
920
- baseParams,
921
- snapshotId,
922
- liveName,
923
- abortSignal
924
- }) {
925
- const {
926
- runtime: _runtime,
927
- image: _image,
928
- source: _source,
929
- persistent: _persistent,
930
- ...forkParams
931
- } = baseParams;
932
- return Sandbox.create({
933
- ...forkParams,
934
- source: { type: "snapshot", snapshotId },
935
- ...liveName != null ? { name: liveName } : {},
936
- ...abortSignal ? { signal: abortSignal } : {}
937
- });
938
- }
939
- async function pollForTemplateSnapshot({
940
- name,
941
- lookupParams,
942
- abortSignal
943
- }) {
944
- const deadline = Date.now() + SNAPSHOT_POLL_TIMEOUT_MS;
945
- while (Date.now() < deadline) {
946
- abortSignal?.throwIfAborted();
947
- const refreshed = await Sandbox.get({
948
- ...lookupParams,
949
- name,
950
- resume: false,
951
- ...abortSignal ? { signal: abortSignal } : {}
952
- });
953
- if (refreshed.currentSnapshotId) {
954
- return refreshed.currentSnapshotId;
955
- }
956
- await new Promise(
957
- (resolve) => setTimeout(resolve, SNAPSHOT_POLL_INTERVAL_MS)
958
- );
959
- }
960
- throw new Error(
961
- `Timed out waiting for snapshot of template "${name}" to publish.`
962
- );
963
- }
964
-
965
- // src/vercel-legacy-sandbox-provider.ts
966
- var SESSION_NAME_PREFIX = "ai-sdk-harness-session";
662
+ return {
663
+ ...hasExplicitSandboxEnvironment(createParams) ? {} : { runtime: DEFAULT_SANDBOX_RUNTIME },
664
+ ...createParams,
665
+ timeout: createParams.timeout ?? 18e5
666
+ };
667
+ }
668
+ async function ensureTemplateSnapshot({ baseParams, templateName, onCreate, lookupParams, abortSignal, snapshotCache }) {
669
+ const cachedSnapshotId = snapshotCache?.get(templateName);
670
+ if (cachedSnapshotId != null) return cachedSnapshotId;
671
+ const prepared = await Sandbox.getOrCreate({
672
+ ...baseParams,
673
+ name: templateName,
674
+ persistent: true,
675
+ snapshotExpiration: baseParams.snapshotExpiration ?? 0,
676
+ onCreate,
677
+ ...abortSignal ? { signal: abortSignal } : {}
678
+ });
679
+ let snapshotId = prepared.currentSnapshotId;
680
+ if (snapshotId == null) snapshotId = (await prepared.stop(abortSignal ? { signal: abortSignal } : void 0)).snapshot?.id ?? await pollForTemplateSnapshot({
681
+ name: templateName,
682
+ lookupParams,
683
+ abortSignal
684
+ });
685
+ snapshotCache?.set(templateName, snapshotId);
686
+ return snapshotId;
687
+ }
688
+ function createLiveSandboxFromSnapshot({ baseParams, snapshotId, liveName, abortSignal }) {
689
+ const { runtime: _runtime, image: _image, source: _source, persistent: _persistent, ...forkParams } = baseParams;
690
+ return Sandbox.create({
691
+ ...forkParams,
692
+ source: {
693
+ type: "snapshot",
694
+ snapshotId
695
+ },
696
+ ...liveName != null ? { name: liveName } : {},
697
+ ...abortSignal ? { signal: abortSignal } : {}
698
+ });
699
+ }
700
+ async function pollForTemplateSnapshot({ name, lookupParams, abortSignal }) {
701
+ const deadline = Date.now() + SNAPSHOT_POLL_TIMEOUT_MS;
702
+ while (Date.now() < deadline) {
703
+ abortSignal?.throwIfAborted();
704
+ const refreshed = await Sandbox.get({
705
+ ...lookupParams,
706
+ name,
707
+ resume: false,
708
+ ...abortSignal ? { signal: abortSignal } : {}
709
+ });
710
+ if (refreshed.currentSnapshotId) return refreshed.currentSnapshotId;
711
+ await new Promise((resolve) => setTimeout(resolve, SNAPSHOT_POLL_INTERVAL_MS));
712
+ }
713
+ throw new Error(`Timed out waiting for snapshot of template "${name}" to publish.`);
714
+ }
715
+ //#endregion
716
+ //#region src/vercel-legacy-sandbox-provider.ts
717
+ const SESSION_NAME_PREFIX = "ai-sdk-harness-session";
967
718
  function sessionSandboxName(sessionId) {
968
- return `${SESSION_NAME_PREFIX}-${sessionId}`;
719
+ return `${SESSION_NAME_PREFIX}-${sessionId}`;
969
720
  }
721
+ /** @deprecated Use `createVercelNetworkSandboxSession` instead. */
970
722
  function createVercelSandbox(settings = {}) {
971
- console.warn(
972
- "createVercelSandbox is deprecated. Use createVercelNetworkSandboxSession and HarnessAgent.createSession({ sandboxSession }) instead."
973
- );
974
- return new VercelSandboxProvider(settings);
975
- }
723
+ console.warn("createVercelSandbox is deprecated. Use createVercelNetworkSandboxSession and HarnessAgent.createSession({ sandboxSession }) instead.");
724
+ return new VercelSandboxProvider(settings);
725
+ }
726
+ /**
727
+ * `HarnessV1SandboxProvider` implementation backed by `@vercel/sandbox`.
728
+ * Construct one via {@link createVercelSandbox} at module scope and pass it
729
+ * to a `HarnessAgent` (or call `createSession()` directly if you want raw
730
+ * access to a network sandbox session).
731
+ */
732
+ /** @deprecated Use `createVercelNetworkSandboxSession` instead. */
976
733
  var VercelSandboxProvider = class {
977
- constructor(settings) {
978
- this.settings = settings;
979
- this.specificationVersion = "harness-sandbox-v1";
980
- this.providerId = VERCEL_PROVIDER_ID3;
981
- this.createSession = async (options) => {
982
- options?.abortSignal?.throwIfAborted();
983
- if ("sandbox" in this.settings && this.settings.sandbox != null) {
984
- return new VercelNetworkSandboxSession({
985
- sandbox: this.settings.sandbox,
986
- ownsLifecycle: false
987
- });
988
- }
989
- const settings = this.settings;
990
- const {
991
- sandbox: _ignoredSandbox,
992
- name: explicitName,
993
- ...createParams
994
- } = settings;
995
- const baseParams = withDefaultSandboxSettings(
996
- createParams
997
- );
998
- const identity = options?.identity;
999
- const onFirstCreate = options?.onFirstCreate;
1000
- const sessionNameOverride = options?.sessionId ? { name: sessionSandboxName(options.sessionId) } : {};
1001
- if (identity == null || onFirstCreate == null) {
1002
- const sandbox = await withVercelSandboxAuthenticationError({
1003
- settings: this.settings,
1004
- operation: () => Sandbox2.create({
1005
- ...baseParams,
1006
- ...sessionNameOverride,
1007
- ...options?.abortSignal ? { signal: options.abortSignal } : {}
1008
- })
1009
- });
1010
- return new VercelNetworkSandboxSession({ sandbox, ownsLifecycle: true });
1011
- }
1012
- const templateName = explicitName ?? `ai-sdk-harness-${identity}`;
1013
- const snapshotId = await withVercelSandboxAuthenticationError({
1014
- settings: this.settings,
1015
- operation: () => ensureTemplateSnapshot({
1016
- baseParams,
1017
- templateName,
1018
- lookupParams: getSandboxLookupParams(baseParams),
1019
- abortSignal: options?.abortSignal,
1020
- snapshotCache: getSnapshotCache(),
1021
- onCreate: async (sbx) => {
1022
- await onFirstCreate(new VercelSandboxSession(sbx), {
1023
- abortSignal: options?.abortSignal
1024
- });
1025
- }
1026
- })
1027
- });
1028
- const fork = await withVercelSandboxAuthenticationError({
1029
- settings: this.settings,
1030
- operation: () => createLiveSandboxFromSnapshot({
1031
- baseParams,
1032
- snapshotId,
1033
- liveName: sessionNameOverride.name,
1034
- abortSignal: options?.abortSignal
1035
- })
1036
- });
1037
- return new VercelNetworkSandboxSession({
1038
- sandbox: fork,
1039
- ownsLifecycle: true
1040
- });
1041
- };
1042
- this.resumeSession = async (options) => {
1043
- options.abortSignal?.throwIfAborted();
1044
- if ("sandbox" in this.settings && this.settings.sandbox != null) {
1045
- return new VercelNetworkSandboxSession({
1046
- sandbox: this.settings.sandbox,
1047
- ownsLifecycle: false
1048
- });
1049
- }
1050
- const sandbox = await withVercelSandboxAuthenticationError({
1051
- settings: this.settings,
1052
- operation: () => Sandbox2.get({
1053
- ...getSandboxLookupParams(this.settings),
1054
- name: sessionSandboxName(options.sessionId),
1055
- ...options.abortSignal ? { signal: options.abortSignal } : {}
1056
- })
1057
- });
1058
- return new VercelNetworkSandboxSession({ sandbox, ownsLifecycle: true });
1059
- };
1060
- console.warn(
1061
- "VercelSandboxProvider is deprecated. Use createVercelNetworkSandboxSession instead."
1062
- );
1063
- }
734
+ constructor(settings) {
735
+ this.settings = settings;
736
+ this.specificationVersion = "harness-sandbox-v1";
737
+ this.providerId = VERCEL_PROVIDER_ID;
738
+ this.createSession = async (options) => {
739
+ options?.abortSignal?.throwIfAborted();
740
+ if ("sandbox" in this.settings && this.settings.sandbox != null) return new VercelNetworkSandboxSession({
741
+ sandbox: this.settings.sandbox,
742
+ ownsLifecycle: false
743
+ });
744
+ const { sandbox: _ignoredSandbox, name: explicitName, ...createParams } = this.settings;
745
+ const baseParams = withDefaultSandboxSettings(createParams);
746
+ const identity = options?.identity;
747
+ const onFirstCreate = options?.onFirstCreate;
748
+ const sessionNameOverride = options?.sessionId ? { name: sessionSandboxName(options.sessionId) } : {};
749
+ if (identity == null || onFirstCreate == null) return new VercelNetworkSandboxSession({
750
+ sandbox: await withVercelSandboxAuthenticationError({
751
+ settings: this.settings,
752
+ operation: () => Sandbox.create({
753
+ ...baseParams,
754
+ ...sessionNameOverride,
755
+ ...options?.abortSignal ? { signal: options.abortSignal } : {}
756
+ })
757
+ }),
758
+ ownsLifecycle: true
759
+ });
760
+ const templateName = explicitName ?? `ai-sdk-harness-${identity}`;
761
+ const snapshotId = await withVercelSandboxAuthenticationError({
762
+ settings: this.settings,
763
+ operation: () => ensureTemplateSnapshot({
764
+ baseParams,
765
+ templateName,
766
+ lookupParams: getSandboxLookupParams(baseParams),
767
+ abortSignal: options?.abortSignal,
768
+ snapshotCache: getSnapshotCache(),
769
+ onCreate: async (sbx) => {
770
+ await onFirstCreate(new VercelSandboxSession(sbx), { abortSignal: options?.abortSignal });
771
+ }
772
+ })
773
+ });
774
+ return new VercelNetworkSandboxSession({
775
+ sandbox: await withVercelSandboxAuthenticationError({
776
+ settings: this.settings,
777
+ operation: () => createLiveSandboxFromSnapshot({
778
+ baseParams,
779
+ snapshotId,
780
+ liveName: sessionNameOverride.name,
781
+ abortSignal: options?.abortSignal
782
+ })
783
+ }),
784
+ ownsLifecycle: true
785
+ });
786
+ };
787
+ this.resumeSession = async (options) => {
788
+ options.abortSignal?.throwIfAborted();
789
+ if ("sandbox" in this.settings && this.settings.sandbox != null) return new VercelNetworkSandboxSession({
790
+ sandbox: this.settings.sandbox,
791
+ ownsLifecycle: false
792
+ });
793
+ return new VercelNetworkSandboxSession({
794
+ sandbox: await withVercelSandboxAuthenticationError({
795
+ settings: this.settings,
796
+ operation: () => Sandbox.get({
797
+ ...getSandboxLookupParams(this.settings),
798
+ name: sessionSandboxName(options.sessionId),
799
+ ...options.abortSignal ? { signal: options.abortSignal } : {}
800
+ })
801
+ }),
802
+ ownsLifecycle: true
803
+ });
804
+ };
805
+ console.warn("VercelSandboxProvider is deprecated. Use createVercelNetworkSandboxSession instead.");
806
+ }
1064
807
  };
1065
- var SNAPSHOT_CACHE_KEY = /* @__PURE__ */ Symbol.for(
1066
- "ai-sdk.harness.vercel-template-snapshots"
1067
- );
808
+ const SNAPSHOT_CACHE_KEY = Symbol.for("ai-sdk.harness.vercel-template-snapshots");
1068
809
  function getSnapshotCache() {
1069
- const globals = globalThis;
1070
- let cache = globals[SNAPSHOT_CACHE_KEY];
1071
- if (cache == null) {
1072
- cache = /* @__PURE__ */ new Map();
1073
- globals[SNAPSHOT_CACHE_KEY] = cache;
1074
- }
1075
- return cache;
1076
- }
1077
-
1078
- // src/vercel-sandbox.ts
1079
- import { Sandbox as Sandbox3 } from "@vercel/sandbox";
810
+ const globals = globalThis;
811
+ let cache = globals[SNAPSHOT_CACHE_KEY];
812
+ if (cache == null) {
813
+ cache = /* @__PURE__ */ new Map();
814
+ globals[SNAPSHOT_CACHE_KEY] = cache;
815
+ }
816
+ return cache;
817
+ }
818
+ //#endregion
819
+ //#region src/vercel-sandbox.ts
1080
820
  async function createVercelNetworkSandboxSession(options = {}) {
1081
- if ("sandbox" in options) {
1082
- throw new Error(
1083
- "createVercelNetworkSandboxSession: use createVercelNetworkSandboxSessionFromNativeSandbox for an existing sandbox."
1084
- );
1085
- }
1086
- const {
1087
- template,
1088
- abortSignal,
1089
- sandboxId,
1090
- sandbox: _sandbox,
1091
- ...nativeOptions
1092
- } = options;
1093
- const effectiveSignal = abortSignal ?? nativeOptions.signal;
1094
- effectiveSignal?.throwIfAborted();
1095
- const { name, ...creationOptions } = nativeOptions;
1096
- if (sandboxId != null && name != null && sandboxId !== name) {
1097
- throw new Error(
1098
- "createVercelNetworkSandboxSession: sandboxId and name must match when both are provided."
1099
- );
1100
- }
1101
- const liveName = sandboxId ?? name;
1102
- const baseParams = withDefaultSandboxSettings({
1103
- ...creationOptions,
1104
- ...effectiveSignal ? { signal: effectiveSignal } : {}
1105
- });
1106
- const settings = options;
1107
- if (template == null) {
1108
- const sandbox = await withVercelSandboxAuthenticationError({
1109
- settings,
1110
- operation: () => Sandbox3.create({
1111
- ...baseParams,
1112
- ...liveName != null ? { name: liveName } : {}
1113
- })
1114
- });
1115
- return createVercelNetworkSandboxSessionFromNativeSandbox(sandbox);
1116
- }
1117
- const selection = "source" in baseParams && baseParams.source != null ? baseParams.source : "image" in baseParams && baseParams.image != null ? { image: baseParams.image } : { runtime: baseParams.runtime };
1118
- const material = JSON.stringify([2, template.identity, selection]);
1119
- const digest = new Uint8Array(
1120
- await crypto.subtle.digest("SHA-256", new TextEncoder().encode(material))
1121
- );
1122
- const templateName = `ai-sdk-harness-v2-${Array.from(digest.slice(0, 12), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
1123
- const snapshotId = await withVercelSandboxAuthenticationError({
1124
- settings,
1125
- operation: () => ensureTemplateSnapshot({
1126
- baseParams,
1127
- templateName,
1128
- lookupParams: getSandboxLookupParams(baseParams),
1129
- abortSignal: effectiveSignal,
1130
- onCreate: async (sandbox) => {
1131
- await template.prepare({
1132
- session: createVercelSandboxSessionFromNativeSandbox(sandbox),
1133
- abortSignal: effectiveSignal
1134
- });
1135
- }
1136
- })
1137
- });
1138
- const liveSandbox = await withVercelSandboxAuthenticationError({
1139
- settings,
1140
- operation: () => createLiveSandboxFromSnapshot({
1141
- baseParams,
1142
- snapshotId,
1143
- liveName
1144
- })
1145
- });
1146
- return createVercelNetworkSandboxSessionFromNativeSandbox(liveSandbox);
821
+ if ("sandbox" in options) throw new Error("createVercelNetworkSandboxSession: use createVercelNetworkSandboxSessionFromNativeSandbox for an existing sandbox.");
822
+ const { template, abortSignal, sandboxId, sandbox: _sandbox, ...nativeOptions } = options;
823
+ const effectiveSignal = abortSignal ?? nativeOptions.signal;
824
+ effectiveSignal?.throwIfAborted();
825
+ const { name, ...creationOptions } = nativeOptions;
826
+ if (sandboxId != null && name != null && sandboxId !== name) throw new Error("createVercelNetworkSandboxSession: sandboxId and name must match when both are provided.");
827
+ const liveName = sandboxId ?? name;
828
+ const baseParams = withDefaultSandboxSettings({
829
+ ...creationOptions,
830
+ ...effectiveSignal ? { signal: effectiveSignal } : {}
831
+ });
832
+ const settings = options;
833
+ if (template == null) return createVercelNetworkSandboxSessionFromNativeSandbox(await withVercelSandboxAuthenticationError({
834
+ settings,
835
+ operation: () => Sandbox.create({
836
+ ...baseParams,
837
+ ...liveName != null ? { name: liveName } : {}
838
+ })
839
+ }));
840
+ const selection = "source" in baseParams && baseParams.source != null ? baseParams.source : "image" in baseParams && baseParams.image != null ? { image: baseParams.image } : { runtime: baseParams.runtime };
841
+ const material = JSON.stringify([
842
+ 2,
843
+ template.identity,
844
+ selection
845
+ ]);
846
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(material)));
847
+ const templateName = `ai-sdk-harness-v2-${Array.from(digest.slice(0, 12), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
848
+ const snapshotId = await withVercelSandboxAuthenticationError({
849
+ settings,
850
+ operation: () => ensureTemplateSnapshot({
851
+ baseParams,
852
+ templateName,
853
+ lookupParams: getSandboxLookupParams(baseParams),
854
+ abortSignal: effectiveSignal,
855
+ onCreate: async (sandbox) => {
856
+ await template.prepare({
857
+ session: createVercelSandboxSessionFromNativeSandbox(sandbox),
858
+ abortSignal: effectiveSignal
859
+ });
860
+ }
861
+ })
862
+ });
863
+ return createVercelNetworkSandboxSessionFromNativeSandbox(await withVercelSandboxAuthenticationError({
864
+ settings,
865
+ operation: () => createLiveSandboxFromSnapshot({
866
+ baseParams,
867
+ snapshotId,
868
+ liveName
869
+ })
870
+ }));
1147
871
  }
1148
872
  async function resumeVercelNetworkSandboxSession(options) {
1149
- const {
1150
- sandboxId,
1151
- abortSignal,
1152
- signal,
1153
- name: _name,
1154
- resume: _resume,
1155
- ...lookupOptions
1156
- } = options;
1157
- const effectiveSignal = abortSignal ?? signal;
1158
- effectiveSignal?.throwIfAborted();
1159
- const sandbox = await withVercelSandboxAuthenticationError({
1160
- settings: options,
1161
- operation: () => Sandbox3.get({
1162
- ...lookupOptions,
1163
- name: sandboxId,
1164
- resume: true,
1165
- ...effectiveSignal ? { signal: effectiveSignal } : {}
1166
- })
1167
- });
1168
- return createVercelNetworkSandboxSessionFromNativeSandbox(sandbox);
873
+ const { sandboxId, abortSignal, signal, name: _name, resume: _resume, ...lookupOptions } = options;
874
+ const effectiveSignal = abortSignal ?? signal;
875
+ effectiveSignal?.throwIfAborted();
876
+ return createVercelNetworkSandboxSessionFromNativeSandbox(await withVercelSandboxAuthenticationError({
877
+ settings: options,
878
+ operation: () => Sandbox.get({
879
+ ...lookupOptions,
880
+ name: sandboxId,
881
+ resume: true,
882
+ ...effectiveSignal ? { signal: effectiveSignal } : {}
883
+ })
884
+ }));
1169
885
  }
1170
886
  function createVercelSandboxSessionFromNativeSandbox(nativeSandbox) {
1171
- return new VercelSandboxSession(nativeSandbox);
887
+ return new VercelSandboxSession(nativeSandbox);
1172
888
  }
1173
889
  function createVercelNetworkSandboxSessionFromNativeSandbox(nativeSandbox) {
1174
- return new VercelNetworkSandboxSession({
1175
- sandbox: nativeSandbox,
1176
- ownsLifecycle: true
1177
- });
890
+ return new VercelNetworkSandboxSession({
891
+ sandbox: nativeSandbox,
892
+ ownsLifecycle: true
893
+ });
1178
894
  }
1179
- export {
1180
- VercelSandboxProvider,
1181
- createVercelNetworkSandboxSession,
1182
- createVercelNetworkSandboxSessionFromNativeSandbox,
1183
- createVercelSandbox,
1184
- createVercelSandboxSessionFromNativeSandbox,
1185
- resumeVercelNetworkSandboxSession
1186
- };
895
+ //#endregion
896
+ export { VercelSandboxProvider, createVercelNetworkSandboxSession, createVercelNetworkSandboxSessionFromNativeSandbox, createVercelSandbox, createVercelSandboxSessionFromNativeSandbox, resumeVercelNetworkSandboxSession };
897
+
1187
898
  //# sourceMappingURL=index.js.map