diff --git a/apps/coordinator/src/server.ts b/apps/coordinator/src/server.ts index b3cd504c8..ee19581ef 100644 --- a/apps/coordinator/src/server.ts +++ b/apps/coordinator/src/server.ts @@ -5,10 +5,13 @@ import { ZodRPC, } from "internal-bridge"; import { + coordinatorCatalog, + CoordinatorCatalog, InternalApiClient, platformCatalog, PlatformCatalog, TriggerMetadataSchema, + ZodPublisher, ZodSubscriber, } from "internal-platform"; import { v4 } from "uuid"; @@ -28,6 +31,7 @@ export class TriggerServer { #organizationId?: string; #isInitialized = false; #triggerSubscriber?: ZodSubscriber; + #triggerPublisher?: ZodPublisher; #apiClient: InternalApiClient; #workflowId?: string; #apiKey: string; @@ -87,7 +91,39 @@ export class TriggerServer { receiver: ServerRPCSchema, handlers: { SEND_LOG: async (data) => { - return true; + if (!this.#triggerPublisher) { + // TODO: need to recover from this issue by trying to reconnect + return false; + } + + if (!this.#organizationId) { + // TODO: this should never really happen + throw new Error( + "Cannot complete workflow run without an organization ID" + ); + } + + if (!this.#workflowId) { + // TODO: this should never really happen + throw new Error("Cannot send log without a workflow ID"); + } + + const response = await this.#triggerPublisher.publish( + "LOG_MESSAGE", + { + id: data.id, + log: { + level: data.level, + message: data.message, + }, + }, + { + "x-api-key": this.#apiKey, + "x-workflow-id": this.#workflowId, + } + ); + + return !!response; }, INITIALIZE_HOST: async (data) => { // Initialize workflow @@ -102,6 +138,54 @@ export class TriggerServer { }; } }, + SEND_WORKFLOW_ERROR: async (data) => { + if (!this.#triggerPublisher) { + // TODO: need to recover from this issue by trying to reconnect + return false; + } + + if (!this.#organizationId) { + // TODO: this should never really happen + throw new Error( + "Cannot complete workflow run without an organization ID" + ); + } + + const response = await this.#triggerPublisher.publish( + "FAIL_WORKFLOW_RUN", + data, + { + "x-api-key": this.#apiKey, + "x-workflow-id": data.workflowId, + } + ); + + return !!response; + }, + COMPLETE_WORKFLOW_RUN: async (data) => { + if (!this.#triggerPublisher) { + // TODO: need to recover from this issue by trying to reconnect + return false; + } + + if (!this.#organizationId) { + // TODO: this should never really happen + throw new Error( + "Cannot complete workflow run without an organization ID" + ); + } + + const response = await this.#triggerPublisher.publish( + "COMPLETE_WORKFLOW_RUN", + data, + { + "x-api-key": this.#apiKey, + "x-workflow-id": data.workflowId, + } + ); + + return !!response; + }, }, }); @@ -180,7 +264,7 @@ export class TriggerServer { this.#workflowId = response.id; - this.#logger.debug("Initializing pub sub..."); + this.#logger.debug("Initializing platform subscriber..."); this.#triggerSubscriber = new ZodSubscriber({ schema: platformCatalog, @@ -206,13 +290,13 @@ export class TriggerServer { return true; } - this.#logger.info("Triggering workflow", id, data, properties); + this.#logger.info("Triggering workflow", data, properties); // Send the trigger to the host machine // TODO - call this TRIGGER_WORKFLOW and then have the host machine create a new run this.#serverRPC?.send("TRIGGER_WORKFLOW", { - id, + id: data.id, trigger: data, meta: { workflowId: properties["x-workflow-id"], @@ -222,7 +306,26 @@ export class TriggerServer { }, }); - return true; + try { + const messageId = await this.#triggerPublisher?.publish( + "START_WORKFLOW_RUN", + { + id: data.id, + }, + { + "x-workflow-id": properties["x-workflow-id"], + "x-api-key": properties["x-api-key"], + } + ); + + return !!messageId; + } catch (error) { + this.#logger.error( + "Failed to notify platform that workflow run started", + error + ); + return false; + } }, }, }); @@ -230,11 +333,31 @@ export class TriggerServer { const result = await this.#triggerSubscriber.initialize(); if (!result) { - this.#logger.debug("Pub sub failed to initialize"); + this.#logger.debug("Platform subscriber failed to initialize"); return false; } - this.#logger.info("Pub sub initialized"); + this.#logger.info("Platform subscriber initialized"); + + this.#logger.info("Initializing coordinator publisher..."); + + this.#triggerPublisher = new ZodPublisher({ + schema: coordinatorCatalog, + client: pulsarClient, + config: { + topic: `persistent://public/default/coordinator-events`, + }, + }); + + const result2 = await this.#triggerPublisher.initialize(); + + if (!result2) { + this.#logger.info("Coordinator publisher failed to initialize"); + await this.#closePubSub(); + return false; + } + + this.#logger.info("Coordinator publisher initialized"); this.#isInitialized = true; @@ -250,6 +373,10 @@ export class TriggerServer { if (this.#triggerSubscriber) { await this.#triggerSubscriber.close(); } + + if (this.#triggerPublisher) { + await this.#triggerPublisher.close(); + } } #closeConnection() { diff --git a/apps/webapp/app/models/workflowRun.server.ts b/apps/webapp/app/models/workflowRun.server.ts new file mode 100644 index 000000000..4bb79ccd0 --- /dev/null +++ b/apps/webapp/app/models/workflowRun.server.ts @@ -0,0 +1,151 @@ +import type { WorkflowRun, WorkflowRunStep } from ".prisma/client"; +import type { + ErrorSchema, + LogMessageSchema, + WaitSchema, +} from "@trigger.dev/common-schemas"; +import type { CustomEventSchema } from "internal-platform"; +import type { z } from "zod"; +import { prisma } from "~/db.server"; +import { IngestEvent } from "~/services/events/ingest.server"; + +export type { WorkflowRun, WorkflowRunStep }; + +export async function startWorkflowRun(id: string, apiKey: string) { + const workflowRun = await findWorkflowRunScopedToApiKey(id, apiKey); + + await prisma.workflowRun.update({ + where: { id: workflowRun.id }, + data: { + status: "RUNNING", + startedAt: new Date(), + }, + }); +} + +export async function failWorkflowRun( + id: string, + error: z.infer, + apiKey: string +) { + const workflowRun = await findWorkflowRunScopedToApiKey(id, apiKey); + + await prisma.workflowRun.update({ + where: { id: workflowRun.id }, + data: { + status: "ERROR", + error, + finishedAt: new Date(), + }, + }); +} + +export async function completeWorkflowRun( + id: string, + output: string, + apiKey: string +) { + const workflowRun = await findWorkflowRunScopedToApiKey(id, apiKey); + + await prisma.$transaction(async (tx) => { + await tx.workflowRun.update({ + where: { id: workflowRun.id }, + data: { + status: "SUCCESS", + finishedAt: new Date(), + }, + }); + + await tx.workflowRunStep.create({ + data: { + runId: id, + type: "OUTPUT", + output: JSON.parse(output), + context: {}, + startedAt: new Date(), + finishedAt: new Date(), + }, + }); + }); +} + +export async function triggerEventInRun( + id: string, + event: z.infer, + apiKey: string +) { + const workflowRun = await findWorkflowRunScopedToApiKey(id, apiKey); + + await prisma.workflowRunStep.create({ + data: { + runId: id, + type: "CUSTOM_EVENT", + input: event, + context: {}, + startedAt: new Date(), + finishedAt: new Date(), + }, + }); + + const ingestService = new IngestEvent(); + + await ingestService.call( + event, + workflowRun.environment.organization, + workflowRun.environment + ); +} + +export async function logMessageInRun( + id: string, + log: z.infer, + apiKey: string +) { + const workflowRun = await findWorkflowRunScopedToApiKey(id, apiKey); + + await prisma.workflowRunStep.create({ + data: { + runId: workflowRun.id, + type: "LOG_MESSAGE", + input: log, + context: {}, + startedAt: new Date(), + finishedAt: new Date(), + }, + }); +} + +export async function initiateWaitInRun( + id: string, + wait: z.infer, + apiKey: string +) { + const workflowRun = await findWorkflowRunScopedToApiKey(id, apiKey); + + await prisma.workflowRunStep.create({ + data: { + runId: workflowRun.id, + type: "DURABLE_DELAY", + input: wait, + context: {}, + startedAt: new Date(), + }, + }); +} + +async function findWorkflowRunScopedToApiKey(id: string, apiKey: string) { + const workflowRun = await prisma.workflowRun.findFirst({ + where: { id }, + include: { + environment: { + include: { organization: true }, + }, + }, + }); + + if (!workflowRun || workflowRun.environment.apiKey !== apiKey) { + throw new Error("Invalid workflow run"); + } + + return workflowRun; +} diff --git a/apps/webapp/app/services/events/ingest.server.ts b/apps/webapp/app/services/events/ingest.server.ts index 3990e9623..7fbcca690 100644 --- a/apps/webapp/app/services/events/ingest.server.ts +++ b/apps/webapp/app/services/events/ingest.server.ts @@ -48,7 +48,6 @@ export class IngestEvent { // Produce a message to the event bus await internalPubSub.publish( - event.id, "CUSTOM_EVENT_CREATED", { id: event.id, diff --git a/apps/webapp/app/services/messageBroker.server.ts b/apps/webapp/app/services/messageBroker.server.ts index 124e75a7f..d784d6455 100644 --- a/apps/webapp/app/services/messageBroker.server.ts +++ b/apps/webapp/app/services/messageBroker.server.ts @@ -1,18 +1,35 @@ -import { JsonSchema, PlatformCatalog } from "internal-platform"; -import { platformCatalog, ZodPublisher, ZodPubSub } from "internal-platform"; +import { JsonSchema } from "@trigger.dev/common-schemas"; +import type { CoordinatorCatalog, PlatformCatalog } from "internal-platform"; +import { + coordinatorCatalog, + platformCatalog, + ZodPublisher, + ZodPubSub, + ZodSubscriber, +} from "internal-platform"; import type { Client as PulsarClient } from "pulsar-client"; import Pulsar from "pulsar-client"; import { z } from "zod"; import { prisma } from "~/db.server"; import { env } from "~/env.server"; +import { + completeWorkflowRun, + failWorkflowRun, + initiateWaitInRun, + logMessageInRun, + startWorkflowRun, + triggerEventInRun, +} from "~/models/workflowRun.server"; let pulsarClient: PulsarClient; let triggerPublisher: ZodPublisher; +let triggerSubscriber: ZodSubscriber; let internalPubSub: ZodPubSub; declare global { var __pulsar_client__: typeof pulsarClient; var __trigger_publisher__: typeof triggerPublisher; + var __trigger_subscriber__: typeof triggerSubscriber; var __internal_pub_sub__: typeof internalPubSub; } @@ -44,6 +61,15 @@ export async function init() { triggerPublisher = global.__trigger_publisher__; } + if (env.NODE_ENV === "production") { + triggerSubscriber = await createTriggerSubscriber(); + } else { + if (!global.__trigger_subscriber__) { + global.__trigger_subscriber__ = await createTriggerSubscriber(); + } + triggerSubscriber = global.__trigger_subscriber__; + } + if (env.NODE_ENV === "production") { internalPubSub = await createInternalPubSub(); } else { @@ -78,6 +104,62 @@ async function createTriggerPublisher() { return producer; } +async function createTriggerSubscriber() { + const subscriber = new ZodSubscriber({ + client: pulsarClient, + config: { + topic: "persistent://public/default/coordinator-events", + subscription: "webapp", + subscriptionType: "Shared", + subscriptionInitialPosition: "Earliest", + }, + schema: coordinatorCatalog, + handlers: { + LOG_MESSAGE: async (id, data, properties) => { + await logMessageInRun(data.id, data.log, properties["x-api-key"]); + + return true; + }, + START_WORKFLOW_RUN: async (id, data, properties) => { + await startWorkflowRun(data.id, properties["x-api-key"]); + + return true; + }, + FAIL_WORKFLOW_RUN: async (id, data, properties) => { + await failWorkflowRun(data.id, data.error, properties["x-api-key"]); + + return true; + }, + INITIATE_INTEGRATION_REQUEST: async (id, data, properties) => { + return true; + }, + COMPLETE_WORKFLOW_RUN: async (id, data, properties) => { + await completeWorkflowRun( + data.id, + data.output, + properties["x-api-key"] + ); + + return true; + }, + TRIGGER_CUSTOM_EVENT: async (id, data, properties) => { + await triggerEventInRun(data.id, data.event, properties["x-api-key"]); + + return true; + }, + INITIATE_WAIT: async (id, data, properties) => { + await initiateWaitInRun(data.id, data.wait, properties["x-api-key"]); + + return true; + }, + }, + }); + + await subscriber.initialize(); + + return subscriber; +} + const CustomEventCreatedEventSchema = z.object({ id: z.string(), name: z.string(), @@ -152,18 +234,15 @@ async function createInternalPubSub() { }, input: data.payload ?? {}, context: data.context ?? undefined, - timestamp: data.timestamp, }, }); await triggerPublisher.publish( - run.id, "TRIGGER_WORKFLOW", { id: run.id, input: data.payload, context: data.context, - timestamp: data.timestamp, }, { "x-api-key": trigger.environment.apiKey, diff --git a/apps/webapp/package.json b/apps/webapp/package.json index a2101224d..ed8d10678 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -79,6 +79,7 @@ "date-fns": "2.0.0-alpha.7 || >=2.0.0", "express": "^4.18.1", "internal-platform": "workspace:*", + "@trigger.dev/common-schemas": "workspace:*", "javascript-time-ago": "^2.5.7", "json-query": "^2.2.2", "jsonata": "^1.8.6", diff --git a/apps/webapp/prisma/migrations/20221219142856_add_workflow_run_step_model/migration.sql b/apps/webapp/prisma/migrations/20221219142856_add_workflow_run_step_model/migration.sql new file mode 100644 index 000000000..fb45d66df --- /dev/null +++ b/apps/webapp/prisma/migrations/20221219142856_add_workflow_run_step_model/migration.sql @@ -0,0 +1,19 @@ +-- CreateEnum +CREATE TYPE "WorkflowRunStepType" AS ENUM ('LOG_MESSAGE', 'DURABLE_DELAY', 'CUSTOM_EVENT'); + +-- CreateTable +CREATE TABLE "WorkflowRunStep" ( + "id" TEXT NOT NULL, + "runId" TEXT NOT NULL, + "type" "WorkflowRunStepType" NOT NULL, + "input" JSONB NOT NULL, + "output" JSONB, + "context" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "WorkflowRunStep_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "WorkflowRunStep" ADD CONSTRAINT "WorkflowRunStep_runId_fkey" FOREIGN KEY ("runId") REFERENCES "WorkflowRun"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/webapp/prisma/migrations/20221219171221_support_output_step/migration.sql b/apps/webapp/prisma/migrations/20221219171221_support_output_step/migration.sql new file mode 100644 index 000000000..d56f25728 --- /dev/null +++ b/apps/webapp/prisma/migrations/20221219171221_support_output_step/migration.sql @@ -0,0 +1,5 @@ +-- AlterEnum +ALTER TYPE "WorkflowRunStepType" ADD VALUE 'OUTPUT'; + +-- AlterTable +ALTER TABLE "WorkflowRunStep" ALTER COLUMN "input" DROP NOT NULL; diff --git a/apps/webapp/prisma/migrations/20221220095618_add_error_to_workflow_run/migration.sql b/apps/webapp/prisma/migrations/20221220095618_add_error_to_workflow_run/migration.sql new file mode 100644 index 000000000..81d2f9e76 --- /dev/null +++ b/apps/webapp/prisma/migrations/20221220095618_add_error_to_workflow_run/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "WorkflowRun" ADD COLUMN "error" JSONB; diff --git a/apps/webapp/prisma/migrations/20221220100932_add_timestamps_to_run_and_steps/migration.sql b/apps/webapp/prisma/migrations/20221220100932_add_timestamps_to_run_and_steps/migration.sql new file mode 100644 index 000000000..75b5240fd --- /dev/null +++ b/apps/webapp/prisma/migrations/20221220100932_add_timestamps_to_run_and_steps/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - You are about to drop the column `timestamp` on the `WorkflowRun` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "WorkflowRun" DROP COLUMN "timestamp", +ADD COLUMN "finishedAt" TIMESTAMP(3), +ADD COLUMN "startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE "WorkflowRunStep" ADD COLUMN "finishedAt" TIMESTAMP(3), +ADD COLUMN "startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/apps/webapp/prisma/migrations/20221220101020_make_started_at_optional/migration.sql b/apps/webapp/prisma/migrations/20221220101020_make_started_at_optional/migration.sql new file mode 100644 index 000000000..b1c5a5645 --- /dev/null +++ b/apps/webapp/prisma/migrations/20221220101020_make_started_at_optional/migration.sql @@ -0,0 +1,7 @@ +-- AlterTable +ALTER TABLE "WorkflowRun" ALTER COLUMN "startedAt" DROP NOT NULL, +ALTER COLUMN "startedAt" DROP DEFAULT; + +-- AlterTable +ALTER TABLE "WorkflowRunStep" ALTER COLUMN "startedAt" DROP NOT NULL, +ALTER COLUMN "startedAt" DROP DEFAULT; diff --git a/apps/webapp/prisma/schema.prisma b/apps/webapp/prisma/schema.prisma index 0920d4fce..18b3e20ac 100644 --- a/apps/webapp/prisma/schema.prisma +++ b/apps/webapp/prisma/schema.prisma @@ -177,14 +177,18 @@ model WorkflowRun { environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) environmentId String - input Json - context Json? - timestamp DateTime + tasks WorkflowRunStep[] + + input Json + context Json? + error Json? status WorkflowRunStatus @default(PENDING) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + startedAt DateTime? + finishedAt DateTime? } enum WorkflowRunStatus { @@ -194,6 +198,31 @@ enum WorkflowRunStatus { ERROR } +model WorkflowRunStep { + id String @id @default(cuid()) + + run WorkflowRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade) + runId String + + type WorkflowRunStepType + input Json? + output Json? + context Json + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + startedAt DateTime? + finishedAt DateTime? +} + +enum WorkflowRunStepType { + OUTPUT + LOG_MESSAGE + DURABLE_DELAY + CUSTOM_EVENT +} + //todo triggers are environment specific //todo connections are shared between environments //todo in the future, connections can be override per environment diff --git a/apps/webapp/remix.config.js b/apps/webapp/remix.config.js index 5ea89903e..c922c05d0 100644 --- a/apps/webapp/remix.config.js +++ b/apps/webapp/remix.config.js @@ -11,8 +11,12 @@ module.exports = { "@nangohq/pizzly-node", "axios", "internal-platform", + "@trigger.dev/common-schemas", ], watchPaths: async () => { - return ["../../packages/internal-platform/src/**/*"]; + return [ + "../../packages/internal-platform/src/**/*", + "../../packages/common-schemas/src/**/*", + ]; }, }; diff --git a/apps/webapp/tsconfig.json b/apps/webapp/tsconfig.json index 1e607893c..95adbe7de 100644 --- a/apps/webapp/tsconfig.json +++ b/apps/webapp/tsconfig.json @@ -19,7 +19,11 @@ "paths": { "~/*": ["./app/*"], "internal-platform": ["../../packages/internal-platform/src/index"], - "internal-platform/*": ["../../packages/internal-platform/src/*"] + "internal-platform/*": ["../../packages/internal-platform/src/*"], + "@trigger.dev/common-schemas": [ + "../../packages/common-schemas/src/index" + ], + "@trigger.dev/common-schemas/*": ["../../packages/common-schemas/src/*"] }, "noEmit": true } diff --git a/examples/smoke-test/src/index.ts b/examples/smoke-test/src/index.ts index 757c80274..7d4634d24 100644 --- a/examples/smoke-test/src/index.ts +++ b/examples/smoke-test/src/index.ts @@ -14,6 +14,8 @@ const trigger = new Trigger({ on: customEvent({ name: "user.created", schema: userCreatedEvent }), run: async (event) => { console.log("Inside the smoke test workflow, received event", event); + + return { foo: "bar" }; }, }); diff --git a/packages/common-schemas/src/error.ts b/packages/common-schemas/src/error.ts new file mode 100644 index 000000000..f5aa5d11b --- /dev/null +++ b/packages/common-schemas/src/error.ts @@ -0,0 +1,7 @@ +import { z } from "zod"; + +export const ErrorSchema = z.object({ + name: z.string(), + message: z.string(), + stackTrace: z.string().optional(), +}); diff --git a/packages/common-schemas/src/index.ts b/packages/common-schemas/src/index.ts index 98cf97ad9..00d314c00 100644 --- a/packages/common-schemas/src/index.ts +++ b/packages/common-schemas/src/index.ts @@ -1 +1,4 @@ export * from "./json"; +export * from "./error"; +export * from "./logs"; +export * from "./waits"; diff --git a/packages/common-schemas/src/logs.ts b/packages/common-schemas/src/logs.ts new file mode 100644 index 000000000..71d7e029d --- /dev/null +++ b/packages/common-schemas/src/logs.ts @@ -0,0 +1,6 @@ +import { z } from "zod"; + +export const LogMessageSchema = z.object({ + level: z.enum(["DEBUG", "INFO", "WARN", "ERROR"]), + message: z.string(), +}); diff --git a/packages/common-schemas/src/waits.ts b/packages/common-schemas/src/waits.ts new file mode 100644 index 000000000..40203f57f --- /dev/null +++ b/packages/common-schemas/src/waits.ts @@ -0,0 +1,16 @@ +import { z } from "zod"; + +export const DelaySchema = z.object({ + type: z.literal("DELAY"), + durationInMs: z.number(), +}); + +export const ScheduledForSchema = z.object({ + type: z.literal("SCHEDULE_FOR"), + scheduledFor: z.string().datetime(), +}); + +export const WaitSchema = z.discriminatedUnion("type", [ + DelaySchema, + ScheduledForSchema, +]); diff --git a/packages/internal-bridge/src/schemas/host.ts b/packages/internal-bridge/src/schemas/host.ts index d8324c29c..530fc922c 100644 --- a/packages/internal-bridge/src/schemas/host.ts +++ b/packages/internal-bridge/src/schemas/host.ts @@ -1,22 +1,13 @@ import { z } from "zod"; -import { TriggerEnvironmentSchema } from "./common"; import { JsonSchema } from "@trigger.dev/common-schemas"; export const HostRPCSchema = { - IO_RESPONSE: { - request: z.object({ - value: z.string(), - transactionId: z.string(), - }), - response: z.void().nullable(), - }, TRIGGER_WORKFLOW: { request: z.object({ id: z.string(), trigger: z.object({ input: JsonSchema.default({}), context: JsonSchema.default({}), - timestamp: z.string().datetime(), }), meta: z.object({ environment: z.string(), diff --git a/packages/internal-bridge/src/schemas/server.ts b/packages/internal-bridge/src/schemas/server.ts index ab8339de4..3bd41ca96 100644 --- a/packages/internal-bridge/src/schemas/server.ts +++ b/packages/internal-bridge/src/schemas/server.ts @@ -4,9 +4,8 @@ export const ServerRPCSchema = { SEND_LOG: { request: z.object({ id: z.string(), - data: z.string(), - index: z.number().optional(), - timestamp: z.number().optional(), + message: z.string(), + level: z.enum(["DEBUG", "INFO", "WARN", "ERROR"]), }), response: z.boolean(), }, @@ -39,6 +38,26 @@ export const ServerRPCSchema = { ]) .nullable(), }, + COMPLETE_WORKFLOW_RUN: { + request: z.object({ + id: z.string(), + workflowId: z.string(), + output: z.string(), + }), + response: z.boolean(), + }, + SEND_WORKFLOW_ERROR: { + request: z.object({ + id: z.string(), + workflowId: z.string(), + error: z.object({ + name: z.string(), + message: z.string(), + stackTrace: z.string().optional(), + }), + }), + response: z.boolean(), + }, }; export type ServerRPC = typeof ServerRPCSchema; diff --git a/packages/internal-bridge/src/zodRPC.ts b/packages/internal-bridge/src/zodRPC.ts index 7829e64e6..c1b0d556b 100644 --- a/packages/internal-bridge/src/zodRPC.ts +++ b/packages/internal-bridge/src/zodRPC.ts @@ -77,8 +77,10 @@ export class ZodRPC< } catch (callError) { if (callError instanceof ZodError) { console.error( - `[ZodRPC] Received invalid call:\n${JSON.stringify(message)}: `, - callError.flatten() + `[ZodRPC][foobar] Received invalid call:\n${JSON.stringify( + message + )}: `, + callError.errors ); } else { console.error( diff --git a/packages/internal-platform/package.json b/packages/internal-platform/package.json index e12f73704..c8d9540f6 100644 --- a/packages/internal-platform/package.json +++ b/packages/internal-platform/package.json @@ -13,7 +13,9 @@ }, "scripts": {}, "dependencies": { + "@trigger.dev/common-schemas": "workspace:*", "pulsar-client": "^1.7.0", + "ulid": "^2.3.0", "zod": "^3.20.2" } } \ No newline at end of file diff --git a/packages/internal-platform/src/api/client.ts b/packages/internal-platform/src/api/client.ts index 5bc83a550..05a97fac6 100644 --- a/packages/internal-platform/src/api/client.ts +++ b/packages/internal-platform/src/api/client.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { WorkflowMetadata } from "../schemas"; +import { UpdateWorkflowRun, WorkflowMetadata } from "../schemas"; export class InternalApiClient { #apiKey: string; @@ -20,7 +20,7 @@ export class InternalApiClient { error: z.string(), }); - const response = await fetch(this.#apiUrl("whoami"), { + const response = await fetch(this.#apiUrl("/whoami"), { method: "GET", headers: this.#headers(), }); @@ -52,7 +52,7 @@ export class InternalApiClient { error: z.string(), }); - const response = await fetch(this.#apiUrl(`workflows/${workflow.id}`), { + const response = await fetch(this.#apiUrl(`/workflows/${workflow.id}`), { method: "PUT", headers: this.#headers({ "Content-Type": "application/json" }), body: JSON.stringify(workflow), @@ -76,7 +76,37 @@ export class InternalApiClient { ); } - #apiUrl = (path: string) => `${this.#baseUrl}/${path}`; + async startWorkflowRun(workflowId: string, runId: string) { + const validationResponseSchema = z.object({ + error: z.string(), + }); + + const response = await fetch( + this.#apiUrl(`/workflows/${workflowId}/runs/${runId}`), + { + method: "PUT", + headers: this.#headers({ "Content-Type": "application/json" }), + body: JSON.stringify({ status: "RUNNING" }), + } + ); + + if (response.ok) { + return true; + } + + if (response.status === 400) { + const rawBody = await response.json(); + const body = validationResponseSchema.parse(rawBody); + + throw new Error(body.error); + } + + throw new Error( + `[${response.status}] Something went wrong: ${response.statusText}` + ); + } + + #apiUrl = (path: string) => `${this.#baseUrl}${path}`; #headers = (additionalHeaders?: Record) => ({ Accept: "application/json", Authorization: `Bearer ${this.#apiKey}`, diff --git a/packages/internal-platform/src/messages/catalogs/coordinator.ts b/packages/internal-platform/src/messages/catalogs/coordinator.ts index 60a1a39f7..29de884dd 100644 --- a/packages/internal-platform/src/messages/catalogs/coordinator.ts +++ b/packages/internal-platform/src/messages/catalogs/coordinator.ts @@ -1,7 +1,19 @@ import initiateIntegrationRequest from "../schemas/initiateIntegrationRequest"; +import startWorklowRun from "../schemas/startWorkflowRun"; +import failWorkflowRun from "../schemas/failWorkflowRun"; +import completeWorkflowRun from "../schemas/completeWorkflowRun"; +import logMessage from "../schemas/logMessage"; +import triggerCustomEvent from "../schemas/triggerCustomEvent"; +import awaits from "../schemas/awaits"; const Catalog = { ...initiateIntegrationRequest, + ...startWorklowRun, + ...failWorkflowRun, + ...completeWorkflowRun, + ...logMessage, + ...triggerCustomEvent, + ...awaits, }; export default Catalog; diff --git a/packages/internal-platform/src/messages/schemas/awaits.ts b/packages/internal-platform/src/messages/schemas/awaits.ts new file mode 100644 index 000000000..4a286b4a0 --- /dev/null +++ b/packages/internal-platform/src/messages/schemas/awaits.ts @@ -0,0 +1,17 @@ +import { WaitSchema } from "@trigger.dev/common-schemas"; +import { z } from "zod"; + +const Catalog = { + INITIATE_WAIT: { + data: z.object({ + id: z.string(), + wait: WaitSchema, + }), + properties: z.object({ + "x-workflow-id": z.string(), + "x-api-key": z.string(), + }), + }, +}; + +export default Catalog; diff --git a/packages/internal-platform/src/messages/schemas/completeWorkflowRun.ts b/packages/internal-platform/src/messages/schemas/completeWorkflowRun.ts new file mode 100644 index 000000000..c3e24de1d --- /dev/null +++ b/packages/internal-platform/src/messages/schemas/completeWorkflowRun.ts @@ -0,0 +1,16 @@ +import { z } from "zod"; + +const Catalog = { + COMPLETE_WORKFLOW_RUN: { + data: z.object({ + id: z.string(), + output: z.string(), + }), + properties: z.object({ + "x-workflow-id": z.string(), + "x-api-key": z.string(), + }), + }, +}; + +export default Catalog; diff --git a/packages/internal-platform/src/messages/schemas/failWorkflowRun.ts b/packages/internal-platform/src/messages/schemas/failWorkflowRun.ts new file mode 100644 index 000000000..826bfc8d1 --- /dev/null +++ b/packages/internal-platform/src/messages/schemas/failWorkflowRun.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; +import { ErrorSchema } from "@trigger.dev/common-schemas"; + +const Catalog = { + FAIL_WORKFLOW_RUN: { + data: z.object({ + id: z.string(), + error: ErrorSchema, + }), + properties: z.object({ + "x-workflow-id": z.string(), + "x-api-key": z.string(), + }), + }, +}; + +export default Catalog; diff --git a/packages/internal-platform/src/messages/schemas/initiateIntegrationRequest.ts b/packages/internal-platform/src/messages/schemas/initiateIntegrationRequest.ts index 90c6c3abf..13f214a85 100644 --- a/packages/internal-platform/src/messages/schemas/initiateIntegrationRequest.ts +++ b/packages/internal-platform/src/messages/schemas/initiateIntegrationRequest.ts @@ -1,5 +1,4 @@ import { z } from "zod"; -import { MessageCatalogSchema } from ".."; import { WorkflowEventPropertiesSchema, RetryOptionsSchema, diff --git a/packages/internal-platform/src/messages/schemas/logMessage.ts b/packages/internal-platform/src/messages/schemas/logMessage.ts new file mode 100644 index 000000000..d450ebca4 --- /dev/null +++ b/packages/internal-platform/src/messages/schemas/logMessage.ts @@ -0,0 +1,17 @@ +import { LogMessageSchema } from "@trigger.dev/common-schemas"; +import { z } from "zod"; + +const Catalog = { + LOG_MESSAGE: { + data: z.object({ + id: z.string(), + log: LogMessageSchema, + }), + properties: z.object({ + "x-workflow-id": z.string(), + "x-api-key": z.string(), + }), + }, +}; + +export default Catalog; diff --git a/packages/internal-platform/src/messages/schemas/startWorkflowRun.ts b/packages/internal-platform/src/messages/schemas/startWorkflowRun.ts new file mode 100644 index 000000000..5bfc44247 --- /dev/null +++ b/packages/internal-platform/src/messages/schemas/startWorkflowRun.ts @@ -0,0 +1,15 @@ +import { z } from "zod"; + +const Catalog = { + START_WORKFLOW_RUN: { + data: z.object({ + id: z.string(), + }), + properties: z.object({ + "x-workflow-id": z.string(), + "x-api-key": z.string(), + }), + }, +}; + +export default Catalog; diff --git a/packages/internal-platform/src/messages/schemas/triggerCustomEvent.ts b/packages/internal-platform/src/messages/schemas/triggerCustomEvent.ts new file mode 100644 index 000000000..7b6d6cbfb --- /dev/null +++ b/packages/internal-platform/src/messages/schemas/triggerCustomEvent.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; +import { CustomEventSchema } from "../../schemas"; + +const Catalog = { + TRIGGER_CUSTOM_EVENT: { + data: z.object({ + id: z.string(), + event: CustomEventSchema, + }), + properties: z.object({ + "x-workflow-id": z.string(), + "x-api-key": z.string(), + }), + }, +}; + +export default Catalog; diff --git a/packages/internal-platform/src/messages/schemas/triggerWorkflow.ts b/packages/internal-platform/src/messages/schemas/triggerWorkflow.ts index b1a7a6915..34b72968e 100644 --- a/packages/internal-platform/src/messages/schemas/triggerWorkflow.ts +++ b/packages/internal-platform/src/messages/schemas/triggerWorkflow.ts @@ -1,12 +1,11 @@ import { z } from "zod"; -import { JsonSchema } from "../../schemas"; +import { JsonSchema } from "@trigger.dev/common-schemas"; import { WorkflowEventPropertiesSchema } from "../sharedSchemas"; export const TriggerWorkflowMessageSchema = z.object({ id: z.string(), input: JsonSchema.default({}), context: JsonSchema.default({}), - timestamp: z.string().datetime(), }); const Catalog = { diff --git a/packages/internal-platform/src/messages/zodPubSub.ts b/packages/internal-platform/src/messages/zodPubSub.ts index 0b12a5094..319e1ac91 100644 --- a/packages/internal-platform/src/messages/zodPubSub.ts +++ b/packages/internal-platform/src/messages/zodPubSub.ts @@ -63,11 +63,10 @@ export class ZodPubSub { } public async publish( - id: string, type: K, data: z.infer, properties?: z.infer ): Promise { - return this.#publisher.publish(id, type, data, properties); + return this.#publisher.publish(type, data, properties); } } diff --git a/packages/internal-platform/src/messages/zodPublisher.ts b/packages/internal-platform/src/messages/zodPublisher.ts index e31437746..aa6533770 100644 --- a/packages/internal-platform/src/messages/zodPublisher.ts +++ b/packages/internal-platform/src/messages/zodPublisher.ts @@ -5,6 +5,7 @@ import { } from "pulsar-client"; import { Logger } from "../logger"; import { MessageCatalogSchema } from "./messageCatalogSchema"; +import { ulid } from "ulid"; import { z, ZodError } from "zod"; @@ -54,7 +55,6 @@ export class ZodPublisher { } public async publish( - id: string, type: K, data: z.infer, properties?: z.infer @@ -64,7 +64,7 @@ export class ZodPublisher { } try { - return this.#handlePublish(id, type, data, properties); + return this.#handlePublish(type, data, properties); } catch (e) { if (e instanceof ZodError) { this.#logger.error( @@ -79,7 +79,6 @@ export class ZodPublisher { } async #handlePublish( - id: string, type: K, data: z.infer, properties?: z.infer @@ -90,6 +89,8 @@ export class ZodPublisher { throw new Error(`Unknown message type: ${String(type)}`); } + const id = ulid(); + const parsedData = messageSchema.data.parse(data); const parsedProperties = messageSchema.properties.parse(properties); diff --git a/packages/internal-platform/src/schemas/index.ts b/packages/internal-platform/src/schemas/index.ts index 9241a9d01..eb1ffebfd 100644 --- a/packages/internal-platform/src/schemas/index.ts +++ b/packages/internal-platform/src/schemas/index.ts @@ -1,3 +1,2 @@ export * from "./workflows"; export * from "./events"; -export * from "./json"; diff --git a/packages/internal-platform/src/schemas/json.ts b/packages/internal-platform/src/schemas/json.ts deleted file mode 100644 index 730010391..000000000 --- a/packages/internal-platform/src/schemas/json.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from "zod"; - -const LiteralSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]); -type Literal = z.infer; - -type Json = Literal | { [key: string]: Json } | Json[]; - -export const JsonSchema: z.ZodType = z.lazy(() => - z.union([LiteralSchema, z.array(JsonSchema), z.record(JsonSchema)]) -); diff --git a/packages/internal-platform/src/schemas/workflows.ts b/packages/internal-platform/src/schemas/workflows.ts index 2e0d537ec..30ba4d66f 100644 --- a/packages/internal-platform/src/schemas/workflows.ts +++ b/packages/internal-platform/src/schemas/workflows.ts @@ -58,3 +58,29 @@ export const WorkflowMetadataSchema = z.object({ }); export type WorkflowMetadata = z.infer; + +export const UpdateRunningWorkflowRunSchema = z.object({ + status: z.literal("RUNNING"), +}); + +export const UpdateCompletedWorkflowRunSchema = z.object({ + status: z.literal("COMPLETED"), + output: z.string(), +}); + +export const UpdateFailedWorkflowRunSchema = z.object({ + status: z.literal("FAILED"), + error: z.object({ + name: z.string(), + message: z.string(), + stackTrace: z.string().optional(), + }), +}); + +export const UpdateWorkflowRunSchema = z.discriminatedUnion("status", [ + UpdateRunningWorkflowRunSchema, + UpdateCompletedWorkflowRunSchema, + UpdateFailedWorkflowRunSchema, +]); + +export type UpdateWorkflowRun = z.infer; diff --git a/packages/trigger-sdk/package.json b/packages/trigger-sdk/package.json index 4618a8322..c80d750b4 100644 --- a/packages/trigger-sdk/package.json +++ b/packages/trigger-sdk/package.json @@ -14,6 +14,7 @@ "@types/uuid": "^9.0.0", "@types/ws": "^8.5.3", "internal-bridge": "workspace:*", + "@trigger.dev/common-schemas": "workspace:*", "rimraf": "^3.0.2", "tsup": "^6.5.0", "tsx": "^3.12.1" diff --git a/packages/trigger-sdk/src/client.ts b/packages/trigger-sdk/src/client.ts index 37c11742a..4c326190c 100644 --- a/packages/trigger-sdk/src/client.ts +++ b/packages/trigger-sdk/src/client.ts @@ -92,14 +92,49 @@ export class TriggerClient { sender: ServerRPCSchema, receiver: HostRPCSchema, handlers: { - IO_RESPONSE: async (data) => { - console.log("IO_RESPONSE", data); - }, TRIGGER_WORKFLOW: async (data) => { console.log("TRIGGER_WORKFLOW", data); // TODO: handle this better - this.#trigger.options.run(data.trigger.input as TEventData); + this.#trigger.options + .run(data.trigger.input as TEventData) + .then((output) => { + return serverRPC.send("COMPLETE_WORKFLOW_RUN", { + id: data.id, + output: JSON.stringify(output), + workflowId: data.meta.workflowId, + }); + }) + .catch((anyError) => { + const parseAnyError = ( + error: any + ): { + name: string; + message: string; + stackTrace?: string; + } => { + if (error instanceof Error) { + return { + name: error.name, + message: error.message, + stackTrace: error.stack, + }; + } + + return { + name: "UnknownError", + message: "An unknown error occurred", + }; + }; + + const error = parseAnyError(anyError); + + return serverRPC.send("SEND_WORKFLOW_ERROR", { + id: data.id, + workflowId: data.meta.workflowId, + error, + }); + }); }, }, }); diff --git a/packages/trigger-sdk/src/trigger/index.ts b/packages/trigger-sdk/src/trigger/index.ts index 4b3c59f80..5862f927d 100644 --- a/packages/trigger-sdk/src/trigger/index.ts +++ b/packages/trigger-sdk/src/trigger/index.ts @@ -1,6 +1,8 @@ import { TriggerClient } from "../client"; import { LogLevel } from "internal-bridge"; import { TriggerEvent } from "../events"; +import { z } from "zod"; +import { JsonSchema } from "@trigger.dev/common-schemas"; export type TriggerOptions = { id: string; @@ -9,7 +11,7 @@ export type TriggerOptions = { apiKey?: string; endpoint?: string; logLevel?: LogLevel; - run: (event: TEventData) => Promise; + run: (event: TEventData) => Promise; }; export class Trigger { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6df730e76..8c278919b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,6 +108,7 @@ importers: '@testing-library/jest-dom': ^5.16.5 '@testing-library/react': ^13.4.0 '@testing-library/user-event': ^14.4.3 + '@trigger.dev/common-schemas': workspace:* '@trigger.dev/tailwind-config': '*' '@types/bcryptjs': ^2.4.2 '@types/compression': ^1.7.2 @@ -235,7 +236,8 @@ importers: '@sentry/remix': 7.24.2_dfehptsum4bkg2mncqmjuvk644 '@tailwindcss/forms': 0.5.3_tailwindcss@3.1.8 '@tanstack/react-table': 8.7.0_biqbaboplfbrettd7655fr4n2y - '@uiw/react-codemirror': 4.17.1_4ysryuwswq2dahvwdlnde5nvpq + '@trigger.dev/common-schemas': link:../../packages/common-schemas + '@uiw/react-codemirror': 4.17.1_xtrn3tyimkzpilanhyvm2ls4eu bcryptjs: 2.4.3 classnames: 2.3.2 clsx: 1.2.1 @@ -455,14 +457,18 @@ importers: packages/internal-platform: specifiers: + '@trigger.dev/common-schemas': workspace:* '@trigger.dev/tsconfig': workspace:* '@types/node': ^18.11.9 pulsar-client: ^1.7.0 typescript: ^4.9.4 + ulid: ^2.3.0 undici: ^5.14.0 zod: ^3.20.2 dependencies: + '@trigger.dev/common-schemas': link:../common-schemas pulsar-client: 1.7.0 + ulid: 2.3.0 zod: 3.20.2 devDependencies: '@trigger.dev/tsconfig': link:../../config-packages/tsconfig @@ -487,6 +493,7 @@ importers: packages/trigger-sdk: specifiers: + '@trigger.dev/common-schemas': workspace:* '@trigger.dev/tsconfig': workspace:* '@types/debug': ^4.1.7 '@types/node': ^18.11.9 @@ -508,6 +515,7 @@ importers: ws: 8.11.0 zod: 3.20.2 devDependencies: + '@trigger.dev/common-schemas': link:../common-schemas '@trigger.dev/tsconfig': link:../../config-packages/tsconfig '@types/debug': 4.1.7 '@types/node': 18.11.11 @@ -2873,13 +2881,12 @@ packages: '@lezer/common': 0.16.1 dev: false - /@codemirror/autocomplete/6.3.4_jvia4rcxqiacrvood3734bhyuy: + /@codemirror/autocomplete/6.3.4_4npvozs3agsv66jx2b7pfvr53q: resolution: {integrity: sha512-irxKsTSjS0OkfMWWt9YxtNK97++/E+XIHfKnRpSVfZyHzda/amYF0BR+T8mMkrGQWidx2zApxHx08GT13egyQA==} peerDependencies: '@codemirror/language': ^6.0.0 '@codemirror/state': ^6.0.0 '@codemirror/view': ^6.0.0 - '@lezer/common': ^1.0.0 dependencies: '@codemirror/language': 6.3.1 '@codemirror/state': 6.1.4 @@ -2929,7 +2936,7 @@ packages: /@codemirror/lang-javascript/6.1.1: resolution: {integrity: sha512-F4+kiuC5d5dUSJmff96tJQwpEXs/tX/4bapMRnZWW6bHKK1Fx6MunTzopkCUWRa9bF87GPmb9m7Qtg7Yv8f3uQ==} dependencies: - '@codemirror/autocomplete': 6.3.4_jvia4rcxqiacrvood3734bhyuy + '@codemirror/autocomplete': 6.3.4_4npvozs3agsv66jx2b7pfvr53q '@codemirror/language': 6.3.1 '@codemirror/lint': 6.1.0 '@codemirror/state': 6.1.4 @@ -3092,6 +3099,7 @@ packages: engines: {node: '>=12'} dependencies: '@jridgewell/trace-mapping': 0.3.9 + dev: true /@cush/relative/1.0.0: resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==} @@ -3323,6 +3331,7 @@ packages: /@jridgewell/resolve-uri/3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} + dev: true /@jridgewell/set-array/1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} @@ -3331,6 +3340,7 @@ packages: /@jridgewell/sourcemap-codec/1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + dev: true /@jridgewell/trace-mapping/0.3.17: resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} @@ -3344,6 +3354,7 @@ packages: dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + dev: true /@jsonhero/codemirror-lang-inline-tokens/0.1.0: resolution: {integrity: sha512-nbvaQBSJbLjckdA2HbkiiXXTpAMrjyzDzxymFfAmgSNHNo+GC6e0RjQDWKyDKFEQZCd3s02SQ17ipFA5FVnkfg==} @@ -3734,7 +3745,7 @@ packages: eslint: 8.29.0 eslint-import-resolver-node: 0.3.6 eslint-import-resolver-typescript: 3.5.2_lt3hqehuojhfcbzgzqfngbtmrq - eslint-plugin-import: 2.26.0_i656iqvetrvx3ajhg4t6psfrl4 + eslint-plugin-import: 2.26.0_qfsg7upu5e4dqco5ntekgyqxwu eslint-plugin-jest: 26.9.0_gtacs36c3cng3fu32eiajkw5qm eslint-plugin-jest-dom: 4.0.3_eslint@8.29.0 eslint-plugin-jsx-a11y: 6.6.1_eslint@8.29.0 @@ -4085,6 +4096,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: true optional: true /@swc/core-darwin-x64/1.3.21: @@ -4093,6 +4105,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: true optional: true /@swc/core-linux-arm-gnueabihf/1.3.21: @@ -4101,6 +4114,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: true optional: true /@swc/core-linux-arm64-gnu/1.3.21: @@ -4109,6 +4123,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: true optional: true /@swc/core-linux-arm64-musl/1.3.21: @@ -4117,6 +4132,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: true optional: true /@swc/core-linux-x64-gnu/1.3.21: @@ -4125,6 +4141,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: true optional: true /@swc/core-linux-x64-musl/1.3.21: @@ -4133,6 +4150,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: true optional: true /@swc/core-win32-arm64-msvc/1.3.21: @@ -4141,6 +4159,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: true optional: true /@swc/core-win32-ia32-msvc/1.3.21: @@ -4149,6 +4168,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: true optional: true /@swc/core-win32-x64-msvc/1.3.21: @@ -4157,6 +4177,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: true optional: true /@swc/core/1.3.21: @@ -4175,6 +4196,7 @@ packages: '@swc/core-win32-arm64-msvc': 1.3.21 '@swc/core-win32-ia32-msvc': 1.3.21 '@swc/core-win32-x64-msvc': 1.3.21 + dev: true /@swc/helpers/0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} @@ -4202,7 +4224,7 @@ packages: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.1.8_v776zzvn44o7tpgzieipaairwm + tailwindcss: 3.1.8_postcss@8.4.19 /@tailwindcss/typography/0.5.8_tailwindcss@3.1.8: resolution: {integrity: sha512-xGQEp8KXN8Sd8m6R4xYmwxghmswrd0cPnNI2Lc6fmrC3OojysTBJJGSIVwPV56q4t6THFUK3HJ0EaWwpglSxWw==} @@ -4213,7 +4235,7 @@ packages: lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.1.8_v776zzvn44o7tpgzieipaairwm + tailwindcss: 3.1.8_postcss@8.4.19 dev: true /@tanstack/react-table/8.7.0_biqbaboplfbrettd7655fr4n2y: @@ -4303,15 +4325,19 @@ packages: /@tsconfig/node10/1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: true /@tsconfig/node12/1.0.11: resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true /@tsconfig/node14/1.0.3: resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true /@tsconfig/node16/1.0.3: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} + dev: true /@types/acorn/4.0.6: resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} @@ -4556,6 +4582,7 @@ packages: /@types/node/18.11.15: resolution: {integrity: sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==} + dev: true /@types/node/8.10.66: resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} @@ -4812,13 +4839,12 @@ packages: eslint-visitor-keys: 3.3.0 dev: true - /@uiw/codemirror-extensions-basic-setup/4.17.1_ahlr5jha6gxy5y2f2whv3jw24q: + /@uiw/codemirror-extensions-basic-setup/4.17.1_wq4lmc3co73jmz4wylu22jt6hu: resolution: {integrity: sha512-lFH3gFPcpKDckaioYL2KonTYeeoP7gGtaDtDai7DV5UVEyuVPlkGukKCmHz6u0ol/Krs/RTbF4ylt8cDlBT1uA==} peerDependencies: '@codemirror/autocomplete': '>=6.0.0' '@codemirror/commands': '>=6.0.0' '@codemirror/language': '>=6.0.0' - '@codemirror/lint': '>=6.0.0' '@codemirror/search': '>=6.0.0' '@codemirror/state': '>=6.0.0' '@codemirror/view': '>=6.0.0' @@ -4832,14 +4858,11 @@ packages: '@codemirror/view': 0.20.7 dev: false - /@uiw/react-codemirror/4.17.1_4ysryuwswq2dahvwdlnde5nvpq: + /@uiw/react-codemirror/4.17.1_xtrn3tyimkzpilanhyvm2ls4eu: resolution: {integrity: sha512-ah7wFhvVW/uKbQR5D12AqDK51XGZaZI1WYO9/sraZzq32TGphL5BU3vcQd1P0YEZR6YLc23+KWNi2DCQ+EEAbA==} peerDependencies: - '@babel/runtime': '>=7.11.0' '@codemirror/state': '>=6.0.0' - '@codemirror/theme-one-dark': '>=6.0.0' '@codemirror/view': '>=6.0.0' - codemirror: '>=6.0.0' react: '>=16.8.0' react-dom: '>=16.8.0' dependencies: @@ -4848,14 +4871,13 @@ packages: '@codemirror/state': 0.20.1 '@codemirror/theme-one-dark': 6.1.0 '@codemirror/view': 0.20.7 - '@uiw/codemirror-extensions-basic-setup': 4.17.1_ahlr5jha6gxy5y2f2whv3jw24q - codemirror: 6.0.1_@lezer+common@1.0.2 + '@uiw/codemirror-extensions-basic-setup': 4.17.1_wq4lmc3co73jmz4wylu22jt6hu + codemirror: 6.0.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 transitivePeerDependencies: - '@codemirror/autocomplete' - '@codemirror/language' - - '@codemirror/lint' - '@codemirror/search' dev: false @@ -4949,6 +4971,7 @@ packages: /acorn-walk/8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} + dev: true /acorn/7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} @@ -4959,6 +4982,7 @@ packages: resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /agent-base/4.2.1: resolution: {integrity: sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==} @@ -5087,6 +5111,7 @@ packages: /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true /arg/5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -5981,18 +6006,16 @@ packages: engines: {node: '>=0.10.0'} dev: false - /codemirror/6.0.1_@lezer+common@1.0.2: + /codemirror/6.0.1: resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} dependencies: - '@codemirror/autocomplete': 6.3.4_jvia4rcxqiacrvood3734bhyuy + '@codemirror/autocomplete': 6.3.4_4npvozs3agsv66jx2b7pfvr53q '@codemirror/commands': 6.1.2 '@codemirror/language': 6.3.1 '@codemirror/lint': 6.1.0 '@codemirror/search': 6.2.3 '@codemirror/state': 6.1.4 '@codemirror/view': 6.6.0 - transitivePeerDependencies: - - '@lezer/common' dev: false /collection-visit/1.0.0: @@ -6158,6 +6181,7 @@ packages: /create-require/1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true /crelt/1.0.5: resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==} @@ -6592,6 +6616,7 @@ packages: /diff/4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} + dev: true /diff/5.1.0: resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} @@ -7294,7 +7319,7 @@ packages: debug: 4.3.4 enhanced-resolve: 5.12.0 eslint: 8.29.0 - eslint-plugin-import: 2.26.0_i656iqvetrvx3ajhg4t6psfrl4 + eslint-plugin-import: 2.26.0_qfsg7upu5e4dqco5ntekgyqxwu get-tsconfig: 4.2.0 globby: 13.1.2 is-core-module: 2.11.0 @@ -7334,7 +7359,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_jnakocfte2jywffz4vixv5kpsq: + /eslint-module-utils/2.7.4_wbv6cezew2qbikiravago3ef2u: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -7359,6 +7384,7 @@ packages: debug: 3.2.7 eslint: 8.29.0 eslint-import-resolver-node: 0.3.6 + eslint-import-resolver-typescript: 3.5.2_lt3hqehuojhfcbzgzqfngbtmrq transitivePeerDependencies: - supports-color dev: true @@ -7414,7 +7440,7 @@ packages: - supports-color dev: true - /eslint-plugin-import/2.26.0_i656iqvetrvx3ajhg4t6psfrl4: + /eslint-plugin-import/2.26.0_qfsg7upu5e4dqco5ntekgyqxwu: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -7431,7 +7457,7 @@ packages: doctrine: 2.1.0 eslint: 8.29.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_jnakocfte2jywffz4vixv5kpsq + eslint-module-utils: 2.7.4_wbv6cezew2qbikiravago3ef2u has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -10042,6 +10068,7 @@ packages: /make-error/1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true /map-cache/0.2.2: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} @@ -11470,7 +11497,6 @@ packages: lilconfig: 2.0.6 postcss: 8.4.19 yaml: 1.10.2 - dev: true /postcss-load-config/3.1.4_v776zzvn44o7tpgzieipaairwm: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} @@ -11488,6 +11514,7 @@ packages: postcss: 8.4.19 ts-node: 10.9.1_fww2c4adio7pltl52sxaeea2ii yaml: 1.10.2 + dev: true /postcss-nested/5.0.6_postcss@8.4.19: resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} @@ -13149,7 +13176,6 @@ packages: resolve: 1.22.1 transitivePeerDependencies: - ts-node - dev: true /tailwindcss/3.1.8_v776zzvn44o7tpgzieipaairwm: resolution: {integrity: sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==} @@ -13182,6 +13208,7 @@ packages: resolve: 1.22.1 transitivePeerDependencies: - ts-node + dev: true /tapable/2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -13449,6 +13476,7 @@ packages: typescript: 4.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + dev: true /ts-toolbelt/9.6.0: resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} @@ -13703,6 +13731,11 @@ packages: hasBin: true dev: true + /ulid/2.3.0: + resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==} + hasBin: true + dev: false + /unbox-primitive/1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -13940,6 +13973,7 @@ packages: /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true /v8-to-istanbul/9.0.1: resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} @@ -14393,6 +14427,7 @@ packages: /yn/3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} + dev: true /yocto-queue/0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}