Skip to content

Commit

Permalink
feat: Added h3 server handler to @ingest/h3. (#310)
Browse files Browse the repository at this point in the history
## Summary

Added h3 server handler to @ingest/h3.

h3 is the unjs project which is the foundation for the Nuxt 3 server
`eventHandlers`.

This MR provides backwards compatibility between Nuxt and h3, and can
also be used within a nitro server setup too.

Includes bumping h3 to the latest version (v1.8.1).

## Checklist

- [ ] Added a [docs PR](https://github.com/inngest/website) that
references this PR
- [X] Added unit/integration tests
- [X] Added changesets if applicable

---------

Co-authored-by: Jack Williams <1736957+jpwilliams@users.noreply.github.com>
michealroberts and jpwilliams authored Sep 19, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 32c34b3 commit 696c411
Showing 9 changed files with 188 additions and 104 deletions.
5 changes: 5 additions & 0 deletions .changeset/warm-steaks-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"inngest": minor
---

Added h3 framework server handler
4 changes: 2 additions & 2 deletions packages/inngest/etc/inngest.api.md
Original file line number Diff line number Diff line change
@@ -174,7 +174,7 @@ export class InngestCommHandler<H extends Handler_2, TResTransform extends (res:
constructor(
frameworkName: string,
client: Inngest<any>,
functions: InngestFunction<any, any, any, any>[], { inngestRegisterUrl, fetch, logLevel, signingKey, serveHost, servePath, streaming, name, }: RegisterOptions | undefined,
functions: InngestFunction<any, any, any, any>[], options: RegisterOptions | undefined,
handler: H,
transformRes: TResTransform,
streamTransformRes?: TStreamTransform);
@@ -362,7 +362,7 @@ export type ZodEventSchemas = Record<string, {
// src/components/InngestMiddleware.ts:332:5 - (ae-forgotten-export) The symbol "MiddlewareSendEventInput" needs to be exported by the entry point index.d.ts
// src/components/InngestMiddleware.ts:342:5 - (ae-forgotten-export) The symbol "MiddlewareSendEventOutput" needs to be exported by the entry point index.d.ts
// src/types.ts:51:5 - (ae-forgotten-export) The symbol "failureEventErrorSchema" needs to be exported by the entry point index.d.ts
// src/types.ts:685:5 - (ae-forgotten-export) The symbol "TimeStrBatch" needs to be exported by the entry point index.d.ts
// src/types.ts:693:5 - (ae-forgotten-export) The symbol "TimeStrBatch" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

2 changes: 1 addition & 1 deletion packages/inngest/package.json
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@
"canonicalize": "^1.0.8",
"chalk": "^4.1.2",
"cross-fetch": "^4.0.0",
"h3": "^1.0.2",
"h3": "^1.8.1",
"hash.js": "^1.1.7",
"json-stringify-safe": "^5.0.1",
"ms": "^2.1.3",
31 changes: 12 additions & 19 deletions packages/inngest/src/components/InngestCommHandler.ts
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ import { type MaybePromise } from "../helpers/types";
import {
type FunctionConfig,
type IncomingOp,
type InternalRegisterOptions,
type IntrospectRequest,
type LogLevel,
type RegisterOptions,
@@ -307,16 +308,7 @@ export class InngestCommHandler<
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
functions: InngestFunction<any, any, any, any>[],
{
inngestRegisterUrl,
fetch,
logLevel = "info",
signingKey,
serveHost,
servePath,
streaming,
name,
}: RegisterOptions = {},
options: RegisterOptions = {},

/**
* The `handler` is the function your framework requires to handle a
@@ -396,9 +388,10 @@ export class InngestCommHandler<
*/
streamTransformRes?: TStreamTransform
) {
this.frameworkName = frameworkName;
this.frameworkName =
(options as InternalRegisterOptions)?.frameworkName || frameworkName;
this.client = client;
this.name = name || this.client.name;
this.name = options.name || this.client.name;

this.handler = handler;
this.transformRes = transformRes;
@@ -451,16 +444,16 @@ export class InngestCommHandler<
}, {});

this.inngestRegisterUrl = new URL(
inngestRegisterUrl || "https://api.inngest.com/fn/register"
options.inngestRegisterUrl || "https://api.inngest.com/fn/register"
);

this.signingKey = signingKey;
this.serveHost = serveHost;
this.servePath = servePath;
this.logLevel = logLevel;
this.streaming = streaming ?? false;
this.signingKey = options.signingKey;
this.serveHost = options.serveHost;
this.servePath = options.servePath;
this.logLevel = options.logLevel ?? "info";
this.streaming = options.streaming ?? false;

this.fetch = getFetch(fetch || this.client["fetch"]);
this.fetch = getFetch(options.fetch || this.client["fetch"]);
}

// hashedSigningKey creates a sha256 checksum of the signing key with the
9 changes: 9 additions & 0 deletions packages/inngest/src/h3.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as h3Handler from "@local/h3";
import { createEvent } from "h3";
import { testFramework } from "./test/helpers";

testFramework("h3", h3Handler, {
transformReq(req, res) {
return [createEvent(req, res)];
},
});
76 changes: 76 additions & 0 deletions packages/inngest/src/h3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
getHeader,
getQuery,
readBody,
send,
setHeaders,
type H3Event,
} from "h3";
import {
InngestCommHandler,
type ServeHandler,
} from "./components/InngestCommHandler";
import { headerKeys, queryKeys } from "./helpers/consts";
import { processEnv } from "./helpers/env";
import { type SupportedFrameworkName } from "./types";

export const name: SupportedFrameworkName = "h3";

/**
* In h3, serve and register any declared functions with Inngest, making
* them available to be triggered by events.
*
* @public
*/
export const serve: ServeHandler = (nameOrInngest, fns, opts) => {
const handler = new InngestCommHandler(
name,
nameOrInngest,
fns,
opts,
(event: H3Event) => {
const host = String(getHeader(event, "host"));
const protocol =
processEnv("NODE_ENV") === "development" ? "http" : "https";
const url = new URL(String(event.path), `${protocol}://${host}`);
const method = event.method;
const query = getQuery(event);

return {
url,
run: async () => {
if (method === "POST") {
return {
fnId: query[queryKeys.FnId]?.toString() ?? "",
stepId: query[queryKeys.StepId]?.toString() ?? "",
signature: getHeader(event, headerKeys.Signature),
data: await readBody(event),
};
}
},
register: () => {
if (method === "PUT") {
return {
deployId: query[queryKeys.DeployId]?.toString(),
};
}
},
view: () => {
if (method === "GET") {
return {
isIntrospection: query && queryKeys.Introspect in query,
};
}
},
};
},
(actionRes, event: H3Event) => {
const { res } = event.node;
res.statusCode = actionRes.status;
setHeaders(event, actionRes.headers);
return send(event, actionRes.body);
}
);

return handler.createHandler();
};
77 changes: 12 additions & 65 deletions packages/inngest/src/nuxt.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import { type ServeHandler } from "./components/InngestCommHandler";
import { serve as serveH3 } from "./h3";
import {
getHeader,
getMethod,
getQuery,
readBody,
send,
setHeaders,
type H3Event,
} from "h3";
import {
InngestCommHandler,
type ServeHandler,
} from "./components/InngestCommHandler";
import { headerKeys, queryKeys } from "./helpers/consts";
import { processEnv } from "./helpers/env";
import { type SupportedFrameworkName } from "./types";
type InternalRegisterOptions,
type SupportedFrameworkName,
} from "./types";

export const name: SupportedFrameworkName = "nuxt";

@@ -23,55 +13,12 @@ export const name: SupportedFrameworkName = "nuxt";
*
* @public
*/
export const serve: ServeHandler = (nameOrInngest, fns, opts) => {
const handler = new InngestCommHandler(
name,
nameOrInngest,
fns,
opts,
(event: H3Event) => {
const host = String(getHeader(event, "host"));
const protocol =
processEnv("NODE_ENV") === "development" ? "http" : "https";
const url = new URL(String(event.path), `${protocol}://${host}`);
const method = getMethod(event);
const query = getQuery(event);

return {
url,
run: async () => {
if (method === "POST") {
return {
fnId: query[queryKeys.FnId]?.toString() ?? "",
stepId: query[queryKeys.StepId]?.toString() ?? "",
signature: getHeader(event, headerKeys.Signature),
data: await readBody(event),
};
}
},
register: () => {
if (method === "PUT") {
return {
deployId: query[queryKeys.DeployId]?.toString(),
};
}
},
view: () => {
if (method === "GET") {
return {
isIntrospection: query && queryKeys.Introspect in query,
};
}
},
};
},
(actionRes, event: H3Event) => {
const { res } = event.node;
res.statusCode = actionRes.status;
setHeaders(event, actionRes.headers);
return send(event, actionRes.body);
}
);
export const serve: ServeHandler = (client, functions, opts) => {
const optsOverrides: InternalRegisterOptions = {
...opts,
frameworkName: name,
};

return handler.createHandler();
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return serveH3(client, functions, optsOverrides);
};
9 changes: 9 additions & 0 deletions packages/inngest/src/types.ts
Original file line number Diff line number Diff line change
@@ -605,6 +605,14 @@ export interface RegisterOptions {
name?: string;
}

export interface InternalRegisterOptions extends RegisterOptions {
/**
* Can be used to override the framework name given to a particular serve
* handler.
*/
frameworkName?: string;
}

/**
* A user-friendly method of specifying a trigger for an Inngest function.
*/
@@ -1019,6 +1027,7 @@ export type SupportedFrameworkName =
| "aws-lambda"
| "nextjs"
| "nuxt"
| "h3"
| "redwoodjs"
| "remix"
| "deno/fresh"
Loading

0 comments on commit 696c411

Please sign in to comment.