Merge branch 'main' of github.com:triggerdotdev/trigger.dev
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Detects JSRuntime (Node/Deno at the moment). Adds basic Deno support
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Improve create-integration output. Use templates and shared configs.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/airtable": patch
|
||||
---
|
||||
|
||||
Export Base and Table
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"astro-build.astro-vscode",
|
||||
"denoland.vscode-deno"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
|
||||
]
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deno.enablePaths": ["references/deno-reference"]
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2019"],
|
||||
"paths": {
|
||||
"@trigger.dev/tsup/*": ["../../config-packages/tsup/src/*"],
|
||||
"@trigger.dev/tsup": ["../../config-packages/tsup/src/index"],
|
||||
"@trigger.dev/sdk/*": ["../../packages/trigger-sdk/src/*"],
|
||||
"@trigger.dev/sdk": ["../../packages/trigger-sdk/src/index"],
|
||||
"@trigger.dev/integration-kit/*": ["../../packages/integration-kit/src/*"],
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "@trigger.dev/tsup",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"tsup": "7.1.x"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { defineConfig } from "tsup";
|
||||
export { deepMergeOptions } from "./utils";
|
||||
export { options as integrationOptions } from "./integration";
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Options, defineConfig } from "tsup";
|
||||
|
||||
export const options: Options = {
|
||||
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"],
|
||||
};
|
||||
|
||||
export default defineConfig(options);
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Options } from "tsup";
|
||||
|
||||
export const deepMergeOptions = deepMergeRecords<Options>;
|
||||
|
||||
function deepMergeRecords<TRecord extends Record<any, any>>(...options: TRecord[]): TRecord {
|
||||
const result = {} as TRecord;
|
||||
|
||||
for (const option of options) {
|
||||
for (const key in option) {
|
||||
if (option.hasOwnProperty(key)) {
|
||||
const optionValue = option[key];
|
||||
const existingValue = result[key];
|
||||
|
||||
if (
|
||||
existingValue &&
|
||||
typeof existingValue === "object" &&
|
||||
typeof optionValue === "object" &&
|
||||
!Array.isArray(existingValue) &&
|
||||
!Array.isArray(optionValue) &&
|
||||
existingValue !== null &&
|
||||
optionValue !== null
|
||||
) {
|
||||
result[key] = deepMergeRecords(existingValue, optionValue);
|
||||
} else {
|
||||
result[key] = optionValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { Base } from "./base";
|
||||
import { Webhooks, createWebhookEventSource } from "./webhooks";
|
||||
|
||||
export * from "./types";
|
||||
export * from "./base";
|
||||
|
||||
export type AirtableIntegrationOptions = {
|
||||
/** An ID for this client */
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"execa": "^7.0.0",
|
||||
"gradient-string": "^2.0.2",
|
||||
"inquirer": "^9.1.4",
|
||||
"liquidjs": "^10.9.2",
|
||||
"localtunnel": "^2.0.2",
|
||||
"mock-fs": "^5.2.0",
|
||||
"nanoid": "^4.0.2",
|
||||
|
||||
@@ -14,7 +14,10 @@ import { checkApiKeyIsDevServer } from "../utils/getApiKeyType";
|
||||
|
||||
export const program = new Command();
|
||||
|
||||
program.name(COMMAND_NAME).description("The Trigger.dev CLI").version("0.0.1");
|
||||
program
|
||||
.name(COMMAND_NAME)
|
||||
.description("The Trigger.dev CLI")
|
||||
.version(getVersion(), "-v, --version", "Display the version number");
|
||||
|
||||
program
|
||||
.command("init")
|
||||
|
||||
@@ -9,7 +9,8 @@ import { generateIntegrationFiles } from "../utils/generateIntegrationFiles";
|
||||
import { getPackageName } from "../utils/getPackagName";
|
||||
import { installDependencies } from "../utils/installDependencies";
|
||||
import { logger } from "../utils/logger";
|
||||
import { resolvePath } from "../utils/parseNameAndPath";
|
||||
import { relativePath, resolvePath } from "../utils/parseNameAndPath";
|
||||
import { createIntegrationFileFromTemplate } from "../utils/createIntegrationFileFromTemplate";
|
||||
|
||||
const CLIOptionsSchema = z.object({
|
||||
packageName: z.string().optional(),
|
||||
@@ -91,108 +92,107 @@ export async function createIntegrationCommand(path: string, cliOptions: any) {
|
||||
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",
|
||||
},
|
||||
const integrationVersion = await getInternalOrExternalPackageVersion({
|
||||
path: "integrations/github",
|
||||
packageName: "@trigger.dev/github",
|
||||
tag: "latest",
|
||||
monorepoPath: triggerMonorepoPath,
|
||||
prependWorkspace: false,
|
||||
});
|
||||
|
||||
if (!integrationVersion) {
|
||||
logger.error(
|
||||
`Could not find the latest version of @trigger.dev/github. Please try again later.`
|
||||
);
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const baseVariables = {
|
||||
packageName: resolvedOptions.packageName,
|
||||
sdkPackage: resolvedOptions.sdkPackage,
|
||||
integrationVersion: integrationVersion,
|
||||
latestVersion: latestVersion,
|
||||
sdkVersion: sdkVersion,
|
||||
integrationKitVersion: integrationKitVersion,
|
||||
triggerMonorepoPath,
|
||||
};
|
||||
|
||||
await createFileInPath(resolvedPath, "package.json", JSON.stringify(packageJson, null, 2));
|
||||
const getOutputPath = (relativePath: string) => pathModule.join(resolvedPath, relativePath);
|
||||
|
||||
// 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",
|
||||
const miscIntegrationFiles = [
|
||||
{
|
||||
relativeTemplatePath: "package.json.j2",
|
||||
outputPath: getOutputPath("package.json"),
|
||||
},
|
||||
include: ["./src/**/*.ts", "tsup.config.ts"],
|
||||
exclude: ["node_modules"],
|
||||
};
|
||||
|
||||
await createFileInPath(resolvedPath, "tsconfig.json", JSON.stringify(tsconfigJson, null, 2));
|
||||
|
||||
const readme = `
|
||||
# ${resolvedOptions.packageName}
|
||||
`;
|
||||
|
||||
await createFileInPath(resolvedPath, "README.md", readme);
|
||||
|
||||
// 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",
|
||||
{
|
||||
// use `tsc --showConfig` to update external tsconfig
|
||||
relativeTemplatePath: `tsconfig-${triggerMonorepoPath ? "internal" : "external"}.json.j2`,
|
||||
outputPath: getOutputPath("tsconfig.json"),
|
||||
},
|
||||
esbuildPlugins: [],
|
||||
external: ["http", "https", "util", "events", "tty", "os", "timers"],
|
||||
},
|
||||
]);
|
||||
{
|
||||
relativeTemplatePath: `tsup.config-${triggerMonorepoPath ? "internal" : "external"}.js.j2`,
|
||||
outputPath: getOutputPath("tsup.config.ts"),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "README.md.j2",
|
||||
outputPath: getOutputPath("README.md"),
|
||||
},
|
||||
];
|
||||
|
||||
`;
|
||||
|
||||
await createFileInPath(resolvedPath, "tsup.config.ts", tsupConfig);
|
||||
await createIntegrationFiles(miscIntegrationFiles, baseVariables);
|
||||
|
||||
// create src/*
|
||||
if (resolvedOptions.skipGeneratingCode) {
|
||||
await createFileInPath(resolvedPath, "src/index.ts", "export {}");
|
||||
const getSrcOutputPath = (relativePath: string) =>
|
||||
getOutputPath(pathModule.join("src", relativePath));
|
||||
|
||||
const srcIntegrationFiles = [
|
||||
{
|
||||
relativeTemplatePath: pathModule.join("payload-examples", "index.js.j2"),
|
||||
outputPath: getSrcOutputPath(pathModule.join("payload-examples", "index.ts")),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "events.js.j2",
|
||||
outputPath: getSrcOutputPath("events.ts"),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "index.js.j2",
|
||||
outputPath: getSrcOutputPath("index.ts"),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "models.js.j2",
|
||||
outputPath: getSrcOutputPath("models.ts"),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "schemas.js.j2",
|
||||
outputPath: getSrcOutputPath("schemas.ts"),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "types.js.j2",
|
||||
outputPath: getSrcOutputPath("types.ts"),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "utils.js.j2",
|
||||
outputPath: getSrcOutputPath("utils.ts"),
|
||||
},
|
||||
{
|
||||
relativeTemplatePath: "webhooks.js.j2",
|
||||
outputPath: getSrcOutputPath("webhooks.ts"),
|
||||
},
|
||||
];
|
||||
|
||||
const validIdentifier = pathModule
|
||||
.basename(path)
|
||||
.replace(/[^a-zA-Z0-9]+/g, "")
|
||||
.replace(/^[0-9]+/g, "");
|
||||
|
||||
await createIntegrationFiles(srcIntegrationFiles, {
|
||||
...baseVariables,
|
||||
apiKeyPropertyName: "apiKey", // TODO: prompt for this
|
||||
authMethod: resolvedOptions.authMethod,
|
||||
identifier: validIdentifier.length ? validIdentifier : "packageName",
|
||||
});
|
||||
} else {
|
||||
await attemptToGenerateIntegrationFiles(pathModule.join(resolvedPath, "src"), resolvedOptions);
|
||||
}
|
||||
@@ -295,8 +295,9 @@ const resolveOptionsWithPrompts = async (
|
||||
resolvedOptions.skipGeneratingCode = true;
|
||||
}
|
||||
|
||||
resolvedOptions.authMethod = await promptAuthMethod();
|
||||
|
||||
if (!resolvedOptions.skipGeneratingCode) {
|
||||
resolvedOptions.authMethod = await promptAuthMethod();
|
||||
resolvedOptions.extraInfo = await promptExtraInfo();
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -448,11 +449,13 @@ async function getInternalOrExternalPackageVersion({
|
||||
tag,
|
||||
path,
|
||||
monorepoPath,
|
||||
prependWorkspace = true,
|
||||
}: {
|
||||
packageName: string;
|
||||
tag: string;
|
||||
path: string;
|
||||
monorepoPath?: string;
|
||||
prependWorkspace?: boolean;
|
||||
}): Promise<{ name: string; version: string } | undefined> {
|
||||
if (!monorepoPath) {
|
||||
return await getLatestPackageVersion(packageName, tag);
|
||||
@@ -470,7 +473,7 @@ async function getInternalOrExternalPackageVersion({
|
||||
|
||||
return {
|
||||
name: packageJson.name,
|
||||
version: `workspace:^${packageJson.version}`,
|
||||
version: `${prependWorkspace ? "workspace:^" : ""}${packageJson.version}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -550,3 +553,26 @@ async function updateJobCatalogWithNewIntegration(
|
||||
};
|
||||
await writeJSONFile(tsConfigPath, newTsConfig);
|
||||
}
|
||||
|
||||
const createIntegrationFiles = async (
|
||||
files: {
|
||||
relativeTemplatePath: string;
|
||||
outputPath: string;
|
||||
}[],
|
||||
variables?: Record<string, any>
|
||||
) => {
|
||||
for (const file of files) {
|
||||
const result = await createIntegrationFileFromTemplate({ ...file, variables });
|
||||
handleCreateResult(file.outputPath, result);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateResult = (
|
||||
outputPath: string,
|
||||
result: Awaited<ReturnType<typeof createIntegrationFileFromTemplate>>
|
||||
) => {
|
||||
if (!result.success) {
|
||||
throw new Error(`Failed to create ${pathModule.basename(outputPath)}: ${result.error}`);
|
||||
}
|
||||
logger.success(`✔ Created ${pathModule.basename(outputPath)} at ${relativePath(outputPath)}`);
|
||||
};
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import boxen from "boxen";
|
||||
import chalk from "chalk";
|
||||
import childProcess from "child_process";
|
||||
import chokidar from "chokidar";
|
||||
import fs from "fs/promises";
|
||||
import ngrok from "ngrok";
|
||||
import { run as ncuRun } from "npm-check-updates";
|
||||
import ora, { Ora } from "ora";
|
||||
import pRetry, { AbortError } from "p-retry";
|
||||
import pathModule from "path";
|
||||
import util from "util";
|
||||
import { z } from "zod";
|
||||
import { Framework, getFramework } from "../frameworks";
|
||||
import { Framework } from "../frameworks";
|
||||
import { standardWatchFilePaths, standardWatchIgnoreRegex } from "../frameworks/watchConfig";
|
||||
import { telemetryClient } from "../telemetry/telemetry";
|
||||
import { getEnvFilename } from "../utils/env";
|
||||
import fetch from "../utils/fetchUseProxy";
|
||||
import { getTriggerApiDetails } from "../utils/getTriggerApiDetails";
|
||||
import { getUserPackageManager } from "../utils/getUserPkgManager";
|
||||
import { JsRuntime, getJsRuntime } from "../utils/jsRuntime";
|
||||
import { logger } from "../utils/logger";
|
||||
import { resolvePath } from "../utils/parseNameAndPath";
|
||||
import { RequireKeys } from "../utils/requiredKeys";
|
||||
@@ -45,6 +41,8 @@ const formattedDate = new Intl.DateTimeFormat("en", {
|
||||
second: "numeric",
|
||||
});
|
||||
|
||||
let runtime: JsRuntime;
|
||||
|
||||
export async function devCommand(path: string, anyOptions: any) {
|
||||
telemetryClient.dev.started(path, anyOptions);
|
||||
|
||||
@@ -57,12 +55,12 @@ export async function devCommand(path: string, anyOptions: any) {
|
||||
const options = result.data;
|
||||
|
||||
const resolvedPath = resolvePath(path);
|
||||
|
||||
runtime = await getJsRuntime(resolvedPath, logger);
|
||||
//check for outdated packages, don't await this
|
||||
checkForOutdatedPackages(resolvedPath);
|
||||
runtime.checkForOutdatedPackages();
|
||||
|
||||
// Read from package.json to get the endpointId
|
||||
const endpointId = await getEndpointIdFromPackageJson(resolvedPath, options);
|
||||
const endpointId = await getEndpointId(runtime, options.clientId);
|
||||
if (!endpointId) {
|
||||
logger.error(
|
||||
"You must run the `init` command first to setup the project – you are missing \n'trigger.dev': { 'endpointId': 'your-client-id' } from your package.json file, or pass in the --client-id option to this command"
|
||||
@@ -73,8 +71,8 @@ export async function devCommand(path: string, anyOptions: any) {
|
||||
logger.success(`✔️ [trigger.dev] Detected TriggerClient id: ${endpointId}`);
|
||||
|
||||
//resolve the options using the detected framework (use default if there isn't a matching framework)
|
||||
const packageManager = await getUserPackageManager(resolvedPath);
|
||||
const framework = await getFramework(resolvedPath, packageManager);
|
||||
const packageManager = await runtime.getUserPackageManager();
|
||||
const framework = await runtime.getFramework();
|
||||
const resolvedOptions = await resolveOptions(framework, resolvedPath, options);
|
||||
|
||||
// Read from .env.local or .env to get the TRIGGER_API_KEY and TRIGGER_API_URL
|
||||
@@ -250,8 +248,7 @@ async function startIndexing({
|
||||
apiClient,
|
||||
}: RefreshOptions & { apiClient: TriggerApi }) {
|
||||
spinner.start();
|
||||
|
||||
const refreshedEndpointId = await getEndpointIdFromPackageJson(path, resolvedOptions);
|
||||
const refreshedEndpointId = await getEndpointId(runtime, resolvedOptions.clientId);
|
||||
|
||||
const authorizedKey = await apiClient.whoami();
|
||||
if (!authorizedKey) {
|
||||
@@ -396,43 +393,10 @@ async function verifyEndpoint(
|
||||
return;
|
||||
}
|
||||
|
||||
export async function checkForOutdatedPackages(path: string) {
|
||||
const updates = (await ncuRun({
|
||||
packageFile: `${path}/package.json`,
|
||||
filter: "/trigger.dev/.+$/",
|
||||
upgrade: false,
|
||||
})) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
if (typeof updates === "undefined" || Object.keys(updates).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const packageFile = await fs.readFile(`${path}/package.json`);
|
||||
const data = JSON.parse(Buffer.from(packageFile).toString("utf8"));
|
||||
const dependencies = data.dependencies;
|
||||
console.log(chalk.bgYellow("Updates available for trigger.dev packages"));
|
||||
console.log(chalk.bgBlue("Run npx @trigger.dev/cli@latest update"));
|
||||
|
||||
for (let dep in updates) {
|
||||
console.log(`${dep} ${dependencies[dep]} → ${updates[dep]}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getEndpointIdFromPackageJson(path: string, options: DevCommandOptions) {
|
||||
if (options.clientId) {
|
||||
return options.clientId;
|
||||
}
|
||||
|
||||
const pkgJsonPath = pathModule.join(path, "package.json");
|
||||
const pkgBuffer = await fs.readFile(pkgJsonPath);
|
||||
const pkgJson = JSON.parse(pkgBuffer.toString());
|
||||
|
||||
const value = pkgJson["trigger.dev"]?.endpointId;
|
||||
if (!value || typeof value !== "string") return;
|
||||
|
||||
return value as string;
|
||||
export function getEndpointId(runtime: JsRuntime, clientId?: string) {
|
||||
if (clientId) {
|
||||
return clientId;
|
||||
} else return runtime.getEndpointId();
|
||||
}
|
||||
|
||||
async function resolveEndpointUrl(apiUrl: string, port: number, hostname: string) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import { resolvePath } from "../utils/parseNameAndPath";
|
||||
import { readPackageJson } from "../utils/readPackageJson";
|
||||
import { renderTitle } from "../utils/renderTitle";
|
||||
import { TriggerApi, WhoamiResponse } from "../utils/triggerApi";
|
||||
import { getJsRuntime } from "../utils/jsRuntime";
|
||||
|
||||
export type InitCommandOptions = {
|
||||
projectPath: string;
|
||||
@@ -38,6 +39,19 @@ export const initCommand = async (options: InitCommandOptions) => {
|
||||
|
||||
const resolvedPath = resolvePath(options.projectPath);
|
||||
|
||||
// assuming nodejs by default
|
||||
let runtimeId: string = "nodejs";
|
||||
try {
|
||||
runtimeId = (await getJsRuntime(resolvedPath, logger)).id;
|
||||
} catch {}
|
||||
if (runtimeId !== "nodejs") {
|
||||
logger.error(
|
||||
`We currently only support automatic setup for NodeJS projects. This is a ${runtimeId} project. View our manual installation guides here: https://trigger.dev/docs/documentation/quickstarts/introduction`
|
||||
);
|
||||
telemetryClient.init.failed("not_supported_runtime", options);
|
||||
return;
|
||||
}
|
||||
|
||||
await renderTitle(resolvedPath);
|
||||
|
||||
if (options.triggerUrl === CLOUD_TRIGGER_URL) {
|
||||
|
||||
@@ -2,9 +2,10 @@ import { z } from "zod";
|
||||
import { logger } from "../utils/logger";
|
||||
import { resolvePath } from "../utils/parseNameAndPath";
|
||||
import { TriggerApi } from "../utils/triggerApi";
|
||||
import { DevCommandOptions, getEndpointIdFromPackageJson } from "./dev";
|
||||
import { DevCommandOptions, getEndpointId } from "./dev";
|
||||
import ora from "ora";
|
||||
import { getTriggerApiDetails } from "../utils/getTriggerApiDetails";
|
||||
import { getJsRuntime } from "../utils/jsRuntime";
|
||||
|
||||
export const WhoAmICommandOptionsSchema = z.object({
|
||||
envFile: z.string(),
|
||||
@@ -26,7 +27,8 @@ export async function whoamiCommand(path: string, anyOptions: any) {
|
||||
const resolvedPath = resolvePath(path);
|
||||
|
||||
// Read from package.json to get the endpointId
|
||||
const endpointId = await getEndpointIdFromPackageJson(resolvedPath, options as DevCommandOptions);
|
||||
const runtime = await getJsRuntime(resolvedPath, logger);
|
||||
const endpointId = await getEndpointId(runtime);
|
||||
if (!endpointId) {
|
||||
logger.error(
|
||||
"You must run the `init` command first to setup the project – you are missing \n'trigger.dev': { 'endpointId': 'your-client-id' } from your package.json file, or pass in the --client-id option to this command"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# {{ packageName }}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { EventSpecification } from "@trigger.dev/sdk";
|
||||
import { CommentEvent, IssueEvent } from "./schemas";
|
||||
import { Get{{ identifier | capitalize }}Payload } from "./types";
|
||||
import {
|
||||
commentCreated,
|
||||
commentRemoved,
|
||||
commentUpdated,
|
||||
issueCreated,
|
||||
issueRemoved,
|
||||
issueUpdated,
|
||||
} from "./payload-examples";
|
||||
import { onCommentProperties, onIssueProperties, updatedFromProperties } from "./utils";
|
||||
|
||||
export const onComment: EventSpecification<Get{{ identifier | capitalize }}Payload<CommentEvent>> = {
|
||||
name: "Comment",
|
||||
title: "On Comment",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
examples: [commentCreated, commentRemoved, commentUpdated],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<CommentEvent>,
|
||||
runProperties: (payload) => [
|
||||
{ label: "Event action", text: payload.action },
|
||||
...onCommentProperties(payload),
|
||||
...updatedFromProperties(payload),
|
||||
],
|
||||
};
|
||||
|
||||
export const onCommentCreated: EventSpecification<Get{{ identifier | capitalize }}Payload<CommentEvent, "create">> = {
|
||||
name: "Comment",
|
||||
title: "On Comment Created",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
filter: {
|
||||
action: ["create"],
|
||||
},
|
||||
examples: [commentCreated],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<CommentEvent, "create">,
|
||||
runProperties: (payload) => onCommentProperties(payload),
|
||||
};
|
||||
|
||||
export const onCommentRemoved: EventSpecification<Get{{ identifier | capitalize }}Payload<CommentEvent, "remove">> = {
|
||||
name: "Comment",
|
||||
title: "On Comment Removed",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
filter: {
|
||||
action: ["remove"],
|
||||
},
|
||||
examples: [commentRemoved],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<CommentEvent, "remove">,
|
||||
runProperties: (payload) => onCommentProperties(payload),
|
||||
};
|
||||
|
||||
export const onCommentUpdated: EventSpecification<Get{{ identifier | capitalize }}Payload<CommentEvent, "update">> = {
|
||||
name: "Comment",
|
||||
title: "On Comment Updated",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
filter: {
|
||||
action: ["update"],
|
||||
},
|
||||
examples: [commentUpdated],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<CommentEvent, "update">,
|
||||
runProperties: (payload) => [...onCommentProperties(payload), ...updatedFromProperties(payload)],
|
||||
};
|
||||
|
||||
export const onIssue: EventSpecification<Get{{ identifier | capitalize }}Payload<IssueEvent>> = {
|
||||
name: "Issue",
|
||||
title: "On Issue",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
examples: [issueCreated, issueRemoved, issueUpdated],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<IssueEvent>,
|
||||
runProperties: (payload) => [
|
||||
{ label: "Event action", text: payload.action },
|
||||
...onIssueProperties(payload),
|
||||
...updatedFromProperties(payload),
|
||||
],
|
||||
};
|
||||
|
||||
export const onIssueCreated: EventSpecification<Get{{ identifier | capitalize }}Payload<IssueEvent, "create">> = {
|
||||
name: "Issue",
|
||||
title: "On Issue Created",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
filter: {
|
||||
action: ["create"],
|
||||
},
|
||||
examples: [issueCreated],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<IssueEvent, "create">,
|
||||
runProperties: (payload) => onIssueProperties(payload),
|
||||
};
|
||||
|
||||
export const onIssueRemoved: EventSpecification<Get{{ identifier | capitalize }}Payload<IssueEvent, "remove">> = {
|
||||
name: "Issue",
|
||||
title: "On Issue Removed",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
filter: {
|
||||
action: ["remove"],
|
||||
},
|
||||
examples: [issueRemoved],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<IssueEvent, "remove">,
|
||||
runProperties: (payload) => onIssueProperties(payload),
|
||||
};
|
||||
|
||||
export const onIssueUpdated: EventSpecification<Get{{ identifier | capitalize }}Payload<IssueEvent, "update">> = {
|
||||
name: "Issue",
|
||||
title: "On Issue Updated",
|
||||
source: "linear.app",
|
||||
icon: "linear",
|
||||
filter: {
|
||||
action: ["update"],
|
||||
},
|
||||
examples: [issueUpdated],
|
||||
parsePayload: (payload) => payload as Get{{ identifier | capitalize }}Payload<IssueEvent, "update">,
|
||||
runProperties: (payload) => [...onIssueProperties(payload), ...updatedFromProperties(payload)],
|
||||
};
|
||||
@@ -0,0 +1,244 @@
|
||||
import {
|
||||
TriggerIntegration,
|
||||
RunTaskOptions,
|
||||
IO,
|
||||
IOTask,
|
||||
IntegrationTaskKey,
|
||||
RunTaskErrorCallback,
|
||||
Json,
|
||||
retry,
|
||||
ConnectionAuth,
|
||||
Prettify,
|
||||
} from "@trigger.dev/sdk";
|
||||
import {{ identifier | capitalize }}Client from "{{ sdkPackage }}";
|
||||
|
||||
import * as events from "./events";
|
||||
import { {{ identifier | capitalize }}ReturnType, Serialized{{ identifier | capitalize }}Output } from "./types";
|
||||
import { TriggerParams, Webhooks, createTrigger, createWebhookEventSource } from "./webhooks";
|
||||
import { Models } from "./models";
|
||||
|
||||
export type {{ identifier | capitalize }}IntegrationOptions = {
|
||||
id: string;
|
||||
{{ apiKeyPropertyName }}: string;
|
||||
};
|
||||
|
||||
export type {{ identifier | capitalize }}RunTask = InstanceType<typeof {{ identifier | capitalize }}>["runTask"];
|
||||
|
||||
export class {{ identifier | capitalize }}{{ " " }} implements TriggerIntegration {
|
||||
private _options: {{ identifier | capitalize }}IntegrationOptions;
|
||||
private _client?: any;
|
||||
private _io?: IO;
|
||||
private _connectionKey?: string;
|
||||
|
||||
constructor(private options: {{ identifier | capitalize }}IntegrationOptions) {
|
||||
if (Object.keys(options).includes("{{ apiKeyPropertyName }}") && !options.{{ apiKeyPropertyName }}) {
|
||||
throw `Can't create {{ identifier | capitalize }} integration (${options.id}) as {{ apiKeyPropertyName }} was undefined`;
|
||||
}
|
||||
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
get authSource() {
|
||||
{% case authMethod %}
|
||||
{% when "api-key" %}
|
||||
return "LOCAL" as const;
|
||||
{% when "oauth" %}
|
||||
return "HOSTED" as const;
|
||||
{% when "both-methods" %}
|
||||
return this._options.{{ apiKeyPropertyName }} ? "LOCAL" : "HOSTED";
|
||||
{% endcase %}
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.options.id;
|
||||
}
|
||||
|
||||
get metadata() {
|
||||
return { id: "{{ identifier }}", name: "{{ identifier | capitalize }}" };
|
||||
}
|
||||
|
||||
get source() {
|
||||
return createWebhookEventSource(this);
|
||||
}
|
||||
|
||||
cloneForRun(io: IO, connectionKey: string, auth?: ConnectionAuth) {
|
||||
const {{ identifier }} = new {{ identifier | capitalize }}(this._options);
|
||||
{{ identifier }}._io = io;
|
||||
{{ identifier }}._connectionKey = connectionKey;
|
||||
{{ identifier }}._client = this.createClient(auth);
|
||||
return {{ identifier }};
|
||||
}
|
||||
|
||||
createClient(auth?: ConnectionAuth) {
|
||||
// oauth
|
||||
if (auth) {
|
||||
return new {{ identifier | capitalize }}Client({
|
||||
auth: auth.accessToken,
|
||||
});
|
||||
}
|
||||
|
||||
// apiKey auth
|
||||
if (this._options.{{ apiKeyPropertyName }}) {
|
||||
return new {{ identifier | capitalize }}Client({
|
||||
apiKey: this._options.{{ apiKeyPropertyName }},
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error("No auth");
|
||||
}
|
||||
|
||||
runTask<T, TResult extends Json<T> | void>(
|
||||
key: IntegrationTaskKey,
|
||||
callback: (client: {{ identifier | capitalize }}Client, task: IOTask, io: IO) => Promise<TResult>,
|
||||
options?: RunTaskOptions,
|
||||
errorCallback?: RunTaskErrorCallback
|
||||
): Promise<TResult> {
|
||||
if (!this._io) throw new Error("No IO");
|
||||
if (!this._connectionKey) throw new Error("No connection key");
|
||||
|
||||
return this._io.runTask<TResult>(
|
||||
key,
|
||||
(task, io) => {
|
||||
if (!this._client) throw new Error("No client");
|
||||
return callback(this._client, task, io);
|
||||
},
|
||||
{
|
||||
icon: "{{ identifier }}",
|
||||
retry: retry.standardBackoff,
|
||||
...(options ?? {}),
|
||||
connectionKey: this._connectionKey,
|
||||
},
|
||||
errorCallback ?? onError
|
||||
);
|
||||
}
|
||||
|
||||
// top-level task
|
||||
|
||||
request<T = any>(
|
||||
key: IntegrationTaskKey,
|
||||
params: {
|
||||
route: string | URL;
|
||||
options: Parameters<{{ identifier | capitalize }}Client["request"]>[1];
|
||||
}
|
||||
): {{ identifier | capitalize }}ReturnType<T> {
|
||||
return this.runTask(
|
||||
key,
|
||||
async (client) => {
|
||||
const response = await client.request(params.route, params.options);
|
||||
|
||||
return response.json();
|
||||
},
|
||||
{
|
||||
name: "Send Request",
|
||||
params,
|
||||
properties: [
|
||||
{ label: "Route", text: params.route.toString() },
|
||||
...(params.options.method ? [{ label: "Method", text: params.options.method }] : []),
|
||||
],
|
||||
callback: { enabled: true },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// nested tasks
|
||||
|
||||
get models() {
|
||||
return new Models(this.runTask.bind(this));
|
||||
}
|
||||
|
||||
// events
|
||||
|
||||
onComment(params: TriggerParams = {}) {
|
||||
return createTrigger(this.source, events.onComment, params);
|
||||
}
|
||||
|
||||
onCommentCreated(params: TriggerParams = {}) {
|
||||
return createTrigger(this.source, events.onCommentCreated, params);
|
||||
}
|
||||
|
||||
onCommentRemoved(params: TriggerParams = {}) {
|
||||
return createTrigger(this.source, events.onCommentRemoved, params);
|
||||
}
|
||||
|
||||
onCommentUpdated(params: TriggerParams = {}) {
|
||||
return createTrigger(this.source, events.onCommentUpdated, params);
|
||||
}
|
||||
|
||||
// triggers (webhooks)
|
||||
|
||||
// private, just here to keep webhook logic in a separate file
|
||||
get #webhooks() {
|
||||
return new Webhooks(this.runTask.bind(this));
|
||||
}
|
||||
|
||||
webhook = this.#webhooks.webhook;
|
||||
webhooks = this.#webhooks.webhooks;
|
||||
|
||||
createWebhook = this.#webhooks.createWebhook;
|
||||
deleteWebhook = this.#webhooks.deleteWebhook;
|
||||
updateWebhook = this.#webhooks.updateWebhook;
|
||||
}
|
||||
|
||||
class {{ identifier | capitalize }}ApiError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
readonly request: Request,
|
||||
readonly response: Response
|
||||
) {
|
||||
super(message);
|
||||
this.name = "{{ identifier | capitalize }}ApiError";
|
||||
}
|
||||
}
|
||||
|
||||
function is{{ identifier | capitalize }}ApiError(error: unknown): error is {{ identifier | capitalize }}ApiError {
|
||||
if (typeof error !== "object" || error === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const apiError = error as {{ identifier | capitalize }}ApiError;
|
||||
|
||||
return (
|
||||
apiError.name === "{{ identifier | capitalize }}ApiError" &&
|
||||
apiError.request instanceof Request &&
|
||||
apiError.response instanceof Response
|
||||
);
|
||||
}
|
||||
|
||||
function shouldRetry(method: string, status: number) {
|
||||
return status === 429 || (method === "GET" && status >= 500);
|
||||
}
|
||||
|
||||
export function onError(error: unknown): ReturnType<RunTaskErrorCallback> {
|
||||
if (!is{{ identifier | capitalize }}ApiError(error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldRetry(error.request.method, error.response.status)) {
|
||||
return {
|
||||
skipRetrying: true,
|
||||
};
|
||||
}
|
||||
|
||||
const rateLimitRemaining = error.response.headers.get("ratelimit-remaining");
|
||||
const rateLimitReset = error.response.headers.get("ratelimit-reset");
|
||||
|
||||
if (rateLimitRemaining === "0" && rateLimitReset) {
|
||||
const resetDate = new Date(Number(rateLimitReset) * 1000);
|
||||
|
||||
if (!Number.isNaN(resetDate.getTime())) {
|
||||
return {
|
||||
retryAt: resetDate,
|
||||
error,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const serialize{{ identifier | capitalize }}Output = <T>(obj: T): Prettify<Serialized{{ identifier | capitalize }}Output<T>> => {
|
||||
return JSON.parse(JSON.stringify(obj), (key, value) => {
|
||||
if (typeof value === "function" || key.startsWith("_")) {
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
import { IntegrationTaskKey } from "@trigger.dev/sdk";
|
||||
import { Model, ModelVersion } from "{{ sdkPackage }}";
|
||||
|
||||
import { {{ capitalizedIdentifier }}RunTask } from "./index";
|
||||
import { modelProperties } from "./utils";
|
||||
import { {{ capitalizedIdentifier }}ReturnType } from "./types";
|
||||
|
||||
export class Models {
|
||||
constructor(private runTask: {{ capitalizedIdentifier }}RunTask) {}
|
||||
|
||||
get(
|
||||
key: IntegrationTaskKey,
|
||||
params: {
|
||||
model_owner: string;
|
||||
model_name: string;
|
||||
}
|
||||
): {{ capitalizedIdentifier }}ReturnType<Model> {
|
||||
return this.runTask(
|
||||
key,
|
||||
(client) => {
|
||||
return client.models.get(params.model_owner, params.model_name);
|
||||
},
|
||||
{
|
||||
name: "Get Model",
|
||||
params,
|
||||
properties: modelProperties(params),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
get versions() {
|
||||
return new Versions(this.runTask);
|
||||
}
|
||||
}
|
||||
|
||||
class Versions {
|
||||
constructor(private runTask: {{ capitalizedIdentifier }}RunTask) {}
|
||||
|
||||
get(
|
||||
key: IntegrationTaskKey,
|
||||
params: {
|
||||
model_owner: string;
|
||||
model_name: string;
|
||||
version_id: string;
|
||||
}
|
||||
): {{ capitalizedIdentifier }}ReturnType<ModelVersion> {
|
||||
return this.runTask(
|
||||
key,
|
||||
(client) => {
|
||||
return client.models.versions.get(params.model_owner, params.model_name, params.version_id);
|
||||
},
|
||||
{
|
||||
name: "Get Model Version",
|
||||
params,
|
||||
properties: modelProperties(params),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
list(
|
||||
key: IntegrationTaskKey,
|
||||
params: {
|
||||
model_owner: string;
|
||||
model_name: string;
|
||||
}
|
||||
): {{ capitalizedIdentifier }}ReturnType<ModelVersion[]> {
|
||||
return this.runTask(
|
||||
key,
|
||||
(client) => {
|
||||
return client.models.versions.list(params.model_owner, params.model_name);
|
||||
},
|
||||
{
|
||||
name: "List Models",
|
||||
params,
|
||||
properties: modelProperties(params),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "{{ packageName }}",
|
||||
"version": "{{ integrationVersion.version }}",
|
||||
"description": "Trigger.dev integration for {{ 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": {
|
||||
{% if triggerMonorepoPath %}
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
"@trigger.dev/tsup": "workspace:*",
|
||||
{% endif %}
|
||||
"@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 }}",
|
||||
"zod": "3.21.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.8.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { EventSpecificationExample } from "@trigger.dev/sdk";
|
||||
|
||||
import CommentCreated from "./CommentCreated.json"
|
||||
import CommentRemoved from "./CommentRemoved.json"
|
||||
import CommentUpdated from "./CommentUpdated.json"
|
||||
import IssueCreated from "./IssueCreated.json"
|
||||
import IssueRemoved from "./IssueRemoved.json"
|
||||
import IssueUpdated from "./IssueUpdated.json"
|
||||
|
||||
export const commentCreated: EventSpecificationExample = {
|
||||
id: "CommentCreated",
|
||||
name: "Comment created",
|
||||
payload: CommentCreated,
|
||||
};
|
||||
export const commentRemoved: EventSpecificationExample = {
|
||||
id: "CommentRemoved",
|
||||
name: "Comment removed",
|
||||
payload: CommentRemoved,
|
||||
};
|
||||
export const commentUpdated: EventSpecificationExample = {
|
||||
id: "CommentUpdated",
|
||||
name: "Comment updated",
|
||||
payload: CommentUpdated,
|
||||
};
|
||||
|
||||
export const issueCreated: EventSpecificationExample = {
|
||||
id: "IssueCreated",
|
||||
name: "Issue created",
|
||||
payload: IssueCreated,
|
||||
};
|
||||
export const issueRemoved: EventSpecificationExample = {
|
||||
id: "IssueRemoved",
|
||||
name: "Issue removed",
|
||||
payload: IssueRemoved,
|
||||
};
|
||||
export const issueUpdated: EventSpecificationExample = {
|
||||
id: "IssueUpdated",
|
||||
name: "Issue updated",
|
||||
payload: IssueUpdated,
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const WebhookResourceTypeSchema = z.union([
|
||||
z.literal("Comment"),
|
||||
z.literal("Issue"),
|
||||
]);
|
||||
export type WebhookResourceType = z.infer<typeof WebhookResourceTypeSchema>;
|
||||
|
||||
export const WebhookActionTypeSchema = z.union([
|
||||
z.literal("create"),
|
||||
z.literal("remove"),
|
||||
z.literal("update"),
|
||||
]);
|
||||
export type WebhookActionType = z.infer<typeof WebhookActionTypeSchema>;
|
||||
|
||||
const IssueLabelDataSchema = z.object({
|
||||
archivedAt: z.coerce.date().optional().nullable(),
|
||||
color: z.string(),
|
||||
createdAt: z.coerce.date(),
|
||||
creatorId: z.string().optional().nullable(),
|
||||
description: z.string().optional().nullable(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
organizationId: z.string(),
|
||||
parentId: z.string().optional().nullable(),
|
||||
teamId: z.string().optional().nullable(),
|
||||
updatedAt: z.coerce.date(),
|
||||
});
|
||||
|
||||
const IssueDataSchema = z.object({
|
||||
archivedAt: z.coerce.date().optional().nullable(),
|
||||
assignee: z.object({ id: z.string(), name: z.string() }).optional().nullable(),
|
||||
assigneeId: z.string().optional().nullable(),
|
||||
id: z.string(),
|
||||
labelIds: z.array(z.string()),
|
||||
labels: z.array(IssueLabelDataSchema.pick({ id: true, color: true, name: true })),
|
||||
number: z.number(),
|
||||
parentId: z.string().optional().nullable(),
|
||||
previousIdentifiers: z.array(z.string()),
|
||||
priority: z.number(),
|
||||
priorityLabel: z.string(),
|
||||
projectId: z.string().optional().nullable(),
|
||||
sortOrder: z.number(),
|
||||
team: z.object({ id: z.string(), key: z.string(), name: z.string() }),
|
||||
teamId: z.string(),
|
||||
title: z.string(),
|
||||
trashed: z.boolean().optional().nullable(),
|
||||
triagedAt: z.coerce.date().optional().nullable(),
|
||||
updatedAt: z.coerce.date(),
|
||||
});
|
||||
|
||||
const CommentDataSchema = z.object({
|
||||
archivedAt: z.coerce.date().optional().nullable(),
|
||||
body: z.string(),
|
||||
botActorId: z.string().optional().nullable(),
|
||||
createdAt: z.coerce.date(),
|
||||
editedAt: z.string().optional().nullable(),
|
||||
id: z.string(),
|
||||
issue: IssueDataSchema.pick({ id: true, title: true }),
|
||||
issueId: z.string(),
|
||||
parentId: z.string().optional().nullable(),
|
||||
reactionData: z.array(z.object({}).passthrough()),
|
||||
updatedAt: z.coerce.date(),
|
||||
userId: z.string().optional().nullable(),
|
||||
});
|
||||
|
||||
export const WebhookPayloadBaseSchema = z.object({
|
||||
createdAt: z.coerce.date(),
|
||||
organizationId: z.string().optional().nullable(),
|
||||
url: z.string().url().optional().nullable(),
|
||||
webhookId: z.string(),
|
||||
webhookTimestamp: z.coerce.date(),
|
||||
});
|
||||
|
||||
const CREATE = z.literal("create");
|
||||
const REMOVE = z.literal("remove");
|
||||
const UPDATE = z.literal("update");
|
||||
|
||||
export const CommentEventBaseSchema = WebhookPayloadBaseSchema.extend({
|
||||
type: z.literal("Comment"),
|
||||
data: CommentDataSchema,
|
||||
});
|
||||
export const CommentEventSchema = z.discriminatedUnion("action", [
|
||||
CommentEventBaseSchema.extend({
|
||||
action: CREATE,
|
||||
}),
|
||||
CommentEventBaseSchema.extend({
|
||||
action: REMOVE,
|
||||
}),
|
||||
CommentEventBaseSchema.extend({
|
||||
action: UPDATE,
|
||||
updatedFrom: CommentDataSchema.partial(),
|
||||
}),
|
||||
]);
|
||||
export type CommentEvent = z.infer<typeof CommentEventSchema>;
|
||||
|
||||
export const IssueEventBaseSchema = WebhookPayloadBaseSchema.extend({
|
||||
type: z.literal("Issue"),
|
||||
data: IssueDataSchema,
|
||||
});
|
||||
export const IssueEventSchema = z.discriminatedUnion("action", [
|
||||
IssueEventBaseSchema.extend({
|
||||
action: CREATE,
|
||||
}),
|
||||
IssueEventBaseSchema.extend({
|
||||
action: REMOVE,
|
||||
}),
|
||||
IssueEventBaseSchema.extend({
|
||||
action: UPDATE,
|
||||
updatedFrom: IssueDataSchema.partial(),
|
||||
}),
|
||||
]);
|
||||
export type IssueEvent = z.infer<typeof IssueEventSchema>;
|
||||
|
||||
export const WebhookPayloadSchema = z.union([
|
||||
CommentEventSchema,
|
||||
IssueEventSchema,
|
||||
]);
|
||||
|
||||
export type WebhookPayload = z.infer<typeof WebhookPayloadSchema>;
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": false,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"inlineSources": false,
|
||||
"isolatedModules": true,
|
||||
"moduleResolution": "node",
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"preserveWatchOutput": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"lib": ["dom", "dom.iterable", "es2019"],
|
||||
"module": "commonjs",
|
||||
"target": "es2021",
|
||||
"stripInternal": true
|
||||
},
|
||||
"include": ["./src/**/*.ts", "tsup.config.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "@trigger.dev/tsconfig/integration.json",
|
||||
"include": ["./src/**/*.ts", "tsup.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
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"],
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig, deepMergeOptions, integrationOptions } from "@trigger.dev/tsup";
|
||||
|
||||
const options = deepMergeOptions(integrationOptions, {
|
||||
// extend base config here
|
||||
});
|
||||
|
||||
export default defineConfig(options);
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Request } from "{{ sdkPackage }}";
|
||||
import { WebhookActionType, WebhookPayload } from "./schemas";
|
||||
|
||||
export type Get{{ identifier | capitalize }}Payload<
|
||||
TPayload extends WebhookPayload,
|
||||
TAction extends any = any,
|
||||
> = TAction extends WebhookActionType ? Extract<TPayload, { action: TAction }> : TPayload;
|
||||
|
||||
type FunctionKeys<T> = {
|
||||
[K in keyof T]: T[K] extends Function ? K : never;
|
||||
}[keyof T];
|
||||
|
||||
export type Serialized{{ identifier | capitalize }}Output<T> = T extends object
|
||||
? T extends Array<infer U>
|
||||
? Array<Serialized{{ identifier | capitalize }}Output<U>>
|
||||
: { [K in keyof T as Exclude<K, FunctionKeys<T> | `_${string}`>]: Serialized{{ identifier | capitalize }}Output<T[K]> }
|
||||
: T;
|
||||
|
||||
export type {{ identifier | capitalize }}ReturnType<
|
||||
TPayload extends Omit<Request, "_request">,
|
||||
K extends unknown = unknown,
|
||||
> = Promise<
|
||||
Awaited<Serialized{{ identifier | capitalize }}Output<Awaited<K extends keyof TPayload ? TPayload[K] : TPayload>>>
|
||||
>;
|
||||
|
||||
export type AwaitNested<T extends object, K extends keyof T> = Omit<T, K> & {
|
||||
[key in K]: Awaited<T[K]>;
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
import { CommentEvent, IssueEvent, WebhookPayload } from "./schemas";
|
||||
import { Get{{ identifier | capitalize }}Payload } from "./types";
|
||||
|
||||
export type QueryVariables = {
|
||||
after: string;
|
||||
before: string;
|
||||
first: number;
|
||||
includeArchived: boolean;
|
||||
last: number;
|
||||
};
|
||||
|
||||
export type Nullable<T> = Partial<{
|
||||
[K in keyof T]: T[K] | null;
|
||||
}>;
|
||||
|
||||
export const onCommentProperties = (payload: Get{{ identifier | capitalize }}Payload<CommentEvent>) => {
|
||||
return [
|
||||
{ label: "Comment ID", text: payload.data.id },
|
||||
{ label: "Issue ID", text: payload.data.issueId },
|
||||
{ label: "Issue Title", text: payload.data.issue.title, url: payload.url ?? undefined },
|
||||
];
|
||||
};
|
||||
|
||||
export const onIssueProperties = (payload: Get{{ identifier | capitalize }}Payload<IssueEvent>) => {
|
||||
return [
|
||||
{ label: "Issue ID", text: payload.data.id },
|
||||
{
|
||||
label: "Issue",
|
||||
text: `[${payload.data.team.key}-${payload.data.number}] ${payload.data.title}`,
|
||||
url: payload.url ?? undefined,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const queryProperties = (query: Nullable<QueryVariables>) => {
|
||||
return [
|
||||
...(query.after ? [{ label: "After", text: query.after }] : []),
|
||||
...(query.before ? [{ label: "Before", text: query.before }] : []),
|
||||
...(query.first ? [{ label: "First", text: String(query.first) }] : []),
|
||||
...(query.last ? [{ label: "Last", text: String(query.last) }] : []),
|
||||
...(query.includeArchived
|
||||
? [{ label: "Include archived", text: String(query.includeArchived) }]
|
||||
: []),
|
||||
];
|
||||
};
|
||||
|
||||
export const updatedFromProperties = (payload: WebhookPayload) => {
|
||||
if (payload.action !== "update") return [];
|
||||
return [
|
||||
{
|
||||
label: "Updated Keys",
|
||||
text: Object.keys(payload.updatedFrom)
|
||||
.filter((key) => !["editedAt", "updatedAt"].includes(key))
|
||||
.join(", "),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const modelProperties = (
|
||||
params: Partial<{
|
||||
model_owner: string;
|
||||
model_name: string;
|
||||
version_id: string;
|
||||
destination: string;
|
||||
}>
|
||||
) => {
|
||||
return [
|
||||
...(params.model_owner ? [{ label: "Model Owner", text: params.model_owner }] : []),
|
||||
...(params.model_name ? [{ label: "Model Name", text: params.model_name }] : []),
|
||||
...(params.version_id ? [{ label: "Model Version", text: params.version_id }] : []),
|
||||
...(params.destination ? [{ label: "Destination Model", text: params.destination }] : []),
|
||||
];
|
||||
};
|
||||
|
||||
export const streamingProperty = (params: { stream?: boolean }) => {
|
||||
return [{ label: "Streaming Enabled", text: String(!!params.stream) }];
|
||||
};
|
||||
@@ -0,0 +1,297 @@
|
||||
import {
|
||||
EventFilter,
|
||||
ExternalSource,
|
||||
ExternalSourceTrigger,
|
||||
HandlerEvent,
|
||||
IntegrationTaskKey,
|
||||
Logger,
|
||||
} from "@trigger.dev/sdk";
|
||||
import {
|
||||
Document,
|
||||
{{ identifier | capitalize }}Webhooks,
|
||||
WebhookPayload,
|
||||
DeletePayload,
|
||||
Webhook,
|
||||
} from "{{ sdkPackage }}";
|
||||
import { z } from "zod";
|
||||
import * as events from "./events";
|
||||
import { {{ identifier | capitalize }}, {{ identifier | capitalize }}RunTask, serialize{{ identifier | capitalize }}Output } from "./index";
|
||||
import { WebhookPayloadSchema } from "./schemas";
|
||||
import { {{ identifier | capitalize }}ReturnType } from "./types";
|
||||
import { queryProperties } from "./utils";
|
||||
|
||||
export class Webhooks {
|
||||
runTask: {{ identifier | capitalize }}RunTask;
|
||||
|
||||
constructor(runTask: {{ identifier | capitalize }}RunTask) {
|
||||
this.runTask = runTask;
|
||||
}
|
||||
|
||||
webhook(key: IntegrationTaskKey, params: { id: string }): {{ identifier | capitalize }}ReturnType<Webhook> {
|
||||
return this.runTask(
|
||||
key,
|
||||
async (client, task, io) => {
|
||||
return serialize{{ identifier | capitalize }}Output(await client.webhook(params.id));
|
||||
},
|
||||
{
|
||||
name: "Get Webhook",
|
||||
params,
|
||||
properties: [{ label: "Webhook ID", text: params.id }],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
webhooks(key: IntegrationTaskKey, params?: Document.WebhooksQueryVariables): {{ identifier | capitalize }}ReturnType<Webhook[]> {
|
||||
return this.runTask(
|
||||
key,
|
||||
async (client, task, io) => {
|
||||
let connections = await client.webhooks(params);
|
||||
const hooks = connections.nodes;
|
||||
while (connections.pageInfo.hasNextPage) {
|
||||
connections = await connections.fetchNext();
|
||||
hooks.push(...connections.nodes);
|
||||
}
|
||||
return serialize{{ identifier | capitalize }}Output(hooks);
|
||||
},
|
||||
{
|
||||
name: "List Webhooks",
|
||||
params,
|
||||
properties: queryProperties(params ?? {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
createWebhook(
|
||||
key: IntegrationTaskKey,
|
||||
params: Document.WebhookCreateInput
|
||||
): {{ identifier | capitalize }}ReturnType<Omit<WebhookPayload, "webhook"> & { webhook: Webhook | undefined }> {
|
||||
return this.runTask(
|
||||
key,
|
||||
async (client, task, io) => {
|
||||
const payload = await client.createWebhook({ ...params, allPublicTeams: !params.teamId });
|
||||
return serialize{{ identifier | capitalize }}Output({
|
||||
...payload,
|
||||
webhook: await payload.webhook,
|
||||
});
|
||||
},
|
||||
{
|
||||
name: "Create Webhook",
|
||||
params,
|
||||
properties: [
|
||||
{ label: "Webhook URL", text: params.url },
|
||||
{ label: "Resource Types", text: params.resourceTypes.join(", ") },
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
deleteWebhook(key: IntegrationTaskKey, params: { id: string }): {{ identifier | capitalize }}ReturnType<DeletePayload> {
|
||||
return this.runTask(
|
||||
key,
|
||||
async (client, task, io) => {
|
||||
return serialize{{ identifier | capitalize }}Output(await client.deleteWebhook(params.id));
|
||||
},
|
||||
{
|
||||
name: "Delete Webhook",
|
||||
params,
|
||||
properties: [{ label: "Webhook ID", text: params.id }],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
updateWebhook(
|
||||
key: IntegrationTaskKey,
|
||||
params: { id: string; input: Document.WebhookUpdateInput }
|
||||
): {{ identifier | capitalize }}ReturnType<Omit<WebhookPayload, "webhook"> & { webhook: Webhook | undefined }> {
|
||||
return this.runTask(
|
||||
key,
|
||||
async (client, task) => {
|
||||
const payload = await client.updateWebhook(params.id, params.input);
|
||||
return serialize{{ identifier | capitalize }}Output({
|
||||
...payload,
|
||||
webhook: await payload.webhook,
|
||||
});
|
||||
},
|
||||
{
|
||||
name: "Update Webhook",
|
||||
params,
|
||||
properties: [
|
||||
{ label: "Webhook ID", text: params.id },
|
||||
...(params.input.url ? [{ label: "Webhook URL", text: params.input.url }] : []),
|
||||
...(params.input.resourceTypes
|
||||
? [{ label: "Resource Types", text: params.input.resourceTypes.join(", ") }]
|
||||
: []),
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type {{ identifier | capitalize }}Events = (typeof events)[keyof typeof events];
|
||||
|
||||
export type TriggerParams = {
|
||||
teamId?: string;
|
||||
filter?: EventFilter;
|
||||
};
|
||||
|
||||
type CreateTriggersResult<TEventSpecification extends {{ identifier | capitalize }}Events> = ExternalSourceTrigger<
|
||||
TEventSpecification,
|
||||
ReturnType<typeof createWebhookEventSource>
|
||||
>;
|
||||
|
||||
export function createTrigger<TEventSpecification extends {{ identifier | capitalize }}Events>(
|
||||
source: ReturnType<typeof createWebhookEventSource>,
|
||||
event: TEventSpecification,
|
||||
params: TriggerParams
|
||||
): CreateTriggersResult<TEventSpecification> {
|
||||
return new ExternalSourceTrigger({
|
||||
event,
|
||||
params,
|
||||
source,
|
||||
options: {},
|
||||
});
|
||||
}
|
||||
|
||||
const WebhookRegistrationDataSchema = z.object({
|
||||
success: z.literal(true),
|
||||
webhook: z.object({
|
||||
id: z.string(),
|
||||
enabled: z.boolean(),
|
||||
}),
|
||||
});
|
||||
|
||||
export function createWebhookEventSource(
|
||||
integration: {{ identifier | capitalize }}
|
||||
): ExternalSource<{{ identifier | capitalize }}, TriggerParams, "HTTP", {}> {
|
||||
return new ExternalSource("HTTP", {
|
||||
id: "{{ identifier }}.webhook",
|
||||
schema: z.object({
|
||||
teamId: z.string().optional(),
|
||||
}),
|
||||
version: "0.1.0",
|
||||
integration,
|
||||
key: (params) => `${params.teamId ? params.teamId : "all"}`,
|
||||
handler: webhookHandler,
|
||||
register: async (event, io, ctx) => {
|
||||
const { params, source: httpSource, options } = event;
|
||||
|
||||
// (key-specific) stored data, undefined if not registered yet
|
||||
const webhookData = WebhookRegistrationDataSchema.safeParse(httpSource.data);
|
||||
|
||||
// set of events to register
|
||||
const allEvents = Array.from(new Set([...options.event.desired, ...options.event.missing]));
|
||||
const registeredOptions = {
|
||||
event: allEvents,
|
||||
};
|
||||
|
||||
// easily identify webhooks on {{ identifier }}
|
||||
const label = `trigger.${params.teamId ? params.teamId : "all"}`;
|
||||
|
||||
if (httpSource.active && webhookData.success) {
|
||||
const hasMissingOptions = Object.values(options).some(
|
||||
(option) => option.missing.length > 0
|
||||
);
|
||||
if (!hasMissingOptions) return;
|
||||
|
||||
const updatedWebhook = await io.integration.updateWebhook("update-webhook", {
|
||||
id: webhookData.data.webhook.id,
|
||||
input: {
|
||||
label,
|
||||
resourceTypes: allEvents,
|
||||
secret: httpSource.secret,
|
||||
url: httpSource.url,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data: WebhookRegistrationDataSchema.parse(updatedWebhook),
|
||||
options: registeredOptions,
|
||||
};
|
||||
}
|
||||
|
||||
// check for existing hooks that match url
|
||||
const listResponse = await io.integration.webhooks("list-webhooks");
|
||||
const existingWebhook = listResponse.find((w) => w.url === httpSource.url);
|
||||
|
||||
if (existingWebhook) {
|
||||
const updatedWebhook = await io.integration.updateWebhook("update-webhook", {
|
||||
id: existingWebhook.id,
|
||||
input: {
|
||||
label,
|
||||
resourceTypes: allEvents,
|
||||
secret: httpSource.secret,
|
||||
url: httpSource.url,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data: WebhookRegistrationDataSchema.parse(updatedWebhook),
|
||||
options: registeredOptions,
|
||||
};
|
||||
}
|
||||
|
||||
const createPayload = await io.integration.createWebhook("create-webhook", {
|
||||
label,
|
||||
resourceTypes: allEvents,
|
||||
secret: httpSource.secret,
|
||||
teamId: params.teamId,
|
||||
url: httpSource.url,
|
||||
});
|
||||
|
||||
return {
|
||||
data: WebhookRegistrationDataSchema.parse(createPayload),
|
||||
secret: (await createPayload.webhook)?.secret,
|
||||
options: registeredOptions,
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function webhookHandler(event: HandlerEvent<"HTTP">, logger: Logger, integration: {{ identifier | capitalize }}) {
|
||||
logger.debug("[@trigger.dev/{{ identifier }}] Handling webhook payload");
|
||||
|
||||
const { rawEvent: request, source } = event;
|
||||
|
||||
const payloadUuid = request.headers.get("{{ identifier | capitalize }}-Delivery");
|
||||
const payloadEvent = request.headers.get("{{ identifier | capitalize }}-Event");
|
||||
|
||||
if (!payloadUuid || !payloadEvent) {
|
||||
logger.debug("[@trigger.dev/{{ identifier }}] Missing required {{ identifier | capitalize }} headers");
|
||||
return { events: [] };
|
||||
}
|
||||
|
||||
if (!request.body) {
|
||||
logger.debug("[@trigger.dev/{{ identifier }}] No body found");
|
||||
return { events: [] };
|
||||
}
|
||||
|
||||
const signature = request.headers.get("WEBHOOK_SIGNATURE_HEADER");
|
||||
|
||||
if (!signature) {
|
||||
logger.error("[@trigger.dev/{{ identifier }}] Error validating webhook signature, no signature found");
|
||||
throw Error("[@trigger.dev/{{ identifier }}] No signature found");
|
||||
}
|
||||
|
||||
const rawBody = await request.text();
|
||||
const body = JSON.parse(rawBody);
|
||||
const webhookHelper = new {{ identifier | capitalize }}Webhooks(source.secret);
|
||||
|
||||
if (!webhookHelper.verify(Buffer.from(rawBody), signature)) {
|
||||
logger.error("[@trigger.dev/{{ identifier }}] Error validating webhook signature, they don't match");
|
||||
throw Error("[@trigger.dev/{{ identifier }}] Invalid signature");
|
||||
}
|
||||
|
||||
const webhookPayload = WebhookPayloadSchema.parse(body);
|
||||
|
||||
return {
|
||||
events: [
|
||||
{
|
||||
id: payloadUuid,
|
||||
name: payloadEvent,
|
||||
source: "{{ identifier }}.app",
|
||||
payload: webhookPayload,
|
||||
context: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import fs from "fs/promises";
|
||||
import { Liquid } from "liquidjs";
|
||||
import path from "path";
|
||||
|
||||
import { pathExists } from "./fileSystem";
|
||||
import { templatesPath } from "../paths";
|
||||
|
||||
type Result =
|
||||
| {
|
||||
success: true;
|
||||
alreadyExisted: boolean;
|
||||
}
|
||||
| {
|
||||
success: false;
|
||||
error: string;
|
||||
};
|
||||
|
||||
const templatesDir = path.join(templatesPath(), "integration");
|
||||
|
||||
const liquid = new Liquid({
|
||||
root: templatesDir,
|
||||
trimTagRight: true,
|
||||
trimOutputRight: true,
|
||||
});
|
||||
|
||||
export async function createIntegrationFileFromTemplate(params: {
|
||||
relativeTemplatePath: string;
|
||||
variables?: Record<string, any>;
|
||||
outputPath: string;
|
||||
}): Promise<Result> {
|
||||
if (await pathExists(params.outputPath)) {
|
||||
return {
|
||||
success: true,
|
||||
alreadyExisted: true,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const output = await liquid.renderFile(params.relativeTemplatePath, params.variables);
|
||||
|
||||
const directoryName = path.dirname(params.outputPath);
|
||||
await fs.mkdir(directoryName, { recursive: true });
|
||||
await fs.writeFile(params.outputPath, output);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
alreadyExisted: false,
|
||||
};
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
return {
|
||||
success: false,
|
||||
error: e.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
error: JSON.stringify(e),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import { Framework, getFramework } from "../frameworks";
|
||||
import { PackageManager, getUserPackageManager } from "./getUserPkgManager";
|
||||
import { Logger } from "./logger";
|
||||
import { run as ncuRun } from "npm-check-updates";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs/promises";
|
||||
import pathModule from "path";
|
||||
|
||||
export abstract class JsRuntime {
|
||||
logger: Logger;
|
||||
projectRootPath: string;
|
||||
constructor(projectRootPath: string, logger: Logger) {
|
||||
this.logger = logger;
|
||||
this.projectRootPath = projectRootPath;
|
||||
}
|
||||
abstract get id(): string;
|
||||
abstract checkForOutdatedPackages(): Promise<void>;
|
||||
abstract getUserPackageManager(): Promise<PackageManager | undefined>;
|
||||
abstract getFramework(): Promise<Framework | undefined>;
|
||||
abstract getEndpointId(): Promise<string | undefined>;
|
||||
}
|
||||
|
||||
export async function getJsRuntime(projectRootPath: string, logger: Logger): Promise<JsRuntime> {
|
||||
if (await NodeJsRuntime.isNodeJsRuntime(projectRootPath)) {
|
||||
return new NodeJsRuntime(projectRootPath, logger);
|
||||
} else if (await DenoRuntime.isDenoJsRuntime(projectRootPath)) {
|
||||
return new DenoRuntime(projectRootPath, logger);
|
||||
}
|
||||
throw new Error("Unsupported runtime");
|
||||
}
|
||||
|
||||
class NodeJsRuntime extends JsRuntime {
|
||||
static async isNodeJsRuntime(projectRootPath: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.stat(pathModule.join(projectRootPath, "package.json"));
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
get id() {
|
||||
return "nodejs";
|
||||
}
|
||||
get packageJsonPath(): string {
|
||||
return pathModule.join(this.projectRootPath, "package.json");
|
||||
}
|
||||
|
||||
async checkForOutdatedPackages(): Promise<void> {
|
||||
const updates = (await ncuRun({
|
||||
packageFile: `${this.packageJsonPath}`,
|
||||
filter: "/trigger.dev/.+$/",
|
||||
upgrade: false,
|
||||
})) as {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
if (typeof updates === "undefined" || Object.keys(updates).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const packageFile = await fs.readFile(this.packageJsonPath);
|
||||
const data = JSON.parse(Buffer.from(packageFile).toString("utf8"));
|
||||
const dependencies = data.dependencies;
|
||||
console.log(chalk.bgYellow("Updates available for trigger.dev packages"));
|
||||
console.log(chalk.bgBlue("Run npx @trigger.dev/cli@latest update"));
|
||||
|
||||
for (let dep in updates) {
|
||||
console.log(`${dep} ${dependencies[dep]} → ${updates[dep]}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getUserPackageManager() {
|
||||
return getUserPackageManager(this.projectRootPath);
|
||||
}
|
||||
|
||||
async getFramework() {
|
||||
const userPackageManager = await this.getUserPackageManager();
|
||||
return getFramework(this.projectRootPath, userPackageManager);
|
||||
}
|
||||
async getEndpointId() {
|
||||
const pkgJsonPath = pathModule.join(this.projectRootPath, "package.json");
|
||||
const pkgBuffer = await fs.readFile(pkgJsonPath);
|
||||
const pkgJson = JSON.parse(pkgBuffer.toString());
|
||||
const value = pkgJson["trigger.dev"]?.endpointId;
|
||||
if (!value || typeof value !== "string") return undefined;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class DenoRuntime extends JsRuntime {
|
||||
getDenoJsonPath(): Promise<string> {
|
||||
try {
|
||||
return fs
|
||||
.stat(pathModule.join(this.projectRootPath, "deno.json"))
|
||||
.then(() => pathModule.join(this.projectRootPath, "deno.json"));
|
||||
} catch {
|
||||
return fs
|
||||
.stat(pathModule.join(this.projectRootPath, "deno.jsonc"))
|
||||
.then(() => pathModule.join(this.projectRootPath, "deno.jsonc"));
|
||||
}
|
||||
}
|
||||
|
||||
get id() {
|
||||
return "deno";
|
||||
}
|
||||
|
||||
static async isDenoJsRuntime(projectRootPath: string): Promise<boolean> {
|
||||
try {
|
||||
try {
|
||||
await fs.stat(pathModule.join(projectRootPath, "deno.json"));
|
||||
} catch (e) {
|
||||
await fs.stat(pathModule.join(projectRootPath, "deno.jsonc"));
|
||||
}
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async checkForOutdatedPackages() {
|
||||
// not implemented currently
|
||||
}
|
||||
async getUserPackageManager() {
|
||||
return undefined;
|
||||
}
|
||||
async getFramework() {
|
||||
// not implemented currently
|
||||
return undefined;
|
||||
}
|
||||
async getEndpointId() {
|
||||
const pkgJsonPath = await this.getDenoJsonPath();
|
||||
const pkgBuffer = await fs.readFile(pkgJsonPath);
|
||||
const pkgJson = JSON.parse(pkgBuffer.toString());
|
||||
return pkgJson["trigger.dev"]?.endpointId;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import chalk from "chalk";
|
||||
|
||||
export type Logger = typeof logger;
|
||||
export const logger = {
|
||||
error(...args: unknown[]) {
|
||||
console.log(chalk.red(...args));
|
||||
|
||||
@@ -4,3 +4,8 @@ import pathModule from "path";
|
||||
export const resolvePath = (input: string) => {
|
||||
return pathModule.resolve(process.cwd(), input);
|
||||
};
|
||||
|
||||
// Takes an absolute path and derives the relative path from the current working directory
|
||||
export const relativePath = (input: string) => {
|
||||
return pathModule.relative(process.cwd(), input);
|
||||
};
|
||||
|
||||
Generated
+51
@@ -367,6 +367,12 @@ importers:
|
||||
config-packages/tsconfig:
|
||||
specifiers: {}
|
||||
|
||||
config-packages/tsup:
|
||||
specifiers:
|
||||
tsup: 7.1.x
|
||||
devDependencies:
|
||||
tsup: 7.1.0
|
||||
|
||||
docs:
|
||||
specifiers: {}
|
||||
|
||||
@@ -679,6 +685,7 @@ importers:
|
||||
execa: ^7.0.0
|
||||
gradient-string: ^2.0.2
|
||||
inquirer: ^9.1.4
|
||||
liquidjs: ^10.9.2
|
||||
localtunnel: ^2.0.2
|
||||
mock-fs: ^5.2.0
|
||||
nanoid: ^4.0.2
|
||||
@@ -714,6 +721,7 @@ importers:
|
||||
execa: 7.0.0
|
||||
gradient-string: 2.0.2
|
||||
inquirer: 9.1.4
|
||||
liquidjs: 10.9.3
|
||||
localtunnel: 2.0.2
|
||||
mock-fs: 5.2.0
|
||||
nanoid: 4.0.2
|
||||
@@ -23374,6 +23382,14 @@ packages:
|
||||
/lines-and-columns/1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
/liquidjs/10.9.3:
|
||||
resolution: {integrity: sha512-vG8fLPSBtf0C6FJg0DwzxwWF0sPE+wIRrrGsNoe0DP3Pg4HOPqycGDT14V4UfyskUXsum7DkhUuZQ9tBRjbX+g==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
commander: 10.0.1
|
||||
dev: false
|
||||
|
||||
/listenercount/1.0.1:
|
||||
resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==}
|
||||
dev: false
|
||||
@@ -30635,6 +30651,41 @@ packages:
|
||||
- ts-node
|
||||
dev: true
|
||||
|
||||
/tsup/7.1.0:
|
||||
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.29.1
|
||||
source-map: 0.8.0-beta.0
|
||||
sucrase: 3.32.0
|
||||
tree-kill: 1.2.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: true
|
||||
|
||||
/tsup/7.1.0_typescript@4.9.4:
|
||||
resolution: {integrity: sha512-mazl/GRAk70j8S43/AbSYXGgvRP54oQeX8Un4iZxzATHt0roW0t6HYDVZIXMw0ZQIpvr1nFMniIVnN5186lW7w==}
|
||||
engines: {node: '>=16.14'}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deno.enable": true
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"trigger.dev": {
|
||||
"endpointId": "borderless"
|
||||
},
|
||||
"tasks": {
|
||||
"dev": "deno run --watch main.ts"
|
||||
}
|
||||
}
|
||||
Generated
+684
@@ -0,0 +1,684 @@
|
||||
{
|
||||
"version": "3",
|
||||
"packages": {
|
||||
"specifiers": {
|
||||
"npm:@trigger.dev/express": "npm:@trigger.dev/express@2.1.7_@trigger.dev+sdk@2.1.7",
|
||||
"npm:@trigger.dev/sdk": "npm:@trigger.dev/sdk@2.1.7"
|
||||
},
|
||||
"npm": {
|
||||
"@remix-run/web-blob@3.1.0": {
|
||||
"integrity": "sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==",
|
||||
"dependencies": {
|
||||
"@remix-run/web-stream": "@remix-run/web-stream@1.1.0",
|
||||
"web-encoding": "web-encoding@1.1.5"
|
||||
}
|
||||
},
|
||||
"@remix-run/web-fetch@4.4.1": {
|
||||
"integrity": "sha512-xMceEGn2kvfeWS91nHSOhEQHPGgjFnmDVpWFZrbWPVdiTByMZIn421/tdSF6Kd1RsNsY+5Iwt3JFEKZHAcMQHw==",
|
||||
"dependencies": {
|
||||
"@remix-run/web-blob": "@remix-run/web-blob@3.1.0",
|
||||
"@remix-run/web-file": "@remix-run/web-file@3.1.0",
|
||||
"@remix-run/web-form-data": "@remix-run/web-form-data@3.1.0",
|
||||
"@remix-run/web-stream": "@remix-run/web-stream@1.1.0",
|
||||
"@web3-storage/multipart-parser": "@web3-storage/multipart-parser@1.0.0",
|
||||
"abort-controller": "abort-controller@3.0.0",
|
||||
"data-uri-to-buffer": "data-uri-to-buffer@3.0.1",
|
||||
"mrmime": "mrmime@1.0.1"
|
||||
}
|
||||
},
|
||||
"@remix-run/web-file@3.1.0": {
|
||||
"integrity": "sha512-dW2MNGwoiEYhlspOAXFBasmLeYshyAyhIdrlXBi06Duex5tDr3ut2LFKVj7tyHLmn8nnNwFf1BjNbkQpygC2aQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/web-blob": "@remix-run/web-blob@3.1.0"
|
||||
}
|
||||
},
|
||||
"@remix-run/web-form-data@3.1.0": {
|
||||
"integrity": "sha512-NdeohLMdrb+pHxMQ/Geuzdp0eqPbea+Ieo8M8Jx2lGC6TBHsgHzYcBvr0LyPdPVycNRDEpWpiDdCOdCryo3f9A==",
|
||||
"dependencies": {
|
||||
"web-encoding": "web-encoding@1.1.5"
|
||||
}
|
||||
},
|
||||
"@remix-run/web-stream@1.1.0": {
|
||||
"integrity": "sha512-KRJtwrjRV5Bb+pM7zxcTJkhIqWWSy+MYsIxHK+0m5atcznsf15YwUBWHWulZerV2+vvHH1Lp1DD7pw6qKW8SgA==",
|
||||
"dependencies": {
|
||||
"web-streams-polyfill": "web-streams-polyfill@3.2.1"
|
||||
}
|
||||
},
|
||||
"@trigger.dev/core@2.1.7": {
|
||||
"integrity": "sha512-Ts0xMFiWi4ph4da6BIbuegz2mMSVYJxWEh5S2mhM5vc+S6cl+MEbTdh+neUVa/0N4qq3Io07e9yDTXnTfiifzg==",
|
||||
"dependencies": {
|
||||
"ulid": "ulid@2.3.0",
|
||||
"zod": "zod@3.21.4",
|
||||
"zod-error": "zod-error@1.5.0"
|
||||
}
|
||||
},
|
||||
"@trigger.dev/express@2.1.7_@trigger.dev+sdk@2.1.7": {
|
||||
"integrity": "sha512-uMoSDpOZJdYs+UXwEkhWYCYm8T6e+cu33LXmXhoF2tpm7m8PritFgR7LPX4H9UdIddRATdsmWgOqPMOQneEtDg==",
|
||||
"dependencies": {
|
||||
"@remix-run/web-fetch": "@remix-run/web-fetch@4.4.1",
|
||||
"@trigger.dev/sdk": "@trigger.dev/sdk@2.1.7",
|
||||
"debug": "debug@4.3.4",
|
||||
"express": "express@4.18.2"
|
||||
}
|
||||
},
|
||||
"@trigger.dev/sdk@2.1.7": {
|
||||
"integrity": "sha512-t3pbXj6+I38a5LNGJg9Ed09NCt0AWnw7hJtUCZyuEfBQulRnVSekNLsxCyGlgiTPiyRvbyefzPrX1GhXh0MY1w==",
|
||||
"dependencies": {
|
||||
"@trigger.dev/core": "@trigger.dev/core@2.1.7",
|
||||
"chalk": "chalk@5.3.0",
|
||||
"cronstrue": "cronstrue@2.32.0",
|
||||
"debug": "debug@4.3.4",
|
||||
"evt": "evt@2.5.3",
|
||||
"get-caller-file": "get-caller-file@2.0.5",
|
||||
"git-remote-origin-url": "git-remote-origin-url@4.0.0",
|
||||
"git-repo-info": "git-repo-info@2.1.1",
|
||||
"node-fetch": "node-fetch@2.6.13",
|
||||
"slug": "slug@6.1.0",
|
||||
"terminal-link": "terminal-link@3.0.0",
|
||||
"ulid": "ulid@2.3.0",
|
||||
"uuid": "uuid@9.0.1",
|
||||
"ws": "ws@8.13.0",
|
||||
"zod": "zod@3.21.4"
|
||||
}
|
||||
},
|
||||
"@web3-storage/multipart-parser@1.0.0": {
|
||||
"integrity": "sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@zxing/text-encoding@0.9.0": {
|
||||
"integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"abort-controller@3.0.0": {
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"dependencies": {
|
||||
"event-target-shim": "event-target-shim@5.0.1"
|
||||
}
|
||||
},
|
||||
"accepts@1.3.8": {
|
||||
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
||||
"dependencies": {
|
||||
"mime-types": "mime-types@2.1.35",
|
||||
"negotiator": "negotiator@0.6.3"
|
||||
}
|
||||
},
|
||||
"ansi-escapes@5.0.0": {
|
||||
"integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==",
|
||||
"dependencies": {
|
||||
"type-fest": "type-fest@1.4.0"
|
||||
}
|
||||
},
|
||||
"array-flatten@1.1.1": {
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"available-typed-arrays@1.0.5": {
|
||||
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"body-parser@1.20.1": {
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"dependencies": {
|
||||
"bytes": "bytes@3.1.2",
|
||||
"content-type": "content-type@1.0.5",
|
||||
"debug": "debug@2.6.9",
|
||||
"depd": "depd@2.0.0",
|
||||
"destroy": "destroy@1.2.0",
|
||||
"http-errors": "http-errors@2.0.0",
|
||||
"iconv-lite": "iconv-lite@0.4.24",
|
||||
"on-finished": "on-finished@2.4.1",
|
||||
"qs": "qs@6.11.0",
|
||||
"raw-body": "raw-body@2.5.1",
|
||||
"type-is": "type-is@1.6.18",
|
||||
"unpipe": "unpipe@1.0.0"
|
||||
}
|
||||
},
|
||||
"bytes@3.1.2": {
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"call-bind@1.0.2": {
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"dependencies": {
|
||||
"function-bind": "function-bind@1.1.1",
|
||||
"get-intrinsic": "get-intrinsic@1.2.1"
|
||||
}
|
||||
},
|
||||
"chalk@5.3.0": {
|
||||
"integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"content-disposition@0.5.4": {
|
||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "safe-buffer@5.2.1"
|
||||
}
|
||||
},
|
||||
"content-type@1.0.5": {
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"cookie-signature@1.0.6": {
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"cookie@0.5.0": {
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"cronstrue@2.32.0": {
|
||||
"integrity": "sha512-dmNflOCNJL6lZEj0dp2YhGIPY83VTjFue6d9feFhnNtrER6mAjBrUvSgK95j3IB/xNGpLjaZDIDG6ACKTZr9Yw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"data-uri-to-buffer@3.0.1": {
|
||||
"integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"debug@2.6.9": {
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "ms@2.0.0"
|
||||
}
|
||||
},
|
||||
"debug@4.3.4": {
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dependencies": {
|
||||
"ms": "ms@2.1.2"
|
||||
}
|
||||
},
|
||||
"depd@2.0.0": {
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"destroy@1.2.0": {
|
||||
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ee-first@1.1.1": {
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"encodeurl@1.0.2": {
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"escape-html@1.0.3": {
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"etag@1.8.1": {
|
||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"event-target-shim@5.0.1": {
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"evt@2.5.3": {
|
||||
"integrity": "sha512-wZKx0JgXaTOVOXI2saNVxINU6VToOHDowMwb3NRcU6l+C59eW3w9dZgNxjokiM8rvMgc7/11yFG0cSDxn4qxgA==",
|
||||
"dependencies": {
|
||||
"minimal-polyfills": "minimal-polyfills@2.2.3",
|
||||
"run-exclusive": "run-exclusive@2.2.19",
|
||||
"tsafe": "tsafe@1.6.5"
|
||||
}
|
||||
},
|
||||
"express@4.18.2": {
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"dependencies": {
|
||||
"accepts": "accepts@1.3.8",
|
||||
"array-flatten": "array-flatten@1.1.1",
|
||||
"body-parser": "body-parser@1.20.1",
|
||||
"content-disposition": "content-disposition@0.5.4",
|
||||
"content-type": "content-type@1.0.5",
|
||||
"cookie": "cookie@0.5.0",
|
||||
"cookie-signature": "cookie-signature@1.0.6",
|
||||
"debug": "debug@2.6.9",
|
||||
"depd": "depd@2.0.0",
|
||||
"encodeurl": "encodeurl@1.0.2",
|
||||
"escape-html": "escape-html@1.0.3",
|
||||
"etag": "etag@1.8.1",
|
||||
"finalhandler": "finalhandler@1.2.0",
|
||||
"fresh": "fresh@0.5.2",
|
||||
"http-errors": "http-errors@2.0.0",
|
||||
"merge-descriptors": "merge-descriptors@1.0.1",
|
||||
"methods": "methods@1.1.2",
|
||||
"on-finished": "on-finished@2.4.1",
|
||||
"parseurl": "parseurl@1.3.3",
|
||||
"path-to-regexp": "path-to-regexp@0.1.7",
|
||||
"proxy-addr": "proxy-addr@2.0.7",
|
||||
"qs": "qs@6.11.0",
|
||||
"range-parser": "range-parser@1.2.1",
|
||||
"safe-buffer": "safe-buffer@5.2.1",
|
||||
"send": "send@0.18.0",
|
||||
"serve-static": "serve-static@1.15.0",
|
||||
"setprototypeof": "setprototypeof@1.2.0",
|
||||
"statuses": "statuses@2.0.1",
|
||||
"type-is": "type-is@1.6.18",
|
||||
"utils-merge": "utils-merge@1.0.1",
|
||||
"vary": "vary@1.1.2"
|
||||
}
|
||||
},
|
||||
"finalhandler@1.2.0": {
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"dependencies": {
|
||||
"debug": "debug@2.6.9",
|
||||
"encodeurl": "encodeurl@1.0.2",
|
||||
"escape-html": "escape-html@1.0.3",
|
||||
"on-finished": "on-finished@2.4.1",
|
||||
"parseurl": "parseurl@1.3.3",
|
||||
"statuses": "statuses@2.0.1",
|
||||
"unpipe": "unpipe@1.0.0"
|
||||
}
|
||||
},
|
||||
"for-each@0.3.3": {
|
||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||
"dependencies": {
|
||||
"is-callable": "is-callable@1.2.7"
|
||||
}
|
||||
},
|
||||
"forwarded@0.2.0": {
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"fresh@0.5.2": {
|
||||
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"function-bind@1.1.1": {
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"get-caller-file@2.0.5": {
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"get-intrinsic@1.2.1": {
|
||||
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
|
||||
"dependencies": {
|
||||
"function-bind": "function-bind@1.1.1",
|
||||
"has": "has@1.0.3",
|
||||
"has-proto": "has-proto@1.0.1",
|
||||
"has-symbols": "has-symbols@1.0.3"
|
||||
}
|
||||
},
|
||||
"git-remote-origin-url@4.0.0": {
|
||||
"integrity": "sha512-EAxDksNdjuWgmVW9pVvA9jQDi/dmTaiDONktIy7qiRRhBZUI4FQK1YvBvteuTSX24aNKg9lfgxNYJEeeSXe6DA==",
|
||||
"dependencies": {
|
||||
"gitconfiglocal": "gitconfiglocal@2.1.0"
|
||||
}
|
||||
},
|
||||
"git-repo-info@2.1.1": {
|
||||
"integrity": "sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"gitconfiglocal@2.1.0": {
|
||||
"integrity": "sha512-qoerOEliJn3z+Zyn1HW2F6eoYJqKwS6MgC9cztTLUB/xLWX8gD/6T60pKn4+t/d6tP7JlybI7Z3z+I572CR/Vg==",
|
||||
"dependencies": {
|
||||
"ini": "ini@1.3.8"
|
||||
}
|
||||
},
|
||||
"gopd@1.0.1": {
|
||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "get-intrinsic@1.2.1"
|
||||
}
|
||||
},
|
||||
"has-flag@4.0.0": {
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"has-proto@1.0.1": {
|
||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"has-symbols@1.0.3": {
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"has-tostringtag@1.0.0": {
|
||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
||||
"dependencies": {
|
||||
"has-symbols": "has-symbols@1.0.3"
|
||||
}
|
||||
},
|
||||
"has@1.0.3": {
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dependencies": {
|
||||
"function-bind": "function-bind@1.1.1"
|
||||
}
|
||||
},
|
||||
"http-errors@2.0.0": {
|
||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||
"dependencies": {
|
||||
"depd": "depd@2.0.0",
|
||||
"inherits": "inherits@2.0.4",
|
||||
"setprototypeof": "setprototypeof@1.2.0",
|
||||
"statuses": "statuses@2.0.1",
|
||||
"toidentifier": "toidentifier@1.0.1"
|
||||
}
|
||||
},
|
||||
"iconv-lite@0.4.24": {
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dependencies": {
|
||||
"safer-buffer": "safer-buffer@2.1.2"
|
||||
}
|
||||
},
|
||||
"inherits@2.0.4": {
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ini@1.3.8": {
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ipaddr.js@1.9.1": {
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"is-arguments@1.1.1": {
|
||||
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||
"dependencies": {
|
||||
"call-bind": "call-bind@1.0.2",
|
||||
"has-tostringtag": "has-tostringtag@1.0.0"
|
||||
}
|
||||
},
|
||||
"is-callable@1.2.7": {
|
||||
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"is-generator-function@1.0.10": {
|
||||
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
|
||||
"dependencies": {
|
||||
"has-tostringtag": "has-tostringtag@1.0.0"
|
||||
}
|
||||
},
|
||||
"is-typed-array@1.1.12": {
|
||||
"integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
|
||||
"dependencies": {
|
||||
"which-typed-array": "which-typed-array@1.1.11"
|
||||
}
|
||||
},
|
||||
"media-typer@0.3.0": {
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"merge-descriptors@1.0.1": {
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"methods@1.1.2": {
|
||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"mime-db@1.52.0": {
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"mime-types@2.1.35": {
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "mime-db@1.52.0"
|
||||
}
|
||||
},
|
||||
"mime@1.6.0": {
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"minimal-polyfills@2.2.3": {
|
||||
"integrity": "sha512-oxdmJ9cL+xV72h0xYxp4tP2d5/fTBpP45H8DIOn9pASuF8a3IYTf+25fMGDYGiWW+MFsuog6KD6nfmhZJQ+uUw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"mrmime@1.0.1": {
|
||||
"integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ms@2.0.0": {
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ms@2.1.2": {
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ms@2.1.3": {
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"negotiator@0.6.3": {
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"node-fetch@2.6.13": {
|
||||
"integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "whatwg-url@5.0.0"
|
||||
}
|
||||
},
|
||||
"object-inspect@1.12.3": {
|
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"on-finished@2.4.1": {
|
||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||
"dependencies": {
|
||||
"ee-first": "ee-first@1.1.1"
|
||||
}
|
||||
},
|
||||
"parseurl@1.3.3": {
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"path-to-regexp@0.1.7": {
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"proxy-addr@2.0.7": {
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"dependencies": {
|
||||
"forwarded": "forwarded@0.2.0",
|
||||
"ipaddr.js": "ipaddr.js@1.9.1"
|
||||
}
|
||||
},
|
||||
"qs@6.11.0": {
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"dependencies": {
|
||||
"side-channel": "side-channel@1.0.4"
|
||||
}
|
||||
},
|
||||
"range-parser@1.2.1": {
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"raw-body@2.5.1": {
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"dependencies": {
|
||||
"bytes": "bytes@3.1.2",
|
||||
"http-errors": "http-errors@2.0.0",
|
||||
"iconv-lite": "iconv-lite@0.4.24",
|
||||
"unpipe": "unpipe@1.0.0"
|
||||
}
|
||||
},
|
||||
"run-exclusive@2.2.19": {
|
||||
"integrity": "sha512-K3mdoAi7tjJ/qT7Flj90L7QyPozwUaAG+CVhkdDje4HLKXUYC3N/Jzkau3flHVDLQVhiHBtcimVodMjN9egYbA==",
|
||||
"dependencies": {
|
||||
"minimal-polyfills": "minimal-polyfills@2.2.3"
|
||||
}
|
||||
},
|
||||
"safe-buffer@5.2.1": {
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"safer-buffer@2.1.2": {
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"send@0.18.0": {
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"dependencies": {
|
||||
"debug": "debug@2.6.9",
|
||||
"depd": "depd@2.0.0",
|
||||
"destroy": "destroy@1.2.0",
|
||||
"encodeurl": "encodeurl@1.0.2",
|
||||
"escape-html": "escape-html@1.0.3",
|
||||
"etag": "etag@1.8.1",
|
||||
"fresh": "fresh@0.5.2",
|
||||
"http-errors": "http-errors@2.0.0",
|
||||
"mime": "mime@1.6.0",
|
||||
"ms": "ms@2.1.3",
|
||||
"on-finished": "on-finished@2.4.1",
|
||||
"range-parser": "range-parser@1.2.1",
|
||||
"statuses": "statuses@2.0.1"
|
||||
}
|
||||
},
|
||||
"serve-static@1.15.0": {
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"dependencies": {
|
||||
"encodeurl": "encodeurl@1.0.2",
|
||||
"escape-html": "escape-html@1.0.3",
|
||||
"parseurl": "parseurl@1.3.3",
|
||||
"send": "send@0.18.0"
|
||||
}
|
||||
},
|
||||
"setprototypeof@1.2.0": {
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"side-channel@1.0.4": {
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"dependencies": {
|
||||
"call-bind": "call-bind@1.0.2",
|
||||
"get-intrinsic": "get-intrinsic@1.2.1",
|
||||
"object-inspect": "object-inspect@1.12.3"
|
||||
}
|
||||
},
|
||||
"slug@6.1.0": {
|
||||
"integrity": "sha512-x6vLHCMasg4DR2LPiyFGI0gJJhywY6DTiGhCrOMzb3SOk/0JVLIaL4UhyFSHu04SD3uAavrKY/K3zZ3i6iRcgA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"statuses@2.0.1": {
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"supports-color@7.2.0": {
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dependencies": {
|
||||
"has-flag": "has-flag@4.0.0"
|
||||
}
|
||||
},
|
||||
"supports-hyperlinks@2.3.0": {
|
||||
"integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==",
|
||||
"dependencies": {
|
||||
"has-flag": "has-flag@4.0.0",
|
||||
"supports-color": "supports-color@7.2.0"
|
||||
}
|
||||
},
|
||||
"terminal-link@3.0.0": {
|
||||
"integrity": "sha512-flFL3m4wuixmf6IfhFJd1YPiLiMuxEc8uHRM1buzIeZPm22Au2pDqBJQgdo7n1WfPU1ONFGv7YDwpFBmHGF6lg==",
|
||||
"dependencies": {
|
||||
"ansi-escapes": "ansi-escapes@5.0.0",
|
||||
"supports-hyperlinks": "supports-hyperlinks@2.3.0"
|
||||
}
|
||||
},
|
||||
"toidentifier@1.0.1": {
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"tr46@0.0.3": {
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"tsafe@1.6.5": {
|
||||
"integrity": "sha512-895zss8xqqHKTc28sHGIfZKnt3C5jrstB1DyPr/h3/flK0zojsZUMQL1/W4ytdDW6KI4Oth62nb9rrxmA3s3Iw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"type-fest@1.4.0": {
|
||||
"integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"type-is@1.6.18": {
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"dependencies": {
|
||||
"media-typer": "media-typer@0.3.0",
|
||||
"mime-types": "mime-types@2.1.35"
|
||||
}
|
||||
},
|
||||
"ulid@2.3.0": {
|
||||
"integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"unpipe@1.0.0": {
|
||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"util@0.12.5": {
|
||||
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
|
||||
"dependencies": {
|
||||
"inherits": "inherits@2.0.4",
|
||||
"is-arguments": "is-arguments@1.1.1",
|
||||
"is-generator-function": "is-generator-function@1.0.10",
|
||||
"is-typed-array": "is-typed-array@1.1.12",
|
||||
"which-typed-array": "which-typed-array@1.1.11"
|
||||
}
|
||||
},
|
||||
"utils-merge@1.0.1": {
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"uuid@9.0.1": {
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"vary@1.1.2": {
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"web-encoding@1.1.5": {
|
||||
"integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==",
|
||||
"dependencies": {
|
||||
"@zxing/text-encoding": "@zxing/text-encoding@0.9.0",
|
||||
"util": "util@0.12.5"
|
||||
}
|
||||
},
|
||||
"web-streams-polyfill@3.2.1": {
|
||||
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"webidl-conversions@3.0.1": {
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"whatwg-url@5.0.0": {
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "tr46@0.0.3",
|
||||
"webidl-conversions": "webidl-conversions@3.0.1"
|
||||
}
|
||||
},
|
||||
"which-typed-array@1.1.11": {
|
||||
"integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "available-typed-arrays@1.0.5",
|
||||
"call-bind": "call-bind@1.0.2",
|
||||
"for-each": "for-each@0.3.3",
|
||||
"gopd": "gopd@1.0.1",
|
||||
"has-tostringtag": "has-tostringtag@1.0.0"
|
||||
}
|
||||
},
|
||||
"ws@8.13.0": {
|
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"zod-error@1.5.0": {
|
||||
"integrity": "sha512-zzopKZ/skI9iXpqCEPj+iLCKl9b88E43ehcU+sbRoHuwGd9F1IDVGQ70TyO6kmfiRL1g4IXkjsXK+g1gLYl4WQ==",
|
||||
"dependencies": {
|
||||
"zod": "zod@3.21.4"
|
||||
}
|
||||
},
|
||||
"zod@3.21.4": {
|
||||
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remote": {}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { TriggerClient } from "npm:@trigger.dev/sdk";
|
||||
import { eventTrigger } from "npm:@trigger.dev/sdk";
|
||||
|
||||
export const triggerClient = new TriggerClient({
|
||||
id: "borderless",
|
||||
apiKey: "...",
|
||||
});
|
||||
|
||||
// your first job
|
||||
triggerClient.defineJob({
|
||||
id: "example-job",
|
||||
name: "Example Job",
|
||||
version: "0.0.1",
|
||||
trigger: eventTrigger({
|
||||
name: "example.event",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.logger.info("Hello world!", { payload });
|
||||
|
||||
return {
|
||||
message: "Hello world!",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
const response = await triggerClient.handleRequest(req);
|
||||
if (!response) {
|
||||
return Response.json(
|
||||
{ error: "Not found" },
|
||||
{
|
||||
status: 404,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return Response.json(response.body, {
|
||||
status: response.status,
|
||||
headers: response.headers,
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user