Fix broken cloud deploys by using depot ephemeral registry, skip the registry proxy (#1637)

This commit is contained in:
Eric Allam
2025-01-24 17:22:35 +00:00
committed by GitHub
parent eaf46bac58
commit f6eeaa1001
14 changed files with 351 additions and 195 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"trigger.dev": patch
"@trigger.dev/core": patch
---
Fix broken cloud deploys by using depot ephemeral registry
+3
View File
@@ -147,7 +147,10 @@ const EnvironmentSchema = z.object({
CONTAINER_REGISTRY_ORIGIN: z.string().optional(),
CONTAINER_REGISTRY_USERNAME: z.string().optional(),
CONTAINER_REGISTRY_PASSWORD: z.string().optional(),
ENABLE_REGISTRY_PROXY: z.string().optional(),
DEPLOY_REGISTRY_HOST: z.string().optional(),
DEPLOY_REGISTRY_USERNAME: z.string().optional(),
DEPLOY_REGISTRY_PASSWORD: z.string().optional(),
DEPLOY_REGISTRY_NAMESPACE: z.string().default("trigger"),
DEPLOY_TIMEOUT_MS: z.coerce
.number()
@@ -1,9 +1,10 @@
import { ActionFunctionArgs, json } from "@remix-run/server-runtime";
import { StartDeploymentIndexingRequestBody } from "@trigger.dev/core/v3";
import { FinalizeDeploymentRequestBody } from "@trigger.dev/core/v3";
import { z } from "zod";
import { authenticateApiRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { StartDeploymentIndexing } from "~/v3/services/startDeploymentIndexing.server";
import { ServiceValidationError } from "~/v3/services/baseService.server";
import { FinalizeDeploymentV2Service } from "~/v3/services/finalizeDeploymentV2";
const ParamsSchema = z.object({
deploymentId: z.string(),
@@ -34,21 +35,31 @@ export async function action({ request, params }: ActionFunctionArgs) {
const { deploymentId } = parsedParams.data;
const rawBody = await request.json();
const body = StartDeploymentIndexingRequestBody.safeParse(rawBody);
const body = FinalizeDeploymentRequestBody.safeParse(rawBody);
if (!body.success) {
return json({ error: "Invalid body", issues: body.error.issues }, { status: 400 });
}
const service = new StartDeploymentIndexing();
try {
const service = new FinalizeDeploymentV2Service();
await service.call(authenticatedEnv, deploymentId, body.data);
const deployment = await service.call(authenticatedEnv, deploymentId, body.data);
return json(
{
id: deployment.friendlyId,
contentHash: deployment.contentHash,
},
{ status: 200 }
);
return json(
{
id: deploymentId,
},
{ status: 200 }
);
} catch (error) {
if (error instanceof ServiceValidationError) {
return json({ error: error.message }, { status: 400 });
} else if (error instanceof Error) {
logger.error("Error finalizing deployment", { error: error.message });
return json({ error: `Internal server error: ${error.message}` }, { status: 500 });
} else {
logger.error("Error finalizing deployment", { error: String(error) });
return json({ error: "Internal server error" }, { status: 500 });
}
}
}
@@ -435,6 +435,11 @@ function initializeProxy() {
return;
}
if (!env.ENABLE_REGISTRY_PROXY || env.ENABLE_REGISTRY_PROXY === "false") {
logger.info("Registry proxy is disabled");
return;
}
return new RegistryProxy({
origin: env.CONTAINER_REGISTRY_ORIGIN,
auth: {
@@ -16,7 +16,7 @@ export class FinalizeDeploymentService extends BaseService {
id: string,
body: FinalizeDeploymentRequestBody
) {
const deployment = await this._prisma.workerDeployment.findUnique({
const deployment = await this._prisma.workerDeployment.findFirst({
where: {
friendlyId: id,
environmentId: authenticatedEnv.id,
@@ -48,6 +48,12 @@ export class FinalizeDeploymentService extends BaseService {
throw new ServiceValidationError("Worker deployment is not in DEPLOYING status");
}
let imageReference = body.imageReference;
if (registryProxy && body.selfHosted !== true && body.skipRegistryProxy !== true) {
imageReference = registryProxy.rewriteImageReference(body.imageReference);
}
// Link the deployment with the background worker
const finalizedDeployment = await this._prisma.workerDeployment.update({
where: {
@@ -56,10 +62,7 @@ export class FinalizeDeploymentService extends BaseService {
data: {
status: "DEPLOYED",
deployedAt: new Date(),
imageReference:
registryProxy && body.selfHosted !== true
? registryProxy.rewriteImageReference(body.imageReference)
: body.imageReference,
imageReference: imageReference,
},
});
@@ -0,0 +1,259 @@
import { ExternalBuildData, FinalizeDeploymentRequestBody } from "@trigger.dev/core/v3/schemas";
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { BaseService, ServiceValidationError } from "./baseService.server";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { mkdtemp, writeFile } from "node:fs/promises";
import { env } from "~/env.server";
import { depot as execDepot } from "@depot/cli";
import { FinalizeDeploymentService } from "./finalizeDeployment.server";
export class FinalizeDeploymentV2Service extends BaseService {
public async call(
authenticatedEnv: AuthenticatedEnvironment,
id: string,
body: FinalizeDeploymentRequestBody
) {
// if it's self hosted, lets just use the v1 finalize deployment service
if (body.selfHosted) {
const finalizeService = new FinalizeDeploymentService();
return finalizeService.call(authenticatedEnv, id, body);
}
const deployment = await this._prisma.workerDeployment.findFirst({
where: {
friendlyId: id,
environmentId: authenticatedEnv.id,
},
include: {
environment: true,
worker: {
include: {
tasks: true,
project: true,
},
},
},
});
if (!deployment) {
logger.error("Worker deployment not found", { id });
return;
}
if (!deployment.worker) {
logger.error("Worker deployment does not have a worker", { id });
throw new ServiceValidationError("Worker deployment does not have a worker");
}
if (deployment.status !== "DEPLOYING") {
logger.error("Worker deployment is not in DEPLOYING status", { id });
throw new ServiceValidationError("Worker deployment is not in DEPLOYING status");
}
const externalBuildData = deployment.externalBuildData
? ExternalBuildData.safeParse(deployment.externalBuildData)
: undefined;
if (!externalBuildData) {
throw new ServiceValidationError("External build data is missing");
}
if (!externalBuildData.success) {
throw new ServiceValidationError("External build data is invalid");
}
if (
!env.DEPLOY_REGISTRY_HOST ||
!env.DEPLOY_REGISTRY_USERNAME ||
!env.DEPLOY_REGISTRY_PASSWORD
) {
throw new ServiceValidationError("Missing deployment registry credentials");
}
if (!env.DEPOT_TOKEN) {
throw new ServiceValidationError("Missing depot token");
}
const pushResult = await executePushToRegistry({
depot: {
buildId: externalBuildData.data.buildId,
orgToken: env.DEPOT_TOKEN,
projectId: externalBuildData.data.projectId,
},
registry: {
host: env.DEPLOY_REGISTRY_HOST,
namespace: env.DEPLOY_REGISTRY_NAMESPACE,
username: env.DEPLOY_REGISTRY_USERNAME,
password: env.DEPLOY_REGISTRY_PASSWORD,
},
deployment: {
version: deployment.version,
environmentSlug: deployment.environment.slug,
projectExternalRef: deployment.worker.project.externalRef,
},
});
if (!pushResult.ok) {
throw new ServiceValidationError(pushResult.error);
}
const finalizeService = new FinalizeDeploymentService();
const finalizedDeployment = await finalizeService.call(authenticatedEnv, id, {
imageReference: pushResult.image,
skipRegistryProxy: true,
});
return finalizedDeployment;
}
}
type ExecutePushToRegistryOptions = {
depot: {
buildId: string;
orgToken: string;
projectId: string;
};
registry: {
host: string;
namespace: string;
username: string;
password: string;
};
deployment: {
version: string;
environmentSlug: string;
projectExternalRef: string;
};
};
type ExecutePushResult =
| {
ok: true;
image: string;
logs: string;
}
| {
ok: false;
error: string;
logs: string;
};
async function executePushToRegistry({
depot,
registry,
deployment,
}: ExecutePushToRegistryOptions): Promise<ExecutePushResult> {
// Step 1: We need to "login" to the digital ocean registry
const configDir = await ensureLoggedIntoDockerRegistry(registry.host, {
username: registry.username,
password: registry.password,
});
const imageTag = `${registry.host}/${registry.namespace}/${deployment.projectExternalRef}:${deployment.version}.${deployment.environmentSlug}`;
// Step 2: We need to run the depot push command
// DEPOT_TOKEN="<org token>" DEPOT_PROJECT_ID="<project id>" depot push <build id> -t registry.digitalocean.com/trigger-failover/proj_bzhdaqhlymtuhlrcgbqy:20250124.54.prod
// Step 4: Build and push the image
const childProcess = execDepot(["push", depot.buildId, "-t", imageTag, "--progress", "plain"], {
env: {
NODE_ENV: process.env.NODE_ENV,
DEPOT_TOKEN: depot.orgToken,
DEPOT_PROJECT_ID: depot.projectId,
DEPOT_NO_SUMMARY_LINK: "1",
DEPOT_NO_UPDATE_NOTIFIER: "1",
DOCKER_CONFIG: configDir,
},
});
const errors: string[] = [];
try {
const processCode = await new Promise<number | null>((res, rej) => {
// For some reason everything is output on stderr, not stdout
childProcess.stderr?.on("data", (data: Buffer) => {
const text = data.toString();
// Emitted data chunks can contain multiple lines. Remove empty lines.
const lines = text.split("\n").filter(Boolean);
errors.push(...lines);
logger.debug(text, {
imageTag,
deployment,
});
});
childProcess.on("error", (e) => rej(e));
childProcess.on("close", (code) => res(code));
});
const logs = extractLogs(errors);
if (processCode !== 0) {
return {
ok: false as const,
error: `Error pushing image`,
logs,
};
}
return {
ok: true as const,
image: imageTag,
logs,
};
} catch (e) {
return {
ok: false as const,
error: e instanceof Error ? e.message : JSON.stringify(e),
logs: extractLogs(errors),
};
}
}
async function ensureLoggedIntoDockerRegistry(
registryHost: string,
auth: { username: string; password: string }
) {
const tmpDir = await createTempDir();
// Read the current docker config
const dockerConfigPath = join(tmpDir, "config.json");
await writeJSONFile(dockerConfigPath, {
auths: {
[registryHost]: {
auth: Buffer.from(`${auth.username}:${auth.password}`).toString("base64"),
},
},
});
logger.debug(`Writing docker config to ${dockerConfigPath}`);
return tmpDir;
}
// Create a temporary directory within the OS's temp directory
async function createTempDir(): Promise<string> {
// Generate a unique temp directory path
const tempDirPath: string = join(tmpdir(), "trigger-");
// Create the temp directory synchronously and return the path
const directory = await mkdtemp(tempDirPath);
return directory;
}
async function writeJSONFile(path: string, json: any, pretty = false) {
await writeFile(path, JSON.stringify(json, undefined, pretty ? 2 : undefined), "utf8");
}
function extractLogs(outputs: string[]) {
// Remove empty lines
const cleanedOutputs = outputs.map((line) => line.trim()).filter((line) => line !== "");
return cleanedOutputs.map((line) => line.trim()).join("\n");
}
@@ -1,31 +0,0 @@
import { StartDeploymentIndexingRequestBody } from "@trigger.dev/core/v3";
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
import { registryProxy } from "../registryProxy.server";
import { BaseService } from "./baseService.server";
import { IndexDeploymentService } from "./indexDeployment.server";
export class StartDeploymentIndexing extends BaseService {
public async call(
environment: AuthenticatedEnvironment,
deploymentId: string,
body: StartDeploymentIndexingRequestBody
) {
const deployment = await this._prisma.workerDeployment.update({
where: {
friendlyId: deploymentId,
},
data: {
imageReference:
registryProxy && body.selfHosted !== true
? registryProxy.rewriteImageReference(body.imageReference)
: body.imageReference,
status: "DEPLOYING",
builtAt: new Date(),
},
});
await IndexDeploymentService.enqueue(deployment.id);
return deployment;
}
}
+1
View File
@@ -46,6 +46,7 @@
"@conform-to/react": "^0.6.1",
"@conform-to/zod": "^0.6.1",
"@depot/sdk-node": "^1.0.0",
"@depot/cli": "0.0.1-cli.2.80.0",
"@electric-sql/react": "^0.3.5",
"@headlessui/react": "^1.7.8",
"@heroicons/react": "^2.0.12",
+1 -1
View File
@@ -74,7 +74,7 @@
},
"dependencies": {
"@clack/prompts": "^0.7.0",
"@depot/cli": "0.0.1-cli.2.73.0",
"@depot/cli": "0.0.1-cli.2.80.0",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/api-logs": "0.52.1",
"@opentelemetry/exporter-logs-otlp-http": "0.52.1",
+1 -1
View File
@@ -254,7 +254,7 @@ export class CliApiClient {
return wrapZodFetch(
FailDeploymentResponseBody,
`${this.apiURL}/api/v1/deployments/${id}/finalize`,
`${this.apiURL}/api/v2/deployments/${id}/finalize`,
{
method: "POST",
headers: {
+6 -109
View File
@@ -1,14 +1,13 @@
import { intro, outro } from "@clack/prompts";
import { prepareDeploymentError } from "@trigger.dev/core/v3";
import { ResolvedConfig } from "@trigger.dev/core/v3/build";
import { BuildManifest, InitializeDeploymentResponseBody } from "@trigger.dev/core/v3/schemas";
import { InitializeDeploymentResponseBody } from "@trigger.dev/core/v3/schemas";
import { Command, Option as CommandOption } from "commander";
import { writeFile } from "node:fs/promises";
import { join, relative, resolve } from "node:path";
import { readPackageJSON, writePackageJSON } from "pkg-types";
import { resolve } from "node:path";
import { x } from "tinyexec";
import { z } from "zod";
import { CliApiClient } from "../apiClient.js";
import { buildWorker } from "../build/buildWorker.js";
import { resolveAlwaysExternal } from "../build/externals.js";
import {
CommonCommandOptions,
commonOptions,
@@ -17,7 +16,7 @@ import {
wrapCommandAction,
} from "../cli/common.js";
import { loadConfig } from "../config.js";
import { buildImage, generateContainerfile } from "../deploy/buildImage.js";
import { buildImage } from "../deploy/buildImage.js";
import {
checkLogsForErrors,
checkLogsForWarnings,
@@ -25,10 +24,8 @@ import {
printWarnings,
saveLogs,
} from "../deploy/logs.js";
import { buildManifestToJSON } from "../utilities/buildManifest.js";
import { chalkError, cliLink, isLinksSupported, prettyError } from "../utilities/cliOutput.js";
import { loadDotEnvVars } from "../utilities/dotEnv.js";
import { writeJSONFile } from "../utilities/fileSystem.js";
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
import { logger } from "../utilities/logger.js";
import { getProjectClient } from "../utilities/session.js";
@@ -36,8 +33,6 @@ import { getTmpDir } from "../utilities/tempDirectories.js";
import { spinner } from "../utilities/windows.js";
import { login } from "./login.js";
import { updateTriggerPackages } from "./update.js";
import { resolveAlwaysExternal } from "../build/externals.js";
import { x } from "tinyexec";
const DeployCommandOptions = CommonCommandOptions.extend({
dryRun: z.boolean().default(false),
@@ -429,7 +424,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
? `${selfHostedRegistryHost ? `${selfHostedRegistryHost}/` : ""}${buildResult.image}${
buildResult.digest ? `@${buildResult.digest}` : ""
}`
: `${registryHost}/${buildResult.image}${buildResult.digest ? `@${buildResult.digest}` : ""}`;
: `${buildResult.image}${buildResult.digest ? `@${buildResult.digest}` : ""}`;
const finalizeResponse = await projectClient.client.finalizeDeployment(deployment.id, {
imageReference,
@@ -459,104 +454,6 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
);
}
function rewriteBuildManifestPaths(
buildManifest: BuildManifest,
destinationDir: string
): BuildManifest {
return {
...buildManifest,
files: buildManifest.files.map((file) => ({
...file,
entry: cleanEntryPath(file.entry),
out: rewriteOutputPath(destinationDir, file.out),
})),
outputPath: rewriteOutputPath(destinationDir, buildManifest.outputPath),
configPath: rewriteOutputPath(destinationDir, buildManifest.configPath),
runControllerEntryPoint: buildManifest.runControllerEntryPoint
? rewriteOutputPath(destinationDir, buildManifest.runControllerEntryPoint)
: undefined,
runWorkerEntryPoint: rewriteOutputPath(destinationDir, buildManifest.runWorkerEntryPoint),
indexControllerEntryPoint: buildManifest.indexControllerEntryPoint
? rewriteOutputPath(destinationDir, buildManifest.indexControllerEntryPoint)
: undefined,
indexWorkerEntryPoint: rewriteOutputPath(destinationDir, buildManifest.indexWorkerEntryPoint),
loaderEntryPoint: buildManifest.loaderEntryPoint
? rewriteOutputPath(destinationDir, buildManifest.loaderEntryPoint)
: undefined,
};
}
async function writeProjectFiles(
buildManifest: BuildManifest,
resolvedConfig: ResolvedConfig,
outputPath: string
) {
// Step 1. Read the package.json file
const packageJson = await readProjectPackageJson(resolvedConfig.packageJsonPath);
if (!packageJson) {
throw new Error("Could not read the package.json file");
}
const dependencies =
buildManifest.externals?.reduce(
(acc, external) => {
acc[external.name] = external.version;
return acc;
},
{} as Record<string, string>
) ?? {};
// Step 3: Write the resolved dependencies to the package.json file
await writePackageJSON(join(outputPath, "package.json"), {
...packageJson,
name: packageJson.name ?? "trigger-project",
dependencies: {
...dependencies,
},
trustedDependencies: Object.keys(dependencies),
devDependencies: {},
peerDependencies: {},
scripts: {},
});
await writeJSONFile(join(outputPath, "build.json"), buildManifestToJSON(buildManifest));
await writeContainerfile(outputPath, buildManifest);
}
async function readProjectPackageJson(packageJsonPath: string) {
const packageJson = await readPackageJSON(packageJsonPath);
return packageJson;
}
// Remove any query parameters from the entry path
// For example, src/trigger/ai.ts?sentryProxyModule=true -> src/trigger/ai.ts
function cleanEntryPath(entry: string): string {
return entry.split("?")[0]!;
}
function rewriteOutputPath(destinationDir: string, filePath: string) {
return `/app/${relative(destinationDir, filePath)}`;
}
async function writeContainerfile(outputPath: string, buildManifest: BuildManifest) {
if (!buildManifest.runControllerEntryPoint || !buildManifest.indexControllerEntryPoint) {
throw new Error("Something went wrong with the build. Aborting deployment. [code 7789]");
}
const containerfile = await generateContainerfile({
runtime: buildManifest.runtime,
entrypoint: buildManifest.runControllerEntryPoint,
build: buildManifest.build,
image: buildManifest.image,
indexScript: buildManifest.indexControllerEntryPoint,
});
await writeFile(join(outputPath, "Containerfile"), containerfile);
}
export async function syncEnvVarsWithServer(
apiClient: CliApiClient,
projectRef: string,
+2 -4
View File
@@ -194,10 +194,8 @@ async function depotBuildImage(options: DepotBuildImageOptions): Promise<BuildIm
...(options.extraCACerts ? ["--build-arg", `NODE_EXTRA_CA_CERTS=${options.extraCACerts}`] : []),
"--progress",
"plain",
"-t",
`${options.registryHost}/${options.imageTag}`,
".",
"--push",
"--save",
options.loadImage ? "--load" : undefined,
].filter(Boolean) as string[];
@@ -249,7 +247,7 @@ async function depotBuildImage(options: DepotBuildImageOptions): Promise<BuildIm
return {
ok: true as const,
image: options.imageTag,
image: `registry.depot.dev/${options.buildProjectId}:${options.buildId}`,
logs,
digest,
};
+1
View File
@@ -222,6 +222,7 @@ export type StartDeploymentIndexingResponseBody = z.infer<
export const FinalizeDeploymentRequestBody = z.object({
imageReference: z.string(),
selfHosted: z.boolean().optional(),
skipRegistryProxy: z.boolean().optional(),
});
export type FinalizeDeploymentRequestBody = z.infer<typeof FinalizeDeploymentRequestBody>;
+34 -31
View File
@@ -228,6 +228,9 @@ importers:
'@conform-to/zod':
specifier: ^0.6.1
version: 0.6.1(@conform-to/dom@0.6.1)(zod@3.23.8)
'@depot/cli':
specifier: 0.0.1-cli.2.80.0
version: 0.0.1-cli.2.80.0
'@depot/sdk-node':
specifier: ^1.0.0
version: 1.0.0
@@ -1070,8 +1073,8 @@ importers:
specifier: ^0.7.0
version: 0.7.0
'@depot/cli':
specifier: 0.0.1-cli.2.73.0
version: 0.0.1-cli.2.73.0
specifier: 0.0.1-cli.2.80.0
version: 0.0.1-cli.2.80.0
'@opentelemetry/api':
specifier: 1.9.0
version: 1.9.0
@@ -5477,8 +5480,8 @@ packages:
dependencies:
'@jridgewell/trace-mapping': 0.3.9
/@depot/cli-darwin-arm64@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-nXG6loMJxbfWnKoVvTvrw19GAX3TxsgUy2mnb7sKv06VjUeMvsvBueXAW4lxO5Cf89oim9b0/Agnj/B3IVD2Kg==}
/@depot/cli-darwin-arm64@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-H7tQ0zWXVmdYXGFvt3d/v5fmquMlMM1I9JC8C2yiBZ9En9a20hzSbKoiym92RtcfqjKQFvhXL0DT6vQmJ8bgQA==}
engines: {node: '>=14'}
cpu: [arm64]
os: [darwin]
@@ -5486,8 +5489,8 @@ packages:
dev: false
optional: true
/@depot/cli-darwin-x64@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-AqkNIIOuzh/8hmwTwu1FIY5Lvez7h4/STO3oPjaalLajV+ZfHgV2xpmbtTwxPmgLVFPaE2e77wzvpRWuFarWwQ==}
/@depot/cli-darwin-x64@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-3RDyybnCC2YSvbJCkHxXBYbKR7adUO7U00O9DHreX8EyS2E/C3kQgET+rFXR+iDdeG0h+h+At2rDng7AxvUhDw==}
engines: {node: '>=14'}
cpu: [x64]
os: [darwin]
@@ -5495,8 +5498,8 @@ packages:
dev: false
optional: true
/@depot/cli-linux-arm64@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-Rfiil6MAO/SkAK27vaEA1IOPOJq8DgCvm09sfasrXFvpldDYa700Hx7c+V1uuBYfIckVh2S/i7AQjGg535MDjg==}
/@depot/cli-linux-arm64@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-Fc1+Guqdsl2WM+b+76FirRjjRvEoYZX0MI4uuIQF9c9gwp6UZSZ5o3U7lAUpdkclVMKXSAW5bsIpgcOfUiJX3w==}
engines: {node: '>=14'}
cpu: [arm64]
os: [linux]
@@ -5504,8 +5507,8 @@ packages:
dev: false
optional: true
/@depot/cli-linux-arm@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-/HspMwaVYYPErg372Bk4x7Gno7n8VuaLqaGm39wbZEb9C4S9YAP7r7T0wSywrUZBzJBxX7f+GoHbBic0IQoraQ==}
/@depot/cli-linux-arm@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-95kjKwKxP6RKkAhJoPlO6g3drEYpFWy9AC7QfvQMHDRnI3HXgbxA/BSTp4R3C4TTfp5JUPShVf8Js/NAcrUpUQ==}
engines: {node: '>=14'}
cpu: [arm]
os: [linux]
@@ -5513,8 +5516,8 @@ packages:
dev: false
optional: true
/@depot/cli-linux-ia32@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-1GHDaNe6KXYjHWNoUrd2GutnseyYt3yrUKmRYKAR+/AU3BW/eQGcRAp50bSu9nntIaL+ByugkR+LjwKJIqRzmg==}
/@depot/cli-linux-ia32@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-2KoyIoYqnyIuynPN+mWbugoOB2APiNNvFLKERWOwPa0KYLSfcENT3sYxDW8tDuIw2dftHlmZN73uvXrGFeMcDQ==}
engines: {node: '>=14'}
cpu: [ia32]
os: [linux]
@@ -5522,8 +5525,8 @@ packages:
dev: false
optional: true
/@depot/cli-linux-x64@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-CY4IwXT5l2btXbjCYl+85tfF/viz6zdyaWjiu7MUuxxAM+s9bMYl7HKBITHdflx9Z/dRfDGFX8tM1i2AsKBcqA==}
/@depot/cli-linux-x64@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-B8xDlXFxhYHD2tUk0jUv7SKipLfWwJVlY7ZhDQixyQzatibXakahdqpvZJgE6FLZJd3lgFIEAVsKURZHa1l57A==}
engines: {node: '>=14'}
cpu: [x64]
os: [linux]
@@ -5531,8 +5534,8 @@ packages:
dev: false
optional: true
/@depot/cli-win32-arm64@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-mslCCUzlK53aYstJH6//mPOVTWa8vU2IemBGLFsntgB1f/0fqDdfAskyfu+RVx/ZNqjr2Ih2jtdlfyOA3XKZdw==}
/@depot/cli-win32-arm64@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-CPJX691MKEhnKZX25xS+opWESgPQ73HKkEwkAvvVqdBzahndcHoqAeIxYLv2hoCqrDlkH3YCF+DJleLiEP3blA==}
engines: {node: '>=14'}
cpu: [arm64]
os: [win32]
@@ -5540,8 +5543,8 @@ packages:
dev: false
optional: true
/@depot/cli-win32-ia32@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-/xsLWyIO7tAHTkFTFO0j9Csc78WnoENeEWROeUWsvAizFX6GF6Toir1xRZbM28yRRlGsOG+KWsFwULyEJkI1Wg==}
/@depot/cli-win32-ia32@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-6eewZ1zPEyNL3zcCwC01s3rZNMqMGVu1iv/EPywj3/uk4CNyUBaTlZ3StQ1BLFHPQnU0vk29yOzA5ZEuRLSyxA==}
engines: {node: '>=14'}
cpu: [ia32]
os: [win32]
@@ -5549,8 +5552,8 @@ packages:
dev: false
optional: true
/@depot/cli-win32-x64@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-iC8FpHij2yrO1hNQPuRYgreYsyvXgC6xaBdBpfM5x7C7Uf+vOg4k5ERToj0WCfvRhkja+uguQdw2V3il6IhNeA==}
/@depot/cli-win32-x64@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-9CRcc7D0/x4UrBkDuc35WVPMQG5gKMD1JckGLEl6VREE0Ppdny6n+hunQ8prwVc8aqzKG134XCC2U4DUjYg18A==}
engines: {node: '>=14'}
cpu: [x64]
os: [win32]
@@ -5558,21 +5561,21 @@ packages:
dev: false
optional: true
/@depot/cli@0.0.1-cli.2.73.0:
resolution: {integrity: sha512-pu5SKOj95jzCPG5H5SZvAN6Z+h4ACcjs6shv7S1lXqSGxNBVTvq7LlTiBFGpLcLo+EkSfbEjAdlNBdh1LRqrKA==}
/@depot/cli@0.0.1-cli.2.80.0:
resolution: {integrity: sha512-KvmOiQdpbamFziqnzzgqBm6RjfGhLJimBBYEOVriTxCPtVJuBIFm34xZllM36OQzPZIWpWBP+2/UnOyRG5smUg==}
engines: {node: '>=14'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@depot/cli-darwin-arm64': 0.0.1-cli.2.73.0
'@depot/cli-darwin-x64': 0.0.1-cli.2.73.0
'@depot/cli-linux-arm': 0.0.1-cli.2.73.0
'@depot/cli-linux-arm64': 0.0.1-cli.2.73.0
'@depot/cli-linux-ia32': 0.0.1-cli.2.73.0
'@depot/cli-linux-x64': 0.0.1-cli.2.73.0
'@depot/cli-win32-arm64': 0.0.1-cli.2.73.0
'@depot/cli-win32-ia32': 0.0.1-cli.2.73.0
'@depot/cli-win32-x64': 0.0.1-cli.2.73.0
'@depot/cli-darwin-arm64': 0.0.1-cli.2.80.0
'@depot/cli-darwin-x64': 0.0.1-cli.2.80.0
'@depot/cli-linux-arm': 0.0.1-cli.2.80.0
'@depot/cli-linux-arm64': 0.0.1-cli.2.80.0
'@depot/cli-linux-ia32': 0.0.1-cli.2.80.0
'@depot/cli-linux-x64': 0.0.1-cli.2.80.0
'@depot/cli-win32-arm64': 0.0.1-cli.2.80.0
'@depot/cli-win32-ia32': 0.0.1-cli.2.80.0
'@depot/cli-win32-x64': 0.0.1-cli.2.80.0
dev: false
/@depot/sdk-node@1.0.0: