@weifuwujs/weifuwu 0.9.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 (122) hide show
  1. package/README.md +605 -0
  2. package/dist/app.d.ts +122 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +484 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +506 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/compose.d.ts +12 -0
  11. package/dist/compose.d.ts.map +1 -0
  12. package/dist/compose.js +29 -0
  13. package/dist/compose.js.map +1 -0
  14. package/dist/env.d.ts +12 -0
  15. package/dist/env.d.ts.map +1 -0
  16. package/dist/env.js +46 -0
  17. package/dist/env.js.map +1 -0
  18. package/dist/group.d.ts +32 -0
  19. package/dist/group.d.ts.map +1 -0
  20. package/dist/group.js +66 -0
  21. package/dist/group.js.map +1 -0
  22. package/dist/helpers.d.ts +37 -0
  23. package/dist/helpers.d.ts.map +1 -0
  24. package/dist/helpers.js +101 -0
  25. package/dist/helpers.js.map +1 -0
  26. package/dist/index.d.ts +15 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +9 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/ioredis.d.ts +16 -0
  31. package/dist/ioredis.d.ts.map +1 -0
  32. package/dist/ioredis.js +42 -0
  33. package/dist/ioredis.js.map +1 -0
  34. package/dist/methods.d.ts +3 -0
  35. package/dist/methods.d.ts.map +1 -0
  36. package/dist/methods.js +10 -0
  37. package/dist/methods.js.map +1 -0
  38. package/dist/middleware/cors.d.ts +24 -0
  39. package/dist/middleware/cors.d.ts.map +1 -0
  40. package/dist/middleware/cors.js +77 -0
  41. package/dist/middleware/cors.js.map +1 -0
  42. package/dist/middleware/index.d.ts +7 -0
  43. package/dist/middleware/index.d.ts.map +1 -0
  44. package/dist/middleware/index.js +4 -0
  45. package/dist/middleware/index.js.map +1 -0
  46. package/dist/middleware/logger.d.ts +27 -0
  47. package/dist/middleware/logger.d.ts.map +1 -0
  48. package/dist/middleware/logger.js +48 -0
  49. package/dist/middleware/logger.js.map +1 -0
  50. package/dist/middleware/static.d.ts +27 -0
  51. package/dist/middleware/static.d.ts.map +1 -0
  52. package/dist/middleware/static.js +150 -0
  53. package/dist/middleware/static.js.map +1 -0
  54. package/dist/node.d.ts +27 -0
  55. package/dist/node.d.ts.map +1 -0
  56. package/dist/node.js +193 -0
  57. package/dist/node.js.map +1 -0
  58. package/dist/path.d.ts +9 -0
  59. package/dist/path.d.ts.map +1 -0
  60. package/dist/path.js +31 -0
  61. package/dist/path.js.map +1 -0
  62. package/dist/postgres.d.ts +19 -0
  63. package/dist/postgres.d.ts.map +1 -0
  64. package/dist/postgres.js +27 -0
  65. package/dist/postgres.js.map +1 -0
  66. package/dist/react-router.d.ts +31 -0
  67. package/dist/react-router.d.ts.map +1 -0
  68. package/dist/react-router.js +25 -0
  69. package/dist/react-router.js.map +1 -0
  70. package/dist/resources.d.ts +35 -0
  71. package/dist/resources.d.ts.map +1 -0
  72. package/dist/resources.js +54 -0
  73. package/dist/resources.js.map +1 -0
  74. package/dist/router.d.ts +30 -0
  75. package/dist/router.d.ts.map +1 -0
  76. package/dist/router.js +122 -0
  77. package/dist/router.js.map +1 -0
  78. package/dist/types.d.ts +124 -0
  79. package/dist/types.d.ts.map +1 -0
  80. package/dist/types.js +2 -0
  81. package/dist/types.js.map +1 -0
  82. package/dist/vite.d.ts +21 -0
  83. package/dist/vite.d.ts.map +1 -0
  84. package/dist/vite.js +101 -0
  85. package/dist/vite.js.map +1 -0
  86. package/dist/websocket/accept.d.ts +22 -0
  87. package/dist/websocket/accept.d.ts.map +1 -0
  88. package/dist/websocket/accept.js +104 -0
  89. package/dist/websocket/accept.js.map +1 -0
  90. package/dist/websocket/close-code.d.ts +22 -0
  91. package/dist/websocket/close-code.d.ts.map +1 -0
  92. package/dist/websocket/close-code.js +35 -0
  93. package/dist/websocket/close-code.js.map +1 -0
  94. package/dist/websocket/connection.d.ts +71 -0
  95. package/dist/websocket/connection.d.ts.map +1 -0
  96. package/dist/websocket/connection.js +287 -0
  97. package/dist/websocket/connection.js.map +1 -0
  98. package/dist/websocket/index.d.ts +7 -0
  99. package/dist/websocket/index.d.ts.map +1 -0
  100. package/dist/websocket/index.js +4 -0
  101. package/dist/websocket/index.js.map +1 -0
  102. package/dist/websocket/types.d.ts +66 -0
  103. package/dist/websocket/types.d.ts.map +1 -0
  104. package/dist/websocket/types.js +2 -0
  105. package/dist/websocket/types.js.map +1 -0
  106. package/docs/ai.md +175 -0
  107. package/docs/data.md +81 -0
  108. package/docs/migrating.md +116 -0
  109. package/docs/react-router.md +187 -0
  110. package/docs/styling.md +69 -0
  111. package/package.json +144 -0
  112. package/templates/react-router/_gitignore +3 -0
  113. package/templates/react-router/app/app.css +1 -0
  114. package/templates/react-router/app/context.ts +4 -0
  115. package/templates/react-router/app/root.tsx +50 -0
  116. package/templates/react-router/app/routes/home.tsx +17 -0
  117. package/templates/react-router/app/routes.ts +3 -0
  118. package/templates/react-router/app/server.ts +29 -0
  119. package/templates/react-router/package.json +29 -0
  120. package/templates/react-router/react-router.config.ts +5 -0
  121. package/templates/react-router/tsconfig.json +19 -0
  122. package/templates/react-router/vite.config.ts +6 -0
@@ -0,0 +1,32 @@
1
+ import type { App } from './app.ts';
2
+ import type { Context, MountableApi, MountOptions, OnRegistrar, RouteRegistrar } from './types.ts';
3
+ import type { WsRegistrar } from './websocket/types.ts';
4
+ /**
5
+ * 路由分组:为一组路由统一添加路径前缀。
6
+ *
7
+ * ```ts
8
+ * app.group('/api', (api) => {
9
+ * api.get('/users/:id', (req, ctx) => json(ctx.params.id)) // GET /api/users/:id
10
+ * })
11
+ * ```
12
+ */
13
+ export declare class Group<C extends Context = Context, Prefix extends string = ''> {
14
+ #private;
15
+ constructor(app: App<C>, prefix: string);
16
+ get: RouteRegistrar<C, Prefix, this>;
17
+ post: RouteRegistrar<C, Prefix, this>;
18
+ put: RouteRegistrar<C, Prefix, this>;
19
+ patch: RouteRegistrar<C, Prefix, this>;
20
+ delete: RouteRegistrar<C, Prefix, this>;
21
+ head: RouteRegistrar<C, Prefix, this>;
22
+ options: RouteRegistrar<C, Prefix, this>;
23
+ all: RouteRegistrar<C, Prefix, this>;
24
+ on: OnRegistrar<C, Prefix, this>;
25
+ /** 在分组内注册 WebSocket 路由,前缀同样生效 */
26
+ ws: WsRegistrar<C, Prefix, this>;
27
+ /** 在分组内挂载单源 API,前缀生效 */
28
+ mount(api: MountableApi<C>, options?: MountOptions): this;
29
+ /** 嵌套分组,前缀会继续叠加 */
30
+ group<P extends string>(prefix: P, define: (group: Group<C, `${Prefix}${P}`>) => void): this;
31
+ }
32
+ //# sourceMappingURL=group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../src/group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAGnC,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,cAAc,EACf,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvD;;;;;;;;GAQG;AACH,qBAAa,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,SAAS,MAAM,GAAG,EAAE;;gBAI5D,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM;IAKvC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CACF;IAElC,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CACF;IAEnC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CACF;IAElC,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CACF;IAEpC,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAGC;IAExC,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CACF;IAEnC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAGC;IAEzC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAGnC;IAED,EAAE,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAIM;IAEtC,iCAAiC;IACjC,EAAE,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAM/B;IAED,wBAAwB;IACxB,KAAK,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,YAAiB,GAAG,IAAI;IAiB7D,mBAAmB;IACnB,KAAK,CAAC,CAAC,SAAS,MAAM,EACpB,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI,GACjD,IAAI;CAYR"}
package/dist/group.js ADDED
@@ -0,0 +1,66 @@
1
+ import { METHODS } from "./methods.js";
2
+ import { joinPaths } from "./path.js";
3
+ /**
4
+ * 路由分组:为一组路由统一添加路径前缀。
5
+ *
6
+ * ```ts
7
+ * app.group('/api', (api) => {
8
+ * api.get('/users/:id', (req, ctx) => json(ctx.params.id)) // GET /api/users/:id
9
+ * })
10
+ * ```
11
+ */
12
+ export class Group {
13
+ #app;
14
+ #prefix;
15
+ constructor(app, prefix) {
16
+ this.#app = app;
17
+ this.#prefix = prefix;
18
+ }
19
+ get = (path, ...handlers) => this.#add('GET', path, handlers);
20
+ post = (path, ...handlers) => this.#add('POST', path, handlers);
21
+ put = (path, ...handlers) => this.#add('PUT', path, handlers);
22
+ patch = (path, ...handlers) => this.#add('PATCH', path, handlers);
23
+ delete = (path, ...handlers) => this.#add('DELETE', path, handlers);
24
+ head = (path, ...handlers) => this.#add('HEAD', path, handlers);
25
+ options = (path, ...handlers) => this.#add('OPTIONS', path, handlers);
26
+ all = (path, ...handlers) => {
27
+ for (const method of METHODS)
28
+ this.#add(method, path, handlers);
29
+ return this;
30
+ };
31
+ on = (method, path, ...handlers) => this.#add(method, path, handlers);
32
+ /** 在分组内注册 WebSocket 路由,前缀同样生效 */
33
+ ws = (path, ...args) => {
34
+ const app = this.#app;
35
+ app.ws(joinPaths(this.#prefix, path), ...args);
36
+ return this;
37
+ };
38
+ /** 在分组内挂载单源 API,前缀生效 */
39
+ mount(api, options = {}) {
40
+ if (options.rest !== false) {
41
+ for (const route of api.routes()) {
42
+ this.#add(route.method, route.path, [route.handler]);
43
+ }
44
+ }
45
+ if (typeof options.graphql === 'string') {
46
+ if (!api.graphqlHandler) {
47
+ throw new Error('This API does not provide a GraphQL handler');
48
+ }
49
+ const handler = api.graphqlHandler();
50
+ this.#add('GET', options.graphql, [handler]);
51
+ this.#add('POST', options.graphql, [handler]);
52
+ }
53
+ return this;
54
+ }
55
+ /** 嵌套分组,前缀会继续叠加 */
56
+ group(prefix, define) {
57
+ define(new Group(this.#app, joinPaths(this.#prefix, prefix)));
58
+ return this;
59
+ }
60
+ #add(method, path, handlers) {
61
+ const app = this.#app;
62
+ app.on(method, joinPaths(this.#prefix, path), ...handlers);
63
+ return this;
64
+ }
65
+ }
66
+ //# sourceMappingURL=group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.js","sourceRoot":"","sources":["../src/group.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export interface HttpErrorOptions {
2
+ /** 是否把 message 暴露给客户端(默认 5xx 不暴露、4xx 暴露) */
3
+ expose?: boolean;
4
+ headers?: ConstructorParameters<typeof Headers>[0];
5
+ cause?: unknown;
6
+ }
7
+ /**
8
+ * 抛出后由框架统一转换为对应的 HTTP 响应。
9
+ *
10
+ * ```ts
11
+ * app.get('/users/:id', async (req, ctx) => {
12
+ * const user = await db.find(ctx.params.id)
13
+ * if (!user) throw new HttpError(404, 'User not found')
14
+ * return json(user)
15
+ * })
16
+ * ```
17
+ */
18
+ export declare class HttpError extends Error {
19
+ readonly status: number;
20
+ readonly expose: boolean;
21
+ readonly headers: ConstructorParameters<typeof Headers>[0] | undefined;
22
+ constructor(status: number, message?: string, options?: HttpErrorOptions);
23
+ toResponse(): Response;
24
+ }
25
+ /**
26
+ * 可以外发给客户端的错误文案:`expose=false`(默认 5xx)退化为状态文案。
27
+ * HTTP 响应与 GraphQL 错误共用这一条规则。
28
+ */
29
+ export declare function publicErrorMessage(error: HttpError): string;
30
+ export declare function getStatusText(status: number): string;
31
+ /** `Response.json` 的封装,统一带上 `charset=utf-8` */
32
+ export declare function json(data: unknown, init?: ResponseInit): Response;
33
+ export declare function text(body: string, init?: ResponseInit): Response;
34
+ export declare function html(body: string, init?: ResponseInit): Response;
35
+ export declare function redirect(location: string, status?: 301 | 302 | 303 | 307 | 308): Response;
36
+ export declare function noContent(init?: ResponseInit): Response;
37
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,qBAAqB,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;IAClD,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;gBAE1D,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAW5E,UAAU,IAAI,QAAQ;CAMvB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAE3D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,+CAA+C;AAC/C,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAOrE;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAMpE;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAMpE;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAS,GACxC,QAAQ,CAEV;AAED,wBAAgB,SAAS,CAAC,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAE3D"}
@@ -0,0 +1,101 @@
1
+ const STATUS_TEXT = {
2
+ 400: 'Bad Request',
3
+ 401: 'Unauthorized',
4
+ 402: 'Payment Required',
5
+ 403: 'Forbidden',
6
+ 404: 'Not Found',
7
+ 405: 'Method Not Allowed',
8
+ 406: 'Not Acceptable',
9
+ 408: 'Request Timeout',
10
+ 409: 'Conflict',
11
+ 410: 'Gone',
12
+ 411: 'Length Required',
13
+ 412: 'Precondition Failed',
14
+ 413: 'Payload Too Large',
15
+ 415: 'Unsupported Media Type',
16
+ 418: "I'm a Teapot",
17
+ 422: 'Unprocessable Entity',
18
+ 423: 'Locked',
19
+ 424: 'Failed Dependency',
20
+ 425: 'Too Early',
21
+ 426: 'Upgrade Required',
22
+ 428: 'Precondition Required',
23
+ 429: 'Too Many Requests',
24
+ 431: 'Request Header Fields Too Large',
25
+ 451: 'Unavailable For Legal Reasons',
26
+ 500: 'Internal Server Error',
27
+ 501: 'Not Implemented',
28
+ 502: 'Bad Gateway',
29
+ 503: 'Service Unavailable',
30
+ 504: 'Gateway Timeout',
31
+ 505: 'HTTP Version Not Supported',
32
+ };
33
+ /**
34
+ * 抛出后由框架统一转换为对应的 HTTP 响应。
35
+ *
36
+ * ```ts
37
+ * app.get('/users/:id', async (req, ctx) => {
38
+ * const user = await db.find(ctx.params.id)
39
+ * if (!user) throw new HttpError(404, 'User not found')
40
+ * return json(user)
41
+ * })
42
+ * ```
43
+ */
44
+ export class HttpError extends Error {
45
+ status;
46
+ expose;
47
+ headers;
48
+ constructor(status, message, options = {}) {
49
+ super(message ?? STATUS_TEXT[status] ?? `HTTP ${status}`, options.cause === undefined ? undefined : { cause: options.cause });
50
+ this.name = 'HttpError';
51
+ this.status = status;
52
+ this.expose = options.expose ?? status < 500;
53
+ this.headers = options.headers;
54
+ }
55
+ toResponse() {
56
+ return new Response(publicErrorMessage(this), {
57
+ status: this.status,
58
+ headers: this.headers,
59
+ });
60
+ }
61
+ }
62
+ /**
63
+ * 可以外发给客户端的错误文案:`expose=false`(默认 5xx)退化为状态文案。
64
+ * HTTP 响应与 GraphQL 错误共用这一条规则。
65
+ */
66
+ export function publicErrorMessage(error) {
67
+ return error.expose ? error.message : STATUS_TEXT[error.status] ?? 'Error';
68
+ }
69
+ export function getStatusText(status) {
70
+ return STATUS_TEXT[status] ?? '';
71
+ }
72
+ /** `Response.json` 的封装,统一带上 `charset=utf-8` */
73
+ export function json(data, init = {}) {
74
+ const body = data === undefined ? '' : JSON.stringify(data);
75
+ const headers = new Headers(init.headers);
76
+ if (!headers.has('content-type')) {
77
+ headers.set('content-type', 'application/json; charset=utf-8');
78
+ }
79
+ return new Response(body, { ...init, headers });
80
+ }
81
+ export function text(body, init = {}) {
82
+ const headers = new Headers(init.headers);
83
+ if (!headers.has('content-type')) {
84
+ headers.set('content-type', 'text/plain; charset=utf-8');
85
+ }
86
+ return new Response(body, { ...init, headers });
87
+ }
88
+ export function html(body, init = {}) {
89
+ const headers = new Headers(init.headers);
90
+ if (!headers.has('content-type')) {
91
+ headers.set('content-type', 'text/html; charset=utf-8');
92
+ }
93
+ return new Response(body, { ...init, headers });
94
+ }
95
+ export function redirect(location, status = 302) {
96
+ return new Response(null, { status, headers: { location } });
97
+ }
98
+ export function noContent(init = {}) {
99
+ return new Response(null, { ...init, status: init.status ?? 204 });
100
+ }
101
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export { App, createApp } from './app.ts';
2
+ export { resource } from './resources.ts';
3
+ export type { Resource, ResourceOptions } from './resources.ts';
4
+ export { Group } from './group.ts';
5
+ export { compose } from './compose.ts';
6
+ export { Router } from './router.ts';
7
+ export type { RouteEntry, RouteMatch } from './router.ts';
8
+ export { HttpError, json, publicErrorMessage, text, html, redirect, noContent, } from './helpers.ts';
9
+ export type { HttpErrorOptions } from './helpers.ts';
10
+ export { serve, toNodeHandler, toUpgradeHandler, attachToServer } from './node.ts';
11
+ export type { FetchApp, NodeHandlerOptions, ServeOptions, UpgradeApp } from './node.ts';
12
+ export { acceptWebSocket, CLOSE_CODE, isValidCloseCode, validateUpgradeRequest, WebSocketConnection, } from './websocket/index.ts';
13
+ export type { AcceptOptions, WebSocketHandler, WebSocketHandlers, WebSocketLifecycle, WebSocketMessage, WebSocketMiddleware, WebSocketNext, WebSocketOptions, WebSocketReadyState, WsRegistrar, } from './websocket/index.ts';
14
+ export type { Context, ContextWithParams, ErrorHandler, Handler, HttpMethod, Middleware, MountableApi, MountableRoute, MountOptions, Next, NotFoundHandler, OnRegistrar, PathParams, RouteHandlers, RouteMiddleware, RouteRegistrar, } from './types.ts';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EACL,SAAS,EACT,IAAI,EACJ,kBAAkB,EAClB,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,SAAS,GACV,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAClF,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACvF,OAAO,EACL,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,GACZ,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EACV,OAAO,EACP,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,IAAI,EACJ,eAAe,EACf,WAAW,EACX,UAAU,EACV,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export { App, createApp } from "./app.js";
2
+ export { resource } from "./resources.js";
3
+ export { Group } from "./group.js";
4
+ export { compose } from "./compose.js";
5
+ export { Router } from "./router.js";
6
+ export { HttpError, json, publicErrorMessage, text, html, redirect, noContent, } from "./helpers.js";
7
+ export { serve, toNodeHandler, toUpgradeHandler, attachToServer } from "./node.js";
8
+ export { acceptWebSocket, CLOSE_CODE, isValidCloseCode, validateUpgradeRequest, WebSocketConnection, } from "./websocket/index.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,OAAO,EACL,SAAS,EACT,IAAI,EACJ,kBAAkB,EAClB,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,SAAS,GACV,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAElF,OAAO,EACL,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,16 @@
1
+ import type { Redis, RedisOptions } from 'ioredis';
2
+ import { type Resource } from './resources.ts';
3
+ export type { Redis, RedisOptions };
4
+ /**
5
+ * 注入 `ctx.redis`(ioredis 客户端)的中间件。
6
+ *
7
+ * - 首次请求时懒加载 `ioredis` 并连接
8
+ * - `app.close()` / CLI SIGTERM 时 `quit()`(失败则 `disconnect()`)
9
+ * - 默认连接串:`process.env.REDIS_URL`(缺省时用 ioredis 默认 localhost:6379)
10
+ *
11
+ * ```ts
12
+ * app.use(redis()) // ctx.redis: Redis
13
+ * ```
14
+ */
15
+ export declare function redis(urlOrOptions?: string | RedisOptions, options?: RedisOptions): Resource<'redis', Redis>;
16
+ //# sourceMappingURL=ioredis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ioredis.d.ts","sourceRoot":"","sources":["../src/ioredis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAExD,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA;AAEnC;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CACnB,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,EACpC,OAAO,CAAC,EAAE,YAAY,GACrB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAoC1B"}
@@ -0,0 +1,42 @@
1
+ import { resource } from "./resources.js";
2
+ /**
3
+ * 注入 `ctx.redis`(ioredis 客户端)的中间件。
4
+ *
5
+ * - 首次请求时懒加载 `ioredis` 并连接
6
+ * - `app.close()` / CLI SIGTERM 时 `quit()`(失败则 `disconnect()`)
7
+ * - 默认连接串:`process.env.REDIS_URL`(缺省时用 ioredis 默认 localhost:6379)
8
+ *
9
+ * ```ts
10
+ * app.use(redis()) // ctx.redis: Redis
11
+ * ```
12
+ */
13
+ export function redis(urlOrOptions, options) {
14
+ return resource('redis', async () => {
15
+ const { default: RedisClient } = (await import('ioredis'));
16
+ if (typeof urlOrOptions === 'string') {
17
+ return new RedisClient(urlOrOptions, options);
18
+ }
19
+ const url = process.env.REDIS_URL;
20
+ if (url)
21
+ return new RedisClient(url, urlOrOptions);
22
+ return new RedisClient(urlOrOptions ?? {});
23
+ }, {
24
+ close: (client) => new Promise((resolveClose) => {
25
+ if (client.status === 'end')
26
+ return resolveClose();
27
+ const timer = setTimeout(resolveClose, 1_000);
28
+ const finish = () => {
29
+ clearTimeout(timer);
30
+ resolveClose();
31
+ };
32
+ client.once('end', finish);
33
+ // ioredis v6 的 quit() 在 end 事件之前 resolve,所以等事件本身;
34
+ // quit 失败时降级 disconnect。
35
+ client.quit().catch(() => {
36
+ client.disconnect();
37
+ finish();
38
+ });
39
+ }),
40
+ });
41
+ }
42
+ //# sourceMappingURL=ioredis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ioredis.js","sourceRoot":"","sources":["../src/ioredis.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAiB,MAAM,gBAAgB,CAAA;AAIxD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,KAAK,CACnB,YAAoC,EACpC,OAAsB;IAEtB,OAAO,QAAQ,CACb,OAAO,EACP,KAAK,IAAI,EAAE;QACT,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAKxD,CAAA;QACD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAO,IAAI,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;QAC/C,CAAC;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAA;QACjC,IAAI,GAAG;YAAE,OAAO,IAAI,WAAW,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;QAClD,OAAO,IAAI,WAAW,CAAC,YAAY,IAAI,EAAE,CAAC,CAAA;IAC5C,CAAC,EACD;QACE,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAChB,IAAI,OAAO,CAAO,CAAC,YAAY,EAAE,EAAE;YACjC,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK;gBAAE,OAAO,YAAY,EAAE,CAAA;YAClD,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;YAC7C,MAAM,MAAM,GAAG,GAAG,EAAE;gBAClB,YAAY,CAAC,KAAK,CAAC,CAAA;gBACnB,YAAY,EAAE,CAAA;YAChB,CAAC,CAAA;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YAC1B,kDAAkD;YAClD,yBAAyB;YACzB,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;gBACvB,MAAM,CAAC,UAAU,EAAE,CAAA;gBACnB,MAAM,EAAE,CAAA;YACV,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC;KACL,CACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { HttpMethod } from './types.ts';
2
+ export declare const METHODS: readonly HttpMethod[];
3
+ //# sourceMappingURL=methods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../src/methods.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,eAAO,MAAM,OAAO,EAAE,SAAS,UAAU,EAQxC,CAAA"}
@@ -0,0 +1,10 @@
1
+ export const METHODS = [
2
+ 'GET',
3
+ 'POST',
4
+ 'PUT',
5
+ 'PATCH',
6
+ 'DELETE',
7
+ 'HEAD',
8
+ 'OPTIONS',
9
+ ];
10
+ //# sourceMappingURL=methods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"methods.js","sourceRoot":"","sources":["../src/methods.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAA0B;IAC5C,KAAK;IACL,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,MAAM;IACN,SAAS;CACV,CAAA"}
@@ -0,0 +1,24 @@
1
+ import type { Middleware } from '../types.ts';
2
+ export type CorsOrigin = string | string[] | ((origin: string) => string | null | undefined);
3
+ export interface CorsOptions {
4
+ /**
5
+ * 允许的来源。默认 `'*'`;
6
+ * 当 `credentials: true` 且为 `'*'` 时会回显请求的 Origin。
7
+ */
8
+ origin?: CorsOrigin;
9
+ methods?: string | string[];
10
+ allowedHeaders?: string | string[];
11
+ exposedHeaders?: string | string[];
12
+ credentials?: boolean;
13
+ /** 预检结果缓存秒数 */
14
+ maxAge?: number;
15
+ }
16
+ /**
17
+ * CORS 中间件,自动处理预检请求(OPTIONS + Access-Control-Request-Method)。
18
+ *
19
+ * ```ts
20
+ * app.use(cors({ origin: ['https://a.com'], credentials: true }))
21
+ * ```
22
+ */
23
+ export declare function cors(options?: CorsOptions): Middleware;
24
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,MAAM,EAAE,GACR,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAEnD,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC3B,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAClC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAClC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAID;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,UAAU,CA6C1D"}
@@ -0,0 +1,77 @@
1
+ const DEFAULT_METHODS = 'GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS';
2
+ /**
3
+ * CORS 中间件,自动处理预检请求(OPTIONS + Access-Control-Request-Method)。
4
+ *
5
+ * ```ts
6
+ * app.use(cors({ origin: ['https://a.com'], credentials: true }))
7
+ * ```
8
+ */
9
+ export function cors(options = {}) {
10
+ const methods = toHeaderValue(options.methods) ?? DEFAULT_METHODS;
11
+ const allowedHeaders = toHeaderValue(options.allowedHeaders);
12
+ const exposedHeaders = toHeaderValue(options.exposedHeaders);
13
+ const credentials = options.credentials === true;
14
+ const maxAge = options.maxAge;
15
+ return async (req, ctx, next) => {
16
+ const requestOrigin = req.headers.get('origin');
17
+ const allowOrigin = resolveOrigin(options.origin, requestOrigin, credentials);
18
+ const isPreflight = req.method === 'OPTIONS' &&
19
+ req.headers.has('access-control-request-method');
20
+ if (isPreflight) {
21
+ const headers = new Headers();
22
+ if (allowOrigin)
23
+ headers.set('access-control-allow-origin', allowOrigin);
24
+ headers.set('access-control-allow-methods', methods);
25
+ const requestedHeaders = req.headers.get('access-control-request-headers');
26
+ if (allowedHeaders)
27
+ headers.set('access-control-allow-headers', allowedHeaders);
28
+ else if (requestedHeaders)
29
+ headers.set('access-control-allow-headers', requestedHeaders);
30
+ if (exposedHeaders)
31
+ headers.set('access-control-expose-headers', exposedHeaders);
32
+ if (credentials)
33
+ headers.set('access-control-allow-credentials', 'true');
34
+ if (maxAge !== undefined)
35
+ headers.set('access-control-max-age', String(maxAge));
36
+ appendVary(headers, allowOrigin);
37
+ return new Response(null, { status: 204, headers });
38
+ }
39
+ const response = await next(req, ctx);
40
+ if (!allowOrigin)
41
+ return response;
42
+ const headers = new Headers(response.headers);
43
+ headers.set('access-control-allow-origin', allowOrigin);
44
+ if (credentials)
45
+ headers.set('access-control-allow-credentials', 'true');
46
+ if (exposedHeaders)
47
+ headers.set('access-control-expose-headers', exposedHeaders);
48
+ appendVary(headers, allowOrigin);
49
+ return new Response(response.body, {
50
+ status: response.status,
51
+ statusText: response.statusText,
52
+ headers,
53
+ });
54
+ };
55
+ }
56
+ function resolveOrigin(origin, requestOrigin, credentials) {
57
+ if (origin === undefined) {
58
+ return credentials ? requestOrigin : '*';
59
+ }
60
+ if (typeof origin === 'string') {
61
+ if (origin === '*' && credentials)
62
+ return requestOrigin;
63
+ return origin;
64
+ }
65
+ if (Array.isArray(origin)) {
66
+ return requestOrigin && origin.includes(requestOrigin) ? requestOrigin : null;
67
+ }
68
+ return requestOrigin ? origin(requestOrigin) ?? null : null;
69
+ }
70
+ function toHeaderValue(value) {
71
+ return Array.isArray(value) ? value.join(',') : value;
72
+ }
73
+ function appendVary(headers, allowOrigin) {
74
+ if (allowOrigin !== '*')
75
+ headers.append('vary', 'Origin');
76
+ }
77
+ //# sourceMappingURL=cors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAqBA,MAAM,eAAe,GAAG,wCAAwC,CAAA;AAEhE;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,UAAuB,EAAE;IAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,eAAe,CAAA;IACjE,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IAC5D,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,KAAK,IAAI,CAAA;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAE7B,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC9B,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC/C,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;QAE7E,MAAM,WAAW,GACf,GAAG,CAAC,MAAM,KAAK,SAAS;YACxB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;QAElD,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;YAC7B,IAAI,WAAW;gBAAE,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,WAAW,CAAC,CAAA;YACxE,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,OAAO,CAAC,CAAA;YACpD,MAAM,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAA;YAC1E,IAAI,cAAc;gBAAE,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAA;iBAC1E,IAAI,gBAAgB;gBACvB,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,gBAAgB,CAAC,CAAA;YAC/D,IAAI,cAAc;gBAAE,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,cAAc,CAAC,CAAA;YAChF,IAAI,WAAW;gBAAE,OAAO,CAAC,GAAG,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAA;YACxE,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;YAC/E,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;YAChC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;QACrD,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QACrC,IAAI,CAAC,WAAW;YAAE,OAAO,QAAQ,CAAA;QAEjC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QAC7C,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,WAAW,CAAC,CAAA;QACvD,IAAI,WAAW;YAAE,OAAO,CAAC,GAAG,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAA;QACxE,IAAI,cAAc;YAAE,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,cAAc,CAAC,CAAA;QAChF,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QAEhC,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;YACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,OAAO;SACR,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CACpB,MAA8B,EAC9B,aAA4B,EAC5B,WAAoB;IAEpB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAA;IAC1C,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,KAAK,GAAG,IAAI,WAAW;YAAE,OAAO,aAAa,CAAA;QACvD,OAAO,MAAM,CAAA;IACf,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,aAAa,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAA;IAC/E,CAAC;IACD,OAAO,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;AAC7D,CAAC;AAED,SAAS,aAAa,CAAC,KAAoC;IACzD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;AACvD,CAAC;AAED,SAAS,UAAU,CAAC,OAAgB,EAAE,WAA0B;IAC9D,IAAI,WAAW,KAAK,GAAG;QAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAC3D,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { logger } from './logger.ts';
2
+ export type { LogInfo, LoggerOptions } from './logger.ts';
3
+ export { cors } from './cors.ts';
4
+ export type { CorsOptions, CorsOrigin } from './cors.ts';
5
+ export { serveStatic } from './static.ts';
6
+ export type { ServeStaticOptions } from './static.ts';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { logger } from "./logger.js";
2
+ export { cors } from "./cors.js";
3
+ export { serveStatic } from "./static.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,27 @@
1
+ import type { Middleware } from '../types.ts';
2
+ export interface LogInfo {
3
+ method: string;
4
+ path: string;
5
+ status: number;
6
+ /** 毫秒 */
7
+ duration: number;
8
+ request: Request;
9
+ response?: Response;
10
+ /** handler 抛出的原始错误(仅失败时有值) */
11
+ error?: unknown;
12
+ }
13
+ export interface LoggerOptions {
14
+ /** 输出函数,默认 `console.log` */
15
+ log?: (message: string) => void;
16
+ /** 自定义日志格式 */
17
+ format?: (info: LogInfo) => string;
18
+ }
19
+ /**
20
+ * 访问日志中间件。
21
+ *
22
+ * ```ts
23
+ * app.use(logger())
24
+ * ```
25
+ */
26
+ export declare function logger(options?: LoggerOptions): Middleware;
27
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/middleware/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,SAAS;IACT,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,4BAA4B;IAC5B,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,cAAc;IACd,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,CAAA;CACnC;AAKD;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,UAAU,CAmC9D"}
@@ -0,0 +1,48 @@
1
+ const defaultFormat = (info) => `${info.method} ${info.path} ${info.status} ${info.duration.toFixed(1)}ms`;
2
+ /**
3
+ * 访问日志中间件。
4
+ *
5
+ * ```ts
6
+ * app.use(logger())
7
+ * ```
8
+ */
9
+ export function logger(options = {}) {
10
+ const log = options.log ?? ((message) => console.log(message));
11
+ const format = options.format ?? defaultFormat;
12
+ return async (req, ctx, next) => {
13
+ const start = performance.now();
14
+ const path = pathOf(req.url);
15
+ try {
16
+ const response = await next(req, ctx);
17
+ log(format({
18
+ method: req.method,
19
+ path,
20
+ status: response.status,
21
+ duration: performance.now() - start,
22
+ request: req,
23
+ response,
24
+ }));
25
+ return response;
26
+ }
27
+ catch (error) {
28
+ log(format({
29
+ method: req.method,
30
+ path,
31
+ status: 500,
32
+ duration: performance.now() - start,
33
+ request: req,
34
+ error,
35
+ }));
36
+ throw error;
37
+ }
38
+ };
39
+ }
40
+ function pathOf(url) {
41
+ try {
42
+ return new URL(url).pathname;
43
+ }
44
+ catch {
45
+ return url;
46
+ }
47
+ }
48
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/middleware/logger.ts"],"names":[],"mappings":"AAqBA,MAAM,aAAa,GAAG,CAAC,IAAa,EAAU,EAAE,CAC9C,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;AAE5E;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,UAAyB,EAAE;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;IACtE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAA;IAE9C,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAE5B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YACrC,GAAG,CACD,MAAM,CAAC;gBACL,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI;gBACJ,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;gBACnC,OAAO,EAAE,GAAG;gBACZ,QAAQ;aACT,CAAC,CACH,CAAA;YACD,OAAO,QAAQ,CAAA;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CACD,MAAM,CAAC;gBACL,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI;gBACJ,MAAM,EAAE,GAAG;gBACX,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;gBACnC,OAAO,EAAE,GAAG;gBACZ,KAAK;aACN,CAAC,CACH,CAAA;YACD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED,SAAS,MAAM,CAAC,GAAW;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAA;IACZ,CAAC;AACH,CAAC"}