diff --git a/.gitignore b/.gitignore index 9bee46fc27..6f435d0400 100644 --- a/.gitignore +++ b/.gitignore @@ -63,4 +63,5 @@ apps/**/public/build /packages/core/src/package.json /packages/trigger-sdk/src/package.json /packages/python/src/package.json -.claude \ No newline at end of file +.claude +.mcp.log \ No newline at end of file diff --git a/apps/supervisor/package.json b/apps/supervisor/package.json index ae36549272..9cce9d5feb 100644 --- a/apps/supervisor/package.json +++ b/apps/supervisor/package.json @@ -19,7 +19,7 @@ "prom-client": "^15.1.0", "socket.io": "4.7.4", "std-env": "^3.8.0", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@types/dockerode": "^3.3.33" diff --git a/apps/webapp/app/v3/services/createBackgroundWorker.server.ts b/apps/webapp/app/v3/services/createBackgroundWorker.server.ts index 5ca2d5d387..f7489879ea 100644 --- a/apps/webapp/app/v3/services/createBackgroundWorker.server.ts +++ b/apps/webapp/app/v3/services/createBackgroundWorker.server.ts @@ -77,7 +77,7 @@ export class CreateBackgroundWorkerService extends BaseService { version: nextVersion, runtimeEnvironmentId: environment.id, projectId: project.id, - metadata: body.metadata, + metadata: body.metadata as any, contentHash: body.metadata.contentHash, cliVersion: body.metadata.cliPackageVersion, sdkVersion: body.metadata.packageVersion, @@ -280,6 +280,7 @@ async function createWorkerTask( fileId: tasksToBackgroundFiles?.get(task.id) ?? null, maxDurationInSeconds: task.maxDuration ? clampMaxDuration(task.maxDuration) : null, queueId: queue.id, + payloadSchema: task.payloadSchema as any, }, }); } catch (error) { diff --git a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts index 76be016528..9ac42478aa 100644 --- a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts +++ b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts @@ -48,7 +48,7 @@ export class CreateDeploymentBackgroundWorkerServiceV3 extends BaseService { version: deployment.version, runtimeEnvironmentId: environment.id, projectId: environment.projectId, - metadata: body.metadata, + metadata: body.metadata as any, contentHash: body.metadata.contentHash, cliVersion: body.metadata.cliPackageVersion, sdkVersion: body.metadata.packageVersion, diff --git a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts index 2fb32966de..d17d409536 100644 --- a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts +++ b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts @@ -65,7 +65,7 @@ export class CreateDeploymentBackgroundWorkerServiceV4 extends BaseService { version: deployment.version, runtimeEnvironmentId: environment.id, projectId: environment.projectId, - metadata: body.metadata, + metadata: body.metadata as any, contentHash: body.metadata.contentHash, cliVersion: body.metadata.cliPackageVersion, sdkVersion: body.metadata.packageVersion, diff --git a/apps/webapp/package.json b/apps/webapp/package.json index 80b7c9614b..69473b78b9 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -203,7 +203,7 @@ "ulidx": "^2.2.1", "uuid": "^9.0.0", "ws": "^8.11.0", - "zod": "3.23.8", + "zod": "3.25.76", "zod-error": "1.5.0", "zod-validation-error": "^1.5.0" }, diff --git a/internal-packages/clickhouse/package.json b/internal-packages/clickhouse/package.json index d85051b506..efa7cffd12 100644 --- a/internal-packages/clickhouse/package.json +++ b/internal-packages/clickhouse/package.json @@ -9,7 +9,7 @@ "@clickhouse/client": "^1.11.1", "@internal/tracing": "workspace:*", "@trigger.dev/core": "workspace:*", - "zod": "3.23.8", + "zod": "3.25.76", "zod-error": "1.5.0" }, "devDependencies": { diff --git a/internal-packages/database/prisma/migrations/20250730084611_add_payload_schema_to_background_worker_task/migration.sql b/internal-packages/database/prisma/migrations/20250730084611_add_payload_schema_to_background_worker_task/migration.sql new file mode 100644 index 0000000000..bbbb6694fd --- /dev/null +++ b/internal-packages/database/prisma/migrations/20250730084611_add_payload_schema_to_background_worker_task/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "BackgroundWorkerTask" ADD COLUMN "payloadSchema" JSONB; \ No newline at end of file diff --git a/internal-packages/database/prisma/schema.prisma b/internal-packages/database/prisma/schema.prisma index 211ff2b355..ce12dcf7c7 100644 --- a/internal-packages/database/prisma/schema.prisma +++ b/internal-packages/database/prisma/schema.prisma @@ -510,6 +510,8 @@ model BackgroundWorkerTask { triggerSource TaskTriggerSource @default(STANDARD) + payloadSchema Json? + @@unique([workerId, slug]) // Quick lookup of task identifiers @@index([projectId, slug]) diff --git a/internal-packages/emails/package.json b/internal-packages/emails/package.json index 85cb7abe01..e5d35cb2ee 100644 --- a/internal-packages/emails/package.json +++ b/internal-packages/emails/package.json @@ -17,7 +17,7 @@ "react-email": "^2.1.1", "resend": "^3.2.0", "tiny-invariant": "^1.2.0", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@types/nodemailer": "^6.4.17", diff --git a/internal-packages/run-engine/package.json b/internal-packages/run-engine/package.json index 62f0837897..a12abc73e2 100644 --- a/internal-packages/run-engine/package.json +++ b/internal-packages/run-engine/package.json @@ -30,7 +30,7 @@ "nanoid": "3.3.8", "redlock": "5.0.0-beta.2", "seedrandom": "^3.0.5", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@internal/testcontainers": "workspace:*", diff --git a/internal-packages/schedule-engine/package.json b/internal-packages/schedule-engine/package.json index ecdf151247..86929a3934 100644 --- a/internal-packages/schedule-engine/package.json +++ b/internal-packages/schedule-engine/package.json @@ -22,7 +22,7 @@ "cron-parser": "^4.9.0", "cronstrue": "^2.50.0", "nanoid": "3.3.8", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@internal/testcontainers": "workspace:*", diff --git a/internal-packages/zod-worker/package.json b/internal-packages/zod-worker/package.json index 1d9cbad93c..352fa94529 100644 --- a/internal-packages/zod-worker/package.json +++ b/internal-packages/zod-worker/package.json @@ -10,7 +10,7 @@ "@trigger.dev/database": "workspace:*", "graphile-worker": "0.16.6", "lodash.omit": "^4.5.0", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@types/lodash.omit": "^4.5.7", diff --git a/packages/cli-v3/install-mcp.sh b/packages/cli-v3/install-mcp.sh new file mode 100755 index 0000000000..f3424c85cc --- /dev/null +++ b/packages/cli-v3/install-mcp.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +set -e # Exit on error + +echo "🚀 Installing Trigger.dev MCP Server..." + +# Get the absolute path to the node binary +NODE_PATH=$(which node) +if [ -z "$NODE_PATH" ]; then + echo "❌ Error: Node.js not found in PATH" + echo "Please ensure Node.js is installed and available in your PATH" + exit 1 +fi + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Construct the path to the CLI index.js file +CLI_PATH="$SCRIPT_DIR/dist/esm/index.js" + +# Construct the path to the MCP log file +MCP_LOG_FILE="$SCRIPT_DIR/.mcp.log" + +# Make sure the MCP log file exists +touch "$MCP_LOG_FILE" + +# Check if the CLI file exists +if [ ! -f "$CLI_PATH" ]; then + echo "❌ Error: CLI file not found at $CLI_PATH" + echo "Make sure to build the CLI first with: pnpm run build" + exit 1 +fi + +# Ensure the CLI is executable +chmod +x "$CLI_PATH" + +echo "✅ Found Node.js at: $NODE_PATH" +echo "✅ Found CLI at: $CLI_PATH" + +# Claude Code configuration +CLAUDE_CONFIG="$HOME/.claude.json" + +echo "📁 Claude configuration file: $CLAUDE_CONFIG" + +# Check if Claude config exists, create if it doesn't +if [ ! -f "$CLAUDE_CONFIG" ]; then + echo "📝 Creating new Claude configuration file..." + echo '{"mcpServers": {}}' > "$CLAUDE_CONFIG" +fi + +# Use Node.js to manipulate the JSON +echo "🔧 Updating Claude configuration..." + +node -e " +const fs = require('fs'); +const path = require('path'); + +const configPath = '$CLAUDE_CONFIG'; +const nodePath = '$NODE_PATH'; +const cliPath = '$CLI_PATH'; +const logFile = '$MCP_LOG_FILE'; + +try { + // Read existing config + let config; + try { + const configContent = fs.readFileSync(configPath, 'utf8'); + config = JSON.parse(configContent); + } catch (error) { + console.log('📝 Creating new configuration structure...'); + config = {}; + } + + // Ensure mcpServers object exists + if (!config.mcpServers) { + config.mcpServers = {}; + } + + // Add/update trigger.dev entry + config.mcpServers['trigger'] = { + command: nodePath, + args: [cliPath, 'mcp', '--log-file', logFile] + }; + + // Write back to file with proper formatting + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + + console.log('✅ Successfully installed Trigger.dev MCP server to Claude Code'); + console.log(''); + console.log('📋 Configuration Details:'); + console.log(' • Config file:', configPath); + console.log(' • Node.js path:', nodePath); + console.log(' • CLI path:', cliPath); + console.log(''); + console.log('🎉 Installation complete! You can now use Trigger.dev MCP commands in Claude Code.'); + console.log('💡 Try typing @ in Claude Code and select \"triggerdev\" to get started.'); + +} catch (error) { + console.error('❌ Error updating Claude configuration:', error.message); + process.exit(1); +} +" + +echo "" +echo "🔍 You can test the MCP server with:" +echo " pnpm run inspector" diff --git a/packages/cli-v3/package.json b/packages/cli-v3/package.json index 846c067598..a172abfc05 100644 --- a/packages/cli-v3/package.json +++ b/packages/cli-v3/package.json @@ -75,12 +75,14 @@ "dev": "tshy --watch", "test": "vitest", "test:e2e": "vitest --run -c ./e2e/vitest.config.ts", - "update-version": "tsx ../../scripts/updateVersion.ts" + "update-version": "tsx ../../scripts/updateVersion.ts", + "install-mcp": "./install-mcp.sh", + "inspector": "npx @modelcontextprotocol/inspector dist/esm/index.js mcp --log-file .mcp.log" }, "dependencies": { "@clack/prompts": "^0.10.0", "@depot/cli": "0.0.1-cli.2.80.0", - "@modelcontextprotocol/sdk": "^1.6.1", + "@modelcontextprotocol/sdk": "^1.17.0", "@opentelemetry/api": "1.9.0", "@opentelemetry/api-logs": "0.52.1", "@opentelemetry/exporter-logs-otlp-http": "0.52.1", @@ -95,6 +97,7 @@ "@opentelemetry/semantic-conventions": "1.25.1", "@trigger.dev/build": "workspace:4.0.0-v4-beta.25", "@trigger.dev/core": "workspace:4.0.0-v4-beta.25", + "@trigger.dev/schema-to-json": "workspace:4.0.0-v4-beta.25", "ansi-escapes": "^7.0.0", "braces": "^3.0.3", "c12": "^1.11.1", @@ -138,7 +141,7 @@ "tinyglobby": "^0.2.10", "ws": "^8.18.0", "xdg-app-paths": "^8.3.0", - "zod": "3.23.8", + "zod": "3.25.76", "zod-validation-error": "^1.5.0" }, "engines": { diff --git a/packages/cli-v3/src/cli/index.ts b/packages/cli-v3/src/cli/index.ts index 4a575831a5..d74686c983 100644 --- a/packages/cli-v3/src/cli/index.ts +++ b/packages/cli-v3/src/cli/index.ts @@ -1,21 +1,20 @@ import { Command } from "commander"; +import { configureAnalyzeCommand } from "../commands/analyze.js"; +import { configureDeployCommand } from "../commands/deploy.js"; import { configureDevCommand } from "../commands/dev.js"; import { configureInitCommand } from "../commands/init.js"; +import { configureListProfilesCommand } from "../commands/list-profiles.js"; import { configureLoginCommand } from "../commands/login.js"; import { configureLogoutCommand } from "../commands/logout.js"; +import { configurePreviewCommand } from "../commands/preview.js"; +import { configurePromoteCommand } from "../commands/promote.js"; +import { configureSwitchProfilesCommand } from "../commands/switch.js"; +import { configureUpdateCommand } from "../commands/update.js"; import { configureWhoamiCommand } from "../commands/whoami.js"; +import { configureMcpCommand } from "../commands/mcp.js"; import { COMMAND_NAME } from "../consts.js"; -import { configureListProfilesCommand } from "../commands/list-profiles.js"; -import { configureAnalyzeCommand } from "../commands/analyze.js"; -import { configureUpdateCommand } from "../commands/update.js"; import { VERSION } from "../version.js"; -import { configureDeployCommand } from "../commands/deploy.js"; import { installExitHandler } from "./common.js"; -import { configureWorkersCommand } from "../commands/workers/index.js"; -import { configureSwitchProfilesCommand } from "../commands/switch.js"; -import { configureTriggerTaskCommand } from "../commands/trigger.js"; -import { configurePromoteCommand } from "../commands/promote.js"; -import { configurePreviewCommand } from "../commands/preview.js"; export const program = new Command(); @@ -24,6 +23,7 @@ program .description("Create, run locally and deploy Trigger.dev background tasks.") .version(VERSION, "-v, --version", "Display the version number"); +configureMcpCommand(program); configureLoginCommand(program); configureInitCommand(program); configureDevCommand(program); diff --git a/packages/cli-v3/src/commands/mcp.ts b/packages/cli-v3/src/commands/mcp.ts new file mode 100644 index 0000000000..d7f9b5af89 --- /dev/null +++ b/packages/cli-v3/src/commands/mcp.ts @@ -0,0 +1,85 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { Command } from "commander"; +import { z } from "zod"; +import { CommonCommandOptions, commonOptions, wrapCommandAction } from "../cli/common.js"; +import { login } from "./login.js"; +import { performSearch } from "../mcp/mintlifyClient.js"; +import { logger } from "../utilities/logger.js"; +import { FileLogger } from "../mcp/logger.js"; +import { McpContext } from "../mcp/context.js"; +import { registerGetProjectDetailsTool } from "../mcp/tools.js"; + +const McpCommandOptions = CommonCommandOptions.extend({ + projectRef: z.string().optional(), + logFile: z.string().optional(), +}); + +export type McpCommandOptions = z.infer; + +export function configureMcpCommand(program: Command) { + return commonOptions( + program + .command("mcp") + .description("Run the MCP server") + .option("-p, --project-ref ", "The project ref to use") + .option("--log-file ", "The file to log to") + ).action(async (options) => { + wrapCommandAction("mcp", McpCommandOptions, options, async (opts) => { + await mcpCommand(opts); + }); + }); +} + +export async function mcpCommand(options: McpCommandOptions) { + logger.loggerLevel = "none"; + + const authorization = await login({ + embedded: true, + silent: true, + defaultApiUrl: options.apiUrl, + profile: options.profile, + }); + + if (!authorization.ok) { + process.exitCode = 1; + return; + } + + const server = new McpServer({ + name: "triggerdev", + version: "1.0.0", + description: "Trigger.dev MCP server. Search the Trigger.dev docs.", + }); + + const fileLogger: FileLogger | undefined = options.logFile + ? new FileLogger(options.logFile, server) + : undefined; + + const context = new McpContext(server, { + login: authorization, + projectRef: options.projectRef, + fileLogger, + }); + + server.registerTool( + "search_docs", + { + description: + "Search across the Trigger.dev documentation to find relevant information, code examples, API references, and guides. Use this tool when you need to answer questions about Trigger.dev, find specific documentation, understand how features work, or locate implementation details. The search returns contextual content with titles and direct links to the documentation pages", + inputSchema: { + query: z.string(), + }, + }, + async ({ query }) => { + const results = await performSearch(query); + return results; + } + ); + + registerGetProjectDetailsTool(context); + + // Start receiving messages on stdin and sending messages on stdout + const transport = new StdioServerTransport(); + await server.connect(transport); +} diff --git a/packages/cli-v3/src/dev/mcpServer.ts b/packages/cli-v3/src/dev/mcpServer.ts index 8c4e57da34..849e87f38b 100644 --- a/packages/cli-v3/src/dev/mcpServer.ts +++ b/packages/cli-v3/src/dev/mcpServer.ts @@ -27,7 +27,7 @@ const server = new McpServer({ // This could be a good fit for the `resource` entity in MCP. // Also, a custom `prompt` entity could be useful to instruct the LLM to prompt the user // for selecting a task from a list of matching tasks, when the confidence for an exact match is low. -server.tool("list-all-tasks", "List all available task IDs in the worker.", async () => { +server.tool("list-all-tasks", "List all available task IDs in the worker.", async (params) => { return { content: [ { diff --git a/packages/cli-v3/src/entryPoints/dev-index-worker.ts b/packages/cli-v3/src/entryPoints/dev-index-worker.ts index d44ac53fe5..d47c01cbfc 100644 --- a/packages/cli-v3/src/entryPoints/dev-index-worker.ts +++ b/packages/cli-v3/src/entryPoints/dev-index-worker.ts @@ -18,6 +18,7 @@ import { registerResources } from "../indexing/registerResources.js"; import { env } from "std-env"; import { normalizeImportPath } from "../utilities/normalizeImportPath.js"; import { detectRuntimeVersion } from "@trigger.dev/core/v3/build"; +import { schemaToJsonSchema, initializeSchemaConverters } from "@trigger.dev/schema-to-json"; sourceMapSupport.install({ handleUncaughtExceptions: false, @@ -100,7 +101,7 @@ async function bootstrap() { const { buildManifest, importErrors, config, timings } = await bootstrap(); -let tasks = resourceCatalog.listTaskManifests(); +let tasks = await convertSchemasToJsonSchemas(resourceCatalog.listTaskManifests()); // If the config has retry defaults, we need to apply them to all tasks that don't have any retry settings if (config.retries?.default) { @@ -190,3 +191,20 @@ await new Promise((resolve) => { resolve(); }, 10); }); + +async function convertSchemasToJsonSchemas(tasks: TaskManifest[]): Promise { + await initializeSchemaConverters(); + + const convertedTasks = tasks.map((task) => { + const schema = resourceCatalog.getTaskSchema(task.id); + + if (schema) { + const result = schemaToJsonSchema(schema); + return { ...task, payloadSchema: result?.jsonSchema }; + } + + return task; + }); + + return convertedTasks; +} diff --git a/packages/cli-v3/src/entryPoints/managed-index-worker.ts b/packages/cli-v3/src/entryPoints/managed-index-worker.ts index 845ece47af..30f33433e0 100644 --- a/packages/cli-v3/src/entryPoints/managed-index-worker.ts +++ b/packages/cli-v3/src/entryPoints/managed-index-worker.ts @@ -18,6 +18,7 @@ import { registerResources } from "../indexing/registerResources.js"; import { env } from "std-env"; import { normalizeImportPath } from "../utilities/normalizeImportPath.js"; import { detectRuntimeVersion } from "@trigger.dev/core/v3/build"; +import { schemaToJsonSchema, initializeSchemaConverters } from "@trigger.dev/schema-to-json"; sourceMapSupport.install({ handleUncaughtExceptions: false, @@ -100,7 +101,7 @@ async function bootstrap() { const { buildManifest, importErrors, config, timings } = await bootstrap(); -let tasks = resourceCatalog.listTaskManifests(); +let tasks = await convertSchemasToJsonSchemas(resourceCatalog.listTaskManifests()); // If the config has retry defaults, we need to apply them to all tasks that don't have any retry settings if (config.retries?.default) { @@ -196,3 +197,20 @@ await new Promise((resolve) => { resolve(); }, 10); }); + +async function convertSchemasToJsonSchemas(tasks: TaskManifest[]): Promise { + await initializeSchemaConverters(); + + const convertedTasks = tasks.map((task) => { + const schema = resourceCatalog.getTaskSchema(task.id); + + if (schema) { + const result = schemaToJsonSchema(schema); + return { ...task, payloadSchema: result?.jsonSchema }; + } + + return task; + }); + + return convertedTasks; +} diff --git a/packages/cli-v3/src/mcp/context.ts b/packages/cli-v3/src/mcp/context.ts new file mode 100644 index 0000000000..ace12e6f22 --- /dev/null +++ b/packages/cli-v3/src/mcp/context.ts @@ -0,0 +1,23 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { FileLogger } from "./logger.js"; +import { LoginResult } from "../utilities/session.js"; + +export type McpContextOptions = { + login: LoginResult; + projectRef?: string; + fileLogger?: FileLogger; +}; + +export class McpContext { + public readonly server: McpServer; + public readonly options: McpContextOptions; + + constructor(server: McpServer, options: McpContextOptions) { + this.server = server; + this.options = options; + } + + get logger() { + return this.options.fileLogger; + } +} diff --git a/packages/cli-v3/src/mcp/logger.ts b/packages/cli-v3/src/mcp/logger.ts new file mode 100644 index 0000000000..b30576a331 --- /dev/null +++ b/packages/cli-v3/src/mcp/logger.ts @@ -0,0 +1,47 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { appendFileSync } from "node:fs"; +import util from "node:util"; + +export class FileLogger { + private filePath: string; + private server: McpServer; + + constructor(filePath: string, server: McpServer) { + this.filePath = filePath; + this.server = server; + } + + log(message: string, ...args: unknown[]) { + const logMessage = `[${new Date().toISOString()}][${this.formatServerInfo()}] ${message} - ${util.inspect( + args, + { + depth: null, + colors: false, + } + )}\n`; + appendFileSync(this.filePath, logMessage); + } + + private formatServerInfo() { + return `${this.formatClientName()} ${this.formatClientVersion()} ${this.formatClientCapabilities()}`; + } + + private formatClientName() { + const clientName = this.server.server.getClientVersion()?.name; + return `client=${clientName ?? "unknown"}`; + } + + private formatClientVersion() { + const clientVersion = this.server.server.getClientVersion(); + + return `version=${clientVersion?.version ?? "unknown"}`; + } + + private formatClientCapabilities() { + const clientCapabilities = this.server.server.getClientCapabilities(); + + const keys = Object.keys(clientCapabilities ?? {}); + + return `capabilities=${keys.join(",")}`; + } +} diff --git a/packages/cli-v3/src/mcp/mintlifyClient.ts b/packages/cli-v3/src/mcp/mintlifyClient.ts new file mode 100644 index 0000000000..1b05f07301 --- /dev/null +++ b/packages/cli-v3/src/mcp/mintlifyClient.ts @@ -0,0 +1,73 @@ +export async function performSearch(query: string) { + const body = callToolBody("search", { query }); + + const response = await fetch("https://trigger.dev/docs/mcp", { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json, text/event-stream", + "MCP-Protocol-Version": "2025-06-18", + }, + body: JSON.stringify(body), + }); + + const data = await parseResponse(response); + return data; +} + +async function parseResponse(response: Response) { + if (response.headers.get("content-type")?.includes("text/event-stream")) { + return parseSSEResponse(response); + } else { + return parseJSONResponse(response); + } +} + +async function parseJSONResponse(response: Response) { + const data = await response.json(); + return data; +} + +// Get the first data: event and return the parsed JSON of the event +async function parseSSEResponse(response: Response) { + const reader = response.body?.getReader(); + const decoder = new TextDecoder(); + + if (!reader) { + throw new Error("No reader found"); + } + + let buffer = ""; + + while (true) { + const { value, done } = await reader.read(); + if (done) throw new Error("SSE stream closed before data arrived"); + + buffer += decoder.decode(value, { stream: true }); + const events = buffer.split("\n\n"); // SSE delimiter + buffer = events.pop()!; // keep incomplete + + for (const evt of events) { + for (const line of evt.split("\n")) { + if (line.startsWith("data:")) { + const json = line.slice(5).trim(); + return JSON.parse(json); // ✅ got it + } + } + } + } + + throw new Error("No data: event found"); +} + +function callToolBody(tool: string, args: Record) { + return { + jsonrpc: "2.0", + id: 1, + method: "tools/call", + params: { + name: tool, + arguments: args, + }, + }; +} diff --git a/packages/cli-v3/src/mcp/tools.ts b/packages/cli-v3/src/mcp/tools.ts new file mode 100644 index 0000000000..e0e0f18541 --- /dev/null +++ b/packages/cli-v3/src/mcp/tools.ts @@ -0,0 +1,23 @@ +import z from "zod"; +import { McpContext } from "./context.js"; + +export function registerGetProjectDetailsTool(context: McpContext) { + context.server.registerTool( + "get_project_details", + { + description: "Get the details of the project", + inputSchema: { + projectRef: z.string().optional(), + }, + }, + async ({ projectRef }, extra) => { + const roots = await context.server.server.listRoots(); + + context.logger?.log("get_project_details", { roots, projectRef, extra }); + + return { + content: [{ type: "text", text: "Not implemented" }], + }; + } + ); +} diff --git a/packages/core/package.json b/packages/core/package.json index 42c76333a4..4a7bbeb808 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -197,7 +197,7 @@ "superjson": "^2.2.1", "tinyexec": "^0.3.2", "uncrypto": "^0.1.3", - "zod": "3.23.8", + "zod": "3.25.76", "zod-error": "1.5.0", "zod-validation-error": "^1.5.0" }, diff --git a/packages/core/src/v3/resource-catalog/catalog.ts b/packages/core/src/v3/resource-catalog/catalog.ts index 725899c0d1..9ad14dd848 100644 --- a/packages/core/src/v3/resource-catalog/catalog.ts +++ b/packages/core/src/v3/resource-catalog/catalog.ts @@ -1,5 +1,5 @@ import { QueueManifest, TaskManifest, WorkerManifest } from "../schemas/index.js"; -import { TaskMetadataWithFunctions } from "../types/index.js"; +import { TaskMetadataWithFunctions, TaskSchema } from "../types/index.js"; export interface ResourceCatalog { setCurrentFileContext(filePath: string, entryPoint: string): void; @@ -13,4 +13,5 @@ export interface ResourceCatalog { registerWorkerManifest(workerManifest: WorkerManifest): void; registerQueueMetadata(queue: QueueManifest): void; listQueueManifests(): Array; + getTaskSchema(id: string): TaskSchema | undefined; } diff --git a/packages/core/src/v3/resource-catalog/index.ts b/packages/core/src/v3/resource-catalog/index.ts index 6773f1b621..a564648fcc 100644 --- a/packages/core/src/v3/resource-catalog/index.ts +++ b/packages/core/src/v3/resource-catalog/index.ts @@ -1,7 +1,7 @@ const API_NAME = "resource-catalog"; import { QueueManifest, TaskManifest, WorkerManifest } from "../schemas/index.js"; -import { TaskMetadataWithFunctions } from "../types/index.js"; +import { TaskMetadataWithFunctions, TaskSchema } from "../types/index.js"; import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals.js"; import { type ResourceCatalog } from "./catalog.js"; import { NoopResourceCatalog } from "./noopResourceCatalog.js"; @@ -65,6 +65,10 @@ export class ResourceCatalogAPI { return this.#getCatalog().getTask(id); } + public getTaskSchema(id: string): TaskSchema | undefined { + return this.#getCatalog().getTaskSchema(id); + } + public taskExists(id: string): boolean { return this.#getCatalog().taskExists(id); } diff --git a/packages/core/src/v3/resource-catalog/noopResourceCatalog.ts b/packages/core/src/v3/resource-catalog/noopResourceCatalog.ts index b0e0f73056..53a953393a 100644 --- a/packages/core/src/v3/resource-catalog/noopResourceCatalog.ts +++ b/packages/core/src/v3/resource-catalog/noopResourceCatalog.ts @@ -1,5 +1,5 @@ import { QueueManifest, TaskManifest, WorkerManifest } from "../schemas/index.js"; -import { TaskMetadataWithFunctions } from "../types/index.js"; +import { TaskMetadataWithFunctions, TaskSchema } from "../types/index.js"; import { ResourceCatalog } from "./catalog.js"; export class NoopResourceCatalog implements ResourceCatalog { @@ -31,6 +31,10 @@ export class NoopResourceCatalog implements ResourceCatalog { return undefined; } + getTaskSchema(id: string): TaskSchema | undefined { + return undefined; + } + taskExists(id: string): boolean { return false; } diff --git a/packages/core/src/v3/resource-catalog/standardResourceCatalog.ts b/packages/core/src/v3/resource-catalog/standardResourceCatalog.ts index 7468b63d80..3b8eaa7d67 100644 --- a/packages/core/src/v3/resource-catalog/standardResourceCatalog.ts +++ b/packages/core/src/v3/resource-catalog/standardResourceCatalog.ts @@ -5,10 +5,11 @@ import { WorkerManifest, QueueManifest, } from "../schemas/index.js"; -import { TaskMetadataWithFunctions } from "../types/index.js"; +import { TaskMetadataWithFunctions, TaskSchema } from "../types/index.js"; import { ResourceCatalog } from "./catalog.js"; export class StandardResourceCatalog implements ResourceCatalog { + private _taskSchemas: Map = new Map(); private _taskMetadata: Map = new Map(); private _taskFunctions: Map = new Map(); private _taskFileMetadata: Map = new Map(); @@ -72,6 +73,10 @@ export class StandardResourceCatalog implements ResourceCatalog { this._taskMetadata.set(task.id, metadata); this._taskFunctions.set(task.id, fns); + + if (task.schema) { + this._taskSchemas.set(task.id, task.schema); + } } updateTaskMetadata(id: string, updates: Partial): void { @@ -107,15 +112,21 @@ export class StandardResourceCatalog implements ResourceCatalog { continue; } - result.push({ + const taskManifest = { ...metadata, ...fileMetadata, - }); + }; + + result.push(taskManifest); } return result; } + getTaskSchema(id: string): TaskSchema | undefined { + return this._taskSchemas.get(id); + } + listQueueManifests(): Array { return Array.from(this._queueMetadata.values()); } diff --git a/packages/core/src/v3/schemas/resources.ts b/packages/core/src/v3/schemas/resources.ts index ec2b180bbc..08764906ed 100644 --- a/packages/core/src/v3/schemas/resources.ts +++ b/packages/core/src/v3/schemas/resources.ts @@ -13,6 +13,8 @@ export const TaskResource = z.object({ triggerSource: z.string().optional(), schedule: ScheduleMetadata.optional(), maxDuration: z.number().optional(), + // JSONSchema type - using z.unknown() for runtime validation to accept JSONSchema7 + payloadSchema: z.unknown().optional(), }); export type TaskResource = z.infer; diff --git a/packages/core/src/v3/schemas/schemas.ts b/packages/core/src/v3/schemas/schemas.ts index bd32d848ff..31bb410086 100644 --- a/packages/core/src/v3/schemas/schemas.ts +++ b/packages/core/src/v3/schemas/schemas.ts @@ -189,6 +189,7 @@ const taskMetadata = { triggerSource: z.string().optional(), schedule: ScheduleMetadata.optional(), maxDuration: z.number().optional(), + payloadSchema: z.unknown().optional(), }; export const TaskMetadata = z.object(taskMetadata); diff --git a/packages/core/src/v3/types/index.ts b/packages/core/src/v3/types/index.ts index 55cc4d3a12..ea2bc8d558 100644 --- a/packages/core/src/v3/types/index.ts +++ b/packages/core/src/v3/types/index.ts @@ -7,6 +7,7 @@ export * from "./tasks.js"; export * from "./idempotencyKeys.js"; export * from "./tools.js"; export * from "./queues.js"; +export * from "./jsonSchema.js"; type ResolveEnvironmentVariablesOptions = { variables: Record | Array<{ name: string; value: string }>; diff --git a/packages/core/src/v3/types/jsonSchema.ts b/packages/core/src/v3/types/jsonSchema.ts new file mode 100644 index 0000000000..7abf241a66 --- /dev/null +++ b/packages/core/src/v3/types/jsonSchema.ts @@ -0,0 +1,76 @@ +/** + * JSON Schema type definition - compatible with JSON Schema Draft 7 + * Based on the JSONSchema7 type from @types/json-schema but defined inline to avoid import issues + */ +export interface JSONSchema { + $id?: string; + $ref?: string; + $schema?: string; + $comment?: string; + + type?: JSONSchemaType | JSONSchemaType[]; + enum?: any[]; + const?: any; + + // Number/Integer validations + multipleOf?: number; + maximum?: number; + exclusiveMaximum?: number; + minimum?: number; + exclusiveMinimum?: number; + + // String validations + maxLength?: number; + minLength?: number; + pattern?: string; + format?: string; + + // Array validations + items?: JSONSchema | JSONSchema[]; + additionalItems?: JSONSchema | boolean; + maxItems?: number; + minItems?: number; + uniqueItems?: boolean; + contains?: JSONSchema; + + // Object validations + maxProperties?: number; + minProperties?: number; + required?: string[]; + properties?: Record; + patternProperties?: Record; + additionalProperties?: JSONSchema | boolean; + dependencies?: Record; + propertyNames?: JSONSchema; + + // Conditional schemas + if?: JSONSchema; + then?: JSONSchema; + else?: JSONSchema; + + // Boolean logic + allOf?: JSONSchema[]; + anyOf?: JSONSchema[]; + oneOf?: JSONSchema[]; + not?: JSONSchema; + + // Metadata + title?: string; + description?: string; + default?: any; + readOnly?: boolean; + writeOnly?: boolean; + examples?: any[]; + + // Additional properties for extensibility + [key: string]: any; +} + +export type JSONSchemaType = + | "string" + | "number" + | "integer" + | "boolean" + | "object" + | "array" + | "null"; diff --git a/packages/core/src/v3/types/tasks.ts b/packages/core/src/v3/types/tasks.ts index f9595b51e6..66c9d98d5f 100644 --- a/packages/core/src/v3/types/tasks.ts +++ b/packages/core/src/v3/types/tasks.ts @@ -28,6 +28,7 @@ import { QueueOptions } from "./queues.js"; import { AnySchemaParseFn, inferSchemaIn, inferSchemaOut, Schema } from "./schemas.js"; import { inferToolParameters, ToolTaskParameters } from "./tools.js"; import { Prettify } from "./utils.js"; +import { JSONSchema } from "./jsonSchema.js"; export type Queue = QueueOptions; export type TaskSchema = Schema; @@ -339,6 +340,12 @@ type CommonTaskOptions< * onFailure is called after a task run has failed (meaning the run function threw an error and won't be retried anymore) */ onFailure?: OnFailureHookFunction; + + /** + * JSON Schema for the task payload. This will be synced to the server during indexing. + * Should be a valid JSON Schema Draft 7 object. + */ + jsonSchema?: JSONSchema; }; export type TaskOptions< @@ -348,6 +355,15 @@ export type TaskOptions< TInitOutput extends InitOutput = any, > = CommonTaskOptions; +// Task options when payloadSchema is provided - payload should be any +export type TaskOptionsWithSchema< + TIdentifier extends string, + TOutput = unknown, + TInitOutput extends InitOutput = any, +> = CommonTaskOptions & { + jsonSchema: JSONSchema; +}; + export type TaskWithSchemaOptions< TIdentifier extends string, TSchema extends TaskSchema | undefined = undefined, @@ -881,6 +897,7 @@ export type TaskMetadataWithFunctions = TaskMetadata & { onStart?: (payload: any, params: StartFnParams) => Promise; parsePayload?: AnySchemaParseFn; }; + schema?: TaskSchema; }; export type RunTypes = { diff --git a/packages/redis-worker/package.json b/packages/redis-worker/package.json index 3698cb76e3..ff238300b6 100644 --- a/packages/redis-worker/package.json +++ b/packages/redis-worker/package.json @@ -27,7 +27,7 @@ "lodash.omit": "^4.5.0", "nanoid": "^5.0.7", "p-limit": "^6.2.0", - "zod": "3.23.8", + "zod": "3.25.76", "cron-parser": "^4.9.0" }, "devDependencies": { diff --git a/packages/schema-to-json/.gitignore b/packages/schema-to-json/.gitignore new file mode 100644 index 0000000000..c887152393 --- /dev/null +++ b/packages/schema-to-json/.gitignore @@ -0,0 +1,6 @@ +node_modules +dist +.tshy +.tshy-build +*.log +.DS_Store \ No newline at end of file diff --git a/packages/schema-to-json/README.md b/packages/schema-to-json/README.md new file mode 100644 index 0000000000..9576b6e800 --- /dev/null +++ b/packages/schema-to-json/README.md @@ -0,0 +1,151 @@ +# @trigger.dev/schema-to-json + +Convert various schema validation libraries to JSON Schema format. + +## Installation + +```bash +npm install @trigger.dev/schema-to-json +``` + +## Important: Bundle Safety + +This package is designed to be **bundle-safe**. It does NOT bundle any schema libraries (zod, yup, etc.) as dependencies. Instead: + +1. **Built-in conversions** work immediately (ArkType, Zod 4, TypeBox) +2. **External conversions** (Zod 3, Yup, Effect) require the conversion libraries to be available at runtime + +This design ensures that: +- ✅ Your bundle size stays small +- ✅ You only include the schema libraries you actually use +- ✅ Tree-shaking works properly +- ✅ No unnecessary dependencies are installed + +## Supported Schema Libraries + +- ✅ **Zod** - Full support + - Zod 4: Native support via built-in `toJsonSchema` method (no external deps needed) + - Zod 3: Requires `zod-to-json-schema` to be installed +- ✅ **Yup** - Requires `@sodaru/yup-to-json-schema` to be installed +- ✅ **ArkType** - Native support (built-in `toJsonSchema` method) +- ✅ **Effect/Schema** - Requires `effect` or `@effect/schema` to be installed +- ✅ **TypeBox** - Native support (already JSON Schema compliant) +- ⏳ **Valibot** - Coming soon +- ⏳ **Superstruct** - Coming soon +- ⏳ **Runtypes** - Coming soon + +## Usage + +### Basic Usage (Built-in conversions only) + +```typescript +import { schemaToJsonSchema } from '@trigger.dev/schema-to-json'; +import { type } from 'arktype'; + +// Works immediately for schemas with built-in conversion +const arkSchema = type({ + name: 'string', + age: 'number', +}); + +const result = schemaToJsonSchema(arkSchema); +console.log(result); +// { jsonSchema: {...}, schemaType: 'arktype' } +``` + +### Full Usage (With external conversion libraries) + +```typescript +import { schemaToJsonSchema, initializeSchemaConverters } from '@trigger.dev/schema-to-json'; +import { z } from 'zod'; + +// Initialize converters once in your app (loads conversion libraries if available) +await initializeSchemaConverters(); + +// Now you can convert Zod 3, Yup, and Effect schemas +const zodSchema = z.object({ + name: z.string(), + age: z.number(), + email: z.string().email(), +}); + +const result = schemaToJsonSchema(zodSchema); +console.log(result); +// { +// jsonSchema: { +// type: 'object', +// properties: { +// name: { type: 'string' }, +// age: { type: 'number' }, +// email: { type: 'string', format: 'email' } +// }, +// required: ['name', 'age', 'email'] +// }, +// schemaType: 'zod' +// } +``` + +## API + +### `schemaToJsonSchema(schema, options?)` + +Convert a schema to JSON Schema format. + +**Parameters:** +- `schema` - The schema to convert +- `options` (optional) + - `name` - Name to use for the schema (supported by some converters) + - `additionalProperties` - Additional properties to merge into the result + +**Returns:** +- `{ jsonSchema, schemaType }` - The converted JSON Schema and detected type +- `undefined` - If the schema cannot be converted + +### `initializeSchemaConverters()` + +Initialize the external conversion libraries. Call this once in your application if you need to convert schemas that don't have built-in JSON Schema support (Zod 3, Yup, Effect). + +**Returns:** `Promise` + +### `canConvertSchema(schema)` + +Check if a schema can be converted to JSON Schema. + +**Returns:** `boolean` + +### `detectSchemaType(schema)` + +Detect the type of schema. + +**Returns:** `'zod' | 'yup' | 'arktype' | 'effect' | 'valibot' | 'superstruct' | 'runtypes' | 'typebox' | 'unknown'` + +### `areConvertersInitialized()` + +Check which conversion libraries are available. + +**Returns:** `{ zod: boolean, yup: boolean, effect: boolean }` + +## Peer Dependencies + +Each schema library is an optional peer dependency. Install only the ones you need: + +```bash +# For Zod +npm install zod + +# For Yup +npm install yup + +# For ArkType +npm install arktype + +# For Effect +npm install effect @effect/schema + +# For TypeBox +npm install @sinclair/typebox +``` + +## License + +MIT \ No newline at end of file diff --git a/packages/schema-to-json/package.json b/packages/schema-to-json/package.json new file mode 100644 index 0000000000..753c045d16 --- /dev/null +++ b/packages/schema-to-json/package.json @@ -0,0 +1,112 @@ +{ + "name": "@trigger.dev/schema-to-json", + "version": "4.0.0-v4-beta.25", + "description": "Convert various schema validation libraries to JSON Schema", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/triggerdotdev/trigger.dev", + "directory": "packages/schema-to-json" + }, + "type": "module", + "engines": { + "node": ">=18.20.0" + }, + "files": [ + "dist" + ], + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + } + }, + "scripts": { + "clean": "rimraf dist", + "build": "npm run clean && npm run build:tshy", + "build:tshy": "tshy", + "dev": "tshy --watch", + "typecheck": "tsc -p tsconfig.src.json --noEmit", + "test": "vitest", + "update-version": "tsx ../../scripts/updateVersion.ts", + "check-exports": "attw --pack ." + }, + "dependencies": { + "@trigger.dev/core": "workspace:*", + "zod-to-json-schema": "^3.24.5", + "@sodaru/yup-to-json-schema": "^2.0.1" + }, + "devDependencies": { + "@effect/schema": "^0.75.5", + "arktype": "^2.0.0", + "effect": "^3.11.11", + "runtypes": "^6.7.0", + "superstruct": "^2.0.2", + "tshy": "^3.0.2", + "@sinclair/typebox": "^0.34.3", + "valibot": "^1.0.0-beta.8", + "vitest": "^2.1.8", + "yup": "^1.6.1", + "zod": "^3.24.1 || ^4.0.0", + "rimraf": "6.0.1" + }, + "peerDependencies": { + "@effect/schema": "^0.75.5", + "arktype": "^2.0.0", + "effect": "^3.11.11", + "runtypes": "^6.7.0", + "superstruct": "^2.0.2", + "@sinclair/typebox": "^0.34.3", + "valibot": "^1.0.0-beta.8", + "yup": "^1.6.1", + "zod": "^3.24.1 || ^4.0.0" + }, + "peerDependenciesMeta": { + "@effect/schema": { + "optional": true + }, + "arktype": { + "optional": true + }, + "effect": { + "optional": true + }, + "runtypes": { + "optional": true + }, + "superstruct": { + "optional": true + }, + "typebox": { + "optional": true + }, + "valibot": { + "optional": true + }, + "yup": { + "optional": true + }, + "zod": { + "optional": true + } + }, + "tshy": { + "selfLink": false, + "exports": { + ".": "./src/index.ts" + }, + "project": "./tsconfig.src.json" + }, + "main": "./dist/commonjs/index.js", + "types": "./dist/commonjs/index.d.ts", + "module": "./dist/esm/index.js" +} diff --git a/packages/schema-to-json/src/index.ts b/packages/schema-to-json/src/index.ts new file mode 100644 index 0000000000..7a3e5899d5 --- /dev/null +++ b/packages/schema-to-json/src/index.ts @@ -0,0 +1,243 @@ +// Import JSONSchema from core to ensure compatibility +import type { JSONSchema } from "@trigger.dev/core/v3"; + +export type Schema = unknown; +export type { JSONSchema }; + +export interface ConversionOptions { + /** + * The name to use for the schema in the JSON Schema + */ + name?: string; + /** + * Additional JSON Schema properties to merge + */ + additionalProperties?: Record; +} + +export interface ConversionResult { + /** + * The JSON Schema representation (JSON Schema Draft 7) + */ + jsonSchema: JSONSchema; + /** + * The detected schema type + */ + schemaType: + | "zod" + | "yup" + | "arktype" + | "effect" + | "valibot" + | "superstruct" + | "runtypes" + | "typebox" + | "unknown"; +} + +/** + * Convert a schema from various validation libraries to JSON Schema + * + * This function attempts to convert schemas without requiring external dependencies to be bundled. + * It will only succeed if: + * 1. The schema has built-in JSON Schema conversion (ArkType, Zod 4, TypeBox) + * 2. The required conversion library is available at runtime (zod-to-json-schema, @sodaru/yup-to-json-schema, etc.) + * + * @param schema The schema to convert + * @param options Optional conversion options + * @returns The conversion result or undefined if conversion is not possible + */ +export function schemaToJsonSchema( + schema: Schema, + options?: ConversionOptions +): ConversionResult | undefined { + const parser = schema as any; + + // Check if schema has a built-in toJsonSchema method (e.g., ArkType, Zod 4) + if (typeof parser.toJsonSchema === "function") { + try { + const jsonSchema = parser.toJsonSchema(); + // Determine if it's Zod or ArkType based on other methods + const schemaType = + typeof parser.parseAsync === "function" || typeof parser.parse === "function" + ? "zod" + : "arktype"; + return { + jsonSchema: options?.additionalProperties + ? { ...jsonSchema, ...options.additionalProperties } + : jsonSchema, + schemaType, + }; + } catch (error) { + // If toJsonSchema fails, continue to other checks + } + } + + // Check if it's a TypeBox schema (has Static and Kind symbols) + if (parser[Symbol.for("TypeBox.Kind")] !== undefined) { + // TypeBox schemas are already JSON Schema compliant + return { + jsonSchema: options?.additionalProperties + ? { ...parser, ...options.additionalProperties } + : parser, + schemaType: "typebox", + }; + } + + // For schemas that need external libraries, we need to check if they're available + // This approach avoids bundling the dependencies while still allowing runtime usage + + // Check if it's a Zod schema (without built-in toJsonSchema) + if (typeof parser.parseAsync === "function" || typeof parser.parse === "function") { + try { + // Try to access zod-to-json-schema if it's available + // @ts-ignore - This is intentionally dynamic + if (typeof globalThis.__zodToJsonSchema !== "undefined") { + // @ts-ignore + const { zodToJsonSchema } = globalThis.__zodToJsonSchema; + const jsonSchema = options?.name + ? zodToJsonSchema(parser, options.name) + : zodToJsonSchema(parser); + + if (jsonSchema && typeof jsonSchema === "object" && "$schema" in jsonSchema) { + const { $schema, ...rest } = jsonSchema as any; + return { + jsonSchema: options?.additionalProperties + ? { ...rest, ...options.additionalProperties } + : rest, + schemaType: "zod", + }; + } + + return { + jsonSchema: options?.additionalProperties + ? { ...jsonSchema, ...options.additionalProperties } + : jsonSchema, + schemaType: "zod", + }; + } + } catch (error) { + // Library not available + } + } + + // Check if it's a Yup schema + if (typeof parser.validateSync === "function" && typeof parser.describe === "function") { + try { + // @ts-ignore + if (typeof globalThis.__yupToJsonSchema !== "undefined") { + // @ts-ignore + const { convertSchema } = globalThis.__yupToJsonSchema; + const jsonSchema = convertSchema(parser); + return { + jsonSchema: options?.additionalProperties + ? { ...jsonSchema, ...options.additionalProperties } + : jsonSchema, + schemaType: "yup", + }; + } + } catch (error) { + // Library not available + } + } + + // Check if it's an Effect schema + if ( + parser._tag === "Schema" || + parser._tag === "SchemaClass" || + typeof parser.ast === "function" + ) { + try { + // @ts-ignore + if (typeof globalThis.__effectJsonSchema !== "undefined") { + // @ts-ignore + const { JSONSchema } = globalThis.__effectJsonSchema; + const jsonSchema = JSONSchema.make(parser); + return { + jsonSchema: options?.additionalProperties + ? { ...jsonSchema, ...options.additionalProperties } + : jsonSchema, + schemaType: "effect", + }; + } + } catch (error) { + // Library not available + } + } + + // Future schema types can be added here... + + // Unknown schema type + return undefined; +} + +/** + * Initialize the schema conversion libraries + * This should be called by the consuming application if they want to enable + * conversion for schemas that don't have built-in JSON Schema support + */ +export async function initializeSchemaConverters(): Promise { + try { + // @ts-ignore + globalThis.__zodToJsonSchema = await import("zod-to-json-schema"); + } catch { + // Zod conversion not available + } + + try { + // @ts-ignore + globalThis.__yupToJsonSchema = await import("@sodaru/yup-to-json-schema"); + } catch { + // Yup conversion not available + } + + try { + // Try Effect first, then @effect/schema + let module; + try { + module = await import("effect"); + } catch { + module = await import("@effect/schema"); + } + if (module?.JSONSchema) { + // @ts-ignore + globalThis.__effectJsonSchema = { JSONSchema: module.JSONSchema }; + } + } catch { + // Effect conversion not available + } +} + +/** + * Check if a schema can be converted to JSON Schema + */ +export function canConvertSchema(schema: Schema): boolean { + const result = schemaToJsonSchema(schema); + return result !== undefined; +} + +/** + * Get the detected schema type + */ +export function detectSchemaType(schema: Schema): ConversionResult["schemaType"] { + const result = schemaToJsonSchema(schema); + return result?.schemaType ?? "unknown"; +} + +/** + * Check if the conversion libraries are initialized + */ +export function areConvertersInitialized(): { + zod: boolean; + yup: boolean; + effect: boolean; +} { + return { + // @ts-ignore + zod: typeof globalThis.__zodToJsonSchema !== "undefined", + // @ts-ignore + yup: typeof globalThis.__yupToJsonSchema !== "undefined", + // @ts-ignore + effect: typeof globalThis.__effectJsonSchema !== "undefined", + }; +} diff --git a/packages/schema-to-json/src/tests/index.test.ts b/packages/schema-to-json/src/tests/index.test.ts new file mode 100644 index 0000000000..3bc3111d63 --- /dev/null +++ b/packages/schema-to-json/src/tests/index.test.ts @@ -0,0 +1,351 @@ +import { describe, it, expect, beforeAll } from "vitest"; +import { z } from "zod"; +import * as y from "yup"; +// @ts-ignore +import { type } from "arktype"; +import { Schema } from "@effect/schema"; +import { Type } from "@sinclair/typebox"; +import { + schemaToJsonSchema, + canConvertSchema, + detectSchemaType, + initializeSchemaConverters, + areConvertersInitialized, +} from "../index.js"; + +// Initialize converters before running tests +beforeAll(async () => { + await initializeSchemaConverters(); +}); + +describe("schemaToJsonSchema", () => { + describe("Initialization", () => { + it("should have converters initialized", () => { + const status = areConvertersInitialized(); + expect(status.zod).toBe(true); + expect(status.yup).toBe(true); + expect(status.effect).toBe(true); + }); + }); + + describe("Zod schemas", () => { + it("should convert a simple Zod object schema", () => { + const schema = z.object({ + name: z.string(), + age: z.number(), + email: z.string().email(), + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.schemaType).toBe("zod"); + expect(result?.jsonSchema).toMatchObject({ + type: "object", + properties: { + name: { type: "string" }, + age: { type: "number" }, + email: { type: "string", format: "email" }, + }, + required: ["name", "age", "email"], + }); + }); + + it("should convert a Zod schema with optional fields", () => { + const schema = z.object({ + id: z.string(), + description: z.string().optional(), + tags: z.array(z.string()).optional(), + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.jsonSchema).toMatchObject({ + type: "object", + properties: { + id: { type: "string" }, + description: { type: "string" }, + tags: { type: "array", items: { type: "string" } }, + }, + required: ["id"], + }); + }); + + it("should handle Zod schema with name option", () => { + const schema = z.object({ + value: z.number(), + }); + + const result = schemaToJsonSchema(schema, { name: "MySchema" }); + + expect(result).toBeDefined(); + expect(result?.jsonSchema).toBeDefined(); + // The exact structure depends on zod-to-json-schema implementation + }); + + it("should handle Zod 4 schema with built-in toJsonSchema method", () => { + // Mock a Zod 4 schema with toJsonSchema method + const mockZod4Schema = { + parse: (val: unknown) => val, + parseAsync: async (val: unknown) => val, + toJsonSchema: () => ({ + type: "object", + properties: { + id: { type: "string" }, + count: { type: "number" }, + }, + required: ["id", "count"], + }), + }; + + const result = schemaToJsonSchema(mockZod4Schema); + + expect(result).toBeDefined(); + expect(result?.schemaType).toBe("zod"); + expect(result?.jsonSchema).toEqual({ + type: "object", + properties: { + id: { type: "string" }, + count: { type: "number" }, + }, + required: ["id", "count"], + }); + }); + }); + + describe("Yup schemas", () => { + it("should convert a simple Yup object schema", () => { + const schema = y.object({ + name: y.string().required(), + age: y.number().required(), + email: y.string().email().required(), + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.schemaType).toBe("yup"); + expect(result?.jsonSchema).toMatchObject({ + type: "object", + properties: { + name: { type: "string" }, + age: { type: "number" }, + email: { type: "string", format: "email" }, + }, + required: ["name", "age", "email"], + }); + }); + + it("should convert a Yup schema with optional fields", () => { + const schema = y.object({ + id: y.string().required(), + description: y.string(), + count: y.number().min(0).max(100), + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.jsonSchema).toMatchObject({ + type: "object", + properties: { + id: { type: "string" }, + description: { type: "string" }, + count: { type: "number", minimum: 0, maximum: 100 }, + }, + required: ["id"], + }); + }); + }); + + describe("ArkType schemas", () => { + it("should convert a simple ArkType schema", () => { + const schema = type({ + name: "string", + age: "number", + active: "boolean", + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.schemaType).toBe("arktype"); + expect(result?.jsonSchema).toBeDefined(); + expect(result?.jsonSchema.type).toBe("object"); + }); + + it("should convert an ArkType schema with optional fields", () => { + const schema = type({ + id: "string", + "description?": "string", + "tags?": "string[]", + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.jsonSchema).toBeDefined(); + expect(result?.jsonSchema.type).toBe("object"); + }); + }); + + describe("Effect schemas", () => { + it("should convert a simple Effect schema", () => { + const schema = Schema.Struct({ + name: Schema.String, + age: Schema.Number, + active: Schema.Boolean, + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.schemaType).toBe("effect"); + expect(result?.jsonSchema).toMatchObject({ + type: "object", + properties: { + name: { type: "string" }, + age: { type: "number" }, + active: { type: "boolean" }, + }, + required: ["name", "age", "active"], + }); + }); + + it("should convert an Effect schema with optional fields", () => { + const schema = Schema.Struct({ + id: Schema.String, + description: Schema.optional(Schema.String), + count: Schema.optional(Schema.Number), + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.jsonSchema).toBeDefined(); + expect(result?.jsonSchema.type).toBe("object"); + }); + }); + + describe("TypeBox schemas", () => { + it("should convert a simple TypeBox schema", () => { + const schema = Type.Object({ + name: Type.String(), + age: Type.Number(), + active: Type.Boolean(), + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.schemaType).toBe("typebox"); + expect(result?.jsonSchema).toMatchObject({ + type: "object", + properties: { + name: { type: "string" }, + age: { type: "number" }, + active: { type: "boolean" }, + }, + required: ["name", "age", "active"], + }); + }); + + it("should convert a TypeBox schema with optional fields", () => { + const schema = Type.Object({ + id: Type.String(), + description: Type.Optional(Type.String()), + tags: Type.Optional(Type.Array(Type.String())), + }); + + const result = schemaToJsonSchema(schema); + + expect(result).toBeDefined(); + expect(result?.jsonSchema).toMatchObject({ + type: "object", + properties: { + id: { type: "string" }, + description: { type: "string" }, + tags: { type: "array", items: { type: "string" } }, + }, + required: ["id"], + }); + }); + }); + + describe("Additional options", () => { + it("should merge additional properties", () => { + const schema = z.object({ + value: z.number(), + }); + + const result = schemaToJsonSchema(schema, { + additionalProperties: { + title: "My Schema", + description: "A test schema", + "x-custom": "custom value", + }, + }); + + expect(result).toBeDefined(); + expect(result?.jsonSchema.title).toBe("My Schema"); + expect(result?.jsonSchema.description).toBe("A test schema"); + expect(result?.jsonSchema["x-custom"]).toBe("custom value"); + }); + }); + + describe("Unsupported schemas", () => { + it("should return undefined for unsupported schema types", () => { + const invalidSchema = { notASchema: true }; + const result = schemaToJsonSchema(invalidSchema); + expect(result).toBeUndefined(); + }); + + it("should return undefined for plain functions", () => { + const fn = (value: unknown) => typeof value === "string"; + const result = schemaToJsonSchema(fn); + expect(result).toBeUndefined(); + }); + }); +}); + +describe("canConvertSchema", () => { + it("should return true for supported schemas", () => { + expect(canConvertSchema(z.string())).toBe(true); + expect(canConvertSchema(y.string())).toBe(true); + expect(canConvertSchema(type("string"))).toBe(true); + expect(canConvertSchema(Schema.String)).toBe(true); + expect(canConvertSchema(Type.String())).toBe(true); + }); + + it("should return false for unsupported schemas", () => { + expect(canConvertSchema({ notASchema: true })).toBe(false); + expect(canConvertSchema(() => true)).toBe(false); + }); +}); + +describe("detectSchemaType", () => { + it("should detect Zod schemas", () => { + expect(detectSchemaType(z.string())).toBe("zod"); + }); + + it("should detect Yup schemas", () => { + expect(detectSchemaType(y.string())).toBe("yup"); + }); + + it("should detect ArkType schemas", () => { + expect(detectSchemaType(type("string"))).toBe("arktype"); + }); + + it("should detect Effect schemas", () => { + expect(detectSchemaType(Schema.String)).toBe("effect"); + }); + + it("should detect TypeBox schemas", () => { + expect(detectSchemaType(Type.String())).toBe("typebox"); + }); + + it("should return unknown for unsupported schemas", () => { + expect(detectSchemaType({ notASchema: true })).toBe("unknown"); + }); +}); diff --git a/packages/schema-to-json/tsconfig.json b/packages/schema-to-json/tsconfig.json new file mode 100644 index 0000000000..5bf5eba8d5 --- /dev/null +++ b/packages/schema-to-json/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../.configs/tsconfig.base.json", + "references": [ + { + "path": "./tsconfig.src.json" + }, + { + "path": "./tsconfig.test.json" + } + ] +} \ No newline at end of file diff --git a/packages/schema-to-json/tsconfig.src.json b/packages/schema-to-json/tsconfig.src.json new file mode 100644 index 0000000000..db06c53317 --- /dev/null +++ b/packages/schema-to-json/tsconfig.src.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "include": ["./src/**/*.ts"], + "compilerOptions": { + "isolatedDeclarations": false, + "composite": true, + "sourceMap": true, + "customConditions": ["@triggerdotdev/source"] + } +} diff --git a/packages/schema-to-json/tsconfig.test.json b/packages/schema-to-json/tsconfig.test.json new file mode 100644 index 0000000000..fb90f380ec --- /dev/null +++ b/packages/schema-to-json/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "include": ["./test/**/*.ts"], + "references": [{ "path": "./tsconfig.src.json" }], + "compilerOptions": { + "isolatedDeclarations": false, + "composite": true, + "sourceMap": true, + "types": ["vitest/globals"] + } +} diff --git a/packages/schema-to-json/vitest.config.ts b/packages/schema-to-json/vitest.config.ts new file mode 100644 index 0000000000..c7da6b38e1 --- /dev/null +++ b/packages/schema-to-json/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + }, +}); \ No newline at end of file diff --git a/packages/trigger-sdk/package.json b/packages/trigger-sdk/package.json index c42cd98d36..b3227c48e3 100644 --- a/packages/trigger-sdk/package.json +++ b/packages/trigger-sdk/package.json @@ -75,10 +75,10 @@ "tshy": "^3.0.2", "tsx": "4.17.0", "typed-emitter": "^2.1.0", - "zod": "3.23.8" + "zod": "3.25.76" }, "peerDependencies": { - "zod": "^3.0.0", + "zod": "^3.0.0 || ^4.0.0", "ai": "^4.2.0" }, "peerDependenciesMeta": { diff --git a/packages/trigger-sdk/src/v3/index.ts b/packages/trigger-sdk/src/v3/index.ts index 4527cd6d01..78554b4539 100644 --- a/packages/trigger-sdk/src/v3/index.ts +++ b/packages/trigger-sdk/src/v3/index.ts @@ -13,6 +13,7 @@ export * from "./metadata.js"; export * from "./timeout.js"; export * from "./webhooks.js"; export * from "./locals.js"; +export * from "./schemas.js"; export type { Context }; import type { Context } from "./shared.js"; diff --git a/packages/trigger-sdk/src/v3/schemas.ts b/packages/trigger-sdk/src/v3/schemas.ts new file mode 100644 index 0000000000..65be53024e --- /dev/null +++ b/packages/trigger-sdk/src/v3/schemas.ts @@ -0,0 +1,2 @@ +// Re-export JSON Schema types for user convenience +export type { JSONSchema } from "@trigger.dev/core/v3"; \ No newline at end of file diff --git a/packages/trigger-sdk/src/v3/shared.ts b/packages/trigger-sdk/src/v3/shared.ts index 487c16308e..05300dc4f9 100644 --- a/packages/trigger-sdk/src/v3/shared.ts +++ b/packages/trigger-sdk/src/v3/shared.ts @@ -76,6 +76,7 @@ import type { TaskBatchOutputHandle, TaskIdentifier, TaskOptions, + TaskOptionsWithSchema, TaskOutput, TaskOutputHandle, TaskPayload, @@ -128,6 +129,16 @@ export function queue(options: QueueOptions): Queue { return options; } +// Overload: when payloadSchema is provided, payload type should be any +export function createTask< + TIdentifier extends string, + TOutput = unknown, + TInitOutput extends InitOutput = any, +>( + params: TaskOptionsWithSchema +): Task; + +// Overload: normal case without payloadSchema export function createTask< TIdentifier extends string, TInput = void, @@ -135,7 +146,18 @@ export function createTask< TInitOutput extends InitOutput = any, >( params: TaskOptions -): Task { +): Task; + +export function createTask< + TIdentifier extends string, + TInput = void, + TOutput = unknown, + TInitOutput extends InitOutput = any, +>( + params: + | TaskOptions + | TaskOptionsWithSchema +): Task | Task { const task: Task = { id: params.id, description: params.description, @@ -204,6 +226,7 @@ export function createTask< retry: params.retry ? { ...defaultRetryOptions, ...params.retry } : undefined, machine: typeof params.machine === "string" ? { preset: params.machine } : params.machine, maxDuration: params.maxDuration, + payloadSchema: params.jsonSchema, fns: { run: params.run, }, @@ -338,6 +361,7 @@ export function createSchemaTask< run: params.run, parsePayload, }, + schema: params.schema, }); const queue = params.queue; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 258ebd571a..ecf9102e50 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -182,8 +182,8 @@ importers: specifier: ^3.8.0 version: 3.8.1 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@types/dockerode': specifier: ^3.3.33 @@ -193,7 +193,7 @@ importers: dependencies: '@ai-sdk/openai': specifier: ^1.3.23 - version: 1.3.23(zod@3.23.8) + version: 1.3.23(zod@3.25.76) '@ariakit/react': specifier: ^0.4.6 version: 0.4.6(react-dom@18.2.0)(react@18.2.0) @@ -244,7 +244,7 @@ importers: version: 0.9.2(react@18.2.0) '@conform-to/zod': specifier: 0.9.2 - version: 0.9.2(@conform-to/dom@0.9.2)(zod@3.23.8) + version: 0.9.2(@conform-to/dom@0.9.2)(zod@3.25.76) '@depot/cli': specifier: 0.0.1-cli.2.80.0 version: 0.0.1-cli.2.80.0 @@ -304,7 +304,7 @@ importers: version: 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0) + version: 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation-express': specifier: ^0.36.1 version: 0.36.1(@opentelemetry/api@1.9.0) @@ -322,7 +322,7 @@ importers: version: 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0) + version: 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': specifier: 1.25.1 version: 1.25.1(@opentelemetry/api@1.9.0) @@ -385,22 +385,22 @@ importers: version: 3.7.1(react@18.2.0) '@remix-run/express': specifier: 2.1.0 - version: 2.1.0(express@4.20.0)(typescript@5.5.4) + version: 2.1.0(express@4.20.0)(typescript@5.8.3) '@remix-run/node': specifier: 2.1.0 - version: 2.1.0(typescript@5.5.4) + version: 2.1.0(typescript@5.8.3) '@remix-run/react': specifier: 2.1.0 - version: 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) + version: 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) '@remix-run/router': specifier: ^1.15.3 version: 1.15.3 '@remix-run/serve': specifier: 2.1.0 - version: 2.1.0(typescript@5.5.4) + version: 2.1.0(typescript@5.8.3) '@remix-run/server-runtime': specifier: 2.1.0 - version: 2.1.0(typescript@5.5.4) + version: 2.1.0(typescript@5.8.3) '@remix-run/v1-meta': specifier: ^0.1.3 version: 0.1.3(@remix-run/react@2.1.0)(@remix-run/server-runtime@2.1.0) @@ -469,7 +469,7 @@ importers: version: 0.9.14 ai: specifier: ^4.3.19 - version: 4.3.19(react@18.2.0)(zod@3.23.8) + version: 4.3.19(react@18.2.0)(zod@3.25.76) assert-never: specifier: ^1.2.1 version: 1.2.1 @@ -478,7 +478,7 @@ importers: version: 1.0.18 class-variance-authority: specifier: ^0.5.2 - version: 0.5.2(typescript@5.5.4) + version: 0.5.2(typescript@5.8.3) clsx: specifier: ^1.2.1 version: 1.2.1 @@ -523,7 +523,7 @@ importers: version: 10.12.11(react-dom@18.2.0)(react@18.2.0) graphile-worker: specifier: 0.16.6 - version: 0.16.6(patch_hash=hdpetta7btqcc7xb5wfkcnanoa)(typescript@5.5.4) + version: 0.16.6(patch_hash=hdpetta7btqcc7xb5wfkcnanoa)(typescript@5.8.3) humanize-duration: specifier: ^3.27.3 version: 3.27.3 @@ -652,7 +652,7 @@ importers: version: 0.3.1(@remix-run/react@2.1.0)(@remix-run/server-runtime@2.1.0)(react@18.2.0) remix-utils: specifier: ^7.7.0 - version: 7.7.0(@remix-run/node@2.1.0)(@remix-run/react@2.1.0)(@remix-run/router@1.15.3)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.23.8) + version: 7.7.0(@remix-run/node@2.1.0)(@remix-run/react@2.1.0)(@remix-run/router@1.15.3)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.25.76) seedrandom: specifier: ^3.0.5 version: 3.0.5 @@ -711,14 +711,14 @@ importers: specifier: ^8.11.0 version: 8.12.0 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 zod-error: specifier: 1.5.0 version: 1.5.0 zod-validation-error: specifier: ^1.5.0 - version: 1.5.0(zod@3.23.8) + version: 1.5.0(zod@3.25.76) devDependencies: '@internal/clickhouse': specifier: workspace:* @@ -731,13 +731,13 @@ importers: version: link:../../internal-packages/testcontainers '@remix-run/dev': specifier: 2.1.0 - version: 2.1.0(@remix-run/serve@2.1.0)(@types/node@20.14.14)(ts-node@10.9.1)(typescript@5.5.4) + version: 2.1.0(@remix-run/serve@2.1.0)(@types/node@20.14.14)(ts-node@10.9.1)(typescript@5.8.3) '@remix-run/eslint-config': specifier: 2.1.0 - version: 2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.5.4) + version: 2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.8.3) '@remix-run/testing': specifier: ^2.1.0 - version: 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) + version: 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) '@sentry/cli': specifier: 2.50.2 version: 2.50.2 @@ -836,10 +836,10 @@ importers: version: 8.5.4 '@typescript-eslint/eslint-plugin': specifier: ^5.59.6 - version: 5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.5.4) + version: 5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.8.3) '@typescript-eslint/parser': specifier: ^5.59.6 - version: 5.59.6(eslint@8.31.0)(typescript@5.5.4) + version: 5.59.6(eslint@8.31.0)(typescript@5.8.3) autoevals: specifier: ^0.0.130 version: 0.0.130(ws@8.12.0) @@ -884,7 +884,7 @@ importers: version: 16.0.1(postcss@8.5.4) postcss-loader: specifier: ^8.1.1 - version: 8.1.1(postcss@8.5.4)(typescript@5.5.4)(webpack@5.99.9) + version: 8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.99.9) prettier: specifier: ^2.8.8 version: 2.8.8 @@ -911,13 +911,13 @@ importers: version: 3.4.1(ts-node@10.9.1) ts-node: specifier: ^10.7.0 - version: 10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.5.4) + version: 10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.8.3) tsconfig-paths: specifier: ^3.14.1 version: 3.14.1 vite-tsconfig-paths: specifier: ^4.0.5 - version: 4.0.5(typescript@5.5.4) + version: 4.0.5(typescript@5.8.3) docs: {} @@ -951,8 +951,8 @@ importers: specifier: workspace:* version: link:../../packages/core zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 zod-error: specifier: 1.5.0 version: 1.5.0 @@ -1004,8 +1004,8 @@ importers: specifier: ^1.2.0 version: 1.3.1 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@types/nodemailer': specifier: ^6.4.17 @@ -1103,8 +1103,8 @@ importers: specifier: ^3.0.5 version: 3.0.5 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@internal/testcontainers': specifier: workspace:* @@ -1143,8 +1143,8 @@ importers: specifier: 3.3.8 version: 3.3.8 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@internal/testcontainers': specifier: workspace:* @@ -1220,8 +1220,8 @@ importers: specifier: ^4.5.0 version: 4.5.0 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@types/lodash.omit': specifier: ^4.5.7 @@ -1270,8 +1270,8 @@ importers: specifier: 0.0.1-cli.2.80.0 version: 0.0.1-cli.2.80.0 '@modelcontextprotocol/sdk': - specifier: ^1.6.1 - version: 1.6.1(supports-color@10.0.0) + specifier: ^1.17.0 + version: 1.17.0(supports-color@10.0.0) '@opentelemetry/api': specifier: 1.9.0 version: 1.9.0 @@ -1314,6 +1314,9 @@ importers: '@trigger.dev/core': specifier: workspace:4.0.0-v4-beta.25 version: link:../core + '@trigger.dev/schema-to-json': + specifier: workspace:4.0.0-v4-beta.25 + version: link:../schema-to-json ansi-escapes: specifier: ^7.0.0 version: 7.0.0 @@ -1444,11 +1447,11 @@ importers: specifier: ^8.3.0 version: 8.3.0 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 zod-validation-error: specifier: ^1.5.0 - version: 1.5.0(zod@3.23.8) + version: 1.5.0(zod@3.25.76) devDependencies: '@epic-web/test-server': specifier: ^0.1.0 @@ -1526,38 +1529,35 @@ importers: specifier: 1.9.0 version: 1.9.0 '@opentelemetry/api-logs': - specifier: 0.52.1 - version: 0.52.1 + specifier: 0.203.0 + version: 0.203.0 '@opentelemetry/core': - specifier: ^1.30.1 - version: 1.30.1(@opentelemetry/api@1.9.0) + specifier: 2.0.1 + version: 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-logs-otlp-http': - specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0) + specifier: 0.203.0 + version: 0.203.0(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-http': - specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0) + specifier: 0.203.0 + version: 0.203.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': - specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0) + specifier: 0.203.0 + version: 0.203.0(@opentelemetry/api@1.9.0)(supports-color@10.0.0) '@opentelemetry/resources': - specifier: 1.25.1 - version: 1.25.1(@opentelemetry/api@1.9.0) + specifier: 2.0.1 + version: 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-logs': - specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-node': - specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0) + specifier: 0.203.0 + version: 0.203.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': - specifier: 1.25.1 - version: 1.25.1(@opentelemetry/api@1.9.0) + specifier: 2.0.1 + version: 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': - specifier: 1.25.1 - version: 1.25.1(@opentelemetry/api@1.9.0) + specifier: 2.0.1 + version: 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': - specifier: 1.25.1 - version: 1.25.1 + specifier: 1.36.0 + version: 1.36.0 dequal: specifier: ^2.0.3 version: 2.0.3 @@ -1604,18 +1604,18 @@ importers: specifier: ^0.1.3 version: 0.1.3 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 zod-error: specifier: 1.5.0 version: 1.5.0 zod-validation-error: specifier: ^1.5.0 - version: 1.5.0(zod@3.23.8) + version: 1.5.0(zod@3.25.76) devDependencies: '@ai-sdk/provider-utils': specifier: ^1.0.22 - version: 1.0.22(zod@3.23.8) + version: 1.0.22(zod@3.25.76) '@arethetypeswrong/cli': specifier: ^0.15.4 version: 0.15.4 @@ -1636,7 +1636,7 @@ importers: version: 4.0.14 ai: specifier: ^3.4.33 - version: 3.4.33(react@18.3.1)(svelte@5.33.14)(vue@3.5.16)(zod@3.23.8) + version: 3.4.33(react@18.3.1)(svelte@5.33.14)(vue@3.5.16)(zod@3.25.76) defu: specifier: ^6.1.4 version: 6.1.4 @@ -1745,8 +1745,8 @@ importers: specifier: ^6.2.0 version: 6.2.0 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@internal/redis': specifier: workspace:* @@ -1810,6 +1810,55 @@ importers: specifier: 4.17.0 version: 4.17.0 + packages/schema-to-json: + dependencies: + '@sodaru/yup-to-json-schema': + specifier: ^2.0.1 + version: 2.0.1 + '@trigger.dev/core': + specifier: workspace:* + version: link:../core + zod-to-json-schema: + specifier: ^3.24.5 + version: 3.24.5(zod@3.25.76) + devDependencies: + '@effect/schema': + specifier: ^0.75.5 + version: 0.75.5(effect@3.17.1) + '@sinclair/typebox': + specifier: ^0.34.3 + version: 0.34.38 + arktype: + specifier: ^2.0.0 + version: 2.1.20 + effect: + specifier: ^3.11.11 + version: 3.17.1 + rimraf: + specifier: 6.0.1 + version: 6.0.1 + runtypes: + specifier: ^6.7.0 + version: 6.7.0 + superstruct: + specifier: ^2.0.2 + version: 2.0.2 + tshy: + specifier: ^3.0.2 + version: 3.0.2 + valibot: + specifier: ^1.0.0-beta.8 + version: 1.1.0(typescript@5.5.4) + vitest: + specifier: ^2.1.8 + version: 2.1.9(@types/node@20.14.14) + yup: + specifier: ^1.6.1 + version: 1.6.1 + zod: + specifier: ^3.24.1 || ^4.0.0 + version: 3.25.76 + packages/trigger-sdk: dependencies: '@opentelemetry/api': @@ -1869,7 +1918,7 @@ importers: version: 8.5.4 ai: specifier: ^4.2.0 - version: 4.2.5(react@18.3.1)(zod@3.23.8) + version: 4.2.5(react@18.3.1)(zod@3.25.76) encoding: specifier: ^0.1.13 version: 0.1.13 @@ -1886,8 +1935,8 @@ importers: specifier: ^2.1.0 version: 2.1.0 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 references/bun-catalog: dependencies: @@ -1906,10 +1955,10 @@ importers: dependencies: '@ai-sdk/anthropic': specifier: ^1.2.4 - version: 1.2.4(zod@3.23.8) + version: 1.2.4(zod@3.25.76) '@ai-sdk/openai': specifier: 1.3.3 - version: 1.3.3(zod@3.23.8) + version: 1.3.3(zod@3.25.76) '@e2b/code-interpreter': specifier: ^1.1.0 version: 1.1.0 @@ -1939,7 +1988,7 @@ importers: version: 0.10.0 ai: specifier: 4.2.5 - version: 4.2.5(react@19.0.0)(zod@3.23.8) + version: 4.2.5(react@19.0.0)(zod@3.25.76) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -1974,8 +2023,8 @@ importers: specifier: ^1.2.4 version: 1.2.4 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@tailwindcss/postcss': specifier: ^4 @@ -2012,7 +2061,7 @@ importers: dependencies: '@ai-sdk/openai': specifier: 1.3.3 - version: 1.3.3(zod@3.23.8) + version: 1.3.3(zod@3.25.76) '@slack/web-api': specifier: 7.9.1 version: 7.9.1 @@ -2030,7 +2079,7 @@ importers: version: 0.10.0 ai: specifier: 4.2.5 - version: 4.2.5(react@19.0.0)(zod@3.23.8) + version: 4.2.5(react@19.0.0)(zod@3.25.76) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -2059,11 +2108,11 @@ importers: specifier: ^1.2.4 version: 1.2.4 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 zod-to-json-schema: specifier: ^3.24.5 - version: 3.24.5(zod@3.23.8) + version: 3.24.5(zod@3.25.76) devDependencies: '@tailwindcss/postcss': specifier: ^4 @@ -2114,24 +2163,33 @@ importers: references/hello-world: dependencies: + '@sinclair/typebox': + specifier: ^0.34.3 + version: 0.34.38 '@trigger.dev/build': specifier: workspace:* version: link:../../packages/build '@trigger.dev/sdk': specifier: workspace:* version: link:../../packages/trigger-sdk + arktype: + specifier: ^2.0.0 + version: 2.1.20 openai: specifier: ^4.97.0 - version: 4.97.0(ws@8.12.0)(zod@3.23.8) + version: 4.97.0(ws@8.12.0)(zod@3.25.76) puppeteer-core: specifier: ^24.15.0 version: 24.15.0 replicate: specifier: ^1.0.1 version: 1.0.1 + yup: + specifier: ^1.6.1 + version: 1.6.1 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: trigger.dev: specifier: workspace:* @@ -2149,11 +2207,51 @@ importers: specifier: workspace:* version: link:../../packages/cli-v3 + references/json-schema-test: + dependencies: + '@effect/schema': + specifier: ^0.75.5 + version: 0.75.5(effect@3.17.1) + '@sinclair/typebox': + specifier: ^0.34.3 + version: 0.34.38 + '@trigger.dev/sdk': + specifier: workspace:* + version: link:../../packages/trigger-sdk + arktype: + specifier: ^2.0.0 + version: 2.1.20 + effect: + specifier: ^3.11.11 + version: 3.17.1 + runtypes: + specifier: ^6.7.0 + version: 6.7.0 + superstruct: + specifier: ^2.0.2 + version: 2.0.2 + valibot: + specifier: ^1.0.0-beta.8 + version: 1.1.0(typescript@5.8.3) + yup: + specifier: ^1.6.1 + version: 1.6.1 + zod: + specifier: 3.22.3 + version: 3.22.3 + devDependencies: + '@types/node': + specifier: ^20.14.8 + version: 20.14.14 + typescript: + specifier: ^5.7.2 + version: 5.8.3 + references/nextjs-realtime: dependencies: '@ai-sdk/openai': specifier: ^1.0.1 - version: 1.0.1(zod@3.23.8) + version: 1.0.1(zod@3.25.76) '@fal-ai/serverless-client': specifier: ^0.15.0 version: 0.15.0 @@ -2192,7 +2290,7 @@ importers: version: 7.0.3(next@14.2.21)(react@18.3.1)(uploadthing@7.1.0) ai: specifier: ^4.0.0 - version: 4.0.0(react@18.3.1)(zod@3.23.8) + version: 4.0.0(react@18.3.1)(zod@3.25.76) class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -2213,7 +2311,7 @@ importers: version: 14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.37.0)(react-dom@18.2.0)(react@18.3.1) openai: specifier: ^4.68.4 - version: 4.68.4(zod@3.23.8) + version: 4.68.4(zod@3.25.76) react: specifier: ^18 version: 18.3.1 @@ -2230,8 +2328,8 @@ importers: specifier: ^7.1.0 version: 7.1.0(next@14.2.21)(tailwindcss@3.4.1) zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@next/bundle-analyzer': specifier: ^15.0.2 @@ -2264,8 +2362,8 @@ importers: specifier: workspace:* version: link:../../packages/trigger-sdk zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@trigger.dev/build': specifier: workspace:* @@ -2283,8 +2381,8 @@ importers: specifier: workspace:* version: link:../../packages/trigger-sdk zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@trigger.dev/build': specifier: workspace:* @@ -2330,10 +2428,10 @@ importers: version: 2.2.1 '@t3-oss/env-core': specifier: ^0.11.0 - version: 0.11.0(typescript@5.5.4)(zod@3.23.8) + version: 0.11.0(typescript@5.8.3)(zod@3.25.76) '@t3-oss/env-nextjs': specifier: ^0.10.1 - version: 0.10.1(typescript@5.5.4)(zod@3.23.8) + version: 0.10.1(typescript@5.8.3)(zod@3.25.76) '@traceloop/instrumentation-openai': specifier: ^0.10.0 version: 0.10.0(@opentelemetry/api@1.4.1) @@ -2345,7 +2443,7 @@ importers: version: 0.14.0(@sinclair/typebox@0.33.17) ai: specifier: ^3.3.24 - version: 3.3.24(openai@4.56.0)(react@19.0.0-rc.0)(svelte@5.33.14)(vue@3.5.16)(zod@3.23.8) + version: 3.3.24(openai@4.56.0)(react@19.0.0-rc.0)(svelte@5.33.14)(vue@3.5.16)(zod@3.25.76) arktype: specifier: 2.0.0-rc.17 version: 2.0.0-rc.17 @@ -2375,13 +2473,13 @@ importers: version: 0.27.4 msw: specifier: ^2.2.1 - version: 2.3.5(typescript@5.5.4) + version: 2.3.5(typescript@5.8.3) mupdf: specifier: ^1.3.6 version: 1.3.6 openai: specifier: ^4.47.0 - version: 4.56.0(zod@3.23.8) + version: 4.56.0(zod@3.25.76) pg: specifier: ^8.11.5 version: 8.11.5 @@ -2390,7 +2488,7 @@ importers: version: 1.50.1 puppeteer: specifier: ^23.4.0 - version: 23.4.0(typescript@5.5.4) + version: 23.4.0(typescript@5.8.3) react: specifier: 19.0.0-rc.0 version: 19.0.0-rc.0 @@ -2423,7 +2521,7 @@ importers: version: 0.3.20(pg@8.11.5)(sqlite3@5.1.7)(ts-node@10.9.2) valibot: specifier: ^0.42.1 - version: 0.42.1(typescript@5.5.4) + version: 0.42.1(typescript@5.8.3) wrangler: specifier: 3.70.0 version: 3.70.0 @@ -2437,8 +2535,8 @@ importers: specifier: ^0.0.11 version: 0.0.11 zod: - specifier: 3.23.8 - version: 3.23.8 + specifier: 3.25.76 + version: 3.25.76 devDependencies: '@opentelemetry/core': specifier: ^1.22.0 @@ -2514,7 +2612,7 @@ importers: version: link:../../packages/cli-v3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.14.14)(typescript@5.5.4) + version: 10.9.2(@types/node@20.14.14)(typescript@5.8.3) tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 @@ -2535,51 +2633,51 @@ packages: resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} dev: false - /@ai-sdk/anthropic@1.2.4(zod@3.23.8): + /@ai-sdk/anthropic@1.2.4(zod@3.25.76): resolution: {integrity: sha512-dAN6MXvLffeFVAr2gz3RGvOTgX1KL/Yn5q1l4/Dt0TUeDjQgCt4AbbYxZZB2qIAYzQvoyAFPhlw0sB3nNizG/g==} engines: {node: '>=18'} peerDependencies: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.3(zod@3.23.8) - zod: 3.23.8 + '@ai-sdk/provider-utils': 2.2.3(zod@3.25.76) + zod: 3.25.76 dev: false - /@ai-sdk/openai@1.0.1(zod@3.23.8): + /@ai-sdk/openai@1.0.1(zod@3.25.76): resolution: {integrity: sha512-snZge8457afWlosVNUn+BG60MrxAPOOm3zmIMxJZih8tneNSiRbTVCbSzAtq/9vsnOHDe5RR83PRl85juOYEnA==} engines: {node: '>=18'} peerDependencies: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.0.0 - '@ai-sdk/provider-utils': 2.0.0(zod@3.23.8) - zod: 3.23.8 + '@ai-sdk/provider-utils': 2.0.0(zod@3.25.76) + zod: 3.25.76 dev: false - /@ai-sdk/openai@1.3.23(zod@3.23.8): + /@ai-sdk/openai@1.3.23(zod@3.25.76): resolution: {integrity: sha512-86U7rFp8yacUAOE/Jz8WbGcwMCqWvjK33wk5DXkfnAOEn3mx2r7tNSJdjukQFZbAK97VMXGPPHxF+aEARDXRXQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - zod: 3.23.8 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 dev: false - /@ai-sdk/openai@1.3.3(zod@3.23.8): + /@ai-sdk/openai@1.3.3(zod@3.25.76): resolution: {integrity: sha512-CH57tonLB4DwkwqwnMmTCoIOR7cNW3bP5ciyloI7rBGJS/Bolemsoo+vn5YnwkyT9O1diWJyvYeTh7A4UfiYOw==} engines: {node: '>=18'} peerDependencies: zod: ^3.0.0 dependencies: '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.1(zod@3.23.8) - zod: 3.23.8 + '@ai-sdk/provider-utils': 2.2.1(zod@3.25.76) + zod: 3.25.76 dev: false - /@ai-sdk/provider-utils@1.0.17(zod@3.23.8): + /@ai-sdk/provider-utils@1.0.17(zod@3.25.76): resolution: {integrity: sha512-2VyeTH5DQ6AxqvwdyytKIeiZyYTyJffpufWjE67zM2sXMIHgYl7fivo8m5wVl6Cbf1dFPSGKq//C9s+lz+NHrQ==} engines: {node: '>=18'} peerDependencies: @@ -2592,10 +2690,10 @@ packages: eventsource-parser: 1.1.2 nanoid: 3.3.6 secure-json-parse: 2.7.0 - zod: 3.23.8 + zod: 3.25.76 dev: false - /@ai-sdk/provider-utils@1.0.22(zod@3.23.8): + /@ai-sdk/provider-utils@1.0.22(zod@3.25.76): resolution: {integrity: sha512-YHK2rpj++wnLVc9vPGzGFP3Pjeld2MwhKinetA0zKXOoHAT/Jit5O8kZsxcSlJPu9wvcGT1UGZEjZrtO7PfFOQ==} engines: {node: '>=18'} peerDependencies: @@ -2608,10 +2706,10 @@ packages: eventsource-parser: 1.1.2 nanoid: 3.3.8 secure-json-parse: 2.7.0 - zod: 3.23.8 + zod: 3.25.76 dev: true - /@ai-sdk/provider-utils@2.0.0(zod@3.23.8): + /@ai-sdk/provider-utils@2.0.0(zod@3.25.76): resolution: {integrity: sha512-uITgVJByhtzuQU2ZW+2CidWRmQqTUTp6KADevy+4aRnmILZxY2LCt+UZ/ZtjJqq0MffwkuQPPY21ExmFAQ6kKA==} engines: {node: '>=18'} peerDependencies: @@ -2624,10 +2722,10 @@ packages: eventsource-parser: 3.0.0 nanoid: 5.1.5 secure-json-parse: 2.7.0 - zod: 3.23.8 + zod: 3.25.76 dev: false - /@ai-sdk/provider-utils@2.2.1(zod@3.23.8): + /@ai-sdk/provider-utils@2.2.1(zod@3.25.76): resolution: {integrity: sha512-BuExLp+NcpwsAVj1F4bgJuQkSqO/+roV9wM7RdIO+NVrcT8RBUTdXzf5arHt5T58VpK7bZyB2V9qigjaPHE+Dg==} engines: {node: '>=18'} peerDependencies: @@ -2636,9 +2734,9 @@ packages: '@ai-sdk/provider': 1.1.0 nanoid: 3.3.8 secure-json-parse: 2.7.0 - zod: 3.23.8 + zod: 3.25.76 - /@ai-sdk/provider-utils@2.2.3(zod@3.23.8): + /@ai-sdk/provider-utils@2.2.3(zod@3.25.76): resolution: {integrity: sha512-o3fWTzkxzI5Af7U7y794MZkYNEsxbjLam2nxyoUZSScqkacb7vZ3EYHLh21+xCcSSzEC161C7pZAGHtC0hTUMw==} engines: {node: '>=18'} peerDependencies: @@ -2647,10 +2745,10 @@ packages: '@ai-sdk/provider': 1.1.0 nanoid: 3.3.8 secure-json-parse: 2.7.0 - zod: 3.23.8 + zod: 3.25.76 dev: false - /@ai-sdk/provider-utils@2.2.8(zod@3.23.8): + /@ai-sdk/provider-utils@2.2.8(zod@3.25.76): resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} engines: {node: '>=18'} peerDependencies: @@ -2659,7 +2757,7 @@ packages: '@ai-sdk/provider': 1.1.3 nanoid: 3.3.8 secure-json-parse: 2.7.0 - zod: 3.23.8 + zod: 3.25.76 dev: false /@ai-sdk/provider@0.0.22: @@ -2696,7 +2794,7 @@ packages: json-schema: 0.4.0 dev: false - /@ai-sdk/react@0.0.53(react@19.0.0-rc.0)(zod@3.23.8): + /@ai-sdk/react@0.0.53(react@19.0.0-rc.0)(zod@3.25.76): resolution: {integrity: sha512-sIsmTFoR/QHvUUkltmHwP4bPjwy2vko6j/Nj8ayxLhEHs04Ug+dwXQyfA7MwgimEE3BcDQpWL8ikVj0m3ZILWQ==} engines: {node: '>=18'} peerDependencies: @@ -2708,14 +2806,14 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.17(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.40(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.17(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.40(zod@3.25.76) react: 19.0.0-rc.0 swr: 2.2.5(react@19.0.0-rc.0) - zod: 3.23.8 + zod: 3.25.76 dev: false - /@ai-sdk/react@0.0.70(react@18.3.1)(zod@3.23.8): + /@ai-sdk/react@0.0.70(react@18.3.1)(zod@3.25.76): resolution: {integrity: sha512-GnwbtjW4/4z7MleLiW+TOZC2M29eCg1tOUpuEiYFMmFNZK8mkrqM0PFZMo6UsYeUYMWqEOOcPOU9OQVJMJh7IQ==} engines: {node: '>=18'} peerDependencies: @@ -2727,15 +2825,15 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.50(zod@3.25.76) react: 18.3.1 swr: 2.2.5(react@18.3.1) throttleit: 2.1.0 - zod: 3.23.8 + zod: 3.25.76 dev: true - /@ai-sdk/react@1.0.0(react@18.3.1)(zod@3.23.8): + /@ai-sdk/react@1.0.0(react@18.3.1)(zod@3.25.76): resolution: {integrity: sha512-BDrZqQA07Btg64JCuhFvBgYV+tt2B8cXINzEqWknGoxqcwgdE8wSLG2gkXoLzyC2Rnj7oj0HHpOhLUxDCmoKZg==} engines: {node: '>=18'} peerDependencies: @@ -2747,15 +2845,15 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 2.0.0(zod@3.23.8) - '@ai-sdk/ui-utils': 1.0.0(zod@3.23.8) + '@ai-sdk/provider-utils': 2.0.0(zod@3.25.76) + '@ai-sdk/ui-utils': 1.0.0(zod@3.25.76) react: 18.3.1 swr: 2.2.5(react@18.3.1) throttleit: 2.1.0 - zod: 3.23.8 + zod: 3.25.76 dev: false - /@ai-sdk/react@1.2.12(react@18.2.0)(zod@3.23.8): + /@ai-sdk/react@1.2.12(react@18.2.0)(zod@3.25.76): resolution: {integrity: sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==} engines: {node: '>=18'} peerDependencies: @@ -2765,15 +2863,15 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.11(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) react: 18.2.0 swr: 2.2.5(react@18.2.0) throttleit: 2.1.0 - zod: 3.23.8 + zod: 3.25.76 dev: false - /@ai-sdk/react@1.2.2(react@18.3.1)(zod@3.23.8): + /@ai-sdk/react@1.2.2(react@18.3.1)(zod@3.25.76): resolution: {integrity: sha512-rxyNTFjUd3IilVOJFuUJV5ytZBYAIyRi50kFS2gNmSEiG4NHMBBm31ddrxI/i86VpY8gzZVp1/igtljnWBihUA==} engines: {node: '>=18'} peerDependencies: @@ -2783,15 +2881,15 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 2.2.1(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.1(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.1(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.1(zod@3.25.76) react: 18.3.1 swr: 2.2.5(react@18.3.1) throttleit: 2.1.0 - zod: 3.23.8 + zod: 3.25.76 dev: true - /@ai-sdk/react@1.2.2(react@19.0.0)(zod@3.23.8): + /@ai-sdk/react@1.2.2(react@19.0.0)(zod@3.25.76): resolution: {integrity: sha512-rxyNTFjUd3IilVOJFuUJV5ytZBYAIyRi50kFS2gNmSEiG4NHMBBm31ddrxI/i86VpY8gzZVp1/igtljnWBihUA==} engines: {node: '>=18'} peerDependencies: @@ -2801,15 +2899,15 @@ packages: zod: optional: true dependencies: - '@ai-sdk/provider-utils': 2.2.1(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.1(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.1(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.1(zod@3.25.76) react: 19.0.0 swr: 2.2.5(react@19.0.0) throttleit: 2.1.0 - zod: 3.23.8 + zod: 3.25.76 dev: false - /@ai-sdk/solid@0.0.43(zod@3.23.8): + /@ai-sdk/solid@0.0.43(zod@3.25.76): resolution: {integrity: sha512-7PlPLaeMAu97oOY2gjywvKZMYHF+GDfUxYNcuJ4AZ3/MRBatzs/U2r4ClT1iH8uMOcMg02RX6UKzP5SgnUBjVw==} engines: {node: '>=18'} peerDependencies: @@ -2818,13 +2916,13 @@ packages: solid-js: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.17(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.40(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.17(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.40(zod@3.25.76) transitivePeerDependencies: - zod dev: false - /@ai-sdk/solid@0.0.54(zod@3.23.8): + /@ai-sdk/solid@0.0.54(zod@3.25.76): resolution: {integrity: sha512-96KWTVK+opdFeRubqrgaJXoNiDP89gNxFRWUp0PJOotZW816AbhUf4EnDjBjXTLjXL1n0h8tGSE9sZsRkj9wQQ==} engines: {node: '>=18'} peerDependencies: @@ -2833,13 +2931,13 @@ packages: solid-js: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.50(zod@3.25.76) transitivePeerDependencies: - zod dev: true - /@ai-sdk/svelte@0.0.45(svelte@5.33.14)(zod@3.23.8): + /@ai-sdk/svelte@0.0.45(svelte@5.33.14)(zod@3.25.76): resolution: {integrity: sha512-w5Sdl0ArFIM3Fp8BbH4TUvlrS84WP/jN/wC1+fghMOXd7ceVO3Yhs9r71wTqndhgkLC7LAEX9Ll7ZEPfW9WBDA==} engines: {node: '>=18'} peerDependencies: @@ -2848,15 +2946,15 @@ packages: svelte: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.17(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.40(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.17(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.40(zod@3.25.76) sswr: 2.1.0(svelte@5.33.14) svelte: 5.33.14 transitivePeerDependencies: - zod dev: false - /@ai-sdk/svelte@0.0.57(svelte@5.33.14)(zod@3.23.8): + /@ai-sdk/svelte@0.0.57(svelte@5.33.14)(zod@3.25.76): resolution: {integrity: sha512-SyF9ItIR9ALP9yDNAD+2/5Vl1IT6kchgyDH8xkmhysfJI6WrvJbtO1wdQ0nylvPLcsPoYu+cAlz1krU4lFHcYw==} engines: {node: '>=18'} peerDependencies: @@ -2865,15 +2963,15 @@ packages: svelte: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.50(zod@3.25.76) sswr: 2.1.0(svelte@5.33.14) svelte: 5.33.14 transitivePeerDependencies: - zod dev: true - /@ai-sdk/ui-utils@0.0.40(zod@3.23.8): + /@ai-sdk/ui-utils@0.0.40(zod@3.25.76): resolution: {integrity: sha512-f0eonPUBO13pIO8jA9IGux7IKMeqpvWK22GBr3tOoSRnO5Wg5GEpXZU1V0Po+unpeZHyEPahrWbj5JfXcyWCqw==} engines: {node: '>=18'} peerDependencies: @@ -2883,14 +2981,14 @@ packages: optional: true dependencies: '@ai-sdk/provider': 0.0.22 - '@ai-sdk/provider-utils': 1.0.17(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.17(zod@3.25.76) json-schema: 0.4.0 secure-json-parse: 2.7.0 - zod: 3.23.8 - zod-to-json-schema: 3.23.2(zod@3.23.8) + zod: 3.25.76 + zod-to-json-schema: 3.23.2(zod@3.25.76) dev: false - /@ai-sdk/ui-utils@0.0.50(zod@3.23.8): + /@ai-sdk/ui-utils@0.0.50(zod@3.25.76): resolution: {integrity: sha512-Z5QYJVW+5XpSaJ4jYCCAVG7zIAuKOOdikhgpksneNmKvx61ACFaf98pmOd+xnjahl0pIlc/QIe6O4yVaJ1sEaw==} engines: {node: '>=18'} peerDependencies: @@ -2900,14 +2998,14 @@ packages: optional: true dependencies: '@ai-sdk/provider': 0.0.26 - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) json-schema: 0.4.0 secure-json-parse: 2.7.0 - zod: 3.23.8 - zod-to-json-schema: 3.24.5(zod@3.23.8) + zod: 3.25.76 + zod-to-json-schema: 3.24.5(zod@3.25.76) dev: true - /@ai-sdk/ui-utils@1.0.0(zod@3.23.8): + /@ai-sdk/ui-utils@1.0.0(zod@3.25.76): resolution: {integrity: sha512-oXBDIM/0niWeTWyw77RVl505dNxBUDLLple7bTsqo2d3i1UKwGlzBUX8XqZsh7GbY7I6V05nlG0Y8iGlWxv1Aw==} engines: {node: '>=18'} peerDependencies: @@ -2917,35 +3015,35 @@ packages: optional: true dependencies: '@ai-sdk/provider': 1.0.0 - '@ai-sdk/provider-utils': 2.0.0(zod@3.23.8) - zod: 3.23.8 - zod-to-json-schema: 3.24.5(zod@3.23.8) + '@ai-sdk/provider-utils': 2.0.0(zod@3.25.76) + zod: 3.25.76 + zod-to-json-schema: 3.24.5(zod@3.25.76) dev: false - /@ai-sdk/ui-utils@1.2.1(zod@3.23.8): + /@ai-sdk/ui-utils@1.2.1(zod@3.25.76): resolution: {integrity: sha512-BzvMbYm7LHBlbWuLlcG1jQh4eu14MGpz7L+wrGO1+F4oQ+O0fAjgUSNwPWGlZpKmg4NrcVq/QLmxiVJrx2R4Ew==} engines: {node: '>=18'} peerDependencies: zod: ^3.23.8 dependencies: '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.1(zod@3.23.8) - zod: 3.23.8 - zod-to-json-schema: 3.24.5(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.1(zod@3.25.76) + zod: 3.25.76 + zod-to-json-schema: 3.24.5(zod@3.25.76) - /@ai-sdk/ui-utils@1.2.11(zod@3.23.8): + /@ai-sdk/ui-utils@1.2.11(zod@3.25.76): resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==} engines: {node: '>=18'} peerDependencies: zod: ^3.23.8 dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - zod: 3.23.8 - zod-to-json-schema: 3.24.5(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + zod-to-json-schema: 3.24.5(zod@3.25.76) dev: false - /@ai-sdk/vue@0.0.45(vue@3.5.16)(zod@3.23.8): + /@ai-sdk/vue@0.0.45(vue@3.5.16)(zod@3.25.76): resolution: {integrity: sha512-bqeoWZqk88TQmfoPgnFUKkrvhOIcOcSH5LMPgzZ8XwDqz5tHHrMHzpPfHCj7XyYn4ROTFK/2kKdC/ta6Ko0fMw==} engines: {node: '>=18'} peerDependencies: @@ -2954,15 +3052,15 @@ packages: vue: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.17(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.40(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.17(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.40(zod@3.25.76) swrv: 1.0.4(vue@3.5.16) - vue: 3.5.16(typescript@5.5.4) + vue: 3.5.16(typescript@5.8.3) transitivePeerDependencies: - zod dev: false - /@ai-sdk/vue@0.0.59(vue@3.5.16)(zod@3.23.8): + /@ai-sdk/vue@0.0.59(vue@3.5.16)(zod@3.25.76): resolution: {integrity: sha512-+ofYlnqdc8c4F6tM0IKF0+7NagZRAiqBJpGDJ+6EYhDW8FHLUP/JFBgu32SjxSxC6IKFZxEnl68ZoP/Z38EMlw==} engines: {node: '>=18'} peerDependencies: @@ -2971,8 +3069,8 @@ packages: vue: optional: true dependencies: - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.50(zod@3.25.76) swrv: 1.0.4(vue@3.5.16) vue: 3.5.16(typescript@5.5.4) transitivePeerDependencies: @@ -3059,10 +3157,18 @@ packages: '@ark/util': 0.18.0 dev: false + /@ark/schema@0.46.0: + resolution: {integrity: sha512-c2UQdKgP2eqqDArfBqQIJppxJHvNNXuQPeuSPlDML4rjw+f1cu0qAlzOG4b8ujgm9ctIDWwhpyw6gjG5ledIVQ==} + dependencies: + '@ark/util': 0.46.0 + /@ark/util@0.18.0: resolution: {integrity: sha512-TpHY532LKQwwYHui5NN/eO/6eSiSMvf652YNt1BsV7fya7RzXL27IiU9x4bm7jTFZxLQGYDQTB7nw41TqeuF4g==} dev: false + /@ark/util@0.46.0: + resolution: {integrity: sha512-JPy/NGWn/lvf1WmGCPw2VGpBg5utZraE84I7wli18EDF3p3zc/e9WolT35tINeZO3l7C77SjqRJeAUoT0CvMRg==} + /@arr/every@1.0.1: resolution: {integrity: sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==} engines: {node: '>=4'} @@ -4817,7 +4923,7 @@ packages: '@babel/traverse': 7.24.7 '@babel/types': 7.24.0 convert-source-map: 1.9.0 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -4839,7 +4945,7 @@ packages: '@babel/traverse': 7.24.7 '@babel/types': 7.27.0 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -5416,7 +5522,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.24.7 '@babel/types': 7.24.0 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -5434,7 +5540,7 @@ packages: '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.27.0 '@babel/types': 7.27.0 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -5448,7 +5554,7 @@ packages: '@babel/parser': 7.27.0 '@babel/template': 7.25.0 '@babel/types': 7.27.0 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6010,14 +6116,14 @@ packages: react: 18.2.0 dev: false - /@conform-to/zod@0.9.2(@conform-to/dom@0.9.2)(zod@3.23.8): + /@conform-to/zod@0.9.2(@conform-to/dom@0.9.2)(zod@3.25.76): resolution: {integrity: sha512-treG9ZcuNuRERQ1uYvJSWT0zZuqHnYTzRwucg20+/WdjgKNSb60Br+Cy6BAHvVQ8dN6wJsGkHenkX2mSVw3xOA==} peerDependencies: '@conform-to/dom': 0.9.2 zod: ^3.21.0 dependencies: '@conform-to/dom': 0.9.2 - zod: 3.23.8 + zod: 3.25.76 dev: false /@connectrpc/connect-node@1.4.0(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.4.0): @@ -6196,6 +6302,7 @@ packages: /@effect/schema@0.72.2(effect@3.7.2): resolution: {integrity: sha512-/x1BIA2pqcUidNrOMmwYe6Z58KtSgHSc5iJu7bNwIxi2LHMVuUao1BvpI5x6i7T/zkoi4dd1S6qasZzJIYDjdw==} + deprecated: this package has been merged into the main effect package peerDependencies: effect: ^3.7.2 dependencies: @@ -6205,12 +6312,12 @@ packages: /@effect/schema@0.75.5(effect@3.17.1): resolution: {integrity: sha512-TQInulTVCuF+9EIbJpyLP6dvxbQJMphrnRqgexm/Ze39rSjfhJuufF7XvU3SxTgg3HnL7B/kpORTJbHhlE6thw==} + deprecated: this package has been merged into the main effect package peerDependencies: effect: ^3.9.2 dependencies: effect: 3.17.1 - fast-check: 3.22.0 - dev: false + fast-check: 3.23.2 /@electric-sql/client@0.4.0: resolution: {integrity: sha512-YVYSqHitqVIDC1RBTfmHMfAfqDNAKMK9/AFVTDFQQxN3Q85dIQS49zThAuJVecYiuYRJvTiqf40c4n39jZSNrQ==} @@ -7955,7 +8062,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 espree: 9.6.0 globals: 13.19.0 ignore: 5.2.4 @@ -8332,7 +8439,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -9003,10 +9110,6 @@ packages: '@jridgewell/trace-mapping': 0.3.25 dev: true - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: false - /@jridgewell/sourcemap-codec@1.5.0: resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} @@ -9241,19 +9344,22 @@ packages: - supports-color dev: true - /@modelcontextprotocol/sdk@1.6.1(supports-color@10.0.0): - resolution: {integrity: sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA==} + /@modelcontextprotocol/sdk@1.17.0(supports-color@10.0.0): + resolution: {integrity: sha512-qFfbWFA7r1Sd8D697L7GkTd36yqDuTkvz0KfOGkgXR8EUhQn3/EDNIR/qUdQNMT8IjmasBvHWuXeisxtXTQT2g==} engines: {node: '>=18'} dependencies: + ajv: 6.12.6 content-type: 1.0.5 cors: 2.8.5 + cross-spawn: 7.0.6 eventsource: 3.0.5 + eventsource-parser: 3.0.0 express: 5.0.1(supports-color@10.0.0) express-rate-limit: 7.5.0(express@5.0.1) - pkce-challenge: 4.1.0 + pkce-challenge: 5.0.0 raw-body: 3.0.0 - zod: 3.23.8 - zod-to-json-schema: 3.24.3(zod@3.23.8) + zod: 3.25.76 + zod-to-json-schema: 3.24.5(zod@3.25.76) transitivePeerDependencies: - supports-color dev: false @@ -10260,7 +10366,7 @@ packages: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.25.1 semver: 7.6.3 transitivePeerDependencies: @@ -10485,7 +10591,7 @@ packages: '@opentelemetry/api-logs': 0.49.1 '@types/shimmer': 1.0.2 import-in-the-middle: 1.7.1 - require-in-the-middle: 7.1.1(supports-color@10.0.0) + require-in-the-middle: 7.1.1 semver: 7.6.3 shimmer: 1.2.1 transitivePeerDependencies: @@ -10502,7 +10608,7 @@ packages: '@opentelemetry/api-logs': 0.49.1 '@types/shimmer': 1.0.2 import-in-the-middle: 1.7.1 - require-in-the-middle: 7.1.1(supports-color@10.0.0) + require-in-the-middle: 7.1.1 semver: 7.6.3 shimmer: 1.2.1 transitivePeerDependencies: @@ -10519,7 +10625,7 @@ packages: '@opentelemetry/api-logs': 0.49.1 '@types/shimmer': 1.0.2 import-in-the-middle: 1.7.1 - require-in-the-middle: 7.1.1(supports-color@10.0.0) + require-in-the-middle: 7.1.1 semver: 7.6.3 shimmer: 1.2.1 transitivePeerDependencies: @@ -10536,7 +10642,7 @@ packages: '@opentelemetry/api-logs': 0.51.1 '@types/shimmer': 1.0.2 import-in-the-middle: 1.7.4 - require-in-the-middle: 7.1.1(supports-color@10.0.0) + require-in-the-middle: 7.1.1 semver: 7.6.3 shimmer: 1.2.1 transitivePeerDependencies: @@ -10553,7 +10659,24 @@ packages: '@opentelemetry/api-logs': 0.52.1 '@types/shimmer': 1.0.2 import-in-the-middle: 1.11.0 - require-in-the-middle: 7.1.1(supports-color@10.0.0) + require-in-the-middle: 7.1.1 + semver: 7.6.3 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0): + resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.52.1 + '@types/shimmer': 1.0.2 + import-in-the-middle: 1.11.0 + require-in-the-middle: 7.1.1 semver: 7.6.3 shimmer: 1.2.1 transitivePeerDependencies: @@ -10587,7 +10710,7 @@ packages: '@opentelemetry/api-logs': 0.57.2 '@types/shimmer': 1.2.0 import-in-the-middle: 1.11.0 - require-in-the-middle: 7.1.1(supports-color@10.0.0) + require-in-the-middle: 7.1.1 semver: 7.7.2 shimmer: 1.2.1 transitivePeerDependencies: @@ -10951,6 +11074,30 @@ packages: - supports-color dev: true + /@opentelemetry/sdk-node@0.52.1(@opentelemetry/api@1.9.0): + resolution: {integrity: sha512-uEG+gtEr6eKd8CVWeKMhH2olcCHM9dEK68pe0qE0be32BcCRsvYURhHaD1Srngh1SQcnQzZ4TP324euxqtBOJA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.52.1 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-grpc': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-http': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-proto': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-zipkin': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 + transitivePeerDependencies: + - supports-color + dev: false + /@opentelemetry/sdk-node@0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0): resolution: {integrity: sha512-uEG+gtEr6eKd8CVWeKMhH2olcCHM9dEK68pe0qE0be32BcCRsvYURhHaD1Srngh1SQcnQzZ4TP324euxqtBOJA==} engines: {node: '>=14'} @@ -11154,7 +11301,7 @@ packages: resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 is-glob: 4.0.3 open: 8.4.0 picocolors: 1.1.1 @@ -11330,7 +11477,7 @@ packages: '@opentelemetry/api': ^1.8 dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color dev: false @@ -11427,7 +11574,7 @@ packages: engines: {node: '>=18'} hasBin: true dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.5.0 @@ -11444,7 +11591,7 @@ packages: engines: {node: '>=18'} hasBin: true dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.4.0 @@ -16958,7 +17105,7 @@ packages: - encoding dev: false - /@remix-run/dev@2.1.0(@remix-run/serve@2.1.0)(@types/node@20.14.14)(ts-node@10.9.1)(typescript@5.5.4): + /@remix-run/dev@2.1.0(@remix-run/serve@2.1.0)(@types/node@20.14.14)(ts-node@10.9.1)(typescript@5.8.3): resolution: {integrity: sha512-Hn5lw46F+a48dp5uHKe68ckaHgdStW4+PmLod+LMFEqrMbkF0j4XD1ousebxlv989o0Uy/OLgfRMgMy4cBOvHg==} engines: {node: '>=18.0.0'} hasBin: true @@ -16980,8 +17127,8 @@ packages: '@babel/traverse': 7.22.17 '@mdx-js/mdx': 2.3.0 '@npmcli/package-json': 4.0.1 - '@remix-run/serve': 2.1.0(typescript@5.5.4) - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/serve': 2.1.0(typescript@5.8.3) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) '@types/mdx': 2.0.5 '@vanilla-extract/integration': 6.2.1(@types/node@20.14.14) arg: 5.0.2 @@ -17019,7 +17166,7 @@ packages: semver: 7.6.3 tar-fs: 2.1.3 tsconfig-paths: 4.2.0 - typescript: 5.5.4 + typescript: 5.8.3 ws: 7.5.9 transitivePeerDependencies: - '@types/node' @@ -17037,7 +17184,7 @@ packages: - utf-8-validate dev: true - /@remix-run/eslint-config@2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.5.4): + /@remix-run/eslint-config@2.1.0(eslint@8.31.0)(react@18.2.0)(typescript@5.8.3): resolution: {integrity: sha512-yfeUnHpUG+XveujMi6QODKMGhs5CvKWCKzASU397BPXiPWbMv6r2acfODSWK64ZdBMu9hcLbOb42GBFydVQeHA==} engines: {node: '>=18.0.0'} peerDependencies: @@ -17052,28 +17199,28 @@ packages: '@babel/eslint-parser': 7.21.8(@babel/core@7.22.17)(eslint@8.31.0) '@babel/preset-react': 7.18.6(@babel/core@7.22.17) '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.5.4) - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.8.3) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.8.3) eslint: 8.31.0 eslint-import-resolver-node: 0.3.7 eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.59.6)(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.31.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.59.6)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) - eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.59.6)(eslint@8.31.0)(typescript@5.5.4) + eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.59.6)(eslint@8.31.0)(typescript@5.8.3) eslint-plugin-jest-dom: 4.0.3(eslint@8.31.0) eslint-plugin-jsx-a11y: 6.7.1(eslint@8.31.0) eslint-plugin-node: 11.1.0(eslint@8.31.0) eslint-plugin-react: 7.32.2(eslint@8.31.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.31.0) - eslint-plugin-testing-library: 5.11.0(eslint@8.31.0)(typescript@5.5.4) + eslint-plugin-testing-library: 5.11.0(eslint@8.31.0)(typescript@5.8.3) react: 18.2.0 - typescript: 5.5.4 + typescript: 5.8.3 transitivePeerDependencies: - eslint-import-resolver-webpack - jest - supports-color dev: true - /@remix-run/express@2.1.0(express@4.20.0)(typescript@5.5.4): + /@remix-run/express@2.1.0(express@4.20.0)(typescript@5.8.3): resolution: {integrity: sha512-R5myPowQx6LYWY3+EqP42q19MOCT3+ZGwb2f0UKNs9a34R8U3nFpGWL7saXryC+To+EasujEScc8rTQw5Pftog==} engines: {node: '>=18.0.0'} peerDependencies: @@ -17083,11 +17230,11 @@ packages: typescript: optional: true dependencies: - '@remix-run/node': 2.1.0(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.8.3) express: 4.20.0 - typescript: 5.5.4 + typescript: 5.8.3 - /@remix-run/node@2.1.0(typescript@5.5.4): + /@remix-run/node@2.1.0(typescript@5.8.3): resolution: {integrity: sha512-TeSgjXnZUUlmw5FVpBVnXY7MLpracjdnwFNwoJE5NQkiUEFnGD/Yhvk4F2fOCkszqc2Z25KRclc5noweyiFu6Q==} engines: {node: '>=18.0.0'} peerDependencies: @@ -17096,7 +17243,7 @@ packages: typescript: optional: true dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) '@remix-run/web-fetch': 4.4.1 '@remix-run/web-file': 3.1.0 '@remix-run/web-stream': 1.1.0 @@ -17104,9 +17251,9 @@ packages: cookie-signature: 1.2.0 source-map-support: 0.5.21 stream-slice: 0.1.2 - typescript: 5.5.4 + typescript: 5.8.3 - /@remix-run/react@2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4): + /@remix-run/react@2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3): resolution: {integrity: sha512-DeYgfsvNxHqNn29sGA3XsZCciMKo2EFTQ9hHkuVPTsJXC4ipHr6Dja1j6UzZYPe/ZuKppiuTjueWCQlE2jOe1w==} engines: {node: '>=18.0.0'} peerDependencies: @@ -17118,11 +17265,11 @@ packages: optional: true dependencies: '@remix-run/router': 1.10.0 - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-router-dom: 6.17.0(react-dom@18.2.0)(react@18.2.0) - typescript: 5.5.4 + typescript: 5.8.3 /@remix-run/router@1.10.0: resolution: {integrity: sha512-Lm+fYpMfZoEucJ7cMxgt4dYt8jLfbpwRCzAjm9UgSLOkmlqo9gupxt6YX3DY0Fk155NT9l17d/ydi+964uS9Lw==} @@ -17133,13 +17280,13 @@ packages: engines: {node: '>=14.0.0'} dev: false - /@remix-run/serve@2.1.0(typescript@5.5.4): + /@remix-run/serve@2.1.0(typescript@5.8.3): resolution: {integrity: sha512-XHI+vPYz217qrg1QcV38TTPlEBTzMJzAt0SImPutyF0S2IBrZGZIFMEsspI0i0wNvdcdQz1IqmSx+mTghzW8eQ==} engines: {node: '>=18.0.0'} hasBin: true dependencies: - '@remix-run/express': 2.1.0(express@4.20.0)(typescript@5.5.4) - '@remix-run/node': 2.1.0(typescript@5.5.4) + '@remix-run/express': 2.1.0(express@4.20.0)(typescript@5.8.3) + '@remix-run/node': 2.1.0(typescript@5.8.3) chokidar: 3.6.0 compression: 1.7.4 express: 4.20.0 @@ -17150,7 +17297,7 @@ packages: - supports-color - typescript - /@remix-run/server-runtime@2.1.0(typescript@5.5.4): + /@remix-run/server-runtime@2.1.0(typescript@5.8.3): resolution: {integrity: sha512-Uz69yF4Gu6F3VYQub3JgDo9godN8eDMeZclkadBTAWN7bYLonu0ChR/GlFxS35OLeF7BDgudxOSZob0nE1WHNg==} engines: {node: '>=18.0.0'} peerDependencies: @@ -17165,9 +17312,9 @@ packages: cookie: 0.4.2 set-cookie-parser: 2.6.0 source-map: 0.7.4 - typescript: 5.5.4 + typescript: 5.8.3 - /@remix-run/testing@2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4): + /@remix-run/testing@2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3): resolution: {integrity: sha512-eLPx4Bmjt243kyRpQTong1eFo6nkvSfCr65bb5PfoF172DKnsSSCYWAmBmB72VwtAPESHxBm3g6AUbhwphkU6A==} engines: {node: '>=18.0.0'} peerDependencies: @@ -17177,12 +17324,12 @@ packages: typescript: optional: true dependencies: - '@remix-run/node': 2.1.0(typescript@5.5.4) - '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.8.3) + '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) '@remix-run/router': 1.10.0 react: 18.2.0 react-router-dom: 6.17.0(react-dom@18.2.0)(react@18.2.0) - typescript: 5.5.4 + typescript: 5.8.3 transitivePeerDependencies: - react-dom dev: true @@ -17193,8 +17340,8 @@ packages: '@remix-run/react': ^1.15.0 || ^2.0.0 '@remix-run/server-runtime': ^1.15.0 || ^2.0.0 dependencies: - '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) dev: false /@remix-run/web-blob@3.1.0: @@ -17683,10 +17830,10 @@ packages: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.36.0 - '@remix-run/node': 2.1.0(typescript@5.5.4) - '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.8.3) + '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) '@remix-run/router': 1.15.3 - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) '@sentry/cli': 2.50.2 '@sentry/core': 9.40.0 '@sentry/node': 9.40.0 @@ -17717,6 +17864,9 @@ packages: resolution: {integrity: sha512-75232GRx3wp3P7NP+yc4nRK3XUAnaQShxTAzapgmQrgs0QvSq0/mOJGoZXRpH15cFCKyys+4laCPbBselqJ5Ag==} dev: false + /@sinclair/typebox@0.34.38: + resolution: {integrity: sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA==} + /@sindresorhus/is@0.14.0: resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==} engines: {node: '>=6'} @@ -18910,6 +19060,10 @@ packages: - supports-color dev: false + /@sodaru/yup-to-json-schema@2.0.1: + resolution: {integrity: sha512-lWb0Wiz8KZ9ip/dY1eUqt7fhTPmL24p6Hmv5Fd9pzlzAdw/YNcWZr+tiCT4oZ4Zyxzi9+1X4zv82o7jYvcFxYA==} + dev: false + /@splinetool/react-spline@2.2.6(@splinetool/runtime@1.9.98)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-y9L2VEbnC6FNZZu8XMmWM9YTTTWal6kJVfP05Amf0QqDNzCSumKsJxZyGUODvuCmiAvy0PfIfEsiVKnSxvhsDw==} peerDependencies: @@ -18937,7 +19091,6 @@ packages: /@standard-schema/spec@1.0.0: resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - dev: false /@stricli/auto-complete@1.2.0: resolution: {integrity: sha512-r9/msiloVmTF95mdhe04Uzqei1B0ZofhYRLeiPqpJ1W1RMCC8p9iW7kqBZEbALl2aRL5ZK9OEW3Q1cIejH7KEQ==} @@ -19209,7 +19362,7 @@ packages: defer-to-connect: 1.1.3 dev: true - /@t3-oss/env-core@0.10.1(typescript@5.5.4)(zod@3.23.8): + /@t3-oss/env-core@0.10.1(typescript@5.8.3)(zod@3.25.76): resolution: {integrity: sha512-GcKZiCfWks5CTxhezn9k5zWX3sMDIYf6Kaxy2Gx9YEQftFcz8hDRN56hcbylyAO3t4jQnQ5ifLawINsNgCDpOg==} peerDependencies: typescript: '>=5.0.0' @@ -19218,11 +19371,11 @@ packages: typescript: optional: true dependencies: - typescript: 5.5.4 - zod: 3.23.8 + typescript: 5.8.3 + zod: 3.25.76 dev: false - /@t3-oss/env-core@0.11.0(typescript@5.5.4)(zod@3.23.8): + /@t3-oss/env-core@0.11.0(typescript@5.8.3)(zod@3.25.76): resolution: {integrity: sha512-PSalC5bG0a7XbyoLydiQdAnx3gICX6IQNctvh+TyLrdFxsxgocdj9Ui7sd061UlBzi+z4aIGjnem1kZx9QtUgQ==} peerDependencies: typescript: '>=5.0.0' @@ -19231,11 +19384,11 @@ packages: typescript: optional: true dependencies: - typescript: 5.5.4 - zod: 3.23.8 + typescript: 5.8.3 + zod: 3.25.76 dev: false - /@t3-oss/env-nextjs@0.10.1(typescript@5.5.4)(zod@3.23.8): + /@t3-oss/env-nextjs@0.10.1(typescript@5.8.3)(zod@3.25.76): resolution: {integrity: sha512-iy2qqJLnFh1RjEWno2ZeyTu0ufomkXruUsOZludzDIroUabVvHsrSjtkHqwHp1/pgPUzN3yBRHMILW162X7x2Q==} peerDependencies: typescript: '>=5.0.0' @@ -19244,9 +19397,9 @@ packages: typescript: optional: true dependencies: - '@t3-oss/env-core': 0.10.1(typescript@5.5.4)(zod@3.23.8) - typescript: 5.5.4 - zod: 3.23.8 + '@t3-oss/env-core': 0.10.1(typescript@5.8.3)(zod@3.25.76) + typescript: 5.8.3 + zod: 3.25.76 dev: false /@tabler/icons-react@2.47.0(react@18.2.0): @@ -19472,7 +19625,7 @@ packages: dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.6.0) graphql: 16.6.0 - zod: 3.23.8 + zod: 3.25.76 dev: false /@testcontainers/postgresql@10.28.0: @@ -20378,7 +20531,7 @@ packages: - '@types/json-schema' dev: false - /@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.5.4): + /@typescript-eslint/eslint-plugin@5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.8.3): resolution: {integrity: sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -20390,23 +20543,23 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.8.3) '@typescript-eslint/scope-manager': 5.59.6 - '@typescript-eslint/type-utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/type-utils': 5.59.6(eslint@8.31.0)(typescript@5.8.3) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.8.3) debug: 4.3.4 eslint: 8.31.0 grapheme-splitter: 1.0.4 ignore: 5.2.4 natural-compare-lite: 1.4.0 semver: 7.6.3 - tsutils: 3.21.0(typescript@5.5.4) - typescript: 5.5.4 + tsutils: 3.21.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.5.4): + /@typescript-eslint/parser@5.59.6(eslint@8.31.0)(typescript@5.8.3): resolution: {integrity: sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -20418,10 +20571,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.59.6 '@typescript-eslint/types': 5.59.6 - '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.5.4) - debug: 4.4.0(supports-color@10.0.0) + '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.8.3) + debug: 4.4.0 eslint: 8.31.0 - typescript: 5.5.4 + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true @@ -20434,7 +20587,7 @@ packages: '@typescript-eslint/visitor-keys': 5.59.6 dev: true - /@typescript-eslint/type-utils@5.59.6(eslint@8.31.0)(typescript@5.5.4): + /@typescript-eslint/type-utils@5.59.6(eslint@8.31.0)(typescript@5.8.3): resolution: {integrity: sha512-A4tms2Mp5yNvLDlySF+kAThV9VTBPCvGf0Rp8nl/eoDX9Okun8byTKoj3fJ52IJitjWOk0fKPNQhXEB++eNozQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -20444,12 +20597,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.5.4) - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) - debug: 4.4.0(supports-color@10.0.0) + '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.8.3) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.8.3) + debug: 4.4.0 eslint: 8.31.0 - tsutils: 3.21.0(typescript@5.5.4) - typescript: 5.5.4 + tsutils: 3.21.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true @@ -20459,7 +20612,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.59.6(typescript@5.5.4): + /@typescript-eslint/typescript-estree@5.59.6(typescript@5.8.3): resolution: {integrity: sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -20470,17 +20623,17 @@ packages: dependencies: '@typescript-eslint/types': 5.59.6 '@typescript-eslint/visitor-keys': 5.59.6 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.3 - tsutils: 3.21.0(typescript@5.5.4) - typescript: 5.5.4 + tsutils: 3.21.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.59.6(eslint@8.31.0)(typescript@5.5.4): + /@typescript-eslint/utils@5.59.6(eslint@8.31.0)(typescript@5.8.3): resolution: {integrity: sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -20491,7 +20644,7 @@ packages: '@types/semver': 7.5.1 '@typescript-eslint/scope-manager': 5.59.6 '@typescript-eslint/types': 5.59.6 - '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 5.59.6(typescript@5.8.3) eslint: 8.31.0 eslint-scope: 5.1.1 semver: 7.6.3 @@ -20570,7 +20723,7 @@ packages: /@unkey/error@0.2.0: resolution: {integrity: sha512-DFGb4A7SrusZPP0FYuRIF0CO+Gi4etLUAEJ6EKc+TKYmscL0nEJ2Pr38FyX9MvjI4Wx5l35Wc9KsBjMm9Ybh7w==} dependencies: - zod: 3.23.8 + zod: 3.25.76 dev: false /@uploadthing/mime-types@0.3.0: @@ -20698,7 +20851,7 @@ packages: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -20713,6 +20866,15 @@ packages: - supports-color dev: true + /@vitest/expect@2.1.9: + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.2.0 + tinyrainbow: 1.2.0 + dev: true + /@vitest/expect@3.1.4: resolution: {integrity: sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==} dependencies: @@ -20722,6 +20884,23 @@ packages: tinyrainbow: 2.0.0 dev: true + /@vitest/mocker@2.1.9(vite@5.2.7): + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.17 + vite: 5.2.7(@types/node@20.14.14) + dev: true + /@vitest/mocker@3.1.4(vite@5.2.7): resolution: {integrity: sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==} peerDependencies: @@ -20765,6 +20944,14 @@ packages: pathe: 2.0.3 dev: true + /@vitest/snapshot@2.1.9: + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.17 + pathe: 1.1.2 + dev: true + /@vitest/snapshot@3.1.4: resolution: {integrity: sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==} dependencies: @@ -20773,6 +20960,12 @@ packages: pathe: 2.0.3 dev: true + /@vitest/spy@2.1.9: + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + dependencies: + tinyspy: 3.0.2 + dev: true + /@vitest/spy@3.1.4: resolution: {integrity: sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==} dependencies: @@ -21276,7 +21469,7 @@ packages: engines: {node: '>= 6.0.0'} requiresBuild: true dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color @@ -21284,7 +21477,7 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color @@ -21318,7 +21511,7 @@ packages: resolution: {integrity: sha512-hCOfMzbFx5IDutmWLAt6MZwOUjIfSM9G9FyVxytmE4Rs/5YDPWQrD/+IR1w+FweD9H2oOZEnv36TmkjhNURBVA==} dev: true - /ai@3.3.24(openai@4.56.0)(react@19.0.0-rc.0)(svelte@5.33.14)(vue@3.5.16)(zod@3.23.8): + /ai@3.3.24(openai@4.56.0)(react@19.0.0-rc.0)(svelte@5.33.14)(vue@3.5.16)(zod@3.25.76): resolution: {integrity: sha512-hhyczvEdCQeeEMWBWP4Af8k1YIzsheC+dHv6lAsti8NBiOnySFhnjS1sTiIrLyuCgciHXoFYLhlA2+/3AtBLAQ==} engines: {node: '>=18'} peerDependencies: @@ -21340,29 +21533,29 @@ packages: optional: true dependencies: '@ai-sdk/provider': 0.0.22 - '@ai-sdk/provider-utils': 1.0.17(zod@3.23.8) - '@ai-sdk/react': 0.0.53(react@19.0.0-rc.0)(zod@3.23.8) - '@ai-sdk/solid': 0.0.43(zod@3.23.8) - '@ai-sdk/svelte': 0.0.45(svelte@5.33.14)(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.40(zod@3.23.8) - '@ai-sdk/vue': 0.0.45(vue@3.5.16)(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.17(zod@3.25.76) + '@ai-sdk/react': 0.0.53(react@19.0.0-rc.0)(zod@3.25.76) + '@ai-sdk/solid': 0.0.43(zod@3.25.76) + '@ai-sdk/svelte': 0.0.45(svelte@5.33.14)(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.40(zod@3.25.76) + '@ai-sdk/vue': 0.0.45(vue@3.5.16)(zod@3.25.76) '@opentelemetry/api': 1.9.0 eventsource-parser: 1.1.2 json-schema: 0.4.0 jsondiffpatch: 0.6.0 nanoid: 3.3.6 - openai: 4.56.0(zod@3.23.8) + openai: 4.56.0(zod@3.25.76) react: 19.0.0-rc.0 secure-json-parse: 2.7.0 svelte: 5.33.14 - zod: 3.23.8 - zod-to-json-schema: 3.23.2(zod@3.23.8) + zod: 3.25.76 + zod-to-json-schema: 3.23.2(zod@3.25.76) transitivePeerDependencies: - solid-js - vue dev: false - /ai@3.4.33(react@18.3.1)(svelte@5.33.14)(vue@3.5.16)(zod@3.23.8): + /ai@3.4.33(react@18.3.1)(svelte@5.33.14)(vue@3.5.16)(zod@3.25.76): resolution: {integrity: sha512-plBlrVZKwPoRTmM8+D1sJac9Bq8eaa2jiZlHLZIWekKWI1yMWYZvCCEezY9ASPwRhULYDJB2VhKOBUUeg3S5JQ==} engines: {node: '>=18'} peerDependencies: @@ -21384,12 +21577,12 @@ packages: optional: true dependencies: '@ai-sdk/provider': 0.0.26 - '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) - '@ai-sdk/react': 0.0.70(react@18.3.1)(zod@3.23.8) - '@ai-sdk/solid': 0.0.54(zod@3.23.8) - '@ai-sdk/svelte': 0.0.57(svelte@5.33.14)(zod@3.23.8) - '@ai-sdk/ui-utils': 0.0.50(zod@3.23.8) - '@ai-sdk/vue': 0.0.59(vue@3.5.16)(zod@3.23.8) + '@ai-sdk/provider-utils': 1.0.22(zod@3.25.76) + '@ai-sdk/react': 0.0.70(react@18.3.1)(zod@3.25.76) + '@ai-sdk/solid': 0.0.54(zod@3.25.76) + '@ai-sdk/svelte': 0.0.57(svelte@5.33.14)(zod@3.25.76) + '@ai-sdk/ui-utils': 0.0.50(zod@3.25.76) + '@ai-sdk/vue': 0.0.59(vue@3.5.16)(zod@3.25.76) '@opentelemetry/api': 1.9.0 eventsource-parser: 1.1.2 json-schema: 0.4.0 @@ -21397,14 +21590,14 @@ packages: react: 18.3.1 secure-json-parse: 2.7.0 svelte: 5.33.14 - zod: 3.23.8 - zod-to-json-schema: 3.24.3(zod@3.23.8) + zod: 3.25.76 + zod-to-json-schema: 3.24.3(zod@3.25.76) transitivePeerDependencies: - solid-js - vue dev: true - /ai@4.0.0(react@18.3.1)(zod@3.23.8): + /ai@4.0.0(react@18.3.1)(zod@3.25.76): resolution: {integrity: sha512-cqf2GCaXnOPhUU+Ccq6i+5I0jDjnFkzfq7t6mc0SUSibSa1wDPn5J4p8+Joh2fDGDYZOJ44rpTW9hSs40rXNAw==} engines: {node: '>=18'} peerDependencies: @@ -21417,17 +21610,17 @@ packages: optional: true dependencies: '@ai-sdk/provider': 1.0.0 - '@ai-sdk/provider-utils': 2.0.0(zod@3.23.8) - '@ai-sdk/react': 1.0.0(react@18.3.1)(zod@3.23.8) - '@ai-sdk/ui-utils': 1.0.0(zod@3.23.8) + '@ai-sdk/provider-utils': 2.0.0(zod@3.25.76) + '@ai-sdk/react': 1.0.0(react@18.3.1)(zod@3.25.76) + '@ai-sdk/ui-utils': 1.0.0(zod@3.25.76) '@opentelemetry/api': 1.9.0 jsondiffpatch: 0.6.0 react: 18.3.1 - zod: 3.23.8 - zod-to-json-schema: 3.24.5(zod@3.23.8) + zod: 3.25.76 + zod-to-json-schema: 3.24.5(zod@3.25.76) dev: false - /ai@4.2.5(react@18.3.1)(zod@3.23.8): + /ai@4.2.5(react@18.3.1)(zod@3.25.76): resolution: {integrity: sha512-URJEslI3cgF/atdTJHtz+Sj0W1JTmiGmD3znw9KensL3qV605odktDim+GTazNJFPR4QaIu1lUio5b8RymvOjA==} engines: {node: '>=18'} peerDependencies: @@ -21438,16 +21631,16 @@ packages: optional: true dependencies: '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.1(zod@3.23.8) - '@ai-sdk/react': 1.2.2(react@18.3.1)(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.1(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.1(zod@3.25.76) + '@ai-sdk/react': 1.2.2(react@18.3.1)(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.1(zod@3.25.76) '@opentelemetry/api': 1.9.0 jsondiffpatch: 0.6.0 react: 18.3.1 - zod: 3.23.8 + zod: 3.25.76 dev: true - /ai@4.2.5(react@19.0.0)(zod@3.23.8): + /ai@4.2.5(react@19.0.0)(zod@3.25.76): resolution: {integrity: sha512-URJEslI3cgF/atdTJHtz+Sj0W1JTmiGmD3znw9KensL3qV605odktDim+GTazNJFPR4QaIu1lUio5b8RymvOjA==} engines: {node: '>=18'} peerDependencies: @@ -21458,16 +21651,16 @@ packages: optional: true dependencies: '@ai-sdk/provider': 1.1.0 - '@ai-sdk/provider-utils': 2.2.1(zod@3.23.8) - '@ai-sdk/react': 1.2.2(react@19.0.0)(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.1(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.1(zod@3.25.76) + '@ai-sdk/react': 1.2.2(react@19.0.0)(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.1(zod@3.25.76) '@opentelemetry/api': 1.9.0 jsondiffpatch: 0.6.0 react: 19.0.0 - zod: 3.23.8 + zod: 3.25.76 dev: false - /ai@4.3.19(react@18.2.0)(zod@3.23.8): + /ai@4.3.19(react@18.2.0)(zod@3.25.76): resolution: {integrity: sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==} engines: {node: '>=18'} peerDependencies: @@ -21478,13 +21671,13 @@ packages: optional: true dependencies: '@ai-sdk/provider': 1.1.3 - '@ai-sdk/provider-utils': 2.2.8(zod@3.23.8) - '@ai-sdk/react': 1.2.12(react@18.2.0)(zod@3.23.8) - '@ai-sdk/ui-utils': 1.2.11(zod@3.23.8) + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + '@ai-sdk/react': 1.2.12(react@18.2.0)(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) '@opentelemetry/api': 1.9.0 jsondiffpatch: 0.6.0 react: 18.2.0 - zod: 3.23.8 + zod: 3.25.76 dev: false /ajv-formats@2.1.1(ajv@8.17.1): @@ -21736,6 +21929,12 @@ packages: '@ark/util': 0.18.0 dev: false + /arktype@2.1.20: + resolution: {integrity: sha512-IZCEEXaJ8g+Ijd59WtSYwtjnqXiwM8sWQ5EjGamcto7+HVN9eK0C4p0zDlCuAwWhpqr6fIBkxPuYDl4/Mcj/+Q==} + dependencies: + '@ark/schema': 0.46.0 + '@ark/util': 0.46.0 + /array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -21939,9 +22138,9 @@ packages: js-yaml: 4.1.0 linear-sum-assignment: 1.0.7 mustache: 4.2.0 - openai: 4.97.0(ws@8.12.0)(zod@3.23.8) - zod: 3.23.8 - zod-to-json-schema: 3.24.5(zod@3.23.8) + openai: 4.97.0(ws@8.12.0)(zod@3.25.76) + zod: 3.25.76 + zod-to-json-schema: 3.24.5(zod@3.25.76) transitivePeerDependencies: - encoding - ws @@ -22216,7 +22415,7 @@ packages: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) http-errors: 2.0.0 iconv-lite: 0.6.3 on-finished: 2.4.1 @@ -22577,7 +22776,7 @@ packages: /capnp-ts@0.7.0: resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -22784,7 +22983,7 @@ packages: /cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - /class-variance-authority@0.5.2(typescript@5.5.4): + /class-variance-authority@0.5.2(typescript@5.8.3): resolution: {integrity: sha512-j7Qqw3NPbs4IpO80gvdACWmVvHiLLo5MECacUBLnJG17CrLpWaQ7/4OaWX6P0IO1j2nvZ7AuSfBS/ImtEUZJGA==} peerDependencies: typescript: '>= 4.5.5 < 6' @@ -22792,7 +22991,7 @@ packages: typescript: optional: true dependencies: - typescript: 5.5.4 + typescript: 5.8.3 dev: false /class-variance-authority@0.7.0: @@ -23246,7 +23445,23 @@ packages: typescript: 5.5.4 dev: false - /cosmiconfig@9.0.0(typescript@5.5.4): + /cosmiconfig@8.3.6(typescript@5.8.3): + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + typescript: 5.8.3 + dev: false + + /cosmiconfig@9.0.0(typescript@5.8.3): resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} engines: {node: '>=14'} peerDependencies: @@ -23259,7 +23474,7 @@ packages: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 - typescript: 5.5.4 + typescript: 5.8.3 /cp-file@10.0.0: resolution: {integrity: sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==} @@ -23386,6 +23601,14 @@ packages: shebang-command: 2.0.0 which: 2.0.2 + /cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + /crypto-js@4.1.1: resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==} dev: false @@ -23691,7 +23914,7 @@ packages: ms: 2.1.3 supports-color: 10.0.0 - /debug@4.4.0(supports-color@10.0.0): + /debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} peerDependencies: @@ -23701,9 +23924,8 @@ packages: optional: true dependencies: ms: 2.1.3 - supports-color: 10.0.0 - /debug@4.4.1: + /debug@4.4.1(supports-color@10.0.0): resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} peerDependencies: @@ -23713,7 +23935,7 @@ packages: optional: true dependencies: ms: 2.1.3 - dev: false + supports-color: 10.0.0 /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} @@ -23977,7 +24199,7 @@ packages: resolution: {integrity: sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ==} engines: {node: '>= 8.0'} dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 readable-stream: 3.6.0 split-ca: 1.0.1 ssh2: 1.16.0 @@ -24174,7 +24396,6 @@ packages: dependencies: '@standard-schema/spec': 1.0.0 fast-check: 3.23.2 - dev: false /effect@3.7.2: resolution: {integrity: sha512-pV7l1+LSZFvVObj4zuy4nYiBaC7qZOfrKV6s/Ef4p3KueiQwZFgamazklwyZ+x7Nyj2etRDFvHE/xkThTfQD1w==} @@ -25030,7 +25251,7 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 enhanced-resolve: 5.15.0 eslint: 8.31.0 eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.59.6)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.31.0) @@ -25068,7 +25289,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.8.3) debug: 3.2.7 eslint: 8.31.0 eslint-import-resolver-node: 0.3.7 @@ -25098,7 +25319,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.8.3) debug: 3.2.7 eslint: 8.31.0 eslint-import-resolver-node: 0.3.9 @@ -25128,7 +25349,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.59.6(eslint@8.31.0)(typescript@5.8.3) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -25165,7 +25386,7 @@ packages: requireindex: 1.2.0 dev: true - /eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.6)(eslint@8.31.0)(typescript@5.5.4): + /eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.6)(eslint@8.31.0)(typescript@5.8.3): resolution: {integrity: sha512-TWJxWGp1J628gxh2KhaH1H1paEdgE2J61BBF1I59c6xWeL5+D1BzMxGDN/nXAfX+aSkR5u80K+XhskK6Gwq9ng==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -25178,8 +25399,8 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.5.4) - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/eslint-plugin': 5.59.6(@typescript-eslint/parser@5.59.6)(eslint@8.31.0)(typescript@5.8.3) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.8.3) eslint: 8.31.0 transitivePeerDependencies: - supports-color @@ -25259,13 +25480,13 @@ packages: string.prototype.matchall: 4.0.8 dev: true - /eslint-plugin-testing-library@5.11.0(eslint@8.31.0)(typescript@5.5.4): + /eslint-plugin-testing-library@5.11.0(eslint@8.31.0)(typescript@5.8.3): resolution: {integrity: sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} peerDependencies: eslint: ^7.5.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.5.4) + '@typescript-eslint/utils': 5.59.6(eslint@8.31.0)(typescript@5.8.3) eslint: 8.31.0 transitivePeerDependencies: - supports-color @@ -25727,7 +25948,7 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -25753,7 +25974,6 @@ packages: engines: {node: '>=8.0.0'} dependencies: pure-rand: 6.1.0 - dev: false /fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} @@ -25998,7 +26218,7 @@ packages: resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} engines: {node: '>= 0.8'} dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -26097,7 +26317,7 @@ packages: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 /forever-agent@0.6.1: @@ -26479,7 +26699,7 @@ packages: dependencies: basic-ftp: 5.0.3 data-uri-to-buffer: 5.0.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) fs-extra: 8.1.0 transitivePeerDependencies: - supports-color @@ -26709,7 +26929,7 @@ packages: '@types/node': 20.14.14 '@types/semver': 7.5.1 chalk: 4.1.2 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 interpret: 3.1.1 semver: 7.6.3 tslib: 2.6.2 @@ -26739,6 +26959,27 @@ packages: dev: false patched: true + /graphile-worker@0.16.6(patch_hash=hdpetta7btqcc7xb5wfkcnanoa)(typescript@5.8.3): + resolution: {integrity: sha512-e7gGYDmGqzju2l83MpzX8vNG/lOtVJiSzI3eZpAFubSxh/cxs7sRrRGBGjzBP1kNG0H+c95etPpNRNlH65PYhw==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@graphile/logger': 0.2.0 + '@types/debug': 4.1.12 + '@types/pg': 8.11.6 + cosmiconfig: 8.3.6(typescript@5.8.3) + graphile-config: 0.0.1-beta.8 + json5: 2.2.3 + pg: 8.11.5 + tslib: 2.6.2 + yargs: 17.7.2 + transitivePeerDependencies: + - pg-native + - supports-color + - typescript + dev: false + patched: true + /graphql@16.6.0: resolution: {integrity: sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -27008,7 +27249,7 @@ packages: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color dev: false @@ -27019,7 +27260,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color @@ -27028,7 +27269,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color dev: false @@ -27047,7 +27288,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -27056,7 +27297,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color dev: true @@ -27066,7 +27307,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color dev: false @@ -27076,7 +27317,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color dev: false @@ -27770,7 +28011,7 @@ packages: engines: {node: '>=10'} dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -28094,7 +28335,7 @@ packages: dependencies: '@types/uuid': 10.0.0 commander: 10.0.1 - openai: 4.68.4(zod@3.23.8) + openai: 4.68.4(zod@3.25.76) p-queue: 6.6.2 p-retry: 4.6.2 semver: 7.6.3 @@ -28640,7 +28881,7 @@ packages: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 dev: false /magicast@0.3.4: @@ -29500,7 +29741,7 @@ packages: resolution: {integrity: sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==} dependencies: '@types/debug': 4.1.12 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) decode-named-character-reference: 1.0.2 micromark-core-commonmark: 1.0.6 micromark-factory-space: 1.0.0 @@ -29524,7 +29765,7 @@ packages: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} dependencies: '@types/debug': 4.1.12 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -29631,7 +29872,7 @@ packages: workerd: 1.20240806.0 ws: 8.18.0(bufferutil@4.0.9) youch: 3.3.3 - zod: 3.23.8 + zod: 3.25.76 transitivePeerDependencies: - bufferutil - supports-color @@ -29929,7 +30170,7 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /msw@2.3.5(typescript@5.5.4): + /msw@2.3.5(typescript@5.8.3): resolution: {integrity: sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q==} engines: {node: '>=18'} hasBin: true @@ -29956,7 +30197,7 @@ packages: path-to-regexp: 6.2.1 strict-event-emitter: 0.5.1 type-fest: 4.10.3 - typescript: 5.5.4 + typescript: 5.8.3 yargs: 17.7.2 dev: false @@ -30820,7 +31061,7 @@ packages: - encoding dev: false - /openai@4.56.0(zod@3.23.8): + /openai@4.56.0(zod@3.25.76): resolution: {integrity: sha512-zcag97+3bG890MNNa0DQD9dGmmTWL8unJdNkulZzWRXrl+QeD+YkBI4H58rJcwErxqGK6a0jVPZ4ReJjhDGcmw==} hasBin: true peerDependencies: @@ -30836,12 +31077,12 @@ packages: form-data-encoder: 1.7.2 formdata-node: 4.4.1 node-fetch: 2.6.12 - zod: 3.23.8 + zod: 3.25.76 transitivePeerDependencies: - encoding dev: false - /openai@4.68.4(zod@3.23.8): + /openai@4.68.4(zod@3.25.76): resolution: {integrity: sha512-LRinV8iU9VQplkr25oZlyrsYGPGasIwYN8KFMAAFTHHLHjHhejtJ5BALuLFrkGzY4wfbKhOhuT+7lcHZ+F3iEA==} hasBin: true peerDependencies: @@ -30857,12 +31098,12 @@ packages: form-data-encoder: 1.7.2 formdata-node: 4.4.1 node-fetch: 2.6.12 - zod: 3.23.8 + zod: 3.25.76 transitivePeerDependencies: - encoding dev: false - /openai@4.97.0(ws@8.12.0)(zod@3.23.8): + /openai@4.97.0(ws@8.12.0)(zod@3.25.76): resolution: {integrity: sha512-LRoiy0zvEf819ZUEJhgfV8PfsE8G5WpQi4AwA1uCV8SKvvtXQkoWUFkepD6plqyJQRghy2+AEPQ07FrJFKHZ9Q==} hasBin: true peerDependencies: @@ -30882,7 +31123,7 @@ packages: formdata-node: 4.4.1 node-fetch: 2.6.12 ws: 8.12.0 - zod: 3.23.8 + zod: 3.25.76 transitivePeerDependencies: - encoding @@ -31134,7 +31375,7 @@ packages: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) get-uri: 6.0.1 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 @@ -31150,7 +31391,7 @@ packages: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) get-uri: 6.0.1 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -31565,8 +31806,8 @@ packages: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} - /pkce-challenge@4.1.0: - resolution: {integrity: sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==} + /pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} engines: {node: '>=16.20.0'} dev: false @@ -31704,7 +31945,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.29 - ts-node: 10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.5.4) + ts-node: 10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.8.3) yaml: 2.3.1 dev: true @@ -31722,7 +31963,7 @@ packages: dependencies: lilconfig: 3.1.3 postcss: 8.5.3 - ts-node: 10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.5.4) + ts-node: 10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.8.3) yaml: 2.7.1 /postcss-load-config@6.0.1(postcss@8.5.4)(tsx@4.17.0): @@ -31748,7 +31989,7 @@ packages: tsx: 4.17.0 dev: true - /postcss-loader@8.1.1(postcss@8.5.4)(typescript@5.5.4)(webpack@5.99.9): + /postcss-loader@8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.99.9): resolution: {integrity: sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==} engines: {node: '>= 18.12.0'} peerDependencies: @@ -31761,7 +32002,7 @@ packages: webpack: optional: true dependencies: - cosmiconfig: 9.0.0(typescript@5.5.4) + cosmiconfig: 9.0.0(typescript@5.8.3) jiti: 1.21.0 postcss: 8.5.4 semver: 7.6.3 @@ -32192,8 +32433,8 @@ packages: '@mrleebo/prisma-ast': 0.7.0 '@prisma/generator-helper': 5.3.1 '@prisma/internals': 5.3.1 - typescript: 5.5.4 - zod: 3.23.8 + typescript: 5.8.3 + zod: 3.25.76 transitivePeerDependencies: - encoding - supports-color @@ -32313,7 +32554,6 @@ packages: /property-expr@2.0.6: resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} - dev: false /property-information@6.2.0: resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} @@ -32357,7 +32597,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 lru-cache: 7.18.3 @@ -32373,7 +32613,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -32435,7 +32675,7 @@ packages: dependencies: '@puppeteer/browsers': 2.4.0 chromium-bidi: 0.6.5(devtools-protocol@0.0.1342118) - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) devtools-protocol: 0.0.1342118 typed-query-selector: 2.12.0 ws: 8.18.0(bufferutil@4.0.9) @@ -32452,7 +32692,7 @@ packages: dependencies: '@puppeteer/browsers': 2.10.6 chromium-bidi: 7.2.0(devtools-protocol@0.0.1464554) - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) devtools-protocol: 0.0.1464554 typed-query-selector: 2.12.0 ws: 8.18.3 @@ -32463,7 +32703,7 @@ packages: - utf-8-validate dev: false - /puppeteer@23.4.0(typescript@5.5.4): + /puppeteer@23.4.0(typescript@5.8.3): resolution: {integrity: sha512-FxgFFJI7NAsX8uebiEDSjS86vufz9TaqERQHShQT0lCbSRI3jUPEcz/0HdwLiYvfYNsc1zGjqY3NsGZya4PvUA==} engines: {node: '>=18'} hasBin: true @@ -32471,7 +32711,7 @@ packages: dependencies: '@puppeteer/browsers': 2.4.0 chromium-bidi: 0.6.5(devtools-protocol@0.0.1342118) - cosmiconfig: 9.0.0(typescript@5.5.4) + cosmiconfig: 9.0.0(typescript@5.8.3) devtools-protocol: 0.0.1342118 puppeteer-core: 23.4.0 typed-query-selector: 2.12.0 @@ -32485,7 +32725,6 @@ packages: /pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - dev: false /purgecss@2.3.0: resolution: {integrity: sha512-BE5CROfVGsx2XIhxGuZAT7rTH9lLeQx/6M0P7DTXQH4IUc3BBzs9JUzt4yzGf3JrH9enkeq6YJBe9CTtkm1WmQ==} @@ -33521,7 +33760,7 @@ packages: '@remix-run/server-runtime': ^1.1.1 remix-auth: ^3.2.1 dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) crypto-js: 4.1.1 remix-auth: 3.6.0(@remix-run/react@2.1.0)(@remix-run/server-runtime@2.1.0) dev: false @@ -33532,7 +33771,7 @@ packages: '@remix-run/server-runtime': ^1.0.0 remix-auth: ^3.4.0 dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) remix-auth: 3.6.0(@remix-run/react@2.1.0)(@remix-run/server-runtime@2.1.0) remix-auth-oauth2: 1.11.0(@remix-run/server-runtime@2.1.0)(remix-auth@3.6.0) transitivePeerDependencies: @@ -33545,8 +33784,8 @@ packages: '@remix-run/server-runtime': ^1.0.0 || ^2.0.0 remix-auth: ^3.6.0 dependencies: - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) - debug: 4.4.0(supports-color@10.0.0) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) + debug: 4.4.0 remix-auth: 3.6.0(@remix-run/react@2.1.0)(@remix-run/server-runtime@2.1.0) transitivePeerDependencies: - supports-color @@ -33558,8 +33797,8 @@ packages: '@remix-run/react': ^1.0.0 || ^2.0.0 '@remix-run/server-runtime': ^1.0.0 || ^2.0.0 dependencies: - '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) uuid: 8.3.2 dev: false @@ -33570,12 +33809,12 @@ packages: '@remix-run/server-runtime': ^1.16.0 || ^2.0 react: ^17.0.2 || ^18.0.0 dependencies: - '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) - '@remix-run/server-runtime': 2.1.0(typescript@5.5.4) + '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) + '@remix-run/server-runtime': 2.1.0(typescript@5.8.3) react: 18.2.0 dev: false - /remix-utils@7.7.0(@remix-run/node@2.1.0)(@remix-run/react@2.1.0)(@remix-run/router@1.15.3)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.23.8): + /remix-utils@7.7.0(@remix-run/node@2.1.0)(@remix-run/react@2.1.0)(@remix-run/router@1.15.3)(intl-parse-accept-language@1.0.0)(react@18.2.0)(zod@3.25.76): resolution: {integrity: sha512-J8NhP044nrNIam/xOT1L9a4RQ9FSaA2wyrUwmN8ZT+c/+CdAAf70yfaLnvMyKcV5U+8BcURQ/aVbth77sT6jGA==} engines: {node: '>=18.0.0'} peerDependencies: @@ -33608,13 +33847,13 @@ packages: zod: optional: true dependencies: - '@remix-run/node': 2.1.0(typescript@5.5.4) - '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.5.4) + '@remix-run/node': 2.1.0(typescript@5.8.3) + '@remix-run/react': 2.1.0(react-dom@18.2.0)(react@18.2.0)(typescript@5.8.3) '@remix-run/router': 1.15.3 intl-parse-accept-language: 1.0.0 react: 18.2.0 type-fest: 4.33.0 - zod: 3.23.8 + zod: 3.25.76 dev: false /remove-accents@0.5.0: @@ -33669,15 +33908,26 @@ packages: engines: {node: '>=0.10.0'} dev: true + /require-in-the-middle@7.1.1: + resolution: {integrity: sha512-OScOjQjrrjhAdFpQmnkE/qbIBGCRFhQB/YaJhcC3CPOlmhe7llnW46Ac1J5+EjcNXOTnDdpF96Erw/yedsGksQ==} + engines: {node: '>=8.6.0'} + dependencies: + debug: 4.4.0 + module-details-from-path: 1.0.3 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + /require-in-the-middle@7.1.1(supports-color@10.0.0): resolution: {integrity: sha512-OScOjQjrrjhAdFpQmnkE/qbIBGCRFhQB/YaJhcC3CPOlmhe7llnW46Ac1J5+EjcNXOTnDdpF96Erw/yedsGksQ==} engines: {node: '>=8.6.0'} dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) module-details-from-path: 1.0.3 resolve: 1.22.8 transitivePeerDependencies: - supports-color + dev: false /require-like@0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} @@ -33926,7 +34176,6 @@ packages: /runtypes@6.7.0: resolution: {integrity: sha512-3TLdfFX8YHNFOhwHrSJza6uxVBmBrEjnNQlNXvXCdItS0Pdskfg5vVXUTWIN+Y23QR09jWpSl99UHkA83m4uWA==} - dev: false /rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -34131,7 +34380,7 @@ packages: resolution: {integrity: sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==} engines: {node: '>= 18'} dependencies: - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) destroy: 1.2.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -34584,7 +34833,7 @@ packages: requiresBuild: true dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -34596,7 +34845,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -34607,7 +34856,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -35198,7 +35447,7 @@ packages: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 fast-safe-stringify: 2.1.1 form-data: 4.0.4 formidable: 3.5.1 @@ -35219,7 +35468,6 @@ packages: /superstruct@2.0.2: resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} engines: {node: '>=14.0.0'} - dev: false /supertest@7.0.0: resolution: {integrity: sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==} @@ -35748,7 +35996,7 @@ packages: archiver: 7.0.1 async-lock: 1.4.1 byline: 5.0.0 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 docker-compose: 0.24.8 dockerode: 4.0.6 get-port: 7.1.0 @@ -35810,7 +36058,6 @@ packages: /tiny-case@1.0.3: resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} - dev: false /tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} @@ -35977,7 +36224,6 @@ packages: /toposort@2.0.2: resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} - dev: false /totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} @@ -36056,7 +36302,7 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - /ts-node@10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.5.4): + /ts-node@10.9.1(@swc/core@1.3.26)(@types/node@20.14.14)(typescript@5.8.3): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -36083,11 +36329,11 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.5.4 + typescript: 5.8.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - /ts-node@10.9.2(@types/node@20.14.14)(typescript@5.5.4): + /ts-node@10.9.2(@types/node@20.14.14)(typescript@5.8.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -36113,7 +36359,7 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.5.4 + typescript: 5.8.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -36161,6 +36407,19 @@ packages: typescript: 5.5.4 dev: true + /tsconfck@2.1.2(typescript@5.8.3): + resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==} + engines: {node: ^14.13.1 || ^16 || >=18} + hasBin: true + peerDependencies: + typescript: ^4.3.5 || ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.8.3 + dev: true + /tsconfck@3.1.3(typescript@5.5.4): resolution: {integrity: sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ==} engines: {node: ^18 || >=20} @@ -36259,7 +36518,7 @@ packages: cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 esbuild: 0.25.1 joycon: 3.1.1 picocolors: 1.1.1 @@ -36280,14 +36539,14 @@ packages: - yaml dev: true - /tsutils@3.21.0(typescript@5.5.4): + /tsutils@3.21.0(typescript@5.8.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 5.5.4 + typescript: 5.8.3 dev: true /tsx@3.12.2: @@ -36461,7 +36720,6 @@ packages: /type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - dev: false /type-fest@4.10.3: resolution: {integrity: sha512-JLXyjizi072smKGGcZiAJDCNweT8J+AuRxmPZ1aG7TERg4ijx9REl8CNhbr36RV4qXqL1gO1FF9HL8OkVmmrsA==} @@ -36622,7 +36880,7 @@ packages: reflect-metadata: 0.2.2 sha.js: 2.4.11 sqlite3: 5.1.7 - ts-node: 10.9.2(@types/node@20.14.14)(typescript@5.5.4) + ts-node: 10.9.2(@types/node@20.14.14)(typescript@5.8.3) tslib: 2.6.2 uuid: 9.0.1 yargs: 17.7.2 @@ -36647,6 +36905,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + /typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + /ufo@1.5.4: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} @@ -37175,8 +37438,19 @@ packages: engines: {node: '>=0.10.0'} dev: false - /valibot@0.42.1(typescript@5.5.4): + /valibot@0.42.1(typescript@5.8.3): resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.8.3 + dev: false + + /valibot@1.1.0(typescript@5.5.4): + resolution: {integrity: sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -37184,6 +37458,17 @@ packages: optional: true dependencies: typescript: 5.5.4 + dev: true + + /valibot@1.1.0(typescript@5.8.3): + resolution: {integrity: sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.8.3 dev: false /validate-npm-package-license@3.0.4: @@ -37288,7 +37573,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) mlly: 1.7.1 pathe: 1.1.2 picocolors: 1.1.1 @@ -37306,13 +37591,34 @@ packages: - terser dev: true + /vite-node@2.1.9(@types/node@20.14.14): + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.4.1(supports-color@10.0.0) + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.2.7(@types/node@20.14.14) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vite-node@3.1.4(@types/node@20.14.14): resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.1(supports-color@10.0.0) es-module-lexer: 1.7.0 pathe: 2.0.3 vite: 5.2.7(@types/node@20.14.14) @@ -37338,6 +37644,17 @@ packages: - typescript dev: true + /vite-tsconfig-paths@4.0.5(typescript@5.8.3): + resolution: {integrity: sha512-/L/eHwySFYjwxoYt1WRJniuK/jPv+WGwgRGBYx3leciR5wBeqntQpUE6Js6+TJemChc+ter7fDBKieyEWDx4yQ==} + dependencies: + debug: 4.3.7(supports-color@10.0.0) + globrex: 0.1.2 + tsconfck: 2.1.2(typescript@5.8.3) + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /vite@4.1.4(@types/node@20.14.14): resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -37438,12 +37755,69 @@ packages: dependencies: '@types/node': 20.14.14 esbuild: 0.20.2 - postcss: 8.5.3 + postcss: 8.5.4 rollup: 4.36.0 optionalDependencies: fsevents: 2.3.3 dev: true + /vitest@2.1.9(@types/node@20.14.14): + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/node': 20.14.14 + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.2.7) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.2.0 + debug: 4.4.1(supports-color@10.0.0) + expect-type: 1.2.1 + magic-string: 0.30.17 + pathe: 1.1.2 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 1.2.0 + vite: 5.2.7(@types/node@20.14.14) + vite-node: 2.1.9(@types/node@20.14.14) + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vitest@3.1.4(@types/node@20.14.14): resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -37481,7 +37855,7 @@ packages: '@vitest/spy': 3.1.4 '@vitest/utils': 3.1.4 chai: 5.2.0 - debug: 4.4.0(supports-color@10.0.0) + debug: 4.4.0 expect-type: 1.2.1 magic-string: 0.30.17 pathe: 2.0.3 @@ -37520,6 +37894,22 @@ packages: '@vue/shared': 3.5.16 typescript: 5.5.4 + /vue@3.5.16(typescript@5.8.3): + resolution: {integrity: sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.5.16 + '@vue/compiler-sfc': 3.5.16 + '@vue/runtime-dom': 3.5.16 + '@vue/server-renderer': 3.5.16(vue@3.5.16) + '@vue/shared': 3.5.16 + typescript: 5.8.3 + dev: false + /w3c-keyname@2.2.6: resolution: {integrity: sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==} dev: false @@ -38124,6 +38514,14 @@ packages: type-fest: 2.19.0 dev: false + /yup@1.6.1: + resolution: {integrity: sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==} + dependencies: + property-expr: 2.0.6 + tiny-case: 1.0.3 + toposort: 2.0.2 + type-fest: 2.19.0 + /zimmerframe@1.1.2: resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} @@ -38157,46 +38555,51 @@ packages: /zod-error@1.5.0: resolution: {integrity: sha512-zzopKZ/skI9iXpqCEPj+iLCKl9b88E43ehcU+sbRoHuwGd9F1IDVGQ70TyO6kmfiRL1g4IXkjsXK+g1gLYl4WQ==} dependencies: - zod: 3.23.8 + zod: 3.25.76 dev: false - /zod-to-json-schema@3.23.2(zod@3.23.8): + /zod-to-json-schema@3.23.2(zod@3.25.76): resolution: {integrity: sha512-uSt90Gzc/tUfyNqxnjlfBs8W6WSGpNBv0rVsNxP/BVSMHMKGdthPYff4xtCHYloJGM0CFxFsb3NbC0eqPhfImw==} peerDependencies: zod: ^3.23.3 dependencies: - zod: 3.23.8 + zod: 3.25.76 dev: false - /zod-to-json-schema@3.24.3(zod@3.23.8): + /zod-to-json-schema@3.24.3(zod@3.25.76): resolution: {integrity: sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==} peerDependencies: zod: ^3.24.1 dependencies: - zod: 3.23.8 + zod: 3.25.76 + dev: true - /zod-to-json-schema@3.24.5(zod@3.23.8): + /zod-to-json-schema@3.24.5(zod@3.25.76): resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} peerDependencies: zod: ^3.24.1 dependencies: - zod: 3.23.8 + zod: 3.25.76 - /zod-validation-error@1.5.0(zod@3.23.8): + /zod-validation-error@1.5.0(zod@3.25.76): resolution: {integrity: sha512-/7eFkAI4qV0tcxMBB/3+d2c1P6jzzZYdYSlBuAklzMuCrJu5bzJfHS0yVAS87dRHVlhftd6RFJDIvv03JgkSbw==} engines: {node: '>=16.0.0'} peerDependencies: zod: ^3.18.0 dependencies: - zod: 3.23.8 + zod: 3.25.76 + dev: false + + /zod@3.22.3: + resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} dev: false /zod@3.23.8: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + dev: false /zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - dev: false /zustand@4.5.5(@types/react@18.2.69)(react@18.2.0): resolution: {integrity: sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==} diff --git a/references/d3-chat/package.json b/references/d3-chat/package.json index 36dc313f2b..55e657203b 100644 --- a/references/d3-chat/package.json +++ b/references/d3-chat/package.json @@ -42,7 +42,7 @@ "react-markdown": "^10.1.0", "tailwind-merge": "^3.1.0", "tw-animate-css": "^1.2.4", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@tailwindcss/postcss": "^4", diff --git a/references/d3-openai-agents/package.json b/references/d3-openai-agents/package.json index e94dc26a21..91309ea5a3 100644 --- a/references/d3-openai-agents/package.json +++ b/references/d3-openai-agents/package.json @@ -33,7 +33,7 @@ "react-dom": "^19.0.0", "tailwind-merge": "^3.0.2", "tw-animate-css": "^1.2.4", - "zod": "3.23.8", + "zod": "3.25.76", "zod-to-json-schema": "^3.24.5" }, "devDependencies": { diff --git a/references/hello-world/package.json b/references/hello-world/package.json index 89dbeea911..dea86c6b7a 100644 --- a/references/hello-world/package.json +++ b/references/hello-world/package.json @@ -8,10 +8,13 @@ "dependencies": { "@trigger.dev/build": "workspace:*", "@trigger.dev/sdk": "workspace:*", + "arktype": "^2.0.0", "openai": "^4.97.0", "puppeteer-core": "^24.15.0", "replicate": "^1.0.1", - "zod": "3.23.8" + "yup": "^1.6.1", + "zod": "3.25.76", + "@sinclair/typebox": "^0.34.3" }, "scripts": { "dev": "trigger dev", diff --git a/references/hello-world/src/trigger/example.ts b/references/hello-world/src/trigger/example.ts index 1eb7f18916..91827e145c 100644 --- a/references/hello-world/src/trigger/example.ts +++ b/references/hello-world/src/trigger/example.ts @@ -19,7 +19,7 @@ export const helloWorldTask = task({ env: process.env, }); - logger.debug("debug: Hello, world!", { payload }); + logger.debug("debug: Hello, worlds!", { payload }); logger.info("info: Hello, world!", { payload }); logger.log("log: Hello, world!", { payload }); logger.warn("warn: Hello, world!", { payload }); diff --git a/references/hello-world/src/trigger/jsonSchema.ts b/references/hello-world/src/trigger/jsonSchema.ts new file mode 100644 index 0000000000..f347f9d389 --- /dev/null +++ b/references/hello-world/src/trigger/jsonSchema.ts @@ -0,0 +1,413 @@ +import { task, schemaTask, logger, type JSONSchema } from "@trigger.dev/sdk/v3"; +import { z } from "zod"; +import * as y from "yup"; +import { type } from "arktype"; +import { Type, Static } from "@sinclair/typebox"; + +// =========================================== +// Example 1: Using schemaTask with Zod +// =========================================== +const userSchema = z.object({ + id: z.string().uuid(), + name: z.string().min(1), + email: z.string().email(), + age: z.number().int().min(0).max(150), + preferences: z + .object({ + newsletter: z.boolean().default(false), + theme: z.enum(["light", "dark"]).default("light"), + }) + .optional(), +}); + +export const processUserWithZod = schemaTask({ + id: "json-schema-zod-example", + schema: userSchema, + run: async (payload, { ctx }) => { + // payload is fully typed based on the Zod schema + logger.info("Processing user with Zod schema", { + userId: payload.id, + userName: payload.name, + }); + + // The schema is automatically converted to JSON Schema and synced + return { + processed: true, + userId: payload.id, + welcomeMessage: `Welcome ${payload.name}!`, + }; + }, +}); + +// =========================================== +// Example 2: Using plain task with manual JSON Schema +// =========================================== +export const processOrderManualSchema = task({ + id: "json-schema-manual-example", + // Manually provide JSON Schema for the payload + jsonSchema: { + $schema: "http://json-schema.org/draft-07/schema#", + type: "object", + title: "Order Processing Request", + description: "Schema for processing customer orders", + properties: { + orderId: { + type: "string", + pattern: "^ORD-[0-9]+$", + description: "Order ID in format ORD-XXXXX", + }, + customerId: { + type: "string", + format: "uuid", + }, + items: { + type: "array", + minItems: 1, + items: { + type: "object", + properties: { + productId: { type: "string" }, + quantity: { type: "integer", minimum: 1 }, + price: { type: "number", minimum: 0, multipleOf: 0.01 }, + }, + required: ["productId", "quantity", "price"], + additionalProperties: false, + }, + }, + totalAmount: { + type: "number", + minimum: 0, + multipleOf: 0.01, + }, + status: { + type: "string", + enum: ["pending", "processing", "shipped", "delivered"], + default: "pending", + }, + }, + required: ["orderId", "customerId", "items", "totalAmount"], + additionalProperties: false, + } satisfies JSONSchema, + run: async (payload, { ctx }) => { + logger.info("Processing order with manual JSON Schema", { + orderId: payload.orderId, + }); + + // Note: With plain tasks, the payload is typed as 'any' + // The JSON Schema will be used for documentation and validation on the server + return { + processed: true, + orderId: payload.orderId, + status: "processing", + }; + }, +}); + +// =========================================== +// Example 3: Using schemaTask with Yup +// =========================================== +const productSchema = y.object({ + sku: y + .string() + .required() + .matches(/^[A-Z]{3}-[0-9]{5}$/), + name: y.string().required().min(3).max(100), + description: y.string().max(500), + price: y.number().required().positive(), + categories: y.array().of(y.string()).min(1).required(), + inStock: y.boolean().default(true), +}); + +export const processProductWithYup = schemaTask({ + id: "json-schema-yup-example", + schema: productSchema, + run: async (payload, { ctx }) => { + logger.info("Processing product with Yup schema", { + sku: payload.sku, + name: payload.name, + }); + + return { + processed: true, + sku: payload.sku, + message: `Product ${payload.name} has been processed`, + }; + }, +}); + +// =========================================== +// Example 4: Using schemaTask with ArkType +// =========================================== +const invoiceSchema = type({ + invoiceNumber: "string", + date: "Date", + dueDate: "Date", + "discount?": "number", + lineItems: [ + { + description: "string", + quantity: "number", + unitPrice: "number", + }, + ], + customer: { + id: "string", + name: "string", + "taxId?": "string", + }, +}); + +export const processInvoiceWithArkType = schemaTask({ + id: "json-schema-arktype-example", + schema: invoiceSchema, + run: async (payload, { ctx }) => { + logger.info("Processing invoice with ArkType schema", { + invoiceNumber: payload.invoiceNumber, + customerName: payload.customer.name, + }); + + const total = payload.lineItems.reduce((sum, item) => sum + item.quantity * item.unitPrice, 0); + + const discount = payload.discount || 0; + const finalAmount = total * (1 - discount / 100); + + return { + processed: true, + invoiceNumber: payload.invoiceNumber, + totalAmount: finalAmount, + }; + }, +}); + +// =========================================== +// Example 5: Using TypeBox (already JSON Schema) +// =========================================== +const eventSchema = Type.Object({ + eventId: Type.String({ format: "uuid" }), + eventType: Type.Union([ + Type.Literal("user.created"), + Type.Literal("user.updated"), + Type.Literal("user.deleted"), + Type.Literal("order.placed"), + Type.Literal("order.shipped"), + ]), + timestamp: Type.Integer({ minimum: 0 }), + userId: Type.String(), + metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown())), + payload: Type.Unknown(), +}); + +type EventType = Static; + +export const processEventWithTypeBox = task({ + id: "json-schema-typebox-example", + // TypeBox schemas are already JSON Schema compliant + jsonSchema: eventSchema, + run: async (payload: EventType, { ctx }) => { + // Cast to get TypeScript type safety + const event = payload; + + logger.info("Processing event with TypeBox schema", { + eventId: event.eventId, + eventType: event.eventType, + userId: event.userId, + }); + + // Handle different event types + switch (event.eventType) { + case "user.created": + logger.info("New user created", { userId: event.userId }); + break; + case "order.placed": + logger.info("Order placed", { userId: event.userId }); + break; + default: + logger.info("Event processed", { eventType: event.eventType }); + } + + return { + processed: true, + eventId: event.eventId, + eventType: event.eventType, + }; + }, +}); + +// =========================================== +// Example 6: Using plain task with a Zod schema +// =========================================== +// If you need to use a plain task but have a Zod schema, +// you should use schemaTask instead for better DX. +// This example shows what NOT to do: + +const notificationSchema = z.object({ + recipientId: z.string(), + type: z.enum(["email", "sms", "push"]), + subject: z.string().optional(), + message: z.string(), + priority: z.enum(["low", "normal", "high"]).default("normal"), + scheduledFor: z.date().optional(), + metadata: z.record(z.unknown()).optional(), +}); + +// ❌ Don't do this - use schemaTask instead! +export const sendNotificationBadExample = task({ + id: "json-schema-dont-do-this", + run: async (payload, { ctx }) => { + // You'd have to manually validate + const notification = notificationSchema.parse(payload); + + logger.info("This is not ideal - use schemaTask instead!"); + + return { sent: true }; + }, +}); + +// ✅ Do this instead - much better! +export const sendNotificationGoodExample = schemaTask({ + id: "json-schema-do-this-instead", + schema: notificationSchema, + run: async (notification, { ctx }) => { + // notification is already validated and typed! + logger.info("Sending notification", { + recipientId: notification.recipientId, + type: notification.type, + priority: notification.priority, + }); + + // Simulate sending notification + await new Promise((resolve) => setTimeout(resolve, 1000)); + + return { + sent: true, + notificationId: ctx.run.id, + recipientId: notification.recipientId, + type: notification.type, + }; + }, +}); + +// =========================================== +// Example 7: Complex nested schema with references +// =========================================== +const addressSchema = z.object({ + street: z.string(), + city: z.string(), + state: z.string().length(2), + zipCode: z.string().regex(/^\d{5}(-\d{4})?$/), + country: z.string().default("US"), +}); + +const companySchema = z.object({ + companyId: z.string().uuid(), + name: z.string(), + taxId: z.string().optional(), + addresses: z.object({ + billing: addressSchema, + shipping: addressSchema.optional(), + }), + contacts: z + .array( + z.object({ + name: z.string(), + email: z.string().email(), + phone: z.string().optional(), + role: z.enum(["primary", "billing", "technical"]), + }) + ) + .min(1), + settings: z.object({ + invoicePrefix: z.string().default("INV"), + paymentTerms: z.number().int().min(0).max(90).default(30), + currency: z.enum(["USD", "EUR", "GBP"]).default("USD"), + }), +}); + +export const processCompanyWithComplexSchema = schemaTask({ + id: "json-schema-complex-example", + schema: companySchema, + maxDuration: 300, // 5 minutes + retry: { + maxAttempts: 3, + factor: 2, + }, + run: async (payload, { ctx }) => { + logger.info("Processing company with complex schema", { + companyId: payload.companyId, + name: payload.name, + contactCount: payload.contacts.length, + }); + + // Process each contact + for (const contact of payload.contacts) { + logger.info("Processing contact", { + name: contact.name, + role: contact.role, + }); + } + + return { + processed: true, + companyId: payload.companyId, + name: payload.name, + primaryContact: payload.contacts.find((c) => c.role === "primary"), + }; + }, +}); + +// =========================================== +// Example 8: Demonstrating schema benefits +// =========================================== +export const triggerExamples = task({ + id: "json-schema-trigger-examples", + run: async (_, { ctx }) => { + logger.info("Triggering various schema examples"); + + // Trigger Zod example - TypeScript will enforce correct payload + await processUserWithZod.trigger({ + id: "550e8400-e29b-41d4-a716-446655440000", + name: "John Doe", + email: "john@example.com", + age: 30, + preferences: { + newsletter: true, + theme: "dark", + }, + }); + + // Trigger Yup example + await processProductWithYup.trigger({ + sku: "ABC-12345", + name: "Premium Widget", + description: "A high-quality widget for all your needs", + price: 99.99, + categories: ["electronics", "gadgets"], + inStock: true, + }); + + // Trigger manual schema example (no compile-time validation) + await processOrderManualSchema.trigger({ + orderId: "ORD-12345", + customerId: "550e8400-e29b-41d4-a716-446655440001", + items: [ + { + productId: "PROD-001", + quantity: 2, + price: 29.99, + }, + { + productId: "PROD-002", + quantity: 1, + price: 49.99, + }, + ], + totalAmount: 109.97, + status: "pending", + }); + + return { + message: "All examples triggered successfully", + timestamp: new Date().toISOString(), + }; + }, +}); \ No newline at end of file diff --git a/references/hello-world/src/trigger/jsonSchemaApi.ts b/references/hello-world/src/trigger/jsonSchemaApi.ts new file mode 100644 index 0000000000..9ac121b369 --- /dev/null +++ b/references/hello-world/src/trigger/jsonSchemaApi.ts @@ -0,0 +1,343 @@ +import { task, schemaTask, logger, type JSONSchema } from "@trigger.dev/sdk/v3"; +import { z } from "zod"; + +// =========================================== +// Example: Webhook Handler with Schema Validation +// =========================================== + +// Define schemas for different webhook event types +const baseWebhookSchema = z.object({ + id: z.string(), + timestamp: z.string().datetime(), + type: z.string(), + version: z.literal("1.0"), +}); + +// Payment webhook events +const paymentEventSchema = baseWebhookSchema.extend({ + type: z.literal("payment"), + data: z.object({ + paymentId: z.string(), + amount: z.number().positive(), + currency: z.string().length(3), + status: z.enum(["pending", "processing", "completed", "failed"]), + customerId: z.string(), + paymentMethod: z.object({ + type: z.enum(["card", "bank_transfer", "paypal"]), + last4: z.string().optional(), + }), + metadata: z.record(z.string()).optional(), + }), +}); + +// Customer webhook events +const customerEventSchema = baseWebhookSchema.extend({ + type: z.literal("customer"), + data: z.object({ + customerId: z.string(), + action: z.enum(["created", "updated", "deleted"]), + email: z.string().email(), + name: z.string(), + subscription: z.object({ + status: z.enum(["active", "cancelled", "past_due"]), + plan: z.string(), + }).optional(), + }), +}); + +// Union of all webhook types +const webhookSchema = z.discriminatedUnion("type", [ + paymentEventSchema, + customerEventSchema, +]); + +export const handleWebhook = schemaTask({ + id: "handle-webhook", + schema: webhookSchema, + run: async (payload, { ctx }) => { + logger.info("Processing webhook", { + id: payload.id, + type: payload.type, + timestamp: payload.timestamp, + }); + + // TypeScript knows the exact shape based on the discriminated union + switch (payload.type) { + case "payment": + logger.info("Payment event received", { + paymentId: payload.data.paymentId, + amount: payload.data.amount, + status: payload.data.status, + }); + + if (payload.data.status === "completed") { + // Trigger order fulfillment + await fulfillOrder.trigger({ + customerId: payload.data.customerId, + paymentId: payload.data.paymentId, + amount: payload.data.amount, + }); + } + break; + + case "customer": + logger.info("Customer event received", { + customerId: payload.data.customerId, + action: payload.data.action, + }); + + if (payload.data.action === "created") { + // Send welcome email + await sendWelcomeEmail.trigger({ + email: payload.data.email, + name: payload.data.name, + }); + } + break; + } + + return { + processed: true, + eventId: payload.id, + eventType: payload.type, + }; + }, +}); + +// =========================================== +// Example: External API Integration +// =========================================== + +// Schema for making API requests to a third-party service +const apiRequestSchema = z.object({ + endpoint: z.enum(["/users", "/products", "/orders"]), + method: z.enum(["GET", "POST", "PUT", "DELETE"]), + params: z.record(z.string()).optional(), + body: z.unknown().optional(), + headers: z.record(z.string()).optional(), + retryOnError: z.boolean().default(true), +}); + +// Response schemas for different endpoints +const userResponseSchema = z.object({ + id: z.string(), + email: z.string().email(), + name: z.string(), + createdAt: z.string().datetime(), +}); + +const productResponseSchema = z.object({ + id: z.string(), + name: z.string(), + price: z.number(), + inStock: z.boolean(), +}); + +export const callExternalApi = schemaTask({ + id: "call-external-api", + schema: apiRequestSchema, + retry: { + maxAttempts: 3, + factor: 2, + minTimeoutInMs: 1000, + maxTimeoutInMs: 10000, + }, + run: async (payload, { ctx }) => { + logger.info("Making API request", { + endpoint: payload.endpoint, + method: payload.method, + }); + + // Simulate API call + const response = await makeApiCall(payload); + + // Validate response based on endpoint + let validatedResponse; + switch (payload.endpoint) { + case "/users": + validatedResponse = userResponseSchema.parse(response); + break; + case "/products": + validatedResponse = productResponseSchema.parse(response); + break; + default: + validatedResponse = response; + } + + return { + success: true, + endpoint: payload.endpoint, + response: validatedResponse, + }; + }, +}); + +// Helper function to simulate API calls +async function makeApiCall(request: z.infer) { + // Simulate network delay + await new Promise(resolve => setTimeout(resolve, 100)); + + // Return mock data based on endpoint + switch (request.endpoint) { + case "/users": + return { + id: "user_123", + email: "user@example.com", + name: "John Doe", + createdAt: new Date().toISOString(), + }; + case "/products": + return { + id: "prod_456", + name: "Premium Widget", + price: 99.99, + inStock: true, + }; + default: + return { message: "Success" }; + } +} + +// =========================================== +// Example: Batch Processing with Validation +// =========================================== + +const batchItemSchema = z.object({ + id: z.string(), + operation: z.enum(["create", "update", "delete"]), + resourceType: z.enum(["user", "product", "order"]), + data: z.record(z.unknown()), +}); + +const batchRequestSchema = z.object({ + batchId: z.string(), + items: z.array(batchItemSchema).min(1).max(100), + options: z.object({ + stopOnError: z.boolean().default(false), + parallel: z.boolean().default(true), + maxConcurrency: z.number().int().min(1).max(10).default(5), + }).default({}), +}); + +export const processBatch = schemaTask({ + id: "process-batch", + schema: batchRequestSchema, + maxDuration: 300, // 5 minutes for large batches + run: async (payload, { ctx }) => { + logger.info("Processing batch", { + batchId: payload.batchId, + itemCount: payload.items.length, + parallel: payload.options.parallel, + }); + + const results = []; + const errors = []; + + if (payload.options.parallel) { + // Process items in parallel with concurrency limit + const chunks = chunkArray(payload.items, payload.options.maxConcurrency); + + for (const chunk of chunks) { + const chunkResults = await Promise.allSettled( + chunk.map(item => processItem(item)) + ); + + chunkResults.forEach((result, index) => { + if (result.status === "fulfilled") { + results.push(result.value); + } else { + errors.push({ + item: chunk[index], + error: result.reason, + }); + + if (payload.options.stopOnError) { + throw new Error(`Batch processing stopped due to error in item ${chunk[index].id}`); + } + } + }); + } + } else { + // Process items sequentially + for (const item of payload.items) { + try { + const result = await processItem(item); + results.push(result); + } catch (error) { + errors.push({ item, error }); + + if (payload.options.stopOnError) { + throw new Error(`Batch processing stopped due to error in item ${item.id}`); + } + } + } + } + + return { + batchId: payload.batchId, + processed: results.length, + failed: errors.length, + results, + errors, + }; + }, +}); + +async function processItem(item: z.infer) { + logger.info("Processing batch item", { + id: item.id, + operation: item.operation, + resourceType: item.resourceType, + }); + + // Simulate processing + await new Promise(resolve => setTimeout(resolve, 50)); + + return { + id: item.id, + success: true, + operation: item.operation, + resourceType: item.resourceType, + }; +} + +function chunkArray(array: T[], size: number): T[][] { + const chunks: T[][] = []; + for (let i = 0; i < array.length; i += size) { + chunks.push(array.slice(i, i + size)); + } + return chunks; +} + +// =========================================== +// Helper Tasks +// =========================================== + +const orderSchema = z.object({ + customerId: z.string(), + paymentId: z.string(), + amount: z.number(), +}); + +export const fulfillOrder = schemaTask({ + id: "fulfill-order", + schema: orderSchema, + run: async (payload, { ctx }) => { + logger.info("Fulfilling order", payload); + return { fulfilled: true }; + }, +}); + +const welcomeEmailSchema = z.object({ + email: z.string().email(), + name: z.string(), +}); + +export const sendWelcomeEmail = schemaTask({ + id: "send-welcome-email", + schema: welcomeEmailSchema, + run: async (payload, { ctx }) => { + logger.info("Sending welcome email", payload); + return { sent: true }; + }, +}); \ No newline at end of file diff --git a/references/hello-world/src/trigger/jsonSchemaSimple.ts b/references/hello-world/src/trigger/jsonSchemaSimple.ts new file mode 100644 index 0000000000..a844b14034 --- /dev/null +++ b/references/hello-world/src/trigger/jsonSchemaSimple.ts @@ -0,0 +1,235 @@ +import { task, schemaTask, logger, type JSONSchema } from "@trigger.dev/sdk/v3"; +import { z } from "zod"; + +// =========================================== +// The Two Main Approaches +// =========================================== + +// Approach 1: Using schemaTask (Recommended) +// - Automatic JSON Schema conversion +// - Full TypeScript type safety +// - Runtime validation built-in +const emailSchema = z.object({ + to: z.string().email(), + subject: z.string(), + body: z.string(), + attachments: z + .array( + z.object({ + filename: z.string(), + url: z.string().url(), + }) + ) + .optional(), +}); + +export const sendEmailSchemaTask = schemaTask({ + id: "send-email-schema-task", + schema: emailSchema, + run: async (payload, { ctx }) => { + // payload is fully typed as: + // { + // to: string; + // subject: string; + // body: string; + // attachments?: Array<{ filename: string; url: string; }>; + // } + + logger.info("Sending email", { + to: payload.to, + subject: payload.subject, + hasAttachments: !!payload.attachments?.length, + }); + + // Your email sending logic here... + + return { + sent: true, + messageId: `msg_${ctx.run.id}`, + sentAt: new Date().toISOString(), + }; + }, +}); + +// Approach 2: Using plain task with payloadSchema +// - Manual JSON Schema definition +// - No automatic type inference (payload is 'any') +// - Good for when you already have JSON Schema definitions +export const sendEmailPlainTask = task({ + id: "send-email-plain-task", + jsonSchema: { + type: "object", + properties: { + to: { + type: "string", + format: "email", + description: "Recipient email address", + }, + subject: { + type: "string", + maxLength: 200, + }, + body: { + type: "string", + }, + attachments: { + type: "array", + items: { + type: "object", + properties: { + filename: { type: "string" }, + url: { type: "string", format: "uri" }, + }, + required: ["filename", "url"], + }, + }, + }, + required: ["to", "subject", "body"], + } satisfies JSONSchema, // Use 'satisfies' for type checking + run: async (payload, { ctx }) => { + // payload is typed as 'any' - you need to validate/cast it yourself + logger.info("Sending email", { + to: payload.to, + subject: payload.subject, + }); + + // Your email sending logic here... + + return { + sent: true, + messageId: `msg_${ctx.run.id}`, + sentAt: new Date().toISOString(), + }; + }, +}); + +// =========================================== +// Benefits of JSON Schema +// =========================================== + +// 1. Documentation - The schema is visible in the Trigger.dev dashboard +// 2. Validation - Invalid payloads are rejected before execution +// 3. Type Safety - With schemaTask, you get full TypeScript support +// 4. OpenAPI Generation - Can be used to generate API documentation +// 5. Client SDKs - Can generate typed clients for other languages + +export const demonstrateBenefits = task({ + id: "json-schema-benefits-demo", + run: async (_, { ctx }) => { + logger.info("Demonstrating JSON Schema benefits"); + + // With schemaTask, TypeScript prevents invalid payloads at compile time + try { + await sendEmailSchemaTask.trigger({ + to: "user@example.com", + subject: "Welcome!", + body: "Thanks for signing up!", + // TypeScript error if you try to add invalid fields + // invalidField: "This would cause a TypeScript error", + }); + } catch (error) { + logger.error("Failed to send email", { error }); + } + + // With plain task, validation happens at runtime + try { + await sendEmailPlainTask.trigger({ + to: "not-an-email", // This will fail validation at runtime + subject: "Test", + body: "Test email", + }); + } catch (error) { + logger.error("Failed validation", { error }); + } + + return { demonstrated: true }; + }, +}); + +// =========================================== +// Real-World Example: User Registration Flow +// =========================================== +const userRegistrationSchema = z.object({ + email: z.string().email(), + username: z + .string() + .min(3) + .max(20) + .regex(/^[a-zA-Z0-9_]+$/), + password: z.string().min(8), + profile: z.object({ + firstName: z.string(), + lastName: z.string(), + dateOfBirth: z.string().optional(), // ISO date string + preferences: z + .object({ + newsletter: z.boolean().default(false), + notifications: z.boolean().default(true), + }) + .default({}), + }), + referralCode: z.string().optional(), +}); + +export const registerUser = schemaTask({ + id: "register-user", + schema: userRegistrationSchema, + retry: { + maxAttempts: 3, + minTimeoutInMs: 1000, + maxTimeoutInMs: 10000, + }, + run: async (payload, { ctx }) => { + logger.info("Registering new user", { + email: payload.email, + username: payload.username, + }); + + // Step 1: Validate uniqueness + logger.info("Checking if user exists"); + // ... database check logic ... + + // Step 2: Create user account + logger.info("Creating user account"); + const userId = `user_${Date.now()}`; + // ... user creation logic ... + + // Step 3: Send welcome email + await sendEmailSchemaTask.trigger({ + to: payload.email, + subject: `Welcome to our platform, ${payload.profile.firstName}!`, + body: `Hi ${payload.profile.firstName},\n\nThanks for joining us...`, + }); + + // Step 4: Apply referral code if provided + if (payload.referralCode) { + logger.info("Processing referral code", { code: payload.referralCode }); + // ... referral logic ... + } + + return { + success: true, + userId, + username: payload.username, + welcomeEmailSent: true, + }; + }, +}); + +// =========================================== +// When to Use Each Approach +// =========================================== + +/* +Use schemaTask when: +- You're already using Zod, Yup, ArkType, etc. in your codebase +- You want TypeScript type inference +- You want runtime validation handled automatically +- You're building new tasks from scratch + +Use plain task with payloadSchema when: +- You have existing JSON Schema definitions +- You're migrating from another system that uses JSON Schema +- You need fine-grained control over the schema format +- You're working with generated schemas from OpenAPI/Swagger +*/ \ No newline at end of file diff --git a/references/json-schema-test/README.md b/references/json-schema-test/README.md new file mode 100644 index 0000000000..bbde286f24 --- /dev/null +++ b/references/json-schema-test/README.md @@ -0,0 +1,118 @@ +# JSON Schema Test Reference Project + +This project demonstrates and tests the JSON schema functionality in Trigger.dev v3. + +## Features Implemented + +### 1. JSONSchema Type Export +- ✅ Proper `JSONSchema` type based on JSON Schema Draft 7 +- ✅ Exported from `@trigger.dev/sdk/v3` +- ✅ Can be used with TypeScript's `satisfies` operator + +### 2. Plain Task with payloadSchema +- ✅ Tasks accept a `payloadSchema` property +- ✅ Schema is stored and will be synced during indexing +- ✅ Type-safe schema definition + +### 3. Schema Task with Automatic Conversion +- ✅ `schemaTask` automatically converts Zod schemas to JSON Schema +- ✅ Full TypeScript type inference from schema +- ✅ Runtime validation built-in + +### 4. Type Safety +- ✅ `trigger()` and `triggerAndWait()` have proper type inference +- ✅ Batch operations maintain type safety +- ✅ Output types are properly inferred + +### 5. Schema Conversion Package +- ✅ `@trigger.dev/schema-to-json` package created +- ✅ Supports multiple schema libraries (Zod, Yup, ArkType, etc.) +- ✅ Bundle-safe with dynamic imports +- ✅ Auto-initialized by SDK (no user configuration needed) + +## Example Usage + +```typescript +import { schemaTask, task, type JSONSchema } from "@trigger.dev/sdk/v3"; +import { z } from "zod"; + +// Option 1: Using schemaTask with Zod (recommended) +const userSchema = z.object({ + id: z.string(), + name: z.string(), + email: z.string().email(), +}); + +export const mySchemaTask = schemaTask({ + id: "my-schema-task", + schema: userSchema, + run: async (payload, { ctx }) => { + // payload is fully typed! + console.log(payload.id, payload.name, payload.email); + return { processed: true }; + }, +}); + +// Option 2: Using plain task with manual JSON schema +const jsonSchema: JSONSchema = { + type: "object", + properties: { + message: { type: "string" }, + }, + required: ["message"], +}; + +export const myPlainTask = task({ + id: "my-plain-task", + payloadSchema: jsonSchema, + run: async (payload, { ctx }) => { + // payload is untyped, but schema is stored + return { received: payload.message }; + }, +}); +``` + +## Architecture + +1. **Core Package** (`@trigger.dev/core`): + - Defines `JSONSchema` type + - Includes `payloadSchema` in task metadata + +2. **SDK Package** (`@trigger.dev/sdk`): + - Re-exports `JSONSchema` type + - Auto-initializes schema converters + - Registers `payloadSchema` during task creation + +3. **Schema Conversion Package** (`@trigger.dev/schema-to-json`): + - Converts various schema libraries to JSON Schema + - Uses dynamic imports for bundle safety + - Encapsulated as implementation detail + +4. **Webapp**: + - Saves `payloadSchema` to `BackgroundWorkerTask` model + - Schema available for API documentation, validation, etc. + +## Testing + +Run the integration test to verify all functionality: + +```bash +npm run dev +# Then trigger the integration test task +``` + +The integration test covers: +- Plain task with JSON schema +- Zod schema conversion +- Complex nested schemas +- Trigger type safety +- Batch operations +- Error handling + +## Benefits + +1. **Documentation**: Schemas visible in Trigger.dev dashboard +2. **Validation**: Invalid payloads rejected before execution +3. **Type Safety**: Full TypeScript support with schemaTask +4. **API Generation**: Can generate OpenAPI specs +5. **Client SDKs**: Can generate typed clients for other languages \ No newline at end of file diff --git a/references/json-schema-test/package.json b/references/json-schema-test/package.json new file mode 100644 index 0000000000..ccb807988d --- /dev/null +++ b/references/json-schema-test/package.json @@ -0,0 +1,27 @@ +{ + "name": "json-schema-test", + "version": "1.0.0", + "description": "Test project for JSON schema functionality", + "type": "module", + "scripts": { + "dev": "trigger.dev@beta dev", + "trigger:deploy": "trigger.dev@beta deploy", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@trigger.dev/sdk": "workspace:*", + "zod": "3.22.3", + "@sinclair/typebox": "^0.34.3", + "superstruct": "^2.0.2", + "@effect/schema": "^0.75.5", + "effect": "^3.11.11", + "arktype": "^2.0.0", + "valibot": "^1.0.0-beta.8", + "runtypes": "^6.7.0", + "yup": "^1.6.1" + }, + "devDependencies": { + "@types/node": "^20.14.8", + "typescript": "^5.7.2" + } +} \ No newline at end of file diff --git a/references/json-schema-test/src/trigger/core-functionality-test.ts b/references/json-schema-test/src/trigger/core-functionality-test.ts new file mode 100644 index 0000000000..1ec4997802 --- /dev/null +++ b/references/json-schema-test/src/trigger/core-functionality-test.ts @@ -0,0 +1,431 @@ +// Core functionality test - testing JSON schema implementation with minimal dependencies +import { schemaTask, task, type JSONSchema } from "@trigger.dev/sdk/v3"; +import { z } from "zod"; + +// Test 1: Verify JSONSchema type is exported and usable +const manualSchema: JSONSchema = { + type: "object", + properties: { + id: { type: "string" }, + name: { type: "string", minLength: 1, maxLength: 100 }, + email: { type: "string", format: "email" }, + active: { type: "boolean" }, + score: { type: "number", minimum: 0, maximum: 100 }, + tags: { + type: "array", + items: { type: "string" }, + maxItems: 10, + }, + metadata: { + type: "object", + additionalProperties: true, + }, + }, + required: ["id", "name", "email"], +}; + +// Test 2: Plain task accepts jsonSchema +export const plainJsonSchemaTask = task({ + id: "plain-json-schema-task", + jsonSchema: manualSchema, + run: async (payload: any, { ctx }) => { + // payload is any, but schema is properly stored + console.log("Received payload:", payload); + + return { + taskId: ctx.task.id, + runId: ctx.run.id, + received: true, + // Manual type assertion needed with plain task + userId: payload.id as string, + userName: payload.name as string, + }; + }, +}); + +// Test 3: Zod schema with automatic conversion +const userSchema = z.object({ + userId: z.string().uuid(), + userName: z.string().min(2).max(50), + userEmail: z.string().email(), + age: z.number().int().min(18).max(120), + preferences: z.object({ + theme: z.enum(["light", "dark", "auto"]).default("auto"), + notifications: z.boolean().default(true), + language: z.string().default("en"), + }), + tags: z.array(z.string()).max(5).default([]), + createdAt: z.string().datetime().optional(), +}); + +export const zodSchemaTask = schemaTask({ + id: "zod-schema-task", + schema: userSchema, + run: async (payload, { ctx }) => { + // Full type inference from Zod schema + console.log("Processing user:", payload.userName); + + // All these are properly typed + const id: string = payload.userId; + const name: string = payload.userName; + const email: string = payload.userEmail; + const age: number = payload.age; + const theme: "light" | "dark" | "auto" = payload.preferences.theme; + const notifications: boolean = payload.preferences.notifications; + const tagCount: number = payload.tags.length; + + return { + processedUserId: id, + processedUserName: name, + processedUserEmail: email, + userAge: age, + theme, + notificationsEnabled: notifications, + tagCount, + }; + }, +}); + +// Test 4: Complex nested schema +const orderSchema = z.object({ + orderId: z.string(), + customerId: z.string(), + items: z + .array( + z.object({ + productId: z.string(), + productName: z.string(), + quantity: z.number().positive(), + unitPrice: z.number().positive(), + discount: z.number().min(0).max(100).default(0), + }) + ) + .min(1), + shippingAddress: z.object({ + street: z.string(), + city: z.string(), + state: z.string(), + zipCode: z.string(), + country: z.string().default("US"), + }), + billingAddress: z + .object({ + street: z.string(), + city: z.string(), + state: z.string(), + zipCode: z.string(), + country: z.string(), + }) + .optional(), + paymentMethod: z.discriminatedUnion("type", [ + z.object({ + type: z.literal("credit_card"), + cardNumber: z.string().regex(/^\d{4}$/), // last 4 digits only + cardBrand: z.enum(["visa", "mastercard", "amex", "discover"]), + }), + z.object({ + type: z.literal("paypal"), + paypalEmail: z.string().email(), + }), + z.object({ + type: z.literal("bank_transfer"), + accountNumber: z.string(), + routingNumber: z.string(), + }), + ]), + orderStatus: z + .enum(["pending", "processing", "shipped", "delivered", "cancelled"]) + .default("pending"), + createdAt: z.string().datetime(), + notes: z.string().optional(), +}); + +export const complexOrderTask = schemaTask({ + id: "complex-order-task", + schema: orderSchema, + run: async (payload, { ctx }) => { + // Deep nested type inference + const orderId = payload.orderId; + const firstItem = payload.items[0]; + const productName = firstItem.productName; + const quantity = firstItem.quantity; + + // Calculate totals with full type safety + const subtotal = payload.items.reduce((sum, item) => { + const itemTotal = item.quantity * item.unitPrice; + const discount = itemTotal * (item.discount / 100); + return sum + (itemTotal - discount); + }, 0); + + // Discriminated union handling + let paymentSummary: string; + switch (payload.paymentMethod.type) { + case "credit_card": + paymentSummary = `${payload.paymentMethod.cardBrand} ending in ${payload.paymentMethod.cardNumber}`; + break; + case "paypal": + paymentSummary = `PayPal (${payload.paymentMethod.paypalEmail})`; + break; + case "bank_transfer": + paymentSummary = `Bank transfer ending in ${payload.paymentMethod.accountNumber.slice(-4)}`; + break; + } + + // Optional field handling + const hasBillingAddress = !!payload.billingAddress; + const billingCity = payload.billingAddress?.city ?? payload.shippingAddress.city; + + return { + orderId, + customerId: payload.customerId, + itemCount: payload.items.length, + subtotal, + status: payload.orderStatus, + paymentSummary, + shippingCity: payload.shippingAddress.city, + billingCity, + hasBillingAddress, + hasNotes: !!payload.notes, + }; + }, +}); + +// Test 5: Task trigger type safety +export const testTriggerTypeSafety = task({ + id: "test-trigger-type-safety", + run: async (_, { ctx }) => { + console.log("Testing trigger type safety..."); + + // Valid trigger - should compile + const handle1 = await zodSchemaTask.trigger({ + userId: "550e8400-e29b-41d4-a716-446655440000", + userName: "John Doe", + userEmail: "john@example.com", + age: 30, + preferences: { + theme: "dark", + notifications: false, + language: "es", + }, + tags: ["customer", "premium"], + createdAt: new Date().toISOString(), + }); + + // Using defaults - should also compile + const handle2 = await zodSchemaTask.trigger({ + userId: "550e8400-e29b-41d4-a716-446655440001", + userName: "Jane Smith", + userEmail: "jane@example.com", + age: 25, + preferences: {}, // Will use defaults + // tags will default to [] + }); + + // Test triggerAndWait with result handling + const result = await zodSchemaTask.triggerAndWait({ + userId: "550e8400-e29b-41d4-a716-446655440002", + userName: "Bob Wilson", + userEmail: "bob@example.com", + age: 45, + preferences: { + theme: "light", + }, + }); + + if (result.ok) { + // Type-safe access to output + console.log("Processed user:", result.output.processedUserName); + console.log("User email:", result.output.processedUserEmail); + console.log("Theme:", result.output.theme); + + return { + success: true, + processedUserId: result.output.processedUserId, + userName: result.output.processedUserName, + }; + } else { + return { + success: false, + error: String(result.error), + }; + } + }, +}); + +// Test 6: Batch operations with type safety +export const testBatchOperations = task({ + id: "test-batch-operations", + run: async (_, { ctx }) => { + console.log("Testing batch operations..."); + + // Batch trigger + const batchHandle = await zodSchemaTask.batchTrigger([ + { + payload: { + userId: "batch-001", + userName: "Batch User 1", + userEmail: "batch1@example.com", + age: 20, + preferences: { + theme: "dark", + }, + }, + }, + { + payload: { + userId: "batch-002", + userName: "Batch User 2", + userEmail: "batch2@example.com", + age: 30, + preferences: { + theme: "light", + notifications: false, + }, + tags: ["batch", "test"], + }, + }, + ]); + + console.log(`Triggered batch ${batchHandle.batchId} with ${batchHandle.runCount} runs`); + + // Batch trigger and wait + const batchResult = await zodSchemaTask.batchTriggerAndWait([ + { + payload: { + userId: "batch-003", + userName: "Batch User 3", + userEmail: "batch3@example.com", + age: 40, + preferences: {}, + }, + }, + { + payload: { + userId: "batch-004", + userName: "Batch User 4", + userEmail: "batch4@example.com", + age: 50, + preferences: { + language: "fr", + }, + tags: ["batch", "wait"], + }, + }, + ]); + + // Process results with type safety + const processed = batchResult.runs.map((run) => { + if (run.ok) { + return { + success: true, + userId: run.output.processedUserId, + userName: run.output.processedUserName, + theme: run.output.theme, + }; + } else { + return { + success: false, + runId: run.id, + error: String(run.error), + }; + } + }); + + return { + batchId: batchResult.id, + totalRuns: batchResult.runs.length, + successfulRuns: processed.filter((p) => p.success).length, + processed, + }; + }, +}); + +// Test 7: Integration test - all features together +export const integrationTest = task({ + id: "json-schema-integration-test", + run: async (_, { ctx }) => { + console.log("Running integration test..."); + + const results = { + plainTask: false, + zodTask: false, + complexTask: false, + triggerTypes: false, + batchOps: false, + }; + + try { + // Test plain JSON schema task + const plainResult = await plainJsonSchemaTask.trigger({ + id: "test-001", + name: "Test User", + email: "test@example.com", + active: true, + score: 85, + tags: ["test"], + metadata: { source: "integration-test" }, + }); + results.plainTask = !!plainResult.id; + + // Test Zod schema task + const zodResult = await zodSchemaTask + .triggerAndWait({ + userId: "int-test-001", + userName: "Integration Test User", + userEmail: "integration@example.com", + age: 35, + preferences: { + theme: "auto", + }, + }) + .unwrap(); + results.zodTask = zodResult.processedUserId === "int-test-001"; + + // Test complex schema + const complexResult = await complexOrderTask.trigger({ + orderId: "order-int-001", + customerId: "cust-int-001", + items: [ + { + productId: "prod-001", + productName: "Test Product", + quantity: 2, + unitPrice: 29.99, + discount: 10, + }, + ], + shippingAddress: { + street: "123 Test St", + city: "Test City", + state: "TC", + zipCode: "12345", + }, + paymentMethod: { + type: "credit_card", + cardNumber: "1234", + cardBrand: "visa", + }, + createdAt: new Date().toISOString(), + }); + results.complexTask = !!complexResult.id; + + // Test trigger type safety + const triggerResult = await testTriggerTypeSafety.triggerAndWait(undefined); + results.triggerTypes = triggerResult.ok && triggerResult.output.success; + + // Test batch operations + const batchResult = await testBatchOperations.triggerAndWait(undefined); + results.batchOps = batchResult.ok && batchResult.output.successfulRuns > 0; + } catch (error) { + console.error("Integration test error:", error); + } + + const allPassed = Object.values(results).every((r) => r); + + return { + success: allPassed, + results, + message: allPassed ? "All JSON schema tests passed!" : "Some tests failed - check results", + }; + }, +}); diff --git a/references/json-schema-test/src/trigger/simple-type-test.ts b/references/json-schema-test/src/trigger/simple-type-test.ts new file mode 100644 index 0000000000..f0c2e4fc5e --- /dev/null +++ b/references/json-schema-test/src/trigger/simple-type-test.ts @@ -0,0 +1,243 @@ +// This file tests the core JSON schema functionality without external dependencies +import { schemaTask, task, type JSONSchema } from "@trigger.dev/sdk"; +import { z } from "zod"; + +// Test 1: Basic type inference with schemaTask +const userSchema = z.object({ + id: z.string(), + name: z.string(), + email: z.string().email(), + age: z.number(), +}); + +export const testZodTypeInference = schemaTask({ + id: "test-zod-type-inference", + schema: userSchema, + run: async (payload, { ctx }) => { + // These should all be properly typed without explicit type annotations + const id = payload.id; // string + const name = payload.name; // string + const email = payload.email; // string + const age = payload.age; // number + + // This would cause a TypeScript error if uncommented: + // const invalid = payload.nonExistentField; + + return { + userId: id, + userName: name, + userEmail: email, + userAge: age, + }; + }, +}); + +// Test 2: JSONSchema type is properly exported and usable +const jsonSchemaExample = { + type: "object", + properties: { + message: { type: "string" }, + count: { type: "integer" }, + active: { type: "boolean" }, + }, + required: ["message", "count"], +} satisfies JSONSchema; + +export const testJSONSchemaType = task({ + id: "test-json-schema-type", + jsonSchema: jsonSchemaExample, + run: async (payload, { ctx }) => { + // payload is 'any' with plain task, but the schema is properly typed + return { + received: true, + message: payload.message, + count: payload.count, + active: payload.active ?? false, + }; + }, +}); + +// Test 3: Trigger type safety +export const testTriggerTypeSafety = task({ + id: "test-trigger-type-safety", + run: async (_, { ctx }) => { + // This should compile with proper type inference + const handle1 = await testZodTypeInference.trigger({ + id: "123", + name: "John Doe", + email: "john@example.com", + age: 30, + }); + + // This would cause TypeScript errors if uncommented: + // const handle2 = await testZodTypeInference.trigger({ + // id: 123, // wrong type + // name: "Jane", + // email: "not-an-email", // invalid format (caught at runtime) + // age: "thirty", // wrong type + // }); + + // Test triggerAndWait + const result = await testZodTypeInference.triggerAndWait({ + id: "456", + name: "Jane Smith", + email: "jane@example.com", + age: 25, + }); + + if (result.ok) { + // Type inference works on the output + const userId: string = result.output.userId; + const userName: string = result.output.userName; + const userEmail: string = result.output.userEmail; + const userAge: number = result.output.userAge; + + return { + success: true, + userId, + userName, + userEmail, + userAge, + }; + } else { + return { + success: false, + error: String(result.error), + }; + } + }, +}); + +// Test 4: Batch operations maintain type safety +export const testBatchTypeSafety = task({ + id: "test-batch-type-safety", + run: async (_, { ctx }) => { + // Batch trigger with type safety + const batchHandle = await testZodTypeInference.batchTrigger([ + { + payload: { + id: "1", + name: "User One", + email: "user1@example.com", + age: 20, + }, + }, + { + payload: { + id: "2", + name: "User Two", + email: "user2@example.com", + age: 30, + }, + }, + ]); + + // Batch trigger and wait + const batchResult = await testZodTypeInference.batchTriggerAndWait([ + { + payload: { + id: "3", + name: "User Three", + email: "user3@example.com", + age: 40, + }, + }, + { + payload: { + id: "4", + name: "User Four", + email: "user4@example.com", + age: 50, + }, + }, + ]); + + // Process results with type safety + const successfulUsers: string[] = []; + const failedUsers: string[] = []; + + for (const run of batchResult.runs) { + if (run.ok) { + // output is properly typed + successfulUsers.push(run.output.userId); + } else { + failedUsers.push(run.id); + } + } + + return { + batchId: batchHandle.batchId, + batchRunCount: batchHandle.runCount, + successfulUsers, + failedUsers, + totalProcessed: batchResult.runs.length, + }; + }, +}); + +// Test 5: Complex nested schema +const complexSchema = z.object({ + order: z.object({ + id: z.string(), + items: z.array( + z.object({ + productId: z.string(), + quantity: z.number(), + price: z.number(), + }) + ), + customer: z.object({ + id: z.string(), + email: z.string().email(), + address: z + .object({ + street: z.string(), + city: z.string(), + country: z.string(), + }) + .optional(), + }), + }), + metadata: z.record(z.unknown()).optional(), +}); + +export const testComplexSchema = schemaTask({ + id: "test-complex-schema", + schema: complexSchema, + run: async (payload, { ctx }) => { + // Deep type inference works + const orderId = payload.order.id; + const firstItem = payload.order.items[0]; + const quantity = firstItem?.quantity ?? 0; + const customerEmail = payload.order.customer.email; + const city = payload.order.customer.address?.city; + + // Calculate total + const total = payload.order.items.reduce((sum, item) => sum + item.quantity * item.price, 0); + + return { + orderId, + customerEmail, + itemCount: payload.order.items.length, + total, + hasAddress: !!payload.order.customer.address, + city: city ?? "Unknown", + }; + }, +}); + +// Test 6: Verify that JSON schema is properly set during task registration +export const verifySchemaRegistration = task({ + id: "verify-schema-registration", + run: async (_, { ctx }) => { + // This test verifies that when we create tasks with schemas, + // they properly register the payloadSchema for syncing to the server + + return { + test: "Schema registration", + message: "If this task runs, schema registration is working", + // The actual verification happens during indexing when the CLI + // reads the task metadata and sees the payloadSchema field + }; + }, +}); diff --git a/references/json-schema-test/src/trigger/test-batch-operations.ts b/references/json-schema-test/src/trigger/test-batch-operations.ts new file mode 100644 index 0000000000..627981c81c --- /dev/null +++ b/references/json-schema-test/src/trigger/test-batch-operations.ts @@ -0,0 +1,311 @@ +import { schemaTask, task } from "@trigger.dev/sdk/v3"; +import { z } from "zod"; + +// Define schemas for batch operations +const emailSchema = z.object({ + to: z.string().email(), + subject: z.string(), + body: z.string(), + priority: z.enum(["low", "normal", "high"]).default("normal"), +}); + +const smsSchema = z.object({ + phoneNumber: z.string().regex(/^\+[1-9]\d{1,14}$/), + message: z.string().max(160), +}); + +const notificationSchema = z.object({ + userId: z.string(), + title: z.string(), + message: z.string(), + type: z.enum(["info", "warning", "error", "success"]), + metadata: z.record(z.unknown()).optional(), +}); + +// Create schema tasks +export const sendEmail = schemaTask({ + id: "send-email", + schema: emailSchema, + run: async (payload, { ctx }) => { + // Simulate sending email + await new Promise(resolve => setTimeout(resolve, Math.random() * 1000)); + + return { + messageId: `email_${ctx.run.id}`, + sentAt: new Date().toISOString(), + to: payload.to, + subject: payload.subject, + priority: payload.priority, + }; + }, +}); + +export const sendSms = schemaTask({ + id: "send-sms", + schema: smsSchema, + run: async (payload, { ctx }) => { + // Simulate sending SMS + await new Promise(resolve => setTimeout(resolve, Math.random() * 500)); + + return { + messageId: `sms_${ctx.run.id}`, + sentAt: new Date().toISOString(), + to: payload.phoneNumber, + characterCount: payload.message.length, + }; + }, +}); + +export const sendNotification = schemaTask({ + id: "send-notification", + schema: notificationSchema, + run: async (payload, { ctx }) => { + // Simulate sending notification + await new Promise(resolve => setTimeout(resolve, Math.random() * 300)); + + return { + notificationId: `notif_${ctx.run.id}`, + sentAt: new Date().toISOString(), + userId: payload.userId, + type: payload.type, + delivered: Math.random() > 0.1, // 90% success rate + }; + }, +}); + +// Test batch operations with schema tasks +export const testBatchTrigger = task({ + id: "test-batch-trigger", + run: async (_, { ctx }) => { + // Batch trigger emails + const emailBatch = await sendEmail.batchTrigger([ + { + payload: { + to: "user1@example.com", + subject: "Welcome!", + body: "Welcome to our service.", + priority: "high", + }, + }, + { + payload: { + to: "user2@example.com", + subject: "Weekly Update", + body: "Here's your weekly update.", + // priority will default to "normal" + }, + }, + { + payload: { + to: "user3@example.com", + subject: "Special Offer", + body: "Check out our special offer!", + priority: "low", + }, + }, + ]); + + // Batch trigger SMS messages + const smsBatch = await sendSms.batchTrigger([ + { + payload: { + phoneNumber: "+1234567890", + message: "Your verification code is 123456", + }, + }, + { + payload: { + phoneNumber: "+9876543210", + message: "Appointment reminder: Tomorrow at 2PM", + }, + }, + ]); + + return { + emailBatchId: emailBatch.batchId, + emailCount: emailBatch.runCount, + smsBatchId: smsBatch.batchId, + smsCount: smsBatch.runCount, + }; + }, +}); + +// Test batch trigger and wait +export const testBatchTriggerAndWait = task({ + id: "test-batch-trigger-and-wait", + run: async (_, { ctx }) => { + // Batch trigger and wait for notifications + const notificationResults = await sendNotification.batchTriggerAndWait([ + { + payload: { + userId: "user123", + title: "Info", + message: "This is an informational message", + type: "info", + }, + }, + { + payload: { + userId: "user456", + title: "Warning", + message: "This is a warning message", + type: "warning", + metadata: { + source: "system", + priority: "medium", + }, + }, + }, + { + payload: { + userId: "user789", + title: "Success", + message: "Operation completed successfully", + type: "success", + }, + }, + ]); + + // Process results + const successCount = notificationResults.runs.filter(run => run.ok).length; + const failureCount = notificationResults.runs.filter(run => !run.ok).length; + const deliveredCount = notificationResults.runs + .filter(run => run.ok && run.output.delivered) + .length; + + // Collect all notification IDs + const notificationIds = notificationResults.runs + .filter(run => run.ok) + .map(run => run.output.notificationId); + + // Type safety check - these should all be properly typed + for (const run of notificationResults.runs) { + if (run.ok) { + const notifId: string = run.output.notificationId; + const sentAt: string = run.output.sentAt; + const userId: string = run.output.userId; + const type: "info" | "warning" | "error" | "success" = run.output.type; + const delivered: boolean = run.output.delivered; + } + } + + return { + batchId: notificationResults.id, + totalRuns: notificationResults.runs.length, + successCount, + failureCount, + deliveredCount, + notificationIds, + }; + }, +}); + +// Test mixed batch operations +export const testMixedBatchOperations = task({ + id: "test-mixed-batch-operations", + run: async (_, { ctx }) => { + // Trigger different types of messages for the same user + const results = await Promise.all([ + // Send welcome email + sendEmail.trigger({ + to: "newuser@example.com", + subject: "Welcome to our platform!", + body: "Thanks for signing up. Here's what you need to know...", + priority: "high", + }), + + // Send SMS verification + sendSms.trigger({ + phoneNumber: "+1234567890", + message: "Welcome! Your verification code is 789012", + }), + + // Send in-app notification + sendNotification.trigger({ + userId: "newuser123", + title: "Account Created", + message: "Your account has been successfully created", + type: "success", + metadata: { + accountType: "premium", + referralCode: "WELCOME2024", + }, + }), + ]); + + // Wait for specific tasks using triggerAndWait + const criticalEmail = await sendEmail.triggerAndWait({ + to: "admin@example.com", + subject: "New User Alert", + body: "A new premium user has signed up", + priority: "high", + }); + + if (criticalEmail.ok) { + const messageId: string = criticalEmail.output.messageId; + const sentAt: string = criticalEmail.output.sentAt; + + return { + allMessagesSent: true, + emailId: results[0].id, + smsId: results[1].id, + notificationId: results[2].id, + criticalEmailId: messageId, + criticalEmailSentAt: sentAt, + }; + } else { + return { + allMessagesSent: false, + error: "Failed to send critical email", + }; + } + }, +}); + +// Test error handling in batch operations +export const testBatchErrorHandling = task({ + id: "test-batch-error-handling", + run: async (_, { ctx }) => { + // Create a batch with some invalid data to test error handling + const results = await sendEmail.batchTriggerAndWait([ + { + payload: { + to: "valid@example.com", + subject: "Valid Email", + body: "This should succeed", + }, + }, + { + payload: { + to: "another.valid@example.com", + subject: "Another Valid Email", + body: "This should also succeed", + priority: "normal", + }, + }, + // Note: We can't actually create invalid payloads at compile time + // because TypeScript prevents it! This is the power of schema tasks. + // If we tried to add { to: "invalid-email", ... }, TypeScript would error + ]); + + // Process results with proper type safety + const report = { + totalAttempts: results.runs.length, + successful: [] as string[], + failed: [] as { id: string; error: string }[], + }; + + for (const run of results.runs) { + if (run.ok) { + report.successful.push(run.output.messageId); + } else { + report.failed.push({ + id: run.id, + error: String(run.error), + }); + } + } + + return report; + }, +}); \ No newline at end of file diff --git a/references/json-schema-test/src/trigger/test-other-schemas.ts b/references/json-schema-test/src/trigger/test-other-schemas.ts new file mode 100644 index 0000000000..94508ed2cc --- /dev/null +++ b/references/json-schema-test/src/trigger/test-other-schemas.ts @@ -0,0 +1,393 @@ +import { schemaTask } from "@trigger.dev/sdk"; +import { Type } from "@sinclair/typebox"; +import { + array, + object, + string, + number, + boolean, + optional, + union, + literal, + record, + Infer, +} from "superstruct"; +import * as S from "@effect/schema/Schema"; +import { type } from "arktype"; +import * as v from "valibot"; +import * as rt from "runtypes"; + +// Test TypeBox schema +const typeBoxSchema = Type.Object({ + id: Type.String({ pattern: "^[a-zA-Z0-9]+$" }), + title: Type.String({ minLength: 1, maxLength: 100 }), + content: Type.String({ minLength: 10 }), + author: Type.Object({ + name: Type.String(), + email: Type.String({ format: "email" }), + role: Type.Union([Type.Literal("admin"), Type.Literal("editor"), Type.Literal("viewer")]), + }), + tags: Type.Array(Type.String(), { minItems: 1, maxItems: 5 }), + published: Type.Boolean(), + publishedAt: Type.Optional(Type.String({ format: "date-time" })), + metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown())), +}); + +export const typeBoxTask = schemaTask({ + id: "typebox-schema-task", + schema: typeBoxSchema, + run: async (payload, { ctx }) => { + // TypeBox provides static type inference + const id: string = payload.id; + const title: string = payload.title; + const authorEmail: string = payload.author.email; + const role: "admin" | "editor" | "viewer" = payload.author.role; + const tagCount = payload.tags.length; + const isPublished: boolean = payload.published; + + return { + documentId: id, + title, + authorEmail, + role, + tagCount, + status: isPublished ? "published" : "draft", + }; + }, +}); + +// Test Superstruct schema +const superstructSchema = object({ + transaction: object({ + id: string(), + amount: number(), + currency: union([literal("USD"), literal("EUR"), literal("GBP")]), + type: union([literal("credit"), literal("debit")]), + description: optional(string()), + tags: optional(array(string())), + metadata: optional(record(string(), string())), + }), + account: object({ + accountId: string(), + balance: number(), + overdraftLimit: optional(number()), + }), + timestamp: string(), + approved: boolean(), +}); + +type SuperstructTransaction = Infer; + +export const superstructTask = schemaTask({ + id: "superstruct-schema-task", + schema: superstructSchema, + run: async (payload: SuperstructTransaction, { ctx }) => { + // Superstruct infers types correctly + const transactionId = payload.transaction.id; + const amount = payload.transaction.amount; + const currency = payload.transaction.currency; + const accountBalance = payload.account.balance; + const isApproved = payload.approved; + + const newBalance = + payload.transaction.type === "credit" ? accountBalance + amount : accountBalance - amount; + + return { + transactionId, + processedAt: new Date().toISOString(), + newBalance, + currency, + approved: isApproved, + requiresReview: newBalance < 0 && !payload.account.overdraftLimit, + }; + }, +}); + +// Test Effect Schema +const effectSchema = S.Struct({ + event: S.Struct({ + eventId: S.String, + eventType: S.Literal("click", "view", "purchase"), + timestamp: S.Date, + sessionId: S.String, + }), + user: S.Struct({ + userId: S.String, + email: S.String, + }), + product: S.optional( + S.Struct({ + productId: S.String, + name: S.String, + price: S.Number, + category: S.String, + }) + ), + location: S.optional( + S.Struct({ + country: S.String, + city: S.optional(S.String), + region: S.optional(S.String), + }) + ), +}); + +type EffectEvent = S.Schema.Type; + +export const effectSchemaTask = schemaTask({ + id: "effect-schema-task", + schema: effectSchema, + run: async (payload, { ctx }) => { + // Effect Schema provides type safety + const eventId = payload.event.eventId; + const eventType = payload.event.eventType; + const userId = payload.user.userId; + const hasProduct = !!payload.product; + const productName = payload.product?.name; + const country = payload.location?.country; + + return { + eventId, + eventType, + userId, + hasProduct, + productName, + country: country ?? "unknown", + processed: true, + }; + }, +}); + +// Test ArkType schema +const arkTypeSchema = type({ + request: { + method: "'GET' | 'POST' | 'PUT' | 'DELETE'", + path: "string", + headers: "Record", + "body?": "unknown", + "query?": "Record", + }, + response: { + status: "number", + "headers?": "Record", + "body?": "unknown", + }, + timing: { + start: "Date", + end: "Date", + duration: "number", + }, + "metadata?": { + "ip?": "string", + "userAgent?": "string", + "referer?": "string", + }, +}); + +export const arkTypeTask = schemaTask({ + id: "arktype-schema-task", + schema: arkTypeSchema, + run: async (payload, { ctx }) => { + // ArkType infers types + const method = payload.request.method; + const path = payload.request.path; + const status = payload.response.status; + const duration = payload.timing.duration; + const hasBody = !!payload.request.body; + const userAgent = payload.metadata?.userAgent; + + return { + logId: `log_${ctx.run.id}`, + method, + path, + status, + duration, + hasBody, + userAgent: userAgent ?? "unknown", + success: status >= 200 && status < 300, + }; + }, +}); + +// Test Valibot schema +const valibotSchema = v.object({ + form: v.object({ + name: v.pipe(v.string(), v.minLength(2), v.maxLength(50)), + email: v.pipe(v.string(), v.email()), + age: v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(150)), + website: v.optional(v.pipe(v.string(), v.url())), + bio: v.optional(v.pipe(v.string(), v.maxLength(500))), + interests: v.array(v.string()), + preferences: v.object({ + theme: v.union([v.literal("light"), v.literal("dark"), v.literal("auto")]), + notifications: v.boolean(), + language: v.string(), + }), + }), + submittedAt: v.string(), + source: v.union([v.literal("web"), v.literal("mobile"), v.literal("api")]), +}); + +type ValibotForm = v.InferOutput; + +export const valibotTask = schemaTask({ + id: "valibot-schema-task", + schema: valibotSchema, + run: async (payload: ValibotForm, { ctx }) => { + // Valibot provides type inference + const name = payload.form.name; + const email = payload.form.email; + const age = payload.form.age; + const hasWebsite = !!payload.form.website; + const theme = payload.form.preferences.theme; + const source = payload.source; + + return { + submissionId: `sub_${ctx.run.id}`, + name, + email, + age, + hasWebsite, + theme, + source, + processed: true, + }; + }, +}); + +// Test Runtypes schema +const runtypesSchema = rt.Record({ + payment: rt.Record({ + paymentId: rt.String, + amount: rt.Number, + currency: rt.Union(rt.Literal("USD"), rt.Literal("EUR"), rt.Literal("GBP")), + method: rt.Union( + rt.Record({ + type: rt.Literal("card"), + last4: rt.String, + brand: rt.String, + }), + rt.Record({ + type: rt.Literal("bank"), + accountNumber: rt.String, + routingNumber: rt.String, + }) + ), + status: rt.Union( + rt.Literal("pending"), + rt.Literal("processing"), + rt.Literal("completed"), + rt.Literal("failed") + ), + }), + customer: rt.Record({ + customerId: rt.String, + email: rt.String, + name: rt.String, + }), + metadata: rt.Optional(rt.Dictionary(rt.Unknown)), +}); + +type RuntypesPayment = rt.Static; + +export const runtypesTask = schemaTask({ + id: "runtypes-schema-task", + schema: runtypesSchema, + run: async (payload: RuntypesPayment, { ctx }) => { + // Runtypes provides static types + const paymentId = payload.payment.paymentId; + const amount = payload.payment.amount; + const currency = payload.payment.currency; + const status = payload.payment.status; + const customerEmail = payload.customer.email; + + // Discriminated union handling + const paymentDetails = + payload.payment.method.type === "card" + ? `Card ending in ${payload.payment.method.last4}` + : `Bank account ${payload.payment.method.accountNumber}`; + + return { + paymentId, + amount, + currency, + status, + customerEmail, + paymentDetails, + requiresAction: status === "pending" || status === "processing", + }; + }, +}); + +// Test task that triggers all schema tasks +export const testAllSchemas = schemaTask({ + id: "test-all-schemas", + schema: z.object({ runAll: z.boolean() }), + run: async (payload, { ctx }) => { + const results = []; + + // Test TypeBox + const typeBoxResult = await typeBoxTask.trigger({ + id: "doc123", + title: "Test Document", + content: "This is a test document with sufficient content.", + author: { + name: "John Doe", + email: "john@example.com", + role: "editor", + }, + tags: ["test", "sample"], + published: true, + publishedAt: new Date().toISOString(), + }); + results.push({ task: "typebox", runId: typeBoxResult.id }); + + // Test Superstruct + const superstructResult = await superstructTask.trigger({ + transaction: { + id: "txn123", + amount: 100.5, + currency: "USD", + type: "credit", + description: "Test transaction", + }, + account: { + accountId: "acc456", + balance: 1000, + overdraftLimit: 500, + }, + timestamp: new Date().toISOString(), + approved: true, + }); + results.push({ task: "superstruct", runId: superstructResult.id }); + + // Test Effect Schema + const effectResult = await effectSchemaTask.trigger({ + event: { + eventId: "evt789", + eventType: "purchase", + timestamp: new Date(), + sessionId: "sess123", + }, + user: { + userId: "user456", + email: "user@example.com", + }, + product: { + productId: "prod789", + name: "Test Product", + price: 29.99, + category: "Electronics", + }, + }); + results.push({ task: "effect", runId: effectResult.id }); + + return { + tested: results.length, + results, + }; + }, +}); + +// Import zod for the test task +import { z } from "zod"; \ No newline at end of file diff --git a/references/json-schema-test/src/trigger/test-yup.ts b/references/json-schema-test/src/trigger/test-yup.ts new file mode 100644 index 0000000000..7c98796605 --- /dev/null +++ b/references/json-schema-test/src/trigger/test-yup.ts @@ -0,0 +1,189 @@ +import { schemaTask } from "@trigger.dev/sdk/v3"; +import * as yup from "yup"; + +// Test Yup schema conversion +const contactSchema = yup.object({ + firstName: yup.string().required().min(2).max(50), + lastName: yup.string().required().min(2).max(50), + email: yup.string().email().required(), + phone: yup.string().matches(/^[\d\s\-\+\(\)]+$/, "Invalid phone number").optional(), + age: yup.number().positive().integer().min(18).max(120), + preferences: yup.object({ + contactMethod: yup.string().oneOf(["email", "phone", "sms"]).default("email"), + newsletter: yup.boolean().default(false), + language: yup.string().oneOf(["en", "es", "fr", "de"]).default("en"), + }).default({}), + address: yup.object({ + street: yup.string().required(), + city: yup.string().required(), + state: yup.string().length(2).required(), + zip: yup.string().matches(/^\d{5}$/).required(), + }).optional(), + tags: yup.array().of(yup.string()).min(1).max(10), +}); + +export const yupSchemaTask = schemaTask({ + id: "yup-schema-task", + schema: contactSchema, + run: async (payload, { ctx }) => { + // Type checking: payload should be inferred from Yup schema + const fullName = `${payload.firstName} ${payload.lastName}`; + const email: string = payload.email; + const phone: string | undefined = payload.phone; + const age: number = payload.age; + + // Nested properties + const contactMethod = payload.preferences.contactMethod; + const newsletter: boolean = payload.preferences.newsletter; + + // Optional nested object + const hasAddress = !!payload.address; + const city = payload.address?.city; + + // Array + const tagCount = payload.tags?.length ?? 0; + + return { + contactId: `contact_${ctx.run.id}`, + fullName, + email, + hasPhone: !!phone, + hasAddress, + tagCount, + preferredContact: contactMethod, + }; + }, +}); + +// Test complex Yup validation with conditional logic +const orderValidationSchema = yup.object({ + orderType: yup.string().oneOf(["standard", "express", "same-day"]).required(), + items: yup.array().of( + yup.object({ + sku: yup.string().required(), + quantity: yup.number().positive().integer().required(), + price: yup.number().positive().required(), + }) + ).min(1).required(), + shipping: yup.object().when("orderType", { + is: "standard", + then: (schema) => schema.shape({ + method: yup.string().oneOf(["ground", "air"]).required(), + estimatedDays: yup.number().min(3).max(10).required(), + }), + otherwise: (schema) => schema.shape({ + method: yup.string().oneOf(["priority", "express"]).required(), + estimatedDays: yup.number().min(1).max(2).required(), + }), + }), + discount: yup.object({ + code: yup.string().optional(), + percentage: yup.number().min(0).max(100).when("code", { + is: (code: any) => !!code, + then: (schema) => schema.required(), + otherwise: (schema) => schema.optional(), + }), + }).optional(), + customerNotes: yup.string().max(500).optional(), +}); + +export const yupConditionalTask = schemaTask({ + id: "yup-conditional-task", + schema: orderValidationSchema, + run: async (payload, { ctx }) => { + // Type inference with conditional validation + const orderType = payload.orderType; + const itemCount = payload.items.length; + const totalQuantity = payload.items.reduce((sum, item) => sum + item.quantity, 0); + const totalPrice = payload.items.reduce((sum, item) => sum + (item.quantity * item.price), 0); + + // Shipping details based on order type + const shippingMethod = payload.shipping.method; + const estimatedDays = payload.shipping.estimatedDays; + + // Optional discount + const hasDiscount = !!payload.discount?.code; + const discountPercentage = payload.discount?.percentage ?? 0; + const discountAmount = hasDiscount ? (totalPrice * discountPercentage / 100) : 0; + + return { + orderId: `order_${ctx.run.id}`, + orderType, + itemCount, + totalQuantity, + subtotal: totalPrice, + discount: discountAmount, + total: totalPrice - discountAmount, + shipping: { + method: shippingMethod, + estimatedDelivery: new Date(Date.now() + estimatedDays * 24 * 60 * 60 * 1000).toISOString(), + }, + }; + }, +}); + +// Test Yup with custom validation and transforms +const userRegistrationSchema = yup.object({ + username: yup.string() + .required() + .min(3) + .max(20) + .matches(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores") + .test("no-reserved", "Username is reserved", (value) => { + const reserved = ["admin", "root", "system", "user"]; + return !reserved.includes(value?.toLowerCase() ?? ""); + }), + email: yup.string() + .email() + .required() + .test("email-domain", "Email domain not allowed", (value) => { + const blockedDomains = ["tempmail.com", "throwaway.email"]; + const domain = value?.split("@")[1]?.toLowerCase(); + return !blockedDomains.includes(domain ?? ""); + }), + password: yup.string() + .required() + .min(8) + .matches(/[A-Z]/, "Password must contain at least one uppercase letter") + .matches(/[a-z]/, "Password must contain at least one lowercase letter") + .matches(/[0-9]/, "Password must contain at least one number") + .matches(/[^A-Za-z0-9]/, "Password must contain at least one special character"), + confirmPassword: yup.string() + .required() + .oneOf([yup.ref("password")], "Passwords must match"), + dateOfBirth: yup.date() + .required() + .max(new Date(), "Date of birth cannot be in the future") + .test("age", "Must be at least 18 years old", (value) => { + if (!value) return false; + const age = new Date().getFullYear() - value.getFullYear(); + return age >= 18; + }), + termsAccepted: yup.boolean() + .required() + .oneOf([true], "You must accept the terms and conditions"), +}); + +export const yupCustomValidationTask = schemaTask({ + id: "yup-custom-validation-task", + schema: userRegistrationSchema, + run: async (payload, { ctx }) => { + // All validations have passed if we get here + const username: string = payload.username; + const email: string = payload.email; + const dateOfBirth: Date = payload.dateOfBirth; + const termsAccepted: boolean = payload.termsAccepted; + + // Calculate age + const age = new Date().getFullYear() - dateOfBirth.getFullYear(); + + return { + userId: `user_${ctx.run.id}`, + username, + email, + age, + registeredAt: new Date().toISOString(), + welcomeEmailRequired: true, + }; + }, +}); \ No newline at end of file diff --git a/references/json-schema-test/src/trigger/test-zod.ts b/references/json-schema-test/src/trigger/test-zod.ts new file mode 100644 index 0000000000..2519fcca8a --- /dev/null +++ b/references/json-schema-test/src/trigger/test-zod.ts @@ -0,0 +1,288 @@ +import { schemaTask, task, type JSONSchema } from "@trigger.dev/sdk/v3"; +import { z } from "zod"; + +// Test 1: Basic Zod schema with schemaTask +const userSchema = z.object({ + id: z.string(), + name: z.string(), + email: z.string().email(), + age: z.number().int().min(0).max(150), + isActive: z.boolean(), + roles: z.array(z.enum(["admin", "user", "guest"])), + metadata: z.record(z.unknown()).optional(), +}); + +export const zodSchemaTask = schemaTask({ + id: "zod-schema-task", + schema: userSchema, + run: async (payload, { ctx }) => { + // Type checking: payload should be fully typed + const id: string = payload.id; + const name: string = payload.name; + const email: string = payload.email; + const age: number = payload.age; + const isActive: boolean = payload.isActive; + const roles: ("admin" | "user" | "guest")[] = payload.roles; + const metadata: Record | undefined = payload.metadata; + + return { + processed: true, + userId: payload.id, + userName: payload.name, + }; + }, +}); + +// Test 2: Complex nested Zod schema +const complexSchema = z.object({ + order: z.object({ + orderId: z.string().uuid(), + items: z.array( + z.object({ + productId: z.string(), + quantity: z.number().positive(), + price: z.number().positive(), + discount: z.number().min(0).max(100).optional(), + }) + ), + customer: z.object({ + customerId: z.string(), + email: z.string().email(), + shippingAddress: z.object({ + street: z.string(), + city: z.string(), + state: z.string().length(2), + zipCode: z.string().regex(/^\d{5}(-\d{4})?$/), + country: z.string().default("US"), + }), + }), + paymentMethod: z.discriminatedUnion("type", [ + z.object({ + type: z.literal("credit_card"), + last4: z.string().length(4), + brand: z.enum(["visa", "mastercard", "amex"]), + }), + z.object({ + type: z.literal("paypal"), + email: z.string().email(), + }), + ]), + createdAt: z.string().datetime(), + status: z.enum(["pending", "processing", "shipped", "delivered", "cancelled"]), + }), + notes: z.string().optional(), + priority: z.number().int().min(1).max(5).default(3), +}); + +export const complexZodTask = schemaTask({ + id: "complex-zod-task", + schema: complexSchema, + run: async (payload, { ctx }) => { + // Test type inference on nested properties + const orderId: string = payload.order.orderId; + const firstItem = payload.order.items[0]; + const quantity: number = firstItem.quantity; + const customerEmail: string = payload.order.customer.email; + const zipCode: string = payload.order.customer.shippingAddress.zipCode; + + // Discriminated union type checking + if (payload.order.paymentMethod.type === "credit_card") { + const brand: "visa" | "mastercard" | "amex" = payload.order.paymentMethod.brand; + const last4: string = payload.order.paymentMethod.last4; + } else { + const paypalEmail: string = payload.order.paymentMethod.email; + } + + return { + orderId: payload.order.orderId, + itemCount: payload.order.items.length, + status: payload.order.status, + }; + }, +}); + +// Test 3: Plain task with manual JSON schema +const manualJsonSchema: JSONSchema = { + type: "object", + properties: { + taskId: { type: "string", pattern: "^task_[a-zA-Z0-9]+$" }, + priority: { type: "integer", minimum: 1, maximum: 10 }, + tags: { + type: "array", + items: { type: "string" }, + minItems: 1, + maxItems: 5, + }, + config: { + type: "object", + properties: { + timeout: { type: "number" }, + retries: { type: "integer", minimum: 0 }, + async: { type: "boolean" }, + }, + required: ["timeout", "retries"], + }, + }, + required: ["taskId", "priority"], + additionalProperties: false, +}; + +export const plainJsonSchemaTask = task({ + id: "plain-json-schema-task", + jsonSchema: manualJsonSchema, + run: async (payload, { ctx }) => { + // With plain task, payload is 'any' so we need to manually type it + const taskId = payload.taskId as string; + const priority = payload.priority as number; + const tags = payload.tags as string[] | undefined; + const config = payload.config as + | { timeout: number; retries: number; async?: boolean } + | undefined; + + return { + processed: true, + taskId, + priority, + hasConfig: !!config, + }; + }, +}); + +// Test 4: Testing trigger type safety +export const testTriggerTypeSafety = task({ + id: "test-trigger-type-safety", + run: async (_, { ctx }) => { + // This should compile successfully with proper types + const result1 = await zodSchemaTask.trigger({ + id: "user123", + name: "John Doe", + email: "john@example.com", + age: 30, + isActive: true, + roles: ["user", "admin"], + }); + + // This should show TypeScript errors if uncommented: + // const result2 = await zodSchemaTask.trigger({ + // id: "user123", + // name: "John Doe", + // email: "not-an-email", // Invalid email + // age: "thirty", // Wrong type + // isActive: "yes", // Wrong type + // roles: ["superuser"], // Invalid enum value + // }); + + // Test complex schema trigger + const result3 = await complexZodTask.trigger({ + order: { + orderId: "550e8400-e29b-41d4-a716-446655440000", + items: [ + { + productId: "prod123", + quantity: 2, + price: 29.99, + discount: 10, + }, + ], + customer: { + customerId: "cust456", + email: "customer@example.com", + shippingAddress: { + street: "123 Main St", + city: "Anytown", + state: "CA", + zipCode: "12345", + country: "US", + }, + }, + paymentMethod: { + type: "credit_card", + last4: "1234", + brand: "visa", + }, + createdAt: new Date().toISOString(), + status: "pending", + }, + priority: 5, + }); + + return { + triggered: true, + runIds: [result1.id, result3.id], + }; + }, +}); + +// Test 5: Testing triggerAndWait with proper unwrap +export const testTriggerAndWait = task({ + id: "test-trigger-and-wait", + run: async (_, { ctx }) => { + // Test type inference with triggerAndWait + const result = await zodSchemaTask.triggerAndWait({ + id: "user456", + name: "Jane Smith", + email: "jane@example.com", + age: 25, + isActive: false, + roles: ["guest"], + metadata: { + source: "api", + version: "1.0", + }, + }); + + if (result.ok) { + // result.output should be typed + const processed: boolean = result.output.processed; + const userId: string = result.output.userId; + const userName: string = result.output.userName; + + return { + success: true, + processedUserId: userId, + processedUserName: userName, + }; + } else { + return { + success: false, + error: String(result.error), + }; + } + }, +}); + +// Test 6: Using unwrap() method +export const testUnwrap = task({ + id: "test-unwrap", + run: async (_, { ctx }) => { + try { + // Using unwrap() for cleaner code + const output = await zodSchemaTask + .triggerAndWait({ + id: "user789", + name: "Bob Johnson", + email: "bob@example.com", + age: 35, + isActive: true, + roles: ["user"], + }) + .unwrap(); + + // output is directly typed without needing to check result.ok + const processed: boolean = output.processed; + const userId: string = output.userId; + const userName: string = output.userName; + + return { + unwrapped: true, + userId, + userName, + }; + } catch (error) { + return { + unwrapped: false, + error: String(error), + }; + } + }, +}); \ No newline at end of file diff --git a/references/json-schema-test/trigger.config.ts b/references/json-schema-test/trigger.config.ts new file mode 100644 index 0000000000..8e1eeedf67 --- /dev/null +++ b/references/json-schema-test/trigger.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "@trigger.dev/sdk/v3"; + +export default defineConfig({ + project: "json-schema-test", + retries: { + enabledInDev: false, + }, + triggerDirectories: ["./src/trigger"], +}); \ No newline at end of file diff --git a/references/json-schema-test/tsconfig.json b/references/json-schema-test/tsconfig.json new file mode 100644 index 0000000000..b67ed39319 --- /dev/null +++ b/references/json-schema-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "lib": ["ES2022"], + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "allowJs": false, + "noEmit": true, + "paths": { + "@trigger.dev/sdk": ["../../packages/trigger-sdk/src/index.ts"], + "@trigger.dev/sdk/v3": ["../../packages/trigger-sdk/src/v3/index.ts"], + "@trigger.dev/core": ["../../packages/core/src/index.ts"], + "@trigger.dev/core/v3": ["../../packages/core/src/v3/index.ts"], + "@trigger.dev/schema-to-json": ["../../packages/schema-to-json/src/index.ts"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/references/json-schema-test/type-test.ts b/references/json-schema-test/type-test.ts new file mode 100644 index 0000000000..fd59e4e7af --- /dev/null +++ b/references/json-schema-test/type-test.ts @@ -0,0 +1,259 @@ +// Standalone type test to verify JSON schema implementation +// This imports directly from the source files to test compilation + +import { schemaTask, task } from "../../packages/trigger-sdk/src/v3/index.js"; +import type { JSONSchema } from "../../packages/trigger-sdk/src/v3/index.js"; +import { z } from "zod"; + +// Test 1: JSONSchema type is properly exported +const testJsonSchemaType: JSONSchema = { + type: "object", + properties: { + id: { type: "string" }, + name: { type: "string", minLength: 1 }, + age: { type: "integer", minimum: 0, maximum: 150 }, + email: { type: "string", format: "email" }, + tags: { + type: "array", + items: { type: "string" }, + minItems: 0, + maxItems: 10, + }, + active: { type: "boolean" }, + metadata: { + type: "object", + additionalProperties: true, + }, + }, + required: ["id", "name", "email"], + additionalProperties: false, +}; + +// Test 2: Plain task accepts JSONSchema type +const plainTask = task({ + id: "plain-task-with-schema", + payloadSchema: testJsonSchemaType, // This should compile without errors + run: async (payload, { ctx }) => { + return { processed: true }; + }, +}); + +// Test 3: Schema task with Zod +const zodSchema = z.object({ + userId: z.string(), + userName: z.string(), + userEmail: z.string().email(), + isActive: z.boolean(), + score: z.number(), + tags: z.array(z.string()), + metadata: z.record(z.unknown()).optional(), +}); + +const zodTask = schemaTask({ + id: "zod-schema-task", + schema: zodSchema, + run: async (payload, { ctx }) => { + // Type checking - all these should be properly typed + const userId: string = payload.userId; + const userName: string = payload.userName; + const userEmail: string = payload.userEmail; + const isActive: boolean = payload.isActive; + const score: number = payload.score; + const tags: string[] = payload.tags; + const metadata: Record | undefined = payload.metadata; + + return { + processedUserId: userId, + processedUserName: userName, + tagCount: tags.length, + }; + }, +}); + +// Test 4: Complex nested schemas +const nestedSchema = z.object({ + order: z.object({ + orderId: z.string().uuid(), + items: z.array(z.object({ + itemId: z.string(), + quantity: z.number().positive(), + unitPrice: z.number().positive(), + })), + customer: z.object({ + customerId: z.string(), + email: z.string().email(), + shipping: z.object({ + address: z.string(), + city: z.string(), + postalCode: z.string(), + country: z.string(), + }).optional(), + }), + status: z.enum(["pending", "processing", "shipped", "delivered"]), + }), + createdAt: z.string().datetime(), + notes: z.string().optional(), +}); + +const nestedTask = schemaTask({ + id: "nested-schema-task", + schema: nestedSchema, + run: async (payload, { ctx }) => { + // Deep property access with full type safety + const orderId = payload.order.orderId; + const firstItem = payload.order.items[0]; + const quantity = firstItem?.quantity ?? 0; + const email = payload.order.customer.email; + const city = payload.order.customer.shipping?.city; + const status = payload.order.status; + + // Status is properly typed as enum + const isShipped: boolean = status === "shipped" || status === "delivered"; + + return { + orderId, + customerEmail: email, + itemCount: payload.order.items.length, + isShipped, + shippingCity: city ?? "N/A", + }; + }, +}); + +// Test 5: Trigger type safety +async function testTriggerTypes() { + // Valid trigger calls - should compile + const handle1 = await zodTask.trigger({ + userId: "123", + userName: "John Doe", + userEmail: "john@example.com", + isActive: true, + score: 95.5, + tags: ["premium", "verified"], + metadata: { source: "web" }, + }); + + // The following would cause TypeScript errors if uncommented: + /* + const handle2 = await zodTask.trigger({ + userId: 123, // Error: Type 'number' is not assignable to type 'string' + userName: "Jane", + userEmail: "jane@example.com", + isActive: "yes", // Error: Type 'string' is not assignable to type 'boolean' + score: "high", // Error: Type 'string' is not assignable to type 'number' + tags: "single-tag", // Error: Type 'string' is not assignable to type 'string[]' + }); + + const handle3 = await zodTask.trigger({ + // Error: Missing required properties + userId: "456", + userName: "Bob", + }); + */ + + // triggerAndWait with result handling + const result = await zodTask.triggerAndWait({ + userId: "789", + userName: "Alice Smith", + userEmail: "alice@example.com", + isActive: false, + score: 88, + tags: ["new"], + }); + + if (result.ok) { + // Output is properly typed + const processedId: string = result.output.processedUserId; + const processedName: string = result.output.processedUserName; + const tagCount: number = result.output.tagCount; + } + + // Using unwrap + try { + const output = await zodTask.triggerAndWait({ + userId: "999", + userName: "Eve", + userEmail: "eve@example.com", + isActive: true, + score: 100, + tags: ["admin", "super"], + }).unwrap(); + + // Direct access to typed output + console.log(output.processedUserId); + console.log(output.processedUserName); + console.log(output.tagCount); + } catch (error) { + console.error("Task failed:", error); + } +} + +// Test 6: Batch operations type safety +async function testBatchTypes() { + // Batch trigger + const batchHandle = await zodTask.batchTrigger([ + { + payload: { + userId: "b1", + userName: "Batch User 1", + userEmail: "batch1@example.com", + isActive: true, + score: 75, + tags: ["batch"], + }, + }, + { + payload: { + userId: "b2", + userName: "Batch User 2", + userEmail: "batch2@example.com", + isActive: false, + score: 82, + tags: ["batch", "test"], + }, + }, + ]); + + // Batch trigger and wait + const batchResult = await zodTask.batchTriggerAndWait([ + { + payload: { + userId: "b3", + userName: "Batch User 3", + userEmail: "batch3@example.com", + isActive: true, + score: 90, + tags: [], + }, + }, + ]); + + // Process batch results with type safety + for (const run of batchResult.runs) { + if (run.ok) { + const userId: string = run.output.processedUserId; + const userName: string = run.output.processedUserName; + const tagCount: number = run.output.tagCount; + } + } +} + +// Test 7: Verify satisfies works for JSON Schema +const schemaWithSatisfies = { + type: "object", + properties: { + foo: { type: "string" }, + }, + required: ["foo"], +} satisfies JSONSchema; + +const taskWithSatisfies = task({ + id: "task-with-satisfies", + payloadSchema: schemaWithSatisfies, + run: async (payload) => { + return { foo: payload.foo }; + }, +}); + +// If this file compiles without errors, our implementation is working correctly! +console.log("Type tests completed successfully!"); \ No newline at end of file diff --git a/references/nextjs-realtime/package.json b/references/nextjs-realtime/package.json index 9e9edd34a1..4c2736a020 100644 --- a/references/nextjs-realtime/package.json +++ b/references/nextjs-realtime/package.json @@ -37,7 +37,7 @@ "tailwind-merge": "^2.5.3", "tailwindcss-animate": "^1.0.7", "uploadthing": "^7.1.0", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@next/bundle-analyzer": "^15.0.2", diff --git a/references/python-catalog/package.json b/references/python-catalog/package.json index 171a1e3ea4..1c4f585926 100644 --- a/references/python-catalog/package.json +++ b/references/python-catalog/package.json @@ -10,7 +10,7 @@ "dependencies": { "@trigger.dev/sdk": "workspace:*", "@trigger.dev/python": "workspace:*", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@trigger.dev/build": "workspace:*", diff --git a/references/test-tasks/package.json b/references/test-tasks/package.json index 6739b44b30..9ed2635da1 100644 --- a/references/test-tasks/package.json +++ b/references/test-tasks/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "@trigger.dev/sdk": "workspace:*", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@trigger.dev/build": "workspace:*", diff --git a/references/v3-catalog/package.json b/references/v3-catalog/package.json index 5b2315fe67..b637520197 100644 --- a/references/v3-catalog/package.json +++ b/references/v3-catalog/package.json @@ -62,7 +62,7 @@ "yt-dlp-wrap": "^2.3.12", "yup": "^1.4.0", "zip-node-addon": "^0.0.11", - "zod": "3.23.8" + "zod": "3.25.76" }, "devDependencies": { "@opentelemetry/api": "^1.8.0",