Adding the typeform integration with webhook support

This commit is contained in:
Eric Allam
2023-07-06 13:42:46 +01:00
parent 090037602c
commit 3ee396d788
21 changed files with 1336 additions and 53 deletions
+7
View File
@@ -0,0 +1,7 @@
---
"@trigger.dev/integration-kit": patch
"@trigger.dev/sdk": patch
"@trigger.dev/typeform": patch
---
Creating the typeform integration package
@@ -180,6 +180,10 @@ export const apisList = [
identifier: "spotify",
name: "Spotify",
},
{
identifier: "stabilityai",
name: "Stability AI",
},
{
identifier: "stripe",
name: "Stripe",
@@ -204,6 +208,10 @@ export const apisList = [
identifier: "twitter",
name: "Twitter",
},
{
identifier: "typeform",
name: "Typeform",
},
{
identifier: "whatsapp",
name: "WhatsApp",
+1 -1
View File
@@ -68,7 +68,7 @@
"@remix-run/server-runtime": "1.18.1",
"@tanstack/react-table": "^8.0.0-alpha.87",
"@team-plain/typescript-sdk": "^2.2.0",
"@trigger.dev/companyicons": "^1.5.10",
"@trigger.dev/companyicons": "^1.5.14",
"@trigger.dev/database": "workspace:*",
"@trigger.dev/internal": "workspace:*",
"@typeform/embed-react": "^2.14.1",
+2 -1
View File
@@ -15,6 +15,7 @@
"@trigger.dev/sdk": "workspace:*",
"@trigger.dev/slack": "workspace:*",
"@trigger.dev/resend": "workspace:*",
"@trigger.dev/typeform": "workspace:*",
"@types/node": "18.15.13",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
@@ -36,4 +37,4 @@
"trigger.dev": {
"endpointId": "nextjs-example"
}
}
}
@@ -0,0 +1,59 @@
import { client } from "@/trigger";
import { Typeform, events } from "@trigger.dev/typeform";
import { Job, eventTrigger } from "@trigger.dev/sdk";
import { DynamicTrigger } from "@trigger.dev/sdk";
export const typeform = new Typeform({
id: "typeform-1",
token: process.env.TYPEFORM_API_KEY!,
});
new Job(client, {
id: "typeform-playground",
name: "Typeform Playground",
version: "0.1.1",
integrations: {
typeform,
},
trigger: eventTrigger({
name: "typeform.playground",
}),
run: async (payload, io, ctx) => {
await io.typeform.listForms("list-forms");
if (payload.formId) {
const form = await io.typeform.getForm("get-form", {
uid: payload.formId,
});
const listResponses = await io.typeform.listResponses("list-responses", {
uid: payload.formId,
pageSize: 50,
});
const allResponses = await io.typeform.getAllResponses(
"get-all-responses",
{
uid: payload.formId,
}
);
}
},
});
new Job(client, {
id: "typeform-webhook-2",
name: "Typeform Webhook 2",
version: "0.1.1",
trigger: typeform.onFormResponse({
uid: "QQnotGJM",
tag: "tag3",
}),
run: async (payload, io, ctx) => {},
});
const dynamicTrigger = new DynamicTrigger(client, {
id: "typeform-dynamic-trigger",
source: typeform.source,
event: events.onFormResponse,
});
@@ -5,6 +5,7 @@ import "@/jobs/openai";
import "@/jobs/resend";
import "@/jobs/general";
import "@/jobs/slack";
import "@/jobs/typeform";
import "@/jobs/logging";
import "@/jobs/schedules";
import "@/jobs/events";
+3 -1
View File
@@ -35,7 +35,9 @@
"@trigger.dev/openai": ["../../integrations/openai/src/index"],
"@trigger.dev/openai/*": ["../../integrations/openai/src/*"],
"@trigger.dev/resend": ["../../integrations/resend/src/index"],
"@trigger.dev/resend/*": ["../../integrations/resend/src/*"]
"@trigger.dev/resend/*": ["../../integrations/resend/src/*"],
"@trigger.dev/typeform": ["../../integrations/typeform/src/index"],
"@trigger.dev/typeform/*": ["../../integrations/typeform/src/*"]
},
"plugins": [
{
View File
+35
View File
@@ -0,0 +1,35 @@
{
"name": "@trigger.dev/typeform",
"version": "1.0.0-next.2",
"description": "The official Typeform integration for Trigger.dev",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"publishConfig": {
"access": "public"
},
"files": [
"dist/index.js",
"dist/index.d.ts",
"dist/index.js.map"
],
"devDependencies": {
"@trigger.dev/tsconfig": "workspace:*",
"@types/node": "18",
"rimraf": "^3.0.2",
"tsup": "^6.5.0"
},
"scripts": {
"clean": "rimraf dist",
"build": "npm run clean && npm run build:tsup",
"build:tsup": "tsup"
},
"dependencies": {
"@typeform/api-client": "^1.8.0",
"@trigger.dev/sdk": "workspace:^2.0.0-next.8",
"@trigger.dev/integration-kit": "workspace:^2.0.0-next.2",
"zod": "3.20.2"
},
"engines": {
"node": ">=18"
}
}
+1
View File
@@ -0,0 +1 @@
export const SOURCE = "typeform.com";
+286
View File
@@ -0,0 +1,286 @@
import { createClient } from "@typeform/api-client";
import { tasks } from "./tasks";
import {
FormResponseEvent,
GetWebhookResponse,
TypeformIntegrationOptions,
TypeformSDK,
} from "./types";
import {
TriggerIntegration,
IntegrationClient,
ExternalSource,
HandlerEvent,
Logger,
ExternalSourceTrigger,
EventSpecification,
} from "@trigger.dev/sdk";
import { createHmac } from "node:crypto";
import { z } from "zod";
import { formResponseExample } from "./payload-examples";
import { safeParseBody } from "@trigger.dev/integration-kit/webhooks";
import { SOURCE } from "./consts";
export * from "./types";
type TypeformIntegration = TriggerIntegration<TypeformIntegrationClient>;
type TypeformIntegrationClient = IntegrationClient<TypeformSDK, typeof tasks>;
type TypeformSource = ReturnType<typeof createWebhookEventSource>;
type TypeformTrigger = ReturnType<typeof createWebhookEventTrigger>;
export class Typeform implements TypeformIntegration {
client: TypeformIntegrationClient;
constructor(private options: TypeformIntegrationOptions) {
this.client = {
tasks,
usesLocalAuth: true,
client: createClient({ token: options.token }),
auth: {
token: options.token,
apiBaseUrl: options.apiBaseUrl,
},
};
}
get id() {
return this.options.id;
}
get metadata() {
return { id: "typeform", name: "Typeform" };
}
get source(): TypeformSource {
return createWebhookEventSource(this);
}
get trigger(): TypeformTrigger {
return createWebhookEventTrigger(this.source);
}
onFormResponse(params: { uid: string; tag: string }) {
return this.trigger({
event: events.onFormResponse,
uid: params.uid,
tag: params.tag,
});
}
}
const onFormResponse: EventSpecification<FormResponseEvent> = {
name: "form_response",
title: "On issue",
source: SOURCE,
icon: "typeform",
examples: [formResponseExample],
parsePayload: (payload) => payload as FormResponseEvent,
runProperties: (payload) => [
{ label: "Form ID", text: payload.form_response.form_id },
],
};
export const events = {
onFormResponse,
};
type TypeformEvents = (typeof events)[keyof typeof events];
type CreateTypeformTriggerReturnType = <
TEventSpecification extends TypeformEvents
>(args: {
event: TEventSpecification;
uid: string;
tag: string;
}) => ExternalSourceTrigger<
TEventSpecification,
ReturnType<typeof createWebhookEventSource>
>;
function createWebhookEventTrigger(
source: ReturnType<typeof createWebhookEventSource>
): CreateTypeformTriggerReturnType {
return <TEventSpecification extends TypeformEvents>({
event,
uid,
tag,
}: {
event: TEventSpecification;
uid: string;
tag: string;
}) => {
return new ExternalSourceTrigger({
event,
params: { uid, tag },
source,
});
};
}
const WebhookSchema = z.object({
uid: z.string(),
tag: z.string(),
});
export function createWebhookEventSource(
integration: TypeformIntegration
): ExternalSource<TypeformIntegration, { uid: string; tag: string }, "HTTP"> {
return new ExternalSource("HTTP", {
id: "typeform.forms",
schema: WebhookSchema,
version: "0.1.1",
integration,
filter: (params) => {
return {
event_type: ["form_response"],
};
},
key: (params) => `${params.uid}/${params.tag}`,
properties: (params) => [
{
label: "Form ID",
text: params.uid,
},
{
label: "Tag",
text: params.tag,
},
],
handler: webhookHandler,
register: async (event, io, ctx) => {
const { params, source: httpSource } = event;
if (
httpSource.active &&
isWebhookData(httpSource.data) &&
!httpSource.data.enabled
) {
// Update the webhook to re-enable it
const newWebhookData = await io.integration.updateWebhook(
"update-webhook",
{
uid: params.uid,
tag: params.tag,
url: httpSource.url,
enabled: true,
secret: httpSource.secret,
verifySSL: true,
}
);
return {
data: newWebhookData,
registeredEvents: ["form_response"],
};
}
try {
const existingWebhook = await io.integration.getWebhook(
"get-webhook",
params
);
if (existingWebhook.enabled) {
return {
data: existingWebhook,
registeredEvents: ["form_response"],
};
}
const newWebhookData = await io.integration.updateWebhook(
"update-webhook",
{
uid: params.uid,
tag: params.tag,
url: httpSource.url,
enabled: true,
secret: httpSource.secret,
verifySSL: true,
}
);
return {
data: newWebhookData,
registeredEvents: ["all"],
};
} catch (error) {
const newWebhookData = await io.integration.createWebhook(
"create-webhook",
{
uid: params.uid,
tag: params.tag,
url: httpSource.url,
enabled: true,
secret: httpSource.secret,
verifySSL: true,
}
);
return {
data: newWebhookData,
registeredEvents: ["all"],
};
}
},
});
}
async function webhookHandler(event: HandlerEvent<"HTTP">, logger: Logger) {
logger.debug(
"[inside typeform integration] Handling typeform webhook handler"
);
const { rawEvent: request, source } = event;
if (!request.body) {
logger.debug("[inside typeform integration] No body found");
return;
}
const rawBody = await request.text();
const signature = request.headers.get("typeform-signature");
if (!signature) {
logger.debug("[inside typeform integration] No signature found");
return { events: [] };
}
const hash = createHmac("sha256", source.secret)
.update(rawBody)
.digest("base64");
const actualSig = `sha256=${hash}`;
if (signature !== actualSig) {
logger.debug(
"[inside typeform integration] Signature does not match, ignoring"
);
return { events: [] };
}
const payload = safeParseBody(rawBody);
return {
events: [
{
id: payload.event_id,
name: payload.event_type,
source: SOURCE,
payload,
context: {},
},
],
};
}
function isWebhookData(data: any): data is GetWebhookResponse {
return (
typeof data === "object" && data !== null && typeof data.id === "string"
);
}
@@ -0,0 +1,280 @@
import { EventSpecificationExample } from "@trigger.dev/sdk";
export const formResponseExample: EventSpecificationExample = {
id: "form_response",
name: "Form response",
payload: {
event_id: "LtWXD3crgy",
event_type: "form_response",
form_response: {
form_id: "lT4Z3j",
token: "a3a12ec67a1365927098a606107fac15",
submitted_at: "2018-01-18T18:17:02Z",
landed_at: "2018-01-18T18:07:02Z",
calculated: {
score: 9,
},
variables: [
{
key: "score",
type: "number",
number: 4,
},
{
key: "name",
type: "text",
text: "typeform",
},
],
hidden: {
user_id: "abc123456",
},
definition: {
id: "lT4Z3j",
title: "Webhooks example",
fields: [
{
id: "DlXFaesGBpoF",
title:
"Thanks, {{answer_60906475}}! What's it like where you live? Tell us in a few sentences.",
type: "long_text",
ref: "readable_ref_long_text",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "SMEUb7VJz92Q",
title:
"If you're OK with our city management following up if they have further questions, please give us your email address.",
type: "email",
ref: "readable_ref_email",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "JwWggjAKtOkA",
title: "What is your first name?",
type: "short_text",
ref: "readable_ref_short_text",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "KoJxDM3c6x8h",
title: "When did you move to the place where you live?",
type: "date",
ref: "readable_ref_date",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "PNe8ZKBK8C2Q",
title:
"Which pictures do you like? You can choose as many as you like.",
type: "picture_choice",
ref: "readable_ref_picture_choice",
allow_multiple_selections: true,
allow_other_choice: false,
},
{
id: "Q7M2XAwY04dW",
title:
"On a scale of 1 to 5, what rating would you give the weather in Sydney? 1 is poor weather, 5 is excellent weather",
type: "number",
ref: "readable_ref_number1",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "gFFf3xAkJKsr",
title:
"By submitting this form, you understand and accept that we will share your answers with city management. Your answers will be anonymous will not be shared.",
type: "legal",
ref: "readable_ref_legal",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "k6TP9oLGgHjl",
title: "Which of these cities is your favorite?",
type: "multiple_choice",
ref: "readable_ref_multiple_choice",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "RUqkXSeXBXSd",
title: "Do you have a favorite city we haven't listed?",
type: "yes_no",
ref: "readable_ref_yes_no",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "NRsxU591jIW9",
title:
"How important is the weather to your opinion about a city? 1 is not important, 5 is very important.",
type: "opinion_scale",
ref: "readable_ref_opinion_scale",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "WOTdC00F8A3h",
title:
"How would you rate the weather where you currently live? 1 is poor weather, 5 is excellent weather.",
type: "rating",
ref: "readable_ref_rating",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "pn48RmPazVdM",
title:
"On a scale of 1 to 5, what rating would you give the general quality of life in Sydney? 1 is poor, 5 is excellent",
type: "number",
ref: "readable_ref_number2",
allow_multiple_selections: false,
allow_other_choice: false,
},
{
id: "M5tXK5kG7IeA",
title: "Book a time with me",
type: "calendly",
ref: "readable_ref_calendly",
properties: {},
},
],
endings: [
{
id: "dN5FLyFpCMFo",
ref: "01GRC8GR2017M6WW347T86VV39",
title: "Bye!",
type: "thankyou_screen",
properties: {
button_text: "Create a typeform",
show_button: true,
share_icons: true,
button_mode: "default_redirect",
},
},
],
},
answers: [
{
type: "text",
text: "It's cold right now! I live in an older medium-sized city with a university. Geographically, the area is hilly.",
field: {
id: "DlXFaesGBpoF",
type: "long_text",
},
},
{
type: "email",
email: "laura@example.com",
field: {
id: "SMEUb7VJz92Q",
type: "email",
},
},
{
type: "text",
text: "Laura",
field: {
id: "JwWggjAKtOkA",
type: "short_text",
},
},
{
type: "date",
date: "2005-10-15",
field: {
id: "KoJxDM3c6x8h",
type: "date",
},
},
{
type: "choices",
choices: {
labels: ["London", "Sydney"],
},
field: {
id: "PNe8ZKBK8C2Q",
type: "picture_choice",
},
},
{
type: "number",
number: 5,
field: {
id: "Q7M2XAwY04dW",
type: "number",
},
},
{
type: "boolean",
boolean: true,
field: {
id: "gFFf3xAkJKsr",
type: "legal",
},
},
{
type: "choice",
choice: {
label: "London",
},
field: {
id: "k6TP9oLGgHjl",
type: "multiple_choice",
},
},
{
type: "boolean",
boolean: false,
field: {
id: "RUqkXSeXBXSd",
type: "yes_no",
},
},
{
type: "number",
number: 2,
field: {
id: "NRsxU591jIW9",
type: "opinion_scale",
},
},
{
type: "number",
number: 3,
field: {
id: "WOTdC00F8A3h",
type: "rating",
},
},
{
type: "number",
number: 4,
field: {
id: "pn48RmPazVdM",
type: "number",
},
},
{
type: "url",
url: "https://calendly.com/scheduled_events/EVENT_TYPE/invitees/INVITEE",
field: {
id: "M5tXK5kG7IeA",
type: "calendly",
ref: "readable_ref_calendly",
},
},
],
ending: {
id: "dN5FLyFpCMFo",
ref: "01GRC8GR2017M6WW347T86VV39",
},
},
},
};
+291
View File
@@ -0,0 +1,291 @@
import type { AuthenticatedTask } from "@trigger.dev/sdk";
import { Typeform } from "@typeform/api-client";
import type {
CreateWebhookParams,
DeleteWebhookParams,
DeleteWebhookResponse,
GetAllResponsesParams,
GetAllResponsesResponse,
GetFormParams,
GetFormResponse,
GetWebhookParams,
GetWebhookResponse,
ListFormsParams,
ListResponsesParams,
ListResponsesResponse,
ListWebhooksParams,
ListWebhooksResponse,
TypeformSDK,
UpdateWebhookParams,
} from "./types";
const listForms: AuthenticatedTask<
TypeformSDK,
ListFormsParams,
Typeform.API.Forms.List
> = {
run: async (params, client) => {
return client.forms.list(params ?? {});
},
init: (params) => {
return {
name: "List Forms",
params,
icon: "typeform",
properties: [
...(params?.workspaceId
? [{ label: "Workspace ID", text: params.workspaceId }]
: []),
...(params?.search ? [{ label: "Search", text: params.search }] : []),
...(params?.page ? [{ label: "Page", text: String(params.page) }] : []),
...(params?.pageSize
? [{ label: "Page Size", text: String(params.pageSize) }]
: []),
],
};
},
};
const getForm: AuthenticatedTask<TypeformSDK, GetFormParams, GetFormResponse> =
{
run: async (params, client) => {
return client.forms.get(params);
},
init: (params) => {
return {
name: "Get Form",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
],
};
},
};
const listResponses: AuthenticatedTask<
TypeformSDK,
ListResponsesParams,
ListResponsesResponse
> = {
run: async (params, client) => {
return client.responses.list(params);
},
init: (params) => {
return {
name: "List Responses",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
],
};
},
};
const getAllResponses: AuthenticatedTask<
TypeformSDK,
GetAllResponsesParams,
GetAllResponsesResponse
> = {
run: async (params, client, task, io, auth) => {
// We're going to create a subtask for each page of responses
const pageSize = 50;
async function listResponsesForPage(page: number) {
// @ts-ignore
// This is needed because of the index signature on the response type
return await io.runTask<ListResponsesResponse>(
`page-${page}`,
listResponses.init(params),
async (t, io) => {
const subResponse = await listResponses.run(
params,
client,
t,
io,
auth
);
return subResponse;
}
);
}
const firstPage = await listResponsesForPage(1);
const totalPages = Math.ceil(firstPage.total_items / pageSize);
const allResponses = firstPage.items;
for (let i = 2; i <= totalPages; i++) {
const page = await listResponsesForPage(i);
allResponses.push(...page.items);
}
return allResponses;
},
init: (params) => {
return {
name: "Get All Responses",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
],
};
},
};
const createWebhook: AuthenticatedTask<
TypeformSDK,
CreateWebhookParams,
GetWebhookResponse
> = {
run: async (params, client) => {
return client.webhooks.create(params);
},
init: (params) => {
return {
name: "Create Webhook",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
{
label: "Tag",
text: params.tag,
},
],
};
},
};
const listWebhooks: AuthenticatedTask<
TypeformSDK,
ListWebhooksParams,
ListWebhooksResponse
> = {
run: async (params, client) => {
return client.webhooks.list(params);
},
init: (params) => {
return {
name: "List Webhooks",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
],
};
},
};
const updateWebhook: AuthenticatedTask<
TypeformSDK,
UpdateWebhookParams,
GetWebhookResponse
> = {
run: async (params, client) => {
return client.webhooks.update(params);
},
init: (params) => {
return {
name: "Update Webhook",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
{
label: "Tag",
text: params.tag,
},
],
};
},
};
const getWebhook: AuthenticatedTask<
TypeformSDK,
GetWebhookParams,
GetWebhookResponse
> = {
run: async (params, client) => {
return client.webhooks.get(params);
},
init: (params) => {
return {
name: "Get Webhook",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
{
label: "Tag",
text: params.tag,
},
],
};
},
};
const deleteWebhook: AuthenticatedTask<
TypeformSDK,
DeleteWebhookParams,
DeleteWebhookResponse
> = {
run: async (params, client) => {
return client.webhooks.delete(params);
},
init: (params) => {
return {
name: "Delete Webhook",
params,
icon: "typeform",
properties: [
{
label: "Form ID",
text: params.uid,
},
{
label: "Tag",
text: params.tag,
},
],
};
},
};
export const tasks = {
listForms,
getForm,
listResponses,
getAllResponses,
createWebhook,
updateWebhook,
getWebhook,
deleteWebhook,
listWebhooks,
};
+202
View File
@@ -0,0 +1,202 @@
import { Prettify } from "@trigger.dev/integration-kit";
import { Typeform, createClient } from "@typeform/api-client";
export type TypeformIntegrationOptions = {
id: string;
token: string;
apiBaseUrl?: string;
};
export type TypeformSDK = ReturnType<typeof createClient>;
export type ListFormsParams = {
page?: number;
pageSize?: number;
search?: string;
workspaceId?: string;
} | void;
export type ListFormsResponse = Prettify<Typeform.API.Forms.List>;
export type ListResponsesParams = {
uid: string;
pageSize?: number;
since?: string;
until?: string;
after?: string;
before?: string;
ids?: string | string[];
completed?: boolean;
sort?: string;
query?: string;
fields?: string | string[];
};
export type ListResponsesResponse = Prettify<Typeform.API.Responses.List>;
export type GetFormParams = {
uid: string;
};
export type GetFormResponse = Prettify<Typeform.Form>;
export type GetAllResponsesParams = Prettify<
Omit<ListResponsesParams, "pageSize">
>;
export type GetAllResponsesResponse = Prettify<
Typeform.API.Responses.List["items"]
>;
export type GetWebhookResponse = Prettify<Typeform.Webhook>;
export type ListWebhooksParams = {
uid: string;
};
export type ListWebhooksResponse = Prettify<Typeform.API.Webhooks.List>;
export type CreateWebhookParams = {
uid: string;
tag: string;
url: string;
enabled?: boolean;
secret?: string;
verifySSL?: boolean;
};
export type UpdateWebhookParams = {
uid: string;
tag: string;
url: string;
enabled?: boolean;
secret?: string;
verifySSL?: boolean;
};
export type GetWebhookParams = {
uid: string;
tag: string;
};
export type DeleteWebhookParams = {
uid: string;
tag: string;
};
export type DeleteWebhookResponse = null;
export type FormResponseEvent = {
event_id: string;
event_type: "form_response";
form_response: {
form_id: string;
token: string;
landed_at: string;
submitted_at: string;
calculated: {
score: number;
};
variables: Array<
| {
key: string;
type: "number";
number: number;
}
| {
key: string;
type: "text";
text: string;
}
>;
hidden: Record<string, string>;
definition: {
id: string;
title: string;
fields: Array<{
id: string;
ref: string;
type: string;
title: string;
allow_multiple_selections?: boolean;
allow_other_choice?: boolean;
properties?: Record<string, string | boolean | number>;
choices?: Array<{
id: string;
label: string;
}>;
}>;
ending: {
id: string;
title: string;
ref: string;
type: string;
properties?: Record<string, string | boolean | number>;
};
};
answers: Array<FormResponseAnswer>;
ending: {
id: string;
ref: string;
};
};
};
type FormResponseAnswerBase = {
field: {
id: string;
type: string;
ref: string;
};
};
type FormResponseAnswerEmail = Prettify<
FormResponseAnswerBase & {
type: "email";
email: string;
}
>;
type FormResponseAnswerText = Prettify<
FormResponseAnswerBase & {
type: "text";
text: string;
}
>;
type FormResponseAnswerNumber = Prettify<
FormResponseAnswerBase & {
type: "number";
number: number;
}
>;
type FormResponseAnswerBoolean = Prettify<
FormResponseAnswerBase & {
type: "boolean";
boolean: boolean;
}
>;
type FormResponseAnswerDate = Prettify<
FormResponseAnswerBase & {
type: "date";
date: string;
}
>;
type FormResponseAnswerChoice = Prettify<
FormResponseAnswerBase & {
type: "choice";
choice: {
label: string;
};
}
>;
type FormResponseAnswer = Prettify<
| FormResponseAnswerEmail
| FormResponseAnswerText
| FormResponseAnswerNumber
| FormResponseAnswerBoolean
| FormResponseAnswerDate
| FormResponseAnswerChoice
>;
+21
View File
@@ -0,0 +1,21 @@
{
"extends": "@trigger.dev/tsconfig/node18.json",
"include": ["./src/**/*.ts", "tsup.config.ts"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"paths": {
"@trigger.dev/sdk/*": ["../../packages/trigger-sdk/src/*"],
"@trigger.dev/sdk": ["../../packages/trigger-sdk/src/index"],
"@trigger.dev/integration-kit/*": [
"../../packages/integration-kit/src/*"
],
"@trigger.dev/integration-kit": [
"../../packages/integration-kit/src/index"
]
},
"declaration": false,
"declarationMap": false,
"baseUrl": "."
},
"exclude": ["node_modules"]
}
+22
View File
@@ -0,0 +1,22 @@
import { defineConfig } from "tsup";
export default defineConfig([
{
name: "main",
entry: ["./src/index.ts"],
outDir: "./dist",
platform: "node",
format: ["cjs"],
legacyOutput: true,
sourcemap: true,
clean: true,
bundle: true,
splitting: false,
dts: true,
treeshake: {
preset: "smallest",
},
esbuildPlugins: [],
external: ["http", "https", "util", "events", "tty", "os", "timers"],
},
]);
+1
View File
@@ -1,4 +1,5 @@
export * from "./json";
export * from "./webhooks";
export * from "./omit";
export * from "./properties";
export * from "./file";
+16
View File
@@ -0,0 +1,16 @@
// Parses the body of a request
import { safeJsonParse } from "./json";
// If it's a Buffer, it will be parsed as JSON
export function safeParseBody(body: any) {
if (Buffer.isBuffer(body)) {
return safeJsonParse(body.toString());
}
if (typeof body === "string") {
return safeJsonParse(body);
}
return body;
}
+1 -1
View File
@@ -50,7 +50,7 @@
"ulid": "^2.3.0",
"uuid": "^9.0.0",
"ws": "^8.11.0",
"zod": "^3.20.2",
"zod": "3.20.2",
"zod-error": "^1.1.0",
"zod-to-json-schema": "^3.20.2"
},
@@ -111,7 +111,7 @@ type ExternalSourceOptions<
schema: z.Schema<TParams>;
integration: TIntegration;
register: RegisterFunction<TIntegration, TParams, TChannel>;
filter: FilterFunction<TParams>;
filter?: FilterFunction<TParams>;
handler: HandlerFunction<TChannel, TParams>;
key: KeyFunction<TParams>;
properties?: (params: TParams) => DisplayProperty[];
@@ -146,7 +146,7 @@ export class ExternalSource<
}
filter(params: TParams): EventFilter {
return this.options.filter(params);
return this.options.filter?.(params) ?? {};
}
properties(params: TParams): DisplayProperty[] {
+97 -47
View File
@@ -105,7 +105,7 @@ importers:
'@testing-library/react': ^13.4.0
'@testing-library/user-event': ^14.4.3
'@total-typescript/ts-reset': ^0.4.2
'@trigger.dev/companyicons': ^1.5.10
'@trigger.dev/companyicons': ^1.5.14
'@trigger.dev/database': workspace:*
'@trigger.dev/internal': workspace:*
'@trigger.dev/tailwind-config': workspace:*
@@ -274,7 +274,7 @@ importers:
'@remix-run/server-runtime': 1.18.1
'@tanstack/react-table': 8.7.6_biqbaboplfbrettd7655fr4n2y
'@team-plain/typescript-sdk': 2.2.0
'@trigger.dev/companyicons': 1.5.10_biqbaboplfbrettd7655fr4n2y
'@trigger.dev/companyicons': 1.5.14_biqbaboplfbrettd7655fr4n2y
'@trigger.dev/database': link:../../packages/database
'@trigger.dev/internal': link:../../packages/internal
'@typeform/embed-react': 2.14.1_react@18.2.0
@@ -500,6 +500,7 @@ importers:
'@trigger.dev/resend': workspace:*
'@trigger.dev/sdk': workspace:*
'@trigger.dev/slack': workspace:*
'@trigger.dev/typeform': workspace:*
'@types/node': 18.15.13
'@types/node-fetch': 2.6.x
'@types/react': ^18.0.21
@@ -521,6 +522,7 @@ importers:
'@trigger.dev/resend': link:../../integrations/resend
'@trigger.dev/sdk': link:../../packages/trigger-sdk
'@trigger.dev/slack': link:../../integrations/slack
'@trigger.dev/typeform': link:../../integrations/typeform
'@types/node': 18.15.13
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
@@ -659,6 +661,27 @@ importers:
rimraf: 3.0.2
tsup: 6.6.3
integrations/typeform:
specifiers:
'@trigger.dev/integration-kit': workspace:^2.0.0-next.2
'@trigger.dev/sdk': workspace:^2.0.0-next.8
'@trigger.dev/tsconfig': workspace:*
'@typeform/api-client': ^1.8.0
'@types/node': '18'
rimraf: ^3.0.2
tsup: ^6.5.0
zod: 3.20.2
dependencies:
'@trigger.dev/integration-kit': link:../../packages/integration-kit
'@trigger.dev/sdk': link:../../packages/trigger-sdk
'@typeform/api-client': 1.8.0
zod: 3.20.2
devDependencies:
'@trigger.dev/tsconfig': link:../../config-packages/tsconfig
'@types/node': 18.15.13
rimraf: 3.0.2
tsup: 6.6.3
packages/cli:
specifiers:
'@types/degit': ^2.8.3
@@ -861,7 +884,7 @@ importers:
ulid: ^2.3.0
uuid: ^9.0.0
ws: ^8.11.0
zod: ^3.20.2
zod: 3.20.2
zod-error: ^1.1.0
zod-to-json-schema: ^3.20.2
dependencies:
@@ -6915,7 +6938,7 @@ packages:
dependencies:
'@types/istanbul-lib-coverage': 2.0.4
'@types/istanbul-reports': 3.0.1
'@types/node': 20.3.1
'@types/node': 20.3.3
'@types/yargs': 16.0.5
chalk: 4.1.2
dev: true
@@ -6927,7 +6950,7 @@ packages:
'@jest/schemas': 29.4.3
'@types/istanbul-lib-coverage': 2.0.4
'@types/istanbul-reports': 3.0.1
'@types/node': 20.3.1
'@types/node': 20.3.3
'@types/yargs': 17.0.19
chalk: 4.1.2
dev: true
@@ -9159,7 +9182,7 @@ packages:
resolution: {integrity: sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA==}
engines: {node: '>= 12.13.0', npm: '>= 6.12.0'}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: false
/@slack/types/2.8.0:
@@ -10806,8 +10829,8 @@ packages:
resolution: {integrity: sha512-vqd7ZUDSrXFVT1n8b2kc3LnklncDQFPvR58yUS1kEP23/nHPAO9l1lMjUfnPrXYYk4Hj54rrLKMW5ipwk7k09A==}
dev: true
/@trigger.dev/companyicons/1.5.10_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-0oSuaZcv6ByV3RvJe67ngh7mLianapOJvDm4o79hpabZ9m0DUWkdycgj2IZEG/dKvGQ1etBfXd6v639nmhRPrw==}
/@trigger.dev/companyicons/1.5.14_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-+qiv5+YxZDdtUvzJdOlACz7BVmV1Zdo0wdvWrzHJX6/LoiGvyEXbcM3ozIMxD71NaCxv5axeDY/Iq92iPSj6Ew==}
peerDependencies:
react: ^18.2.0
react-dom: 18.2.0
@@ -10869,6 +10892,15 @@ packages:
/@tsconfig/node16/1.0.3:
resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==}
/@typeform/api-client/1.8.0:
resolution: {integrity: sha512-eRaq7Enyi3Y05gZsCnMTFfRyEZiLjR1/WkB51d82sop28BSR4K3yLQmj41YMj82bWyJU4ECHixf/LBbtVsRfyw==}
engines: {node: '>=12'}
dependencies:
axios: 0.21.4
transitivePeerDependencies:
- debug
dev: false
/@typeform/embed-react/2.14.1_react@18.2.0:
resolution: {integrity: sha512-+lPZyk3ghPYNyUPabBhMuG6pCP9Bx3qkNAXfKnWq3VMG2A7WXbfVOq2MouaCBRv539kryR6DVnvSvpBewHaoug==}
engines: {node: '>=10'}
@@ -10931,7 +10963,7 @@ packages:
/@types/basic-auth/1.1.3:
resolution: {integrity: sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: false
/@types/bcryptjs/2.4.2:
@@ -10942,7 +10974,7 @@ packages:
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
dependencies:
'@types/connect': 3.4.35
'@types/node': 20.3.2
'@types/node': 20.3.3
/@types/btoa-lite/1.0.0:
resolution: {integrity: sha512-wJsiX1tosQ+J5+bY5LrSahHxr2wT+uME5UDwdN1kg4frt40euqA+wzECkmq4t5QbveHiJepfdThgQrPw6KiSlg==}
@@ -10953,7 +10985,7 @@ packages:
dependencies:
'@types/http-cache-semantics': 4.0.1
'@types/keyv': 3.1.4
'@types/node': 20.3.2
'@types/node': 20.3.3
'@types/responselike': 1.0.0
/@types/chai-subset/1.3.3:
@@ -10975,13 +11007,13 @@ packages:
/@types/concat-stream/1.6.1:
resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: true
/@types/connect/3.4.35:
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
dependencies:
'@types/node': 20.3.2
'@types/node': 20.3.3
/@types/cookie/0.4.1:
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
@@ -10992,7 +11024,7 @@ packages:
'@types/connect': 3.4.35
'@types/express': 4.17.15
'@types/keygrip': 1.0.2
'@types/node': 20.3.2
'@types/node': 20.3.3
dev: false
/@types/debug/4.1.7:
@@ -11057,7 +11089,7 @@ packages:
/@types/express-serve-static-core/4.17.32:
resolution: {integrity: sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==}
dependencies:
'@types/node': 20.3.2
'@types/node': 20.3.3
'@types/qs': 6.9.7
'@types/range-parser': 1.2.4
@@ -11085,33 +11117,33 @@ packages:
/@types/form-data/0.0.33:
resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: true
/@types/fs-extra/11.0.1:
resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==}
dependencies:
'@types/jsonfile': 6.1.1
'@types/node': 20.3.2
'@types/node': 20.3.3
dev: true
/@types/glob/7.2.0:
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 20.3.1
'@types/node': 20.3.3
/@types/glob/8.1.0:
resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==}
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: true
/@types/graceful-fs/4.1.6:
resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: true
/@types/gradient-string/1.1.2:
@@ -11153,7 +11185,7 @@ packages:
/@types/is-stream/1.1.0:
resolution: {integrity: sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: false
/@types/istanbul-lib-coverage/2.0.4:
@@ -11202,7 +11234,7 @@ packages:
/@types/jsonfile/6.1.1:
resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==}
dependencies:
'@types/node': 20.3.2
'@types/node': 20.3.3
dev: true
/@types/jsonwebtoken/9.0.1:
@@ -11217,7 +11249,7 @@ packages:
/@types/keyv/3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
'@types/node': 20.3.2
'@types/node': 20.3.3
/@types/lodash/4.14.191:
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
@@ -11311,7 +11343,6 @@ packages:
/@types/node/20.3.3:
resolution: {integrity: sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==}
dev: false
/@types/node/8.10.66:
resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==}
@@ -11330,7 +11361,7 @@ packages:
/@types/pg/8.6.6:
resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
pg-protocol: 1.6.0
pg-types: 2.2.0
dev: false
@@ -11374,7 +11405,7 @@ packages:
/@types/responselike/1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
'@types/node': 20.3.2
'@types/node': 20.3.3
/@types/retry/0.12.0:
resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
@@ -11394,12 +11425,12 @@ packages:
resolution: {integrity: sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==}
dependencies:
'@types/mime': 3.0.1
'@types/node': 20.3.2
'@types/node': 20.3.3
/@types/set-cookie-parser/2.4.2:
resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: true
/@types/simple-oauth2/5.0.4:
@@ -11446,7 +11477,7 @@ packages:
/@types/through/0.0.30:
resolution: {integrity: sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==}
dependencies:
'@types/node': 20.3.2
'@types/node': 20.3.3
dev: true
/@types/tinycolor2/1.4.3:
@@ -11471,7 +11502,7 @@ packages:
/@types/ws/8.5.4:
resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: true
/@types/yargs-parser/21.0.0:
@@ -11494,7 +11525,7 @@ packages:
resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
requiresBuild: true
dependencies:
'@types/node': 20.3.2
'@types/node': 20.3.3
optional: true
/@typescript-eslint/eslint-plugin/5.59.6_bhjpu5ld5qmewts22wsycix4mi:
@@ -12560,6 +12591,14 @@ packages:
engines: {node: '>=4'}
dev: true
/axios/0.21.4:
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
dependencies:
follow-redirects: 1.15.2
transitivePeerDependencies:
- debug
dev: false
/axios/0.21.4_debug@4.3.2:
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
dependencies:
@@ -12571,7 +12610,7 @@ packages:
/axios/0.25.0_debug@4.3.4:
resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==}
dependencies:
follow-redirects: 1.15.2_debug@4.3.2
follow-redirects: 1.15.2
transitivePeerDependencies:
- debug
dev: true
@@ -12579,7 +12618,7 @@ packages:
/axios/0.26.1:
resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==}
dependencies:
follow-redirects: 1.15.2_debug@4.3.2
follow-redirects: 1.15.2
transitivePeerDependencies:
- debug
dev: false
@@ -12587,7 +12626,7 @@ packages:
/axios/0.27.2:
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
dependencies:
follow-redirects: 1.15.2_debug@4.3.2
follow-redirects: 1.15.2
form-data: 4.0.0
transitivePeerDependencies:
- debug
@@ -12596,7 +12635,7 @@ packages:
/axios/1.4.0:
resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
dependencies:
follow-redirects: 1.15.2_debug@4.3.2
follow-redirects: 1.15.2
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
@@ -14162,6 +14201,7 @@ packages:
optional: true
dependencies:
ms: 2.1.2
dev: false
/debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
@@ -16434,6 +16474,15 @@ packages:
engines: {node: '>=0.4.0'}
dev: true
/follow-redirects/1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
/follow-redirects/1.15.2_debug@4.3.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
@@ -16444,6 +16493,7 @@ packages:
optional: true
dependencies:
debug: 4.3.2
dev: false
/for-each/0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@@ -18204,7 +18254,7 @@ packages:
dependencies:
'@jest/types': 29.5.0
'@types/graceful-fs': 4.1.6
'@types/node': 20.3.1
'@types/node': 20.3.3
anymatch: 3.1.3
fb-watchman: 2.0.2
graceful-fs: 4.2.10
@@ -18247,7 +18297,7 @@ packages:
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
dependencies:
'@jest/types': 27.5.1
'@types/node': 20.3.1
'@types/node': 20.3.3
dev: true
/jest-regex-util/29.4.3:
@@ -18272,7 +18322,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.5.0
'@types/node': 20.3.1
'@types/node': 20.3.3
chalk: 4.1.2
ci-info: 3.7.1
graceful-fs: 4.2.10
@@ -18283,7 +18333,7 @@ packages:
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
engines: {node: '>= 10.13.0'}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
merge-stream: 2.0.0
supports-color: 8.1.1
dev: true
@@ -18292,7 +18342,7 @@ packages:
resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
jest-util: 29.5.0
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -25157,7 +25207,7 @@ packages:
- terser
dev: true
/vite-node/0.28.5_@types+node@20.3.1:
/vite-node/0.28.5_@types+node@20.3.3:
resolution: {integrity: sha512-LmXb9saMGlrMZbXTvOveJKwMTBTNUH66c8rJnQ0ZPNX+myPEol64+szRzXtV5ORb0Hb/91yq+/D3oERoyAt6LA==}
engines: {node: '>=v14.16.0'}
hasBin: true
@@ -25169,7 +25219,7 @@ packages:
picocolors: 1.0.0
source-map: 0.6.1
source-map-support: 0.5.21
vite: 4.1.4_@types+node@20.3.1
vite: 4.1.4_@types+node@20.3.3
transitivePeerDependencies:
- '@types/node'
- less
@@ -25340,7 +25390,7 @@ packages:
fsevents: 2.3.2
dev: true
/vite/4.1.4_@types+node@20.3.1:
/vite/4.1.4_@types+node@20.3.3:
resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
@@ -25365,7 +25415,7 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 20.3.1
'@types/node': 20.3.3
esbuild: 0.16.17
postcss: 8.4.24
resolve: 1.22.1
@@ -25441,7 +25491,7 @@ packages:
dependencies:
'@types/chai': 4.3.4
'@types/chai-subset': 1.3.3
'@types/node': 20.3.1
'@types/node': 20.3.3
'@vitest/expect': 0.28.5
'@vitest/runner': 0.28.5
'@vitest/spy': 0.28.5
@@ -25460,8 +25510,8 @@ packages:
tinybench: 2.3.1
tinypool: 0.3.1
tinyspy: 1.0.2
vite: 4.1.4_@types+node@20.3.1
vite-node: 0.28.5_@types+node@20.3.1
vite: 4.1.4_@types+node@20.3.3
vite-node: 0.28.5_@types+node@20.3.3
why-is-node-running: 2.2.2
transitivePeerDependencies:
- less