nextrush 3.0.5 → 4.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/README.md +389 -122
- package/bin/nextrush.js +19 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/class.d.ts +105 -3
- package/dist/class.js +79 -28
- package/dist/class.js.map +1 -1
- package/dist/dev-cli-launcher.d.ts +63 -0
- package/dist/dev-cli-launcher.js +112 -0
- package/dist/dev-cli-launcher.js.map +1 -0
- package/dist/index.d.ts +31 -11
- package/dist/index.js +27 -11
- package/dist/index.js.map +1 -1
- package/package.json +33 -19
package/README.md
CHANGED
|
@@ -1,44 +1,111 @@
|
|
|
1
|
-
#
|
|
1
|
+
# nextrush
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> The meta package - install this one to build a NextRush app: `createApp`, `createRouter`, `listen`, HTTP errors, and the shared types, plus an opt-in `nextrush/class` subpath for decorators and DI.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/nextrush)
|
|
6
|
-
[](https://www.npmjs.com/package/nextrush)
|
|
7
|
+
[](https://bundlephobia.com/package/nextrush)
|
|
8
|
+
[](https://www.npmjs.com/package/nextrush)
|
|
9
|
+
[](https://nodejs.org/api/esm.html)
|
|
10
|
+
[](https://github.com/0xTanzim/nextRush/blob/main/LICENSE)
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
| | |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| **Purpose** | The single entry point for building a NextRush app - re-exports `createApp`, `createRouter`, `listen`, HTTP errors, and the shared types; `nextrush/class` adds decorators and DI as an explicit, separate install |
|
|
15
|
+
| **Package type** | Core (meta package) |
|
|
16
|
+
| **Status** | Stable [x] |
|
|
17
|
+
| **Included in `nextrush`?** | This *is* `nextrush` - the package everything else in the ecosystem re-exports through |
|
|
18
|
+
| **Support tier** | Public - core (stable, semver-guarded) - see [ADR-0005](https://github.com/0xTanzim/nextRush/blob/main/docs/adr/ADR-0005-package-tiers-sealed-surface-deprecation.md) |
|
|
19
|
+
| **Maintenance** | Active |
|
|
20
|
+
| **Runtime** | Node.js (via `@nextrush/adapter-node`) - other runtimes via their own adapter, imported directly |
|
|
21
|
+
| **Requires** | Node `>=22`, ESM-only, TypeScript `>=5.x` |
|
|
22
|
+
| **Introduced** | `v3.0.0` |
|
|
11
23
|
|
|
12
|
-
|
|
13
|
-
- **Minimal** — Core under 3,000 lines of code
|
|
14
|
-
- **Modular** — Install only what you need
|
|
15
|
-
- **Type-Safe** — Full TypeScript with zero `any`
|
|
16
|
-
- **Zero Dependencies** — No external runtime dependencies in core
|
|
24
|
+
## Highlights
|
|
17
25
|
|
|
18
|
-
|
|
26
|
+
- [x] **Zero runtime dependencies on the functional path** - `createApp`/`createRouter`/`listen` pull in no third-party package
|
|
27
|
+
- [x] **`@nextrush/class`, `@nextrush/di`, and `reflect-metadata` are optional peers** - a plain `pnpm add nextrush` never resolves them onto disk
|
|
28
|
+
- [x] **ESM-only**, tree-shakable; only the `nextrush/class` subpath carries a side effect (`reflect-metadata`'s global patch)
|
|
29
|
+
- **Bundle:** the functional entry re-exports five workspace packages with no added weight of its own
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
<details>
|
|
32
|
+
<summary><strong>Table of contents</strong></summary>
|
|
21
33
|
|
|
22
|
-
-
|
|
23
|
-
- `createRouter`, `Router` — Create and manage routers
|
|
24
|
-
- `listen`, `serve`, `createHandler` — Start HTTP server (Node.js)
|
|
25
|
-
- `compose` — Compose middleware
|
|
26
|
-
- Error classes (`HttpError`, `NotFoundError`, `BadRequestError`, `MethodNotAllowedError`, etc.)
|
|
27
|
-
- Error utilities (`createError`, `isHttpError`, `errorHandler`, `notFoundHandler`, `catchAsync`)
|
|
28
|
-
- TypeScript types (`Context`, `Middleware`, `Next`, `Plugin`, `RouteHandler`, `HttpMethod`, etc.)
|
|
29
|
-
- Constants (`VERSION`, `HttpStatus`, `ContentType`)
|
|
34
|
+
[The problem](#the-problem) | [When to use](#when-to-use) | [Installation](#installation) | [Quick start](#quick-start) | [Capabilities](#capabilities) | [Mental model](#mental-model) | [Common tasks](#common-tasks) | [API overview](#api-overview) | [Options](#options) | [Compatibility](#compatibility) | [Troubleshooting](#troubleshooting) | [FAQ](#faq) | [Package relationships](#package-relationships) | [Architecture](#architecture) | [Resources](#resources)
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
</details>
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## The problem
|
|
41
|
+
|
|
42
|
+
NextRush is deliberately split into ~35 independent packages - a router, a core engine, an adapter per runtime, a class/DI runtime, and dozens of middleware/extension packages - so that each piece can version, test, and ship on its own. That is good for the packages and bad for a first-time user: nobody wants to work out that `createApp` lives in `@nextrush/core` but needs a router from `@nextrush/router` wired in by hand, and an HTTP server from `@nextrush/adapter-node` on top, before a single request can be served.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// TODAY, without the meta package - wiring the pieces by hand:
|
|
46
|
+
import { createApp } from '@nextrush/core';
|
|
47
|
+
import { createRouter } from '@nextrush/router';
|
|
48
|
+
import { listen } from '@nextrush/adapter-node';
|
|
49
|
+
|
|
50
|
+
const app = createApp({ router: createRouter() }); // router is NOT wired in for you here
|
|
51
|
+
listen(app, 8080);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`nextrush` is that wiring, done once, correctly: its own `createApp` injects a router so `app.get(...)` works immediately, and its barrel re-exports exactly the symbols a functional app needs - nothing from the class/DI stack, so a functional-only install stays as small as the "zero-dependency core" claim promises.
|
|
55
|
+
|
|
56
|
+
## When to use
|
|
57
|
+
|
|
58
|
+
**Use `nextrush` if:**
|
|
59
|
+
|
|
60
|
+
- You're building a NextRush application - this is the entry point every quick-start example uses
|
|
61
|
+
- You want `createApp` to come with a router already attached, so route shortcuts (`app.get`, `app.post`, ...) work without extra setup
|
|
62
|
+
- You want the class-based API (`@Controller`, `@Service`, DI) available behind one additional, explicit install (`nextrush/class`), never bundled into the functional path
|
|
63
|
+
|
|
64
|
+
**Reach for something else if:**
|
|
65
|
+
|
|
66
|
+
- You're building your own meta-package, adapter, or runtime on top of NextRush and need the raw, router-agnostic `Application` - use [`@nextrush/core`](../core) directly
|
|
67
|
+
- You need only route matching, with no application/lifecycle layer - use [`@nextrush/router`](../router) directly
|
|
68
|
+
- You're targeting Bun, Deno, or an edge runtime - `nextrush`'s `listen`/`serve` come from `@nextrush/adapter-node`; import the matching `@nextrush/adapter-{bun,deno,edge}` directly for other runtimes
|
|
69
|
+
|
|
70
|
+
---
|
|
32
71
|
|
|
33
72
|
## Installation
|
|
34
73
|
|
|
35
74
|
```bash
|
|
36
75
|
pnpm add nextrush
|
|
76
|
+
# npm i nextrush | yarn add nextrush | bun add nextrush
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This resolves only the functional core and its five workspace dependencies (`@nextrush/core`,
|
|
80
|
+
`@nextrush/router`, `@nextrush/adapter-node`, `@nextrush/errors`, `@nextrush/types`) - no class
|
|
81
|
+
runtime, no DI container, no `reflect-metadata`. See [Compatibility](#compatibility) for the
|
|
82
|
+
exact dependency footprint by usage path.
|
|
83
|
+
|
|
84
|
+
> [!NOTE]
|
|
85
|
+
> Scaffolding a new project? `pnpm create nextrush my-api` sets up `nextrush` (and, for
|
|
86
|
+
> class-based/full templates, `@nextrush/class`) for you - see
|
|
87
|
+
> [Scaffold a project](#scaffold-a-project) below.
|
|
88
|
+
|
|
89
|
+
### Two intentional install steps: Runtime and Development Toolkit
|
|
90
|
+
|
|
91
|
+
`nextrush` is the **runtime** - everything you need to *serve* requests. The dev server, production
|
|
92
|
+
builds, and code generators live in a separate **development toolkit**, `@nextrush/dev`, installed
|
|
93
|
+
as a dev dependency. This split is deliberate (nothing dev-only ships to production), not a missing
|
|
94
|
+
bundle:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pnpm add nextrush # 1. Runtime - build and serve your app
|
|
98
|
+
pnpm add -D @nextrush/dev # 2. Development Toolkit - `nextrush dev` / `build` / `generate`
|
|
37
99
|
```
|
|
38
100
|
|
|
39
|
-
|
|
101
|
+
The `nextrush` command is provided by the runtime itself, so it always resolves. If you run
|
|
102
|
+
`nextrush dev` before installing the toolkit, it doesn't fail with a raw "command not found" - it
|
|
103
|
+
prints the exact install command for your package manager and a one-line description of what the
|
|
104
|
+
toolkit provides. `pnpm create nextrush` adds both steps for you.
|
|
105
|
+
|
|
106
|
+
## Quick start
|
|
40
107
|
|
|
41
|
-
```
|
|
108
|
+
```ts
|
|
42
109
|
import { createApp, createRouter, listen } from 'nextrush';
|
|
43
110
|
|
|
44
111
|
const app = createApp();
|
|
@@ -50,33 +117,86 @@ router.get('/', (ctx) => {
|
|
|
50
117
|
|
|
51
118
|
app.route('/', router);
|
|
52
119
|
|
|
53
|
-
listen(app,
|
|
120
|
+
listen(app, 8080);
|
|
54
121
|
```
|
|
55
122
|
|
|
56
|
-
|
|
123
|
+
`createApp()` here wraps `@nextrush/core`'s `createApp` and injects a default router, so
|
|
124
|
+
`app.get(...)` also works without the explicit `createRouter()` step above - the two forms are
|
|
125
|
+
equivalent; this one shows the router as its own object because most real apps mount several
|
|
126
|
+
feature routers with `app.route(prefix, router)`.
|
|
127
|
+
|
|
128
|
+
## Capabilities
|
|
129
|
+
|
|
130
|
+
**Application & routing**
|
|
131
|
+
- **`createApp` / `Application`** - an `@nextrush/core` application with a router pre-wired
|
|
132
|
+
- **`createRouter` / `Router` / `endpoint`** - the segment-trie router and its route-metadata marker
|
|
133
|
+
- **`compose`** - the Koa-style middleware composer, re-exported standalone
|
|
134
|
+
|
|
135
|
+
**Server**
|
|
136
|
+
- **`listen` / `serve` / `createHandler`** - start an HTTP server on Node.js via `@nextrush/adapter-node`
|
|
137
|
+
|
|
138
|
+
**Errors**
|
|
139
|
+
- **The full `HttpError` hierarchy** - `BadRequestError`, `NotFoundError`, `UnauthorizedError`, and every other 4xx/5xx class
|
|
140
|
+
- **`createError` / `isHttpError` / `errorHandler` / `notFoundHandler`** - error factories and middleware
|
|
141
|
+
- **`ERROR_CODES` / `codeForStatus` / `ValidationError`** - the central error-code registry
|
|
142
|
+
|
|
143
|
+
**Types & constants**
|
|
144
|
+
- **`Context`, `Middleware`, `Next`, `Extension`, `ExtensionContext`, `RouteHandler`, `RouteDefinition`, `RouteMetadata`, `HttpMethod`** - the shared contracts every NextRush package builds on
|
|
145
|
+
- **`HttpStatus`, `ContentType`** - HTTP constants
|
|
146
|
+
|
|
147
|
+
**Class-based (opt-in, via `nextrush/class`)**
|
|
148
|
+
- **Decorators, DI, controllers, modules, guards, interceptors, filters** - see [Class-based controllers](#class-based-controllers)
|
|
149
|
+
|
|
150
|
+
**Developer experience**
|
|
151
|
+
- **Fully typed, zero `any`** - every re-export carries its source package's exact types
|
|
152
|
+
- **Actionable failure on a missing peer** - importing `nextrush/class` without its peers installed throws a message naming the exact install command, not an opaque resolution error
|
|
153
|
+
|
|
154
|
+
## Mental model
|
|
155
|
+
|
|
156
|
+
`nextrush` is a **barrel with one behavioral addition**: its root entry re-exports the functional stack as-is, except `createApp`, which wraps `@nextrush/core`'s version to inject a default router. The `nextrush/class` subpath is a second, independent barrel that dynamically loads the optional class/DI peers and re-exports their runtime values by assignment - so a resolution failure there produces an actionable error instead of crashing at import time.
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
'nextrush' ---> re-exports @nextrush/{core,router,adapter-node,errors,types}
|
|
160
|
+
(createApp wraps @nextrush/core's, injecting a default router)
|
|
161
|
+
|
|
162
|
+
'nextrush/class' ---> dynamically imports reflect-metadata + @nextrush/di + @nextrush/class
|
|
163
|
+
(only if you import this subpath - never loaded by the root entry)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Rule:** importing `nextrush` never touches the class/DI stack. Importing `nextrush/class` is
|
|
167
|
+
the one and only place that stack gets loaded - and only if you've installed its peers.
|
|
168
|
+
|
|
169
|
+
> [!TIP]
|
|
170
|
+
> The exports-map routing between the two entries, and the dynamic-import/re-export-by-assignment
|
|
171
|
+
> mechanism behind `nextrush/class`, are diagrammed in [`ARCHITECTURE.md`](./ARCHITECTURE.md).
|
|
57
172
|
|
|
58
|
-
|
|
59
|
-
See https://github.com/0xTanzim/nextRush/blob/main/apps/docs/content/docs/performance/index.mdx for methodology, versions, and reproducible scripts.
|
|
173
|
+
---
|
|
60
174
|
|
|
61
|
-
|
|
62
|
-
| --------------- | -------------- | -------------- | -------------- |
|
|
63
|
-
| Fastify | 48,045 RPS | 21,412 RPS | 48,493 RPS |
|
|
64
|
-
| **NextRush v3** | **43,268 RPS** | **20,438 RPS** | **43,283 RPS** |
|
|
65
|
-
| Hono | 37,476 RPS | 12,625 RPS | 38,759 RPS |
|
|
66
|
-
| Koa | 34,683 RPS | 17,664 RPS | 35,566 RPS |
|
|
67
|
-
| Express | 23,739 RPS | 14,417 RPS | 23,783 RPS |
|
|
175
|
+
## Common tasks
|
|
68
176
|
|
|
69
|
-
|
|
177
|
+
### Build a functional app
|
|
70
178
|
|
|
71
|
-
|
|
179
|
+
```ts
|
|
180
|
+
import { createApp, createRouter, listen } from 'nextrush';
|
|
181
|
+
|
|
182
|
+
const app = createApp();
|
|
183
|
+
const users = createRouter();
|
|
184
|
+
|
|
185
|
+
users.get('/', (ctx) => ctx.json([]));
|
|
186
|
+
users.get('/:id', (ctx) => ctx.json({ id: ctx.params.id }));
|
|
187
|
+
|
|
188
|
+
app.route('/users', users); // Hono-style composition - mount a feature router at a prefix
|
|
72
189
|
|
|
73
|
-
|
|
190
|
+
listen(app, 8080);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Add middleware
|
|
74
194
|
|
|
75
195
|
```bash
|
|
76
196
|
pnpm add @nextrush/cors @nextrush/body-parser
|
|
77
197
|
```
|
|
78
198
|
|
|
79
|
-
```
|
|
199
|
+
```ts
|
|
80
200
|
import { createApp, listen } from 'nextrush';
|
|
81
201
|
import { cors } from '@nextrush/cors';
|
|
82
202
|
import { json } from '@nextrush/body-parser';
|
|
@@ -86,29 +206,57 @@ const app = createApp();
|
|
|
86
206
|
app.use(cors());
|
|
87
207
|
app.use(json());
|
|
88
208
|
|
|
89
|
-
app.
|
|
90
|
-
|
|
209
|
+
app.post('/api/users', (ctx) => {
|
|
210
|
+
const { name, email } = ctx.body as { name: string; email: string };
|
|
211
|
+
ctx.status = 201;
|
|
212
|
+
ctx.json({ id: Date.now(), name, email });
|
|
91
213
|
});
|
|
92
214
|
|
|
93
|
-
listen(app,
|
|
215
|
+
listen(app, 8080);
|
|
94
216
|
```
|
|
95
217
|
|
|
96
|
-
|
|
218
|
+
### Handle errors
|
|
97
219
|
|
|
98
|
-
|
|
220
|
+
```ts
|
|
221
|
+
import { NotFoundError, BadRequestError } from 'nextrush';
|
|
99
222
|
|
|
100
|
-
|
|
101
|
-
|
|
223
|
+
app.get('/users/:id', async (ctx) => {
|
|
224
|
+
const user = await db.findUser(ctx.params.id);
|
|
225
|
+
if (!user) throw new NotFoundError('User not found');
|
|
226
|
+
ctx.json(user);
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Any `HttpError` subclass thrown from a handler is caught by `@nextrush/core`'s default error
|
|
231
|
+
path and serialized through the same contract as `errorHandler()` - no manual `try`/`catch`
|
|
232
|
+
needed around individual routes.
|
|
102
233
|
|
|
103
|
-
|
|
234
|
+
### Scaffold a project
|
|
104
235
|
|
|
105
236
|
```bash
|
|
106
|
-
pnpm
|
|
237
|
+
pnpm create nextrush my-api
|
|
238
|
+
cd my-api && pnpm dev
|
|
107
239
|
```
|
|
108
240
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
241
|
+
The `create nextrush` form (with a space) installs the `create-nextrush` package - you can also
|
|
242
|
+
use `npx create-nextrush@latest` or `pnpm dlx create-nextrush@latest`. The interactive
|
|
243
|
+
scaffolder lets you choose functional, class-based, or full style, a middleware preset, and a
|
|
244
|
+
runtime target; class-based and full templates add `@nextrush/class` to your `package.json`
|
|
245
|
+
automatically. See the
|
|
246
|
+
[create-nextrush docs](https://github.com/0xTanzim/nextRush/tree/main/packages/create-nextrush#usage).
|
|
247
|
+
|
|
248
|
+
## Class-Based Controllers
|
|
249
|
+
|
|
250
|
+
Class-based APIs (decorators, DI, controllers) live behind the `nextrush/class` subpath, an
|
|
251
|
+
explicit, optional install:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
pnpm add nextrush @nextrush/class
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { createApp, listen } from 'nextrush';
|
|
259
|
+
import { Controller, Get, Service, registerControllers } from 'nextrush/class';
|
|
112
260
|
|
|
113
261
|
@Service()
|
|
114
262
|
class GreetService {
|
|
@@ -128,108 +276,227 @@ class HelloController {
|
|
|
128
276
|
}
|
|
129
277
|
|
|
130
278
|
const app = createApp();
|
|
131
|
-
|
|
279
|
+
await registerControllers(app, { root: './src' });
|
|
280
|
+
await listen(app, 8080);
|
|
281
|
+
```
|
|
132
282
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
283
|
+
The `nextrush/class` entry auto-imports `reflect-metadata`, so decorators and DI work with no
|
|
284
|
+
extra setup once `@nextrush/class` is installed. `registerControllers` is a **registrar**, not a
|
|
285
|
+
plugin - call and `await` it directly; it reads `app.router` and `app.container` (both injected
|
|
286
|
+
by `nextrush`'s `createApp()`) and must resolve before `listen()`/`serve()` starts the server.
|
|
287
|
+
|
|
288
|
+
> [!IMPORTANT]
|
|
289
|
+
> `experimentalDecorators` and `emitDecoratorMetadata` must be enabled in `tsconfig.json` when
|
|
290
|
+
> using `nextrush/class`. `create-nextrush` turns them **on** for class-based and full templates
|
|
291
|
+
> and **omits** them for functional (routes-only) projects, where they are unnecessary.
|
|
292
|
+
|
|
293
|
+
## API overview
|
|
294
|
+
|
|
295
|
+
The sealed public surface (ADR-0005), by entry point.
|
|
296
|
+
|
|
297
|
+
### `nextrush` (root entry)
|
|
298
|
+
|
|
299
|
+
| Export | From | Since | Stability | Description |
|
|
300
|
+
| ------ | ---- | ----- | --------- | ----------- |
|
|
301
|
+
| `createApp` | wraps `@nextrush/core` | `3.0.0` | Stable [x] | Creates an `Application` with a default router pre-wired. |
|
|
302
|
+
| `Application`, `compose` | `@nextrush/core` | `3.0.0` | Stable [x] | The application class and the middleware composer. |
|
|
303
|
+
| `Router`, `createRouter`, `endpoint` | `@nextrush/router` | `3.0.0` | Stable [x] | Segment-trie router and its route-metadata marker. |
|
|
304
|
+
| `createHandler`, `listen`, `serve` | `@nextrush/adapter-node` | `3.0.0` | Stable [x] | Start an HTTP server on Node.js. |
|
|
305
|
+
| `HttpError`, `NextRushError`, and every 4xx/5xx class | `@nextrush/errors` | `3.0.0` | Stable [x] | `BadRequestError`, `NotFoundError`, `UnauthorizedError`, `ForbiddenError`, `ConflictError`, `MethodNotAllowedError`, `UnprocessableEntityError`, `TooManyRequestsError`, `InternalServerError`, `NotImplementedError`, `BadGatewayError`, `ServiceUnavailableError`, `GatewayTimeoutError`. |
|
|
306
|
+
| `createError`, `isHttpError`, `errorHandler`, `notFoundHandler` | `@nextrush/errors` | `3.0.0` | Stable [x] | Error factory and middleware. |
|
|
307
|
+
| `ERROR_CODES`, `codeForStatus`, `ValidationError` | `@nextrush/errors` | `3.1.0` | Stable [x] | The central error-code registry and validation error type. |
|
|
308
|
+
| `ContentType`, `HttpStatus` | `@nextrush/types` | `3.0.0` | Stable [x] | HTTP constants. |
|
|
309
|
+
| `type ApplicationOptions`, `ComposedMiddleware` | `@nextrush/core` | `3.0.0` | Stable [x] | Application-level contracts. |
|
|
310
|
+
| `type RouterOptions` | `@nextrush/router` | `3.0.0` | Stable [x] | Router configuration. |
|
|
311
|
+
| `type ServeOptions`, `ServerInstance` | `@nextrush/adapter-node` | `3.0.0` | Stable [x] | Server-start contracts. |
|
|
312
|
+
| `type ErrorHandlerOptions`, `HttpErrorOptions`, `ValidationIssue` | `@nextrush/errors` | `3.0.0` | Stable [x] | Error-handling contracts. |
|
|
313
|
+
| `type Context`, `Extension`, `ExtensionContext`, `HttpMethod`, `HttpStatusCode`, `Middleware`, `Next`, `RouteHandler`, `RouteDefinition`, `RouteMetadata`, `Runtime` | `@nextrush/types` | `3.0.0` | Stable [x] | The shared contracts every NextRush package builds on. |
|
|
314
|
+
|
|
315
|
+
This runtime surface is locked by `src/__tests__/public-surface.test.ts`; if this table ever
|
|
316
|
+
claims an export that test doesn't list, that's a documentation bug - please file an issue.
|
|
317
|
+
|
|
318
|
+
### `nextrush/class` (opt-in subpath)
|
|
319
|
+
|
|
320
|
+
| Export | From | Since | Stability | Description |
|
|
321
|
+
| ------ | ---- | ----- | --------- | ----------- |
|
|
322
|
+
| `Controller`, `Get`, `Post`, `Put`, `Patch`, `Delete`, `Head`, `Options`, `All` | `@nextrush/class` | `3.0.0` | Stable [x] | Class and route decorators. |
|
|
323
|
+
| `Body`, `Param`, `Query`, `Header`, `Ctx`, `Req`, `Res`, `createCustomParamDecorator` | `@nextrush/class` | `3.0.0` | Stable [x] | Parameter-binding decorators. |
|
|
324
|
+
| `HttpCode`, `Redirect`, `SetHeader` | `@nextrush/class` | `3.0.0` | Stable [x] | Response decorators. |
|
|
325
|
+
| `UseGuard`, `UseInterceptor`, `Catch`, `UseFilter` | `@nextrush/class` | `3.0.0` | Stable [x] | Guards, interceptors, exception filters. |
|
|
326
|
+
| `isOnInit`, `isOnShutdown` | `@nextrush/class` | `3.0.0` | Stable [x] | Lifecycle-hook type guards. |
|
|
327
|
+
| `Module`, `getModuleMetadata`, `isModule`, `registerModule` | `@nextrush/class` | `3.1.0` | Stable [x] | Module composition and registration. |
|
|
328
|
+
| `registerControllers` | `@nextrush/class` | `3.0.0` | Stable [x] | Registrar - discovers and wires controllers into an app. |
|
|
329
|
+
| `Config`, `container`, `createContainer`, `delay`, `inject`, `Injectable`, `Optional`, `Repository`, `Service` | `@nextrush/di` | `3.0.0` | Stable [x] | The DI container surface. |
|
|
330
|
+
| `type ClassProvider`, `ConfigOptions`, `Container`, `FactoryProvider`, `Provider`, `Scope`, `ServiceOptions`, `Token`, `ValueProvider` | `@nextrush/di` | `3.0.0` | Stable [x] | DI contracts. |
|
|
331
|
+
| `type BodyOptions`, `CanActivate`, `ControllerMetadata`, `ControllerOptions`, `ControllerRouteMetadata`, `CustomParamExtractor`, `ExceptionFilter`, `GuardContext`, `GuardFn`, `HeaderOptions`, `Interceptor`, `ModuleMetadata`, `ModuleOptions`, `ModuleProvider`, `ModuleProviderConfig`, `ParamMetadata`, `ParamOptions`, `ParamSource`, `QueryOptions`, `RouteOptions`, `TransformFn`, `OnInit`, `OnShutdown`, `ControllersOptions`, `ModuleRegistrationOptions` | `@nextrush/class` | `3.0.0`-`3.1.0` | Stable [x] | Class-runtime contracts. |
|
|
332
|
+
| `type RouteMetadata` (from `@nextrush/class`) | `@nextrush/class` | `3.0.0` | Deprecated | Superseded by `ControllerRouteMetadata`; removed in the next major. |
|
|
333
|
+
|
|
334
|
+
Loading `nextrush/class` requires `@nextrush/class`, `@nextrush/di`, and `reflect-metadata` to be
|
|
335
|
+
installed - see [Compatibility](#compatibility).
|
|
336
|
+
|
|
337
|
+
## Options
|
|
338
|
+
|
|
339
|
+
`createApp(options?)` re-exports `@nextrush/core`'s `ApplicationOptions` unchanged - see
|
|
340
|
+
[`@nextrush/core`'s Options](../core#options) for the full table. There is no configuration
|
|
341
|
+
specific to the meta package itself: it adds one behavior (a default router injected into
|
|
342
|
+
`options.router` when you don't pass one) and no new option.
|
|
343
|
+
|
|
344
|
+
## Compatibility
|
|
345
|
+
|
|
346
|
+
**Requirements**
|
|
347
|
+
|
|
348
|
+
| Requirement | Version |
|
|
349
|
+
| ----------- | ------- |
|
|
350
|
+
| NextRush | `3.x` |
|
|
351
|
+
| Node.js | `>=22` |
|
|
352
|
+
| TypeScript | `>=5.x` |
|
|
353
|
+
|
|
354
|
+
**Runtimes**
|
|
355
|
+
|
|
356
|
+
| Runtime | Supported | Notes |
|
|
357
|
+
| ------- | --------- | ----- |
|
|
358
|
+
| Node.js `>=22` | [x] | Via `@nextrush/adapter-node`; ESM-only |
|
|
359
|
+
| Bun / Deno / Edge | Not via this package | Import `@nextrush/core` + `@nextrush/router` + the matching `@nextrush/adapter-{bun,deno,edge}` directly - `nextrush`'s `listen`/`serve` are Node-specific |
|
|
360
|
+
|
|
361
|
+
**Dependency footprint by usage path**
|
|
362
|
+
|
|
363
|
+
| Usage path | Entry point | Install | Runtime dependencies |
|
|
364
|
+
| ---------- | ----------- | ------- | --------------------- |
|
|
365
|
+
| Functional core | `createApp`, `createRouter`, `listen` from `nextrush` | `pnpm add nextrush` | `@nextrush/core`, `@nextrush/router`, `@nextrush/adapter-node`, `@nextrush/errors`, `@nextrush/types` (all hard `dependencies`) |
|
|
366
|
+
| Class-based / DI | `nextrush/class` | `pnpm add nextrush @nextrush/class` | Adds `@nextrush/class`, `@nextrush/di` (wraps `tsyringe@^4.10.0`), `reflect-metadata@^0.2.2` |
|
|
367
|
+
|
|
368
|
+
`@nextrush/class`, `@nextrush/di`, and `reflect-metadata` are declared as **optional
|
|
369
|
+
`peerDependencies`** in `package.json` (`peerDependenciesMeta.<name>.optional: true`) - a
|
|
370
|
+
functional-only `pnpm add nextrush` never resolves any of the three onto disk. If you import
|
|
371
|
+
`nextrush/class` without installing the peers, the import throws an actionable error naming the
|
|
372
|
+
exact install command instead of an opaque module-resolution failure.
|
|
373
|
+
|
|
374
|
+
`@nextrush/stream` and `@nextrush/runtime` ship transitively through `@nextrush/adapter-node`'s
|
|
375
|
+
own dependencies - they are present once `nextrush` is installed, but are not re-exported from
|
|
376
|
+
`nextrush` directly. Add either as a direct dependency of your own project only if you import its
|
|
377
|
+
API yourself rather than through the adapter.
|
|
378
|
+
|
|
379
|
+
**Integration**
|
|
380
|
+
- **Peer dependencies:** `@nextrush/class`, `@nextrush/di`, `reflect-metadata` - all optional, needed only for `nextrush/class`.
|
|
381
|
+
- **Works with:** every `@nextrush/*` middleware and extension package (installed separately - see the [package catalog](https://0xtanzim.github.io/nextRush/docs/resources/package-catalog)).
|
|
382
|
+
- **Incompatible with:** none.
|
|
383
|
+
|
|
384
|
+
> [!IMPORTANT]
|
|
385
|
+
> NextRush is **ESM-only, permanently** - no CommonJS build. On Node `>=22`, CommonJS consumers
|
|
386
|
+
> can `require()` this ESM package natively. See the
|
|
387
|
+
> [Module Format Policy](https://github.com/0xTanzim/nextRush#module-format-policy).
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Troubleshooting
|
|
392
|
+
|
|
393
|
+
<details>
|
|
394
|
+
<summary><strong><code>Cannot find module '@nextrush/class'</code> when importing <code>nextrush/class</code></strong></summary>
|
|
395
|
+
|
|
396
|
+
**Cause:** `@nextrush/class`, `@nextrush/di`, and `reflect-metadata` are optional peer
|
|
397
|
+
dependencies - a plain `pnpm add nextrush` never installs them. **Fix:** install the peer
|
|
398
|
+
explicitly:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
pnpm add @nextrush/class reflect-metadata
|
|
136
402
|
```
|
|
137
403
|
|
|
138
|
-
>
|
|
404
|
+
</details>
|
|
139
405
|
|
|
140
|
-
|
|
406
|
+
<details>
|
|
407
|
+
<summary><strong>Decorators throw or metadata is missing at runtime</strong></summary>
|
|
141
408
|
|
|
142
|
-
|
|
409
|
+
**Cause:** `experimentalDecorators` and/or `emitDecoratorMetadata` are not enabled in
|
|
410
|
+
`tsconfig.json`. **Fix:** enable both - `create-nextrush` does this automatically for
|
|
411
|
+
class-based/full templates:
|
|
143
412
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
413
|
+
```json
|
|
414
|
+
{
|
|
415
|
+
"compilerOptions": {
|
|
416
|
+
"experimentalDecorators": true,
|
|
417
|
+
"emitDecoratorMetadata": true
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
```
|
|
151
421
|
|
|
152
|
-
|
|
422
|
+
</details>
|
|
153
423
|
|
|
154
|
-
|
|
424
|
+
<details>
|
|
425
|
+
<summary><strong><code>app.get(...)</code> throws <code>No router configured</code></strong></summary>
|
|
155
426
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
| `@nextrush/core` | Application & middleware composition |
|
|
159
|
-
| `@nextrush/router` | High-performance radix tree router |
|
|
160
|
-
| `@nextrush/adapter-node` | Node.js HTTP adapter |
|
|
161
|
-
| `@nextrush/types` | Shared TypeScript types |
|
|
162
|
-
| `@nextrush/errors` | HTTP error classes |
|
|
427
|
+
**Cause:** you're calling `@nextrush/core`'s own `createApp()` (router-agnostic by design)
|
|
428
|
+
instead of `nextrush`'s. **Fix:** import `createApp` from `nextrush`, which injects a router:
|
|
163
429
|
|
|
164
|
-
|
|
430
|
+
```ts
|
|
431
|
+
import { createApp } from 'nextrush'; // injects a router; app.get works
|
|
432
|
+
```
|
|
165
433
|
|
|
166
|
-
|
|
167
|
-
| ----------------------- | -------------------------------------- |
|
|
168
|
-
| `@nextrush/body-parser` | JSON/form/text body parsing |
|
|
169
|
-
| `@nextrush/cors` | CORS headers |
|
|
170
|
-
| `@nextrush/helmet` | Security headers |
|
|
171
|
-
| `@nextrush/cookies` | Cookie handling |
|
|
172
|
-
| `@nextrush/compression` | Response compression (gzip/brotli) |
|
|
173
|
-
| `@nextrush/rate-limit` | Rate limiting with multiple algorithms |
|
|
174
|
-
| `@nextrush/request-id` | Request ID generation |
|
|
175
|
-
| `@nextrush/timer` | Request timing headers |
|
|
434
|
+
</details>
|
|
176
435
|
|
|
177
|
-
|
|
436
|
+
## FAQ
|
|
178
437
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| `@nextrush/logger` | Structured logging |
|
|
182
|
-
| `@nextrush/static` | Static file serving |
|
|
183
|
-
| `@nextrush/websocket` | WebSocket support with rooms |
|
|
184
|
-
| `@nextrush/template` | Multi-engine template rendering |
|
|
185
|
-
| `@nextrush/events` | Type-safe event emitter |
|
|
186
|
-
| `@nextrush/controllers` | Decorator-based controllers |
|
|
438
|
+
**Can I skip the meta package and use `@nextrush/core` / `@nextrush/router` / `@nextrush/adapter-node` directly?**
|
|
439
|
+
Yes - see [Direct package usage](#direct-package-usage) below. `nextrush` only adds the pre-wired router and the convenience barrel; nothing it re-exports is otherwise inaccessible.
|
|
187
440
|
|
|
188
|
-
|
|
441
|
+
**Why ESM-only?**
|
|
442
|
+
See the [Module Format Policy](https://github.com/0xTanzim/nextRush#module-format-policy).
|
|
189
443
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
| `@nextrush/di` | Dependency injection container |
|
|
193
|
-
| `@nextrush/decorators` | Controller & route decorators |
|
|
444
|
+
**Does it work on Bun / Deno / Edge?**
|
|
445
|
+
Not through `nextrush` itself - its `listen`/`serve` come from `@nextrush/adapter-node`. For other runtimes, import `@nextrush/core` + `@nextrush/router` + the matching `@nextrush/adapter-{bun,deno,edge}` directly; the functional API is otherwise identical, and parity across adapters is enforced by the conformance suite.
|
|
194
446
|
|
|
195
|
-
|
|
447
|
+
**Why are `@nextrush/class` and `@nextrush/di` peer dependencies instead of regular dependencies?**
|
|
448
|
+
So a functional-only install never downloads or resolves the class/DI stack (and its `tsyringe`/`reflect-metadata` supply-chain surface) - see [ADR-0009](https://github.com/0xTanzim/nextRush/blob/main/docs/adr/ADR-0009-framework-composition-and-functional-install-boundary.md).
|
|
196
449
|
|
|
197
|
-
|
|
198
|
-
| ----------------- | --------------------------------------------------------- |
|
|
199
|
-
| `@nextrush/dev` | Hot reload dev server, production builds, code generators |
|
|
200
|
-
| `create-nextrush` | Project scaffolder — `pnpm create nextrush`, `npx create-nextrush` ([usage](https://github.com/0xTanzim/nextRush/blob/main/packages/create-nextrush/README.md)) |
|
|
450
|
+
---
|
|
201
451
|
|
|
202
452
|
## Direct Package Usage
|
|
203
453
|
|
|
204
|
-
For maximum control, skip the meta package:
|
|
454
|
+
For maximum control, skip the meta package's convenience wrapping:
|
|
205
455
|
|
|
206
|
-
```
|
|
456
|
+
```ts
|
|
207
457
|
import { createApp } from '@nextrush/core';
|
|
208
458
|
import { createRouter } from '@nextrush/router';
|
|
209
459
|
import { listen } from '@nextrush/adapter-node';
|
|
210
460
|
import { cors } from '@nextrush/cors';
|
|
211
461
|
```
|
|
212
462
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
Built-in HTTP error classes:
|
|
463
|
+
`@nextrush/core`'s `createApp` does not inject a router - pass one explicitly
|
|
464
|
+
(`createApp({ router: createRouter() })`) if you take this path.
|
|
216
465
|
|
|
217
|
-
|
|
218
|
-
import { NotFoundError, BadRequestError, HttpError } from 'nextrush';
|
|
466
|
+
## Package relationships
|
|
219
467
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
468
|
+
```text
|
|
469
|
+
depends on @nextrush/core, @nextrush/router, @nextrush/adapter-node
|
|
470
|
+
nextrush --------------------------> @nextrush/errors, @nextrush/types
|
|
471
|
+
optional peer @nextrush/class, @nextrush/di, reflect-metadata
|
|
472
|
+
usually used next @nextrush/cors, @nextrush/body-parser, any middleware/extension
|
|
224
473
|
```
|
|
225
474
|
|
|
226
|
-
|
|
475
|
+
- **Depends on:** [`@nextrush/core`](../core), [`@nextrush/router`](../router), [`@nextrush/adapter-node`](../adapters/node), [`@nextrush/errors`](../errors), [`@nextrush/types`](../types) - hard dependencies, resolved on every install.
|
|
476
|
+
- **Optional peer:** [`@nextrush/class`](../class), [`@nextrush/di`](../di), `reflect-metadata` - resolved only if you install them, for `nextrush/class`.
|
|
477
|
+
- **Often used with:** [`create-nextrush`](https://github.com/0xTanzim/nextRush/tree/main/packages/create-nextrush) - scaffolds a project that already depends on `nextrush` correctly configured.
|
|
478
|
+
- **Usually used next:** any middleware package (`@nextrush/cors`, `@nextrush/body-parser`, `@nextrush/helmet`, ...) - see the [package catalog](https://0xtanzim.github.io/nextRush/docs/resources/package-catalog).
|
|
479
|
+
- **Alternative:** [`@nextrush/core`](../core) directly, if you're building your own meta-package or adapter and don't want the pre-wired router.
|
|
227
480
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
481
|
+
## Architecture
|
|
482
|
+
|
|
483
|
+
Maintaining or contributing to this package? The internal design - the exports-map routing
|
|
484
|
+
between the root entry and the `nextrush/class` subpath, the dynamic-import/re-export-by-
|
|
485
|
+
assignment mechanism that turns a missing optional peer into an actionable error, the single-DI-
|
|
486
|
+
instance guarantee, and the decisions and trade-offs behind them (with diagrams) - is in
|
|
487
|
+
**[`ARCHITECTURE.md`](./ARCHITECTURE.md)**. Design history:
|
|
488
|
+
[RFC-020 - framework composition integrity](https://github.com/0xTanzim/nextRush/tree/main/docs/RFC/framework-composition/020-framework-composition-integrity.md),
|
|
489
|
+
[ADR-0009](https://github.com/0xTanzim/nextRush/blob/main/docs/adr/ADR-0009-framework-composition-and-functional-install-boundary.md).
|
|
490
|
+
|
|
491
|
+
## Resources
|
|
492
|
+
|
|
493
|
+
- **Learn** - [Documentation](https://0xtanzim.github.io/nextRush/docs) | [Getting started](https://0xtanzim.github.io/nextRush/docs/getting-started) | [Architecture](./ARCHITECTURE.md) | [RFCs](https://github.com/0xTanzim/nextRush/tree/main/docs/RFC)
|
|
494
|
+
- **Changelog** - [CHANGELOG.md](./CHANGELOG.md)
|
|
495
|
+
- **Migration** - [Framework composition migration guide](https://github.com/0xTanzim/nextRush/blob/main/docs/guides/migration-framework-composition.md)
|
|
496
|
+
- **Examples** - [create-nextrush templates](https://github.com/0xTanzim/nextRush/tree/main/packages/create-nextrush)
|
|
497
|
+
- **Report an issue** - [GitHub Issues](https://github.com/0xTanzim/nextRush/issues)
|
|
498
|
+
- **Contribute** - [CONTRIBUTING.md](https://github.com/0xTanzim/nextRush/blob/main/CONTRIBUTING.md)
|
|
232
499
|
|
|
233
|
-
|
|
500
|
+
---
|
|
234
501
|
|
|
235
|
-
MIT
|
|
502
|
+
MIT (c) [Tanzim Hossain](https://github.com/0xTanzim)
|
package/bin/nextrush.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `nextrush` meta-package launcher (ADR-0013).
|
|
4
|
+
*
|
|
5
|
+
* Delegates to the optional `@nextrush/dev` toolkit when installed, or prints an actionable
|
|
6
|
+
* install message when it is absent. All logic lives in `dev-cli-launcher.ts`; this file is only
|
|
7
|
+
* the executable entry point and never runs at install time (only on explicit `nextrush <command>`).
|
|
8
|
+
*/
|
|
9
|
+
import { runDevCliLauncher } from '../dist/dev-cli-launcher.js';
|
|
10
|
+
|
|
11
|
+
runDevCliLauncher(process.argv.slice(2))
|
|
12
|
+
.then((code) => {
|
|
13
|
+
process.exit(code);
|
|
14
|
+
})
|
|
15
|
+
.catch((err) => {
|
|
16
|
+
// Unrelated error surfaced unchanged (not the missing-toolkit case).
|
|
17
|
+
console.error(err);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|