@forinda/kickjs 6.1.0 → 6.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 (167) hide show
  1. package/README.md +14 -14
  2. package/dist/{adapter-D_uzU-QA.d.mts → adapter-DCfEFZMY.d.mts} +33 -10
  3. package/dist/adapter-DCfEFZMY.d.mts.map +1 -0
  4. package/dist/{app-module-CuAS6hJC.d.mts → app-module-BwYtACD6.d.mts} +3 -3
  5. package/dist/{app-module-CuAS6hJC.d.mts.map → app-module-BwYtACD6.d.mts.map} +1 -1
  6. package/dist/application-DS7t40r-.mjs +12 -0
  7. package/dist/application-DS7t40r-.mjs.map +1 -0
  8. package/dist/{application-CFenLjbY.d.mts → application-p8RRz7p6.d.mts} +4 -4
  9. package/dist/{application-CFenLjbY.d.mts.map → application-p8RRz7p6.d.mts.map} +1 -1
  10. package/dist/{bootstrap-DGUAqImq.mjs → bootstrap-DESuFm-t.mjs} +3 -3
  11. package/dist/{bootstrap-DGUAqImq.mjs.map → bootstrap-DESuFm-t.mjs.map} +1 -1
  12. package/dist/{bootstrap-DodgsiDG.d.mts → bootstrap-JXdD0wVC.d.mts} +2 -2
  13. package/dist/{bootstrap-DodgsiDG.d.mts.map → bootstrap-JXdD0wVC.d.mts.map} +1 -1
  14. package/dist/{cache-BSFDtsEG.d.mts → cache-CwZzIH0D.d.mts} +9 -11
  15. package/dist/cache-CwZzIH0D.d.mts.map +1 -0
  16. package/dist/config/index.d.mts +1 -1
  17. package/dist/config/index.mjs +2 -2
  18. package/dist/{config-bUVJOptu.mjs → config-CqN6u5CP.mjs} +3 -3
  19. package/dist/{config-bUVJOptu.mjs.map → config-CqN6u5CP.mjs.map} +1 -1
  20. package/dist/container-CkcVS_gA.mjs +108 -0
  21. package/dist/container-CkcVS_gA.mjs.map +1 -0
  22. package/dist/{container-TWOUyR_0.d.mts → container-iED1swkd.d.mts} +19 -3
  23. package/dist/container-iED1swkd.d.mts.map +1 -0
  24. package/dist/context-Cd-p7DfC.mjs +12 -0
  25. package/dist/context-Cd-p7DfC.mjs.map +1 -0
  26. package/dist/contributor-runner-BP9rOU_2.mjs +13 -0
  27. package/dist/contributor-runner-BP9rOU_2.mjs.map +1 -0
  28. package/dist/core/adapter.d.mts +1 -1
  29. package/dist/core/adapter.mjs +1 -1
  30. package/dist/core/app-module.d.mts +1 -1
  31. package/dist/core/app-module.mjs +1 -1
  32. package/dist/core/cache.d.mts +1 -1
  33. package/dist/core/cache.mjs +2 -2
  34. package/dist/core/cache.mjs.map +1 -1
  35. package/dist/core/container.d.mts +1 -1
  36. package/dist/core/container.mjs +2 -2
  37. package/dist/core/cron.mjs +2 -2
  38. package/dist/core/decorators.d.mts +2 -2
  39. package/dist/core/decorators.mjs +2 -2
  40. package/dist/core/decorators.mjs.map +1 -1
  41. package/dist/core/errors.mjs +1 -1
  42. package/dist/core/interfaces.d.mts +1 -1
  43. package/dist/core/interfaces.mjs +2 -2
  44. package/dist/core/interfaces.mjs.map +1 -1
  45. package/dist/core/logger.mjs +2 -2
  46. package/dist/core/logger.mjs.map +1 -1
  47. package/dist/core/path.mjs +1 -1
  48. package/dist/core/plugin.d.mts +1 -1
  49. package/dist/core/plugin.mjs +1 -1
  50. package/dist/core/reactivity.d.mts +1 -1
  51. package/dist/core/reactivity.mjs +2 -2
  52. package/dist/core/reactivity.mjs.map +1 -1
  53. package/dist/core-BBnRIW_2.mjs +12 -0
  54. package/dist/core-BBnRIW_2.mjs.map +1 -0
  55. package/dist/csrf-7nUXGTuz.d.mts.map +1 -1
  56. package/dist/csrf-CrChcN0K.mjs +12 -0
  57. package/dist/csrf-CrChcN0K.mjs.map +1 -0
  58. package/dist/{decorators-ejABLo9H.d.mts → decorators-DKjpujFp.d.mts} +13 -4
  59. package/dist/decorators-DKjpujFp.d.mts.map +1 -0
  60. package/dist/disposables-msQG0AHt.mjs +12 -0
  61. package/dist/disposables-msQG0AHt.mjs.map +1 -0
  62. package/dist/env-CrvPEW3K.mjs +13 -0
  63. package/dist/{env-CqRVEtoa.mjs.map → env-CrvPEW3K.mjs.map} +1 -1
  64. package/dist/handler-BMUwLMu_.mjs +12 -0
  65. package/dist/handler-BMUwLMu_.mjs.map +1 -0
  66. package/dist/http/application.d.mts +1 -1
  67. package/dist/http/application.mjs +2 -2
  68. package/dist/http/bootstrap.d.mts +1 -1
  69. package/dist/http/bootstrap.mjs +2 -2
  70. package/dist/http/context.d.mts +2 -2
  71. package/dist/http/context.mjs +2 -2
  72. package/dist/http/middleware/cors.mjs +1 -1
  73. package/dist/http/middleware/csrf.mjs +2 -3
  74. package/dist/http/middleware/error-handler.mjs +2 -2
  75. package/dist/http/middleware/helmet.mjs +1 -1
  76. package/dist/http/middleware/rate-limit.mjs +2 -2
  77. package/dist/http/middleware/rate-limit.mjs.map +1 -1
  78. package/dist/http/middleware/request-id.mjs +2 -2
  79. package/dist/http/middleware/request-id.mjs.map +1 -1
  80. package/dist/http/middleware/request-logger.mjs +2 -2
  81. package/dist/http/middleware/session.mjs +2 -2
  82. package/dist/http/middleware/session.mjs.map +1 -1
  83. package/dist/http/middleware/spa.d.mts +1 -1
  84. package/dist/http/middleware/spa.mjs +2 -2
  85. package/dist/http/middleware/spa.mjs.map +1 -1
  86. package/dist/http/middleware/upload.d.mts +2 -2
  87. package/dist/http/middleware/upload.mjs +3 -3
  88. package/dist/http/middleware/upload.mjs.map +1 -1
  89. package/dist/http/middleware/validate.mjs +2 -2
  90. package/dist/http/middleware/validate.mjs.map +1 -1
  91. package/dist/http/middleware/views.d.mts +1 -1
  92. package/dist/http/middleware/views.mjs +2 -2
  93. package/dist/http/query/index.mjs +2 -2
  94. package/dist/http/router-builder.d.mts +1 -1
  95. package/dist/http/router-builder.mjs +2 -2
  96. package/dist/http/router-builder.mjs.map +1 -1
  97. package/dist/http/runtimes/fastify.d.mts +1 -1
  98. package/dist/http/runtimes/fastify.d.mts.map +1 -1
  99. package/dist/http/runtimes/fastify.mjs +3 -3
  100. package/dist/http/runtimes/fastify.mjs.map +1 -1
  101. package/dist/http/runtimes/h3-web.d.mts +52 -0
  102. package/dist/http/runtimes/h3-web.d.mts.map +1 -0
  103. package/dist/http/runtimes/h3-web.mjs +12 -0
  104. package/dist/http/runtimes/h3-web.mjs.map +1 -0
  105. package/dist/http/runtimes/h3.d.mts +10 -4
  106. package/dist/http/runtimes/h3.d.mts.map +1 -1
  107. package/dist/http/runtimes/h3.mjs +2 -2
  108. package/dist/http/runtimes/h3.mjs.map +1 -1
  109. package/dist/{index-zIcb4wjg.d.mts → index-ChK5rOgq.d.mts} +2 -2
  110. package/dist/{index-zIcb4wjg.d.mts.map → index-ChK5rOgq.d.mts.map} +1 -1
  111. package/dist/index.d.mts +16 -15
  112. package/dist/index.mjs +2 -2
  113. package/dist/index.mjs.map +1 -1
  114. package/dist/{interfaces-DbTyKGdS.d.mts → interfaces-CayXPOAf.d.mts} +2 -1
  115. package/dist/{interfaces-DbTyKGdS.d.mts.map → interfaces-CayXPOAf.d.mts.map} +1 -1
  116. package/dist/{metadata-3QjXqAh_.mjs → metadata-WlPWz6fi.mjs} +2 -2
  117. package/dist/{metadata-3QjXqAh_.mjs.map → metadata-WlPWz6fi.mjs.map} +1 -1
  118. package/dist/module-registry-DmTQjSdD.mjs +12 -0
  119. package/dist/module-registry-DmTQjSdD.mjs.map +1 -0
  120. package/dist/{query-0FYLK2Mg.mjs → query-B2w_8bwe.mjs} +2 -2
  121. package/dist/{query-0FYLK2Mg.mjs.map → query-B2w_8bwe.mjs.map} +1 -1
  122. package/dist/rate-limit-oLL5EPUf.d.mts.map +1 -1
  123. package/dist/{reactivity-DWmLcN0A.d.mts → reactivity-XL0fFDvG.d.mts} +10 -16
  124. package/dist/reactivity-XL0fFDvG.d.mts.map +1 -0
  125. package/dist/reply-Dh15A_0R.mjs +12 -0
  126. package/dist/reply-Dh15A_0R.mjs.map +1 -0
  127. package/dist/reply-Elm9mc8Z.d.mts +63 -0
  128. package/dist/reply-Elm9mc8Z.d.mts.map +1 -0
  129. package/dist/request-id-IDobbxU-.d.mts.map +1 -1
  130. package/dist/rolldown-runtime-C4pdyXoH.mjs +11 -0
  131. package/dist/{router-builder-Bh3qSiDz.d.mts → router-builder-BHTp3zL3.d.mts} +2 -2
  132. package/dist/router-builder-BHTp3zL3.d.mts.map +1 -0
  133. package/dist/session-DSRA-PUX.d.mts.map +1 -1
  134. package/dist/{spa-BdvZFXJz.d.mts → spa-D8I4YnpL.d.mts} +2 -2
  135. package/dist/{spa-BdvZFXJz.d.mts.map → spa-D8I4YnpL.d.mts.map} +1 -1
  136. package/dist/{upload-Bc_rBRtE.d.mts → upload-CUyZ0zNt.d.mts} +9 -7
  137. package/dist/upload-CUyZ0zNt.d.mts.map +1 -0
  138. package/dist/upload-config-B6vGWI0_.mjs +12 -0
  139. package/dist/upload-config-B6vGWI0_.mjs.map +1 -0
  140. package/dist/validate-DoZDOhCi.d.mts.map +1 -1
  141. package/dist/{views-DcTVDiOh.d.mts → views-PFf-CBvN.d.mts} +7 -5
  142. package/dist/views-PFf-CBvN.d.mts.map +1 -0
  143. package/dist/web.d.mts +150 -0
  144. package/dist/web.d.mts.map +1 -0
  145. package/dist/web.mjs +12 -0
  146. package/dist/web.mjs.map +1 -0
  147. package/package.json +24 -15
  148. package/dist/adapter-D_uzU-QA.d.mts.map +0 -1
  149. package/dist/application-D5VVcJFf.mjs +0 -12
  150. package/dist/application-D5VVcJFf.mjs.map +0 -1
  151. package/dist/cache-BSFDtsEG.d.mts.map +0 -1
  152. package/dist/container-9AvE4y3u.mjs +0 -108
  153. package/dist/container-9AvE4y3u.mjs.map +0 -1
  154. package/dist/container-TWOUyR_0.d.mts.map +0 -1
  155. package/dist/context-CXLrVAx5.mjs +0 -12
  156. package/dist/context-CXLrVAx5.mjs.map +0 -1
  157. package/dist/core-IrvhPT6O.mjs +0 -13
  158. package/dist/core-IrvhPT6O.mjs.map +0 -1
  159. package/dist/decorators-ejABLo9H.d.mts.map +0 -1
  160. package/dist/env-CqRVEtoa.mjs +0 -13
  161. package/dist/http/middleware/csrf.mjs.map +0 -1
  162. package/dist/reactivity-DWmLcN0A.d.mts.map +0 -1
  163. package/dist/request-scope-D5j8kWQ7.mjs +0 -12
  164. package/dist/request-scope-D5j8kWQ7.mjs.map +0 -1
  165. package/dist/router-builder-Bh3qSiDz.d.mts.map +0 -1
  166. package/dist/upload-Bc_rBRtE.d.mts.map +0 -1
  167. package/dist/views-DcTVDiOh.d.mts.map +0 -1
@@ -36,6 +36,15 @@ interface ComputedRef<T = any> {
36
36
  * same as reading `.value`.
37
37
  */
38
38
  toJSON(): T;
39
+ /**
40
+ * Unsubscribe this computed from its reactive sources. Call when the
41
+ * computed's lifetime is shorter than its sources' (e.g. created
42
+ * per-request/per-tenant against app-lifetime refs) — without it the
43
+ * internal effect stays pinned in the sources' dep Sets forever.
44
+ * After disposal, reading `.value` still works but recomputes on every
45
+ * access and no longer tracks.
46
+ */
47
+ dispose(): void;
39
48
  }
40
49
  /**
41
50
  * Create a computed value that auto-recalculates when its reactive
@@ -70,21 +79,6 @@ type WatchSource<T> = Ref<T> | ComputedRef<T> | (() => T);
70
79
  * ```
71
80
  */
72
81
  declare function watch<T>(source: WatchSource<T>, callback: (newValue: T, oldValue: T) => void, options?: WatchOptions): () => void;
73
- /**
74
- * Create a deeply reactive proxy around a plain object. Property reads
75
- * are tracked, property writes trigger watchers and computed recalculations.
76
- *
77
- * @example
78
- * ```ts
79
- * const state = reactive({ users: 0, errors: 0 })
80
- * const errorRate = computed(() =>
81
- * state.users > 0 ? state.errors / state.users : 0
82
- * )
83
- * state.users = 100
84
- * state.errors = 5
85
- * console.log(errorRate.value) // 0.05
86
- * ```
87
- */
88
82
  declare function reactive<T extends Record<string, any>>(target: T): T;
89
83
  /** Check if a value is a Ref */
90
84
  declare function isRef(value: any): value is Ref;
@@ -94,4 +88,4 @@ declare function unref<T>(value: Ref<T> | T): T;
94
88
  declare function toRefs<T extends Record<string, any>>(obj: T): { [K in keyof T]: Ref<T[K]> };
95
89
  //#endregion
96
90
  export { isRef as a, toRefs as c, computed as i, unref as l, Ref as n, reactive as o, WatchOptions as r, ref as s, ComputedRef as t, watch as u };
97
- //# sourceMappingURL=reactivity-DWmLcN0A.d.mts.map
91
+ //# sourceMappingURL=reactivity-XL0fFDvG.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactivity-XL0fFDvG.d.mts","names":[],"sources":["../src/core/reactivity.ts"],"mappings":";;;AAgFA;;;;UAAiB,GAAA;EACf,KAAA,EAAO,CAAA;EASG;EAPV,SAAA,CAAU,EAAA,GAAK,QAAA,EAAU,CAAA,EAAG,QAAA,EAAU,CAAA;EAO3B;;;;;;EAAX,MAAA,IAAU,CAAA;AAAA;;;;;;AAAC;AAab;;;;iBAAgB,GAAA,IAAO,YAAA,EAAc,CAAA,GAAI,GAAA,CAAI,CAAA;AAAA,UAuC5B,WAAA;EAAA,SACN,KAAA,EAAO,CAAA;EAxC0B;;;;;EA8C1C,MAAA,IAAU,CAAC;EA9CiC;AAAA;AAuC9C;;;;;;EAgBE,OAAA;AAAA;;;;AAAO;AAeT;;;;;;;;iBAAgB,QAAA,IAAY,MAAA,QAAc,CAAA,GAAI,WAAA,CAAY,CAAA;AAAA,UA4DzC,YAAA;EA5DW;EA8D1B,SAAS;AAAA;AAAA,KAGN,WAAA,MAAiB,GAAA,CAAI,CAAA,IAAK,WAAA,CAAY,CAAA,WAAY,CAAA;AAjEI;AA4D3D;;;;AAEW;AACV;;;;;;;;AA/D0D,iBAiF3C,KAAA,IACd,MAAA,EAAQ,WAAA,CAAY,CAAA,GACpB,QAAA,GAAW,QAAA,EAAU,CAAA,EAAG,QAAA,EAAU,CAAA,WAClC,OAAA,GAAU,YAAA;AAAA,iBAwDI,QAAA,WAAmB,MAAA,eAAqB,MAAA,EAAQ,CAAA,GAAI,CAAA;;iBA8BpD,KAAA,CAAM,KAAA,QAAa,KAAA,IAAS,GAAG;;iBAK/B,KAAA,IAAS,KAAA,EAAO,GAAA,CAAI,CAAA,IAAK,CAAA,GAAI,CAAA;;iBAK7B,MAAA,WAAiB,MAAA,eAAqB,GAAA,EAAK,CAAA,iBAAkB,CAAA,GAAI,GAAA,CAAI,CAAA,CAAE,CAAA"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @forinda/kickjs v6.2.0
3
+ *
4
+ * Copyright (c) Felix Orinda
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ import{METADATA}from"./core/interfaces.mjs";import{createLogger}from"./core/logger.mjs";import{n as getClassMetaOrUndefined}from"./metadata-WlPWz6fi.mjs";import{i as requestStore}from"./context-Cd-p7DfC.mjs";const log=createLogger(`RequestScope`),preDestroyCache=new Map;function preDestroyMethod(ctor){let method=preDestroyCache.get(ctor);return method===void 0&&(method=getClassMetaOrUndefined(METADATA.PRE_DESTROY,ctor.prototype)??null,preDestroyCache.set(ctor,method)),method}function disposeRequestStore(store){if(!store.disposed&&(store.disposed=!0,store.instances.size!==0)){for(let instance of store.instances.values()){if(typeof instance!=`object`||!instance)continue;let method=preDestroyMethod(instance.constructor);if(!(!method||typeof instance[method]!=`function`))try{let result=instance[method]();result&&typeof result.then==`function`&&result.catch(err=>log.error(err,`@PreDestroy on ${instance.constructor.name} rejected`))}catch(err){log.error(err,`@PreDestroy on ${instance.constructor.name} threw`)}}store.instances.clear()}}const REQUEST_SCOPE_MIDDLEWARE_MARKER=Symbol.for(`@kickjs/requestScopeMiddleware`);function createRequestStore(requestId){return{requestId:requestId||crypto.randomUUID(),instances:new Map,values:new Map}}function requestScopeMiddleware(){let mw=(req,res,next)=>{let requestIdHeader=req.headers[`x-request-id`],requestId=(Array.isArray(requestIdHeader)?requestIdHeader[0]:requestIdHeader)||crypto.randomUUID(),store=createRequestStore(requestId);req.requestId=requestId,res.once(`close`,()=>disposeRequestStore(store)),requestStore.run(store,next)};return mw[REQUEST_SCOPE_MIDDLEWARE_MARKER]=!0,mw}function isRequestScopeMiddleware(value){return typeof value==`function`?value[REQUEST_SCOPE_MIDDLEWARE_MARKER]===!0:!1}const REPLY_BRAND=Symbol.for(`kickjs.reply`);function reply(status,body){return{[REPLY_BRAND]:!0,status,body}}reply.created=body=>reply(201,body),reply.accepted=body=>reply(202,body),reply.noContent=()=>reply(204,void 0);function isReply(value){return typeof value==`object`&&!!value&&value[REPLY_BRAND]===!0}function applyHandlerResult(ctx,result){return result===void 0?!1:isReply(result)?result.status===204?(ctx.noContent(),!0):(ctx.json(result.body,result.status),!0):(ctx.json(result),!0)}export{disposeRequestStore as a,createRequestStore as i,isReply as n,isRequestScopeMiddleware as o,reply as r,requestScopeMiddleware as s,applyHandlerResult as t};
12
+ //# sourceMappingURL=reply-Dh15A_0R.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-Dh15A_0R.mjs","names":[],"sources":["../src/http/middleware/request-scope.ts","../src/http/reply.ts"],"sourcesContent":["// Web Crypto via globalThis.crypto (randomUUID) — portable across\n// node/bun/deno/workers; node:crypto deliberately NOT imported here so this\n// module stays on the edge-safe request path.\nimport type { Request, Response, NextFunction } from 'express'\nimport { requestStore, type RequestStore } from '../request-store'\nimport { METADATA } from '../../core/interfaces'\nimport { getClassMetaOrUndefined } from '../../core/metadata'\nimport { createLogger } from '../../core/logger'\n\nconst log = createLogger('RequestScope')\n\n// Per-class @PreDestroy method-name cache: the metadata is immutable after\n// class definition, so pay the Reflect read once per class, not once per\n// instance per request. `null` = \"checked, none declared\".\nconst preDestroyCache = new Map<Function, string | symbol | null>()\n\nfunction preDestroyMethod(ctor: Function): string | symbol | null {\n let method = preDestroyCache.get(ctor)\n if (method === undefined) {\n method =\n getClassMetaOrUndefined<string | symbol>(METADATA.PRE_DESTROY, (ctor as any).prototype) ??\n null\n preDestroyCache.set(ctor, method)\n }\n return method\n}\n\n/**\n * Run `@PreDestroy` hooks on every REQUEST-scoped instance the request\n * created, then drop them. Called when the response closes (finished or\n * aborted) — the counterpart to `@PostConstruct`, closing the lifecycle gap\n * where per-request services holding transactions/handles/subscriptions were\n * silently dropped with no cleanup callback.\n *\n * Idempotent (guarded by `store.disposed`); hook errors are logged and\n * swallowed so one failing teardown can't break request completion. Async\n * hooks are fired without being awaited — the response is already gone.\n */\nexport function disposeRequestStore(store: RequestStore): void {\n if (store.disposed) return\n store.disposed = true\n if (store.instances.size === 0) return\n for (const instance of store.instances.values()) {\n if (instance === null || typeof instance !== 'object') continue\n const method = preDestroyMethod(instance.constructor)\n if (!method || typeof instance[method] !== 'function') continue\n try {\n const result = instance[method]()\n if (result && typeof result.then === 'function') {\n ;(result as Promise<void>).catch((err) =>\n log.error(err, `@PreDestroy on ${instance.constructor.name} rejected`),\n )\n }\n } catch (err) {\n log.error(err, `@PreDestroy on ${instance.constructor.name} threw`)\n }\n }\n store.instances.clear()\n}\n\n/**\n * Marker symbol stamped on the function returned by {@link requestScopeMiddleware}.\n *\n * `Application.setup()` uses {@link isRequestScopeMiddleware} to detect whether\n * the user-supplied middleware list already contains the request-scope wrapper,\n * and skips its automatic auto-mount when one is found. Lets adopters control\n * the exact position of the ALS frame in their pipeline (e.g., after a custom\n * tracing wrapper) without ending up with two nested frames.\n */\n// `Symbol.for(...)` returns a plain `symbol` (not `unique symbol`), but the\n// runtime detection marker doesn't need the unique nominal property — it only\n// needs the interned-slot reference equality that `Symbol.for` already provides.\nconst REQUEST_SCOPE_MIDDLEWARE_MARKER = Symbol.for('@kickjs/requestScopeMiddleware')\n\n/**\n * Build a fresh per-request store. Shared by {@link requestScopeMiddleware}\n * (Express) and by runtimes whose handler runs outside the connect-middleware\n * chain (e.g. Fastify), so both establish an identical ALS frame.\n */\nexport function createRequestStore(requestId?: string): RequestStore {\n return {\n requestId: requestId || crypto.randomUUID(),\n instances: new Map(),\n // Explicit generic locks the \"string keys only\" decision.\n values: new Map<string, unknown>(),\n }\n}\n\n/**\n * Wraps each request in an AsyncLocalStorage context.\n * Enables REQUEST-scoped DI and automatic requestId propagation to logs.\n *\n * Should be mounted early in the middleware pipeline (before route handlers).\n * `Application` mounts this automatically unless `contextStore: 'manual'` is set\n * or the user already includes one in their middleware list.\n */\nexport function requestScopeMiddleware() {\n const mw = (req: Request, res: Response, next: NextFunction) => {\n const requestIdHeader = req.headers['x-request-id']\n const requestId =\n (Array.isArray(requestIdHeader) ? requestIdHeader[0] : requestIdHeader) || crypto.randomUUID()\n const store = createRequestStore(requestId)\n // Surface the requestId on req so the standalone requestId() middleware\n // (when also mounted) reuses this value instead of generating a divergent\n // second one. Without this, log lines that read from the ALS store would\n // disagree with the X-Request-Id response header for any request that\n // didn't carry an inbound x-request-id header.\n ;(req as Request & { requestId?: string }).requestId = requestId\n // 'close' fires once the response finished OR the client aborted — run\n // @PreDestroy teardown for the request's scoped instances either way.\n res.once('close', () => disposeRequestStore(store))\n // Pass `next` directly — `run` invokes it with no args, so the arrow\n // wrapper previously allocated per request added nothing.\n requestStore.run(store, next)\n }\n ;(mw as unknown as Record<symbol, unknown>)[REQUEST_SCOPE_MIDDLEWARE_MARKER] = true\n return mw\n}\n\n/**\n * Returns `true` when `value` is the function produced by {@link requestScopeMiddleware}.\n *\n * Detection uses a `Symbol.for(...)` marker so the check survives different\n * copies of `@forinda/kickjs` loaded under different module identities (e.g.,\n * a published package alongside a workspace-linked one during local dev).\n */\nexport function isRequestScopeMiddleware(value: unknown): boolean {\n if (typeof value !== 'function') return false\n return (value as unknown as Record<symbol, unknown>)[REQUEST_SCOPE_MIDDLEWARE_MARKER] === true\n}\n","// Return-value handler support (response-inference-design.md §3.1).\n//\n// Handlers may RETURN their response payload instead of calling `ctx.json`:\n// the runtime auto-sends it when the pipeline finishes with nothing written.\n// `reply(status, body)` wraps a payload with a non-200 status while staying\n// transparent to type inference (`Reply<201, Task>` carries both statically).\n//\n// Edge-safe: no node imports — shared by all four runtimes including the\n// `@forinda/kickjs/web` entry.\n\nimport type { RequestContext } from './context'\n\n// `Symbol.for` so the brand survives duplicate module copies (workspace-linked\n// + published package in one process — same rationale as the request-scope\n// middleware marker).\nconst REPLY_BRAND = Symbol.for('kickjs.reply')\n\n/**\n * A status-carrying response payload for return-value handlers. Create via\n * {@link reply} — the brand is what runtimes detect, and the generics are\n * what the `kick/routes` response typegen unwraps (`Reply<S, T>` → `T`).\n */\nexport interface Reply<S extends number = number, T = unknown> {\n readonly [REPLY_BRAND]: true\n readonly status: S\n readonly body: T\n}\n\n/**\n * Wrap a return-value handler's payload with an explicit status code:\n *\n * ```ts\n * @Post('/')\n * async create(ctx: RequestContext) {\n * return reply(201, await this.tasks.create(ctx.body))\n * }\n * ```\n */\nexport function reply<S extends number, T>(status: S, body: T): Reply<S, T> {\n return { [REPLY_BRAND]: true, status, body }\n}\n\n/** `reply(201, body)` */\nreply.created = <T>(body: T): Reply<201, T> => reply(201, body)\n/** `reply(202, body)` */\nreply.accepted = <T>(body: T): Reply<202, T> => reply(202, body)\n/** Empty 204 — maps to `ctx.noContent()`. */\nreply.noContent = (): Reply<204, undefined> => reply(204, undefined)\n\n/**\n * The statically-inferred response type of a controller handler — what\n * `kick typegen` emits into `KickRoutes[...].response`:\n *\n * - `Awaited<ReturnType>` of the method\n * - `Reply<S, T>` unwraps to `T`\n * - `void`/`undefined` members are dropped (imperative `ctx.json` branches);\n * a handler that never returns a value stays `unknown`, matching the\n * pre-inference emission\n *\n * ```ts\n * type R = InferHandlerResponse<UsersController['get']> // → User\n * ```\n */\nexport type InferHandlerResponse<H> = H extends (...args: never[]) => infer R\n ? [Exclude<Awaited<R>, void | undefined>] extends [never]\n ? unknown\n : UnwrapReply<Exclude<Awaited<R>, void | undefined>>\n : unknown\n\ntype UnwrapReply<A> = A extends Reply<number, infer B> ? B : A\n\nexport function isReply(value: unknown): value is Reply {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<symbol, unknown>)[REPLY_BRAND] === true\n )\n}\n\n/**\n * Send a handler's RETURN value when the pipeline finished without anything\n * having written a response. Callers guard on \"driver/response unsettled\" —\n * this only decides how to send:\n *\n * - `undefined` → not handled (returns false; runtime keeps today's behavior)\n * - `Reply` wrapper → status + body (204 → `ctx.noContent()`)\n * - anything else → `ctx.json(value)` (200)\n *\n * Returns true when a response was produced.\n */\nexport function applyHandlerResult(ctx: RequestContext, result: unknown): boolean {\n if (result === undefined) return false\n if (isReply(result)) {\n // Only 204 maps to noContent — an undefined body must NOT coerce the\n // declared status (reply(304, undefined) keeps its 304; the json body\n // is simply empty).\n if (result.status === 204) {\n ctx.noContent()\n return true\n }\n ctx.json(result.body, result.status)\n return true\n }\n ctx.json(result)\n return true\n}\n"],"mappings":";;;;;;;;;;gNASA,MAAM,IAAM,aAAa,cAAc,EAKjC,gBAAkB,IAAI,IAE5B,SAAS,iBAAiB,KAAwC,CAChE,IAAI,OAAS,gBAAgB,IAAI,IAAI,EAOrC,OANI,SAAW,IAAA,KACb,OACE,wBAAyC,SAAS,YAAc,KAAa,SAAS,GACtF,KACF,gBAAgB,IAAI,KAAM,MAAM,GAE3B,MACT,CAaA,SAAgB,oBAAoB,MAA2B,CACzD,UAAM,WACV,MAAM,SAAW,GACb,MAAM,UAAU,OAAS,GAC7B,KAAK,IAAM,YAAY,MAAM,UAAU,OAAO,EAAG,CAC/C,GAAyB,OAAO,UAAa,WAAzC,SAAmD,SACvD,IAAM,OAAS,iBAAiB,SAAS,WAAW,EAChD,MAAC,QAAU,OAAO,SAAS,SAAY,YAC3C,GAAI,CACF,IAAM,OAAS,SAAS,OAAO,CAAC,EAC5B,QAAU,OAAO,OAAO,MAAS,YAClC,OAA0B,MAAO,KAChC,IAAI,MAAM,IAAK,kBAAkB,SAAS,YAAY,KAAK,UAAU,CACvE,CAEJ,OAAS,IAAK,CACZ,IAAI,MAAM,IAAK,kBAAkB,SAAS,YAAY,KAAK,OAAO,CACpE,CACF,CACA,MAAM,UAAU,MAAM,CADtB,CAEF,CAcA,MAAM,gCAAkC,OAAO,IAAI,gCAAgC,EAOnF,SAAgB,mBAAmB,UAAkC,CACnE,MAAO,CACL,UAAW,WAAa,OAAO,WAAW,EAC1C,UAAW,IAAI,IAEf,OAAQ,IAAI,GACd,CACF,CAUA,SAAgB,wBAAyB,CACvC,IAAM,IAAM,IAAc,IAAe,OAAuB,CAC9D,IAAM,gBAAkB,IAAI,QAAQ,gBAC9B,WACH,MAAM,QAAQ,eAAe,EAAI,gBAAgB,GAAK,kBAAoB,OAAO,WAAW,EACzF,MAAQ,mBAAmB,SAAS,EAMzC,IAA0C,UAAY,UAGvD,IAAI,KAAK,YAAe,oBAAoB,KAAK,CAAC,EAGlD,aAAa,IAAI,MAAO,IAAI,CAC9B,EAEA,MADC,IAA2C,iCAAmC,GACxE,EACT,CASA,SAAgB,yBAAyB,MAAyB,CAEhE,OADI,OAAO,OAAU,WACb,MAA6C,mCAAqC,GADlD,EAE1C,CClHA,MAAM,YAAc,OAAO,IAAI,cAAc,EAuB7C,SAAgB,MAA2B,OAAW,KAAsB,CAC1E,MAAO,EAAG,aAAc,GAAM,OAAQ,IAAK,CAC7C,CAGA,MAAM,QAAc,MAA2B,MAAM,IAAK,IAAI,EAE9D,MAAM,SAAe,MAA2B,MAAM,IAAK,IAAI,EAE/D,MAAM,cAAyC,MAAM,IAAK,IAAA,EAAS,EAwBnE,SAAgB,QAAQ,MAAgC,CACtD,OACE,OAAO,OAAU,YACjB,OACC,MAAkC,eAAiB,EAExD,CAaA,SAAgB,mBAAmB,IAAqB,OAA0B,CAchF,OAbI,SAAW,IAAA,GAAkB,GAC7B,QAAQ,MAAM,EAIZ,OAAO,SAAW,KACpB,IAAI,UAAU,EACP,KAET,IAAI,KAAK,OAAO,KAAM,OAAO,MAAM,EAC5B,KAET,IAAI,KAAK,MAAM,EACR,GACT"}
@@ -0,0 +1,63 @@
1
+
2
+ import { T as RequestContext } from "./adapter-DCfEFZMY.mjs";
3
+
4
+ //#region src/http/reply.d.ts
5
+ declare const REPLY_BRAND: unique symbol;
6
+ /**
7
+ * A status-carrying response payload for return-value handlers. Create via
8
+ * {@link reply} — the brand is what runtimes detect, and the generics are
9
+ * what the `kick/routes` response typegen unwraps (`Reply<S, T>` → `T`).
10
+ */
11
+ interface Reply<S extends number = number, T = unknown> {
12
+ readonly [REPLY_BRAND]: true;
13
+ readonly status: S;
14
+ readonly body: T;
15
+ }
16
+ /**
17
+ * Wrap a return-value handler's payload with an explicit status code:
18
+ *
19
+ * ```ts
20
+ * @Post('/')
21
+ * async create(ctx: RequestContext) {
22
+ * return reply(201, await this.tasks.create(ctx.body))
23
+ * }
24
+ * ```
25
+ */
26
+ declare function reply<S extends number, T>(status: S, body: T): Reply<S, T>;
27
+ declare namespace reply {
28
+ var created: <T>(body: T) => Reply<201, T>;
29
+ var accepted: <T>(body: T) => Reply<202, T>;
30
+ var noContent: () => Reply<204, undefined>;
31
+ }
32
+ /**
33
+ * The statically-inferred response type of a controller handler — what
34
+ * `kick typegen` emits into `KickRoutes[...].response`:
35
+ *
36
+ * - `Awaited<ReturnType>` of the method
37
+ * - `Reply<S, T>` unwraps to `T`
38
+ * - `void`/`undefined` members are dropped (imperative `ctx.json` branches);
39
+ * a handler that never returns a value stays `unknown`, matching the
40
+ * pre-inference emission
41
+ *
42
+ * ```ts
43
+ * type R = InferHandlerResponse<UsersController['get']> // → User
44
+ * ```
45
+ */
46
+ type InferHandlerResponse<H> = H extends ((...args: never[]) => infer R) ? [Exclude<Awaited<R>, void | undefined>] extends [never] ? unknown : UnwrapReply<Exclude<Awaited<R>, void | undefined>> : unknown;
47
+ type UnwrapReply<A> = A extends Reply<number, infer B> ? B : A;
48
+ declare function isReply(value: unknown): value is Reply;
49
+ /**
50
+ * Send a handler's RETURN value when the pipeline finished without anything
51
+ * having written a response. Callers guard on "driver/response unsettled" —
52
+ * this only decides how to send:
53
+ *
54
+ * - `undefined` → not handled (returns false; runtime keeps today's behavior)
55
+ * - `Reply` wrapper → status + body (204 → `ctx.noContent()`)
56
+ * - anything else → `ctx.json(value)` (200)
57
+ *
58
+ * Returns true when a response was produced.
59
+ */
60
+ declare function applyHandlerResult(ctx: RequestContext, result: unknown): boolean;
61
+ //#endregion
62
+ export { reply as a, isReply as i, Reply as n, applyHandlerResult as r, InferHandlerResponse as t };
63
+ //# sourceMappingURL=reply-Elm9mc8Z.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-Elm9mc8Z.d.mts","names":[],"sources":["../src/http/reply.ts"],"mappings":";;;;cAeM,WAAA;;AALyC;;;;UAY9B,KAAA;EAAA,UACL,WAAA;EAAA,SACD,MAAA,EAAQ,CAAA;EAAA,SACR,IAAA,EAAM,CAAA;AAAA;;;;;;;;;;;iBAaD,KAAA,sBAA2B,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,CAAA,GAAI,KAAA,CAAM,CAAA,EAAG,CAAA;AAAA,kBAAzD,KAAA;EAAA,iBAKE,IAAA,EAAQ,CAAA,KAAI,KAAA,MAAW,CAAA;EAAA,kBAEtB,IAAA,EAAQ,CAAA,KAAI,KAAA,MAAW,CAAA;EAAA,qBAEpB,KAAA;AAAA;;;;;;;;;;;;;;;KAgBV,oBAAA,MAA0B,CAAA,cAAc,IAAA,0BAC/C,OAAA,CAAQ,OAAA,CAAQ,CAAA,kDAEf,WAAA,CAAY,OAAA,CAAQ,OAAA,CAAQ,CAAA;AAAA,KAG7B,WAAA,MAAiB,CAAA,SAAU,KAAA,oBAAyB,CAAA,GAAI,CAAA;AAAA,iBAE7C,OAAA,CAAQ,KAAA,YAAiB,KAAA,IAAS,KAAK;AAjCmB;;;;;;;;;;;AAAA,iBAoD1D,kBAAA,CAAmB,GAAA,EAAK,cAAc,EAAE,MAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"request-id-IDobbxU-.d.mts","names":[],"sources":["../src/http/middleware/request-id.ts"],"mappings":";;;;cAGa,iBAAA;;AAAb;;;;AAA8B;AAY9B;;;;iBAAgB,SAAA,KAAS,GAAA,EACV,OAAA,EAAO,GAAA,EAAO,QAAA,EAAQ,IAAA,EAAQ,YAAA"}
1
+ {"version":3,"file":"request-id-IDobbxU-.d.mts","names":[],"sources":["../src/http/middleware/request-id.ts"],"mappings":";;;;cAEa,iBAAA;;AAAb;;;;AAA8B;AAY9B;;;;iBAAgB,SAAA,KAAS,GAAA,EACV,OAAA,EAAO,GAAA,EAAO,QAAA,EAAQ,IAAA,EAAQ,YAAA"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @forinda/kickjs v6.2.0
3
+ *
4
+ * Copyright (c) Felix Orinda
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ import{createRequire}from"node:module";var __require=createRequire(import.meta.url);export{__require as t};
@@ -1,5 +1,5 @@
1
1
 
2
- import { J as SourcedRegistration, m as RouteEntry } from "./adapter-D_uzU-QA.mjs";
2
+ import { J as SourcedRegistration, m as RouteEntry } from "./adapter-DCfEFZMY.mjs";
3
3
 
4
4
  //#region src/http/router-builder.d.ts
5
5
  /** @internal — set by Application.setup() before each `mod.routes()` call. */
@@ -36,4 +36,4 @@ interface BuildRoutesOptions {
36
36
  declare function buildRouteTable(controllerClass: any, options?: BuildRoutesOptions): RouteEntry[];
37
37
  //#endregion
38
38
  export { _setExternalContributorSources as n, buildRouteTable as r, BuildRoutesOptions as t };
39
- //# sourceMappingURL=router-builder-Bh3qSiDz.d.mts.map
39
+ //# sourceMappingURL=router-builder-BHTp3zL3.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router-builder-BHTp3zL3.d.mts","names":[],"sources":["../src/http/router-builder.ts"],"mappings":";;;;;iBA8BgB,8BAAA,CAA+B,OAAuC,WAArB,mBAAmB;AAAA,UAInE,kBAAA;;;AAJqE;AAItF;;;EAOE,eAAA,YAA2B,mBAAmB;AAAA;AAuBhD;;;;;;;;;AAGa;;;;;;;;;;;AAHb,iBAAgB,eAAA,CACd,eAAA,OACA,OAAA,GAAS,kBAAA,GACR,UAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"session-DSRA-PUX.d.mts","names":[],"sources":["../src/http/middleware/session.ts"],"mappings":";;;;UAGiB,WAAA;EAAA,CACd,GAAW;AAAA;AAAA,UAGG,YAAA;EACf,GAAA,CAAI,GAAA,WAAc,OAAA,CAAQ,WAAA;EAC1B,GAAA,CAAI,GAAA,UAAa,IAAA,EAAM,WAAA,EAAa,MAAA,WAAiB,OAAA;EACrD,OAAA,CAAQ,GAAA,WAAc,OAAA;EACtB,KAAA,EAAO,GAAA,UAAa,MAAA,WAAiB,OAAA;AAAA;AAAA,UAGtB,OAAA;EACf,EAAA;EACA,IAAA,EAAM,WAAA;EACN,UAAA,IAAc,OAAA;EACd,OAAA,IAAW,OAAA;EACX,IAAA,IAAQ,OAAA;AAAA;AAAA,UAGO,cAAA;EAX6B;EAa5C,MAAA;EAhBI;EAkBJ,UAAA;EAlB0B;EAoB1B,MAAA;EAnBI;EAqBJ,OAAA;EArBiB;EAuBjB,iBAAA;EAvBqD;EAyBrD,MAAA;IACE,QAAA;IACA,MAAA;IACA,QAAA;IACA,IAAA;IACA,MAAA;EAAA;EA5B0C;EA+B5C,KAAA,GAAQ,YAAY;AAAA;;;;;;;;;;;;;;;;;;;AAvBL;AAGjB;;;;;iBAiJgB,OAAA,CAAQ,OAAA,EAAS,cAAA,IAAc,GAAA,EAoB1B,OAAA,EAAO,GAAA,EAAO,QAAA,EAAQ,IAAA,EAAQ,YAAA,KAAY,OAAA"}
1
+ {"version":3,"file":"session-DSRA-PUX.d.mts","names":[],"sources":["../src/http/middleware/session.ts"],"mappings":";;;;UAKiB,WAAA;EAAA,CACd,GAAW;AAAA;AAAA,UAGG,YAAA;EACf,GAAA,CAAI,GAAA,WAAc,OAAA,CAAQ,WAAA;EAC1B,GAAA,CAAI,GAAA,UAAa,IAAA,EAAM,WAAA,EAAa,MAAA,WAAiB,OAAA;EACrD,OAAA,CAAQ,GAAA,WAAc,OAAA;EACtB,KAAA,EAAO,GAAA,UAAa,MAAA,WAAiB,OAAA;AAAA;AAAA,UAGtB,OAAA;EACf,EAAA;EACA,IAAA,EAAM,WAAA;EACN,UAAA,IAAc,OAAA;EACd,OAAA,IAAW,OAAA;EACX,IAAA,IAAQ,OAAA;AAAA;AAAA,UAGO,cAAA;EAX6B;EAa5C,MAAA;EAhBI;EAkBJ,UAAA;EAlB0B;EAoB1B,MAAA;EAnBI;EAqBJ,OAAA;EArBiB;EAuBjB,iBAAA;EAvBqD;EAyBrD,MAAA;IACE,QAAA;IACA,MAAA;IACA,QAAA;IACA,IAAA;IACA,MAAA;EAAA;EA5B0C;EA+B5C,KAAA,GAAQ,YAAY;AAAA;;;;;;;;;;;;;;;;;;;AAvBL;AAGjB;;;;;iBA2JgB,OAAA,CAAQ,OAAA,EAAS,cAAA,IAAc,GAAA,EAoB1B,OAAA,EAAO,GAAA,EAAO,QAAA,EAAQ,IAAA,EAAQ,YAAA,KAAY,OAAA"}
@@ -1,5 +1,5 @@
1
1
 
2
- import { r as AppAdapter, t as AdapterContext } from "./adapter-D_uzU-QA.mjs";
2
+ import { r as AppAdapter, t as AdapterContext } from "./adapter-DCfEFZMY.mjs";
3
3
 
4
4
  //#region src/http/middleware/spa.d.ts
5
5
  interface SpaAdapterOptions {
@@ -99,4 +99,4 @@ declare class SpaAdapter implements AppAdapter {
99
99
  }
100
100
  //#endregion
101
101
  export { SpaAdapterOptions as n, SpaAdapter as t };
102
- //# sourceMappingURL=spa-BdvZFXJz.d.mts.map
102
+ //# sourceMappingURL=spa-D8I4YnpL.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spa-BdvZFXJz.d.mts","names":[],"sources":["../src/http/middleware/spa.ts"],"mappings":";;;;UAMiB,iBAAA;;AAAjB;;;;;;;;;;AAiDmB;AAkCnB;EArEE,SAAA;;;;;;;;;;;EAYA,SAAA;EA0DA;;;;;;;;;EA/CA,OAAA;EAiEA;;;;EA3DA,YAAA;EAoGc;;;;EA9Fd,iBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkCW,UAAA,YAAsB,UAAA;EAAA,QASb,OAAA;EARpB,IAAA;EAAA,QACQ,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QACA,YAAA;EAAA,QACA,iBAAA;EAAA,QACA,SAAA;EAER,WAAA,CAAoB,OAAA,GAAS,iBAAA;EAU7B,WAAA;IAAc;EAAA,GAAO,cAAA;EAyCrB,WAAA;IAAc;EAAA,GAAO,cAAA;AAAA"}
1
+ {"version":3,"file":"spa-D8I4YnpL.d.mts","names":[],"sources":["../src/http/middleware/spa.ts"],"mappings":";;;;UAMiB,iBAAA;;AAAjB;;;;;;;;;;AAiDmB;AAkCnB;EArEE,SAAA;;;;;;;;;;;EAYA,SAAA;EA0DA;;;;;;;;;EA/CA,OAAA;EAiEA;;;;EA3DA,YAAA;EAoGc;;;;EA9Fd,iBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkCW,UAAA,YAAsB,UAAA;EAAA,QASb,OAAA;EARpB,IAAA;EAAA,QACQ,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QACA,YAAA;EAAA,QACA,iBAAA;EAAA,QACA,SAAA;EAER,WAAA,CAAoB,OAAA,GAAS,iBAAA;EAU7B,WAAA;IAAc;EAAA,GAAO,cAAA;EAyCrB,WAAA;IAAc;EAAA,GAAO,cAAA;AAAA"}
@@ -1,9 +1,9 @@
1
1
 
2
- import { g as FileUploadConfig, o as BaseUploadOptions } from "./decorators-ejABLo9H.mjs";
2
+ import { g as FileUploadConfig, o as BaseUploadOptions } from "./decorators-DKjpujFp.mjs";
3
3
  import { NextFunction, Request, RequestHandler, Response } from "express";
4
4
  import { Options } from "multer";
5
5
 
6
- //#region src/http/middleware/upload.d.ts
6
+ //#region src/http/middleware/upload-config.d.ts
7
7
  /**
8
8
  * Resolves a list of file type identifiers to MIME type strings.
9
9
  * Accepts short extensions (`'jpg'`, `'pdf'`) or full MIME types (`'image/jpeg'`).
@@ -19,8 +19,8 @@ declare function resolveMimeTypes(types: string[]): string[];
19
19
  * Build a runtime-agnostic `(mimetype, filename) => boolean` file-type filter
20
20
  * from `allowedTypes` (a predicate, or a list of extensions / MIME types /
21
21
  * wildcards). Returned by both the multer middleware (Express) and the
22
- * Fastify / h3 multipart paths so the accept/reject rule stays identical
23
- * across engines. No `allowedTypes` → accept everything.
22
+ * Fastify / h3 / web multipart paths so the accept/reject rule stays
23
+ * identical across engines. No `allowedTypes` → accept everything.
24
24
  */
25
25
  declare function buildFileTypeFilter(allowedTypes: BaseUploadOptions['allowedTypes'], customMimeMap?: Record<string, string>): (mimetype: string, filename: string) => boolean;
26
26
  /** A multer-shaped uploaded file — what `ctx.file` / `ctx.files` expose. */
@@ -44,12 +44,14 @@ interface RawUploadPart {
44
44
  * the multer-shaped `file` / `files` for `ctx`. Enforces the field name, type
45
45
  * filter, per-file size limit, and (array mode) max count — throwing
46
46
  * `HttpException` on a violation, mirroring the Express/multer error path.
47
- * Used by the Fastify and h3 runtimes; Express keeps using multer directly.
47
+ * Used by the Fastify, h3 and web runtimes; Express keeps using multer directly.
48
48
  */
49
49
  declare function applyUploadConfig(parts: RawUploadPart[], config: FileUploadConfig): {
50
50
  file?: UploadedFileLike;
51
51
  files?: UploadedFileLike[];
52
52
  };
53
+ //#endregion
54
+ //#region src/http/middleware/upload.d.ts
53
55
  /**
54
56
  * Upload options for the middleware.
55
57
  * Extends BaseUploadOptions from core (shared with @FileUpload decorator)
@@ -110,5 +112,5 @@ declare const upload: {
110
112
  none: typeof none;
111
113
  };
112
114
  //#endregion
113
- export { buildFileTypeFilter as a, resolveMimeTypes as c, applyUploadConfig as i, upload as l, UploadOptions as n, buildUploadMiddleware as o, UploadedFileLike as r, cleanupFiles as s, RawUploadPart as t };
114
- //# sourceMappingURL=upload-Bc_rBRtE.d.mts.map
115
+ export { RawUploadPart as a, buildFileTypeFilter as c, upload as i, resolveMimeTypes as l, buildUploadMiddleware as n, UploadedFileLike as o, cleanupFiles as r, applyUploadConfig as s, UploadOptions as t };
116
+ //# sourceMappingURL=upload-CUyZ0zNt.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-CUyZ0zNt.d.mts","names":[],"sources":["../src/http/middleware/upload-config.ts","../src/http/middleware/upload.ts"],"mappings":";;;;;;;;;;AAuEA;;;;AAAgD;AAchD;iBAdgB,gBAAA,CAAiB,KAAe;;;;;;;;iBAchC,mBAAA,CACd,YAAA,EAAc,iBAAA,kBACd,aAAA,GAAgB,MAAM,oBACpB,QAAA,UAAkB,QAAA;;UAYL,gBAAA;EACf,SAAA;EACA,YAAA;EACA,QAAA;EACA,QAAA;EACA,IAAA;EACA,MAAA,EAAQ,MAAM;AAAA;;UAIC,aAAA;EACf,SAAA;EACA,QAAA;EACA,QAAA;EACA,MAAA,EAAQ,MAAM;AAAA;;;;;;;;iBAYA,iBAAA,CACd,KAAA,EAAO,aAAA,IACP,MAAA,EAAQ,gBAAA;EACL,IAAA,GAAO,gBAAA;EAAkB,KAAA,GAAQ,gBAAA;AAAA;;;;;AA1DtC;;;UCtBiB,aAAA,SAAsB,iBAAiB;EDsBR;ECpB9C,OAAA,GAAU,OAAA;EDkCuB;EChCjC,IAAA;AAAA;;;;;;;;ADmCoC;AAYtC;;;;iBCLS,MAAA,CAAO,SAAA,UAAmB,OAAA,GAAS,aAAA,GAAqB,cAAc;;;;iBAQtE,KAAA,CAAM,SAAA,UAAmB,QAAA,WAAe,OAAA,GAAS,aAAA,GAAqB,cAAc;;;;iBAQpF,IAAA,CAAK,OAAA,GAAS,aAAA,GAAqB,cAAc;ADD1D;;;;;;;;;;AAIgB;AAYhB;;;AAhBA,iBCoBgB,YAAA,KAAY,GAAA,EACb,OAAA,EAAO,GAAA,EAAO,QAAA,EAAQ,IAAA,EAAQ,YAAA;;;;;;iBA+B7B,qBAAA,CAAsB,MAAA,EAAQ,gBAAA,GAAmB,cAAc;;cAmBlE,MAAA"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @forinda/kickjs v6.2.0
3
+ *
4
+ * Copyright (c) Felix Orinda
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ import{HttpException,HttpStatus}from"./core/errors.mjs";const MIME_MAP={jpg:`image/jpeg`,jpeg:`image/jpeg`,png:`image/png`,gif:`image/gif`,webp:`image/webp`,svg:`image/svg+xml`,bmp:`image/bmp`,ico:`image/x-icon`,tiff:`image/tiff`,tif:`image/tiff`,avif:`image/avif`,pdf:`application/pdf`,doc:`application/msword`,docx:`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,xls:`application/vnd.ms-excel`,xlsx:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,ppt:`application/vnd.ms-powerpoint`,pptx:`application/vnd.openxmlformats-officedocument.presentationml.presentation`,odt:`application/vnd.oasis.opendocument.text`,ods:`application/vnd.oasis.opendocument.spreadsheet`,odp:`application/vnd.oasis.opendocument.presentation`,rtf:`application/rtf`,txt:`text/plain`,csv:`text/csv`,zip:`application/zip`,gz:`application/gzip`,tar:`application/x-tar`,rar:`application/vnd.rar`,"7z":`application/x-7z-compressed`,mp3:`audio/mpeg`,wav:`audio/wav`,ogg:`audio/ogg`,flac:`audio/flac`,aac:`audio/aac`,mp4:`video/mp4`,webm:`video/webm`,avi:`video/x-msvideo`,mov:`video/quicktime`,mkv:`video/x-matroska`,json:`application/json`,xml:`application/xml`,html:`text/html`};function resolveMimeTypes(types){return types.map(t=>{let lower=t.toLowerCase().replace(/^\./,``);return MIME_MAP[lower]??t})}function buildFileTypeFilter(allowedTypes,customMimeMap){if(!allowedTypes)return()=>!0;if(typeof allowedTypes==`function`)return allowedTypes;let mimeMap=customMimeMap?{...MIME_MAP,...customMimeMap}:MIME_MAP,resolved=allowedTypes.map(t=>mimeMap[t.toLowerCase().replace(/^\./,``)]??t);return mimetype=>resolved.some(type=>type.endsWith(`/*`)?mimetype.startsWith(type.replace(`/*`,`/`)):mimetype===type)}function applyUploadConfig(parts,config){if(config.mode===`none`)return{};let field=config.fieldName??`file`,maxSize=config.maxSize??5242880,typeAllowed=buildFileTypeFilter(config.allowedTypes,config.customMimeMap),files=parts.filter(p=>p.fieldname===field).map(p=>{if(!typeAllowed(p.mimetype,p.filename))throw new HttpException(HttpStatus.UNSUPPORTED_MEDIA_TYPE,`File type ${p.mimetype} is not allowed`);if(p.buffer.length>maxSize)throw new HttpException(HttpStatus.PAYLOAD_TOO_LARGE,`File ${p.filename} exceeds the ${maxSize}-byte limit`);return{fieldname:p.fieldname,originalname:p.filename,encoding:`7bit`,mimetype:p.mimetype,size:p.buffer.length,buffer:p.buffer}});if(config.mode===`single`)return{file:files[0]};let maxCount=config.maxCount??10;return{files:files.slice(0,maxCount)}}export{buildFileTypeFilter as n,resolveMimeTypes as r,applyUploadConfig as t};
12
+ //# sourceMappingURL=upload-config-B6vGWI0_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-config-B6vGWI0_.mjs","names":[],"sources":["../src/http/middleware/upload-config.ts"],"sourcesContent":["// Pure (edge-safe) upload core — the engine-neutral half of the upload\n// middleware. Extracted from `upload.ts` so the `@forinda/kickjs/web` entry\n// graph can validate/shape buffered multipart parts WITHOUT dragging in\n// upload.ts's node-only surface (multer peer loading via `node:module`,\n// disk cleanup via `node:fs/promises`). `upload.ts` re-exports everything\n// here, so existing import sites are unchanged.\n\nimport { HttpException, HttpStatus } from '../../core/errors'\nimport type { BaseUploadOptions, FileUploadConfig } from '../../core/decorators'\n\nexport const MIME_MAP: Record<string, string> = {\n // Images\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n bmp: 'image/bmp',\n ico: 'image/x-icon',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n avif: 'image/avif',\n // Documents\n pdf: 'application/pdf',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n odt: 'application/vnd.oasis.opendocument.text',\n ods: 'application/vnd.oasis.opendocument.spreadsheet',\n odp: 'application/vnd.oasis.opendocument.presentation',\n rtf: 'application/rtf',\n txt: 'text/plain',\n csv: 'text/csv',\n // Archives\n zip: 'application/zip',\n gz: 'application/gzip',\n tar: 'application/x-tar',\n rar: 'application/vnd.rar',\n '7z': 'application/x-7z-compressed',\n // Audio\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n flac: 'audio/flac',\n aac: 'audio/aac',\n // Video\n mp4: 'video/mp4',\n webm: 'video/webm',\n avi: 'video/x-msvideo',\n mov: 'video/quicktime',\n mkv: 'video/x-matroska',\n // Other\n json: 'application/json',\n xml: 'application/xml',\n html: 'text/html',\n}\n\n/**\n * Resolves a list of file type identifiers to MIME type strings.\n * Accepts short extensions (`'jpg'`, `'pdf'`) or full MIME types (`'image/jpeg'`).\n *\n * @example\n * ```ts\n * resolveMimeTypes(['jpg', 'png', 'application/pdf'])\n * // → ['image/jpeg', 'image/png', 'application/pdf']\n * ```\n */\nexport function resolveMimeTypes(types: string[]): string[] {\n return types.map((t) => {\n const lower = t.toLowerCase().replace(/^\\./, '')\n return MIME_MAP[lower] ?? t\n })\n}\n\n/**\n * Build a runtime-agnostic `(mimetype, filename) => boolean` file-type filter\n * from `allowedTypes` (a predicate, or a list of extensions / MIME types /\n * wildcards). Returned by both the multer middleware (Express) and the\n * Fastify / h3 / web multipart paths so the accept/reject rule stays\n * identical across engines. No `allowedTypes` → accept everything.\n */\nexport function buildFileTypeFilter(\n allowedTypes: BaseUploadOptions['allowedTypes'],\n customMimeMap?: Record<string, string>,\n): (mimetype: string, filename: string) => boolean {\n if (!allowedTypes) return () => true\n if (typeof allowedTypes === 'function') return allowedTypes\n const mimeMap = customMimeMap ? { ...MIME_MAP, ...customMimeMap } : MIME_MAP\n const resolved = allowedTypes.map((t) => mimeMap[t.toLowerCase().replace(/^\\./, '')] ?? t)\n return (mimetype: string) =>\n resolved.some((type) =>\n type.endsWith('/*') ? mimetype.startsWith(type.replace('/*', '/')) : mimetype === type,\n )\n}\n\n/** A multer-shaped uploaded file — what `ctx.file` / `ctx.files` expose. */\nexport interface UploadedFileLike {\n fieldname: string\n originalname: string\n encoding: string\n mimetype: string\n size: number\n buffer: Buffer\n}\n\n/** A buffered multipart file part, as the runtime hands it to {@link applyUploadConfig}. */\nexport interface RawUploadPart {\n fieldname: string\n filename: string\n mimetype: string\n buffer: Buffer\n}\n\nconst DEFAULT_MAX_SIZE = 5 * 1024 * 1024\n\n/**\n * Apply a `@FileUpload` config to already-buffered multipart parts and return\n * the multer-shaped `file` / `files` for `ctx`. Enforces the field name, type\n * filter, per-file size limit, and (array mode) max count — throwing\n * `HttpException` on a violation, mirroring the Express/multer error path.\n * Used by the Fastify, h3 and web runtimes; Express keeps using multer directly.\n */\nexport function applyUploadConfig(\n parts: RawUploadPart[],\n config: FileUploadConfig,\n): { file?: UploadedFileLike; files?: UploadedFileLike[] } {\n if (config.mode === 'none') return {}\n\n const field = config.fieldName ?? 'file'\n const maxSize = config.maxSize ?? DEFAULT_MAX_SIZE\n const typeAllowed = buildFileTypeFilter(config.allowedTypes, config.customMimeMap)\n\n const matched = parts.filter((p) => p.fieldname === field)\n const files: UploadedFileLike[] = matched.map((p) => {\n if (!typeAllowed(p.mimetype, p.filename)) {\n throw new HttpException(\n HttpStatus.UNSUPPORTED_MEDIA_TYPE,\n `File type ${p.mimetype} is not allowed`,\n )\n }\n if (p.buffer.length > maxSize) {\n throw new HttpException(\n HttpStatus.PAYLOAD_TOO_LARGE,\n `File ${p.filename} exceeds the ${maxSize}-byte limit`,\n )\n }\n return {\n fieldname: p.fieldname,\n originalname: p.filename,\n encoding: '7bit',\n mimetype: p.mimetype,\n size: p.buffer.length,\n buffer: p.buffer,\n }\n })\n\n if (config.mode === 'single') return { file: files[0] }\n const maxCount = config.maxCount ?? 10\n return { files: files.slice(0, maxCount) }\n}\n"],"mappings":";;;;;;;;;;wDAUA,MAAa,SAAmC,CAE9C,IAAK,aACL,KAAM,aACN,IAAK,YACL,IAAK,YACL,KAAM,aACN,IAAK,gBACL,IAAK,YACL,IAAK,eACL,KAAM,aACN,IAAK,aACL,KAAM,aAEN,IAAK,kBACL,IAAK,qBACL,KAAM,0EACN,IAAK,2BACL,KAAM,oEACN,IAAK,gCACL,KAAM,4EACN,IAAK,0CACL,IAAK,iDACL,IAAK,kDACL,IAAK,kBACL,IAAK,aACL,IAAK,WAEL,IAAK,kBACL,GAAI,mBACJ,IAAK,oBACL,IAAK,sBACL,KAAM,8BAEN,IAAK,aACL,IAAK,YACL,IAAK,YACL,KAAM,aACN,IAAK,YAEL,IAAK,YACL,KAAM,aACN,IAAK,kBACL,IAAK,kBACL,IAAK,mBAEL,KAAM,mBACN,IAAK,kBACL,KAAM,WACR,EAYA,SAAgB,iBAAiB,MAA2B,CAC1D,OAAO,MAAM,IAAK,GAAM,CACtB,IAAM,MAAQ,EAAE,YAAY,CAAC,CAAC,QAAQ,MAAO,EAAE,EAC/C,OAAO,SAAS,QAAU,CAC5B,CAAC,CACH,CASA,SAAgB,oBACd,aACA,cACiD,CACjD,GAAI,CAAC,aAAc,UAAa,GAChC,GAAI,OAAO,cAAiB,WAAY,OAAO,aAC/C,IAAM,QAAU,cAAgB,CAAE,GAAG,SAAU,GAAG,aAAc,EAAI,SAC9D,SAAW,aAAa,IAAK,GAAM,QAAQ,EAAE,YAAY,CAAC,CAAC,QAAQ,MAAO,EAAE,IAAM,CAAC,EACzF,MAAQ,WACN,SAAS,KAAM,MACb,KAAK,SAAS,IAAI,EAAI,SAAS,WAAW,KAAK,QAAQ,KAAM,GAAG,CAAC,EAAI,WAAa,IACpF,CACJ,CA6BA,SAAgB,kBACd,MACA,OACyD,CACzD,GAAI,OAAO,OAAS,OAAQ,MAAO,CAAC,EAEpC,IAAM,MAAQ,OAAO,WAAa,OAC5B,QAAU,OAAO,SAAW,QAC5B,YAAc,oBAAoB,OAAO,aAAc,OAAO,aAAa,EAG3E,MADU,MAAM,OAAQ,GAAM,EAAE,YAAc,KACZ,CAAC,CAAC,IAAK,GAAM,CACnD,GAAI,CAAC,YAAY,EAAE,SAAU,EAAE,QAAQ,EACrC,MAAM,IAAI,cACR,WAAW,uBACX,aAAa,EAAE,SAAS,gBAC1B,EAEF,GAAI,EAAE,OAAO,OAAS,QACpB,MAAM,IAAI,cACR,WAAW,kBACX,QAAQ,EAAE,SAAS,eAAe,QAAQ,YAC5C,EAEF,MAAO,CACL,UAAW,EAAE,UACb,aAAc,EAAE,SAChB,SAAU,OACV,SAAU,EAAE,SACZ,KAAM,EAAE,OAAO,OACf,OAAQ,EAAE,MACZ,CACF,CAAC,EAED,GAAI,OAAO,OAAS,SAAU,MAAO,CAAE,KAAM,MAAM,EAAG,EACtD,IAAM,SAAW,OAAO,UAAY,GACpC,MAAO,CAAE,MAAO,MAAM,MAAM,EAAG,QAAQ,CAAE,CAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate-DoZDOhCi.d.mts","names":[],"sources":["../src/http/middleware/validate.ts"],"mappings":";;;;UAIiB,gBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;;;;;;AAAM;AAgDR;;;;;;;iBAAgB,QAAA,CAAS,MAAA,EAAQ,gBAAA,IAAgB,GAAA,EAClC,OAAA,EAAO,IAAA,EAAQ,QAAA,EAAQ,IAAA,EAAQ,YAAA"}
1
+ {"version":3,"file":"validate-DoZDOhCi.d.mts","names":[],"sources":["../src/http/middleware/validate.ts"],"mappings":";;;;UAMiB,gBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;;;;;;AAAM;AAgDR;;;;;;;iBAAgB,QAAA,CAAS,MAAA,EAAQ,gBAAA,IAAgB,GAAA,EAClC,OAAA,EAAO,IAAA,EAAQ,QAAA,EAAQ,IAAA,EAAQ,YAAA"}
@@ -1,7 +1,7 @@
1
1
 
2
- import { f as DepValue, o as ContextDecorator, s as ContextDecoratorSpec, v as MetaValue } from "./app-module-CuAS6hJC.mjs";
3
- import { P as AdapterFactory, T as RequestContext, f as HttpRuntime, m as RouteEntry } from "./adapter-D_uzU-QA.mjs";
4
- import { t as BuildRoutesOptions } from "./router-builder-Bh3qSiDz.mjs";
2
+ import { f as DepValue, o as ContextDecorator, s as ContextDecoratorSpec, v as MetaValue } from "./app-module-BwYtACD6.mjs";
3
+ import { P as AdapterFactory, T as RequestContext, f as HttpRuntime, m as RouteEntry } from "./adapter-DCfEFZMY.mjs";
4
+ import { t as BuildRoutesOptions } from "./router-builder-BHTp3zL3.mjs";
5
5
  import { Express, NextFunction, Request, Response, Router } from "express";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
 
@@ -113,6 +113,8 @@ interface RequestStore {
113
113
  * write helper.
114
114
  */
115
115
  values: Map<string, unknown>;
116
+ /** Set once {@link disposeRequestStore} has run — guards double-dispose. */
117
+ disposed?: boolean;
116
118
  }
117
119
  /** AsyncLocalStorage instance shared across the framework */
118
120
  declare const requestStore: AsyncLocalStorage<RequestStore>;
@@ -158,7 +160,7 @@ declare function getRequestValue<K extends string>(key: K): MetaValue<K> | undef
158
160
  * `Application` mounts this automatically unless `contextStore: 'manual'` is set
159
161
  * or the user already includes one in their middleware list.
160
162
  */
161
- declare function requestScopeMiddleware(): (req: Request, _res: Response, next: NextFunction) => void;
163
+ declare function requestScopeMiddleware(): (req: Request, res: Response, next: NextFunction) => void;
162
164
  //#endregion
163
165
  //#region src/http/middleware/trace-context.d.ts
164
166
  /**
@@ -270,4 +272,4 @@ interface ViewAdapterOptions {
270
272
  declare const ViewAdapter: AdapterFactory<ViewAdapterOptions, unknown>;
271
273
  //#endregion
272
274
  export { ClusterOptions as _, TraceContextOptions as a, requestScopeMiddleware as c, getRequestValue as d, requestStore as f, defineHttpContextDecorator as g, materializeRouter as h, TraceContext as i, RequestStore as l, expressRuntime as m, ViewAdapterOptions as n, parseTraceparent as o, buildRoutes as p, TRACEPARENT_HEADER as r, traceContext as s, ViewAdapter as t, getRequestStore as u, isClusterPrimary as v };
273
- //# sourceMappingURL=views-DcTVDiOh.d.mts.map
275
+ //# sourceMappingURL=views-PFf-CBvN.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"views-PFf-CBvN.d.mts","names":[],"sources":["../src/http/cluster.ts","../src/http/define-http-context-decorator.ts","../src/http/runtimes/express.ts","../src/http/request-store.ts","../src/http/middleware/request-scope.ts","../src/http/middleware/trace-context.ts","../src/http/middleware/views.ts"],"mappings":";;;;;;;;UAOiB,cAAA;;EAEf,OAAA;;EAEA,uBAAA;;EAEA,YAAA;;EAEA,WAAA;;EAEA,aAAA;AAAA;;iBAIc,gBAAA;;;;;;;;UCuDC,oCAAA,WAA+C,MAAA;EAAA,6BACjC,MAAA,SAAe,QAAA,IAAY,MAAA,iBACtD,IAAA,EAAM,oBAAA,CAAqB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA,IACnC,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA;AAAA;;;;;;UAQd,4BAAA;EAAA,6BAGH,MAAA,SAAe,QAAA,IAAY,MAAA,2BAC3B,MAAA,oBAA0B,MAAA,iBAEpC,IAAA,EAAM,oBAAA,CAAqB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA,IACnC,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,cAAA;EAfc;AAQ7C;;;;;;;;;;;;;;EAwBE,UAAA,WAAqB,MAAA,sBAA4B,oCAAA,CAAqC,CAAA;AAAA;AAAA,cAW3E,0BAAA,EAA4B,4BAQR;;;;;;;;;;;iBC3FjB,iBAAA,CAAkB,OAAA,EAAS,UAAA,KAAe,MAAM;;;;;;;;;iBAiEhD,WAAA,CAAY,eAAA,OAAsB,OAAA,GAAS,kBAAA,GAA0B,MAAM;;AFjG3F;;;iBEyGgB,cAAA,IAAkB,WAAW,CAAC,OAAA;;;;UC5G7B,YAAA;;EAEf,SAAA;;;;;;EAMA,SAAA,EAAW,GAAA;;;;;;;;;;;AHLb;;;;;;;;;;EG0BE,MAAA,EAAQ,GAAG;EHZG;EGcd,QAAA;AAAA;;cAIW,YAAA,EAAY,iBAAA,CAAA,YAAA;;;;AFqCzB;iBE/BgB,eAAA,IAAmB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoC/B,eAAA,mBAAkC,GAAA,EAAK,CAAA,GAAI,SAAA,CAAU,CAAA;;;;;AH1ErE;;;;;;iBIyFgB,sBAAA,KAAsB,GAAA,EACnB,OAAA,EAAO,GAAA,EAAO,QAAA,EAAQ,IAAA,EAAQ,YAAA;;;;;;;cCxFpC,kBAAA;AAAA,UAKI,mBAAA;;;;;EAKf,iBAAiB;AAAA;;;;UAMF,YAAA;;EAEf,OAAA;;EAEA,OAAA;;EAEA,YAAA;ELxB6B;EK0B7B,KAAA;AAAA;;;;;iBAqBc,gBAAA,CAAiB,MAAA,WAAiB,YAAY;;ALrC/C;AAIf;;;;AAAgC;;;;ACuDhC;;;;;;;;;;;iBIoBgB,YAAA,CAAa,OAAA,GAAS,mBAAA,IAAwB,GAAA,EAC/C,OAAA,EAAO,GAAA,EAAO,QAAA,EAAQ,IAAA,EAAQ,YAAA;;;UC5F5B,kBAAA;;;;;;;;;;;;;;;EAef,MAAA;;EAGA,GAAA;;EAGA,QAAA;;EAGA,MAAA;AAAA;;;;;;;;;;ANZa;AAIf;;;;AAAgC;;;;ACuDhC;;;;;;;;;;;cKfa,WAAA,EAAW,cAAA,CAAA,kBAAA"}
package/dist/web.d.mts ADDED
@@ -0,0 +1,150 @@
1
+
2
+ import { d as ContributorRegistrations, r as AppModuleEntry } from "./app-module-BwYtACD6.mjs";
3
+ import { b as RuntimeResponse, m as RouteEntry } from "./adapter-DCfEFZMY.mjs";
4
+ import { a as reply, i as isReply, n as Reply, t as InferHandlerResponse } from "./reply-Elm9mc8Z.mjs";
5
+
6
+ //#region src/http/web/driver.d.ts
7
+ /**
8
+ * Presents a web `Request` as the express-shaped `req` object that
9
+ * `RequestContext` (and route validation) reads: plain-object `headers`,
10
+ * assignable `body`/`params`/`query`, and `on/once('close')` bridged from
11
+ * the request's `AbortSignal` — the only EventEmitter surface the context
12
+ * layer uses (`ctx.signal`, SSE close).
13
+ */
14
+ declare class WebRequestShim {
15
+ readonly method: string;
16
+ readonly url: string;
17
+ /** Lower-cased plain header object (RequestContext indexes it directly). */
18
+ readonly headers: Record<string, string>;
19
+ body: unknown;
20
+ params: Record<string, string>;
21
+ query: Record<string, unknown>;
22
+ requestId?: string;
23
+ file?: unknown;
24
+ files?: unknown;
25
+ [key: string]: unknown;
26
+ private readonly signal;
27
+ constructor(request: Request, url: URL);
28
+ /** `req.once('close')` — abort of the underlying request signal. */
29
+ once(event: string, listener: () => void): this;
30
+ /** `req.on('close')` — same bridge; signals only abort once anyway. */
31
+ on(event: string, listener: () => void): this;
32
+ }
33
+ /**
34
+ * `RuntimeResponse` over a web `Response`.
35
+ *
36
+ * Two modes:
37
+ * - **Buffered** (default): `status/json/send/type/setHeader` record state;
38
+ * the terminal call resolves {@link ready} with a complete `Response`.
39
+ * - **Streaming**: the first `writeHead`/`flushHeaders`/`write` call switches
40
+ * to a `TransformStream` and resolves {@link ready} IMMEDIATELY with a
41
+ * streamed `Response` — SSE works on edge this way; `write` feeds the
42
+ * writer, `end` closes it.
43
+ *
44
+ * A class so the method table lives on a shared prototype (one allocation
45
+ * per request — same rationale as the Fastify/h3 driver classes).
46
+ */
47
+ declare class WebResponseDriver implements RuntimeResponse {
48
+ private readonly signal?;
49
+ /** Resolves with the final (or streamed) Response. */
50
+ readonly ready: Promise<Response>;
51
+ /** True once a terminal/streaming action produced the Response. */
52
+ settled: boolean;
53
+ private _status;
54
+ private readonly headers;
55
+ private _headersSent;
56
+ private writer?;
57
+ private resolveReady;
58
+ constructor(signal?: AbortSignal | undefined);
59
+ status(code: number): this;
60
+ json(data: unknown): this;
61
+ send(data: unknown): this;
62
+ type(contentType: string): this;
63
+ setHeader(name: string, value: unknown): this;
64
+ render(): never;
65
+ writeHead(statusCode: number, headers?: Record<string, string | number | string[]>): this;
66
+ flushHeaders(): this;
67
+ write(chunk: unknown): boolean;
68
+ end(data?: unknown): this;
69
+ once(event: string, listener: (...args: unknown[]) => void): this;
70
+ get headersSent(): boolean;
71
+ /** Buffered terminal: build the final Response exactly once. */
72
+ private finish;
73
+ /** Switch to streaming mode and resolve `ready` with the streamed Response. */
74
+ private startStream;
75
+ }
76
+ //#endregion
77
+ //#region src/http/web/handler.d.ts
78
+ interface WebRouteInvocation {
79
+ request: Request;
80
+ url: URL;
81
+ params: Record<string, string>;
82
+ }
83
+ interface WebRouteHooks {
84
+ /**
85
+ * Error bridge — receives pipeline rejections (validation failures,
86
+ * handler throws) with the shim + driver so an engine can dispatch the
87
+ * framework's connect-style error handler. When absent (or when it
88
+ * doesn't settle the driver), a minimal JSON error is produced from
89
+ * `err.status`/`err.statusCode` (500 default).
90
+ */
91
+ onError?: (err: unknown, req: WebRequestShim, res: WebResponseDriver) => void | Promise<void>;
92
+ }
93
+ /**
94
+ * Compile a RouteEntry into a `(invocation) => Promise<Response>` function.
95
+ * Everything derivable at route-build time (validator, upload config) is
96
+ * hoisted here — per-request work is shim + store + pipeline only.
97
+ */
98
+ declare function compileWebRoute(entry: RouteEntry, hooks?: WebRouteHooks): (invocation: WebRouteInvocation) => Promise<Response>;
99
+ //#endregion
100
+ //#region src/web.d.ts
101
+ interface CreateWebAppOptions {
102
+ /**
103
+ * The h3 v2 module, statically imported by the caller:
104
+ * `import * as h3 from 'h3'`. Passed in (rather than loaded here) because
105
+ * edge bundlers have no `createRequire`, and a static `import 'h3'` inside
106
+ * this entry would force the peer on every consumer of the subpath.
107
+ */
108
+ h3: unknown;
109
+ /** App modules — same shapes `bootstrap({ modules })` accepts. */
110
+ modules: AppModuleEntry[];
111
+ /** Route prefix (default '/api') — parity with bootstrap. */
112
+ apiPrefix?: string;
113
+ /** Default route version (default 1) — parity with bootstrap. */
114
+ defaultVersion?: number;
115
+ /** Global Context Contributors — parity with `bootstrap({ contributors })`. */
116
+ contributors?: ContributorRegistrations;
117
+ /**
118
+ * Env values for ConfigService/@Value resolution. On Workers, pass the
119
+ * `env` binding from the fetch handler (see `createFetchHandler`); on
120
+ * Bun/Deno, ambient `process.env` already works and this can be omitted.
121
+ */
122
+ env?: Record<string, string | undefined>;
123
+ }
124
+ interface WebApp {
125
+ /** Web-standard entry: `Request` in, `Response` out. */
126
+ fetch: (request: Request) => Promise<Response>;
127
+ /** The underlying h3 v2 app, for advanced composition. */
128
+ h3: unknown;
129
+ }
130
+ /**
131
+ * Build a KickJS app as a web-standard fetch handler — no node http server,
132
+ * no Application/bootstrap. Module registration, DI, and the contributor
133
+ * pipeline behave exactly like `bootstrap()`; routes are compiled once here
134
+ * and served through h3 v2's router.
135
+ */
136
+ declare function createWebApp(options: CreateWebAppOptions): WebApp;
137
+ /**
138
+ * Cloudflare Workers convenience: lazily build the app on the first request
139
+ * so the Workers `env` binding can seed config before any module resolves.
140
+ *
141
+ * ```ts
142
+ * export default createFetchHandler((env) => ({ h3, modules, env }))
143
+ * ```
144
+ */
145
+ declare function createFetchHandler(build: (env: Record<string, string | undefined>) => CreateWebAppOptions): {
146
+ fetch: (request: Request, env?: Record<string, string | undefined>) => Promise<Response>;
147
+ };
148
+ //#endregion
149
+ export { CreateWebAppOptions, type InferHandlerResponse, type Reply, WebApp, WebRequestShim, WebResponseDriver, compileWebRoute, createFetchHandler, createWebApp, isReply, reply };
150
+ //# sourceMappingURL=web.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.mts","names":[],"sources":["../src/http/web/driver.ts","../src/http/web/handler.ts","../src/web.ts"],"mappings":";;;;;;;;;;AAiBA;;;cAAa,cAAA;EAAA,SACF,MAAA;EAAA,SACA,GAAA;EAeY;EAAA,SAbZ,OAAA,EAAS,MAAA;EAClB,IAAA;EACA,MAAA,EAAQ,MAAA;EACR,KAAA,EAAO,MAAA;EACP,SAAA;EACA,IAAA;EACA,KAAA;EAAA,CAGC,GAAA;EAAA,iBAEgB,MAAA;EAEjB,WAAA,CAAY,OAAA,EAAS,OAAA,EAAS,GAAA,EAAK,GAAA;EAVnC;EA6BA,IAAA,CAAK,KAAA,UAAe,QAAA;EA5BpB;EAkCA,EAAA,CAAG,KAAA,UAAe,QAAA;AAAA;;;;;;;;;;;;;;;cA0BP,iBAAA,YAA6B,eAAA;EAAA,iBAYX,MAAA;EAZA;EAAA,SAEpB,KAAA,EAAO,OAAA,CAAQ,QAAA;EAAA;EAExB,OAAA;EAAA,QAEQ,OAAA;EAAA,iBACS,OAAA;EAAA,QACT,YAAA;EAAA,QACA,MAAA;EAAA,QACA,YAAA;EAER,WAAA,CAA6B,MAAA,GAAS,WAAA;EAMtC,MAAA,CAAO,IAAA;EAKP,IAAA,CAAK,IAAA;EAML,IAAA,CAAK,IAAA;EAYL,IAAA,CAAK,WAAA;EAKL,SAAA,CAAU,IAAA,UAAc,KAAA;EAUxB,MAAA;EAIA,SAAA,CAAU,UAAA,UAAoB,OAAA,GAAU,MAAA;EASxC,YAAA;EAKA,KAAA,CAAM,KAAA;EAQN,GAAA,CAAI,IAAA;EAUJ,IAAA,CAAK,KAAA,UAAe,QAAA,MAAc,IAAA;EAAA,IAM9B,WAAA;EAtFyB;EAAA,QA2FrB,MAAA;EArFD;EAAA,QAqGC,WAAA;AAAA;;;UC3LO,kBAAA;EACf,OAAA,EAAS,OAAA;EACT,GAAA,EAAK,GAAA;EACL,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,aAAA;EDFG;;;;;;;ECUlB,OAAA,IAAW,GAAA,WAAc,GAAA,EAAK,cAAA,EAAgB,GAAA,EAAK,iBAAA,YAA6B,OAAA;AAAA;;;;;;iBAqBlE,eAAA,CACd,KAAA,EAAO,UAAA,EACP,KAAA,GAAQ,aAAA,IACN,UAAA,EAAY,kBAAA,KAAuB,OAAA,CAAQ,QAAA;;;UCL9B,mBAAA;EFjCU;;;;;;EEwCzB,EAAA;EFvBsC;EEyBtC,OAAA,EAAS,cAAA;EFzCA;EE2CT,SAAA;EFxCS;EE0CT,cAAA;EFzCA;EE2CA,YAAA,GAAe,wBAAA;EF1CP;;;;;EEgDR,GAAA,GAAM,MAAA;AAAA;AAAA,UAGS,MAAA;EFxCf;EE0CA,KAAA,GAAQ,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA;EF1CzB;EE4CZ,EAAA;AAAA;;;;;;;iBASc,YAAA,CAAa,OAAA,EAAS,mBAAA,GAAsB,MAAM;AF5B1B;AA0BxC;;;;;;;AA1BwC,iBEmIxB,kBAAA,CACd,KAAA,GAAQ,GAAA,EAAK,MAAA,iCAAuC,mBAAA;EACjD,KAAA,GAAQ,OAAA,EAAS,OAAA,EAAS,GAAA,GAAM,MAAA,iCAAuC,OAAA,CAAQ,QAAA;AAAA"}
package/dist/web.mjs ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @forinda/kickjs v6.2.0
3
+ *
4
+ * Copyright (c) Felix Orinda
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ import{t as Container}from"./container-CkcVS_gA.mjs";import{t as MutableModuleRegistry}from"./module-registry-DmTQjSdD.mjs";import{normalizePath}from"./core/path.mjs";import{i as requestStore}from"./context-Cd-p7DfC.mjs";import{n as isReply,r as reply}from"./reply-Dh15A_0R.mjs";import{_setExternalContributorSources,buildRouteTable}from"./http/router-builder.mjs";import{n as WebRequestShim,r as WebResponseDriver,t as compileWebRoute}from"./handler-BMUwLMu_.mjs";function createWebApp(options){let h3mod=options.h3;if(typeof h3mod?.H3!=`function`)throw Error(`@forinda/kickjs/web: pass the h3 v2 module — \`createWebApp({ h3: await import("h3"), ... })\`. The installed h3 must be v2 (npm dist-tag 'latest'); v1 has no H3 class.`);let container=Container.getInstance();if(options.env){let env=options.env;Container._envResolver=key=>env[key]}Container._requestStoreProvider=()=>requestStore.getStore()??null;let registry=new MutableModuleRegistry;for(let m of options.modules)registry.mount(m);let modules=registry.entries.map(entry=>{let mod=typeof entry==`function`?new entry:entry;return mod.register?.(container),mod});container.bootstrap();let app=new h3mod.H3,apiPrefix=options.apiPrefix??`/api`,defaultVersion=options.defaultVersion??1,globalSources=(options.contributors??[]).map(registration=>({source:`global`,registration,label:`createWebApp`}));for(let mod of modules){let declaredName=mod.name,moduleLabel=typeof declaredName==`string`&&declaredName.length>0?declaredName:mod.constructor?.name??`module`;_setExternalContributorSources([...(mod.contributors?.()??[]).map(registration=>({source:`module`,registration,label:moduleLabel})),...globalSources]);try{let result=mod.routes();if(!result)continue;let routeSets=Array.isArray(result)?result:[result];for(let route of routeSets){if(!route.controller)throw Error(`@forinda/kickjs/web: module route at '${route.path}' has no controller. Express-style \`router\` mounts are not supported on the web entry.`);let mountPath=`${apiPrefix}/v${route.version??defaultVersion}${normalizePath(route.path)}`;for(let entry of buildRouteTable(route.controller)){let url=joinPath(mountPath,entry.path),run=compileWebRoute(entry);app.on(entry.method,url,event=>run({request:event.req,url:event.url,params:event.context.params??{}}))}}}finally{_setExternalContributorSources([])}}return{fetch:request=>app.fetch(request),h3:app}}function createFetchHandler(build){let app;return{fetch:(request,env={})=>(app??=createWebApp(build(env)),app.fetch(request))}}function joinPath(mountPath,path){let a=mountPath.endsWith(`/`)?mountPath.slice(0,-1):mountPath;return path===`/`||path===``?a===``?`/`:a:`${a}${path.startsWith(`/`)?path:`/${path}`}`}export{WebRequestShim,WebResponseDriver,compileWebRoute,createFetchHandler,createWebApp,isReply,reply};
12
+ //# sourceMappingURL=web.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.mjs","names":[],"sources":["../src/web.ts"],"sourcesContent":["// `@forinda/kickjs/web` — the web-standard fetch entry for edge runtimes\n// (Cloudflare Workers), Bun, and Deno. See web-standards-edge-design.md §3.\n//\n// PURITY CONTRACT: this entry's import graph must stay free of node-only\n// runtime imports — no `node:http`, `node:cluster`, `node:fs`, `node:module`,\n// no `express`, no `Application`/`bootstrap`. The single sanctioned node API\n// is `node:async_hooks` (AsyncLocalStorage — available on Workers with\n// `nodejs_compat`, Deno, and Bun). Enforced by the bundle-graph purity test.\n//\n// ```ts\n// // Cloudflare Workers (wrangler.toml: compatibility_flags = [\"nodejs_compat\"])\n// import { createWebApp } from '@forinda/kickjs/web'\n// import * as h3 from 'h3'\n// import { modules } from './modules'\n//\n// const app = createWebApp({ h3, modules })\n// export default { fetch: (req: Request) => app.fetch(req) }\n//\n// // Bun\n// Bun.serve({ fetch: (req) => app.fetch(req) })\n// ```\n\nimport { Container } from './core/container'\nimport { MutableModuleRegistry } from './core/module-registry'\nimport type { AppModule, AppModuleClass, AppModuleEntry } from './core/app-module'\nimport type { ContributorRegistrations } from './core/context-decorator'\nimport type { SourcedRegistration } from './core/contributor-pipeline'\nimport { _setExternalContributorSources, buildRouteTable } from './http/router-builder'\nimport { requestStore } from './http/request-store'\nimport { compileWebRoute } from './http/web/handler'\nimport { normalizePath } from './core/path'\n\nexport { WebRequestShim, WebResponseDriver } from './http/web/driver'\nexport { compileWebRoute } from './http/web/handler'\n// Return-value handler helpers — edge consumers can't import the main barrel.\nexport { reply, isReply, type Reply, type InferHandlerResponse } from './http/reply'\n\n// Minimal structural surface of h3 v2 used here (kept local so this entry\n// never imports the node-coupled h3-web runtime module).\ninterface H3AppLike {\n on(method: string, path: string, handler: (event: H3EventLike) => unknown): unknown\n all(path: string, handler: (event: H3EventLike) => unknown): unknown\n fetch(request: Request): Promise<Response>\n}\ninterface H3EventLike {\n req: Request\n url: URL\n context: { params?: Record<string, string> }\n}\n\nexport interface CreateWebAppOptions {\n /**\n * The h3 v2 module, statically imported by the caller:\n * `import * as h3 from 'h3'`. Passed in (rather than loaded here) because\n * edge bundlers have no `createRequire`, and a static `import 'h3'` inside\n * this entry would force the peer on every consumer of the subpath.\n */\n h3: unknown\n /** App modules — same shapes `bootstrap({ modules })` accepts. */\n modules: AppModuleEntry[]\n /** Route prefix (default '/api') — parity with bootstrap. */\n apiPrefix?: string\n /** Default route version (default 1) — parity with bootstrap. */\n defaultVersion?: number\n /** Global Context Contributors — parity with `bootstrap({ contributors })`. */\n contributors?: ContributorRegistrations\n /**\n * Env values for ConfigService/@Value resolution. On Workers, pass the\n * `env` binding from the fetch handler (see `createFetchHandler`); on\n * Bun/Deno, ambient `process.env` already works and this can be omitted.\n */\n env?: Record<string, string | undefined>\n}\n\nexport interface WebApp {\n /** Web-standard entry: `Request` in, `Response` out. */\n fetch: (request: Request) => Promise<Response>\n /** The underlying h3 v2 app, for advanced composition. */\n h3: unknown\n}\n\n/**\n * Build a KickJS app as a web-standard fetch handler — no node http server,\n * no Application/bootstrap. Module registration, DI, and the contributor\n * pipeline behave exactly like `bootstrap()`; routes are compiled once here\n * and served through h3 v2's router.\n */\nexport function createWebApp(options: CreateWebAppOptions): WebApp {\n const h3mod = options.h3 as { H3?: new () => H3AppLike }\n if (typeof h3mod?.H3 !== 'function') {\n throw new Error(\n '@forinda/kickjs/web: pass the h3 v2 module — `createWebApp({ h3: await import(\"h3\"), ... })`. ' +\n \"The installed h3 must be v2 (npm dist-tag 'latest'); v1 has no H3 class.\",\n )\n }\n\n const container = Container.getInstance()\n\n // Wire ConfigService/@Value env resolution when the platform has no\n // ambient process.env (Workers). Latest-wins like loadEnv().\n if (options.env) {\n const env = options.env\n Container._envResolver = (key: string) => env[key]\n }\n\n // Request-scope provider — same wiring Application.setup() performs.\n Container._requestStoreProvider = () => requestStore.getStore() ?? null\n\n // Module mounting — mirrors Application.setup() steps 1:1 for the module\n // path (plugins/adapters are out of scope for the edge entry at launch).\n const registry = new MutableModuleRegistry()\n for (const m of options.modules) registry.mount(m)\n const modules = registry.entries.map((entry) => {\n const mod: AppModule = typeof entry === 'function' ? new (entry as AppModuleClass)() : entry\n mod.register?.(container)\n return mod\n })\n container.bootstrap()\n\n const app = new h3mod.H3()\n const apiPrefix = options.apiPrefix ?? '/api'\n const defaultVersion = options.defaultVersion ?? 1\n\n const globalSources: SourcedRegistration[] = (options.contributors ?? []).map(\n (registration): SourcedRegistration => ({\n source: 'global',\n registration: registration as SourcedRegistration['registration'],\n label: 'createWebApp',\n }),\n )\n\n for (const mod of modules) {\n const declaredName = (mod as { name?: unknown }).name\n const moduleLabel =\n typeof declaredName === 'string' && declaredName.length > 0\n ? declaredName\n : (mod.constructor?.name ?? 'module')\n const moduleSources: SourcedRegistration[] = (mod.contributors?.() ?? []).map(\n (registration): SourcedRegistration => ({\n source: 'module',\n registration,\n label: moduleLabel,\n }),\n )\n\n _setExternalContributorSources([...moduleSources, ...globalSources])\n try {\n const result = mod.routes()\n if (!result) continue\n const routeSets = Array.isArray(result) ? result : [result]\n for (const route of routeSets) {\n if (!route.controller) {\n throw new Error(\n `@forinda/kickjs/web: module route at '${route.path}' has no controller. ` +\n 'Express-style `router` mounts are not supported on the web entry.',\n )\n }\n const version = route.version ?? defaultVersion\n const mountPath = `${apiPrefix}/v${version}${normalizePath(route.path)}`\n for (const entry of buildRouteTable(route.controller)) {\n const url = joinPath(mountPath, entry.path)\n const run = compileWebRoute(entry)\n app.on(entry.method, url, (event: H3EventLike) =>\n run({\n request: event.req,\n url: event.url,\n params: event.context.params ?? {},\n }),\n )\n }\n }\n } finally {\n _setExternalContributorSources([])\n }\n }\n\n return {\n fetch: (request: Request) => app.fetch(request),\n h3: app,\n }\n}\n\n/**\n * Cloudflare Workers convenience: lazily build the app on the first request\n * so the Workers `env` binding can seed config before any module resolves.\n *\n * ```ts\n * export default createFetchHandler((env) => ({ h3, modules, env }))\n * ```\n */\nexport function createFetchHandler(\n build: (env: Record<string, string | undefined>) => CreateWebAppOptions,\n): { fetch: (request: Request, env?: Record<string, string | undefined>) => Promise<Response> } {\n let app: WebApp | undefined\n return {\n fetch: (request, env = {}) => {\n app ??= createWebApp(build(env))\n return app.fetch(request)\n },\n }\n}\n\n/** Join a mount prefix and a route path into one URL, collapsing slashes. */\nfunction joinPath(mountPath: string, path: string): string {\n const a = mountPath.endsWith('/') ? mountPath.slice(0, -1) : mountPath\n if (path === '/' || path === '') return a === '' ? '/' : a\n const b = path.startsWith('/') ? path : `/${path}`\n return `${a}${b}`\n}\n"],"mappings":";;;;;;;;;;idAuFA,SAAgB,aAAa,QAAsC,CACjE,IAAM,MAAQ,QAAQ,GACtB,GAAI,OAAO,OAAO,IAAO,WACvB,MAAU,MACR,0KAEF,EAGF,IAAM,UAAY,UAAU,YAAY,EAIxC,GAAI,QAAQ,IAAK,CACf,IAAM,IAAM,QAAQ,IACpB,UAAU,aAAgB,KAAgB,IAAI,IAChD,CAGA,UAAU,0BAA8B,aAAa,SAAS,GAAK,KAInE,IAAM,SAAW,IAAI,sBACrB,IAAK,IAAM,KAAK,QAAQ,QAAS,SAAS,MAAM,CAAC,EACjD,IAAM,QAAU,SAAS,QAAQ,IAAK,OAAU,CAC9C,IAAM,IAAiB,OAAO,OAAU,WAAa,IAAK,MAA6B,MAEvF,OADA,IAAI,WAAW,SAAS,EACjB,GACT,CAAC,EACD,UAAU,UAAU,EAEpB,IAAM,IAAM,IAAI,MAAM,GAChB,UAAY,QAAQ,WAAa,OACjC,eAAiB,QAAQ,gBAAkB,EAE3C,eAAwC,QAAQ,cAAgB,CAAC,EAAA,CAAG,IACvE,eAAuC,CACtC,OAAQ,SACM,aACd,MAAO,cACT,EACF,EAEA,IAAK,IAAM,OAAO,QAAS,CACzB,IAAM,aAAgB,IAA2B,KAC3C,YACJ,OAAO,cAAiB,UAAY,aAAa,OAAS,EACtD,aACC,IAAI,aAAa,MAAQ,SAShC,+BAA+B,CAAC,IARc,IAAI,eAAe,GAAK,CAAC,EAAA,CAAG,IACvE,eAAuC,CACtC,OAAQ,SACR,aACA,MAAO,WACT,EAG6C,EAAG,GAAG,aAAa,CAAC,EACnE,GAAI,CACF,IAAM,OAAS,IAAI,OAAO,EAC1B,GAAI,CAAC,OAAQ,SACb,IAAM,UAAY,MAAM,QAAQ,MAAM,EAAI,OAAS,CAAC,MAAM,EAC1D,IAAK,IAAM,SAAS,UAAW,CAC7B,GAAI,CAAC,MAAM,WACT,MAAU,MACR,yCAAyC,MAAM,KAAK,yFAEtD,EAGF,IAAM,UAAY,GAAG,UAAU,IADf,MAAM,SAAW,iBACY,cAAc,MAAM,IAAI,IACrE,IAAK,IAAM,SAAS,gBAAgB,MAAM,UAAU,EAAG,CACrD,IAAM,IAAM,SAAS,UAAW,MAAM,IAAI,EACpC,IAAM,gBAAgB,KAAK,EACjC,IAAI,GAAG,MAAM,OAAQ,IAAM,OACzB,IAAI,CACF,QAAS,MAAM,IACf,IAAK,MAAM,IACX,OAAQ,MAAM,QAAQ,QAAU,CAAC,CACnC,CAAC,CACH,CACF,CACF,CACF,QAAU,CACR,+BAA+B,CAAC,CAAC,CACnC,CACF,CAEA,MAAO,CACL,MAAQ,SAAqB,IAAI,MAAM,OAAO,EAC9C,GAAI,GACN,CACF,CAUA,SAAgB,mBACd,MAC8F,CAC9F,IAAI,IACJ,MAAO,CACL,OAAQ,QAAS,IAAM,CAAC,KACtB,MAAQ,aAAa,MAAM,GAAG,CAAC,EACxB,IAAI,MAAM,OAAO,EAE5B,CACF,CAGA,SAAS,SAAS,UAAmB,KAAsB,CACzD,IAAM,EAAI,UAAU,SAAS,GAAG,EAAI,UAAU,MAAM,EAAG,EAAE,EAAI,UAG7D,OAFI,OAAS,KAAO,OAAS,GAAW,IAAM,GAAK,IAAM,EAElD,GAAG,IADA,KAAK,WAAW,GAAG,EAAI,KAAO,IAAI,QAE9C"}