Skip to content

Commit 1294076

Browse files
authored
feat: index json schemas on tasks and schemaTask (#2351)
* Add payload schema handling for task indexing This change introduces support for handling payload schemas during task indexing. By incorporating the `payloadSchema` attribute into various components, we ensure that each task's payload structure is clearly defined and can be validated before processing. - Updated the TaskManifest and task metadata structures to include an optional `payloadSchema` attribute. This addition allows for more robust validation and handling of task payloads. - Enhanced several core modules to export and utilize the new `getSchemaToJsonSchema` function, providing easier conversion of schema types to JSON schemas. - Modified the database schema to store the `payloadSchema` attribute, ensuring that the payload schema information is persisted. - The change helps in maintaining consistency in data handling and improves the integrity of task data across the application. * Refactor: Remove getSchemaToJsonSchema in favor of schemaToJsonSchema The `getSchemaToJsonSchema` function was removed and replaced with `schemaToJsonSchema` across the codebase. This update introduces a new `@trigger.dev/schema-to-json` package to handle conversions of schema validation libraries to JSON Schema format, centralizing the functionality and improving maintainability. - Removed `getSchemaToJsonSchema` exports and references. - Added new schema conversion utility `@trigger.dev/schema-to-json`. - Updated `trigger-sdk` package to utilize `schemaToJsonSchema` for payloads. - Extensive testing coverage included to ensure conversion accuracy across various schema libraries including Zod, Yup, ArkType, Effect, and TypeBox. - The update ensures consistent and reliable schema conversions, facilitating future enhancements and supporting additional schema libraries. * Add support for Zod 4 in schema-to-json This change enhances the schema-to-json package by adding support for Zod version 4, which introduces the native `toJsonSchema` method. This method facilitates a direct conversion of Zod schemas to JSON Schema format, improving performance and reducing reliance on the `zod-to-json-schema` library. - Updated README to reflect Zod 4 support with native method and retained support for Zod 3 via existing library. - Modified package.json to allow installation of both Zod 3 and 4 versions. - Implemented handling for Zod 4 schemas in `src/index.ts` using their native method. - Added a test case to verify the proper conversion of Zod 4 schemas to JSON Schema. - Included a script for updating the package version based on the root package.json. - Introduced a specific TypeScript config for source files. * Revise schema-to-json for bundle safety and tests The package @trigger.dev/schema-to-json has been revised to ensure bundle safety by removing direct dependencies on schema libraries such as Zod, Yup, and Effect. This change minimizes bundle size and enhances tree-shaking by allowing external conversion libraries to be utilized only at runtime if necessary. As a result, the README was updated to reflect this usage pattern. - Introduced `initializeSchemaConverters` function to load necessary conversion libraries at runtime, keeping the base package slim. - Adjusted test suite to initialize converters before tests, ensuring accurate testing of schema conversion capabilities. - Updated `schemaToJsonSchema` function to dynamically check for availability of conversion libraries, improving flexibility without increasing the package size. - Added configuration files for Vitest to support the new testing framework, reflecting the transition from previous test setups. These enhancements ensure that only the schema libraries actively used in an application are bundled, optimizing performance and resource usage. * Refine JSON Schema typing across packages The changes introduce stricter typing for JSON Schema-related definitions, specifically replacing vague types with more precise ones, such as using `z.record(z.unknown())` instead of `z.any()` and `Record<string, unknown>` in place of `any`. This is part of an effort to better align with common practices and improve type safety in the packages. - Updated the `payloadSchema` in several files to use `z.record(z.unknown())`, enhancing the type strictness and consistency with JSON Schema Draft 7 recommendations. - Added `@types/json-schema` as a dependency, utilizing its definitions for improved type clarity and adherence to best practices in TypeScript. - Modified various comments to explicitly mention JSON Schema Draft 7, ensuring developers are aware of the JSON Schema version being implemented. - These adjustments are informed by research into how popular libraries and tools handle JSON Schema typing, aiming to integrate best practices for improved maintainability and interoperability. * Add JSON Schema examples using various libraries The change introduces extensive examples of using JSON Schemas in the 'references/hello-world' project within the 'trigger.dev' repository. These examples utilize libraries like Zod, Yup, and TypeBox for JSON Schema conversion and validation. The new examples demonstrate different use cases, including automatic conversion with schemaTask, manual schema provision, and schema conversion at build time. We also updated the dependencies in 'package.json' to include the necessary libraries for schema conversion and validation. - Included examples of processing tasks with JSON Schema using libraries such as Zod, Yup, TypeBox, and ArkType. - Showcased schema conversion techniques and type-safe JSON Schema creation. - Updated 'package.json' to ensure all necessary dependencies for schema operations are available. - Created illustrative scripts that cover task management from user processing to complex schema implementations. * Refactor SDK to encapsulate schema-to-json package The previous implementation required users to directly import and initialize functions from the `@trigger.dev/schema-to-json` package, which was not the intended user experience. This change refactors the SDK so that all necessary functions and types from `@trigger.dev/schema-to-json` are encapsulated within the `@trigger.dev/*` packages. - The examples in `usage.ts` have been updated to clearly mark `@trigger.dev/schema-to-json` as an internal-only package. - Re-export JSON Schema types and conversions in the SDK to improve developer experience (DX). - Removed unnecessary direct dependencies on `@trigger.dev/schema-to-json` from user-facing code, ensuring initialization and conversion logic is handled internally. - Replaced instances where users were required to manually perform schema conversions with automatic handling within the SDK for simplification and better maintainability. * Add JSONSchema type for payloadSchema in tasks The change was necessary to improve type safety by using a proper JSONSchema type definition instead of a generic Record<string, unknown>. This enhances the developer experience and ensures that task payloads conform to the JSON Schema Draft 7 specification. The JSONSchema type is now re-exported from the SDK for user convenience, hiding internal complexity and maintaining a seamless developer experience. - Added JSONSchema type based on Draft 7 specification - Updated task metadata and options to use JSONSchema type - Hid internal schema conversion logic from users by re-exporting types from SDK - Improved bundle safety and dependency management * Add JSON schema testing and revert package dependencies This commit introduces a comprehensive set of JSON schema testing within the monorepo, specifically adding a new test project in `references/json-schema-test`. This includes a variety of schema definitions and tasks utilizing multiple validation libraries to ensure robust type-checking and runtime validation. Additionally, the dependency versions for `@effect/schema` have been adjusted from `^0.76.5` to `^0.75.5` to maintain compatibility across the project components. This ensures consistent behavior and compatibility with existing code bases without introducing breaking changes or unexpected behavior due to version discrepancies. Key updates include: - Added new test project with extensive schema validation tests. - Ensured type safety across various task implementations. - Reverted dependency versions to ensure compatibility. - Created multiple schema tasks using libraries like Zod, Yup, and others for thorough testing. * Refactor JSON Schema test files for clarity Whitespace and formatting changes were applied across the `json-schema-test` reference project to enhance code readability and cohesion. This included removing unnecessary trailing spaces and ensuring consistent indentation patterns, which improves maintainability and readability by following the project's code style guidelines. - Renamed JSONSchema type annotations to adhere to TypeScript conventions, ensuring that all schema definitions properly satisfy the JSONSchema interface. - Restructured some object declarations for improved clarity, especially within complex schema definitions. - These adjustments are crucial for better future maintainability, reducing potential developer errors when interacting with these test schemas. * Fixed some stuff * WIP * we now convert schema to jsonSchema on the CLI side via the indexing * Remove the json-schema-test reference project * Improve schema-to-json peer deps and fix effect schema * Explain the casting and match the version numbers * Fixed a bunch more schema stuff * Don't clean files that might be written to * Don't use a custom version of vitest in the new package * fix attw in schema-to-json
1 parent f82a4e9 commit 1294076

36 files changed

+2234
-40
lines changed

apps/webapp/app/v3/services/createBackgroundWorker.server.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ export class CreateBackgroundWorkerService extends BaseService {
7777
version: nextVersion,
7878
runtimeEnvironmentId: environment.id,
7979
projectId: project.id,
80-
metadata: body.metadata,
80+
// body.metadata has an index signature that Prisma doesn't like (from the JSONSchema type) so we are safe to just cast it
81+
metadata: body.metadata as Prisma.InputJsonValue,
8182
contentHash: body.metadata.contentHash,
8283
cliVersion: body.metadata.cliPackageVersion,
8384
sdkVersion: body.metadata.packageVersion,
@@ -280,6 +281,7 @@ async function createWorkerTask(
280281
fileId: tasksToBackgroundFiles?.get(task.id) ?? null,
281282
maxDurationInSeconds: task.maxDuration ? clampMaxDuration(task.maxDuration) : null,
282283
queueId: queue.id,
284+
payloadSchema: task.payloadSchema as any,
283285
},
284286
});
285287
} catch (error) {

apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CreateBackgroundWorkerRequestBody } from "@trigger.dev/core/v3";
2-
import type { BackgroundWorker } from "@trigger.dev/database";
2+
import type { BackgroundWorker, Prisma } from "@trigger.dev/database";
33
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
44
import { logger } from "~/services/logger.server";
55
import { socketIo } from "../handleSocketIo.server";
@@ -48,7 +48,8 @@ export class CreateDeploymentBackgroundWorkerServiceV3 extends BaseService {
4848
version: deployment.version,
4949
runtimeEnvironmentId: environment.id,
5050
projectId: environment.projectId,
51-
metadata: body.metadata,
51+
// body.metadata has an index signature that Prisma doesn't like (from the JSONSchema type) so we are safe to just cast it
52+
metadata: body.metadata as Prisma.InputJsonValue,
5253
contentHash: body.metadata.contentHash,
5354
cliVersion: body.metadata.cliPackageVersion,
5455
sdkVersion: body.metadata.packageVersion,

apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { CreateBackgroundWorkerRequestBody, logger, tryCatch } from "@trigger.dev/core/v3";
22
import { BackgroundWorkerId } from "@trigger.dev/core/v3/isomorphic";
3-
import type { BackgroundWorker, WorkerDeployment } from "@trigger.dev/database";
3+
import type { BackgroundWorker, Prisma, WorkerDeployment } from "@trigger.dev/database";
44
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
55
import { BaseService, ServiceValidationError } from "./baseService.server";
66
import {
@@ -65,7 +65,8 @@ export class CreateDeploymentBackgroundWorkerServiceV4 extends BaseService {
6565
version: deployment.version,
6666
runtimeEnvironmentId: environment.id,
6767
projectId: environment.projectId,
68-
metadata: body.metadata,
68+
// body.metadata has an index signature that Prisma doesn't like (from the JSONSchema type) so we are safe to just cast it
69+
metadata: body.metadata as Prisma.InputJsonValue,
6970
contentHash: body.metadata.contentHash,
7071
cliVersion: body.metadata.cliPackageVersion,
7172
sdkVersion: body.metadata.packageVersion,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "BackgroundWorkerTask" ADD COLUMN "payloadSchema" JSONB;

internal-packages/database/prisma/schema.prisma

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,8 @@ model BackgroundWorkerTask {
510510
511511
triggerSource TaskTriggerSource @default(STANDARD)
512512
513+
payloadSchema Json?
514+
513515
@@unique([workerId, slug])
514516
// Quick lookup of task identifiers
515517
@@index([projectId, slug])

packages/cli-v3/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"@opentelemetry/semantic-conventions": "1.36.0",
9292
"@trigger.dev/build": "workspace:4.0.0-v4-beta.26",
9393
"@trigger.dev/core": "workspace:4.0.0-v4-beta.26",
94+
"@trigger.dev/schema-to-json": "workspace:4.0.0-v4-beta.26",
9495
"ansi-escapes": "^7.0.0",
9596
"braces": "^3.0.3",
9697
"c12": "^1.11.1",

packages/cli-v3/src/entryPoints/dev-index-worker.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { registerResources } from "../indexing/registerResources.js";
1818
import { env } from "std-env";
1919
import { normalizeImportPath } from "../utilities/normalizeImportPath.js";
2020
import { detectRuntimeVersion } from "@trigger.dev/core/v3/build";
21+
import { schemaToJsonSchema, initializeSchemaConverters } from "@trigger.dev/schema-to-json";
2122

2223
sourceMapSupport.install({
2324
handleUncaughtExceptions: false,
@@ -100,7 +101,7 @@ async function bootstrap() {
100101

101102
const { buildManifest, importErrors, config, timings } = await bootstrap();
102103

103-
let tasks = resourceCatalog.listTaskManifests();
104+
let tasks = await convertSchemasToJsonSchemas(resourceCatalog.listTaskManifests());
104105

105106
// If the config has retry defaults, we need to apply them to all tasks that don't have any retry settings
106107
if (config.retries?.default) {
@@ -190,3 +191,24 @@ await new Promise<void>((resolve) => {
190191
resolve();
191192
}, 10);
192193
});
194+
195+
async function convertSchemasToJsonSchemas(tasks: TaskManifest[]): Promise<TaskManifest[]> {
196+
await initializeSchemaConverters();
197+
198+
const convertedTasks = tasks.map((task) => {
199+
const schema = resourceCatalog.getTaskSchema(task.id);
200+
201+
if (schema) {
202+
try {
203+
const result = schemaToJsonSchema(schema);
204+
return { ...task, payloadSchema: result?.jsonSchema };
205+
} catch {
206+
return task;
207+
}
208+
}
209+
210+
return task;
211+
});
212+
213+
return convertedTasks;
214+
}

packages/cli-v3/src/entryPoints/managed-index-worker.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { registerResources } from "../indexing/registerResources.js";
1818
import { env } from "std-env";
1919
import { normalizeImportPath } from "../utilities/normalizeImportPath.js";
2020
import { detectRuntimeVersion } from "@trigger.dev/core/v3/build";
21+
import { schemaToJsonSchema, initializeSchemaConverters } from "@trigger.dev/schema-to-json";
2122

2223
sourceMapSupport.install({
2324
handleUncaughtExceptions: false,
@@ -100,7 +101,7 @@ async function bootstrap() {
100101

101102
const { buildManifest, importErrors, config, timings } = await bootstrap();
102103

103-
let tasks = resourceCatalog.listTaskManifests();
104+
let tasks = await convertSchemasToJsonSchemas(resourceCatalog.listTaskManifests());
104105

105106
// If the config has retry defaults, we need to apply them to all tasks that don't have any retry settings
106107
if (config.retries?.default) {
@@ -196,3 +197,24 @@ await new Promise<void>((resolve) => {
196197
resolve();
197198
}, 10);
198199
});
200+
201+
async function convertSchemasToJsonSchemas(tasks: TaskManifest[]): Promise<TaskManifest[]> {
202+
await initializeSchemaConverters();
203+
204+
const convertedTasks = tasks.map((task) => {
205+
const schema = resourceCatalog.getTaskSchema(task.id);
206+
207+
if (schema) {
208+
try {
209+
const result = schemaToJsonSchema(schema);
210+
return { ...task, payloadSchema: result?.jsonSchema };
211+
} catch {
212+
return task;
213+
}
214+
}
215+
216+
return task;
217+
});
218+
219+
return convertedTasks;
220+
}

packages/core/src/v3/resource-catalog/catalog.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { QueueManifest, TaskManifest, WorkerManifest } from "../schemas/index.js";
2-
import { TaskMetadataWithFunctions } from "../types/index.js";
2+
import { TaskMetadataWithFunctions, TaskSchema } from "../types/index.js";
33

44
export interface ResourceCatalog {
55
setCurrentFileContext(filePath: string, entryPoint: string): void;
@@ -13,4 +13,5 @@ export interface ResourceCatalog {
1313
registerWorkerManifest(workerManifest: WorkerManifest): void;
1414
registerQueueMetadata(queue: QueueManifest): void;
1515
listQueueManifests(): Array<QueueManifest>;
16+
getTaskSchema(id: string): TaskSchema | undefined;
1617
}

packages/core/src/v3/resource-catalog/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const API_NAME = "resource-catalog";
22

33
import { QueueManifest, TaskManifest, WorkerManifest } from "../schemas/index.js";
4-
import { TaskMetadataWithFunctions } from "../types/index.js";
4+
import { TaskMetadataWithFunctions, TaskSchema } from "../types/index.js";
55
import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals.js";
66
import { type ResourceCatalog } from "./catalog.js";
77
import { NoopResourceCatalog } from "./noopResourceCatalog.js";
@@ -65,6 +65,10 @@ export class ResourceCatalogAPI {
6565
return this.#getCatalog().getTask(id);
6666
}
6767

68+
public getTaskSchema(id: string): TaskSchema | undefined {
69+
return this.#getCatalog().getTaskSchema(id);
70+
}
71+
6872
public taskExists(id: string): boolean {
6973
return this.#getCatalog().taskExists(id);
7074
}

0 commit comments

Comments
 (0)