From 52d21ac84df6d001b904864d9a677b36b662ccdc Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Fri, 27 Jan 2023 10:18:13 +0000 Subject: [PATCH] Added support for delaying delivery when sending custom events --- .changeset/cuddly-ligers-reflect.md | 5 + apps/docs/functions/send-event.mdx | 150 +++++++++++++++- apps/docs/mint.json | 3 +- apps/docs/reference/send-event.mdx | 97 +++++++++++ apps/webapp/app/models/workflowRun.server.ts | 28 ++- .../workflows/$workflowSlug/runs/$runId.tsx | 36 +++- apps/webapp/app/routes/api/v1/events.ts | 23 +-- .../$organizationSlug/test/$workflowSlug.ts | 24 ++- .../events/ingestCustomEvent.server.ts | 60 +++++++ .../app/services/messageBroker.server.ts | 38 +++- apps/webapp/app/utils/json.ts | 7 + apps/webapp/app/utils/objects.ts | 14 ++ examples/smoke-test/src/index.ts | 20 +++ packages/common-schemas/src/events.ts | 18 ++ pnpm-lock.yaml | 162 ------------------ 15 files changed, 475 insertions(+), 210 deletions(-) create mode 100644 .changeset/cuddly-ligers-reflect.md create mode 100644 apps/docs/reference/send-event.mdx create mode 100644 apps/webapp/app/services/events/ingestCustomEvent.server.ts create mode 100644 apps/webapp/app/utils/json.ts create mode 100644 apps/webapp/app/utils/objects.ts diff --git a/.changeset/cuddly-ligers-reflect.md b/.changeset/cuddly-ligers-reflect.md new file mode 100644 index 000000000..5b45f5ba9 --- /dev/null +++ b/.changeset/cuddly-ligers-reflect.md @@ -0,0 +1,5 @@ +--- +"@trigger.dev/sdk": patch +--- + +Added support for delaying delivery when sending custom events diff --git a/apps/docs/functions/send-event.mdx b/apps/docs/functions/send-event.mdx index bb299ac21..9c11909a5 100644 --- a/apps/docs/functions/send-event.mdx +++ b/apps/docs/functions/send-event.mdx @@ -31,7 +31,7 @@ curl --request POST \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ - "id": "", + "id": "", "event": { "name": "user.created", "payload": { @@ -48,12 +48,154 @@ If you are calling this from inside a workflow, ensure that the first parameter ## Sending events from other workflows -It is useful to send events from workflows because you can split your logic into smaller chunks and reuse them. +It is useful to send events from workflows because you can split your logic into smaller chunks and reuse them. The below example shows how a scheduled workflow delegates the work via sending a custom event: -## Writing a workflow that is triggered by an event + -You should read [the documentation on custom events](/triggers/custom-events) to learn how to write a workflow that is triggered by an event. +```ts check-scheduler.ts +new Trigger({ + id: "check-scheduler", + name: "Check Scheduler", + on: scheduleEvent({ rateOf: { minutes: 10 } }), + run: async (event, context) => { + await context.sendEvent("health.check trigger.dev", { + name: "health.check", + payload: { + url: "https://trigger.dev", + host: "trigger.dev", + }, + }); + await context.sendEvent("health.check docs.trigger.dev", { + name: "health.check", + payload: { + url: "https://docs.trigger.dev", + host: "docs.trigger.dev", + }, + }); + + await context.sendEvent("health.check app.trigger.dev", { + name: "health.check", + payload: { + url: "https://app.trigger.dev/healthcheck", + host: "app.trigger.dev", + }, + }); + }, +}).listen(); ``` +```ts health-check.ts +export const healthCheck = new Trigger({ + id: "health-check", + name: "Health Check", + on: customEvent({ + name: "health.check", + schema: z.object({ + url: z.string().url(), + host: z.string(), + }), + }), + run: async (event, context) => { + const response = await context.fetch("fetch site", event.url, { + method: "GET", + retry: { + enabled: false, + }, + }); + + if (response.ok) { + await context.logger.info(`${event.host} is up!`); + return; + } + + await slack.postMessage("Site is down", { + channelName: "health-checks", + text: `${event.host} is down: ${response.status}`, + }); + }, +}).listen(); +``` + + + +## Delaying event delivery + +Through both our Node.js SDK and our HTTP API, you can delay the delivery of an event. This is useful if you want to send an event to trigger a workflow, but you want to wait for a certain amount of time before the event is delivered. + +Using the health check example above, we can delay the delivery of the `health.check` event in various ways: + +```ts +new Trigger({ + id: "check-scheduler", + name: "Check Scheduler", + on: scheduleEvent({ rateOf: { minutes: 10 } }), + run: async (event, context) => { + await context.sendEvent("health.check trigger.dev", { + name: "health.check", + payload: { + url: "https://trigger.dev", + host: "trigger.dev", + }, + delay: { until: new Date(Date.now() + 1000 * 60 * 5) }, // Delay until a specific date + }); + + await context.sendEvent("health.check docs.trigger.dev", { + name: "health.check", + payload: { + url: "https://docs.trigger.dev", + host: "docs.trigger.dev", + }, + delay: { minutes: 5 }, // Delay for a specific amount of time + }); + + await context.sendEvent("health.check app.trigger.dev", { + name: "health.check", + payload: { + url: "https://app.trigger.dev/healthcheck", + host: "app.trigger.dev", + }, + delay: { seconds: 30 }, // Delay for a specific amount of time + }); + }, +}).listen(); +``` + + + When sending events in the context of a workflow run, adding a delay DOES NOT + add a delay to the workflow run, as sending a custom event is a + fire-and-forget action. + + +You can add delays via the HTTP API by adding a `delay` object to the event: + +```bash +curl --request POST \ + --url https://app.trigger.dev/api/v1/events \ + --header 'Authorization: Bearer ' \ + --header 'Content-Type: application/json' \ + --data '{ + "id": "", + "event": { + "name": "user.created", + "payload": { + "userId": "123456" + }, + "delay": { + "seconds": 30 + } + } + }' +``` + +## Event deduplication + +When sending events, you can specify an `id` for the event. If you send an event with the same `id` multiple times, only the first event will be delivered. This is useful if you want to ensure that an event is only delivered once, even if you send it multiple times. + +```ts +sendEvent({ + id: "my-event-id", + name: "my-event", + payload: { foo: "bar" }, +}); ``` diff --git a/apps/docs/mint.json b/apps/docs/mint.json index 41e403a37..9fa5c4b22 100644 --- a/apps/docs/mint.json +++ b/apps/docs/mint.json @@ -111,7 +111,8 @@ "reference/trigger", "reference/custom-event", "reference/webhook-event", - "reference/schedule-event" + "reference/schedule-event", + "reference/send-event" ] }, { diff --git a/apps/docs/reference/send-event.mdx b/apps/docs/reference/send-event.mdx new file mode 100644 index 000000000..06c931d9f --- /dev/null +++ b/apps/docs/reference/send-event.mdx @@ -0,0 +1,97 @@ +--- +title: "sendEvent" +sidebarTitle: "sendEvent" +description: "Send a custom event to Trigger, from inside or outside of a workflow." +--- + +## Usage + +```ts +import { Trigger, customEvent } from "@trigger.dev/sdk"; + +new Trigger({ + id: "usage", + name: "usage", + on: customEvent({ + name: "user.created", + schema: z.any(), + }), + run: async (event, ctx) => { + await ctx.sendEvent("Sending context user.created event", { + name: "user.created", + payload: { + id: "1234_abc", + }, + }); + }, +}).listen(); +``` + +You can also use `sendEvent` by importing it from `@trigger.dev/sdk`: + +```ts +import { sendEvent } from "@trigger.dev/sdk"; + +await sendEvent("Sending context user.created event", { + name: "user.created", + payload: { + id: "1234_abc", + }, +}); +``` + + + If calling `sendEvent` from outside of a workflow run, it will make an HTTP + API request to app.trigger.dev to send the event. Make sure you set the + `TRIGGER_API_KEY` environment variable if you will be using it this way. + + +## Parameters + + + A unique key for the event in the context of a workflow run. Please see the + [Keys and Resumability](/guides/resumability) guide for more info. + + + + + + An optional unique ID for the event. If not provided, one will be + generated automatically (using `clid`). Set this field to perform event + deduplication. + + + + The name of the event. This is the name you set when creating the + `customEvent` trigger. + + + + The payload of the event. + + + + An optional timestamp for the event. If not provided, one will be generated. Must be in ISO 8601 format (e.g. `new Date().toISOString()`) + + + + An optional context object for the event. This can be used to pass + additional information about the event, such as the user who triggered + it. Note that this is not currently exposed to the workflow (coming soon). + + + + An optional delay object for the event. This can be used to delay the + event by a certain amount of time. Use one of the following options: + + - `{ seconds: number }` - delay the event by a certain number of seconds + - `{ minutes: number }` - delay the event by a certain number of minutes + - `{ hours: number }` - delay the event by a certain number of hours + - `{ days: number }` - delay the event by a certain number of days + - `{ until: Date }` - delay the event until a certain date + + See the [Delaying Event Delivery](/functions/send-event#delaying-event-delivery) docs for more info. + + + + diff --git a/apps/webapp/app/models/workflowRun.server.ts b/apps/webapp/app/models/workflowRun.server.ts index 77c5d976b..123c6c9fb 100644 --- a/apps/webapp/app/models/workflowRun.server.ts +++ b/apps/webapp/app/models/workflowRun.server.ts @@ -1,14 +1,16 @@ -import type { WorkflowRun, WorkflowRunStep } from ".prisma/client"; -import type { WorkflowRunStatus } from ".prisma/client"; +import type { + WorkflowRun, + WorkflowRunStatus, + WorkflowRunStep, +} from ".prisma/client"; import type { CustomEventSchema, ErrorSchema, LogMessageSchema, } from "@trigger.dev/common-schemas"; -import { ulid } from "ulid"; import type { z } from "zod"; import { prisma } from "~/db.server"; -import { IngestEvent } from "~/services/events/ingest.server"; +import { IngestCustomEvent } from "~/services/events/ingestCustomEvent.server"; import { createStepOnce } from "./workflowRunStep.server"; export type { WorkflowRun, WorkflowRunStep, WorkflowRunStatus }; @@ -160,20 +162,12 @@ export async function triggerEventInRun( return; } - const ingestService = new IngestEvent(); + const ingestService = new IngestCustomEvent(); - await ingestService.call( - { - id: ulid(), - name: event.name, - type: "CUSTOM_EVENT", - service: "trigger", - payload: event.payload, - context: event.context, - apiKey: workflowRun.environment.apiKey, - }, - workflowRun.environment.organization - ); + await ingestService.call({ + apiKey: workflowRun.environment.apiKey, + event, + }); await prisma.workflowRunStep.update({ where: { id: step.step.id }, diff --git a/apps/webapp/app/routes/__app/orgs/$organizationSlug/workflows/$workflowSlug/runs/$runId.tsx b/apps/webapp/app/routes/__app/orgs/$organizationSlug/workflows/$workflowSlug/runs/$runId.tsx index 6e144aff8..65b3c33ab 100644 --- a/apps/webapp/app/routes/__app/orgs/$organizationSlug/workflows/$workflowSlug/runs/$runId.tsx +++ b/apps/webapp/app/routes/__app/orgs/$organizationSlug/workflows/$workflowSlug/runs/$runId.tsx @@ -9,10 +9,10 @@ import { } from "@heroicons/react/24/outline"; import { ArrowPathRoundedSquareIcon, + ChatBubbleOvalLeftEllipsisIcon, CheckCircleIcon, ExclamationCircleIcon, ExclamationTriangleIcon, - ChatBubbleOvalLeftEllipsisIcon, } from "@heroicons/react/24/solid"; import { useFetcher } from "@remix-run/react"; import type { LoaderArgs } from "@remix-run/server-runtime"; @@ -623,6 +623,40 @@ function CustomEventStep({ event }: { event: StepType }) { {event.input.name} + {"delay" in event.input && event.input.delay && ( + <> + + Delay + + + {"seconds" in event.input.delay ? ( + <> + {event.input.delay.seconds}{" "} + {event.input.delay.seconds > 1 ? "seconds" : "second"} + + ) : "minutes" in event.input.delay ? ( + <> + {event.input.delay.minutes}{" "} + {event.input.delay.minutes > 1 ? "minutes" : "minute"} + + ) : "hours" in event.input.delay ? ( + <> + {event.input.delay.hours}{" "} + {event.input.delay.hours > 1 ? "hours" : "hour"} + + ) : "days" in event.input.delay ? ( + <> + {event.input.delay.days}{" "} + {event.input.delay.days > 1 ? "days" : "day"} + + ) : "until" in event.input.delay ? ( + <>Until {event.input.delay.until} + ) : ( + <> + )} + + + )} Payload {event.input.context && ( diff --git a/apps/webapp/app/routes/api/v1/events.ts b/apps/webapp/app/routes/api/v1/events.ts index 062d6aaf9..7f1ac0c42 100644 --- a/apps/webapp/app/routes/api/v1/events.ts +++ b/apps/webapp/app/routes/api/v1/events.ts @@ -3,7 +3,7 @@ import { json } from "@remix-run/server-runtime"; import { CustomEventSchema } from "@trigger.dev/common-schemas"; import { z } from "zod"; import { authenticateApiRequest } from "~/services/apiAuth.server"; -import { IngestEvent } from "~/services/events/ingest.server"; +import { IngestCustomEvent } from "~/services/events/ingestCustomEvent.server"; const EventBodySchema = z.object({ id: z.string(), @@ -32,20 +32,13 @@ export async function action({ request }: ActionArgs) { return json({ error: eventBody.error.message }, { status: 400 }); } - const service = new IngestEvent(); + const service = new IngestCustomEvent(); - const result = await service.call( - { - id: eventBody.data.id, - name: eventBody.data.event.name, - type: "CUSTOM_EVENT", - service: "trigger", - payload: eventBody.data.event.payload, - context: eventBody.data.event.context, - apiKey: authenticatedEnv.apiKey, - }, - authenticatedEnv.organization - ); + await service.call({ + id: eventBody.data.id, + event: eventBody.data.event, + apiKey: authenticatedEnv.apiKey, + }); - return json(result.data); + return { status: 200 }; } diff --git a/apps/webapp/app/routes/resources/run/$organizationSlug/test/$workflowSlug.ts b/apps/webapp/app/routes/resources/run/$organizationSlug/test/$workflowSlug.ts index 30cd55775..9ddc914c4 100644 --- a/apps/webapp/app/routes/resources/run/$organizationSlug/test/$workflowSlug.ts +++ b/apps/webapp/app/routes/resources/run/$organizationSlug/test/$workflowSlug.ts @@ -13,6 +13,7 @@ import { import { getWorkflowFromSlugs } from "~/models/workflow.server"; import { CreateWorkflowTestRun } from "~/services/runs/createTestRun.server"; import { requireUserId } from "~/services/session.server"; +import { safeJsonParse } from "~/utils/json"; const requestSchema = z.object({ eventName: z.string(), @@ -39,7 +40,15 @@ export const action = async ({ request, params }: ActionArgs) => { const body = Object.fromEntries(formData.entries()); const { eventName, payload, source } = requestSchema.parse(body); - const jsonPayload = JSON.parse(payload); + const jsonPayload = safeJsonParse(payload); + + if (!jsonPayload) { + return redirectWithErrorMessage( + redirectUriForSource(source, organizationSlug, workflowSlug), + request, + "Invalid JSON payload" + ); + } const workflow = await getWorkflowFromSlugs({ userId, @@ -98,6 +107,19 @@ export const action = async ({ request, params }: ActionArgs) => { } }; +function redirectUriForSource( + source: "rerun" | "test", + organizationSlug: string, + workflowSlug: string, + runId?: string +) { + if (source === "rerun") { + return `/orgs/${organizationSlug}/workflows/${workflowSlug}/runs/${runId}`; + } else { + return `/orgs/${organizationSlug}/workflows/${workflowSlug}/test`; + } +} + function errorMessageForSource(source: "rerun" | "test") { if (source === "rerun") { return "Unable to rerun this workflow. Please contact help@trigger.dev for assistance."; diff --git a/apps/webapp/app/services/events/ingestCustomEvent.server.ts b/apps/webapp/app/services/events/ingestCustomEvent.server.ts new file mode 100644 index 000000000..06673e776 --- /dev/null +++ b/apps/webapp/app/services/events/ingestCustomEvent.server.ts @@ -0,0 +1,60 @@ +import type { CustomEventSchema } from "@trigger.dev/common-schemas"; +import type { PublishOptions } from "internal-platform"; +import { ulid } from "ulid"; +import type { z } from "zod"; +import { taskQueue } from "~/services/messageBroker.server"; +import { omit } from "~/utils/objects"; +import { IngestEvent } from "./ingest.server"; + +export type IngestCustomEventOptions = { + id?: string; + apiKey: string; + event: z.infer; + isTest?: boolean; +}; + +export class IngestCustomEvent { + public async call(options: IngestCustomEventOptions) { + if (options.event.delay) { + const deliveryOptions: PublishOptions = + "until" in options.event.delay + ? { deliverAt: new Date(options.event.delay.until).getTime() } + : "seconds" in options.event.delay + ? { deliverAfter: options.event.delay.seconds * 1000 } + : "minutes" in options.event.delay + ? { deliverAfter: options.event.delay.minutes * 60 * 1000 } + : "hours" in options.event.delay + ? { deliverAfter: options.event.delay.hours * 60 * 60 * 1000 } + : "days" in options.event.delay + ? { deliverAfter: options.event.delay.days * 60 * 60 * 24 * 1000 } + : { deliverAfter: 0 }; + + await taskQueue.publish( + "INGEST_DELAYED_EVENT", + { + id: options.id, + apiKey: options.apiKey, + event: omit(options.event, ["delay"]), + }, + {}, + deliveryOptions + ); + + return; + } + + const ingestService = new IngestEvent(); + + await ingestService.call({ + id: options.id ?? ulid(), + name: options.event.name, + type: "CUSTOM_EVENT", + service: "trigger", + payload: options.event.payload, + context: options.event.context, + timestamp: options.event.timestamp, + apiKey: options.apiKey, + isTest: options.isTest, + }); + } +} diff --git a/apps/webapp/app/services/messageBroker.server.ts b/apps/webapp/app/services/messageBroker.server.ts index ddff46a03..1d4f04cc1 100644 --- a/apps/webapp/app/services/messageBroker.server.ts +++ b/apps/webapp/app/services/messageBroker.server.ts @@ -35,7 +35,7 @@ import { InitiateDelay } from "./delays/initiateDelay.server"; import { ResolveDelay } from "./delays/resolveDelay.server"; import { sendEmail } from "./email.server"; import { DispatchEvent } from "./events/dispatch.server"; -import { IngestEvent } from "./events/ingest.server"; +import { IngestCustomEvent } from "./events/ingestCustomEvent.server"; import { HandleNewServiceConnection } from "./externalServices/handleNewConnection.server"; import { RegisterExternalSource } from "./externalSources/registerExternalSource.server"; import { CreateFetchRequest } from "./fetches/createFetchRequest.server"; @@ -51,6 +51,7 @@ import { WorkflowRunDisconnected } from "./runs/runDisconnected.server"; import { WorkflowRunTriggerTimeout } from "./runs/runTriggerTimeout.server"; import { DeliverScheduledEvent } from "./scheduler/deliverScheduledEvent.server"; import { RegisterSchedulerSource } from "./scheduler/registerSchedulerSource.server"; +import { omit } from "~/utils/objects"; let pulsarClient: PulsarClient; let triggerPublisher: ZodPublisher; @@ -374,6 +375,14 @@ const taskQueueCatalog = { data: z.object({ id: z.string() }), properties: z.object({}), }, + INGEST_DELAYED_EVENT: { + data: z.object({ + id: z.string().optional(), + apiKey: z.string(), + event: CustomEventSchema.omit({ delay: true }), + }), + properties: z.object({}), + }, TRIGGER_WORKFLOW_RUN: { data: z.object({ id: z.string() }), properties: z.object({}), @@ -646,6 +655,17 @@ function createTaskQueue() { return true; }, + INGEST_DELAYED_EVENT: async (id, data, properties, attributes) => { + if (attributes.redeliveryCount >= 4) { + return true; + } + + const ingestService = new IngestCustomEvent(); + + await ingestService.call(data); + + return true; + }, TRIGGER_WORKFLOW_RUN: async (id, data, properties) => { const run = await findWorklowRunById(data.id); @@ -690,19 +710,19 @@ function createTaskQueue() { return true; } - const service = new IngestEvent(); + if (!env.INTERNAL_TRIGGER_API_KEY) { + return true; + } - const result = await service.call({ + const service = new IngestCustomEvent(); + + await service.call({ id: data.id, - name: data.name, - type: "CUSTOM_EVENT", - service: "trigger", - payload: data.payload, - context: data.context, + event: omit(data, ["id"]), apiKey: env.INTERNAL_TRIGGER_API_KEY, }); - return result.status === "success"; + return true; }, }, }); diff --git a/apps/webapp/app/utils/json.ts b/apps/webapp/app/utils/json.ts new file mode 100644 index 000000000..2da50949c --- /dev/null +++ b/apps/webapp/app/utils/json.ts @@ -0,0 +1,7 @@ +export function safeJsonParse(json: string): unknown { + try { + return JSON.parse(json); + } catch (e) { + return null; + } +} diff --git a/apps/webapp/app/utils/objects.ts b/apps/webapp/app/utils/objects.ts new file mode 100644 index 000000000..337fba9ca --- /dev/null +++ b/apps/webapp/app/utils/objects.ts @@ -0,0 +1,14 @@ +export function omit, K extends keyof T>( + obj: T, + keys: K[] +): Omit { + const result: any = {}; + + for (const key of Object.keys(obj)) { + if (!keys.includes(key as K)) { + result[key] = obj[key]; + } + } + + return result; +} diff --git a/examples/smoke-test/src/index.ts b/examples/smoke-test/src/index.ts index 62093a8b1..c082e4871 100644 --- a/examples/smoke-test/src/index.ts +++ b/examples/smoke-test/src/index.ts @@ -23,11 +23,13 @@ const trigger = new Trigger({ await ctx.sendEvent("start-fire", { name: "smoke.test", payload: { baz: "banana" }, + delay: { until: new Date(Date.now() + 1000 * 60) }, }); await sendEvent("start-fire-2", { name: "smoke.test2", payload: { baz: "banana2" }, + delay: { minutes: 1 }, }); return { foo: "bar" }; @@ -36,6 +38,24 @@ const trigger = new Trigger({ trigger.listen(); +new Trigger({ + id: "smoke-test", + name: "Smoke Test", + apiKey: "trigger_dev_zC25mKNn6c0q", + endpoint: "ws://localhost:8889/ws", + logLevel: "debug", + on: customEvent({ + name: "smoke.test", + schema: z.object({ baz: z.string() }), + }), + run: async (event, ctx) => { + await ctx.logger.info("Inside the smoke test workflow, received event", { + event, + myDate: new Date(), + }); + }, +}).listen(); + new Trigger({ id: "log-tests", name: "My logs", diff --git a/packages/common-schemas/src/events.ts b/packages/common-schemas/src/events.ts index 5ece38727..37fff268e 100644 --- a/packages/common-schemas/src/events.ts +++ b/packages/common-schemas/src/events.ts @@ -6,6 +6,15 @@ export const CustomEventSchema = z.object({ payload: JsonSchema, context: JsonSchema.optional(), timestamp: z.string().datetime().optional(), + delay: z + .union([ + z.object({ seconds: z.number().int() }), + z.object({ minutes: z.number().int() }), + z.object({ hours: z.number().int() }), + z.object({ days: z.number().int() }), + z.object({ until: z.string().datetime() }), + ]) + .optional(), }); export const SerializableCustomEventSchema = z.object({ @@ -13,6 +22,15 @@ export const SerializableCustomEventSchema = z.object({ payload: SerializableJsonSchema, context: SerializableJsonSchema.optional(), timestamp: z.string().datetime().optional(), + delay: z + .union([ + z.object({ seconds: z.number().int() }), + z.object({ minutes: z.number().int() }), + z.object({ hours: z.number().int() }), + z.object({ days: z.number().int() }), + z.object({ until: z.date() }), + ]) + .optional(), }); const EventMatcherSchema = z.union([ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d061b2ea1..b5ab3ac8c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,33 +35,6 @@ importers: devDependencies: mintlify: 2.0.16 - apps/internal-triggers: - specifiers: - '@trigger.dev/integrations': ^0.1.13 - '@trigger.dev/sdk': ^0.2.10 - '@trigger.dev/tsconfig': workspace:* - '@types/node': '16' - '@types/pg': ^8.6.6 - dotenv: ^16.0.3 - pg: ^8.8.0 - rimraf: ^3.0.2 - tsup: ^6.5.0 - typescript: ^4.9.4 - zod: ^3.20.2 - dependencies: - '@trigger.dev/integrations': 0.1.13 - '@trigger.dev/sdk': 0.2.10 - pg: 8.8.0 - zod: 3.20.2 - devDependencies: - '@trigger.dev/tsconfig': link:../../config-packages/tsconfig - '@types/node': 16.18.11 - '@types/pg': 8.6.6 - dotenv: 16.0.3 - rimraf: 3.0.2 - tsup: 6.5.0_typescript@4.9.4 - typescript: 4.9.4 - apps/webapp: specifiers: '@aws-sdk/client-s3': ^3.186.0 @@ -5412,48 +5385,6 @@ packages: engines: {node: '>= 6'} dev: true - /@trigger.dev/integrations/0.1.13: - resolution: {integrity: sha512-2CfQNGqdC82om8Zr+PAdZZWov5SPAAAuVGV39d/MTNFLHhJZmJx47nbc5nnT/ujPSkoRrvOolwl93rVeceYoYA==} - dependencies: - '@react-email/render': 0.0.3 - '@trigger.dev/providers': 0.1.7 - '@trigger.dev/sdk': 0.2.10 - zod: 3.20.2 - transitivePeerDependencies: - - bufferutil - - encoding - - react - - supports-color - - utf-8-validate - dev: false - - /@trigger.dev/providers/0.1.7: - resolution: {integrity: sha512-wy7bh/bOGNgYbpUOJz59BkFU/0e3U0p7/5rClYY52QgAXZ9Z6c4JfocCqmYRxh+/Lb18N/wUd+vo5V9YfoyeIQ==} - dependencies: - '@shopify/admin-graphql-api-utilities': 2.0.1 - tiny-invariant: 1.3.1 - zod: 3.20.2 - dev: false - - /@trigger.dev/sdk/0.2.10: - resolution: {integrity: sha512-768mZmXi2iLgUfRIKOlpU3q9wRF6anhSnKoToJnRRzyAX3o6Kw5GkBXyM2QVuB5rt6psgbD+M4RKDaTnLpn/wQ==} - dependencies: - debug: 4.3.4 - evt: 2.4.13 - node-fetch: 2.6.7 - slug: 6.1.0 - ulid: 2.3.0 - uuid: 9.0.0 - ws: 8.12.0 - zod: 3.20.2 - zod-error: 1.1.0 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: false - /@tsconfig/node10/1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} @@ -5724,14 +5655,6 @@ packages: /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} - /@types/pg/8.6.6: - resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} - dependencies: - '@types/node': 18.11.18 - pg-protocol: 1.5.0 - pg-types: 2.2.0 - dev: true - /@types/prismjs/1.26.0: resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==} dev: true @@ -6837,11 +6760,6 @@ packages: resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} engines: {node: '>=0.10'} - /buffer-writer/2.0.0: - resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} - engines: {node: '>=4'} - dev: false - /buffer/5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: @@ -13195,10 +13113,6 @@ packages: semver: 6.3.0 dev: true - /packet-reader/1.0.0: - resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} - dev: false - /pako/0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} dev: true @@ -13357,59 +13271,6 @@ packages: is-reference: 3.0.1 dev: true - /pg-connection-string/2.5.0: - resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} - dev: false - - /pg-int8/1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - /pg-pool/3.5.2_pg@8.8.0: - resolution: {integrity: sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==} - peerDependencies: - pg: '>=8.0' - dependencies: - pg: 8.8.0 - dev: false - - /pg-protocol/1.5.0: - resolution: {integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==} - - /pg-types/2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.0 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - - /pg/8.8.0: - resolution: {integrity: sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==} - engines: {node: '>= 8.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - dependencies: - buffer-writer: 2.0.0 - packet-reader: 1.0.0 - pg-connection-string: 2.5.0 - pg-pool: 3.5.2_pg@8.8.0 - pg-protocol: 1.5.0 - pg-types: 2.2.0 - pgpass: 1.0.5 - dev: false - - /pgpass/1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - dependencies: - split2: 4.1.0 - dev: false - /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -13563,24 +13424,6 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /postgres-array/2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - /postgres-bytea/1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} - engines: {node: '>=0.10.0'} - - /postgres-date/1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - /postgres-interval/1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} - dependencies: - xtend: 4.0.2 - /posthog-js/1.39.4: resolution: {integrity: sha512-Elpf1gwyuObueXi89iH+9pP+WhpkiivP8Qwej4RzOLwSTa7Floaa4rgAw7rnCnX1PtRoJ3F0kqb6q9T+aZjRiA==} dependencies: @@ -15112,11 +14955,6 @@ packages: through: 2.3.8 dev: true - /split2/4.1.0: - resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==} - engines: {node: '>= 10.x'} - dev: false - /sprintf-js/1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}