Getting slack/chat.postMessage to work
- Added ability for integrations to cache values - Integrations now determine if a request is retryable - Retried requests are now scheduled with a delay
This commit is contained in:
@@ -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<typeof EnvironmentSchema>;
|
||||
|
||||
@@ -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<void> {
|
||||
if (ttl) {
|
||||
await redis.set(`${this.namespace}:${key}`, value, "EX", ttl);
|
||||
} else {
|
||||
await redis.set(`${this.namespace}:${key}`, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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 };
|
||||
@@ -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",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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<boolean> {
|
||||
async call(id: string): Promise<CallResponse> {
|
||||
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<NormalizedResponse> {
|
||||
integrationRequest: IntegrationRequest,
|
||||
cache: CacheService
|
||||
): Promise<PerformedRequestResponse> {
|
||||
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}`);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
icon: /integrations/slack.png
|
||||
scopes:
|
||||
- channels:read
|
||||
- channels:join
|
||||
- chat:write
|
||||
environments:
|
||||
development:
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -122,7 +122,7 @@ model Workflow {
|
||||
rules EventRule[]
|
||||
externalServices ExternalService[]
|
||||
|
||||
service String @default("trigger")
|
||||
service String @default("trigger")
|
||||
eventNames String[]
|
||||
|
||||
@@unique([organizationId, slug])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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<TResponseSchema extends z.ZodTypeAny> =
|
||||
| {
|
||||
success: true;
|
||||
statusCode: number;
|
||||
headers: Record<string, string>;
|
||||
data: z.infer<TResponseSchema>;
|
||||
}
|
||||
| {
|
||||
success: false;
|
||||
statusCode: number;
|
||||
headers: Record<string, string>;
|
||||
};
|
||||
|
||||
export class HttpService {
|
||||
constructor(private readonly options: HttpServiceOptions) {}
|
||||
|
||||
async performRequest<
|
||||
TResponseSchema extends z.ZodTypeAny,
|
||||
TBodySchema extends z.ZodTypeAny = z.ZodUndefined
|
||||
>(
|
||||
endpoint: HttpEndpoint<TResponseSchema, TBodySchema>,
|
||||
body?: z.infer<TBodySchema>
|
||||
): Promise<HttpResponse<TResponseSchema>> {
|
||||
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<TResponseSchema, TBodySchema>
|
||||
) {}
|
||||
}
|
||||
@@ -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<NormalizedResponse> {
|
||||
#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<PerformedRequestResponse> {
|
||||
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<NormalizedResponse> {
|
||||
params: any,
|
||||
cache?: CacheService
|
||||
): Promise<PerformedRequestResponse> {
|
||||
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<string | undefined> {
|
||||
service: HttpService,
|
||||
channel: string,
|
||||
cache?: CacheService
|
||||
): Promise<string> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
]);
|
||||
|
||||
@@ -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<NormalizedResponse>;
|
||||
perform: (
|
||||
options: PerformRequestOptions
|
||||
) => Promise<PerformedRequestResponse>;
|
||||
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<string | null>;
|
||||
set: (key: string, value: string, ttl?: number) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -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<TPubSubSchema extends MessageCatalogSchema> = {
|
||||
@@ -65,8 +65,9 @@ export class ZodPubSub<TPubSubSchema extends MessageCatalogSchema> {
|
||||
public async publish<K extends keyof TPubSubSchema>(
|
||||
type: K,
|
||||
data: z.infer<TPubSubSchema[K]["data"]>,
|
||||
properties?: z.infer<TPubSubSchema[K]["properties"]>
|
||||
properties?: z.infer<TPubSubSchema[K]["properties"]>,
|
||||
options?: PublishOptions
|
||||
): Promise<string | undefined> {
|
||||
return this.#publisher.publish(type, data, properties);
|
||||
return this.#publisher.publish(type, data, properties, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@ import { ulid } from "ulid";
|
||||
|
||||
import { z, ZodError } from "zod";
|
||||
|
||||
export type PublishOptions = {
|
||||
deliverAfter?: number;
|
||||
deliverAt?: number;
|
||||
};
|
||||
|
||||
export type ZodPublisherOptions<PublisherSchema extends MessageCatalogSchema> =
|
||||
{
|
||||
client: PulsarClient;
|
||||
@@ -57,14 +62,15 @@ export class ZodPublisher<PublisherSchema extends MessageCatalogSchema> {
|
||||
public async publish<K extends keyof PublisherSchema>(
|
||||
type: K,
|
||||
data: z.infer<PublisherSchema[K]["data"]>,
|
||||
properties?: z.infer<PublisherSchema[K]["properties"]>
|
||||
properties?: z.infer<PublisherSchema[K]["properties"]>,
|
||||
options?: PublishOptions
|
||||
): Promise<string | undefined> {
|
||||
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<PublisherSchema extends MessageCatalogSchema> {
|
||||
async #handlePublish<K extends keyof PublisherSchema>(
|
||||
type: K,
|
||||
data: z.infer<PublisherSchema[K]["data"]>,
|
||||
properties?: z.infer<PublisherSchema[K]["properties"]>
|
||||
properties?: z.infer<PublisherSchema[K]["properties"]>,
|
||||
options?: PublishOptions
|
||||
): Promise<string> {
|
||||
const messageSchema = this.#schema[type];
|
||||
|
||||
@@ -112,6 +119,8 @@ export class ZodPublisher<PublisherSchema extends MessageCatalogSchema> {
|
||||
const response = await this.#producer!.send({
|
||||
data: Buffer.from(message),
|
||||
properties: parsedProperties,
|
||||
deliverAfter: options?.deliverAfter,
|
||||
deliverAt: options?.deliverAt,
|
||||
});
|
||||
|
||||
return response.toString();
|
||||
|
||||
Generated
+55
-84
@@ -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==}
|
||||
|
||||
+33
-12
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user