diff --git a/app/api/sandboxes/route.ts b/app/api/sandboxes/route.ts index 897848a2..eec0ab82 100644 --- a/app/api/sandboxes/route.ts +++ b/app/api/sandboxes/route.ts @@ -19,7 +19,7 @@ export async function OPTIONS() { /** * POST /api/sandboxes * - * Creates a new ephemeral sandbox environment. + * Creates a new ephemeral sandbox environment and executes a command. * Sandboxes are isolated Linux microVMs that can be used to evaluate * account-generated code, run AI agent output safely, or execute reproducible tasks. * The sandbox will automatically stop after the timeout period. @@ -27,11 +27,13 @@ export async function OPTIONS() { * Authentication: x-api-key header or Authorization Bearer token required. * * Request body: - * - prompt: string (required, min length 1) - The prompt to send to Claude Code + * - command: string (required) - The command to execute in the sandbox + * - args: string[] (optional) - Arguments to pass to the command + * - cwd: string (optional) - Working directory for command execution * * Response (200): * - status: "success" - * - sandboxes: [{ sandboxId, sandboxStatus, timeout, createdAt }] + * - sandboxes: [{ sandboxId, sandboxStatus, timeout, createdAt, runId }] * * Error (400/401): * - status: "error" diff --git a/lib/sandbox/__tests__/createSandbox.test.ts b/lib/sandbox/__tests__/createSandbox.test.ts index 6cc3eb06..7cbe4970 100644 --- a/lib/sandbox/__tests__/createSandbox.test.ts +++ b/lib/sandbox/__tests__/createSandbox.test.ts @@ -28,7 +28,7 @@ describe("createSandbox", () => { vi.clearAllMocks(); }); - it("creates sandbox with correct configuration", async () => { + it("creates sandbox with default configuration when no params provided", async () => { await createSandbox(); expect(Sandbox.create).toHaveBeenCalledWith({ @@ -38,6 +38,35 @@ describe("createSandbox", () => { }); }); + it("creates sandbox from snapshot when source is provided", async () => { + await createSandbox({ source: { type: "snapshot", snapshotId: "snap_abc123" } }); + + expect(Sandbox.create).toHaveBeenCalledWith({ + source: { type: "snapshot", snapshotId: "snap_abc123" }, + timeout: 600000, + }); + }); + + it("allows overriding default timeout", async () => { + await createSandbox({ timeout: 300000 }); + + expect(Sandbox.create).toHaveBeenCalledWith({ + resources: { vcpus: 4 }, + timeout: 300000, + runtime: "node22", + }); + }); + + it("allows overriding default resources", async () => { + await createSandbox({ resources: { vcpus: 2 } }); + + expect(Sandbox.create).toHaveBeenCalledWith({ + resources: { vcpus: 2 }, + timeout: 600000, + runtime: "node22", + }); + }); + it("returns sandbox created response with sandboxStatus", async () => { const result = await createSandbox(); diff --git a/lib/sandbox/__tests__/createSandboxPostHandler.test.ts b/lib/sandbox/__tests__/createSandboxPostHandler.test.ts index 28d49dab..c975b8eb 100644 --- a/lib/sandbox/__tests__/createSandboxPostHandler.test.ts +++ b/lib/sandbox/__tests__/createSandboxPostHandler.test.ts @@ -7,6 +7,7 @@ import { validateSandboxBody } from "@/lib/sandbox/validateSandboxBody"; import { createSandbox } from "@/lib/sandbox/createSandbox"; import { insertAccountSandbox } from "@/lib/supabase/account_sandboxes/insertAccountSandbox"; import { triggerRunSandboxCommand } from "@/lib/trigger/triggerRunSandboxCommand"; +import { selectAccountSnapshots } from "@/lib/supabase/account_snapshots/selectAccountSnapshots"; vi.mock("@/lib/sandbox/validateSandboxBody", () => ({ validateSandboxBody: vi.fn(), @@ -24,6 +25,10 @@ vi.mock("@/lib/trigger/triggerRunSandboxCommand", () => ({ triggerRunSandboxCommand: vi.fn(), })); +vi.mock("@/lib/supabase/account_snapshots/selectAccountSnapshots", () => ({ + selectAccountSnapshots: vi.fn(), +})); + /** * Creates a mock NextRequest for testing. * @@ -51,13 +56,14 @@ describe("createSandboxPostHandler", () => { expect(response.status).toBe(401); }); - it("returns 200 with sandboxes array on success", async () => { + it("returns 200 with sandboxes array including runId on success", async () => { vi.mocked(validateSandboxBody).mockResolvedValue({ accountId: "acc_123", orgId: null, authToken: "token", - prompt: "tell me hello", + command: "ls", }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([]); vi.mocked(createSandbox).mockResolvedValue({ sandboxId: "sbx_123", sandboxStatus: "running", @@ -73,6 +79,9 @@ describe("createSandboxPostHandler", () => { }, error: null, }); + vi.mocked(triggerRunSandboxCommand).mockResolvedValue({ + id: "run_abc123", + }); const request = createMockRequest(); const response = await createSandboxPostHandler(request); @@ -87,18 +96,27 @@ describe("createSandboxPostHandler", () => { sandboxStatus: "running", timeout: 600000, createdAt: "2024-01-01T00:00:00.000Z", + runId: "run_abc123", }, ], }); }); - it("calls createSandbox without arguments", async () => { + it("calls createSandbox with snapshotId when account has snapshot", async () => { vi.mocked(validateSandboxBody).mockResolvedValue({ accountId: "acc_123", orgId: null, authToken: "token", - prompt: "tell me hello", + command: "ls", }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([ + { + id: "snap_record_123", + account_id: "acc_123", + snapshot_id: "snap_xyz", + created_at: "2024-01-01T00:00:00.000Z", + }, + ]); vi.mocked(createSandbox).mockResolvedValue({ sandboxId: "sbx_456", sandboxStatus: "running", @@ -114,11 +132,47 @@ describe("createSandboxPostHandler", () => { }, error: null, }); + vi.mocked(triggerRunSandboxCommand).mockResolvedValue({ + id: "run_def456", + }); const request = createMockRequest(); await createSandboxPostHandler(request); - expect(createSandbox).toHaveBeenCalledWith(); + expect(createSandbox).toHaveBeenCalledWith({ source: { type: "snapshot", snapshotId: "snap_xyz" } }); + }); + + it("calls createSandbox with empty params when account has no snapshot", async () => { + vi.mocked(validateSandboxBody).mockResolvedValue({ + accountId: "acc_123", + orgId: null, + authToken: "token", + command: "ls", + }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([]); + vi.mocked(createSandbox).mockResolvedValue({ + sandboxId: "sbx_456", + sandboxStatus: "running", + timeout: 600000, + createdAt: "2024-01-01T00:00:00.000Z", + }); + vi.mocked(insertAccountSandbox).mockResolvedValue({ + data: { + id: "record_123", + account_id: "acc_123", + sandbox_id: "sbx_456", + created_at: "2024-01-01T00:00:00.000Z", + }, + error: null, + }); + vi.mocked(triggerRunSandboxCommand).mockResolvedValue({ + id: "run_def456", + }); + + const request = createMockRequest(); + await createSandboxPostHandler(request); + + expect(createSandbox).toHaveBeenCalledWith({}); }); it("calls insertAccountSandbox with correct account_id and sandbox_id", async () => { @@ -126,8 +180,9 @@ describe("createSandboxPostHandler", () => { accountId: "acc_123", orgId: null, authToken: "token", - prompt: "tell me hello", + command: "ls", }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([]); vi.mocked(createSandbox).mockResolvedValue({ sandboxId: "sbx_456", sandboxStatus: "running", @@ -143,6 +198,9 @@ describe("createSandboxPostHandler", () => { }, error: null, }); + vi.mocked(triggerRunSandboxCommand).mockResolvedValue({ + id: "run_def456", + }); const request = createMockRequest(); await createSandboxPostHandler(request); @@ -153,13 +211,16 @@ describe("createSandboxPostHandler", () => { }); }); - it("calls triggerRunSandboxCommand with prompt and sandboxId", async () => { + it("calls triggerRunSandboxCommand with command, args, cwd, sandboxId, and accountId", async () => { vi.mocked(validateSandboxBody).mockResolvedValue({ accountId: "acc_123", orgId: null, authToken: "token", - prompt: "tell me hello", + command: "ls", + args: ["-la"], + cwd: "/home", }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([]); vi.mocked(createSandbox).mockResolvedValue({ sandboxId: "sbx_789", sandboxStatus: "running", @@ -175,13 +236,19 @@ describe("createSandboxPostHandler", () => { }, error: null, }); + vi.mocked(triggerRunSandboxCommand).mockResolvedValue({ + id: "run_ghi789", + }); const request = createMockRequest(); await createSandboxPostHandler(request); expect(triggerRunSandboxCommand).toHaveBeenCalledWith({ - prompt: "tell me hello", + command: "ls", + args: ["-la"], + cwd: "/home", sandboxId: "sbx_789", + accountId: "acc_123", }); }); @@ -190,8 +257,9 @@ describe("createSandboxPostHandler", () => { accountId: "acc_123", orgId: null, authToken: "token", - prompt: "tell me hello", + command: "ls", }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([]); vi.mocked(createSandbox).mockRejectedValue(new Error("Sandbox creation failed")); const request = createMockRequest(); @@ -210,8 +278,9 @@ describe("createSandboxPostHandler", () => { accountId: "acc_123", orgId: null, authToken: "token", - prompt: "tell me hello", + command: "ls", }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([]); vi.mocked(createSandbox).mockResolvedValue({ sandboxId: "sbx_123", sandboxStatus: "running", @@ -231,13 +300,14 @@ describe("createSandboxPostHandler", () => { }); }); - it("returns 400 with error status when triggerRunSandboxCommand throws", async () => { + it("returns 200 without runId when triggerRunSandboxCommand throws", async () => { vi.mocked(validateSandboxBody).mockResolvedValue({ accountId: "acc_123", orgId: null, authToken: "token", - prompt: "tell me hello", + command: "ls", }); + vi.mocked(selectAccountSnapshots).mockResolvedValue([]); vi.mocked(createSandbox).mockResolvedValue({ sandboxId: "sbx_123", sandboxStatus: "running", @@ -258,11 +328,20 @@ describe("createSandboxPostHandler", () => { const request = createMockRequest(); const response = await createSandboxPostHandler(request); - expect(response.status).toBe(400); + // Sandbox was created successfully, so return 200 even if trigger fails + expect(response.status).toBe(200); const json = await response.json(); expect(json).toEqual({ - status: "error", - error: "Task trigger failed", + status: "success", + sandboxes: [ + { + sandboxId: "sbx_123", + sandboxStatus: "running", + timeout: 600000, + createdAt: "2024-01-01T00:00:00.000Z", + // Note: runId is not included when trigger fails + }, + ], }); }); }); diff --git a/lib/sandbox/__tests__/validateSandboxBody.test.ts b/lib/sandbox/__tests__/validateSandboxBody.test.ts index 3aa37cb1..5ac255ab 100644 --- a/lib/sandbox/__tests__/validateSandboxBody.test.ts +++ b/lib/sandbox/__tests__/validateSandboxBody.test.ts @@ -41,13 +41,13 @@ describe("validateSandboxBody", () => { expect((result as NextResponse).status).toBe(401); }); - it("returns validated body with auth context when prompt is provided", async () => { + it("returns validated body with auth context when command is provided", async () => { vi.mocked(validateAuthContext).mockResolvedValue({ accountId: "acc_123", orgId: "org_456", authToken: "token", }); - vi.mocked(safeParseJson).mockResolvedValue({ prompt: "tell me hello" }); + vi.mocked(safeParseJson).mockResolvedValue({ command: "ls" }); const request = createMockRequest(); const result = await validateSandboxBody(request); @@ -56,11 +56,36 @@ describe("validateSandboxBody", () => { accountId: "acc_123", orgId: "org_456", authToken: "token", - prompt: "tell me hello", + command: "ls", }); }); - it("returns error response when prompt is missing", async () => { + it("returns validated body with optional args and cwd", async () => { + vi.mocked(validateAuthContext).mockResolvedValue({ + accountId: "acc_123", + orgId: "org_456", + authToken: "token", + }); + vi.mocked(safeParseJson).mockResolvedValue({ + command: "ls", + args: ["-la", "/home"], + cwd: "/tmp", + }); + + const request = createMockRequest(); + const result = await validateSandboxBody(request); + + expect(result).toEqual({ + accountId: "acc_123", + orgId: "org_456", + authToken: "token", + command: "ls", + args: ["-la", "/home"], + cwd: "/tmp", + }); + }); + + it("returns error response when command is missing", async () => { vi.mocked(validateAuthContext).mockResolvedValue({ accountId: "acc_123", orgId: null, @@ -75,13 +100,13 @@ describe("validateSandboxBody", () => { expect((result as NextResponse).status).toBe(400); }); - it("returns error response when prompt is empty string", async () => { + it("returns error response when command is empty string", async () => { vi.mocked(validateAuthContext).mockResolvedValue({ accountId: "acc_123", orgId: null, authToken: "token", }); - vi.mocked(safeParseJson).mockResolvedValue({ prompt: "" }); + vi.mocked(safeParseJson).mockResolvedValue({ command: "" }); const request = createMockRequest(); const result = await validateSandboxBody(request); diff --git a/lib/sandbox/createSandbox.ts b/lib/sandbox/createSandbox.ts index 9f3824fc..570621af 100644 --- a/lib/sandbox/createSandbox.ts +++ b/lib/sandbox/createSandbox.ts @@ -8,20 +8,40 @@ export interface SandboxCreatedResponse { createdAt: string; } +/** Extract CreateSandboxParams from Sandbox.create method signature */ +export type CreateSandboxParams = NonNullable[0]>; + +const DEFAULT_TIMEOUT = ms("10m"); +const DEFAULT_VCPUS = 4; +const DEFAULT_RUNTIME = "node22"; + /** * Creates a Vercel Sandbox and returns its info. * * The sandbox is left running so that commands can be executed via the runSandboxCommand task. + * Accepts the same parameters as Sandbox.create from @vercel/sandbox. * + * @param params - Sandbox creation parameters (source, timeout, resources, runtime, ports) * @returns The sandbox creation response * @throws Error if sandbox creation fails */ -export async function createSandbox(): Promise { - const sandbox = await Sandbox.create({ - resources: { vcpus: 4 }, - timeout: ms("10m"), - runtime: "node22", - }); +export async function createSandbox(params: CreateSandboxParams = {}): Promise { + const hasSnapshotSource = params.source && "type" in params.source && params.source.type === "snapshot"; + + // Pass params directly to SDK - it handles all the type variants + const sandbox = await Sandbox.create( + hasSnapshotSource + ? { + ...params, + timeout: params.timeout ?? DEFAULT_TIMEOUT, + } + : { + resources: { vcpus: DEFAULT_VCPUS }, + timeout: params.timeout ?? DEFAULT_TIMEOUT, + runtime: DEFAULT_RUNTIME, + ...params, + }, + ); return { sandboxId: sandbox.sandboxId, diff --git a/lib/sandbox/createSandboxPostHandler.ts b/lib/sandbox/createSandboxPostHandler.ts index 9b503e52..b01a79c3 100644 --- a/lib/sandbox/createSandboxPostHandler.ts +++ b/lib/sandbox/createSandboxPostHandler.ts @@ -5,16 +5,18 @@ import { createSandbox } from "@/lib/sandbox/createSandbox"; import { validateSandboxBody } from "@/lib/sandbox/validateSandboxBody"; import { insertAccountSandbox } from "@/lib/supabase/account_sandboxes/insertAccountSandbox"; import { triggerRunSandboxCommand } from "@/lib/trigger/triggerRunSandboxCommand"; +import { selectAccountSnapshots } from "@/lib/supabase/account_snapshots/selectAccountSnapshots"; /** * Handler for POST /api/sandboxes. * - * Creates a Vercel Sandbox and triggers the run-sandbox-command task to execute the prompt. + * Creates a Vercel Sandbox (from account's snapshot if available, otherwise fresh) + * and triggers the run-sandbox-command task to execute the command. * Requires authentication via x-api-key header or Authorization Bearer token. * Saves sandbox info to the account_sandboxes table. * * @param request - The request object - * @returns A NextResponse with sandbox creation result or error + * @returns A NextResponse with sandbox creation result including runId */ export async function createSandboxPostHandler(request: NextRequest): Promise { const validated = await validateSandboxBody(request); @@ -23,20 +25,45 @@ export async function createSandboxPostHandler(request: NextRequest): Promise & AuthContext; diff --git a/lib/supabase/account_snapshots/selectAccountSnapshots.ts b/lib/supabase/account_snapshots/selectAccountSnapshots.ts new file mode 100644 index 00000000..89139725 --- /dev/null +++ b/lib/supabase/account_snapshots/selectAccountSnapshots.ts @@ -0,0 +1,25 @@ +import supabase from "../serverClient"; +import type { Tables } from "@/types/database.types"; + +/** + * Selects snapshots for an account, ordered by creation date (newest first). + * + * @param accountId - The account ID to get snapshots for + * @returns Array of snapshot records, or empty array if none found + */ +export async function selectAccountSnapshots( + accountId: string, +): Promise[]> { + const { data, error } = await supabase + .from("account_snapshots") + .select("*") + .eq("account_id", accountId) + .order("created_at", { ascending: false }); + + if (error) { + // Table might not exist or query failed - return empty array + return []; + } + + return data ?? []; +} diff --git a/lib/trigger/__tests__/triggerRunSandboxCommand.test.ts b/lib/trigger/__tests__/triggerRunSandboxCommand.test.ts index e98377ad..64718f39 100644 --- a/lib/trigger/__tests__/triggerRunSandboxCommand.test.ts +++ b/lib/trigger/__tests__/triggerRunSandboxCommand.test.ts @@ -14,12 +14,15 @@ describe("triggerRunSandboxCommand", () => { }); it("triggers run-sandbox-command task with correct payload", async () => { - const mockHandle = { id: "task_123" }; + const mockHandle = { id: "run_123" }; vi.mocked(tasks.trigger).mockResolvedValue(mockHandle); const payload = { - prompt: "tell me hello", + command: "ls", + args: ["-la"], + cwd: "/home", sandboxId: "sbx_456", + accountId: "acc_123", }; const result = await triggerRunSandboxCommand(payload); @@ -29,12 +32,13 @@ describe("triggerRunSandboxCommand", () => { }); it("passes through the task handle from trigger", async () => { - const mockHandle = { id: "task_789", publicAccessToken: "token_abc" }; + const mockHandle = { id: "run_789", publicAccessToken: "token_abc" }; vi.mocked(tasks.trigger).mockResolvedValue(mockHandle); const result = await triggerRunSandboxCommand({ - prompt: "another prompt", + command: "echo", sandboxId: "sbx_999", + accountId: "acc_456", }); expect(result).toBe(mockHandle); diff --git a/lib/trigger/triggerRunSandboxCommand.ts b/lib/trigger/triggerRunSandboxCommand.ts index dd6db6e5..524f68ec 100644 --- a/lib/trigger/triggerRunSandboxCommand.ts +++ b/lib/trigger/triggerRunSandboxCommand.ts @@ -1,15 +1,18 @@ import { tasks } from "@trigger.dev/sdk"; type RunSandboxCommandPayload = { - prompt: string; + command: string; + args?: string[]; + cwd?: string; sandboxId: string; + accountId: string; }; /** - * Triggers the run-sandbox-command task to execute a prompt in a sandbox. + * Triggers the run-sandbox-command task to execute a command in a sandbox. * - * @param payload - The task payload with prompt and sandboxId - * @returns The task handle + * @param payload - The task payload with command, args, cwd, sandboxId, and accountId + * @returns The task handle with runId */ export async function triggerRunSandboxCommand(payload: RunSandboxCommandPayload) { const handle = await tasks.trigger("run-sandbox-command", payload); diff --git a/package.json b/package.json index dea03405..c53bb782 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "mcp-handler": "^1.0.4", "ms": "^2.1.3", "multiformats": "^13.4.1", - "next": "^16.0.7", + "next": "16.0.10", "node-telegram-bot-api": "^0.66.0", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff6111b4..f0b0d314 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -79,7 +79,7 @@ importers: version: 15.0.12 mcp-handler: specifier: ^1.0.4 - version: 1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@4.1.13))(next@16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)) + version: 1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@4.1.13))(next@16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)) ms: specifier: ^2.1.3 version: 2.1.3 @@ -87,8 +87,8 @@ importers: specifier: ^13.4.1 version: 13.4.1 next: - specifier: ^16.0.7 - version: 16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + specifier: 16.0.10 + version: 16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) node-telegram-bot-api: specifier: ^0.66.0 version: 0.66.0(request@2.88.2) @@ -112,7 +112,7 @@ importers: version: 0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.2.7)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(react@19.2.1)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) x402-next: specifier: ^0.7.3 - version: 0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.2.7)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(next@16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.2.7)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(next@16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) zod: specifier: ^4.1.13 version: 4.1.13 @@ -1056,56 +1056,56 @@ packages: '@next/env@14.2.35': resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} - '@next/env@16.0.7': - resolution: {integrity: sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==} + '@next/env@16.0.10': + resolution: {integrity: sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==} '@next/eslint-plugin-next@15.1.7': resolution: {integrity: sha512-kRP7RjSxfTO13NE317ek3mSGzoZlI33nc/i5hs1KaWpK+egs85xg0DJ4p32QEiHnR0mVjuUfhRIun7awqfL7pQ==} - '@next/swc-darwin-arm64@16.0.7': - resolution: {integrity: sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==} + '@next/swc-darwin-arm64@16.0.10': + resolution: {integrity: sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.0.7': - resolution: {integrity: sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==} + '@next/swc-darwin-x64@16.0.10': + resolution: {integrity: sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.0.7': - resolution: {integrity: sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==} + '@next/swc-linux-arm64-gnu@16.0.10': + resolution: {integrity: sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.0.7': - resolution: {integrity: sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==} + '@next/swc-linux-arm64-musl@16.0.10': + resolution: {integrity: sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@16.0.7': - resolution: {integrity: sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==} + '@next/swc-linux-x64-gnu@16.0.10': + resolution: {integrity: sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.0.7': - resolution: {integrity: sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==} + '@next/swc-linux-x64-musl@16.0.10': + resolution: {integrity: sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@16.0.7': - resolution: {integrity: sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==} + '@next/swc-win32-arm64-msvc@16.0.10': + resolution: {integrity: sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.0.7': - resolution: {integrity: sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==} + '@next/swc-win32-x64-msvc@16.0.10': + resolution: {integrity: sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2434,6 +2434,7 @@ packages: '@walletconnect/ethereum-provider@2.21.1': resolution: {integrity: sha512-SSlIG6QEVxClgl1s0LMk4xr2wg4eT3Zn/Hb81IocyqNSGfXpjtawWxKxiC5/9Z95f1INyBD6MctJbL/R1oBwIw==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/events@1.0.1': resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} @@ -2478,9 +2479,11 @@ packages: '@walletconnect/sign-client@2.21.0': resolution: {integrity: sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/sign-client@2.21.1': resolution: {integrity: sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/time@1.0.2': resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} @@ -2493,9 +2496,11 @@ packages: '@walletconnect/universal-provider@2.21.0': resolution: {integrity: sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/universal-provider@2.21.1': resolution: {integrity: sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/utils@2.21.0': resolution: {integrity: sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==} @@ -4520,8 +4525,8 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - next@16.0.7: - resolution: {integrity: sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==} + next@16.0.10: + resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -7150,34 +7155,34 @@ snapshots: '@next/env@14.2.35': {} - '@next/env@16.0.7': {} + '@next/env@16.0.10': {} '@next/eslint-plugin-next@15.1.7': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@16.0.7': + '@next/swc-darwin-arm64@16.0.10': optional: true - '@next/swc-darwin-x64@16.0.7': + '@next/swc-darwin-x64@16.0.10': optional: true - '@next/swc-linux-arm64-gnu@16.0.7': + '@next/swc-linux-arm64-gnu@16.0.10': optional: true - '@next/swc-linux-arm64-musl@16.0.7': + '@next/swc-linux-arm64-musl@16.0.10': optional: true - '@next/swc-linux-x64-gnu@16.0.7': + '@next/swc-linux-x64-gnu@16.0.10': optional: true - '@next/swc-linux-x64-musl@16.0.7': + '@next/swc-linux-x64-musl@16.0.10': optional: true - '@next/swc-win32-arm64-msvc@16.0.7': + '@next/swc-win32-arm64-msvc@16.0.10': optional: true - '@next/swc-win32-x64-msvc@16.0.7': + '@next/swc-win32-x64-msvc@16.0.10': optional: true '@noble/ciphers@1.2.1': {} @@ -11831,14 +11836,14 @@ snapshots: math-intrinsics@1.1.0: {} - mcp-handler@1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@4.1.13))(next@16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)): + mcp-handler@1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@4.1.13))(next@16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)): dependencies: '@modelcontextprotocol/sdk': 1.24.3(zod@4.1.13) chalk: 5.6.2 commander: 11.1.0 redis: 4.7.1 optionalDependencies: - next: 16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + next: 16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) md5@2.3.0: dependencies: @@ -11981,9 +11986,9 @@ snapshots: negotiator@1.0.0: {} - next@16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + next@16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - '@next/env': 16.0.7 + '@next/env': 16.0.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001757 postcss: 8.4.31 @@ -11991,14 +11996,14 @@ snapshots: react-dom: 19.2.1(react@19.2.1) styled-jsx: 5.1.6(react@19.2.1) optionalDependencies: - '@next/swc-darwin-arm64': 16.0.7 - '@next/swc-darwin-x64': 16.0.7 - '@next/swc-linux-arm64-gnu': 16.0.7 - '@next/swc-linux-arm64-musl': 16.0.7 - '@next/swc-linux-x64-gnu': 16.0.7 - '@next/swc-linux-x64-musl': 16.0.7 - '@next/swc-win32-arm64-msvc': 16.0.7 - '@next/swc-win32-x64-msvc': 16.0.7 + '@next/swc-darwin-arm64': 16.0.10 + '@next/swc-darwin-x64': 16.0.10 + '@next/swc-linux-arm64-gnu': 16.0.10 + '@next/swc-linux-arm64-musl': 16.0.10 + '@next/swc-linux-x64-gnu': 16.0.10 + '@next/swc-linux-x64-musl': 16.0.10 + '@next/swc-win32-arm64-msvc': 16.0.10 + '@next/swc-win32-x64-msvc': 16.0.10 '@opentelemetry/api': 1.9.0 sharp: 0.34.5 transitivePeerDependencies: @@ -13878,11 +13883,11 @@ snapshots: - utf-8-validate - ws - x402-next@0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.2.7)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(next@16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): + x402-next@0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.2.7)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(next@16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): dependencies: '@coinbase/cdp-sdk': 1.38.6(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - next: 16.0.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + next: 16.0.10(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) x402: 0.7.3(@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.2.7)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.8.2)(react@19.2.1)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) zod: 3.25.76 diff --git a/types/database.types.ts b/types/database.types.ts index 58a12bfa..e22ee933 100644 --- a/types/database.types.ts +++ b/types/database.types.ts @@ -166,8 +166,6 @@ export type Database = { job_title: string | null knowledges: Json | null label: string | null - onboarding_data: Json | null - onboarding_status: Json | null organization: string | null role_type: string | null updated_at: string @@ -181,8 +179,6 @@ export type Database = { job_title?: string | null knowledges?: Json | null label?: string | null - onboarding_data?: Json | null - onboarding_status?: Json | null organization?: string | null role_type?: string | null updated_at?: string @@ -196,8 +192,6 @@ export type Database = { job_title?: string | null knowledges?: Json | null label?: string | null - onboarding_data?: Json | null - onboarding_status?: Json | null organization?: string | null role_type?: string | null updated_at?: string @@ -306,6 +300,35 @@ export type Database = { }, ] } + account_snapshots: { + Row: { + account_id: string + created_at: string | null + expires_at: string + snapshot_id: string + } + Insert: { + account_id: string + created_at?: string | null + expires_at: string + snapshot_id: string + } + Update: { + account_id?: string + created_at?: string | null + expires_at?: string + snapshot_id?: string + } + Relationships: [ + { + foreignKeyName: "account_snapshots_account_id_fkey" + columns: ["account_id"] + isOneToOne: true + referencedRelation: "accounts" + referencedColumns: ["id"] + }, + ] + } account_socials: { Row: { account_id: string | null