self-bench 0.3.3 → 0.3.4
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/Dockerfile.sandbox +1 -1
- package/README.md +20 -0
- package/bun.lock +48 -0
- package/compose.yaml +7 -1
- package/dist/agent-smoke-main.js +3 -2
- package/dist/agent-smoke-main.js.map +1 -1
- package/dist/agent-smoke.d.ts +2 -1
- package/dist/agent-smoke.d.ts.map +1 -1
- package/dist/agent-smoke.js +6 -1
- package/dist/agent-smoke.js.map +1 -1
- package/dist/api.d.ts +24 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +25 -18
- package/dist/api.js.map +1 -1
- package/dist/build-metadata.js +1 -1
- package/dist/cli.js +67 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +36 -10
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +89 -15
- package/dist/config.js.map +1 -1
- package/dist/contracts.d.ts +22 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +31 -6
- package/dist/contracts.js.map +1 -1
- package/dist/eval-main.js +3 -2
- package/dist/eval-main.js.map +1 -1
- package/dist/evaluate.d.ts +2 -1
- package/dist/evaluate.d.ts.map +1 -1
- package/dist/evaluate.js +2 -1
- package/dist/evaluate.js.map +1 -1
- package/dist/harbor-environment.d.ts +2 -0
- package/dist/harbor-environment.d.ts.map +1 -0
- package/dist/harbor-environment.js +15 -0
- package/dist/harbor-environment.js.map +1 -0
- package/dist/harbor-results.d.ts.map +1 -1
- package/dist/harbor-results.js +2 -0
- package/dist/harbor-results.js.map +1 -1
- package/dist/process.d.ts +2 -1
- package/dist/process.d.ts.map +1 -1
- package/dist/process.js.map +1 -1
- package/dist/providers.d.ts +8 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +14 -0
- package/dist/providers.js.map +1 -0
- package/dist/reaudit-main.js +5 -5
- package/dist/reaudit-main.js.map +1 -1
- package/dist/repair-main.js +5 -5
- package/dist/repair-main.js.map +1 -1
- package/dist/sandbox-author.bundle.js +40 -6
- package/dist/sandbox-timeout.d.ts +11 -0
- package/dist/sandbox-timeout.d.ts.map +1 -0
- package/dist/sandbox-timeout.js +41 -0
- package/dist/sandbox-timeout.js.map +1 -0
- package/dist/sandbox-validation-repair.bundle.js +40 -6
- package/dist/sandbox.d.ts +2 -2
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +10 -3
- package/dist/sandbox.js.map +1 -1
- package/dist/temporal/activities.d.ts +2 -2
- package/dist/temporal/activities.d.ts.map +1 -1
- package/dist/temporal/activities.js +7 -1
- package/dist/temporal/activities.js.map +1 -1
- package/dist/temporal/worker-main.js +2 -2
- package/dist/temporal/worker-main.js.map +1 -1
- package/dist/terminal-prompts.d.ts +26 -0
- package/dist/terminal-prompts.d.ts.map +1 -0
- package/dist/terminal-prompts.js +137 -0
- package/dist/terminal-prompts.js.map +1 -0
- package/dist/terminal-reporter.d.ts +30 -0
- package/dist/terminal-reporter.d.ts.map +1 -0
- package/dist/terminal-reporter.js +90 -0
- package/dist/terminal-reporter.js.map +1 -0
- package/dist/validate-main.js +8 -2
- package/dist/validate-main.js.map +1 -1
- package/dist/vercel-cli.d.ts +64 -0
- package/dist/vercel-cli.d.ts.map +1 -0
- package/dist/vercel-cli.js +303 -0
- package/dist/vercel-cli.js.map +1 -0
- package/dist/vercel-command.d.ts +14 -0
- package/dist/vercel-command.d.ts.map +1 -0
- package/dist/vercel-command.js +93 -0
- package/dist/vercel-command.js.map +1 -0
- package/dist/vercel-executor.d.ts +14 -0
- package/dist/vercel-executor.d.ts.map +1 -0
- package/dist/vercel-executor.js +356 -0
- package/dist/vercel-executor.js.map +1 -0
- package/dist/vercel-fetch.d.ts +6 -0
- package/dist/vercel-fetch.d.ts.map +1 -0
- package/dist/vercel-fetch.js +39 -0
- package/dist/vercel-fetch.js.map +1 -0
- package/dist/vercel-profile.d.ts +34 -0
- package/dist/vercel-profile.d.ts.map +1 -0
- package/dist/vercel-profile.js +244 -0
- package/dist/vercel-profile.js.map +1 -0
- package/dist/vercel-runtime-image.d.ts +51 -0
- package/dist/vercel-runtime-image.d.ts.map +1 -0
- package/dist/vercel-runtime-image.js +123 -0
- package/dist/vercel-runtime-image.js.map +1 -0
- package/dist/vercel-setup-probe.d.ts +49 -0
- package/dist/vercel-setup-probe.d.ts.map +1 -0
- package/dist/vercel-setup-probe.js +151 -0
- package/dist/vercel-setup-probe.js.map +1 -0
- package/dist/vercel-setup.d.ts +42 -0
- package/dist/vercel-setup.d.ts.map +1 -0
- package/dist/vercel-setup.js +280 -0
- package/dist/vercel-setup.js.map +1 -0
- package/docs/evaluations.md +2 -0
- package/docs/operations.md +128 -6
- package/package.json +3 -1
- package/src/agent-smoke-main.ts +3 -2
- package/src/agent-smoke.ts +8 -2
- package/src/api.ts +31 -18
- package/src/cli.ts +72 -11
- package/src/config.ts +150 -25
- package/src/contracts.ts +33 -6
- package/src/eval-main.ts +3 -2
- package/src/evaluate.ts +5 -3
- package/src/harbor-environment.ts +17 -0
- package/src/harbor-results.ts +2 -0
- package/src/process.ts +3 -1
- package/src/providers.ts +22 -0
- package/src/reaudit-main.ts +8 -5
- package/src/repair-main.ts +8 -5
- package/src/sandbox-timeout.ts +56 -0
- package/src/sandbox.ts +15 -5
- package/src/temporal/activities.ts +9 -3
- package/src/temporal/worker-main.ts +2 -2
- package/src/terminal-prompts.ts +197 -0
- package/src/terminal-reporter.ts +126 -0
- package/src/validate-main.ts +9 -3
- package/src/vercel-cli.ts +403 -0
- package/src/vercel-command.ts +127 -0
- package/src/vercel-executor.ts +448 -0
- package/src/vercel-fetch.ts +45 -0
- package/src/vercel-profile.ts +319 -0
- package/src/vercel-runtime-image.ts +204 -0
- package/src/vercel-setup-probe.ts +229 -0
- package/src/vercel-setup.ts +419 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { chmod, lstat, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { parseSandboxTimeoutCapText, STANDARD_VERCEL_TIMEOUT_CAP_MS } from "./sandbox-timeout.js";
|
|
7
|
+
const CONFIG_FILE = "config.json";
|
|
8
|
+
const CREDENTIALS_FILE = "credentials.json";
|
|
9
|
+
const PRIVATE_DIRECTORY_MODE = 0o700;
|
|
10
|
+
const PRIVATE_FILE_MODE = 0o600;
|
|
11
|
+
const profileNameSchema = z
|
|
12
|
+
.string()
|
|
13
|
+
.trim()
|
|
14
|
+
.regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/, {
|
|
15
|
+
error: "Vercel profile name must use 1-64 letters, digits, dots, underscores, or hyphens",
|
|
16
|
+
});
|
|
17
|
+
const digestPinnedImageSchema = z
|
|
18
|
+
.string()
|
|
19
|
+
.regex(/^[^@\s]+@sha256:[0-9a-f]{64}$/i, "expected a digest-pinned VCR image");
|
|
20
|
+
export const vercelProfileSchema = z
|
|
21
|
+
.object({
|
|
22
|
+
teamId: z.string().trim().min(1),
|
|
23
|
+
teamSlug: z.string().trim().min(1),
|
|
24
|
+
teamName: z.string().trim().min(1),
|
|
25
|
+
projectId: z.string().trim().min(1),
|
|
26
|
+
projectName: z.string().trim().min(1),
|
|
27
|
+
vcrRepository: z.string().trim().min(1),
|
|
28
|
+
image: digestPinnedImageSchema,
|
|
29
|
+
runtimeFingerprint: z.string().regex(/^[0-9a-f]{64}$/),
|
|
30
|
+
timeoutCapMs: z.number().int().min(100).max(STANDARD_VERCEL_TIMEOUT_CAP_MS),
|
|
31
|
+
capabilityCheckedAt: z.iso.datetime(),
|
|
32
|
+
})
|
|
33
|
+
.strict();
|
|
34
|
+
const configSchema = z
|
|
35
|
+
.object({
|
|
36
|
+
schemaVersion: z.literal(1),
|
|
37
|
+
activeVercelProfile: profileNameSchema.optional(),
|
|
38
|
+
vercelProfiles: z.record(profileNameSchema, vercelProfileSchema),
|
|
39
|
+
})
|
|
40
|
+
.strict();
|
|
41
|
+
const credentialsSchema = z
|
|
42
|
+
.object({
|
|
43
|
+
schemaVersion: z.literal(1),
|
|
44
|
+
vercelProfiles: z.record(profileNameSchema, z.object({ token: z.string().trim().min(1) }).strict()),
|
|
45
|
+
})
|
|
46
|
+
.strict();
|
|
47
|
+
export function selfBenchConfigDirectory(environment = process.env) {
|
|
48
|
+
const override = environment.SELFBENCH_CONFIG_DIR?.trim();
|
|
49
|
+
return resolve(override || join(homedir(), ".selfbench"));
|
|
50
|
+
}
|
|
51
|
+
export function validateVercelProfileName(value) {
|
|
52
|
+
return profileNameSchema.parse(value);
|
|
53
|
+
}
|
|
54
|
+
export async function loadVercelProfileData(directory = selfBenchConfigDirectory()) {
|
|
55
|
+
const mutable = await loadMutableProfileData(directory);
|
|
56
|
+
return {
|
|
57
|
+
...(mutable.activeVercelProfile ? { activeVercelProfile: mutable.activeVercelProfile } : {}),
|
|
58
|
+
profiles: mutable.profiles,
|
|
59
|
+
tokens: mutable.tokens,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export async function saveVercelProfile(input) {
|
|
63
|
+
const directory = resolve(input.directory ?? selfBenchConfigDirectory());
|
|
64
|
+
const profileName = validateVercelProfileName(input.profileName);
|
|
65
|
+
const token = input.token.trim();
|
|
66
|
+
if (!token) {
|
|
67
|
+
throw new Error("Vercel access token must not be blank");
|
|
68
|
+
}
|
|
69
|
+
const profile = vercelProfileSchema.parse(input.profile);
|
|
70
|
+
await ensurePrivateDirectory(directory);
|
|
71
|
+
const existing = await loadMutableProfileData(directory);
|
|
72
|
+
const nextCredentials = credentialsSchema.parse({
|
|
73
|
+
schemaVersion: 1,
|
|
74
|
+
vercelProfiles: {
|
|
75
|
+
...Object.fromEntries(Object.entries(existing.tokens).map(([name, existingToken]) => [
|
|
76
|
+
name,
|
|
77
|
+
{ token: existingToken },
|
|
78
|
+
])),
|
|
79
|
+
[profileName]: { token },
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
const nextConfig = configSchema.parse({
|
|
83
|
+
schemaVersion: 1,
|
|
84
|
+
activeVercelProfile: profileName,
|
|
85
|
+
vercelProfiles: { ...existing.profiles, [profileName]: profile },
|
|
86
|
+
});
|
|
87
|
+
// Credentials are written first. A crash can leave an unreferenced token, but
|
|
88
|
+
// never an active profile whose credential has not reached disk.
|
|
89
|
+
await writePrivateJson(join(directory, CREDENTIALS_FILE), nextCredentials);
|
|
90
|
+
await writePrivateJson(join(directory, CONFIG_FILE), nextConfig);
|
|
91
|
+
}
|
|
92
|
+
export async function applyVercelProfile(environment, requestedProfile) {
|
|
93
|
+
const result = { ...environment };
|
|
94
|
+
const hasCompleteEnvironment = requiredEnvironmentKeys.every((key) => result[key]?.trim());
|
|
95
|
+
if (hasCompleteEnvironment && requestedProfile === undefined) {
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
const data = await loadVercelProfileData(selfBenchConfigDirectory(environment));
|
|
99
|
+
const profileName = selectProfileName(data, requestedProfile);
|
|
100
|
+
const profile = data.profiles[profileName];
|
|
101
|
+
const token = data.tokens[profileName];
|
|
102
|
+
if (!profile || !token) {
|
|
103
|
+
throw new Error(`Vercel profile "${profileName}" is incomplete; rerun self-bench setup vercel --profile ${profileName}`);
|
|
104
|
+
}
|
|
105
|
+
assertCompatibleOverride("VERCEL_TEAM_ID", result.VERCEL_TEAM_ID, profile.teamId);
|
|
106
|
+
assertCompatibleOverride("VERCEL_PROJECT_ID", result.VERCEL_PROJECT_ID, profile.projectId);
|
|
107
|
+
result.VERCEL_TOKEN = result.VERCEL_TOKEN?.trim() || token;
|
|
108
|
+
result.VERCEL_TEAM_ID = result.VERCEL_TEAM_ID?.trim() || profile.teamId;
|
|
109
|
+
result.VERCEL_PROJECT_ID = result.VERCEL_PROJECT_ID?.trim() || profile.projectId;
|
|
110
|
+
result.SELFBENCH_VERCEL_IMAGE = result.SELFBENCH_VERCEL_IMAGE?.trim() || profile.image;
|
|
111
|
+
result.SELFBENCH_VERCEL_TIMEOUT_CAP = resolveProfileTimeoutCap(result.SELFBENCH_VERCEL_TIMEOUT_CAP, profile.timeoutCapMs);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
export function profileFilePaths(directory = selfBenchConfigDirectory()) {
|
|
115
|
+
return {
|
|
116
|
+
config: join(directory, CONFIG_FILE),
|
|
117
|
+
credentials: join(directory, CREDENTIALS_FILE),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const requiredEnvironmentKeys = [
|
|
121
|
+
"VERCEL_TOKEN",
|
|
122
|
+
"VERCEL_TEAM_ID",
|
|
123
|
+
"VERCEL_PROJECT_ID",
|
|
124
|
+
"SELFBENCH_VERCEL_IMAGE",
|
|
125
|
+
];
|
|
126
|
+
function selectProfileName(data, requestedProfile) {
|
|
127
|
+
if (requestedProfile !== undefined) {
|
|
128
|
+
return validateVercelProfileName(requestedProfile);
|
|
129
|
+
}
|
|
130
|
+
if (data.activeVercelProfile) {
|
|
131
|
+
return data.activeVercelProfile;
|
|
132
|
+
}
|
|
133
|
+
const names = Object.keys(data.profiles);
|
|
134
|
+
if (names.length === 1 && names[0]) {
|
|
135
|
+
return names[0];
|
|
136
|
+
}
|
|
137
|
+
throw new Error("Vercel is not configured; run self-bench setup vercel or provide VERCEL_TOKEN, VERCEL_TEAM_ID, VERCEL_PROJECT_ID, and SELFBENCH_VERCEL_IMAGE");
|
|
138
|
+
}
|
|
139
|
+
function resolveProfileTimeoutCap(value, verifiedCapMs) {
|
|
140
|
+
const override = value?.trim();
|
|
141
|
+
if (!override) {
|
|
142
|
+
return `${verifiedCapMs}ms`;
|
|
143
|
+
}
|
|
144
|
+
const parsed = parseSandboxTimeoutCapText(override);
|
|
145
|
+
if (parsed === undefined || !Number.isInteger(parsed) || parsed < 100 || parsed > verifiedCapMs) {
|
|
146
|
+
throw new Error(`SELFBENCH_VERCEL_TIMEOUT_CAP must be between 100ms and the selected profile's verified ${verifiedCapMs}ms ceiling`);
|
|
147
|
+
}
|
|
148
|
+
return override;
|
|
149
|
+
}
|
|
150
|
+
function assertCompatibleOverride(key, value, expected) {
|
|
151
|
+
const override = value?.trim();
|
|
152
|
+
if (override && override !== expected) {
|
|
153
|
+
throw new Error(`${key} does not match the selected Vercel profile; provide the complete Vercel environment instead of mixing project scopes`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function loadMutableProfileData(directory) {
|
|
157
|
+
await assertDirectoryIfPresent(directory);
|
|
158
|
+
const paths = profileFilePaths(directory);
|
|
159
|
+
const [rawConfig, rawCredentials] = await Promise.all([
|
|
160
|
+
readPrivateJson(paths.config),
|
|
161
|
+
readPrivateJson(paths.credentials),
|
|
162
|
+
]);
|
|
163
|
+
const config = parseProfileDocument(paths.config, rawConfig, configSchema);
|
|
164
|
+
const credentials = parseProfileDocument(paths.credentials, rawCredentials, credentialsSchema);
|
|
165
|
+
return {
|
|
166
|
+
...(config?.activeVercelProfile ? { activeVercelProfile: config.activeVercelProfile } : {}),
|
|
167
|
+
profiles: { ...(config?.vercelProfiles ?? {}) },
|
|
168
|
+
tokens: Object.fromEntries(Object.entries(credentials?.vercelProfiles ?? {}).map(([name, value]) => [name, value.token])),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function parseProfileDocument(path, value, schema) {
|
|
172
|
+
if (value === undefined) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
return schema.parse(value);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
throw new Error(`SelfBench profile file has an incompatible format: ${path}. Move the file or set SELFBENCH_CONFIG_DIR to another directory.`, { cause: error });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function assertDirectoryIfPresent(directory) {
|
|
183
|
+
let stats;
|
|
184
|
+
try {
|
|
185
|
+
stats = await lstat(directory);
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
if (isFileNotFound(error)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
194
|
+
throw new Error(`SelfBench config path must be a directory, not a file or symlink: ${directory}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async function ensurePrivateDirectory(directory) {
|
|
198
|
+
await assertDirectoryIfPresent(directory);
|
|
199
|
+
await mkdir(directory, { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
|
|
200
|
+
await chmod(directory, PRIVATE_DIRECTORY_MODE);
|
|
201
|
+
}
|
|
202
|
+
async function readPrivateJson(path) {
|
|
203
|
+
let stats;
|
|
204
|
+
try {
|
|
205
|
+
stats = await lstat(path);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
if (isFileNotFound(error)) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
214
|
+
throw new Error(`SelfBench profile path must be a regular file: ${path}`);
|
|
215
|
+
}
|
|
216
|
+
if ((stats.mode & 0o077) !== 0) {
|
|
217
|
+
throw new Error(`SelfBench profile file must be owner-only; run chmod 600 ${path}`);
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
throw new Error(`Unable to parse SelfBench profile file ${path}`, { cause: error });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function writePrivateJson(path, value) {
|
|
227
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
228
|
+
try {
|
|
229
|
+
await writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`, {
|
|
230
|
+
encoding: "utf8",
|
|
231
|
+
flag: "wx",
|
|
232
|
+
mode: PRIVATE_FILE_MODE,
|
|
233
|
+
});
|
|
234
|
+
await rename(temporary, path);
|
|
235
|
+
await chmod(path, PRIVATE_FILE_MODE);
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
await rm(temporary, { force: true });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function isFileNotFound(error) {
|
|
242
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=vercel-profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-profile.js","sourceRoot":"","sources":["../src/vercel-profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { CommandOutputHandler } from "./process.js";
|
|
2
|
+
import type { SetupPrompter } from "./terminal-prompts.js";
|
|
3
|
+
import type { SetupReporter } from "./terminal-reporter.js";
|
|
4
|
+
import type { VcrTag } from "./vercel-cli.js";
|
|
5
|
+
export declare const DEFAULT_VCR_REPOSITORY = "selfbench-runtime";
|
|
6
|
+
interface VcrScope {
|
|
7
|
+
readonly teamSlug: string;
|
|
8
|
+
readonly projectId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface VercelRuntimeImageCli {
|
|
11
|
+
repositoryExists(input: VcrScope & {
|
|
12
|
+
readonly repository: string;
|
|
13
|
+
}): Promise<boolean>;
|
|
14
|
+
createRepository(input: VcrScope & {
|
|
15
|
+
readonly repository: string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
listTags(input: VcrScope & {
|
|
18
|
+
readonly repository: string;
|
|
19
|
+
}): Promise<readonly VcrTag[]>;
|
|
20
|
+
inspectTag(input: VcrScope & {
|
|
21
|
+
readonly repository: string;
|
|
22
|
+
readonly tag: string;
|
|
23
|
+
}): Promise<VcrTag | undefined>;
|
|
24
|
+
buildImage(input: VcrScope & {
|
|
25
|
+
readonly repository: string;
|
|
26
|
+
readonly tag: string;
|
|
27
|
+
readonly projectRoot: string;
|
|
28
|
+
readonly onOutput?: CommandOutputHandler;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
interface RuntimeImageServices {
|
|
32
|
+
readonly cli: VercelRuntimeImageCli;
|
|
33
|
+
readonly prompter: SetupPrompter;
|
|
34
|
+
readonly reporter: SetupReporter;
|
|
35
|
+
readonly sleep: (delayMs: number) => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export interface VercelRuntimeImage {
|
|
38
|
+
readonly repository: string;
|
|
39
|
+
readonly image: string;
|
|
40
|
+
readonly published: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare function ensureVercelRuntimeImage(input: {
|
|
43
|
+
readonly services: RuntimeImageServices;
|
|
44
|
+
readonly scope: VcrScope;
|
|
45
|
+
readonly projectRoot: string;
|
|
46
|
+
readonly fingerprint: string;
|
|
47
|
+
readonly preferredRepository: string;
|
|
48
|
+
}): Promise<VercelRuntimeImage>;
|
|
49
|
+
export declare function vercelRuntimeFingerprint(projectRoot: string): Promise<string>;
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=vercel-runtime-image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-runtime-image.d.ts","sourceRoot":"","sources":["../src/vercel-runtime-image.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAO1D,UAAU,QAAQ;IAChB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,GAAG;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtF,gBAAgB,CAAC,KAAK,EAAE,QAAQ,GAAG;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnF,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACxF,UAAU,CACR,KAAK,EAAE,QAAQ,GAAG;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GACtE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/B,UAAU,CACR,KAAK,EAAE,QAAQ,GAAG;QAChB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAC;KAC1C,GACA,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,GAAG,EAAE,qBAAqB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IACpD,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA8E9B;AAED,wBAAsB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAenF"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { sha256 } from "./hash.js";
|
|
4
|
+
export const DEFAULT_VCR_REPOSITORY = "selfbench-runtime";
|
|
5
|
+
const IMAGE_TAG_PREFIX = "selfbench-";
|
|
6
|
+
const IMAGE_PLATFORM = "linux/amd64";
|
|
7
|
+
const IMAGE_READINESS_TIMEOUT_MS = 15 * 60 * 1_000;
|
|
8
|
+
const IMAGE_POLL_INTERVAL_MS = 5_000;
|
|
9
|
+
export async function ensureVercelRuntimeImage(input) {
|
|
10
|
+
const { services, scope, projectRoot, fingerprint } = input;
|
|
11
|
+
const tag = `${IMAGE_TAG_PREFIX}${fingerprint}`;
|
|
12
|
+
let repository = input.preferredRepository;
|
|
13
|
+
for (;;) {
|
|
14
|
+
if (!isValidVcrRepositoryName(repository)) {
|
|
15
|
+
throw new Error(`Invalid VCR repository name in saved profile: ${repository}`);
|
|
16
|
+
}
|
|
17
|
+
const exists = await services.cli.repositoryExists({ ...scope, repository });
|
|
18
|
+
if (!exists) {
|
|
19
|
+
try {
|
|
20
|
+
await services.cli.createRepository({ ...scope, repository });
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
// A concurrent setup or a lost success response can leave the repository
|
|
25
|
+
// present. Re-inspect it before treating the operation as failed.
|
|
26
|
+
if (await services.cli.repositoryExists({ ...scope, repository })) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const tags = await services.cli.listTags({ ...scope, repository });
|
|
33
|
+
const compatible = tags.every((candidate) => candidate.tag.startsWith(IMAGE_TAG_PREFIX));
|
|
34
|
+
if (!compatible) {
|
|
35
|
+
services.reporter.warn(`VCR repository "${repository}" contains unrelated images. SelfBench will not modify it.`);
|
|
36
|
+
repository = await requestVcrRepositoryName(services);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const matching = tags.find((candidate) => candidate.tag === tag);
|
|
40
|
+
if (matching) {
|
|
41
|
+
if (matching.kind !== "index" &&
|
|
42
|
+
(matching.status === null || ["ready", "preparing"].includes(matching.status))) {
|
|
43
|
+
const ready = await services.reporter.task({
|
|
44
|
+
pending: "Checking the existing runtime image",
|
|
45
|
+
success: "Runtime image ready",
|
|
46
|
+
failure: "Runtime image check failed",
|
|
47
|
+
}, async () => await waitForReadyTag(services, { ...scope, repository, tag }, matching));
|
|
48
|
+
return {
|
|
49
|
+
repository,
|
|
50
|
+
image: `${repository}@${ready.manifestDigest}`,
|
|
51
|
+
published: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
services.reporter.warn(`Existing SelfBench image ${repository}:${tag} is ${tagState(matching)}; rebuilding it.`);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
const ready = await services.reporter.task({
|
|
60
|
+
pending: `Building and publishing the ${IMAGE_PLATFORM} runtime image`,
|
|
61
|
+
success: "Runtime image published",
|
|
62
|
+
failure: "Runtime image publication failed",
|
|
63
|
+
}, async (onOutput) => {
|
|
64
|
+
await services.cli.buildImage({ ...scope, repository, tag, projectRoot, onOutput });
|
|
65
|
+
return await waitForReadyTag(services, { ...scope, repository, tag });
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
repository,
|
|
69
|
+
image: `${repository}@${ready.manifestDigest}`,
|
|
70
|
+
published: true,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export async function vercelRuntimeFingerprint(projectRoot) {
|
|
74
|
+
const dockerfile = await readFile(resolve(projectRoot, "Dockerfile.sandbox"), "utf8");
|
|
75
|
+
if (/^\s*(?:ADD|COPY)\s/imu.test(dockerfile)) {
|
|
76
|
+
throw new Error("Dockerfile.sandbox now copies local files; update the VCR fingerprint inputs before publishing");
|
|
77
|
+
}
|
|
78
|
+
return sha256(JSON.stringify({
|
|
79
|
+
schemaVersion: 2,
|
|
80
|
+
buildProvenance: false,
|
|
81
|
+
platform: IMAGE_PLATFORM,
|
|
82
|
+
dockerfile,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
async function waitForReadyTag(services, input, initial) {
|
|
86
|
+
const startedAt = Date.now();
|
|
87
|
+
let candidate = initial ?? (await services.cli.inspectTag(input));
|
|
88
|
+
for (;;) {
|
|
89
|
+
if (candidate?.kind === "index") {
|
|
90
|
+
throw new Error(`VCR image ${input.repository}:${input.tag} is an OCI index; expected one linux/amd64 manifest`);
|
|
91
|
+
}
|
|
92
|
+
if (candidate?.status === "ready") {
|
|
93
|
+
return candidate;
|
|
94
|
+
}
|
|
95
|
+
if (candidate && candidate.status !== null && candidate.status !== "preparing") {
|
|
96
|
+
throw new Error(`VCR image ${input.repository}:${input.tag} entered status ${candidate.status}`);
|
|
97
|
+
}
|
|
98
|
+
if (Date.now() - startedAt >= IMAGE_READINESS_TIMEOUT_MS) {
|
|
99
|
+
throw new Error(`VCR image ${input.repository}:${input.tag} was not ready within 15 minutes`);
|
|
100
|
+
}
|
|
101
|
+
await services.sleep(IMAGE_POLL_INTERVAL_MS);
|
|
102
|
+
candidate = await services.cli.inspectTag(input);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function tagState(tag) {
|
|
106
|
+
if (tag.kind === "index") {
|
|
107
|
+
return "an unsupported OCI index";
|
|
108
|
+
}
|
|
109
|
+
return tag.status ?? "not yet classified by VCR";
|
|
110
|
+
}
|
|
111
|
+
function isValidVcrRepositoryName(value) {
|
|
112
|
+
return /^[a-z0-9]+(?:(?:\.|_|__|-+)[a-z0-9]+)*$/.test(value);
|
|
113
|
+
}
|
|
114
|
+
async function requestVcrRepositoryName(services) {
|
|
115
|
+
for (;;) {
|
|
116
|
+
const value = (await services.prompter.text("Choose another VCR repository name")).trim();
|
|
117
|
+
if (isValidVcrRepositoryName(value)) {
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
services.reporter.warn("VCR repository names require lowercase letters or digits separated by dots, underscores, or hyphens.");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=vercel-runtime-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-runtime-image.js","sourceRoot":"","sources":["../src/vercel-runtime-image.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { VercelCredentials } from "./config.js";
|
|
2
|
+
export interface VercelCapability {
|
|
3
|
+
readonly timeoutCapMs: number;
|
|
4
|
+
readonly timeoutClass: "45m" | "standard";
|
|
5
|
+
readonly checkedAt: string;
|
|
6
|
+
}
|
|
7
|
+
interface ProbeSandbox {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
runCommand(command: string, args: string[], options: {
|
|
10
|
+
readonly signal?: AbortSignal;
|
|
11
|
+
readonly timeoutMs?: number;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
readonly exitCode: number;
|
|
14
|
+
}>;
|
|
15
|
+
delete(options: {
|
|
16
|
+
readonly signal?: AbortSignal;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export interface VercelSandboxProbeApi {
|
|
20
|
+
create(input: {
|
|
21
|
+
readonly token: string;
|
|
22
|
+
readonly teamId: string;
|
|
23
|
+
readonly projectId: string;
|
|
24
|
+
readonly image: string;
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly persistent: false;
|
|
27
|
+
readonly resources: {
|
|
28
|
+
readonly vcpus: 1;
|
|
29
|
+
};
|
|
30
|
+
readonly signal?: AbortSignal;
|
|
31
|
+
readonly tags: Readonly<Record<string, string>>;
|
|
32
|
+
readonly timeout: number;
|
|
33
|
+
}): Promise<ProbeSandbox>;
|
|
34
|
+
get(input: {
|
|
35
|
+
readonly token: string;
|
|
36
|
+
readonly teamId: string;
|
|
37
|
+
readonly projectId: string;
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly resume: false;
|
|
40
|
+
readonly signal?: AbortSignal;
|
|
41
|
+
}): Promise<ProbeSandbox>;
|
|
42
|
+
}
|
|
43
|
+
export declare function probeVercelCapability(input: {
|
|
44
|
+
readonly credentials: VercelCredentials;
|
|
45
|
+
readonly image: string;
|
|
46
|
+
readonly signal?: AbortSignal;
|
|
47
|
+
}, api?: VercelSandboxProbeApi): Promise<VercelCapability>;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=vercel-setup-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-setup-probe.d.ts","sourceRoot":"","sources":["../src/vercel-setup-probe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOrD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,KAAK,GAAG,UAAU,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,UAAU,CACR,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GACtE,OAAO,CAAC;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1C,MAAM,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,KAAK,EAAE;QACZ,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;QAC3B,QAAQ,CAAC,SAAS,EAAE;YAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;SAAE,CAAC;QAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;QAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1B,GAAG,CAAC,KAAK,EAAE;QACT,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;QACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;KAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC3B;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE;IACL,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,EACD,GAAG,GAAE,qBAA6C,GACjD,OAAO,CAAC,gBAAgB,CAAC,CAwB3B"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
+
import { APIError, Sandbox } from "@vercel/sandbox";
|
|
3
|
+
import { HOBBY_VERCEL_TIMEOUT_CAP_MS, STANDARD_VERCEL_TIMEOUT_CAP_MS } from "./sandbox-timeout.js";
|
|
4
|
+
const PROBE_COMMAND_TIMEOUT_MS = 15_000;
|
|
5
|
+
const CLEANUP_TIMEOUT_MS = 60_000;
|
|
6
|
+
const ABSENCE_RETRIES = 3;
|
|
7
|
+
export async function probeVercelCapability(input, api = vercelSandboxProbeApi) {
|
|
8
|
+
try {
|
|
9
|
+
await runProbe(input, STANDARD_VERCEL_TIMEOUT_CAP_MS, api);
|
|
10
|
+
return {
|
|
11
|
+
timeoutCapMs: STANDARD_VERCEL_TIMEOUT_CAP_MS,
|
|
12
|
+
timeoutClass: "standard",
|
|
13
|
+
checkedAt: new Date().toISOString(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (!isFortyFiveMinuteLimit(error)) {
|
|
18
|
+
throw sanitizeError(error, input.credentials.token);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
await runProbe(input, HOBBY_VERCEL_TIMEOUT_CAP_MS, api);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
throw sanitizeError(error, input.credentials.token);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
timeoutCapMs: HOBBY_VERCEL_TIMEOUT_CAP_MS,
|
|
29
|
+
timeoutClass: "45m",
|
|
30
|
+
checkedAt: new Date().toISOString(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const vercelSandboxProbeApi = {
|
|
34
|
+
async create(input) {
|
|
35
|
+
return await Sandbox.create(input);
|
|
36
|
+
},
|
|
37
|
+
async get(input) {
|
|
38
|
+
return await Sandbox.get(input);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
async function runProbe(input, timeoutMs, api) {
|
|
42
|
+
input.signal?.throwIfAborted();
|
|
43
|
+
const name = `selfbench-setup-${crypto.randomUUID().replaceAll("-", "").slice(0, 20)}`;
|
|
44
|
+
let sandbox;
|
|
45
|
+
let primaryError;
|
|
46
|
+
try {
|
|
47
|
+
sandbox = await api.create({
|
|
48
|
+
...input.credentials,
|
|
49
|
+
image: input.image,
|
|
50
|
+
name,
|
|
51
|
+
persistent: false,
|
|
52
|
+
resources: { vcpus: 1 },
|
|
53
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
54
|
+
tags: { selfbench_stage: "setup-probe" },
|
|
55
|
+
timeout: timeoutMs,
|
|
56
|
+
});
|
|
57
|
+
const result = await sandbox.runCommand("true", [], {
|
|
58
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
59
|
+
timeoutMs: PROBE_COMMAND_TIMEOUT_MS,
|
|
60
|
+
});
|
|
61
|
+
if (result.exitCode !== 0) {
|
|
62
|
+
throw new Error(`Vercel setup probe exited ${result.exitCode}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
primaryError = error;
|
|
67
|
+
}
|
|
68
|
+
let cleanupError;
|
|
69
|
+
const status = httpStatus(primaryError);
|
|
70
|
+
const recoverMissingHandle = sandbox === undefined && primaryError !== undefined && (status === undefined || status >= 500);
|
|
71
|
+
try {
|
|
72
|
+
await cleanupProbe(name, sandbox, recoverMissingHandle, input.credentials, api);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
cleanupError = error;
|
|
76
|
+
}
|
|
77
|
+
if (cleanupError !== undefined) {
|
|
78
|
+
throw new AggregateError(primaryError === undefined ? [cleanupError] : [primaryError, cleanupError], `Vercel setup probe ${name} could not be deleted cleanly`);
|
|
79
|
+
}
|
|
80
|
+
if (primaryError !== undefined) {
|
|
81
|
+
throw primaryError;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function cleanupProbe(name, sandbox, recoverMissingHandle, credentials, api) {
|
|
85
|
+
let directDeleteError;
|
|
86
|
+
if (sandbox) {
|
|
87
|
+
try {
|
|
88
|
+
await sandbox.delete({ signal: AbortSignal.timeout(CLEANUP_TIMEOUT_MS) });
|
|
89
|
+
await confirmAbsent(name, credentials, api);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
directDeleteError = error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else if (!recoverMissingHandle) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
await confirmAbsent(name, credentials, api);
|
|
101
|
+
}
|
|
102
|
+
catch (recoveryError) {
|
|
103
|
+
throw new AggregateError(directDeleteError === undefined ? [recoveryError] : [directDeleteError, recoveryError], `failed to recover Vercel setup probe ${name} by exact name`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function confirmAbsent(name, credentials, api) {
|
|
107
|
+
for (let attempt = 0; attempt < ABSENCE_RETRIES; attempt += 1) {
|
|
108
|
+
try {
|
|
109
|
+
const recovered = await api.get({
|
|
110
|
+
...credentials,
|
|
111
|
+
name,
|
|
112
|
+
resume: false,
|
|
113
|
+
signal: AbortSignal.timeout(CLEANUP_TIMEOUT_MS),
|
|
114
|
+
});
|
|
115
|
+
await recovered.delete({ signal: AbortSignal.timeout(CLEANUP_TIMEOUT_MS) });
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (httpStatus(error) === 404) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
await delay(250 * (attempt + 1));
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`Vercel setup probe ${name} still exists after deletion`);
|
|
126
|
+
}
|
|
127
|
+
function isFortyFiveMinuteLimit(error) {
|
|
128
|
+
return (httpStatus(error) === 400 &&
|
|
129
|
+
/`?timeout`?.*(?:should be|must be).*<=\s*45m/i.test(errorDetail(error)));
|
|
130
|
+
}
|
|
131
|
+
function httpStatus(error) {
|
|
132
|
+
if (error instanceof APIError) {
|
|
133
|
+
return error.response.status;
|
|
134
|
+
}
|
|
135
|
+
if (error && typeof error === "object" && "status" in error && typeof error.status === "number") {
|
|
136
|
+
return error.status;
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
function errorDetail(error) {
|
|
141
|
+
if (error instanceof APIError) {
|
|
142
|
+
return [error.message, error.text, JSON.stringify(error.json)].filter(Boolean).join(" ");
|
|
143
|
+
}
|
|
144
|
+
return error instanceof Error ? error.message : String(error);
|
|
145
|
+
}
|
|
146
|
+
function sanitizeError(error, token) {
|
|
147
|
+
const sanitized = new Error(errorDetail(error).replaceAll(token, "[redacted]").slice(0, 2_000));
|
|
148
|
+
sanitized.name = error instanceof Error ? error.name : "VercelSetupError";
|
|
149
|
+
return sanitized;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=vercel-setup-probe.js.map
|