weifuwu 0.24.3 → 0.25.1
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 +225 -0
- package/dist/iii/client.d.ts +1 -1
- package/dist/iii/register-worker.d.ts +0 -1
- package/dist/iii/types.d.ts +19 -33
- package/dist/iii/ws.d.ts +0 -7
- package/dist/index.d.ts +6 -1
- package/dist/index.js +1007 -537
- package/dist/mcp.d.ts +34 -0
- package/dist/notifier/client.d.ts +2 -0
- package/dist/notifier/index.d.ts +2 -0
- package/dist/notifier/types.d.ts +105 -0
- package/dist/opencode/rest.d.ts +2 -1
- package/dist/opencode/ws.d.ts +2 -2
- package/dist/queue/types.d.ts +0 -1
- package/dist/rate-limit.d.ts +10 -5
- package/dist/redis/client.d.ts +2 -0
- package/dist/redis/index.d.ts +2 -3
- package/dist/router.d.ts +30 -0
- package/dist/serve.d.ts +1 -1
- package/dist/session.d.ts +20 -0
- package/dist/test-utils.d.ts +80 -2
- package/dist/types.d.ts +13 -0
- package/dist/user/client.d.ts +6 -1
- package/dist/user/types.d.ts +21 -0
- package/dist/validate.d.ts +16 -0
- package/package.json +1 -1
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface MCPClientOptions {
|
|
2
|
+
/** Command to spawn (e.g. 'npx', 'node', 'uvx'). */
|
|
3
|
+
command: string;
|
|
4
|
+
/** Arguments passed to the command. */
|
|
5
|
+
args?: string[];
|
|
6
|
+
/** Environment variables (merged with process.env). */
|
|
7
|
+
env?: Record<string, string>;
|
|
8
|
+
/** How long to wait for handshake/response (ms). Default: 15_000. */
|
|
9
|
+
timeout?: number;
|
|
10
|
+
/** Max tool response body size in bytes. Default: 10MB. */
|
|
11
|
+
maxResponseSize?: number;
|
|
12
|
+
}
|
|
13
|
+
/** A tool definition from an MCP server. */
|
|
14
|
+
export interface MCPToolDef {
|
|
15
|
+
name: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
inputSchema?: {
|
|
18
|
+
type: 'object';
|
|
19
|
+
properties?: Record<string, unknown>;
|
|
20
|
+
required?: string[];
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** MCP client — spawns and manages a single MCP server subprocess. */
|
|
24
|
+
export interface MCPClient {
|
|
25
|
+
/** Fetch tool definitions from the server and return AI SDK Tool objects. */
|
|
26
|
+
getTools(): Promise<Record<string, unknown>>;
|
|
27
|
+
/** Refresh tool definitions (re-call tools/list). */
|
|
28
|
+
refresh(): Promise<void>;
|
|
29
|
+
/** Call a tool by name. Returns the raw result from the MCP server. */
|
|
30
|
+
callTool(name: string, args: unknown): Promise<unknown>;
|
|
31
|
+
/** Shutdown the MCP server and release resources. */
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export declare function mcpClient(options: MCPClientOptions): MCPClient;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { Context, Middleware, Closeable } from '../types.ts';
|
|
2
|
+
import type { Mailer } from '../mailer.ts';
|
|
3
|
+
import type { Hub } from '../hub.ts';
|
|
4
|
+
import type { SqlClient } from '../vendor.ts';
|
|
5
|
+
declare module '../types.ts' {
|
|
6
|
+
interface Context {
|
|
7
|
+
notifier: Notifier;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** Shape injected into ctx when notifier middleware is active. */
|
|
11
|
+
export interface NotifierInjected {
|
|
12
|
+
notifier: Notifier;
|
|
13
|
+
}
|
|
14
|
+
/** Configuration for the notifier module. */
|
|
15
|
+
export interface NotifierOptions {
|
|
16
|
+
/** SQL client (PostgreSQL) for persistent notifications. */
|
|
17
|
+
sql: SqlClient;
|
|
18
|
+
/** Optional mailer for email channel. */
|
|
19
|
+
mailer?: Mailer;
|
|
20
|
+
/** Optional hub for WebSocket push channel. */
|
|
21
|
+
hub?: Hub;
|
|
22
|
+
/** Default sender name for email (default: system name). */
|
|
23
|
+
fromName?: string;
|
|
24
|
+
/** Table name for notifications (default: '_notifications'). */
|
|
25
|
+
table?: string;
|
|
26
|
+
/** Max notification list page size (default: 50). */
|
|
27
|
+
pageSize?: number;
|
|
28
|
+
}
|
|
29
|
+
/** A notification message. */
|
|
30
|
+
export interface NotifyMessage {
|
|
31
|
+
/** Notification title. */
|
|
32
|
+
title: string;
|
|
33
|
+
/** Notification body text. */
|
|
34
|
+
body?: string;
|
|
35
|
+
/** Optional action URL. */
|
|
36
|
+
actionUrl?: string;
|
|
37
|
+
/** Optional action button text. */
|
|
38
|
+
actionText?: string;
|
|
39
|
+
/** Notification type for categorization (default: 'default'). */
|
|
40
|
+
type?: string;
|
|
41
|
+
/** Arbitrary metadata (JSON object). */
|
|
42
|
+
metadata?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
/** A notification record from the database. */
|
|
45
|
+
export interface Notification {
|
|
46
|
+
id: number;
|
|
47
|
+
user_id: number;
|
|
48
|
+
title: string;
|
|
49
|
+
body: string;
|
|
50
|
+
action_url: string | null;
|
|
51
|
+
action_text: string | null;
|
|
52
|
+
type: string;
|
|
53
|
+
metadata: Record<string, unknown>;
|
|
54
|
+
read_at: string | null;
|
|
55
|
+
created_at: string;
|
|
56
|
+
}
|
|
57
|
+
/** Supported notification channels. */
|
|
58
|
+
export type NotifyChannel = 'inbox' | 'email' | 'ws';
|
|
59
|
+
/** User's channel preferences for a notification type. */
|
|
60
|
+
export interface NotifyPreferences {
|
|
61
|
+
/** Which channels are enabled. Default: ['inbox']. */
|
|
62
|
+
channels: NotifyChannel[];
|
|
63
|
+
}
|
|
64
|
+
/** The notifier API injected into ctx. */
|
|
65
|
+
export interface Notifier extends Closeable {
|
|
66
|
+
/**
|
|
67
|
+
* Send a notification to a specific user.
|
|
68
|
+
* Routes through the user's channel preferences automatically.
|
|
69
|
+
*/
|
|
70
|
+
send(to: {
|
|
71
|
+
userId: number;
|
|
72
|
+
email?: string;
|
|
73
|
+
}, message: NotifyMessage): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Send a system-wide notification to all users.
|
|
76
|
+
* Useful for announcements.
|
|
77
|
+
*/
|
|
78
|
+
broadcast(message: NotifyMessage): Promise<void>;
|
|
79
|
+
/** Get user's unread notification count. */
|
|
80
|
+
unreadCount(userId: number): Promise<number>;
|
|
81
|
+
/** Mark specific notifications as read. If no ids given, mark all as read. */
|
|
82
|
+
markRead(userId: number, notificationIds?: number[]): Promise<void>;
|
|
83
|
+
/** List notifications for a user, newest first. */
|
|
84
|
+
list(userId: number, opts?: {
|
|
85
|
+
limit?: number;
|
|
86
|
+
offset?: number;
|
|
87
|
+
unreadOnly?: boolean;
|
|
88
|
+
}): Promise<Notification[]>;
|
|
89
|
+
/** Get or set user's notification channel preferences. */
|
|
90
|
+
getPreferences(userId: number): Promise<NotifyPreferences>;
|
|
91
|
+
setPreferences(userId: number, prefs: NotifyPreferences): Promise<void>;
|
|
92
|
+
/** Count total notifications for a user. */
|
|
93
|
+
count(userId: number, unreadOnly?: boolean): Promise<number>;
|
|
94
|
+
/** Clean up old notifications (older than days). */
|
|
95
|
+
clean(days: number): Promise<number>;
|
|
96
|
+
/** Create the notifications and preferences tables. Safe to call multiple times. */
|
|
97
|
+
migrate(): Promise<void>;
|
|
98
|
+
/** Release resources. */
|
|
99
|
+
close(): Promise<void>;
|
|
100
|
+
}
|
|
101
|
+
/** Notifier middleware type. */
|
|
102
|
+
export interface NotifierMiddleware extends Middleware<Context, Context & NotifierInjected>, Notifier {
|
|
103
|
+
/** Alias for backward compatibility. */
|
|
104
|
+
middleware: () => Middleware<Context, Context & NotifierInjected>;
|
|
105
|
+
}
|
package/dist/opencode/rest.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Router } from '../router.ts';
|
|
2
2
|
import type { LanguageModel } from 'ai';
|
|
3
|
+
import type { SqlClient } from '../vendor.ts';
|
|
3
4
|
import type { SkillDef, SkillRegistry, OpencodePermissions, PendingQuestion } from './types.ts';
|
|
4
5
|
interface RestDeps {
|
|
5
|
-
sql:
|
|
6
|
+
sql: SqlClient;
|
|
6
7
|
model: LanguageModel;
|
|
7
8
|
workspace: string;
|
|
8
9
|
systemPrompt?: string;
|
package/dist/opencode/ws.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { WebSocket } from '../vendor.ts';
|
|
1
|
+
import type { WebSocket, SqlClient } from '../vendor.ts';
|
|
2
2
|
import type { LanguageModel } from 'ai';
|
|
3
3
|
import type { Context } from '../types.ts';
|
|
4
4
|
import type { PendingQuestion, SkillDef, SkillRegistry, OpencodePermissions } from './types.ts';
|
|
5
5
|
interface WsDeps {
|
|
6
|
-
sql:
|
|
6
|
+
sql: SqlClient;
|
|
7
7
|
model: LanguageModel;
|
|
8
8
|
workspace: string;
|
|
9
9
|
systemPrompt?: string;
|
package/dist/queue/types.d.ts
CHANGED
|
@@ -43,7 +43,6 @@ export interface Queue extends Middleware<Context, Context & QueueInjected>, Clo
|
|
|
43
43
|
}): Promise<string>;
|
|
44
44
|
process<T>(type: string, handler: (job: QueueJob<T>) => Promise<void>): void;
|
|
45
45
|
run(): Promise<void>;
|
|
46
|
-
stop(): void;
|
|
47
46
|
stats(): {
|
|
48
47
|
running: boolean;
|
|
49
48
|
inflight: number;
|
package/dist/rate-limit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Redis } from './vendor.ts';
|
|
2
|
-
import type { Context, Middleware } from './types.ts';
|
|
2
|
+
import type { Context, Middleware, Closeable } from './types.ts';
|
|
3
3
|
/** Options for {@link rateLimit}. */
|
|
4
4
|
export interface RateLimitOptions {
|
|
5
5
|
/** Maximum requests within the window (default: 100). */
|
|
@@ -17,6 +17,14 @@ export interface RateLimitOptions {
|
|
|
17
17
|
/** Redis key prefix (default: `'ratelimit:'`). */
|
|
18
18
|
prefix?: string;
|
|
19
19
|
}
|
|
20
|
+
/** Rate limit module — middleware + stats. */
|
|
21
|
+
export interface RateLimitModule extends Middleware<Context, Context>, Closeable {
|
|
22
|
+
stats(): {
|
|
23
|
+
store: string;
|
|
24
|
+
entries?: number;
|
|
25
|
+
maxEntries: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
20
28
|
/**
|
|
21
29
|
* Rate limiting middleware (in-memory or Redis-backed).
|
|
22
30
|
*
|
|
@@ -34,7 +42,4 @@ export interface RateLimitOptions {
|
|
|
34
42
|
* app.use(rateLimit({ store: 'redis', redis: new Redis(), max: 100 }))
|
|
35
43
|
* ```
|
|
36
44
|
*/
|
|
37
|
-
export declare function rateLimit(options?: RateLimitOptions):
|
|
38
|
-
close: () => void;
|
|
39
|
-
stop?: () => void;
|
|
40
|
-
};
|
|
45
|
+
export declare function rateLimit(options?: RateLimitOptions): RateLimitModule;
|
package/dist/redis/index.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
export declare function redis(opts?: string | RedisOptions): RedisClient;
|
|
1
|
+
export { redis } from './client.ts';
|
|
2
|
+
export type { RedisOptions, RedisClient, RedisInjected } from './types.ts';
|
package/dist/router.d.ts
CHANGED
|
@@ -10,6 +10,24 @@ export type WebSocketHandler = {
|
|
|
10
10
|
error?: (ws: WebSocket, ctx: Context, error: Error) => void | Promise<void>;
|
|
11
11
|
};
|
|
12
12
|
type WsUpgradeHandler = (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Middleware metadata for dependency checking.
|
|
15
|
+
* Middleware factories can attach this to their return value for runtime validation.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* function postgres(): PostgresClient {
|
|
19
|
+
* const mw = async (req, ctx, next) => { ... }
|
|
20
|
+
* mw.__meta = { injects: ['sql'], depends: [] }
|
|
21
|
+
* return Object.assign(mw, { sql, migrate, close })
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export interface MiddlewareMeta {
|
|
26
|
+
/** Fields this middleware injects into ctx. */
|
|
27
|
+
injects: string[];
|
|
28
|
+
/** Fields this middleware depends on (must be injected earlier). */
|
|
29
|
+
depends: string[];
|
|
30
|
+
}
|
|
13
31
|
export declare class Router<T extends Context = Context> {
|
|
14
32
|
private root;
|
|
15
33
|
private wsRoot;
|
|
@@ -18,6 +36,8 @@ export declare class Router<T extends Context = Context> {
|
|
|
18
36
|
private _hasWildcard;
|
|
19
37
|
private _hub?;
|
|
20
38
|
private _wss?;
|
|
39
|
+
/** Track which ctx fields have been injected so far (for dependency checking). */
|
|
40
|
+
private _ctxFields;
|
|
21
41
|
private get wss();
|
|
22
42
|
private get hub();
|
|
23
43
|
/** Inject a custom hub (e.g. with Redis for cross-process broadcast). */
|
|
@@ -28,6 +48,16 @@ export declare class Router<T extends Context = Context> {
|
|
|
28
48
|
use(mod: Router & {
|
|
29
49
|
middleware: () => Middleware;
|
|
30
50
|
}): Router<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Check a middleware's dependency metadata and emit warnings if
|
|
53
|
+
* required fields haven't been injected yet.
|
|
54
|
+
* Attach __meta to a middleware function:
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* mw.__meta = { injects: ['sql'], depends: ['session'] }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
private _checkMiddlewareMeta;
|
|
31
61
|
get(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
32
62
|
post(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
|
33
63
|
put(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
|
package/dist/serve.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
2
2
|
import type { Duplex } from 'node:stream';
|
|
3
|
-
import type
|
|
3
|
+
import { type Handler } from './types.ts';
|
|
4
4
|
export interface ServeOptions {
|
|
5
5
|
port?: number;
|
|
6
6
|
hostname?: string;
|
package/dist/session.d.ts
CHANGED
|
@@ -80,6 +80,10 @@ export declare class MemoryStore implements SessionStore {
|
|
|
80
80
|
/** Testing only: return approximate count. */
|
|
81
81
|
get size(): number;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Redis-backed session store.
|
|
85
|
+
* Pass to `session({ store: new RedisStore({ redis }) })`.
|
|
86
|
+
*/
|
|
83
87
|
export declare class RedisStore implements SessionStore {
|
|
84
88
|
private redis;
|
|
85
89
|
private prefix;
|
|
@@ -90,6 +94,22 @@ export declare class RedisStore implements SessionStore {
|
|
|
90
94
|
destroy(sid: string): Promise<void>;
|
|
91
95
|
close(): Promise<void>;
|
|
92
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Session middleware. Injects `ctx.session` with a persistent key-value store
|
|
99
|
+
* scoped to the request. Data is automatically saved to the store on response.
|
|
100
|
+
*
|
|
101
|
+
* Defaults to memory store. Use `{ store: 'redis', redis }` for multi-process setups.
|
|
102
|
+
*
|
|
103
|
+
* ```ts
|
|
104
|
+
* import { session } from 'weifuwu'
|
|
105
|
+
* app.use(session())
|
|
106
|
+
*
|
|
107
|
+
* app.get('/visit', (req, ctx) => {
|
|
108
|
+
* ctx.session.count = (ctx.session.count ?? 0) + 1
|
|
109
|
+
* return Response.json({ visits: ctx.session.count })
|
|
110
|
+
* })
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
93
113
|
export declare function session(options?: SessionOptions): Middleware<Context, Context & SessionInjected> & {
|
|
94
114
|
close: () => Promise<void>;
|
|
95
115
|
store: SessionStore;
|
package/dist/test-utils.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Context, Handler } from './types.ts';
|
|
2
2
|
import type { SqlClient } from './vendor.ts';
|
|
3
|
+
import { Router } from './router.ts';
|
|
4
|
+
import { WebSocket as WSWebSocket } from 'ws';
|
|
3
5
|
export interface TestResponse {
|
|
4
6
|
readonly status: number;
|
|
5
7
|
readonly headers: Headers;
|
|
@@ -35,7 +37,15 @@ export declare class TestRequest {
|
|
|
35
37
|
}
|
|
36
38
|
export declare class TestApp {
|
|
37
39
|
private router;
|
|
40
|
+
private wsServer;
|
|
41
|
+
private wsConnections;
|
|
38
42
|
constructor();
|
|
43
|
+
/**
|
|
44
|
+
* Register a WebSocket handler.
|
|
45
|
+
*/
|
|
46
|
+
ws(path: string, handler: import('./router.ts').WebSocketHandler): this;
|
|
47
|
+
/** Get the raw Router (for advanced use). */
|
|
48
|
+
get _router(): Router;
|
|
39
49
|
/** Add global middleware */
|
|
40
50
|
use(mw: any): this;
|
|
41
51
|
/** Register a GET route — supports route-level middleware via spread args. */
|
|
@@ -60,6 +70,74 @@ export declare class TestApp {
|
|
|
60
70
|
deleteReq(path: string): TestRequest;
|
|
61
71
|
/** Get the underlying handler (for advanced usage) */
|
|
62
72
|
handler(): Handler;
|
|
73
|
+
/** Start building a WebSocket connection to the given path. */
|
|
74
|
+
wsReq(path: string): TestWSRequest;
|
|
75
|
+
/**
|
|
76
|
+
* Internal: ensure HTTP server is running for WebSocket connections.
|
|
77
|
+
* Starts on a random port.
|
|
78
|
+
*/
|
|
79
|
+
_ensureServer(): Promise<string>;
|
|
80
|
+
/**
|
|
81
|
+
* Internal: register a WS connection for cleanup.
|
|
82
|
+
*/
|
|
83
|
+
_trackConnection(conn: TestWSConnection): void;
|
|
84
|
+
/**
|
|
85
|
+
* Cleanup all WebSocket connections and stop the server.
|
|
86
|
+
*/
|
|
87
|
+
close(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
/** Start building a WebSocket test connection. */
|
|
90
|
+
export declare class TestWSRequest {
|
|
91
|
+
private app;
|
|
92
|
+
private path;
|
|
93
|
+
private _timeout;
|
|
94
|
+
constructor(app: TestApp, path: string);
|
|
95
|
+
/** Set the timeout for operations (default: 5000ms). */
|
|
96
|
+
timeout(ms: number): this;
|
|
97
|
+
/**
|
|
98
|
+
* Connect to the WebSocket endpoint.
|
|
99
|
+
* Starts a real HTTP server (random port) if not already running.
|
|
100
|
+
*/
|
|
101
|
+
connect(): Promise<TestWSConnection>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A connected WebSocket for testing.
|
|
105
|
+
*
|
|
106
|
+
* ```ts
|
|
107
|
+
* const conn = await app.wsReq('/echo').connect()
|
|
108
|
+
* conn.send('hello')
|
|
109
|
+
* const msg = await conn.receive()
|
|
110
|
+
* assert.equal(msg, 'hello')
|
|
111
|
+
* conn.close()
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare class TestWSConnection {
|
|
115
|
+
private ws;
|
|
116
|
+
private _timeout;
|
|
117
|
+
private messageQueue;
|
|
118
|
+
private resolveQueue;
|
|
119
|
+
private _closed;
|
|
120
|
+
constructor(ws: WSWebSocket, timeout?: number);
|
|
121
|
+
/** Send a text message. */
|
|
122
|
+
send(data: string): void;
|
|
123
|
+
/** Send a JSON message. */
|
|
124
|
+
json(data: unknown): void;
|
|
125
|
+
/**
|
|
126
|
+
* Wait for the next message. Returns the raw text.
|
|
127
|
+
* Throws on timeout or if the connection is closed.
|
|
128
|
+
*/
|
|
129
|
+
receive(timeout?: number): Promise<string>;
|
|
130
|
+
/** Wait for the next message and parse as JSON. */
|
|
131
|
+
receiveJson<T = unknown>(): Promise<T>;
|
|
132
|
+
/**
|
|
133
|
+
* Assert that no message is received within the given silence period.
|
|
134
|
+
* Useful for verifying that something did NOT happen.
|
|
135
|
+
*/
|
|
136
|
+
expectSilent(ms: number): Promise<void>;
|
|
137
|
+
/** Close the connection. */
|
|
138
|
+
close(): void;
|
|
139
|
+
/** Whether the connection is closed. */
|
|
140
|
+
get closed(): boolean;
|
|
63
141
|
}
|
|
64
142
|
/** Create a new test app */
|
|
65
143
|
export declare function testApp(): TestApp;
|
|
@@ -84,7 +162,7 @@ export interface TestDb {
|
|
|
84
162
|
*
|
|
85
163
|
* ```ts
|
|
86
164
|
* const db = await createTestDb()
|
|
87
|
-
* await db.sql
|
|
165
|
+
* await db.sql`CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)`
|
|
88
166
|
* // ... run tests ...
|
|
89
167
|
* await db.destroy() // drops the schema
|
|
90
168
|
* ```
|
|
@@ -103,7 +181,7 @@ export declare function createTestDb(options?: {
|
|
|
103
181
|
*
|
|
104
182
|
* ```ts
|
|
105
183
|
* await withTestDb(async (sql) => {
|
|
106
|
-
* await sql
|
|
184
|
+
* await sql`INSERT INTO users ...`
|
|
107
185
|
* // All changes are rolled back after this callback returns
|
|
108
186
|
* })
|
|
109
187
|
* ```
|
package/dist/types.d.ts
CHANGED
|
@@ -19,3 +19,16 @@ export interface Closeable {
|
|
|
19
19
|
/** Release all resources. Call once when shutting down. */
|
|
20
20
|
close(): Promise<void>;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* HTTP error with an explicit status code.
|
|
24
|
+
* Throw from a handler or middleware to return a non-200 response.
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* if (!resource) throw new HttpError('Not found', 404)
|
|
28
|
+
* serve() catches it and returns the status code.
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class HttpError extends Error {
|
|
32
|
+
status: number;
|
|
33
|
+
constructor(message: string, status: number);
|
|
34
|
+
}
|
package/dist/user/client.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type { UserOptions, UserModule } from './types.ts';
|
|
1
|
+
import type { UserOptions, UserData, UserModule } from './types.ts';
|
|
2
|
+
declare module '../types.ts' {
|
|
3
|
+
interface Context {
|
|
4
|
+
user: UserData;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* User authentication module — local register/login, JWT verification, OAuth2 server, social login.
|
|
4
9
|
* Supports DB-less auth via tokens/verify/proxy options.
|
package/dist/user/types.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ export interface UserOptions {
|
|
|
81
81
|
* If not provided and no pg, `ctx.user` is set to `{ id: userId }`.
|
|
82
82
|
*/
|
|
83
83
|
resolveUser?: (userId: unknown) => unknown | Promise<unknown>;
|
|
84
|
+
/** Enable API key management (per-user keys with scopes). */
|
|
85
|
+
apiKeys?: boolean;
|
|
84
86
|
/** Enable OAuth2 server mode (authorization code flow). */
|
|
85
87
|
oauth2?: OAuth2ServerOptions;
|
|
86
88
|
/**
|
|
@@ -152,6 +154,25 @@ export interface UserModule extends Router, Closeable {
|
|
|
152
154
|
getClient: (clientId: string) => Promise<OAuth2Client | null>;
|
|
153
155
|
/** Revoke an OAuth2 client. */
|
|
154
156
|
revokeClient: (clientId: string) => Promise<void>;
|
|
157
|
+
/** Create a new API key for a user. Returns the full key (only shown once). */
|
|
158
|
+
createApiKey: (userId: number, name: string, scopes?: string[]) => Promise<{
|
|
159
|
+
id: number;
|
|
160
|
+
key: string;
|
|
161
|
+
}>;
|
|
162
|
+
/** List user\'s API keys (masked — only prefix + last 4 chars visible). */
|
|
163
|
+
listApiKeys: (userId: number) => Promise<ApiKeyInfo[]>;
|
|
164
|
+
/** Revoke an API key by ID. */
|
|
165
|
+
revokeApiKey: (userId: number, keyId: number) => Promise<void>;
|
|
155
166
|
/** Close the underlying DB connection. */
|
|
156
167
|
close: () => Promise<void>;
|
|
157
168
|
}
|
|
169
|
+
/** An API key record (as returned by listApiKeys — masked). */
|
|
170
|
+
export interface ApiKeyInfo {
|
|
171
|
+
id: number;
|
|
172
|
+
name: string;
|
|
173
|
+
prefix: string;
|
|
174
|
+
scopes: string[];
|
|
175
|
+
last_used_at: string | null;
|
|
176
|
+
created_at: string;
|
|
177
|
+
revoked: boolean;
|
|
178
|
+
}
|
package/dist/validate.d.ts
CHANGED
|
@@ -11,4 +11,20 @@ export interface ValidationSchemas {
|
|
|
11
11
|
params?: ZodSchema;
|
|
12
12
|
headers?: ZodSchema;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Request validation middleware using Zod schemas.
|
|
16
|
+
*
|
|
17
|
+
* Validates `params`, `query`, `body`, and/or `headers` against schemas.
|
|
18
|
+
* Returns 422 with error details on mismatch.
|
|
19
|
+
* Injects `ctx.parsed` with validated-and-transformed values.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { z } from 'zod'
|
|
23
|
+
*
|
|
24
|
+
* app.get('/users/:id', validate({
|
|
25
|
+
* params: z.object({ id: z.string() }),
|
|
26
|
+
* query: z.object({ include: z.string().optional() }),
|
|
27
|
+
* }), handler)
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
14
30
|
export declare function validate(schemas?: ValidationSchemas): Middleware;
|