Skip to content

Commit

Permalink
INN-1087 Add edge streaming support to all serve handlers (#163)
Browse files Browse the repository at this point in the history
## Summary INN-1087

Adds the ability for the SDK to stream responses back to Inngest,
enabling longer timeouts in edge runtimes such as Deno, Cloudflare, or
Next.js.

- **Add edge streaming support**
> We're currently very strict about streaming support, only allowing it
for `"inngest/next"`, ensuring users must opt in using
`allowEdgeStreaming: true` and only allowing Next.js projects on Vercel.
  >
> Following this being tested in production for a while, streaming
support for other supported platforms is trivial to add, just writing
code to turn it on.
- **Add support for Next.js Edge Functions**
> The `"inngest/next"` handler now supports both Serverless Functions
and Edge Functions; users can switch between both using Next.js
conventions without having to change any of our code or imports.
- **Add support for Next.js 13+ [Route
Handlers](https://beta.nextjs.org/docs/routing/route-handlers)**
> Ended up wanting this as part of testing; if folks are using
edge/streaming then it feels more likely that they're happy to use a
beta version of Next.js itself too, so we might as well support this.
  > 
> Route handlers use the same `"inngest/next"` serve handler, but users
must export differently:
  > ```ts
  > export default serve(...);
  > // to
  > export const { GET, POST, PUT } = serve(...);
  > ```

## Related

- inngest/inngest#429
  • Loading branch information
jpwilliams committed Apr 25, 2023
1 parent 604e102 commit 65966f5
Show file tree
Hide file tree
Showing 22 changed files with 595 additions and 123 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-tools-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"inngest": minor
---

INN-1087 Add edge streaming support to `"inngest/next"` serve handler
18 changes: 12 additions & 6 deletions etc/inngest.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,22 @@ export class Inngest<Events extends Record<string, EventPayload> = Record<string
}

// Warning: (ae-forgotten-export) The symbol "Handler_2" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "ActionResponse" needs to be exported by the entry point index.d.ts
//
// @public
export class InngestCommHandler<H extends Handler_2, TransformedRes> {
export class InngestCommHandler<H extends Handler_2, TResTransform extends (res: ActionResponse<string>, ...args: Parameters<H>) => any, TStreamTransform extends (res: ActionResponse<ReadableStream>, ...args: Parameters<H>) => any> {
constructor(
frameworkName: string,
appNameOrInngest: string | Inngest<any>,
functions: InngestFunction<any, any, any>[], { inngestRegisterUrl, fetch, landingPage, logLevel, signingKey, serveHost, servePath, }: RegisterOptions | undefined,
functions: InngestFunction<any, any, any>[], { inngestRegisterUrl, fetch, landingPage, logLevel, signingKey, serveHost, servePath, streaming, }: RegisterOptions | undefined,
handler: H,
transformRes: (actionRes: ActionResponse, ...args: Parameters<H>) => TransformedRes);
transformRes: TResTransform,
streamTransformRes?: TStreamTransform);
// Warning: (ae-forgotten-export) The symbol "FunctionConfig" needs to be exported by the entry point index.d.ts
//
// (undocumented)
protected configs(url: URL): FunctionConfig[];
createHandler(): (...args: Parameters<H>) => Promise<TransformedRes>;
createHandler(): (...args: Parameters<H>) => Promise<Awaited<ReturnType<TResTransform>>>;
protected readonly frameworkName: string;
readonly handler: H;
protected _isProd: boolean;
Expand Down Expand Up @@ -157,8 +159,11 @@ export class InngestCommHandler<H extends Handler_2, TransformedRes> {
protected signingKey: string | undefined;
// (undocumented)
protected signResponse(): string;
// Warning: (ae-forgotten-export) The symbol "ActionResponse" needs to be exported by the entry point index.d.ts
readonly transformRes: (res: ActionResponse, ...args: Parameters<H>) => TransformedRes;
// (undocumented)
protected readonly streaming: RegisterOptions["streaming"];
// (undocumented)
readonly streamTransformRes: TStreamTransform | undefined;
readonly transformRes: TResTransform;
// (undocumented)
protected validateSignature(sig: string | undefined, body: Record<string, unknown>): void;
}
Expand Down Expand Up @@ -200,6 +205,7 @@ export interface RegisterOptions {
serveHost?: string;
servePath?: string;
signingKey?: string;
streaming?: "allow" | "force" | false;
}

// @public
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"build:landing": "cd landing && yarn run build",
"build:check": "api-extractor run --verbose",
"build:copy": "cp package.json LICENSE.md README.md CHANGELOG.md dist",
"prelink": "yarn run build:copy"
"prelink": "yarn run build:copy",
"local:pack": "yarn build && yarn prelink && yarn pack --verbose --frozen-lockfile --filename inngest.tgz --cwd dist"
},
"homepage": "https://github.com/inngest/inngest-js#readme",
"repository": {
Expand Down
3 changes: 2 additions & 1 deletion src/cloudflare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
ServeHandler,
} from "./components/InngestCommHandler";
import { headerKeys, queryKeys } from "./helpers/consts";
import type { SupportedFrameworkName } from "./types";

export const name = "cloudflare-pages";
export const name: SupportedFrameworkName = "cloudflare-pages";

/**
* In Cloudflare, serve and register any declared functions with Inngest, making
Expand Down
20 changes: 2 additions & 18 deletions src/components/Inngest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { envKeys } from "../helpers/consts";
import { devServerAvailable, devServerUrl } from "../helpers/devserver";
import {
devServerHost,
getFetch,
inngestHeaders,
isProd,
processEnv,
Expand Down Expand Up @@ -134,24 +135,7 @@ export class Inngest<
inngestEnv: env,
});

this.fetch = Inngest.parseFetch(fetch);
}

/**
* Given a potential fetch function, return the fetch function to use based on
* this and the environment.
*/
private static parseFetch(fetchArg: FetchT | undefined): FetchT {
if (fetchArg) {
return fetchArg;
}

if (typeof fetch !== "undefined") {
return fetch;
}

// eslint-disable-next-line @typescript-eslint/no-var-requires
return require("cross-fetch") as FetchT;
this.fetch = getFetch(fetch);
}

/**
Expand Down
Loading

0 comments on commit 65966f5

Please sign in to comment.