yinzerflow 0.6.14 → 0.8.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/CHANGELOG.md +39 -0
- package/docs/configuration/configuration.md +34 -65
- package/docs/core/logging.md +654 -347
- package/docs/core/websockets.md +343 -0
- package/index.d.ts +474 -73
- package/index.js +33 -21
- package/index.js.map +31 -22
- package/package.json +25 -28
package/index.d.ts
CHANGED
|
@@ -984,24 +984,26 @@ interface Response$1 {
|
|
|
984
984
|
}
|
|
985
985
|
/**
|
|
986
986
|
Time duration string format
|
|
987
|
-
|
|
988
|
-
Format: number followed by unit (s, m, h, d)
|
|
989
|
-
|
|
987
|
+
|
|
988
|
+
Format: number followed by unit (ms, s, m, h, d)
|
|
989
|
+
|
|
990
990
|
Units:
|
|
991
|
+
- ms: milliseconds
|
|
991
992
|
- s: seconds
|
|
992
993
|
- m: minutes
|
|
993
994
|
- h: hours
|
|
994
995
|
- d: days
|
|
995
|
-
|
|
996
|
+
|
|
996
997
|
@example
|
|
997
998
|
```typescript
|
|
998
|
-
'
|
|
999
|
-
'
|
|
1000
|
-
'
|
|
1001
|
-
'
|
|
999
|
+
'500ms' // 500 milliseconds
|
|
1000
|
+
'30s' // 30 seconds
|
|
1001
|
+
'15m' // 15 minutes
|
|
1002
|
+
'2h' // 2 hours
|
|
1003
|
+
'1d' // 1 day
|
|
1002
1004
|
```
|
|
1003
1005
|
*/
|
|
1004
|
-
export type TimeString = `${number}${"d" | "h" | "m" | "s"}`;
|
|
1006
|
+
export type TimeString = `${number}${"d" | "h" | "m" | "ms" | "s"}`;
|
|
1005
1007
|
export interface InternalCookieOptions {
|
|
1006
1008
|
/**
|
|
1007
1009
|
* Expiration date/time for the cookie
|
|
@@ -1454,6 +1456,156 @@ export interface Context<T extends HandlerCallbackGenerics = HandlerCallbackGene
|
|
|
1454
1456
|
* @see {@link HandlerCallbackGenerics} for custom typing options
|
|
1455
1457
|
*/
|
|
1456
1458
|
export type HandlerCallback<T extends HandlerCallbackGenerics = HandlerCallbackGenerics> = (ctx: Context<T>, error?: unknown) => Promise<T["response"] | void> | T["response"] | void;
|
|
1459
|
+
/**
|
|
1460
|
+
* User-facing WebSocket types for YinzerFlow.
|
|
1461
|
+
*
|
|
1462
|
+
* These types define the public API surface for WebSocket support:
|
|
1463
|
+
* route handlers, the per-connection `ws` object, upgrade requests,
|
|
1464
|
+
* route options, and backpressure configuration.
|
|
1465
|
+
*/
|
|
1466
|
+
// ============================================
|
|
1467
|
+
// WebSocket Connection Object
|
|
1468
|
+
// ============================================
|
|
1469
|
+
/**
|
|
1470
|
+
* A live WebSocket connection exposed to route handlers.
|
|
1471
|
+
*
|
|
1472
|
+
* @template T - Shape of per-socket data attached during upgrade
|
|
1473
|
+
*
|
|
1474
|
+
* @example
|
|
1475
|
+
* ```typescript
|
|
1476
|
+
* app.ws<{ userId: string }>('/feed', {
|
|
1477
|
+
* message(ws, data) {
|
|
1478
|
+
* ws.send(`Echo: ${data}`);
|
|
1479
|
+
* ws.publish('updates', data as string);
|
|
1480
|
+
* console.log(ws.data.userId, ws.readyState);
|
|
1481
|
+
* }
|
|
1482
|
+
* });
|
|
1483
|
+
* ```
|
|
1484
|
+
*/
|
|
1485
|
+
interface WebSocket$1<T = unknown> {
|
|
1486
|
+
/** Send a text or binary message to this client. */
|
|
1487
|
+
send: (data: Buffer | string) => void;
|
|
1488
|
+
/** Write a pre-encoded WebSocket frame directly (used internally by pub/sub broadcast). */
|
|
1489
|
+
sendRaw: (encodedFrame: Buffer) => void;
|
|
1490
|
+
/** Initiate a graceful close handshake. */
|
|
1491
|
+
close: (code?: number, reason?: string) => void;
|
|
1492
|
+
/** Send a ping frame (payload must be ≤125 bytes per RFC 6455 §5.5). */
|
|
1493
|
+
ping: (data?: Buffer) => void;
|
|
1494
|
+
/** Subscribe this connection to a named channel for pub/sub. */
|
|
1495
|
+
subscribe: (channel: string) => void;
|
|
1496
|
+
/** Unsubscribe this connection from a named channel. */
|
|
1497
|
+
unsubscribe: (channel: string) => void;
|
|
1498
|
+
/** Publish a message to all subscribers of a channel (excluding this connection). Returns recipient count. */
|
|
1499
|
+
publish: (channel: string, data: Buffer | string) => number;
|
|
1500
|
+
/** Check if this connection is subscribed to a channel. */
|
|
1501
|
+
isSubscribed: (channel: string) => boolean;
|
|
1502
|
+
/** Per-socket data attached during the upgrade handler. */
|
|
1503
|
+
readonly data: T;
|
|
1504
|
+
/** Current connection state (use wsReadyState constants for comparison). */
|
|
1505
|
+
readonly readyState: number;
|
|
1506
|
+
/** Remote IP address of the connected client. */
|
|
1507
|
+
readonly remoteAddress: string;
|
|
1508
|
+
/** Number of bytes queued in the socket's write buffer. */
|
|
1509
|
+
readonly bufferedAmount: number;
|
|
1510
|
+
}
|
|
1511
|
+
// ============================================
|
|
1512
|
+
// Upgrade Request
|
|
1513
|
+
// ============================================
|
|
1514
|
+
/**
|
|
1515
|
+
* Parsed HTTP upgrade request passed to the `upgrade` handler.
|
|
1516
|
+
* Contains everything needed to decide whether to accept the connection
|
|
1517
|
+
* and what per-socket data to attach.
|
|
1518
|
+
*/
|
|
1519
|
+
export interface WebSocketUpgradeRequest {
|
|
1520
|
+
/** HTTP headers from the upgrade request (lowercased keys). */
|
|
1521
|
+
headers: Record<string, string>;
|
|
1522
|
+
/** URL path of the upgrade request. */
|
|
1523
|
+
path: string;
|
|
1524
|
+
/** Parsed query string parameters. */
|
|
1525
|
+
query: Record<string, string>;
|
|
1526
|
+
/** Route parameters extracted from parameterized paths (e.g., `/ws/:room` → `{ room: 'lobby' }`). */
|
|
1527
|
+
params: Record<string, string>;
|
|
1528
|
+
/** Remote IP address of the client. */
|
|
1529
|
+
remoteAddress: string;
|
|
1530
|
+
}
|
|
1531
|
+
// ============================================
|
|
1532
|
+
// Route Handlers
|
|
1533
|
+
// ============================================
|
|
1534
|
+
/**
|
|
1535
|
+
* Handler functions for a WebSocket route.
|
|
1536
|
+
*
|
|
1537
|
+
* @template T - Shape of per-socket data returned from `upgrade`
|
|
1538
|
+
*
|
|
1539
|
+
* @example
|
|
1540
|
+
* ```typescript
|
|
1541
|
+
* app.ws<{ username: string }>('/chat', {
|
|
1542
|
+
* upgrade(req) {
|
|
1543
|
+
* const user = validateToken(req.headers.authorization);
|
|
1544
|
+
* return user ? { username: user.name } : false;
|
|
1545
|
+
* },
|
|
1546
|
+
* open(ws) {
|
|
1547
|
+
* ws.subscribe('chat');
|
|
1548
|
+
* },
|
|
1549
|
+
* message(ws, data, isBinary) {
|
|
1550
|
+
* ws.publish('chat', data as string);
|
|
1551
|
+
* },
|
|
1552
|
+
* close(ws, code, reason) {
|
|
1553
|
+
* // cleanup — unsubscribe is automatic
|
|
1554
|
+
* }
|
|
1555
|
+
* });
|
|
1556
|
+
* ```
|
|
1557
|
+
*/
|
|
1558
|
+
export interface WebSocketHandlers<T = unknown> {
|
|
1559
|
+
/**
|
|
1560
|
+
* Called before the handshake completes. Return per-socket data to accept,
|
|
1561
|
+
* or `false` to reject the connection with a 403 response.
|
|
1562
|
+
* If omitted, the connection is accepted with `undefined` as data.
|
|
1563
|
+
*/
|
|
1564
|
+
upgrade?: (request: WebSocketUpgradeRequest) => Promise<T | false> | T | false;
|
|
1565
|
+
/** Called when the connection is established and ready. */
|
|
1566
|
+
open?: (ws: WebSocket$1<T>) => void;
|
|
1567
|
+
/** Called when a complete message (text or binary) is received. */
|
|
1568
|
+
message?: (ws: WebSocket$1<T>, data: Buffer | string, isBinary: boolean) => void;
|
|
1569
|
+
/** Called when the connection is closed (after close handshake or on error). */
|
|
1570
|
+
close?: (ws: WebSocket$1<T>, code: number, reason: string) => void;
|
|
1571
|
+
/** Called when a socket error occurs. */
|
|
1572
|
+
error?: (ws: WebSocket$1<T>, error: Error) => void;
|
|
1573
|
+
/** Called when a backpressured socket's write buffer drains. */
|
|
1574
|
+
drain?: (ws: WebSocket$1<T>) => void;
|
|
1575
|
+
}
|
|
1576
|
+
// ============================================
|
|
1577
|
+
// Route Options
|
|
1578
|
+
// ============================================
|
|
1579
|
+
/**
|
|
1580
|
+
* Per-route WebSocket options that override global websocket configuration.
|
|
1581
|
+
*/
|
|
1582
|
+
export interface WebSocketRouteOptions {
|
|
1583
|
+
/** Maximum incoming message payload in bytes (default: global `websocket.maxPayloadLength`). */
|
|
1584
|
+
maxPayloadLength?: number;
|
|
1585
|
+
/** Seconds of inactivity before closing the connection (default: global `websocket.idleTimeout`). 0 = no timeout. */
|
|
1586
|
+
idleTimeout?: number;
|
|
1587
|
+
/** Backpressure handling for this route. */
|
|
1588
|
+
backpressure?: WebSocketBackpressureOptions;
|
|
1589
|
+
}
|
|
1590
|
+
/**
|
|
1591
|
+
* Backpressure configuration for WebSocket connections.
|
|
1592
|
+
*/
|
|
1593
|
+
export interface WebSocketBackpressureOptions {
|
|
1594
|
+
/**
|
|
1595
|
+
* Strategy when the client can't keep up with outgoing data:
|
|
1596
|
+
* - `'buffer'`: Queue messages up to `limit` bytes, then close the connection (safe default)
|
|
1597
|
+
* - `'drop'`: Silently discard messages (ideal for real-time data like trading quotes)
|
|
1598
|
+
* @default 'buffer'
|
|
1599
|
+
*/
|
|
1600
|
+
strategy: "buffer" | "drop";
|
|
1601
|
+
/** Maximum buffered bytes before the connection is closed (only applies to 'buffer' strategy). @default 1048576 (1MB) */
|
|
1602
|
+
limit?: number;
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* WebSocket message hook handler signature.
|
|
1606
|
+
* Used for `wsBeforeMessage` and `wsAfterMessage` global hooks.
|
|
1607
|
+
*/
|
|
1608
|
+
export type WebSocketMessageHook = (ws: WebSocket$1, data: Buffer | string, isBinary: boolean) => Promise<void> | void;
|
|
1457
1609
|
export type InternalGlobalHookOptions = {
|
|
1458
1610
|
routesToExclude: Array<string>;
|
|
1459
1611
|
} & {
|
|
@@ -1472,13 +1624,26 @@ export interface InternalHookRegistryImpl {
|
|
|
1472
1624
|
handler: HandlerCallback;
|
|
1473
1625
|
options?: InternalGlobalHookOptions;
|
|
1474
1626
|
}>;
|
|
1627
|
+
readonly _wsBeforeMessage: Set<{
|
|
1628
|
+
handler: WebSocketMessageHook;
|
|
1629
|
+
}>;
|
|
1630
|
+
readonly _wsAfterMessage: Set<{
|
|
1631
|
+
handler: WebSocketMessageHook;
|
|
1632
|
+
}>;
|
|
1475
1633
|
_onError: HandlerCallback;
|
|
1476
1634
|
_onNotFound: HandlerCallback;
|
|
1477
1635
|
_addBeforeRoutingHooks: (handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions) => void;
|
|
1478
1636
|
_addBeforeHooks: (handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions) => void;
|
|
1479
1637
|
_addAfterHooks: (handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions) => void;
|
|
1638
|
+
_addWsBeforeMessageHooks: (handlers: Array<WebSocketMessageHook>) => void;
|
|
1639
|
+
_addWsAfterMessageHooks: (handlers: Array<WebSocketMessageHook>) => void;
|
|
1480
1640
|
_addOnError: (handler: HandlerCallback) => void;
|
|
1481
1641
|
_addOnNotFound: (handler: HandlerCallback) => void;
|
|
1642
|
+
setLogger: (logger: {
|
|
1643
|
+
info: (...args: Array<unknown>) => void;
|
|
1644
|
+
warn: (...args: Array<unknown>) => void;
|
|
1645
|
+
error: (...args: Array<unknown>) => void;
|
|
1646
|
+
}) => void;
|
|
1482
1647
|
}
|
|
1483
1648
|
/**
|
|
1484
1649
|
* Internal route registry implementation for managing route storage and lookup.
|
|
@@ -1887,33 +2052,52 @@ export declare const logLevels: {
|
|
|
1887
2052
|
readonly error: "error";
|
|
1888
2053
|
readonly warn: "warn";
|
|
1889
2054
|
readonly info: "info";
|
|
2055
|
+
readonly debug: "debug";
|
|
1890
2056
|
};
|
|
1891
2057
|
/**
|
|
1892
2058
|
* YinzerFlow Logging Levels
|
|
1893
2059
|
*
|
|
1894
2060
|
* String-based logging levels for intuitive configuration:
|
|
1895
|
-
* - 'off': No logging at all
|
|
2061
|
+
* - 'off': No logging at all
|
|
1896
2062
|
* - 'error': Only errors
|
|
1897
|
-
* - 'warn': Warnings and errors (includes security warnings
|
|
2063
|
+
* - 'warn': Warnings and errors (includes security warnings)
|
|
1898
2064
|
* - 'info': Info, warnings, and errors (standard application logging)
|
|
2065
|
+
* - 'debug': All messages including verbose connection details
|
|
1899
2066
|
*
|
|
1900
|
-
*
|
|
2067
|
+
* Access logging is controlled separately via `logging.requests` config.
|
|
1901
2068
|
*/
|
|
1902
2069
|
export type LogLevel = CreateEnum<typeof logLevels>;
|
|
1903
2070
|
export interface Logger {
|
|
1904
2071
|
info: (...args: Array<unknown>) => void;
|
|
1905
2072
|
warn: (...args: Array<unknown>) => void;
|
|
1906
2073
|
error: (...args: Array<unknown>) => void;
|
|
2074
|
+
debug?: ((...args: Array<unknown>) => void) | undefined;
|
|
1907
2075
|
}
|
|
1908
2076
|
export interface LoggerConfig {
|
|
1909
|
-
|
|
2077
|
+
level?: LogLevel | undefined;
|
|
1910
2078
|
prefix?: string | undefined;
|
|
1911
|
-
|
|
1912
|
-
info: (...args: Array<unknown>) => void;
|
|
1913
|
-
warn: (...args: Array<unknown>) => void;
|
|
1914
|
-
error: (...args: Array<unknown>) => void;
|
|
1915
|
-
} | undefined;
|
|
2079
|
+
logLevel?: LogLevel | undefined;
|
|
1916
2080
|
}
|
|
2081
|
+
/**
|
|
2082
|
+
* Byte size string format
|
|
2083
|
+
*
|
|
2084
|
+
* Format: number followed by unit (b, kb, mb, gb)
|
|
2085
|
+
*
|
|
2086
|
+
* Units:
|
|
2087
|
+
* - b: bytes
|
|
2088
|
+
* - kb: kilobytes (1024 bytes)
|
|
2089
|
+
* - mb: megabytes (1048576 bytes)
|
|
2090
|
+
* - gb: gigabytes (1073741824 bytes)
|
|
2091
|
+
*
|
|
2092
|
+
* @example
|
|
2093
|
+
* ```typescript
|
|
2094
|
+
* '512b' // 512 bytes
|
|
2095
|
+
* '256kb' // 256 kilobytes
|
|
2096
|
+
* '1mb' // 1 megabyte
|
|
2097
|
+
* '2gb' // 2 gigabytes
|
|
2098
|
+
* ```
|
|
2099
|
+
*/
|
|
2100
|
+
export type ByteString = `${number}${"b" | "gb" | "kb" | "mb"}`;
|
|
1917
2101
|
export declare const rateLimitAlgorithm: {
|
|
1918
2102
|
readonly slidingWindowCounter: "sliding-window-counter";
|
|
1919
2103
|
};
|
|
@@ -2380,32 +2564,14 @@ export interface InternalServerOptions {
|
|
|
2380
2564
|
*/
|
|
2381
2565
|
host: string;
|
|
2382
2566
|
/**
|
|
2383
|
-
*
|
|
2567
|
+
* Logging configuration — controls app logger, access logs, and diagnostics.
|
|
2384
2568
|
*
|
|
2385
|
-
*
|
|
2386
|
-
*
|
|
2387
|
-
*
|
|
2388
|
-
*
|
|
2389
|
-
* ```typescript
|
|
2390
|
-
* const logger = createLogger({ prefix: 'APP', logLevel: 'info' });
|
|
2391
|
-
* new YinzerFlow({ logger });
|
|
2392
|
-
* ```
|
|
2393
|
-
*/
|
|
2394
|
-
logger?: Logger;
|
|
2395
|
-
/**
|
|
2396
|
-
* Network request/response logging (nginx-style logs)
|
|
2397
|
-
* Completely separate from application logs - simple on/off toggle
|
|
2398
|
-
* @default false
|
|
2569
|
+
* Three independent channels:
|
|
2570
|
+
* - **App logger**: Developer logs + framework errors/warnings (gated by `level`)
|
|
2571
|
+
* - **Access log**: nginx-style request/response lines (gated by `requests` on/off)
|
|
2572
|
+
* - **Diagnostics**: Framework health monitoring (gated by individual thresholds)
|
|
2399
2573
|
*/
|
|
2400
|
-
|
|
2401
|
-
/**
|
|
2402
|
-
* Custom logger for network logs (optional)
|
|
2403
|
-
* If provided, network logs will be routed to this logger instead of built-in formatting
|
|
2404
|
-
* Can be the same as the application logger or a different one
|
|
2405
|
-
* Useful for unified monitoring (e.g., Winston with Datadog transport for both app and network logs)
|
|
2406
|
-
* @default undefined (uses built-in network logging)
|
|
2407
|
-
*/
|
|
2408
|
-
networkLogger?: Logger;
|
|
2574
|
+
logging: InternalLoggingOptions;
|
|
2409
2575
|
/**
|
|
2410
2576
|
* Cross-Origin Resource Sharing configuration
|
|
2411
2577
|
*/
|
|
@@ -2441,6 +2607,117 @@ export interface InternalServerOptions {
|
|
|
2441
2607
|
* @default true
|
|
2442
2608
|
*/
|
|
2443
2609
|
gracefulShutdownTimeout: TimeString | number;
|
|
2610
|
+
/**
|
|
2611
|
+
* WebSocket configuration — controls max payload, idle timeout, connection limits, and backpressure.
|
|
2612
|
+
* Only takes effect when `app.ws()` routes are registered (zero overhead otherwise).
|
|
2613
|
+
*/
|
|
2614
|
+
websocket: InternalWebSocketOptions;
|
|
2615
|
+
}
|
|
2616
|
+
/**
|
|
2617
|
+
* Internal WebSocket Configuration
|
|
2618
|
+
*/
|
|
2619
|
+
export interface InternalWebSocketOptions {
|
|
2620
|
+
/** Maximum incoming message payload in bytes. @default 16777216 (16MB) */
|
|
2621
|
+
maxPayloadLength: number;
|
|
2622
|
+
/** Seconds of inactivity before closing. 0 = no timeout. @default 120 */
|
|
2623
|
+
idleTimeout: number;
|
|
2624
|
+
/** Maximum concurrent WebSocket connections per IP. @default 50 */
|
|
2625
|
+
maxConnectionsPerIp: number;
|
|
2626
|
+
/** Allowed origins for upgrade requests. Empty = allow all. @default [] */
|
|
2627
|
+
allowedOrigins: Array<string>;
|
|
2628
|
+
/** Backpressure handling when clients can't keep up. */
|
|
2629
|
+
backpressure: {
|
|
2630
|
+
/** 'buffer' (queue up to limit, safe default) or 'drop' (discard, for real-time data). @default 'buffer' */
|
|
2631
|
+
strategy: "buffer" | "drop";
|
|
2632
|
+
/** Max queued bytes before closing connection (buffer strategy only). @default 1048576 (1MB) */
|
|
2633
|
+
limit: number;
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
/**
|
|
2637
|
+
* Internal Logging Configuration
|
|
2638
|
+
* Controls three independent channels: app logger, access logs, and diagnostics.
|
|
2639
|
+
*/
|
|
2640
|
+
export interface InternalLoggingOptions {
|
|
2641
|
+
/**
|
|
2642
|
+
* Log level threshold — messages at this severity and above are output.
|
|
2643
|
+
* From least to most severe: debug → info → warn → error.
|
|
2644
|
+
* @default 'warn'
|
|
2645
|
+
*/
|
|
2646
|
+
level: LogLevel;
|
|
2647
|
+
/**
|
|
2648
|
+
* Log line prefix shown in brackets, e.g. [YINZER]
|
|
2649
|
+
* @default 'YINZER'
|
|
2650
|
+
*/
|
|
2651
|
+
prefix: string;
|
|
2652
|
+
/**
|
|
2653
|
+
* Enable Pittsburgh personality phrases in log output
|
|
2654
|
+
* @default true
|
|
2655
|
+
*/
|
|
2656
|
+
personality: boolean;
|
|
2657
|
+
/**
|
|
2658
|
+
* Enable nginx-style access logs (one line per request/response)
|
|
2659
|
+
* @default false
|
|
2660
|
+
*/
|
|
2661
|
+
requests: boolean;
|
|
2662
|
+
/**
|
|
2663
|
+
* Custom logger for application logs (optional)
|
|
2664
|
+
* If provided, app logs route to this logger instead of built-in formatting
|
|
2665
|
+
* @default undefined
|
|
2666
|
+
*/
|
|
2667
|
+
logger?: Logger;
|
|
2668
|
+
/**
|
|
2669
|
+
* Custom logger for access logs (optional)
|
|
2670
|
+
* If provided, access logs route to this logger instead of built-in formatting
|
|
2671
|
+
* @default undefined
|
|
2672
|
+
*/
|
|
2673
|
+
accessLogger?: Logger;
|
|
2674
|
+
/**
|
|
2675
|
+
* Framework diagnostics — health monitoring independent of app log level.
|
|
2676
|
+
* All thresholds default to false (disabled). Set a threshold to enable.
|
|
2677
|
+
*/
|
|
2678
|
+
diagnostics: InternalDiagnosticsOptions;
|
|
2679
|
+
}
|
|
2680
|
+
/**
|
|
2681
|
+
* Internal Diagnostics Configuration
|
|
2682
|
+
* Framework health monitoring that fires independently of the app log level.
|
|
2683
|
+
* Even with `level: 'off'`, diagnostics still fire when thresholds are exceeded.
|
|
2684
|
+
*/
|
|
2685
|
+
export interface InternalDiagnosticsOptions {
|
|
2686
|
+
/**
|
|
2687
|
+
* Log requests slower than this threshold
|
|
2688
|
+
* @default false (disabled)
|
|
2689
|
+
* @example '500ms' or 500 (milliseconds)
|
|
2690
|
+
*/
|
|
2691
|
+
slowRequests: TimeString | number | false;
|
|
2692
|
+
/**
|
|
2693
|
+
* Log responses larger than this threshold
|
|
2694
|
+
* @default false (disabled)
|
|
2695
|
+
* @example '1mb' or 1048576 (bytes)
|
|
2696
|
+
*/
|
|
2697
|
+
largeResponses: ByteString | number | false;
|
|
2698
|
+
/**
|
|
2699
|
+
* Log requests with bodies larger than this threshold
|
|
2700
|
+
* @default false (disabled)
|
|
2701
|
+
* @example '1mb' or 1048576 (bytes)
|
|
2702
|
+
*/
|
|
2703
|
+
largeRequests: ByteString | number | false;
|
|
2704
|
+
/**
|
|
2705
|
+
* Log periodic memory/heap usage at this interval
|
|
2706
|
+
* @default false (disabled)
|
|
2707
|
+
* @example '30s' or 30000 (milliseconds)
|
|
2708
|
+
*/
|
|
2709
|
+
memory: TimeString | number | false;
|
|
2710
|
+
/**
|
|
2711
|
+
* Log event loop lag exceeding this threshold
|
|
2712
|
+
* @default false (disabled)
|
|
2713
|
+
* @example '100ms' or 100 (milliseconds)
|
|
2714
|
+
*/
|
|
2715
|
+
eventLoop: TimeString | number | false;
|
|
2716
|
+
/**
|
|
2717
|
+
* Log rate limit hits
|
|
2718
|
+
* @default false (disabled)
|
|
2719
|
+
*/
|
|
2720
|
+
rateLimits: boolean;
|
|
2444
2721
|
}
|
|
2445
2722
|
export type HttpMethodHandlers = Record<Lowercase<keyof typeof httpMethod>, InternalSetupMethod>;
|
|
2446
2723
|
export type RouteGroupMethod = (prefix: string, callback: (group: RouteGroup) => void, options?: InternalRouteRegistryOptions) => RouteGroup;
|
|
@@ -2772,12 +3049,33 @@ export interface Setup extends HttpMethodHandlers {
|
|
|
2772
3049
|
* @see {@link HandlerCallback} for not-found handler function signature
|
|
2773
3050
|
*/
|
|
2774
3051
|
onNotFound: (handler: HandlerCallback) => void;
|
|
3052
|
+
/**
|
|
3053
|
+
* Register a WebSocket route.
|
|
3054
|
+
*
|
|
3055
|
+
* @template T - Per-socket data shape returned from the upgrade handler
|
|
3056
|
+
* @param path - URL path for WebSocket connections (e.g., '/ws', '/chat/:room')
|
|
3057
|
+
* @param handlers - Lifecycle handlers (upgrade, open, message, close, error, drain)
|
|
3058
|
+
* @param options - Per-route options that override global websocket config
|
|
3059
|
+
*/
|
|
3060
|
+
ws: <T = unknown>(path: string, handlers: WebSocketHandlers<T>, options?: WebSocketRouteOptions) => void;
|
|
3061
|
+
/** Register global hooks that run before each WebSocket message handler. */
|
|
3062
|
+
wsBeforeMessage: (handlers: Array<WebSocketMessageHook>) => void;
|
|
3063
|
+
/** Register global hooks that run after each WebSocket message handler. */
|
|
3064
|
+
wsAfterMessage: (handlers: Array<WebSocketMessageHook>) => void;
|
|
2775
3065
|
}
|
|
2776
3066
|
export type InternalSetupMethod = (path: string, handler: HandlerCallback<any>, options?: InternalRouteRegistryOptions) => void;
|
|
2777
3067
|
export interface InternalSetupImpl extends Setup {
|
|
2778
3068
|
readonly _configuration: InternalServerOptions;
|
|
2779
3069
|
readonly _routeRegistry: InternalRouteRegistryImpl;
|
|
2780
3070
|
readonly _hooks: InternalHookRegistryImpl;
|
|
3071
|
+
/** Per-instance logger. Set by `_configureLogging()` in YinzerFlow. */
|
|
3072
|
+
_log: {
|
|
3073
|
+
info: (...args: Array<unknown>) => void;
|
|
3074
|
+
warn: (...args: Array<unknown>) => void;
|
|
3075
|
+
error: (...args: Array<unknown>) => void;
|
|
3076
|
+
debug: (...args: Array<unknown>) => void;
|
|
3077
|
+
table: (data: unknown, ...additionalArgs: Array<unknown>) => void;
|
|
3078
|
+
};
|
|
2781
3079
|
}
|
|
2782
3080
|
declare class HookRegistryImpl implements InternalHookRegistryImpl {
|
|
2783
3081
|
readonly _beforeRouting: Set<{
|
|
@@ -2792,12 +3090,26 @@ declare class HookRegistryImpl implements InternalHookRegistryImpl {
|
|
|
2792
3090
|
handler: HandlerCallback;
|
|
2793
3091
|
options?: InternalGlobalHookOptions;
|
|
2794
3092
|
}>;
|
|
3093
|
+
readonly _wsBeforeMessage: Set<{
|
|
3094
|
+
handler: WebSocketMessageHook;
|
|
3095
|
+
}>;
|
|
3096
|
+
readonly _wsAfterMessage: Set<{
|
|
3097
|
+
handler: WebSocketMessageHook;
|
|
3098
|
+
}>;
|
|
2795
3099
|
_onError: HandlerCallback;
|
|
2796
3100
|
_onNotFound: HandlerCallback;
|
|
3101
|
+
private _logger;
|
|
3102
|
+
setLogger(logger: {
|
|
3103
|
+
info: (...args: Array<unknown>) => void;
|
|
3104
|
+
warn: (...args: Array<unknown>) => void;
|
|
3105
|
+
error: (...args: Array<unknown>) => void;
|
|
3106
|
+
}): void;
|
|
2797
3107
|
constructor();
|
|
2798
3108
|
_addBeforeRoutingHooks(handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions): void;
|
|
2799
3109
|
_addBeforeHooks(handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions): void;
|
|
2800
3110
|
_addAfterHooks(handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions): void;
|
|
3111
|
+
_addWsBeforeMessageHooks(handlers: Array<WebSocketMessageHook>): void;
|
|
3112
|
+
_addWsAfterMessageHooks(handlers: Array<WebSocketMessageHook>): void;
|
|
2801
3113
|
private _validateHandlersArray;
|
|
2802
3114
|
_addOnError(handler: HandlerCallback): void;
|
|
2803
3115
|
_addOnNotFound(handler: HandlerCallback): void;
|
|
@@ -2827,29 +3139,30 @@ declare class HookRegistryImpl implements InternalHookRegistryImpl {
|
|
|
2827
3139
|
* // Basic configuration with logging
|
|
2828
3140
|
* const app = new YinzerFlow({
|
|
2829
3141
|
* port: 8080,
|
|
2830
|
-
*
|
|
2831
|
-
* networkLogs: true
|
|
3142
|
+
* logging: { level: 'info', requests: true }
|
|
2832
3143
|
* });
|
|
2833
3144
|
*
|
|
2834
3145
|
* // Full configuration example
|
|
2835
3146
|
* const app = new YinzerFlow({
|
|
2836
3147
|
* port: 3000,
|
|
2837
3148
|
* host: '0.0.0.0',
|
|
2838
|
-
*
|
|
2839
|
-
*
|
|
2840
|
-
*
|
|
3149
|
+
* logging: {
|
|
3150
|
+
* level: 'debug',
|
|
3151
|
+
* personality: true,
|
|
3152
|
+
* requests: true,
|
|
3153
|
+
* logger: {
|
|
3154
|
+
* info: (message, ...args) => console.log(`[APP] ${message}`, ...args),
|
|
3155
|
+
* warn: (message, ...args) => console.warn(`[APP] ${message}`, ...args),
|
|
3156
|
+
* error: (message, ...args) => console.error(`[APP] ${message}`, ...args),
|
|
3157
|
+
* debug: (message, ...args) => console.debug(`[APP] ${message}`, ...args)
|
|
3158
|
+
* }
|
|
3159
|
+
* },
|
|
2841
3160
|
* cors: {
|
|
2842
3161
|
* enabled: true,
|
|
2843
3162
|
* origin: ['https://example.com', 'https://app.example.com'],
|
|
2844
3163
|
* methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
2845
3164
|
* headers: ['Content-Type', 'Authorization'],
|
|
2846
3165
|
* credentials: true
|
|
2847
|
-
* },
|
|
2848
|
-
* logger: {
|
|
2849
|
-
* info: (message, ...args) => console.log(`[APP] ${message}`, ...args),
|
|
2850
|
-
* warn: (message, ...args) => console.warn(`[APP] ${message}`, ...args),
|
|
2851
|
-
* error: (message, ...args) => console.error(`[APP] ${message}`, ...args),
|
|
2852
|
-
* debug: (message, ...args) => console.debug(`[APP] ${message}`, ...args)
|
|
2853
3166
|
* }
|
|
2854
3167
|
* });
|
|
2855
3168
|
* ```
|
|
@@ -2949,10 +3262,61 @@ declare class RouteRegistryImpl implements InternalRouteRegistryImpl {
|
|
|
2949
3262
|
private _storeParameterizedRoute;
|
|
2950
3263
|
private _findParameterizedRoute;
|
|
2951
3264
|
}
|
|
3265
|
+
declare const loggerBrand: unique symbol;
|
|
3266
|
+
declare const LOG_LEVELS: {
|
|
3267
|
+
readonly off: 0;
|
|
3268
|
+
readonly error: 1;
|
|
3269
|
+
readonly warn: 2;
|
|
3270
|
+
readonly info: 3;
|
|
3271
|
+
readonly debug: 4;
|
|
3272
|
+
};
|
|
3273
|
+
export declare const createLogger: (initialConfig?: LoggerConfig & {
|
|
3274
|
+
personality?: boolean;
|
|
3275
|
+
logger?: Logger | null | undefined;
|
|
3276
|
+
}) => {
|
|
3277
|
+
info: (...args: Array<unknown>) => void;
|
|
3278
|
+
warn: (...args: Array<unknown>) => void;
|
|
3279
|
+
error: (...args: Array<unknown>) => void;
|
|
3280
|
+
debug: (...args: Array<unknown>) => void;
|
|
3281
|
+
table: (data: unknown, ...additionalArgs: Array<unknown>) => void;
|
|
3282
|
+
levels: typeof LOG_LEVELS;
|
|
3283
|
+
[loggerBrand]: {
|
|
3284
|
+
level: string;
|
|
3285
|
+
prefix: string;
|
|
3286
|
+
personality: boolean;
|
|
3287
|
+
};
|
|
3288
|
+
};
|
|
3289
|
+
declare const log: {
|
|
3290
|
+
info: (...args: Array<unknown>) => void;
|
|
3291
|
+
warn: (...args: Array<unknown>) => void;
|
|
3292
|
+
error: (...args: Array<unknown>) => void;
|
|
3293
|
+
debug: (...args: Array<unknown>) => void;
|
|
3294
|
+
table: (data: unknown, ...additionalArgs: Array<unknown>) => void;
|
|
3295
|
+
levels: typeof LOG_LEVELS;
|
|
3296
|
+
[loggerBrand]: {
|
|
3297
|
+
level: string;
|
|
3298
|
+
prefix: string;
|
|
3299
|
+
personality: boolean;
|
|
3300
|
+
};
|
|
3301
|
+
};
|
|
3302
|
+
export interface WsRouteMatch {
|
|
3303
|
+
handlers: WebSocketHandlers;
|
|
3304
|
+
options: WebSocketRouteOptions | undefined;
|
|
3305
|
+
params: Record<string, string>;
|
|
3306
|
+
}
|
|
3307
|
+
declare class WebSocketRouter {
|
|
3308
|
+
private readonly _exactRoutes;
|
|
3309
|
+
private readonly _parameterizedRoutes;
|
|
3310
|
+
_register(path: string, handlers: WebSocketHandlers, options?: WebSocketRouteOptions): void;
|
|
3311
|
+
_match(path: string): WsRouteMatch | undefined;
|
|
3312
|
+
_hasRoutes(): boolean;
|
|
3313
|
+
}
|
|
2952
3314
|
declare class SetupImpl implements InternalSetupImpl {
|
|
2953
3315
|
readonly _configuration: InternalServerOptions;
|
|
2954
3316
|
readonly _routeRegistry: RouteRegistryImpl;
|
|
2955
3317
|
readonly _hooks: HookRegistryImpl;
|
|
3318
|
+
readonly _wsRouter: WebSocketRouter;
|
|
3319
|
+
_log: typeof log;
|
|
2956
3320
|
constructor(customConfiguration?: ServerOptions);
|
|
2957
3321
|
get(path: string, handler: HandlerCallback<any>, options?: InternalRouteRegistryOptions): void;
|
|
2958
3322
|
head(path: string, handler: HandlerCallback<any>, options?: InternalRouteRegistryOptions): void;
|
|
@@ -2967,13 +3331,24 @@ declare class SetupImpl implements InternalSetupImpl {
|
|
|
2967
3331
|
afterAll(handlers: Array<HandlerCallback<any>>, options?: InternalGlobalHookOptions): void;
|
|
2968
3332
|
onError(handler: HandlerCallback<any>): void;
|
|
2969
3333
|
onNotFound(handler: HandlerCallback<any>): void;
|
|
3334
|
+
ws<T = unknown>(path: string, handlers: WebSocketHandlers<T>, options?: WebSocketRouteOptions): void;
|
|
3335
|
+
wsBeforeMessage(handlers: Array<WebSocketMessageHook>): void;
|
|
3336
|
+
wsAfterMessage(handlers: Array<WebSocketMessageHook>): void;
|
|
2970
3337
|
}
|
|
2971
3338
|
export declare class YinzerFlow extends SetupImpl {
|
|
2972
3339
|
private _isListening;
|
|
2973
3340
|
private _server?;
|
|
2974
3341
|
private _globalRateLimiter?;
|
|
3342
|
+
private _diagnostics?;
|
|
2975
3343
|
private readonly _maxBufferSize;
|
|
3344
|
+
private _accessLog?;
|
|
3345
|
+
private _accessLogEnabled;
|
|
3346
|
+
private _wsConnections?;
|
|
3347
|
+
private _wsChannelManager?;
|
|
3348
|
+
private _wsSecurity?;
|
|
2976
3349
|
constructor(configuration?: ServerOptions);
|
|
3350
|
+
get log(): typeof YinzerFlow._log;
|
|
3351
|
+
private _configureLogging;
|
|
2977
3352
|
private _setupServer;
|
|
2978
3353
|
private _processRequest;
|
|
2979
3354
|
private _handleRequestError;
|
|
@@ -2982,6 +3357,17 @@ export declare class YinzerFlow extends SetupImpl {
|
|
|
2982
3357
|
private _looksLikeHttp;
|
|
2983
3358
|
private _parseContentLength;
|
|
2984
3359
|
private _handleConnection;
|
|
3360
|
+
private _handleConnectionData;
|
|
3361
|
+
private _handleHeaderPhase;
|
|
3362
|
+
private _handleWebSocketUpgrade;
|
|
3363
|
+
private _handleWebSocketUpgradeAsync;
|
|
3364
|
+
private _setupWsConnection;
|
|
3365
|
+
private _mergeWsConnectionOptions;
|
|
3366
|
+
private _wrapWsHandlers;
|
|
3367
|
+
private _parseHeadersMap;
|
|
3368
|
+
private _sendHttpError;
|
|
3369
|
+
publish(channel: string, data: Buffer | string): number;
|
|
3370
|
+
subscriberCount(channel: string): number;
|
|
2985
3371
|
listen(): Promise<void>;
|
|
2986
3372
|
close(): Promise<void>;
|
|
2987
3373
|
status(): {
|
|
@@ -2991,26 +3377,6 @@ export declare class YinzerFlow extends SetupImpl {
|
|
|
2991
3377
|
};
|
|
2992
3378
|
private _setupGracefulShutdown;
|
|
2993
3379
|
}
|
|
2994
|
-
declare const LOG_LEVELS: {
|
|
2995
|
-
readonly off: 0;
|
|
2996
|
-
readonly error: 1;
|
|
2997
|
-
readonly warn: 2;
|
|
2998
|
-
readonly info: 3;
|
|
2999
|
-
};
|
|
3000
|
-
export declare const createLogger: (initialConfig?: LoggerConfig) => {
|
|
3001
|
-
info: (...args: Array<unknown>) => void;
|
|
3002
|
-
warn: (...args: Array<unknown>) => void;
|
|
3003
|
-
error: (...args: Array<unknown>) => void;
|
|
3004
|
-
table: (data: unknown, ...additionalArgs: Array<unknown>) => void;
|
|
3005
|
-
levels: typeof LOG_LEVELS;
|
|
3006
|
-
};
|
|
3007
|
-
export declare const log: {
|
|
3008
|
-
info: (...args: Array<unknown>) => void;
|
|
3009
|
-
warn: (...args: Array<unknown>) => void;
|
|
3010
|
-
error: (...args: Array<unknown>) => void;
|
|
3011
|
-
table: (data: unknown, ...additionalArgs: Array<unknown>) => void;
|
|
3012
|
-
levels: typeof LOG_LEVELS;
|
|
3013
|
-
};
|
|
3014
3380
|
export declare const corsHook: (config: InternalCorsEnabledOptions) => HandlerCallback;
|
|
3015
3381
|
export declare const rateLimitHook: <T extends HandlerCallbackGenerics>(rateLimitOptions: RateLimitOptions) => HandlerCallback<T>;
|
|
3016
3382
|
export declare const colors: {
|
|
@@ -3022,5 +3388,40 @@ export declare const colors: {
|
|
|
3022
3388
|
readonly magenta: "\u001B[95m";
|
|
3023
3389
|
readonly gray: "\u001B[90m";
|
|
3024
3390
|
};
|
|
3391
|
+
export declare const wsOpcode: {
|
|
3392
|
+
readonly continuation: 0;
|
|
3393
|
+
readonly text: 1;
|
|
3394
|
+
readonly binary: 2;
|
|
3395
|
+
readonly close: 8;
|
|
3396
|
+
readonly ping: 9;
|
|
3397
|
+
readonly pong: 10;
|
|
3398
|
+
};
|
|
3399
|
+
export declare const wsCloseCode: {
|
|
3400
|
+
readonly normal: 1000;
|
|
3401
|
+
readonly goingAway: 1001;
|
|
3402
|
+
readonly protocolError: 1002;
|
|
3403
|
+
readonly unsupported: 1003;
|
|
3404
|
+
readonly noStatus: 1005;
|
|
3405
|
+
readonly abnormal: 1006;
|
|
3406
|
+
readonly invalidPayload: 1007;
|
|
3407
|
+
readonly policyViolation: 1008;
|
|
3408
|
+
readonly tooLarge: 1009;
|
|
3409
|
+
readonly missingExtension: 1010;
|
|
3410
|
+
readonly internalError: 1011;
|
|
3411
|
+
};
|
|
3412
|
+
export declare const wsReadyState: {
|
|
3413
|
+
readonly connecting: 0;
|
|
3414
|
+
readonly open: 1;
|
|
3415
|
+
readonly closing: 2;
|
|
3416
|
+
readonly closed: 3;
|
|
3417
|
+
};
|
|
3418
|
+
export declare const wsBackpressureStrategy: {
|
|
3419
|
+
readonly buffer: "buffer";
|
|
3420
|
+
readonly drop: "drop";
|
|
3421
|
+
};
|
|
3422
|
+
|
|
3423
|
+
export {
|
|
3424
|
+
WebSocket$1 as WebSocket,
|
|
3425
|
+
};
|
|
3025
3426
|
|
|
3026
3427
|
export {};
|