weifuwu 0.28.2 → 0.30.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 +394 -0
- package/dist/ai/provider.d.ts +45 -0
- package/dist/ai/stream.d.ts +13 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +178 -0
- package/dist/core/cookie.d.ts +36 -0
- package/dist/core/env.d.ts +69 -0
- package/dist/core/html.d.ts +34 -0
- package/dist/core/logger.d.ts +16 -0
- package/dist/core/router.d.ts +95 -0
- package/dist/core/serve.d.ts +36 -0
- package/dist/core/sse.d.ts +47 -0
- package/dist/core/trace.d.ts +95 -0
- package/dist/graphql.d.ts +16 -0
- package/dist/hub.d.ts +36 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +3387 -0
- package/dist/middleware/compress.d.ts +20 -0
- package/dist/middleware/cors.d.ts +25 -0
- package/dist/middleware/csrf.d.ts +31 -0
- package/dist/middleware/flash.d.ts +44 -0
- package/dist/middleware/health.d.ts +24 -0
- package/dist/middleware/helmet.d.ts +33 -0
- package/dist/middleware/i18n.d.ts +39 -0
- package/dist/middleware/rate-limit.d.ts +44 -0
- package/dist/middleware/request-id.d.ts +40 -0
- package/dist/middleware/static.d.ts +23 -0
- package/dist/middleware/theme.d.ts +31 -0
- package/dist/middleware/upload.d.ts +55 -0
- package/dist/middleware/validate.d.ts +32 -0
- package/dist/postgres/client.d.ts +4 -0
- package/dist/postgres/index.d.ts +3 -0
- package/dist/postgres/module.d.ts +12 -0
- package/dist/postgres/types.d.ts +42 -0
- package/dist/queue/cron.d.ts +9 -0
- package/dist/queue/index.d.ts +2 -0
- package/dist/queue/types.d.ts +61 -0
- package/dist/react/index.js +2573 -0
- package/dist/redis/client.d.ts +2 -0
- package/dist/redis/index.d.ts +2 -0
- package/dist/redis/types.d.ts +17 -0
- package/dist/test/test-utils.d.ts +193 -0
- package/dist/types.d.ts +82 -0
- package/package.json +31 -9
- package/index.d.ts +0 -8
- package/index.js +0 -26
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Context, Middleware } from '../types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Get all public environment variables (those prefixed with `WEIFUWU_PUBLIC_`),
|
|
4
|
+
* with the prefix stripped.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* const pub = getPublicEnv()
|
|
8
|
+
* // WEIFUWU_PUBLIC_API_URL=http://api.example.com → { API_URL: 'http://api.example.com' }
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare function getPublicEnv(): Record<string, string>;
|
|
12
|
+
declare module '../types.ts' {
|
|
13
|
+
interface Context {
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Whether this code is running from the compiled `dist/index.js` bundle.
|
|
19
|
+
* `false` when running TypeScript source directly (dev workflow in weifuwu repo).
|
|
20
|
+
*
|
|
21
|
+
* Used by modules that need to resolve package-internal files differently
|
|
22
|
+
* depending on whether they are compiled (published npm package) or raw TS.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isBundled(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Whether `NODE_ENV` is explicitly set to `'development'`.
|
|
27
|
+
*
|
|
28
|
+
* Used for dev-only features: HMR, livereload, React `createRoot` (not hydrate).
|
|
29
|
+
* **Not** the opposite of {@link isProd} — when `NODE_ENV` is unset, both return `false`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isDev(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Whether `NODE_ENV` is explicitly set to `'production'`.
|
|
34
|
+
*
|
|
35
|
+
* Used for production-only behavior: plain-text 404, suppressed warnings, minified output.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isProd(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Load environment variables from a `.env` file into `process.env`.
|
|
40
|
+
*
|
|
41
|
+
* Does **not** override existing `process.env` values.
|
|
42
|
+
* Supports quoted values and inline comments.
|
|
43
|
+
*
|
|
44
|
+
* @param path - Path to `.env` file (default: `'.env'` relative to cwd).
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { loadEnv } from 'weifuwu'
|
|
48
|
+
* loadEnv()
|
|
49
|
+
* console.log(process.env.PORT)
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function loadEnv(path?: string): void;
|
|
53
|
+
/**
|
|
54
|
+
* Public env middleware.
|
|
55
|
+
*
|
|
56
|
+
* Injects `ctx.env` with all environment variables prefixed with `WEIFUWU_PUBLIC_`,
|
|
57
|
+
* with the prefix stripped. Safe to expose to the client.
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { env } from 'weifuwu'
|
|
61
|
+
* app.use(env())
|
|
62
|
+
*
|
|
63
|
+
* // .env: WEIFUWU_PUBLIC_API_URL=https://api.example.com
|
|
64
|
+
* // ctx: ctx.env.API_URL === 'https://api.example.com'
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function env(): Middleware<Context, Context & {
|
|
68
|
+
env: Record<string, string>;
|
|
69
|
+
}>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe HTML rendering via tagged template literals.
|
|
3
|
+
*
|
|
4
|
+
* Auto-escapes interpolated values to prevent XSS.
|
|
5
|
+
* Use `raw()` for trusted HTML that should not be escaped.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { html, raw } from '@weifuwujs/core'
|
|
9
|
+
*
|
|
10
|
+
* html`<h1>${title}</h1>` // auto-escaped
|
|
11
|
+
* html`<div>${raw(trustedHtml)}</div>` // unescaped
|
|
12
|
+
* html`<ul>${items.map(i => html`<li>${i}</li>`)}</ul>` // arrays
|
|
13
|
+
* html`${isAdmin && html`<button>Admin</button>`}` // conditionals
|
|
14
|
+
* html`<div>${html`<span>nested</span>`}</div>` // nested (safe)
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
interface RawHtml {
|
|
18
|
+
_raw: string;
|
|
19
|
+
}
|
|
20
|
+
export type HtmlValue = string | number | boolean | null | undefined | HtmlValue[] | RawHtml;
|
|
21
|
+
/**
|
|
22
|
+
* Tagged template literal for safe HTML.
|
|
23
|
+
*
|
|
24
|
+
* Interpolated values are auto-escaped. Use {@link raw} to bypass escaping
|
|
25
|
+
* for trusted HTML. Nested `html` calls are safe (not double-escaped).
|
|
26
|
+
*/
|
|
27
|
+
export declare function html(strings: TemplateStringsArray, ...values: HtmlValue[]): string;
|
|
28
|
+
/**
|
|
29
|
+
* Bypass HTML escaping for trusted content.
|
|
30
|
+
*
|
|
31
|
+
* Can be used standalone or inside {@link html} tagged templates.
|
|
32
|
+
*/
|
|
33
|
+
export declare function raw(content: string): HtmlValue;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Middleware, Context } from '../types.ts';
|
|
2
|
+
export interface LoggerOptions {
|
|
3
|
+
/** 'short' = method + path + status + ms, 'combined' = short + query string, 'json' = structured stderr JSON */
|
|
4
|
+
format?: 'short' | 'combined' | 'json';
|
|
5
|
+
}
|
|
6
|
+
export interface LogEvent {
|
|
7
|
+
level: 'info' | 'warn' | 'error';
|
|
8
|
+
message: string;
|
|
9
|
+
method?: string;
|
|
10
|
+
path?: string;
|
|
11
|
+
status?: number;
|
|
12
|
+
elapsed_ms?: number;
|
|
13
|
+
traceId?: string;
|
|
14
|
+
timestamp?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function logger(options?: LoggerOptions): Middleware<Context, Context>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { WebSocket, Context, Handler, Middleware, ErrorHandler } from '../types.ts';
|
|
2
|
+
import { type IncomingMessage } from 'node:http';
|
|
3
|
+
import type { Duplex } from 'node:stream';
|
|
4
|
+
import { type Hub } from '../hub.ts';
|
|
5
|
+
declare module '../types.ts' {
|
|
6
|
+
interface Context {
|
|
7
|
+
ws: {
|
|
8
|
+
/** Per-connection state object */
|
|
9
|
+
state: Record<string, unknown>;
|
|
10
|
+
/** Send JSON to this connection */
|
|
11
|
+
json(data: unknown): void;
|
|
12
|
+
/** Join a room */
|
|
13
|
+
join(room: string): void;
|
|
14
|
+
/** Leave a room */
|
|
15
|
+
leave(room: string): void;
|
|
16
|
+
/** Broadcast to a room */
|
|
17
|
+
sendRoom(room: string, data: unknown): void;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export type WebSocketHandler = {
|
|
22
|
+
open?: (ws: WebSocket, ctx: Context) => void | Promise<void>;
|
|
23
|
+
message?: (ws: WebSocket, ctx: Context, data: string | Buffer) => void | Promise<void>;
|
|
24
|
+
close?: (ws: WebSocket, ctx: Context) => void | Promise<void>;
|
|
25
|
+
error?: (ws: WebSocket, ctx: Context, error: Error) => void | Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
type WsUpgradeHandler = (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
|
|
28
|
+
export declare class Router<T extends Context = Context> {
|
|
29
|
+
private root;
|
|
30
|
+
private wsRoot;
|
|
31
|
+
private globalMws;
|
|
32
|
+
private errorHandler?;
|
|
33
|
+
private _hasWildcard;
|
|
34
|
+
private _hub?;
|
|
35
|
+
private _wss?;
|
|
36
|
+
/** Track which ctx fields have been injected so far (for dependency checking). */
|
|
37
|
+
private _ctxFields;
|
|
38
|
+
private get wss();
|
|
39
|
+
private get hub();
|
|
40
|
+
/** Inject a custom hub (e.g. with Redis for cross-process broadcast). */
|
|
41
|
+
wsHub(hub: Hub): this;
|
|
42
|
+
/** Global middleware — accumulates types into Router<T>. */
|
|
43
|
+
use<Out extends Context>(mw: Middleware<Context, Out>): Router<T & Out>;
|
|
44
|
+
/**
|
|
45
|
+
* Mount a sub-router at the given path prefix.
|
|
46
|
+
* All routes from the sub-router are registered with the prefix.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const admin = new Router()
|
|
50
|
+
* admin.get('/dashboard', handler)
|
|
51
|
+
* app.mount('/admin', admin) // → GET /admin/dashboard
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
mount(path: string, router: Router<Context>): Router<T>;
|
|
55
|
+
/**
|
|
56
|
+
* Check a middleware's dependency metadata and emit warnings if
|
|
57
|
+
* required fields haven't been injected yet.
|
|
58
|
+
* Attach __meta to a middleware function:
|
|
59
|
+
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* mw.__meta = { injects: ['sql'], depends: ['session'] }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
private _checkMiddlewareMeta;
|
|
65
|
+
get(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
66
|
+
post(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
67
|
+
put(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
68
|
+
delete(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
69
|
+
patch(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
70
|
+
head(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
71
|
+
options(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
72
|
+
all(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
73
|
+
onError(handler: ErrorHandler<T>): Router<T>;
|
|
74
|
+
private _route;
|
|
75
|
+
/** Internal route registration — no type constraints (used by _mountRouter). */
|
|
76
|
+
private _routeImpl;
|
|
77
|
+
ws(path: string, ...args: [...Middleware<T, T>[], WebSocketHandler]): Router<T>;
|
|
78
|
+
handler(): Handler<T>;
|
|
79
|
+
/** Returns a human-readable list of all registered routes. Useful for debugging. */
|
|
80
|
+
routes(): string[];
|
|
81
|
+
private _collectRoutes;
|
|
82
|
+
private _collectWsRoutes;
|
|
83
|
+
websocketHandler(): WsUpgradeHandler;
|
|
84
|
+
private _mountRouter;
|
|
85
|
+
private _collect;
|
|
86
|
+
private _collectWs;
|
|
87
|
+
private splitPath;
|
|
88
|
+
private matchTrie;
|
|
89
|
+
private matchWsTrie;
|
|
90
|
+
private handleError;
|
|
91
|
+
private _notFoundResponse;
|
|
92
|
+
private handle;
|
|
93
|
+
private runChain;
|
|
94
|
+
}
|
|
95
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
2
|
+
import { Router } from './router.ts';
|
|
3
|
+
export interface ServeOptions {
|
|
4
|
+
port?: number;
|
|
5
|
+
hostname?: string;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
/** Max request body size in bytes. Default: 10MB. Set to 0 for unlimited. */
|
|
8
|
+
maxBodySize?: number;
|
|
9
|
+
/** Socket timeout in ms (inactivity). Default: 30_000. */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** Keep-Alive idle timeout in ms. Default: 5_000. */
|
|
12
|
+
keepAliveTimeout?: number;
|
|
13
|
+
/** Headers timeout in ms (must be > keepAliveTimeout). Default: 6_000. */
|
|
14
|
+
headersTimeout?: number;
|
|
15
|
+
shutdown?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface Server {
|
|
18
|
+
stop: (timeoutMs?: number) => Promise<void>;
|
|
19
|
+
/** Alias for `stop()`. Prefer this for consistency with other modules. */
|
|
20
|
+
close: (timeoutMs?: number) => Promise<void>;
|
|
21
|
+
readonly port: number;
|
|
22
|
+
readonly hostname: string;
|
|
23
|
+
ready: Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/** Default max body size: 10MB. Set maxBodySize: 0 for unlimited. */
|
|
26
|
+
export declare const DEFAULT_MAX_BODY: number;
|
|
27
|
+
export declare function readBody(req: IncomingMessage, maxSize?: number): Promise<Buffer>;
|
|
28
|
+
export declare function createRequest(req: IncomingMessage, body: Buffer): [Request, Record<string, string>];
|
|
29
|
+
export declare function sendResponse(res: ServerResponse, response: Response, opts?: {
|
|
30
|
+
traceId?: string | null;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
export declare function createTestServer(router: Router, options?: ServeOptions): Promise<{
|
|
33
|
+
server: Server;
|
|
34
|
+
url: string;
|
|
35
|
+
}>;
|
|
36
|
+
export declare function serve(router: Router, options?: ServeOptions): Server;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format an SSE message string with a named event type.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* formatSSE('ping', { ts: Date.now() })
|
|
6
|
+
* // "event: ping\ndata: {"ts":...}\n\n"
|
|
7
|
+
* ```
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatSSE(event: string, data: unknown): string;
|
|
10
|
+
/**
|
|
11
|
+
* Format an SSE message string with only a data line (no event type).
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* formatSSEData({ message: 'hello' })
|
|
15
|
+
* // "data: {"message":"hello"}\n\n"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatSSEData(data: unknown): string;
|
|
19
|
+
/** An SSE event to be sent via {@link createSSEStream}. */
|
|
20
|
+
export interface SSEEvent {
|
|
21
|
+
/** Event type (maps to `event:` field). */
|
|
22
|
+
event: string;
|
|
23
|
+
/** Event payload (serialized as JSON in `data:` field). */
|
|
24
|
+
data: unknown;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a Server-Sent Events (SSE) `Response` from an async iterable.
|
|
28
|
+
*
|
|
29
|
+
* Each item in the iterable is serialized as an SSE message:
|
|
30
|
+
* - If the item has a `.type` property → `event: {type}` + `data: {item}`
|
|
31
|
+
* - Otherwise → `data: {item}`
|
|
32
|
+
*
|
|
33
|
+
* Errors are sent as `event: error` messages. `AbortError` is silently ignored.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* app.get('/events', () => {
|
|
37
|
+
* async function* generate() {
|
|
38
|
+
* yield { type: 'ping', data: { ts: Date.now() } }
|
|
39
|
+
* }
|
|
40
|
+
* return createSSEStream(generate())
|
|
41
|
+
* })
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function createSSEStream(iterable: AsyncIterable<any>, opts?: {
|
|
45
|
+
headers?: Record<string, string>;
|
|
46
|
+
status?: number;
|
|
47
|
+
}): Response;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Context, Middleware } from '../types.ts';
|
|
2
|
+
declare module '../types.ts' {
|
|
3
|
+
interface Context {
|
|
4
|
+
trace: TraceInjected;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export interface TraceInjected {
|
|
8
|
+
/** Unique request identifier (from X-Request-ID header or auto-generated). */
|
|
9
|
+
requestId: string;
|
|
10
|
+
/** Unique trace identifier for the request. */
|
|
11
|
+
traceId: string;
|
|
12
|
+
/** Milliseconds elapsed since the trace started. */
|
|
13
|
+
elapsed: () => number;
|
|
14
|
+
/** Timestamp (ms) when the trace started. */
|
|
15
|
+
startTime: number;
|
|
16
|
+
}
|
|
17
|
+
export interface TraceContext {
|
|
18
|
+
/** Unique identifier for the current request trace. */
|
|
19
|
+
traceId: string;
|
|
20
|
+
/** Timestamp (ms since epoch) when the trace started. */
|
|
21
|
+
startTime: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the current request's trace ID.
|
|
25
|
+
* Returns `undefined` when called outside a request context (e.g. at startup).
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const traceId = currentTraceId()
|
|
29
|
+
* log.info({ traceId }, 'request started')
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function currentTraceId(): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Get the full current trace context ({ traceId, startTime }).
|
|
35
|
+
* Returns `undefined` outside a request.
|
|
36
|
+
*/
|
|
37
|
+
export declare function currentTrace(): TraceContext | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Run a function inside a trace context.
|
|
40
|
+
* Used internally by `serve()` for every incoming request.
|
|
41
|
+
* If `incomingTraceId` is provided (e.g. from an `X-Trace-Id` header) it is reused;
|
|
42
|
+
* otherwise a new UUID is generated.
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* const result = runWithTrace(req.headers.get('x-trace-id'), () => {
|
|
46
|
+
* return handleRequest(req)
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @param incomingTraceId - Optional trace ID from upstream. Pass `null` to auto-generate.
|
|
51
|
+
* @param fn - Function to execute within the trace scope.
|
|
52
|
+
* @returns The return value of `fn`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function runWithTrace<T>(incomingTraceId: string | null, fn: () => T): T;
|
|
55
|
+
/**
|
|
56
|
+
* Milliseconds elapsed since the current trace started.
|
|
57
|
+
* Returns `0` if called outside a request context.
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* app.use(async (req, ctx, next) => {
|
|
61
|
+
* const res = await next(req, ctx)
|
|
62
|
+
* console.log('handled in', traceElapsed(), 'ms')
|
|
63
|
+
* return res
|
|
64
|
+
* })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function traceElapsed(): number;
|
|
68
|
+
/** Options for {@link trace}. */
|
|
69
|
+
export interface TraceOptions {
|
|
70
|
+
/** Header name for request ID (default: `'X-Request-ID'`). */
|
|
71
|
+
header?: string;
|
|
72
|
+
/** Custom ID generator (default: `crypto.randomUUID`). */
|
|
73
|
+
generator?: () => string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Request tracing middleware.
|
|
77
|
+
*
|
|
78
|
+
* Injects `ctx.trace = { requestId, traceId, elapsed, startTime }`.
|
|
79
|
+
* Reads/writes `X-Request-ID` header. Combines the functionality of `requestId()`
|
|
80
|
+
* with the per-request tracing from `AsyncLocalStorage`.
|
|
81
|
+
*
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { trace } from 'weifuwu'
|
|
84
|
+
* app.use(trace())
|
|
85
|
+
*
|
|
86
|
+
* app.get('/', (req, ctx) => {
|
|
87
|
+
* console.log(ctx.trace.requestId) // 550e8400-e29b-...
|
|
88
|
+
* console.log(ctx.trace.traceId) // same as currentTraceId()
|
|
89
|
+
* console.log(ctx.trace.elapsed()) // ms since request start
|
|
90
|
+
* })
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function trace(options?: TraceOptions): Middleware<Context, Context & {
|
|
94
|
+
trace: TraceInjected;
|
|
95
|
+
}>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type GraphQLSchema } from 'graphql';
|
|
2
|
+
import type { Context } from './types.ts';
|
|
3
|
+
import { Router } from './core/router.ts';
|
|
4
|
+
export interface GraphQLOptions {
|
|
5
|
+
schema: string | GraphQLSchema;
|
|
6
|
+
rootValue?: any;
|
|
7
|
+
resolvers?: any;
|
|
8
|
+
context?: (req: Request, ctx: Context) => Record<string, any> | Promise<Record<string, any>>;
|
|
9
|
+
graphiql?: boolean;
|
|
10
|
+
/** Max query depth (nesting). Default: 10. Set 0 to disable. */
|
|
11
|
+
maxDepth?: number;
|
|
12
|
+
/** Execution timeout in ms. Default: 30_000. */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
export type GraphQLHandler = (req: Request, ctx: Context) => GraphQLOptions | Promise<GraphQLOptions>;
|
|
16
|
+
export declare function graphql(handler: GraphQLHandler): Router;
|
package/dist/hub.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Redis, WebSocket, Closeable } from './types.ts';
|
|
2
|
+
/** Options for {@link createHub}. */
|
|
3
|
+
export interface HubOptions {
|
|
4
|
+
/** Optional Redis client for cross-process pub/sub broadcast. */
|
|
5
|
+
redis?: Redis;
|
|
6
|
+
/** Key prefix for Redis channels (default: `'hub:'`). */
|
|
7
|
+
prefix?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* In-memory (and optionally Redis-backed) pub/sub hub for WebSocket rooms.
|
|
11
|
+
*
|
|
12
|
+
* Used internally by the WebSocket handler to implement `ctx.ws.join()` / `ctx.ws.sendRoom()`. */
|
|
13
|
+
export interface Hub extends Closeable {
|
|
14
|
+
/** Subscribe a WebSocket to a room/group. */
|
|
15
|
+
join(key: string, ws: WebSocket): void;
|
|
16
|
+
/** Unsubscribe a WebSocket from all rooms. */
|
|
17
|
+
leave(ws: WebSocket): void;
|
|
18
|
+
/** Send a JSON message to all members of a room. */
|
|
19
|
+
broadcast(key: string, data: unknown): void;
|
|
20
|
+
/** Close the hub, disconnect Redis subscribers, clear all rooms. */
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create a pub/sub hub for WebSocket room management.
|
|
25
|
+
*
|
|
26
|
+
* In-memory by default. Pass `redis` to enable cross-process broadcasting.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { createHub } from 'weifuwu'
|
|
30
|
+
*
|
|
31
|
+
* const hub = createHub()
|
|
32
|
+
* hub.join('room:general', ws)
|
|
33
|
+
* hub.broadcast('room:general', { type: 'chat', text: 'Hello' })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function createHub(opts?: HubOptions): Hub;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type { Context, Handler, Middleware, ErrorHandler, WsContext, WebSocket } from './types.ts';
|
|
2
|
+
export { HttpError } from './types.ts';
|
|
3
|
+
export { currentTraceId, currentTrace, runWithTrace, traceElapsed, trace } from './core/trace.ts';
|
|
4
|
+
export type { TraceContext, TraceInjected, TraceOptions } from './core/trace.ts';
|
|
5
|
+
export { loadEnv, isDev, isProd, isBundled, getPublicEnv, env } from './core/env.ts';
|
|
6
|
+
export { serve, createTestServer, DEFAULT_MAX_BODY } from './core/serve.ts';
|
|
7
|
+
export type { ServeOptions, Server } from './core/serve.ts';
|
|
8
|
+
export { Router } from './core/router.ts';
|
|
9
|
+
export type { WebSocketHandler } from './core/router.ts';
|
|
10
|
+
export { logger } from './core/logger.ts';
|
|
11
|
+
export type { LoggerOptions } from './core/logger.ts';
|
|
12
|
+
export { cors } from './middleware/cors.ts';
|
|
13
|
+
export type { CORSOptions } from './middleware/cors.ts';
|
|
14
|
+
export { serveStatic } from './middleware/static.ts';
|
|
15
|
+
export type { ServeStaticOptions } from './middleware/static.ts';
|
|
16
|
+
export { validate } from './middleware/validate.ts';
|
|
17
|
+
export type { ValidationSchemas, ValidateModule } from './middleware/validate.ts';
|
|
18
|
+
export { getCookies, setCookie, deleteCookie } from './core/cookie.ts';
|
|
19
|
+
export type { CookieOptions } from './core/cookie.ts';
|
|
20
|
+
export { upload } from './middleware/upload.ts';
|
|
21
|
+
export type { UploadOptions, UploadedFile, UploadModule } from './middleware/upload.ts';
|
|
22
|
+
export { rateLimit } from './middleware/rate-limit.ts';
|
|
23
|
+
export type { RateLimitOptions } from './middleware/rate-limit.ts';
|
|
24
|
+
export { compress } from './middleware/compress.ts';
|
|
25
|
+
export type { CompressOptions } from './middleware/compress.ts';
|
|
26
|
+
export { helmet } from './middleware/helmet.ts';
|
|
27
|
+
export type { HelmetOptions } from './middleware/helmet.ts';
|
|
28
|
+
export { requestId } from './middleware/request-id.ts';
|
|
29
|
+
export type { RequestIdOptions, RequestIdModule } from './middleware/request-id.ts';
|
|
30
|
+
export { createSSEStream, formatSSE, formatSSEData } from './core/sse.ts';
|
|
31
|
+
export type { SSEEvent } from './core/sse.ts';
|
|
32
|
+
export { testApp, TestApp, TestRequest, createTestDb, withTestDb } from './test/test-utils.ts';
|
|
33
|
+
export type { TestResponse, TestDb } from './test/test-utils.ts';
|
|
34
|
+
export { graphql } from './graphql.ts';
|
|
35
|
+
export type { GraphQLOptions, GraphQLHandler } from './graphql.ts';
|
|
36
|
+
export { postgres, MIGRATIONS_TABLE } from './postgres/index.ts';
|
|
37
|
+
export type { PostgresOptions, PostgresClient, PostgresInjected } from './postgres/types.ts';
|
|
38
|
+
export { redis } from './redis/index.ts';
|
|
39
|
+
export type { RedisOptions, RedisClient, RedisInjected } from './redis/types.ts';
|
|
40
|
+
export { createHub } from './hub.ts';
|
|
41
|
+
export type { Hub, HubOptions } from './hub.ts';
|
|
42
|
+
export { queue } from './queue/index.ts';
|
|
43
|
+
export type { QueueOptions, QueueJob, Queue, QueueInjected } from './queue/types.ts';
|
|
44
|
+
export { health } from './middleware/health.ts';
|
|
45
|
+
export type { HealthOptions } from './middleware/health.ts';
|
|
46
|
+
export { html, raw } from './core/html.ts';
|
|
47
|
+
export { theme } from './middleware/theme.ts';
|
|
48
|
+
export type { ThemeOptions, ThemeInjected, ThemeModule } from './middleware/theme.ts';
|
|
49
|
+
export { i18n } from './middleware/i18n.ts';
|
|
50
|
+
export type { I18nOptions, I18nInjected, I18nModule } from './middleware/i18n.ts';
|
|
51
|
+
export { flash } from './middleware/flash.ts';
|
|
52
|
+
export type { FlashOptions, FlashInjected, FlashModule } from './middleware/flash.ts';
|
|
53
|
+
export { csrf } from './middleware/csrf.ts';
|
|
54
|
+
export type { CsrfOptions, CsrfInjected, CsrfModule } from './middleware/csrf.ts';
|