4b3b418abb
* Added Endpoint deletedAt column * Only show endpoints where they’re not deleted * Don’t delete Endpoints, set the deletedAt and change their slug name * Only perform indexing if the endpoint isn’t deleted * Have a nullable URL for endpoints * Deal with null URLs throughout the app * Re-running and retrying behaves properly when there’s no endpoint URL * Remove console.log * Better error message when doing a run
127 lines
3.3 KiB
TypeScript
127 lines
3.3 KiB
TypeScript
import { z } from "zod";
|
|
import type { PrismaClient } from "~/db.server";
|
|
import { prisma } from "~/db.server";
|
|
import { resolveSourceConnection } from "~/models/sourceConnection.server";
|
|
import { EndpointApi } from "../endpointApi.server";
|
|
import { IngestSendEvent } from "../events/ingestSendEvent.server";
|
|
import { getSecretStore } from "../secrets/secretStore.server";
|
|
|
|
export class DeliverHttpSourceRequestService {
|
|
#prismaClient: PrismaClient;
|
|
|
|
constructor(prismaClient: PrismaClient = prisma) {
|
|
this.#prismaClient = prismaClient;
|
|
}
|
|
|
|
public async call(id: string) {
|
|
const httpSourceRequest = await this.#prismaClient.httpSourceRequestDelivery.findUniqueOrThrow({
|
|
where: { id },
|
|
include: {
|
|
endpoint: true,
|
|
environment: {
|
|
include: {
|
|
organization: true,
|
|
project: true,
|
|
},
|
|
},
|
|
source: {
|
|
include: {
|
|
secretReference: true,
|
|
dynamicTrigger: true,
|
|
externalAccount: true,
|
|
integration: {
|
|
include: {
|
|
connections: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!httpSourceRequest.source.active) {
|
|
return;
|
|
}
|
|
|
|
if (!httpSourceRequest.endpoint.url) {
|
|
return;
|
|
}
|
|
|
|
const secretStore = getSecretStore(httpSourceRequest.source.secretReference.provider);
|
|
|
|
const secret = await secretStore.getSecret(
|
|
z.object({
|
|
secret: z.string(),
|
|
}),
|
|
httpSourceRequest.source.secretReference.key
|
|
);
|
|
|
|
if (!secret) {
|
|
throw new Error(`Secret not found for ${httpSourceRequest.source.key}`);
|
|
}
|
|
|
|
const auth = await resolveSourceConnection(this.#prismaClient, httpSourceRequest.source);
|
|
|
|
const clientApi = new EndpointApi(
|
|
httpSourceRequest.environment.apiKey,
|
|
httpSourceRequest.endpoint.url
|
|
);
|
|
|
|
const { response, events, metadata } = await clientApi.deliverHttpSourceRequest({
|
|
key: httpSourceRequest.source.key,
|
|
dynamicId: httpSourceRequest.source.dynamicTrigger?.slug,
|
|
secret: secret.secret,
|
|
params: httpSourceRequest.source.params,
|
|
data: httpSourceRequest.source.channelData,
|
|
request: {
|
|
url: httpSourceRequest.url,
|
|
method: httpSourceRequest.method,
|
|
headers: httpSourceRequest.headers as Record<string, string>,
|
|
rawBody: httpSourceRequest.body,
|
|
},
|
|
auth,
|
|
metadata: httpSourceRequest.source.metadata,
|
|
});
|
|
|
|
await this.#prismaClient.httpSourceRequestDelivery.update({
|
|
where: {
|
|
id,
|
|
},
|
|
data: {
|
|
deliveredAt: new Date(),
|
|
},
|
|
});
|
|
|
|
if (metadata) {
|
|
await this.#prismaClient.triggerSource.update({
|
|
where: {
|
|
id: httpSourceRequest.source.id,
|
|
},
|
|
data: {
|
|
metadata: metadata,
|
|
},
|
|
});
|
|
}
|
|
|
|
const ingestService = new IngestSendEvent();
|
|
|
|
for (const event of events) {
|
|
await ingestService.call(
|
|
httpSourceRequest.environment,
|
|
event,
|
|
{
|
|
accountId: httpSourceRequest.source.externalAccount?.identifier,
|
|
},
|
|
httpSourceRequest.source.dynamicSourceId
|
|
? {
|
|
id: httpSourceRequest.source.dynamicSourceId,
|
|
metadata: httpSourceRequest.source.dynamicSourceMetadata,
|
|
}
|
|
: undefined
|
|
);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
}
|