weifuwu 0.23.4 → 0.24.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 +431 -152
- package/cli.ts +3 -0
- package/dist/agent/types.d.ts +2 -1
- package/dist/ai/provider.d.ts +10 -1
- package/dist/analytics.d.ts +2 -2
- package/dist/cache.d.ts +4 -4
- package/dist/cli.js +3 -0
- package/dist/cors.d.ts +2 -2
- package/dist/csrf.d.ts +11 -5
- package/dist/deploy/types.d.ts +2 -2
- package/dist/env.d.ts +33 -0
- package/dist/flash.d.ts +5 -0
- package/dist/helmet.d.ts +2 -2
- package/dist/hub.d.ts +2 -1
- package/dist/i18n.d.ts +27 -2
- package/dist/iii/register-worker.d.ts +1 -1
- package/dist/iii/types.d.ts +5 -3
- package/dist/index.d.ts +8 -10
- package/dist/index.js +434 -359
- package/dist/kb/types.d.ts +8 -0
- package/dist/logdb/types.d.ts +2 -1
- package/dist/mailer.d.ts +2 -1
- package/dist/messager/types.d.ts +2 -1
- package/dist/opencode/types.d.ts +2 -1
- package/dist/permissions.d.ts +2 -2
- package/dist/postgres/module.d.ts +2 -1
- package/dist/postgres/types.d.ts +2 -2
- package/dist/queue/types.d.ts +2 -2
- package/dist/rate-limit.d.ts +3 -2
- package/dist/react.js +6 -6
- package/dist/redis/types.d.ts +2 -2
- package/dist/request-id.d.ts +16 -7
- package/dist/router.d.ts +3 -0
- package/dist/seo.d.ts +2 -2
- package/dist/serve.d.ts +1 -1
- package/dist/session.d.ts +9 -5
- package/dist/tailwind.d.ts +9 -0
- package/dist/tenant/types.d.ts +3 -3
- package/dist/theme.d.ts +25 -2
- package/dist/trace.d.ts +44 -0
- package/dist/types.d.ts +8 -17
- package/dist/upload.d.ts +9 -2
- package/dist/user/client.d.ts +11 -3
- package/dist/user/types.d.ts +21 -6
- package/dist/validate.d.ts +5 -0
- package/package.json +9 -9
package/dist/kb/types.d.ts
CHANGED
|
@@ -41,6 +41,14 @@ export interface KBListEntry {
|
|
|
41
41
|
title: string;
|
|
42
42
|
chunks: number;
|
|
43
43
|
}
|
|
44
|
+
export interface KBInjected {
|
|
45
|
+
search(query: string, searchOptions?: KBSearchOptions): Promise<KBSearchResult[]>;
|
|
46
|
+
}
|
|
47
|
+
declare module '../types.ts' {
|
|
48
|
+
interface Context {
|
|
49
|
+
kb?: KBInjected;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
44
52
|
export interface KBModule {
|
|
45
53
|
/**
|
|
46
54
|
* Ingest a document: chunk → embed → store.
|
package/dist/logdb/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PostgresClient } from '../postgres/types.ts';
|
|
2
2
|
import type { Router } from '../router.ts';
|
|
3
|
+
import type { Closeable } from '../types.ts';
|
|
3
4
|
export interface LogdbOptions {
|
|
4
5
|
pg: PostgresClient;
|
|
5
6
|
table?: string;
|
|
@@ -18,7 +19,7 @@ export interface LogEntryInput {
|
|
|
18
19
|
message: string;
|
|
19
20
|
metadata?: Record<string, unknown>;
|
|
20
21
|
}
|
|
21
|
-
export interface LogdbModule extends Router {
|
|
22
|
+
export interface LogdbModule extends Router, Closeable {
|
|
22
23
|
log(input: LogEntryInput): Promise<LogEntry>;
|
|
23
24
|
migrate(): Promise<void>;
|
|
24
25
|
clean(retentionMonths: number): Promise<number>;
|
package/dist/mailer.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Transporter } from 'nodemailer';
|
|
2
|
+
import type { Closeable } from './types.ts';
|
|
2
3
|
/** Options for sending an email. */
|
|
3
4
|
export interface MailOptions {
|
|
4
5
|
/** Recipient address(es). */
|
|
@@ -26,7 +27,7 @@ export interface MailerOptions {
|
|
|
26
27
|
send?: (opts: MailOptions) => Promise<void>;
|
|
27
28
|
}
|
|
28
29
|
/** Mailer instance returned by {@link mailer}. */
|
|
29
|
-
export interface Mailer {
|
|
30
|
+
export interface Mailer extends Closeable {
|
|
30
31
|
/** Send an email. */
|
|
31
32
|
send: (opts: MailOptions) => Promise<void>;
|
|
32
33
|
/** Close the nodemailer transport. */
|
package/dist/messager/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Router } from '../router.ts';
|
|
|
2
2
|
import type { AgentModule } from '../agent/types.ts';
|
|
3
3
|
import type { PostgresClient } from '../postgres/types.ts';
|
|
4
4
|
import type { Redis } from '../vendor.ts';
|
|
5
|
+
import type { Closeable } from '../types.ts';
|
|
5
6
|
export interface MessagerOptions {
|
|
6
7
|
pg: PostgresClient;
|
|
7
8
|
agents?: AgentModule;
|
|
@@ -37,7 +38,7 @@ export interface Message {
|
|
|
37
38
|
mime_type: string | null;
|
|
38
39
|
created_at: string;
|
|
39
40
|
}
|
|
40
|
-
export interface MessagerModule extends Router {
|
|
41
|
+
export interface MessagerModule extends Router, Closeable {
|
|
41
42
|
migrate: () => Promise<void>;
|
|
42
43
|
wsHandler: () => any;
|
|
43
44
|
send: (channelId: number, content: string, opts?: {
|
package/dist/opencode/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Router } from '../router.ts';
|
|
2
2
|
import type { PostgresClient } from '../postgres/types.ts';
|
|
3
|
+
import type { Closeable } from '../types.ts';
|
|
3
4
|
export interface Session {
|
|
4
5
|
id: string;
|
|
5
6
|
tenant_id: string | null;
|
|
@@ -74,7 +75,7 @@ export interface OpencodeOptions {
|
|
|
74
75
|
skills?: SkillDef[];
|
|
75
76
|
permissions?: OpencodePermissions;
|
|
76
77
|
}
|
|
77
|
-
export interface OpencodeModule extends Router {
|
|
78
|
+
export interface OpencodeModule extends Router, Closeable {
|
|
78
79
|
migrate: () => Promise<void>;
|
|
79
80
|
wsHandler: () => any;
|
|
80
81
|
close: () => Promise<void>;
|
package/dist/permissions.d.ts
CHANGED
|
@@ -39,12 +39,12 @@ export interface PermissionsModule extends Middleware {
|
|
|
39
39
|
* Middleware that rejects the request if the user does not have any of the specified roles.
|
|
40
40
|
* Must be placed after `permissions()` middleware (which injects ctx.permissions.roles).
|
|
41
41
|
*/
|
|
42
|
-
requireRole(...roles: string[]): Middleware
|
|
42
|
+
requireRole(...roles: string[]): Middleware<Context, Context>;
|
|
43
43
|
/**
|
|
44
44
|
* Middleware that rejects the request if the user does not have all specified permissions.
|
|
45
45
|
* Must be placed after `permissions()` middleware (which injects ctx.permissions.permissions).
|
|
46
46
|
*/
|
|
47
|
-
requirePermission(...permissions: string[]): Middleware
|
|
47
|
+
requirePermission(...permissions: string[]): Middleware<Context, Context>;
|
|
48
48
|
/** Create the underlying tables. Safe to call multiple times. */
|
|
49
49
|
migrate(): Promise<void>;
|
|
50
50
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { PostgresClient } from './types.ts';
|
|
2
2
|
import type { Sql } from '../vendor.ts';
|
|
3
3
|
import type { ColumnBuilder, BoundTable, Table } from './schema/index.ts';
|
|
4
|
-
|
|
4
|
+
import type { Closeable } from '../types.ts';
|
|
5
|
+
export declare class PgModule implements Closeable {
|
|
5
6
|
protected sql: Sql<{}>;
|
|
6
7
|
protected pg: PostgresClient;
|
|
7
8
|
constructor(pg: PostgresClient);
|
package/dist/postgres/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Sql } from '../vendor.ts';
|
|
2
|
-
import type { Context, Middleware } from '../types.ts';
|
|
2
|
+
import type { Context, Middleware, Closeable } from '../types.ts';
|
|
3
3
|
import type { ColumnBuilder, BoundTable, Table } from './schema/index.ts';
|
|
4
4
|
declare module '../types.ts' {
|
|
5
5
|
interface Context {
|
|
@@ -22,7 +22,7 @@ export interface PostgresOptions {
|
|
|
22
22
|
/** Called after every query completes. Receives query text, duration in ms, and row count. */
|
|
23
23
|
onQuery?: (query: string, durationMs: number, rowCount: number) => void;
|
|
24
24
|
}
|
|
25
|
-
export interface PostgresClient extends Middleware<Context, Context & PostgresInjected
|
|
25
|
+
export interface PostgresClient extends Middleware<Context, Context & PostgresInjected>, Closeable {
|
|
26
26
|
sql: Sql<{}>;
|
|
27
27
|
/** Creates the migration tracking table (_weifuwu_migrations). Called once at startup. */
|
|
28
28
|
migrate: () => Promise<void>;
|
package/dist/queue/types.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
|
declare module '../types.ts' {
|
|
4
4
|
interface Context {
|
|
5
5
|
queue: Queue;
|
|
@@ -32,7 +32,7 @@ export interface QueueJobWithError<T = unknown> extends QueueJob<T> {
|
|
|
32
32
|
error: string;
|
|
33
33
|
failedAt: number;
|
|
34
34
|
}
|
|
35
|
-
export interface Queue extends Middleware<Context, Context & QueueInjected
|
|
35
|
+
export interface Queue extends Middleware<Context, Context & QueueInjected>, Closeable {
|
|
36
36
|
/** Register a cron job. Uses queue's backend (memory/pg/redis) for execution. */
|
|
37
37
|
cron(pattern: string, handler: () => void | Promise<void>): {
|
|
38
38
|
stop: () => void;
|
package/dist/rate-limit.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export interface RateLimitOptions {
|
|
|
34
34
|
* app.use(rateLimit({ store: 'redis', redis: new Redis(), max: 100 }))
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
export declare function rateLimit(options?: RateLimitOptions): Middleware & {
|
|
38
|
-
|
|
37
|
+
export declare function rateLimit(options?: RateLimitOptions): Middleware<Context, Context> & {
|
|
38
|
+
close: () => void;
|
|
39
|
+
stop?: () => void;
|
|
39
40
|
};
|
package/dist/react.js
CHANGED
|
@@ -629,9 +629,10 @@ function useFlashMessage() {
|
|
|
629
629
|
// use-agent-stream.ts
|
|
630
630
|
import { useState as useState6, useCallback as useCallback5, useRef as useRef4 } from "react";
|
|
631
631
|
function useAgentStream(opts) {
|
|
632
|
-
const { wsPath,
|
|
632
|
+
const { wsPath, onStreamEnd, onError } = opts;
|
|
633
633
|
const [streams, setStreams] = useState6({});
|
|
634
634
|
const activeRef = useRef4(/* @__PURE__ */ new Set());
|
|
635
|
+
const streamsRef = useRef4({});
|
|
635
636
|
const getAgentText = useCallback5(
|
|
636
637
|
(agentId) => streams[agentId] || "",
|
|
637
638
|
[streams]
|
|
@@ -652,20 +653,19 @@ function useAgentStream(opts) {
|
|
|
652
653
|
case "agent_stream": {
|
|
653
654
|
activeRef.current.add(agentId);
|
|
654
655
|
const token = msg.data?.token || "";
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
return { ...prev, [agentId]: current + token };
|
|
658
|
-
});
|
|
656
|
+
streamsRef.current[agentId] = (streamsRef.current[agentId] || "") + token;
|
|
657
|
+
setStreams({ ...streamsRef.current });
|
|
659
658
|
break;
|
|
660
659
|
}
|
|
661
660
|
case "agent_stream_end": {
|
|
662
661
|
activeRef.current.delete(agentId);
|
|
663
|
-
const fullText =
|
|
662
|
+
const fullText = streamsRef.current[agentId] || "";
|
|
664
663
|
onStreamEnd?.(agentId, fullText);
|
|
665
664
|
break;
|
|
666
665
|
}
|
|
667
666
|
case "agent_error": {
|
|
668
667
|
activeRef.current.delete(agentId);
|
|
668
|
+
delete streamsRef.current[agentId];
|
|
669
669
|
onError?.(agentId, msg.data?.error || "Unknown error");
|
|
670
670
|
break;
|
|
671
671
|
}
|
package/dist/redis/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Redis, RedisOptions as IORedisOptions } from '../vendor.ts';
|
|
2
|
-
import type { Context, Middleware } from '../types.ts';
|
|
2
|
+
import type { Context, Middleware, Closeable } from '../types.ts';
|
|
3
3
|
declare module '../types.ts' {
|
|
4
4
|
interface Context {
|
|
5
5
|
redis: Redis;
|
|
@@ -12,7 +12,7 @@ export type RedisOptions = IORedisOptions & {
|
|
|
12
12
|
export interface RedisInjected {
|
|
13
13
|
redis: Redis;
|
|
14
14
|
}
|
|
15
|
-
export interface RedisClient extends Middleware<Context, Context & RedisInjected
|
|
15
|
+
export interface RedisClient extends Middleware<Context, Context & RedisInjected>, Closeable {
|
|
16
16
|
redis: Redis;
|
|
17
17
|
close: () => Promise<void>;
|
|
18
18
|
}
|
package/dist/request-id.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { Context, Middleware } from './types.ts';
|
|
2
|
+
declare module './types.ts' {
|
|
3
|
+
interface Context {
|
|
4
|
+
requestId: string;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
2
7
|
/** Options for {@link requestId}. */
|
|
3
8
|
export interface RequestIdOptions {
|
|
4
9
|
/** Header name for request ID (default: `'X-Request-ID'`). */
|
|
@@ -9,18 +14,22 @@ export interface RequestIdOptions {
|
|
|
9
14
|
/**
|
|
10
15
|
* Request ID middleware.
|
|
11
16
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* injects `ctx.requestId`.
|
|
17
|
+
* @deprecated Use `trace()` from 'weifuwu' instead — it injects `ctx.trace.requestId`
|
|
18
|
+
* along with `traceId` and `elapsed()` in a single middleware.
|
|
15
19
|
*
|
|
16
20
|
* ```ts
|
|
17
|
-
*
|
|
21
|
+
* // Old:
|
|
18
22
|
* app.use(requestId())
|
|
23
|
+
* ctx.requestId
|
|
19
24
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
25
|
+
* // New:
|
|
26
|
+
* app.use(trace())
|
|
27
|
+
* ctx.trace.requestId
|
|
23
28
|
* ```
|
|
29
|
+
*
|
|
30
|
+
* Reads an incoming `X-Request-ID` header (or custom header name) from the
|
|
31
|
+
* request. If absent, generates a new UUID. Sets the response header and
|
|
32
|
+
* injects `ctx.requestId`.
|
|
24
33
|
*/
|
|
25
34
|
export declare function requestId(options?: RequestIdOptions): Middleware<Context, Context & {
|
|
26
35
|
requestId: string;
|
package/dist/router.d.ts
CHANGED
|
@@ -25,6 +25,9 @@ export declare class Router<T extends Context = Context> {
|
|
|
25
25
|
use<Out extends Context>(mw: Middleware<Context, Out>): Router<T & Out>;
|
|
26
26
|
use(path: string, mw: Middleware<T, T>): Router<T>;
|
|
27
27
|
use(path: string, router: Router<any>): Router<T>;
|
|
28
|
+
use(mod: Router & {
|
|
29
|
+
middleware: () => Middleware;
|
|
30
|
+
}): Router<T>;
|
|
28
31
|
get(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
|
|
29
32
|
post(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
|
|
30
33
|
put(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
|
package/dist/seo.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Middleware } from './types.ts';
|
|
1
|
+
import type { Middleware, Context } from './types.ts';
|
|
2
2
|
import { Router } from './router.ts';
|
|
3
3
|
/** A rule in `robots.txt`. */
|
|
4
4
|
export interface RobotsRule {
|
|
@@ -54,7 +54,7 @@ export interface SeoOptions {
|
|
|
54
54
|
* }))
|
|
55
55
|
* ```
|
|
56
56
|
*/
|
|
57
|
-
export declare function seoMiddleware(options?: SeoOptions): Middleware
|
|
57
|
+
export declare function seoMiddleware(options?: SeoOptions): Middleware<Context, Context>;
|
|
58
58
|
/**
|
|
59
59
|
* SEO module — serves `robots.txt` and `sitemap.xml`.
|
|
60
60
|
*
|
package/dist/serve.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export declare function createRequest(req: IncomingMessage, body: Buffer): [Requ
|
|
|
29
29
|
export declare function sendResponse(res: ServerResponse, response: Response, opts?: {
|
|
30
30
|
traceId?: string | null;
|
|
31
31
|
}): Promise<void>;
|
|
32
|
-
export declare function createTestServer(handler: Handler): Promise<{
|
|
32
|
+
export declare function createTestServer(handler: Handler, options?: ServeOptions): Promise<{
|
|
33
33
|
server: Server;
|
|
34
34
|
url: string;
|
|
35
35
|
}>;
|
package/dist/session.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Middleware } from './types.ts';
|
|
1
|
+
import type { Context, Middleware } from './types.ts';
|
|
2
2
|
import type { Redis } from './vendor.ts';
|
|
3
|
+
import type { Closeable } from './types.ts';
|
|
3
4
|
declare module './types.ts' {
|
|
4
5
|
interface Context {
|
|
5
6
|
session: Session;
|
|
@@ -27,10 +28,12 @@ export interface Session extends SessionData {
|
|
|
27
28
|
[kStore]: SessionStore;
|
|
28
29
|
[kTtl]: number;
|
|
29
30
|
}
|
|
30
|
-
export interface SessionStore {
|
|
31
|
+
export interface SessionStore extends Closeable {
|
|
31
32
|
get(sid: string): Promise<Record<string, unknown> | null>;
|
|
32
33
|
set(sid: string, data: Record<string, unknown>, ttl: number): Promise<void>;
|
|
33
34
|
destroy(sid: string): Promise<void>;
|
|
35
|
+
/** Release resources. Default no-op. */
|
|
36
|
+
close(): Promise<void>;
|
|
34
37
|
}
|
|
35
38
|
export interface SessionOptions {
|
|
36
39
|
/** Session store. 'memory' (default) or 'redis'. */
|
|
@@ -74,7 +77,7 @@ export declare class MemoryStore implements SessionStore {
|
|
|
74
77
|
set(sid: string, data: Record<string, unknown>, ttl: number): Promise<void>;
|
|
75
78
|
destroy(sid: string): Promise<void>;
|
|
76
79
|
private cleanup;
|
|
77
|
-
close(): void
|
|
80
|
+
close(): Promise<void>;
|
|
78
81
|
/** Testing only: return approximate count. */
|
|
79
82
|
get size(): number;
|
|
80
83
|
}
|
|
@@ -86,9 +89,10 @@ export declare class RedisStore implements SessionStore {
|
|
|
86
89
|
get(sid: string): Promise<Record<string, unknown> | null>;
|
|
87
90
|
set(sid: string, data: Record<string, unknown>, ttl: number): Promise<void>;
|
|
88
91
|
destroy(sid: string): Promise<void>;
|
|
92
|
+
close(): Promise<void>;
|
|
89
93
|
}
|
|
90
|
-
export declare function session(options?: SessionOptions): Middleware & {
|
|
91
|
-
close: () => void
|
|
94
|
+
export declare function session(options?: SessionOptions): Middleware<Context, Context & SessionInjected> & {
|
|
95
|
+
close: () => Promise<void>;
|
|
92
96
|
store: SessionStore;
|
|
93
97
|
};
|
|
94
98
|
export {};
|
package/dist/tailwind.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { Router } from './router.ts';
|
|
2
2
|
import type { Middleware } from './types.ts';
|
|
3
|
+
export interface TailwindInjected {
|
|
4
|
+
css: string;
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
7
|
+
declare module './types.ts' {
|
|
8
|
+
interface Context {
|
|
9
|
+
tailwind?: TailwindInjected;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
3
12
|
export declare function addTailwindSource(dir: string): void;
|
|
4
13
|
export declare function tailwindContext(dir: string): Middleware;
|
|
5
14
|
export declare function tailwindRouter(dir: string): Router;
|
package/dist/tenant/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Context } from '../types.ts';
|
|
1
|
+
import type { Context, Handler } from '../types.ts';
|
|
2
2
|
import type { Router } from '../router.ts';
|
|
3
3
|
import type { PostgresClient } from '../postgres/types.ts';
|
|
4
4
|
declare module '../types.ts' {
|
|
@@ -42,7 +42,7 @@ export interface TenantOptions {
|
|
|
42
42
|
}
|
|
43
43
|
export interface TenantModule extends Router {
|
|
44
44
|
migrate: () => Promise<void>;
|
|
45
|
-
middleware: () => (req: Request, ctx: Context, next:
|
|
46
|
-
graphql: () =>
|
|
45
|
+
middleware: () => (req: Request, ctx: Context, next: Handler<Context>) => Promise<Response>;
|
|
46
|
+
graphql: () => Router;
|
|
47
47
|
close: () => Promise<void>;
|
|
48
48
|
}
|
package/dist/theme.d.ts
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
import type { Middleware } from './types.ts';
|
|
1
|
+
import type { Context, Middleware } from './types.ts';
|
|
2
|
+
import { Router } from './router.ts';
|
|
3
|
+
declare module './types.ts' {
|
|
4
|
+
interface Context {
|
|
5
|
+
theme: ThemeInjected;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export interface ThemeInjected {
|
|
9
|
+
value: string;
|
|
10
|
+
set: (value: string, loc?: string) => Response;
|
|
11
|
+
}
|
|
2
12
|
export interface ThemeOptions {
|
|
3
13
|
/** Default theme value (default: 'system'). */
|
|
4
14
|
default?: string;
|
|
5
15
|
/** Cookie name (default: 'theme'). Set to empty string to disable cookie. */
|
|
6
16
|
cookie?: string;
|
|
7
17
|
}
|
|
8
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Theme module. Returns a Router with an attached `.middleware()` method.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* const t = theme()
|
|
23
|
+
* app.use(t.middleware()) // → ctx.theme = { value, set }
|
|
24
|
+
* app.use('/', t) // → GET /__theme/dark (switch route)
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export interface ThemeModule extends Router {
|
|
28
|
+
/** Middleware that injects `ctx.theme = { value, set }`. */
|
|
29
|
+
middleware: () => Middleware<Context, Context & ThemeInjected>;
|
|
30
|
+
}
|
|
31
|
+
export declare function theme(options?: ThemeOptions): ThemeModule;
|
package/dist/trace.d.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
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
|
+
}
|
|
1
17
|
export interface TraceContext {
|
|
2
18
|
/** Unique identifier for the current request trace. */
|
|
3
19
|
traceId: string;
|
|
@@ -49,3 +65,31 @@ export declare function runWithTrace<T>(incomingTraceId: string | null, fn: () =
|
|
|
49
65
|
* ```
|
|
50
66
|
*/
|
|
51
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
|
+
}>;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
1
|
export interface Context {
|
|
2
2
|
params: Record<string, string>;
|
|
3
3
|
query: Record<string, string>;
|
|
4
|
-
user?: unknown;
|
|
5
|
-
parsed?: Record<string, unknown>;
|
|
6
4
|
mountPath?: string;
|
|
7
|
-
theme?: {
|
|
8
|
-
value: string;
|
|
9
|
-
set?: (value: string, loc?: string) => Response;
|
|
10
|
-
};
|
|
11
|
-
flash?: {
|
|
12
|
-
value: unknown;
|
|
13
|
-
set: (data: unknown, location?: string) => Response;
|
|
14
|
-
};
|
|
15
|
-
i18n?: {
|
|
16
|
-
locale: string;
|
|
17
|
-
messages?: Record<string, unknown>;
|
|
18
|
-
t: (key: string, params?: Record<string, string>, fallback?: string) => string;
|
|
19
|
-
set?: (value: string, loc?: string) => Response;
|
|
20
|
-
};
|
|
21
|
-
env?: Record<string, string>;
|
|
22
5
|
layoutStack?: {
|
|
23
6
|
path: string;
|
|
24
7
|
component: any;
|
|
@@ -28,3 +11,11 @@ export interface Context {
|
|
|
28
11
|
export type Handler<T extends Context = Context> = (req: Request, ctx: T) => Response | Promise<Response>;
|
|
29
12
|
export type Middleware<In extends Context = Context, Out extends In = In> = (req: Request, ctx: In, next: Handler<Out>) => Response | Promise<Response>;
|
|
30
13
|
export type ErrorHandler<T extends Context = Context> = (error: Error, req: Request, ctx: T) => Response | Promise<Response>;
|
|
14
|
+
/**
|
|
15
|
+
* Interface for resources that require explicit cleanup (connections, pools, timers).
|
|
16
|
+
* All stateful modules implement this.
|
|
17
|
+
*/
|
|
18
|
+
export interface Closeable {
|
|
19
|
+
/** Release all resources. Call once when shutting down. */
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
}
|
package/dist/upload.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type { Middleware } from './types.ts';
|
|
1
|
+
import type { Context, Middleware } from './types.ts';
|
|
2
|
+
declare module './types.ts' {
|
|
3
|
+
interface Context {
|
|
4
|
+
parsed: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
2
7
|
/** A parsed file from a multipart upload. */
|
|
3
8
|
export interface UploadedFile {
|
|
4
9
|
/** Original filename from the client. */
|
|
@@ -41,4 +46,6 @@ export interface UploadOptions {
|
|
|
41
46
|
* })
|
|
42
47
|
* ```
|
|
43
48
|
*/
|
|
44
|
-
export declare function upload(options?: UploadOptions): Middleware
|
|
49
|
+
export declare function upload(options?: UploadOptions): Middleware<Context, Context & {
|
|
50
|
+
parsed: Record<string, unknown>;
|
|
51
|
+
}>;
|
package/dist/user/client.d.ts
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import type { UserOptions, UserModule } from './types.ts';
|
|
2
2
|
/**
|
|
3
3
|
* User authentication module — local register/login, JWT verification, OAuth2 server, social login.
|
|
4
|
+
* Supports DB-less auth via tokens/verify/proxy options.
|
|
4
5
|
*
|
|
5
6
|
* ```ts
|
|
7
|
+
* // Full auth with DB
|
|
6
8
|
* import { user, postgres } from 'weifuwu'
|
|
7
|
-
*
|
|
8
9
|
* const pg = postgres({ connection: DATABASE_URL })
|
|
9
10
|
* const auth = user({ pg, jwtSecret: process.env.JWT_SECRET })
|
|
10
11
|
*
|
|
11
12
|
* await auth.migrate()
|
|
13
|
+
* app.use(auth.middleware()) // inject ctx.user
|
|
14
|
+
* app.use('/', auth) // /register, /login
|
|
15
|
+
*
|
|
16
|
+
* // DB-less token auth
|
|
17
|
+
* const auth = user({ tokens: ['sk-123', 'sk-456'] })
|
|
18
|
+
* app.use(auth.middleware()) // injects ctx.user for valid tokens
|
|
12
19
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
20
|
+
* // DB-less custom verify
|
|
21
|
+
* const auth = user({ verify: async (token) => validateToken(token) })
|
|
22
|
+
* app.use(auth.middleware())
|
|
15
23
|
* ```
|
|
16
24
|
*/
|
|
17
25
|
export declare function user(options: UserOptions): UserModule;
|
package/dist/user/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Middleware, Context } from '../types.ts';
|
|
1
|
+
import type { Middleware, Context, Closeable } from '../types.ts';
|
|
2
2
|
import type { Router } from '../router.ts';
|
|
3
3
|
import type { PostgresClient } from '../postgres/types.ts';
|
|
4
4
|
/** A user record from the database. */
|
|
@@ -58,14 +58,29 @@ export interface OAuthProviderConfig {
|
|
|
58
58
|
}
|
|
59
59
|
/** Options for {@link user}. */
|
|
60
60
|
export interface UserOptions {
|
|
61
|
-
/** PostgreSQL client for user storage. */
|
|
62
|
-
pg
|
|
63
|
-
/** Secret key for JWT signing. */
|
|
64
|
-
jwtSecret
|
|
61
|
+
/** PostgreSQL client for user storage. Omit for DB-less token/verify/proxy auth. */
|
|
62
|
+
pg?: PostgresClient;
|
|
63
|
+
/** Secret key for JWT signing. Required for JWT auth and login/register routes. */
|
|
64
|
+
jwtSecret?: string;
|
|
65
65
|
/** Custom table name for users (default: `'users'`). */
|
|
66
66
|
table?: string;
|
|
67
67
|
/** JWT expiration time (default: `'7d'`). */
|
|
68
68
|
expiresIn?: string | number;
|
|
69
|
+
/** Static token(s) for simple bearer auth. No DB or JWT needed. */
|
|
70
|
+
tokens?: string[];
|
|
71
|
+
/** Custom verify function. Receives the token and request, returns user data or null. */
|
|
72
|
+
verify?: (token: string, req: Request) => unknown | Promise<unknown>;
|
|
73
|
+
/** Proxy auth — forward request to an external auth service for validation. */
|
|
74
|
+
proxy?: string | URL;
|
|
75
|
+
/** Custom header name for token extraction (default: `'Authorization'`). */
|
|
76
|
+
header?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Function to load user data from a user ID stored in the session.
|
|
79
|
+
* Called when `ctx.session.userId` is present. Only used when `pg` is not provided.
|
|
80
|
+
* Return a falsy value to reject (e.g. if the user was deleted).
|
|
81
|
+
* If not provided and no pg, `ctx.user` is set to `{ id: userId }`.
|
|
82
|
+
*/
|
|
83
|
+
resolveUser?: (userId: unknown) => unknown | Promise<unknown>;
|
|
69
84
|
/** Enable OAuth2 server mode (authorization code flow). */
|
|
70
85
|
oauth2?: OAuth2ServerOptions;
|
|
71
86
|
/**
|
|
@@ -92,7 +107,7 @@ export interface UserInjected {
|
|
|
92
107
|
* app.use('/', auth) // mounts routes: /register, /login
|
|
93
108
|
* ```
|
|
94
109
|
*/
|
|
95
|
-
export interface UserModule extends Router {
|
|
110
|
+
export interface UserModule extends Router, Closeable {
|
|
96
111
|
/**
|
|
97
112
|
* Strict auth middleware. Reads JWT from `Authorization: Bearer` header.
|
|
98
113
|
* Returns 401 if no valid token is found.
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { ZodSchema } from 'zod';
|
|
2
2
|
import type { Middleware } from './types.ts';
|
|
3
|
+
declare module './types.ts' {
|
|
4
|
+
interface Context {
|
|
5
|
+
parsed: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
3
8
|
export interface ValidationSchemas {
|
|
4
9
|
body?: ZodSchema;
|
|
5
10
|
query?: ZodSchema;
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weifuwu",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.24.1",
|
|
4
5
|
"description": "Web-standard HTTP framework for Node.js — (req, ctx) => Response",
|
|
5
6
|
"main": "./dist/index.js",
|
|
6
7
|
"types": "./dist/index.d.ts",
|
|
@@ -24,7 +25,9 @@
|
|
|
24
25
|
"start": "cd cli/template && node index.ts",
|
|
25
26
|
"build": "esbuild index.ts --bundle --format=esm --platform=node --outfile=dist/index.js --packages=external --define:__WFW_BUNDLED__=true && esbuild cli.ts --bundle --format=esm --platform=node --outfile=dist/cli.js --packages=external && esbuild react.ts --bundle --format=esm --outfile=dist/react.js --external:react --external:react-dom",
|
|
26
27
|
"prepublishOnly": "npm run build && tsc --emitDeclarationOnly --outdir dist",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
27
29
|
"test": "node --test 'test/**/*.test.ts'",
|
|
30
|
+
"test:coverage": "node --experimental-test-coverage --test 'test/**/*.test.ts'",
|
|
28
31
|
"test:unit": "bash scripts/test-unit.sh",
|
|
29
32
|
"test:ci": "node --test 'test/**/*.test.ts'"
|
|
30
33
|
},
|
|
@@ -48,15 +51,12 @@
|
|
|
48
51
|
"yaml": "^2.9.0",
|
|
49
52
|
"zod": "^4.4.3"
|
|
50
53
|
},
|
|
51
|
-
"type": "module",
|
|
52
|
-
"license": "MIT",
|
|
53
54
|
"devDependencies": {
|
|
54
|
-
"@types/jsonwebtoken": "^9.0.
|
|
55
|
-
"@types/
|
|
56
|
-
"@types/nodemailer": "^8.0.0",
|
|
57
|
-
"@types/react": "^19",
|
|
58
|
-
"@types/react-dom": "^19",
|
|
55
|
+
"@types/jsonwebtoken": "^9.0.9",
|
|
56
|
+
"@types/nodemailer": "^6.4.17",
|
|
59
57
|
"@types/ws": "^8.18.1",
|
|
60
|
-
"
|
|
58
|
+
"happy-dom": "^20.10.3",
|
|
59
|
+
"postcss": "^8.5.3",
|
|
60
|
+
"tailwindcss": "^4.0.0"
|
|
61
61
|
}
|
|
62
62
|
}
|