@nifrajs/node 4.0.2 → 5.1.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 +17 -4
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +221 -79
- package/dist/index.js.map +1 -1
- package/dist/open-resolved.d.ts +18 -0
- package/dist/open-resolved.d.ts.map +1 -0
- package/dist/open-resolved.js +64 -0
- package/dist/open-resolved.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +251 -82
- package/src/open-resolved.ts +66 -0
package/README.md
CHANGED
|
@@ -53,10 +53,12 @@ The optional `static` root is served before `app.fetch` for GET and HEAD request
|
|
|
53
53
|
public asset directory and must contain nothing private: no secrets, source maps, build
|
|
54
54
|
metadata, or user uploads. The directory and its ancestor path must be read-only and owned by
|
|
55
55
|
the service (or otherwise protected from untrusted local writers). Nifra resolves and confines
|
|
56
|
-
the file before opening it and refuses
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
the file before opening it, and refuses it when its final file or any directory on its path became
|
|
57
|
+
a symlink in the meantime: on macOS the open itself refuses such a path, and on Linux the opened
|
|
58
|
+
descriptor's path is checked. On Windows and other platforms no file API can open without following a
|
|
59
|
+
middle link, so a process that swaps a directory concurrently can still win a local TOCTOU race;
|
|
60
|
+
the check there only makes it need repeated swaps. Mutable or attacker-writable static trees are
|
|
61
|
+
therefore outside the adapter's guarantee on those platforms. Store user-controlled files outside the static root and serve them through
|
|
60
62
|
an application or object-storage path with its own validation policy.
|
|
61
63
|
|
|
62
64
|
Every file carries a strong `ETag` (from mtime and size), `Last-Modified`, and
|
|
@@ -74,6 +76,13 @@ process signals should be a deliberate choice):
|
|
|
74
76
|
await serve(app, { port: 3000, signals: true })
|
|
75
77
|
```
|
|
76
78
|
|
|
79
|
+
In-flight requests get 10 s to finish before the stop forces them closed. Set the window to fit
|
|
80
|
+
the platform's kill grace period:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
await serve(app, { port: 3000, signals: { drainMs: 8_000 } })
|
|
84
|
+
```
|
|
85
|
+
|
|
77
86
|
## What you get for free
|
|
78
87
|
|
|
79
88
|
The request timeout (`server({ requestTimeoutMs })` → `503 request_timeout`) and body-size
|
|
@@ -81,6 +90,10 @@ cap live **inside `app.fetch`**, not Bun's `listen()` - so they apply through th
|
|
|
81
90
|
with no extra wiring. Slow-client / slow-loris protection is Node's built-in
|
|
82
91
|
`requestTimeout` (300s) and `headersTimeout` (60s) defaults.
|
|
83
92
|
|
|
93
|
+
A hook that throws past `app.fetch`, or a response Node refuses to write (a header value carrying
|
|
94
|
+
CR/LF, say), answers `500` and is logged through the app's own `logger`, as Bun's `listen()` logs it. The `req` a hook sees is a lazy stand-in for Node's request: copy it
|
|
95
|
+
with `req.clone()`, not `new Request(req)`, which Node's `Request` constructor refuses.
|
|
96
|
+
|
|
84
97
|
Works with any `{ fetch(req): Promise<Response> }` handler, not just nifra. ESM-only. MIT.
|
|
85
98
|
|
|
86
99
|
## For AI agents
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ type WsUpgradeOutcome = {
|
|
|
49
49
|
readonly data: unknown;
|
|
50
50
|
readonly pubsub: WsPubSub;
|
|
51
51
|
readonly maxPayloadBytes?: number;
|
|
52
|
+
/** Builds `ws.send` with the route's outbound contract (`validateSend`). */
|
|
53
|
+
sender?(handler: NifraWsHandler, send: (payload: string | ArrayBufferView | ArrayBuffer) => void, onError: (error: unknown) => void): (payload: string | ArrayBufferView | ArrayBuffer) => void;
|
|
52
54
|
};
|
|
53
55
|
export type RequestProtocol = "http" | "https";
|
|
54
56
|
export type RequestProtocolOption = RequestProtocol | ((request: IncomingMessage) => RequestProtocol);
|
|
@@ -64,6 +66,12 @@ export interface ServeStaticOptions {
|
|
|
64
66
|
readonly prefix?: string;
|
|
65
67
|
/** Emit `cache-control: public, max-age=31536000, immutable` - correct for content-hashed files. Default `true`. */
|
|
66
68
|
readonly immutable?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* URL paths of the content-hashed files, such as a client build manifest's `assets`. When set,
|
|
71
|
+
* `immutable` applies only to these; any other file is sent with its validators and no
|
|
72
|
+
* `cache-control`, so a file that keeps its name across deploys still revalidates.
|
|
73
|
+
*/
|
|
74
|
+
readonly hashedFiles?: Iterable<string>;
|
|
67
75
|
/** Extra headers merged onto every served file. */
|
|
68
76
|
readonly headers?: Readonly<Record<string, string>>;
|
|
69
77
|
/**
|
|
@@ -101,13 +109,17 @@ export interface ServeOptions {
|
|
|
101
109
|
* Install SIGTERM/SIGINT handlers that call `stop()` for a graceful drain on
|
|
102
110
|
* `docker stop` / Ctrl-C. Off by default - taking over process signals is opt-in,
|
|
103
111
|
* mirroring nifra's Bun `listen({ gracefulSignals })`.
|
|
112
|
+
* `{ drainMs }` sets how long in-flight requests get before the stop forces them closed
|
|
113
|
+
* (default 10_000).
|
|
104
114
|
*
|
|
105
115
|
* The app-level request timeout (`server({ requestTimeoutMs })` → 503) and body cap
|
|
106
116
|
* are *not* set here - they live inside `app.fetch`, so they already apply through
|
|
107
117
|
* this adapter. Slow-client protection is Node's built-in `requestTimeout` (300s) /
|
|
108
118
|
* `headersTimeout` (60s) defaults.
|
|
109
119
|
*/
|
|
110
|
-
readonly signals?: boolean
|
|
120
|
+
readonly signals?: boolean | {
|
|
121
|
+
readonly drainMs?: number;
|
|
122
|
+
};
|
|
111
123
|
/**
|
|
112
124
|
* Serve static files from disk for matching GET/HEAD requests *before* the app runs - non-matching
|
|
113
125
|
* requests fall through to `app.fetch` with the node-direct fast path intact (no perf regression on
|
|
@@ -132,7 +144,8 @@ export interface NodeServer {
|
|
|
132
144
|
readonly port: number;
|
|
133
145
|
/**
|
|
134
146
|
* Stop accepting connections, let in-flight requests drain (up to `drainMs`), then
|
|
135
|
-
* force-close stragglers + idle keep-alives.
|
|
147
|
+
* force-close stragglers + idle keep-alives. Open WebSockets get a 1001 close at once and are
|
|
148
|
+
* terminated if still open at the deadline. Mirrors nifra's Bun `stop()`.
|
|
136
149
|
*/
|
|
137
150
|
stop(options?: {
|
|
138
151
|
drainMs?: number;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|