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.
Files changed (46) hide show
  1. package/README.md +394 -0
  2. package/dist/ai/provider.d.ts +45 -0
  3. package/dist/ai/stream.d.ts +13 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +178 -0
  6. package/dist/core/cookie.d.ts +36 -0
  7. package/dist/core/env.d.ts +69 -0
  8. package/dist/core/html.d.ts +34 -0
  9. package/dist/core/logger.d.ts +16 -0
  10. package/dist/core/router.d.ts +95 -0
  11. package/dist/core/serve.d.ts +36 -0
  12. package/dist/core/sse.d.ts +47 -0
  13. package/dist/core/trace.d.ts +95 -0
  14. package/dist/graphql.d.ts +16 -0
  15. package/dist/hub.d.ts +36 -0
  16. package/dist/index.d.ts +54 -0
  17. package/dist/index.js +3387 -0
  18. package/dist/middleware/compress.d.ts +20 -0
  19. package/dist/middleware/cors.d.ts +25 -0
  20. package/dist/middleware/csrf.d.ts +31 -0
  21. package/dist/middleware/flash.d.ts +44 -0
  22. package/dist/middleware/health.d.ts +24 -0
  23. package/dist/middleware/helmet.d.ts +33 -0
  24. package/dist/middleware/i18n.d.ts +39 -0
  25. package/dist/middleware/rate-limit.d.ts +44 -0
  26. package/dist/middleware/request-id.d.ts +40 -0
  27. package/dist/middleware/static.d.ts +23 -0
  28. package/dist/middleware/theme.d.ts +31 -0
  29. package/dist/middleware/upload.d.ts +55 -0
  30. package/dist/middleware/validate.d.ts +32 -0
  31. package/dist/postgres/client.d.ts +4 -0
  32. package/dist/postgres/index.d.ts +3 -0
  33. package/dist/postgres/module.d.ts +12 -0
  34. package/dist/postgres/types.d.ts +42 -0
  35. package/dist/queue/cron.d.ts +9 -0
  36. package/dist/queue/index.d.ts +2 -0
  37. package/dist/queue/types.d.ts +61 -0
  38. package/dist/react/index.js +2573 -0
  39. package/dist/redis/client.d.ts +2 -0
  40. package/dist/redis/index.d.ts +2 -0
  41. package/dist/redis/types.d.ts +17 -0
  42. package/dist/test/test-utils.d.ts +193 -0
  43. package/dist/types.d.ts +82 -0
  44. package/package.json +31 -9
  45. package/index.d.ts +0 -8
  46. package/index.js +0 -26
@@ -0,0 +1,2 @@
1
+ import type { RedisOptions, RedisClient } from './types.ts';
2
+ export declare function redis(opts?: string | RedisOptions): RedisClient;
@@ -0,0 +1,2 @@
1
+ export { redis } from './client.ts';
2
+ export type { RedisOptions, RedisClient, RedisInjected } from './types.ts';
@@ -0,0 +1,17 @@
1
+ import type { Redis, RedisOptions as IORedisOptions, Context, Middleware, Closeable } from '../types.ts';
2
+ declare module '../types.ts' {
3
+ interface Context {
4
+ redis: Redis;
5
+ }
6
+ }
7
+ export type { Redis };
8
+ export type RedisOptions = IORedisOptions & {
9
+ url?: string;
10
+ };
11
+ export interface RedisInjected {
12
+ redis: Redis;
13
+ }
14
+ export interface RedisClient extends Middleware<Context, Context & RedisInjected>, Closeable {
15
+ redis: Redis;
16
+ close: () => Promise<void>;
17
+ }
@@ -0,0 +1,193 @@
1
+ import type { Context, Handler, SqlClient } from '../types.ts';
2
+ import { Router } from '../core/router.ts';
3
+ import { WebSocket as WSWebSocket } from 'ws';
4
+ export interface TestResponse {
5
+ readonly status: number;
6
+ readonly headers: Headers;
7
+ json<T = unknown>(): Promise<T>;
8
+ text(): Promise<string>;
9
+ }
10
+ export declare class TestRequest {
11
+ private headers;
12
+ private ctxMixin;
13
+ private bodyData;
14
+ private app;
15
+ private method;
16
+ private path;
17
+ constructor(app: TestApp, method: string, path: string);
18
+ /** Set a request header */
19
+ header(name: string, value: string): this;
20
+ /** Mix properties into ctx (simulating middleware injection) */
21
+ with(mixin: Partial<Context>): this;
22
+ /** Shortcut: set ctx.user */
23
+ withUser(user: unknown): this;
24
+ /** Shortcut: set ctx.tenant */
25
+ withTenant(tenant: {
26
+ id: string;
27
+ name: string;
28
+ role: string;
29
+ }): this;
30
+ /** Set JSON request body */
31
+ body(data: unknown): this;
32
+ /** Set raw text body */
33
+ rawBody(data: string): this;
34
+ /** Send the request and return the response */
35
+ send(): Promise<TestResponse>;
36
+ }
37
+ export declare class TestApp {
38
+ private router;
39
+ private wsServer;
40
+ private wsConnections;
41
+ constructor();
42
+ /**
43
+ * Register a WebSocket handler.
44
+ */
45
+ ws(path: string, handler: import('../core/router.ts').WebSocketHandler): this;
46
+ /** Get the raw Router (for advanced use). */
47
+ get _router(): Router;
48
+ /** Add global middleware */
49
+ use(mw: any): this;
50
+ /** Register a GET route — supports route-level middleware via spread args. */
51
+ get(path: string, ...args: any[]): this;
52
+ /** Register a POST route. */
53
+ post(path: string, ...args: any[]): this;
54
+ /** Register a PUT route. */
55
+ put(path: string, ...args: any[]): this;
56
+ /** Register a PATCH route. */
57
+ patch(path: string, ...args: any[]): this;
58
+ /** Register a DELETE route. */
59
+ delete(path: string, ...args: any[]): this;
60
+ /** Start building a GET request */
61
+ getReq(path: string): TestRequest;
62
+ /** Start building a POST request */
63
+ postReq(path: string): TestRequest;
64
+ /** Start building a PUT request */
65
+ putReq(path: string): TestRequest;
66
+ /** Start building a PATCH request */
67
+ patchReq(path: string): TestRequest;
68
+ /** Start building a DELETE request */
69
+ deleteReq(path: string): TestRequest;
70
+ /** Get the underlying handler (for advanced usage) */
71
+ handler(): Handler;
72
+ /** Start building a WebSocket connection to the given path. */
73
+ wsReq(path: string): TestWSRequest;
74
+ /**
75
+ * Internal: ensure HTTP server is running for WebSocket connections.
76
+ * Starts on a random port.
77
+ */
78
+ _ensureServer(): Promise<string>;
79
+ /**
80
+ * Internal: register a WS connection for cleanup.
81
+ */
82
+ _trackConnection(conn: TestWSConnection): void;
83
+ /**
84
+ * Cleanup all WebSocket connections and stop the server.
85
+ */
86
+ close(): Promise<void>;
87
+ }
88
+ /** Start building a WebSocket test connection. */
89
+ export declare class TestWSRequest {
90
+ private app;
91
+ private path;
92
+ private _timeout;
93
+ constructor(app: TestApp, path: string);
94
+ /** Set the timeout for operations (default: 5000ms). */
95
+ timeout(ms: number): this;
96
+ /**
97
+ * Connect to the WebSocket endpoint.
98
+ * Starts a real HTTP server (random port) if not already running.
99
+ */
100
+ connect(): Promise<TestWSConnection>;
101
+ }
102
+ /**
103
+ * A connected WebSocket for testing.
104
+ *
105
+ * ```ts
106
+ * const conn = await app.wsReq('/echo').connect()
107
+ * conn.send('hello')
108
+ * const msg = await conn.receive()
109
+ * assert.equal(msg, 'hello')
110
+ * conn.close()
111
+ * ```
112
+ */
113
+ export declare class TestWSConnection {
114
+ private ws;
115
+ private _timeout;
116
+ private messageQueue;
117
+ private resolveQueue;
118
+ private _closed;
119
+ constructor(ws: WSWebSocket, timeout?: number);
120
+ /** Send a text message. */
121
+ send(data: string): void;
122
+ /** Send a JSON message. */
123
+ json(data: unknown): void;
124
+ /**
125
+ * Wait for the next message. Returns the raw text.
126
+ * Throws on timeout or if the connection is closed.
127
+ */
128
+ receive(timeout?: number): Promise<string>;
129
+ /** Wait for the next message and parse as JSON. */
130
+ receiveJson<T = unknown>(): Promise<T>;
131
+ /**
132
+ * Assert that no message is received within the given silence period.
133
+ * Useful for verifying that something did NOT happen.
134
+ */
135
+ expectSilent(ms: number): Promise<void>;
136
+ /** Close the connection. */
137
+ close(): void;
138
+ /** Whether the connection is closed. */
139
+ get closed(): boolean;
140
+ }
141
+ /** Create a new test app */
142
+ export declare function testApp(): TestApp;
143
+ /**
144
+ * Result of createTestDb().
145
+ */
146
+ export interface TestDb {
147
+ /** Tagged-template SQL client connected to the test database. */
148
+ sql: SqlClient;
149
+ /** Connection URL of the test database. */
150
+ url: string;
151
+ /** Schema name used for this test session. */
152
+ schema: string;
153
+ /** Destroy the test database (drop schema). */
154
+ destroy: () => Promise<void>;
155
+ }
156
+ /**
157
+ * Create an isolated test database schema for integration testing.
158
+ *
159
+ * Uses PostgreSQL schemas for isolation — no separate database needed.
160
+ * Each call creates a unique schema under the same database.
161
+ *
162
+ * ```ts
163
+ * const db = await createTestDb()
164
+ * await db.sql`CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)`
165
+ * // ... run tests ...
166
+ * await db.destroy() // drops the schema
167
+ * ```
168
+ *
169
+ * Uses `TEST_DATABASE_URL` or `DATABASE_URL` env var.
170
+ */
171
+ export declare function createTestDb(options?: {
172
+ /** Database URL. Default: TEST_DATABASE_URL or DATABASE_URL. */
173
+ url?: string;
174
+ /** Schema name. Default: auto-generated 'test_<timestamp>_<random>'. */
175
+ schema?: string;
176
+ }): Promise<TestDb>;
177
+ /**
178
+ * Run a test callback within an isolated transaction that is rolled back
179
+ * after completion. This provides the fastest isolation — no cleanup needed.
180
+ *
181
+ * ```ts
182
+ * await withTestDb(async (sql) => {
183
+ * await sql`INSERT INTO users ...`
184
+ * // All changes are rolled back after this callback returns
185
+ * })
186
+ * ```
187
+ *
188
+ * @param optionsOrFn Either a URL string or options object, or the callback directly.
189
+ * @param fn Async callback receiving a tagged-template sql client.
190
+ */
191
+ export declare function withTestDb(optionsOrFn: string | {
192
+ url?: string;
193
+ } | ((sql: SqlClient) => Promise<void>), fn?: (sql: SqlClient) => Promise<void>): Promise<void>;
@@ -0,0 +1,82 @@
1
+ import type postgres from 'postgres';
2
+ /** Untyped postgres.js SQL client. Use typed `Sql<{ table: { col: type } }>` for schemas. */
3
+ export type SqlClient = postgres.Sql<Record<string, unknown>>;
4
+ /** Re-export for downstream usage. */
5
+ export type { Sql } from 'postgres';
6
+ /** Lightweight WebSocket interface for WS handler types (avoids external dep resolution). */
7
+ export interface WebSocket {
8
+ send(data: string | Buffer): void;
9
+ close(code?: number, reason?: string): void;
10
+ ping(data?: unknown): void;
11
+ readyState: number;
12
+ readonly OPEN: number;
13
+ readonly CLOSED: number;
14
+ readonly CONNECTING: number;
15
+ readonly CLOSING: number;
16
+ on(event: string, handler: (...args: unknown[]) => void): this;
17
+ off(event: string, handler: (...args: unknown[]) => void): this;
18
+ addEventListener(event: string, handler: (...args: unknown[]) => void): void;
19
+ removeEventListener(event: string, handler: (...args: unknown[]) => void): void;
20
+ }
21
+ export type { Redis, RedisOptions } from 'ioredis';
22
+ export interface WsContext {
23
+ /** Per-connection state object */
24
+ state: Record<string, unknown>;
25
+ /** Send JSON to this connection */
26
+ json(data: unknown): void;
27
+ /** Join a room */
28
+ join(room: string): void;
29
+ /** Leave a room */
30
+ leave(room: string): void;
31
+ /** Broadcast to a room */
32
+ sendRoom(room: string, data: unknown): void;
33
+ }
34
+ export interface Context {
35
+ params: Record<string, string>;
36
+ query: Record<string, string>;
37
+ mountPath?: string;
38
+ /** Currently authenticated user (set by user/auth middleware). */
39
+ user?: unknown;
40
+ /** Server-side data loaded for the current page (React SSR). */
41
+ loaderData?: Record<string, unknown>;
42
+ /** Public environment variables. */
43
+ env?: Record<string, string>;
44
+ [key: string]: unknown;
45
+ }
46
+ export type Handler<T extends Context = Context> = (req: Request, ctx: T) => Response | Promise<Response>;
47
+ /**
48
+ * Metadata for middleware dependency checking.
49
+ * Middleware factories attach this for runtime validation.
50
+ */
51
+ export interface MiddlewareMeta {
52
+ /** Fields this middleware injects into ctx. */
53
+ injects: string[];
54
+ /** Fields this middleware depends on (must be injected earlier). */
55
+ depends: string[];
56
+ }
57
+ export type Middleware<In extends Context = Context, Out extends In = In> = {
58
+ (req: Request, ctx: In, next: Handler<Out>): Response | Promise<Response>;
59
+ __meta?: MiddlewareMeta;
60
+ };
61
+ export type ErrorHandler<T extends Context = Context> = (error: Error, req: Request, ctx: T) => Response | Promise<Response>;
62
+ /**
63
+ * Interface for resources that require explicit cleanup (connections, pools, timers).
64
+ * All stateful modules implement this.
65
+ */
66
+ export interface Closeable {
67
+ /** Release all resources. Call once when shutting down. */
68
+ close(): Promise<void>;
69
+ }
70
+ /**
71
+ * HTTP error with an explicit status code.
72
+ * Throw from a handler or middleware to return a non-200 response.
73
+ *
74
+ * ```ts
75
+ * if (!resource) throw new HttpError('Not found', 404)
76
+ * serve() catches it and returns the status code.
77
+ * ```
78
+ */
79
+ export declare class HttpError extends Error {
80
+ status: number;
81
+ constructor(message: string, status: number);
82
+ }
package/package.json CHANGED
@@ -1,19 +1,41 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.28.2",
5
- "description": "Web-standard HTTP microframework — alias for @weifuwujs/core",
4
+ "version": "0.30.0",
5
+ "description": "Web-standard HTTP microframework for Node.js (req, ctx) => Response",
6
6
  "exports": {
7
7
  ".": {
8
- "types": "./index.d.ts",
9
- "default": "./index.js"
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
10
  }
11
11
  },
12
+ "files": [
13
+ "dist/",
14
+ "README.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "node scripts/build.mjs",
18
+ "prepublishOnly": "npm run build && tsc --emitDeclarationOnly --outdir dist",
19
+ "typecheck": "tsc --noEmit",
20
+ "test": "node --test 'src/test/**/*.test.ts'",
21
+ "test:coverage": "node --experimental-test-coverage --test 'src/test/**/*.test.ts'",
22
+ "release": "node scripts/release.mjs",
23
+ "release:dry": "node scripts/release.mjs --dry-run"
24
+ },
12
25
  "dependencies": {
13
- "@weifuwujs/core": "*"
26
+ "@graphql-tools/schema": "^10",
27
+ "graphql": "^16",
28
+ "ioredis": "^5.11.0",
29
+ "postgres": "^3.4.9",
30
+ "ws": "^8",
31
+ "zod": "^4.4.3"
14
32
  },
15
- "files": [
16
- "index.js",
17
- "index.d.ts"
18
- ]
33
+ "devDependencies": {
34
+ "@types/node": "^25",
35
+ "@types/ws": "^8",
36
+ "@eslint/js": "^10.0.1",
37
+ "globals": "^17.7.0",
38
+ "typescript-eslint": "^8.62.1"
39
+ },
40
+ "sideEffects": false
19
41
  }
package/index.d.ts DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * @deprecated Use `import { ... } from '@weifuwujs/core'` instead.
3
- *
4
- * Migration:
5
- * `weifuwu` → `@weifuwujs/core` for framework core
6
- * `weifuwu` → `@weifuwujs/react` for React SSR
7
- */
8
- export * from '@weifuwujs/core'
package/index.js DELETED
@@ -1,26 +0,0 @@
1
- /**
2
- * @deprecated weifuwu has been split into scoped packages.
3
- *
4
- * Update your imports:
5
- * import { serve } from 'weifuwu' → import { serve } from '@weifuwujs/core'
6
- * import { ssr, theme } from 'weifuwu' → import { ssr, theme } from '@weifuwujs/react'
7
- *
8
- * The 'weifuwu' package is a backward-compatibility alias and
9
- * will receive no new features. Migrate to '@weifuwujs/core'.
10
- */
11
-
12
- if (!process.env.WEIFUWU_SUPPRESS_DEPRECATION) {
13
- process.emitWarning(
14
- [
15
- `'weifuwu' is deprecated. Use scoped packages instead:`,
16
- ` import { serve } from 'weifuwu' → import { serve } from '@weifuwujs/core'`,
17
- ` import { ssr } from 'weifuwu' → import { ssr } from '@weifuwujs/react'`,
18
- ` import { aiProvider } from 'weifuwu' → npm install ai (use vercel/ai-sdk directly)`,
19
- `Set WEIFUWU_SUPPRESS_DEPRECATION=1 to silence this warning.`,
20
- ].join('\n'),
21
- 'DeprecationWarning',
22
- 'WEIFUWU_DEP001',
23
- )
24
- }
25
-
26
- export * from '@weifuwujs/core'