@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 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 symlinked final files, but Node does not expose a native
57
- per-component `openat` primitive; a process that can mutate the tree concurrently can still
58
- create a local TOCTOU race. Mutable or attacker-writable static trees are therefore outside the
59
- adapter's guarantee. Store user-controlled files outside the static root and serve them through
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. Mirrors nifra's Bun `stop()`.
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;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}