weifuwu 0.25.1 → 0.25.2

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.
@@ -5,6 +5,6 @@ loadEnv()
5
5
  const port = Number(process.env.PORT) || 3000
6
6
  const srv = serve(app.handler(), { port, websocket: app.websocketHandler(), shutdown: false })
7
7
  process.on('SIGINT', () => {
8
- srv.stop()
8
+ srv.close()
9
9
  process.exit(0)
10
10
  })
@@ -5,9 +5,9 @@ import type { AIProvider } from '../ai/provider.ts';
5
5
  import type { RunParams, RunResult, KnowledgeDoc } from './types.ts';
6
6
  interface RunnerDeps {
7
7
  sql: SqlClient;
8
- agents: BoundTable<any>;
9
- runs: BoundTable<any>;
10
- knowledge: BoundTable<any>;
8
+ agents: BoundTable<Record<string, unknown>>;
9
+ runs: BoundTable<Record<string, unknown>>;
10
+ knowledge: BoundTable<Record<string, unknown>>;
11
11
  provider: AIProvider;
12
12
  modelName?: string;
13
13
  userTools?: Record<string, Tool>;
@@ -1,13 +1,22 @@
1
1
  import type { Middleware, Closeable } from './types.ts';
2
2
  import { Router } from './router.ts';
3
+ /** Tagged-template SQL function from the postgres.js library. */
4
+ type PgSql = (strings: TemplateStringsArray, ...values: unknown[]) => Promise<unknown[]>;
5
+ /** Schema table builder callback. */
6
+ type PgTable = (name: string, cols: Record<string, unknown>) => {
7
+ create(): Promise<void>;
8
+ createIndex(cols: string[], opts: {
9
+ unique: boolean;
10
+ }): Promise<void>;
11
+ };
3
12
  /** Options for {@link analytics}. */
4
13
  export interface AnalyticsOptions {
5
14
  /** Path prefixes to exclude from analytics (default: `['/__analytics', '/__wfw', '/static']`). */
6
15
  excluded?: string[];
7
16
  /** PostgreSQL client for persistent storage. Required for production use. */
8
17
  pg?: {
9
- sql: (strings: TemplateStringsArray, ...values: any[]) => Promise<any[]>;
10
- table: (name: string, cols: any) => any;
18
+ sql: PgSql;
19
+ table: PgTable;
11
20
  };
12
21
  }
13
22
  /** Analytics module returned by {@link analytics}. */
@@ -33,3 +42,4 @@ export interface AnalyticsModule extends Router, Closeable {
33
42
  * ```
34
43
  */
35
44
  export declare function analytics(options?: AnalyticsOptions): AnalyticsModule;
45
+ export {};
package/dist/compile.d.ts CHANGED
@@ -13,5 +13,3 @@ export declare function compile(path: string): Promise<any>;
13
13
  export declare let vendorHash: string;
14
14
  /** Build a single vendor bundle containing all needed vendor modules */
15
15
  export declare function compileVendorBundle(): Promise<string>;
16
- /** Clean up esbuild's internal worker pool. Call when you're done compiling. */
17
- export declare function closeCompile(): Promise<void>;
package/dist/csrf.d.ts CHANGED
@@ -8,6 +8,8 @@ export interface CsrfInjected {
8
8
  token: string;
9
9
  }
10
10
  /** Options for {@link csrf}. */
11
+ /** CSRF protection module — a {@link Middleware} that injects `ctx.csrf`. */
12
+ export type CsrfModule = Middleware<Context, Context & CsrfInjected>;
11
13
  export interface CsrfOptions {
12
14
  /** Cookie name for CSRF token (default: `'_csrf'`). */
13
15
  cookie?: string;
package/dist/flash.d.ts CHANGED
@@ -29,6 +29,8 @@ declare module './types.ts' {
29
29
  flash: FlashInjected;
30
30
  }
31
31
  }
32
+ /** Flash message module — a {@link Middleware} that injects `ctx.flash`. */
33
+ export type FlashModule = Middleware<Context, Context & FlashInjected>;
32
34
  /** Options for {@link flash}. */
33
35
  export interface FlashOptions {
34
36
  /**
package/dist/index.d.ts CHANGED
@@ -15,11 +15,11 @@ export type { CORSOptions } from './cors.ts';
15
15
  export { serveStatic } from './static.ts';
16
16
  export type { ServeStaticOptions } from './static.ts';
17
17
  export { validate } from './validate.ts';
18
- export type { ValidationSchemas } from './validate.ts';
18
+ export type { ValidationSchemas, ValidateModule } from './validate.ts';
19
19
  export { getCookies, setCookie, deleteCookie } from './cookie.ts';
20
20
  export type { CookieOptions } from './cookie.ts';
21
21
  export { upload } from './upload.ts';
22
- export type { UploadOptions, UploadedFile } from './upload.ts';
22
+ export type { UploadOptions, UploadedFile, UploadModule } from './upload.ts';
23
23
  export { rateLimit } from './rate-limit.ts';
24
24
  export type { RateLimitOptions } from './rate-limit.ts';
25
25
  export { compress } from './compress.ts';
@@ -27,7 +27,7 @@ export type { CompressOptions } from './compress.ts';
27
27
  export { helmet } from './helmet.ts';
28
28
  export type { HelmetOptions } from './helmet.ts';
29
29
  export { requestId } from './request-id.ts';
30
- export type { RequestIdOptions } from './request-id.ts';
30
+ export type { RequestIdOptions, RequestIdModule } from './request-id.ts';
31
31
  export { createSSEStream, formatSSE, formatSSEData } from './sse.ts';
32
32
  export type { SSEEvent } from './sse.ts';
33
33
  export { testApp, TestApp, TestRequest, createTestDb, withTestDb } from './test-utils.ts';
@@ -70,13 +70,13 @@ export type { ThemeOptions, ThemeInjected } from './theme.ts';
70
70
  export { i18n } from './i18n.ts';
71
71
  export type { I18nOptions, I18nInjected } from './i18n.ts';
72
72
  export { flash } from './flash.ts';
73
- export type { FlashOptions, FlashInjected } from './flash.ts';
73
+ export type { FlashOptions, FlashInjected, FlashModule } from './flash.ts';
74
74
  export { seo, seoMiddleware, seoTags } from './seo.ts';
75
75
  export type { SeoOptions, RobotsRule, SitemapUrl, SitemapConfig, SeoHeadersConfig, SeoTagsConfig, } from './seo.ts';
76
76
  export { mailer } from './mailer.ts';
77
77
  export type { MailerOptions, MailOptions, Mailer } from './mailer.ts';
78
78
  export { csrf } from './csrf.ts';
79
- export type { CsrfOptions, CsrfInjected } from './csrf.ts';
79
+ export type { CsrfOptions, CsrfInjected, CsrfModule } from './csrf.ts';
80
80
  export { logdb } from './logdb/index.ts';
81
81
  export type { LogdbOptions, LogdbModule, LogEntry, LogEntryInput } from './logdb/types.ts';
82
82
  export { iii, createWorker, registerWorker } from './iii/index.ts';
package/dist/index.js CHANGED
@@ -256,6 +256,7 @@ function serve(handler, options) {
256
256
  resolveReady();
257
257
  return {
258
258
  stop: () => Promise.resolve(),
259
+ close: () => Promise.resolve(),
259
260
  ready,
260
261
  get port() {
261
262
  return 0;
@@ -289,30 +290,29 @@ function serve(handler, options) {
289
290
  const displayHost = _cachedHostname === "0.0.0.0" ? "localhost" : _cachedHostname || "localhost";
290
291
  console.log(`weifuwu listening on http://${displayHost}:${_cachedPort}`);
291
292
  });
292
- return {
293
- stop: (timeoutMs = 1e4) => {
294
- if (shutdownHandler) {
295
- process.off("SIGTERM", shutdownHandler);
296
- process.off("SIGINT", shutdownHandler);
297
- shutdownHandler = null;
298
- }
299
- return new Promise((resolve16) => {
300
- if (!server.listening) {
301
- resolve16();
302
- return;
303
- }
304
- server.close();
305
- server.closeIdleConnections();
306
- const timer = setTimeout(() => {
307
- server.closeAllConnections();
308
- resolve16();
309
- }, timeoutMs);
310
- server.on("close", () => {
311
- clearTimeout(timer);
312
- resolve16();
313
- });
293
+ async function stop(timeoutMs = 1e4) {
294
+ if (shutdownHandler) {
295
+ process.off("SIGTERM", shutdownHandler);
296
+ process.off("SIGINT", shutdownHandler);
297
+ shutdownHandler = null;
298
+ }
299
+ if (!server.listening) return;
300
+ server.close();
301
+ server.closeIdleConnections();
302
+ return new Promise((resolve16) => {
303
+ const timer = setTimeout(() => {
304
+ server.closeAllConnections();
305
+ resolve16();
306
+ }, timeoutMs);
307
+ server.on("close", () => {
308
+ clearTimeout(timer);
309
+ resolve16();
314
310
  });
315
- },
311
+ });
312
+ }
313
+ return {
314
+ close: stop,
315
+ stop,
316
316
  ready,
317
317
  get port() {
318
318
  if (!server.listening) return 0;
@@ -519,7 +519,7 @@ var Router = class _Router {
519
519
  * ```
520
520
  */
521
521
  _checkMiddlewareMeta(mw, location) {
522
- const meta = mw.__meta ?? mw.middleware?.().__meta;
522
+ const meta = mw.__meta ?? (typeof mw === "object" && mw && "middleware" in mw ? mw.middleware().__meta : void 0);
523
523
  if (!meta) return;
524
524
  for (const dep of meta.depends) {
525
525
  if (!this._ctxFields.has(dep)) {
@@ -1771,7 +1771,7 @@ function createSSEStream(iterable, opts) {
1771
1771
  controller.enqueue(encoder.encode(text2));
1772
1772
  }
1773
1773
  } catch (e) {
1774
- if (e.name !== "AbortError") {
1774
+ if (e instanceof Error && e.name !== "AbortError") {
1775
1775
  controller.enqueue(encoder.encode(formatSSE("error", { error: e.message })));
1776
1776
  }
1777
1777
  } finally {
@@ -2008,7 +2008,7 @@ var TestApp = class {
2008
2008
  }
2009
2009
  this.wsConnections = [];
2010
2010
  if (this.wsServer) {
2011
- this.wsServer.stop();
2011
+ this.wsServer.close();
2012
2012
  this.wsServer = null;
2013
2013
  }
2014
2014
  }
@@ -2422,7 +2422,16 @@ async function getStreamObject() {
2422
2422
  async function aiStream(handler, provider) {
2423
2423
  const r = new Router();
2424
2424
  r.post("/", async (req, ctx) => {
2425
- const options = await handler(req, ctx);
2425
+ let options;
2426
+ try {
2427
+ options = await handler(req, ctx);
2428
+ } catch (err) {
2429
+ const message = err instanceof Error ? err.message : String(err);
2430
+ return new Response(JSON.stringify({ error: message }), {
2431
+ status: 500,
2432
+ headers: { "Content-Type": "application/json" }
2433
+ });
2434
+ }
2426
2435
  if (provider && !options.model) {
2427
2436
  options.model = provider.model();
2428
2437
  }
@@ -3758,7 +3767,6 @@ var BUILTIN_PROVIDERS = {
3758
3767
  tokenUrl: "https://oauth2.googleapis.com/token",
3759
3768
  userUrl: "https://www.googleapis.com/oauth2/v2/userinfo",
3760
3769
  scope: "openid email profile",
3761
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3762
3770
  parseUser: (data) => ({
3763
3771
  id: data.id,
3764
3772
  email: data.email,
@@ -3771,7 +3779,6 @@ var BUILTIN_PROVIDERS = {
3771
3779
  tokenUrl: "https://github.com/login/oauth/access_token",
3772
3780
  userUrl: "https://api.github.com/user",
3773
3781
  scope: "read:user user:email",
3774
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3775
3782
  parseUser: (data) => ({
3776
3783
  id: String(data.id),
3777
3784
  email: data.email ?? "",
@@ -3830,7 +3837,8 @@ function registerOAuthLoginRoutes(router, deps, providers) {
3830
3837
  if (email) {
3831
3838
  const existingUser = await deps.findUserByEmail(email);
3832
3839
  if (existingUser) {
3833
- await linkProvider(existingUser.id, provider, providerId, email, name, avatarUrl);
3840
+ const uid = existingUser.id;
3841
+ await linkProvider(uid, provider, providerId, email, name, avatarUrl);
3834
3842
  return existingUser;
3835
3843
  }
3836
3844
  }
@@ -3838,7 +3846,8 @@ function registerOAuthLoginRoutes(router, deps, providers) {
3838
3846
  email || `${provider}_${providerId}@oauth.local`,
3839
3847
  name || provider
3840
3848
  );
3841
- await linkProvider(newUser.id, provider, providerId, email, name, avatarUrl);
3849
+ const userId2 = newUser.id;
3850
+ await linkProvider(userId2, provider, providerId, email, name, avatarUrl);
3842
3851
  return newUser;
3843
3852
  }
3844
3853
  function getProviderMeta(providerName) {
@@ -6314,7 +6323,6 @@ function chunkContent(content, chunkSize, overlap) {
6314
6323
  // agent/run.ts
6315
6324
  function hasKnowledgeDocs(sql2, agentId) {
6316
6325
  return sql2`SELECT 1 FROM "_knowledge_documents" WHERE agent_id = ${agentId} LIMIT 1`.then(
6317
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6318
6326
  (r) => r.length > 0
6319
6327
  );
6320
6328
  }
@@ -7375,7 +7383,7 @@ async function deploy(config) {
7375
7383
  await stopProcess({ child: app.process, port: app.currentPort });
7376
7384
  }
7377
7385
  }
7378
- httpServer?.stop();
7386
+ httpServer?.close();
7379
7387
  },
7380
7388
  ready: httpServer.ready,
7381
7389
  url: `http://localhost:${config.port}/`,
@@ -8076,7 +8084,6 @@ function moduleServer(opts) {
8076
8084
  _setImportRoots(roots);
8077
8085
  const router = new Router();
8078
8086
  router.get("/__wfw/m/*", (async (req, ctx) => {
8079
- const reqUrl = new URL(req.url);
8080
8087
  const filePath = (ctx.params["*"] || "").split("?")[0];
8081
8088
  const ext = filePath.split(".").pop();
8082
8089
  if (ext !== "tsx" && ext !== "ts") {
@@ -8646,25 +8653,22 @@ async function getSession(sql2, id2) {
8646
8653
  }
8647
8654
  async function listSessions(sql2, userId2) {
8648
8655
  const opts = { orderBy: { updated_at: "desc" } };
8649
- if (userId2 !== void 0) {
8650
- const { data: rows2 } = await sessions.readMany(
8651
- sql2,
8652
- { user_id: userId2, active: true },
8653
- opts
8654
- );
8655
- return rows2;
8656
- }
8657
- const { data: rows } = await sessions.readMany(sql2, { active: true }, opts);
8656
+ const filter = userId2 !== void 0 ? { user_id: userId2, active: true } : { active: true };
8657
+ const { data: rows } = await sessions.readMany(sql2, filter, opts);
8658
8658
  return rows;
8659
8659
  }
8660
8660
  async function deleteSession(sql2, id2) {
8661
8661
  await sessions.update(sql2, id2, { active: false, updated_at: sql`NOW()` });
8662
8662
  }
8663
8663
  async function getHistory(sql2, sessionId, limit = 50) {
8664
- const { data: rows } = await messages.readMany(sql2, { session_id: sessionId }, {
8665
- orderBy: { created_at: "asc" },
8666
- limit
8667
- });
8664
+ const { data: rows } = await messages.readMany(
8665
+ sql2,
8666
+ { session_id: sessionId },
8667
+ {
8668
+ orderBy: { created_at: "asc" },
8669
+ limit
8670
+ }
8671
+ );
8668
8672
  return rows;
8669
8673
  }
8670
8674
  async function addTextMessage(sql2, sessionId, role, content, tokensIn = 0, tokensOut = 0) {
@@ -8865,7 +8869,7 @@ function createBashTool(ctx) {
8865
8869
  // opencode/tools/read.ts
8866
8870
  import { tool as tool4 } from "ai";
8867
8871
  import { z as z6 } from "zod";
8868
- import { readFileSync as readFileSync7 } from "node:fs";
8872
+ import { readFileSync as readFileSync6 } from "node:fs";
8869
8873
  import { resolve as resolve9 } from "node:path";
8870
8874
  function createReadTool(ctx) {
8871
8875
  return tool4({
@@ -8880,7 +8884,7 @@ function createReadTool(ctx) {
8880
8884
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
8881
8885
  return { error: "Path not allowed", content: null, totalLines: 0 };
8882
8886
  }
8883
- const content = readFileSync7(resolved, "utf-8");
8887
+ const content = readFileSync6(resolved, "utf-8");
8884
8888
  const lines = content.split("\n");
8885
8889
  const totalLines = lines.length;
8886
8890
  if (offset !== void 0) {
@@ -8931,7 +8935,7 @@ function createWriteTool(ctx) {
8931
8935
  // opencode/tools/edit.ts
8932
8936
  import { tool as tool6 } from "ai";
8933
8937
  import { z as z8 } from "zod";
8934
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
8938
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
8935
8939
  import { resolve as resolve11 } from "node:path";
8936
8940
  function createEditTool(ctx) {
8937
8941
  return tool6({
@@ -8947,7 +8951,7 @@ function createEditTool(ctx) {
8947
8951
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
8948
8952
  return { error: "Path not allowed" };
8949
8953
  }
8950
- const content = readFileSync8(resolved, "utf-8");
8954
+ const content = readFileSync7(resolved, "utf-8");
8951
8955
  if (replaceAll) {
8952
8956
  if (!content.includes(oldString)) {
8953
8957
  return { error: "oldString not found in file", replaced: 0 };
@@ -1,6 +1,5 @@
1
1
  import { Router } from './router.ts';
2
2
  export declare function clearModuleCache(filePath?: string): void;
3
- export declare function _setImportRoots(roots: string[]): void;
4
3
  export declare function transformModule(absPath: string, root: string, mountPath?: string): Promise<{
5
4
  url: string;
6
5
  code: string;
@@ -5,6 +5,10 @@ declare module './types.ts' {
5
5
  }
6
6
  }
7
7
  /** Options for {@link requestId}. */
8
+ /** Request ID module — a {@link Middleware} that injects `ctx.requestId`. */
9
+ export type RequestIdModule = Middleware<Context, Context & {
10
+ requestId: string;
11
+ }>;
8
12
  export interface RequestIdOptions {
9
13
  /** Header name for request ID (default: `'X-Request-ID'`). */
10
14
  header?: string;
package/dist/router.d.ts CHANGED
@@ -10,24 +10,6 @@ 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
- }
31
13
  export declare class Router<T extends Context = Context> {
32
14
  private root;
33
15
  private wsRoot;
package/dist/serve.d.ts CHANGED
@@ -18,6 +18,8 @@ export interface ServeOptions {
18
18
  }
19
19
  export interface Server {
20
20
  stop: (timeoutMs?: number) => Promise<void>;
21
+ /** Alias for `stop()`. Prefer this for consistency with other modules. */
22
+ close: (timeoutMs?: number) => Promise<void>;
21
23
  readonly port: number;
22
24
  readonly hostname: string;
23
25
  ready: Promise<void>;
@@ -8,5 +8,3 @@ export declare function getServerModule(absPath: string): any;
8
8
  * Otherwise clear all modules.
9
9
  */
10
10
  export declare function clearServerModule(absPath?: string): void;
11
- /** Release resources. Call when shutting down. */
12
- export declare function closeRegistry(): void;
package/dist/ssr.d.ts CHANGED
@@ -1,13 +1,4 @@
1
1
  import { Router } from './router.ts';
2
- interface ResolvedRoute {
3
- routePath: string;
4
- pageFile: string;
5
- layoutFiles: string[];
6
- errorFiles: string[];
7
- notFoundFile: string | null;
8
- }
9
- /** Clear route cache (called by HMR watcher in dev mode). */
10
- export declare function clearRouteCache(cache: Map<string, ResolvedRoute | null>): void;
11
2
  export interface RouteEntry {
12
3
  path: string;
13
4
  file: string;
@@ -18,4 +9,3 @@ export declare function ssr(opts: {
18
9
  close?: () => void;
19
10
  pages?: () => RouteEntry[];
20
11
  };
21
- export {};
@@ -5,6 +5,5 @@ export declare function sqlTypeForField(field: FieldDef): string;
5
5
  export declare function validateSlug(slug: string): string | null;
6
6
  export declare function validateFieldDefs(fields: FieldDef[]): string[];
7
7
  export declare function formatDefault(field: FieldDef): string;
8
- export declare function mapFieldToZod(field: FieldDef): string;
9
8
  export declare function getRelationFields(fields: FieldDef[]): FieldDef[];
10
9
  export declare function findRelation(fields: FieldDef[], targetSlug: string): FieldDef | undefined;
package/dist/types.d.ts CHANGED
@@ -4,12 +4,25 @@ export interface Context {
4
4
  mountPath?: string;
5
5
  layoutStack?: {
6
6
  path: string;
7
- component: any;
7
+ component: unknown;
8
8
  }[];
9
9
  [key: string]: unknown;
10
10
  }
11
11
  export type Handler<T extends Context = Context> = (req: Request, ctx: T) => Response | Promise<Response>;
12
- export type Middleware<In extends Context = Context, Out extends In = In> = (req: Request, ctx: In, next: Handler<Out>) => Response | Promise<Response>;
12
+ /**
13
+ * Metadata for middleware dependency checking.
14
+ * Middleware factories attach this for runtime validation.
15
+ */
16
+ export interface MiddlewareMeta {
17
+ /** Fields this middleware injects into ctx. */
18
+ injects: string[];
19
+ /** Fields this middleware depends on (must be injected earlier). */
20
+ depends: string[];
21
+ }
22
+ export type Middleware<In extends Context = Context, Out extends In = In> = {
23
+ (req: Request, ctx: In, next: Handler<Out>): Response | Promise<Response>;
24
+ __meta?: MiddlewareMeta;
25
+ };
13
26
  export type ErrorHandler<T extends Context = Context> = (error: Error, req: Request, ctx: T) => Response | Promise<Response>;
14
27
  /**
15
28
  * Interface for resources that require explicit cleanup (connections, pools, timers).
package/dist/upload.d.ts CHANGED
@@ -4,6 +4,10 @@ declare module './types.ts' {
4
4
  parsed: Record<string, unknown>;
5
5
  }
6
6
  }
7
+ /** Upload middleware — a {@link Middleware} that injects `ctx.parsed` with file fields. */
8
+ export type UploadModule = Middleware<Context, Context & {
9
+ parsed: Record<string, unknown>;
10
+ }>;
7
11
  /** A parsed file from a multipart upload. */
8
12
  export interface UploadedFile {
9
13
  /** Original filename from the client. */
@@ -9,13 +9,13 @@ interface OAuthLoginDeps {
9
9
  /** Table for provider-user link, derived from usersTable. */
10
10
  providerTable: string;
11
11
  redirectUrl: string;
12
- signToken: (user: any) => string;
12
+ signToken: (user: Record<string, unknown>) => string;
13
13
  /** Create a placeholder user for OAuth login (no password). */
14
- createPlaceholderUser: (email: string, name: string) => Promise<any>;
14
+ createPlaceholderUser: (email: string, name: string) => Promise<Record<string, unknown>>;
15
15
  /** Find user by internal ID. */
16
- findUserById: (id: number) => Promise<any | undefined>;
16
+ findUserById: (id: number) => Promise<Record<string, unknown> | undefined>;
17
17
  /** Find user by email. */
18
- findUserByEmail: (email: string) => Promise<any | undefined>;
18
+ findUserByEmail: (email: string) => Promise<Record<string, unknown> | undefined>;
19
19
  }
20
20
  export declare function registerOAuthLoginRoutes(router: Router, deps: OAuthLoginDeps, providers: Record<string, OAuthProviderConfig>): void;
21
21
  export {};
@@ -5,6 +5,8 @@ declare module './types.ts' {
5
5
  parsed: Record<string, unknown>;
6
6
  }
7
7
  }
8
+ /** Validation middleware — a {@link Middleware} that injects `ctx.parsed` with validated data. */
9
+ export type ValidateModule = Middleware;
8
10
  export interface ValidationSchemas {
9
11
  body?: ZodSchema;
10
12
  query?: ZodSchema;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.25.1",
4
+ "version": "0.25.2",
5
5
  "description": "Web-standard HTTP framework for Node.js — (req, ctx) => Response",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -31,8 +31,9 @@
31
31
  "lint": "eslint --ext .ts,.tsx .",
32
32
  "test": "node --test 'test/**/*.test.ts'",
33
33
  "test:coverage": "node --experimental-test-coverage --test 'test/**/*.test.ts'",
34
- "test:unit": "bash scripts/test-unit.sh",
35
- "test:ci": "node --test 'test/**/*.test.ts'",
34
+ "test:typecheck": "npx tsc -p tsconfig.test.json --noEmit",
35
+ "test:quick": "bash scripts/test-quick.sh",
36
+ "test:ci": "node --test --test-force-exit --test-timeout=60000 'test/**/*.test.ts'",
36
37
  "prepare": "husky"
37
38
  },
38
39
  "dependencies": {