feat: inngest provider

This commit is contained in:
Mythie
2024-06-14 13:53:48 +10:00
parent 1c5da46335
commit 6977381e00
6 changed files with 286 additions and 14 deletions

179
package-lock.json generated
View File

@ -11,6 +11,7 @@
],
"dependencies": {
"@documenso/pdf-sign": "^0.1.0",
"inngest-cli": "^0.29.1",
"next-runtime-env": "^3.2.0",
"react": "18.2.0"
},
@ -10057,6 +10058,14 @@
"node": ">=0.4.0"
}
},
"node_modules/adm-zip": {
"version": "0.5.14",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.14.tgz",
"integrity": "sha512-DnyqqifT4Jrcvb8USYjp6FHtBpEIz1mnXu6pTRHZ0RL69LbQYiO+0lDFg5+OKA7U29oWSs3a/i8fhn8ZcceIWg==",
"engines": {
"node": ">=12.0"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@ -11249,6 +11258,11 @@
}
]
},
"node_modules/canonicalize": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.8.tgz",
"integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A=="
},
"node_modules/canvas": {
"version": "2.11.2",
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
@ -11502,7 +11516,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
"devOptional": true,
"engines": {
"node": ">=10"
}
@ -15463,7 +15476,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"devOptional": true,
"dependencies": {
"minipass": "^3.0.0"
},
@ -15475,7 +15487,6 @@
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"devOptional": true,
"dependencies": {
"yallist": "^4.0.0"
},
@ -16141,6 +16152,15 @@
"resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.11.0.tgz",
"integrity": "sha512-HVusNXlVqHe0fzIzdQOGolnFN6mX/fqcrSAOcTBXdvzrXVHwTz11vXeKRmkR5gTuwVpvHZEIyKoePDvuAR+XwQ=="
},
"node_modules/hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"dependencies": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
}
},
"node_modules/hasha": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
@ -16742,6 +16762,130 @@
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
},
"node_modules/inngest": {
"version": "3.19.13",
"resolved": "https://registry.npmjs.org/inngest/-/inngest-3.19.13.tgz",
"integrity": "sha512-Vc8yy+dq361J4ytqSF0ulc5bSrNCW4/fggpH/5sAvb32zM5ybqcZ9IMHdIpK/Xj7UXJhhtBHweasrpIXJ/mqKA==",
"dependencies": {
"@types/debug": "^4.1.12",
"canonicalize": "^1.0.8",
"chalk": "^4.1.2",
"cross-fetch": "^4.0.0",
"debug": "^4.3.4",
"hash.js": "^1.1.7",
"json-stringify-safe": "^5.0.1",
"ms": "^2.1.3",
"serialize-error-cjs": "^0.1.3",
"strip-ansi": "^5.2.0",
"zod": "~3.22.3"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@sveltejs/kit": ">=1.27.3",
"@vercel/node": ">=2.15.9",
"aws-lambda": ">=1.0.7",
"express": ">=4.19.2",
"fastify": ">=4.21.0",
"h3": ">=1.8.1",
"hono": ">=4.2.7",
"koa": ">=2.14.2",
"next": ">=12.0.0",
"typescript": ">=4.7.2"
},
"peerDependenciesMeta": {
"@sveltejs/kit": {
"optional": true
},
"@vercel/node": {
"optional": true
},
"aws-lambda": {
"optional": true
},
"express": {
"optional": true
},
"fastify": {
"optional": true
},
"h3": {
"optional": true
},
"hono": {
"optional": true
},
"koa": {
"optional": true
},
"next": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/inngest-cli": {
"version": "0.29.1",
"resolved": "https://registry.npmjs.org/inngest-cli/-/inngest-cli-0.29.1.tgz",
"integrity": "sha512-I4wa5QpJP3hO4YbO3sE+ilPgqlc5ny9HPt8kBf2teGnqJ++qPZF+VepHNOFuAwiHdhldGQttfMyysASGJbv2bA==",
"hasInstallScript": true,
"dependencies": {
"adm-zip": "^0.5.10",
"debug": "^4.3.4",
"node-fetch": "2.6.7",
"tar": "6.2.1"
},
"bin": {
"inngest": "bin/inngest",
"inngest-cli": "bin/inngest"
}
},
"node_modules/inngest-cli/node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/inngest/node_modules/ansi-regex": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
"engines": {
"node": ">=6"
}
},
"node_modules/inngest/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/inngest/node_modules/strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dependencies": {
"ansi-regex": "^4.1.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/input-otp": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.2.4.tgz",
@ -17847,6 +17991,11 @@
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
},
"node_modules/json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
@ -20020,6 +20169,11 @@
"resolved": "https://registry.npmjs.org/minimal-polyfills/-/minimal-polyfills-2.2.3.tgz",
"integrity": "sha512-oxdmJ9cL+xV72h0xYxp4tP2d5/fTBpP45H8DIOn9pASuF8a3IYTf+25fMGDYGiWW+MFsuog6KD6nfmhZJQ+uUw=="
},
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -20209,7 +20363,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"devOptional": true,
"dependencies": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
@ -20222,7 +20375,6 @@
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"devOptional": true,
"dependencies": {
"yallist": "^4.0.0"
},
@ -20234,7 +20386,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"devOptional": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
@ -25925,6 +26076,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/serialize-error-cjs": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/serialize-error-cjs/-/serialize-error-cjs-0.1.3.tgz",
"integrity": "sha512-GXwbHkufrNZ87O7DUEvWhR8eBnOqiXtHsOXakkJliG7eLDmjh6gDlbJbMZFFbUx0J5sXKgwq4NFCs41dF5MhiA==",
"funding": {
"url": "https://github.com/sponsors/finwo"
}
},
"node_modules/serialize-error/node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@ -27203,10 +27362,9 @@
}
},
"node_modules/tar": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
"integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
"devOptional": true,
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"dependencies": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
@ -31672,6 +31830,7 @@
"@trigger.dev/sdk": "^2.3.18",
"@upstash/redis": "^1.20.6",
"@vvo/tzdb": "^6.117.0",
"inngest": "^3.19.13",
"kysely": "^0.26.3",
"luxon": "^3.4.0",
"nanoid": "^4.0.2",

View File

@ -53,6 +53,7 @@
],
"dependencies": {
"@documenso/pdf-sign": "^0.1.0",
"inngest-cli": "^0.29.1",
"next-runtime-env": "^3.2.0",
"react": "18.2.0"
},

View File

@ -41,7 +41,10 @@ export type JobDefinition<Name extends string = string, Schema = any> = {
export interface JobRunIO {
// stableRun<T extends Json | void>(cacheKey: string, callback: (io: JobRunIO) => T | Promise<T>): Promise<T>;
runTask<T extends Json | void>(cacheKey: string, callback: () => Promise<T>): Promise<T>;
runTask<T extends Json | void | undefined>(
cacheKey: string,
callback: () => Promise<T>,
): Promise<T>;
triggerJob(cacheKey: string, options: SimpleTriggerJobOptions): Promise<unknown>;
wait(cacheKey: string, ms: number): Promise<void>;
logger: {

View File

@ -0,0 +1,107 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { Context, Handler, InngestFunction } from 'inngest';
import { Inngest as InngestClient } from 'inngest';
import type { Logger } from 'inngest/middleware/logger';
import { serve as createPagesRoute } from 'inngest/next';
import type { JobDefinition, JobRunIO, SimpleTriggerJobOptions } from './_internal/job';
import { BaseJobProvider } from './base';
export class InngestJobProvider extends BaseJobProvider {
private static _instance: InngestJobProvider;
private _client: InngestClient;
private _functions: Array<InngestFunction<InngestFunction.Options, Handler.Any, Handler.Any>> =
[];
private constructor(options: { client: InngestClient }) {
super();
this._client = options.client;
}
static getInstance() {
if (!this._instance) {
const client = new InngestClient({
id: 'documenso-app',
eventKey: process.env.NEXT_PRIVATE_INNGEST_EVENT_KEY,
});
this._instance = new InngestJobProvider({ client });
}
return this._instance;
}
public defineJob<N extends string, T>(job: JobDefinition<N, T>): void {
const fn = this._client.createFunction(
{
id: job.id,
name: job.name,
},
{
event: job.trigger.name,
},
async (ctx) => {
const io = this.convertInngestIoToJobRunIo(ctx);
// We need to cast to any so we can deal with parsing later.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
let payload = ctx.event.data as any;
if (job.trigger.schema) {
payload = job.trigger.schema.parse(payload);
}
await job.handler({ payload, io });
},
);
this._functions.push(fn);
}
public async triggerJob(options: SimpleTriggerJobOptions): Promise<void> {
await this._client.send({
id: options.id,
name: options.name,
data: options.payload,
ts: options.timestamp,
});
}
public getApiHandler(): (req: NextApiRequest, res: NextApiResponse) => Promise<void> {
// !: Ignoring the error here since this is designed to work with the Next.js pages router
// !: but wants a more strict type.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
return createPagesRoute({
client: this._client,
functions: this._functions,
});
}
private convertInngestIoToJobRunIo(ctx: Context.Any & { logger: Logger }) {
const { step } = ctx;
return {
wait: step.sleep,
logger: {
...ctx.logger,
log: ctx.logger.info,
},
runTask: async (cacheKey, callback) => {
const result = await step.run(cacheKey, callback);
// !: Not dealing with this right now but it should be correct.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
return result as any;
},
triggerJob: async (cacheKey, payload) =>
step.sendEvent(cacheKey, {
...payload,
timestamp: payload.timestamp,
}),
} satisfies JobRunIO;
}
}

View File

@ -36,6 +36,7 @@
"@trigger.dev/sdk": "^2.3.18",
"@upstash/redis": "^1.20.6",
"@vvo/tzdb": "^6.117.0",
"inngest": "^3.19.13",
"kysely": "^0.26.3",
"luxon": "^3.4.0",
"nanoid": "^4.0.2",
@ -52,8 +53,8 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@playwright/browser-chromium": "1.43.0",
"@types/luxon": "^3.3.1",
"@types/pg": "^8.11.4",
"@playwright/browser-chromium": "1.43.0"
"@types/pg": "^8.11.4"
}
}

View File

@ -111,6 +111,7 @@
"NEXT_PRIVATE_JOBS_PROVIDER",
"NEXT_PRIVATE_TRIGGER_API_KEY",
"NEXT_PRIVATE_TRIGGER_API_URL",
"NEXT_PRIVATE_INNGEST_EVENT_KEY",
"CI",
"VERCEL",
"VERCEL_ENV",
@ -129,4 +130,4 @@
"E2E_TEST_AUTHENTICATE_USER_EMAIL",
"E2E_TEST_AUTHENTICATE_USER_PASSWORD"
]
}
}