diff --git a/.changeset/icy-nights-bet.md b/.changeset/icy-nights-bet.md new file mode 100644 index 0000000..2f905ee --- /dev/null +++ b/.changeset/icy-nights-bet.md @@ -0,0 +1,5 @@ +--- +"@vercel/sandbox": patch +--- + +Support useworkflow serialization for sandboxes and commands diff --git a/README.md b/README.md index b6787fc..9626fe6 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,26 @@ const sandbox = await Sandbox.create({ }); ``` +## Workflow DevKit integration + +`Sandbox` and `CommandFinished` support serialization with the +[Workflow DevKit](https://vercel.com/docs/workflow). When a sandbox instance +crosses a step boundary the SDK serializes sandbox metadata and routes, then +rehydrates synchronously from that snapshot. + +Because the workflow runtime deserializes in a new execution context, +credentials are not carried over. Call `setSandboxCredentials` in the module +scope so deserialized instances can make API calls when needed: + +```ts +import { Sandbox, setSandboxCredentials } from "@vercel/sandbox"; + +setSandboxCredentials({ + token: process.env.VERCEL_TOKEN!, + teamId: process.env.VERCEL_TEAM_ID!, +}); +``` + ## Limitations - Max resources: 8 vCPUs. You will get 2048 MB of memory per vCPU. diff --git a/packages/vercel-sandbox/README.md b/packages/vercel-sandbox/README.md index 0732622..70831e8 100644 --- a/packages/vercel-sandbox/README.md +++ b/packages/vercel-sandbox/README.md @@ -142,6 +142,26 @@ const sandbox = await Sandbox.create({ }); ``` +## Workflow DevKit integration + +`Sandbox` and `CommandFinished` support serialization with the +[Workflow DevKit](https://vercel.com/docs/workflow). When a sandbox instance +crosses a step boundary the SDK serializes sandbox metadata and routes, then +rehydrates synchronously from that snapshot. + +Because the workflow runtime deserializes in a new execution context, +credentials are not carried over. Call `setSandboxCredentials` in the module +scope so deserialized instances can make API calls when needed: + +```ts +import { Sandbox, setSandboxCredentials } from "@vercel/sandbox"; + +setSandboxCredentials({ + token: process.env.VERCEL_TOKEN!, + teamId: process.env.VERCEL_TEAM_ID!, +}); +``` + ## Limitations - Max resources: 8 vCPUs. You will get 2048 MB of memory per vCPU. diff --git a/packages/vercel-sandbox/package.json b/packages/vercel-sandbox/package.json index 3e3af4b..5fea063 100644 --- a/packages/vercel-sandbox/package.json +++ b/packages/vercel-sandbox/package.json @@ -31,6 +31,7 @@ "license": "Apache-2.0", "dependencies": { "@vercel/oidc": "3.2.0", + "@workflow/serde": "4.1.0-beta.2", "async-retry": "1.3.3", "jsonlines": "0.1.1", "ms": "2.1.3", @@ -46,6 +47,7 @@ "@types/ms": "2.1.0", "@types/node": "22.15.12", "@types/tar-stream": "3.1.4", + "@workflow/core": "4.1.0-beta.62", "dotenv": "16.5.0", "factoree": "^0.1.2", "typedoc": "0.28.5", diff --git a/packages/vercel-sandbox/src/command.serialize.test.ts b/packages/vercel-sandbox/src/command.serialize.test.ts new file mode 100644 index 0000000..865770e --- /dev/null +++ b/packages/vercel-sandbox/src/command.serialize.test.ts @@ -0,0 +1,491 @@ +import { describe, it, expect, vi, afterEach } from "vitest"; +import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde"; +import { registerSerializationClass } from "@workflow/core/class-serialization"; +import { + dehydrateStepReturnValue, + hydrateStepReturnValue, +} from "@workflow/core/serialization"; +import { + CommandFinished, + SerializedCommandFinished, + CommandOutput, +} from "./command"; +import type { CommandData } from "./api-client"; +import { APIClient } from "./api-client"; + +describe("CommandFinished serialization", () => { + const mockCommandData: CommandData = { + id: "cmd_test123", + name: "echo", + args: ["hello", "world"], + cwd: "/vercel/sandbox", + sandboxId: "sbx_test456", + exitCode: 0, + startedAt: 1700000000000, + }; + + const mockSandboxId = "sbx_test456"; + + const mockOutput: CommandOutput = { + stdout: "Hello, world!\n", + stderr: "", + }; + + const createMockCommandFinished = ( + cmd: CommandData = mockCommandData, + sandboxId: string = mockSandboxId, + exitCode: number = 0, + output?: CommandOutput, + ): CommandFinished => { + const client = new APIClient({ + teamId: "team_test", + token: "test_token", + }); + + return new CommandFinished({ + client, + sandboxId, + cmd, + exitCode, + output, + }); + }; + + describe("WORKFLOW_SERIALIZE", () => { + it("serializes a CommandFinished instance with output", () => { + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + mockOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized).toEqual({ + sandboxId: mockSandboxId, + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }); + }); + + it("serializes without output if not fetched", () => { + const commandFinished = createMockCommandFinished(); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.sandboxId).toBe(mockSandboxId); + expect(serialized.cmd).toEqual(mockCommandData); + expect(serialized.exitCode).toBe(0); + expect(serialized.output).toBeUndefined(); + }); + + it("preserves the exit code", () => { + const commandFinished = createMockCommandFinished( + { ...mockCommandData, exitCode: 42 }, + mockSandboxId, + 42, + mockOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.exitCode).toBe(42); + }); + + it("preserves stdout in output", () => { + const customOutput: CommandOutput = { + stdout: "Custom stdout\n", + stderr: "Custom stderr\n", + }; + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + customOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.output?.stdout).toBe("Custom stdout\n"); + expect(serialized.output?.stderr).toBe("Custom stderr\n"); + }); + + it("returns a plain object that can be JSON serialized", () => { + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + mockOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + const jsonString = JSON.stringify(serialized); + const parsed = JSON.parse(jsonString); + + expect(parsed.exitCode).toBe(0); + expect(parsed.sandboxId).toBe(mockSandboxId); + expect(parsed.output).toEqual(mockOutput); + }); + + it("does not include the API client", () => { + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + mockOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized).not.toHaveProperty("client"); + expect(JSON.stringify(serialized)).not.toContain("token"); + }); + }); + + describe("WORKFLOW_DESERIALIZE", () => { + it("creates a CommandFinished instance from serialized data", () => { + const serializedData: SerializedCommandFinished = { + sandboxId: mockSandboxId, + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }; + + const commandFinished = + CommandFinished[WORKFLOW_DESERIALIZE](serializedData); + + expect(commandFinished).toBeInstanceOf(CommandFinished); + expect(commandFinished.exitCode).toBe(0); + }); + + it("returns synchronously (not a promise)", () => { + const serializedData: SerializedCommandFinished = { + sandboxId: mockSandboxId, + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }; + + const result = CommandFinished[WORKFLOW_DESERIALIZE](serializedData); + + // Should not be a promise + expect(result).toBeInstanceOf(CommandFinished); + expect(result).not.toBeInstanceOf(Promise); + }); + + it("preserves exit code after deserialization", () => { + const serializedData: SerializedCommandFinished = { + sandboxId: mockSandboxId, + cmd: { ...mockCommandData, exitCode: 127 }, + exitCode: 127, + output: mockOutput, + }; + + const commandFinished = + CommandFinished[WORKFLOW_DESERIALIZE](serializedData); + + expect(commandFinished.exitCode).toBe(127); + }); + + it("preserves command properties after deserialization", () => { + const serializedData: SerializedCommandFinished = { + sandboxId: mockSandboxId, + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }; + + const commandFinished = + CommandFinished[WORKFLOW_DESERIALIZE](serializedData); + + expect(commandFinished.cmdId).toBe(mockCommandData.id); + expect(commandFinished.cwd).toBe(mockCommandData.cwd); + expect(commandFinished.startedAt).toBe(mockCommandData.startedAt); + }); + + it("restores output for stdout() and stderr() methods", async () => { + const serializedData: SerializedCommandFinished = { + sandboxId: mockSandboxId, + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }; + + const commandFinished = + CommandFinished[WORKFLOW_DESERIALIZE](serializedData); + + expect(await commandFinished.stdout()).toBe(mockOutput.stdout); + expect(await commandFinished.stderr()).toBe(mockOutput.stderr); + }); + + it("deserialized instance has no client until accessed", () => { + const serializedData: SerializedCommandFinished = { + sandboxId: mockSandboxId, + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }; + + const commandFinished = + CommandFinished[WORKFLOW_DESERIALIZE](serializedData); + + // Client is lazily created - internal _client should be null initially + // (accessing .client would create one using OIDC by default) + expect(Reflect.get(commandFinished, "_client")).toBeNull(); + }); + }); + + describe("roundtrip serialization", () => { + it("serializes and deserializes a CommandFinished", async () => { + const originalCommand = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 42, + mockOutput, + ); + + // Serialize + const serialized = CommandFinished[WORKFLOW_SERIALIZE](originalCommand); + + // Deserialize + const deserialized = CommandFinished[WORKFLOW_DESERIALIZE](serialized); + + expect(deserialized.cmdId).toBe(originalCommand.cmdId); + expect(deserialized.exitCode).toBe(42); + expect(await deserialized.stdout()).toBe(mockOutput.stdout); + expect(await deserialized.stderr()).toBe(mockOutput.stderr); + }); + + it("serialized data can be stored and retrieved via JSON", async () => { + const originalCommand = createMockCommandFinished( + { ...mockCommandData, exitCode: 42 }, + mockSandboxId, + 42, + mockOutput, + ); + + // Serialize to JSON (simulating storage) + const serialized = CommandFinished[WORKFLOW_SERIALIZE](originalCommand); + const storedJson = JSON.stringify(serialized); + + // Retrieve from storage and deserialize + const retrievedData: SerializedCommandFinished = JSON.parse(storedJson); + const deserialized = CommandFinished[WORKFLOW_DESERIALIZE](retrievedData); + + expect(deserialized.cmdId).toBe(originalCommand.cmdId); + expect(deserialized.exitCode).toBe(42); + expect(await deserialized.stdout()).toBe(mockOutput.stdout); + }); + }); + + describe("SerializedCommandFinished type", () => { + it("contains all required fields", () => { + const serializedData: SerializedCommandFinished = { + sandboxId: "sbx_test", + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }; + + expect(serializedData).toHaveProperty("sandboxId"); + expect(serializedData).toHaveProperty("cmd"); + expect(serializedData).toHaveProperty("exitCode"); + expect(serializedData).toHaveProperty("output"); + }); + + it("output contains stdout and stderr", () => { + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + mockOutput, + ); + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.output).toHaveProperty("stdout"); + expect(serialized.output).toHaveProperty("stderr"); + }); + }); + + describe("edge cases", () => { + it("handles empty output", async () => { + const emptyOutput: CommandOutput = { stdout: "", stderr: "" }; + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + emptyOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + expect(serialized.output).toEqual(emptyOutput); + + const deserialized = CommandFinished[WORKFLOW_DESERIALIZE](serialized); + expect(await deserialized.stdout()).toBe(""); + expect(await deserialized.stderr()).toBe(""); + }); + + it("handles large output", () => { + const largeOutput: CommandOutput = { + stdout: "x".repeat(10000), + stderr: "y".repeat(10000), + }; + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + largeOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.output?.stdout.length).toBe(10000); + expect(serialized.output?.stderr.length).toBe(10000); + }); + + it("handles output with special characters", async () => { + const specialOutput: CommandOutput = { + stdout: 'Hello\nWorld\t"quoted"\n', + stderr: "Error: 日本語\n", + }; + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + specialOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + expect(serialized.output).toEqual(specialOutput); + + const deserialized = CommandFinished[WORKFLOW_DESERIALIZE](serialized); + expect(await deserialized.stdout()).toBe(specialOutput.stdout); + expect(await deserialized.stderr()).toBe(specialOutput.stderr); + }); + + it("handles exit code 0", () => { + const commandFinished = createMockCommandFinished( + { ...mockCommandData, exitCode: 0 }, + mockSandboxId, + 0, + mockOutput, + ); + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.exitCode).toBe(0); + }); + + it("handles high exit code (255)", () => { + const commandFinished = createMockCommandFinished( + { ...mockCommandData, exitCode: 255 }, + mockSandboxId, + 255, + mockOutput, + ); + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.exitCode).toBe(255); + }); + + it("handles command with special characters in args", () => { + const cmdWithSpecialArgs: CommandData = { + ...mockCommandData, + args: ["--flag=value", "-x", "hello world", "path/to/file"], + }; + const commandFinished = createMockCommandFinished( + cmdWithSpecialArgs, + mockSandboxId, + 0, + mockOutput, + ); + + const serialized = CommandFinished[WORKFLOW_SERIALIZE](commandFinished); + + expect(serialized.cmd.args).toEqual([ + "--flag=value", + "-x", + "hello world", + "path/to/file", + ]); + }); + + it("wait() returns this for deserialized instances", async () => { + const serializedData: SerializedCommandFinished = { + sandboxId: mockSandboxId, + cmd: mockCommandData, + exitCode: 0, + output: mockOutput, + }; + + const commandFinished = + CommandFinished[WORKFLOW_DESERIALIZE](serializedData); + const waited = await commandFinished.wait(); + + expect(waited).toBe(commandFinished); + }); + }); + + describe("workflow runtime integration", () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("CommandFinished survives a step boundary roundtrip", async () => { + registerSerializationClass("CommandFinished", CommandFinished); + + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 0, + mockOutput, + ); + + // Simulate step returning a CommandFinished + const dehydrated = await dehydrateStepReturnValue( + commandFinished, + "run_123", + undefined, + ); + expect(dehydrated).toBeInstanceOf(Uint8Array); + + // Simulate workflow receiving the step result + const rehydrated = await hydrateStepReturnValue( + dehydrated, + "run_123", + undefined, + ); + + expect(rehydrated).toBeInstanceOf(CommandFinished); + expect(rehydrated.exitCode).toBe(0); + expect(rehydrated.cmdId).toBe(mockCommandData.id); + }); + + it("preserves output through the runtime pipeline", async () => { + registerSerializationClass("CommandFinished", CommandFinished); + + const commandFinished = createMockCommandFinished( + mockCommandData, + mockSandboxId, + 42, + mockOutput, + ); + + const dehydrated = await dehydrateStepReturnValue( + commandFinished, + "run_456", + undefined, + ); + const rehydrated = await hydrateStepReturnValue( + dehydrated, + "run_456", + undefined, + ); + + expect(rehydrated.exitCode).toBe(42); + expect(await rehydrated.stdout()).toBe(mockOutput.stdout); + expect(await rehydrated.stderr()).toBe(mockOutput.stderr); + }); + }); +}); diff --git a/packages/vercel-sandbox/src/command.ts b/packages/vercel-sandbox/src/command.ts index 0729d13..5f88ff8 100644 --- a/packages/vercel-sandbox/src/command.ts +++ b/packages/vercel-sandbox/src/command.ts @@ -1,5 +1,32 @@ import { APIClient, type CommandData } from "./api-client"; import { Signal, resolveSignal } from "./utils/resolveSignal"; +import { getSandboxCredentials } from "./utils/sandbox-credentials"; +import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde"; + +/** + * Cached output from a command execution. + */ +export interface CommandOutput { + stdout: string; + stderr: string; +} + +/** + * Serialized representation of a Command for @workflow/serde. + */ +export interface SerializedCommand { + sandboxId: string; + cmd: CommandData; + /** Cached output, included if output was fetched before serialization */ + output?: CommandOutput; +} + +/** + * Serialized representation of a CommandFinished for @workflow/serde. + */ +export interface SerializedCommandFinished extends SerializedCommand { + exitCode: number; +} /** * A command executed in a Sandbox. @@ -16,29 +43,51 @@ import { Signal, resolveSignal } from "./utils/resolveSignal"; */ export class Command { /** + * Cached API client instance. * @internal - * @private */ - protected client: APIClient; + protected _client: APIClient | null = null; + + /** + * Lazily get or create the API client. + * If no client was provided during construction, creates one using global credentials. + */ + get client(): APIClient { + if (!this._client) { + const credentials = getSandboxCredentials(); + this._client = new APIClient({ + teamId: credentials.teamId, + token: credentials.token, + }); + } + return this._client; + } /** * ID of the sandbox this command is running in. */ - private sandboxId: string; + protected sandboxId: string; /** * Data for the command execution. */ - private cmd: CommandData; + protected cmd: CommandData; public exitCode: number | null; - private outputCache: Promise<{ + protected outputCache: Promise<{ stdout: string; stderr: string; both: string; }> | null = null; + /** + * Synchronously accessible resolved output, populated after output is fetched. + * Used for serialization. + * @internal + */ + protected _resolvedOutput: CommandOutput | null = null; + /** * ID of the command execution. */ @@ -55,24 +104,69 @@ export class Command { } /** - * @param params - Object containing the client, sandbox ID, and command ID. - * @param params.client - API client used to interact with the backend. + * @param params - Object containing the client, sandbox ID, and command data. + * @param params.client - Optional API client. If not provided, will be lazily created using global credentials. * @param params.sandboxId - The ID of the sandbox where the command is running. - * @param params.cmdId - The ID of the command execution. + * @param params.cmd - The command data. + * @param params.output - Optional cached output to restore (used during deserialization). */ constructor({ client, sandboxId, cmd, + output, }: { - client: APIClient; + client?: APIClient; sandboxId: string; cmd: CommandData; + output?: CommandOutput; }) { - this.client = client; + this._client = client ?? null; this.sandboxId = sandboxId; this.cmd = cmd; this.exitCode = cmd.exitCode ?? null; + if (output) { + this._resolvedOutput = output; + this.outputCache = Promise.resolve({ + stdout: output.stdout, + stderr: output.stderr, + both: output.stdout + output.stderr, + }); + } + } + + /** + * Serialize a Command instance to plain data for @workflow/serde. + * + * @param instance - The Command instance to serialize + * @returns A plain object containing the sandbox ID, command data, and output if fetched + */ + static [WORKFLOW_SERIALIZE](instance: Command): SerializedCommand { + const serialized: SerializedCommand = { + sandboxId: instance.sandboxId, + cmd: instance.cmd, + }; + if (instance._resolvedOutput) { + serialized.output = instance._resolvedOutput; + } + return serialized; + } + + /** + * Deserialize plain data back into a Command instance for @workflow/serde. + * + * The deserialized instance will lazily create an API client using global credentials + * when needed. Call {@link Sandbox.setCredentials} before using the deserialized instance. + * + * @param data - The serialized command data + * @returns The reconstructed Command instance + */ + static [WORKFLOW_DESERIALIZE](data: SerializedCommand): Command { + return new Command({ + sandboxId: data.sandboxId, + cmd: data.cmd, + output: data.output, + }); } /** @@ -144,7 +238,7 @@ export class Command { * Get cached output, fetching logs only once and reusing for concurrent calls. * This prevents race conditions when stdout() and stderr() are called in parallel. */ - private async getCachedOutput(opts?: { signal?: AbortSignal }): Promise<{ + protected async getCachedOutput(opts?: { signal?: AbortSignal }): Promise<{ stdout: string; stderr: string; both: string; @@ -163,6 +257,8 @@ export class Command { stderr += log.data; } } + // Store resolved output for serialization + this._resolvedOutput = { stdout, stderr }; return { stdout, stderr, both }; } catch (err) { // Clear the promise so future calls can retry @@ -188,7 +284,7 @@ export class Command { */ async output( stream: "stdout" | "stderr" | "both" = "both", - opts?: { signal?: AbortSignal }, + opts?: { signal?: AbortSignal } ) { const cached = await this.getCachedOutput(opts); return cached[stream]; @@ -257,22 +353,64 @@ export class CommandFinished extends Command { public exitCode: number; /** - * @param params - Object containing client, sandbox ID, command ID, and exit code. - * @param params.client - API client used to interact with the backend. + * @param params - Object containing client, sandbox ID, command data, and exit code. + * @param params.client - Optional API client. If not provided, will be lazily created using global credentials. * @param params.sandboxId - The ID of the sandbox where the command ran. - * @param params.cmdId - The ID of the command execution. + * @param params.cmd - The command data. * @param params.exitCode - The exit code of the completed command. + * @param params.output - Optional cached output to restore (used during deserialization). */ constructor(params: { - client: APIClient; + client?: APIClient; sandboxId: string; cmd: CommandData; exitCode: number; + output?: CommandOutput; }) { super({ ...params }); this.exitCode = params.exitCode; } + /** + * Serialize a CommandFinished instance to plain data for @workflow/serde. + * + * @param instance - The CommandFinished instance to serialize + * @returns A plain object containing the sandbox ID, command data, exit code, and output if fetched + */ + static [WORKFLOW_SERIALIZE]( + instance: CommandFinished + ): SerializedCommandFinished { + const serialized: SerializedCommandFinished = { + sandboxId: instance.sandboxId, + cmd: instance.cmd, + exitCode: instance.exitCode, + }; + if (instance._resolvedOutput) { + serialized.output = instance._resolvedOutput; + } + return serialized; + } + + /** + * Deserialize plain data back into a CommandFinished instance for @workflow/serde. + * + * The deserialized instance will lazily create an API client using global credentials + * when needed. Call {@link Sandbox.setCredentials} before using the deserialized instance. + * + * @param data - The serialized command finished data + * @returns The reconstructed CommandFinished instance + */ + static [WORKFLOW_DESERIALIZE]( + data: SerializedCommandFinished + ): CommandFinished { + return new CommandFinished({ + sandboxId: data.sandboxId, + cmd: data.cmd, + exitCode: data.exitCode, + output: data.output, + }); + } + /** * The wait method is not needed for CommandFinished instances since * the command has already completed and exitCode is populated. diff --git a/packages/vercel-sandbox/src/index.ts b/packages/vercel-sandbox/src/index.ts index 5540c76..8c344cf 100644 --- a/packages/vercel-sandbox/src/index.ts +++ b/packages/vercel-sandbox/src/index.ts @@ -1,10 +1,13 @@ export { Sandbox, + setSandboxCredentials, type NetworkPolicy, type NetworkPolicyRule, type NetworkTransformer, } from "./sandbox"; +export type { SerializedSandbox } from "./sandbox"; export { Snapshot } from "./snapshot"; export { Command, CommandFinished } from "./command"; +export type { SerializedCommand, SerializedCommandFinished, CommandOutput } from "./command"; export { StreamError } from "./api-client/api-error"; export { APIError } from "./api-client/api-error"; diff --git a/packages/vercel-sandbox/src/sandbox.serialize.test.ts b/packages/vercel-sandbox/src/sandbox.serialize.test.ts new file mode 100644 index 0000000..aa00ac9 --- /dev/null +++ b/packages/vercel-sandbox/src/sandbox.serialize.test.ts @@ -0,0 +1,224 @@ +import { describe, it, expect, vi, afterEach } from "vitest"; +import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde"; +import { registerSerializationClass } from "@workflow/core/class-serialization"; +import { + dehydrateStepReturnValue, + hydrateStepReturnValue, +} from "@workflow/core/serialization"; +import { Sandbox, type SerializedSandbox } from "./sandbox"; +import type { SandboxMetaData, SandboxRouteData } from "./api-client"; +import { APIClient } from "./api-client"; +import { toSandboxSnapshot } from "./utils/sandbox-snapshot"; + +describe("Sandbox serialization", () => { + const mockMetadata: SandboxMetaData = { + id: "sbx_test123", + memory: 2048, + vcpus: 1, + region: "us-east-1", + runtime: "node24", + timeout: 300000, + status: "running", + requestedAt: 1700000000000, + startedAt: 1700000001000, + createdAt: 1700000000000, + cwd: "/vercel/sandbox", + updatedAt: 1700000002000, + networkPolicy: { mode: "allow-all" }, + }; + + const mockRoutes: SandboxRouteData[] = [ + { url: "https://test-3000.vercel.run", subdomain: "test-3000", port: 3000 }, + { url: "https://test-4000.vercel.run", subdomain: "test-4000", port: 4000 }, + ]; + + const createMockSandbox = ( + metadata: SandboxMetaData = mockMetadata, + routes: SandboxRouteData[] = mockRoutes, + ): Sandbox => { + const client = new APIClient({ + teamId: "team_test", + token: "test_token", + }); + + return new Sandbox({ + client, + sandbox: toSandboxSnapshot(metadata), + routes, + }); + }; + + const serializeSandbox = (sandbox: Sandbox): SerializedSandbox => { + return Sandbox[WORKFLOW_SERIALIZE](sandbox); + }; + + const deserializeSandbox = (data: SerializedSandbox): Sandbox => { + return Sandbox[WORKFLOW_DESERIALIZE](data); + }; + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe("WORKFLOW_SERIALIZE", () => { + it("serializes sandbox snapshot data", () => { + const sandbox = createMockSandbox(); + const serialized = serializeSandbox(sandbox); + + expect(serialized.metadata.id).toBe("sbx_test123"); + expect(serialized.routes).toEqual(mockRoutes); + expect(serialized.metadata.networkPolicy).toBe("allow-all"); + }); + + it("returns plain JSON-serializable data", () => { + const sandbox = createMockSandbox(); + const serialized = serializeSandbox(sandbox); + + const jsonString = JSON.stringify(serialized); + const parsed = JSON.parse(jsonString); + + expect(parsed.metadata.id).toBe("sbx_test123"); + expect(parsed.routes).toEqual(mockRoutes); + }); + + it("does not include the API client or credentials", () => { + const sandbox = createMockSandbox(); + const serialized = serializeSandbox(sandbox); + + expect(serialized).not.toHaveProperty("client"); + expect(JSON.stringify(serialized)).not.toContain("token"); + }); + }); + + describe("WORKFLOW_DESERIALIZE", () => { + it("returns synchronously", () => { + const sandbox = createMockSandbox(); + const serialized = serializeSandbox(sandbox); + + const result = deserializeSandbox(serialized); + + expect(result).toBeInstanceOf(Sandbox); + expect(result).not.toBeInstanceOf(Promise); + }); + + it("reconstructs a fully usable snapshot-backed instance", () => { + const sandbox = createMockSandbox(); + const serialized = serializeSandbox(sandbox); + + const result = deserializeSandbox(serialized); + + expect(result.sandboxId).toBe("sbx_test123"); + expect(result.status).toBe("running"); + expect(result.routes).toEqual(mockRoutes); + expect(result.networkPolicy).toBe("allow-all"); + expect(result.domain(3000)).toBe("https://test-3000.vercel.run"); + }); + + it("does not require global credentials just to deserialize and read metadata", async () => { + vi.resetModules(); + const { Sandbox: FreshSandbox } = await import("./sandbox"); + + const serializedData: SerializedSandbox = { + metadata: { + id: "sbx_test123", + memory: 2048, + vcpus: 1, + region: "us-east-1", + runtime: "node24", + timeout: 300000, + status: "running", + requestedAt: 1700000000000, + startedAt: 1700000001000, + createdAt: 1700000000000, + cwd: "/vercel/sandbox", + updatedAt: 1700000002000, + networkPolicy: "allow-all", + }, + routes: mockRoutes, + }; + + const deserialized = FreshSandbox[WORKFLOW_DESERIALIZE]( + serializedData, + ) as Sandbox; + + expect(deserialized.sandboxId).toBe("sbx_test123"); + expect(deserialized.status).toBe("running"); + expect(deserialized.routes).toEqual(mockRoutes); + }); + + it("still requires global credentials when API client is actually accessed", async () => { + vi.resetModules(); + const { Sandbox: FreshSandbox } = await import("./sandbox"); + + const serializedData: SerializedSandbox = { + metadata: { + id: "sbx_test123", + memory: 2048, + vcpus: 1, + region: "us-east-1", + runtime: "node24", + timeout: 300000, + status: "running", + requestedAt: 1700000000000, + startedAt: 1700000001000, + createdAt: 1700000000000, + cwd: "/vercel/sandbox", + updatedAt: 1700000002000, + networkPolicy: "allow-all", + }, + routes: mockRoutes, + }; + + const deserialized = FreshSandbox[WORKFLOW_DESERIALIZE]( + serializedData, + ) as Sandbox; + + expect(() => deserialized.client).toThrowError( + /Global credentials have not been set/, + ); + }); + }); + + describe("workflow runtime integration", () => { + it("survives a step boundary roundtrip", async () => { + registerSerializationClass("Sandbox", Sandbox); + + const sandbox = createMockSandbox(); + + const dehydrated = await dehydrateStepReturnValue( + sandbox, + "run_123", + undefined, + ); + const rehydrated = await hydrateStepReturnValue( + dehydrated, + "run_123", + undefined, + ); + + expect(rehydrated).toBeInstanceOf(Sandbox); + expect(rehydrated.sandboxId).toBe("sbx_test123"); + expect(rehydrated.routes).toEqual(mockRoutes); + }); + + it("preserves converted metadata through runtime pipeline", async () => { + registerSerializationClass("Sandbox", Sandbox); + + const sandbox = createMockSandbox(); + + const dehydrated = await dehydrateStepReturnValue( + sandbox, + "run_456", + undefined, + ); + const rehydrated = await hydrateStepReturnValue( + dehydrated, + "run_456", + undefined, + ); + + expect(rehydrated.status).toBe("running"); + expect(rehydrated.networkPolicy).toBe("allow-all"); + }); + }); +}); diff --git a/packages/vercel-sandbox/src/sandbox.ts b/packages/vercel-sandbox/src/sandbox.ts index c93c96a..1f7cdd0 100644 --- a/packages/vercel-sandbox/src/sandbox.ts +++ b/packages/vercel-sandbox/src/sandbox.ts @@ -12,12 +12,20 @@ import { WithFetchOptions } from "./api-client/api-client"; import { RUNTIMES } from "./constants"; import { Snapshot } from "./snapshot"; import { consumeReadable } from "./utils/consume-readable"; +import { + setSandboxCredentials, + getSandboxCredentials, +} from "./utils/sandbox-credentials"; import { type NetworkPolicy, type NetworkPolicyRule, type NetworkTransformer, } from "./network-policy"; -import { convertSandbox, type ConvertedSandbox } from "./utils/convert-sandbox"; +import { + toSandboxSnapshot, + type SandboxSnapshot, +} from "./utils/sandbox-snapshot"; +import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from "@workflow/serde"; export type { NetworkPolicy, NetworkPolicyRule, NetworkTransformer }; @@ -115,6 +123,14 @@ interface GetSandboxParams { signal?: AbortSignal; } +/** + * Serialized representation of a Sandbox for @workflow/serde. + */ +export interface SerializedSandbox { + metadata: SandboxSnapshot; + routes: SandboxRouteData[]; +} + /** @inline */ interface RunCommandParams { /** @@ -155,6 +171,13 @@ interface RunCommandParams { signal?: AbortSignal; } +// Re-export for public API +export { setSandboxCredentials } from "./utils/sandbox-credentials"; + +// ============================================================================ +// Sandbox class +// ============================================================================ + /** * A Sandbox is an isolated Linux MicroVM to run commands in. * @@ -162,7 +185,22 @@ interface RunCommandParams { * @hideconstructor */ export class Sandbox { - private readonly client: APIClient; + private _client: APIClient | null = null; + + /** + * Lazily get or create the API client. + * If no client was provided during construction, creates one using global credentials. + */ + get client(): APIClient { + if (!this._client) { + const credentials = getSandboxCredentials(); + this._client = new APIClient({ + teamId: credentials.teamId, + token: credentials.token, + }); + } + return this._client; + } /** * Routes from ports to subdomains. @@ -226,14 +264,40 @@ export class Sandbox { /** * The amount of network data used by the sandbox. Only reported once the VM is stopped. */ - public get networkTransfer(): {ingress: number, egress: number} | undefined { + public get networkTransfer(): + | { ingress: number; egress: number } + | undefined { return this.sandbox.networkTransfer; } /** * Internal metadata about this sandbox. */ - private sandbox: ConvertedSandbox; + private sandbox: SandboxSnapshot; + + /** + * Set global credentials for Sandbox and Command instances. + * These credentials are used when lazily creating API clients for deserialized instances. + * + * If not called, deserialized instances will use OIDC authentication by default. + * + * @param credentials - The credentials to use globally + * + * @example + * // Set credentials once at application startup + * Sandbox.setCredentials({ + * teamId: 'team_xxx', + * token: 'token_xxx', + * projectId: 'prj_xxx' + * }); + * + * // Now deserialized sandboxes can make API calls + * const sandbox = Sandbox[WORKFLOW_DESERIALIZE](serializedData); + * await sandbox.runCommand('echo', ['hello']); + */ + static setCredentials(credentials: Credentials): void { + setSandboxCredentials(credentials); + } /** * Allow to get a list of sandboxes for a team narrowed to the given params. @@ -257,6 +321,35 @@ export class Sandbox { }); } + /** + * Serialize a Sandbox instance to plain data for @workflow/serde. + * + * @param instance - The Sandbox instance to serialize + * @returns A plain object containing sandbox metadata and routes + */ + static [WORKFLOW_SERIALIZE](instance: Sandbox): SerializedSandbox { + return { + metadata: instance.sandbox, + routes: instance.routes, + }; + } + + /** + * Deserialize a Sandbox from serialized snapshot data. + * + * The deserialized instance uses the serialized metadata synchronously and + * lazily creates an API client only when methods perform API requests. + * + * @param data - The serialized sandbox data + * @returns The reconstructed Sandbox instance + */ + static [WORKFLOW_DESERIALIZE](data: SerializedSandbox): Sandbox { + return new Sandbox({ + sandbox: data.metadata, + routes: data.routes, + }); + } + /** * Create a new sandbox. * @@ -298,7 +391,7 @@ export class Sandbox { return new DisposableSandbox({ client, - sandbox: sandbox.json.sandbox, + sandbox: toSandboxSnapshot(sandbox.json.sandbox), routes: sandbox.json.routes, }); } @@ -329,23 +422,30 @@ export class Sandbox { return new Sandbox({ client, - sandbox: sandbox.json.sandbox, + sandbox: toSandboxSnapshot(sandbox.json.sandbox), routes: sandbox.json.routes, }); } + /** + * Create a new Sandbox instance. + * + * @param params.client - Optional API client. If not provided, will be lazily created using global credentials. + * @param params.routes - Port-to-subdomain mappings for exposed ports + * @param params.sandbox - Sandbox snapshot metadata + */ constructor({ client, routes, sandbox, }: { - client: APIClient; + client?: APIClient; routes: SandboxRouteData[]; - sandbox: SandboxMetaData; + sandbox: SandboxSnapshot; }) { - this.client = client; + this._client = client ?? null; this.routes = routes; - this.sandbox = convertSandbox(sandbox); + this.sandbox = sandbox; } /** @@ -411,19 +511,11 @@ export class Sandbox { args?: string[], opts?: { signal?: AbortSignal }, ): Promise { - return typeof commandOrParams === "string" - ? this._runCommand({ cmd: commandOrParams, args, signal: opts?.signal }) - : this._runCommand(commandOrParams); - } + const params: RunCommandParams = + typeof commandOrParams === "string" + ? { cmd: commandOrParams, args, signal: opts?.signal } + : commandOrParams; - /** - * Internal helper to start a command in the sandbox. - * - * @param params - Command execution parameters. - * @returns A {@link Command} or {@link CommandFinished}, depending on `detached`. - * @internal - */ - async _runCommand(params: RunCommandParams) { const wait = params.detached ? false : true; const getLogs = (command: Command) => { if (params.stdout || params.stderr) { @@ -444,7 +536,7 @@ export class Sandbox { } })(); } - } + }; if (wait) { const commandStream = await this.client.runCommand({ @@ -464,7 +556,7 @@ export class Sandbox { cmd: commandStream.command, }); - getLogs(command); + getLogs(command); const finished = await commandStream.finished; return new CommandFinished({ @@ -601,7 +693,7 @@ export class Sandbox { }); return dstPath; } finally { - stream.destroy() + stream.destroy(); } } @@ -652,13 +744,16 @@ export class Sandbox { * @param opts.blocking - If true, poll until the sandbox has fully stopped and return the final state. * @returns The sandbox metadata at the time the stop was acknowledged, or after fully stopped if `blocking` is true. */ - async stop(opts?: { signal?: AbortSignal; blocking?: boolean }): Promise { + async stop(opts?: { + signal?: AbortSignal; + blocking?: boolean; + }): Promise { const response = await this.client.stopSandbox({ sandboxId: this.sandbox.id, signal: opts?.signal, blocking: opts?.blocking, }); - this.sandbox = convertSandbox(response.json.sandbox); + this.sandbox = toSandboxSnapshot(response.json.sandbox); return this.sandbox; } @@ -704,7 +799,7 @@ export class Sandbox { }); // Update the internal sandbox metadata with the new timeout value - this.sandbox = convertSandbox(response.json.sandbox); + this.sandbox = toSandboxSnapshot(response.json.sandbox); return this.sandbox.networkPolicy!; } @@ -735,7 +830,7 @@ export class Sandbox { }); // Update the internal sandbox metadata with the new timeout value - this.sandbox = convertSandbox(response.json.sandbox); + this.sandbox = toSandboxSnapshot(response.json.sandbox); } /** @@ -759,7 +854,7 @@ export class Sandbox { signal: opts?.signal, }); - this.sandbox = convertSandbox(response.json.sandbox); + this.sandbox = toSandboxSnapshot(response.json.sandbox); return new Snapshot({ client: this.client, diff --git a/packages/vercel-sandbox/src/utils/sandbox-credentials.ts b/packages/vercel-sandbox/src/utils/sandbox-credentials.ts new file mode 100644 index 0000000..e7e7674 --- /dev/null +++ b/packages/vercel-sandbox/src/utils/sandbox-credentials.ts @@ -0,0 +1,38 @@ +import pico from "picocolors"; +import type { Credentials } from "./get-credentials"; + +let sandboxCredentials: Credentials | null = null; + +/** + * Set global credentials for Sandbox and Command instances. + * These credentials are used when lazily creating API clients for deserialized instances. + * + * Must be called in the module scope before using deserialized + * Sandbox or Command instances. + * + * @param credentials - The credentials to use globally + */ +export function setSandboxCredentials(credentials: Credentials): void { + sandboxCredentials = credentials; +} + +/** + * Get the global credentials. + * Throws if {@link setSandboxCredentials} has not been called. + * @internal + */ +export function getSandboxCredentials(): Credentials { + if (!sandboxCredentials) { + throw new Error( + [ + `Global credentials have not been set.`, + `${pico.bold("hint:")} Call setSandboxCredentials() in the module scope before using deserialized instances.`, + "├▶ Docs: https://vercel.com/docs/vercel-sandbox", + "╰▶ Example:", + " import { setSandboxCredentials } from '@vercel/sandbox';", + " setSandboxCredentials({ token: process.env.VERCEL_TOKEN, teamId: process.env.VERCEL_TEAM_ID });", + ].join("\n"), + ); + } + return sandboxCredentials; +} diff --git a/packages/vercel-sandbox/src/utils/convert-sandbox.ts b/packages/vercel-sandbox/src/utils/sandbox-snapshot.ts similarity index 71% rename from packages/vercel-sandbox/src/utils/convert-sandbox.ts rename to packages/vercel-sandbox/src/utils/sandbox-snapshot.ts index 0996334..a438905 100644 --- a/packages/vercel-sandbox/src/utils/convert-sandbox.ts +++ b/packages/vercel-sandbox/src/utils/sandbox-snapshot.ts @@ -2,11 +2,11 @@ import type { SandboxMetaData } from "../api-client"; import type { NetworkPolicy } from "../network-policy"; import { fromAPINetworkPolicy } from "./network-policy"; -export type ConvertedSandbox = Omit & { +export type SandboxSnapshot = Omit & { networkPolicy?: NetworkPolicy; }; -export function convertSandbox(sandbox: SandboxMetaData): ConvertedSandbox { +export function toSandboxSnapshot(sandbox: SandboxMetaData): SandboxSnapshot { const { networkPolicy, ...rest } = sandbox; return { ...rest, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b28a858..634fa87 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,13 +164,13 @@ importers: dependencies: '@ai-sdk/gateway': specifier: 1.0.0-beta.4 - version: 1.0.0-beta.4(zod@4.1.5) + version: 1.0.0-beta.4(zod@4.3.6) '@vercel/sandbox': specifier: workspace:* version: link:../../packages/vercel-sandbox ai: specifier: 5.0.0-beta.12 - version: 5.0.0-beta.12(zod@4.1.5) + version: 5.0.0-beta.12(zod@4.3.6) devDependencies: '@types/node': specifier: ^20 @@ -337,6 +337,9 @@ importers: '@vercel/oidc': specifier: 3.2.0 version: 3.2.0 + '@workflow/serde': + specifier: 4.1.0-beta.2 + version: 4.1.0-beta.2 async-retry: specifier: 1.3.3 version: 1.3.3 @@ -377,6 +380,9 @@ importers: '@types/tar-stream': specifier: 3.1.4 version: 3.1.4 + '@workflow/core': + specifier: 4.1.0-beta.62 + version: 4.1.0-beta.62(@opentelemetry/api@1.9.0) dotenv: specifier: 16.5.0 version: 16.5.0 @@ -459,6 +465,83 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/core@3.973.15': + resolution: {integrity: sha512-AlC0oQ1/mdJ8vCIqu524j5RB7M8i8E24bbkZmya1CuiQxkY7SdIZAyw7NDNMGaNINQFq/8oGRMX0HeOfCVsl/A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.13': + resolution: {integrity: sha512-a6iFMh1pgUH0TdcouBppLJUfPM7Yd3R9S1xFodPtCRoLqCz2RQFA3qjA8x4112PVYXEd4/pHX2eihapq39w0rA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-host-header@3.972.6': + resolution: {integrity: sha512-5XHwjPH1lHB+1q4bfC7T8Z5zZrZXfaLcjSMwTd1HPSPrCmPFMbg3UQ5vgNWcVj0xoX4HWqTGkSf2byrjlnRg5w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-logger@3.972.6': + resolution: {integrity: sha512-iFnaMFMQdljAPrvsCVKYltPt2j40LQqukAbXvW7v0aL5I+1GO7bZ/W8m12WxW3gwyK5p5u1WlHg8TSAizC5cZw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.972.6': + resolution: {integrity: sha512-dY4v3of5EEMvik6+UDwQ96KfUFDk8m1oZDdkSc5lwi4o7rFrjnv0A+yTV+gu230iybQZnKgDLg/rt2P3H+Vscw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-user-agent@3.972.15': + resolution: {integrity: sha512-ABlFVcIMmuRAwBT+8q5abAxOr7WmaINirDJBnqGY5b5jSDo00UMlg/G4a0xoAgwm6oAECeJcwkvDlxDwKf58fQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/nested-clients@3.996.3': + resolution: {integrity: sha512-AU5TY1V29xqwg/MxmA2odwysTez+ccFAhmfRJk+QZT5HNv90UTA9qKd1J9THlsQkvmH7HWTEV1lDNxkQO5PzNw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/region-config-resolver@3.972.6': + resolution: {integrity: sha512-Aa5PusHLXAqLTX1UKDvI3pHQJtIsF7Q+3turCHqfz/1F61/zDMWfbTC8evjhrrYVAtz9Vsv3SJ/waSUeu7B6gw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.4': + resolution: {integrity: sha512-RW60aH26Bsc016Y9B98hC0Plx6fK5P2v/iQYwMzrSjiDh1qRMUCP6KrXHYEHe3uFvKiOC93Z9zk4BJsUi6Tj1Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-endpoints@3.996.3': + resolution: {integrity: sha512-yWIQSNiCjykLL+ezN5A+DfBb1gfXTytBxm57e64lYmwxDHNmInYHRJYYRAGWG1o77vKEiWaw4ui28e3yb1k5aQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.4': + resolution: {integrity: sha512-H1onv5SkgPBK2P6JR2MjGgbOnttoNzSPIRoeZTNPZYyaplwGg50zS3amXvXqF0/qfXpWEC9rLWU564QTB9bSog==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-user-agent-browser@3.972.6': + resolution: {integrity: sha512-Fwr/llD6GOrFgQnKaI2glhohdGuBDfHfora6iG9qsBBBR8xv1SdCSwbtf5CWlUdCw5X7g76G/9Hf0Inh0EmoxA==} + + '@aws-sdk/util-user-agent-node@3.973.0': + resolution: {integrity: sha512-A9J2G4Nf236e9GpaC1JnA8wRn6u6GjnOXiTwBLA6NUJhlBTIGfrTy+K1IazmF8y+4OFdW3O5TZlhyspJMqiqjA==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/xml-builder@3.972.8': + resolution: {integrity: sha512-Ql8elcUdYCha83Ol7NznBsgN5GVZnv3vUd86fEc6waU6oUdY0T1O9NODkEEOS/Uaogr87avDrUC6DSeM4oXjZg==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.3': + resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -492,6 +575,36 @@ packages: resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} + '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': + resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} + cpu: [arm64] + os: [darwin] + + '@cbor-extract/cbor-extract-darwin-x64@2.2.0': + resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} + cpu: [x64] + os: [darwin] + + '@cbor-extract/cbor-extract-linux-arm64@2.2.0': + resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} + cpu: [arm64] + os: [linux] + + '@cbor-extract/cbor-extract-linux-arm@2.2.0': + resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} + cpu: [arm] + os: [linux] + + '@cbor-extract/cbor-extract-linux-x64@2.2.0': + resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} + cpu: [x64] + os: [linux] + + '@cbor-extract/cbor-extract-win32-x64@2.2.0': + resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} + cpu: [x64] + os: [win32] + '@changesets/apply-release-plan@7.0.12': resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==} @@ -1332,6 +1445,178 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@smithy/abort-controller@4.2.10': + resolution: {integrity: sha512-qocxM/X4XGATqQtUkbE9SPUB6wekBi+FyJOMbPj0AhvyvFGYEmOlz6VB22iMePCQsFmMIvFSeViDvA7mZJG47g==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@4.4.9': + resolution: {integrity: sha512-ejQvXqlcU30h7liR9fXtj7PIAau1t/sFbJpgWPfiYDs7zd16jpH0IsSXKcba2jF6ChTXvIjACs27kNMc5xxE2Q==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.23.6': + resolution: {integrity: sha512-4xE+0L2NrsFKpEVFlFELkIHQddBvMbQ41LRIP74dGCXnY1zQ9DgksrBcRBDJT+iOzGy4VEJIeU3hkUK5mn06kg==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.2.10': + resolution: {integrity: sha512-3bsMLJJLTZGZqVGGeBVFfLzuRulVsGTj12BzRKODTHqUABpIr0jMN1vN3+u6r2OfyhAQ2pXaMZWX/swBK5I6PQ==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.3.11': + resolution: {integrity: sha512-wbTRjOxdFuyEg0CpumjZO0hkUl+fetJFqxNROepuLIoijQh51aMBmzFLfoQdwRjxsuuS2jizzIUTjPWgd8pd7g==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.2.10': + resolution: {integrity: sha512-1VzIOI5CcsvMDvP3iv1vG/RfLJVVVc67dCRyLSB2Hn9SWCZrDO3zvcIzj3BfEtqRW5kcMg5KAeVf1K3dR6nD3w==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.2.10': + resolution: {integrity: sha512-vy9KPNSFUU0ajFYk0sDZIYiUlAWGEAhRfehIr5ZkdFrRFTAuXEPUd41USuqHU6vvLX4r6Q9X7MKBco5+Il0Org==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.2.1': + resolution: {integrity: sha512-Yfu664Qbf1B4IYIsYgKoABt010daZjkaCRvdU/sPnZG6TtHOB0md0RjNdLGzxe5UIdn9js4ftPICzmkRa9RJ4Q==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.2.10': + resolution: {integrity: sha512-TQZ9kX5c6XbjhaEBpvhSvMEZ0klBs1CFtOdPFwATZSbC9UeQfKHPLPN9Y+I6wZGMOavlYTOlHEPDrt42PMSH9w==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.4.20': + resolution: {integrity: sha512-9W6Np4ceBP3XCYAGLoMCmn8t2RRVzuD1ndWPLBbv7H9CrwM9Bprf6Up6BM9ZA/3alodg0b7Kf6ftBK9R1N04vw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.4.37': + resolution: {integrity: sha512-/1psZZllBBSQ7+qo5+hhLz7AEPGLx3Z0+e3ramMBEuPK2PfvLK4SrncDB9VegX5mBn+oP/UTDrM6IHrFjvX1ZA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.11': + resolution: {integrity: sha512-STQdONGPwbbC7cusL60s7vOa6He6A9w2jWhoapL0mgVjmR19pr26slV+yoSP76SIssMTX/95e5nOZ6UQv6jolg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.2.10': + resolution: {integrity: sha512-pmts/WovNcE/tlyHa8z/groPeOtqtEpp61q3W0nW1nDJuMq/x+hWa/OVQBtgU0tBqupeXq0VBOLA4UZwE8I0YA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.3.10': + resolution: {integrity: sha512-UALRbJtVX34AdP2VECKVlnNgidLHA2A7YgcJzwSBg1hzmnO/bZBHl/LDQQyYifzUwp1UOODnl9JJ3KNawpUJ9w==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.4.12': + resolution: {integrity: sha512-zo1+WKJkR9x7ZtMeMDAAsq2PufwiLDmkhcjpWPRRkmeIuOm6nq1qjFICSZbnjBvD09ei8KMo26BWxsu2BUU+5w==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.10': + resolution: {integrity: sha512-5jm60P0CU7tom0eNrZ7YrkgBaoLFXzmqB0wVS+4uK8PPGmosSrLNf6rRd50UBvukztawZ7zyA8TxlrKpF5z9jw==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.3.10': + resolution: {integrity: sha512-2NzVWpYY0tRdfeCJLsgrR89KE3NTWT2wGulhNUxYlRmtRmPwLQwKzhrfVaiNlA9ZpJvbW7cjTVChYKgnkqXj1A==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.2.10': + resolution: {integrity: sha512-HeN7kEvuzO2DmAzLukE9UryiUvejD3tMp9a1D1NJETerIfKobBUCLfviP6QEk500166eD2IATaXM59qgUI+YDA==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.2.10': + resolution: {integrity: sha512-4Mh18J26+ao1oX5wXJfWlTT+Q1OpDR8ssiC9PDOuEgVBGloqg18Fw7h5Ct8DyT9NBYwJgtJ2nLjKKFU6RP1G1Q==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.2.10': + resolution: {integrity: sha512-0R/+/Il5y8nB/By90o8hy/bWVYptbIfvoTYad0igYQO5RefhNCDmNzqxaMx7K1t/QWo0d6UynqpqN5cCQt1MCg==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.4.5': + resolution: {integrity: sha512-pHgASxl50rrtOztgQCPmOXFjRW+mCd7ALr/3uXNzRrRoGV5G2+78GOsQ3HlQuBVHCh9o6xqMNvlIKZjWn4Euug==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.10': + resolution: {integrity: sha512-Wab3wW8468WqTKIxI+aZe3JYO52/RYT/8sDOdzkUhjnLakLe9qoQqIcfih/qxcF4qWEFoWBszY0mj5uxffaVXA==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.12.0': + resolution: {integrity: sha512-R8bQ9K3lCcXyZmBnQqUZJF4ChZmtWT5NLi6x5kgWx5D+/j0KorXcA0YcFg/X5TOgnTCy1tbKc6z2g2y4amFupQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.13.0': + resolution: {integrity: sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.10': + resolution: {integrity: sha512-uypjF7fCDsRk26u3qHmFI/ePL7bxxB9vKkE+2WKEciHhz+4QtbzWiHRVNRJwU3cKhrYDYQE3b0MRFtqfLYdA4A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.3.1': + resolution: {integrity: sha512-BKGuawX4Doq/bI/uEmg+Zyc36rJKWuin3py89PquXBIBqmbnJwBBsmKhdHfNEp0+A4TDgLmT/3MSKZ1SxHcR6w==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.2.1': + resolution: {integrity: sha512-SiJeLiozrAoCrgDBUgsVbmqHmMgg/2bA15AzcbcW+zan7SuyAVHN4xTSbq0GlebAIwlcaX32xacnrG488/J/6g==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.2.2': + resolution: {integrity: sha512-4rHqBvxtJEBvsZcFQSPQqXP2b/yy/YlB66KlcEgcH2WNoOKCKB03DSLzXmOsXjbl8dJ4OEYTn31knhdznwk7zw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.1': + resolution: {integrity: sha512-/swhmt1qTiVkaejlmMPPDgZhEaWb/HWMGRBheaxwuVkusp/z+ErJyQxO6kaXumOciZSWlmq6Z5mNylCd33X7Ig==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.2.1': + resolution: {integrity: sha512-462id/00U8JWFw6qBuTSWfN5TxOHvDu4WliI97qOIOnuC/g+NDAknTU8eoGXEPlLkRVgWEr03jJBLV4o2FL8+A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.3.36': + resolution: {integrity: sha512-R0smq7EHQXRVMxkAxtH5akJ/FvgAmNF6bUy/GwY/N20T4GrwjT633NFm0VuRpC+8Bbv8R9A0DoJ9OiZL/M3xew==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.2.39': + resolution: {integrity: sha512-otWuoDm35btJV1L8MyHrPl462B07QCdMTktKc7/yM+Psv6KbED/ziXiHnmr7yPHUjfIwE9S8Max0LO24Mo3ZVg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.3.1': + resolution: {integrity: sha512-xyctc4klmjmieQiF9I1wssBWleRV0RhJ2DpO8+8yzi2LO1Z+4IWOZNGZGNj4+hq9kdo+nyfrRLmQTzc16Op2Vg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.1': + resolution: {integrity: sha512-c1hHtkgAWmE35/50gmdKajgGAKV3ePJ7t6UtEmpfCWJmQE9BQAQPz0URUVI89eSkcDqCtzqllxzG28IQoZPvwA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.10': + resolution: {integrity: sha512-LxaQIWLp4y0r72eA8mwPNQ9va4h5KeLM0I3M/HV9klmFaY2kN766wf5vsTzmaOpNNb7GgXAd9a25P3h8T49PSA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.2.10': + resolution: {integrity: sha512-HrBzistfpyE5uqTwiyLsFHscgnwB0kgv8vySp7q5kZ0Eltn/tjosaSGGDj/jJ9ys7pWzIP/icE2d+7vMKXLv7A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.15': + resolution: {integrity: sha512-OlOKnaqnkU9X+6wEkd7mN+WB7orPbCVDauXOj22Q7VtiTkvy7ZdSsOg4QiNAZMgI4OkvNf+/VLUC3VXkxuWJZw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.2.1': + resolution: {integrity: sha512-YmiUDn2eo2IOiWYYvGQkgX5ZkBSiTQu4FlDo5jNPpAxng2t6Sjb6WutnZV9l6VR4eJul1ABmCrnWBC9hKHQa6Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.1': + resolution: {integrity: sha512-DSIwNaWtmzrNQHv8g7DBGR9mulSit65KSj5ymGEIAknmIN8IpbZefEep10LaMG/P/xquwbmJ1h9ectz8z6mV6g==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.1.1': + resolution: {integrity: sha512-dSfDCeihDmZlV2oyr0yWPTUfh07suS+R5OB+FZGiv/hHyK3hrFBW5rR1UYjfa57vBsrP9lciFkRPzebaV1Qujw==} + engines: {node: '>=18.0.0'} + '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -1542,10 +1827,23 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vercel/functions@3.4.3': + resolution: {integrity: sha512-kA14KIUVgAY6VXbhZ5jjY+s0883cV3cZqIU3WhrSRxuJ9KvxatMjtmzl0K23HK59oOUjYl7HaE/eYMmhmqpZzw==} + engines: {node: '>= 20'} + peerDependencies: + '@aws-sdk/credential-provider-web-identity': '*' + peerDependenciesMeta: + '@aws-sdk/credential-provider-web-identity': + optional: true + '@vercel/oidc@3.2.0': resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} + '@vercel/queue@0.1.1': + resolution: {integrity: sha512-ozO0tSBXUYN4gUkK65GbcqgxpC55qaaiY9MzNuXW4cvOSJ5nCkcgO+DQXcfyfL7h+0uIC5HTcP0mPvQ3dW3EhQ==} + engines: {node: '>=20.0.0'} + '@vitest/expect@3.2.1': resolution: {integrity: sha512-FqS/BnDOzV6+IpxrTg5GQRyLOCtcJqkwMwcS8qGCI2IyRVDwPAtutztaf1CjtPHlZlWtl1yUPCd7HM0cNiDOYw==} @@ -1578,6 +1876,44 @@ packages: '@vitest/utils@3.2.1': resolution: {integrity: sha512-KkHlGhePEKZSub5ViknBcN5KEF+u7dSUr9NW8QsVICusUojrgrOnnY3DEWWO877ax2Pyopuk2qHmt+gkNKnBVw==} + '@workflow/core@4.1.0-beta.62': + resolution: {integrity: sha512-ovq908bMRCcy81DUCQwp6MCMczEdhxxOW7Z3nnNQZ13yOsYa5wzJuH2+Y4GtfSr0jbeDr/t472X6aumnVCDRIg==} + peerDependencies: + '@opentelemetry/api': '1' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@workflow/errors@4.1.0-beta.17': + resolution: {integrity: sha512-ctDx9PrTCAkfsGqs6PgYAMGSaOmHESTMJEdj+d+RU0qEDfXWBZmM586hkf9hXw3jwXnw0VMp9X01jLsnWPyZcA==} + + '@workflow/serde@4.1.0-beta.2': + resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} + + '@workflow/utils@4.1.0-beta.13': + resolution: {integrity: sha512-3vVuXZVfLVeJ78MM6D0gNXg6hMZdDYAzmF92p+HxItI0B2Yk1EuDIIUfBXKWwTOKCCuKF4iroZt2u9BFqrs2AQ==} + + '@workflow/world-local@4.1.0-beta.36': + resolution: {integrity: sha512-eOavTINKlpepB4MJyQr0RoUVRnFZM3nP4T+AUMrRjm9qhZvZB5g5TgHBfkrOzdqqOHtuj7dfOccNc76hywZ5Fw==} + peerDependencies: + '@opentelemetry/api': '1' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@workflow/world-vercel@4.1.0-beta.36': + resolution: {integrity: sha512-YF22Kg2tnyyFFEh+3BsvQWmbni/wtJQTwH/OQRenNuY155L1EvnMjDdqxKthuWpK2iL3i768TOB7x+EqE3spZA==} + peerDependencies: + '@opentelemetry/api': '1' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@workflow/world@4.1.0-beta.8': + resolution: {integrity: sha512-zzN0cGqjg0fBI0vlufEW8wz/Rl1vJyGKpy8KQSYAqjBEaHCqey6+2/YPZyQzFR0X2jqxcc45yHw8e3qHjsG1+A==} + peerDependencies: + zod: 4.3.6 + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -1687,6 +2023,9 @@ packages: async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + b4a@1.6.7: resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} @@ -1706,6 +2045,9 @@ packages: birpc@2.8.0: resolution: {integrity: sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw==} + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1743,6 +2085,13 @@ packages: caniuse-lite@1.0.30001739: resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==} + cbor-extract@2.2.0: + resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} + hasBin: true + + cbor-x@1.6.0: + resolution: {integrity: sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1964,6 +2313,9 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + devalue@5.6.3: + resolution: {integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2102,6 +2454,10 @@ packages: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} + fast-xml-parser@5.3.6: + resolution: {integrity: sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==} + hasBin: true + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -2810,6 +3166,10 @@ packages: resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} engines: {node: '>= 18'} + mixpart@0.0.5: + resolution: {integrity: sha512-TpWi9/2UIr7VWCVAM7NB4WR4yOglAetBkuKfxs3K0vFcUukqAaW1xsgX0v1gNGiDKzYhPHFcHgarC7jmnaOy4w==} + engines: {node: '>=20.0.0'} + mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} @@ -2827,6 +3187,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@5.1.6: + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + engines: {node: ^18 || >=20} + hasBin: true + next@15.3.6: resolution: {integrity: sha512-oI6D1zbbsh6JzzZFDCSHnnx6Qpvd1fSkVJu/5d8uluqnxzuoqtodVZjYvNovooznUq8udSAiKp7MbwlfZ8Gm6w==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} @@ -2861,6 +3226,10 @@ packages: encoding: optional: true + node-gyp-build-optional-packages@5.1.1: + resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} + hasBin: true + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -3235,6 +3604,9 @@ packages: scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + seedrandom@3.0.5: + resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} @@ -3404,6 +3776,9 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strnum@2.2.0: + resolution: {integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==} + style-to-js@1.1.17: resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==} @@ -3632,6 +4007,10 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + ulid@3.0.1: + resolution: {integrity: sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q==} + hasBin: true + unconfig-core@7.4.1: resolution: {integrity: sha512-Bp/bPZjV2Vl/fofoA2OYLSnw1Z0MOhCX7zHnVCYrazpfZvseBbGhwcNQMxsg185Mqh7VZQqK3C8hFG/Dyng+yA==} @@ -3645,6 +4024,10 @@ packages: resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} engines: {node: '>=20.18.1'} + undici@7.22.0: + resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + engines: {node: '>=20.18.1'} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -3859,6 +4242,9 @@ packages: zod@4.1.5: resolution: {integrity: sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -3870,11 +4256,11 @@ snapshots: '@ai-sdk/provider-utils': 3.0.0-beta.1(zod@3.25.67) zod: 3.25.67 - '@ai-sdk/gateway@1.0.0-beta.4(zod@4.1.5)': + '@ai-sdk/gateway@1.0.0-beta.4(zod@4.3.6)': dependencies: '@ai-sdk/provider': 2.0.0-beta.1 - '@ai-sdk/provider-utils': 3.0.0-beta.2(zod@4.1.5) - zod: 4.1.5 + '@ai-sdk/provider-utils': 3.0.0-beta.2(zod@4.3.6) + zod: 4.3.6 '@ai-sdk/openai-compatible@1.0.0-alpha.7(zod@3.25.67)': dependencies: @@ -3897,13 +4283,13 @@ snapshots: zod: 3.25.67 zod-to-json-schema: 3.24.6(zod@3.25.67) - '@ai-sdk/provider-utils@3.0.0-beta.2(zod@4.1.5)': + '@ai-sdk/provider-utils@3.0.0-beta.2(zod@4.3.6)': dependencies: '@ai-sdk/provider': 2.0.0-beta.1 '@standard-schema/spec': 1.0.0 eventsource-parser: 3.0.6 - zod: 4.1.5 - zod-to-json-schema: 3.24.6(zod@4.1.5) + zod: 4.3.6 + zod-to-json-schema: 3.24.6(zod@4.3.6) '@ai-sdk/provider@2.0.0-alpha.7': dependencies: @@ -3932,6 +4318,182 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.4 + '@aws-sdk/util-locate-window': 3.965.4 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.4 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.4 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.973.15': + dependencies: + '@aws-sdk/types': 3.973.4 + '@aws-sdk/xml-builder': 3.972.8 + '@smithy/core': 3.23.6 + '@smithy/node-config-provider': 4.3.10 + '@smithy/property-provider': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/signature-v4': 5.3.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.13': + dependencies: + '@aws-sdk/core': 3.973.15 + '@aws-sdk/nested-clients': 3.996.3 + '@aws-sdk/types': 3.973.4 + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/middleware-host-header@3.972.6': + dependencies: + '@aws-sdk/types': 3.973.4 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.972.6': + dependencies: + '@aws-sdk/types': 3.973.4 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.972.6': + dependencies: + '@aws-sdk/types': 3.973.4 + '@aws/lambda-invoke-store': 0.2.3 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.972.15': + dependencies: + '@aws-sdk/core': 3.973.15 + '@aws-sdk/types': 3.973.4 + '@aws-sdk/util-endpoints': 3.996.3 + '@smithy/core': 3.23.6 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.996.3': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.15 + '@aws-sdk/middleware-host-header': 3.972.6 + '@aws-sdk/middleware-logger': 3.972.6 + '@aws-sdk/middleware-recursion-detection': 3.972.6 + '@aws-sdk/middleware-user-agent': 3.972.15 + '@aws-sdk/region-config-resolver': 3.972.6 + '@aws-sdk/types': 3.973.4 + '@aws-sdk/util-endpoints': 3.996.3 + '@aws-sdk/util-user-agent-browser': 3.972.6 + '@aws-sdk/util-user-agent-node': 3.973.0 + '@smithy/config-resolver': 4.4.9 + '@smithy/core': 3.23.6 + '@smithy/fetch-http-handler': 5.3.11 + '@smithy/hash-node': 4.2.10 + '@smithy/invalid-dependency': 4.2.10 + '@smithy/middleware-content-length': 4.2.10 + '@smithy/middleware-endpoint': 4.4.20 + '@smithy/middleware-retry': 4.4.37 + '@smithy/middleware-serde': 4.2.11 + '@smithy/middleware-stack': 4.2.10 + '@smithy/node-config-provider': 4.3.10 + '@smithy/node-http-handler': 4.4.12 + '@smithy/protocol-http': 5.3.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + '@smithy/util-base64': 4.3.1 + '@smithy/util-body-length-browser': 4.2.1 + '@smithy/util-body-length-node': 4.2.2 + '@smithy/util-defaults-mode-browser': 4.3.36 + '@smithy/util-defaults-mode-node': 4.2.39 + '@smithy/util-endpoints': 3.3.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-retry': 4.2.10 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.972.6': + dependencies: + '@aws-sdk/types': 3.973.4 + '@smithy/config-resolver': 4.4.9 + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.4': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.996.3': + dependencies: + '@aws-sdk/types': 3.973.4 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + '@smithy/util-endpoints': 3.3.1 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.4': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.972.6': + dependencies: + '@aws-sdk/types': 3.973.4 + '@smithy/types': 4.13.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.973.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.15 + '@aws-sdk/types': 3.973.4 + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.8': + dependencies: + '@smithy/types': 4.13.0 + fast-xml-parser: 5.3.6 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.3': {} + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -3963,6 +4525,24 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-darwin-x64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-linux-arm64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-linux-arm@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-linux-x64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-win32-x64@2.2.0': + optional: true + '@changesets/apply-release-plan@7.0.12': dependencies: '@changesets/config': 3.1.1 @@ -4642,6 +5222,280 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} + '@smithy/abort-controller@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/config-resolver@4.4.9': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-config-provider': 4.2.1 + '@smithy/util-endpoints': 3.3.1 + '@smithy/util-middleware': 4.2.10 + tslib: 2.8.1 + + '@smithy/core@3.23.6': + dependencies: + '@smithy/middleware-serde': 4.2.11 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + '@smithy/util-body-length-browser': 4.2.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-stream': 4.5.15 + '@smithy/util-utf8': 4.2.1 + '@smithy/uuid': 1.1.1 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.2.10': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/property-provider': 4.2.10 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.3.11': + dependencies: + '@smithy/protocol-http': 5.3.10 + '@smithy/querystring-builder': 4.2.10 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + tslib: 2.8.1 + + '@smithy/hash-node@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + '@smithy/util-buffer-from': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.2.10': + dependencies: + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.4.20': + dependencies: + '@smithy/core': 3.23.6 + '@smithy/middleware-serde': 4.2.11 + '@smithy/node-config-provider': 4.3.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + '@smithy/util-middleware': 4.2.10 + tslib: 2.8.1 + + '@smithy/middleware-retry@4.4.37': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/service-error-classification': 4.2.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-retry': 4.2.10 + '@smithy/uuid': 1.1.1 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.2.11': + dependencies: + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.3.10': + dependencies: + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.4.12': + dependencies: + '@smithy/abort-controller': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/querystring-builder': 4.2.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.3.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + '@smithy/util-uri-escape': 4.2.1 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/service-error-classification@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + + '@smithy/shared-ini-file-loader@4.4.5': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.3.10': + dependencies: + '@smithy/is-array-buffer': 4.2.1 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-hex-encoding': 4.2.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-uri-escape': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/smithy-client@4.12.0': + dependencies: + '@smithy/core': 3.23.6 + '@smithy/middleware-endpoint': 4.4.20 + '@smithy/middleware-stack': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-stream': 4.5.15 + tslib: 2.8.1 + + '@smithy/types@4.13.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.2.10': + dependencies: + '@smithy/querystring-parser': 4.2.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.3.1': + dependencies: + '@smithy/util-buffer-from': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.2.1': + dependencies: + '@smithy/is-array-buffer': 4.2.1 + tslib: 2.8.1 + + '@smithy/util-config-provider@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@4.3.36': + dependencies: + '@smithy/property-provider': 4.2.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.2.39': + dependencies: + '@smithy/config-resolver': 4.4.9 + '@smithy/credential-provider-imds': 4.2.10 + '@smithy/node-config-provider': 4.3.10 + '@smithy/property-provider': 4.2.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-endpoints@3.3.1': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-retry@4.2.10': + dependencies: + '@smithy/service-error-classification': 4.2.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.5.15': + dependencies: + '@smithy/fetch-http-handler': 5.3.11 + '@smithy/node-http-handler': 4.4.12 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + '@smithy/util-buffer-from': 4.2.1 + '@smithy/util-hex-encoding': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/util-uri-escape@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.2.1': + dependencies: + '@smithy/util-buffer-from': 4.2.1 + tslib: 2.8.1 + + '@smithy/uuid@1.1.1': + dependencies: + tslib: 2.8.1 + '@standard-schema/spec@1.0.0': {} '@standard-schema/utils@0.3.0': {} @@ -4839,8 +5693,19 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@vercel/functions@3.4.3(@aws-sdk/credential-provider-web-identity@3.972.13)': + dependencies: + '@vercel/oidc': 3.2.0 + optionalDependencies: + '@aws-sdk/credential-provider-web-identity': 3.972.13 + '@vercel/oidc@3.2.0': {} + '@vercel/queue@0.1.1': + dependencies: + '@vercel/oidc': 3.2.0 + mixpart: 0.0.5 + '@vitest/expect@3.2.1': dependencies: '@types/chai': 5.2.2 @@ -4894,6 +5759,72 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 + '@workflow/core@4.1.0-beta.62(@opentelemetry/api@1.9.0)': + dependencies: + '@aws-sdk/credential-provider-web-identity': 3.972.13 + '@jridgewell/trace-mapping': 0.3.31 + '@standard-schema/spec': 1.0.0 + '@types/ms': 2.1.0 + '@vercel/functions': 3.4.3(@aws-sdk/credential-provider-web-identity@3.972.13) + '@workflow/errors': 4.1.0-beta.17 + '@workflow/serde': 4.1.0-beta.2 + '@workflow/utils': 4.1.0-beta.13 + '@workflow/world': 4.1.0-beta.8(zod@4.3.6) + '@workflow/world-local': 4.1.0-beta.36(@opentelemetry/api@1.9.0) + '@workflow/world-vercel': 4.1.0-beta.36(@opentelemetry/api@1.9.0) + debug: 4.4.3 + devalue: 5.6.3 + ms: 2.1.3 + nanoid: 5.1.6 + seedrandom: 3.0.5 + ulid: 3.0.1 + zod: 4.3.6 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + transitivePeerDependencies: + - aws-crt + - supports-color + + '@workflow/errors@4.1.0-beta.17': + dependencies: + '@workflow/utils': 4.1.0-beta.13 + ms: 2.1.3 + + '@workflow/serde@4.1.0-beta.2': {} + + '@workflow/utils@4.1.0-beta.13': + dependencies: + ms: 2.1.3 + + '@workflow/world-local@4.1.0-beta.36(@opentelemetry/api@1.9.0)': + dependencies: + '@vercel/queue': 0.1.1 + '@workflow/errors': 4.1.0-beta.17 + '@workflow/utils': 4.1.0-beta.13 + '@workflow/world': 4.1.0-beta.8(zod@4.3.6) + async-sema: 3.1.1 + ulid: 3.0.1 + undici: 7.22.0 + zod: 4.3.6 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + + '@workflow/world-vercel@4.1.0-beta.36(@opentelemetry/api@1.9.0)': + dependencies: + '@vercel/oidc': 3.2.0 + '@vercel/queue': 0.1.1 + '@workflow/errors': 4.1.0-beta.17 + '@workflow/world': 4.1.0-beta.8(zod@4.3.6) + cbor-x: 1.6.0 + undici: 7.22.0 + zod: 4.3.6 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + + '@workflow/world@4.1.0-beta.8(zod@4.3.6)': + dependencies: + zod: 4.3.6 + acorn-walk@8.3.4: dependencies: acorn: 8.15.0 @@ -4913,13 +5844,13 @@ snapshots: '@opentelemetry/api': 1.9.0 zod: 3.25.67 - ai@5.0.0-beta.12(zod@4.1.5): + ai@5.0.0-beta.12(zod@4.3.6): dependencies: - '@ai-sdk/gateway': 1.0.0-beta.4(zod@4.1.5) + '@ai-sdk/gateway': 1.0.0-beta.4(zod@4.3.6) '@ai-sdk/provider': 2.0.0-beta.1 - '@ai-sdk/provider-utils': 3.0.0-beta.2(zod@4.1.5) + '@ai-sdk/provider-utils': 3.0.0-beta.2(zod@4.3.6) '@opentelemetry/api': 1.9.0 - zod: 4.1.5 + zod: 4.3.6 ansi-colors@4.1.3: {} @@ -4974,6 +5905,8 @@ snapshots: dependencies: retry: 0.13.1 + async-sema@3.1.1: {} + b4a@1.6.7: {} bail@2.0.2: {} @@ -4989,6 +5922,8 @@ snapshots: birpc@2.8.0: {} + bowser@2.14.1: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -5024,6 +5959,22 @@ snapshots: caniuse-lite@1.0.30001739: {} + cbor-extract@2.2.0: + dependencies: + node-gyp-build-optional-packages: 5.1.1 + optionalDependencies: + '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 + '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 + '@cbor-extract/cbor-extract-linux-x64': 2.2.0 + '@cbor-extract/cbor-extract-win32-x64': 2.2.0 + optional: true + + cbor-x@1.6.0: + optionalDependencies: + cbor-extract: 2.2.0 + ccount@2.0.1: {} chai@5.3.3: @@ -5228,6 +6179,8 @@ snapshots: detect-libc@2.0.4: {} + devalue@5.6.3: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -5373,6 +6326,10 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-xml-parser@5.3.6: + dependencies: + strnum: 2.2.0 + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -6319,6 +7276,8 @@ snapshots: dependencies: minipass: 7.1.2 + mixpart@0.0.5: {} + mkdirp@3.0.1: {} mri@1.2.0: {} @@ -6327,6 +7286,8 @@ snapshots: nanoid@3.3.11: {} + nanoid@5.1.6: {} + next@15.3.6(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@next/env': 15.3.6 @@ -6359,6 +7320,11 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-gyp-build-optional-packages@5.1.1: + dependencies: + detect-libc: 2.0.4 + optional: true + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -6784,6 +7750,8 @@ snapshots: scheduler@0.26.0: {} + seedrandom@3.0.5: {} + semver-compare@1.0.0: {} semver@5.7.2: {} @@ -6959,6 +7927,8 @@ snapshots: strip-final-newline@2.0.0: {} + strnum@2.2.0: {} + style-to-js@1.1.17: dependencies: style-to-object: 1.0.9 @@ -7158,6 +8128,8 @@ snapshots: uc.micro@2.1.0: {} + ulid@3.0.1: {} + unconfig-core@7.4.1: dependencies: '@quansync/fs': 0.1.5 @@ -7169,6 +8141,8 @@ snapshots: undici@7.16.0: {} + undici@7.22.0: {} + unified@11.0.5: dependencies: '@types/unist': 3.0.3 @@ -7454,9 +8428,9 @@ snapshots: dependencies: zod: 3.25.67 - zod-to-json-schema@3.24.6(zod@4.1.5): + zod-to-json-schema@3.24.6(zod@4.3.6): dependencies: - zod: 4.1.5 + zod: 4.3.6 zod@3.24.4: {} @@ -7464,4 +8438,6 @@ snapshots: zod@4.1.5: {} + zod@4.3.6: {} + zwitch@2.0.4: {}