Skip to content

Commit 384580c

Browse files
authored
Add ability for inngest/remix import to handle SDK UI (#50)
## Summary Remix specifies [Resource Routes](https://remix.run/docs/en/v1/guides/resource-routes), which can be used as generic API routes. This handler used to work by exporting a single `action` handler, but since the SDK UI was added, we now also need a `loader` handler. This PR ensures that both are exported. ```ts import { serve } from "inngest/remix"; import fns from "~/inngest"; export const { loader, action } = serve("My Remix App", fns); ```
1 parent f0b3692 commit 384580c

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

.github/workflows/pr.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ jobs:
5353
- inngest/sdk-example-redwoodjs-vercel
5454
- inngest/sdk-example-nextjs-cloudflare
5555
- inngest/sdk-example-nextjs-netlify
56+
- inngest/sdk-example-remix-vercel
5657
steps:
5758
# Checkout the repo
5859
- uses: actions/checkout@v3

src/remix.ts

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Response } from "cross-fetch";
21
import { z } from "zod";
32
import {
43
InngestCommHandler,
@@ -24,6 +23,21 @@ class RemixCommHandler extends InngestCommHandler {
2423
}: {
2524
request: Request;
2625
}): Promise<Response> => {
26+
/**
27+
* If `Response` isn't included in this environment, it's probably a Node
28+
* env that isn't already polyfilling. In this case, we can polyfill it
29+
* here to be safe.
30+
*/
31+
let Res: typeof Response;
32+
33+
if (typeof Response === "undefined") {
34+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-var-requires
35+
Res = require("cross-fetch").Response;
36+
} else {
37+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
38+
Res = Response;
39+
}
40+
2741
const headers = { "x-inngest-sdk": this.sdkHeader.join("") };
2842

2943
let reqUrl: URL;
@@ -37,7 +51,7 @@ class RemixCommHandler extends InngestCommHandler {
3751
isIntrospection = reqUrl.searchParams.has(queryKeys.Introspect);
3852
reqUrl.searchParams.delete(queryKeys.Introspect);
3953
} catch (err) {
40-
return new Response(JSON.stringify(err), {
54+
return new Res(JSON.stringify(err), {
4155
status: 500,
4256
headers,
4357
});
@@ -67,14 +81,14 @@ class RemixCommHandler extends InngestCommHandler {
6781
hasSigningKey: Boolean(this.signingKey),
6882
};
6983

70-
return new Response(JSON.stringify(introspection), {
84+
return new Res(JSON.stringify(introspection), {
7185
status: 200,
7286
headers,
7387
});
7488
}
7589

7690
// Grab landing page and serve
77-
return new Response(landing, {
91+
return new Res(landing, {
7892
status: 200,
7993
headers: {
8094
...headers,
@@ -90,7 +104,7 @@ class RemixCommHandler extends InngestCommHandler {
90104
process.env[envKeys.DevServerUrl]
91105
);
92106

93-
return new Response(JSON.stringify({ message }), {
107+
return new Res(JSON.stringify({ message }), {
94108
status,
95109
headers,
96110
});
@@ -111,20 +125,20 @@ class RemixCommHandler extends InngestCommHandler {
111125
const stepRes = await this.runStep(fnId, stepId, await req.json());
112126

113127
if (stepRes.status === 500) {
114-
return new Response(JSON.stringify(stepRes.error), {
128+
return new Res(JSON.stringify(stepRes.error), {
115129
status: stepRes.status,
116130
headers,
117131
});
118132
}
119133

120-
return new Response(JSON.stringify(stepRes.body), {
134+
return new Res(JSON.stringify(stepRes.body), {
121135
status: stepRes.status,
122136
headers,
123137
});
124138
}
125139
}
126140

127-
return new Response(null, { status: 405, headers });
141+
return new Res(null, { status: 405, headers });
128142
};
129143
}
130144
}
@@ -133,6 +147,22 @@ class RemixCommHandler extends InngestCommHandler {
133147
* In Remix, serve and register any declared functions with Inngest, making them
134148
* available to be triggered by events.
135149
*
150+
* Remix requires that you export both a "loader" for serving `GET` requests,
151+
* and an "action" for serving other requests, therefore exporting both is
152+
* required.
153+
*
154+
* See {@link https://remix.run/docs/en/v1/guides/resource-routes}
155+
*
156+
* @example
157+
* ```ts
158+
* import { serve } from "inngest/remix";
159+
* import fns from "~/inngest";
160+
*
161+
* const handler = serve("My Remix App", fns);
162+
*
163+
* export { handler as loader, handler as action };
164+
* ```
165+
*
136166
* @public
137167
*/
138168
export const serve: ServeHandler = (nameOrInngest, fns, opts): any => {

0 commit comments

Comments
 (0)