mirror of
https://github.com/hanzoai/sign.git
synced 2026-10-30 14:57:59 +00:00
inngest went from 3 to 4 in the version sweep. 4's createFunction takes the
triggers inside its options and the handler second, and throws when handed
the old three arguments. With the Inngest provider selected, the first
defineJob threw "createFunction expected a handler function as the second
argument", so no job could be registered. The trigger now sits in the
options.
Starting a job as a step of another sent `{ ...options, timestamp }`, whose
payload was not the event's `data`, so the job it started parsed an empty
event. inngest 3's types let that through and 4's refuse it. Both ways of
starting a job now send toInngestEvent(options): the payload as `data`, the
timestamp as `ts`, as triggerJob already did. inngest.test.ts holds the
mapping; a run of defineJob against the installed inngest registers each
job with its event or cron trigger and a handler.
Co-authored-by: Hanzo Dev <[email protected]>
117 lines
3.5 KiB
TypeScript
117 lines
3.5 KiB
TypeScript
import type { Context as HonoContext } from 'hono';
|
|
import type { Context, Handler, InngestFunction } from 'inngest';
|
|
import { Inngest as InngestClient } from 'inngest';
|
|
import type { Logger } from 'inngest';
|
|
import { serve as createHonoPagesRoute } from 'inngest/hono';
|
|
|
|
import { env } from '../../utils/env';
|
|
import type { JobDefinition, JobRunIO, SimpleTriggerJobOptions } from './_internal/job';
|
|
import { BaseJobProvider } from './base';
|
|
|
|
/**
|
|
* A job trigger as the Inngest event that starts the job: the payload travels
|
|
* as the event's data and the timestamp as its `ts`.
|
|
*/
|
|
export const toInngestEvent = ({ id, name, payload, timestamp }: SimpleTriggerJobOptions) => ({
|
|
id,
|
|
name,
|
|
data: payload,
|
|
ts: timestamp,
|
|
});
|
|
|
|
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: env('NEXT_PRIVATE_INNGEST_APP_ID') || 'sign-app',
|
|
eventKey: env('INNGEST_EVENT_KEY') || env('NEXT_PRIVATE_INNGEST_EVENT_KEY'),
|
|
logger: console,
|
|
});
|
|
|
|
this._instance = new InngestJobProvider({ client });
|
|
}
|
|
|
|
return this._instance;
|
|
}
|
|
|
|
public defineJob<N extends string, T>(job: JobDefinition<N, T>): void {
|
|
const trigger: { cron: string } | { event: string } = job.trigger.cron
|
|
? { cron: job.trigger.cron }
|
|
: { event: job.trigger.name };
|
|
|
|
const fn = this._client.createFunction(
|
|
{
|
|
id: job.id,
|
|
name: job.name,
|
|
optimizeParallelism: job.optimizeParallelism ?? false,
|
|
triggers: trigger,
|
|
},
|
|
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(toInngestEvent(options));
|
|
}
|
|
|
|
public getApiHandler() {
|
|
return async (context: HonoContext) => {
|
|
const handler = createHonoPagesRoute({
|
|
client: this._client,
|
|
functions: this._functions,
|
|
});
|
|
|
|
return await handler(context);
|
|
};
|
|
}
|
|
|
|
private convertInngestIoToJobRunIo(ctx: Context.Any & { logger: Logger }) {
|
|
const { step } = ctx;
|
|
|
|
return {
|
|
wait: step.sleep,
|
|
logger: {
|
|
info: ctx.logger.info,
|
|
debug: ctx.logger.debug,
|
|
error: ctx.logger.error,
|
|
warn: ctx.logger.warn,
|
|
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, options) => step.sendEvent(cacheKey, toInngestEvent(options)),
|
|
} satisfies JobRunIO;
|
|
}
|
|
}
|