WIP new stuff
This commit is contained in:
@@ -27,20 +27,6 @@ export function getOrganizationFromSlug({
|
||||
}) {
|
||||
return prisma.organization.findFirst({
|
||||
include: {
|
||||
workflows: {
|
||||
include: {
|
||||
externalServices: {
|
||||
select: {
|
||||
service: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: { isArchived: false },
|
||||
orderBy: [
|
||||
{ disabledAt: { sort: "asc", nulls: "first" } },
|
||||
{ title: "asc" },
|
||||
],
|
||||
},
|
||||
environments: true,
|
||||
},
|
||||
where: { slug, members: { some: { userId } } },
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
DeliverEventResponseSchema,
|
||||
ErrorWithStackSchema,
|
||||
RunJobResponseSchema,
|
||||
GetJobsResponseSchema,
|
||||
GetEndpointDataResponseSchema,
|
||||
HttpSourceResponseSchema,
|
||||
PongResponseSchema,
|
||||
PrepareForJobExecutionResponseSchema,
|
||||
@@ -64,7 +64,7 @@ export class ClientApi {
|
||||
return PongResponseSchema.parse(anyBody);
|
||||
}
|
||||
|
||||
async getJobs() {
|
||||
async getEndpointData() {
|
||||
const response = await safeFetch(this.#url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
@@ -91,7 +91,7 @@ export class ClientApi {
|
||||
body: anyBody,
|
||||
});
|
||||
|
||||
return GetJobsResponseSchema.parse(anyBody);
|
||||
return GetEndpointDataResponseSchema.parse(anyBody);
|
||||
}
|
||||
|
||||
async deliverEvent(event: ApiEventLog) {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class EndpointRegisteredService {
|
||||
// Make a request to the endpoint to fetch a list of jobs
|
||||
const client = new ClientApi(endpoint.environment.apiKey, endpoint.url);
|
||||
|
||||
const { jobs } = await client.getJobs();
|
||||
const { jobs, dynamicTriggers } = await client.getEndpointData();
|
||||
|
||||
for (const job of jobs) {
|
||||
await workerQueue.enqueue("registerJob", {
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import { prisma } from "~/db.server";
|
||||
import { IngestSendEvent } from "~/routes/api.v3.events";
|
||||
import semver from "semver";
|
||||
|
||||
export class PrepareJobInstanceService {
|
||||
export class PrepareJobVersionService {
|
||||
#prismaClient: PrismaClient;
|
||||
|
||||
constructor(prismaClient: PrismaClient = prisma) {
|
||||
@@ -11,7 +11,7 @@ export class PrepareJobInstanceService {
|
||||
}
|
||||
|
||||
public async call(id: string) {
|
||||
const jobInstance = await this.#prismaClient.jobInstance.findUniqueOrThrow({
|
||||
const jobInstance = await this.#prismaClient.jobVersion.findUniqueOrThrow({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
@@ -1,15 +1,11 @@
|
||||
import type {
|
||||
ApiConnection,
|
||||
Endpoint,
|
||||
Job,
|
||||
JobConnection,
|
||||
JobInstance,
|
||||
JobVersion,
|
||||
ApiConnectionClient,
|
||||
} from ".prisma/client";
|
||||
import type {
|
||||
ConnectionConfig,
|
||||
GetJobResponse,
|
||||
LocalAuthConnectionConfig,
|
||||
} from "@trigger.dev/internal";
|
||||
import type { ConnectionConfig, JobMetadata } from "@trigger.dev/internal";
|
||||
import { DEFAULT_MAX_CONCURRENT_RUNS } from "~/consts";
|
||||
import type { PrismaClient } from "~/db.server";
|
||||
import { prisma } from "~/db.server";
|
||||
@@ -24,7 +20,7 @@ export class RegisterJobService {
|
||||
this.#prismaClient = prismaClient;
|
||||
}
|
||||
|
||||
public async call(endpointId: string, jobResponse: GetJobResponse) {
|
||||
public async call(endpointId: string, jobResponse: JobMetadata) {
|
||||
const endpoint = await this.#prismaClient.endpoint.findUniqueOrThrow({
|
||||
where: {
|
||||
id: endpointId,
|
||||
@@ -39,15 +35,15 @@ export class RegisterJobService {
|
||||
},
|
||||
});
|
||||
|
||||
const jobInstance = await this.#upsertJob(
|
||||
const jobVersion = await this.#upsertJob(
|
||||
endpoint,
|
||||
endpoint.environment,
|
||||
jobResponse
|
||||
);
|
||||
|
||||
await workerQueue.enqueue(
|
||||
"prepareJobInstance",
|
||||
{ id: jobInstance.id },
|
||||
"prepareJobVersion",
|
||||
{ id: jobVersion.id },
|
||||
{ queueName: `endpoint-${endpoint.id}` }
|
||||
);
|
||||
}
|
||||
@@ -55,8 +51,8 @@ export class RegisterJobService {
|
||||
async #upsertJob(
|
||||
endpoint: Endpoint,
|
||||
environment: AuthenticatedEnvironment,
|
||||
metadata: GetJobResponse
|
||||
): Promise<JobInstance> {
|
||||
metadata: JobMetadata
|
||||
): Promise<JobVersion> {
|
||||
logger.debug("Upserting job", {
|
||||
endpoint,
|
||||
organizationId: environment.organizationId,
|
||||
@@ -72,32 +68,31 @@ export class RegisterJobService {
|
||||
|
||||
if (metadata.connections) {
|
||||
for (const connection of Object.values(metadata.connections)) {
|
||||
if (connection.auth === "hosted") {
|
||||
connectionSlugs.add(connection.id);
|
||||
}
|
||||
connectionSlugs.add(connection.id);
|
||||
}
|
||||
}
|
||||
|
||||
const apiConnections = new Map<string, ApiConnection>();
|
||||
const apiConnectionClients = new Map<string, ApiConnectionClient>();
|
||||
|
||||
for (const connectionSlug of connectionSlugs) {
|
||||
const apiConnection = await this.#prismaClient.apiConnection.findUnique({
|
||||
where: {
|
||||
organizationId_slug: {
|
||||
organizationId: environment.organizationId,
|
||||
slug: connectionSlug,
|
||||
const apiConnectionClient =
|
||||
await this.#prismaClient.apiConnectionClient.findUnique({
|
||||
where: {
|
||||
organizationId_slug: {
|
||||
organizationId: environment.organizationId,
|
||||
slug: connectionSlug,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
if (!apiConnection) {
|
||||
if (!apiConnectionClient) {
|
||||
// TODO: find a better way to handle and message the user about this issue
|
||||
throw new Error(
|
||||
`Could not find ApiConnection with slug ${connectionSlug}`
|
||||
`Could not find ApiConnectionClient with slug ${connectionSlug}`
|
||||
);
|
||||
}
|
||||
|
||||
apiConnections.set(connectionSlug, apiConnection);
|
||||
apiConnectionClients.set(connectionSlug, apiConnectionClient);
|
||||
}
|
||||
|
||||
// Upsert the Job
|
||||
@@ -129,7 +124,7 @@ export class RegisterJobService {
|
||||
include: {
|
||||
connections: {
|
||||
include: {
|
||||
apiConnection: true,
|
||||
apiConnectionClient: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -170,8 +165,8 @@ export class RegisterJobService {
|
||||
},
|
||||
});
|
||||
|
||||
// Upsert the JobInstance
|
||||
const jobInstance = await this.#prismaClient.jobInstance.upsert({
|
||||
// Upsert the JobVersion
|
||||
const jobVersion = await this.#prismaClient.jobVersion.upsert({
|
||||
where: {
|
||||
jobId_version_endpointId: {
|
||||
jobId: job.id,
|
||||
@@ -211,10 +206,10 @@ export class RegisterJobService {
|
||||
},
|
||||
},
|
||||
version: metadata.version,
|
||||
trigger: metadata.trigger,
|
||||
eventSpecification: metadata.event,
|
||||
},
|
||||
update: {
|
||||
trigger: metadata.trigger,
|
||||
eventSpecification: metadata.event,
|
||||
queue: {
|
||||
connect: {
|
||||
id: jobQueue.id,
|
||||
@@ -224,7 +219,7 @@ export class RegisterJobService {
|
||||
include: {
|
||||
connections: {
|
||||
include: {
|
||||
apiConnection: true,
|
||||
apiConnectionClient: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -236,9 +231,9 @@ export class RegisterJobService {
|
||||
for (const [key, connection] of Object.entries(metadata.connections)) {
|
||||
const jobConnection = await this.#upsertJobConnection(
|
||||
job,
|
||||
jobInstance,
|
||||
jobVersion,
|
||||
connection,
|
||||
apiConnections,
|
||||
apiConnectionClients,
|
||||
key
|
||||
);
|
||||
|
||||
@@ -246,7 +241,7 @@ export class RegisterJobService {
|
||||
}
|
||||
|
||||
// Count the number of job instances that have higher version numbers
|
||||
const laterJobInstanceCount = await this.#prismaClient.jobInstance.count({
|
||||
const laterJobVersionCount = await this.#prismaClient.jobVersion.count({
|
||||
where: {
|
||||
jobId: job.id,
|
||||
version: {
|
||||
@@ -257,7 +252,7 @@ export class RegisterJobService {
|
||||
});
|
||||
|
||||
// If there are no later job instances, then we can upsert the latest jobalias
|
||||
if (laterJobInstanceCount === 0) {
|
||||
if (laterJobVersionCount === 0) {
|
||||
// upsert the latest jobalias
|
||||
await this.#prismaClient.jobAlias.upsert({
|
||||
where: {
|
||||
@@ -269,14 +264,14 @@ export class RegisterJobService {
|
||||
},
|
||||
create: {
|
||||
jobId: job.id,
|
||||
jobInstanceId: jobInstance.id,
|
||||
versionId: jobVersion.id,
|
||||
environmentId: environment.id,
|
||||
name: "latest",
|
||||
version: jobInstance.version,
|
||||
value: jobVersion.version,
|
||||
},
|
||||
update: {
|
||||
jobInstanceId: jobInstance.id,
|
||||
version: jobInstance.version,
|
||||
versionId: jobVersion.id,
|
||||
value: jobVersion.version,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -285,75 +280,72 @@ export class RegisterJobService {
|
||||
// It's import this runs after the trigger variant upserts
|
||||
await this.#prismaClient.jobConnection.deleteMany({
|
||||
where: {
|
||||
jobInstanceId: jobInstance.id,
|
||||
versionId: jobVersion.id,
|
||||
id: {
|
||||
notIn: Array.from(jobConnections),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// upsert the eventrule
|
||||
// The event rule should only be enabled if all the external connections are ready
|
||||
await this.#prismaClient.jobEventRule.upsert({
|
||||
where: {
|
||||
jobInstanceId_actionIdentifier: {
|
||||
jobInstanceId: jobInstance.id,
|
||||
actionIdentifier: "__trigger",
|
||||
},
|
||||
},
|
||||
create: {
|
||||
event: metadata.trigger.eventRule.event,
|
||||
source: metadata.trigger.eventRule.source,
|
||||
payloadFilter: metadata.trigger.eventRule.payload,
|
||||
contextFilter: metadata.trigger.eventRule.context,
|
||||
jobId: job.id,
|
||||
jobInstanceId: jobInstance.id,
|
||||
environmentId: environment.id,
|
||||
organizationId: environment.organizationId,
|
||||
projectId: environment.projectId,
|
||||
enabled: true,
|
||||
actionIdentifier: "__trigger",
|
||||
},
|
||||
update: {
|
||||
event: metadata.trigger.eventRule.event,
|
||||
source: metadata.trigger.eventRule.source,
|
||||
payloadFilter: metadata.trigger.eventRule.payload,
|
||||
contextFilter: metadata.trigger.eventRule.context,
|
||||
},
|
||||
});
|
||||
// This is where we upsert the triggers if there are any
|
||||
// // upsert the eventrule
|
||||
// // The event rule should only be enabled if all the external connections are ready
|
||||
// await this.#prismaClient.jobEventRule.upsert({
|
||||
// where: {
|
||||
// jobVersionId_actionIdentifier: {
|
||||
// jobVersionId: jobVersion.id,
|
||||
// actionIdentifier: "__trigger",
|
||||
// },
|
||||
// },
|
||||
// create: {
|
||||
// event: metadata.trigger.eventRule.event,
|
||||
// source: metadata.trigger.eventRule.source,
|
||||
// payloadFilter: metadata.trigger.eventRule.payload,
|
||||
// contextFilter: metadata.trigger.eventRule.context,
|
||||
// jobId: job.id,
|
||||
// jobVersionId: jobVersion.id,
|
||||
// environmentId: environment.id,
|
||||
// organizationId: environment.organizationId,
|
||||
// projectId: environment.projectId,
|
||||
// enabled: true,
|
||||
// actionIdentifier: "__trigger",
|
||||
// },
|
||||
// update: {
|
||||
// event: metadata.trigger.eventRule.event,
|
||||
// source: metadata.trigger.eventRule.source,
|
||||
// payloadFilter: metadata.trigger.eventRule.payload,
|
||||
// contextFilter: metadata.trigger.eventRule.context,
|
||||
// },
|
||||
// });
|
||||
|
||||
return jobInstance;
|
||||
return jobVersion;
|
||||
}
|
||||
|
||||
async #upsertJobConnection(
|
||||
job: Job & {
|
||||
connections: Array<
|
||||
JobConnection & { apiConnection: ApiConnection | null }
|
||||
JobConnection & { apiConnectionClient: ApiConnectionClient | null }
|
||||
>;
|
||||
},
|
||||
jobInstance: JobInstance & {
|
||||
jobVersion: JobVersion & {
|
||||
connections: Array<
|
||||
JobConnection & { apiConnection: ApiConnection | null }
|
||||
JobConnection & { apiConnectionClient: ApiConnectionClient | null }
|
||||
>;
|
||||
},
|
||||
config: ConnectionConfig,
|
||||
apiConnections: Map<string, ApiConnection>,
|
||||
apiConnectionClients: Map<string, ApiConnectionClient>,
|
||||
key: string
|
||||
): Promise<JobConnection> {
|
||||
if (config.auth === "local") {
|
||||
return this.#upsertLocalAuthConnection(job, jobInstance, config, key);
|
||||
}
|
||||
const apiConnectionClient = apiConnectionClients.get(config.id);
|
||||
|
||||
const apiConnection = apiConnections.get(config.id);
|
||||
|
||||
if (!apiConnection) {
|
||||
if (!apiConnectionClient) {
|
||||
throw new Error(
|
||||
`Could not find api connection with id ${config.id} for job ${job.id}`
|
||||
`Could not find api connection client with id ${config.id} for job ${job.id}`
|
||||
);
|
||||
}
|
||||
|
||||
// Find existing connection in the job instance
|
||||
const existingInstanceConnection = jobInstance.connections.find(
|
||||
const existingInstanceConnection = jobVersion.connections.find(
|
||||
(connection) => connection.key === key
|
||||
);
|
||||
|
||||
@@ -363,8 +355,7 @@ export class RegisterJobService {
|
||||
id: existingInstanceConnection.id,
|
||||
},
|
||||
data: {
|
||||
apiConnectionId: apiConnection.id,
|
||||
usesLocalAuth: false,
|
||||
apiConnectionClientId: apiConnectionClient.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -378,14 +369,14 @@ export class RegisterJobService {
|
||||
logger.debug("Creating new job connection from existing", {
|
||||
existingJobConnection,
|
||||
key,
|
||||
jobInstanceId: jobInstance.id,
|
||||
jobVersionId: jobVersion.id,
|
||||
});
|
||||
|
||||
return this.#prismaClient.jobConnection.create({
|
||||
data: {
|
||||
jobInstance: {
|
||||
version: {
|
||||
connect: {
|
||||
id: jobInstance.id,
|
||||
id: jobVersion.id,
|
||||
},
|
||||
},
|
||||
job: {
|
||||
@@ -395,27 +386,26 @@ export class RegisterJobService {
|
||||
},
|
||||
key,
|
||||
connectionMetadata: existingJobConnection.connectionMetadata ?? {},
|
||||
apiConnection: {
|
||||
apiConnectionClient: {
|
||||
connect: {
|
||||
id: apiConnection.id,
|
||||
id: apiConnectionClient.id,
|
||||
},
|
||||
},
|
||||
usesLocalAuth: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
logger.debug("Creating new job connection", {
|
||||
key,
|
||||
jobInstanceId: jobInstance.id,
|
||||
jobVersionId: jobVersion.id,
|
||||
config,
|
||||
});
|
||||
|
||||
return this.#prismaClient.jobConnection.create({
|
||||
data: {
|
||||
jobInstance: {
|
||||
version: {
|
||||
connect: {
|
||||
id: jobInstance.id,
|
||||
id: jobVersion.id,
|
||||
},
|
||||
},
|
||||
job: {
|
||||
@@ -425,94 +415,11 @@ export class RegisterJobService {
|
||||
},
|
||||
key,
|
||||
connectionMetadata: config.metadata,
|
||||
apiConnection: {
|
||||
apiConnectionClient: {
|
||||
connect: {
|
||||
id: apiConnection.id,
|
||||
id: apiConnectionClient.id,
|
||||
},
|
||||
},
|
||||
usesLocalAuth: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async #upsertLocalAuthConnection(
|
||||
job: Job & {
|
||||
connections: Array<
|
||||
JobConnection & { apiConnection: ApiConnection | null }
|
||||
>;
|
||||
},
|
||||
jobInstance: JobInstance & {
|
||||
connections: Array<
|
||||
JobConnection & { apiConnection: ApiConnection | null }
|
||||
>;
|
||||
},
|
||||
config: LocalAuthConnectionConfig,
|
||||
key: string
|
||||
): Promise<JobConnection> {
|
||||
// Find existing connection in the job instance
|
||||
const existingInstanceConnection = jobInstance.connections.find(
|
||||
(connection) => connection.key === key
|
||||
);
|
||||
|
||||
if (
|
||||
existingInstanceConnection &&
|
||||
existingInstanceConnection.apiConnectionId
|
||||
) {
|
||||
return await this.#prismaClient.jobConnection.update({
|
||||
where: {
|
||||
id: existingInstanceConnection.id,
|
||||
},
|
||||
data: {
|
||||
apiConnectionId: null,
|
||||
usesLocalAuth: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (existingInstanceConnection) {
|
||||
return existingInstanceConnection;
|
||||
}
|
||||
|
||||
// Find existing connection in the job
|
||||
const existingJobConnection = job.connections.find(
|
||||
(connection) => connection.key === key
|
||||
);
|
||||
|
||||
if (existingJobConnection) {
|
||||
return this.#prismaClient.jobConnection.create({
|
||||
data: {
|
||||
jobInstance: {
|
||||
connect: {
|
||||
id: jobInstance.id,
|
||||
},
|
||||
},
|
||||
job: {
|
||||
connect: {
|
||||
id: job.id,
|
||||
},
|
||||
},
|
||||
key,
|
||||
connectionMetadata: existingJobConnection.connectionMetadata ?? {},
|
||||
usesLocalAuth: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return this.#prismaClient.jobConnection.create({
|
||||
data: {
|
||||
jobInstance: {
|
||||
connect: {
|
||||
id: jobInstance.id,
|
||||
},
|
||||
},
|
||||
job: {
|
||||
connect: {
|
||||
id: job.id,
|
||||
},
|
||||
},
|
||||
key,
|
||||
connectionMetadata: config.metadata,
|
||||
usesLocalAuth: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { GetJobResponseSchema } from "@/../../packages/internal/src";
|
||||
import { z } from "zod";
|
||||
import { env } from "~/env.server";
|
||||
import { ZodWorker } from "~/platform/zodWorker.server";
|
||||
import { EndpointRegisteredService } from "./endpoints/endpointRegistered.server";
|
||||
import { PrepareJobInstanceService } from "./endpoints/prepareJobInstance.server";
|
||||
import { PrepareJobVersionService } from "./endpoints/prepareJobVersion.server";
|
||||
import { DeliverEventService } from "./events/deliverEvent.server";
|
||||
import { apiConnectionRepository } from "./externalApis/apiAuthenticationRepository.server";
|
||||
import { RegisterJobService } from "./jobs/registerJob.server";
|
||||
@@ -12,6 +11,7 @@ import { StartRunService } from "./runs/startRun.server";
|
||||
import { DeliverHttpSourceRequestService } from "./sources/deliverHttpSourceRequest.server";
|
||||
import { StartQueuedRunsService } from "./runs/startQueuedRuns.server";
|
||||
import { RunFinishedService } from "./runs/runFinished.server";
|
||||
import { JobMetadataSchema } from "@trigger.dev/internal";
|
||||
|
||||
const workerCatalog = {
|
||||
organizationCreated: z.object({ id: z.string() }),
|
||||
@@ -33,7 +33,7 @@ const workerCatalog = {
|
||||
startRun: z.object({ id: z.string() }),
|
||||
runFinished: z.object({ id: z.string() }),
|
||||
resumeTask: z.object({ id: z.string() }),
|
||||
prepareJobInstance: z.object({ id: z.string() }),
|
||||
prepareJobVersion: z.object({ id: z.string() }),
|
||||
deliverHttpSourceRequest: z.object({ id: z.string() }),
|
||||
refreshOAuthToken: z.object({
|
||||
organizationId: z.string(),
|
||||
@@ -41,7 +41,7 @@ const workerCatalog = {
|
||||
}),
|
||||
registerJob: z.object({
|
||||
endpointId: z.string(),
|
||||
job: GetJobResponseSchema,
|
||||
job: JobMetadataSchema,
|
||||
}),
|
||||
startQueuedRuns: z.object({ id: z.string() }),
|
||||
};
|
||||
@@ -112,10 +112,10 @@ function getWorkerQueue() {
|
||||
await service.call(payload.id);
|
||||
},
|
||||
},
|
||||
prepareJobInstance: {
|
||||
prepareJobVersion: {
|
||||
maxAttempts: 3,
|
||||
handler: async (payload, job) => {
|
||||
const service = new PrepareJobInstanceService();
|
||||
const service = new PrepareJobVersionService();
|
||||
|
||||
await service.call(payload.id);
|
||||
},
|
||||
|
||||
+640
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `apiIdentifier` on the `ApiConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `authenticationMethodKey` on the `ApiConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `scopes` on the `ApiConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `slug` on the `ApiConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `title` on the `ApiConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `apiConnectionId` on the `ApiConnectionAttempt` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `apiIdentifier` on the `ApiConnectionAttempt` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `authenticationMethodKey` on the `ApiConnectionAttempt` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `organizationId` on the `ApiConnectionAttempt` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `scopes` on the `ApiConnectionAttempt` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `title` on the `ApiConnectionAttempt` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `jobInstanceId` on the `JobAlias` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `version` on the `JobAlias` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `apiConnectionId` on the `JobConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `jobInstanceId` on the `JobConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `usesLocalAuth` on the `JobConnection` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `eventLogId` on the `JobRun` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `jobInstanceId` on the `JobRun` table. All the data in the column will be lost.
|
||||
- You are about to drop the `CurrentEnvironment` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `DeploymentLog` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `DeploymentLogPoll` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `DurableDelay` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `EventLog` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `EventRule` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `ExternalService` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `ExternalSource` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `FetchRequest` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `FetchResponse` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `GitHubAppAuthorization` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `GitHubAppAuthorizationAttempt` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `IntegrationRequest` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `IntegrationResponse` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `InternalSource` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `JobEventRule` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `JobInstance` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `KeyValueItem` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `OrganizationTemplate` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `ProjectDeployment` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `RepositoryProject` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `SchedulerSource` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `Template` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `TriggerEvent` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `Workflow` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `WorkflowRun` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `WorkflowRunStep` table. If the table is not empty, all the data it contains will be lost.
|
||||
- A unique constraint covering the columns `[versionId,key]` on the table `JobConnection` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `clientId` to the `ApiConnection` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `clientId` to the `ApiConnectionAttempt` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `value` to the `JobAlias` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `versionId` to the `JobAlias` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `apiConnectionClientId` to the `JobConnection` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `versionId` to the `JobConnection` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `eventId` to the `JobRun` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `versionId` to the `JobRun` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ApiConnectionType" AS ENUM ('EXTERNAL', 'DEVELOPER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "JobTriggerAction" AS ENUM ('CREATE_RUN', 'RESUME_TASK');
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ApiConnectionAttempt" DROP CONSTRAINT "ApiConnectionAttempt_apiConnectionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "CurrentEnvironment" DROP CONSTRAINT "CurrentEnvironment_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "CurrentEnvironment" DROP CONSTRAINT "CurrentEnvironment_userId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "CurrentEnvironment" DROP CONSTRAINT "CurrentEnvironment_workflowId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "DeploymentLog" DROP CONSTRAINT "DeploymentLog_deploymentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "DeploymentLogPoll" DROP CONSTRAINT "DeploymentLogPoll_deploymentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "DurableDelay" DROP CONSTRAINT "DurableDelay_runId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "DurableDelay" DROP CONSTRAINT "DurableDelay_stepId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "EventLog" DROP CONSTRAINT "EventLog_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "EventLog" DROP CONSTRAINT "EventLog_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "EventLog" DROP CONSTRAINT "EventLog_projectId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "EventRule" DROP CONSTRAINT "EventRule_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "EventRule" DROP CONSTRAINT "EventRule_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "EventRule" DROP CONSTRAINT "EventRule_workflowId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ExternalService" DROP CONSTRAINT "ExternalService_connectionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ExternalService" DROP CONSTRAINT "ExternalService_workflowId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ExternalSource" DROP CONSTRAINT "ExternalSource_connectionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ExternalSource" DROP CONSTRAINT "ExternalSource_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "FetchRequest" DROP CONSTRAINT "FetchRequest_runId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "FetchRequest" DROP CONSTRAINT "FetchRequest_stepId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "FetchResponse" DROP CONSTRAINT "FetchResponse_requestId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "GitHubAppAuthorization" DROP CONSTRAINT "GitHubAppAuthorization_userId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "GitHubAppAuthorizationAttempt" DROP CONSTRAINT "GitHubAppAuthorizationAttempt_authorizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "IntegrationRequest" DROP CONSTRAINT "IntegrationRequest_externalServiceId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "IntegrationRequest" DROP CONSTRAINT "IntegrationRequest_runId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "IntegrationRequest" DROP CONSTRAINT "IntegrationRequest_stepId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "IntegrationResponse" DROP CONSTRAINT "IntegrationResponse_requestId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "InternalSource" DROP CONSTRAINT "InternalSource_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "InternalSource" DROP CONSTRAINT "InternalSource_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "InternalSource" DROP CONSTRAINT "InternalSource_workflowId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobAlias" DROP CONSTRAINT "JobAlias_jobInstanceId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobConnection" DROP CONSTRAINT "JobConnection_apiConnectionId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobConnection" DROP CONSTRAINT "JobConnection_jobInstanceId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobEventRule" DROP CONSTRAINT "JobEventRule_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobEventRule" DROP CONSTRAINT "JobEventRule_jobId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobEventRule" DROP CONSTRAINT "JobEventRule_jobInstanceId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobEventRule" DROP CONSTRAINT "JobEventRule_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobEventRule" DROP CONSTRAINT "JobEventRule_projectId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobInstance" DROP CONSTRAINT "JobInstance_endpointId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobInstance" DROP CONSTRAINT "JobInstance_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobInstance" DROP CONSTRAINT "JobInstance_jobId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobInstance" DROP CONSTRAINT "JobInstance_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobInstance" DROP CONSTRAINT "JobInstance_projectId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobInstance" DROP CONSTRAINT "JobInstance_queueId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobRun" DROP CONSTRAINT "JobRun_eventLogId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "JobRun" DROP CONSTRAINT "JobRun_jobInstanceId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "KeyValueItem" DROP CONSTRAINT "KeyValueItem_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "OrganizationTemplate" DROP CONSTRAINT "OrganizationTemplate_authorizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "OrganizationTemplate" DROP CONSTRAINT "OrganizationTemplate_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "OrganizationTemplate" DROP CONSTRAINT "OrganizationTemplate_templateId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ProjectDeployment" DROP CONSTRAINT "ProjectDeployment_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "ProjectDeployment" DROP CONSTRAINT "ProjectDeployment_projectId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "RepositoryProject" DROP CONSTRAINT "RepositoryProject_authorizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "RepositoryProject" DROP CONSTRAINT "RepositoryProject_currentDeploymentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "RepositoryProject" DROP CONSTRAINT "RepositoryProject_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "SchedulerSource" DROP CONSTRAINT "SchedulerSource_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "SchedulerSource" DROP CONSTRAINT "SchedulerSource_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "SchedulerSource" DROP CONSTRAINT "SchedulerSource_workflowId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "TriggerEvent" DROP CONSTRAINT "TriggerEvent_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "TriggerEvent" DROP CONSTRAINT "TriggerEvent_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Workflow" DROP CONSTRAINT "Workflow_externalSourceId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Workflow" DROP CONSTRAINT "Workflow_organizationId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Workflow" DROP CONSTRAINT "Workflow_organizationTemplateId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Workflow" DROP CONSTRAINT "Workflow_repositoryProjectId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "WorkflowRun" DROP CONSTRAINT "WorkflowRun_environmentId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "WorkflowRun" DROP CONSTRAINT "WorkflowRun_eventId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "WorkflowRun" DROP CONSTRAINT "WorkflowRun_eventRuleId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "WorkflowRun" DROP CONSTRAINT "WorkflowRun_workflowId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "WorkflowRunStep" DROP CONSTRAINT "WorkflowRunStep_runId_fkey";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "ApiConnection_organizationId_slug_key";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "JobConnection_jobInstanceId_key_key";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "ApiConnection" DROP COLUMN "apiIdentifier",
|
||||
DROP COLUMN "authenticationMethodKey",
|
||||
DROP COLUMN "scopes",
|
||||
DROP COLUMN "slug",
|
||||
DROP COLUMN "title",
|
||||
ADD COLUMN "clientId" TEXT NOT NULL,
|
||||
ADD COLUMN "connectionType" "ApiConnectionType" NOT NULL DEFAULT 'DEVELOPER',
|
||||
ADD COLUMN "externalAccountId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "ApiConnectionAttempt" DROP COLUMN "apiConnectionId",
|
||||
DROP COLUMN "apiIdentifier",
|
||||
DROP COLUMN "authenticationMethodKey",
|
||||
DROP COLUMN "organizationId",
|
||||
DROP COLUMN "scopes",
|
||||
DROP COLUMN "title",
|
||||
ADD COLUMN "clientId" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "JobAlias" DROP COLUMN "jobInstanceId",
|
||||
DROP COLUMN "version",
|
||||
ADD COLUMN "value" TEXT NOT NULL,
|
||||
ADD COLUMN "versionId" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "JobConnection" DROP COLUMN "apiConnectionId",
|
||||
DROP COLUMN "jobInstanceId",
|
||||
DROP COLUMN "usesLocalAuth",
|
||||
ADD COLUMN "apiConnectionClientId" TEXT NOT NULL,
|
||||
ADD COLUMN "versionId" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "JobRun" DROP COLUMN "eventLogId",
|
||||
DROP COLUMN "jobInstanceId",
|
||||
ADD COLUMN "eventId" TEXT NOT NULL,
|
||||
ADD COLUMN "versionId" TEXT NOT NULL;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "CurrentEnvironment";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "DeploymentLog";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "DeploymentLogPoll";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "DurableDelay";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "EventLog";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "EventRule";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "ExternalService";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "ExternalSource";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "FetchRequest";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "FetchResponse";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "GitHubAppAuthorization";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "GitHubAppAuthorizationAttempt";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "IntegrationRequest";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "IntegrationResponse";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "InternalSource";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "JobEventRule";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "JobInstance";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "KeyValueItem";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "OrganizationTemplate";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "ProjectDeployment";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "RepositoryProject";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "SchedulerSource";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "Template";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "TriggerEvent";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "Workflow";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "WorkflowRun";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "WorkflowRunStep";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "DeploymentLogType";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "ExternalServiceStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "ExternalServiceType";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "ExternalSourceStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "ExternalSourceType";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "FetchRequestStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "GitHubAccountType";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "IntegrationRequestStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "InternalSourceStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "InternalSourceType";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "JobEventAction";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "OrganizationTemplateStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "ProjectDeploymentStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "RepositoryProjectStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "SchedulerSourceStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "TriggerEventStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "TriggerType";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "WorkflowRunStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "WorkflowRunStepStatus";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "WorkflowRunStepType";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "WorkflowStatus";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ExternalAccount" (
|
||||
"id" TEXT NOT NULL,
|
||||
"identifier" TEXT NOT NULL,
|
||||
"metadata" JSONB,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ExternalAccount_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ApiConnectionClient" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"schema" JSONB NOT NULL,
|
||||
"scopes" TEXT[],
|
||||
"credentialsReferenceId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "ApiConnectionClient_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "JobVersion" (
|
||||
"id" TEXT NOT NULL,
|
||||
"version" TEXT NOT NULL,
|
||||
"eventSpecification" JSONB NOT NULL,
|
||||
"jobId" TEXT NOT NULL,
|
||||
"endpointId" TEXT NOT NULL,
|
||||
"environmentId" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"queueId" TEXT NOT NULL,
|
||||
"ready" BOOLEAN NOT NULL DEFAULT false,
|
||||
"latest" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "JobVersion_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "JobTrigger" (
|
||||
"id" TEXT NOT NULL,
|
||||
"event" TEXT NOT NULL,
|
||||
"source" TEXT NOT NULL,
|
||||
"payloadFilter" JSONB,
|
||||
"contextFilter" JSONB,
|
||||
"action" "JobTriggerAction" NOT NULL DEFAULT 'CREATE_RUN',
|
||||
"actionIdentifier" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"jobId" TEXT NOT NULL,
|
||||
"versionId" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"environmentId" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"externalAccountId" TEXT,
|
||||
|
||||
CONSTRAINT "JobTrigger_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "EventRecord" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"timestamp" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"payload" JSONB NOT NULL,
|
||||
"context" JSONB,
|
||||
"source" TEXT NOT NULL DEFAULT 'trigger.dev',
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"environmentId" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"deliverAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deliveredAt" TIMESTAMP(3),
|
||||
"isTest" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "EventRecord_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ExternalAccount_organizationId_identifier_key" ON "ExternalAccount"("organizationId", "identifier");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ApiConnectionClient_organizationId_slug_key" ON "ApiConnectionClient"("organizationId", "slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "JobVersion_jobId_version_endpointId_key" ON "JobVersion"("jobId", "version", "endpointId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "JobTrigger_versionId_actionIdentifier_key" ON "JobTrigger"("versionId", "actionIdentifier");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "JobConnection_versionId_key_key" ON "JobConnection"("versionId", "key");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ExternalAccount" ADD CONSTRAINT "ExternalAccount_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApiConnectionClient" ADD CONSTRAINT "ApiConnectionClient_credentialsReferenceId_fkey" FOREIGN KEY ("credentialsReferenceId") REFERENCES "SecretReference"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApiConnectionClient" ADD CONSTRAINT "ApiConnectionClient_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApiConnection" ADD CONSTRAINT "ApiConnection_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "ApiConnectionClient"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApiConnection" ADD CONSTRAINT "ApiConnection_externalAccountId_fkey" FOREIGN KEY ("externalAccountId") REFERENCES "ExternalAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ApiConnectionAttempt" ADD CONSTRAINT "ApiConnectionAttempt_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "ApiConnectionClient"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobVersion" ADD CONSTRAINT "JobVersion_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "Job"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobVersion" ADD CONSTRAINT "JobVersion_endpointId_fkey" FOREIGN KEY ("endpointId") REFERENCES "Endpoint"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobVersion" ADD CONSTRAINT "JobVersion_environmentId_fkey" FOREIGN KEY ("environmentId") REFERENCES "RuntimeEnvironment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobVersion" ADD CONSTRAINT "JobVersion_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobVersion" ADD CONSTRAINT "JobVersion_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobVersion" ADD CONSTRAINT "JobVersion_queueId_fkey" FOREIGN KEY ("queueId") REFERENCES "JobQueue"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobAlias" ADD CONSTRAINT "JobAlias_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "JobVersion"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobConnection" ADD CONSTRAINT "JobConnection_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "JobVersion"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobConnection" ADD CONSTRAINT "JobConnection_apiConnectionClientId_fkey" FOREIGN KEY ("apiConnectionClientId") REFERENCES "ApiConnectionClient"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobTrigger" ADD CONSTRAINT "JobTrigger_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "Job"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobTrigger" ADD CONSTRAINT "JobTrigger_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "JobVersion"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobTrigger" ADD CONSTRAINT "JobTrigger_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobTrigger" ADD CONSTRAINT "JobTrigger_environmentId_fkey" FOREIGN KEY ("environmentId") REFERENCES "RuntimeEnvironment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobTrigger" ADD CONSTRAINT "JobTrigger_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobTrigger" ADD CONSTRAINT "JobTrigger_externalAccountId_fkey" FOREIGN KEY ("externalAccountId") REFERENCES "ExternalAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "EventRecord" ADD CONSTRAINT "EventRecord_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "EventRecord" ADD CONSTRAINT "EventRecord_environmentId_fkey" FOREIGN KEY ("environmentId") REFERENCES "RuntimeEnvironment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "EventRecord" ADD CONSTRAINT "EventRecord_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobRun" ADD CONSTRAINT "JobRun_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "JobVersion"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "JobRun" ADD CONSTRAINT "JobRun_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "EventRecord"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
+118
-825
File diff suppressed because it is too large
Load Diff
+241
-1
@@ -1,8 +1,248 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import { PrismaClient } from ".prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function seed() {}
|
||||
const GITHUB_CONNECTION_KEY = "github-seed-key";
|
||||
const SLACK_CONNECTION_KEY = "slack-seed-key";
|
||||
|
||||
async function seed() {
|
||||
// Create a user, organization, and project
|
||||
const user = await prisma.user.upsert({
|
||||
where: {
|
||||
email: "eric@trigger.dev",
|
||||
},
|
||||
create: {
|
||||
email: "eric@trigger.dev",
|
||||
name: "Eric",
|
||||
authenticationMethod: "MAGIC_LINK",
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
const organization = await prisma.organization.upsert({
|
||||
where: {
|
||||
slug: "seed-org-123",
|
||||
},
|
||||
create: {
|
||||
title: "Personal Workspace",
|
||||
slug: "seed-org-123",
|
||||
members: {
|
||||
create: {
|
||||
userId: user.id,
|
||||
role: "ADMIN",
|
||||
},
|
||||
},
|
||||
projects: {
|
||||
create: {
|
||||
name: "My Project",
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
include: {
|
||||
members: true,
|
||||
projects: true,
|
||||
},
|
||||
});
|
||||
|
||||
const adminMember = organization.members[0];
|
||||
const defaultProject = organization.projects[0];
|
||||
|
||||
await prisma.runtimeEnvironment.upsert({
|
||||
where: {
|
||||
apiKey: "tr_dev_bNaLxayOXqoj",
|
||||
},
|
||||
create: {
|
||||
apiKey: "tr_dev_bNaLxayOXqoj",
|
||||
slug: "dev",
|
||||
type: "DEVELOPMENT",
|
||||
project: {
|
||||
connect: {
|
||||
id: defaultProject.id,
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
connect: {
|
||||
id: organization.id,
|
||||
},
|
||||
},
|
||||
orgMember: {
|
||||
connect: {
|
||||
id: adminMember.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
await prisma.runtimeEnvironment.upsert({
|
||||
where: {
|
||||
apiKey: "tr_prod_bNaLxayOXqoj",
|
||||
},
|
||||
create: {
|
||||
apiKey: "tr_prod_bNaLxayOXqoj",
|
||||
slug: "prod",
|
||||
type: "PRODUCTION",
|
||||
project: {
|
||||
connect: {
|
||||
id: defaultProject.id,
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
connect: {
|
||||
id: organization.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
// Now we need to create a couple of ApiConnectionClients
|
||||
const slackClient = await prisma.apiConnectionClient.upsert({
|
||||
where: {
|
||||
organizationId_slug: {
|
||||
organizationId: organization.id,
|
||||
slug: "my-slack-new",
|
||||
},
|
||||
},
|
||||
create: {
|
||||
organizationId: organization.id,
|
||||
slug: "my-slack-new",
|
||||
schema: {},
|
||||
title: "My Slack",
|
||||
scopes: ["chat:write"],
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
const githubClient = await prisma.apiConnectionClient.upsert({
|
||||
where: {
|
||||
organizationId_slug: {
|
||||
organizationId: organization.id,
|
||||
slug: "github",
|
||||
},
|
||||
},
|
||||
create: {
|
||||
organizationId: organization.id,
|
||||
slug: "github",
|
||||
schema: {},
|
||||
title: "GitHub",
|
||||
scopes: ["admin:repo_hook", "public_repo"],
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
await prisma.apiConnection.upsert({
|
||||
where: {
|
||||
id: "clhkhsvx20000rmdy9u9d25e7",
|
||||
},
|
||||
create: {
|
||||
metadata: { id: "github" },
|
||||
client: {
|
||||
connect: {
|
||||
id: githubClient.id,
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
connect: {
|
||||
id: organization.id,
|
||||
},
|
||||
},
|
||||
connectionType: "DEVELOPER",
|
||||
dataReference: {
|
||||
create: {
|
||||
key: GITHUB_CONNECTION_KEY,
|
||||
provider: "database",
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
await prisma.apiConnection.upsert({
|
||||
where: {
|
||||
id: "clhkigzf90000rmdyfuiec6ew",
|
||||
},
|
||||
create: {
|
||||
metadata: { id: "slack" },
|
||||
client: {
|
||||
connect: {
|
||||
id: slackClient.id,
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
connect: {
|
||||
id: organization.id,
|
||||
},
|
||||
},
|
||||
connectionType: "DEVELOPER",
|
||||
dataReference: {
|
||||
create: {
|
||||
key: SLACK_CONNECTION_KEY,
|
||||
provider: "database",
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
await prisma.secretStore.upsert({
|
||||
where: {
|
||||
key: GITHUB_CONNECTION_KEY,
|
||||
},
|
||||
create: {
|
||||
key: GITHUB_CONNECTION_KEY,
|
||||
value: {
|
||||
raw: {
|
||||
scope: "admin:repo_hook,public_repo",
|
||||
token_type: "bearer",
|
||||
access_token: process.env.SEED_GITHUB_ACCESS_TOKEN,
|
||||
},
|
||||
type: "oauth2",
|
||||
scopes: ["admin:repo_hook,public_repo"],
|
||||
accessToken: process.env.SEED_GITHUB_ACCESS_TOKEN,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
|
||||
await prisma.secretStore.upsert({
|
||||
where: {
|
||||
key: SLACK_CONNECTION_KEY,
|
||||
},
|
||||
create: {
|
||||
key: SLACK_CONNECTION_KEY,
|
||||
value: {
|
||||
raw: {
|
||||
ok: true,
|
||||
team: { id: "T84AW8RBP", name: "Trigger.dev" },
|
||||
scope:
|
||||
"chat:write,channels:read,channels:manage,im:write,channels:join,chat:write.customize,bookmarks:read",
|
||||
app_id: "A04H149K884",
|
||||
enterprise: null,
|
||||
token_type: "bot",
|
||||
authed_user: { id: "U8590FPB9" },
|
||||
bot_user_id: "U04H0UUQPHR",
|
||||
access_token: process.env.SEED_SLACK_ACCESS_TOKEN,
|
||||
is_enterprise_install: false,
|
||||
},
|
||||
type: "oauth2",
|
||||
scopes: [
|
||||
"chat:write",
|
||||
"channels:read",
|
||||
"channels:manage",
|
||||
"im:write",
|
||||
"channels:join",
|
||||
"chat:write.customize",
|
||||
"bookmarks:read",
|
||||
],
|
||||
accessToken: process.env.SEED_SLACK_ACCESS_TOKEN,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
}
|
||||
|
||||
seed()
|
||||
.catch((e) => {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import {
|
||||
comboTrigger,
|
||||
customEvent,
|
||||
customTrigger,
|
||||
DynamicTrigger,
|
||||
Job,
|
||||
NormalizedRequest,
|
||||
TriggerClient,
|
||||
} from "@trigger.dev/sdk";
|
||||
import { github } from "@trigger.dev/github";
|
||||
import { github, events } from "@trigger.dev/github";
|
||||
import { slack as slackConnection } from "@trigger.dev/slack";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
@@ -19,11 +22,25 @@ const client = new TriggerClient("nextjs", {
|
||||
logLevel: "debug",
|
||||
});
|
||||
|
||||
// const dynamicOnIssueOpenedTrigger = new DynamicTrigger(client, {
|
||||
// id: "github-issue-opened",
|
||||
// event: events.onIssueOpened,
|
||||
// connection: gh,
|
||||
// });
|
||||
const dynamicOnIssueOpenedTrigger = new DynamicTrigger(client, {
|
||||
id: "github-issue-opened",
|
||||
event: events.onIssueOpened,
|
||||
source: gh.sources.repo,
|
||||
});
|
||||
|
||||
const dynamicOnIssueOpenedTriggerOrg = new DynamicTrigger(client, {
|
||||
id: "github-issue-opened-org",
|
||||
event: events.onIssueOpened,
|
||||
source: gh.sources.org,
|
||||
});
|
||||
|
||||
dynamicOnIssueOpenedTrigger.register({
|
||||
repo: "ericallam/basic-starter-100k",
|
||||
});
|
||||
|
||||
dynamicOnIssueOpenedTriggerOrg.register({
|
||||
org: "triggerdotdev",
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "alert-on-new-github-issues",
|
||||
@@ -32,7 +49,8 @@ new Job(client, {
|
||||
connections: {
|
||||
slack,
|
||||
},
|
||||
trigger: gh.triggers.onIssueOpened({
|
||||
trigger: gh.triggers.repo({
|
||||
event: events.onIssueOpened,
|
||||
repo: "ericallam/basic-starter-100k",
|
||||
}),
|
||||
run: async (event, io, ctx) => {
|
||||
@@ -44,12 +62,10 @@ new Job(client, {
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "alert-on-new-github-issues-2",
|
||||
name: "Alert on new GitHub issues 2",
|
||||
id: "alert-on-new-github-issues-dynamic",
|
||||
name: "Alert on new GitHub issues Dynamic",
|
||||
version: "0.1.1",
|
||||
trigger: gh.triggers.onIssueOpened({
|
||||
repo: "ericallam/basic-starter-100k",
|
||||
}),
|
||||
trigger: dynamicOnIssueOpenedTrigger,
|
||||
run: async (event, io, ctx) => {},
|
||||
});
|
||||
|
||||
@@ -57,12 +73,88 @@ new Job(client, {
|
||||
id: "alert-on-new-github-stars",
|
||||
name: "Alert on new GitHub stars",
|
||||
version: "0.1.1",
|
||||
trigger: gh.triggers.onStar({
|
||||
trigger: gh.triggers.repo({
|
||||
event: events.onNewStar,
|
||||
repo: "ericallam/basic-starter-100k",
|
||||
}),
|
||||
run: async (event, io, ctx) => {},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "alert-on-new-github-stars-in-org",
|
||||
name: "Alert on new GitHub stars in Org",
|
||||
version: "0.1.1",
|
||||
trigger: gh.triggers.org({
|
||||
event: events.onNewStar,
|
||||
org: "triggerdotdev",
|
||||
}),
|
||||
run: async (event, io, ctx) => {},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "alert-on-new-github-stars-in-org",
|
||||
name: "Alert on new GitHub stars in Org",
|
||||
version: "0.1.1",
|
||||
trigger: comboTrigger({
|
||||
event: events.onNewStar,
|
||||
triggers: [
|
||||
gh.triggers.org({
|
||||
event: events.onNewStar,
|
||||
org: "triggerdotdev",
|
||||
}),
|
||||
gh.triggers.org({
|
||||
event: events.onNewStar,
|
||||
org: "jsonheroio",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
run: async (event, io, ctx) => {},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "custom-event-example",
|
||||
name: "Custom Event Example",
|
||||
version: "0.1.1",
|
||||
trigger: customTrigger({
|
||||
name: "my.custom.trigger",
|
||||
event: customEvent({ schema: z.object({ id: z.string() }) }),
|
||||
}),
|
||||
run: async (event, io, ctx) => {},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "custom-github-event-example",
|
||||
name: "Custom Github Event Example",
|
||||
version: "0.1.1",
|
||||
trigger: customTrigger({
|
||||
name: "my.custom.trigger",
|
||||
event: events.onNewStar,
|
||||
}),
|
||||
run: async (event, io, ctx) => {},
|
||||
});
|
||||
|
||||
// new Job(client, {
|
||||
// id: "alert-on-new-github-stars",
|
||||
// name: "Alert on new GitHub stars",
|
||||
// version: "0.1.1",
|
||||
// trigger: customTrigger({
|
||||
// name: "my.custom.trigger",
|
||||
// event: events.onNewStar,
|
||||
// }),
|
||||
// run: async (event, io, ctx) => {},
|
||||
// });
|
||||
|
||||
// new Job(client, {
|
||||
// id: "alert-on-new-github-stars",
|
||||
// name: "Alert on new GitHub stars",
|
||||
// version: "0.1.1",
|
||||
// trigger: customTrigger({
|
||||
// name: "other.custom.trigger",
|
||||
// event: eventFromZodSchema(z.object({ id: z.string() })),
|
||||
// }),
|
||||
// run: async (event, io, ctx) => {},
|
||||
// });
|
||||
|
||||
// const notifySlackONNewCommentsJob = new Job({
|
||||
// id: "notify-slack-on-new-comments",
|
||||
// name: "Notify Slack on new GitHub comments",
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import {
|
||||
IssueCommentEvent,
|
||||
IssuesEvent,
|
||||
IssuesOpenedEvent,
|
||||
StarCreatedEvent,
|
||||
StarEvent,
|
||||
} from "@octokit/webhooks-types";
|
||||
import {
|
||||
Connection,
|
||||
EventFilter,
|
||||
ExternalSourceEventTrigger,
|
||||
EventSpecification,
|
||||
ExternalSourceTrigger,
|
||||
} from "@trigger.dev/sdk";
|
||||
import { Octokit } from "octokit";
|
||||
import { clientFactory } from "./clientFactory";
|
||||
import { metadata } from "./metadata";
|
||||
import { repositoryWebhookSource } from "./sources";
|
||||
import { createOrgEventSource, createRepoEventSource } from "./sources";
|
||||
import { tasks } from "./tasks";
|
||||
|
||||
export type GitHubConnectionOptions =
|
||||
@@ -26,9 +26,21 @@ export type GitHubConnectionOptions =
|
||||
export const github = (options: GitHubConnectionOptions) => {
|
||||
const connection = createConnectionFromOptions(options);
|
||||
|
||||
const repoSource = createRepoEventSource(connection);
|
||||
const orgSource = createOrgEventSource(connection);
|
||||
const repoTrigger = createRepoTrigger(repoSource);
|
||||
const orgTrigger = createOrgTrigger(orgSource);
|
||||
|
||||
return {
|
||||
...connection,
|
||||
triggers: createTriggers(connection),
|
||||
sources: {
|
||||
repo: repoSource,
|
||||
org: orgSource,
|
||||
},
|
||||
triggers: {
|
||||
repo: repoTrigger,
|
||||
org: orgTrigger,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -57,62 +69,92 @@ function createConnectionFromOptions(
|
||||
};
|
||||
}
|
||||
|
||||
function createTriggers(connection: Connection<Octokit, typeof tasks>) {
|
||||
return {
|
||||
onIssue: buildRepoWebhookTrigger<IssuesEvent>(
|
||||
"On Issue",
|
||||
"issues",
|
||||
connection
|
||||
),
|
||||
onIssueOpened: buildRepoWebhookTrigger<IssuesOpenedEvent>(
|
||||
"On Issue Opened",
|
||||
"issues",
|
||||
connection,
|
||||
{
|
||||
action: ["opened"],
|
||||
}
|
||||
),
|
||||
onStar: buildRepoWebhookTrigger<StarEvent>("On Star", "star", connection),
|
||||
};
|
||||
}
|
||||
const onIssueOpened: EventSpecification<IssuesOpenedEvent> = {
|
||||
name: "issues",
|
||||
title: "On issue opened",
|
||||
source: "github.com",
|
||||
filter: {
|
||||
action: ["opened"],
|
||||
},
|
||||
parsePayload: (payload) => payload as IssuesOpenedEvent,
|
||||
};
|
||||
|
||||
function buildRepoWebhookTrigger<TEvent>(
|
||||
title: string,
|
||||
event: string,
|
||||
connection: Connection<Octokit, typeof tasks>,
|
||||
filter?: EventFilter
|
||||
) {
|
||||
return (params: { repo: string }) =>
|
||||
new ExternalSourceEventTrigger({
|
||||
title,
|
||||
elements: [
|
||||
{
|
||||
label: "Repo",
|
||||
text: params.repo,
|
||||
},
|
||||
{
|
||||
label: "Event",
|
||||
text: event,
|
||||
},
|
||||
],
|
||||
source: repositoryWebhookSource(
|
||||
{
|
||||
repo: params.repo,
|
||||
events: [event],
|
||||
},
|
||||
connection,
|
||||
(payload) => payload as TEvent
|
||||
),
|
||||
eventRule: {
|
||||
event,
|
||||
source: "github.com",
|
||||
const onIssue: EventSpecification<IssuesEvent> = {
|
||||
name: "issues",
|
||||
title: "On issue",
|
||||
source: "github.com",
|
||||
parsePayload: (payload) => payload as IssuesEvent,
|
||||
};
|
||||
|
||||
const onStar: EventSpecification<StarEvent> = {
|
||||
name: "star",
|
||||
title: "On star",
|
||||
source: "github.com",
|
||||
parsePayload: (payload) => payload as StarEvent,
|
||||
};
|
||||
|
||||
const onNewStar: EventSpecification<StarCreatedEvent> = {
|
||||
name: "star",
|
||||
title: "On new star",
|
||||
source: "github.com",
|
||||
filter: {
|
||||
action: ["created"],
|
||||
},
|
||||
parsePayload: (payload) => payload as StarCreatedEvent,
|
||||
};
|
||||
|
||||
export const events = {
|
||||
onIssueOpened,
|
||||
onIssue,
|
||||
onStar,
|
||||
onNewStar,
|
||||
};
|
||||
|
||||
// params.event has to be a union of all the values of the exports events object
|
||||
type GitHubEvents = (typeof events)[keyof typeof events];
|
||||
|
||||
function createRepoTrigger(source: ReturnType<typeof createRepoEventSource>) {
|
||||
return <TEventSpecification extends GitHubEvents>({
|
||||
event,
|
||||
repo,
|
||||
}: {
|
||||
event: TEventSpecification;
|
||||
repo: string;
|
||||
}) => {
|
||||
return new ExternalSourceTrigger({
|
||||
event,
|
||||
params: { repo },
|
||||
source,
|
||||
filter: {
|
||||
payload: {
|
||||
...(filter ?? {}),
|
||||
repository: {
|
||||
...filter?.repository,
|
||||
full_name: [params.repo],
|
||||
full_name: [repo],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function createOrgTrigger(source: ReturnType<typeof createOrgEventSource>) {
|
||||
return <TEventSpecification extends GitHubEvents>({
|
||||
event,
|
||||
org,
|
||||
}: {
|
||||
event: TEventSpecification;
|
||||
org: string;
|
||||
}) => {
|
||||
return new ExternalSourceTrigger({
|
||||
event,
|
||||
params: { org },
|
||||
source,
|
||||
filter: {
|
||||
payload: {
|
||||
organization: {
|
||||
login: [org],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Webhooks } from "@octokit/webhooks";
|
||||
import { Connection, ExternalSource } from "@trigger.dev/sdk";
|
||||
import { Octokit } from "octokit";
|
||||
import { z } from "zod";
|
||||
import { tasks } from "./tasks";
|
||||
|
||||
type WebhookData = {
|
||||
@@ -21,22 +22,15 @@ function webhookData(data: any): data is WebhookData {
|
||||
);
|
||||
}
|
||||
|
||||
export function repositoryWebhookSource<TEventType>(
|
||||
params: {
|
||||
repo: string;
|
||||
events: string[];
|
||||
secret?: string;
|
||||
},
|
||||
connection: Connection<Octokit, typeof tasks>,
|
||||
parsePayload: (payload: any) => TEventType
|
||||
export function createRepoEventSource(
|
||||
connection: Connection<Octokit, typeof tasks>
|
||||
) {
|
||||
// Create a stable key for this source so we only register it once
|
||||
const key = `github.repo.${params.repo}.webhook`;
|
||||
|
||||
return new ExternalSource("http", key, "0.1.1", {
|
||||
parsePayload,
|
||||
return new ExternalSource("http", "0.1.1", {
|
||||
schema: z.object({ repo: z.string() }),
|
||||
connection,
|
||||
register: async (io, ctx) => {
|
||||
register: async (params, spec, io, ctx) => {
|
||||
const key = `github.repo.${params.repo}.webhook`;
|
||||
|
||||
const httpSource = await io.registerHttpSource("register-http-source", {
|
||||
key,
|
||||
});
|
||||
@@ -48,7 +42,7 @@ export function repositoryWebhookSource<TEventType>(
|
||||
) {
|
||||
const existingData = httpSource.data;
|
||||
|
||||
const sourceEvents = new Set(params.events);
|
||||
const sourceEvents = new Set([spec.name]);
|
||||
const existingEvents = new Set(existingData.events);
|
||||
|
||||
const missingEvents = Array.from(
|
||||
@@ -87,7 +81,7 @@ export function repositoryWebhookSource<TEventType>(
|
||||
(w) => w.config.url === httpSource.url
|
||||
);
|
||||
|
||||
const secret = params.secret || Math.random().toString(36).slice(2);
|
||||
const secret = Math.random().toString(36).slice(2);
|
||||
|
||||
if (existingWebhook && existingWebhook.active) {
|
||||
await io.client.updateWebhook("update-webhook", {
|
||||
@@ -109,7 +103,158 @@ export function repositoryWebhookSource<TEventType>(
|
||||
|
||||
const webhook = await io.client.createWebhook("create-webhook", {
|
||||
repo: params.repo,
|
||||
events: params.events,
|
||||
events: [spec.name],
|
||||
url: httpSource.url,
|
||||
secret,
|
||||
});
|
||||
|
||||
await io.updateHttpSource("update-http-source", {
|
||||
id: httpSource.id,
|
||||
secret,
|
||||
data: webhook,
|
||||
active: true,
|
||||
});
|
||||
},
|
||||
handler: async ({ rawEvent: request, source }, io, ctx) => {
|
||||
if (!request.rawBody) {
|
||||
return { events: [] };
|
||||
}
|
||||
|
||||
const deliveryId = request.headers["x-github-delivery"];
|
||||
const hookId = request.headers["x-github-hook-id"];
|
||||
const signature = request.headers["x-hub-signature-256"];
|
||||
|
||||
if (source.secret && signature) {
|
||||
const githubWebhooks = new Webhooks({
|
||||
secret: source.secret,
|
||||
});
|
||||
|
||||
if (!githubWebhooks.verify(request.rawBody, signature)) {
|
||||
return {
|
||||
events: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const name = request.headers["x-github-event"];
|
||||
|
||||
const context = omit(request.headers, [
|
||||
"x-github-event",
|
||||
"x-github-delivery",
|
||||
"x-hub-signature-256",
|
||||
"x-hub-signature",
|
||||
"content-type",
|
||||
"content-length",
|
||||
"accept",
|
||||
"accept-encoding",
|
||||
"x-forwarded-proto",
|
||||
]);
|
||||
|
||||
const payload = parseBody(request.rawBody);
|
||||
|
||||
if (!payload) {
|
||||
return {
|
||||
events: [],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
events: [
|
||||
{
|
||||
id: [hookId, deliveryId].join(":"),
|
||||
source: "github.com",
|
||||
payload,
|
||||
name,
|
||||
context,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function createOrgEventSource(
|
||||
connection: Connection<Octokit, typeof tasks>
|
||||
) {
|
||||
return new ExternalSource("http", "0.1.1", {
|
||||
schema: z.object({ org: z.string() }),
|
||||
connection,
|
||||
register: async (params, spec, io, ctx) => {
|
||||
const key = `github.org.${params.org}.webhook`;
|
||||
|
||||
const httpSource = await io.registerHttpSource("register-http-source", {
|
||||
key,
|
||||
});
|
||||
|
||||
if (
|
||||
httpSource.active &&
|
||||
webhookData(httpSource.data) &&
|
||||
httpSource.secret
|
||||
) {
|
||||
const existingData = httpSource.data;
|
||||
|
||||
const sourceEvents = new Set([spec.name]);
|
||||
const existingEvents = new Set(existingData.events);
|
||||
|
||||
const missingEvents = Array.from(
|
||||
new Set(
|
||||
Array.from(sourceEvents).filter((x) => !existingEvents.has(x))
|
||||
)
|
||||
);
|
||||
|
||||
if (missingEvents.length > 0) {
|
||||
// We need to update the webhook to add the new events and then return
|
||||
const newWebhookData = await io.client.updateOrgWebhook(
|
||||
"update-webhook",
|
||||
{
|
||||
org: params.org,
|
||||
hookId: existingData.id,
|
||||
url: httpSource.url,
|
||||
secret: httpSource.secret,
|
||||
addEvents: missingEvents,
|
||||
}
|
||||
);
|
||||
|
||||
await io.updateHttpSource("update-http-source", {
|
||||
id: httpSource.id,
|
||||
data: newWebhookData,
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const webhooks = await io.client.listOrgWebhooks("list-webhooks", {
|
||||
org: params.org,
|
||||
});
|
||||
|
||||
const existingWebhook = webhooks.find(
|
||||
(w) => w.config.url === httpSource.url
|
||||
);
|
||||
|
||||
const secret = Math.random().toString(36).slice(2);
|
||||
|
||||
if (existingWebhook && existingWebhook.active) {
|
||||
await io.client.updateOrgWebhook("update-webhook", {
|
||||
org: params.org,
|
||||
hookId: existingWebhook.id,
|
||||
url: httpSource.url,
|
||||
secret,
|
||||
});
|
||||
|
||||
await io.updateHttpSource("update-http-source", {
|
||||
id: httpSource.id,
|
||||
secret,
|
||||
data: existingWebhook,
|
||||
active: true,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const webhook = await io.client.createOrgWebhook("create-webhook", {
|
||||
org: params.org,
|
||||
events: [spec.name],
|
||||
url: httpSource.url,
|
||||
secret,
|
||||
});
|
||||
|
||||
@@ -285,6 +285,49 @@ export const updateWebhook = authenticatedTask({
|
||||
},
|
||||
});
|
||||
|
||||
export const updateOrgWebhook = authenticatedTask({
|
||||
run: async (
|
||||
params: {
|
||||
org: string;
|
||||
hookId: number;
|
||||
url: string;
|
||||
secret: string;
|
||||
addEvents?: string[];
|
||||
},
|
||||
client: InstanceType<typeof Octokit>,
|
||||
task
|
||||
) => {
|
||||
return client.rest.orgs
|
||||
.updateWebhook({
|
||||
org: params.org,
|
||||
hook_id: params.hookId,
|
||||
config: {
|
||||
content_type: "json",
|
||||
url: params.url,
|
||||
secret: params.secret,
|
||||
},
|
||||
add_events: params.addEvents,
|
||||
})
|
||||
.then((response) => response.data);
|
||||
},
|
||||
init: (params) => {
|
||||
return {
|
||||
name: "Update Org Webhook",
|
||||
params,
|
||||
elements: [
|
||||
{
|
||||
label: "Org",
|
||||
text: params.org,
|
||||
},
|
||||
{
|
||||
label: "Hook ID",
|
||||
text: String(params.hookId),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const createWebhook = authenticatedTask({
|
||||
run: async (
|
||||
params: {
|
||||
@@ -329,6 +372,48 @@ export const createWebhook = authenticatedTask({
|
||||
},
|
||||
});
|
||||
|
||||
export const createOrgWebhook = authenticatedTask({
|
||||
run: async (
|
||||
params: {
|
||||
org: string;
|
||||
url: string;
|
||||
secret: string;
|
||||
events: string[];
|
||||
},
|
||||
client: InstanceType<typeof Octokit>,
|
||||
task
|
||||
) => {
|
||||
return client.rest.orgs
|
||||
.createWebhook({
|
||||
org: params.org,
|
||||
name: "web",
|
||||
config: {
|
||||
content_type: "json",
|
||||
url: params.url,
|
||||
secret: params.secret,
|
||||
},
|
||||
events: params.events,
|
||||
})
|
||||
.then((response) => response.data);
|
||||
},
|
||||
init: (params) => {
|
||||
return {
|
||||
name: "Create Org Webhook",
|
||||
params,
|
||||
elements: [
|
||||
{
|
||||
label: "Org",
|
||||
text: params.org,
|
||||
},
|
||||
{
|
||||
label: "Events",
|
||||
text: params.events.join(", "),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const listWebhooks = authenticatedTask({
|
||||
run: async (
|
||||
params: {
|
||||
@@ -360,6 +445,34 @@ export const listWebhooks = authenticatedTask({
|
||||
},
|
||||
});
|
||||
|
||||
export const listOrgWebhooks = authenticatedTask({
|
||||
run: async (
|
||||
params: {
|
||||
org: string;
|
||||
},
|
||||
client: InstanceType<typeof Octokit>,
|
||||
task
|
||||
) => {
|
||||
return client.rest.orgs
|
||||
.listWebhooks({
|
||||
org: params.org,
|
||||
})
|
||||
.then((response) => response.data);
|
||||
},
|
||||
init: (params) => {
|
||||
return {
|
||||
name: "List Org Webhooks",
|
||||
params,
|
||||
elements: [
|
||||
{
|
||||
label: "Org",
|
||||
text: params.org,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const tasks = {
|
||||
createIssue,
|
||||
createIssueComment,
|
||||
@@ -369,4 +482,7 @@ export const tasks = {
|
||||
updateWebhook,
|
||||
createWebhook,
|
||||
listWebhooks,
|
||||
updateOrgWebhook,
|
||||
createOrgWebhook,
|
||||
listOrgWebhooks,
|
||||
};
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@
|
||||
"db:migrate:dev": "turbo run db:migrate:dev",
|
||||
"db:push": "turbo run db:push",
|
||||
"db:seed": "turbo run db:seed --no-cache",
|
||||
"i-db:seed": "infisical run -- turbo run db:seed --no-cache",
|
||||
"db:migrate:force": "turbo run db:migrate:force --no-cache",
|
||||
"dev": "turbo run dev --parallel",
|
||||
"i-dev": "infisical run -- turbo run dev --parallel",
|
||||
@@ -66,4 +67,4 @@
|
||||
"@changesets/cli": "^2.26.0",
|
||||
"node-fetch": "2.6.x"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./logger";
|
||||
export * from "./schemas";
|
||||
export * from "./types";
|
||||
export * from "./utils";
|
||||
|
||||
@@ -4,7 +4,11 @@ import { ConnectionAuthSchema, ConnectionConfigSchema } from "./connections";
|
||||
import { DisplayElementSchema } from "./elements";
|
||||
import { DeserializedJsonSchema, SerializableJsonSchema } from "./json";
|
||||
import { CachedTaskSchema, ServerTaskSchema, TaskSchema } from "./tasks";
|
||||
import { TriggerMetadataSchema } from "./triggers";
|
||||
import {
|
||||
DynamicTriggerMetadataSchema,
|
||||
EventSpecificationSchema,
|
||||
TriggerMetadataSchema,
|
||||
} from "./triggers";
|
||||
|
||||
export const RegisterHttpEventSourceBodySchema = z.object({
|
||||
key: z.string(),
|
||||
@@ -78,26 +82,28 @@ export const QueueOptionsSchema = z.object({
|
||||
|
||||
export type QueueOptions = z.infer<typeof QueueOptionsSchema>;
|
||||
|
||||
export const JobSchema = z.object({
|
||||
export const JobMetadataSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
version: z.string(),
|
||||
trigger: TriggerMetadataSchema,
|
||||
event: EventSpecificationSchema,
|
||||
triggers: z.array(TriggerMetadataSchema),
|
||||
connections: z.record(ConnectionConfigSchema),
|
||||
internal: z.boolean().default(false),
|
||||
queue: z.union([QueueOptionsSchema, z.string()]).optional(),
|
||||
});
|
||||
|
||||
export type JobMetadata = z.infer<typeof JobSchema>;
|
||||
export type JobMetadata = z.infer<typeof JobMetadataSchema>;
|
||||
|
||||
export const GetJobResponseSchema = JobSchema;
|
||||
|
||||
export type GetJobResponse = z.infer<typeof GetJobResponseSchema>;
|
||||
|
||||
export const GetJobsResponseSchema = z.object({
|
||||
jobs: z.array(GetJobResponseSchema),
|
||||
export const GetEndpointDataResponseSchema = z.object({
|
||||
jobs: z.array(JobMetadataSchema),
|
||||
dynamicTriggers: z.array(DynamicTriggerMetadataSchema),
|
||||
});
|
||||
|
||||
export type GetEndpointDataResponse = z.infer<
|
||||
typeof GetEndpointDataResponseSchema
|
||||
>;
|
||||
|
||||
export const RawEventSchema = z.object({
|
||||
id: z.string().default(() => ulid()),
|
||||
name: z.string(),
|
||||
@@ -172,7 +178,7 @@ export type RunJobResponse = z.infer<typeof RunJobResponseSchema>;
|
||||
|
||||
export const CreateRunBodySchema = z.object({
|
||||
client: z.string(),
|
||||
job: JobSchema,
|
||||
job: JobMetadataSchema,
|
||||
event: ApiEventLogSchema,
|
||||
elements: z.array(DisplayElementSchema).optional(),
|
||||
});
|
||||
|
||||
@@ -17,28 +17,9 @@ export const ConnectionAuthSchema = z.object({
|
||||
|
||||
export type ConnectionAuth = z.infer<typeof ConnectionAuthSchema>;
|
||||
|
||||
const CommonConnectionConfigSchema = z.object({
|
||||
export const ConnectionConfigSchema = z.object({
|
||||
id: z.string(),
|
||||
metadata: ConnectionMetadataSchema,
|
||||
});
|
||||
|
||||
const LocalAuthConnectionConfigSchema = CommonConnectionConfigSchema.extend({
|
||||
auth: z.literal("local"),
|
||||
});
|
||||
|
||||
const HostedAuthConnectionConfigSchema = CommonConnectionConfigSchema.extend({
|
||||
auth: z.literal("hosted"),
|
||||
id: z.string(),
|
||||
});
|
||||
|
||||
export const ConnectionConfigSchema = z.discriminatedUnion("auth", [
|
||||
LocalAuthConnectionConfigSchema,
|
||||
HostedAuthConnectionConfigSchema,
|
||||
]);
|
||||
|
||||
export type ConnectionConfig = z.infer<typeof ConnectionConfigSchema>;
|
||||
export type LocalAuthConnectionConfig = z.infer<
|
||||
typeof LocalAuthConnectionConfigSchema
|
||||
>;
|
||||
export type HostedAuthConnectionConfig = z.infer<
|
||||
typeof HostedAuthConnectionConfigSchema
|
||||
>;
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
import { z } from "zod";
|
||||
import { EventRuleSchema } from "./eventFilter";
|
||||
import { DeserializedJsonSchema } from "./json";
|
||||
import { EventFilterSchema, EventRuleSchema } from "./eventFilter";
|
||||
import { DisplayElementSchema } from "./elements";
|
||||
|
||||
export const TriggerMetadataSchema = z.object({
|
||||
export const EventSpecificationSchema = z.object({
|
||||
name: z.string(),
|
||||
title: z.string(),
|
||||
elements: z.array(
|
||||
z.object({
|
||||
label: z.string(),
|
||||
text: z.string(),
|
||||
url: z.string().optional(),
|
||||
})
|
||||
),
|
||||
eventRule: EventRuleSchema,
|
||||
schema: DeserializedJsonSchema.optional(),
|
||||
source: z.string(),
|
||||
filter: EventFilterSchema.optional(),
|
||||
elements: z.array(DisplayElementSchema).optional(),
|
||||
schema: z.any().optional(),
|
||||
examples: z.array(z.any()).optional(),
|
||||
});
|
||||
|
||||
export const DynamicTriggerMetadataSchema = z.object({
|
||||
type: z.literal("dynamic"),
|
||||
id: z.string(),
|
||||
});
|
||||
|
||||
export const StaticTriggerMetadataSchema = z.object({
|
||||
type: z.literal("static"),
|
||||
title: z.string(),
|
||||
elements: z.array(DisplayElementSchema).optional(),
|
||||
rule: EventRuleSchema,
|
||||
});
|
||||
|
||||
export const TriggerMetadataSchema = z.discriminatedUnion("type", [
|
||||
DynamicTriggerMetadataSchema,
|
||||
StaticTriggerMetadataSchema,
|
||||
]);
|
||||
|
||||
export type TriggerMetadata = z.infer<typeof TriggerMetadataSchema>;
|
||||
|
||||
export const TriggerVariantConfigSchema = z.object({
|
||||
id: z.string(),
|
||||
trigger: TriggerMetadataSchema,
|
||||
});
|
||||
|
||||
export type TriggerVariantConfig = z.infer<typeof TriggerVariantConfigSchema>;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// EventFilter is typed as type EventFilter = { [key: string]: EventFilter | string[] | number[] | boolean[] }
|
||||
|
||||
import { EventFilter } from "./schemas";
|
||||
|
||||
// This function should take two EventFilters and return a new EventFilter that is the result of merging the two.
|
||||
export function deepMergeFilters(
|
||||
filter: EventFilter,
|
||||
other: EventFilter
|
||||
): EventFilter {
|
||||
const result: EventFilter = { ...filter };
|
||||
|
||||
for (const key in other) {
|
||||
if (other.hasOwnProperty(key)) {
|
||||
const otherValue = other[key];
|
||||
|
||||
if (
|
||||
typeof otherValue === "object" &&
|
||||
!Array.isArray(otherValue) &&
|
||||
otherValue !== null
|
||||
) {
|
||||
const filterValue = filter[key];
|
||||
|
||||
if (
|
||||
filterValue &&
|
||||
typeof filterValue === "object" &&
|
||||
!Array.isArray(filterValue)
|
||||
) {
|
||||
result[key] = deepMergeFilters(filterValue, otherValue);
|
||||
} else {
|
||||
result[key] = { ...other[key] };
|
||||
}
|
||||
} else {
|
||||
result[key] = other[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -12,9 +12,6 @@ import {
|
||||
SendEvent,
|
||||
SendEventOptions,
|
||||
ServerTask,
|
||||
TriggerVariantResponseBody,
|
||||
TriggerVariantConfig,
|
||||
TriggerVariantResponseBodySchema,
|
||||
UpdateHttpEventSourceBody,
|
||||
} from "@trigger.dev/internal";
|
||||
|
||||
@@ -267,56 +264,6 @@ export class ApiClient {
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async addTriggerVariant(
|
||||
client: string,
|
||||
jobId: string,
|
||||
jobVersion: string,
|
||||
config: TriggerVariantConfig
|
||||
): Promise<TriggerVariantResponseBody> {
|
||||
const apiKey = await this.#apiKey();
|
||||
|
||||
this.#logger.debug("Adding Trigger Variant", {
|
||||
client,
|
||||
jobId,
|
||||
jobVersion,
|
||||
config,
|
||||
});
|
||||
|
||||
const response = await fetch(
|
||||
`${this.#apiUrl}/api/v3/${client}/jobs/${jobId}/${jobVersion}/variants`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
body: JSON.stringify(config),
|
||||
}
|
||||
);
|
||||
|
||||
if (response.status === 404) {
|
||||
throw new Error(
|
||||
`Failed to add trigger variant, got status code ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
if (response.status >= 400 && response.status < 500) {
|
||||
const body = await response.json();
|
||||
|
||||
throw new Error(body.error);
|
||||
}
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(
|
||||
`Failed to add trigger variant, got status code ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const anyBody = await response.json();
|
||||
|
||||
return TriggerVariantResponseBodySchema.parse(anyBody);
|
||||
}
|
||||
|
||||
async registerHttpSource(
|
||||
client: string,
|
||||
source: RegisterHttpEventSourceBody
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
export * from "./job";
|
||||
export * from "./triggerClient";
|
||||
export * from "./connections";
|
||||
export * from "./triggers/customEvent";
|
||||
export * from "./triggers/customTrigger";
|
||||
export * from "./triggers/comboTrigger";
|
||||
export * from "./triggers/externalSource";
|
||||
export * from "./triggers/dynamic";
|
||||
export * from "./io";
|
||||
export * from "./types";
|
||||
|
||||
|
||||
@@ -6,10 +6,15 @@ import {
|
||||
} from "@trigger.dev/internal";
|
||||
import { Connection, IOWithConnections } from "./connections";
|
||||
import { TriggerClient } from "./triggerClient";
|
||||
import type { TriggerContext, Trigger, TriggerEventType } from "./types";
|
||||
import type {
|
||||
TriggerContext,
|
||||
Trigger,
|
||||
TriggerEventType,
|
||||
EventSpecification,
|
||||
} from "./types";
|
||||
|
||||
export type JobOptions<
|
||||
TTrigger extends Trigger<any>,
|
||||
TTrigger extends Trigger<EventSpecification<any>>,
|
||||
TConnections extends Record<string, Connection<any, any>> = {}
|
||||
> = {
|
||||
id: string;
|
||||
@@ -28,7 +33,7 @@ export type JobOptions<
|
||||
};
|
||||
|
||||
export class Job<
|
||||
TTrigger extends Trigger<any>,
|
||||
TTrigger extends Trigger<EventSpecification<any>>,
|
||||
TConnections extends Record<string, Connection<any, any>>
|
||||
> {
|
||||
readonly options: JobOptions<TTrigger, TConnections>;
|
||||
@@ -67,14 +72,8 @@ export class Job<
|
||||
(acc: Record<string, ConnectionConfig>, key) => {
|
||||
const connection = this.options.connections![key];
|
||||
|
||||
if (connection.usesLocalAuth) {
|
||||
if (!connection.usesLocalAuth) {
|
||||
acc[key] = {
|
||||
auth: "local",
|
||||
metadata: connection.metadata,
|
||||
};
|
||||
} else {
|
||||
acc[key] = {
|
||||
auth: "hosted",
|
||||
metadata: connection.metadata,
|
||||
id: connection.id!,
|
||||
};
|
||||
@@ -94,7 +93,8 @@ export class Job<
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
version: this.version,
|
||||
trigger: this.trigger.toJSON(),
|
||||
event: this.trigger.event,
|
||||
triggers: this.trigger.toJSON(),
|
||||
connections: this.connections,
|
||||
queue: this.options.queue,
|
||||
internal,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ErrorWithMessage,
|
||||
ErrorWithStackSchema,
|
||||
GetEndpointDataResponse,
|
||||
LogLevel,
|
||||
Logger,
|
||||
NormalizedRequest,
|
||||
@@ -17,7 +18,7 @@ import {
|
||||
import { IO, ResumeWithTask } from "./io";
|
||||
import { Job } from "./job";
|
||||
import { ContextLogger } from "./logger";
|
||||
import type { Trigger, TriggerContext } from "./types";
|
||||
import type { EventSpecification, Trigger, TriggerContext } from "./types";
|
||||
|
||||
export type TriggerClientOptions = {
|
||||
apiKey?: string;
|
||||
@@ -33,7 +34,8 @@ export type ListenOptions = {
|
||||
|
||||
export class TriggerClient {
|
||||
#options: TriggerClientOptions;
|
||||
#registeredJobs: Record<string, Job<Trigger<any>, any>> = {};
|
||||
#registeredJobs: Record<string, Job<Trigger<EventSpecification<any>>, any>> =
|
||||
{};
|
||||
#client: ApiClient;
|
||||
#logger: Logger;
|
||||
name: string;
|
||||
@@ -92,12 +94,15 @@ export class TriggerClient {
|
||||
};
|
||||
}
|
||||
|
||||
const body: GetEndpointDataResponse = {
|
||||
jobs: Object.values(this.#registeredJobs).map((job) => job.toJSON()),
|
||||
dynamicTriggers: [],
|
||||
};
|
||||
|
||||
// if the x-trigger-job-id header is not set, we return all jobs
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
jobs: Object.values(this.#registeredJobs).map((job) => job.toJSON()),
|
||||
},
|
||||
body,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -172,7 +177,7 @@ export class TriggerClient {
|
||||
attach(job: Job<Trigger<any>, any>): void {
|
||||
this.#registeredJobs[job.id] = job;
|
||||
|
||||
job.trigger.attach(this, job);
|
||||
job.trigger.attachToJob(this, job);
|
||||
}
|
||||
|
||||
authorized(apiKey: string) {
|
||||
@@ -214,7 +219,7 @@ export class TriggerClient {
|
||||
|
||||
try {
|
||||
const output = await job.options.run(
|
||||
job.trigger.parsePayload(execution.event.payload ?? {}),
|
||||
job.trigger.event.parsePayload(execution.event.payload ?? {}),
|
||||
ioWithConnections,
|
||||
this.#createJobContext(execution, io, abortController.signal)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { TriggerMetadata } from "@trigger.dev/internal";
|
||||
import { Job } from "../job";
|
||||
import { TriggerClient } from "../triggerClient";
|
||||
import { EventSpecification, Trigger } from "../types";
|
||||
|
||||
type ComboTriggerOptions<
|
||||
TEventSpecification extends EventSpecification<any>,
|
||||
TTriggers extends Array<Trigger<TEventSpecification>>
|
||||
> = {
|
||||
event: TEventSpecification;
|
||||
triggers: TTriggers;
|
||||
};
|
||||
|
||||
class ComboTrigger<
|
||||
TEventSpecification extends EventSpecification<any>,
|
||||
TTriggers extends Array<Trigger<TEventSpecification>>
|
||||
> implements Trigger<TEventSpecification>
|
||||
{
|
||||
#options: ComboTriggerOptions<TEventSpecification, TTriggers>;
|
||||
|
||||
constructor(options: ComboTriggerOptions<TEventSpecification, TTriggers>) {
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
toJSON(): Array<TriggerMetadata> {
|
||||
return this.#options.triggers.flatMap((trigger) => trigger.toJSON());
|
||||
}
|
||||
|
||||
get event() {
|
||||
return this.#options.event;
|
||||
}
|
||||
|
||||
attachToJob(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<TEventSpecification>, any>
|
||||
): void {}
|
||||
}
|
||||
|
||||
export function comboTrigger<
|
||||
TEventSpecification extends EventSpecification<any>,
|
||||
TTriggers extends Array<Trigger<TEventSpecification>>
|
||||
>(
|
||||
options: ComboTriggerOptions<TEventSpecification, TTriggers>
|
||||
): Trigger<TEventSpecification> {
|
||||
return new ComboTrigger(options);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import type {
|
||||
ApiEventLog,
|
||||
EventFilter,
|
||||
TriggerMetadata,
|
||||
} from "@trigger.dev/internal";
|
||||
import { DisplayElement } from "@trigger.dev/internal";
|
||||
import { z } from "zod";
|
||||
import zodToJsonSchema from "zod-to-json-schema";
|
||||
import { Trigger } from "../types";
|
||||
import { TriggerClient } from "../triggerClient";
|
||||
import { Job } from "../job";
|
||||
|
||||
type CustomEventTriggerOptions<TSchema extends z.ZodTypeAny> = {
|
||||
name: string;
|
||||
source?: string;
|
||||
schema?: TSchema;
|
||||
filter?: EventFilter;
|
||||
};
|
||||
|
||||
class CustomEventTrigger<TSchema extends z.ZodTypeAny>
|
||||
implements Trigger<z.infer<TSchema>>
|
||||
{
|
||||
#options: CustomEventTriggerOptions<TSchema>;
|
||||
|
||||
constructor(options: CustomEventTriggerOptions<TSchema>) {
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
eventElements(event: ApiEventLog): DisplayElement[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
toJSON(): TriggerMetadata {
|
||||
return {
|
||||
title: "Custom Event",
|
||||
elements: [{ label: "on", text: this.#options.name }],
|
||||
schema: this.#options.schema
|
||||
? zodToJsonSchema(this.#options.schema)
|
||||
: undefined,
|
||||
eventRule: {
|
||||
event: this.#options.name,
|
||||
source: this.#options.source ?? "trigger.dev",
|
||||
payload: this.#options.filter ?? {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
parsePayload(payload: unknown): z.infer<TSchema> {
|
||||
if (!this.#options.schema) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
return this.#options.schema.parse(payload);
|
||||
}
|
||||
|
||||
attach(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<z.infer<TSchema>>, any>,
|
||||
variantId?: string
|
||||
): void {}
|
||||
}
|
||||
|
||||
export function customEvent<TSchema extends z.ZodTypeAny>(
|
||||
options: CustomEventTriggerOptions<TSchema>
|
||||
): Trigger<z.infer<TSchema>> {
|
||||
return new CustomEventTrigger(options);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { z } from "zod";
|
||||
import { Job } from "../job";
|
||||
import { TriggerClient } from "../triggerClient";
|
||||
import { EventSpecification, Trigger } from "../types";
|
||||
import {
|
||||
EventFilter,
|
||||
TriggerMetadata,
|
||||
deepMergeFilters,
|
||||
} from "@trigger.dev/internal";
|
||||
|
||||
type CustomTriggerOptions<TEventSpecification extends EventSpecification<any>> =
|
||||
{
|
||||
name: string;
|
||||
event: TEventSpecification;
|
||||
source?: string;
|
||||
filter?: EventFilter;
|
||||
};
|
||||
|
||||
class CustomTrigger<TEventSpecification extends EventSpecification<any>>
|
||||
implements Trigger<TEventSpecification>
|
||||
{
|
||||
#options: CustomTriggerOptions<TEventSpecification>;
|
||||
|
||||
constructor(options: CustomTriggerOptions<TEventSpecification>) {
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
toJSON(): Array<TriggerMetadata> {
|
||||
return [
|
||||
{
|
||||
type: "static",
|
||||
title: this.#options.name,
|
||||
rule: {
|
||||
event: this.#options.name,
|
||||
source: this.#options.source ?? "trigger.dev",
|
||||
payload: deepMergeFilters(
|
||||
this.#options.filter ?? {},
|
||||
this.#options.event.filter ?? {}
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
get event() {
|
||||
return this.#options.event;
|
||||
}
|
||||
|
||||
attachToJob(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<TEventSpecification>, any>
|
||||
): void {}
|
||||
}
|
||||
|
||||
export function customTrigger<
|
||||
TEventSpecification extends EventSpecification<any>
|
||||
>(
|
||||
options: CustomTriggerOptions<TEventSpecification>
|
||||
): Trigger<TEventSpecification> {
|
||||
return new CustomTrigger(options);
|
||||
}
|
||||
|
||||
export function customEvent<TEvent>({
|
||||
schema,
|
||||
source,
|
||||
}: {
|
||||
schema: z.Schema<TEvent>;
|
||||
source?: string;
|
||||
}): EventSpecification<TEvent> {
|
||||
return {
|
||||
name: "custom",
|
||||
title: "Custom Event",
|
||||
source: source ?? "trigger.dev",
|
||||
parsePayload: (payload: any) => {
|
||||
return schema.parse(payload);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { TriggerMetadata } from "@trigger.dev/internal";
|
||||
import { Job } from "../job";
|
||||
import { TriggerClient } from "../triggerClient";
|
||||
import { EventSpecification, Trigger } from "../types";
|
||||
import { ExternalSource, ExternalSourceParams } from "./externalSource";
|
||||
|
||||
export type DynamicTriggerOptions<
|
||||
TEventSpec extends EventSpecification<any>,
|
||||
TExternalSource extends ExternalSource<any, any, any>
|
||||
> = {
|
||||
id: string;
|
||||
event: TEventSpec;
|
||||
source?: TExternalSource;
|
||||
};
|
||||
|
||||
export class DynamicTrigger<
|
||||
TEventSpec extends EventSpecification<any>,
|
||||
TExternalSource extends ExternalSource<any, any, any>
|
||||
> implements Trigger<TEventSpec>
|
||||
{
|
||||
#client: TriggerClient;
|
||||
#options: DynamicTriggerOptions<TEventSpec, TExternalSource>;
|
||||
|
||||
constructor(
|
||||
client: TriggerClient,
|
||||
options: DynamicTriggerOptions<TEventSpec, TExternalSource>
|
||||
) {
|
||||
this.#client = client;
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
toJSON(): Array<TriggerMetadata> {
|
||||
return [
|
||||
{
|
||||
type: "dynamic",
|
||||
id: this.#options.id,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
get event() {
|
||||
return this.#options.event;
|
||||
}
|
||||
|
||||
// Just an example for the types
|
||||
register(params: ExternalSourceParams<TExternalSource>): void {}
|
||||
|
||||
attachToJob(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<TEventSpec>, any>
|
||||
): void {}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import type {
|
||||
ApiEventLog,
|
||||
EventRule,
|
||||
TriggerMetadata,
|
||||
} from "@trigger.dev/internal";
|
||||
import { DisplayElement } from "@trigger.dev/internal";
|
||||
import { z } from "zod";
|
||||
|
||||
import { SendEvent } from "@trigger.dev/internal";
|
||||
import {
|
||||
EventFilter,
|
||||
SendEvent,
|
||||
TriggerMetadata,
|
||||
deepMergeFilters,
|
||||
} from "@trigger.dev/internal";
|
||||
import { Connection, IOWithConnections } from "../connections";
|
||||
import { IO } from "../io";
|
||||
import { Job } from "../job";
|
||||
import { TriggerClient } from "../triggerClient";
|
||||
import type { Trigger, TriggerContext } from "../types";
|
||||
import type { EventSpecification, Trigger, TriggerContext } from "../types";
|
||||
|
||||
type HttpSourceEvent = {
|
||||
url: string;
|
||||
@@ -44,7 +44,12 @@ type ExternalSourceChannelMap = {
|
||||
|
||||
type ChannelNames = keyof ExternalSourceChannelMap;
|
||||
|
||||
type RegisterFunction<TConnection extends Connection<any, any>> = (
|
||||
type RegisterFunction<
|
||||
TConnection extends Connection<any, any>,
|
||||
TParams extends any
|
||||
> = (
|
||||
params: TParams,
|
||||
eventSpecification: EventSpecification<any>,
|
||||
io: IOWithConnections<{ client: TConnection }>,
|
||||
ctx: TriggerContext
|
||||
) => Promise<void>;
|
||||
@@ -59,49 +64,56 @@ type HandlerFunction<
|
||||
) => Promise<{ events: SendEvent[] }>;
|
||||
|
||||
type ExternalSourceOptions<
|
||||
TEvent extends any,
|
||||
TChannel extends ChannelNames,
|
||||
TConnection extends Connection<any, any>
|
||||
TConnection extends Connection<any, any>,
|
||||
TParams extends any
|
||||
> = {
|
||||
schema: z.Schema<TParams>;
|
||||
connection: TConnection;
|
||||
register: RegisterFunction<TConnection>;
|
||||
register: RegisterFunction<TConnection, TParams>;
|
||||
handler: HandlerFunction<TChannel, TConnection>;
|
||||
parsePayload: (payload: unknown) => TEvent;
|
||||
};
|
||||
|
||||
export interface AnExternalSource {
|
||||
connection: Connection<any, any>;
|
||||
register: (
|
||||
params: any,
|
||||
spec: EventSpecification<any>,
|
||||
io: IO,
|
||||
ctx: TriggerContext
|
||||
) => Promise<any>;
|
||||
}
|
||||
|
||||
export class ExternalSource<
|
||||
TEvent extends any,
|
||||
TChannel extends ChannelNames,
|
||||
TConnection extends Connection<any, any>
|
||||
> {
|
||||
TConnection extends Connection<any, any>,
|
||||
TParams extends any
|
||||
> implements AnExternalSource
|
||||
{
|
||||
channel: TChannel;
|
||||
key: string;
|
||||
version: string;
|
||||
|
||||
constructor(
|
||||
channel: TChannel,
|
||||
key: string,
|
||||
version: string,
|
||||
private options: ExternalSourceOptions<TEvent, TChannel, TConnection>
|
||||
private options: ExternalSourceOptions<TChannel, TConnection, TParams>
|
||||
) {
|
||||
this.key = key;
|
||||
this.channel = channel;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
async register(
|
||||
io: IOWithConnections<{ client: TConnection }>,
|
||||
params: TParams,
|
||||
spec: EventSpecification<any>,
|
||||
io: IO,
|
||||
ctx: TriggerContext
|
||||
) {
|
||||
return await this.options.register(io, ctx);
|
||||
}
|
||||
|
||||
async handle(
|
||||
event: RawSourceTriggerEvent<TChannel>,
|
||||
io: IOWithConnections<{ client: TConnection }>,
|
||||
ctx: TriggerContext
|
||||
) {
|
||||
return await this.options.handler(event, io, ctx);
|
||||
return await this.options.register(
|
||||
params,
|
||||
spec,
|
||||
io as IOWithConnections<{ client: TConnection }>,
|
||||
ctx
|
||||
);
|
||||
}
|
||||
|
||||
get connection() {
|
||||
@@ -109,73 +121,59 @@ export class ExternalSource<
|
||||
}
|
||||
}
|
||||
|
||||
export type ExternalSourceEventTriggerOptions<
|
||||
TEvent extends any,
|
||||
TChannel extends ChannelNames,
|
||||
TConnection extends Connection<any, any>
|
||||
export type ExternalSourceParams<
|
||||
TExternalSource extends ExternalSource<any, any, any>
|
||||
> = TExternalSource extends ExternalSource<any, any, infer TParams>
|
||||
? TParams
|
||||
: never;
|
||||
|
||||
export type ExternalSourceTriggerOptions<
|
||||
TEventSpecification extends EventSpecification<any>,
|
||||
TEventSource extends ExternalSource<any, any, any>
|
||||
> = {
|
||||
title: string;
|
||||
eventRule: EventRule;
|
||||
elements: DisplayElement[];
|
||||
source: ExternalSource<TEvent, TChannel, TConnection>;
|
||||
event: TEventSpecification;
|
||||
source: TEventSource;
|
||||
params: ExternalSourceParams<TEventSource>;
|
||||
filter?: EventFilter;
|
||||
};
|
||||
|
||||
export class ExternalSourceEventTrigger<
|
||||
TEventType extends any,
|
||||
TChannel extends ChannelNames,
|
||||
TConnection extends Connection<any, any>
|
||||
> implements Trigger<TEventType>
|
||||
export class ExternalSourceTrigger<
|
||||
TEventSpecification extends EventSpecification<any>,
|
||||
TEventSource extends ExternalSource<any, any, any>
|
||||
> implements Trigger<TEventSpecification>
|
||||
{
|
||||
constructor(
|
||||
private options: ExternalSourceEventTriggerOptions<
|
||||
TEventType,
|
||||
TChannel,
|
||||
TConnection
|
||||
private options: ExternalSourceTriggerOptions<
|
||||
TEventSpecification,
|
||||
TEventSource
|
||||
>
|
||||
) {}
|
||||
|
||||
eventElements(event: ApiEventLog): DisplayElement[] {
|
||||
return [];
|
||||
get event() {
|
||||
return this.options.event;
|
||||
}
|
||||
|
||||
parsePayload(payload: unknown): TEventType {
|
||||
return payload as TEventType;
|
||||
toJSON(): Array<TriggerMetadata> {
|
||||
return [
|
||||
{
|
||||
type: "static",
|
||||
title: "External Source",
|
||||
rule: {
|
||||
event: this.event.name,
|
||||
payload: deepMergeFilters(
|
||||
this.options.filter ?? {},
|
||||
this.event.filter ?? {}
|
||||
),
|
||||
source: this.event.source,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
toJSON(): TriggerMetadata {
|
||||
return {
|
||||
title: this.options.title,
|
||||
elements: this.options.elements,
|
||||
eventRule: this.options.eventRule,
|
||||
};
|
||||
}
|
||||
|
||||
attach(
|
||||
attachToJob(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<TEventType>, any>,
|
||||
variantId?: string
|
||||
): void {
|
||||
new Job(triggerClient, {
|
||||
id: `${job.id}-prepare-external-trigger${
|
||||
variantId ? `-${variantId}` : ""
|
||||
}`,
|
||||
name: `Prepare ${this.options.title}`,
|
||||
version: job.version,
|
||||
trigger: internalPrepareTrigger(job, variantId),
|
||||
connections: {
|
||||
client: this.options.source.connection,
|
||||
},
|
||||
queue: {
|
||||
name: `internal:${triggerClient.name}`,
|
||||
maxConcurrent: 1,
|
||||
},
|
||||
run: async (event, io, ctx) => {
|
||||
return await this.options.source.register(io, ctx);
|
||||
},
|
||||
// @ts-ignore
|
||||
__internal: true,
|
||||
});
|
||||
}
|
||||
job: Job<Trigger<TEventSpecification>, any>
|
||||
) {}
|
||||
}
|
||||
|
||||
type RawSourceTriggerEvent<TChannel extends ChannelNames> = {
|
||||
@@ -183,98 +181,98 @@ type RawSourceTriggerEvent<TChannel extends ChannelNames> = {
|
||||
source: { key: string; secret: string; data: any };
|
||||
};
|
||||
|
||||
function rawSourceTrigger<TChannel extends ChannelNames>(
|
||||
channel: TChannel,
|
||||
key: string
|
||||
): Trigger<RawSourceTriggerEvent<TChannel>> {
|
||||
return new RawSourceEventTrigger(channel, key);
|
||||
}
|
||||
// function rawSourceTrigger<TChannel extends ChannelNames>(
|
||||
// channel: TChannel,
|
||||
// key: string
|
||||
// ): Trigger<RawSourceTriggerEvent<TChannel>> {
|
||||
// return new RawSourceEventTrigger(channel, key);
|
||||
// }
|
||||
|
||||
class RawSourceEventTrigger<TChannel extends ChannelNames>
|
||||
implements Trigger<RawSourceTriggerEvent<TChannel>>
|
||||
{
|
||||
constructor(private channel: TChannel, private key: string) {}
|
||||
// class RawSourceEventTrigger<TChannel extends ChannelNames>
|
||||
// implements Trigger<RawSourceTriggerEvent<TChannel>>
|
||||
// {
|
||||
// constructor(private channel: TChannel, private key: string) {}
|
||||
|
||||
eventElements(event: ApiEventLog): DisplayElement[] {
|
||||
return [];
|
||||
}
|
||||
// eventElements(event: ApiEventLog): DisplayElement[] {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
toJSON(): TriggerMetadata {
|
||||
return {
|
||||
title: "Handle Raw Source Event",
|
||||
elements: [{ label: "sourceKey", text: this.key }],
|
||||
eventRule: {
|
||||
event: "internal.trigger.handle-raw-source-event",
|
||||
source: "trigger.dev",
|
||||
payload: {
|
||||
source: { key: [this.key] },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
// toJSON(): TriggerMetadata {
|
||||
// return {
|
||||
// title: "Handle Raw Source Event",
|
||||
// elements: [{ label: "sourceKey", text: this.key }],
|
||||
// eventRule: {
|
||||
// event: "internal.trigger.handle-raw-source-event",
|
||||
// source: "trigger.dev",
|
||||
// payload: {
|
||||
// source: { key: [this.key] },
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
parsePayload(payload: unknown): RawSourceTriggerEvent<TChannel> {
|
||||
return payload as RawSourceTriggerEvent<TChannel>;
|
||||
}
|
||||
// parsePayload(payload: unknown): RawSourceTriggerEvent<TChannel> {
|
||||
// return payload as RawSourceTriggerEvent<TChannel>;
|
||||
// }
|
||||
|
||||
attach(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<RawSourceTriggerEvent<TChannel>>, any>,
|
||||
variantId?: string
|
||||
): void {}
|
||||
}
|
||||
// attach(
|
||||
// triggerClient: TriggerClient,
|
||||
// job: Job<Trigger<RawSourceTriggerEvent<TChannel>>, any>,
|
||||
// variantId?: string
|
||||
// ): void {}
|
||||
// }
|
||||
|
||||
const PrepareTriggerEventSchema = z.object({
|
||||
jobId: z.string(),
|
||||
jobVersion: z.string(),
|
||||
variantId: z.string().optional(),
|
||||
});
|
||||
// const PrepareTriggerEventSchema = z.object({
|
||||
// jobId: z.string(),
|
||||
// jobVersion: z.string(),
|
||||
// variantId: z.string().optional(),
|
||||
// });
|
||||
|
||||
type PrepareTriggerEvent = z.infer<typeof PrepareTriggerEventSchema>;
|
||||
// type PrepareTriggerEvent = z.infer<typeof PrepareTriggerEventSchema>;
|
||||
|
||||
class PrepareTriggerInternalTrigger implements Trigger<PrepareTriggerEvent> {
|
||||
constructor(
|
||||
private job: Job<Trigger<any>, any>,
|
||||
private variantId?: string
|
||||
) {}
|
||||
// class PrepareTriggerInternalTrigger implements Trigger<PrepareTriggerEvent> {
|
||||
// constructor(
|
||||
// private job: Job<Trigger<any>, any>,
|
||||
// private variantId?: string
|
||||
// ) {}
|
||||
|
||||
eventElements(event: ApiEventLog): DisplayElement[] {
|
||||
return [];
|
||||
}
|
||||
// eventElements(event: ApiEventLog): DisplayElement[] {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
toJSON(): TriggerMetadata {
|
||||
return {
|
||||
title: "Prepare Trigger",
|
||||
elements: [
|
||||
{ label: "id", text: this.job.id },
|
||||
{ label: "version", text: this.job.version },
|
||||
],
|
||||
eventRule: {
|
||||
event: "internal.trigger.prepare",
|
||||
source: "trigger.dev",
|
||||
payload: {
|
||||
jobId: [this.job.id],
|
||||
jobVersion: [this.job.version],
|
||||
variantId: this.variantId ? [this.variantId] : [],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
// toJSON(): TriggerMetadata {
|
||||
// return {
|
||||
// title: "Prepare Trigger",
|
||||
// elements: [
|
||||
// { label: "id", text: this.job.id },
|
||||
// { label: "version", text: this.job.version },
|
||||
// ],
|
||||
// eventRule: {
|
||||
// event: "internal.trigger.prepare",
|
||||
// source: "trigger.dev",
|
||||
// payload: {
|
||||
// jobId: [this.job.id],
|
||||
// jobVersion: [this.job.version],
|
||||
// variantId: this.variantId ? [this.variantId] : [],
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
parsePayload(payload: unknown): PrepareTriggerEvent {
|
||||
return PrepareTriggerEventSchema.parse(payload);
|
||||
}
|
||||
// parsePayload(payload: unknown): PrepareTriggerEvent {
|
||||
// return PrepareTriggerEventSchema.parse(payload);
|
||||
// }
|
||||
|
||||
attach(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<PrepareTriggerEvent>, any>,
|
||||
variantId?: string
|
||||
): void {}
|
||||
}
|
||||
// attach(
|
||||
// triggerClient: TriggerClient,
|
||||
// job: Job<Trigger<PrepareTriggerEvent>, any>,
|
||||
// variantId?: string
|
||||
// ): void {}
|
||||
// }
|
||||
|
||||
export function internalPrepareTrigger(
|
||||
job: Job<Trigger<any>, any>,
|
||||
variantId?: string
|
||||
): Trigger<PrepareTriggerEvent> {
|
||||
return new PrepareTriggerInternalTrigger(job, variantId);
|
||||
}
|
||||
// export function internalPrepareTrigger(
|
||||
// job: Job<Trigger<any>, any>,
|
||||
// variantId?: string
|
||||
// ): Trigger<PrepareTriggerEvent> {
|
||||
// return new PrepareTriggerInternalTrigger(job, variantId);
|
||||
// }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type {
|
||||
ApiEventLog,
|
||||
EventFilter,
|
||||
RawEvent,
|
||||
SecureString,
|
||||
SendEvent,
|
||||
@@ -9,6 +10,8 @@ import type {
|
||||
import { DisplayElement } from "@trigger.dev/internal";
|
||||
import { Job } from "./job";
|
||||
import { TriggerClient } from "./triggerClient";
|
||||
import { AnExternalSource } from "./triggers/externalSource";
|
||||
import { Connection } from "./connections";
|
||||
|
||||
export type { SecureString };
|
||||
|
||||
@@ -40,18 +43,32 @@ export interface TaskLogger {
|
||||
}
|
||||
|
||||
export type TriggerEventType<TTrigger extends Trigger<any>> =
|
||||
TTrigger extends Trigger<infer TEventType> ? TEventType : never;
|
||||
|
||||
export interface Trigger<TEventType = any> {
|
||||
eventElements(event: ApiEventLog): DisplayElement[];
|
||||
toJSON(): TriggerMetadata;
|
||||
parsePayload(payload: unknown): TEventType;
|
||||
TTrigger extends Trigger<infer TEventSpec>
|
||||
? ReturnType<TEventSpec["parsePayload"]>
|
||||
: never;
|
||||
|
||||
export interface Trigger<TEventSpec extends EventSpecification<any>> {
|
||||
event: TEventSpec;
|
||||
toJSON(): Array<TriggerMetadata>;
|
||||
// Attach this trigger to the job and the trigger client
|
||||
// Gives different triggers the ability to do things like register internal jobs
|
||||
attach(
|
||||
attachToJob(
|
||||
triggerClient: TriggerClient,
|
||||
job: Job<Trigger<TEventType>, any>,
|
||||
variantId?: string
|
||||
job: Job<Trigger<TEventSpec>, any>
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface EventSpecification<TEvent extends any> {
|
||||
name: string;
|
||||
title: string;
|
||||
source: string;
|
||||
elements?: DisplayElement[];
|
||||
schema?: any;
|
||||
examples?: Array<TEvent>;
|
||||
filter?: EventFilter;
|
||||
parsePayload: (payload: unknown) => TEvent;
|
||||
}
|
||||
|
||||
export type EventTypeFromSpecification<
|
||||
TEventSpec extends EventSpecification<any>
|
||||
> = TEventSpec extends EventSpecification<infer TEvent> ? TEvent : never;
|
||||
|
||||
Reference in New Issue
Block a user