@daloyjs/core 1.0.0-beta.6 → 1.0.0-beta.7

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.
Files changed (99) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/bun.d.ts +13 -1
  3. package/dist/adapters/bun.js +8 -1
  4. package/dist/adapters/cloudflare.d.ts +7 -1
  5. package/dist/adapters/cloudflare.js +6 -1
  6. package/dist/adapters/deno.d.ts +11 -1
  7. package/dist/adapters/deno.js +8 -1
  8. package/dist/adapters/fastly.d.ts +12 -2
  9. package/dist/adapters/fastly.js +12 -2
  10. package/dist/adapters/lambda.d.ts +37 -1
  11. package/dist/adapters/lambda.js +6 -1
  12. package/dist/adapters/node.d.ts +12 -1
  13. package/dist/adapters/node.js +7 -1
  14. package/dist/adapters/vercel.d.ts +13 -1
  15. package/dist/adapters/vercel.js +12 -1
  16. package/dist/app.d.ts +67 -17
  17. package/dist/app.js +97 -31
  18. package/dist/banner.d.ts +6 -0
  19. package/dist/banner.js +6 -0
  20. package/dist/cli.d.ts +35 -0
  21. package/dist/cli.js +23 -1
  22. package/dist/combine.d.ts +8 -0
  23. package/dist/combine.js +8 -0
  24. package/dist/compression.d.ts +3 -0
  25. package/dist/compression.js +3 -0
  26. package/dist/config.d.ts +4 -0
  27. package/dist/config.js +4 -0
  28. package/dist/conn-info.d.ts +35 -2
  29. package/dist/conn-info.js +35 -2
  30. package/dist/contract.d.ts +2 -0
  31. package/dist/contract.js +2 -0
  32. package/dist/cookie.d.ts +12 -0
  33. package/dist/cookie.js +12 -0
  34. package/dist/dependency.d.ts +4 -0
  35. package/dist/dependency.js +3 -0
  36. package/dist/discriminator.d.ts +13 -0
  37. package/dist/discriminator.js +23 -1
  38. package/dist/docs.d.ts +78 -0
  39. package/dist/docs.js +21 -0
  40. package/dist/errors.d.ts +16 -0
  41. package/dist/errors.js +14 -0
  42. package/dist/etag.d.ts +2 -0
  43. package/dist/etag.js +2 -0
  44. package/dist/fetch-guard.d.ts +7 -0
  45. package/dist/fetch-guard.js +7 -0
  46. package/dist/fetch-resilience.d.ts +4 -0
  47. package/dist/fetch-resilience.js +4 -0
  48. package/dist/http-signatures.d.ts +32 -0
  49. package/dist/http-signatures.js +30 -0
  50. package/dist/index.d.ts +1 -1
  51. package/dist/ip-restriction.d.ts +40 -3
  52. package/dist/ip-restriction.js +35 -3
  53. package/dist/jwk.d.ts +12 -1
  54. package/dist/jwk.js +6 -0
  55. package/dist/jwt.d.ts +14 -0
  56. package/dist/jwt.js +10 -0
  57. package/dist/load-shedding.d.ts +3 -0
  58. package/dist/load-shedding.js +3 -0
  59. package/dist/logger.d.ts +13 -0
  60. package/dist/logger.js +3 -0
  61. package/dist/mcp.d.ts +152 -10
  62. package/dist/mcp.js +223 -19
  63. package/dist/middleware.d.ts +68 -0
  64. package/dist/middleware.js +17 -0
  65. package/dist/mtls.d.ts +19 -2
  66. package/dist/mtls.js +12 -2
  67. package/dist/multipart.d.ts +42 -5
  68. package/dist/multipart.js +41 -5
  69. package/dist/openapi.d.ts +15 -9
  70. package/dist/openapi.js +6 -9
  71. package/dist/rate-limit-redis.d.ts +21 -2
  72. package/dist/rate-limit-redis.js +17 -2
  73. package/dist/safe-redirect.d.ts +6 -0
  74. package/dist/safe-redirect.js +6 -0
  75. package/dist/sbom.cdx.json +9 -9
  76. package/dist/sbom.spdx.json +5 -5
  77. package/dist/scheduler.d.ts +4 -0
  78. package/dist/schema.d.ts +25 -0
  79. package/dist/security-schemes.d.ts +50 -0
  80. package/dist/security-schemes.js +6 -0
  81. package/dist/security.d.ts +33 -0
  82. package/dist/security.js +28 -10
  83. package/dist/session.d.ts +34 -5
  84. package/dist/session.js +31 -5
  85. package/dist/streaming.d.ts +19 -0
  86. package/dist/streaming.js +16 -0
  87. package/dist/subdomains.d.ts +4 -0
  88. package/dist/subdomains.js +4 -0
  89. package/dist/time-claims.d.ts +22 -2
  90. package/dist/time-claims.js +6 -0
  91. package/dist/tracing.d.ts +12 -0
  92. package/dist/tracing.js +6 -0
  93. package/dist/types.d.ts +70 -1
  94. package/dist/waf.js +21 -1
  95. package/dist/webhook-delivery.d.ts +6 -0
  96. package/dist/webhook-delivery.js +5 -0
  97. package/dist/websocket.d.ts +137 -4
  98. package/dist/websocket.js +105 -4
  99. package/package.json +1 -1
@@ -76,10 +76,15 @@ export interface WebSocketConnection<TData = unknown> {
76
76
  * been read.
77
77
  */
78
78
  export interface WebSocketContext<P extends string = string, S = AppState> {
79
+ /** The original RFC 6455 upgrade `Request`. */
79
80
  request: Request;
81
+ /** Path parameters extracted from the matched route pattern. */
80
82
  params: PathParams<P>;
83
+ /** Query-string parameters from the upgrade URL. */
81
84
  query: Record<string, string>;
85
+ /** Upgrade request headers, lower-cased keys. */
82
86
  headers: Record<string, string>;
87
+ /** Per-app state produced by the route's state factory. */
83
88
  state: S;
84
89
  /** Subprotocols offered by the client (parsed from `Sec-WebSocket-Protocol`). */
85
90
  protocols: string[];
@@ -208,25 +213,45 @@ export interface WebSocketHandler<P extends string = string, S = AppState, TData
208
213
  * @since 0.33.0
209
214
  */
210
215
  acknowledgeCrossOriginUpgrade?: boolean;
216
+ /**
217
+ * Auth/decision hook run before the 101 response is sent (after the
218
+ * {@link WebSocketHandler.allowedOrigins} check). Return a `Response` to
219
+ * reject, a string to select that subprotocol, or `undefined` to accept.
220
+ */
211
221
  beforeUpgrade?(request: Request, ctx: WebSocketContext<P, S>): Response | string | undefined | Promise<Response | string | undefined>;
222
+ /** Called once after the upgrade completes and the connection is open. */
212
223
  open?(conn: WebSocketConnection<TData>, ctx: WebSocketContext<P, S>): void | Promise<void>;
224
+ /** Called for each complete inbound message; `data` is a string for text frames, bytes for binary (`isBinary: true`). */
213
225
  message?(conn: WebSocketConnection<TData>, data: string | Uint8Array | ArrayBuffer, isBinary: boolean): void | Promise<void>;
226
+ /** Called when the connection closes, with the RFC 6455 close code and reason. */
214
227
  close?(conn: WebSocketConnection<TData>, code: number, reason: string): void | Promise<void>;
228
+ /** Called when a socket or handler error occurs on the connection. */
215
229
  error?(conn: WebSocketConnection<TData>, err: unknown): void | Promise<void>;
230
+ /** Called when the socket's send buffer drains after backpressure. */
216
231
  drain?(conn: WebSocketConnection<TData>): void | Promise<void>;
217
232
  }
218
233
  /** Result of {@link normalizeWebSocketOptions}: fully resolved limits applied by the adapter. */
219
234
  export interface NormalizedWebSocketOptions {
235
+ /** Close the connection when queued outbound bytes exceed `backpressureLimit`. Defaults to `true`. */
220
236
  closeOnBackpressureLimit: boolean;
237
+ /** Maximum queued outbound bytes before backpressure handling triggers. Defaults to 1 MiB. */
221
238
  backpressureLimit: number;
239
+ /** Per-message compression flag. Defaults to `false`; refused in production under secureDefaults. */
222
240
  perMessageDeflate: boolean;
241
+ /** Idle timeout in seconds. Defaults to `120`. */
223
242
  idleTimeout: number;
243
+ /** Maximum inbound message payload length in bytes. Defaults to 1 MiB. */
224
244
  maxPayloadLength: number;
225
245
  }
226
246
  /**
227
247
  * Resolve a user-supplied {@link WebSocketHandler} into the strict
228
248
  * {@link NormalizedWebSocketOptions} the adapter consumes. Applies defaults,
229
249
  * runs production safety checks, and throws on invalid values.
250
+ *
251
+ * @param handler The user-supplied handler whose option fields are validated.
252
+ * @param context Environment flags: `production` and `secureDefaults` gate the perMessageDeflate refusal.
253
+ * @returns The fully resolved options applied by the runtime adapter.
254
+ * @throws Error when a limit is not a positive integer, `allowedOrigins` is malformed, `perMessageDeflate` is enabled in production under secureDefaults, or `maxPayloadLength` exceeds the body schema maximum.
230
255
  */
231
256
  export declare function normalizeWebSocketOptions(handler: WebSocketHandler<any, any, any>, context: {
232
257
  production: boolean;
@@ -239,16 +264,27 @@ export type WebSocketBeforeUpgrade<P extends string = string, S = AppState> = No
239
264
  * a `beforeUpgrade` handler to spend from the same shared buckets as HTTP
240
265
  * routes (for example, login and WebSocket session-establishment endpoints).
241
266
  *
267
+ * @param options The same {@link RateLimitOptions} accepted by the HTTP `rateLimit` middleware.
268
+ * @returns A `beforeUpgrade` hook that returns the 429 (or error) `Response` when the limit is exceeded, or `undefined` to allow the upgrade. Rate-limit headers are copied onto rejection responses.
242
269
  * @since 0.23.0
243
270
  */
244
271
  export declare function wsRateLimit<P extends string = string, S = AppState>(options: RateLimitOptions): WebSocketBeforeUpgrade<P, S>;
245
- /** Helper for declaring a handler with full type-inference. */
272
+ /**
273
+ * Helper for declaring a handler with full type-inference.
274
+ *
275
+ * @param handler The {@link WebSocketHandler} to type-check; returned as-is.
276
+ * @returns The same handler object, with `P`/`S`/`TData` inferred.
277
+ */
246
278
  export declare function defineWebSocket<P extends string, S = AppState, TData = unknown>(handler: WebSocketHandler<P, S, TData>): WebSocketHandler<P, S, TData>;
247
279
  /** Entry stored inside {@link WebSocketRegistry} for a single WS route. */
248
280
  export interface WebSocketRouteEntry {
281
+ /** Route path pattern the entry was registered under (may contain `:param` segments). */
249
282
  path: PathString;
283
+ /** The user-supplied lifecycle handler for this route. */
250
284
  handler: WebSocketHandler<any, any, any>;
285
+ /** Factory producing the per-upgrade `state` object handed to the context. */
251
286
  createState: WebSocketStateFactory;
287
+ /** Resolved limits from {@link normalizeWebSocketOptions} applied by the adapter. */
252
288
  options: NormalizedWebSocketOptions;
253
289
  }
254
290
  type WebSocketStateFactory = () => Record<string, unknown>;
@@ -263,7 +299,21 @@ export declare class WebSocketRegistry {
263
299
  private router;
264
300
  private _size;
265
301
  private entries;
302
+ /**
303
+ * Register a WebSocket route.
304
+ *
305
+ * @param path Route path pattern (supports `:param` segments).
306
+ * @param handler Lifecycle handler for connections on this route.
307
+ * @param createState Per-upgrade state factory. Defaults to `() => ({})`.
308
+ * @param options Resolved limits; defaults to normalizing `handler` with dev-mode secure defaults.
309
+ */
266
310
  add(path: PathString, handler: WebSocketHandler<any, any, any>, createState?: WebSocketStateFactory, options?: NormalizedWebSocketOptions): void;
311
+ /**
312
+ * Match a request pathname against the registered WS routes.
313
+ *
314
+ * @param pathname URL pathname of the upgrade request.
315
+ * @returns The matched entry plus extracted params, or `undefined` when no route matches.
316
+ */
267
317
  find(pathname: string): RouteMatch<WebSocketRouteEntry> | undefined;
268
318
  /**
269
319
  * List every registered WebSocket route entry in registration order.
@@ -276,7 +326,17 @@ export declare class WebSocketRegistry {
276
326
  * @since 0.37.0
277
327
  */
278
328
  list(): WebSocketRouteEntry[];
329
+ /** Number of registered WebSocket routes. */
279
330
  get size(): number;
331
+ /**
332
+ * Aggregate the per-route options into a single set for runtimes (Bun) that
333
+ * take one server-wide WebSocket config: `closeOnBackpressureLimit` only when
334
+ * every route enables it, largest `backpressureLimit`/`maxPayloadLength`,
335
+ * smallest `idleTimeout`, and `perMessageDeflate` if any route enables it.
336
+ * Returns the secure defaults when no routes are registered.
337
+ *
338
+ * @returns The merged {@link NormalizedWebSocketOptions} for the whole app.
339
+ */
280
340
  runtimeOptions(): NormalizedWebSocketOptions;
281
341
  }
282
342
  /**
@@ -284,17 +344,30 @@ export declare class WebSocketRegistry {
284
344
  * `Sec-WebSocket-Key` per RFC 6455 §4.2.2:
285
345
  *
286
346
  * `base64(SHA1(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))`
347
+ *
348
+ * @param key - The client's `Sec-WebSocket-Key` header value.
349
+ * @returns The base64-encoded accept token for the 101 response.
350
+ * @throws Error when Web Crypto (`crypto.subtle`) is unavailable.
287
351
  */
288
352
  export declare function computeAcceptKey(key: string): Promise<string>;
289
353
  /**
290
354
  * Parse the offered subprotocols from a `Sec-WebSocket-Protocol` header.
291
355
  * Returns trimmed, non-empty tokens in client preference order.
356
+ *
357
+ * @param header - Raw header value; `null`/`undefined` yields an empty list.
358
+ * @returns The offered subprotocol tokens, most-preferred first.
292
359
  */
293
360
  export declare function parseSubprotocols(header: string | null | undefined): string[];
294
361
  /**
295
362
  * Validate a server-selected subprotocol before it is written to the 101
296
363
  * response. RFC 6455 requires the value to be one of the client-offered
297
364
  * tokens; enforcing it also prevents accidental response-header injection.
365
+ *
366
+ * @param protocol - The subprotocol the server wants to select.
367
+ * @param offered - Tokens the client offered (from {@link parseSubprotocols}).
368
+ * @returns The validated `protocol`, unchanged.
369
+ * @throws WebSocketProtocolError when `protocol` is not a valid HTTP token
370
+ * or was not offered by the client.
298
371
  */
299
372
  export declare function validateSelectedSubprotocol(protocol: string, offered: readonly string[]): string;
300
373
  /**
@@ -315,6 +388,12 @@ export type HandshakeResult = {
315
388
  * Validate the upgrade request headers and compute the accept key when
316
389
  * valid. This helper does **not** touch the wire — it only decides whether
317
390
  * the handshake should succeed and what the response key should be.
391
+ *
392
+ * @param headers - Header accessor for the upgrade request (any object with
393
+ * a `Headers`-style `get`).
394
+ * @returns `{ ok: true, acceptKey, protocols }` when the RFC 6455 handshake
395
+ * headers are valid, or `{ ok: false, status, reason }` describing the
396
+ * error response the adapter should send.
318
397
  */
319
398
  export declare function validateUpgrade(headers: {
320
399
  get(name: string): string | null;
@@ -329,6 +408,10 @@ export declare function validateUpgrade(headers: {
329
408
  * `{ ok: false, reason }` with a short human-readable reason suitable for
330
409
  * the upgrade-error body.
331
410
  *
411
+ * @param request - The upgrade request whose `Origin` header is checked.
412
+ * @param policy - The route's `allowedOrigins` value: `undefined` (allow
413
+ * all), `"same-origin"`, a string allowlist, or a predicate function.
414
+ * @returns `{ ok: true }` when permitted, otherwise `{ ok: false, reason }`.
332
415
  * @since 0.33.0
333
416
  */
334
417
  export declare function checkWebSocketOrigin(request: Request, policy: WebSocketHandler<any, any, any>["allowedOrigins"]): {
@@ -339,8 +422,11 @@ export declare function checkWebSocketOrigin(request: Request, policy: WebSocket
339
422
  };
340
423
  /** A single decoded RFC 6455 frame, as returned by {@link parseFrame}. */
341
424
  export interface ParsedFrame {
425
+ /** FIN bit — `true` when this frame ends a message. */
342
426
  fin: boolean;
427
+ /** Frame opcode (see `WS_OPCODE`): continuation, text, binary, close, ping, or pong. */
343
428
  opcode: number;
429
+ /** Unmasked payload bytes — a subarray view over the input buffer, not a copy. */
344
430
  payload: Uint8Array;
345
431
  /** Number of bytes consumed from the input buffer (header + payload). */
346
432
  consumed: number;
@@ -355,6 +441,15 @@ export declare const FRAME_INCOMPLETE: unique symbol;
355
441
  * The parser unmasks payloads in-place when needed. The returned `payload`
356
442
  * is a subarray view over `buf`; copy it if you intend to retain it past
357
443
  * the next call.
444
+ *
445
+ * @param buf - Buffered socket bytes beginning at a frame boundary.
446
+ * @param opts - `requireMask: true` enforces the RFC 6455 rule that
447
+ * client-to-server frames are masked. Defaults to `{}` (not enforced).
448
+ * @returns The decoded {@link ParsedFrame}, or {@link FRAME_INCOMPLETE}
449
+ * when more bytes are needed.
450
+ * @throws WebSocketProtocolError on RSV bits, unknown opcodes, fragmented
451
+ * or oversized control frames, unmasked client frames, or payload lengths
452
+ * above `Number.MAX_SAFE_INTEGER`.
358
453
  */
359
454
  export declare function parseFrame(buf: Uint8Array, opts?: {
360
455
  requireMask?: boolean;
@@ -363,6 +458,12 @@ export declare function parseFrame(buf: Uint8Array, opts?: {
363
458
  * Encode a single frame. By default the frame is emitted unmasked (server
364
459
  * → client). Pass `mask: true` to generate a client-style masked frame (used
365
460
  * mainly for testing).
461
+ *
462
+ * @param opts - Frame parts: `opcode` (required), `payload` (default empty),
463
+ * `fin` (default `true`), and `mask` (default `false`).
464
+ * @returns The wire-ready frame bytes (header + payload).
465
+ * @throws WebSocketProtocolError when a control-frame payload exceeds 125
466
+ * bytes; Error when masking is requested without Web Crypto.
366
467
  */
367
468
  export declare function encodeFrame(opts: {
368
469
  fin?: boolean;
@@ -370,9 +471,23 @@ export declare function encodeFrame(opts: {
370
471
  payload?: Uint8Array;
371
472
  mask?: boolean;
372
473
  }): Uint8Array;
373
- /** Encode a CLOSE frame payload (`uint16 code` + optional UTF-8 reason). */
474
+ /**
475
+ * Encode a CLOSE frame payload (`uint16 code` + optional UTF-8 reason).
476
+ *
477
+ * @param code - RFC 6455 close status code, written big-endian.
478
+ * @param reason - Optional human-readable reason. Defaults to `""`.
479
+ * @returns The 2+N byte close payload.
480
+ * @throws WebSocketProtocolError when the encoded reason exceeds 123 bytes.
481
+ */
374
482
  export declare function encodeClosePayload(code: number, reason?: string): Uint8Array;
375
- /** Decode a CLOSE frame payload. Returns `{ code: 1005, reason: "" }` when empty. */
483
+ /**
484
+ * Decode a CLOSE frame payload. Returns `{ code: 1005, reason: "" }` when empty.
485
+ *
486
+ * @param payload - Unmasked close-frame payload bytes.
487
+ * @returns The close `code` and decoded UTF-8 `reason`.
488
+ * @throws WebSocketProtocolError when the payload is exactly 1 byte or the
489
+ * reason is not valid UTF-8.
490
+ */
376
491
  export declare function decodeClosePayload(payload: Uint8Array): {
377
492
  code: number;
378
493
  reason: string;
@@ -400,10 +515,15 @@ export interface MessageEvent {
400
515
  }
401
516
  /** Callbacks supplied to a {@link FrameSink} by an adapter to receive decoded frames and protocol events. */
402
517
  export interface FrameSinkEvents {
518
+ /** A complete (possibly reassembled) text or binary message arrived. */
403
519
  onMessage(ev: MessageEvent): void;
520
+ /** A PING control frame arrived; `payload` is a copied buffer. */
404
521
  onPing(payload: Uint8Array): void;
522
+ /** A PONG control frame arrived; `payload` is a copied buffer. */
405
523
  onPong(payload: Uint8Array): void;
524
+ /** A CLOSE frame arrived; the sink stops processing further input. */
406
525
  onClose(code: number, reason: string): void;
526
+ /** An RFC 6455 violation was detected; the adapter should CLOSE(1002). */
407
527
  onProtocolError(err: WebSocketProtocolError): void;
408
528
  }
409
529
  /**
@@ -422,11 +542,24 @@ export declare class FrameSink {
422
542
  requireMask?: boolean;
423
543
  maxPayloadLength?: number;
424
544
  });
545
+ /**
546
+ * Feed raw socket bytes into the assembler. Complete frames trigger the
547
+ * configured callbacks; partial frames are buffered until more bytes
548
+ * arrive. No-op after a CLOSE frame or protocol error.
549
+ *
550
+ * @param chunk - The next bytes read from the socket.
551
+ */
425
552
  push(chunk: Uint8Array): void;
426
553
  private handle;
427
554
  private assertMessageSize;
428
555
  }
429
- /** Coerce arbitrary `send()` payloads to a `Uint8Array` + opcode pair. */
556
+ /**
557
+ * Coerce arbitrary `send()` payloads to a `Uint8Array` + opcode pair.
558
+ *
559
+ * @param data - A string (sent as TEXT) or any `ArrayBuffer`/view (sent as
560
+ * BINARY without copying when possible).
561
+ * @returns The `WS_OPCODE` to use and the payload bytes to frame.
562
+ */
430
563
  export declare function encodeSendPayload(data: string | ArrayBufferLike | ArrayBufferView): {
431
564
  opcode: number;
432
565
  payload: Uint8Array;
package/dist/websocket.js CHANGED
@@ -124,6 +124,11 @@ function declaredSchemaMaxBytes(schema) {
124
124
  * Resolve a user-supplied {@link WebSocketHandler} into the strict
125
125
  * {@link NormalizedWebSocketOptions} the adapter consumes. Applies defaults,
126
126
  * runs production safety checks, and throws on invalid values.
127
+ *
128
+ * @param handler The user-supplied handler whose option fields are validated.
129
+ * @param context Environment flags: `production` and `secureDefaults` gate the perMessageDeflate refusal.
130
+ * @returns The fully resolved options applied by the runtime adapter.
131
+ * @throws Error when a limit is not a positive integer, `allowedOrigins` is malformed, `perMessageDeflate` is enabled in production under secureDefaults, or `maxPayloadLength` exceeds the body schema maximum.
127
132
  */
128
133
  export function normalizeWebSocketOptions(handler, context) {
129
134
  const closeOnBackpressureLimit = handler.closeOnBackpressureLimit ?? true;
@@ -162,6 +167,8 @@ export function normalizeWebSocketOptions(handler, context) {
162
167
  * a `beforeUpgrade` handler to spend from the same shared buckets as HTTP
163
168
  * routes (for example, login and WebSocket session-establishment endpoints).
164
169
  *
170
+ * @param options The same {@link RateLimitOptions} accepted by the HTTP `rateLimit` middleware.
171
+ * @returns A `beforeUpgrade` hook that returns the 429 (or error) `Response` when the limit is exceeded, or `undefined` to allow the upgrade. Rate-limit headers are copied onto rejection responses.
165
172
  * @since 0.23.0
166
173
  */
167
174
  export function wsRateLimit(options) {
@@ -200,7 +207,12 @@ function copyWsRateLimitHeaders(headers, response) {
200
207
  response.headers.set(key, value);
201
208
  });
202
209
  }
203
- /** Helper for declaring a handler with full type-inference. */
210
+ /**
211
+ * Helper for declaring a handler with full type-inference.
212
+ *
213
+ * @param handler The {@link WebSocketHandler} to type-check; returned as-is.
214
+ * @returns The same handler object, with `P`/`S`/`TData` inferred.
215
+ */
204
216
  export function defineWebSocket(handler) {
205
217
  return handler;
206
218
  }
@@ -215,6 +227,14 @@ export class WebSocketRegistry {
215
227
  router = new Router();
216
228
  _size = 0;
217
229
  entries = [];
230
+ /**
231
+ * Register a WebSocket route.
232
+ *
233
+ * @param path Route path pattern (supports `:param` segments).
234
+ * @param handler Lifecycle handler for connections on this route.
235
+ * @param createState Per-upgrade state factory. Defaults to `() => ({})`.
236
+ * @param options Resolved limits; defaults to normalizing `handler` with dev-mode secure defaults.
237
+ */
218
238
  add(path, handler, createState = () => ({}), options = normalizeWebSocketOptions(handler, {
219
239
  production: false,
220
240
  secureDefaults: true,
@@ -224,6 +244,12 @@ export class WebSocketRegistry {
224
244
  this.entries.push(entry);
225
245
  this._size += 1;
226
246
  }
247
+ /**
248
+ * Match a request pathname against the registered WS routes.
249
+ *
250
+ * @param pathname URL pathname of the upgrade request.
251
+ * @returns The matched entry plus extracted params, or `undefined` when no route matches.
252
+ */
227
253
  find(pathname) {
228
254
  return this.router.find("GET", pathname);
229
255
  }
@@ -240,9 +266,19 @@ export class WebSocketRegistry {
240
266
  list() {
241
267
  return [...this.entries];
242
268
  }
269
+ /** Number of registered WebSocket routes. */
243
270
  get size() {
244
271
  return this._size;
245
272
  }
273
+ /**
274
+ * Aggregate the per-route options into a single set for runtimes (Bun) that
275
+ * take one server-wide WebSocket config: `closeOnBackpressureLimit` only when
276
+ * every route enables it, largest `backpressureLimit`/`maxPayloadLength`,
277
+ * smallest `idleTimeout`, and `perMessageDeflate` if any route enables it.
278
+ * Returns the secure defaults when no routes are registered.
279
+ *
280
+ * @returns The merged {@link NormalizedWebSocketOptions} for the whole app.
281
+ */
246
282
  runtimeOptions() {
247
283
  if (this.entries.length === 0) {
248
284
  return {
@@ -282,6 +318,10 @@ function getSubtle() {
282
318
  * `Sec-WebSocket-Key` per RFC 6455 §4.2.2:
283
319
  *
284
320
  * `base64(SHA1(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))`
321
+ *
322
+ * @param key - The client's `Sec-WebSocket-Key` header value.
323
+ * @returns The base64-encoded accept token for the 101 response.
324
+ * @throws Error when Web Crypto (`crypto.subtle`) is unavailable.
285
325
  */
286
326
  export async function computeAcceptKey(key) {
287
327
  const digest = await getSubtle().digest("SHA-1", enc.encode(key + WS_GUID));
@@ -290,6 +330,9 @@ export async function computeAcceptKey(key) {
290
330
  /**
291
331
  * Parse the offered subprotocols from a `Sec-WebSocket-Protocol` header.
292
332
  * Returns trimmed, non-empty tokens in client preference order.
333
+ *
334
+ * @param header - Raw header value; `null`/`undefined` yields an empty list.
335
+ * @returns The offered subprotocol tokens, most-preferred first.
293
336
  */
294
337
  export function parseSubprotocols(header) {
295
338
  if (!header)
@@ -304,6 +347,12 @@ const WS_TOKEN_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
304
347
  * Validate a server-selected subprotocol before it is written to the 101
305
348
  * response. RFC 6455 requires the value to be one of the client-offered
306
349
  * tokens; enforcing it also prevents accidental response-header injection.
350
+ *
351
+ * @param protocol - The subprotocol the server wants to select.
352
+ * @param offered - Tokens the client offered (from {@link parseSubprotocols}).
353
+ * @returns The validated `protocol`, unchanged.
354
+ * @throws WebSocketProtocolError when `protocol` is not a valid HTTP token
355
+ * or was not offered by the client.
307
356
  */
308
357
  export function validateSelectedSubprotocol(protocol, offered) {
309
358
  if (!WS_TOKEN_RE.test(protocol)) {
@@ -318,6 +367,12 @@ export function validateSelectedSubprotocol(protocol, offered) {
318
367
  * Validate the upgrade request headers and compute the accept key when
319
368
  * valid. This helper does **not** touch the wire — it only decides whether
320
369
  * the handshake should succeed and what the response key should be.
370
+ *
371
+ * @param headers - Header accessor for the upgrade request (any object with
372
+ * a `Headers`-style `get`).
373
+ * @returns `{ ok: true, acceptKey, protocols }` when the RFC 6455 handshake
374
+ * headers are valid, or `{ ok: false, status, reason }` describing the
375
+ * error response the adapter should send.
321
376
  */
322
377
  export async function validateUpgrade(headers) {
323
378
  const upgrade = headers.get("upgrade");
@@ -378,6 +433,10 @@ function isValidWebSocketKey(key) {
378
433
  * `{ ok: false, reason }` with a short human-readable reason suitable for
379
434
  * the upgrade-error body.
380
435
  *
436
+ * @param request - The upgrade request whose `Origin` header is checked.
437
+ * @param policy - The route's `allowedOrigins` value: `undefined` (allow
438
+ * all), `"same-origin"`, a string allowlist, or a predicate function.
439
+ * @returns `{ ok: true }` when permitted, otherwise `{ ok: false, reason }`.
381
440
  * @since 0.33.0
382
441
  */
383
442
  export function checkWebSocketOrigin(request, policy) {
@@ -438,6 +497,15 @@ export const FRAME_INCOMPLETE = Symbol("daloy.ws.frameIncomplete");
438
497
  * The parser unmasks payloads in-place when needed. The returned `payload`
439
498
  * is a subarray view over `buf`; copy it if you intend to retain it past
440
499
  * the next call.
500
+ *
501
+ * @param buf - Buffered socket bytes beginning at a frame boundary.
502
+ * @param opts - `requireMask: true` enforces the RFC 6455 rule that
503
+ * client-to-server frames are masked. Defaults to `{}` (not enforced).
504
+ * @returns The decoded {@link ParsedFrame}, or {@link FRAME_INCOMPLETE}
505
+ * when more bytes are needed.
506
+ * @throws WebSocketProtocolError on RSV bits, unknown opcodes, fragmented
507
+ * or oversized control frames, unmasked client frames, or payload lengths
508
+ * above `Number.MAX_SAFE_INTEGER`.
441
509
  */
442
510
  export function parseFrame(buf, opts = {}) {
443
511
  if (buf.length < 2)
@@ -514,6 +582,12 @@ export function parseFrame(buf, opts = {}) {
514
582
  * Encode a single frame. By default the frame is emitted unmasked (server
515
583
  * → client). Pass `mask: true` to generate a client-style masked frame (used
516
584
  * mainly for testing).
585
+ *
586
+ * @param opts - Frame parts: `opcode` (required), `payload` (default empty),
587
+ * `fin` (default `true`), and `mask` (default `false`).
588
+ * @returns The wire-ready frame bytes (header + payload).
589
+ * @throws WebSocketProtocolError when a control-frame payload exceeds 125
590
+ * bytes; Error when masking is requested without Web Crypto.
517
591
  */
518
592
  export function encodeFrame(opts) {
519
593
  const fin = opts.fin !== false;
@@ -579,7 +653,14 @@ export function encodeFrame(opts) {
579
653
  }
580
654
  return out;
581
655
  }
582
- /** Encode a CLOSE frame payload (`uint16 code` + optional UTF-8 reason). */
656
+ /**
657
+ * Encode a CLOSE frame payload (`uint16 code` + optional UTF-8 reason).
658
+ *
659
+ * @param code - RFC 6455 close status code, written big-endian.
660
+ * @param reason - Optional human-readable reason. Defaults to `""`.
661
+ * @returns The 2+N byte close payload.
662
+ * @throws WebSocketProtocolError when the encoded reason exceeds 123 bytes.
663
+ */
583
664
  export function encodeClosePayload(code, reason = "") {
584
665
  const reasonBytes = enc.encode(reason);
585
666
  if (reasonBytes.length > WS_MAX_CONTROL_PAYLOAD - 2) {
@@ -591,7 +672,14 @@ export function encodeClosePayload(code, reason = "") {
591
672
  out.set(reasonBytes, 2);
592
673
  return out;
593
674
  }
594
- /** Decode a CLOSE frame payload. Returns `{ code: 1005, reason: "" }` when empty. */
675
+ /**
676
+ * Decode a CLOSE frame payload. Returns `{ code: 1005, reason: "" }` when empty.
677
+ *
678
+ * @param payload - Unmasked close-frame payload bytes.
679
+ * @returns The close `code` and decoded UTF-8 `reason`.
680
+ * @throws WebSocketProtocolError when the payload is exactly 1 byte or the
681
+ * reason is not valid UTF-8.
682
+ */
595
683
  export function decodeClosePayload(payload) {
596
684
  if (payload.length === 0)
597
685
  return { code: WS_CLOSE_CODE.NO_STATUS_RECEIVED, reason: "" };
@@ -634,6 +722,13 @@ export class FrameSink {
634
722
  constructor(opts) {
635
723
  this.opts = opts;
636
724
  }
725
+ /**
726
+ * Feed raw socket bytes into the assembler. Complete frames trigger the
727
+ * configured callbacks; partial frames are buffered until more bytes
728
+ * arrive. No-op after a CLOSE frame or protocol error.
729
+ *
730
+ * @param chunk - The next bytes read from the socket.
731
+ */
637
732
  push(chunk) {
638
733
  if (this.closed)
639
734
  return;
@@ -738,7 +833,13 @@ export class FrameSink {
738
833
  }
739
834
  }
740
835
  // ---------- Helpers shared by adapters ----------
741
- /** Coerce arbitrary `send()` payloads to a `Uint8Array` + opcode pair. */
836
+ /**
837
+ * Coerce arbitrary `send()` payloads to a `Uint8Array` + opcode pair.
838
+ *
839
+ * @param data - A string (sent as TEXT) or any `ArrayBuffer`/view (sent as
840
+ * BINARY without copying when possible).
841
+ * @returns The `WS_OPCODE` to use and the payload bytes to frame.
842
+ */
742
843
  export function encodeSendPayload(data) {
743
844
  if (typeof data === "string") {
744
845
  return { opcode: WS_OPCODE.TEXT, payload: enc.encode(data) };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daloyjs/core",
3
- "version": "1.0.0-beta.6",
3
+ "version": "1.0.0-beta.7",
4
4
  "description": "DaloyJS is a runtime-portable, contract-first TypeScript web framework with built-in OpenAPI (Hey API), typed client generation, large-scale maintainability, and security-first defaults. Hono-grade portability, Elysia-grade DX, FastAPI-grade docs, Fastify-grade ops — distributed via pnpm.",
5
5
  "type": "module",
6
6
  "publishConfig": {