diff --git a/apps/webapp/app/env.server.ts b/apps/webapp/app/env.server.ts index dda3ceda7..f5ba10a26 100644 --- a/apps/webapp/app/env.server.ts +++ b/apps/webapp/app/env.server.ts @@ -30,6 +30,7 @@ const EnvironmentSchema = z.object({ .string() .default("0") .transform((v) => v === "1"), + REDIS_URL: z.string().default("redis://localhost:6379"), }); export type Environment = z.infer; diff --git a/apps/webapp/app/services/cacheService.server.ts b/apps/webapp/app/services/cacheService.server.ts new file mode 100644 index 000000000..5e5f1a063 --- /dev/null +++ b/apps/webapp/app/services/cacheService.server.ts @@ -0,0 +1,18 @@ +import type { CacheService } from "internal-integrations"; +import { redis } from "./redis.server"; + +export class RedisCacheService implements CacheService { + constructor(private readonly namespace: string) {} + + async get(key: string) { + return redis.get(`${this.namespace}:${key}`); + } + + async set(key: string, value: string, ttl?: number): Promise { + if (ttl) { + await redis.set(`${this.namespace}:${key}`, value, "EX", ttl); + } else { + await redis.set(`${this.namespace}:${key}`, value); + } + } +} diff --git a/apps/webapp/app/services/messageBroker.server.ts b/apps/webapp/app/services/messageBroker.server.ts index 0eada19c4..673abf407 100644 --- a/apps/webapp/app/services/messageBroker.server.ts +++ b/apps/webapp/app/services/messageBroker.server.ts @@ -236,9 +236,22 @@ async function createRequestPubSub() { PERFORM_INTEGRATION_REQUEST: async (id, data, properties) => { const service = new PerformIntegrationRequest(); - const success = await service.call(data.id); + const response = await service.call(data.id); - return success; + if (response.stop) { + return true; + } else { + await pubSub.publish( + "PERFORM_INTEGRATION_REQUEST", + { + id: data.id, + }, + {}, + { deliverAfter: response.retryInSeconds * 1000 } + ); + + return true; + } }, }, }); diff --git a/apps/webapp/app/services/redis.server.ts b/apps/webapp/app/services/redis.server.ts new file mode 100644 index 000000000..7d46e969e --- /dev/null +++ b/apps/webapp/app/services/redis.server.ts @@ -0,0 +1,23 @@ +import type { Redis as RedisType } from "ioredis"; +import Redis from "ioredis"; +import { env } from "~/env.server"; + +let redis: RedisType; + +declare global { + var __redis: RedisType | undefined; +} + +// this is needed because in development we don't want to restart +// the server with every change, but we want to make sure we don't +// create a new connection to the Redis with every change either. +if (process.env.NODE_ENV === "production") { + redis = new Redis(env.REDIS_URL); +} else { + if (!global.__redis) { + global.__redis = new Redis(env.REDIS_URL); + } + redis = global.__redis; +} + +export { redis }; diff --git a/apps/webapp/app/services/requests/createIntegrationRequest.server.ts b/apps/webapp/app/services/requests/createIntegrationRequest.server.ts index 3d1f975fe..9f190b6a9 100644 --- a/apps/webapp/app/services/requests/createIntegrationRequest.server.ts +++ b/apps/webapp/app/services/requests/createIntegrationRequest.server.ts @@ -74,6 +74,7 @@ export class CreateIntegrationRequest { service: data.service, type: "HTTP_API", connectionId: existingConnection?.id, + status: existingConnection ? "READY" : "CREATED", }, }); } else { @@ -91,6 +92,7 @@ export class CreateIntegrationRequest { }, data: { connectionId: existingConnection.id, + status: existingConnection ? "READY" : "CREATED", }, }); } diff --git a/apps/webapp/app/services/requests/performIntegrationRequest.server.ts b/apps/webapp/app/services/requests/performIntegrationRequest.server.ts index 9fbb0cc2d..5fcfd2023 100644 --- a/apps/webapp/app/services/requests/performIntegrationRequest.server.ts +++ b/apps/webapp/app/services/requests/performIntegrationRequest.server.ts @@ -1,10 +1,24 @@ -import type { NormalizedResponse } from "internal-integrations"; +import type { + CacheService, + NormalizedResponse, + PerformedRequestResponse, +} from "internal-integrations"; import { slack } from "internal-integrations"; import type { PrismaClient } from "~/db.server"; import { prisma } from "~/db.server"; import type { IntegrationRequest } from "~/models/integrationRequest.server"; +import { RedisCacheService } from "../cacheService.server"; import { pizzly } from "../pizzly.server"; +type CallResponse = + | { + stop: true; + } + | { + stop: false; + retryInSeconds: number; + }; + export class PerformIntegrationRequest { #prismaClient: PrismaClient; @@ -12,7 +26,7 @@ export class PerformIntegrationRequest { this.#prismaClient = prismaClient; } - async call(id: string): Promise { + async call(id: string): Promise { const integrationRequest = await this.#prismaClient.integrationRequest.findUnique({ where: { id }, @@ -26,11 +40,11 @@ export class PerformIntegrationRequest { }); if (!integrationRequest) { - return false; + return { stop: true }; } if (!integrationRequest.externalService.connection) { - return false; + return { stop: true }; } const accessToken = await pizzly.accessToken( @@ -39,34 +53,32 @@ export class PerformIntegrationRequest { ); if (!accessToken) { - return false; + return { stop: true }; } - const response = await this.#performRequest( - integrationRequest.externalService.connection.apiIdentifier, - accessToken, - integrationRequest + const cache = new RedisCacheService( + integrationRequest.externalService.connection.id ); - switch (statusCodeToType(response.statusCode)) { - case "informational": { - return this.#completeWithSuccess(integrationRequest, response); - } - case "success": { - return this.#completeWithSuccess(integrationRequest, response); - } - case "redirect": { - return this.#completeWithFailure(integrationRequest, response); - } - case "clientError": { - return this.#completeWithFailure(integrationRequest, response); - } - case "serverError": { - return this.#attemptRetry(integrationRequest, response); - } - default: { - return this.#unknownError(integrationRequest, response); - } + const performedRequest = await this.#performRequest( + integrationRequest.externalService.connection.apiIdentifier, + accessToken, + integrationRequest, + cache + ); + + if (performedRequest.ok) { + return this.#completeWithSuccess( + integrationRequest, + performedRequest.response + ); + } else if (performedRequest.isRetryable) { + return this.#attemptRetry(integrationRequest, performedRequest.response); + } else { + return this.#completeWithFailure( + integrationRequest, + performedRequest.response + ); } } @@ -100,7 +112,7 @@ export class PerformIntegrationRequest { }, }); - return true; + return { stop: true as const }; } async #completeWithFailure( @@ -133,7 +145,7 @@ export class PerformIntegrationRequest { }, }); - return true; + return { stop: true as const }; } async #attemptRetry( @@ -157,26 +169,39 @@ export class PerformIntegrationRequest { await this.#createResponse(integrationRequest, response); - await this.#prismaClient.integrationRequest.update({ - where: { - id: integrationRequest.id, - }, - data: { - status: "RETRYING", - retryCount: { - increment: 1, + const updatedIntegrationRequest = + await this.#prismaClient.integrationRequest.update({ + where: { + id: integrationRequest.id, }, - }, - }); + data: { + status: "RETRYING", + retryCount: { + increment: 1, + }, + }, + }); - return false; + return { + stop: false as const, + retryInSeconds: this.#calculateRetryInSeconds( + updatedIntegrationRequest.retryCount + ), + }; } - async #unknownError( - integrationRequest: IntegrationRequest, - response: NormalizedResponse + // Exponential backoff with a configurable factor and a configurable maximum + #calculateRetryInSeconds( + retryCount: number, + options: { factor: number; maxTimeout: number; minTimeout: number } = { + factor: 2, + minTimeout: 1000, + maxTimeout: Infinity, + } ) { - return false; + const timeout = options.factor ** retryCount * options.minTimeout; + + return Math.min(timeout, options.maxTimeout); } async #createResponse( @@ -193,7 +218,7 @@ export class PerformIntegrationRequest { }, statusCode: response.statusCode, headers: response.headers, - body: response.body, + body: response.body ? response.body : undefined, }, }); @@ -203,14 +228,16 @@ export class PerformIntegrationRequest { async #performRequest( service: string, accessToken: string, - integrationRequest: IntegrationRequest - ): Promise { + integrationRequest: IntegrationRequest, + cache: CacheService + ): Promise { switch (service) { case "slack": { return slack.requests.perform({ accessToken, endpoint: integrationRequest.endpoint, params: integrationRequest.params, + cache, }); } default: { @@ -219,29 +246,3 @@ export class PerformIntegrationRequest { } } } - -function statusCodeToType( - statusCode: number -): "informational" | "success" | "redirect" | "clientError" | "serverError" { - if (statusCode >= 100 && statusCode < 200) { - return "informational"; - } - - if (statusCode >= 200 && statusCode < 300) { - return "success"; - } - - if (statusCode >= 300 && statusCode < 400) { - return "redirect"; - } - - if (statusCode >= 400 && statusCode < 500) { - return "clientError"; - } - - if (statusCode >= 500 && statusCode < 600) { - return "serverError"; - } - - throw new Error(`Unknown status code: ${statusCode}`); -} diff --git a/apps/webapp/integrations.yml b/apps/webapp/integrations.yml index 0f159a5c8..8cf3db489 100644 --- a/apps/webapp/integrations.yml +++ b/apps/webapp/integrations.yml @@ -15,6 +15,7 @@ icon: /integrations/slack.png scopes: - channels:read + - channels:join - chat:write environments: development: diff --git a/apps/webapp/package.json b/apps/webapp/package.json index d7c29fb06..44ae9755c 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -76,9 +76,10 @@ "date-fns": "2.0.0-alpha.7 || >=2.0.0", "express": "^4.18.1", "humanize-duration": "^3.27.3", + "internal-catalog": "workspace:*", "internal-integrations": "workspace:*", "internal-platform": "workspace:*", - "internal-catalog": "workspace:*", + "ioredis": "^5.2.4", "javascript-time-ago": "^2.5.7", "json-query": "^2.2.2", "jsonata": "^1.8.6", diff --git a/apps/webapp/prisma/schema.prisma b/apps/webapp/prisma/schema.prisma index 2e019abcb..9eb3b5ba0 100644 --- a/apps/webapp/prisma/schema.prisma +++ b/apps/webapp/prisma/schema.prisma @@ -122,7 +122,7 @@ model Workflow { rules EventRule[] externalServices ExternalService[] - service String @default("trigger") + service String @default("trigger") eventNames String[] @@unique([organizationId, slug]) diff --git a/docker-compose.yml b/docker-compose.yml index c6325d660..afb61989d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,6 +20,14 @@ services: - database:/var/lib/postgresql/data networks: - app_network + redis: + image: redis:latest + container_name: redis + restart: always + ports: + - "6379:6379" + networks: + - app_network pizzly-server: image: nangohq/pizzly-server:0.4.3 container_name: pizzly-server diff --git a/packages/internal-integrations/package.json b/packages/internal-integrations/package.json index e472f4608..f187def69 100644 --- a/packages/internal-integrations/package.json +++ b/packages/internal-integrations/package.json @@ -7,12 +7,14 @@ "types": "./src/index.ts", "devDependencies": { "@trigger.dev/tsconfig": "workspace:*", + "@types/debug": "^4.1.7", "@types/node": "^18.11.9", "typescript": "^4.9.4" }, "scripts": {}, "dependencies": { "@octokit/webhooks": "^10.4.0", + "debug": "^4.3.4", "zod": "^3.20.2" } } \ No newline at end of file diff --git a/packages/internal-integrations/src/services/index.ts b/packages/internal-integrations/src/services/index.ts new file mode 100644 index 000000000..f8fa1da75 --- /dev/null +++ b/packages/internal-integrations/src/services/index.ts @@ -0,0 +1,116 @@ +import { z } from "zod"; +import { normalizeHeaders } from "../headers"; + +import debug from "debug"; + +const log = debug("trigger:integrations:services"); + +export type HttpServiceOptions = { + accessToken: string; + baseUrl: string; +}; + +export type HttpResponse = + | { + success: true; + statusCode: number; + headers: Record; + data: z.infer; + } + | { + success: false; + statusCode: number; + headers: Record; + }; + +export class HttpService { + constructor(private readonly options: HttpServiceOptions) {} + + async performRequest< + TResponseSchema extends z.ZodTypeAny, + TBodySchema extends z.ZodTypeAny = z.ZodUndefined + >( + endpoint: HttpEndpoint, + body?: z.infer + ): Promise> { + const response = await fetch( + `${this.options.baseUrl}${endpoint.options.path}`, + { + method: endpoint.options.method, + headers: { + Authorization: `Bearer ${this.options.accessToken}`, + "Content-Type": "application/json", + }, + body: body ? JSON.stringify(body) : undefined, + } + ); + + log( + "%s%s response %d", + this.options.baseUrl, + endpoint.options.path, + response.status + ); + + const json = await this.#safeGetJson(response); + + if (json) { + log( + "%s%s response %O", + this.options.baseUrl, + endpoint.options.path, + json + ); + + const parsedJson = endpoint.options.response.safeParse(json); + + if (parsedJson.success) { + return { + success: true, + data: parsedJson.data, + statusCode: response.status, + headers: normalizeHeaders(response.headers), + }; + } + + log( + "response json failed to parse %O, errors: %O", + parsedJson, + parsedJson.error + ); + } + + return { + success: false, + statusCode: response.status, + headers: normalizeHeaders(response.headers), + }; + } + + #safeGetJson = async (response: Response) => { + try { + return await response.json(); + } catch (error) { + return undefined; + } + }; +} + +export type HttpEndpointOptions< + TResponseSchema extends z.ZodTypeAny, + TBodySchema extends z.ZodTypeAny = z.ZodUndefined +> = { + response: TResponseSchema; + body?: TBodySchema; + method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; + path: string; +}; + +export class HttpEndpoint< + TResponseSchema extends z.ZodTypeAny, + TBodySchema extends z.ZodTypeAny = z.ZodUndefined +> { + constructor( + public options: HttpEndpointOptions + ) {} +} diff --git a/packages/internal-integrations/src/slack/index.ts b/packages/internal-integrations/src/slack/index.ts index cfe99858e..cb5bc83d0 100644 --- a/packages/internal-integrations/src/slack/index.ts +++ b/packages/internal-integrations/src/slack/index.ts @@ -1,22 +1,63 @@ -import { normalizeHeaders } from "../headers"; +import { HttpEndpoint, HttpService } from "../services"; import { DisplayProperties, - NormalizedResponse, + CacheService, + PerformedRequestResponse, PerformRequestOptions, RequestIntegration, } from "../types"; -import { PostMessageResponseSchema, PostMessageBodySchema } from "./schemas"; +import { + PostMessageResponseSchema, + PostMessageBodySchema, + JoinConversationResponseSchema, + JoinConversationBodySchema, + ListConversationsResponseSchema, +} from "./schemas"; export const schemas = { PostMessageResponseSchema, PostMessageBodySchema, }; +import debug from "debug"; + +const log = debug("trigger:integrations:slack"); + class SlackRequestIntegration implements RequestIntegration { - perform(options: PerformRequestOptions): Promise { + #joinChannelEndpoint = new HttpEndpoint< + typeof JoinConversationResponseSchema, + typeof JoinConversationBodySchema + >({ + response: JoinConversationResponseSchema, + method: "POST", + path: "/conversations.join", + }); + + #listConversationsEndpoint = new HttpEndpoint({ + response: ListConversationsResponseSchema, + method: "GET", + path: "/conversations.list", + }); + + #postMessageEndpoint = new HttpEndpoint< + typeof PostMessageResponseSchema, + typeof PostMessageBodySchema + >({ + response: PostMessageResponseSchema, + method: "POST", + path: "/chat.postMessage", + }); + + constructor(private readonly baseUrl: string = "https://slack.com/api") {} + + perform(options: PerformRequestOptions): Promise { switch (options.endpoint) { case "chat.postMessage": { - return this.#postMessage(options.accessToken, options.params); + return this.#postMessage( + options.accessToken, + options.params, + options.cache + ); } default: { throw new Error(`Unknown endpoint: ${options.endpoint}`); @@ -45,60 +86,128 @@ class SlackRequestIntegration implements RequestIntegration { async #postMessage( accessToken: string, - params: any - ): Promise { + params: any, + cache?: CacheService + ): Promise { const parsedParams = PostMessageBodySchema.parse(params); - const channelId = await this.#findChannelId( - accessToken, - parsedParams.channel - ); + log("chat.postMessage %O", parsedParams); - const response = await fetch("https://slack.com/api/chat.postMessage", { - method: "POST", - headers: { - Authorization: `Bearer ${accessToken}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - ...parsedParams, - channel: channelId, - }), + const service = new HttpService({ + accessToken, + baseUrl: this.baseUrl, }); - return { - statusCode: response.status, - headers: normalizeHeaders(response.headers), - body: await response.json(), + const channel = await this.#findChannelId( + service, + parsedParams.channel, + cache + ); + + log("found channelId %s", channel); + + const response = await service.performRequest(this.#postMessageEndpoint, { + ...parsedParams, + channel, + }); + + if (!response.success) { + log("chat.postMessage failed %O", response); + + return { + ok: false, + isRetryable: this.#isRetryable(response.statusCode), + response: { + statusCode: response.statusCode, + headers: response.headers, + body: null, + }, + }; + } + + if (!response.data.ok && response.data.error === "not_in_channel") { + log( + "chat.postMessage failed with not_in_channel, attempting to join channel %s", + channel + ); + + // Attempt to join the channel, and then retry the request + const joinResponse = await service.performRequest( + this.#joinChannelEndpoint, + { + channel, + } + ); + + if (joinResponse.success && joinResponse.data.ok) { + log("joined channel %s, retrying postMessage", channel); + + return this.#postMessage(accessToken, params); + } + } + + const ok = response.data.ok; + + const performedRequest = { + ok, + isRetryable: this.#isRetryable(response.statusCode), + response: { + statusCode: response.statusCode, + headers: response.headers, + body: response.data, + }, }; + + log("chat.postMessage performedRequest %O", performedRequest); + + return performedRequest; + } + + #isRetryable(statusCode: number): boolean { + return ( + statusCode === 408 || + statusCode === 429 || + statusCode === 500 || + statusCode === 502 || + statusCode === 503 || + statusCode === 504 + ); } // Will use the conversations.list API (using fetch) to find the channel ID // unless the channel is already provided in the format of a channelID (for example: "D8572TUFR" or "C01BQJZLJGZ") async #findChannelId( - accessToken: string, - channel: string - ): Promise { + service: HttpService, + channel: string, + cache?: CacheService + ): Promise { if (channel.startsWith("C") || channel.startsWith("D")) { return channel; } - const response = await fetch("https://slack.com/api/conversations.list", { - method: "GET", - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }); + const cachedChannelId = await cache?.get(channel); - if (!response.ok) { - throw new Error("Failed to fetch channels"); + if (cachedChannelId) { + return cachedChannelId; } - const { channels } = await response.json(); + const response = await service.performRequest( + this.#listConversationsEndpoint + ); - const channelInfo = channels.find((c: any) => c.name === channel); + if (response.success && response.data.ok) { + const { channels } = response.data; - return channelInfo?.id; + const channelInfo = channels.find((c: any) => c.name === channel); + + if (channelInfo) { + await cache?.set(channel, channelInfo.id, 60 * 60 * 24); + } + + return channelInfo?.id || channel; + } + + return channel; } } diff --git a/packages/internal-integrations/src/slack/schemas.ts b/packages/internal-integrations/src/slack/schemas.ts index 6aa8fa898..b2d0134fd 100644 --- a/packages/internal-integrations/src/slack/schemas.ts +++ b/packages/internal-integrations/src/slack/schemas.ts @@ -1,21 +1,62 @@ import { z } from "zod"; -export const PostMessageResponseSchema = z.object({ - ok: z.boolean(), +export const PostMessageSuccessResponseSchema = z.object({ + ok: z.literal(true), channel: z.string(), ts: z.string(), message: z.object({ text: z.string(), - username: z.string(), + user: z.string(), bot_id: z.string(), - attachments: z.array(z.unknown()), + attachments: z.array(z.unknown()).optional(), type: z.string(), - subtype: z.string(), + subtype: z.string().optional(), ts: z.string(), }), }); +export const ErrorResponseSchema = z.object({ + ok: z.literal(false), + error: z.string(), +}); + +export const PostMessageResponseSchema = z.discriminatedUnion("ok", [ + PostMessageSuccessResponseSchema, + ErrorResponseSchema, +]); + export const PostMessageBodySchema = z.object({ channel: z.string(), text: z.string(), }); + +export const JoinConversationSuccessResponseSchema = z.object({ + ok: z.literal(true), + channel: z.object({ + id: z.string(), + }), +}); + +export const JoinConversationResponseSchema = z.discriminatedUnion("ok", [ + JoinConversationSuccessResponseSchema, + ErrorResponseSchema, +]); + +export const JoinConversationBodySchema = z.object({ + channel: z.string(), +}); + +export const ListConversationsSuccessResponseSchema = z.object({ + ok: z.literal(true), + channels: z.array( + z.object({ + id: z.string(), + name: z.string(), + }) + ), +}); + +export const ListConversationsResponseSchema = z.discriminatedUnion("ok", [ + ListConversationsSuccessResponseSchema, + ErrorResponseSchema, +]); diff --git a/packages/internal-integrations/src/types.ts b/packages/internal-integrations/src/types.ts index 5963391e1..b41896f79 100644 --- a/packages/internal-integrations/src/types.ts +++ b/packages/internal-integrations/src/types.ts @@ -33,6 +33,7 @@ export type PerformRequestOptions = { accessToken: string; endpoint: string; params: any; + cache?: CacheService; }; export type DisplayProperties = { @@ -40,8 +41,16 @@ export type DisplayProperties = { properties?: { key: string; value: string | number | boolean }[]; }; +export interface PerformedRequestResponse { + response: NormalizedResponse; + isRetryable: boolean; + ok: boolean; +} + export interface RequestIntegration { - perform: (options: PerformRequestOptions) => Promise; + perform: ( + options: PerformRequestOptions + ) => Promise; displayProperties: (endpoint: string, params: any) => DisplayProperties; } @@ -55,3 +64,8 @@ export interface WebhookIntegration { | { status: "ignored"; reason: string } | { status: "error"; error: string }; } + +export interface CacheService { + get: (key: string) => Promise; + set: (key: string, value: string, ttl?: number) => Promise; +} diff --git a/packages/internal-platform/src/messages/zodPubSub.ts b/packages/internal-platform/src/messages/zodPubSub.ts index 319e1ac91..14f5be104 100644 --- a/packages/internal-platform/src/messages/zodPubSub.ts +++ b/packages/internal-platform/src/messages/zodPubSub.ts @@ -6,7 +6,7 @@ import { import { MessageCatalogSchema } from "./messageCatalogSchema"; import { z } from "zod"; -import { ZodPublisher } from "./zodPublisher"; +import { PublishOptions, ZodPublisher } from "./zodPublisher"; import { ZodSubscriber, ZodSubscriberHandlers } from "./zodSubscriber"; export type ZodPubSubOptions = { @@ -65,8 +65,9 @@ export class ZodPubSub { public async publish( type: K, data: z.infer, - properties?: z.infer + properties?: z.infer, + options?: PublishOptions ): Promise { - return this.#publisher.publish(type, data, properties); + return this.#publisher.publish(type, data, properties, options); } } diff --git a/packages/internal-platform/src/messages/zodPublisher.ts b/packages/internal-platform/src/messages/zodPublisher.ts index 99042a162..bf319eaea 100644 --- a/packages/internal-platform/src/messages/zodPublisher.ts +++ b/packages/internal-platform/src/messages/zodPublisher.ts @@ -9,6 +9,11 @@ import { ulid } from "ulid"; import { z, ZodError } from "zod"; +export type PublishOptions = { + deliverAfter?: number; + deliverAt?: number; +}; + export type ZodPublisherOptions = { client: PulsarClient; @@ -57,14 +62,15 @@ export class ZodPublisher { public async publish( type: K, data: z.infer, - properties?: z.infer + properties?: z.infer, + options?: PublishOptions ): Promise { if (!this.#producer) { throw new Error("Cannot publish before establishing connection"); } try { - return this.#handlePublish(type, data, properties); + return this.#handlePublish(type, data, properties, options); } catch (e) { if (e instanceof ZodError) { this.#logger.error( @@ -81,7 +87,8 @@ export class ZodPublisher { async #handlePublish( type: K, data: z.infer, - properties?: z.infer + properties?: z.infer, + options?: PublishOptions ): Promise { const messageSchema = this.#schema[type]; @@ -112,6 +119,8 @@ export class ZodPublisher { const response = await this.#producer!.send({ data: Buffer.from(message), properties: parsedProperties, + deliverAfter: options?.deliverAfter, + deliverAt: options?.deliverAt, }); return response.toString(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62bad27c6..61eb42f8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,6 +152,7 @@ importers: internal-catalog: workspace:* internal-integrations: workspace:* internal-platform: workspace:* + ioredis: ^5.2.4 javascript-time-ago: ^2.5.7 json-query: ^2.2.2 jsonata: ^1.8.6 @@ -209,7 +210,7 @@ importers: '@aws-sdk/client-s3': 3.226.0 '@aws-sdk/s3-request-presigner': 3.226.0 '@cfworker/json-schema': 1.12.5 - '@codemirror/autocomplete': 6.3.4_jvia4rcxqiacrvood3734bhyuy + '@codemirror/autocomplete': 6.3.4_4npvozs3agsv66jx2b7pfvr53q '@codemirror/commands': 6.1.2 '@codemirror/lang-javascript': 6.1.1 '@codemirror/lang-json': 6.0.1 @@ -235,7 +236,7 @@ importers: '@tailwindcss/forms': 0.5.3_tailwindcss@3.1.8 '@tanstack/react-table': 8.7.0_biqbaboplfbrettd7655fr4n2y '@trigger.dev/common-schemas': link:../../packages/common-schemas - '@uiw/react-codemirror': 4.17.1_c746qxthrd2ism2rvn4crnq5om + '@uiw/react-codemirror': 4.17.1_c6ric56h4625lhpbtenqifztqq bcryptjs: 2.4.3 classnames: 2.3.2 clsx: 1.2.1 @@ -249,6 +250,7 @@ importers: internal-catalog: link:../../packages/internal-catalog internal-integrations: link:../../packages/internal-integrations internal-platform: link:../../packages/internal-platform + ioredis: 5.2.4 javascript-time-ago: 2.5.9 json-query: 2.2.2 jsonata: 1.8.6 @@ -534,14 +536,18 @@ importers: specifiers: '@octokit/webhooks': ^10.4.0 '@trigger.dev/tsconfig': workspace:* + '@types/debug': ^4.1.7 '@types/node': ^18.11.9 + debug: ^4.3.4 typescript: ^4.9.4 zod: ^3.20.2 dependencies: '@octokit/webhooks': 10.4.0 + debug: 4.3.4 zod: 3.20.2 devDependencies: '@trigger.dev/tsconfig': link:../../config-packages/tsconfig + '@types/debug': 4.1.7 '@types/node': 18.11.15 typescript: 4.9.4 @@ -3301,13 +3307,12 @@ packages: resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} dev: true - /@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 @@ -3327,7 +3332,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 @@ -3403,7 +3408,6 @@ packages: engines: {node: '>=12'} dependencies: '@jridgewell/trace-mapping': 0.3.9 - dev: true /@cush/relative/1.0.0: resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==} @@ -3635,7 +3639,6 @@ 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==} @@ -3644,7 +3647,6 @@ 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==} @@ -3658,7 +3660,6 @@ packages: dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 - dev: true /@jsonhero/fetch-hero/0.2.2: resolution: {integrity: sha512-wO+JrqBfQDTtrGbxmAilJFaBLxdfVdeT7lsi+OaTqAv4taCU7aUzsGeDEtYvNF84xo/tCKi8F+YHiXM6k7er9Q==} @@ -4051,7 +4052,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 @@ -4401,7 +4402,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: true optional: true /@swc/core-darwin-x64/1.3.21: @@ -4410,7 +4410,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: true optional: true /@swc/core-linux-arm-gnueabihf/1.3.21: @@ -4419,7 +4418,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-arm64-gnu/1.3.21: @@ -4428,7 +4426,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-arm64-musl/1.3.21: @@ -4437,7 +4434,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-x64-gnu/1.3.21: @@ -4446,7 +4442,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-x64-musl/1.3.21: @@ -4455,7 +4450,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-win32-arm64-msvc/1.3.21: @@ -4464,7 +4458,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: true optional: true /@swc/core-win32-ia32-msvc/1.3.21: @@ -4473,7 +4466,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: true optional: true /@swc/core-win32-x64-msvc/1.3.21: @@ -4482,7 +4474,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: true optional: true /@swc/core/1.3.21: @@ -4501,7 +4492,6 @@ 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==} @@ -4528,7 +4518,7 @@ packages: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.1.8_postcss@8.4.19 + tailwindcss: 3.1.8_v776zzvn44o7tpgzieipaairwm /@tailwindcss/typography/0.5.8_tailwindcss@3.1.8: resolution: {integrity: sha512-xGQEp8KXN8Sd8m6R4xYmwxghmswrd0cPnNI2Lc6fmrC3OojysTBJJGSIVwPV56q4t6THFUK3HJ0EaWwpglSxWw==} @@ -4539,7 +4529,7 @@ packages: lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.1.8_postcss@8.4.19 + tailwindcss: 3.1.8_v776zzvn44o7tpgzieipaairwm dev: true /@tanstack/react-table/8.7.0_biqbaboplfbrettd7655fr4n2y: @@ -4629,19 +4619,15 @@ 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==} @@ -5140,18 +5126,17 @@ packages: eslint-visitor-keys: 3.3.0 dev: true - /@uiw/codemirror-extensions-basic-setup/4.17.1_yoq5blswu3ydocenanojwujrum: + /@uiw/codemirror-extensions-basic-setup/4.17.1_mldjzacanzbudgr2aukt2yvcyy: 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' 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 @@ -5160,14 +5145,11 @@ packages: '@codemirror/view': 6.6.0 dev: false - /@uiw/react-codemirror/4.17.1_c746qxthrd2ism2rvn4crnq5om: + /@uiw/react-codemirror/4.17.1_c6ric56h4625lhpbtenqifztqq: 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: @@ -5176,14 +5158,13 @@ packages: '@codemirror/state': 6.1.4 '@codemirror/theme-one-dark': 6.1.0 '@codemirror/view': 6.6.0 - '@uiw/codemirror-extensions-basic-setup': 4.17.1_yoq5blswu3ydocenanojwujrum - codemirror: 6.0.1_@lezer+common@1.0.2 + '@uiw/codemirror-extensions-basic-setup': 4.17.1_mldjzacanzbudgr2aukt2yvcyy + 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 @@ -5277,7 +5258,6 @@ 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==} @@ -5288,7 +5268,6 @@ 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==} @@ -5416,7 +5395,6 @@ packages: /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true /arg/5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -6305,18 +6283,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: @@ -6487,7 +6463,6 @@ 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==} @@ -6924,7 +6899,6 @@ 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==} @@ -7626,7 +7600,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 @@ -7636,35 +7610,6 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_jnakocfte2jywffz4vixv5kpsq: - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 5.45.1_s5ps7njkmjlaqajutnox5ntcla - debug: 3.2.7 - eslint: 8.29.0 - eslint-import-resolver-node: 0.3.6 - transitivePeerDependencies: - - supports-color - dev: true - /eslint-module-utils/2.7.4_uplb3bqnui63takc5j27khdnpm: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} @@ -7693,6 +7638,36 @@ packages: - supports-color dev: true + /eslint-module-utils/2.7.4_wbv6cezew2qbikiravago3ef2u: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.45.1_s5ps7njkmjlaqajutnox5ntcla + 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 + /eslint-plugin-cypress/2.12.1_eslint@8.29.0: resolution: {integrity: sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==} peerDependencies: @@ -7743,7 +7718,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: @@ -7760,7 +7735,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 @@ -10392,7 +10367,6 @@ packages: /make-error/1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true /map-cache/0.2.2: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} @@ -11834,6 +11808,7 @@ 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==} @@ -11851,7 +11826,6 @@ 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==} @@ -13509,6 +13483,7 @@ packages: resolve: 1.22.1 transitivePeerDependencies: - ts-node + dev: true /tailwindcss/3.1.8_v776zzvn44o7tpgzieipaairwm: resolution: {integrity: sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==} @@ -13541,7 +13516,6 @@ packages: resolve: 1.22.1 transitivePeerDependencies: - ts-node - dev: true /tapable/2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -13808,7 +13782,6 @@ 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==} @@ -14305,7 +14278,6 @@ 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==} @@ -14763,7 +14735,6 @@ 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==} diff --git a/turbo.json b/turbo.json index c158c7aa2..0e70d92be 100644 --- a/turbo.json +++ b/turbo.json @@ -2,7 +2,9 @@ "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "outputs": [ "dist/**", "public/build/**", @@ -12,12 +14,20 @@ ] }, "webapp#start": { - "dependsOn": ["^build"], - "outputs": ["public/build/**"] + "dependsOn": [ + "^build" + ], + "outputs": [ + "public/build/**" + ] }, "start": { - "dependsOn": ["^build"], - "outputs": ["public/build/**"] + "dependsOn": [ + "^build" + ], + "outputs": [ + "public/build/**" + ] }, "db:migrate:deploy": { "outputs": [] @@ -39,7 +49,9 @@ "cache": false }, "generate": { - "dependsOn": ["^generate"] + "dependsOn": [ + "^generate" + ] }, "lint": { "outputs": [] @@ -56,16 +68,22 @@ "cache": false }, "test:e2e:dev": { - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "outputs": [], "cache": false }, "test:e2e:ci": { - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "outputs": [] }, "typecheck": { - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "outputs": [] }, "clean": { @@ -75,7 +93,9 @@ "cache": false } }, - "globalDependencies": [".env"], + "globalDependencies": [ + ".env" + ], "globalEnv": [ "NODE_ENV", "REMIX_APP_PORT", @@ -93,6 +113,7 @@ "MAILGUN_KEY", "FROM_EMAIL", "MERGENT_KEY", - "PIZZLY_HOST" + "PIZZLY_HOST", + "DEBUG" ] -} +} \ No newline at end of file