@openai/agents-extensions 0.8.4 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/dist/ai-sdk-ui/uiMessageStream.d.ts +5 -0
  2. package/dist/ai-sdk-ui/uiMessageStream.js +10 -3
  3. package/dist/ai-sdk-ui/uiMessageStream.js.map +1 -1
  4. package/dist/ai-sdk-ui/uiMessageStream.mjs +9 -3
  5. package/dist/ai-sdk-ui/uiMessageStream.mjs.map +1 -1
  6. package/dist/metadata.js +2 -2
  7. package/dist/metadata.mjs +2 -2
  8. package/dist/sandbox/blaxel/index.d.ts +2 -0
  9. package/dist/sandbox/blaxel/index.js +19 -0
  10. package/dist/sandbox/blaxel/index.js.map +1 -0
  11. package/dist/sandbox/blaxel/index.mjs +3 -0
  12. package/dist/sandbox/blaxel/index.mjs.map +1 -0
  13. package/dist/sandbox/blaxel/mounts.d.ts +101 -0
  14. package/dist/sandbox/blaxel/mounts.js +542 -0
  15. package/dist/sandbox/blaxel/mounts.js.map +1 -0
  16. package/dist/sandbox/blaxel/mounts.mjs +529 -0
  17. package/dist/sandbox/blaxel/mounts.mjs.map +1 -0
  18. package/dist/sandbox/blaxel/sandbox.d.ts +155 -0
  19. package/dist/sandbox/blaxel/sandbox.js +1110 -0
  20. package/dist/sandbox/blaxel/sandbox.js.map +1 -0
  21. package/dist/sandbox/blaxel/sandbox.mjs +1072 -0
  22. package/dist/sandbox/blaxel/sandbox.mjs.map +1 -0
  23. package/dist/sandbox/cloudflare/index.d.ts +2 -0
  24. package/dist/sandbox/cloudflare/index.js +19 -0
  25. package/dist/sandbox/cloudflare/index.js.map +1 -0
  26. package/dist/sandbox/cloudflare/index.mjs +3 -0
  27. package/dist/sandbox/cloudflare/index.mjs.map +1 -0
  28. package/dist/sandbox/cloudflare/mounts.d.ts +28 -0
  29. package/dist/sandbox/cloudflare/mounts.js +150 -0
  30. package/dist/sandbox/cloudflare/mounts.js.map +1 -0
  31. package/dist/sandbox/cloudflare/mounts.mjs +143 -0
  32. package/dist/sandbox/cloudflare/mounts.mjs.map +1 -0
  33. package/dist/sandbox/cloudflare/sandbox.d.ts +91 -0
  34. package/dist/sandbox/cloudflare/sandbox.js +1163 -0
  35. package/dist/sandbox/cloudflare/sandbox.js.map +1 -0
  36. package/dist/sandbox/cloudflare/sandbox.mjs +1125 -0
  37. package/dist/sandbox/cloudflare/sandbox.mjs.map +1 -0
  38. package/dist/sandbox/daytona/index.d.ts +2 -0
  39. package/dist/sandbox/daytona/index.js +19 -0
  40. package/dist/sandbox/daytona/index.js.map +1 -0
  41. package/dist/sandbox/daytona/index.mjs +3 -0
  42. package/dist/sandbox/daytona/index.mjs.map +1 -0
  43. package/dist/sandbox/daytona/mounts.d.ts +11 -0
  44. package/dist/sandbox/daytona/mounts.js +17 -0
  45. package/dist/sandbox/daytona/mounts.js.map +1 -0
  46. package/dist/sandbox/daytona/mounts.mjs +12 -0
  47. package/dist/sandbox/daytona/mounts.mjs.map +1 -0
  48. package/dist/sandbox/daytona/sandbox.d.ts +160 -0
  49. package/dist/sandbox/daytona/sandbox.js +938 -0
  50. package/dist/sandbox/daytona/sandbox.js.map +1 -0
  51. package/dist/sandbox/daytona/sandbox.mjs +900 -0
  52. package/dist/sandbox/daytona/sandbox.mjs.map +1 -0
  53. package/dist/sandbox/e2b/index.d.ts +2 -0
  54. package/dist/sandbox/e2b/index.js +19 -0
  55. package/dist/sandbox/e2b/index.js.map +1 -0
  56. package/dist/sandbox/e2b/index.mjs +3 -0
  57. package/dist/sandbox/e2b/index.mjs.map +1 -0
  58. package/dist/sandbox/e2b/mounts.d.ts +11 -0
  59. package/dist/sandbox/e2b/mounts.js +17 -0
  60. package/dist/sandbox/e2b/mounts.js.map +1 -0
  61. package/dist/sandbox/e2b/mounts.mjs +12 -0
  62. package/dist/sandbox/e2b/mounts.mjs.map +1 -0
  63. package/dist/sandbox/e2b/sandbox.d.ts +169 -0
  64. package/dist/sandbox/e2b/sandbox.js +829 -0
  65. package/dist/sandbox/e2b/sandbox.js.map +1 -0
  66. package/dist/sandbox/e2b/sandbox.mjs +791 -0
  67. package/dist/sandbox/e2b/sandbox.mjs.map +1 -0
  68. package/dist/sandbox/modal/index.d.ts +2 -0
  69. package/dist/sandbox/modal/index.js +19 -0
  70. package/dist/sandbox/modal/index.js.map +1 -0
  71. package/dist/sandbox/modal/index.mjs +3 -0
  72. package/dist/sandbox/modal/index.mjs.map +1 -0
  73. package/dist/sandbox/modal/mounts.d.ts +24 -0
  74. package/dist/sandbox/modal/mounts.js +194 -0
  75. package/dist/sandbox/modal/mounts.js.map +1 -0
  76. package/dist/sandbox/modal/mounts.mjs +188 -0
  77. package/dist/sandbox/modal/mounts.mjs.map +1 -0
  78. package/dist/sandbox/modal/sandbox.d.ts +220 -0
  79. package/dist/sandbox/modal/sandbox.js +1621 -0
  80. package/dist/sandbox/modal/sandbox.js.map +1 -0
  81. package/dist/sandbox/modal/sandbox.mjs +1581 -0
  82. package/dist/sandbox/modal/sandbox.mjs.map +1 -0
  83. package/dist/sandbox/runloop/index.d.ts +2 -0
  84. package/dist/sandbox/runloop/index.js +19 -0
  85. package/dist/sandbox/runloop/index.js.map +1 -0
  86. package/dist/sandbox/runloop/index.mjs +3 -0
  87. package/dist/sandbox/runloop/index.mjs.map +1 -0
  88. package/dist/sandbox/runloop/mounts.d.ts +11 -0
  89. package/dist/sandbox/runloop/mounts.js +17 -0
  90. package/dist/sandbox/runloop/mounts.js.map +1 -0
  91. package/dist/sandbox/runloop/mounts.mjs +12 -0
  92. package/dist/sandbox/runloop/mounts.mjs.map +1 -0
  93. package/dist/sandbox/runloop/sandbox.d.ts +266 -0
  94. package/dist/sandbox/runloop/sandbox.js +1390 -0
  95. package/dist/sandbox/runloop/sandbox.js.map +1 -0
  96. package/dist/sandbox/runloop/sandbox.mjs +1346 -0
  97. package/dist/sandbox/runloop/sandbox.mjs.map +1 -0
  98. package/dist/sandbox/shared/archive.d.ts +34 -0
  99. package/dist/sandbox/shared/archive.js +397 -0
  100. package/dist/sandbox/shared/archive.js.map +1 -0
  101. package/dist/sandbox/shared/archive.mjs +389 -0
  102. package/dist/sandbox/shared/archive.mjs.map +1 -0
  103. package/dist/sandbox/shared/editor.d.ts +17 -0
  104. package/dist/sandbox/shared/editor.js +65 -0
  105. package/dist/sandbox/shared/editor.js.map +1 -0
  106. package/dist/sandbox/shared/editor.mjs +61 -0
  107. package/dist/sandbox/shared/editor.mjs.map +1 -0
  108. package/dist/sandbox/shared/environment.d.ts +1 -0
  109. package/dist/sandbox/shared/environment.js +13 -0
  110. package/dist/sandbox/shared/environment.js.map +1 -0
  111. package/dist/sandbox/shared/environment.mjs +2 -0
  112. package/dist/sandbox/shared/environment.mjs.map +1 -0
  113. package/dist/sandbox/shared/git.d.ts +4 -0
  114. package/dist/sandbox/shared/git.js +20 -0
  115. package/dist/sandbox/shared/git.js.map +1 -0
  116. package/dist/sandbox/shared/git.mjs +17 -0
  117. package/dist/sandbox/shared/git.mjs.map +1 -0
  118. package/dist/sandbox/shared/inContainerMounts.d.ts +40 -0
  119. package/dist/sandbox/shared/inContainerMounts.js +670 -0
  120. package/dist/sandbox/shared/inContainerMounts.js.map +1 -0
  121. package/dist/sandbox/shared/inContainerMounts.mjs +662 -0
  122. package/dist/sandbox/shared/inContainerMounts.mjs.map +1 -0
  123. package/dist/sandbox/shared/index.d.ts +23 -0
  124. package/dist/sandbox/shared/index.js +112 -0
  125. package/dist/sandbox/shared/index.js.map +1 -0
  126. package/dist/sandbox/shared/index.mjs +18 -0
  127. package/dist/sandbox/shared/index.mjs.map +1 -0
  128. package/dist/sandbox/shared/localSources.d.ts +8 -0
  129. package/dist/sandbox/shared/localSources.js +378 -0
  130. package/dist/sandbox/shared/localSources.js.map +1 -0
  131. package/dist/sandbox/shared/localSources.mjs +372 -0
  132. package/dist/sandbox/shared/localSources.mjs.map +1 -0
  133. package/dist/sandbox/shared/manifest.d.ts +38 -0
  134. package/dist/sandbox/shared/manifest.js +254 -0
  135. package/dist/sandbox/shared/manifest.js.map +1 -0
  136. package/dist/sandbox/shared/manifest.mjs +233 -0
  137. package/dist/sandbox/shared/manifest.mjs.map +1 -0
  138. package/dist/sandbox/shared/media.d.ts +1 -0
  139. package/dist/sandbox/shared/media.js +10 -0
  140. package/dist/sandbox/shared/media.js.map +1 -0
  141. package/dist/sandbox/shared/media.mjs +2 -0
  142. package/dist/sandbox/shared/media.mjs.map +1 -0
  143. package/dist/sandbox/shared/metadata.d.ts +7 -0
  144. package/dist/sandbox/shared/metadata.js +87 -0
  145. package/dist/sandbox/shared/metadata.js.map +1 -0
  146. package/dist/sandbox/shared/metadata.mjs +81 -0
  147. package/dist/sandbox/shared/metadata.mjs.map +1 -0
  148. package/dist/sandbox/shared/output.d.ts +1 -0
  149. package/dist/sandbox/shared/output.js +8 -0
  150. package/dist/sandbox/shared/output.js.map +1 -0
  151. package/dist/sandbox/shared/output.mjs +2 -0
  152. package/dist/sandbox/shared/output.mjs.map +1 -0
  153. package/dist/sandbox/shared/paths.d.ts +27 -0
  154. package/dist/sandbox/shared/paths.js +245 -0
  155. package/dist/sandbox/shared/paths.js.map +1 -0
  156. package/dist/sandbox/shared/paths.mjs +236 -0
  157. package/dist/sandbox/shared/paths.mjs.map +1 -0
  158. package/dist/sandbox/shared/ports.d.ts +14 -0
  159. package/dist/sandbox/shared/ports.js +75 -0
  160. package/dist/sandbox/shared/ports.js.map +1 -0
  161. package/dist/sandbox/shared/ports.mjs +69 -0
  162. package/dist/sandbox/shared/ports.mjs.map +1 -0
  163. package/dist/sandbox/shared/process.d.ts +16 -0
  164. package/dist/sandbox/shared/process.js +90 -0
  165. package/dist/sandbox/shared/process.js.map +1 -0
  166. package/dist/sandbox/shared/process.mjs +86 -0
  167. package/dist/sandbox/shared/process.mjs.map +1 -0
  168. package/dist/sandbox/shared/pty.d.ts +81 -0
  169. package/dist/sandbox/shared/pty.js +382 -0
  170. package/dist/sandbox/shared/pty.js.map +1 -0
  171. package/dist/sandbox/shared/pty.mjs +335 -0
  172. package/dist/sandbox/shared/pty.mjs.map +1 -0
  173. package/dist/sandbox/shared/runAs.d.ts +46 -0
  174. package/dist/sandbox/shared/runAs.js +149 -0
  175. package/dist/sandbox/shared/runAs.js.map +1 -0
  176. package/dist/sandbox/shared/runAs.mjs +141 -0
  177. package/dist/sandbox/shared/runAs.mjs.map +1 -0
  178. package/dist/sandbox/shared/session.d.ts +16 -0
  179. package/dist/sandbox/shared/session.js +138 -0
  180. package/dist/sandbox/shared/session.js.map +1 -0
  181. package/dist/sandbox/shared/session.mjs +128 -0
  182. package/dist/sandbox/shared/session.mjs.map +1 -0
  183. package/dist/sandbox/shared/sessionBase.d.ts +90 -0
  184. package/dist/sandbox/shared/sessionBase.js +446 -0
  185. package/dist/sandbox/shared/sessionBase.js.map +1 -0
  186. package/dist/sandbox/shared/sessionBase.mjs +442 -0
  187. package/dist/sandbox/shared/sessionBase.mjs.map +1 -0
  188. package/dist/sandbox/shared/sessionState.d.ts +7 -0
  189. package/dist/sandbox/shared/sessionState.js +35 -0
  190. package/dist/sandbox/shared/sessionState.js.map +1 -0
  191. package/dist/sandbox/shared/sessionState.mjs +31 -0
  192. package/dist/sandbox/shared/sessionState.mjs.map +1 -0
  193. package/dist/sandbox/shared/snapshots.d.ts +9 -0
  194. package/dist/sandbox/shared/snapshots.js +62 -0
  195. package/dist/sandbox/shared/snapshots.js.map +1 -0
  196. package/dist/sandbox/shared/snapshots.mjs +57 -0
  197. package/dist/sandbox/shared/snapshots.mjs.map +1 -0
  198. package/dist/sandbox/shared/typeGuards.d.ts +10 -0
  199. package/dist/sandbox/shared/typeGuards.js +50 -0
  200. package/dist/sandbox/shared/typeGuards.js.map +1 -0
  201. package/dist/sandbox/shared/typeGuards.mjs +38 -0
  202. package/dist/sandbox/shared/typeGuards.mjs.map +1 -0
  203. package/dist/sandbox/shared/types.d.ts +24 -0
  204. package/dist/sandbox/shared/types.js +3 -0
  205. package/dist/sandbox/shared/types.js.map +1 -0
  206. package/dist/sandbox/shared/types.mjs +2 -0
  207. package/dist/sandbox/shared/types.mjs.map +1 -0
  208. package/dist/sandbox/vercel/index.d.ts +1 -0
  209. package/dist/sandbox/vercel/index.js +18 -0
  210. package/dist/sandbox/vercel/index.js.map +1 -0
  211. package/dist/sandbox/vercel/index.mjs +2 -0
  212. package/dist/sandbox/vercel/index.mjs.map +1 -0
  213. package/dist/sandbox/vercel/sandbox.d.ts +135 -0
  214. package/dist/sandbox/vercel/sandbox.js +1001 -0
  215. package/dist/sandbox/vercel/sandbox.js.map +1 -0
  216. package/dist/sandbox/vercel/sandbox.mjs +963 -0
  217. package/dist/sandbox/vercel/sandbox.mjs.map +1 -0
  218. package/package.json +108 -4
@@ -0,0 +1,963 @@
1
+ import { UserError } from '@openai/agents-core';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { dirname as pathDirname, join as pathJoin, resolve as pathResolve, } from 'node:path';
4
+ import { SandboxLifecycleError, SandboxProviderError, SandboxUnsupportedFeatureError, normalizeSandboxClientCreateArgs, } from '@openai/agents-core/sandbox';
5
+ import { assertCoreSnapshotUnsupported, assertSandboxManifestMetadataSupported, assertRunAsUnsupported, cloneManifestWithRoot, deserializeRemoteSandboxSessionStateValues, decodeNativeSnapshotRef, encodeNativeSnapshotRef, materializeEnvironment, posixDirname, shellQuote, serializeRemoteSandboxSessionState, toUint8Array, readOptionalBoolean, readOptionalNumber, readOptionalNumberArray, readOptionalRecord, readOptionalString, readString, isProviderSandboxNotFoundError, withProviderError, withSandboxSpan, RemoteSandboxSessionBase, } from "../shared/index.mjs";
6
+ const DEFAULT_VERCEL_WORKSPACE_ROOT = '/vercel/sandbox';
7
+ export class VercelSandboxSession extends RemoteSandboxSessionBase {
8
+ sandbox;
9
+ knownDirs;
10
+ pendingDirCreates = new Map();
11
+ closePromise;
12
+ closeCompleted = false;
13
+ credentials;
14
+ constructor(args) {
15
+ super({
16
+ state: args.state,
17
+ options: {
18
+ providerName: 'VercelSandboxClient',
19
+ providerId: 'vercel',
20
+ concurrencyLimits: args.concurrencyLimits,
21
+ },
22
+ });
23
+ this.sandbox = args.sandbox;
24
+ this.credentials = args.credentials ?? {};
25
+ this.knownDirs = new Set();
26
+ this.resetKnownDirs();
27
+ }
28
+ supportsPty() {
29
+ return false;
30
+ }
31
+ assertExecRunAs(runAs) {
32
+ assertRunAsUnsupported('VercelSandboxClient', runAs);
33
+ }
34
+ assertFilesystemRunAs(runAs) {
35
+ assertFilesystemRunAs(runAs);
36
+ }
37
+ resolveManifestForApply(manifest) {
38
+ return resolveManifestRoot(manifest);
39
+ }
40
+ async beforeFilesystemMutation() {
41
+ this.markWorkspaceMutated();
42
+ }
43
+ async beforeExecCommand() {
44
+ this.markWorkspaceMutated();
45
+ this.resetKnownDirs();
46
+ }
47
+ async beforeMaterializeEntry() {
48
+ this.markWorkspaceMutated();
49
+ }
50
+ async beforeApplyManifest() {
51
+ this.markWorkspaceMutated();
52
+ }
53
+ runningWorkdir() {
54
+ return '/';
55
+ }
56
+ exposedPortSource() {
57
+ return 'domain';
58
+ }
59
+ async resolveRemoteExposedPort(requestedPort) {
60
+ if (!this.sandbox.domain) {
61
+ throw new SandboxProviderError('VercelSandboxClient exposed port resolution requires @vercel/sandbox domain(port) support.', {
62
+ provider: 'vercel',
63
+ port: requestedPort,
64
+ });
65
+ }
66
+ try {
67
+ return this.sandbox.domain(requestedPort);
68
+ }
69
+ catch (error) {
70
+ throw new SandboxProviderError(`VercelSandboxClient failed to resolve exposed port ${requestedPort}.`, {
71
+ provider: 'vercel',
72
+ port: requestedPort,
73
+ cause: error instanceof Error ? error.message : String(error),
74
+ });
75
+ }
76
+ }
77
+ async materializeInitialManifest(manifest) {
78
+ this.markWorkspaceMutated();
79
+ await this.materializeManifestEntries(manifest);
80
+ }
81
+ async prepareWorkspaceRoot() {
82
+ this.markWorkspaceMutated();
83
+ await this.ensureDir(this.state.manifest.root);
84
+ }
85
+ async persistWorkspace() {
86
+ if (this.state.workspacePersistence === 'snapshot') {
87
+ await captureVercelSnapshot(this.state, {
88
+ sandbox: this.sandbox,
89
+ });
90
+ const snapshotId = this.state.snapshotId;
91
+ if (!snapshotId) {
92
+ throw new SandboxProviderError('Vercel snapshot persistence did not produce a snapshot id.', {
93
+ provider: 'vercel',
94
+ sandboxId: this.state.sandboxId,
95
+ });
96
+ }
97
+ try {
98
+ await this.replaceSandboxFromSnapshot(snapshotId, {
99
+ snapshotFreshAfterRestore: true,
100
+ ignorePreviousStopFailure: true,
101
+ });
102
+ }
103
+ catch (error) {
104
+ await this.recoverSandboxAfterSnapshotRestoreFailure(snapshotId, error);
105
+ }
106
+ return encodeNativeSnapshotRef({
107
+ provider: 'vercel',
108
+ snapshotId,
109
+ });
110
+ }
111
+ return await this.persistWorkspaceTar();
112
+ }
113
+ async hydrateWorkspace(data) {
114
+ this.markWorkspaceMutated();
115
+ const snapshotRef = this.state.workspacePersistence === 'snapshot'
116
+ ? decodeNativeSnapshotRef(data)
117
+ : undefined;
118
+ if (snapshotRef?.provider === 'vercel') {
119
+ await this.replaceSandboxFromSnapshot(snapshotRef.snapshotId);
120
+ return;
121
+ }
122
+ await this.hydrateWorkspaceTar(data);
123
+ this.resetKnownDirs();
124
+ this.knownDirs.add(this.state.manifest.root);
125
+ }
126
+ async close() {
127
+ if (this.closeCompleted) {
128
+ return;
129
+ }
130
+ this.closePromise ??= this.closeOnce().catch((error) => {
131
+ if (!this.closeCompleted) {
132
+ this.closePromise = undefined;
133
+ }
134
+ throw error;
135
+ });
136
+ await this.closePromise;
137
+ }
138
+ async closeOnce() {
139
+ let snapshotError;
140
+ let snapshotCapturedBeforeStop = false;
141
+ if (this.state.workspacePersistence === 'snapshot' &&
142
+ this.sandbox.snapshot &&
143
+ this.state.snapshotSandboxId !== this.sandbox.sandboxId) {
144
+ try {
145
+ await captureVercelSnapshot(this.state, {
146
+ sandbox: this.sandbox,
147
+ });
148
+ snapshotCapturedBeforeStop = true;
149
+ }
150
+ catch (error) {
151
+ snapshotError = error;
152
+ }
153
+ }
154
+ try {
155
+ await stopVercelSandbox(this.sandbox);
156
+ this.closeCompleted = true;
157
+ }
158
+ catch (stopError) {
159
+ if (snapshotError) {
160
+ throw new UserError(`Failed to capture a Vercel sandbox snapshot and stop the sandbox. Snapshot error: ${errorMessage(snapshotError)} Stop error: ${errorMessage(stopError)}`);
161
+ }
162
+ if (snapshotCapturedBeforeStop) {
163
+ this.closeCompleted = true;
164
+ return;
165
+ }
166
+ throw stopError;
167
+ }
168
+ if (snapshotError) {
169
+ throw snapshotError;
170
+ }
171
+ }
172
+ async shutdown() {
173
+ await this.close();
174
+ }
175
+ async delete() {
176
+ await this.close();
177
+ }
178
+ async execShell(command, cwd, sudo) {
179
+ const result = await this.sandbox.runCommand({
180
+ cmd: '/bin/sh',
181
+ args: ['-lc', command],
182
+ cwd,
183
+ env: this.state.environment,
184
+ ...(sudo ? { sudo: true } : {}),
185
+ });
186
+ return {
187
+ exitCode: result.exitCode ?? 1,
188
+ output: await result.output('both'),
189
+ };
190
+ }
191
+ async replaceSandboxFromSnapshot(snapshotId, options = {}) {
192
+ const previousSandbox = this.sandbox;
193
+ const credentials = await this.resolveSnapshotCredentials();
194
+ const sandbox = await this.createAndPrepareSandboxFromSnapshot(snapshotId, credentials);
195
+ try {
196
+ await stopVercelSandbox(previousSandbox);
197
+ }
198
+ catch (error) {
199
+ if (options.ignorePreviousStopFailure &&
200
+ isVercelSandboxAlreadyStoppedError(error)) {
201
+ this.bindRestoredSandbox(sandbox, snapshotId, options.snapshotFreshAfterRestore);
202
+ return;
203
+ }
204
+ let replacementStopCause;
205
+ try {
206
+ await stopVercelSandbox(sandbox);
207
+ }
208
+ catch (replacementStopError) {
209
+ replacementStopCause = errorMessage(replacementStopError);
210
+ }
211
+ throw new SandboxProviderError('Vercel snapshot restore created a replacement sandbox, but stopping the previous sandbox failed.', {
212
+ provider: 'vercel',
213
+ sandboxId: previousSandbox.sandboxId,
214
+ replacementSandboxId: sandbox.sandboxId,
215
+ cause: errorMessage(error),
216
+ ...(replacementStopCause ? { replacementStopCause } : {}),
217
+ });
218
+ }
219
+ this.bindRestoredSandbox(sandbox, snapshotId, options.snapshotFreshAfterRestore);
220
+ }
221
+ async recoverSandboxAfterSnapshotRestoreFailure(snapshotId, restoreError) {
222
+ try {
223
+ await this.replaceSandboxFromSnapshot(snapshotId, {
224
+ snapshotFreshAfterRestore: true,
225
+ ignorePreviousStopFailure: true,
226
+ });
227
+ }
228
+ catch (recoveryError) {
229
+ throw new SandboxProviderError('Vercel snapshot persistence captured a snapshot, but restoring the live session failed and recovery also failed.', {
230
+ provider: 'vercel',
231
+ sandboxId: this.state.sandboxId,
232
+ snapshotId,
233
+ cause: errorMessage(restoreError),
234
+ recoveryCause: errorMessage(recoveryError),
235
+ });
236
+ }
237
+ }
238
+ async resolveSnapshotCredentials() {
239
+ const credentials = await resolveVercelCredentials({
240
+ ...this.credentials,
241
+ projectId: this.state.projectId ?? this.credentials.projectId,
242
+ teamId: this.state.teamId ?? this.credentials.teamId,
243
+ token: this.state.token ?? this.credentials.token,
244
+ });
245
+ applyResolvedVercelCredentials(this.state, credentials);
246
+ return credentials;
247
+ }
248
+ async createAndPrepareSandboxFromSnapshot(snapshotId, credentials) {
249
+ const sandbox = await this.createSandboxFromSnapshot(snapshotId, credentials);
250
+ const replacementSession = new VercelSandboxSession({
251
+ credentials: { ...this.credentials, ...credentials },
252
+ sandbox,
253
+ state: {
254
+ ...this.state,
255
+ sandboxId: sandbox.sandboxId,
256
+ snapshotId,
257
+ snapshotSandboxId: undefined,
258
+ snapshotSupported: supportsVercelSnapshot(sandbox),
259
+ exposedPorts: undefined,
260
+ },
261
+ });
262
+ try {
263
+ await waitForVercelSandboxRunning(replacementSession);
264
+ await replacementSession.prepareWorkspaceRoot();
265
+ }
266
+ catch (error) {
267
+ try {
268
+ await stopVercelSandbox(sandbox);
269
+ }
270
+ catch (stopError) {
271
+ throw new UserError(`Failed to restore a Vercel sandbox from snapshot and stop the replacement sandbox. Restore error: ${errorMessage(error)} Stop error: ${errorMessage(stopError)}`);
272
+ }
273
+ throw error;
274
+ }
275
+ return sandbox;
276
+ }
277
+ async createSandboxFromSnapshot(snapshotId, credentials) {
278
+ const Sandbox = await loadVercelSandboxClass();
279
+ return await withProviderError('VercelSandboxClient', 'vercel', 'restore snapshot', async () => await Sandbox.create({
280
+ ...credentials,
281
+ source: {
282
+ type: 'snapshot',
283
+ snapshotId,
284
+ },
285
+ ...(this.state.runtime ? { runtime: this.state.runtime } : {}),
286
+ ...(this.state.resources ? { resources: this.state.resources } : {}),
287
+ ...(this.state.configuredExposedPorts
288
+ ? { ports: this.state.configuredExposedPorts }
289
+ : {}),
290
+ ...(typeof this.state.interactive === 'boolean'
291
+ ? { interactive: this.state.interactive }
292
+ : {}),
293
+ ...(this.state.networkPolicy
294
+ ? { networkPolicy: this.state.networkPolicy }
295
+ : {}),
296
+ ...(typeof this.state.timeoutMs === 'number'
297
+ ? { timeout: this.state.timeoutMs }
298
+ : {}),
299
+ env: this.state.environment,
300
+ }), { snapshotId });
301
+ }
302
+ bindRestoredSandbox(sandbox, snapshotId, snapshotFreshAfterRestore) {
303
+ this.sandbox = sandbox;
304
+ this.resetKnownDirs();
305
+ this.knownDirs.add(this.state.manifest.root);
306
+ this.state.sandboxId = sandbox.sandboxId;
307
+ this.state.snapshotId = snapshotId;
308
+ this.state.snapshotSandboxId = snapshotFreshAfterRestore
309
+ ? sandbox.sandboxId
310
+ : undefined;
311
+ this.state.snapshotSupported = supportsVercelSnapshot(sandbox);
312
+ this.clearExposedPortCache();
313
+ }
314
+ resetKnownDirs() {
315
+ this.knownDirs.clear();
316
+ this.pendingDirCreates.clear();
317
+ this.knownDirs.add(DEFAULT_VERCEL_WORKSPACE_ROOT);
318
+ }
319
+ markWorkspaceMutated() {
320
+ if (this.state.workspacePersistence === 'snapshot') {
321
+ this.state.snapshotSandboxId = undefined;
322
+ }
323
+ }
324
+ clearExposedPortCache() {
325
+ this.state.exposedPorts = undefined;
326
+ }
327
+ async ensureDir(path) {
328
+ if (path === '/' || path === '.' || this.knownDirs.has(path)) {
329
+ return;
330
+ }
331
+ const pending = this.pendingDirCreates.get(path);
332
+ if (pending) {
333
+ await pending;
334
+ return;
335
+ }
336
+ const create = (async () => {
337
+ const parent = posixDirname(path);
338
+ if (parent !== path && parent !== '/' && parent !== '.') {
339
+ await this.ensureDir(parent);
340
+ }
341
+ try {
342
+ await this.sandbox.mkDir(path);
343
+ }
344
+ catch (error) {
345
+ if (!isVercelAlreadyExistsError(error)) {
346
+ throw error;
347
+ }
348
+ }
349
+ this.knownDirs.add(path);
350
+ })();
351
+ this.pendingDirCreates.set(path, create);
352
+ try {
353
+ await create;
354
+ }
355
+ finally {
356
+ this.pendingDirCreates.delete(path);
357
+ }
358
+ }
359
+ async runRemoteCommand(command, options) {
360
+ const result = await this.execShell(command, options.workdir, undefined);
361
+ return {
362
+ status: result.exitCode,
363
+ stdout: result.output,
364
+ stderr: '',
365
+ };
366
+ }
367
+ async mkdirRemote(path) {
368
+ await this.ensureDir(path);
369
+ }
370
+ async readRemoteText(path) {
371
+ return new TextDecoder().decode(await this.readRemoteFile(path));
372
+ }
373
+ async readRemoteFile(path) {
374
+ const bytes = await this.sandbox.readFileToBuffer({ path });
375
+ if (!bytes) {
376
+ throw new UserError(`Sandbox path not found: ${path}`);
377
+ }
378
+ return await toUint8Array(bytes);
379
+ }
380
+ async writeRemoteFile(path, content) {
381
+ await this.sandbox.writeFiles([
382
+ {
383
+ path,
384
+ content,
385
+ },
386
+ ]);
387
+ }
388
+ async deleteRemotePath(path) {
389
+ const result = await this.runRemoteCommand(`rm -f -- ${shellQuote(path)}`, {
390
+ kind: 'manifest',
391
+ workdir: this.state.manifest.root,
392
+ });
393
+ if (result.status !== 0) {
394
+ throw new SandboxProviderError('VercelSandboxClient failed to delete path.', {
395
+ provider: 'vercel',
396
+ operation: 'delete path',
397
+ sandboxId: this.state.sandboxId,
398
+ path,
399
+ exitCode: result.status,
400
+ output: result.stdout ?? '',
401
+ });
402
+ }
403
+ }
404
+ }
405
+ /**
406
+ * @see {@link https://vercel.com/docs/vercel-sandbox | Vercel Sandbox overview}.
407
+ * @see {@link https://vercel.com/docs/vercel-sandbox/sdk-reference | Sandbox SDK reference}.
408
+ * @see {@link https://vercel.com/docs/vercel-sandbox/working-with-sandbox | Working with Sandbox examples}.
409
+ */
410
+ export class VercelSandboxClient {
411
+ backendId = 'vercel';
412
+ options;
413
+ constructor(options = {}) {
414
+ this.options = options;
415
+ }
416
+ async create(args, manifestOptions) {
417
+ const createArgs = normalizeSandboxClientCreateArgs(args, manifestOptions);
418
+ assertCoreSnapshotUnsupported('VercelSandboxClient', createArgs.snapshot);
419
+ const manifest = createArgs.manifest;
420
+ const resolvedOptions = {
421
+ ...this.options,
422
+ ...createArgs.options,
423
+ };
424
+ const resolvedManifest = resolveManifestRoot(manifest);
425
+ assertSandboxManifestMetadataSupported('VercelSandboxClient', resolvedManifest);
426
+ return await withSandboxSpan('sandbox.start', {
427
+ backend_id: this.backendId,
428
+ }, async () => {
429
+ const Sandbox = await loadVercelSandboxClass();
430
+ const environment = await materializeEnvironment(resolvedManifest, resolvedOptions.env);
431
+ const credentials = await resolveVercelCredentials(resolvedOptions);
432
+ const sandbox = await withProviderError('VercelSandboxClient', 'vercel', 'create sandbox', async () => await Sandbox.create({
433
+ ...credentials,
434
+ ...(resolvedOptions.runtime
435
+ ? { runtime: resolvedOptions.runtime }
436
+ : {}),
437
+ ...(resolvedOptions.resources
438
+ ? { resources: resolvedOptions.resources }
439
+ : {}),
440
+ ...(resolvedOptions.exposedPorts
441
+ ? { ports: resolvedOptions.exposedPorts }
442
+ : {}),
443
+ ...(typeof resolvedOptions.interactive === 'boolean'
444
+ ? { interactive: resolvedOptions.interactive }
445
+ : {}),
446
+ ...(resolvedOptions.networkPolicy
447
+ ? { networkPolicy: resolvedOptions.networkPolicy }
448
+ : {}),
449
+ ...(typeof resolvedOptions.timeoutMs === 'number'
450
+ ? { timeout: resolvedOptions.timeoutMs }
451
+ : {}),
452
+ env: environment,
453
+ }), { runtime: resolvedOptions.runtime });
454
+ const session = new VercelSandboxSession({
455
+ sandbox,
456
+ credentials: { ...resolvedOptions, ...credentials },
457
+ concurrencyLimits: createArgs.concurrencyLimits,
458
+ state: {
459
+ manifest: resolvedManifest,
460
+ sandboxId: sandbox.sandboxId,
461
+ projectId: resolvedOptions.projectId ?? credentials.projectId,
462
+ teamId: resolvedOptions.teamId ?? credentials.teamId,
463
+ token: credentials.token,
464
+ runtime: resolvedOptions.runtime,
465
+ resources: resolvedOptions.resources,
466
+ configuredExposedPorts: resolvedOptions.exposedPorts,
467
+ interactive: resolvedOptions.interactive,
468
+ networkPolicy: resolvedOptions.networkPolicy,
469
+ timeoutMs: resolvedOptions.timeoutMs,
470
+ workspacePersistence: resolvedOptions.workspacePersistence ?? 'tar',
471
+ snapshotExpirationMs: resolvedOptions.snapshotExpirationMs,
472
+ environment,
473
+ snapshotSupported: supportsVercelSnapshot(sandbox),
474
+ },
475
+ });
476
+ try {
477
+ await waitForVercelSandboxRunning(session);
478
+ await session.prepareWorkspaceRoot();
479
+ await session.materializeInitialManifest(resolvedManifest);
480
+ }
481
+ catch (error) {
482
+ try {
483
+ await stopVercelSandbox(sandbox);
484
+ }
485
+ catch (stopError) {
486
+ throw new UserError(`Failed to apply a Vercel sandbox manifest and stop the sandbox. Manifest error: ${errorMessage(error)} Stop error: ${errorMessage(stopError)}`);
487
+ }
488
+ throw error;
489
+ }
490
+ return session;
491
+ });
492
+ }
493
+ async serializeSessionState(state, options) {
494
+ if (state.workspacePersistence === 'snapshot' &&
495
+ state.snapshotSupported !== false &&
496
+ state.snapshotSandboxId !== state.sandboxId &&
497
+ (options?.reuseLiveSession === false || options?.willCloseAfterSerialize)) {
498
+ await captureVercelSnapshot(state, {
499
+ options: {
500
+ ...this.options,
501
+ projectId: state.projectId ?? this.options.projectId,
502
+ teamId: state.teamId ?? this.options.teamId,
503
+ token: state.token ?? this.options.token,
504
+ },
505
+ });
506
+ }
507
+ return serializeRemoteSandboxSessionState(state);
508
+ }
509
+ canPersistOwnedSessionState(state) {
510
+ return (state.workspacePersistence === 'snapshot' &&
511
+ state.snapshotSupported !== false);
512
+ }
513
+ canReusePreservedOwnedSession(state) {
514
+ return (state.workspacePersistence !== 'snapshot' ||
515
+ state.snapshotSupported === false);
516
+ }
517
+ async deserializeSessionState(state) {
518
+ const baseState = deserializeRemoteSandboxSessionStateValues(state, this.options.env);
519
+ const manifest = resolveManifestRoot(baseState.manifest);
520
+ assertSandboxManifestMetadataSupported('VercelSandboxClient', manifest);
521
+ return {
522
+ ...state,
523
+ ...baseState,
524
+ manifest,
525
+ sandboxId: readString(state, 'sandboxId'),
526
+ workspacePersistence: state.workspacePersistence ?? 'tar',
527
+ projectId: readOptionalString(state, 'projectId'),
528
+ teamId: readOptionalString(state, 'teamId'),
529
+ token: readOptionalString(state, 'token'),
530
+ runtime: readOptionalString(state, 'runtime'),
531
+ resources: readOptionalRecord(state.resources),
532
+ configuredExposedPorts: readOptionalNumberArray(state.configuredExposedPorts),
533
+ interactive: readOptionalBoolean(state, 'interactive'),
534
+ networkPolicy: readOptionalRecord(state.networkPolicy),
535
+ timeoutMs: readOptionalNumber(state, 'timeoutMs'),
536
+ snapshotExpirationMs: readOptionalNumber(state, 'snapshotExpirationMs'),
537
+ snapshotId: readOptionalString(state, 'snapshotId'),
538
+ snapshotSandboxId: readOptionalString(state, 'snapshotSandboxId'),
539
+ snapshotSupported: readOptionalBoolean(state, 'snapshotSupported'),
540
+ };
541
+ }
542
+ async resume(state) {
543
+ const Sandbox = await loadVercelSandboxClass();
544
+ const credentials = await resolveVercelCredentials({
545
+ ...this.options,
546
+ projectId: state.projectId ?? this.options.projectId,
547
+ teamId: state.teamId ?? this.options.teamId,
548
+ token: state.token ?? this.options.token,
549
+ });
550
+ applyResolvedVercelCredentials(state, credentials);
551
+ const resumeFromSnapshot = hasFreshVercelSnapshot(state);
552
+ const sandbox = resumeFromSnapshot
553
+ ? await withProviderError('VercelSandboxClient', 'vercel', 'resume sandbox from snapshot', async () => await Sandbox.create({
554
+ ...credentials,
555
+ source: {
556
+ type: 'snapshot',
557
+ snapshotId: state.snapshotId,
558
+ },
559
+ ...(state.runtime ? { runtime: state.runtime } : {}),
560
+ ...(state.resources ? { resources: state.resources } : {}),
561
+ ...(state.configuredExposedPorts
562
+ ? { ports: state.configuredExposedPorts }
563
+ : {}),
564
+ ...(state.interactive !== undefined
565
+ ? { interactive: state.interactive }
566
+ : {}),
567
+ ...(state.networkPolicy
568
+ ? { networkPolicy: state.networkPolicy }
569
+ : {}),
570
+ ...(state.timeoutMs !== undefined
571
+ ? { timeout: state.timeoutMs }
572
+ : {}),
573
+ env: state.environment,
574
+ }), { snapshotId: state.snapshotId, sandboxId: state.sandboxId })
575
+ : await withProviderError('VercelSandboxClient', 'vercel', 'resume sandbox', async () => await Sandbox.get({
576
+ sandboxId: state.sandboxId,
577
+ ...credentials,
578
+ }), { sandboxId: state.sandboxId });
579
+ const session = new VercelSandboxSession({
580
+ credentials,
581
+ state: resumeFromSnapshot
582
+ ? {
583
+ ...state,
584
+ sandboxId: sandbox.sandboxId,
585
+ snapshotSandboxId: undefined,
586
+ snapshotSupported: supportsVercelSnapshot(sandbox),
587
+ exposedPorts: undefined,
588
+ }
589
+ : {
590
+ ...state,
591
+ snapshotSupported: supportsVercelSnapshot(sandbox),
592
+ },
593
+ sandbox,
594
+ });
595
+ try {
596
+ await waitForVercelSandboxRunning(session);
597
+ await session.prepareWorkspaceRoot();
598
+ }
599
+ catch (error) {
600
+ if (!resumeFromSnapshot) {
601
+ throw error;
602
+ }
603
+ try {
604
+ await stopVercelSandbox(sandbox);
605
+ }
606
+ catch (stopError) {
607
+ throw new UserError(`Failed to resume a Vercel sandbox from snapshot and stop the replacement sandbox. Resume error: ${errorMessage(error)} Stop error: ${errorMessage(stopError)}`);
608
+ }
609
+ throw error;
610
+ }
611
+ return session;
612
+ }
613
+ }
614
+ async function loadVercelSandboxClass() {
615
+ try {
616
+ const { Sandbox } = await import('@vercel/sandbox');
617
+ if (!Sandbox) {
618
+ throw new Error('Missing Sandbox export from @vercel/sandbox.');
619
+ }
620
+ return adaptVercelSandboxClass(Sandbox);
621
+ }
622
+ catch (error) {
623
+ throw new UserError(`Vercel sandbox support requires the optional \`@vercel/sandbox\` package. Install it before using Vercel-backed sandbox examples. ${error.message}`);
624
+ }
625
+ }
626
+ function adaptVercelSandboxClass(Sandbox) {
627
+ return {
628
+ create: async (params) => adaptVercelSandbox(await Sandbox.create(params)),
629
+ get: async (params) => adaptVercelSandbox(await Sandbox.get(params)),
630
+ };
631
+ }
632
+ function adaptVercelSandbox(sandbox) {
633
+ const optionalSandbox = sandbox;
634
+ const adapted = {
635
+ sandboxId: sandbox.sandboxId,
636
+ runCommand: async (params) => adaptVercelCommandFinished(await sandbox.runCommand(params)),
637
+ mkDir: async (path) => await sandbox.mkDir(path),
638
+ readFileToBuffer: async (file) => await sandbox.readFileToBuffer(file),
639
+ writeFiles: async (files) => await sandbox.writeFiles(files),
640
+ };
641
+ if (typeof optionalSandbox.domain === 'function') {
642
+ const domain = optionalSandbox.domain.bind(sandbox);
643
+ adapted.domain = (port) => domain(port);
644
+ }
645
+ if (typeof optionalSandbox.stop === 'function') {
646
+ const stop = optionalSandbox.stop.bind(sandbox);
647
+ adapted.stop = async () => await stop();
648
+ }
649
+ if (typeof optionalSandbox.snapshot === 'function') {
650
+ const snapshotFn = optionalSandbox.snapshot.bind(sandbox);
651
+ adapted.snapshot = async (params) => {
652
+ const snapshot = await snapshotFn(params);
653
+ return { snapshotId: snapshot.snapshotId };
654
+ };
655
+ }
656
+ return adapted;
657
+ }
658
+ function adaptVercelCommandFinished(command) {
659
+ return {
660
+ exitCode: command.exitCode,
661
+ output: async (stream) => await command.output(stream),
662
+ };
663
+ }
664
+ function resolveManifestRoot(manifest) {
665
+ if (manifest.root === '/workspace') {
666
+ return cloneManifestWithRoot(manifest, DEFAULT_VERCEL_WORKSPACE_ROOT);
667
+ }
668
+ if (manifest.root === DEFAULT_VERCEL_WORKSPACE_ROOT ||
669
+ manifest.root.startsWith(`${DEFAULT_VERCEL_WORKSPACE_ROOT}/`)) {
670
+ return manifest;
671
+ }
672
+ throw new UserError(`Vercel sandboxes require manifest.root to stay within "${DEFAULT_VERCEL_WORKSPACE_ROOT}".`);
673
+ }
674
+ function pickVercelCredentials(options) {
675
+ const credentials = {};
676
+ if (options.projectId) {
677
+ credentials.projectId = options.projectId;
678
+ }
679
+ if (options.teamId) {
680
+ credentials.teamId = options.teamId;
681
+ }
682
+ if (options.token) {
683
+ credentials.token = options.token;
684
+ }
685
+ return credentials;
686
+ }
687
+ async function resolveVercelCredentials(options) {
688
+ const envOptions = {
689
+ projectId: process.env.VERCEL_PROJECT_ID,
690
+ teamId: process.env.VERCEL_TEAM_ID,
691
+ token: process.env.VERCEL_TOKEN,
692
+ };
693
+ const layeredCredentials = pickVercelCredentials({
694
+ projectId: options.projectId ?? envOptions.projectId,
695
+ teamId: options.teamId ?? envOptions.teamId,
696
+ token: options.token ?? envOptions.token,
697
+ });
698
+ if (layeredCredentials.token) {
699
+ const refreshedCredentials = await refreshLayeredVercelCliCredentials(layeredCredentials);
700
+ if (refreshedCredentials === null) {
701
+ const { token: _token, ...credentialsWithoutToken } = layeredCredentials;
702
+ void _token;
703
+ return credentialsWithoutToken;
704
+ }
705
+ return refreshedCredentials ?? layeredCredentials;
706
+ }
707
+ if (Object.keys(layeredCredentials).length > 0) {
708
+ const cliToken = await resolveVercelCliAuthToken();
709
+ if (cliToken) {
710
+ return {
711
+ ...layeredCredentials,
712
+ token: cliToken,
713
+ };
714
+ }
715
+ return {};
716
+ }
717
+ if (hasAnyVercelCredentialOption(options)) {
718
+ return {};
719
+ }
720
+ return (await resolveVercelCliCredentials()) ?? {};
721
+ }
722
+ function hasAnyVercelCredentialOption(options) {
723
+ return Boolean(options.projectId || options.teamId || options.token);
724
+ }
725
+ async function resolveVercelCliCredentials() {
726
+ const token = await resolveVercelCliAuthToken();
727
+ if (!token) {
728
+ return undefined;
729
+ }
730
+ const linkedProject = findLinkedVercelProject();
731
+ if (!linkedProject) {
732
+ return { token };
733
+ }
734
+ return {
735
+ token,
736
+ projectId: linkedProject.projectId,
737
+ teamId: linkedProject.teamId,
738
+ };
739
+ }
740
+ async function resolveVercelCliAuthToken() {
741
+ const authModule = await loadVercelAuthModule();
742
+ if (!authModule) {
743
+ return undefined;
744
+ }
745
+ const auth = await resolveVercelCliAuth(authModule);
746
+ return auth?.token;
747
+ }
748
+ async function refreshLayeredVercelCliCredentials(credentials) {
749
+ if (!credentials.token) {
750
+ return undefined;
751
+ }
752
+ const authModule = await loadVercelAuthModule();
753
+ if (!authModule) {
754
+ return undefined;
755
+ }
756
+ const auth = authModule.getAuth();
757
+ if (!auth?.token || auth.token !== credentials.token) {
758
+ return undefined;
759
+ }
760
+ const resolvedAuth = await resolveVercelCliAuth(authModule, auth);
761
+ if (!resolvedAuth?.token) {
762
+ return null;
763
+ }
764
+ return {
765
+ ...credentials,
766
+ token: resolvedAuth.token,
767
+ };
768
+ }
769
+ async function loadVercelAuthModule() {
770
+ if (process.env.NODE_ENV === 'test' && !process.env.VERCEL_AUTH_CONFIG_DIR) {
771
+ return undefined;
772
+ }
773
+ try {
774
+ return await import('@vercel/sandbox/dist/auth/index.js');
775
+ }
776
+ catch {
777
+ return undefined;
778
+ }
779
+ }
780
+ async function resolveVercelCliAuth(authModule, initialAuth = authModule.getAuth()) {
781
+ let auth = initialAuth;
782
+ if (!auth?.token && !auth?.refreshToken) {
783
+ return undefined;
784
+ }
785
+ if (auth?.expiresAt && auth.expiresAt.getTime() <= Date.now()) {
786
+ if (!auth.refreshToken) {
787
+ return undefined;
788
+ }
789
+ const refreshed = await (await authModule.OAuth()).refreshToken(auth.refreshToken);
790
+ auth = {
791
+ expiresAt: new Date(Date.now() + refreshed.expires_in * 1_000),
792
+ token: refreshed.access_token,
793
+ refreshToken: refreshed.refresh_token ?? auth.refreshToken,
794
+ };
795
+ try {
796
+ authModule.updateAuthConfig(auth);
797
+ }
798
+ catch {
799
+ // The refreshed token is still usable for this process.
800
+ }
801
+ }
802
+ return auth ?? undefined;
803
+ }
804
+ function applyResolvedVercelCredentials(state, credentials) {
805
+ if (credentials.projectId) {
806
+ state.projectId = credentials.projectId;
807
+ }
808
+ if (credentials.teamId) {
809
+ state.teamId = credentials.teamId;
810
+ }
811
+ if (credentials.token) {
812
+ state.token = credentials.token;
813
+ }
814
+ else {
815
+ delete state.token;
816
+ }
817
+ }
818
+ function findLinkedVercelProject() {
819
+ const candidateCwds = [
820
+ process.env.INIT_CWD,
821
+ process.env.PWD,
822
+ process.cwd(),
823
+ ].filter((value) => Boolean(value));
824
+ for (const cwd of candidateCwds) {
825
+ const projectPath = findUpVercelProjectFile(cwd);
826
+ if (!projectPath) {
827
+ continue;
828
+ }
829
+ try {
830
+ const data = JSON.parse(readFileSync(projectPath, 'utf8'));
831
+ if (typeof data.projectId === 'string' &&
832
+ typeof data.orgId === 'string') {
833
+ return {
834
+ projectId: data.projectId,
835
+ teamId: data.orgId,
836
+ };
837
+ }
838
+ }
839
+ catch {
840
+ continue;
841
+ }
842
+ }
843
+ return undefined;
844
+ }
845
+ function findUpVercelProjectFile(startDir) {
846
+ let current = pathResolve(startDir);
847
+ while (true) {
848
+ const candidate = pathJoin(current, '.vercel', 'project.json');
849
+ if (existsSync(candidate)) {
850
+ return candidate;
851
+ }
852
+ const parent = pathDirname(current);
853
+ if (parent === current) {
854
+ return undefined;
855
+ }
856
+ current = parent;
857
+ }
858
+ }
859
+ async function captureVercelSnapshot(state, args = {}) {
860
+ if (state.workspacePersistence !== 'snapshot') {
861
+ return;
862
+ }
863
+ let sandbox = args.sandbox;
864
+ if (!sandbox) {
865
+ const credentials = await resolveVercelCredentials({
866
+ projectId: state.projectId ?? args.options?.projectId,
867
+ teamId: state.teamId ?? args.options?.teamId,
868
+ token: state.token ?? args.options?.token,
869
+ });
870
+ applyResolvedVercelCredentials(state, credentials);
871
+ sandbox = await withProviderError('VercelSandboxClient', 'vercel', 'look up sandbox for snapshot', async () => await (await loadVercelSandboxClass()).get({
872
+ sandboxId: state.sandboxId,
873
+ ...credentials,
874
+ }), { sandboxId: state.sandboxId });
875
+ }
876
+ state.snapshotSupported = supportsVercelSnapshot(sandbox);
877
+ if (!state.snapshotSupported) {
878
+ throw new UserError('Vercel snapshot persistence requires @vercel/sandbox snapshot support.');
879
+ }
880
+ const snapshot = await withSandboxSpan('sandbox.snapshot', {
881
+ backend_id: 'vercel',
882
+ sandbox_id: state.sandboxId,
883
+ }, async () => await withProviderError('VercelSandboxClient', 'vercel', 'capture snapshot', async () => await sandbox.snapshot({
884
+ expiration: state.snapshotExpirationMs,
885
+ }), { sandboxId: state.sandboxId }));
886
+ if (!snapshot.snapshotId) {
887
+ throw new UserError('Vercel snapshot persistence did not return a snapshotId.');
888
+ }
889
+ state.snapshotId = snapshot.snapshotId;
890
+ state.snapshotSandboxId = sandbox.sandboxId;
891
+ }
892
+ function supportsVercelSnapshot(sandbox) {
893
+ return typeof sandbox.snapshot === 'function';
894
+ }
895
+ function hasFreshVercelSnapshot(state) {
896
+ return Boolean(state.snapshotId && state.snapshotSandboxId === state.sandboxId);
897
+ }
898
+ async function stopVercelSandbox(sandbox) {
899
+ if (!sandbox.stop) {
900
+ return;
901
+ }
902
+ await withSandboxSpan('sandbox.stop', {
903
+ backend_id: 'vercel',
904
+ sandbox_id: sandbox.sandboxId,
905
+ }, async () => {
906
+ await sandbox.stop();
907
+ });
908
+ }
909
+ async function waitForVercelSandboxRunning(session, timeoutMs = 30_000) {
910
+ const deadline = Date.now() + timeoutMs;
911
+ while (Date.now() <= deadline) {
912
+ if (await session.running()) {
913
+ return;
914
+ }
915
+ await new Promise((resolve) => setTimeout(resolve, 250));
916
+ }
917
+ throw new SandboxLifecycleError(`Vercel sandbox ${session.state.sandboxId} did not become runnable within ${timeoutMs}ms.`, {
918
+ provider: 'vercel',
919
+ sandboxId: session.state.sandboxId,
920
+ timeoutMs,
921
+ });
922
+ }
923
+ function errorMessage(error) {
924
+ return error instanceof Error ? error.message : String(error);
925
+ }
926
+ function isVercelSandboxAlreadyStoppedError(error) {
927
+ if (isProviderSandboxNotFoundError(error)) {
928
+ return true;
929
+ }
930
+ const message = errorMessage(error);
931
+ return (/\b(sandbox|sandbox instance|instance)\b.*\b(already\s+)?(stopped|terminated|not running)\b/iu.test(message) ||
932
+ /\b(already\s+)?(stopped|terminated|not running)\b.*\b(sandbox|sandbox instance|instance)\b/iu.test(message));
933
+ }
934
+ function assertFilesystemRunAs(runAs) {
935
+ if (runAs && runAs !== 'root') {
936
+ assertRunAsUnsupported('VercelSandboxClient', runAs);
937
+ }
938
+ if (runAs === 'root') {
939
+ throw new SandboxUnsupportedFeatureError('VercelSandboxClient does not support runAs for filesystem operations.', {
940
+ provider: 'vercel',
941
+ feature: 'runAs',
942
+ });
943
+ }
944
+ }
945
+ function isVercelAlreadyExistsError(error) {
946
+ if (!error || typeof error !== 'object') {
947
+ return false;
948
+ }
949
+ const json = 'json' in error ? error.json : undefined;
950
+ if (!json || typeof json !== 'object') {
951
+ return false;
952
+ }
953
+ const payload = 'error' in json ? json.error : undefined;
954
+ if (!payload || typeof payload !== 'object') {
955
+ return false;
956
+ }
957
+ const code = 'code' in payload ? payload.code : undefined;
958
+ const message = 'message' in payload ? payload.message : undefined;
959
+ return (code === 'file_error' &&
960
+ typeof message === 'string' &&
961
+ message.includes('File exists'));
962
+ }
963
+ //# sourceMappingURL=sandbox.mjs.map