Registering webhooks with existing connections (and github only)

This commit is contained in:
Eric Allam
2022-12-21 16:56:32 +00:00
parent 3d50d24825
commit 67612a8e0c
46 changed files with 1015 additions and 197 deletions
+4
View File
@@ -83,3 +83,7 @@ curl --request POST \
}
}'
```
## Dependency & Package graph
![Dependency Graph](assets/dependencyGraph.png)
+2 -70
View File
@@ -1,71 +1,3 @@
# trigger.dev
# Trigger.dev
## Development
> **Warning**
> All the following commands should be launched from the **monorepo root directory**
1. Install the dependencies.
```bash
pnpm install
```
2. Environment variables. You will need to create copies of the `.env.example` files in `app/webapp`
```sh
cp ./apps/webapp/.env.example ./apps/webapp/.env
```
3. Start postgresql, pulsar, and the pizzly server
```bash
pnpm run docker:db
```
> **Note:** The npm script will complete while Docker sets up the container in the background. Ensure that Docker has finished and your container is running before proceeding.
4. Generate prisma schema
```bash
pnpm run generate
```
5. Run the Prisma migration to the database
```bash
pnpm run db:migrate:deploy
```
6. Run the first build (with dependencies via the `...` option)
```bash
pnpm run build --filter=webapp...
```
**Running simply `pnpm run build` will build everything, including the NextJS app.**
7. Run the Remix dev server
```bash
pnpm run dev --filter=webapp
```
## Tests, Typechecks, Lint, Install packages...
Check the `turbo.json` file to see the available pipelines.
- Run the Cypress tests and Dev
```bash
pnpm run test:e2e:dev --filter=webapp
```
- Lint everything
```bash
pnpm run lint
```
- Typecheck the whole monorepo
```bash
pnpm run typecheck
```
- Test the whole monorepo
```bash
pnpm run test
or
pnpm run test:dev
```
- How to install an npm package in the Remix app ?
```bash
pnpm add dayjs --filter webapp
```
- Tweak the tsconfigs, eslint configs in the `config-package` folder. Any package or app will then extend from these configs.
The developer-first open-source Zapier Alternative
+16 -4
View File
@@ -16,7 +16,7 @@ import {
} from "internal-platform";
import { v4 } from "uuid";
import { WebSocket } from "ws";
import { z } from "zod";
import { z, ZodError } from "zod";
import { TriggerServerConnection } from "./connection";
import { env } from "./env";
import { pulsarClient } from "./pulsarClient";
@@ -282,13 +282,13 @@ export class TriggerServer {
try {
// TODO: do this in a better/safer way
const parsedTrigger = TriggerMetadataSchema.parse(data.trigger);
const trigger = TriggerMetadataSchema.parse(data.trigger);
// register the workflow with the platform
const response = await this.#apiClient.registerWorkflow({
id: data.workflowId,
name: data.workflowName,
trigger: parsedTrigger,
trigger,
package: {
name: data.packageName,
version: data.packageVersion,
@@ -396,7 +396,19 @@ export class TriggerServer {
return true;
} catch (error) {
this.#logger.error("Failed to initialize workflow", error);
if (error instanceof ZodError) {
this.#logger.error(
`Failed to initialize workflow because the trigger is invalid: ${JSON.stringify(
data.trigger
)}`,
error.issues
);
} else {
this.#logger.error(
"Failed to initialize workflow for some unknown reason",
error
);
}
return false;
}
+2
View File
@@ -3,6 +3,7 @@ import { RemixServer } from "@remix-run/react";
import { renderToString } from "react-dom/server";
import * as Sentry from "@sentry/remix";
import * as MessageBroker from "~/services/messageBroker.server";
import * as WebhookProxy from "~/services/webhookProxy.server";
import { prisma } from "./db.server";
export default function handleRequest(
@@ -36,3 +37,4 @@ if (process.env.NODE_ENV === "production" && process.env.SENTRY_DSN) {
}
MessageBroker.init();
WebhookProxy.init();
+2
View File
@@ -30,6 +30,8 @@ const EnvironmentSchema = z.object({
.string()
.default("0")
.transform((v) => v === "1"),
NGROK_AUTH_TOKEN: z.string().optional(),
NGROK_SUBDOMAIN: z.string().optional(),
});
export type Environment = z.infer<typeof EnvironmentSchema>;
@@ -0,0 +1,22 @@
import { prisma } from "~/db.server";
export type RegisteredWebhookWithRelationships = NonNullable<
Awaited<ReturnType<typeof findRegisteredWebhookById>>
>;
export async function findRegisteredWebhookById(id: string) {
return prisma.registeredWebhook.findFirst({
where: {
id,
},
include: {
connectionSlot: {
include: {
connection: true,
},
},
trigger: true,
workflow: true,
},
});
}
@@ -0,0 +1,15 @@
import { prisma } from "~/db.server";
export async function findWorkflowConnectionSlotById(id: string) {
return prisma.workflowConnectionSlot.findFirst({
where: {
id,
},
include: {
connection: true,
workflow: true,
trigger: true,
registeredWebhook: true,
},
});
}
@@ -0,0 +1,36 @@
import type { ActionArgs } from "@remix-run/server-runtime";
import { z } from "zod";
import { findRegisteredWebhookById } from "~/models/registeredWebhook.server";
import { HandleWebhook } from "~/services/webhooks/handleWebhook.server";
export async function action({ request, params }: ActionArgs) {
const { id, serviceIdentifier } = z
.object({ id: z.string(), serviceIdentifier: z.string() })
.parse(params);
const webhook = await findRegisteredWebhookById(id);
if (!webhook) {
return {
status: 404,
body: `Could not find webhook with id ${id} and serviceIdentifier ${serviceIdentifier}`,
};
}
if (webhook.connectionSlot.connection?.apiIdentifier !== serviceIdentifier) {
return { status: 500, body: "Service identifier does not match" };
}
try {
const handleWebhookService = new HandleWebhook();
await handleWebhookService.call(webhook, serviceIdentifier, request);
return { status: 200 };
} catch (error) {
return {
status: 500,
body: error instanceof Error ? error.message : `Unknown error: ${error}`,
};
}
}
@@ -12,6 +12,7 @@ import Pulsar from "pulsar-client";
import { z } from "zod";
import { prisma } from "~/db.server";
import { env } from "~/env.server";
import { findRegisteredWebhookById } from "~/models/registeredWebhook.server";
import {
completeWorkflowRun,
failWorkflowRun,
@@ -20,6 +21,7 @@ import {
startWorkflowRun,
triggerEventInRun,
} from "~/models/workflowRun.server";
import { RegisterWebhook } from "./webhooks/registerWebhook.server";
let pulsarClient: PulsarClient;
let triggerPublisher: ZodPublisher<PlatformCatalog>;
@@ -178,6 +180,10 @@ const InternalCatalog = {
data: CustomEventCreatedEventSchema,
properties: CustomEventCreatedPropertiesSchema,
},
REGISTERED_WEBHOOK_CREATED: {
data: z.object({ id: z.string() }),
properties: z.object({}),
},
};
async function createInternalPubSub() {
@@ -193,6 +199,19 @@ async function createInternalPubSub() {
},
schema: InternalCatalog,
handlers: {
REGISTERED_WEBHOOK_CREATED: async (id, data, properties) => {
const webhook = await findRegisteredWebhookById(data.id);
if (!webhook) {
return true;
}
const registerWebhookService = new RegisterWebhook();
const isRegistered = await registerWebhookService.call(webhook);
return isRegistered; // Returning true will mean we don't retry
},
CUSTOM_EVENT_CREATED: async (id, data, properties) => {
console.log("CUSTOM_EVENT_CREATED", id, data, properties);
@@ -0,0 +1,4 @@
import { Pizzly } from "@nangohq/pizzly-node";
import { env } from "~/env.server";
export const pizzly = new Pizzly(env.PIZZLY_HOST);
@@ -0,0 +1,33 @@
import ngrok from "ngrok";
import { env } from "~/env.server";
let originOrProxyUrl: string;
declare global {
var __origin_or_proxy_url__: string;
}
export async function init() {
if (originOrProxyUrl) {
return;
}
if (env.NODE_ENV === "production" || !env.NGROK_AUTH_TOKEN) {
originOrProxyUrl = env.APP_ORIGIN;
} else {
if (!global.__origin_or_proxy_url__) {
const proxyUrl = await ngrok.connect({
addr: process.env.REMIX_APP_PORT || 3000,
authtoken: env.NGROK_AUTH_TOKEN,
subdomain: env.NGROK_SUBDOMAIN,
});
console.log(`🚧 Initiated Proxy URL: ${proxyUrl} 🚧`);
global.__origin_or_proxy_url__ = proxyUrl;
}
originOrProxyUrl = global.__origin_or_proxy_url__;
}
}
export { originOrProxyUrl };
@@ -0,0 +1,64 @@
import type { PrismaClient } from "~/db.server";
import { prisma } from "~/db.server";
import type { RegisteredWebhookWithRelationships } from "~/models/registeredWebhook.server";
import { github } from "internal-integrations";
export class HandleWebhook {
#prismaClient: PrismaClient;
constructor(prismaClient: PrismaClient = prisma) {
this.#prismaClient = prismaClient;
}
public async call(
webhook: RegisteredWebhookWithRelationships,
serviceIdentifier: string,
request: Request
) {
const requestUrl = new URL(request.url);
const rawSearchParams = requestUrl.searchParams;
const rawBody = await request.json();
const rawHeaders = Object.fromEntries(request.headers.entries());
const webhookEvent = await this.#handleWebhook(
webhook,
serviceIdentifier,
rawBody,
rawHeaders,
rawSearchParams
);
console.log(
`Received webhook event: ${JSON.stringify(webhookEvent, null, 2)}`
);
return true;
}
async #handleWebhook(
webhook: RegisteredWebhookWithRelationships,
serviceIdentifier: string,
rawBody: any,
rawHeaders: Record<string, string>,
rawSearchParams: URLSearchParams
) {
switch (serviceIdentifier) {
case "github": {
return github.webhooks.handleWebhookRequest({
request: {
body: rawBody,
headers: rawHeaders,
searchParams: rawSearchParams,
},
secret: webhook.secret,
params: webhook.connectionSlot.auth,
});
}
default: {
throw new Error(
`Could not handle webhook with unsupported service identifier: ${serviceIdentifier}`
);
}
}
}
}
@@ -0,0 +1,77 @@
import type { PrismaClient } from "~/db.server";
import { prisma } from "~/db.server";
import type { RegisteredWebhookWithRelationships } from "~/models/registeredWebhook.server";
import { github } from "internal-integrations";
import { pizzly } from "../pizzly.server";
import { originOrProxyUrl } from "../webhookProxy.server";
export class RegisterWebhook {
#prismaClient: PrismaClient;
constructor(prismaClient: PrismaClient = prisma) {
this.#prismaClient = prismaClient;
}
public async call(webhook: RegisteredWebhookWithRelationships) {
if (webhook.status === "CONNECTED") {
return true;
}
if (!webhook.connectionSlot || !webhook.connectionSlot.connection) {
return true; // Somehow the connection slot was deleted, so by returning true we're saying we're done with this webhook
}
const accessToken = await pizzly.accessToken(
webhook.connectionSlot.connection.apiIdentifier,
webhook.connectionSlot.connection.id
);
const webhookUrl = `${originOrProxyUrl}/api/v1/internal/webhooks/${webhook.connectionSlot.connection.apiIdentifier}/${webhook.id}`;
const serviceWebhook = await this.#registerWebhookWithConnection(
webhook.connectionSlot.connection.apiIdentifier,
accessToken,
webhookUrl,
webhook.secret,
webhook.connectionSlot.auth
);
await this.#prismaClient.registeredWebhook.update({
where: {
id: webhook.id,
},
data: {
status: "CONNECTED",
webhookConfig: serviceWebhook,
},
});
return true;
}
async #registerWebhookWithConnection(
serviceIdentifier: string,
accessToken: string,
callbackUrl: string,
secret: string,
data: unknown
) {
switch (serviceIdentifier) {
case "github": {
return github.webhooks.registerWebhook(
{
callbackUrl,
secret: secret,
accessToken,
},
data
);
}
default: {
throw new Error(
`Could not register webhook with unsupported service identifier: ${serviceIdentifier}`
);
}
}
}
}
@@ -3,6 +3,8 @@ import type { PrismaClient } from "~/db.server";
import { prisma } from "~/db.server";
import type { Organization } from "~/models/organization.server";
import type { RuntimeEnvironment } from "~/models/runtimeEnvironment.server";
import { internalPubSub } from "~/services/messageBroker.server";
import crypto from "node:crypto";
export class RegisterWorkflow {
#prismaClient: PrismaClient;
@@ -66,6 +68,56 @@ export class RegisterWorkflow {
},
});
if (validation.data.trigger.type === "WEBHOOK") {
const serviceIdentifier = this.#parseServiceIdentifier(
validation.data.trigger.config.id
);
const existingConnection =
await this.#findLatestExistingConnectionInOrg(
serviceIdentifier,
organization
);
// Create the connectionSlot and then fire the connectionSlot created event
const connectionSlot =
await this.#prismaClient.workflowConnectionSlot.create({
data: {
workflowId: workflow.id,
triggerId: trigger.id,
serviceIdentifier,
connectionId: existingConnection?.id,
slotName: "trigger",
auth: validation.data.trigger.config.webhook,
},
});
const webhook = await this.#prismaClient.registeredWebhook.create({
data: {
connectionSlot: {
connect: {
id: connectionSlot.id,
},
},
workflow: {
connect: {
id: trigger.workflowId,
},
},
trigger: {
connect: {
id: trigger.id,
},
},
secret: crypto.randomBytes(32).toString("hex"),
},
});
await internalPubSub.publish("REGISTERED_WEBHOOK_CREATED", {
id: webhook.id,
});
}
return {
status: "success" as const,
data: {
@@ -83,6 +135,79 @@ export class RegisterWorkflow {
},
});
if (validation.data.trigger.type === "WEBHOOK") {
const serviceIdentifier = this.#parseServiceIdentifier(
validation.data.trigger.config.id
);
const existingConnection =
await this.#findLatestExistingConnectionInOrg(
serviceIdentifier,
organization
);
const existingConnectionSlot =
await this.#prismaClient.workflowConnectionSlot.findFirst({
where: {
workflowId: workflow.id,
triggerId: existingTrigger.id,
serviceIdentifier,
},
});
if (existingConnectionSlot) {
await this.#prismaClient.workflowConnectionSlot.update({
where: {
id: existingConnectionSlot.id,
},
data: {
connectionId: existingConnectionSlot.connectionId
? existingConnectionSlot.connectionId
: existingConnection?.id,
auth: validation.data.trigger.config.webhook,
},
});
} else {
// Create the connectionSlot and then fire the connectionSlot created event
const connectionSlot =
await this.#prismaClient.workflowConnectionSlot.create({
data: {
workflowId: workflow.id,
triggerId: existingTrigger.id,
serviceIdentifier,
connectionId: existingConnection?.id,
slotName: "trigger",
auth: validation.data.trigger.config.webhook,
},
});
const webhook = await this.#prismaClient.registeredWebhook.create({
data: {
connectionSlot: {
connect: {
id: connectionSlot.id,
},
},
workflow: {
connect: {
id: existingTrigger.workflowId,
},
},
trigger: {
connect: {
id: existingTrigger.id,
},
},
secret: crypto.randomBytes(32).toString("hex"),
},
});
await internalPubSub.publish("REGISTERED_WEBHOOK_CREATED", {
id: webhook.id,
});
}
}
return {
status: "success" as const,
data: {
@@ -107,4 +232,28 @@ export class RegisterWorkflow {
//todo Workflow has one trigger (can also have a slot with connection)
//todo WorkflowRuns belong to a workflow + environment
}
#parseServiceIdentifier(id: string): string {
const [serviceIdentifier] = id.split(".");
return serviceIdentifier;
}
async #findLatestExistingConnectionInOrg(
serviceIdentifier: string,
organization: Organization
) {
const connection = await this.#prismaClient.aPIConnection.findFirst({
where: {
organizationId: organization.id,
apiIdentifier: serviceIdentifier,
status: "CONNECTED",
},
orderBy: {
createdAt: "desc",
},
});
return connection;
}
}
+2
View File
@@ -81,6 +81,7 @@
"express": "^4.18.1",
"humanize-duration": "^3.27.3",
"internal-platform": "workspace:*",
"internal-integrations": "workspace:*",
"javascript-time-ago": "^2.5.7",
"json-query": "^2.2.2",
"jsonata": "^1.8.6",
@@ -92,6 +93,7 @@
"mergent": "^1.4.0",
"morgan": "^1.10.0",
"nanoid": "^3.3.4",
"ngrok": "^4.3.3",
"openapi-types": "^12.0.0",
"postcss-import": "^14.1.0",
"posthog-js": "^1.31.0",
@@ -0,0 +1,27 @@
-- CreateTable
CREATE TABLE "WorkflowConnectionSlot" (
"id" TEXT NOT NULL,
"workflowId" TEXT NOT NULL,
"triggerId" TEXT,
"connectionId" TEXT,
"slotName" TEXT NOT NULL,
"serviceIdentifier" TEXT NOT NULL,
"auth" JSONB,
CONSTRAINT "WorkflowConnectionSlot_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "WorkflowConnectionSlot_triggerId_key" ON "WorkflowConnectionSlot"("triggerId");
-- CreateIndex
CREATE UNIQUE INDEX "WorkflowConnectionSlot_workflowId_slotName_key" ON "WorkflowConnectionSlot"("workflowId", "slotName");
-- AddForeignKey
ALTER TABLE "WorkflowConnectionSlot" ADD CONSTRAINT "WorkflowConnectionSlot_workflowId_fkey" FOREIGN KEY ("workflowId") REFERENCES "Workflow"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "WorkflowConnectionSlot" ADD CONSTRAINT "WorkflowConnectionSlot_triggerId_fkey" FOREIGN KEY ("triggerId") REFERENCES "WorkflowTrigger"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "WorkflowConnectionSlot" ADD CONSTRAINT "WorkflowConnectionSlot_connectionId_fkey" FOREIGN KEY ("connectionId") REFERENCES "APIConnection"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,29 @@
-- CreateTable
CREATE TABLE "RegisteredWebhook" (
"id" TEXT NOT NULL,
"workflowId" TEXT NOT NULL,
"triggerId" TEXT NOT NULL,
"connectionSlotId" TEXT NOT NULL,
"webhookConfig" JSONB NOT NULL,
"isEnabled" BOOLEAN NOT NULL DEFAULT true,
CONSTRAINT "RegisteredWebhook_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "RegisteredWebhook_triggerId_key" ON "RegisteredWebhook"("triggerId");
-- CreateIndex
CREATE UNIQUE INDEX "RegisteredWebhook_connectionSlotId_key" ON "RegisteredWebhook"("connectionSlotId");
-- CreateIndex
CREATE UNIQUE INDEX "RegisteredWebhook_workflowId_triggerId_key" ON "RegisteredWebhook"("workflowId", "triggerId");
-- AddForeignKey
ALTER TABLE "RegisteredWebhook" ADD CONSTRAINT "RegisteredWebhook_workflowId_fkey" FOREIGN KEY ("workflowId") REFERENCES "Workflow"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "RegisteredWebhook" ADD CONSTRAINT "RegisteredWebhook_triggerId_fkey" FOREIGN KEY ("triggerId") REFERENCES "WorkflowTrigger"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "RegisteredWebhook" ADD CONSTRAINT "RegisteredWebhook_connectionSlotId_fkey" FOREIGN KEY ("connectionSlotId") REFERENCES "WorkflowConnectionSlot"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,20 @@
/*
Warnings:
- You are about to drop the column `isEnabled` on the `RegisteredWebhook` table. All the data in the column will be lost.
- Added the required column `updatedAt` to the `RegisteredWebhook` table without a default value. This is not possible if the table is not empty.
*/
-- CreateEnum
CREATE TYPE "RegisteredWebhookStatus" AS ENUM ('CREATED', 'CONNECTED');
-- DropIndex
DROP INDEX "RegisteredWebhook_workflowId_triggerId_key";
-- AlterTable
ALTER TABLE "RegisteredWebhook" DROP COLUMN "isEnabled",
ADD COLUMN "connectedAt" TIMESTAMP(3),
ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "status" "RegisteredWebhookStatus" NOT NULL DEFAULT 'CREATED',
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL,
ALTER COLUMN "webhookConfig" DROP NOT NULL;
@@ -0,0 +1,8 @@
/*
Warnings:
- Added the required column `secret` to the `RegisteredWebhook` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "RegisteredWebhook" ADD COLUMN "secret" TEXT NOT NULL;
+58 -6
View File
@@ -62,8 +62,9 @@ model APIConnection {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
organizationId String
connectionSlots WorkflowConnectionSlot[]
}
enum APIConnectionType {
@@ -107,8 +108,10 @@ model Workflow {
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
organizationId String
triggers WorkflowTrigger[]
runs WorkflowRun[]
triggers WorkflowTrigger[]
runs WorkflowRun[]
connectionSlots WorkflowConnectionSlot[]
registeredWebhooks RegisteredWebhook[] // Can have multiple because there are multiple environments
@@unique([organizationId, slug])
}
@@ -126,8 +129,10 @@ model WorkflowTrigger {
config Json
status WorkflowTriggerStatus @default(CREATED)
isDefault Boolean @default(false)
runs WorkflowRun[]
isDefault Boolean @default(false)
runs WorkflowRun[]
connectionSlot WorkflowConnectionSlot?
registeredWebhook RegisteredWebhook?
@@unique([workflowId, environmentId])
}
@@ -144,6 +149,53 @@ enum WorkflowTriggerStatus {
CONNECTED
}
model WorkflowConnectionSlot {
id String @id @default(cuid())
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade, onUpdate: Cascade)
workflowId String
trigger WorkflowTrigger? @relation(fields: [triggerId], references: [id], onDelete: Cascade, onUpdate: Cascade)
triggerId String? @unique
connection APIConnection? @relation(fields: [connectionId], references: [id], onDelete: Cascade, onUpdate: Cascade)
connectionId String?
slotName String
serviceIdentifier String
auth Json?
registeredWebhook RegisteredWebhook?
@@unique([workflowId, slotName])
}
model RegisteredWebhook {
id String @id @default(cuid())
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade, onUpdate: Cascade)
workflowId String
trigger WorkflowTrigger @relation(fields: [triggerId], references: [id], onDelete: Cascade, onUpdate: Cascade)
triggerId String @unique
connectionSlot WorkflowConnectionSlot @relation(fields: [connectionSlotId], references: [id], onDelete: Cascade, onUpdate: Cascade)
connectionSlotId String @unique
secret String
webhookConfig Json?
status RegisteredWebhookStatus @default(CREATED)
connectedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum RegisteredWebhookStatus {
CREATED
CONNECTED
}
model CustomEvent {
id String @id @default(cuid())
name String
+2
View File
@@ -11,12 +11,14 @@ module.exports = {
"@nangohq/pizzly-node",
"axios",
"internal-platform",
"internal-integrations",
"@trigger.dev/common-schemas",
],
watchPaths: async () => {
return [
"../../packages/internal-platform/src/**/*",
"../../packages/common-schemas/src/**/*",
"../../packages/internal-integrations/src/**/*",
];
},
};
+4
View File
@@ -20,6 +20,10 @@
"~/*": ["./app/*"],
"internal-platform": ["../../packages/internal-platform/src/index"],
"internal-platform/*": ["../../packages/internal-platform/src/*"],
"internal-integrations": [
"../../packages/internal-integrations/src/index"
],
"internal-integrations/*": ["../../packages/internal-integrations/src/*"],
"@trigger.dev/common-schemas": [
"../../packages/common-schemas/src/index"
],
Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

+19
View File
@@ -0,0 +1,19 @@
{
"private": true,
"name": "@examples/github-webhook",
"version": "0.0.1",
"description": "Example trigger.dev workflow that uses the Github Webhook integration",
"dependencies": {
"@trigger.dev/integrations": "workspace:*",
"@trigger.dev/sdk": "workspace:*",
"zod": "^3.20.2"
},
"devDependencies": {
"@trigger.dev/tsconfig": "workspace:*",
"@types/node": "^18.11.9",
"tsx": "^3.12.0"
},
"scripts": {
"dev": "tsx src/index.ts"
}
}
+23
View File
@@ -0,0 +1,23 @@
import { Trigger } from "@trigger.dev/sdk";
import { github } from "@trigger.dev/integrations";
const trigger = new Trigger({
id: "github-webhook-5",
name: "GitHub Issue changes for jsonhero-web",
apiKey: "trigger_dev_zC25mKNn6c0q",
endpoint: "ws://localhost:8889/ws",
logLevel: "debug",
on: github.issueEvent({ repo: "apihero-run/jsonhero-web" }),
run: async (event, ctx) => {
await ctx.logger.info(
"Inside the github-webhook workflow, received event",
{
event,
}
);
return event;
},
});
trigger.listen();
+12
View File
@@ -0,0 +1,12 @@
{
"extends": "@trigger.dev/tsconfig/node18.json",
"include": ["src/**/*.ts"],
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"lib": ["esnext", "dom"],
"outDir": "lib",
"moduleResolution": "node"
},
"exclude": ["node_modules", "**/*.test.*"]
}
@@ -0,0 +1,17 @@
{
"private": true,
"name": "internal-integrations",
"version": "0.0.1",
"description": "Common code used by integrations and the trigger.dev platform",
"main": "./src/index.ts",
"types": "./src/index.ts",
"devDependencies": {
"@trigger.dev/tsconfig": "workspace:*",
"@types/node": "^18.11.9",
"typescript": "^4.9.4"
},
"scripts": {},
"dependencies": {
"zod": "^3.20.2"
}
}
@@ -0,0 +1,70 @@
import {
HandleWebhookOptions,
WebhookConfig,
WebhookIntegration,
} from "../types";
import { WebhookSchema, IssueEventSchema } from "./schemas";
export class GitHubWebhookIntegration implements WebhookIntegration {
registerWebhook(config: WebhookConfig, params: unknown) {
const parsedParams = parseWebhookData(params);
return registerWebhook(config, {
repo: parsedParams.params.repo,
events: parsedParams.events,
});
}
handleWebhookRequest(options: HandleWebhookOptions) {
return options.request.body;
}
}
export const webhooks = new GitHubWebhookIntegration();
export const schemas = {
IssueEventSchema,
WebhookSchema,
};
async function registerWebhook(
config: WebhookConfig,
options: { repo: string; events: string[] }
) {
// Create the webhook in github
const response = await fetch(
`https://api.github.com/repos/${options.repo}/hooks`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/vnd.github+json",
Authorization: `Bearer ${config.accessToken}`,
"X-GitHub-Api-Version": "2022-11-28",
},
body: JSON.stringify({
name: "web",
active: true,
events: options.events,
config: {
url: config.callbackUrl,
content_type: "json",
secret: config.secret,
insecure_ssl: "0",
},
}),
}
);
if (!response.ok) {
throw new Error(`Failed to register webhook: ${response.statusText}`);
}
const webhook = await response.json();
return webhook;
}
function parseWebhookData(data: unknown) {
return WebhookSchema.parse(data);
}
@@ -0,0 +1,19 @@
import { z } from "zod";
export const WebhookSchema = z.object({
events: z.array(z.string()),
params: z.object({
repo: z.string(),
}),
scopes: z.array(z.string()).optional(),
});
export const IssueEventSchema = z.object({
action: z.literal("opened"),
issue: z.object({
id: z.string(),
title: z.string(),
body: z.string(),
url: z.string(),
}),
});
@@ -0,0 +1,3 @@
export * as github from "./github";
export * from "./webhooks";
@@ -0,0 +1,22 @@
export interface WebhookConfig {
accessToken: string;
callbackUrl: string;
secret: string;
}
export interface NormalizedWebhookRequest {
body: any;
headers: Record<string, string>;
searchParams: URLSearchParams;
}
export interface HandleWebhookOptions {
request: NormalizedWebhookRequest;
secret?: string;
params: unknown;
}
export interface WebhookIntegration {
registerWebhook: (config: WebhookConfig, params: unknown) => Promise<any>;
handleWebhookRequest: (options: HandleWebhookOptions) => any;
}
@@ -0,0 +1,12 @@
import { z } from "zod";
export function createWebhookConfig<TSchema extends z.ZodTypeAny>(
schema: TSchema,
id: string,
webhook: any
): { id: string; webhook: z.infer<TSchema> } {
return {
id,
webhook: schema.parse(webhook),
};
}
@@ -0,0 +1,11 @@
{
"extends": "@trigger.dev/tsconfig/node18.json",
"include": ["./src/**/*.ts"],
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"paths": {},
"lib": ["DOM"]
},
"exclude": ["node_modules"]
}
@@ -91,8 +91,15 @@ export class ZodPublisher<PublisherSchema extends MessageCatalogSchema> {
const id = ulid();
this.#logger.debug(
"Parsing message data and properties",
type,
data,
properties
);
const parsedData = messageSchema.data.parse(data);
const parsedProperties = messageSchema.properties.parse(properties);
const parsedProperties = messageSchema.properties.parse(properties ?? {});
const message = JSON.stringify({
id,
@@ -11,7 +11,7 @@ export const WebhookEventTriggerSchema = z.object({
type: z.literal("WEBHOOK"),
config: z.object({
id: z.string(),
params: z.record(z.string()),
webhook: z.any(),
}),
});
@@ -0,0 +1,11 @@
## Trigger.dev Integrations Development Guide
### JSON Schema to Zod
If you need to convert a JSON Schema to Zod, use this handy [transform.tools utility](https://transform.tools/json-schema-to-zod)
### Add a new provider configuration to pizzly
```sh
PIZZLY_HOSTPORT=http://localhost:3004 npx pizzly config:create github github <client id> <client secret> "scopes,here"
```
+3 -1
View File
@@ -9,6 +9,7 @@
],
"devDependencies": {
"@trigger.dev/tsconfig": "workspace:*",
"internal-integrations": "workspace:*",
"@types/node": "^18.11.9",
"rimraf": "^3.0.2",
"tsup": "^6.5.0"
@@ -20,6 +21,7 @@
"dev": "tsup --watch"
},
"dependencies": {
"zod": "^3.20.2"
"zod": "^3.20.2",
"@trigger.dev/sdk": "workspace:*"
}
}
+3 -2
View File
@@ -1,2 +1,3 @@
export * from "./integrations/github";
export * from "./integrations/slack";
import * as github from "./integrations/github";
export { github };
@@ -1,34 +0,0 @@
export type GitHubIssue = {
id: string;
title: string;
body: string;
url: string;
};
export type GitHubIntegration = {
id: "github";
getIssue(repo: string, id: string): Promise<GitHubIssue>;
};
// export const github = createIntegration<GitHubIntegration>({
// id: "github",
// methods: {
// getIssue: {
// request: (repo: string, id: string) => ({
// url: `
// https://api.github.com/repos/${repo}/issues/${id}
// `,
// method: "GET",
// headers: {
// Accept: "application/vnd.github.v3+json",
// },
// }),
// response: (data: any) => ({
// id: data.id,
// title: data.title,
// body: data.body,
// url: data.html_url,
// }),
// },
// },
// });
@@ -0,0 +1 @@
export * from "./webhooks";
@@ -0,0 +1,38 @@
import { TriggerEvent } from "@trigger.dev/sdk";
import { createWebhookConfig, github } from "internal-integrations";
type IssueEventParams = {
repo: string;
};
export function issueEvent(
params: IssueEventParams
): TriggerEvent<typeof github.schemas.IssueEventSchema> {
return {
type: "WEBHOOK",
config: createWebhookConfig(github.schemas.WebhookSchema, "github.issue", {
events: ["issues"],
params,
scopes: ["repo"],
}),
schema: github.schemas.IssueEventSchema,
};
}
export function issueCommentEvent(
params: IssueEventParams
): TriggerEvent<typeof github.schemas.IssueEventSchema> {
return {
type: "WEBHOOK",
config: createWebhookConfig(
github.schemas.WebhookSchema,
"github.issueComment",
{
events: ["issue_comment"],
params,
scopes: ["repo"],
}
),
schema: github.schemas.IssueEventSchema,
};
}
@@ -1,5 +0,0 @@
export interface SlackIntegration {
sendMessage(message: string): Promise<void>;
}
export const slack = { id: "slack" } as unknown as SlackIntegration;
+7 -8
View File
@@ -13,9 +13,9 @@ import { Trigger, TriggerOptions } from "./trigger";
import { TriggerContext } from "./types";
import { ContextLogger } from "./logger";
export class TriggerClient<TEventData = void> {
#trigger: Trigger<TEventData>;
#options: TriggerOptions<TEventData>;
export class TriggerClient<TSchema extends z.ZodTypeAny> {
#trigger: Trigger<TSchema>;
#options: TriggerOptions<TSchema>;
#connection?: HostConnection;
#serverRPC?: ZodRPC<typeof ServerRPCSchema, typeof HostRPCSchema>;
@@ -27,10 +27,7 @@ export class TriggerClient<TEventData = void> {
#retryIntervalMs: number = 3000;
#logger: Logger;
constructor(
trigger: Trigger<TEventData>,
options: TriggerOptions<TEventData>
) {
constructor(trigger: Trigger<TSchema>, options: TriggerOptions<TSchema>) {
this.#trigger = trigger;
this.#options = options;
@@ -120,9 +117,11 @@ export class TriggerClient<TEventData = void> {
},
};
const eventData = this.#options.on.schema.parse(data.trigger.input);
// TODO: handle this better
this.#trigger.options
.run(data.trigger.input as TEventData, ctx)
.run(eventData, ctx)
.then((output) => {
return serverRPC.send("COMPLETE_WORKFLOW_RUN", {
id: data.id,
+5 -3
View File
@@ -1,8 +1,9 @@
import { z } from "zod";
export type TriggerEvent<TEventData = unknown> = {
export type TriggerEvent<TSchema extends z.ZodTypeAny> = {
type: "CUSTOM_EVENT" | "HTTP_ENDPOINT" | "SCHEDULE" | "WEBHOOK";
config: any;
schema: TSchema;
};
export type TriggerCustomEventOptions<TSchema extends z.ZodTypeAny> = {
@@ -12,9 +13,10 @@ export type TriggerCustomEventOptions<TSchema extends z.ZodTypeAny> = {
export function customEvent<TSchema extends z.ZodTypeAny>(
options: TriggerCustomEventOptions<TSchema>
): TriggerEvent<z.infer<TSchema>> {
): TriggerEvent<TSchema> {
return {
type: "CUSTOM_EVENT",
config: options,
config: { name: options.name },
schema: options.schema,
};
}
+8 -7
View File
@@ -3,22 +3,23 @@ import { LogLevel } from "internal-bridge";
import { TriggerEvent } from "../events";
import type { TriggerContext } from "../types";
import { z } from "zod";
export type TriggerOptions<TEventData = void> = {
export type TriggerOptions<TSchema extends z.ZodTypeAny> = {
id: string;
name: string;
on: TriggerEvent<TEventData>;
on: TriggerEvent<TSchema>;
apiKey?: string;
endpoint?: string;
logLevel?: LogLevel;
run: (event: TEventData, ctx: TriggerContext) => Promise<any>;
run: (event: z.infer<TSchema>, ctx: TriggerContext) => Promise<any>;
};
export class Trigger<TEventData = void> {
options: TriggerOptions<TEventData>;
#client: TriggerClient<TEventData> | undefined;
export class Trigger<TSchema extends z.ZodTypeAny> {
options: TriggerOptions<TSchema>;
#client: TriggerClient<TSchema> | undefined;
constructor(options: TriggerOptions<TEventData>) {
constructor(options: TriggerOptions<TSchema>) {
this.options = options;
}
+127 -55
View File
@@ -153,6 +153,7 @@ importers:
glob: ^8.0.3
happy-dom: ^6.0.4
humanize-duration: ^3.27.3
internal-integrations: workspace:*
internal-platform: workspace:*
javascript-time-ago: ^2.5.7
json-query: ^2.2.2
@@ -166,6 +167,7 @@ importers:
morgan: ^1.10.0
msw: ^0.47.0
nanoid: ^3.3.4
ngrok: ^4.3.3
node-fetch: 2.x
nodemon: ^2.0.19
npm-run-all: ^4.1.5
@@ -239,7 +241,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_4ysryuwswq2dahvwdlnde5nvpq
'@uiw/react-codemirror': 4.17.1_xtrn3tyimkzpilanhyvm2ls4eu
bcryptjs: 2.4.3
classnames: 2.3.2
clsx: 1.2.1
@@ -250,6 +252,7 @@ importers:
date-fns: 2.29.3
express: 4.18.2
humanize-duration: 3.27.3
internal-integrations: link:../../packages/internal-integrations
internal-platform: link:../../packages/internal-platform
javascript-time-ago: 2.5.9
json-query: 2.2.2
@@ -262,6 +265,7 @@ importers:
mergent: 1.4.0
morgan: 1.10.0
nanoid: 3.3.4
ngrok: 4.3.3
openapi-types: 12.0.2
postcss-import: 14.1.0_postcss@8.4.19
posthog-js: 1.36.1
@@ -400,6 +404,23 @@ importers:
config-packages/tsconfig:
specifiers: {}
examples/github-webhook:
specifiers:
'@trigger.dev/integrations': workspace:*
'@trigger.dev/sdk': workspace:*
'@trigger.dev/tsconfig': workspace:*
'@types/node': ^18.11.9
tsx: ^3.12.0
zod: ^3.20.2
dependencies:
'@trigger.dev/integrations': link:../../packages/trigger-integrations
'@trigger.dev/sdk': link:../../packages/trigger-sdk
zod: 3.20.2
devDependencies:
'@trigger.dev/tsconfig': link:../../config-packages/tsconfig
'@types/node': 18.11.15
tsx: 3.12.1
examples/smoke-test:
specifiers:
'@trigger.dev/integrations': workspace:*
@@ -459,6 +480,19 @@ importers:
'@types/ws': 8.5.3
tsx: 3.12.1
packages/internal-integrations:
specifiers:
'@trigger.dev/tsconfig': workspace:*
'@types/node': ^18.11.9
typescript: ^4.9.4
zod: ^3.20.2
dependencies:
zod: 3.20.2
devDependencies:
'@trigger.dev/tsconfig': link:../../config-packages/tsconfig
'@types/node': 18.11.15
typescript: 4.9.4
packages/internal-platform:
specifiers:
'@trigger.dev/common-schemas': workspace:*
@@ -482,16 +516,20 @@ importers:
packages/trigger-integrations:
specifiers:
'@trigger.dev/sdk': workspace:*
'@trigger.dev/tsconfig': workspace:*
'@types/node': ^18.11.9
internal-integrations: workspace:*
rimraf: ^3.0.2
tsup: ^6.5.0
zod: ^3.20.2
dependencies:
'@trigger.dev/sdk': link:../trigger-sdk
zod: 3.20.2
devDependencies:
'@trigger.dev/tsconfig': link:../../config-packages/tsconfig
'@types/node': 18.11.11
internal-integrations: link:../internal-integrations
rimraf: 3.0.2
tsup: 6.5.0
@@ -2885,13 +2923,12 @@ packages:
'@lezer/common': 0.16.1
dev: false
/@codemirror/autocomplete/6.3.4_jvia4rcxqiacrvood3734bhyuy:
/@codemirror/autocomplete/6.3.4_4npvozs3agsv66jx2b7pfvr53q:
resolution: {integrity: sha512-irxKsTSjS0OkfMWWt9YxtNK97++/E+XIHfKnRpSVfZyHzda/amYF0BR+T8mMkrGQWidx2zApxHx08GT13egyQA==}
peerDependencies:
'@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
'@lezer/common': ^1.0.0
dependencies:
'@codemirror/language': 6.3.1
'@codemirror/state': 6.1.4
@@ -2941,7 +2978,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
@@ -3104,6 +3141,7 @@ packages:
engines: {node: '>=12'}
dependencies:
'@jridgewell/trace-mapping': 0.3.9
dev: true
/@cush/relative/1.0.0:
resolution: {integrity: sha512-RpfLEtTlyIxeNPGKcokS+p3BZII/Q3bYxryFRglh5H3A3T8q9fsLYm72VYAMEOOIBLEa8o93kFLiBDUWKrwXZA==}
@@ -3335,6 +3373,7 @@ packages:
/@jridgewell/resolve-uri/3.1.0:
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
engines: {node: '>=6.0.0'}
dev: true
/@jridgewell/set-array/1.1.2:
resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
@@ -3343,6 +3382,7 @@ packages:
/@jridgewell/sourcemap-codec/1.4.14:
resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
dev: true
/@jridgewell/trace-mapping/0.3.17:
resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
@@ -3356,6 +3396,7 @@ packages:
dependencies:
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
dev: true
/@jsonhero/codemirror-lang-inline-tokens/0.1.0:
resolution: {integrity: sha512-nbvaQBSJbLjckdA2HbkiiXXTpAMrjyzDzxymFfAmgSNHNo+GC6e0RjQDWKyDKFEQZCd3s02SQ17ipFA5FVnkfg==}
@@ -3746,7 +3787,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
@@ -4089,7 +4130,6 @@ packages:
/@sindresorhus/is/4.6.0:
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
dev: true
/@swc/core-darwin-arm64/1.3.21:
resolution: {integrity: sha512-5dBrJyrCzdHOQ9evS9NBJm2geKcXffIuAvSrnwbMHkfTpl+pOM7crry2tolydFXdOE/Jbx8yyahAIXPne1fTHw==}
@@ -4097,6 +4137,7 @@ packages:
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@swc/core-darwin-x64/1.3.21:
@@ -4105,6 +4146,7 @@ packages:
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@swc/core-linux-arm-gnueabihf/1.3.21:
@@ -4113,6 +4155,7 @@ packages:
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@swc/core-linux-arm64-gnu/1.3.21:
@@ -4121,6 +4164,7 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@swc/core-linux-arm64-musl/1.3.21:
@@ -4129,6 +4173,7 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@swc/core-linux-x64-gnu/1.3.21:
@@ -4137,6 +4182,7 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@swc/core-linux-x64-musl/1.3.21:
@@ -4145,6 +4191,7 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@swc/core-win32-arm64-msvc/1.3.21:
@@ -4153,6 +4200,7 @@ packages:
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@swc/core-win32-ia32-msvc/1.3.21:
@@ -4161,6 +4209,7 @@ packages:
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@swc/core-win32-x64-msvc/1.3.21:
@@ -4169,6 +4218,7 @@ packages:
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@swc/core/1.3.21:
@@ -4187,6 +4237,7 @@ packages:
'@swc/core-win32-arm64-msvc': 1.3.21
'@swc/core-win32-ia32-msvc': 1.3.21
'@swc/core-win32-x64-msvc': 1.3.21
dev: true
/@swc/helpers/0.4.14:
resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==}
@@ -4206,7 +4257,6 @@ packages:
engines: {node: '>=10'}
dependencies:
defer-to-connect: 2.0.1
dev: true
/@tailwindcss/forms/0.5.3_tailwindcss@3.1.8:
resolution: {integrity: sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==}
@@ -4214,7 +4264,7 @@ packages:
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
dependencies:
mini-svg-data-uri: 1.4.4
tailwindcss: 3.1.8_v776zzvn44o7tpgzieipaairwm
tailwindcss: 3.1.8_postcss@8.4.19
/@tailwindcss/typography/0.5.8_tailwindcss@3.1.8:
resolution: {integrity: sha512-xGQEp8KXN8Sd8m6R4xYmwxghmswrd0cPnNI2Lc6fmrC3OojysTBJJGSIVwPV56q4t6THFUK3HJ0EaWwpglSxWw==}
@@ -4225,7 +4275,7 @@ packages:
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
tailwindcss: 3.1.8_v776zzvn44o7tpgzieipaairwm
tailwindcss: 3.1.8_postcss@8.4.19
dev: true
/@tanstack/react-table/8.7.0_biqbaboplfbrettd7655fr4n2y:
@@ -4315,15 +4365,19 @@ packages:
/@tsconfig/node10/1.0.9:
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
dev: true
/@tsconfig/node12/1.0.11:
resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
dev: true
/@tsconfig/node14/1.0.3:
resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
dev: true
/@tsconfig/node16/1.0.3:
resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==}
dev: true
/@types/acorn/4.0.6:
resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==}
@@ -4353,7 +4407,6 @@ packages:
'@types/keyv': 3.1.4
'@types/node': 18.11.15
'@types/responselike': 1.0.0
dev: true
/@types/chai-subset/1.3.3:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
@@ -4453,7 +4506,6 @@ packages:
/@types/http-cache-semantics/4.0.1:
resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
dev: true
/@types/humanize-duration/3.27.1:
resolution: {integrity: sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==}
@@ -4502,7 +4554,6 @@ packages:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
'@types/node': 18.11.15
dev: true
/@types/lodash/4.14.191:
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
@@ -4575,7 +4626,6 @@ packages:
/@types/node/8.10.66:
resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==}
dev: true
/@types/prismjs/1.26.0:
resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==}
@@ -4618,7 +4668,6 @@ packages:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
'@types/node': 18.11.15
dev: true
/@types/scheduler/0.16.2:
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
@@ -4696,7 +4745,6 @@ packages:
requiresBuild: true
dependencies:
'@types/node': 18.11.15
dev: true
optional: true
/@typescript-eslint/eslint-plugin/5.45.1_tdm6ms4ntwhlpozn7kjqrhum74:
@@ -4828,13 +4876,12 @@ packages:
eslint-visitor-keys: 3.3.0
dev: true
/@uiw/codemirror-extensions-basic-setup/4.17.1_ahlr5jha6gxy5y2f2whv3jw24q:
/@uiw/codemirror-extensions-basic-setup/4.17.1_wq4lmc3co73jmz4wylu22jt6hu:
resolution: {integrity: sha512-lFH3gFPcpKDckaioYL2KonTYeeoP7gGtaDtDai7DV5UVEyuVPlkGukKCmHz6u0ol/Krs/RTbF4ylt8cDlBT1uA==}
peerDependencies:
'@codemirror/autocomplete': '>=6.0.0'
'@codemirror/commands': '>=6.0.0'
'@codemirror/language': '>=6.0.0'
'@codemirror/lint': '>=6.0.0'
'@codemirror/search': '>=6.0.0'
'@codemirror/state': '>=6.0.0'
'@codemirror/view': '>=6.0.0'
@@ -4848,14 +4895,11 @@ packages:
'@codemirror/view': 0.20.7
dev: false
/@uiw/react-codemirror/4.17.1_4ysryuwswq2dahvwdlnde5nvpq:
/@uiw/react-codemirror/4.17.1_xtrn3tyimkzpilanhyvm2ls4eu:
resolution: {integrity: sha512-ah7wFhvVW/uKbQR5D12AqDK51XGZaZI1WYO9/sraZzq32TGphL5BU3vcQd1P0YEZR6YLc23+KWNi2DCQ+EEAbA==}
peerDependencies:
'@babel/runtime': '>=7.11.0'
'@codemirror/state': '>=6.0.0'
'@codemirror/theme-one-dark': '>=6.0.0'
'@codemirror/view': '>=6.0.0'
codemirror: '>=6.0.0'
react: '>=16.8.0'
react-dom: '>=16.8.0'
dependencies:
@@ -4864,14 +4908,13 @@ packages:
'@codemirror/state': 0.20.1
'@codemirror/theme-one-dark': 6.1.0
'@codemirror/view': 0.20.7
'@uiw/codemirror-extensions-basic-setup': 4.17.1_ahlr5jha6gxy5y2f2whv3jw24q
codemirror: 6.0.1_@lezer+common@1.0.2
'@uiw/codemirror-extensions-basic-setup': 4.17.1_wq4lmc3co73jmz4wylu22jt6hu
codemirror: 6.0.1
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
transitivePeerDependencies:
- '@codemirror/autocomplete'
- '@codemirror/language'
- '@codemirror/lint'
- '@codemirror/search'
dev: false
@@ -4965,6 +5008,7 @@ packages:
/acorn-walk/8.2.0:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
engines: {node: '>=0.4.0'}
dev: true
/acorn/7.4.1:
resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
@@ -4975,6 +5019,7 @@ packages:
resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
/agent-base/4.2.1:
resolution: {integrity: sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==}
@@ -5103,6 +5148,7 @@ packages:
/arg/4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
dev: true
/arg/5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
@@ -5561,7 +5607,6 @@ packages:
/buffer-crc32/0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
dev: true
/buffer-from/1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
@@ -5671,7 +5716,6 @@ packages:
/cacheable-lookup/5.0.4:
resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
engines: {node: '>=10.6.0'}
dev: true
/cacheable-request/6.1.0:
resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==}
@@ -5697,7 +5741,6 @@ packages:
lowercase-keys: 2.0.0
normalize-url: 6.1.0
responselike: 2.0.1
dev: true
/cachedir/2.3.0:
resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==}
@@ -5970,7 +6013,6 @@ packages:
resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
dependencies:
mimic-response: 1.0.1
dev: true
/clone/1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
@@ -5997,18 +6039,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:
@@ -6174,6 +6214,7 @@ packages:
/create-require/1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
dev: true
/crelt/1.0.5:
resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==}
@@ -6435,7 +6476,6 @@ packages:
engines: {node: '>=10'}
dependencies:
mimic-response: 3.1.0
dev: true
/deep-eql/4.1.3:
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
@@ -6490,7 +6530,6 @@ packages:
/defer-to-connect/2.0.1:
resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
engines: {node: '>=10'}
dev: true
/define-lazy-prop/2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
@@ -6608,6 +6647,7 @@ packages:
/diff/4.0.2:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
dev: true
/diff/5.1.0:
resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==}
@@ -6706,7 +6746,6 @@ packages:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
dependencies:
once: 1.4.0
dev: true
/enhanced-resolve/5.12.0:
resolution: {integrity: sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==}
@@ -7310,7 +7349,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
@@ -7350,7 +7389,7 @@ packages:
- supports-color
dev: true
/eslint-module-utils/2.7.4_jnakocfte2jywffz4vixv5kpsq:
/eslint-module-utils/2.7.4_wbv6cezew2qbikiravago3ef2u:
resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==}
engines: {node: '>=4'}
peerDependencies:
@@ -7375,6 +7414,7 @@ packages:
debug: 3.2.7
eslint: 8.29.0
eslint-import-resolver-node: 0.3.6
eslint-import-resolver-typescript: 3.5.2_lt3hqehuojhfcbzgzqfngbtmrq
transitivePeerDependencies:
- supports-color
dev: true
@@ -7430,7 +7470,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:
@@ -7447,7 +7487,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
@@ -7991,6 +8031,20 @@ packages:
engines: {node: '>=8'}
dev: true
/extract-zip/2.0.1:
resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
engines: {node: '>= 10.17.0'}
hasBin: true
dependencies:
debug: 4.3.4
get-stream: 5.2.0
yauzl: 2.10.0
optionalDependencies:
'@types/yauzl': 2.10.0
transitivePeerDependencies:
- supports-color
dev: false
/extract-zip/2.0.1_supports-color@8.1.1:
resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
engines: {node: '>= 10.17.0'}
@@ -8064,7 +8118,6 @@ packages:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
dependencies:
pend: 1.2.0
dev: true
/fflate/0.4.8:
resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
@@ -8418,7 +8471,6 @@ packages:
engines: {node: '>=8'}
dependencies:
pump: 3.0.0
dev: true
/get-stream/6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
@@ -8635,7 +8687,6 @@ packages:
lowercase-keys: 2.0.0
p-cancelable: 2.1.1
responselike: 2.0.1
dev: true
/got/9.6.0:
resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==}
@@ -8820,6 +8871,12 @@ packages:
resolution: {integrity: sha512-2zuLt85Ta+gIyvs4N88pCYskNrxf1TFv3LR9t5mdAZIX8BcgQQ48F2opUptvHa6m8zsy5v/a0i9mWzTrlNWU0Q==}
dev: false
/hpagent/0.1.2:
resolution: {integrity: sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==}
requiresBuild: true
dev: false
optional: true
/html-escaper/2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
dev: true
@@ -8889,7 +8946,6 @@ packages:
dependencies:
quick-lru: 5.1.1
resolve-alpn: 1.2.1
dev: true
/https-proxy-agent/3.0.1:
resolution: {integrity: sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==}
@@ -9912,6 +9968,10 @@ packages:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
dev: true
/lodash.clonedeep/4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
dev: false
/lodash.debounce/4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
dev: true
@@ -9984,7 +10044,6 @@ packages:
/lowercase-keys/2.0.0:
resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
engines: {node: '>=8'}
dev: true
/lru-cache/4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
@@ -10062,6 +10121,7 @@ packages:
/make-error/1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
dev: true
/map-cache/0.2.2:
resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
@@ -10565,12 +10625,10 @@ packages:
/mimic-response/1.0.1:
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
engines: {node: '>=4'}
dev: true
/mimic-response/3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
dev: true
/min-indent/1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
@@ -10802,6 +10860,24 @@ packages:
engines: {node: '>= 0.4.0'}
dev: true
/ngrok/4.3.3:
resolution: {integrity: sha512-a2KApnkiG5urRxBPdDf76nNBQTnNNWXU0nXw0SsqsPI+Kmt2lGf9TdVYpYrHMnC+T9KhcNSWjCpWqBgC6QcFvw==}
engines: {node: '>=10.19.0 <14 || >=14.2'}
hasBin: true
requiresBuild: true
dependencies:
'@types/node': 8.10.66
extract-zip: 2.0.1
got: 11.8.5
lodash.clonedeep: 4.5.0
uuid: 8.3.2
yaml: 1.10.2
optionalDependencies:
hpagent: 0.1.2
transitivePeerDependencies:
- supports-color
dev: false
/nice-try/1.0.5:
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
dev: true
@@ -10887,7 +10963,6 @@ packages:
/normalize-url/6.1.0:
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
engines: {node: '>=10'}
dev: true
/npm-run-all/4.1.5:
resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==}
@@ -11138,7 +11213,6 @@ packages:
/p-cancelable/2.1.1:
resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
engines: {node: '>=8'}
dev: true
/p-limit/2.3.0:
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
@@ -11382,7 +11456,6 @@ packages:
/pend/1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
dev: true
/performance-now/2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
@@ -11490,7 +11563,6 @@ packages:
lilconfig: 2.0.6
postcss: 8.4.19
yaml: 1.10.2
dev: true
/postcss-load-config/3.1.4_v776zzvn44o7tpgzieipaairwm:
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
@@ -11508,6 +11580,7 @@ packages:
postcss: 8.4.19
ts-node: 10.9.1_fww2c4adio7pltl52sxaeea2ii
yaml: 1.10.2
dev: true
/postcss-nested/5.0.6_postcss@8.4.19:
resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==}
@@ -11771,7 +11844,6 @@ packages:
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
dev: true
/pumpify/1.5.1:
resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
@@ -12300,7 +12372,6 @@ packages:
/resolve-alpn/1.2.1:
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
dev: true
/resolve-from/4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
@@ -12344,7 +12415,6 @@ packages:
resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
dependencies:
lowercase-keys: 2.0.0
dev: true
/restore-cursor/3.1.0:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
@@ -13169,7 +13239,6 @@ packages:
resolve: 1.22.1
transitivePeerDependencies:
- ts-node
dev: true
/tailwindcss/3.1.8_v776zzvn44o7tpgzieipaairwm:
resolution: {integrity: sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==}
@@ -13202,6 +13271,7 @@ packages:
resolve: 1.22.1
transitivePeerDependencies:
- ts-node
dev: true
/tapable/2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
@@ -13469,6 +13539,7 @@ packages:
typescript: 4.9.3
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
dev: true
/ts-toolbelt/9.6.0:
resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==}
@@ -13965,6 +14036,7 @@ packages:
/v8-compile-cache-lib/3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
dev: true
/v8-to-istanbul/9.0.1:
resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==}
@@ -14413,11 +14485,11 @@ packages:
dependencies:
buffer-crc32: 0.2.13
fd-slicer: 1.1.0
dev: true
/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==}