Adding the create-integration command to scaffold out new integration packages (inside or outside of the monorepo)

This commit is contained in:
Eric Allam
2023-07-12 13:38:43 +01:00
parent f96da50e6a
commit 520ab88a97
14 changed files with 1296 additions and 87 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@trigger.dev/cli": patch
---
Adding the create-integration command to scaffold out new integration packages (inside or outside of the monorepo)
+2 -1
View File
@@ -51,7 +51,8 @@
"turbo": "^1.10.3",
"vite": "^4.1.1",
"vite-tsconfig-paths": "^4.0.5",
"vitest": "^0.28.4"
"vitest": "^0.28.4",
"@trigger.dev/cli": "workspace:*"
},
"packageManager": "pnpm@7.18.1",
"dependencies": {
-2
View File
@@ -35,7 +35,6 @@
"trigger-cli": "./dist/index.js"
},
"devDependencies": {
"@types/fs-extra": "^11.0.1",
"@types/gradient-string": "^1.1.2",
"@types/inquirer": "^9.0.3",
"@types/node": "16",
@@ -59,7 +58,6 @@
"commander": "^9.4.1",
"degit": "^2.8.4",
"execa": "^7.0.0",
"fs-extra": "^11.1.0",
"gradient-string": "^2.0.2",
"inquirer": "^9.1.4",
"localtunnel": "^2.0.2",
+21 -20
View File
@@ -5,6 +5,7 @@ import { COMMAND_NAME, CLOUD_TRIGGER_URL } from "../consts.js";
import { getVersion } from "../utils/getVersion.js";
import pathModule from "node:path";
import { devCommand } from "../commands/dev.js";
import { createIntegrationCommand } from "../commands/createIntegration.js";
export const program = new Command();
@@ -57,26 +58,26 @@ program
await devCommand(path, options);
});
// program
// .command("create-integration")
// .description("Create a new integration package for Trigger.dev")
// .argument(
// "[path]",
// "The path where you would like the package to be created",
// "."
// )
// .option(
// "-n, --package-name <package name>",
// "The name of the package to create (e.g. @trigger.dev/slack)"
// )
// .option(
// "-s, --sdk-package <integration package>",
// "The name of the SDK package to use (e.g. @slack/web-api)"
// )
// .version(getVersion(), "-v, --version", "Display the version number")
// .action(async (path, options) => {
// await createIntegrationCommand(path, options);
// });
program
.command("create-integration")
.description("Create a new integration package for Trigger.dev")
.argument(
"[path]",
"The path where you would like the package to be created",
"."
)
.option(
"-n, --package-name <package name>",
"The name of the package to create (e.g. @trigger.dev/slack)"
)
.option(
"-s, --sdk-package <integration package>",
"The name of the SDK package to use (e.g. @slack/web-api)"
)
.version(getVersion(), "-v, --version", "Display the version number")
.action(async (path, options) => {
await createIntegrationCommand(path, options);
});
export const promptTriggerUrl = async (): Promise<string> => {
const { instanceType } = await inquirer.prompt<{
+468 -8
View File
@@ -1,13 +1,26 @@
import inquirer from "inquirer";
import pathModule from "node:path";
import ora from "ora";
import { z } from "zod";
import { COMMAND_NAME } from "../consts.js";
import { getLatestPackageVersion } from "../utils/addDependencies.js";
import {
createFile,
pathExists,
readJSONFile,
writeJSONFile,
} from "../utils/fileSystem.js";
import { generateIntegrationFiles } from "../utils/generateIntegrationFiles.js";
import { installDependencies } from "../utils/installDependencies.js";
import { logger } from "../utils/logger.js";
import { resolvePath } from "../utils/parseNameAndPath.js";
import { COMMAND_NAME } from "../consts.js";
import inquirer from "inquirer";
// import { OpenAIApi } from "openai";
const CLIOptionsSchema = z.object({
packageName: z.string().optional(),
sdkPackage: z.string().optional(),
extraInfo: z.string().optional(),
skipGeneratingCode: z.coerce.boolean().optional(),
authMethod: z.enum(["api-key", "oauth", "both-methods"]).optional(),
});
type CLIOptions = z.infer<typeof CLIOptionsSchema>;
@@ -26,28 +39,294 @@ export async function createIntegrationCommand(path: string, cliOptions: any) {
const resolvedPath = resolvePath(path);
// make sure the resolvedPath doesn't exist
// if it does, print a warning and exit
const resolvedPathExists = await pathExists(resolvedPath);
if (resolvedPathExists) {
logger.error(
`The path ${resolvedPath} already exists. Please try again with a different path.`
);
process.exit(1);
}
const resolvedOptions = await resolveOptionsWithPrompts(
options,
resolvedPath
);
console.log(resolvedOptions);
const latestVersion = await getLatestPackageVersion(
resolvedOptions.sdkPackage,
"latest"
);
if (!latestVersion) {
logger.error(
`Could not find the latest version of ${resolvedOptions.sdkPackage}. Please try again later.`
);
process.exit(1);
}
const triggerMonorepoPath = await detectTriggerMonorepoPath(resolvedPath);
const sdkVersion = await getInternalOrExternalPackageVersion({
path: "packages/trigger-sdk",
packageName: "@trigger.dev/sdk",
tag: "next",
monorepoPath: triggerMonorepoPath,
});
if (!sdkVersion) {
logger.error(
`Could not find the latest version of @trigger.dev/sdk. Please try again later.`
);
process.exit(1);
}
const integrationKitVersion = await getInternalOrExternalPackageVersion({
path: "packages/integration-kit",
packageName: "@trigger.dev/integration-kit",
tag: "latest",
monorepoPath: triggerMonorepoPath,
});
if (!integrationKitVersion) {
logger.error(
`Could not find the latest version of @trigger.dev/integration-kit. Please try again later.`
);
process.exit(1);
}
// Create the package.json
const packageJson = {
name: resolvedOptions.packageName,
version: "0.0.1",
description: `Trigger.dev integration for ${resolvedOptions.sdkPackage}`,
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: {
"@types/node": "16.x",
rimraf: "^3.0.2",
tsup: "7.1.x",
typescript: "4.9.4",
},
scripts: {
clean: "rimraf dist",
build: "npm run clean && npm run build:tsup",
"build:tsup": "tsup",
typecheck: "tsc --noEmit",
},
dependencies: {
[latestVersion.name]: `^${latestVersion.version}`,
[sdkVersion.name]: sdkVersion.version,
[integrationKitVersion.name]: integrationKitVersion.version,
},
engines: {
node: ">=16.8.0",
},
};
await createFileInPath(
resolvedPath,
"package.json",
JSON.stringify(packageJson, null, 2)
);
// Create the tsconfig.json
const tsconfigJson = {
compilerOptions: {
composite: false,
declaration: false,
declarationMap: false,
esModuleInterop: true,
forceConsistentCasingInFileNames: true,
inlineSources: false,
isolatedModules: true,
moduleResolution: "node16",
noUnusedLocals: false,
noUnusedParameters: false,
preserveWatchOutput: true,
skipLibCheck: true,
strict: true,
experimentalDecorators: true,
emitDecoratorMetadata: true,
sourceMap: true,
resolveJsonModule: true,
lib: ["es2019"],
module: "commonjs",
target: "es2021",
},
include: ["./src/**/*.ts", "tsup.config.ts"],
exclude: ["node_modules"],
};
await createFileInPath(
resolvedPath,
"tsconfig.json",
JSON.stringify(tsconfigJson, null, 2)
);
// Create the tsup.config.ts
const tsupConfig = `
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"],
},
]);
`;
await createFileInPath(resolvedPath, "tsup.config.ts", tsupConfig);
if (resolvedOptions.skipGeneratingCode) {
await createFileInPath(resolvedPath, "src/index.ts", "export {}");
} else {
await attemptToGenerateIntegrationFiles(
pathModule.join(resolvedPath, "src"),
resolvedOptions
);
}
// If inside the monorepo:
if (triggerMonorepoPath) {
// Add the dependency to the nextjs-example package.json
// Add the paths to the nextjs-example tsconfig paths
await updateNextJsExampleProjectWithNewIntegration(
triggerMonorepoPath,
resolvedPath,
resolvedOptions
);
}
// Install the dependencies
await installDependencies(resolvedPath);
logger.success(
`✅ Successfully initialized ${resolvedOptions.packageName} at ${resolvedPath}`
);
logger.info("Next steps:");
logger.info(` 1. If you generated code, double check it for errors.`);
logger.info(
` 2. Read the "Creating an Integration" guide at https://trigger.dev/docs/integrations/create`
);
if (triggerMonorepoPath) {
logger.info(
` 3. Write some test jobs in the examples/nextjs-example project`
);
}
}
async function attemptToGenerateIntegrationFiles(
path: string,
options: ResolvedCLIOptions
) {
const spinner = ora("Generating integration code (may take ~30s)").start();
function generateExtraInfo(
authMethod: "api-key" | "oauth" | "both-methods",
extraInfo?: string
): string {
let authExtraInfo = "";
switch (authMethod) {
case "api-key": {
authExtraInfo =
"Note that the only auth method that this integration supports is API keys so can only useLocalAuth to true and don't use the clientFactory option";
break;
}
case "oauth": {
authExtraInfo =
"Note that the only auth method that this integration supports is OAuth so can only useLocalAuth to false and make sure to use the clientFactory option";
break;
}
case "both-methods": {
authExtraInfo =
"Note that this integration supports both API keys and OAuth so the options passed to the constructor must support both.";
break;
}
}
return `${authExtraInfo}\n\n${extraInfo ?? ""}`;
}
const extraInfo = generateExtraInfo(options.authMethod, options.extraInfo);
const files = await generateIntegrationFiles({
packageName: options.packageName,
sdkPackage: options.sdkPackage,
extraInfo,
});
if (files) {
await Promise.all(
Object.entries(files).map(([file, contents]) =>
createFileInPath(path, file, contents)
)
);
spinner.succeed(`Generated integration code in ${path}`);
} else {
spinner.fail("Failed to generate integration code");
}
}
async function createFileInPath(
path: string,
fileName: string,
contents: string
) {
await createFile(pathModule.join(path, fileName), contents);
}
const resolveOptionsWithPrompts = async (
options: CLIOptions,
_path: string
path: string
): Promise<ResolvedCLIOptions> => {
const resolvedOptions: CLIOptions = { ...options };
try {
if (!options.packageName) {
resolvedOptions.packageName = await promptPackageName();
resolvedOptions.packageName = await promptPackageName(path);
}
if (!options.sdkPackage) {
resolvedOptions.sdkPackage = await promptSdkPackage();
}
if (!process.env.OPENAI_API_KEY) {
resolvedOptions.skipGeneratingCode = true;
}
if (!resolvedOptions.skipGeneratingCode) {
resolvedOptions.authMethod = await promptAuthMethod();
resolvedOptions.extraInfo = await promptExtraInfo();
}
} catch (err) {
// If the user is not calling the command from an interactive terminal, inquirer will throw an error with isTTYError = true
// If this happens, we catch the error, tell the user what has happened, and then continue to run the program with a default trigger project
@@ -79,10 +358,13 @@ const resolveOptionsWithPrompts = async (
return resolvedOptions as ResolvedCLIOptions;
};
export const promptPackageName = async (): Promise<string> => {
export const promptPackageName = async (path: string): Promise<string> => {
const basename = pathModule.basename(path);
const { packageName } = await inquirer.prompt<{ packageName: string }>({
type: "input",
name: "packageName",
default: `@trigger.dev/${basename}`,
message: "What is the name of your integration package?",
validate: (input) => {
if (!input) {
@@ -100,7 +382,7 @@ export const promptSdkPackage = async (): Promise<string> => {
const { sdkPackage } = await inquirer.prompt<{ sdkPackage: string }>({
type: "input",
name: "sdkPackage",
message: "What is the name of the SDK package you would like to use?",
message: "What is the name of the npm package of the integration?",
validate: (input) => {
if (!input) {
return "Please enter an SDK package name";
@@ -112,3 +394,181 @@ export const promptSdkPackage = async (): Promise<string> => {
return sdkPackage;
};
export const promptExtraInfo = async (): Promise<string | undefined> => {
const { extraInfo } = await inquirer.prompt<{ extraInfo?: string }>({
type: "input",
name: "extraInfo",
message:
"Please describe in english anything else about using the SDK that might be useful (optional)",
});
return extraInfo;
};
// Choose between api-key, oauth, or both
export const promptAuthMethod = async (): Promise<
"api-key" | "oauth" | "both-methods"
> => {
const { authMethod } = await inquirer.prompt<{
authMethod: "api-key" | "oauth" | "both-methods";
}>({
type: "list",
name: "authMethod",
message: "What authentication method does this API use?",
choices: [
{
name: "API Key",
value: "api-key",
},
{
name: "OAuth",
value: "oauth",
},
{
name: "Both API Key and OAuth",
value: "both-methods",
},
],
});
return authMethod;
};
export const promptSkipGeneratingCode = async (): Promise<boolean> => {
const { skipGeneratingCode } = await inquirer.prompt<{
skipGeneratingCode: boolean;
}>({
type: "checkbox",
name: "skipGeneratingCode",
default: false,
message: "Would you like to skip generating the initial code?",
});
return skipGeneratingCode;
};
// Find where the github repo is located and check if it's the trigger.dev monorepo
async function detectTriggerMonorepoPath(
path: string
): Promise<string | undefined> {
const gitPath = await findGitPath(path);
if (!gitPath) {
return;
}
// Read the package.json file at
const rootPackageJsonPath = pathModule.join(gitPath, "package.json");
const rootPackageJsonExists = await pathExists(rootPackageJsonPath);
if (!rootPackageJsonExists) {
return;
}
const rootPackageJson = await readJSONFile(rootPackageJsonPath);
if (rootPackageJson.name === "triggerdotdev") {
return gitPath;
}
return;
}
async function getInternalOrExternalPackageVersion({
packageName,
tag,
path,
monorepoPath,
}: {
packageName: string;
tag: string;
path: string;
monorepoPath?: string;
}): Promise<{ name: string; version: string } | undefined> {
if (!monorepoPath) {
return await getLatestPackageVersion(packageName, tag);
}
// If there is a monorepo path then we will read the version from the package.json at that path
const packageJsonPath = pathModule.join(monorepoPath, path, "package.json");
const packageJsonExists = await pathExists(packageJsonPath);
if (!packageJsonExists) {
return await getLatestPackageVersion(packageName, tag);
}
const packageJson = await readJSONFile(packageJsonPath);
return {
name: packageJson.name,
version: `workspace:^${packageJson.version}`,
};
}
// Recursively search for a .git folder
async function findGitPath(path: string): Promise<string | undefined> {
const gitPath = pathModule.join(path, ".git");
const gitPathExists = await pathExists(gitPath);
if (gitPathExists) {
return path;
}
const parentPath = pathModule.dirname(path);
if (parentPath === path) {
return undefined;
}
return findGitPath(parentPath);
}
async function updateNextJsExampleProjectWithNewIntegration(
monorepoPath: string,
integrationPath: string,
resolvedOptions: ResolvedCLIOptions
) {
const nextjsPath = pathModule.join(
monorepoPath,
"examples",
"nextjs-example"
);
const packageJsonPath = pathModule.join(nextjsPath, "package.json");
const packageJson = await readJSONFile(packageJsonPath);
const newPackageJson = {
...packageJson,
dependencies: {
...packageJson.dependencies,
[resolvedOptions.packageName]: `workspace:*`,
},
};
await writeJSONFile(packageJsonPath, newPackageJson);
const tsConfigPath = pathModule.join(nextjsPath, "tsconfig.json");
const tsConfig = await readJSONFile(tsConfigPath);
const newTsConfig = {
...tsConfig,
compilerOptions: {
...tsConfig.compilerOptions,
paths: {
...tsConfig.compilerOptions.paths,
[resolvedOptions.packageName]: [
`../../integrations/${pathModule.basename(
integrationPath
)}/src/index`,
],
[`${resolvedOptions.packageName}/*`]: [
`../../integrations/${pathModule.basename(integrationPath)}/src/*`,
],
},
},
};
await writeJSONFile(tsConfigPath, newTsConfig);
}
+1 -9
View File
@@ -19,6 +19,7 @@ import { renderTitle } from "../utils/renderTitle.js";
import { detectNextJsProject } from "../utils/detectNextJsProject.js";
import { TriggerApi, WhoamiResponse } from "../utils/triggerApi.js";
import { readFile } from "tsconfig";
import { pathExists } from "../utils/fileSystem.js";
export type InitCommandOptions = {
projectPath: string;
@@ -706,12 +707,3 @@ async function setupEnvironmentVariable(
);
}
}
async function pathExists(path: string): Promise<boolean> {
try {
await fs.access(path);
return true;
} catch (error) {
return false;
}
}
+1 -1
View File
@@ -74,7 +74,7 @@ const PackageSchema = z.object({
"dist-tags": z.record(z.string()),
});
async function getLatestPackageVersion(
export async function getLatestPackageVersion(
packageName: string,
tag: string
): Promise<InstalledPackage | undefined> {
@@ -1,14 +0,0 @@
import path from "path";
import fs from "fs-extra";
export async function createDotEnvFile(projectPath: string, apiKey?: string) {
const envPath = path.join(projectPath, ".env");
const envExists = await fs.pathExists(envPath);
if (envExists) {
return;
}
const envContents = apiKey
? `TRIGGER_API_KEY=${apiKey}`
: "TRIGGER_API_KEY=<enter your API key here>";
await fs.writeFile(envPath, envContents);
}
+44
View File
@@ -0,0 +1,44 @@
import fsModule, { writeFile } from "fs/promises";
import fsSync from "fs";
import pathModule from "path";
// Creates a file at the given path, if the directory doesn't exist it will be created
export async function createFile(
path: string,
contents: string
): Promise<string> {
await fsModule.mkdir(pathModule.dirname(path), { recursive: true });
await fsModule.writeFile(path, contents);
return path;
}
export async function pathExists(path: string): Promise<boolean> {
try {
await fsModule.access(path);
return true;
} catch (err) {
return false;
}
}
export async function removeFile(path: string) {
await fsModule.unlink(path);
}
export async function readJSONFile(path: string) {
const fileContents = await fsModule.readFile(path, "utf-8");
return JSON.parse(fileContents);
}
export async function writeJSONFile(path: string, json: any) {
await writeFile(path, JSON.stringify(json, null, 2));
}
export function readJSONFileSync(path: string) {
const fileContents = fsSync.readFileSync(path, "utf-8");
return JSON.parse(fileContents);
}
@@ -0,0 +1,370 @@
import { OpenAIApi, Configuration } from "openai";
import { z } from "zod";
function createExampleResponse(args: {
index: string;
types: string;
tasks: string;
packageName: string;
sdkPackage: string;
}) {
const exampleFiles = {
"index.ts": args.index,
"types.ts": args.types,
"tasks.ts": args.tasks,
};
return `
Here is an example of what the files should look like for the package "${
args.packageName
}" using the SDK package "${args.sdkPackage}".
(Note that these files are formatted as a pair of JSON key/values, where the key is the file name and the value is the file contents.)
${JSON.stringify(exampleFiles, null, 2)}
`;
}
function createPrompt(
packageName: string,
sdkPackage: string,
extraInfo?: string
) {
return `'I\'m wanting to know what the minimal starting point index.ts, types.ts, and tasks.ts files should look like for the package "${packageName}" using the SDK package "${sdkPackage}". ${
extraInfo ?? ""
}`;
}
function createExampleMessages() {
return [
{
role: "user",
content: createPrompt(
"@trigger.dev.slack",
"@slack/web-api",
"Note that the only auth method support for slack is OAuth2 so shouldn't allow usesLocalAuth set to true"
),
},
{
role: "assistant",
content: createExampleResponse({
packageName: "@trigger.dev/slack",
sdkPackage: "@slack/web-api",
index: `
import { WebClient } from "@slack/web-api";
import type { IntegrationClient, TriggerIntegration } from "@trigger.dev/sdk";
import type { SlackSDK, SlackIntegrationOptions } from "./types";
import * as tasks from "./tasks";
export * from "./types";
type SlackIntegrationClient = IntegrationClient<SlackSDK, typeof tasks>;
type SlackIntegration = TriggerIntegration<SlackIntegrationClient>;
export class Slack
implements SlackIntegration
{
client: SlackIntegrationClient;
constructor(private options: SlackIntegrationOptions) {
this.client = {
tasks,
usesLocalAuth: false,
clientFactory: (auth) => {
return new WebClient(auth.accessToken);
},
};
}
get id() {
return this.options.id;
}
get metadata() {
return { id: "slack", name: "Slack.com" };
}
}
`,
tasks: `
import type {
SlackSDK,
ChatPostMessageParams,
ChatPostMessageResponse,
} from "./types";
export const postMessage: AuthenticatedTask<
SlackSDK,
ChatPostMessageParams,
ChatPostMessageResponse
> = {
run: async (params, client, task, io, auth) => {
const response = await client.chat.postMessage(params);
return response;
},
init: (params) => {
return {
name: "Post Message",
params,
icon: "slack",
properties: [
{
label: "Channel ID",
text: params.channel,
},
...(params.text ? [{ label: "Message", text: params.text }] : []),
],
};
},
};
`,
types: `
import { WebClient } from "@slack/web-api";
import { Prettify } from "@trigger.dev/integration-kit";
export type SlackSDK = WebClient;
export type SlackIntegrationOptions = {
id: string;
};
export type ChatPostMessageParams = {
channel: string;
text?: string;
as_user?: boolean;
attachments?: MessageAttachment[];
blocks?: (KnownBlock | Block)[];
icon_emoji?: string;
icon_url?: string;
metadata?: MessageMetadata;
link_names?: boolean;
mrkdwn?: boolean;
parse?: "full" | "none";
reply_broadcast?: boolean;
thread_ts?: string;
unfurl_links?: boolean;
unfurl_media?: boolean;
username?: string;
};
export type ChatPostMessageResponse = Prettify<Awaited<ReturnType<SlackSDK["chat"]["postMessage"]>>>;
`,
}),
},
{
role: "user",
content: createPrompt(
"@trigger.dev/typeform",
"@typeform/api-client",
"Note that the only auth method support for typeform is API Key should only allow usesLocalAuth set to true"
),
},
{
role: "assistant",
content: createExampleResponse({
packageName: "@trigger.dev/typeform",
sdkPackage: "@typeform/api-client",
index: `
import { createClient } from "@typeform/api-client";
import {
TypeformIntegrationOptions,
TypeformSDK,
} from "./types";
import {
TriggerIntegration,
IntegrationClient,
} from "@trigger.dev/sdk";
import * as tasks from "./tasks";
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" };
}
}
`,
tasks: `
import type { AuthenticatedTask } from "@trigger.dev/sdk";
import type {
GetFormParams,
GetFormResponse,
TypeformSDK,
} from "./types";
export 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,
},
],
};
},
};
`,
types: `
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 GetFormParams = {
uid: string;
};
export type GetFormResponse = Prettify<Typeform.Form>;
`,
}),
},
] as const;
}
export async function generateIntegrationFiles(payload: {
packageName: string;
sdkPackage: string;
extraInfo?: string;
}) {
if (!process.env.OPENAI_API_KEY) {
return;
}
const openai = new OpenAIApi(
new Configuration({
apiKey: process.env.OPENAI_API_KEY,
organization: process.env.OPENAI_ORGANIZATION,
})
);
try {
const response = await openai.createChatCompletion({
model: "gpt-4",
messages: [
{
role: "system",
content:
"You will be provided with the task of creating the typescript files necessary for a new Trigger.dev integration package. You will be provided the name of the integration package and the name of the SDK package.",
},
...createExampleMessages(),
{
role: "user",
content: createPrompt(
payload.packageName,
payload.sdkPackage,
payload.extraInfo
),
},
],
function_call: { name: "createTypescriptFiles" },
functions: [
{
name: "createTypescriptFiles",
description:
"Creates the initial typescript files for a new Trigger.dev package",
parameters: {
type: "object",
properties: {
"index.ts": {
type: "string",
description: "The contents of the index.ts file",
},
"tasks.ts": {
type: "string",
description: "The contents of the tasks.ts file",
},
"types.ts": {
type: "string",
description: "The contents of the types.ts file",
},
},
},
},
],
});
const responseData = response.data;
const firstChoice = responseData.choices[0];
if (!firstChoice) {
return;
}
const message = firstChoice.message;
if (!message) {
return;
}
if (!message.function_call || !message.function_call.arguments) {
return;
}
const functionCallArgs = safeJsonParse(message.function_call.arguments);
if (!functionCallArgs) {
return;
}
const filesSchema = z.record(z.string());
const files = filesSchema.safeParse(functionCallArgs);
if (!files.success) {
return;
}
return files.data;
} catch (error) {
console.error(error);
return;
}
}
function safeJsonParse(jsonString: string) {
try {
return JSON.parse(jsonString);
} catch (e) {
return null;
}
}
+4 -4
View File
@@ -1,12 +1,12 @@
import { type PackageJson } from "type-fest";
import path from "path";
import fs from "fs-extra";
import { PKG_ROOT } from "../consts.js";
import { readJSONFileSync } from "./fileSystem.js";
export const getVersion = () => {
export function getVersion() {
const packageJsonPath = path.join(PKG_ROOT, "package.json");
const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson;
const packageJsonContent = readJSONFileSync(packageJsonPath) as PackageJson;
return packageJsonContent.version ?? "1.0.0";
};
}
+5 -5
View File
@@ -1,11 +1,11 @@
import chalk from "chalk";
import { execSync } from "child_process";
import { execa } from "execa";
import fs from "fs-extra";
import inquirer from "inquirer";
import ora from "ora";
import path from "path";
import { logger } from "./logger.js";
import { pathExists, removeFile } from "./fileSystem.js";
const isGitInstalled = (dir: string): boolean => {
try {
@@ -17,8 +17,8 @@ const isGitInstalled = (dir: string): boolean => {
};
/** @returns Whether or not the provided directory has a `.git` subdirectory in it. */
const isRootGitRepo = (dir: string): boolean => {
return fs.existsSync(path.join(dir, ".git"));
const isRootGitRepo = (dir: string): Promise<boolean> => {
return pathExists(path.join(dir, ".git"));
};
/** @returns Whether or not this directory or a parent directory has a `.git` directory. */
@@ -64,7 +64,7 @@ export const initializeGit = async (projectDir: string) => {
const spinner = ora("Creating a new git repo...\n").start();
const isRoot = isRootGitRepo(projectDir);
const isRoot = await isRootGitRepo(projectDir);
const isInside = await isInsideGitRepo(projectDir);
const dirName = path.parse(projectDir).name; // skip full path for logging
@@ -86,7 +86,7 @@ export const initializeGit = async (projectDir: string) => {
return;
}
// Deleting the .git folder
fs.removeSync(path.join(projectDir, ".git"));
await removeFile(path.join(projectDir, ".git"));
} else if (isInside && !isRoot) {
// Dir is inside a git worktree
spinner.stop();
@@ -0,0 +1,74 @@
import { getUserPkgManager, type PackageManager } from "./getUserPkgManager.js";
import { logger } from "./logger.js";
import ora, { type Ora } from "ora";
import chalk from "chalk";
import { execa } from "execa";
export async function installDependencies(projectDir: string) {
logger.info("Installing dependencies...");
const pkgManager = getUserPkgManager();
const installSpinner = await runInstallCommand(pkgManager, projectDir);
// If the spinner was used to show the progress, use succeed method on it
// If not, use the succeed on a new spinner
(installSpinner || ora()).succeed(
chalk.green("Successfully installed dependencies!\n")
);
}
async function runInstallCommand(
pkgManager: PackageManager,
projectDir: string
): Promise<Ora | null> {
switch (pkgManager) {
// When using npm, inherit the stderr stream so that the progress bar is shown
case "npm":
await execa(pkgManager, ["install"], {
cwd: projectDir,
stderr: "inherit",
});
return null;
// When using yarn or pnpm, use the stdout stream and ora spinner to show the progress
case "pnpm":
const pnpmSpinner = ora("Running pnpm install...").start();
const pnpmSubprocess = execa(pkgManager, ["install"], {
cwd: projectDir,
stdout: "pipe",
});
await new Promise<void>((res, rej) => {
pnpmSubprocess.stdout?.on("data", (data: Buffer) => {
const text = data.toString();
if (text.includes("Progress")) {
pnpmSpinner.text = text.includes("|")
? text.split(" | ")[1] ?? ""
: text;
}
});
pnpmSubprocess.on("error", (e) => rej(e));
pnpmSubprocess.on("close", () => res());
});
return pnpmSpinner;
case "yarn":
const yarnSpinner = ora("Running yarn...").start();
const yarnSubprocess = execa(pkgManager, [], {
cwd: projectDir,
stdout: "pipe",
});
await new Promise<void>((res, rej) => {
yarnSubprocess.stdout?.on("data", (data: Buffer) => {
yarnSpinner.text = data.toString();
});
yarnSubprocess.on("error", (e) => rej(e));
yarnSubprocess.on("close", () => res());
});
return yarnSpinner;
}
}
+301 -23
View File
@@ -8,6 +8,7 @@ importers:
'@manypkg/cli': ^0.19.2
'@tailwindcss/forms': ^0.5.3
'@tailwindcss/typography': ^0.5.8
'@trigger.dev/cli': workspace:*
autoprefixer: ^10.4.12
eslint-config-custom: workspace:*
node-fetch: 2.6.x
@@ -26,6 +27,7 @@ importers:
'@manypkg/cli': 0.19.2
'@tailwindcss/forms': 0.5.3_tailwindcss@3.1.8
'@tailwindcss/typography': 0.5.9_tailwindcss@3.1.8
'@trigger.dev/cli': link:packages/cli
autoprefixer: 10.4.13_postcss@8.4.21
eslint-config-custom: link:config-packages/eslint-config-custom
postcss: 8.4.21
@@ -527,11 +529,11 @@ importers:
specifiers:
'@trigger.dev/integration-kit': workspace:^2.0.0-next.5
'@trigger.dev/sdk': workspace:^2.0.0-next.15
'@trigger.dev/tsconfig': workspace:*
'@typeform/api-client': ^1.8.0
'@types/node': '18'
'@types/node': 16.x
rimraf: ^3.0.2
tsup: ^6.5.0
tsup: 7.1.x
typescript: 4.9.4
zod: 3.21.4
dependencies:
'@trigger.dev/integration-kit': link:../../packages/integration-kit
@@ -539,15 +541,14 @@ importers:
'@typeform/api-client': 1.8.0
zod: 3.21.4
devDependencies:
'@trigger.dev/tsconfig': link:../../config-packages/tsconfig
'@types/node': 18.15.13
'@types/node': 16.18.11
rimraf: 3.0.2
tsup: 6.6.3
tsup: 7.1.0_typescript@4.9.4
typescript: 4.9.4
packages/cli:
specifiers:
'@types/degit': ^2.8.3
'@types/fs-extra': ^11.0.1
'@types/gradient-string': ^1.1.2
'@types/inquirer': ^9.0.3
'@types/node': '16'
@@ -557,7 +558,6 @@ importers:
commander: ^9.4.1
degit: ^2.8.4
execa: ^7.0.0
fs-extra: ^11.1.0
gradient-string: ^2.0.2
inquirer: ^9.1.4
localtunnel: ^2.0.2
@@ -581,7 +581,6 @@ importers:
commander: 9.5.0
degit: 2.8.4
execa: 7.0.0
fs-extra: 11.1.0
gradient-string: 2.0.2
inquirer: 9.1.4
localtunnel: 2.0.2
@@ -595,7 +594,6 @@ importers:
tsconfig: 7.0.0
zod: 3.21.4
devDependencies:
'@types/fs-extra': 11.0.1
'@types/gradient-string': 1.1.2
'@types/inquirer': 9.0.3
'@types/node': 16.18.11
@@ -3732,6 +3730,15 @@ packages:
dev: true
optional: true
/@esbuild/android-arm/0.18.11:
resolution: {integrity: sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm64/0.16.17:
resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==}
engines: {node: '>=12'}
@@ -3768,6 +3775,15 @@ packages:
dev: true
optional: true
/@esbuild/android-arm64/0.18.11:
resolution: {integrity: sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-x64/0.16.17:
resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==}
engines: {node: '>=12'}
@@ -3804,6 +3820,15 @@ packages:
dev: true
optional: true
/@esbuild/android-x64/0.18.11:
resolution: {integrity: sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-arm64/0.16.17:
resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==}
engines: {node: '>=12'}
@@ -3840,6 +3865,15 @@ packages:
dev: true
optional: true
/@esbuild/darwin-arm64/0.18.11:
resolution: {integrity: sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-x64/0.16.17:
resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==}
engines: {node: '>=12'}
@@ -3876,6 +3910,15 @@ packages:
dev: true
optional: true
/@esbuild/darwin-x64/0.18.11:
resolution: {integrity: sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-arm64/0.16.17:
resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==}
engines: {node: '>=12'}
@@ -3912,6 +3955,15 @@ packages:
dev: true
optional: true
/@esbuild/freebsd-arm64/0.18.11:
resolution: {integrity: sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-x64/0.16.17:
resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==}
engines: {node: '>=12'}
@@ -3948,6 +4000,15 @@ packages:
dev: true
optional: true
/@esbuild/freebsd-x64/0.18.11:
resolution: {integrity: sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm/0.16.17:
resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==}
engines: {node: '>=12'}
@@ -3984,6 +4045,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-arm/0.18.11:
resolution: {integrity: sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm64/0.16.17:
resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==}
engines: {node: '>=12'}
@@ -4020,6 +4090,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-arm64/0.18.11:
resolution: {integrity: sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ia32/0.16.17:
resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==}
engines: {node: '>=12'}
@@ -4056,6 +4135,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-ia32/0.18.11:
resolution: {integrity: sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-loong64/0.15.18:
resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==}
engines: {node: '>=12'}
@@ -4101,6 +4189,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-loong64/0.18.11:
resolution: {integrity: sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-mips64el/0.16.17:
resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==}
engines: {node: '>=12'}
@@ -4137,6 +4234,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-mips64el/0.18.11:
resolution: {integrity: sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ppc64/0.16.17:
resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==}
engines: {node: '>=12'}
@@ -4173,6 +4279,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-ppc64/0.18.11:
resolution: {integrity: sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-riscv64/0.16.17:
resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==}
engines: {node: '>=12'}
@@ -4209,6 +4324,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-riscv64/0.18.11:
resolution: {integrity: sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-s390x/0.16.17:
resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==}
engines: {node: '>=12'}
@@ -4245,6 +4369,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-s390x/0.18.11:
resolution: {integrity: sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-x64/0.16.17:
resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==}
engines: {node: '>=12'}
@@ -4281,6 +4414,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-x64/0.18.11:
resolution: {integrity: sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/netbsd-x64/0.16.17:
resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==}
engines: {node: '>=12'}
@@ -4317,6 +4459,15 @@ packages:
dev: true
optional: true
/@esbuild/netbsd-x64/0.18.11:
resolution: {integrity: sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/openbsd-x64/0.16.17:
resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==}
engines: {node: '>=12'}
@@ -4353,6 +4504,15 @@ packages:
dev: true
optional: true
/@esbuild/openbsd-x64/0.18.11:
resolution: {integrity: sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/sunos-x64/0.16.17:
resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==}
engines: {node: '>=12'}
@@ -4389,6 +4549,15 @@ packages:
dev: true
optional: true
/@esbuild/sunos-x64/0.18.11:
resolution: {integrity: sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-arm64/0.16.17:
resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==}
engines: {node: '>=12'}
@@ -4425,6 +4594,15 @@ packages:
dev: true
optional: true
/@esbuild/win32-arm64/0.18.11:
resolution: {integrity: sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-ia32/0.16.17:
resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==}
engines: {node: '>=12'}
@@ -4461,6 +4639,15 @@ packages:
dev: true
optional: true
/@esbuild/win32-ia32/0.18.11:
resolution: {integrity: sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-x64/0.16.17:
resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==}
engines: {node: '>=12'}
@@ -4497,6 +4684,15 @@ packages:
dev: true
optional: true
/@esbuild/win32-x64/0.18.11:
resolution: {integrity: sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@eslint-community/eslint-utils/4.4.0_eslint@8.31.0:
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -9778,13 +9974,6 @@ packages:
resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==}
dev: true
/@types/fs-extra/11.0.1:
resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==}
dependencies:
'@types/jsonfile': 6.1.1
'@types/node': 20.3.3
dev: true
/@types/generic-pool/3.8.1:
resolution: {integrity: sha512-eaMAbZS0EfKvaP5PUZ/Cdf5uJBO2t6T3RdvQTKuMqUwGhNpCnPAsKWEMyV+mCeCQG3UiHrtgdzni8X6DmhxRaQ==}
deprecated: This is a stub types definition. generic-pool provides its own type definitions, so you do not need this installed.
@@ -9932,12 +10121,6 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
/@types/jsonfile/6.1.1:
resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==}
dependencies:
'@types/node': 20.3.3
dev: true
/@types/jsonwebtoken/9.0.1:
resolution: {integrity: sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==}
dependencies:
@@ -11736,6 +11919,16 @@ packages:
load-tsconfig: 0.2.3
dev: true
/bundle-require/4.0.1_esbuild@0.18.11:
resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
peerDependencies:
esbuild: '>=0.17'
dependencies:
esbuild: 0.18.11
load-tsconfig: 0.2.3
dev: true
/busboy/1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
@@ -13572,6 +13765,36 @@ packages:
'@esbuild/win32-x64': 0.17.6
dev: true
/esbuild/0.18.11:
resolution: {integrity: sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.18.11
'@esbuild/android-arm64': 0.18.11
'@esbuild/android-x64': 0.18.11
'@esbuild/darwin-arm64': 0.18.11
'@esbuild/darwin-x64': 0.18.11
'@esbuild/freebsd-arm64': 0.18.11
'@esbuild/freebsd-x64': 0.18.11
'@esbuild/linux-arm': 0.18.11
'@esbuild/linux-arm64': 0.18.11
'@esbuild/linux-ia32': 0.18.11
'@esbuild/linux-loong64': 0.18.11
'@esbuild/linux-mips64el': 0.18.11
'@esbuild/linux-ppc64': 0.18.11
'@esbuild/linux-riscv64': 0.18.11
'@esbuild/linux-s390x': 0.18.11
'@esbuild/linux-x64': 0.18.11
'@esbuild/netbsd-x64': 0.18.11
'@esbuild/openbsd-x64': 0.18.11
'@esbuild/sunos-x64': 0.18.11
'@esbuild/win32-arm64': 0.18.11
'@esbuild/win32-ia32': 0.18.11
'@esbuild/win32-x64': 0.18.11
dev: true
/escalade/3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
@@ -15195,6 +15418,7 @@ packages:
graceful-fs: 4.2.10
jsonfile: 6.1.0
universalify: 2.0.0
dev: true
/fs-extra/7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
@@ -16882,6 +17106,7 @@ packages:
universalify: 2.0.0
optionalDependencies:
graceful-fs: 4.2.10
dev: true
/jsonpointer/5.0.1:
resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
@@ -19329,6 +19554,22 @@ packages:
yaml: 1.10.2
dev: true
/postcss-load-config/4.0.1:
resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
engines: {node: '>= 14'}
peerDependencies:
postcss: '>=8.0.9'
ts-node: '>=9.0.0'
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
dependencies:
lilconfig: 2.1.0
yaml: 2.3.1
dev: true
/postcss-load-config/4.0.1_3fojqsmttcn75cbnzsztj3o6qa:
resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
engines: {node: '>= 14'}
@@ -22277,6 +22518,42 @@ packages:
- ts-node
dev: true
/tsup/7.1.0_typescript@4.9.4:
resolution: {integrity: sha512-mazl/GRAk70j8S43/AbSYXGgvRP54oQeX8Un4iZxzATHt0roW0t6HYDVZIXMw0ZQIpvr1nFMniIVnN5186lW7w==}
engines: {node: '>=16.14'}
hasBin: true
peerDependencies:
'@swc/core': ^1
postcss: ^8.4.12
typescript: '>=4.1.0'
peerDependenciesMeta:
'@swc/core':
optional: true
postcss:
optional: true
typescript:
optional: true
dependencies:
bundle-require: 4.0.1_esbuild@0.18.11
cac: 6.7.14
chokidar: 3.5.3
debug: 4.3.4
esbuild: 0.18.11
execa: 5.1.1
globby: 11.1.0
joycon: 3.1.1
postcss-load-config: 4.0.1
resolve-from: 5.0.0
rollup: 3.10.0
source-map: 0.8.0-beta.0
sucrase: 3.32.0
tree-kill: 1.2.2
typescript: 4.9.4
transitivePeerDependencies:
- supports-color
- ts-node
dev: true
/tsutils/3.21.0:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
@@ -22673,6 +22950,7 @@ packages:
/universalify/2.0.0:
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
engines: {node: '>= 10.0.0'}
dev: true
/unpipe/1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}