@nextrush/adapter-edge 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +386 -0
- package/dist/index.d.ts +287 -0
- package/dist/index.js +178 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
- package/src/__tests__/adapter.test.ts +89 -0
- package/src/__tests__/body-source.test.ts +85 -0
- package/src/__tests__/context-response-microtrims.test.ts +52 -0
- package/src/__tests__/context.test.ts +536 -0
- package/src/__tests__/default-timeout.test.ts +82 -0
- package/src/__tests__/per-request-work-trim.test.ts +171 -0
- package/src/__tests__/public-surface.test.ts +85 -0
- package/src/__tests__/utils.test.ts +140 -0
- package/src/adapter.ts +333 -0
- package/src/body-source.ts +19 -0
- package/src/context.ts +122 -0
- package/src/index.ts +64 -0
- package/src/utils.ts +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tanzim (NextRush)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# @nextrush/adapter-edge
|
|
2
|
+
|
|
3
|
+
> Runs a NextRush app on any Fetch API edge runtime -- Cloudflare Workers, Vercel Edge
|
|
4
|
+
> Functions, and Netlify Edge Functions -- through one shared handler implementation.
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/@nextrush/adapter-edge)
|
|
7
|
+
[](https://www.npmjs.com/package/@nextrush/adapter-edge)
|
|
8
|
+
[](https://bundlephobia.com/package/@nextrush/adapter-edge)
|
|
9
|
+
[](https://www.npmjs.com/package/@nextrush/adapter-edge)
|
|
10
|
+
[](https://nodejs.org/api/esm.html)
|
|
11
|
+
[](https://github.com/0xTanzim/nextRush/blob/main/LICENSE)
|
|
12
|
+
|
|
13
|
+
| | |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| **Purpose** | Fetch-API entry points that run a NextRush `Application` on edge runtimes |
|
|
16
|
+
| **Package type** | Adapter |
|
|
17
|
+
| **Status** | Stable (implementation) -- but see Support tier below |
|
|
18
|
+
| **Included in `nextrush`?** | No -- standalone install |
|
|
19
|
+
| **Support tier** | Internal -- non-`-node` adapter until GA, may change without a major (see [ADR-0005](https://github.com/0xTanzim/nextRush/blob/main/docs/adr/ADR-0005-package-tiers-sealed-surface-deprecation.md)) |
|
|
20
|
+
| **Maintenance** | Active |
|
|
21
|
+
| **Runtime** | Edge -- any runtime implementing the Fetch API (Cloudflare Workers, Vercel Edge, Netlify Edge) |
|
|
22
|
+
| **Requires** | Node `>=22` for local tooling/build -- ESM-only -- TypeScript `>=5.x` |
|
|
23
|
+
| **Introduced** | `v1.0.0` |
|
|
24
|
+
|
|
25
|
+
## Highlights
|
|
26
|
+
|
|
27
|
+
- Zero external runtime dependencies -- only `@nextrush/{core,errors,runtime,stream,types}` (workspace packages)
|
|
28
|
+
- ESM-only, tree-shakable, side-effect-free (`sideEffects: false`)
|
|
29
|
+
- One shared request runner behind three platform-specific entry points -- Cloudflare, Vercel,
|
|
30
|
+
and Netlify handlers cannot silently drift from each other
|
|
31
|
+
- Fully typed -- strict TypeScript, zero `any`
|
|
32
|
+
|
|
33
|
+
## The problem
|
|
34
|
+
|
|
35
|
+
Edge runtimes agree on the Fetch API (`Request` in, `Response` out) but disagree on the
|
|
36
|
+
surrounding module contract: Cloudflare Workers export `{ fetch(request, env, ctx) }`, Vercel
|
|
37
|
+
Edge Functions export a plain `(request) => Response` with `export const config = { runtime:
|
|
38
|
+
'edge' }`, and Netlify Edge Functions export the same plain shape again. Writing a NextRush app
|
|
39
|
+
against each platform's raw contract by hand means re-deriving request timeout handling,
|
|
40
|
+
404/error fallback, and `Application` boot sequencing three separate times -- and one of those
|
|
41
|
+
copies quietly drifting is how a platform-specific bug ships.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// TODAY, without this package -- three near-duplicate handlers, easy to drift:
|
|
45
|
+
export default {
|
|
46
|
+
fetch(request: Request, env: Env, ctx: ExecutionContext) {
|
|
47
|
+
// boot the app, race a timeout, build a Response... written by hand, three times
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`@nextrush/adapter-edge` centralizes that request-handling logic in one internal runner and
|
|
53
|
+
exposes a thin, platform-shaped wrapper per target.
|
|
54
|
+
|
|
55
|
+
## When to use
|
|
56
|
+
|
|
57
|
+
**Use `@nextrush/adapter-edge` if:**
|
|
58
|
+
|
|
59
|
+
- You are deploying a NextRush app to Cloudflare Workers, Vercel Edge Functions, or Netlify
|
|
60
|
+
Edge Functions.
|
|
61
|
+
- Your app only needs the Web-standard `Request`/`Response`/`fetch` surface -- no Node.js APIs.
|
|
62
|
+
|
|
63
|
+
**Reach for something else if:**
|
|
64
|
+
|
|
65
|
+
- You are deploying to a long-running Node.js process -> use
|
|
66
|
+
[`@nextrush/adapter-node`](../node) instead.
|
|
67
|
+
- You are deploying to AWS Lambda, Google Cloud Functions, or another FaaS platform with its
|
|
68
|
+
own event format -> use [`@nextrush/adapter-serverless`](../serverless) (built on top of this
|
|
69
|
+
package's fetch handler -- see Package relationships below).
|
|
70
|
+
- You are running on Bun or Deno directly (not via an edge platform) -> use
|
|
71
|
+
[`@nextrush/adapter-bun`](../bun) or [`@nextrush/adapter-deno`](../deno).
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pnpm add @nextrush/adapter-edge @nextrush/core
|
|
77
|
+
# npm i @nextrush/adapter-edge @nextrush/core
|
|
78
|
+
# yarn add @nextrush/adapter-edge @nextrush/core
|
|
79
|
+
# bun add @nextrush/adapter-edge @nextrush/core
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> [!NOTE]
|
|
83
|
+
> Not included in the `nextrush` meta package. Install it directly when deploying to an edge
|
|
84
|
+
> runtime.
|
|
85
|
+
|
|
86
|
+
## Quick start
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// Cloudflare Workers -- src/index.ts
|
|
90
|
+
import { createApp } from '@nextrush/core';
|
|
91
|
+
import { createCloudflareHandler } from '@nextrush/adapter-edge';
|
|
92
|
+
|
|
93
|
+
const app = createApp();
|
|
94
|
+
|
|
95
|
+
app.use(async (ctx) => {
|
|
96
|
+
ctx.json({ message: 'Hello from the edge', runtime: ctx.runtime });
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export default createCloudflareHandler(app);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The handler boots the `Application` on the first incoming request (there is no separate
|
|
103
|
+
`listen()` step on edge), then reuses that boot for every subsequent request in the same
|
|
104
|
+
isolate.
|
|
105
|
+
|
|
106
|
+
## Capabilities
|
|
107
|
+
|
|
108
|
+
**Capabilities**
|
|
109
|
+
- **Three platform entry points, one runner** -- `createCloudflareHandler`,
|
|
110
|
+
`createVercelHandler`, and `createNetlifyHandler` all delegate to the same internal request
|
|
111
|
+
runner (`createFetchHandler` is the runner exposed directly, for any other Fetch-API host).
|
|
112
|
+
- **Cloudflare `env` bindings threaded onto context** -- `createCloudflareHandler`'s `env`
|
|
113
|
+
argument (KV, D1, R2, Durable Objects, Queues, secrets) is exposed as `ctx.env`, typed via a
|
|
114
|
+
generic.
|
|
115
|
+
- **Cooperative request timeout** -- races the handler against a timer; on timeout, aborts
|
|
116
|
+
`ctx.signal` and returns `504`, so the framework's own bounded timeout fires before the
|
|
117
|
+
platform kills the isolate.
|
|
118
|
+
- **`waitUntil` for fire-and-forget work** -- `ctx.waitUntil(promise)` extends the request
|
|
119
|
+
lifetime for background tasks (logging, analytics) when the platform provides an execution
|
|
120
|
+
context; a no-op otherwise.
|
|
121
|
+
|
|
122
|
+
**Developer experience**
|
|
123
|
+
- Fully typed exports, including a compile-time guard (`FetchAdapter`,
|
|
124
|
+
`AdapterContextFactory`) that fails the build if this adapter's shape drifts from the shared
|
|
125
|
+
cross-adapter contract.
|
|
126
|
+
|
|
127
|
+
## Mental model
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
Request (Fetch API) --> createXxxHandler --> shared request runner --> Application.callback()
|
|
131
|
+
|
|
|
132
|
+
+-- races Application against a timeout timer
|
|
133
|
+
+-- builds Response via EdgeContext
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Rule:** every platform-specific handler (`createCloudflareHandler`, `createVercelHandler`,
|
|
137
|
+
`createNetlifyHandler`) is a thin wrapper around the same internal runner -- there is exactly
|
|
138
|
+
one request-handling code path to reason about, regardless of platform.
|
|
139
|
+
|
|
140
|
+
> [!TIP]
|
|
141
|
+
> The full request lifecycle (Mermaid) is in [`ARCHITECTURE.md`](./ARCHITECTURE.md).
|
|
142
|
+
|
|
143
|
+
## Common tasks
|
|
144
|
+
|
|
145
|
+
### Deploy to Cloudflare Workers
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
// src/index.ts
|
|
149
|
+
import { createApp } from '@nextrush/core';
|
|
150
|
+
import { createCloudflareHandler } from '@nextrush/adapter-edge';
|
|
151
|
+
|
|
152
|
+
interface Env {
|
|
153
|
+
MY_KV: KVNamespace;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const app = createApp();
|
|
157
|
+
app.use(async (ctx) => {
|
|
158
|
+
const value = await ctx.env?.MY_KV.get('key');
|
|
159
|
+
ctx.json({ value });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
export default createCloudflareHandler<Env>(app);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```toml
|
|
166
|
+
# wrangler.toml
|
|
167
|
+
name = "my-nextrush-worker"
|
|
168
|
+
main = "src/index.ts"
|
|
169
|
+
compatibility_date = "2025-01-01"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Deploy to Vercel Edge Functions
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
// api/hello.ts
|
|
176
|
+
import { createApp } from '@nextrush/core';
|
|
177
|
+
import { createVercelHandler } from '@nextrush/adapter-edge';
|
|
178
|
+
|
|
179
|
+
const app = createApp();
|
|
180
|
+
app.use(async (ctx) => {
|
|
181
|
+
ctx.json({ message: 'Hello from Vercel Edge' });
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
export const config = { runtime: 'edge' };
|
|
185
|
+
export default createVercelHandler(app);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Deploy to Netlify Edge Functions
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
// netlify/edge-functions/api.ts
|
|
192
|
+
import { createApp } from '@nextrush/core';
|
|
193
|
+
import { createNetlifyHandler } from '@nextrush/adapter-edge';
|
|
194
|
+
|
|
195
|
+
const app = createApp();
|
|
196
|
+
app.use(async (ctx) => {
|
|
197
|
+
ctx.json({ message: 'Hello from Netlify Edge' });
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
export default createNetlifyHandler(app);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Read the request body across runtimes
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
app.use(async (ctx) => {
|
|
207
|
+
const text = await ctx.bodySource.text();
|
|
208
|
+
const json = await ctx.bodySource.json();
|
|
209
|
+
const buffer = await ctx.bodySource.buffer();
|
|
210
|
+
const stream = ctx.bodySource.stream();
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Handle errors with a custom handler
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
const handler = createCloudflareHandler(app, {
|
|
218
|
+
onError: (error, ctx) => {
|
|
219
|
+
console.error({ error: error.message, path: ctx.path });
|
|
220
|
+
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
|
|
221
|
+
status: 500,
|
|
222
|
+
headers: { 'Content-Type': 'application/json' },
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## API overview
|
|
229
|
+
|
|
230
|
+
| Export | Signature | Since | Stability | Description |
|
|
231
|
+
| ------ | --------- | ----- | --------- | ------------ |
|
|
232
|
+
| `createFetchHandler` | `(app: Application, options?: FetchHandlerOptions) => FetchHandler` | `1.0.0` | Internal | Generic Fetch-API handler; the runner every other export delegates to |
|
|
233
|
+
| `createCloudflareHandler` | `<Env>(app: Application, options?: FetchHandlerOptions) => { fetch: CloudflareFetchHandler<Env> }` | `1.0.0` | Internal | Cloudflare Workers module export -- `(request, env, ctx)` signature; threads `env` onto `ctx.env` |
|
|
234
|
+
| `createVercelHandler` | `(app: Application, options?: FetchHandlerOptions) => FetchHandler` | `1.0.0` | Internal | Vercel Edge Function handler (delegates to `createFetchHandler`) |
|
|
235
|
+
| `createNetlifyHandler` | `(app: Application, options?: FetchHandlerOptions) => FetchHandler` | `1.0.0` | Internal | Netlify Edge Function handler (delegates to `createFetchHandler`) |
|
|
236
|
+
| `createHandler` | same as `createFetchHandler` | `1.0.0` | Internal | Alias of `createFetchHandler`, kept for naming consistency with other adapters |
|
|
237
|
+
| `DEFAULT_EDGE_TIMEOUT_MS` | `25_000` | `1.0.0` | Internal | Default request timeout in ms when `options.timeout` is omitted |
|
|
238
|
+
| `detectEdgeRuntime` | `() => EdgeRuntimeInfo` | `1.0.0` | Internal | Detects which edge platform is running -- see Runtime detection below |
|
|
239
|
+
| `EdgeContext` | class | `1.0.0` | Internal | `Context` implementation for edge runtimes |
|
|
240
|
+
| `createEdgeContext` | `<Env>(request, executionContext?, trustProxy?, env?) => EdgeContext<Env>` | `1.0.0` | Internal | Constructs an `EdgeContext` directly |
|
|
241
|
+
| `type FetchHandler` | `(request: Request, ctx?: EdgeExecutionContext) => Response \| Promise<Response>` | `1.0.0` | Internal | The handler signature every `createXxxHandler` returns |
|
|
242
|
+
| `type EdgeExecutionContext` | `{ waitUntil, passThroughOnException? }` | `1.0.0` | Internal | Platform execution-context shape consumed by `ctx.waitUntil` |
|
|
243
|
+
| `type EdgeRuntimeInfo` | `{ runtime, isCloudflare, isVercel, isNetlify, isGenericEdge }` | `1.0.0` | Internal | Result shape of `detectEdgeRuntime()` |
|
|
244
|
+
| `HttpError` | re-exported from `@nextrush/errors` | `1.0.0` | Internal | Uniform error class across all adapters |
|
|
245
|
+
|
|
246
|
+
## Options
|
|
247
|
+
|
|
248
|
+
`FetchHandlerOptions`, accepted by every `createXxxHandler`:
|
|
249
|
+
|
|
250
|
+
| Option | Type | Required | Default | Security-sensitive | Description |
|
|
251
|
+
| ------ | ---- | -------- | ------- | ------------------- | ------------ |
|
|
252
|
+
| `onError` | `(error: Error, ctx: EdgeContext) => Response \| Promise<Response>` | No | built-in JSON 500 | -- | Custom error handler; receives the thrown error and the in-flight context |
|
|
253
|
+
| `timeout` | `number` | No | `25000` (`DEFAULT_EDGE_TIMEOUT_MS`) | -- | Request timeout in ms; races the handler and returns `504` on expiry, aborting `ctx.signal`. `0` disables the framework timeout (the platform's own limit still applies) |
|
|
254
|
+
|
|
255
|
+
## Runtime detection
|
|
256
|
+
|
|
257
|
+
`detectEdgeRuntime()` (re-exported from `@nextrush/runtime`) answers "which edge platform am I
|
|
258
|
+
on", distinct from the generic `detectRuntime()`. Verified against
|
|
259
|
+
`packages/runtime/src/detection.ts`, it checks exactly three platforms in order and has no
|
|
260
|
+
AWS/Lambda branch:
|
|
261
|
+
|
|
262
|
+
1. **Cloudflare Workers** -- `navigator.userAgent` contains `'Cloudflare-Workers'` -> `runtime:
|
|
263
|
+
'cloudflare-workers'`, `isCloudflare: true`.
|
|
264
|
+
2. **Vercel Edge** -- `process.env.VERCEL_REGION` is defined -> `runtime: 'vercel-edge'`,
|
|
265
|
+
`isVercel: true`.
|
|
266
|
+
3. **Netlify Edge** -- a `Deno` global exists AND `process.env.NETLIFY === 'true'` (Netlify Edge
|
|
267
|
+
Functions run on Deno under the hood) -> `runtime: 'edge'` (not a distinct string),
|
|
268
|
+
`isNetlify: true`.
|
|
269
|
+
|
|
270
|
+
If none of the three match, `runtime` stays at its initial value of `'edge'` and
|
|
271
|
+
`isGenericEdge` is `true`. There is no fourth branch for AWS Lambda or any other FaaS platform
|
|
272
|
+
-- `@nextrush/adapter-serverless` builds its own handler on top of this package's fetch runner
|
|
273
|
+
and inherits this same detection, so `ctx.runtime` reports `'edge'` there too (see
|
|
274
|
+
[`@nextrush/adapter-serverless`](../serverless)'s own docs for that package's scope).
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import { detectEdgeRuntime } from '@nextrush/adapter-edge';
|
|
278
|
+
|
|
279
|
+
const info = detectEdgeRuntime();
|
|
280
|
+
// Cloudflare Workers: { runtime: 'cloudflare-workers', isCloudflare: true, isVercel: false, isNetlify: false, isGenericEdge: false }
|
|
281
|
+
// Vercel Edge: { runtime: 'vercel-edge', isCloudflare: false, isVercel: true, isNetlify: false, isGenericEdge: false }
|
|
282
|
+
// Netlify Edge: { runtime: 'edge', isCloudflare: false, isVercel: false, isNetlify: true, isGenericEdge: false }
|
|
283
|
+
// Anything else: { runtime: 'edge', isCloudflare: false, isVercel: false, isNetlify: false, isGenericEdge: true }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Result is cached after the first call within a given isolate.
|
|
287
|
+
|
|
288
|
+
## Compatibility
|
|
289
|
+
|
|
290
|
+
**Requirements**
|
|
291
|
+
|
|
292
|
+
| Requirement | Version |
|
|
293
|
+
| ----------- | ------- |
|
|
294
|
+
| NextRush | `1.x` (`@nextrush/core`) |
|
|
295
|
+
| Node.js (local build/test only) | `>=22` |
|
|
296
|
+
| TypeScript | `>=5.x` |
|
|
297
|
+
|
|
298
|
+
**Runtimes**
|
|
299
|
+
|
|
300
|
+
| Runtime | Supported | Notes |
|
|
301
|
+
| ------- | --------- | ------ |
|
|
302
|
+
| Cloudflare Workers | Yes | via `createCloudflareHandler` |
|
|
303
|
+
| Vercel Edge Functions | Yes | via `createVercelHandler` |
|
|
304
|
+
| Netlify Edge Functions | Yes | via `createNetlifyHandler` (runs on Deno under the hood) |
|
|
305
|
+
| Node.js | No | use [`@nextrush/adapter-node`](../node) |
|
|
306
|
+
|
|
307
|
+
**Integration**
|
|
308
|
+
- **Peer dependencies:** none -- direct workspace dependencies on `@nextrush/{core,errors,runtime,stream,types}`.
|
|
309
|
+
- **Works with:** any NextRush middleware that only touches the `Context` API (no raw Node
|
|
310
|
+
`req`/`res` access).
|
|
311
|
+
- **Built on by:** [`@nextrush/adapter-serverless`](../serverless), which wraps this package's
|
|
312
|
+
fetch handler for FaaS platforms (AWS Lambda, Google Cloud Functions).
|
|
313
|
+
|
|
314
|
+
> [!IMPORTANT]
|
|
315
|
+
> NextRush is ESM-only, permanently -- no CommonJS build. See the
|
|
316
|
+
> [Module Format Policy](https://github.com/0xTanzim/nextRush#module-format-policy).
|
|
317
|
+
|
|
318
|
+
## Limitations
|
|
319
|
+
|
|
320
|
+
Edge runtimes share constraints this package does not paper over:
|
|
321
|
+
|
|
322
|
+
- No file system access -- use platform storage (R2, KV) or an external store.
|
|
323
|
+
- No native Node.js modules or native addons -- Web API equivalents only.
|
|
324
|
+
- CPU time and memory limits vary by platform -- consult the platform's own documentation.
|
|
325
|
+
- Large payloads should be streamed rather than buffered in memory.
|
|
326
|
+
|
|
327
|
+
## FAQ
|
|
328
|
+
|
|
329
|
+
**Does `ctx.runtime` tell me I am on AWS Lambda?**
|
|
330
|
+
No. `detectEdgeRuntime()` has no Lambda branch; it only distinguishes Cloudflare, Vercel, and
|
|
331
|
+
Netlify, defaulting to the generic `'edge'` otherwise. `@nextrush/adapter-serverless` is built
|
|
332
|
+
on this package and inherits the same detection, so Lambda deployments also report
|
|
333
|
+
`runtime: 'edge'` -- verified in `packages/runtime/src/detection.ts`.
|
|
334
|
+
|
|
335
|
+
**Why is this package tier "Internal" instead of "Public"?**
|
|
336
|
+
Per [ADR-0005](https://github.com/0xTanzim/nextRush/blob/main/docs/adr/ADR-0005-package-tiers-sealed-surface-deprecation.md),
|
|
337
|
+
non-`-node` adapters (bun, deno, edge, serverless) stay Internal until each is declared GA;
|
|
338
|
+
`@nextrush/adapter-node` is the only adapter in the Public-core tier today.
|
|
339
|
+
|
|
340
|
+
**Does it work without `@nextrush/router`?**
|
|
341
|
+
Yes -- `app.use()` alone is enough for simple handlers. Add
|
|
342
|
+
[`@nextrush/router`](../../router) only when you need dynamic route matching.
|
|
343
|
+
|
|
344
|
+
**Can I use it outside Cloudflare/Vercel/Netlify?**
|
|
345
|
+
Yes -- `createFetchHandler` (and its alias `createHandler`) is a plain `(request, ctx?) =>
|
|
346
|
+
Response` function usable on any host that speaks the Fetch API, not only the three named
|
|
347
|
+
platforms.
|
|
348
|
+
|
|
349
|
+
## Package relationships
|
|
350
|
+
|
|
351
|
+
```text
|
|
352
|
+
depends on @nextrush/{core,errors,runtime,stream,types}
|
|
353
|
+
@nextrush/adapter-edge -------------->
|
|
354
|
+
often used with @nextrush/router
|
|
355
|
+
usually used next @nextrush/adapter-serverless (for FaaS platforms)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
- **Depends on:** [`@nextrush/core`](../../core), [`@nextrush/errors`](../../errors),
|
|
359
|
+
[`@nextrush/runtime`](../../runtime), [`@nextrush/stream`](../../stream),
|
|
360
|
+
[`@nextrush/types`](../../types).
|
|
361
|
+
- **Often used with:** [`@nextrush/router`](../../router) -- for dynamic route matching beyond
|
|
362
|
+
a single `app.use()` handler.
|
|
363
|
+
- **Usually used next:** [`@nextrush/adapter-serverless`](../serverless) -- if the deploy target
|
|
364
|
+
turns out to be AWS Lambda or Google Cloud Functions rather than an edge platform.
|
|
365
|
+
- **Alternative:** [`@nextrush/adapter-node`](../node) -- for a long-running Node.js process
|
|
366
|
+
instead of an edge isolate; [`@nextrush/adapter-bun`](../bun) / [`@nextrush/adapter-deno`](../deno)
|
|
367
|
+
-- for running directly on Bun/Deno outside an edge platform.
|
|
368
|
+
|
|
369
|
+
## Architecture
|
|
370
|
+
|
|
371
|
+
Maintaining or contributing to this package? The internal design -- the shared request runner,
|
|
372
|
+
context construction, and the compile-time adapter-contract guards -- is in
|
|
373
|
+
[`ARCHITECTURE.md`](./ARCHITECTURE.md). Design history:
|
|
374
|
+
[RFC-013 (adapter contract)](https://github.com/0xTanzim/nextRush/blob/main/docs/RFC/runtime-adapters/013-adapter-contract.md),
|
|
375
|
+
[ADR-0010 (cross-runtime parity hardening)](https://github.com/0xTanzim/nextRush/blob/main/docs/adr/ADR-0010-cross-runtime-parity-hardening.md).
|
|
376
|
+
|
|
377
|
+
## Resources
|
|
378
|
+
|
|
379
|
+
- Learn -- [Documentation](https://0xtanzim.github.io/nextRush/docs) -- [Architecture](./ARCHITECTURE.md) -- [RFCs](https://github.com/0xTanzim/nextRush/tree/main/docs/RFC)
|
|
380
|
+
- Changelog -- [CHANGELOG.md](./CHANGELOG.md)
|
|
381
|
+
- Report an issue -- [GitHub Issues](https://github.com/0xTanzim/nextRush/issues)
|
|
382
|
+
- Contribute -- [CONTRIBUTING.md](https://github.com/0xTanzim/nextRush/blob/main/CONTRIBUTING.md)
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
MIT (c) [Tanzim Hossain](https://github.com/0xTanzim)
|