@lovrozagar/honey 0.1.0 → 0.2.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 (263) hide show
  1. package/README.md +1596 -6
  2. package/dist/accepts.d.ts +6 -0
  3. package/dist/accepts.d.ts.map +1 -0
  4. package/dist/body-limit.d.ts +22 -0
  5. package/dist/body-limit.d.ts.map +1 -0
  6. package/dist/build/index.d.ts +42 -0
  7. package/dist/build/index.d.ts.map +1 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/client/error.d.ts +14 -0
  11. package/dist/client/error.d.ts.map +1 -0
  12. package/dist/client/http.d.ts +88 -0
  13. package/dist/client/http.d.ts.map +1 -0
  14. package/dist/client/index.d.ts +22 -0
  15. package/dist/client/index.d.ts.map +1 -0
  16. package/dist/client/sdk.d.ts +34 -0
  17. package/dist/client/sdk.d.ts.map +1 -0
  18. package/dist/client/sse.d.ts +10 -0
  19. package/dist/client/sse.d.ts.map +1 -0
  20. package/dist/client/types.d.ts +124 -0
  21. package/dist/client/types.d.ts.map +1 -0
  22. package/dist/client/ws.d.ts +15 -0
  23. package/dist/client/ws.d.ts.map +1 -0
  24. package/dist/client-mcp/server.d.ts +10 -0
  25. package/dist/client-mcp/server.d.ts.map +1 -0
  26. package/dist/client-mcp/types.d.ts +16 -0
  27. package/dist/client-mcp/types.d.ts.map +1 -0
  28. package/dist/cloudflare/realtime.d.ts +30 -0
  29. package/dist/cloudflare/realtime.d.ts.map +1 -0
  30. package/dist/codegen-go-cli.d.ts +22 -0
  31. package/dist/codegen-go-cli.d.ts.map +1 -0
  32. package/dist/codegen-go.d.ts +29 -0
  33. package/dist/codegen-go.d.ts.map +1 -0
  34. package/dist/codegen-hash.d.ts +3 -0
  35. package/dist/codegen-hash.d.ts.map +1 -0
  36. package/dist/codegen-ir.d.ts +123 -0
  37. package/dist/codegen-ir.d.ts.map +1 -0
  38. package/dist/codegen-loaders.d.ts +12 -0
  39. package/dist/codegen-loaders.d.ts.map +1 -0
  40. package/dist/codegen-mcp.d.ts +13 -0
  41. package/dist/codegen-mcp.d.ts.map +1 -0
  42. package/dist/codegen-python.d.ts +21 -0
  43. package/dist/codegen-python.d.ts.map +1 -0
  44. package/dist/codegen-rust.d.ts +18 -0
  45. package/dist/codegen-rust.d.ts.map +1 -0
  46. package/dist/codegen-sanitize.d.ts +3 -0
  47. package/dist/codegen-sanitize.d.ts.map +1 -0
  48. package/dist/codegen-schema-naming.d.ts +22 -0
  49. package/dist/codegen-schema-naming.d.ts.map +1 -0
  50. package/dist/codegen.d.ts +178 -0
  51. package/dist/codegen.d.ts.map +1 -0
  52. package/dist/context.d.ts +56 -0
  53. package/dist/context.d.ts.map +1 -0
  54. package/dist/cookie-sign.d.ts +3 -0
  55. package/dist/cookie-sign.d.ts.map +1 -0
  56. package/dist/cookie.d.ts +12 -0
  57. package/dist/cookie.d.ts.map +1 -0
  58. package/dist/cors.d.ts +13 -0
  59. package/dist/cors.d.ts.map +1 -0
  60. package/dist/crypto.d.ts +2 -0
  61. package/dist/crypto.d.ts.map +1 -0
  62. package/dist/csrf.d.ts +9 -0
  63. package/dist/csrf.d.ts.map +1 -0
  64. package/dist/curl-logger.d.ts +33 -0
  65. package/dist/curl-logger.d.ts.map +1 -0
  66. package/dist/detect-runtime.d.ts +16 -0
  67. package/dist/detect-runtime.d.ts.map +1 -0
  68. package/dist/error.d.ts +21 -0
  69. package/dist/error.d.ts.map +1 -0
  70. package/dist/errors.d.ts +40 -0
  71. package/dist/errors.d.ts.map +1 -0
  72. package/dist/etag.d.ts +9 -0
  73. package/dist/etag.d.ts.map +1 -0
  74. package/dist/feature-load.d.ts +3 -0
  75. package/dist/feature-load.d.ts.map +1 -0
  76. package/dist/go-type-emitter.d.ts +33 -0
  77. package/dist/go-type-emitter.d.ts.map +1 -0
  78. package/dist/honey-response.d.ts +82 -0
  79. package/dist/honey-response.d.ts.map +1 -0
  80. package/dist/i18n-slot.d.ts +7 -0
  81. package/dist/i18n-slot.d.ts.map +1 -0
  82. package/dist/i18n.d.ts +26 -0
  83. package/dist/i18n.d.ts.map +1 -0
  84. package/dist/index.d.ts +470 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/init.d.ts +7 -0
  87. package/dist/init.d.ts.map +1 -0
  88. package/dist/input.d.ts +6 -0
  89. package/dist/input.d.ts.map +1 -0
  90. package/dist/ip-restrict.d.ts +12 -0
  91. package/dist/ip-restrict.d.ts.map +1 -0
  92. package/dist/logger.d.ts +45 -0
  93. package/dist/logger.d.ts.map +1 -0
  94. package/dist/meta-spec.d.ts +81 -0
  95. package/dist/meta-spec.d.ts.map +1 -0
  96. package/dist/middleware.d.ts +60 -0
  97. package/dist/middleware.d.ts.map +1 -0
  98. package/dist/node-request.d.ts +59 -0
  99. package/dist/node-request.d.ts.map +1 -0
  100. package/dist/node.d.ts +13 -0
  101. package/dist/node.d.ts.map +1 -0
  102. package/dist/openapi/register.d.ts +3 -0
  103. package/dist/openapi/register.d.ts.map +1 -0
  104. package/dist/openapi/scalar.d.ts +12 -0
  105. package/dist/openapi/scalar.d.ts.map +1 -0
  106. package/dist/openapi/spec-factory.d.ts +31 -0
  107. package/dist/openapi/spec-factory.d.ts.map +1 -0
  108. package/dist/openapi/spec.d.ts +19 -0
  109. package/dist/openapi/spec.d.ts.map +1 -0
  110. package/dist/openapi/swagger.d.ts +12 -0
  111. package/dist/openapi/swagger.d.ts.map +1 -0
  112. package/dist/plugin.d.ts +167 -0
  113. package/dist/plugin.d.ts.map +1 -0
  114. package/dist/powered-by.d.ts +7 -0
  115. package/dist/powered-by.d.ts.map +1 -0
  116. package/dist/pretty-json.d.ts +10 -0
  117. package/dist/pretty-json.d.ts.map +1 -0
  118. package/dist/proxy.d.ts +51 -0
  119. package/dist/proxy.d.ts.map +1 -0
  120. package/dist/python-type-emitter.d.ts +11 -0
  121. package/dist/python-type-emitter.d.ts.map +1 -0
  122. package/dist/realtime/buffer.d.ts +18 -0
  123. package/dist/realtime/buffer.d.ts.map +1 -0
  124. package/dist/realtime/bus.d.ts +11 -0
  125. package/dist/realtime/bus.d.ts.map +1 -0
  126. package/dist/realtime/longpoll.d.ts +23 -0
  127. package/dist/realtime/longpoll.d.ts.map +1 -0
  128. package/dist/realtime/protocol.d.ts +50 -0
  129. package/dist/realtime/protocol.d.ts.map +1 -0
  130. package/dist/realtime/route.d.ts +42 -0
  131. package/dist/realtime/route.d.ts.map +1 -0
  132. package/dist/realtime/runtime.d.ts +74 -0
  133. package/dist/realtime/runtime.d.ts.map +1 -0
  134. package/dist/request-id.d.ts +12 -0
  135. package/dist/request-id.d.ts.map +1 -0
  136. package/dist/request-to-curl.d.ts +9 -0
  137. package/dist/request-to-curl.d.ts.map +1 -0
  138. package/dist/response.d.ts +57 -0
  139. package/dist/response.d.ts.map +1 -0
  140. package/dist/rust-type-emitter.d.ts +32 -0
  141. package/dist/rust-type-emitter.d.ts.map +1 -0
  142. package/dist/secure-headers.d.ts +16 -0
  143. package/dist/secure-headers.d.ts.map +1 -0
  144. package/dist/serve-register.d.ts +2 -0
  145. package/dist/serve-register.d.ts.map +1 -0
  146. package/dist/serve-slot.d.ts +6 -0
  147. package/dist/serve-slot.d.ts.map +1 -0
  148. package/dist/serve.d.ts +21 -0
  149. package/dist/serve.d.ts.map +1 -0
  150. package/dist/server-timing.d.ts +9 -0
  151. package/dist/server-timing.d.ts.map +1 -0
  152. package/dist/static.d.ts +12 -0
  153. package/dist/static.d.ts.map +1 -0
  154. package/dist/telemetry/otel.d.ts +59 -0
  155. package/dist/telemetry/otel.d.ts.map +1 -0
  156. package/dist/testing.d.ts +24 -0
  157. package/dist/testing.d.ts.map +1 -0
  158. package/dist/timeout.d.ts +7 -0
  159. package/dist/timeout.d.ts.map +1 -0
  160. package/dist/tree.d.ts +90 -0
  161. package/dist/tree.d.ts.map +1 -0
  162. package/dist/ts-type-emitter.d.ts +4 -0
  163. package/dist/ts-type-emitter.d.ts.map +1 -0
  164. package/dist/type-emitter.d.ts +8 -0
  165. package/dist/type-emitter.d.ts.map +1 -0
  166. package/dist/type-extractor.d.ts +39 -0
  167. package/dist/type-extractor.d.ts.map +1 -0
  168. package/dist/types.d.ts +451 -0
  169. package/dist/types.d.ts.map +1 -0
  170. package/dist/validation.d.ts +18 -0
  171. package/dist/validation.d.ts.map +1 -0
  172. package/dist/ws/bun.d.ts +28 -0
  173. package/dist/ws/bun.d.ts.map +1 -0
  174. package/dist/ws/cloudflare.d.ts +55 -0
  175. package/dist/ws/cloudflare.d.ts.map +1 -0
  176. package/dist/ws/deno.d.ts +13 -0
  177. package/dist/ws/deno.d.ts.map +1 -0
  178. package/dist/ws/node.d.ts +10 -0
  179. package/dist/ws/node.d.ts.map +1 -0
  180. package/dist/yaml.d.ts +4 -0
  181. package/dist/yaml.d.ts.map +1 -0
  182. package/docs/api-ref/go.md +82 -82
  183. package/docs/api-ref/python.md +82 -82
  184. package/docs/api-ref/rust.md +82 -82
  185. package/docs/api-ref/typescript.md +82 -82
  186. package/docs/invalidate-spec.md +13 -13
  187. package/docs/meta-spec.md +513 -0
  188. package/docs/packaging.md +85 -0
  189. package/docs/sdk.md +87 -73
  190. package/package.json +195 -51
  191. package/src/body-limit.ts +2 -1
  192. package/src/build/index.ts +2 -9
  193. package/src/cli.ts +2 -3
  194. package/src/client/http.ts +204 -223
  195. package/src/client/index.ts +6 -14
  196. package/src/client/sdk.ts +24 -17
  197. package/src/client/types.ts +4 -9
  198. package/src/client/ws.ts +3 -5
  199. package/src/client-mcp/server.ts +1 -4
  200. package/src/cloudflare/realtime.ts +8 -10
  201. package/src/codegen-go-cli.ts +74 -67
  202. package/src/codegen-go.ts +71 -51
  203. package/src/codegen-ir.ts +16 -27
  204. package/src/codegen-loaders.ts +5 -8
  205. package/src/codegen-mcp.ts +9 -27
  206. package/src/codegen-python.ts +47 -27
  207. package/src/codegen-rust.ts +110 -66
  208. package/src/codegen-sanitize.ts +1 -7
  209. package/src/codegen-schema-naming.ts +8 -2
  210. package/src/codegen.ts +299 -196
  211. package/src/context.ts +91 -95
  212. package/src/cookie-sign.ts +5 -13
  213. package/src/cookie.ts +1 -2
  214. package/src/cors.ts +4 -6
  215. package/src/crypto.ts +1 -4
  216. package/src/csrf.ts +3 -3
  217. package/src/curl-logger.ts +14 -32
  218. package/src/detect-runtime.ts +1 -3
  219. package/src/errors.ts +1 -3
  220. package/src/etag.ts +3 -4
  221. package/src/go-type-emitter.ts +45 -40
  222. package/src/honey-response.ts +1 -3
  223. package/src/i18n.ts +3 -12
  224. package/src/index.ts +1168 -1412
  225. package/src/ip-restrict.ts +2 -1
  226. package/src/logger.ts +13 -13
  227. package/src/meta-spec.ts +0 -0
  228. package/src/middleware.ts +111 -79
  229. package/src/node-request.ts +2 -1
  230. package/src/node.ts +9 -10
  231. package/src/openapi/register.ts +1 -2
  232. package/src/openapi/scalar.ts +9 -9
  233. package/src/openapi/spec-factory.ts +2 -2
  234. package/src/openapi/spec.ts +26 -19
  235. package/src/openapi/swagger.ts +9 -9
  236. package/src/plugin.ts +226 -256
  237. package/src/powered-by.ts +2 -1
  238. package/src/pretty-json.ts +2 -1
  239. package/src/proxy.ts +1 -3
  240. package/src/python-type-emitter.ts +37 -12
  241. package/src/realtime/route.ts +1 -1
  242. package/src/realtime/runtime.ts +9 -12
  243. package/src/request-id.ts +3 -4
  244. package/src/request-to-curl.ts +1 -4
  245. package/src/response.ts +150 -199
  246. package/src/rust-type-emitter.ts +66 -25
  247. package/src/secure-headers.ts +2 -1
  248. package/src/serve.ts +3 -12
  249. package/src/server-timing.ts +2 -1
  250. package/src/static.ts +3 -4
  251. package/src/telemetry/otel.ts +1 -6
  252. package/src/testing.ts +2 -11
  253. package/src/timeout.ts +2 -1
  254. package/src/tree.ts +12 -27
  255. package/src/ts-type-emitter.ts +71 -15
  256. package/src/type-emitter.ts +226 -237
  257. package/src/type-extractor.ts +260 -334
  258. package/src/types.ts +168 -68
  259. package/src/validation.ts +7 -30
  260. package/src/ws/bun.ts +2 -9
  261. package/src/ws/cloudflare.ts +13 -16
  262. package/src/ws/deno.ts +31 -40
  263. package/src/ws/node.ts +4 -19
package/src/context.ts CHANGED
@@ -1,21 +1,21 @@
1
- import { isNodeOutbound } from "./honey-response.ts";
2
- import type { SSEOptions, SSEStream, TypedResponse } from "./response.ts";
3
- import { HoneyRes } from "./response.ts";
4
- import type { PendingTap } from "./types.ts";
5
- import { EMPTY_OBJ } from "./types.ts";
6
- import { parseCookies } from "./validation.ts";
1
+ import { isNodeOutbound } from "./honey-response.ts"
2
+ import type { SSEOptions, SSEStream, TypedResponse } from "./response.ts"
3
+ import { HoneyRes } from "./response.ts"
4
+ import type { PendingTap } from "./types.ts"
5
+ import { EMPTY_OBJ } from "./types.ts"
6
+ import { parseCookies } from "./validation.ts"
7
7
 
8
8
  /**
9
9
  * Per-request res with lazy lastEventId — only reads the header when SSE is actually called.
10
10
  * All non-SSE methods (json/text/html/etc) are inherited from HoneyRes with zero overhead.
11
11
  */
12
12
  class ContextRes extends HoneyRes {
13
- private _req: Request;
14
- private _lastEventId: string | undefined | false = false;
13
+ private _req: Request
14
+ private _lastEventId: string | undefined | false = false
15
15
 
16
16
  constructor(req: Request) {
17
- super(isNodeOutbound(req));
18
- this._req = req;
17
+ super(isNodeOutbound(req))
18
+ this._req = req
19
19
  }
20
20
 
21
21
  override sse(
@@ -23,35 +23,35 @@ class ContextRes extends HoneyRes {
23
23
  opts?: SSEOptions,
24
24
  ): TypedResponse<"text/event-stream", "ok"> {
25
25
  if (this._lastEventId === false) {
26
- this._lastEventId = this._req.headers.get("last-event-id") ?? undefined;
26
+ this._lastEventId = this._req.headers.get("last-event-id") ?? undefined
27
27
  }
28
28
  return super.sse(callback, {
29
29
  ...opts,
30
30
  lastEventId: opts?.lastEventId ?? this._lastEventId,
31
- });
31
+ })
32
32
  }
33
33
  }
34
34
  function parseSearch(ctx: HoneyContext): void {
35
- const url = ctx._lzUrlFn ? ctx._lzUrlFn() : new URL(ctx.req.url);
36
- const first: Record<string, string> = {};
37
- const all: Record<string, string[]> = {};
35
+ const url = ctx._lzUrlFn ? ctx._lzUrlFn() : new URL(ctx.req.url)
36
+ const first: Record<string, string> = {}
37
+ const all: Record<string, string[]> = {}
38
38
  for (const [key, value] of url.searchParams) {
39
39
  if (first[key] === undefined) {
40
- first[key] = value;
41
- all[key] = [value];
40
+ first[key] = value
41
+ all[key] = [value]
42
42
  } else {
43
- const values = all[key];
43
+ const values = all[key]
44
44
  if (values) {
45
- values.push(value);
45
+ values.push(value)
46
46
  }
47
47
  }
48
48
  }
49
- ctx._lzSearch = first;
50
- ctx._lzSearchAll = all;
49
+ ctx._lzSearch = first
50
+ ctx._lzSearchAll = all
51
51
  }
52
52
 
53
53
  function bgSwallow(p: Promise<unknown>) {
54
- p.catch(noop);
54
+ p.catch(noop)
55
55
  }
56
56
  function noop() {}
57
57
 
@@ -64,98 +64,94 @@ function noop() {}
64
64
  * works structurally for ApplyOutput type narrowing.
65
65
  */
66
66
  export class HoneyContext<TEnv = Record<string, unknown>> {
67
- readonly background: (p: Promise<unknown>) => void;
68
- readonly env: TEnv;
69
- readonly params: Record<string, string>;
70
- readonly req: Request;
71
- readonly res: HoneyRes;
67
+ readonly background: (p: Promise<unknown>) => void
68
+ readonly env: TEnv
69
+ readonly params: Record<string, string>
70
+ readonly req: Request
71
+ readonly res: HoneyRes
72
72
 
73
73
  /* set after construction — declare keeps them off the private brand */
74
- declare readonly cookies: Record<string, string>;
75
- declare readonly errors: Record<string, (...args: never[]) => unknown>;
76
- declare readonly executionCtx:
77
- | { waitUntil?: (p: Promise<unknown>) => void }
78
- | undefined;
79
- declare readonly headers: Record<string, string>;
80
- declare readonly meta: Record<string, unknown>;
81
- declare readonly path: string;
82
- declare readonly realtime: { publish(topic: string, data: unknown): void };
83
- declare readonly routePattern: string;
84
- declare readonly search: Record<string, string>;
85
- declare readonly searchAll: Record<string, string[]>;
74
+ declare readonly cookies: Record<string, string>
75
+ declare readonly errors: Record<string, (...args: never[]) => unknown>
76
+ declare readonly executionCtx: { waitUntil?: (p: Promise<unknown>) => void } | undefined
77
+ declare readonly headers: Record<string, string>
78
+ declare readonly meta: Record<string, unknown>
79
+ declare readonly path: string
80
+ declare readonly realtime: { publish(topic: string, data: unknown): void }
81
+ declare readonly routePattern: string
82
+ declare readonly search: Record<string, string>
83
+ declare readonly searchAll: Record<string, string[]>
86
84
 
87
85
  /* backing state for lazy getters — stored directly on instance to avoid extra object allocation */
88
- /** @internal */ _lzCookies: Record<string, string> | null;
89
- /** @internal */ _lzHeaders: Record<string, string> | null;
90
- /** @internal */ _lzSearch: Record<string, string> | null;
91
- /** @internal */ _lzSearchAll: Record<string, string[]> | null;
92
- /** @internal */ _lzUrlFn: (() => URL) | null;
86
+ /** @internal */ _lzCookies: Record<string, string> | null
87
+ /** @internal */ _lzHeaders: Record<string, string> | null
88
+ /** @internal */ _lzSearch: Record<string, string> | null
89
+ /** @internal */ _lzSearchAll: Record<string, string[]> | null
90
+ /** @internal */ _lzUrlFn: (() => URL) | null
93
91
 
94
92
  /* error propagation — lets handler errors flow back through middleware chain */
95
- /** @internal */ _errorToResponse:
96
- | ((thrown: unknown) => Promise<Response>)
97
- | null;
98
- /** @internal */ _isErrorResponse: boolean;
93
+ /** @internal */ _errorToResponse: ((thrown: unknown) => Promise<Response>) | null
94
+ /** @internal */ _isErrorResponse: boolean
99
95
 
100
96
  /* tap side-effects — queued by c.tap(), drained after handler */
101
- /** @internal */ _pendingTaps: PendingTap[] | null;
97
+ /** @internal */ _pendingTaps: PendingTap[] | null
102
98
 
103
99
  constructor(opts: {
104
- env: TEnv;
105
- executionCtx?: { waitUntil?: (p: Promise<unknown>) => void };
106
- meta?: Record<string, unknown>;
107
- params: Record<string, string>;
108
- path?: string;
109
- req: Request;
110
- routePattern?: string;
111
- urlFn?: () => URL;
100
+ env: TEnv
101
+ executionCtx?: { waitUntil?: (p: Promise<unknown>) => void }
102
+ meta?: Record<string, unknown>
103
+ params: Record<string, string>
104
+ path?: string
105
+ req: Request
106
+ routePattern?: string
107
+ urlFn?: () => URL
112
108
  }) {
113
- this.req = opts.req;
114
- this.env = opts.env;
115
- this.params = opts.params;
116
- this.res = new ContextRes(opts.req);
109
+ this.req = opts.req
110
+ this.env = opts.env
111
+ this.params = opts.params
112
+ this.res = new ContextRes(opts.req)
117
113
 
118
114
  /* direct assignment — no defineProperty */
119
- (this as Record<string, unknown>)["executionCtx"] = opts.executionCtx;
120
- (this as Record<string, unknown>)["path"] = opts.path ?? "";
121
- (this as Record<string, unknown>)["routePattern"] = opts.routePattern ?? "";
122
- (this as Record<string, unknown>)["meta"] = opts.meta ?? EMPTY_OBJ;
115
+ ;(this as Record<string, unknown>)["executionCtx"] = opts.executionCtx
116
+ ;(this as Record<string, unknown>)["path"] = opts.path ?? ""
117
+ ;(this as Record<string, unknown>)["routePattern"] = opts.routePattern ?? ""
118
+ ;(this as Record<string, unknown>)["meta"] = opts.meta ?? EMPTY_OBJ
123
119
 
124
120
  /* invoke through executionCtx so `this` binds to the owning object — workerd's native ExecutionContext.waitUntil throws "Illegal invocation" when called detached */
125
- const executionCtx = opts.executionCtx;
126
- const waitUntil = executionCtx?.waitUntil;
121
+ const executionCtx = opts.executionCtx
122
+ const waitUntil = executionCtx?.waitUntil
127
123
  this.background = waitUntil
128
124
  ? (p: Promise<unknown>) => {
129
- waitUntil.call(executionCtx, p);
125
+ waitUntil.call(executionCtx, p)
130
126
  }
131
- : bgSwallow;
127
+ : bgSwallow
132
128
 
133
129
  /* lazy getter backing — flat on instance, no extra object */
134
- this._lzCookies = null;
135
- this._lzHeaders = null;
136
- this._lzSearch = null;
137
- this._lzSearchAll = null;
138
- this._lzUrlFn = opts.urlFn ?? null;
130
+ this._lzCookies = null
131
+ this._lzHeaders = null
132
+ this._lzSearch = null
133
+ this._lzSearchAll = null
134
+ this._lzUrlFn = opts.urlFn ?? null
139
135
 
140
136
  /* error propagation */
141
- this._errorToResponse = null;
142
- this._isErrorResponse = false;
137
+ this._errorToResponse = null
138
+ this._isErrorResponse = false
143
139
 
144
140
  /* taps */
145
- this._pendingTaps = null;
141
+ this._pendingTaps = null
146
142
  }
147
143
 
148
144
  /** @internal */
149
145
  _setErrors(errors: Record<string, (...args: never[]) => unknown>): void {
150
- (this as { errors: typeof errors }).errors = errors;
146
+ ;(this as { errors: typeof errors }).errors = errors
151
147
  }
152
148
 
153
149
  /** Queue a side-effect to fire after handler returns successfully */
154
150
  tap(key: string, payload: unknown): void {
155
151
  if (this._pendingTaps === null) {
156
- this._pendingTaps = [{ key, payload }];
152
+ this._pendingTaps = [{ key, payload }]
157
153
  } else {
158
- this._pendingTaps.push({ key, payload });
154
+ this._pendingTaps.push({ key, payload })
159
155
  }
160
156
  }
161
157
 
@@ -167,44 +163,44 @@ export class HoneyContext<TEnv = Record<string, unknown>> {
167
163
  enumerable: true,
168
164
  get(this: HoneyContext): Record<string, string> {
169
165
  if (this._lzCookies === null) {
170
- this._lzCookies = parseCookies(this.req.headers.get("cookie") ?? "");
166
+ this._lzCookies = parseCookies(this.req.headers.get("cookie") ?? "")
171
167
  }
172
- return this._lzCookies;
168
+ return this._lzCookies
173
169
  },
174
- });
170
+ })
175
171
  Object.defineProperty(HoneyContext.prototype, "headers", {
176
172
  configurable: true,
177
173
  enumerable: true,
178
174
  get(this: HoneyContext): Record<string, string> {
179
175
  if (this._lzHeaders === null) {
180
- const h: Record<string, string> = {};
176
+ const h: Record<string, string> = {}
181
177
  this.req.headers.forEach((value, key) => {
182
- h[key] = value;
183
- });
184
- this._lzHeaders = h;
178
+ h[key] = value
179
+ })
180
+ this._lzHeaders = h
185
181
  }
186
- return this._lzHeaders;
182
+ return this._lzHeaders
187
183
  },
188
- });
184
+ })
189
185
  Object.defineProperty(HoneyContext.prototype, "search", {
190
186
  configurable: true,
191
187
  enumerable: true,
192
188
  get(this: HoneyContext): Record<string, string> {
193
189
  if (this._lzSearch === null) {
194
- parseSearch(this);
190
+ parseSearch(this)
195
191
  }
196
- return this._lzSearch as Record<string, string>;
192
+ return this._lzSearch as Record<string, string>
197
193
  },
198
- });
194
+ })
199
195
  Object.defineProperty(HoneyContext.prototype, "searchAll", {
200
196
  configurable: true,
201
197
  enumerable: true,
202
198
  get(this: HoneyContext): Record<string, string[]> {
203
199
  if (this._lzSearchAll === null) {
204
- parseSearch(this);
200
+ parseSearch(this)
205
201
  }
206
- return this._lzSearchAll as Record<string, string[]>;
202
+ return this._lzSearchAll as Record<string, string[]>
207
203
  },
208
- });
204
+ })
209
205
  }
210
206
  }
@@ -1,13 +1,10 @@
1
1
  const encoder = new TextEncoder()
2
2
 
3
3
  function importKey(secret: string): Promise<CryptoKey> {
4
- return crypto.subtle.importKey(
5
- "raw",
6
- encoder.encode(secret),
7
- { hash: "SHA-256", name: "HMAC" },
8
- false,
9
- ["sign", "verify"],
10
- )
4
+ return crypto.subtle.importKey("raw", encoder.encode(secret), { hash: "SHA-256", name: "HMAC" }, false, [
5
+ "sign",
6
+ "verify",
7
+ ])
11
8
  }
12
9
 
13
10
  function toBase64Url(buffer: ArrayBuffer): string {
@@ -45,12 +42,7 @@ export async function verify(signed: string, secrets: string[]): Promise<string
45
42
 
46
43
  for (const secret of secrets) {
47
44
  const key = await importKey(secret)
48
- const valid = await crypto.subtle.verify(
49
- "HMAC",
50
- key,
51
- sig.buffer as ArrayBuffer,
52
- encoder.encode(value),
53
- )
45
+ const valid = await crypto.subtle.verify("HMAC", key, sig.buffer as ArrayBuffer, encoder.encode(value))
54
46
  if (valid) return value
55
47
  }
56
48
 
package/src/cookie.ts CHANGED
@@ -83,7 +83,6 @@ export function serializeCookie(name: string, opts: CookieOptions): string {
83
83
  }
84
84
  if (opts.httpOnly) cookie += "; HttpOnly"
85
85
  if (secure) cookie += "; Secure"
86
- if (opts.sameSite)
87
- cookie += `; SameSite=${opts.sameSite.charAt(0).toUpperCase()}${opts.sameSite.slice(1)}`
86
+ if (opts.sameSite) cookie += `; SameSite=${opts.sameSite.charAt(0).toUpperCase()}${opts.sameSite.slice(1)}`
88
87
  return cookie
89
88
  }
package/src/cors.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import { replaceResponse } from "./honey-response.ts"
2
3
  import type { MiddlewareFn } from "./middleware.ts"
3
4
 
@@ -25,8 +26,7 @@ export function cors(options?: CORSOptions): MiddlewareFn<{ req: Request }, {}>
25
26
  const opts = options ?? {}
26
27
 
27
28
  /* credentials + wildcard is a CORS spec violation — auto-narrow to echo origin */
28
- const credentialWildcard =
29
- opts.credentials === true && (opts.origin === undefined || opts.origin === "*")
29
+ const credentialWildcard = opts.credentials === true && (opts.origin === undefined || opts.origin === "*")
30
30
 
31
31
  const mw: MiddlewareFn<{ req: Request }, {}> = async (ctx, next) => {
32
32
  const req = ctx.req
@@ -37,9 +37,7 @@ export function cors(options?: CORSOptions): MiddlewareFn<{ req: Request }, {}>
37
37
  return next()
38
38
  }
39
39
 
40
- const allowedOrigin = credentialWildcard
41
- ? requestOrigin
42
- : matchOrigin(requestOrigin, opts.origin)
40
+ const allowedOrigin = credentialWildcard ? requestOrigin : matchOrigin(requestOrigin, opts.origin)
43
41
 
44
42
  /* origin not allowed */
45
43
  if (allowedOrigin === null) {
@@ -92,5 +90,5 @@ export function cors(options?: CORSOptions): MiddlewareFn<{ req: Request }, {}>
92
90
  })
93
91
  }
94
92
 
95
- return mw
93
+ return namedMiddleware("cors", mw)
96
94
  }
package/src/crypto.ts CHANGED
@@ -4,10 +4,7 @@ let cachedKey: CryptoKey | null = null
4
4
 
5
5
  async function getKey(): Promise<CryptoKey> {
6
6
  if (cachedKey === null) {
7
- cachedKey = await crypto.subtle.generateKey({ hash: "SHA-256", name: "HMAC" }, false, [
8
- "sign",
9
- "verify",
10
- ])
7
+ cachedKey = await crypto.subtle.generateKey({ hash: "SHA-256", name: "HMAC" }, false, ["sign", "verify"])
11
8
  }
12
9
  return cachedKey
13
10
  }
package/src/csrf.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import { HoneyError } from "./error.ts"
2
3
  import type { MiddlewareFn } from "./middleware.ts"
3
4
  import { EK, SK } from "./types.ts"
@@ -7,8 +8,7 @@ type CSRFOptions = {
7
8
  }
8
9
 
9
10
  const safeMethodRe = /^(GET|HEAD|OPTIONS)$/
10
- const formContentTypeRe =
11
- /^\b(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)\b/i
11
+ const formContentTypeRe = /^\b(application\/x-www-form-urlencoded|multipart\/form-data|text\/plain)\b/i
12
12
 
13
13
  function matchOrigin(origin: string, config: CSRFOptions["origin"]): boolean {
14
14
  if (config === undefined) return false
@@ -50,5 +50,5 @@ export function csrf(options?: CSRFOptions): MiddlewareFn<{ req: Request }, {}>
50
50
  })
51
51
  }
52
52
 
53
- return mw
53
+ return namedMiddleware("csrf", mw)
54
54
  }
@@ -1,12 +1,8 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import type { MiddlewareFn } from "./middleware.ts"
2
3
  import type { LoggerInstance } from "./logger.ts"
3
4
 
4
- type BodyOmittedReason =
5
- | "content-type"
6
- | "disabled"
7
- | "missing"
8
- | "read-error"
9
- | "too-large"
5
+ type BodyOmittedReason = "content-type" | "disabled" | "missing" | "read-error" | "too-large"
10
6
 
11
7
  type CurlLogData = {
12
8
  bodyIncluded: boolean
@@ -33,12 +29,7 @@ type CurlLoggerOptions = {
33
29
  skip?: (data: CurlLogData) => boolean
34
30
  }
35
31
 
36
- const DEFAULT_BODY_CONTENT_TYPES = [
37
- "application/json",
38
- "application/x-www-form-urlencoded",
39
- "application/xml",
40
- "text/",
41
- ]
32
+ const DEFAULT_BODY_CONTENT_TYPES = ["application/json", "application/x-www-form-urlencoded", "application/xml", "text/"]
42
33
 
43
34
  const DEFAULT_MAX_BODY_BYTES = 16_384
44
35
 
@@ -70,7 +61,10 @@ function redactUrl(url: URL, redactQueryParam?: (name: string, value: string) =>
70
61
  return redacted.toString()
71
62
  }
72
63
 
73
- async function readBodyWithinLimit(request: Request, maxBytes: number): Promise<{
64
+ async function readBodyWithinLimit(
65
+ request: Request,
66
+ maxBytes: number,
67
+ ): Promise<{
74
68
  body: string | null
75
69
  omittedReason: BodyOmittedReason | null
76
70
  }> {
@@ -131,9 +125,7 @@ async function buildCurlLogData(
131
125
  const parts: string[] = [`curl -X ${request.method}`]
132
126
 
133
127
  for (const [name, value] of request.headers.entries()) {
134
- const redactedValue = options?.redactHeader !== undefined
135
- ? options.redactHeader(name, value)
136
- : value
128
+ const redactedValue = options?.redactHeader !== undefined ? options.redactHeader(name, value) : value
137
129
  if (redactedValue === null) continue
138
130
  parts.push(`-H '${shellEscape(name)}: ${shellEscape(redactedValue)}'`)
139
131
  }
@@ -149,10 +141,7 @@ async function buildCurlLogData(
149
141
  if (shouldIncludeBody(contentType, allowContentTypes) === false) {
150
142
  bodyOmittedReason = request.body === null ? "missing" : "content-type"
151
143
  } else {
152
- const result = await readBodyWithinLimit(
153
- request,
154
- bodyOptions.maxBytes ?? DEFAULT_MAX_BODY_BYTES,
155
- )
144
+ const result = await readBodyWithinLimit(request, bodyOptions.maxBytes ?? DEFAULT_MAX_BODY_BYTES)
156
145
 
157
146
  if (result.body === null) {
158
147
  bodyOmittedReason = result.omittedReason
@@ -174,17 +163,15 @@ async function buildCurlLogData(
174
163
  }
175
164
  }
176
165
 
177
- function curlLogger(
178
- options?: CurlLoggerOptions,
179
- ): MiddlewareFn<{ path: string, req: Request }, {}> {
166
+ function curlLogger(options?: CurlLoggerOptions): MiddlewareFn<{ path: string; req: Request }, {}> {
180
167
  const log = options?.log ?? defaultLog
181
168
  const skip = options?.skip
182
169
 
183
- return async (ctx, next) => {
170
+ return namedMiddleware("curlLogger", async (ctx, next) => {
184
171
  const start = performance.now()
185
172
  const method = ctx.req.method
186
173
  const path = ctx.path
187
- const rid = (ctx as Record<string, unknown>)["requestId"] as string | null ?? null
174
+ const rid = ((ctx as Record<string, unknown>)["requestId"] as string | null) ?? null
188
175
  const curlDataPromise = buildCurlLogData(ctx.req, options)
189
176
 
190
177
  const response = await next()
@@ -223,13 +210,8 @@ function curlLogger(
223
210
  }
224
211
 
225
212
  return response
226
- }
213
+ })
227
214
  }
228
215
 
229
216
  export { buildCurlLogData, curlLogger }
230
- export type {
231
- BodyOmittedReason,
232
- CurlLogData,
233
- CurlLoggerBodyOptions,
234
- CurlLoggerOptions,
235
- }
217
+ export type { BodyOmittedReason, CurlLogData, CurlLoggerBodyOptions, CurlLoggerOptions }
@@ -13,7 +13,5 @@ export function detectRuntime(g: DetectGlobal = globalThis): ServeRuntime {
13
13
  const ua = g.navigator?.userAgent ?? ""
14
14
  if (ua.includes("Cloudflare-Workers") || ua.includes("workerd")) return "cloudflare"
15
15
  if (g.process?.versions?.node) return "node"
16
- throw new Error(
17
- 'Honey.serve() could not detect a runtime. Pass runtime: "bun" | "node" | "deno".',
18
- )
16
+ throw new Error('Honey.serve() could not detect a runtime. Pass runtime: "bun" | "node" | "deno".')
19
17
  }
package/src/errors.ts CHANGED
@@ -43,9 +43,7 @@ type ErrorFactoryResult<TMap extends Record<string, ErrorDef>, TTranslations ext
43
43
  export function defineErrors<
44
44
  TMap extends Record<string, ErrorDef>,
45
45
  TTranslations extends Record<string, string> = Record<string, string>,
46
- >(
47
- map: TMap,
48
- ): ErrorFactoryResult<TMap, TTranslations> {
46
+ >(map: TMap): ErrorFactoryResult<TMap, TTranslations> {
49
47
  const result = Object.create(null) as Record<string, unknown>
50
48
  const meta = Object.create(null) as Record<string, ErrorMetaEntry>
51
49
 
package/src/etag.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import { replaceResponse } from "./honey-response.ts"
2
3
  import type { MiddlewareFn } from "./middleware.ts"
3
4
 
@@ -35,9 +36,7 @@ export function etag(options?: ETagOptions): MiddlewareFn<{ req: Request }, {}>
35
36
  /* skip streaming responses — can't hash without buffering entire stream */
36
37
  if (
37
38
  response.headers.get("transfer-encoding") === "chunked" ||
38
- (response.body !== null &&
39
- !response.headers.has("content-length") &&
40
- !response.headers.has("content-type"))
39
+ (response.body !== null && !response.headers.has("content-length") && !response.headers.has("content-type"))
41
40
  ) {
42
41
  return response
43
42
  }
@@ -70,5 +69,5 @@ export function etag(options?: ETagOptions): MiddlewareFn<{ req: Request }, {}>
70
69
  })
71
70
  }
72
71
 
73
- return mw
72
+ return namedMiddleware("etag", mw)
74
73
  }