@forinda/kickjs 9.0.2 → 9.1.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 (96) hide show
  1. package/dist/{application-BSDt9vOo.mjs → application-nDj-76EX.mjs} +3 -3
  2. package/dist/{application-BSDt9vOo.mjs.map → application-nDj-76EX.mjs.map} +1 -1
  3. package/dist/{bootstrap-CJ8ALvif.mjs → bootstrap-BqcT1h9H.mjs} +3 -3
  4. package/dist/{bootstrap-CJ8ALvif.mjs.map → bootstrap-BqcT1h9H.mjs.map} +1 -1
  5. package/dist/{client-ip-BHH-wDR7.mjs → client-ip-DMKc-Trg.mjs} +2 -2
  6. package/dist/{client-ip-BHH-wDR7.mjs.map → client-ip-DMKc-Trg.mjs.map} +1 -1
  7. package/dist/config/index.mjs +2 -2
  8. package/dist/{config-Dz5GgLKS.mjs → config-DrgIbebd.mjs} +3 -3
  9. package/dist/{config-Dz5GgLKS.mjs.map → config-DrgIbebd.mjs.map} +1 -1
  10. package/dist/{container-DM3gPzGt.mjs → container-ZnfelY_a.mjs} +3 -3
  11. package/dist/{container-DM3gPzGt.mjs.map → container-ZnfelY_a.mjs.map} +1 -1
  12. package/dist/{context-DEntnLmq.mjs → context-BGPof8bs.mjs} +3 -3
  13. package/dist/{context-DEntnLmq.mjs.map → context-BGPof8bs.mjs.map} +1 -1
  14. package/dist/{context-errors-Cb4jKwm4.mjs → context-errors-Cgtrrqfs.mjs} +2 -2
  15. package/dist/{context-errors-Cb4jKwm4.mjs.map → context-errors-Cgtrrqfs.mjs.map} +1 -1
  16. package/dist/{contributor-runner-Buxk3Ay_.mjs → contributor-runner-BSpshfPN.mjs} +3 -3
  17. package/dist/{contributor-runner-Buxk3Ay_.mjs.map → contributor-runner-BSpshfPN.mjs.map} +1 -1
  18. package/dist/core/adapter.mjs +1 -1
  19. package/dist/core/app-module.mjs +1 -1
  20. package/dist/core/cache.mjs +1 -1
  21. package/dist/core/container.mjs +2 -2
  22. package/dist/core/cron.mjs +2 -2
  23. package/dist/core/decorators.mjs +2 -2
  24. package/dist/core/errors.mjs +1 -1
  25. package/dist/core/interfaces.mjs +1 -1
  26. package/dist/core/logger.d.mts +2 -2
  27. package/dist/core/logger.mjs +2 -2
  28. package/dist/core/logger.mjs.map +1 -1
  29. package/dist/core/path.mjs +1 -1
  30. package/dist/core/plugin.mjs +1 -1
  31. package/dist/core/reactivity.mjs +1 -1
  32. package/dist/{core-Cv1KjPCj.mjs → core-_WNyghl_.mjs} +3 -3
  33. package/dist/{core-Cv1KjPCj.mjs.map → core-_WNyghl_.mjs.map} +1 -1
  34. package/dist/{csrf-BgfnRJ_y.mjs → csrf-BcxqzCZW.mjs} +3 -3
  35. package/dist/{csrf-BgfnRJ_y.mjs.map → csrf-BcxqzCZW.mjs.map} +1 -1
  36. package/dist/{decorate-CnpOo_Rp.mjs → decorate-BBwu7--P.mjs} +1 -1
  37. package/dist/{define-adapter-7WlOyHBR.mjs → define-adapter-CajLeMzM.mjs} +2 -2
  38. package/dist/{define-adapter-7WlOyHBR.mjs.map → define-adapter-CajLeMzM.mjs.map} +1 -1
  39. package/dist/{disposables-C2uznWks.mjs → disposables-DIXt8ze-.mjs} +2 -2
  40. package/dist/{disposables-C2uznWks.mjs.map → disposables-DIXt8ze-.mjs.map} +1 -1
  41. package/dist/{env-Cj-U1sin.mjs → env-DtJ-6gyL.mjs} +3 -3
  42. package/dist/{env-Cj-U1sin.mjs.map → env-DtJ-6gyL.mjs.map} +1 -1
  43. package/dist/{handler-CnjyOHSw.mjs → handler-2OebsoPr.mjs} +3 -3
  44. package/dist/{handler-CnjyOHSw.mjs.map → handler-2OebsoPr.mjs.map} +1 -1
  45. package/dist/http/application.mjs +2 -2
  46. package/dist/http/bootstrap.mjs +2 -2
  47. package/dist/http/context.mjs +2 -2
  48. package/dist/http/middleware/cors.mjs +1 -1
  49. package/dist/http/middleware/csrf.mjs +2 -2
  50. package/dist/http/middleware/error-handler.mjs +2 -2
  51. package/dist/http/middleware/helmet.mjs +1 -1
  52. package/dist/http/middleware/rate-limit.mjs +2 -2
  53. package/dist/http/middleware/request-id.mjs +1 -1
  54. package/dist/http/middleware/request-logger.mjs +2 -2
  55. package/dist/http/middleware/request-logger.mjs.map +1 -1
  56. package/dist/http/middleware/session.mjs +2 -2
  57. package/dist/http/middleware/spa.mjs +2 -2
  58. package/dist/http/middleware/upload.mjs +2 -2
  59. package/dist/http/middleware/validate.mjs +1 -1
  60. package/dist/http/middleware/views.mjs +2 -2
  61. package/dist/http/query/index.mjs +2 -2
  62. package/dist/http/router-builder.mjs +2 -2
  63. package/dist/http/runtimes/fastify.mjs +2 -2
  64. package/dist/http/runtimes/h3-web.mjs +2 -2
  65. package/dist/http/runtimes/h3.mjs +2 -2
  66. package/dist/index.d.mts +1 -1
  67. package/dist/index.mjs +2 -2
  68. package/dist/{jobs-DIEQILZ8.mjs → jobs-dx-MTUUb.mjs} +3 -3
  69. package/dist/{jobs-DIEQILZ8.mjs.map → jobs-dx-MTUUb.mjs.map} +1 -1
  70. package/dist/{kv-stores-D4dmpn6D.mjs → kv-stores-Ba5_rcz-.mjs} +3 -3
  71. package/dist/{kv-stores-D4dmpn6D.mjs.map → kv-stores-Ba5_rcz-.mjs.map} +1 -1
  72. package/dist/{logger-DA43DvNY.d.mts → logger-xE9qI_FS.d.mts} +45 -5
  73. package/dist/logger-xE9qI_FS.d.mts.map +1 -0
  74. package/dist/{metadata-DrCyWXgz.mjs → metadata-CW4I35nN.mjs} +2 -2
  75. package/dist/{metadata-DrCyWXgz.mjs.map → metadata-CW4I35nN.mjs.map} +1 -1
  76. package/dist/{module-registry-Bv3NMDX5.mjs → module-registry-kqozOSo0.mjs} +2 -2
  77. package/dist/{module-registry-Bv3NMDX5.mjs.map → module-registry-kqozOSo0.mjs.map} +1 -1
  78. package/dist/{observers-DzVW_zb7.mjs → observers-CC3sO1BM.mjs} +2 -2
  79. package/dist/{observers-DzVW_zb7.mjs.map → observers-CC3sO1BM.mjs.map} +1 -1
  80. package/dist/{query-BGQdAxkX.mjs → query-DPlkWOw6.mjs} +2 -2
  81. package/dist/{query-BGQdAxkX.mjs.map → query-DPlkWOw6.mjs.map} +1 -1
  82. package/dist/{respond--WlinyCt.mjs → respond-DjxNwGnN.mjs} +2 -2
  83. package/dist/{respond--WlinyCt.mjs.map → respond-DjxNwGnN.mjs.map} +1 -1
  84. package/dist/{route-flag-DEUYr5Br.mjs → route-flag-sIYXay3q.mjs} +3 -3
  85. package/dist/{route-flag-DEUYr5Br.mjs.map → route-flag-sIYXay3q.mjs.map} +1 -1
  86. package/dist/{route-policy-BmiX7NiW.mjs → route-policy-B6_toGJW.mjs} +2 -2
  87. package/dist/{route-policy-BmiX7NiW.mjs.map → route-policy-B6_toGJW.mjs.map} +1 -1
  88. package/dist/{router-builder-Cig7o4BH.mjs → router-builder-CzVjPs5y.mjs} +3 -3
  89. package/dist/{router-builder-Cig7o4BH.mjs.map → router-builder-CzVjPs5y.mjs.map} +1 -1
  90. package/dist/{runtime-C3izjAep.mjs → runtime-CDz5ayBt.mjs} +3 -3
  91. package/dist/{runtime-C3izjAep.mjs.map → runtime-CDz5ayBt.mjs.map} +1 -1
  92. package/dist/{upload-config-BhaBjCiB.mjs → upload-config-d0pisVsK.mjs} +2 -2
  93. package/dist/{upload-config-BhaBjCiB.mjs.map → upload-config-d0pisVsK.mjs.map} +1 -1
  94. package/dist/web.mjs +2 -2
  95. package/package.json +2 -2
  96. package/dist/logger-DA43DvNY.d.mts.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{r as registerDisposable}from"../../disposables-C2uznWks.mjs";import{n as assertFlagTest,s as matchesFlagTest}from"../../route-flag-DEUYr5Br.mjs";import{n as bindRoutePolicy}from"../../route-policy-BmiX7NiW.mjs";import{n as resolvePathname,t as resolveClientIp}from"../../client-ip-BHH-wDR7.mjs";import{r as sendJson}from"../../respond--WlinyCt.mjs";var MemoryStore=class{windowMs;hits=new Map;cleanupTimer;constructor(windowMs){this.windowMs=windowMs,this.cleanupTimer=setInterval(()=>this.cleanup(),windowMs),this.cleanupTimer.unref&&this.cleanupTimer.unref(),registerDisposable(()=>this.dispose())}dispose(){clearInterval(this.cleanupTimer),this.hits.clear()}async increment(key){let now=Date.now(),entry=this.hits.get(key);if(entry&&entry.resetTime.getTime()>now)return entry.totalHits++,{totalHits:entry.totalHits,resetTime:entry.resetTime};let resetTime=new Date(now+this.windowMs),newEntry={totalHits:1,resetTime};return this.hits.set(key,newEntry),{totalHits:1,resetTime}}async decrement(key){let entry=this.hits.get(key);entry&&entry.totalHits>0&&entry.totalHits--}async reset(key){this.hits.delete(key)}cleanup(){let now=Date.now();for(let[key,entry]of this.hits)entry.resetTime.getTime()<=now&&this.hits.delete(key)}};function rateLimit(options={}){let max=options.max??100,windowMs=options.windowMs??6e4,message=options.message??`Too Many Requests`,statusCode=options.statusCode??429,keyGenerator=options.keyGenerator??(req=>resolveClientIp(req)??`global`),sendHeaders=options.headers??!0,store=options.store??new MemoryStore(windowMs),skip=options.skip,skipPaths=new Set(options.skipPaths??[]),exemptWhen=options.exemptWhen;exemptWhen!==void 0&&assertFlagTest(exemptWhen,`rateLimit({ exemptWhen })`);let policy;return bindRoutePolicy(async(req,res,next)=>{let pathname=resolvePathname(req);if(skipPaths.has(pathname))return next();if(exemptWhen!==void 0&&policy){let flags=policy.lookup(String(req.method??`GET`),pathname);if(matchesFlagTest(exemptWhen,flags))return next()}if(skip&&skip(req))return next();let key=keyGenerator(req),{totalHits,resetTime}=await store.increment(key),remaining=Math.max(0,max-totalHits);if(sendHeaders&&(res.setHeader(`RateLimit-Limit`,max),res.setHeader(`RateLimit-Remaining`,remaining),res.setHeader(`RateLimit-Reset`,Math.ceil(resetTime.getTime()/1e3))),totalHits>max)return sendJson(res,statusCode,{message});next()},table=>{policy=table})}export{rateLimit};
11
+ import{r as registerDisposable}from"../../disposables-DIXt8ze-.mjs";import{n as assertFlagTest,s as matchesFlagTest}from"../../route-flag-sIYXay3q.mjs";import{n as bindRoutePolicy}from"../../route-policy-B6_toGJW.mjs";import{n as resolvePathname,t as resolveClientIp}from"../../client-ip-DMKc-Trg.mjs";import{r as sendJson}from"../../respond-DjxNwGnN.mjs";var MemoryStore=class{windowMs;hits=new Map;cleanupTimer;constructor(windowMs){this.windowMs=windowMs,this.cleanupTimer=setInterval(()=>this.cleanup(),windowMs),this.cleanupTimer.unref&&this.cleanupTimer.unref(),registerDisposable(()=>this.dispose())}dispose(){clearInterval(this.cleanupTimer),this.hits.clear()}async increment(key){let now=Date.now(),entry=this.hits.get(key);if(entry&&entry.resetTime.getTime()>now)return entry.totalHits++,{totalHits:entry.totalHits,resetTime:entry.resetTime};let resetTime=new Date(now+this.windowMs),newEntry={totalHits:1,resetTime};return this.hits.set(key,newEntry),{totalHits:1,resetTime}}async decrement(key){let entry=this.hits.get(key);entry&&entry.totalHits>0&&entry.totalHits--}async reset(key){this.hits.delete(key)}cleanup(){let now=Date.now();for(let[key,entry]of this.hits)entry.resetTime.getTime()<=now&&this.hits.delete(key)}};function rateLimit(options={}){let max=options.max??100,windowMs=options.windowMs??6e4,message=options.message??`Too Many Requests`,statusCode=options.statusCode??429,keyGenerator=options.keyGenerator??(req=>resolveClientIp(req)??`global`),sendHeaders=options.headers??!0,store=options.store??new MemoryStore(windowMs),skip=options.skip,skipPaths=new Set(options.skipPaths??[]),exemptWhen=options.exemptWhen;exemptWhen!==void 0&&assertFlagTest(exemptWhen,`rateLimit({ exemptWhen })`);let policy;return bindRoutePolicy(async(req,res,next)=>{let pathname=resolvePathname(req);if(skipPaths.has(pathname))return next();if(exemptWhen!==void 0&&policy){let flags=policy.lookup(String(req.method??`GET`),pathname);if(matchesFlagTest(exemptWhen,flags))return next()}if(skip&&skip(req))return next();let key=keyGenerator(req),{totalHits,resetTime}=await store.increment(key),remaining=Math.max(0,max-totalHits);if(sendHeaders&&(res.setHeader(`RateLimit-Limit`,max),res.setHeader(`RateLimit-Remaining`,remaining),res.setHeader(`RateLimit-Reset`,Math.ceil(resetTime.getTime()/1e3))),totalHits>max)return sendJson(res,statusCode,{message});next()},table=>{policy=table})}export{rateLimit};
12
12
  //# sourceMappingURL=rate-limit.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{createLogger}from"../../core/logger.mjs";import"../../core-Cv1KjPCj.mjs";function pathnameOf(url){if(!url)return`/`;let q=url.indexOf(`?`);return(q===-1?url:url.slice(0,q))||`/`}function requestLogger(options={}){let log=createLogger(options.name??`HTTP`),level=options.level??`info`,skip=options.skip??[];return(req,res,next)=>{let pathname=req.path??pathnameOf(req.url);if(skip.some(prefix=>pathname.startsWith(prefix)))return next();let start=Date.now();res.on(`finish`,()=>{let duration=Date.now()-start,requestId=req.requestId||req.headers[`x-request-id`]||`-`,status=res.statusCode,path=req.originalUrl??req.url??`/`;log[level](`${req.method} ${path} ${status} ${duration}ms ${requestId}`)}),next()}}export{requestLogger};
11
+ import{createLogger}from"../../core/logger.mjs";import"../../core-_WNyghl_.mjs";function pathnameOf(url){if(!url)return`/`;let q=url.indexOf(`?`);return(q===-1?url:url.slice(0,q))||`/`}function requestLogger(options={}){let log=createLogger(options.name??`HTTP`),level=options.level??`info`,skip=options.skip??[];return(req,res,next)=>{let pathname=req.path??pathnameOf(req.url);if(skip.some(prefix=>pathname.startsWith(prefix)))return next();let start=Date.now();res.on(`finish`,()=>{let duration=Date.now()-start,requestId=req.requestId||req.headers[`x-request-id`]||`-`,status=res.statusCode,path=req.originalUrl??req.url??`/`;log.child({method:req.method,path,status,ms:duration,requestId})[level](`${req.method} ${path} ${status} ${duration}ms ${requestId}`)}),next()}}export{requestLogger};
12
12
  //# sourceMappingURL=request-logger.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-logger.mjs","names":[],"sources":["../../../src/http/middleware/request-logger.ts"],"sourcesContent":["/**\n * The slice of the request/response this logger touches, from node's shapes\n * rather than Express's. This runs under EVERY runtime — Fastify and h3 hand\n * connect middleware the raw node objects — so anything Express-only is\n * `undefined` there.\n */\n/**\n * The request shape this middleware reads.\n *\n * Exported because it appears in the returned handler's signature: a consumer\n * following the documented `src/middleware/index.ts` layout exports the\n * middleware array with an inferred type, and a type the entry does not\n * re-export cannot be named there — `TS4023: Exported variable 'middleware'\n * has or is using name 'LoggedRequest' … but cannot be named`.\n *\n * Deliberately structural rather than Express's `Request`: the Fastify and h3\n * runtimes pass a raw Node request, which has `url` but no `path`.\n */\nexport interface LoggedRequest {\n method?: string\n url?: string\n /** Express-only convenience; the raw node request has only `url`. */\n path?: string\n /** Express-only; absent on the raw node request the other runtimes pass. */\n originalUrl?: string\n headers: Record<string, string | string[] | undefined>\n}\n\n/** The response shape this middleware reads. Exported for the same reason as {@link LoggedRequest}. */\nexport interface LoggedResponse {\n statusCode: number\n on(event: 'finish', listener: () => void): unknown\n}\n\n/** Pathname only — `req.url` carries the query string. */\nfunction pathnameOf(url: string | undefined): string {\n if (!url) return '/'\n const q = url.indexOf('?')\n return (q === -1 ? url : url.slice(0, q)) || '/'\n}\nimport { createLogger } from '../../core'\n\nexport interface RequestLoggerOptions {\n /** Logger name (default: 'HTTP') */\n name?: string\n /** Log level for successful requests (default: 'info') */\n level?: 'info' | 'debug' | 'trace'\n /** Skip logging for paths matching these prefixes (e.g. ['/health', '/_debug']) */\n skip?: string[]\n}\n\n/**\n * Middleware that logs every request with method, URL, status, duration, and request ID.\n *\n * @example\n * ```ts\n * bootstrap({\n * middlewares: [requestId(), requestLogger(), express.json()],\n * })\n * ```\n *\n * Output:\n * ```\n * [HTTP] GET /api/v1/users 200 12ms req-abc123\n * [HTTP] POST /api/v1/users 201 45ms req-def456\n * ```\n */\nexport function requestLogger(options: RequestLoggerOptions = {}) {\n const log = createLogger(options.name ?? 'HTTP')\n const level = options.level ?? 'info'\n const skip = options.skip ?? []\n\n return (req: LoggedRequest, res: LoggedResponse, next: () => void) => {\n // `req.path` is Express-only. Under Fastify and h3 it is `undefined`, so\n // this threw `Cannot read properties of undefined (reading 'startsWith')`\n // on EVERY request as soon as a `skip` prefix was configured — the\n // middleware crashed the request rather than declining to log it.\n const pathname = req.path ?? pathnameOf(req.url)\n if (skip.some((prefix) => pathname.startsWith(prefix))) {\n return next()\n }\n\n const start = Date.now()\n\n res.on('finish', () => {\n const duration = Date.now() - start\n const requestId = (req as any).requestId || req.headers['x-request-id'] || '-'\n const status = res.statusCode\n\n // `originalUrl` is Express-only — on Fastify and h3 this logged\n // `GET undefined 200 12ms`, dropping the path from every access-log\n // line under those runtimes.\n // Both are optional, so the pair still needs a floor — otherwise the\n // line reads `GET undefined` again, just via a different route.\n const path = req.originalUrl ?? req.url ?? '/'\n log[level](`${req.method} ${path} ${status} ${duration}ms ${requestId}`)\n })\n\n next()\n }\n}\n"],"mappings":";;;;;;;;;;gFAmCA,SAAS,WAAW,IAAiC,CACnD,GAAI,CAAC,IAAK,MAAO,IACjB,IAAM,EAAI,IAAI,QAAQ,GAAG,EACzB,OAAQ,IAAM,GAAK,IAAM,IAAI,MAAM,EAAG,CAAC,IAAM,GAC/C,CA4BA,SAAgB,cAAc,QAAgC,CAAC,EAAG,CAChE,IAAM,IAAM,aAAa,QAAQ,MAAQ,MAAM,EACzC,MAAQ,QAAQ,OAAS,OACzB,KAAO,QAAQ,MAAQ,CAAC,EAE9B,OAAQ,IAAoB,IAAqB,OAAqB,CAKpE,IAAM,SAAW,IAAI,MAAQ,WAAW,IAAI,GAAG,EAC/C,GAAI,KAAK,KAAM,QAAW,SAAS,WAAW,MAAM,CAAC,EACnD,OAAO,KAAK,EAGd,IAAM,MAAQ,KAAK,IAAI,EAEvB,IAAI,GAAG,aAAgB,CACrB,IAAM,SAAW,KAAK,IAAI,EAAI,MACxB,UAAa,IAAY,WAAa,IAAI,QAAQ,iBAAmB,IACrE,OAAS,IAAI,WAOb,KAAO,IAAI,aAAe,IAAI,KAAO,IAC3C,IAAI,MAAM,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,KAAK,WAAW,CACzE,CAAC,EAED,KAAK,CACP,CACF"}
1
+ {"version":3,"file":"request-logger.mjs","names":[],"sources":["../../../src/http/middleware/request-logger.ts"],"sourcesContent":["/**\n * The slice of the request/response this logger touches, from node's shapes\n * rather than Express's. This runs under EVERY runtime — Fastify and h3 hand\n * connect middleware the raw node objects — so anything Express-only is\n * `undefined` there.\n */\n/**\n * The request shape this middleware reads.\n *\n * Exported because it appears in the returned handler's signature: a consumer\n * following the documented `src/middleware/index.ts` layout exports the\n * middleware array with an inferred type, and a type the entry does not\n * re-export cannot be named there — `TS4023: Exported variable 'middleware'\n * has or is using name 'LoggedRequest' … but cannot be named`.\n *\n * Deliberately structural rather than Express's `Request`: the Fastify and h3\n * runtimes pass a raw Node request, which has `url` but no `path`.\n */\nexport interface LoggedRequest {\n method?: string\n url?: string\n /** Express-only convenience; the raw node request has only `url`. */\n path?: string\n /** Express-only; absent on the raw node request the other runtimes pass. */\n originalUrl?: string\n headers: Record<string, string | string[] | undefined>\n}\n\n/** The response shape this middleware reads. Exported for the same reason as {@link LoggedRequest}. */\nexport interface LoggedResponse {\n statusCode: number\n on(event: 'finish', listener: () => void): unknown\n}\n\n/** Pathname only — `req.url` carries the query string. */\nfunction pathnameOf(url: string | undefined): string {\n if (!url) return '/'\n const q = url.indexOf('?')\n return (q === -1 ? url : url.slice(0, q)) || '/'\n}\nimport { createLogger } from '../../core'\n\nexport interface RequestLoggerOptions {\n /** Logger name (default: 'HTTP') */\n name?: string\n /** Log level for successful requests (default: 'info') */\n level?: 'info' | 'debug' | 'trace'\n /** Skip logging for paths matching these prefixes (e.g. ['/health', '/_debug']) */\n skip?: string[]\n}\n\n/**\n * Middleware that logs every request with method, URL, status, duration, and request ID.\n *\n * @example\n * ```ts\n * bootstrap({\n * middlewares: [requestId(), requestLogger(), express.json()],\n * })\n * ```\n *\n * Output:\n * ```\n * [HTTP] GET /api/v1/users 200 12ms req-abc123\n * [HTTP] POST /api/v1/users 201 45ms req-def456\n * ```\n */\nexport function requestLogger(options: RequestLoggerOptions = {}) {\n const log = createLogger(options.name ?? 'HTTP')\n const level = options.level ?? 'info'\n const skip = options.skip ?? []\n\n return (req: LoggedRequest, res: LoggedResponse, next: () => void) => {\n // `req.path` is Express-only. Under Fastify and h3 it is `undefined`, so\n // this threw `Cannot read properties of undefined (reading 'startsWith')`\n // on EVERY request as soon as a `skip` prefix was configured — the\n // middleware crashed the request rather than declining to log it.\n const pathname = req.path ?? pathnameOf(req.url)\n if (skip.some((prefix) => pathname.startsWith(prefix))) {\n return next()\n }\n\n const start = Date.now()\n\n res.on('finish', () => {\n const duration = Date.now() - start\n const requestId = (req as any).requestId || req.headers['x-request-id'] || '-'\n const status = res.statusCode\n\n // `originalUrl` is Express-only — on Fastify and h3 this logged\n // `GET undefined 200 12ms`, dropping the path from every access-log\n // line under those runtimes.\n // Both are optional, so the pair still needs a floor — otherwise the\n // line reads `GET undefined` again, just via a different route.\n const path = req.originalUrl ?? req.url ?? '/'\n // The same line as always, with the parts as fields too — a provider\n // writing JSON (`LOG_FORMAT=json`, pino) gets queryable columns.\n const fields = log.child({ method: req.method, path, status, ms: duration, requestId })\n fields[level](`${req.method} ${path} ${status} ${duration}ms ${requestId}`)\n })\n\n next()\n }\n}\n"],"mappings":";;;;;;;;;;gFAmCA,SAAS,WAAW,IAAiC,CACnD,GAAI,CAAC,IAAK,MAAO,IACjB,IAAM,EAAI,IAAI,QAAQ,GAAG,EACzB,OAAQ,IAAM,GAAK,IAAM,IAAI,MAAM,EAAG,CAAC,IAAM,GAC/C,CA4BA,SAAgB,cAAc,QAAgC,CAAC,EAAG,CAChE,IAAM,IAAM,aAAa,QAAQ,MAAQ,MAAM,EACzC,MAAQ,QAAQ,OAAS,OACzB,KAAO,QAAQ,MAAQ,CAAC,EAE9B,OAAQ,IAAoB,IAAqB,OAAqB,CAKpE,IAAM,SAAW,IAAI,MAAQ,WAAW,IAAI,GAAG,EAC/C,GAAI,KAAK,KAAM,QAAW,SAAS,WAAW,MAAM,CAAC,EACnD,OAAO,KAAK,EAGd,IAAM,MAAQ,KAAK,IAAI,EAEvB,IAAI,GAAG,aAAgB,CACrB,IAAM,SAAW,KAAK,IAAI,EAAI,MACxB,UAAa,IAAY,WAAa,IAAI,QAAQ,iBAAmB,IACrE,OAAS,IAAI,WAOb,KAAO,IAAI,aAAe,IAAI,KAAO,IAI3C,IADmB,MAAM,CAAE,OAAQ,IAAI,OAAQ,KAAM,OAAQ,GAAI,SAAU,SAAU,CAChF,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,KAAK,WAAW,CAC5E,CAAC,EAED,KAAK,CACP,CACF"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{r as registerDisposable}from"../../disposables-C2uznWks.mjs";import{i as setCookie,t as parseCookieHeader}from"../../respond--WlinyCt.mjs";import{createHmac,randomUUID,timingSafeEqual}from"node:crypto";var MemoryStore=class{sessions=new Map;cleanupInterval;constructor(){this.cleanupInterval=setInterval(()=>this.purge(),6e4),this.cleanupInterval.unref(),registerDisposable(()=>this.dispose())}dispose(){clearInterval(this.cleanupInterval),this.sessions.clear()}async get(sid){let entry=this.sessions.get(sid);return entry?Date.now()>entry.expires?(this.sessions.delete(sid),null):entry.data:null}async set(sid,data,maxAge){this.sessions.set(sid,{data,expires:Date.now()+maxAge})}async destroy(sid){this.sessions.delete(sid)}async touch(sid,maxAge){let entry=this.sessions.get(sid);entry&&(entry.expires=Date.now()+maxAge)}purge(){let now=Date.now();for(let[sid,entry]of this.sessions)now>entry.expires&&this.sessions.delete(sid)}};function sign(value,secret){return`s:${value}.${createHmac(`sha256`,secret).update(value).digest(`base64url`)}`}function unsign(signed,secret){if(!signed.startsWith(`s:`))return!1;let raw=signed.slice(2),dotIndex=raw.lastIndexOf(`.`);if(dotIndex===-1)return!1;let value=raw.slice(0,dotIndex),providedSig=raw.slice(dotIndex+1),expectedSig=createHmac(`sha256`,secret).update(value).digest(`base64url`),a=Buffer.from(providedSig),b=Buffer.from(expectedSig);return a.length!==b.length||!timingSafeEqual(a,b)?!1:value}function session(options){let{secret,cookieName=`kick.sid`,maxAge=864e5,rolling=!1,saveUninitialized=!0,store=new MemoryStore,cookie:cookieOpts={}}=options,cookieDefaults={httpOnly:cookieOpts.httpOnly??!0,secure:cookieOpts.secure??process.env.NODE_ENV===`production`,sameSite:cookieOpts.sameSite??`lax`,path:cookieOpts.path??`/`,...cookieOpts.domain?{domain:cookieOpts.domain}:{},maxAge};return async(req,res,next)=>{let cookies=req.cookies;if(!cookies){let header=req.headers.cookie;cookies=header?parseCookieHeader(header):{}}let signedCookie=cookies[cookieName],sid=!1,sessionData=null,isNew=!1;signedCookie&&(sid=unsign(signedCookie,secret),sid&&(sessionData=await store.get(sid))),(!sid||!sessionData)&&(sid=randomUUID(),sessionData={},isNew=!0);let currentSid=sid,currentData={...sessionData},destroyed=!1,sessionObj={get id(){return currentSid},data:currentData,async regenerate(){await store.destroy(currentSid),currentSid=randomUUID(),currentData={},sessionObj.data=currentData,await store.set(currentSid,currentData,maxAge),setCookie(res,cookieName,sign(currentSid,secret),cookieDefaults)},async destroy(){await store.destroy(currentSid),destroyed=!0,currentData={},sessionObj.data=currentData,setCookie(res,cookieName,``,{...cookieDefaults,maxAge:0,expires:new Date(0)})},async save(){destroyed||await store.set(currentSid,currentData,maxAge)}};req.session=sessionObj,isNew&&setCookie(res,cookieName,sign(currentSid,secret),cookieDefaults),res.on(`finish`,async()=>{destroyed||(!isNew||saveUninitialized||Object.keys(currentData).length!==0)&&(await store.set(currentSid,currentData,maxAge),rolling&&!isNew&&store.touch&&await store.touch(currentSid,maxAge))}),rolling&&!isNew&&setCookie(res,cookieName,sign(currentSid,secret),cookieDefaults),next()}}export{session};
11
+ import{r as registerDisposable}from"../../disposables-DIXt8ze-.mjs";import{i as setCookie,t as parseCookieHeader}from"../../respond-DjxNwGnN.mjs";import{createHmac,randomUUID,timingSafeEqual}from"node:crypto";var MemoryStore=class{sessions=new Map;cleanupInterval;constructor(){this.cleanupInterval=setInterval(()=>this.purge(),6e4),this.cleanupInterval.unref(),registerDisposable(()=>this.dispose())}dispose(){clearInterval(this.cleanupInterval),this.sessions.clear()}async get(sid){let entry=this.sessions.get(sid);return entry?Date.now()>entry.expires?(this.sessions.delete(sid),null):entry.data:null}async set(sid,data,maxAge){this.sessions.set(sid,{data,expires:Date.now()+maxAge})}async destroy(sid){this.sessions.delete(sid)}async touch(sid,maxAge){let entry=this.sessions.get(sid);entry&&(entry.expires=Date.now()+maxAge)}purge(){let now=Date.now();for(let[sid,entry]of this.sessions)now>entry.expires&&this.sessions.delete(sid)}};function sign(value,secret){return`s:${value}.${createHmac(`sha256`,secret).update(value).digest(`base64url`)}`}function unsign(signed,secret){if(!signed.startsWith(`s:`))return!1;let raw=signed.slice(2),dotIndex=raw.lastIndexOf(`.`);if(dotIndex===-1)return!1;let value=raw.slice(0,dotIndex),providedSig=raw.slice(dotIndex+1),expectedSig=createHmac(`sha256`,secret).update(value).digest(`base64url`),a=Buffer.from(providedSig),b=Buffer.from(expectedSig);return a.length!==b.length||!timingSafeEqual(a,b)?!1:value}function session(options){let{secret,cookieName=`kick.sid`,maxAge=864e5,rolling=!1,saveUninitialized=!0,store=new MemoryStore,cookie:cookieOpts={}}=options,cookieDefaults={httpOnly:cookieOpts.httpOnly??!0,secure:cookieOpts.secure??process.env.NODE_ENV===`production`,sameSite:cookieOpts.sameSite??`lax`,path:cookieOpts.path??`/`,...cookieOpts.domain?{domain:cookieOpts.domain}:{},maxAge};return async(req,res,next)=>{let cookies=req.cookies;if(!cookies){let header=req.headers.cookie;cookies=header?parseCookieHeader(header):{}}let signedCookie=cookies[cookieName],sid=!1,sessionData=null,isNew=!1;signedCookie&&(sid=unsign(signedCookie,secret),sid&&(sessionData=await store.get(sid))),(!sid||!sessionData)&&(sid=randomUUID(),sessionData={},isNew=!0);let currentSid=sid,currentData={...sessionData},destroyed=!1,sessionObj={get id(){return currentSid},data:currentData,async regenerate(){await store.destroy(currentSid),currentSid=randomUUID(),currentData={},sessionObj.data=currentData,await store.set(currentSid,currentData,maxAge),setCookie(res,cookieName,sign(currentSid,secret),cookieDefaults)},async destroy(){await store.destroy(currentSid),destroyed=!0,currentData={},sessionObj.data=currentData,setCookie(res,cookieName,``,{...cookieDefaults,maxAge:0,expires:new Date(0)})},async save(){destroyed||await store.set(currentSid,currentData,maxAge)}};req.session=sessionObj,isNew&&setCookie(res,cookieName,sign(currentSid,secret),cookieDefaults),res.on(`finish`,async()=>{destroyed||(!isNew||saveUninitialized||Object.keys(currentData).length!==0)&&(await store.set(currentSid,currentData,maxAge),rolling&&!isNew&&store.touch&&await store.touch(currentSid,maxAge))}),rolling&&!isNew&&setCookie(res,cookieName,sign(currentSid,secret),cookieDefaults),next()}}export{session};
12
12
  //# sourceMappingURL=session.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{Logger}from"../../core/logger.mjs";import"../../core-Cv1KjPCj.mjs";import{t as defineAdapter}from"../../define-adapter-7WlOyHBR.mjs";import{existsSync,readFileSync,readdirSync}from"node:fs";import{dirname,isAbsolute,join,resolve}from"node:path";const log=Logger.for(`SpaAdapter`);function nearestPackageRoot(from){let dir=from;for(;;){if(existsSync(join(dir,`package.json`)))return dir;let parent=dirname(dir);if(parent===dir)return null;dir=parent}}function resolveClientDir(clientDir,cwd=process.cwd(),entry=process.argv[1]){if(isAbsolute(clientDir))return resolve(clientDir);let fromCwd=resolve(cwd,clientDir);if(existsSync(fromCwd))return fromCwd;if(entry){let root=nearestPackageRoot(dirname(resolve(entry)));if(root){let fromEntry=resolve(root,clientDir);if(existsSync(fromEntry))return fromEntry}}return fromCwd}function pathnameOf(url){if(!url)return`/`;let q=url.indexOf(`?`),h=url.indexOf(`#`),end=Math.min(q===-1?url.length:q,h===-1?url.length:h);return url.slice(0,end)||`/`}function isUnder(pathname,prefix){if(!prefix||prefix===`/`)return!0;let p=prefix.endsWith(`/`)?prefix.slice(0,-1):prefix;return pathname===p||pathname.startsWith(`${p}/`)}const HTML_TYPES=[`text/html`,`application/xhtml+xml`];function qualityOf(params){let q=params.find(param=>param.startsWith(`q=`));if(!q)return 1;let value=Number.parseFloat(q.slice(2));return Number.isNaN(value)?1:value}function acceptsHtml(accept){let raw=Array.isArray(accept)?accept.join(`,`):accept??``;if(!raw)return!1;let ranges=raw.split(`,`).map(part=>part.split(`;`).map(t=>t.trim().toLowerCase())).filter(([type])=>!!type);return HTML_TYPES.some(htmlType=>{let[group]=htmlType.split(`/`),exact=ranges.find(([type])=>type===htmlType),wildcard=ranges.find(([type])=>type===`${group}/*`),match=exact??wildcard;return match?qualityOf(match.slice(1))>0:!1})}const SpaAdapter=defineAdapter({name:`SpaAdapter`,defaults:{clientDir:`dist/client`,apiPrefix:`/api`,exclude:[],cacheControl:`public, max-age=31536000, immutable`,indexCacheControl:`no-cache`,alwaysFallback:!1},build:config=>{let clientDir=resolveClientDir(config.clientDir??`dist/client`),rawPrefix=config.apiPrefix??`/api`,apiPrefixes=Array.isArray(rawPrefix)?rawPrefix:[rawPrefix],excludePaths=config.exclude??[],cacheControl=config.cacheControl??`public, max-age=31536000, immutable`,indexCacheControl=config.indexCacheControl??`no-cache`,alwaysFallback=config.alwaysFallback??!1,indexHtml=null,assetPaths=new Set;function snapshotClientDir(){let paths=new Set,walk=(absDir,prefix)=>{for(let entry of readdirSync(absDir,{withFileTypes:!0})){let child=`${prefix}/${entry.name}`;entry.isDirectory()?walk(join(absDir,entry.name),child):entry.isFile()&&paths.add(child)}};try{walk(clientDir,``)}catch{return new Set}return paths}let classifyPath=pathname=>{let decoded;try{decoded=decodeURIComponent(pathname)}catch{return null}if(decoded.includes(`\0`))return null;let asIndex=decoded.endsWith(`/`)?`${decoded}index.html`:null;return asIndex&&assetPaths.has(asIndex)?`index`:assetPaths.has(decoded)?decoded.endsWith(`.html`)?`index`:`file`:null},isReserved=pathname=>apiPrefixes.some(p=>isUnder(pathname,p))||excludePaths.some(p=>isUnder(pathname,p));return{beforeMount({http}){if(!existsSync(clientDir)){log.warn(`SPA client directory not found: ${clientDir}`),log.warn(`Build your frontend first, or set clientDir to the correct path (relative paths resolve from ${process.cwd()}).`);return}let indexPath=join(clientDir,`index.html`);if(!existsSync(indexPath)){log.warn(`index.html not found in ${clientDir}`);return}indexHtml=readFileSync(indexPath,`utf-8`),assetPaths=snapshotClientDir(),cacheControl!==!1&&http.use(((req,res,next)=>{let pathname=pathnameOf(req.url),kind=isReserved(pathname)?null:classifyPath(pathname);kind&&res.setHeader(`Cache-Control`,kind===`index`?indexCacheControl:cacheControl),next()})),http.serveStatic(`/`,clientDir),log.debug(`Serving SPA from ${clientDir}`)},beforeStart({http}){indexHtml&&http.use(((req,res,next)=>{let method=(req.method??`GET`).toUpperCase();if(method!==`GET`&&method!==`HEAD`)return next();let pathname=pathnameOf(req.url);if(isReserved(pathname))return next();let accept=req.headers?.accept;if(!alwaysFallback&&!acceptsHtml(accept))return next();let body=indexHtml;res.setHeader(`Content-Type`,`text/html; charset=utf-8`),res.setHeader(`Cache-Control`,indexCacheControl),res.setHeader(`Content-Length`,String(Buffer.byteLength(body))),res.statusCode=200,res.end(method===`HEAD`?void 0:body)}))}}}});export{SpaAdapter,resolveClientDir};
11
+ import{Logger}from"../../core/logger.mjs";import"../../core-_WNyghl_.mjs";import{t as defineAdapter}from"../../define-adapter-CajLeMzM.mjs";import{existsSync,readFileSync,readdirSync}from"node:fs";import{dirname,isAbsolute,join,resolve}from"node:path";const log=Logger.for(`SpaAdapter`);function nearestPackageRoot(from){let dir=from;for(;;){if(existsSync(join(dir,`package.json`)))return dir;let parent=dirname(dir);if(parent===dir)return null;dir=parent}}function resolveClientDir(clientDir,cwd=process.cwd(),entry=process.argv[1]){if(isAbsolute(clientDir))return resolve(clientDir);let fromCwd=resolve(cwd,clientDir);if(existsSync(fromCwd))return fromCwd;if(entry){let root=nearestPackageRoot(dirname(resolve(entry)));if(root){let fromEntry=resolve(root,clientDir);if(existsSync(fromEntry))return fromEntry}}return fromCwd}function pathnameOf(url){if(!url)return`/`;let q=url.indexOf(`?`),h=url.indexOf(`#`),end=Math.min(q===-1?url.length:q,h===-1?url.length:h);return url.slice(0,end)||`/`}function isUnder(pathname,prefix){if(!prefix||prefix===`/`)return!0;let p=prefix.endsWith(`/`)?prefix.slice(0,-1):prefix;return pathname===p||pathname.startsWith(`${p}/`)}const HTML_TYPES=[`text/html`,`application/xhtml+xml`];function qualityOf(params){let q=params.find(param=>param.startsWith(`q=`));if(!q)return 1;let value=Number.parseFloat(q.slice(2));return Number.isNaN(value)?1:value}function acceptsHtml(accept){let raw=Array.isArray(accept)?accept.join(`,`):accept??``;if(!raw)return!1;let ranges=raw.split(`,`).map(part=>part.split(`;`).map(t=>t.trim().toLowerCase())).filter(([type])=>!!type);return HTML_TYPES.some(htmlType=>{let[group]=htmlType.split(`/`),exact=ranges.find(([type])=>type===htmlType),wildcard=ranges.find(([type])=>type===`${group}/*`),match=exact??wildcard;return match?qualityOf(match.slice(1))>0:!1})}const SpaAdapter=defineAdapter({name:`SpaAdapter`,defaults:{clientDir:`dist/client`,apiPrefix:`/api`,exclude:[],cacheControl:`public, max-age=31536000, immutable`,indexCacheControl:`no-cache`,alwaysFallback:!1},build:config=>{let clientDir=resolveClientDir(config.clientDir??`dist/client`),rawPrefix=config.apiPrefix??`/api`,apiPrefixes=Array.isArray(rawPrefix)?rawPrefix:[rawPrefix],excludePaths=config.exclude??[],cacheControl=config.cacheControl??`public, max-age=31536000, immutable`,indexCacheControl=config.indexCacheControl??`no-cache`,alwaysFallback=config.alwaysFallback??!1,indexHtml=null,assetPaths=new Set;function snapshotClientDir(){let paths=new Set,walk=(absDir,prefix)=>{for(let entry of readdirSync(absDir,{withFileTypes:!0})){let child=`${prefix}/${entry.name}`;entry.isDirectory()?walk(join(absDir,entry.name),child):entry.isFile()&&paths.add(child)}};try{walk(clientDir,``)}catch{return new Set}return paths}let classifyPath=pathname=>{let decoded;try{decoded=decodeURIComponent(pathname)}catch{return null}if(decoded.includes(`\0`))return null;let asIndex=decoded.endsWith(`/`)?`${decoded}index.html`:null;return asIndex&&assetPaths.has(asIndex)?`index`:assetPaths.has(decoded)?decoded.endsWith(`.html`)?`index`:`file`:null},isReserved=pathname=>apiPrefixes.some(p=>isUnder(pathname,p))||excludePaths.some(p=>isUnder(pathname,p));return{beforeMount({http}){if(!existsSync(clientDir)){log.warn(`SPA client directory not found: ${clientDir}`),log.warn(`Build your frontend first, or set clientDir to the correct path (relative paths resolve from ${process.cwd()}).`);return}let indexPath=join(clientDir,`index.html`);if(!existsSync(indexPath)){log.warn(`index.html not found in ${clientDir}`);return}indexHtml=readFileSync(indexPath,`utf-8`),assetPaths=snapshotClientDir(),cacheControl!==!1&&http.use(((req,res,next)=>{let pathname=pathnameOf(req.url),kind=isReserved(pathname)?null:classifyPath(pathname);kind&&res.setHeader(`Cache-Control`,kind===`index`?indexCacheControl:cacheControl),next()})),http.serveStatic(`/`,clientDir),log.debug(`Serving SPA from ${clientDir}`)},beforeStart({http}){indexHtml&&http.use(((req,res,next)=>{let method=(req.method??`GET`).toUpperCase();if(method!==`GET`&&method!==`HEAD`)return next();let pathname=pathnameOf(req.url);if(isReserved(pathname))return next();let accept=req.headers?.accept;if(!alwaysFallback&&!acceptsHtml(accept))return next();let body=indexHtml;res.setHeader(`Content-Type`,`text/html; charset=utf-8`),res.setHeader(`Cache-Control`,indexCacheControl),res.setHeader(`Content-Length`,String(Buffer.byteLength(body))),res.statusCode=200,res.end(method===`HEAD`?void 0:body)}))}}}});export{SpaAdapter,resolveClientDir};
12
12
  //# sourceMappingURL=spa.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,6 +8,6 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{HttpException,HttpStatus}from"../../core/errors.mjs";import{n as buildFileTypeFilter,r as resolveMimeTypes,t as applyUploadConfig}from"../../upload-config-BhaBjCiB.mjs";import{createRequire}from"node:module";import{unlink}from"node:fs/promises";const requireFromHere=createRequire(import.meta.url);let _multer;function loadMulter(){if(_multer)return _multer;try{return _multer=requireFromHere(`multer`),_multer}catch{throw Error(`@forinda/kickjs: file uploads require the 'multer' package, which is not installed.
11
+ import{HttpException,HttpStatus}from"../../core/errors.mjs";import{n as buildFileTypeFilter,r as resolveMimeTypes,t as applyUploadConfig}from"../../upload-config-d0pisVsK.mjs";import{createRequire}from"node:module";import{unlink}from"node:fs/promises";const requireFromHere=createRequire(import.meta.url);let _multer;function loadMulter(){if(_multer)return _multer;try{return _multer=requireFromHere(`multer`),_multer}catch{throw Error(`@forinda/kickjs: file uploads require the 'multer' package, which is not installed.
12
12
  Install it as a peer dependency: pnpm add multer (or npm i multer / yarn add multer).`)}}function translateMulterErrors(mw,options){let maxSize=options.maxSize??5242880;return(req,res,next)=>{mw(req,res,err=>{if(err&&err.code===`LIMIT_FILE_SIZE`){let name=err.field??`file`;return next(new HttpException(HttpStatus.PAYLOAD_TOO_LARGE,`File ${name} exceeds the ${maxSize}-byte limit`))}next(err)})}}function createMulter(options){let limits={fileSize:options.maxSize??5242880},fileFilter;if(options.allowedTypes){let typeAllowed=buildFileTypeFilter(options.allowedTypes,options.customMimeMap);fileFilter=(_req,file,cb)=>{typeAllowed(file.mimetype,file.originalname)?cb(null,!0):cb(new HttpException(HttpStatus.UNSUPPORTED_MEDIA_TYPE,`File type ${file.mimetype} is not allowed`))}}let multerOptions={limits,...fileFilter?{fileFilter}:{},...options.storage?{storage:options.storage}:{},...options.dest?{dest:options.dest}:{}};return loadMulter()(multerOptions)}function bothConventions(handler){return((first,second,third)=>third===void 0&&typeof second==`function`&&typeof first==`object`&&first&&`req`in first&&`res`in first?new Promise((resolve,reject)=>{handler(first.req,first.res,err=>{if(err)return reject(err);resolve(),second()})}):handler(first,second,third))}function single(fieldName,options={}){return bothConventions(translateMulterErrors(createMulter(options).single(fieldName),options))}function array(fieldName,maxCount=10,options={}){return bothConventions(translateMulterErrors(createMulter(options).array(fieldName,maxCount),options))}function none(options={}){return bothConventions(translateMulterErrors(createMulter(options).none(),options))}function cleanupFiles(){return(req,res,next)=>{res.on(`finish`,async()=>{let files=[];if(req.file?.path&&files.push(req.file),Array.isArray(req.files))for(let f of req.files)f?.path&&files.push(f);for(let file of files)try{await unlink(file.path)}catch{}}),next()}}function buildUploadMiddleware(config){let options={};config.maxSize&&(options.maxSize=config.maxSize),config.allowedTypes&&(options.allowedTypes=config.allowedTypes),config.customMimeMap&&(options.customMimeMap=config.customMimeMap);let fieldName=config.fieldName??`file`;switch(config.mode){case`single`:return single(fieldName,options);case`array`:return array(fieldName,config.maxCount??10,options);case`none`:return none(options)}}const upload={single,array,none};export{applyUploadConfig,buildFileTypeFilter,buildUploadMiddleware,cleanupFiles,resolveMimeTypes,upload};
13
13
  //# sourceMappingURL=upload.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{Logger}from"../../core/logger.mjs";import"../../core-Cv1KjPCj.mjs";import{t as defineAdapter}from"../../define-adapter-7WlOyHBR.mjs";import{resolve}from"node:path";const log=Logger.for(`ViewEngine`),ViewAdapter=defineAdapter({name:`ViewAdapter`,build:options=>({beforeMount({app}){let{engine,ext,viewsDir=`src/views`}=options;engine.__express?app.engine(ext,engine.__express):typeof engine.renderFile==`function`?app.engine(ext,(path,opts,callback)=>{engine.renderFile(path,opts,callback)}):(typeof engine==`function`||log.warn(`Engine for .${ext} does not have __express or renderFile. Trying as-is.`),app.engine(ext,engine)),app.set(`view engine`,ext),app.set(`views`,resolve(viewsDir)),log.debug(`View engine: ${ext} (${resolve(viewsDir)})`)}})});export{ViewAdapter};
11
+ import{Logger}from"../../core/logger.mjs";import"../../core-_WNyghl_.mjs";import{t as defineAdapter}from"../../define-adapter-CajLeMzM.mjs";import{resolve}from"node:path";const log=Logger.for(`ViewEngine`),ViewAdapter=defineAdapter({name:`ViewAdapter`,build:options=>({beforeMount({app}){let{engine,ext,viewsDir=`src/views`}=options;engine.__express?app.engine(ext,engine.__express):typeof engine.renderFile==`function`?app.engine(ext,(path,opts,callback)=>{engine.renderFile(path,opts,callback)}):(typeof engine==`function`||log.warn(`Engine for .${ext} does not have __express or renderFile. Trying as-is.`),app.engine(ext,engine)),app.set(`view engine`,ext),app.set(`views`,resolve(viewsDir)),log.debug(`View engine: ${ext} (${resolve(viewsDir)})`)}})});export{ViewAdapter};
12
12
  //# sourceMappingURL=views.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,4 +8,4 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{a as parseQuery,c as resetQueryParsingDefaults,i as parsePagination,l as setQueryParsingDefaults,n as getQueryParsingDefaults,o as parseSearchQuery,r as parseFilters,s as parseSort,t as buildQueryParams,u as FILTER_OPERATORS}from"../../query-BGQdAxkX.mjs";export{FILTER_OPERATORS,buildQueryParams,getQueryParsingDefaults,parseFilters,parsePagination,parseQuery,parseSearchQuery,parseSort,resetQueryParsingDefaults,setQueryParsingDefaults};
11
+ import{a as parseQuery,c as resetQueryParsingDefaults,i as parsePagination,l as setQueryParsingDefaults,n as getQueryParsingDefaults,o as parseSearchQuery,r as parseFilters,s as parseSort,t as buildQueryParams,u as FILTER_OPERATORS}from"../../query-DPlkWOw6.mjs";export{FILTER_OPERATORS,buildQueryParams,getQueryParsingDefaults,parseFilters,parsePagination,parseQuery,parseSearchQuery,parseSort,resetQueryParsingDefaults,setQueryParsingDefaults};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,4 +8,4 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{n as assertRouteUnique,r as buildRouteTable,t as _setExternalContributorSources}from"../router-builder-Cig7o4BH.mjs";export{_setExternalContributorSources,assertRouteUnique,buildRouteTable};
11
+ import{n as assertRouteUnique,r as buildRouteTable,t as _setExternalContributorSources}from"../router-builder-CzVjPs5y.mjs";export{_setExternalContributorSources,assertRouteUnique,buildRouteTable};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,6 +8,6 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{HttpException}from"../../core/errors.mjs";import{a as createRequestStore,f as unsupportedMediaTypeError,n as applyHandlerResult,o as disposeRequestStore,t as publishMatchedRoute}from"../../runtime-C3izjAep.mjs";import{l as requestStore,t as RequestContext}from"../../context-DEntnLmq.mjs";import{validate}from"../middleware/validate.mjs";import{t as applyUploadConfig}from"../../upload-config-BhaBjCiB.mjs";import"../middleware/upload.mjs";import{createRequire}from"node:module";const peerRequire=createRequire(import.meta.url),loadPeer=name=>{let mod=peerRequire(name);return mod&&mod.__esModule&&mod.default?mod.default:mod.default??mod},QUEUE=Symbol(`kickjs.fastify.connectQueue`),READY=Symbol(`kickjs.fastify.ready`),NEXT=Symbol(`kickjs.fastify.next`),NEEDS_MULTIPART=Symbol(`kickjs.fastify.needsMultipart`),NOOP_NEXT=()=>{};var FastifyReplyDriver=class{reply;constructor(reply){this.reply=reply}status(code){return this.reply.code(code),this}json(data){return this.reply.send(data),this}send(data){return this.reply.send(data),this}type(contentType){return this.reply.type(contentType),this}setHeader(name,value){return this.reply.header(name,value),this}render(){throw Error(`ctx.render() is not supported on the Fastify runtime (no view engine).`)}writeHead(statusCode,headers){return this.reply.hijack(),this.reply.raw.writeHead(statusCode,headers),this}flushHeaders(){return this.reply.raw.flushHeaders?.(),this}write(chunk){return this.reply.raw.write(chunk)}end(data){return this.reply.raw.end(data),this}once(event,listener){return this.reply.raw.once(event,listener),this}get headersSent(){return this.reply.sent||this.reply.raw.headersSent}};function replyDriver(reply){return new FastifyReplyDriver(reply)}function routeHandler(entry){let validator=entry.meta.validation?validate(entry.meta.validation):void 0;return async(request,reply)=>{let raw=request.raw;if(raw.body=request.body,raw.params=request.params,raw.query=request.query,entry.meta.upload&&entry.meta.upload.mode!==`none`){if(typeof request.parts!=`function`)throw Error(`@forinda/kickjs: @FileUpload on the Fastify runtime requires '@fastify/multipart'.
11
+ import{HttpException}from"../../core/errors.mjs";import{a as createRequestStore,f as unsupportedMediaTypeError,n as applyHandlerResult,o as disposeRequestStore,t as publishMatchedRoute}from"../../runtime-CDz5ayBt.mjs";import{l as requestStore,t as RequestContext}from"../../context-BGPof8bs.mjs";import{validate}from"../middleware/validate.mjs";import{t as applyUploadConfig}from"../../upload-config-d0pisVsK.mjs";import"../middleware/upload.mjs";import{createRequire}from"node:module";const peerRequire=createRequire(import.meta.url),loadPeer=name=>{let mod=peerRequire(name);return mod&&mod.__esModule&&mod.default?mod.default:mod.default??mod},QUEUE=Symbol(`kickjs.fastify.connectQueue`),READY=Symbol(`kickjs.fastify.ready`),NEXT=Symbol(`kickjs.fastify.next`),NEEDS_MULTIPART=Symbol(`kickjs.fastify.needsMultipart`),NOOP_NEXT=()=>{};var FastifyReplyDriver=class{reply;constructor(reply){this.reply=reply}status(code){return this.reply.code(code),this}json(data){return this.reply.send(data),this}send(data){return this.reply.send(data),this}type(contentType){return this.reply.type(contentType),this}setHeader(name,value){return this.reply.header(name,value),this}render(){throw Error(`ctx.render() is not supported on the Fastify runtime (no view engine).`)}writeHead(statusCode,headers){return this.reply.hijack(),this.reply.raw.writeHead(statusCode,headers),this}flushHeaders(){return this.reply.raw.flushHeaders?.(),this}write(chunk){return this.reply.raw.write(chunk)}end(data){return this.reply.raw.end(data),this}once(event,listener){return this.reply.raw.once(event,listener),this}get headersSent(){return this.reply.sent||this.reply.raw.headersSent}};function replyDriver(reply){return new FastifyReplyDriver(reply)}function routeHandler(entry){let validator=entry.meta.validation?validate(entry.meta.validation):void 0;return async(request,reply)=>{let raw=request.raw;if(raw.body=request.body,raw.params=request.params,raw.query=request.query,entry.meta.upload&&entry.meta.upload.mode!==`none`){if(typeof request.parts!=`function`)throw Error(`@forinda/kickjs: @FileUpload on the Fastify runtime requires '@fastify/multipart'.
12
12
  Install it as a peer dependency: pnpm add @fastify/multipart.`);let rawParts=[],fields={};for await(let part of request.parts())part.type===`file`&&part.toBuffer?rawParts.push({fieldname:part.fieldname,filename:part.filename??``,mimetype:part.mimetype??`application/octet-stream`,buffer:await part.toBuffer()}):fields[part.fieldname]=part.value;let{file,files}=applyUploadConfig(rawParts,entry.meta.upload);raw.file=file,raw.files=files,raw.body={...raw.body,...fields}}let headerId=raw.headers[`x-request-id`],requestId=(Array.isArray(headerId)?headerId[0]:headerId)||raw.requestId,store=createRequestStore(requestId);raw.requestId=store.requestId,reply.raw.once(`close`,()=>disposeRequestStore(store)),await requestStore.run(store,async()=>{publishMatchedRoute(raw,entry);let ctx=new RequestContext(raw,reply,NOOP_NEXT,replyDriver(reply));if(entry.earlyContributorRunner&&(await entry.earlyContributorRunner(ctx),reply.sent))return;validator&&await new Promise((resolve,reject)=>{validator(raw,void 0,err=>err?reject(err):resolve())});for(let mw of entry.middlewares){let advanced=!1;if(await new Promise((resolve,reject)=>{Promise.resolve(mw(ctx,err=>{advanced=!0,err?reject(err):resolve()})).catch(reject)}),!advanced||reply.sent)return}if(entry.contributorRunner&&await entry.contributorRunner(ctx),reply.sent)return;let result=await entry.handler(ctx);reply.sent||applyHandlerResult(ctx,result)})}}function fastifyRuntime(){return{name:`fastify`,createApp(options={}){let app=loadPeer(`fastify`)({logger:!1,routerOptions:{ignoreTrailingSlash:!0},trustProxy:typeof options.trustProxy!=`function`&&options.trustProxy});app[QUEUE]=[];let addParser=app.addContentTypeParser?.bind(app);return addParser&&(addParser(/^application\/[\w.+-]+\+json$/,{parseAs:`string`},(_req,body,done)=>{if(body===``)return done(null,void 0);try{done(null,JSON.parse(body))}catch(err){done(HttpException.badRequest(err instanceof Error?err.message:`Request body could not be parsed`),void 0)}}),addParser(`application/x-www-form-urlencoded`,{parseAs:`string`},(_req,body,done)=>{done(null,Object.fromEntries(new URLSearchParams(body)))}),addParser(/^text\//,{parseAs:`string`},(_req,body,done)=>{done(null,body)}),addParser(`*`,{parseAs:`string`},(req,body,done)=>{if(!body)return done(null,void 0);done(unsupportedMediaTypeError(req.headers?.[`content-type`]),void 0)})),app},nodeHandler(app){let state=app;state[READY]||(state[READY]=(async()=>{if(state[NEEDS_MULTIPART]){let multipart=loadPeer(`@fastify/multipart`);await app.register(multipart,{limits:{fileSize:2**53-1}})}let middie=loadPeer(`@fastify/middie`);await app.register(middie);for(let{mw,opts}of state[QUEUE]??[])opts?.path===void 0?app.use(mw):app.use(opts.path,mw);await app.ready()})());let readyP=state[READY];return(req,res,next)=>{next&&(req[NEXT]=next),readyP.then(()=>app.routing(req,res)).catch(err=>{next&&next(err)})}},mountRoutes(app,table){for(let{mountPath,routes}of table)for(let entry of routes){entry.meta.upload&&(app[NEEDS_MULTIPART]=!0);let url=joinPath(mountPath,entry.path);app.route({method:entry.method,url,handler:routeHandler(entry)})}},useConnect(app,mw,opts){app[QUEUE]?.push({mw,opts})},serveStatic(app,prefix,dir){let serveStatic=loadPeer(`serve-static`);this.useConnect(app,serveStatic(dir),{path:prefix})},setNotFound(app,mw){app.setNotFoundHandler((request,reply)=>{let next=request.raw[NEXT];if(next){reply.hijack(),next();return}mw(request.raw,replyDriver(reply),NOOP_NEXT)})},setErrorHandler(app,mw){app.setErrorHandler((err,request,reply)=>{mw(err,request.raw,replyDriver(reply),NOOP_NEXT)})},capabilities:{render:!1,uploads:!0,connectMiddleware:!0,nativeBodyParsing:!0,http2:!0}}}function joinPath(mountPath,path){let a=mountPath.endsWith(`/`)?mountPath.slice(0,-1):mountPath;return path===`/`||path===``?a===``?`/`:a:`${a}${path.startsWith(`/`)?path:`/${path}`}`}export{fastifyRuntime};
13
13
  //# sourceMappingURL=fastify.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{createLogger,describeError}from"../../core/logger.mjs";import{n as WebRequestShim,r as WebResponseDriver,t as compileWebRoute}from"../../handler-CnjyOHSw.mjs";import{createRequire}from"node:module";const log=createLogger(`H3WebRuntime`),peerRequire=createRequire(import.meta.url),NOTFOUND_MW=Symbol(`kickjs.h3web.notFoundMw`),ERROR_MW=Symbol(`kickjs.h3web.errorMw`),ASSEMBLED=Symbol(`kickjs.h3web.assembled`),NOOP_NEXT=()=>{};function loadH3v2(injected){let m=injected??peerRequire(`h3`),resolved=m&&m.__esModule&&m.default?{...m.default,...m}:m;if(typeof resolved.H3!=`function`)throw Error("@forinda/kickjs: h3WebRuntime() requires h3 v2 (the web-standards line, npm dist-tag 'latest'), but the installed h3 has no H3 class — that is the v1 line. Either `pnpm add h3@latest` for this runtime, or keep h3 v1 and use h3Runtime() from '@forinda/kickjs/h3'.");return resolved}async function runConnectTerminal(mw,event,err){let req=new WebRequestShim(event.req,event.url),driver=new WebResponseDriver(event.req.signal);return mw&&(err===void 0?mw(req,driver,NOOP_NEXT):mw(err,req,driver,NOOP_NEXT)),driver.settled||(err===void 0?driver.status(404).json({error:`Not Found`}):(log.error(err,`h3-web: error handler did not settle the response — ${describeError(err)}`),driver.status(500).json({error:`Internal Server Error`,...typeof process<`u`&&process.env?.NODE_ENV===`production`?{}:{message:describeError(err)}}))),driver.ready}const FETCH_CONNECT=new WeakMap;function fetchConnectState(event){let state=FETCH_CONNECT.get(event);return state||(state={req:new WebRequestShim(event.req,event.url),headers:new Headers},FETCH_CONNECT.set(event,state)),state}function withConnectHeaders(event,response){let state=FETCH_CONNECT.get(event);if(!state)return response;let missing=[...state.headers].filter(([name])=>name===`set-cookie`||!response.headers.has(name));if(state.headers=new Headers,missing.length===0)return response;try{for(let[name,value]of missing)response.headers.append(name,value);return response}catch{let headers=new Headers(response.headers);for(let[name,value]of missing)headers.append(name,value);return new Response(response.body,{status:response.status,statusText:response.statusText,headers})}}var FetchConnectResponse=class extends WebResponseDriver{prepared;code=200;listeners=[];constructor(prepared,signal){super(signal),this.prepared=prepared}get statusCode(){return this.code}set statusCode(code){this.status(code)}status(code){return this.code=code,super.status(code)}writeHead(code,headers){return this.code=code,super.writeHead(code,headers)}setHeader(name,value){if(Array.isArray(value)){this.prepared.delete(name);for(let v of value)this.prepared.append(name,String(v))}else this.prepared.set(name,String(value));return this}getHeader(name){return this.prepared.get(name)??void 0}hasHeader(name){return this.prepared.has(name)}removeHeader(name){this.prepared.delete(name)}once(event,listener){return this.listeners.push([event,listener]),this}on(event,listener){return this.once(event,listener)}removeListener(event,listener){return this.listeners=this.listeners.filter(([e,l])=>e!==event||l!==listener),this}off(event,listener){return this.removeListener(event,listener)}done(){for(let event of[`finish`,`close`]){for(let[e,listener]of this.listeners)e===event&&listener();this.listeners=this.listeners.filter(([e])=>e!==event)}}};function runConnectOnFetch(mw,event,next){let state=fetchConnectState(event),res=new FetchConnectResponse(state.headers,event.req.signal);return new Promise((resolve,reject)=>{let respond=response=>{res.done(),resolve(withConnectHeaders(event,response))},fail=err=>{res.done(),reject(err)};res.ready.then(respond);let connectNext=err=>{if(err)return fail(err);if(res.settled)return;let id=state.req.requestId;if(id&&event.req.headers.get(`x-request-id`)!==id)try{event.req.headers.set(`x-request-id`,id)}catch{}let downstream;try{downstream=next()}catch(e){return fail(e)}Promise.resolve(downstream).then(value=>{if(value instanceof Response)return respond(value);res.done(),resolve(value)},fail)};try{mw(state.req,res,connectNext)}catch(err){fail(err)}})}function assembleCatchAll(app){let state=app;state[ASSEMBLED]||(state[ASSEMBLED]=!0,app.all(`/**`,event=>{let mw=state[NOTFOUND_MW];return runConnectTerminal(mw,event)}))}function h3WebRuntime(options={}){let{H3,toNodeHandler,fromNodeHandler}=loadH3v2(options.h3);return{name:`h3-web`,createApp(_options={}){let holder={},app=new H3({onError:(error,event)=>{let mw=holder.app?.[ERROR_MW];return runConnectTerminal(mw,event,error).then(response=>withConnectHeaders(event,response))}});return holder.app=app,app},nodeHandler(app){assembleCatchAll(app);let listener=toNodeHandler(app);return(req,res,next)=>{try{let result=listener(req,res);result&&typeof result.then==`function`&&result.catch(err=>next?.(err))}catch(err){next?.(err)}}},mountRoutes(app,table){for(let{mountPath,routes}of table)for(let entry of routes){let url=joinPath(mountPath,entry.path),run=compileWebRoute(entry,{onError:async(err,req,driver)=>{let mw=app[ERROR_MW];mw&&mw(err,req,driver,NOOP_NEXT)}});app.on(entry.method,url,event=>run({request:event.req,url:event.url,params:event.context.params??{}}))}},useConnect(app,mw,opts){let viaNode=fromNodeHandler(mw),handler=(event,next)=>event.req.runtime?.node?.res?viaNode(event):runConnectOnFetch(mw,event,next);opts?.path===void 0?app.use(handler):app.use(joinPath(String(opts.path),`/**`),handler)},serveStatic(app,prefix,dir){let serveStatic=peerRequire(`serve-static`);this.useConnect(app,serveStatic(dir),{path:prefix})},setNotFound(app,mw){app[NOTFOUND_MW]=mw,assembleCatchAll(app)},setErrorHandler(app,mw){app[ERROR_MW]=mw},capabilities:{render:!1,uploads:!0,connectMiddleware:!0,nativeBodyParsing:!0}}}function joinPath(mountPath,path){let a=mountPath.endsWith(`/`)?mountPath.slice(0,-1):mountPath;return path===`/`||path===``?a===``?`/`:a:`${a}${path.startsWith(`/`)?path:`/${path}`}`}export{h3WebRuntime};
11
+ import{createLogger,describeError}from"../../core/logger.mjs";import{n as WebRequestShim,r as WebResponseDriver,t as compileWebRoute}from"../../handler-2OebsoPr.mjs";import{createRequire}from"node:module";const log=createLogger(`H3WebRuntime`),peerRequire=createRequire(import.meta.url),NOTFOUND_MW=Symbol(`kickjs.h3web.notFoundMw`),ERROR_MW=Symbol(`kickjs.h3web.errorMw`),ASSEMBLED=Symbol(`kickjs.h3web.assembled`),NOOP_NEXT=()=>{};function loadH3v2(injected){let m=injected??peerRequire(`h3`),resolved=m&&m.__esModule&&m.default?{...m.default,...m}:m;if(typeof resolved.H3!=`function`)throw Error("@forinda/kickjs: h3WebRuntime() requires h3 v2 (the web-standards line, npm dist-tag 'latest'), but the installed h3 has no H3 class — that is the v1 line. Either `pnpm add h3@latest` for this runtime, or keep h3 v1 and use h3Runtime() from '@forinda/kickjs/h3'.");return resolved}async function runConnectTerminal(mw,event,err){let req=new WebRequestShim(event.req,event.url),driver=new WebResponseDriver(event.req.signal);return mw&&(err===void 0?mw(req,driver,NOOP_NEXT):mw(err,req,driver,NOOP_NEXT)),driver.settled||(err===void 0?driver.status(404).json({error:`Not Found`}):(log.error(err,`h3-web: error handler did not settle the response — ${describeError(err)}`),driver.status(500).json({error:`Internal Server Error`,...typeof process<`u`&&process.env?.NODE_ENV===`production`?{}:{message:describeError(err)}}))),driver.ready}const FETCH_CONNECT=new WeakMap;function fetchConnectState(event){let state=FETCH_CONNECT.get(event);return state||(state={req:new WebRequestShim(event.req,event.url),headers:new Headers},FETCH_CONNECT.set(event,state)),state}function withConnectHeaders(event,response){let state=FETCH_CONNECT.get(event);if(!state)return response;let missing=[...state.headers].filter(([name])=>name===`set-cookie`||!response.headers.has(name));if(state.headers=new Headers,missing.length===0)return response;try{for(let[name,value]of missing)response.headers.append(name,value);return response}catch{let headers=new Headers(response.headers);for(let[name,value]of missing)headers.append(name,value);return new Response(response.body,{status:response.status,statusText:response.statusText,headers})}}var FetchConnectResponse=class extends WebResponseDriver{prepared;code=200;listeners=[];constructor(prepared,signal){super(signal),this.prepared=prepared}get statusCode(){return this.code}set statusCode(code){this.status(code)}status(code){return this.code=code,super.status(code)}writeHead(code,headers){return this.code=code,super.writeHead(code,headers)}setHeader(name,value){if(Array.isArray(value)){this.prepared.delete(name);for(let v of value)this.prepared.append(name,String(v))}else this.prepared.set(name,String(value));return this}getHeader(name){return this.prepared.get(name)??void 0}hasHeader(name){return this.prepared.has(name)}removeHeader(name){this.prepared.delete(name)}once(event,listener){return this.listeners.push([event,listener]),this}on(event,listener){return this.once(event,listener)}removeListener(event,listener){return this.listeners=this.listeners.filter(([e,l])=>e!==event||l!==listener),this}off(event,listener){return this.removeListener(event,listener)}done(){for(let event of[`finish`,`close`]){for(let[e,listener]of this.listeners)e===event&&listener();this.listeners=this.listeners.filter(([e])=>e!==event)}}};function runConnectOnFetch(mw,event,next){let state=fetchConnectState(event),res=new FetchConnectResponse(state.headers,event.req.signal);return new Promise((resolve,reject)=>{let respond=response=>{res.done(),resolve(withConnectHeaders(event,response))},fail=err=>{res.done(),reject(err)};res.ready.then(respond);let connectNext=err=>{if(err)return fail(err);if(res.settled)return;let id=state.req.requestId;if(id&&event.req.headers.get(`x-request-id`)!==id)try{event.req.headers.set(`x-request-id`,id)}catch{}let downstream;try{downstream=next()}catch(e){return fail(e)}Promise.resolve(downstream).then(value=>{if(value instanceof Response)return respond(value);res.done(),resolve(value)},fail)};try{mw(state.req,res,connectNext)}catch(err){fail(err)}})}function assembleCatchAll(app){let state=app;state[ASSEMBLED]||(state[ASSEMBLED]=!0,app.all(`/**`,event=>{let mw=state[NOTFOUND_MW];return runConnectTerminal(mw,event)}))}function h3WebRuntime(options={}){let{H3,toNodeHandler,fromNodeHandler}=loadH3v2(options.h3);return{name:`h3-web`,createApp(_options={}){let holder={},app=new H3({onError:(error,event)=>{let mw=holder.app?.[ERROR_MW];return runConnectTerminal(mw,event,error).then(response=>withConnectHeaders(event,response))}});return holder.app=app,app},nodeHandler(app){assembleCatchAll(app);let listener=toNodeHandler(app);return(req,res,next)=>{try{let result=listener(req,res);result&&typeof result.then==`function`&&result.catch(err=>next?.(err))}catch(err){next?.(err)}}},mountRoutes(app,table){for(let{mountPath,routes}of table)for(let entry of routes){let url=joinPath(mountPath,entry.path),run=compileWebRoute(entry,{onError:async(err,req,driver)=>{let mw=app[ERROR_MW];mw&&mw(err,req,driver,NOOP_NEXT)}});app.on(entry.method,url,event=>run({request:event.req,url:event.url,params:event.context.params??{}}))}},useConnect(app,mw,opts){let viaNode=fromNodeHandler(mw),handler=(event,next)=>event.req.runtime?.node?.res?viaNode(event):runConnectOnFetch(mw,event,next);opts?.path===void 0?app.use(handler):app.use(joinPath(String(opts.path),`/**`),handler)},serveStatic(app,prefix,dir){let serveStatic=peerRequire(`serve-static`);this.useConnect(app,serveStatic(dir),{path:prefix})},setNotFound(app,mw){app[NOTFOUND_MW]=mw,assembleCatchAll(app)},setErrorHandler(app,mw){app[ERROR_MW]=mw},capabilities:{render:!1,uploads:!0,connectMiddleware:!0,nativeBodyParsing:!0}}}function joinPath(mountPath,path){let a=mountPath.endsWith(`/`)?mountPath.slice(0,-1):mountPath;return path===`/`||path===``?a===``?`/`:a:`${a}${path.startsWith(`/`)?path:`/${path}`}`}export{h3WebRuntime};
12
12
  //# sourceMappingURL=h3-web.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{HttpException}from"../../core/errors.mjs";import{a as createRequestStore,f as unsupportedMediaTypeError,n as applyHandlerResult,o as disposeRequestStore,t as publishMatchedRoute,u as classifyMediaType}from"../../runtime-C3izjAep.mjs";import{l as requestStore,t as RequestContext}from"../../context-DEntnLmq.mjs";import{validate}from"../middleware/validate.mjs";import{t as applyUploadConfig}from"../../upload-config-BhaBjCiB.mjs";import"../middleware/upload.mjs";import{createRequire}from"node:module";const peerRequire=createRequire(import.meta.url),h3=()=>peerRequire(`h3`),NEXT=Symbol(`kickjs.h3.next`),ERROR_MW=Symbol(`kickjs.h3.errorMw`),ROUTER=Symbol(`kickjs.h3.router`),NOTFOUND_MW=Symbol(`kickjs.h3.notFoundMw`),ASSEMBLED=Symbol(`kickjs.h3.assembled`),NOOP_NEXT=()=>{},BODY_METHODS=new Set([`POST`,`PUT`,`PATCH`,`DELETE`]);var NodeResDriver=class{res;constructor(res){this.res=res}status(code){return this.res.statusCode=code,this}json(data){return!this.res.headersSent&&!this.res.getHeader(`content-type`)&&this.res.setHeader(`content-type`,`application/json; charset=utf-8`),this.res.end(JSON.stringify(data)),this}send(data){return this.res.end(data),this}type(contentType){return this.res.setHeader(`content-type`,contentType),this}setHeader(name,value){return this.res.setHeader(name,value),this}render(){throw Error(`ctx.render() is not supported on the h3 runtime (no view engine).`)}writeHead(statusCode,headers){return this.res.writeHead(statusCode,headers),this}flushHeaders(){return this.res.flushHeaders(),this}write(chunk){return this.res.write(chunk)}end(data){return this.res.end(data),this}once(event,listener){return this.res.once(event,listener),this}get headersSent(){return this.res.headersSent}};function resDriver(res){return new NodeResDriver(res)}const TRUST_PROXY=Symbol(`kickjs.h3.trustProxy`);function makeEventHandler(entry,trustProxy){let{getRouterParams,getQuery,readRawBody,readMultipartFormData}=h3(),upload=entry.meta.upload,validator=entry.meta.validation?validate(entry.meta.validation):void 0;return async event=>{let req=event.node.req,res=event.node.res;if(trustProxy&&!req.ip){let forwarded=req.headers[`x-forwarded-for`],first=(Array.isArray(forwarded)?forwarded[0]:forwarded)?.split(`,`)[0]?.trim();first&&(req.ip=first)}if(req.params=getRouterParams(event)??{},req.query=getQuery(event)??{},req.httpVersionMajor===2&&req.headers[`content-length`]===void 0&&BODY_METHODS.has(req.method??`GET`)&&(req.rawBody=await readStreamBuffer(req)),upload&&upload.mode!==`none`){let form=await readMultipartFormData(event).catch(()=>void 0),rawParts=[],fields={};for(let part of form??[])part.filename?rawParts.push({fieldname:part.name??``,filename:part.filename,mimetype:part.type??`application/octet-stream`,buffer:part.data}):part.name&&(fields[part.name]=part.data.toString(`utf-8`));let{file,files}=applyUploadConfig(rawParts,upload);req.file=file,req.files=files,req.body=fields}else if(BODY_METHODS.has(req.method??`GET`)){let{"content-length":length,"transfer-encoding":encoding}=req.headers;if(encoding!==void 0||length!==void 0&&length!==`0`||req.httpVersionMajor===2&&length!==`0`){let kind=classifyMediaType(req.headers[`content-type`]);if(kind!==`multipart`){let raw=await readRawBody(event,`utf8`);if(raw){if(kind===`unsupported`)throw unsupportedMediaTypeError(req.headers[`content-type`]);if(kind===`json`)try{req.body=JSON.parse(raw)}catch(err){throw HttpException.badRequest(err instanceof Error?err.message:`Request body could not be parsed`)}else req.body=kind===`urlencoded`?Object.fromEntries(new URLSearchParams(raw)):raw}}}}let headerId=req.headers[`x-request-id`],requestId=(Array.isArray(headerId)?headerId[0]:headerId)||req.requestId,store=createRequestStore(requestId);req.requestId=store.requestId,res.once(`close`,()=>disposeRequestStore(store)),await requestStore.run(store,async()=>{publishMatchedRoute(req,entry);let ctx=new RequestContext(req,res,NOOP_NEXT,resDriver(res));if(entry.earlyContributorRunner&&(await entry.earlyContributorRunner(ctx),res.writableEnded))return;validator&&await new Promise((resolve,reject)=>{validator(req,void 0,err=>err?reject(err):resolve())});for(let mw of entry.middlewares){let advanced=!1;if(await new Promise((resolve,reject)=>{Promise.resolve(mw(ctx,err=>{advanced=!0,err?reject(err):resolve()})).catch(reject)}),!advanced||res.writableEnded)return}if(entry.contributorRunner&&await entry.contributorRunner(ctx),res.writableEnded)return;let result=await entry.handler(ctx);!res.writableEnded&&!res.headersSent&&applyHandlerResult(ctx,result)})}}function unwrapH3Error(error){if(!(error instanceof Error))return error;let{cause}=error;return cause instanceof Error?cause:error}async function readStreamBuffer(req){let chunks=[];for await(let chunk of req)chunks.push(typeof chunk==`string`?Buffer.from(chunk):chunk);return Buffer.concat(chunks)}function h3Runtime(){return{name:`h3`,createApp(options={}){let{createApp}=h3(),app=createApp({onError:(error,event)=>{let res=event.node.res;if(res.writableEnded)return;let state=app,status=error?.statusCode,thrownByHandler=error?.cause instanceof Error;if(status===404&&!thrownByHandler){let next=event.node.req[NEXT];if(next){next();return}let nf=state[NOTFOUND_MW];if(nf){nf(event.node.req,resDriver(res),NOOP_NEXT);return}}let mw=state[ERROR_MW];mw&&mw(unwrapH3Error(error),event.node.req,resDriver(res),NOOP_NEXT)}});return app[TRUST_PROXY]=options.trustProxy,app},nodeHandler(app){let{toNodeListener}=h3(),state=app;state[ASSEMBLED]||(state[ASSEMBLED]=!0,state[ROUTER]&&app.use(state[ROUTER]));let listener=toNodeListener(app);return(req,res,next)=>{next&&(req[NEXT]=next),Promise.resolve(listener(req,res)).catch(err=>{next&&next(err)})}},mountRoutes(app,table){let{createRouter,eventHandler}=h3(),trustProxy=!!app[TRUST_PROXY],state=app;state[ROUTER]||(state[ROUTER]=createRouter());let router=state[ROUTER];for(let{mountPath,routes}of table)for(let entry of routes){let url=joinPath(mountPath,entry.path);router[entry.method.toLowerCase()](url,eventHandler(makeEventHandler(entry,trustProxy)))}},useConnect(app,mw,opts){let{fromNodeMiddleware}=h3(),handler=fromNodeMiddleware(mw);opts?.path===void 0?app.use(handler):app.use(opts.path,handler)},serveStatic(app,prefix,dir){let serveStatic=peerRequire(`serve-static`);this.useConnect(app,serveStatic(dir),{path:prefix})},setNotFound(app,mw){app[NOTFOUND_MW]=mw},setErrorHandler(app,mw){app[ERROR_MW]=mw},capabilities:{render:!1,uploads:!0,connectMiddleware:!0,nativeBodyParsing:!0,http2:!0}}}function joinPath(mountPath,path){let a=mountPath.endsWith(`/`)?mountPath.slice(0,-1):mountPath;return path===`/`||path===``?a===``?`/`:a:`${a}${path.startsWith(`/`)?path:`/${path}`}`}export{h3Runtime};
11
+ import{HttpException}from"../../core/errors.mjs";import{a as createRequestStore,f as unsupportedMediaTypeError,n as applyHandlerResult,o as disposeRequestStore,t as publishMatchedRoute,u as classifyMediaType}from"../../runtime-CDz5ayBt.mjs";import{l as requestStore,t as RequestContext}from"../../context-BGPof8bs.mjs";import{validate}from"../middleware/validate.mjs";import{t as applyUploadConfig}from"../../upload-config-d0pisVsK.mjs";import"../middleware/upload.mjs";import{createRequire}from"node:module";const peerRequire=createRequire(import.meta.url),h3=()=>peerRequire(`h3`),NEXT=Symbol(`kickjs.h3.next`),ERROR_MW=Symbol(`kickjs.h3.errorMw`),ROUTER=Symbol(`kickjs.h3.router`),NOTFOUND_MW=Symbol(`kickjs.h3.notFoundMw`),ASSEMBLED=Symbol(`kickjs.h3.assembled`),NOOP_NEXT=()=>{},BODY_METHODS=new Set([`POST`,`PUT`,`PATCH`,`DELETE`]);var NodeResDriver=class{res;constructor(res){this.res=res}status(code){return this.res.statusCode=code,this}json(data){return!this.res.headersSent&&!this.res.getHeader(`content-type`)&&this.res.setHeader(`content-type`,`application/json; charset=utf-8`),this.res.end(JSON.stringify(data)),this}send(data){return this.res.end(data),this}type(contentType){return this.res.setHeader(`content-type`,contentType),this}setHeader(name,value){return this.res.setHeader(name,value),this}render(){throw Error(`ctx.render() is not supported on the h3 runtime (no view engine).`)}writeHead(statusCode,headers){return this.res.writeHead(statusCode,headers),this}flushHeaders(){return this.res.flushHeaders(),this}write(chunk){return this.res.write(chunk)}end(data){return this.res.end(data),this}once(event,listener){return this.res.once(event,listener),this}get headersSent(){return this.res.headersSent}};function resDriver(res){return new NodeResDriver(res)}const TRUST_PROXY=Symbol(`kickjs.h3.trustProxy`);function makeEventHandler(entry,trustProxy){let{getRouterParams,getQuery,readRawBody,readMultipartFormData}=h3(),upload=entry.meta.upload,validator=entry.meta.validation?validate(entry.meta.validation):void 0;return async event=>{let req=event.node.req,res=event.node.res;if(trustProxy&&!req.ip){let forwarded=req.headers[`x-forwarded-for`],first=(Array.isArray(forwarded)?forwarded[0]:forwarded)?.split(`,`)[0]?.trim();first&&(req.ip=first)}if(req.params=getRouterParams(event)??{},req.query=getQuery(event)??{},req.httpVersionMajor===2&&req.headers[`content-length`]===void 0&&BODY_METHODS.has(req.method??`GET`)&&(req.rawBody=await readStreamBuffer(req)),upload&&upload.mode!==`none`){let form=await readMultipartFormData(event).catch(()=>void 0),rawParts=[],fields={};for(let part of form??[])part.filename?rawParts.push({fieldname:part.name??``,filename:part.filename,mimetype:part.type??`application/octet-stream`,buffer:part.data}):part.name&&(fields[part.name]=part.data.toString(`utf-8`));let{file,files}=applyUploadConfig(rawParts,upload);req.file=file,req.files=files,req.body=fields}else if(BODY_METHODS.has(req.method??`GET`)){let{"content-length":length,"transfer-encoding":encoding}=req.headers;if(encoding!==void 0||length!==void 0&&length!==`0`||req.httpVersionMajor===2&&length!==`0`){let kind=classifyMediaType(req.headers[`content-type`]);if(kind!==`multipart`){let raw=await readRawBody(event,`utf8`);if(raw){if(kind===`unsupported`)throw unsupportedMediaTypeError(req.headers[`content-type`]);if(kind===`json`)try{req.body=JSON.parse(raw)}catch(err){throw HttpException.badRequest(err instanceof Error?err.message:`Request body could not be parsed`)}else req.body=kind===`urlencoded`?Object.fromEntries(new URLSearchParams(raw)):raw}}}}let headerId=req.headers[`x-request-id`],requestId=(Array.isArray(headerId)?headerId[0]:headerId)||req.requestId,store=createRequestStore(requestId);req.requestId=store.requestId,res.once(`close`,()=>disposeRequestStore(store)),await requestStore.run(store,async()=>{publishMatchedRoute(req,entry);let ctx=new RequestContext(req,res,NOOP_NEXT,resDriver(res));if(entry.earlyContributorRunner&&(await entry.earlyContributorRunner(ctx),res.writableEnded))return;validator&&await new Promise((resolve,reject)=>{validator(req,void 0,err=>err?reject(err):resolve())});for(let mw of entry.middlewares){let advanced=!1;if(await new Promise((resolve,reject)=>{Promise.resolve(mw(ctx,err=>{advanced=!0,err?reject(err):resolve()})).catch(reject)}),!advanced||res.writableEnded)return}if(entry.contributorRunner&&await entry.contributorRunner(ctx),res.writableEnded)return;let result=await entry.handler(ctx);!res.writableEnded&&!res.headersSent&&applyHandlerResult(ctx,result)})}}function unwrapH3Error(error){if(!(error instanceof Error))return error;let{cause}=error;return cause instanceof Error?cause:error}async function readStreamBuffer(req){let chunks=[];for await(let chunk of req)chunks.push(typeof chunk==`string`?Buffer.from(chunk):chunk);return Buffer.concat(chunks)}function h3Runtime(){return{name:`h3`,createApp(options={}){let{createApp}=h3(),app=createApp({onError:(error,event)=>{let res=event.node.res;if(res.writableEnded)return;let state=app,status=error?.statusCode,thrownByHandler=error?.cause instanceof Error;if(status===404&&!thrownByHandler){let next=event.node.req[NEXT];if(next){next();return}let nf=state[NOTFOUND_MW];if(nf){nf(event.node.req,resDriver(res),NOOP_NEXT);return}}let mw=state[ERROR_MW];mw&&mw(unwrapH3Error(error),event.node.req,resDriver(res),NOOP_NEXT)}});return app[TRUST_PROXY]=options.trustProxy,app},nodeHandler(app){let{toNodeListener}=h3(),state=app;state[ASSEMBLED]||(state[ASSEMBLED]=!0,state[ROUTER]&&app.use(state[ROUTER]));let listener=toNodeListener(app);return(req,res,next)=>{next&&(req[NEXT]=next),Promise.resolve(listener(req,res)).catch(err=>{next&&next(err)})}},mountRoutes(app,table){let{createRouter,eventHandler}=h3(),trustProxy=!!app[TRUST_PROXY],state=app;state[ROUTER]||(state[ROUTER]=createRouter());let router=state[ROUTER];for(let{mountPath,routes}of table)for(let entry of routes){let url=joinPath(mountPath,entry.path);router[entry.method.toLowerCase()](url,eventHandler(makeEventHandler(entry,trustProxy)))}},useConnect(app,mw,opts){let{fromNodeMiddleware}=h3(),handler=fromNodeMiddleware(mw);opts?.path===void 0?app.use(handler):app.use(opts.path,handler)},serveStatic(app,prefix,dir){let serveStatic=peerRequire(`serve-static`);this.useConnect(app,serveStatic(dir),{path:prefix})},setNotFound(app,mw){app[NOTFOUND_MW]=mw},setErrorHandler(app,mw){app[ERROR_MW]=mw},capabilities:{render:!1,uploads:!0,connectMiddleware:!0,nativeBodyParsing:!0,http2:!0}}}function joinPath(mountPath,path){let a=mountPath.endsWith(`/`)?mountPath.slice(0,-1):mountPath;return path===`/`||path===``?a===``?`/`:a:`${a}${path.startsWith(`/`)?path:`/${path}`}`}export{h3Runtime};
12
12
  //# sourceMappingURL=h3.mjs.map
package/dist/index.d.mts CHANGED
@@ -9,7 +9,7 @@ import { C as MetaValue, S as ExecutionContext, _ as ResolvedDeps, a as ModuleRo
9
9
  import { a as CronOptions, c as getCronJobs, d as runCronJob, f as runCronJobs, i as CronJobMeta, l as isCronJobEnabled, n as Cron, o as CronRun, r as CronJob, s as cronScheduleId, t as CRON_META, u as listCronJobs } from "./cron-BTGytNg-.mjs";
10
10
  import { A as runJob, C as JobLike, D as listJobHandlers, E as ProcessDefinition, O as listJobQueues, S as JobHandler, T as Process, _ as JOB_DISPATCHER, a as KvSessionStoreOptions, b as JobContextCarrier, c as InferHandlerResponse, d as isReply, f as reply, g as JOB_CONTEXT_FIELD, h as waitUntil, i as KvSessionStore, j as stampJobContext, k as registerJobContext, l as Reply, m as settleBackgroundWork, n as KvRateLimitStore, o as RateLimitGuardOptions, p as PlatformContext, r as KvRateLimitStoreOptions, s as rateLimitGuard, t as KvLike, u as applyHandlerResult, v as JOB_META, w as NoJobHandlerError, x as JobDispatcher, y as Job } from "./kv-stores-CetFF9N_.mjs";
11
11
  import { a as Cacheable, c as setCacheProvider, i as CacheProvider, n as CacheEvict, o as MemoryCacheProvider, r as CacheOptions, s as getCacheProvider } from "./cache-C0qL0NSD.mjs";
12
- import { a as describeError, i as createLogger, n as Logger, r as LoggerProvider, t as ConsoleLoggerProvider } from "./logger-DA43DvNY.mjs";
12
+ import { a as describeError, i as createLogger, n as Logger, r as LoggerProvider, t as ConsoleLoggerProvider } from "./logger-xE9qI_FS.mjs";
13
13
  import { $ as MissingMountDepError, A as defineHttpContextDecorator, B as CRON_WORKER_ENV, C as RequestStore, D as buildRoutes, E as requestStore, F as bootstrap, G as offerRoutePolicy, H as KickCronAdapter, I as ERROR_CHANNEL, J as GroupAssetKeysOptions, K as AssetKeyPair, L as HANDLER_CHANNEL, M as isClusterPrimary, N as KickHandler, O as expressRuntime, P as createHandler, Q as DuplicateMountNameError, R as HandlerTraceContext, S as requestScopeMiddleware, T as getRequestValue, U as RoutePolicyTable, V as CronAdapterOptions, W as bindRoutePolicy, X as groupAssetKeys, Y as GroupAssetKeysResult, Z as stripExt, _ as TRACEPARENT_HEADER, _t as Disposable, at as DuplicateContributorError, b as parseTraceparent, c as HealthController, ct as CircuitBreaker, d as healthModule, dt as CircuitBreakerStats, et as MountCycleError, f as SpaAdapter, ft as CircuitOpenError, g as ViewAdapterOptions, gt as formatKickError, h as ViewAdapter, ht as KickErrorInit, i as ServerOptions, it as ContributorCycleError, j as ClusterOptions, k as materializeRouter, l as HealthModuleConfig, lt as CircuitBreakerOptions, mt as KickError, n as ApplicationOptions, nt as MountSortItem, o as HEALTH_PROBE, ot as MissingContextValueError, p as SpaAdapterOptions, pt as FormatKickErrorOptions, q as AssetKeyStrategy, r as MiddlewareEntry, rt as mountSort, s as HealthCheckResult, st as MissingContributorError, t as Application, tt as MountKind, u as HealthProbe, ut as CircuitBreakerState, v as TraceContext, vt as disposeAll, w as getRequestStore, x as traceContext, y as TraceContextOptions, yt as registerDisposable, z as RESPONSE_CHANNEL } from "./application-DqD58rhF.mjs";
14
14
  import { a as ProblemException, c as defaultProblemTitle, i as ProblemDetails, l as normalizeProblem, n as HttpStatus, o as Problems, r as HttpStatusCode, s as ValidationError, t as HttpException } from "./errors-By6UueCm.mjs";
15
15
  import { n as joinPaths, r as normalizePath, t as buildMountPath } from "./path-CMwIHsdv.mjs";
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{a as loadEnvFromSchema,c as withEnv,i as loadEnv,n as defineEnv,o as reloadEnv,r as getEnv,s as resetEnvCache,t as baseEnvSchema}from"./env-Cj-U1sin.mjs";import{METADATA,Scope}from"./core/interfaces.mjs";import{a as isInjectionToken,d as KickError,f as formatKickError,i as createToken,n as tokenName,r as INJECTION_TOKEN,t as Container}from"./container-DM3gPzGt.mjs";import{ConsoleLoggerProvider,Logger,createLogger,describeError}from"./core/logger.mjs";import{a as getMethodMeta,c as pushClassMeta,d as setInMetaMap,f as setInMetaRecord,i as getMetaRecord,l as pushMethodMeta,n as getClassMetaOrUndefined,o as getMethodMetaOrUndefined,p as setMethodMeta,r as getMetaMap,s as hasClassMeta,t as getClassMeta,u as setClassMeta}from"./metadata-DrCyWXgz.mjs";import{ApiQueryParams,Asset,Autowired,Builder,Component,Controller,Delete,FileUpload,Get,Inject,Injectable,Middleware,Patch,Post,PostConstruct,PreDestroy,Put,Repository,Service,Value,normalizeApiQueryParamsConfig,withBuilder}from"./core/decorators.mjs";import{a as HEALTH_PROBE,c as ERROR_CHANNEL,d as DuplicateMountNameError,f as MissingMountDepError,h as defineModule,i as materializeRouter,l as HANDLER_CHANNEL,m as mountSort,n as buildRoutes,o as HealthController,p as MountCycleError,r as expressRuntime,s as healthModule,t as Application,u as RESPONSE_CHANNEL}from"./application-BSDt9vOo.mjs";import{t as MutableModuleRegistry}from"./module-registry-Bv3NMDX5.mjs";import{i as reportResponse,r as reportError}from"./observers-DzVW_zb7.mjs";import{CRON_META,Cron,cronScheduleId,getCronJobs,isCronJobEnabled,listCronJobs,runCronJob,runCronJobs}from"./core/cron.mjs";import{a as NoJobHandlerError,c as listJobQueues,d as stampJobContext,i as Job,l as registerJobContext,n as JOB_DISPATCHER,o as Process,r as JOB_META,s as listJobHandlers,t as JOB_CONTEXT_FIELD,u as runJob}from"./jobs-DIEQILZ8.mjs";import{CacheEvict,Cacheable,MemoryCacheProvider,getCacheProvider,setCacheProvider}from"./core/cache.mjs";import{r as registerDisposable,t as disposeAll}from"./disposables-C2uznWks.mjs";import{HttpException,HttpStatus,ProblemException,Problems,defaultProblemTitle,normalizeProblem}from"./core/errors.mjs";import{buildMountPath,joinPaths,normalizePath}from"./core/path.mjs";import{computed,isRef,reactive,ref,toRefs,unref,watch}from"./core/reactivity.mjs";import{l as resolveRouteFlags,n as assertFlagTest,o as getRouteFlags,r as defineRouteFlag,s as matchesFlagTest}from"./route-flag-DEUYr5Br.mjs";import{a as clearAssetCache,c as groupAssetKeys,i as assets,l as stripExt,n as ASSET_MANIFEST_VERSION,o as resolveAsset,r as UnknownAssetError,s as useAssets,t as ASSETS,u as defineContextDecorator}from"./core-Cv1KjPCj.mjs";import{i as MissingContributorError,n as DuplicateContributorError,r as MissingContextValueError,t as ContributorCycleError}from"./context-errors-Cb4jKwm4.mjs";import{i as buildPipeline,r as buildRouteTable}from"./router-builder-Cig7o4BH.mjs";import{t as runContributors}from"./contributor-runner-Buxk3Ay_.mjs";import{t as defineAdapter}from"./define-adapter-7WlOyHBR.mjs";import{n as bindRoutePolicy,r as offerRoutePolicy,t as RoutePolicyTable}from"./route-policy-BmiX7NiW.mjs";import{c as requestScopeMiddleware,i as reply,n as applyHandlerResult,r as isReply}from"./runtime-C3izjAep.mjs";import{REQUEST_ID_HEADER,requestId}from"./http/middleware/request-id.mjs";import{a as settleBackgroundWork,c as getRequestValue,l as requestStore,o as waitUntil,r as forwardBackgroundWork,s as getRequestStore,t as RequestContext}from"./context-DEntnLmq.mjs";import{errorHandler,notFoundHandler}from"./http/middleware/error-handler.mjs";import{a as parseQuery,c as resetQueryParsingDefaults,i as parsePagination,l as setQueryParsingDefaults,n as getQueryParsingDefaults,o as parseSearchQuery,r as parseFilters,s as parseSort,t as buildQueryParams,u as FILTER_OPERATORS}from"./query-BGQdAxkX.mjs";import{validate}from"./http/middleware/validate.mjs";import{r as resolveMimeTypes}from"./upload-config-BhaBjCiB.mjs";import{buildUploadMiddleware,cleanupFiles,upload}from"./http/middleware/upload.mjs";import{i as KickCronAdapter,n as isClusterPrimary,r as CRON_WORKER_ENV,t as bootstrap}from"./bootstrap-CJ8ALvif.mjs";import{n as csrfGuard,r as randomHex,t as csrf}from"./csrf-BgfnRJ_y.mjs";import{requestLogger}from"./http/middleware/request-logger.mjs";import{helmet}from"./http/middleware/helmet.mjs";import{cors}from"./http/middleware/cors.mjs";import{rateLimit}from"./http/middleware/rate-limit.mjs";import{n as KvSessionStore,r as rateLimitGuard,t as KvRateLimitStore}from"./kv-stores-D4dmpn6D.mjs";import{session}from"./http/middleware/session.mjs";import{ViewAdapter}from"./http/middleware/views.mjs";import{SpaAdapter}from"./http/middleware/spa.mjs";import{n as createConfigService,t as ConfigService}from"./config-Dz5GgLKS.mjs";var ModuleList=class extends Array{mount(module){return this.push(module),this}};function defineModules(...initial){let list=new ModuleList;for(let entry of initial)list.push(entry);return list}var CircuitOpenError=class extends Error{breakerName;constructor(breakerName){super(`Circuit breaker "${breakerName}" is open — request rejected`),this.breakerName=breakerName,this.name=`CircuitOpenError`}},CircuitBreaker=class{name;state=`closed`;failures=0;successes=0;halfOpenAttempts=0;lastFailure;openedAt;failureThreshold;resetTimeout;halfOpenMax;constructor(name,options){this.name=name,this.failureThreshold=options.failureThreshold,this.resetTimeout=options.resetTimeout,this.halfOpenMax=options.halfOpenMax??1}async execute(fn){if(this.maybeTransitionToHalfOpen(),this.state===`open`||this.state===`half_open`&&this.halfOpenAttempts>=this.halfOpenMax)throw new CircuitOpenError(this.name);this.state===`half_open`&&this.halfOpenAttempts++;try{let result=await fn();return this.onSuccess(),result}catch(error){throw this.onFailure(),error}}getState(){return this.maybeTransitionToHalfOpen(),this.state}getStats(){return this.maybeTransitionToHalfOpen(),{failures:this.failures,successes:this.successes,state:this.state,...this.lastFailure?{lastFailure:this.lastFailure}:{}}}reset(){this.state=`closed`,this.failures=0,this.successes=0,this.halfOpenAttempts=0,this.lastFailure=void 0,this.openedAt=void 0}onSuccess(){this.state===`half_open`&&(this.state=`closed`,this.failures=0,this.halfOpenAttempts=0,this.openedAt=void 0),this.successes++}onFailure(){this.failures++,this.lastFailure=new Date,this.state===`half_open`?(this.state=`open`,this.openedAt=Date.now(),this.halfOpenAttempts=0):this.state===`closed`&&this.failures>=this.failureThreshold&&(this.state=`open`,this.openedAt=Date.now())}maybeTransitionToHalfOpen(){this.state===`open`&&this.openedAt!=null&&Date.now()-this.openedAt>=this.resetTimeout&&(this.state=`half_open`,this.halfOpenAttempts=0)}};const mergeConfig=(defaults={},overrides={})=>({...defaults,...overrides}),composeName=(base,scope)=>`${base}:${scope}`;function definePlugin(options){let buildSync=(instanceName,scoped,overrides)=>{let config=mergeConfig(options.defaults,overrides),built=options.build(config,{name:instanceName,scoped});return built.name=instanceName,built},buildAsync=(instanceName,opts)=>{let inner,ensureInner=async container=>{if(inner)return inner;let deps=(opts.inject??[]).map(tok=>container.resolve(tok)),config=await opts.useFactory(...deps);return inner=buildSync(instanceName,!1,config),inner};return{name:instanceName,async onReady(container){let built=await ensureInner(container);built.register?.(container),await built.onReady?.(container)},async shutdown(){await inner?.shutdown?.()}}},factory=(config=>buildSync(options.name,!1,config));return factory.scoped=(scopeName,config)=>buildSync(composeName(options.name,scopeName),!0,config),factory.async=opts=>buildAsync(options.name,opts),Object.defineProperty(factory,"definition",{value:Object.freeze({...options})}),factory}function createHandler(options){let app,ready=()=>(app??=(async()=>{let instance=new Application(options);try{await instance.startWithoutServer()}catch(err){throw app=void 0,await instance.shutdown().catch(()=>{}),err}return instance})(),app);return{ready,async fetch(request,platform){let response=await(await ready()).fetch(request);return forwardBackgroundWork(platform),response},async node(req,res,platform){if((await ready()).handle(req,res),platform?.waitUntil){let sent=new Promise(resolve=>res.once(`close`,()=>resolve()));platform.waitUntil(sent.then(settleBackgroundWork))}},async close(){let current=app;app=void 0,current&&await(await current).shutdown()}}}function defineHttpContextDecoratorImpl(spec){return defineContextDecorator(spec)}const defineHttpContextDecorator=Object.freeze(Object.assign(defineHttpContextDecoratorImpl,{withParams:()=>spec=>defineHttpContextDecoratorImpl(spec)})),TRACEPARENT_HEADER=`traceparent`,TRACEPARENT_RE=/^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;function generateTraceId(){return randomHex(16)}function generateSpanId(){return randomHex(8)}function parseTraceparent(header){let match=TRACEPARENT_RE.exec(header.trim().toLowerCase());if(!match)return null;let version=match[1],traceId=match[2],parentSpanId=match[3],flags=match[4];return version===`ff`||traceId===`00000000000000000000000000000000`||parentSpanId===`0000000000000000`?null:{version,traceId,parentSpanId,flags}}function traceContext(options={}){return(req,res,next)=>{let store=requestStore.getStore(),traceparentHeader=req.headers[TRACEPARENT_HEADER],raw=Array.isArray(traceparentHeader)?traceparentHeader[0]:traceparentHeader,parsed=raw?parseTraceparent(raw):null,traceId=parsed?.traceId??generateTraceId(),spanId=generateSpanId();store&&(store.values.set(`traceId`,traceId),store.values.set(`spanId`,spanId),parsed&&(store.values.set(`parentSpanId`,parsed.parentSpanId),store.values.set(`traceFlags`,parsed.flags),store.values.set(`traceVersion`,parsed.version))),req.traceId=traceId,req.spanId=spanId,options.propagateResponse&&res.setHeader(`traceresponse`,traceId),next()}}export{ASSETS,ASSET_MANIFEST_VERSION,ApiQueryParams,Application,Asset,Autowired,Builder,CRON_META,CRON_WORKER_ENV,CacheEvict,Cacheable,CircuitBreaker,CircuitOpenError,Component,ConfigService,ConsoleLoggerProvider,Container,ContributorCycleError,Controller,Cron,Delete,DuplicateContributorError,DuplicateMountNameError,ERROR_CHANNEL,FILTER_OPERATORS,FileUpload,Get,HANDLER_CHANNEL,HEALTH_PROBE,HealthController,HttpException,HttpStatus,INJECTION_TOKEN,Inject,Injectable,JOB_CONTEXT_FIELD,JOB_DISPATCHER,JOB_META,Job,KickCronAdapter,KickError,KvRateLimitStore,KvSessionStore,Logger,METADATA,MemoryCacheProvider,Middleware,MissingContextValueError,MissingContributorError,MissingMountDepError,ModuleList,MountCycleError,MutableModuleRegistry,NoJobHandlerError,Patch,Post,PostConstruct,PreDestroy,ProblemException,Problems,Process,Put,REQUEST_ID_HEADER,RESPONSE_CHANNEL,Repository,RequestContext,RoutePolicyTable,Scope,Service,SpaAdapter,TRACEPARENT_HEADER,UnknownAssetError,Value,ViewAdapter,applyHandlerResult,assertFlagTest,assets,baseEnvSchema,bindRoutePolicy,bootstrap,buildMountPath,buildPipeline,buildQueryParams,buildRouteTable,buildRoutes,buildUploadMiddleware,cleanupFiles,clearAssetCache,computed,cors,createConfigService,createHandler,createLogger,createToken,cronScheduleId,csrf,csrfGuard,defaultProblemTitle,defineAdapter,defineContextDecorator,defineEnv,defineHttpContextDecorator,defineModule,defineModules,definePlugin,defineRouteFlag,describeError,disposeAll,errorHandler,expressRuntime,formatKickError,getCacheProvider,getClassMeta,getClassMetaOrUndefined,getCronJobs,getEnv,getMetaMap,getMetaRecord,getMethodMeta,getMethodMetaOrUndefined,getQueryParsingDefaults,getRequestStore,getRequestValue,getRouteFlags,groupAssetKeys,hasClassMeta,healthModule,helmet,isClusterPrimary,isCronJobEnabled,isInjectionToken,isRef,isReply,joinPaths,listCronJobs,listJobHandlers,listJobQueues,loadEnv,loadEnvFromSchema,matchesFlagTest,materializeRouter,mountSort,normalizeApiQueryParamsConfig,normalizePath,normalizeProblem,notFoundHandler,offerRoutePolicy,parseFilters,parsePagination,parseQuery,parseSearchQuery,parseSort,parseTraceparent,pushClassMeta,pushMethodMeta,rateLimit,rateLimitGuard,reactive,ref,registerDisposable,registerJobContext,reloadEnv,reply,reportError,reportResponse,requestId,requestLogger,requestScopeMiddleware,requestStore,resetEnvCache,resetQueryParsingDefaults,resolveAsset,resolveMimeTypes,resolveRouteFlags,runContributors,runCronJob,runCronJobs,runJob,session,setCacheProvider,setClassMeta,setInMetaMap,setInMetaRecord,setMethodMeta,setQueryParsingDefaults,settleBackgroundWork,stampJobContext,stripExt,toRefs,tokenName,traceContext,unref,upload,useAssets,validate,waitUntil,watch,withBuilder,withEnv};
11
+ import{a as loadEnvFromSchema,c as withEnv,i as loadEnv,n as defineEnv,o as reloadEnv,r as getEnv,s as resetEnvCache,t as baseEnvSchema}from"./env-DtJ-6gyL.mjs";import{METADATA,Scope}from"./core/interfaces.mjs";import{a as isInjectionToken,d as KickError,f as formatKickError,i as createToken,n as tokenName,r as INJECTION_TOKEN,t as Container}from"./container-ZnfelY_a.mjs";import{ConsoleLoggerProvider,Logger,createLogger,describeError}from"./core/logger.mjs";import{a as getMethodMeta,c as pushClassMeta,d as setInMetaMap,f as setInMetaRecord,i as getMetaRecord,l as pushMethodMeta,n as getClassMetaOrUndefined,o as getMethodMetaOrUndefined,p as setMethodMeta,r as getMetaMap,s as hasClassMeta,t as getClassMeta,u as setClassMeta}from"./metadata-CW4I35nN.mjs";import{ApiQueryParams,Asset,Autowired,Builder,Component,Controller,Delete,FileUpload,Get,Inject,Injectable,Middleware,Patch,Post,PostConstruct,PreDestroy,Put,Repository,Service,Value,normalizeApiQueryParamsConfig,withBuilder}from"./core/decorators.mjs";import{a as HEALTH_PROBE,c as ERROR_CHANNEL,d as DuplicateMountNameError,f as MissingMountDepError,h as defineModule,i as materializeRouter,l as HANDLER_CHANNEL,m as mountSort,n as buildRoutes,o as HealthController,p as MountCycleError,r as expressRuntime,s as healthModule,t as Application,u as RESPONSE_CHANNEL}from"./application-nDj-76EX.mjs";import{t as MutableModuleRegistry}from"./module-registry-kqozOSo0.mjs";import{i as reportResponse,r as reportError}from"./observers-CC3sO1BM.mjs";import{CRON_META,Cron,cronScheduleId,getCronJobs,isCronJobEnabled,listCronJobs,runCronJob,runCronJobs}from"./core/cron.mjs";import{a as NoJobHandlerError,c as listJobQueues,d as stampJobContext,i as Job,l as registerJobContext,n as JOB_DISPATCHER,o as Process,r as JOB_META,s as listJobHandlers,t as JOB_CONTEXT_FIELD,u as runJob}from"./jobs-dx-MTUUb.mjs";import{CacheEvict,Cacheable,MemoryCacheProvider,getCacheProvider,setCacheProvider}from"./core/cache.mjs";import{r as registerDisposable,t as disposeAll}from"./disposables-DIXt8ze-.mjs";import{HttpException,HttpStatus,ProblemException,Problems,defaultProblemTitle,normalizeProblem}from"./core/errors.mjs";import{buildMountPath,joinPaths,normalizePath}from"./core/path.mjs";import{computed,isRef,reactive,ref,toRefs,unref,watch}from"./core/reactivity.mjs";import{l as resolveRouteFlags,n as assertFlagTest,o as getRouteFlags,r as defineRouteFlag,s as matchesFlagTest}from"./route-flag-sIYXay3q.mjs";import{a as clearAssetCache,c as groupAssetKeys,i as assets,l as stripExt,n as ASSET_MANIFEST_VERSION,o as resolveAsset,r as UnknownAssetError,s as useAssets,t as ASSETS,u as defineContextDecorator}from"./core-_WNyghl_.mjs";import{i as MissingContributorError,n as DuplicateContributorError,r as MissingContextValueError,t as ContributorCycleError}from"./context-errors-Cgtrrqfs.mjs";import{i as buildPipeline,r as buildRouteTable}from"./router-builder-CzVjPs5y.mjs";import{t as runContributors}from"./contributor-runner-BSpshfPN.mjs";import{t as defineAdapter}from"./define-adapter-CajLeMzM.mjs";import{n as bindRoutePolicy,r as offerRoutePolicy,t as RoutePolicyTable}from"./route-policy-B6_toGJW.mjs";import{c as requestScopeMiddleware,i as reply,n as applyHandlerResult,r as isReply}from"./runtime-CDz5ayBt.mjs";import{REQUEST_ID_HEADER,requestId}from"./http/middleware/request-id.mjs";import{a as settleBackgroundWork,c as getRequestValue,l as requestStore,o as waitUntil,r as forwardBackgroundWork,s as getRequestStore,t as RequestContext}from"./context-BGPof8bs.mjs";import{errorHandler,notFoundHandler}from"./http/middleware/error-handler.mjs";import{a as parseQuery,c as resetQueryParsingDefaults,i as parsePagination,l as setQueryParsingDefaults,n as getQueryParsingDefaults,o as parseSearchQuery,r as parseFilters,s as parseSort,t as buildQueryParams,u as FILTER_OPERATORS}from"./query-DPlkWOw6.mjs";import{validate}from"./http/middleware/validate.mjs";import{r as resolveMimeTypes}from"./upload-config-d0pisVsK.mjs";import{buildUploadMiddleware,cleanupFiles,upload}from"./http/middleware/upload.mjs";import{i as KickCronAdapter,n as isClusterPrimary,r as CRON_WORKER_ENV,t as bootstrap}from"./bootstrap-BqcT1h9H.mjs";import{n as csrfGuard,r as randomHex,t as csrf}from"./csrf-BcxqzCZW.mjs";import{requestLogger}from"./http/middleware/request-logger.mjs";import{helmet}from"./http/middleware/helmet.mjs";import{cors}from"./http/middleware/cors.mjs";import{rateLimit}from"./http/middleware/rate-limit.mjs";import{n as KvSessionStore,r as rateLimitGuard,t as KvRateLimitStore}from"./kv-stores-Ba5_rcz-.mjs";import{session}from"./http/middleware/session.mjs";import{ViewAdapter}from"./http/middleware/views.mjs";import{SpaAdapter}from"./http/middleware/spa.mjs";import{n as createConfigService,t as ConfigService}from"./config-DrgIbebd.mjs";var ModuleList=class extends Array{mount(module){return this.push(module),this}};function defineModules(...initial){let list=new ModuleList;for(let entry of initial)list.push(entry);return list}var CircuitOpenError=class extends Error{breakerName;constructor(breakerName){super(`Circuit breaker "${breakerName}" is open — request rejected`),this.breakerName=breakerName,this.name=`CircuitOpenError`}},CircuitBreaker=class{name;state=`closed`;failures=0;successes=0;halfOpenAttempts=0;lastFailure;openedAt;failureThreshold;resetTimeout;halfOpenMax;constructor(name,options){this.name=name,this.failureThreshold=options.failureThreshold,this.resetTimeout=options.resetTimeout,this.halfOpenMax=options.halfOpenMax??1}async execute(fn){if(this.maybeTransitionToHalfOpen(),this.state===`open`||this.state===`half_open`&&this.halfOpenAttempts>=this.halfOpenMax)throw new CircuitOpenError(this.name);this.state===`half_open`&&this.halfOpenAttempts++;try{let result=await fn();return this.onSuccess(),result}catch(error){throw this.onFailure(),error}}getState(){return this.maybeTransitionToHalfOpen(),this.state}getStats(){return this.maybeTransitionToHalfOpen(),{failures:this.failures,successes:this.successes,state:this.state,...this.lastFailure?{lastFailure:this.lastFailure}:{}}}reset(){this.state=`closed`,this.failures=0,this.successes=0,this.halfOpenAttempts=0,this.lastFailure=void 0,this.openedAt=void 0}onSuccess(){this.state===`half_open`&&(this.state=`closed`,this.failures=0,this.halfOpenAttempts=0,this.openedAt=void 0),this.successes++}onFailure(){this.failures++,this.lastFailure=new Date,this.state===`half_open`?(this.state=`open`,this.openedAt=Date.now(),this.halfOpenAttempts=0):this.state===`closed`&&this.failures>=this.failureThreshold&&(this.state=`open`,this.openedAt=Date.now())}maybeTransitionToHalfOpen(){this.state===`open`&&this.openedAt!=null&&Date.now()-this.openedAt>=this.resetTimeout&&(this.state=`half_open`,this.halfOpenAttempts=0)}};const mergeConfig=(defaults={},overrides={})=>({...defaults,...overrides}),composeName=(base,scope)=>`${base}:${scope}`;function definePlugin(options){let buildSync=(instanceName,scoped,overrides)=>{let config=mergeConfig(options.defaults,overrides),built=options.build(config,{name:instanceName,scoped});return built.name=instanceName,built},buildAsync=(instanceName,opts)=>{let inner,ensureInner=async container=>{if(inner)return inner;let deps=(opts.inject??[]).map(tok=>container.resolve(tok)),config=await opts.useFactory(...deps);return inner=buildSync(instanceName,!1,config),inner};return{name:instanceName,async onReady(container){let built=await ensureInner(container);built.register?.(container),await built.onReady?.(container)},async shutdown(){await inner?.shutdown?.()}}},factory=(config=>buildSync(options.name,!1,config));return factory.scoped=(scopeName,config)=>buildSync(composeName(options.name,scopeName),!0,config),factory.async=opts=>buildAsync(options.name,opts),Object.defineProperty(factory,"definition",{value:Object.freeze({...options})}),factory}function createHandler(options){let app,ready=()=>(app??=(async()=>{let instance=new Application(options);try{await instance.startWithoutServer()}catch(err){throw app=void 0,await instance.shutdown().catch(()=>{}),err}return instance})(),app);return{ready,async fetch(request,platform){let response=await(await ready()).fetch(request);return forwardBackgroundWork(platform),response},async node(req,res,platform){if((await ready()).handle(req,res),platform?.waitUntil){let sent=new Promise(resolve=>res.once(`close`,()=>resolve()));platform.waitUntil(sent.then(settleBackgroundWork))}},async close(){let current=app;app=void 0,current&&await(await current).shutdown()}}}function defineHttpContextDecoratorImpl(spec){return defineContextDecorator(spec)}const defineHttpContextDecorator=Object.freeze(Object.assign(defineHttpContextDecoratorImpl,{withParams:()=>spec=>defineHttpContextDecoratorImpl(spec)})),TRACEPARENT_HEADER=`traceparent`,TRACEPARENT_RE=/^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;function generateTraceId(){return randomHex(16)}function generateSpanId(){return randomHex(8)}function parseTraceparent(header){let match=TRACEPARENT_RE.exec(header.trim().toLowerCase());if(!match)return null;let version=match[1],traceId=match[2],parentSpanId=match[3],flags=match[4];return version===`ff`||traceId===`00000000000000000000000000000000`||parentSpanId===`0000000000000000`?null:{version,traceId,parentSpanId,flags}}function traceContext(options={}){return(req,res,next)=>{let store=requestStore.getStore(),traceparentHeader=req.headers[TRACEPARENT_HEADER],raw=Array.isArray(traceparentHeader)?traceparentHeader[0]:traceparentHeader,parsed=raw?parseTraceparent(raw):null,traceId=parsed?.traceId??generateTraceId(),spanId=generateSpanId();store&&(store.values.set(`traceId`,traceId),store.values.set(`spanId`,spanId),parsed&&(store.values.set(`parentSpanId`,parsed.parentSpanId),store.values.set(`traceFlags`,parsed.flags),store.values.set(`traceVersion`,parsed.version))),req.traceId=traceId,req.spanId=spanId,options.propagateResponse&&res.setHeader(`traceresponse`,traceId),next()}}export{ASSETS,ASSET_MANIFEST_VERSION,ApiQueryParams,Application,Asset,Autowired,Builder,CRON_META,CRON_WORKER_ENV,CacheEvict,Cacheable,CircuitBreaker,CircuitOpenError,Component,ConfigService,ConsoleLoggerProvider,Container,ContributorCycleError,Controller,Cron,Delete,DuplicateContributorError,DuplicateMountNameError,ERROR_CHANNEL,FILTER_OPERATORS,FileUpload,Get,HANDLER_CHANNEL,HEALTH_PROBE,HealthController,HttpException,HttpStatus,INJECTION_TOKEN,Inject,Injectable,JOB_CONTEXT_FIELD,JOB_DISPATCHER,JOB_META,Job,KickCronAdapter,KickError,KvRateLimitStore,KvSessionStore,Logger,METADATA,MemoryCacheProvider,Middleware,MissingContextValueError,MissingContributorError,MissingMountDepError,ModuleList,MountCycleError,MutableModuleRegistry,NoJobHandlerError,Patch,Post,PostConstruct,PreDestroy,ProblemException,Problems,Process,Put,REQUEST_ID_HEADER,RESPONSE_CHANNEL,Repository,RequestContext,RoutePolicyTable,Scope,Service,SpaAdapter,TRACEPARENT_HEADER,UnknownAssetError,Value,ViewAdapter,applyHandlerResult,assertFlagTest,assets,baseEnvSchema,bindRoutePolicy,bootstrap,buildMountPath,buildPipeline,buildQueryParams,buildRouteTable,buildRoutes,buildUploadMiddleware,cleanupFiles,clearAssetCache,computed,cors,createConfigService,createHandler,createLogger,createToken,cronScheduleId,csrf,csrfGuard,defaultProblemTitle,defineAdapter,defineContextDecorator,defineEnv,defineHttpContextDecorator,defineModule,defineModules,definePlugin,defineRouteFlag,describeError,disposeAll,errorHandler,expressRuntime,formatKickError,getCacheProvider,getClassMeta,getClassMetaOrUndefined,getCronJobs,getEnv,getMetaMap,getMetaRecord,getMethodMeta,getMethodMetaOrUndefined,getQueryParsingDefaults,getRequestStore,getRequestValue,getRouteFlags,groupAssetKeys,hasClassMeta,healthModule,helmet,isClusterPrimary,isCronJobEnabled,isInjectionToken,isRef,isReply,joinPaths,listCronJobs,listJobHandlers,listJobQueues,loadEnv,loadEnvFromSchema,matchesFlagTest,materializeRouter,mountSort,normalizeApiQueryParamsConfig,normalizePath,normalizeProblem,notFoundHandler,offerRoutePolicy,parseFilters,parsePagination,parseQuery,parseSearchQuery,parseSort,parseTraceparent,pushClassMeta,pushMethodMeta,rateLimit,rateLimitGuard,reactive,ref,registerDisposable,registerJobContext,reloadEnv,reply,reportError,reportResponse,requestId,requestLogger,requestScopeMiddleware,requestStore,resetEnvCache,resetQueryParsingDefaults,resolveAsset,resolveMimeTypes,resolveRouteFlags,runContributors,runCronJob,runCronJobs,runJob,session,setCacheProvider,setClassMeta,setInMetaMap,setInMetaRecord,setMethodMeta,setQueryParsingDefaults,settleBackgroundWork,stampJobContext,stripExt,toRefs,tokenName,traceContext,unref,upload,useAssets,validate,waitUntil,watch,withBuilder,withEnv};
12
12
  //# sourceMappingURL=index.mjs.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{i as createToken}from"./container-DM3gPzGt.mjs";import{createLogger}from"./core/logger.mjs";import{c as pushClassMeta,n as getClassMetaOrUndefined,t as getClassMeta,u as setClassMeta}from"./metadata-DrCyWXgz.mjs";import{Service}from"./core/decorators.mjs";import{r as reportError}from"./observers-DzVW_zb7.mjs";const log=createLogger(`KickJobs`),JOB_META={JOB:`kick/queue/job`,PROCESS:`kick/queue/process`},jobClasses=new Map;function Job(queue){return target=>{Service()(target),setClassMeta(JOB_META.JOB,queue,target),jobClasses.set(target.name,target)}}function Process(jobName){return(target,propertyKey)=>{pushClassMeta(JOB_META.PROCESS,target.constructor,{handlerName:propertyKey,jobName})}}function listJobHandlers(container){let handlers=[];for(let target of jobClasses.values()){if(!container.has(target))continue;let queue=getClassMetaOrUndefined(JOB_META.JOB,target);if(queue===void 0)continue;let processes=getClassMeta(JOB_META.PROCESS,target,[]);processes.length===0&&log.warn(`@Job('${queue}') class ${target.name} has no @Process methods`);for(let process of processes)handlers.push({...process,queue,target})}return handlers}function listJobQueues(container){return[...new Set(listJobHandlers(container).map(h=>h.queue))]}var NoJobHandlerError=class extends Error{queue;jobName;constructor(queue,jobName){super(`No @Process handler for job "${jobName}" on queue "${queue}"`),this.queue=queue,this.jobName=jobName,this.name=`NoJobHandlerError`}};async function runJob(container,queue,job,report={}){let handlers=listJobHandlers(container).filter(h=>h.queue===queue),handler=handlers.find(h=>h.jobName===job.name)??handlers.find(h=>h.jobName===void 0);try{if(!handler)throw new NoJobHandlerError(queue,job.name);let instance=container.resolve(handler.target);return await withJobContext(job,()=>instance[handler.handlerName](job))()}catch(err){throw log.error({err},`Job ${queue}/${job.name} failed`),reportError(err,{source:`job`,context:{queue,job:job.name,id:job.id,...report}}),err}}const JOB_CONTEXT_FIELD=`__kickContext`,jobContextCarriers=new Map;function registerJobContext(carrier){jobContextCarriers.set(carrier.key,carrier)}const isPlainObject=v=>!!v&&typeof v==`object`&&Object.getPrototypeOf(v)===Object.prototype;function stampJobContext(data){if(!isPlainObject(data))return data;let{[JOB_CONTEXT_FIELD]:_untrusted,...rest}=data,context={};for(let[key,carrier]of jobContextCarriers){let value=carrier.capture();value!==void 0&&(context[key]=value)}return Object.keys(context).length>0?{...rest,[JOB_CONTEXT_FIELD]:context}:rest}function withJobContext(job,run){let data=job.data;if(!isPlainObject(data)||!(`__kickContext`in data))return run;let context=data[JOB_CONTEXT_FIELD];if(delete data[JOB_CONTEXT_FIELD],!isPlainObject(context))return run;let wrapped=run;for(let[key,value]of Object.entries(context)){let carrier=jobContextCarriers.get(key);if(!carrier)continue;let inner=wrapped;wrapped=()=>carrier.restore(value,inner)}return wrapped}const JOB_DISPATCHER=createToken(`kick/jobs/Dispatcher`);export{NoJobHandlerError as a,listJobQueues as c,stampJobContext as d,Job as i,registerJobContext as l,JOB_DISPATCHER as n,Process as o,JOB_META as r,listJobHandlers as s,JOB_CONTEXT_FIELD as t,runJob as u};
12
- //# sourceMappingURL=jobs-DIEQILZ8.mjs.map
11
+ import{i as createToken}from"./container-ZnfelY_a.mjs";import{createLogger}from"./core/logger.mjs";import{c as pushClassMeta,n as getClassMetaOrUndefined,t as getClassMeta,u as setClassMeta}from"./metadata-CW4I35nN.mjs";import{Service}from"./core/decorators.mjs";import{r as reportError}from"./observers-CC3sO1BM.mjs";const log=createLogger(`KickJobs`),JOB_META={JOB:`kick/queue/job`,PROCESS:`kick/queue/process`},jobClasses=new Map;function Job(queue){return target=>{Service()(target),setClassMeta(JOB_META.JOB,queue,target),jobClasses.set(target.name,target)}}function Process(jobName){return(target,propertyKey)=>{pushClassMeta(JOB_META.PROCESS,target.constructor,{handlerName:propertyKey,jobName})}}function listJobHandlers(container){let handlers=[];for(let target of jobClasses.values()){if(!container.has(target))continue;let queue=getClassMetaOrUndefined(JOB_META.JOB,target);if(queue===void 0)continue;let processes=getClassMeta(JOB_META.PROCESS,target,[]);processes.length===0&&log.warn(`@Job('${queue}') class ${target.name} has no @Process methods`);for(let process of processes)handlers.push({...process,queue,target})}return handlers}function listJobQueues(container){return[...new Set(listJobHandlers(container).map(h=>h.queue))]}var NoJobHandlerError=class extends Error{queue;jobName;constructor(queue,jobName){super(`No @Process handler for job "${jobName}" on queue "${queue}"`),this.queue=queue,this.jobName=jobName,this.name=`NoJobHandlerError`}};async function runJob(container,queue,job,report={}){let handlers=listJobHandlers(container).filter(h=>h.queue===queue),handler=handlers.find(h=>h.jobName===job.name)??handlers.find(h=>h.jobName===void 0);try{if(!handler)throw new NoJobHandlerError(queue,job.name);let instance=container.resolve(handler.target);return await withJobContext(job,()=>instance[handler.handlerName](job))()}catch(err){throw log.error({err},`Job ${queue}/${job.name} failed`),reportError(err,{source:`job`,context:{queue,job:job.name,id:job.id,...report}}),err}}const JOB_CONTEXT_FIELD=`__kickContext`,jobContextCarriers=new Map;function registerJobContext(carrier){jobContextCarriers.set(carrier.key,carrier)}const isPlainObject=v=>!!v&&typeof v==`object`&&Object.getPrototypeOf(v)===Object.prototype;function stampJobContext(data){if(!isPlainObject(data))return data;let{[JOB_CONTEXT_FIELD]:_untrusted,...rest}=data,context={};for(let[key,carrier]of jobContextCarriers){let value=carrier.capture();value!==void 0&&(context[key]=value)}return Object.keys(context).length>0?{...rest,[JOB_CONTEXT_FIELD]:context}:rest}function withJobContext(job,run){let data=job.data;if(!isPlainObject(data)||!(`__kickContext`in data))return run;let context=data[JOB_CONTEXT_FIELD];if(delete data[JOB_CONTEXT_FIELD],!isPlainObject(context))return run;let wrapped=run;for(let[key,value]of Object.entries(context)){let carrier=jobContextCarriers.get(key);if(!carrier)continue;let inner=wrapped;wrapped=()=>carrier.restore(value,inner)}return wrapped}const JOB_DISPATCHER=createToken(`kick/jobs/Dispatcher`);export{NoJobHandlerError as a,listJobQueues as c,stampJobContext as d,Job as i,registerJobContext as l,JOB_DISPATCHER as n,Process as o,JOB_META as r,listJobHandlers as s,JOB_CONTEXT_FIELD as t,runJob as u};
12
+ //# sourceMappingURL=jobs-dx-MTUUb.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"jobs-DIEQILZ8.mjs","names":[],"sources":["../src/core/jobs.ts"],"sourcesContent":["/**\n * Background jobs, with whatever runs them.\n *\n * `@Job(queue)` / `@Process(name)` only record which method handles which\n * job — the same way `@Cron` only records a schedule. Any job tool turns that\n * into running code in a few lines: subscribe to each queue from\n * {@link listJobQueues}, and hand every job it receives to {@link runJob}.\n *\n * @Job('email')\n * export class EmailJobs {\n * @Process('welcome')\n * async welcome(job: JobLike<{ to: string }>) { await sendWelcome(job.data.to) }\n * }\n *\n * Enqueueing goes through {@link JOB_DISPATCHER}, which the active adapter\n * provides — code that dispatches never names the tool.\n *\n * `@forinda/kickjs-queue` ships a BullMQ adapter (plus RabbitMQ / Kafka /\n * Redis pub-sub providers); the web entry's `queue()` runs Cloudflare Queues.\n */\nimport { Service } from './decorators'\nimport { getClassMeta, getClassMetaOrUndefined, pushClassMeta, setClassMeta } from './metadata'\nimport { reportError } from './observers'\nimport { createLogger } from './logger'\nimport { createToken } from './token'\n\nconst log = createLogger('KickJobs')\n\n/** Metadata keys — the same ones `@forinda/kickjs-queue` used, so existing readers keep working. */\nexport const JOB_META = {\n JOB: 'kick/queue/job',\n PROCESS: 'kick/queue/process',\n} as const\n\n/** What a `@Process` method records. */\nexport interface ProcessDefinition {\n /** Method name on the class. */\n handlerName: string\n /** Job name it handles; `undefined` handles every job in the queue. */\n jobName?: string\n}\n\n/**\n * The least a job tool hands over. Runners pass their own job object through\n * unchanged — BullMQ's `Job`, a Cloudflare message — so a handler can still\n * reach tool-specific fields (`job.attemptsMade`, `job.updateProgress()`).\n */\nexport interface JobLike<Data = unknown> {\n name: string\n data: Data\n id?: string\n}\n\n/**\n * Every `@Job` class, keyed by class name like the DI registry: an HMR\n * re-evaluation replaces the old class instead of leaving both subscribed.\n */\nconst jobClasses = new Map<string, Function>()\n\n/** Mark a class as handling jobs on `queue`. The class is a DI singleton. */\nexport function Job(queue: string): ClassDecorator {\n return (target) => {\n Service()(target)\n setClassMeta(JOB_META.JOB, queue, target)\n jobClasses.set(target.name, target)\n }\n}\n\n/** Mark a method as handling `jobName` — or, without a name, every job its queue gets. */\nexport function Process(jobName?: string): MethodDecorator {\n return (target, propertyKey) => {\n pushClassMeta<ProcessDefinition>(JOB_META.PROCESS, target.constructor, {\n handlerName: propertyKey as string,\n jobName,\n })\n }\n}\n\n/** One handler: its queue, job name (absent for a catch-all), class and method. */\nexport interface JobHandler extends ProcessDefinition {\n queue: string\n target: Function\n}\n\n/**\n * Every `@Process` method of a `@Job` class the container can resolve.\n * Classes it doesn't know (not in a module, or from before an HMR reload)\n * are skipped.\n */\nexport function listJobHandlers(container: { has(token: unknown): boolean }): JobHandler[] {\n const handlers: JobHandler[] = []\n for (const target of jobClasses.values()) {\n if (!container.has(target)) continue\n const queue = getClassMetaOrUndefined<string>(JOB_META.JOB, target)\n if (queue === undefined) continue\n const processes = getClassMeta<ProcessDefinition[]>(JOB_META.PROCESS, target, [])\n if (processes.length === 0) {\n log.warn(`@Job('${queue}') class ${target.name} has no @Process methods`)\n }\n for (const process of processes) handlers.push({ ...process, queue, target })\n }\n return handlers\n}\n\n/** The queues something handles — what a runner subscribes to. */\nexport function listJobQueues(container: { has(token: unknown): boolean }): string[] {\n return [...new Set(listJobHandlers(container).map((h) => h.queue))]\n}\n\n/** Thrown when a queue receives a job no `@Process` method handles. */\nexport class NoJobHandlerError extends Error {\n constructor(\n readonly queue: string,\n readonly jobName: string,\n ) {\n super(`No @Process handler for job \"${jobName}\" on queue \"${queue}\"`)\n this.name = 'NoJobHandlerError'\n }\n}\n\n/**\n * Run one job: pick the `@Process` method for `job.name` (or the queue's\n * catch-all), resolve its class from the container and call it with `job`\n * as given. A failure is reported to the error observers (`source: 'job'`)\n * and rethrown, so the tool's own retry and dead-letter handling still\n * applies. A job nothing handles throws {@link NoJobHandlerError} rather\n * than being acknowledged and lost.\n */\nexport async function runJob(\n container: { has(token: unknown): boolean; resolve(token: unknown): unknown },\n queue: string,\n job: JobLike,\n /** Extra fields for the error report — e.g. the tool's attempt count. */\n report: Record<string, unknown> = {},\n): Promise<unknown> {\n const handlers = listJobHandlers(container).filter((h) => h.queue === queue)\n const handler =\n handlers.find((h) => h.jobName === job.name) ?? handlers.find((h) => h.jobName === undefined)\n try {\n if (!handler) throw new NoJobHandlerError(queue, job.name)\n const instance = container.resolve(handler.target) as Record<string, (j: JobLike) => unknown>\n return await withJobContext(job, () => instance[handler.handlerName]!(job))()\n } catch (err) {\n log.error({ err }, `Job ${queue}/${job.name} failed`)\n reportError(err, { source: 'job', context: { queue, job: job.name, id: job.id, ...report } })\n throw err\n }\n}\n\n/**\n * Something about where a job was dispatched from that its handler should\n * run with — the tenant, a trace id, the acting user. Captured when the job\n * is dispatched, carried in its data, and restored around the handler.\n */\nexport interface JobContextCarrier<T = unknown> {\n /** Unique: the field it travels under. */\n key: string\n /** The value to carry, or `undefined` for nothing. */\n capture(): T | undefined\n /** Run the handler with the value back in place. */\n restore<R>(value: T, run: () => R): R\n}\n\n/** The field a job's data carries its context in. Removed before the handler sees the data. */\nexport const JOB_CONTEXT_FIELD = '__kickContext'\n\nconst jobContextCarriers = new Map<string, JobContextCarrier>()\n\n/** Carry a value from dispatch to handler for every job. Registering a key again replaces it. */\nexport function registerJobContext<T>(carrier: JobContextCarrier<T>): void {\n jobContextCarriers.set(carrier.key, carrier as JobContextCarrier)\n}\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n !!v && typeof v === 'object' && Object.getPrototypeOf(v) === Object.prototype\n\n/**\n * `data` with the current job context added — for a {@link JobDispatcher}\n * implementation to call before enqueueing. Any `__kickContext` already in\n * `data` is removed first: only this call may set it, so a dispatcher that\n * enqueues caller-supplied data without it lets that data choose the context. Only plain-object data can carry\n * it; anything else, or nothing to carry, is returned as is.\n */\nexport function stampJobContext<Data>(data: Data): Data {\n if (!isPlainObject(data)) return data\n // Only the dispatcher's own context travels. A caller's data (a request\n // body, say) carrying the field would otherwise pick the job's tenant.\n const { [JOB_CONTEXT_FIELD]: _untrusted, ...rest } = data\n const context: Record<string, unknown> = {}\n for (const [key, carrier] of jobContextCarriers) {\n const value = carrier.capture()\n if (value !== undefined) context[key] = value\n }\n const stamped = Object.keys(context).length > 0 ? { ...rest, [JOB_CONTEXT_FIELD]: context } : rest\n return stamped as Data\n}\n\n/** Take the carried context off the job's data, and wrap `run` in every restore. */\nfunction withJobContext<R>(job: JobLike, run: () => R): () => R {\n const data = job.data\n if (!isPlainObject(data) || !(JOB_CONTEXT_FIELD in data)) return run\n const context = data[JOB_CONTEXT_FIELD]\n delete data[JOB_CONTEXT_FIELD]\n // Only an object of carrier keys is context; anything else is dropped.\n if (!isPlainObject(context)) return run\n let wrapped = run\n for (const [key, value] of Object.entries(context)) {\n const carrier = jobContextCarriers.get(key)\n if (!carrier) continue\n const inner = wrapped\n wrapped = () => carrier.restore(value, inner)\n }\n return wrapped\n}\n\n/** Enqueue a job — implemented by whichever adapter runs the jobs. */\nexport interface JobDispatcher {\n dispatch<Data = unknown>(\n queue: string,\n name: string,\n data: Data,\n options?: Record<string, unknown>,\n ): Promise<unknown>\n}\n\n/**\n * The active job dispatcher. Inject it to enqueue without naming the tool:\n * `@Inject(JOB_DISPATCHER) private jobs!: JobDispatcher`.\n */\nexport const JOB_DISPATCHER = createToken<JobDispatcher>('kick/jobs/Dispatcher')\n"],"mappings":";;;;;;;;;;8TA0BA,MAAM,IAAM,aAAa,UAAU,EAGtB,SAAW,CACtB,IAAK,iBACL,QAAS,oBACX,EAyBM,WAAa,IAAI,IAGvB,SAAgB,IAAI,MAA+B,CACjD,MAAQ,SAAW,CACjB,QAAQ,CAAC,CAAC,MAAM,EAChB,aAAa,SAAS,IAAK,MAAO,MAAM,EACxC,WAAW,IAAI,OAAO,KAAM,MAAM,CACpC,CACF,CAGA,SAAgB,QAAQ,QAAmC,CACzD,OAAQ,OAAQ,cAAgB,CAC9B,cAAiC,SAAS,QAAS,OAAO,YAAa,CACrE,YAAa,YACb,OACF,CAAC,CACH,CACF,CAaA,SAAgB,gBAAgB,UAA2D,CACzF,IAAM,SAAyB,CAAC,EAChC,IAAK,IAAM,UAAU,WAAW,OAAO,EAAG,CACxC,GAAI,CAAC,UAAU,IAAI,MAAM,EAAG,SAC5B,IAAM,MAAQ,wBAAgC,SAAS,IAAK,MAAM,EAClE,GAAI,QAAU,IAAA,GAAW,SACzB,IAAM,UAAY,aAAkC,SAAS,QAAS,OAAQ,CAAC,CAAC,EAC5E,UAAU,SAAW,GACvB,IAAI,KAAK,SAAS,MAAM,WAAW,OAAO,KAAK,yBAAyB,EAE1E,IAAK,IAAM,WAAW,UAAW,SAAS,KAAK,CAAE,GAAG,QAAS,MAAO,MAAO,CAAC,CAC9E,CACA,OAAO,QACT,CAGA,SAAgB,cAAc,UAAuD,CACnF,MAAO,CAAC,GAAG,IAAI,IAAI,gBAAgB,SAAS,CAAC,CAAC,IAAK,GAAM,EAAE,KAAK,CAAC,CAAC,CACpE,CAGA,IAAa,kBAAb,cAAuC,KAAM,CAEhC,MACA,QAFX,YACE,MACA,QACA,CACA,MAAM,gCAAgC,QAAQ,cAAc,MAAM,EAAE,EAH3D,KAAA,MAAA,MACA,KAAA,QAAA,QAGT,KAAK,KAAO,mBACd,CACF,EAUA,eAAsB,OACpB,UACA,MACA,IAEA,OAAkC,CAAC,EACjB,CAClB,IAAM,SAAW,gBAAgB,SAAS,CAAC,CAAC,OAAQ,GAAM,EAAE,QAAU,KAAK,EACrE,QACJ,SAAS,KAAM,GAAM,EAAE,UAAY,IAAI,IAAI,GAAK,SAAS,KAAM,GAAM,EAAE,UAAY,IAAA,EAAS,EAC9F,GAAI,CACF,GAAI,CAAC,QAAS,MAAM,IAAI,kBAAkB,MAAO,IAAI,IAAI,EACzD,IAAM,SAAW,UAAU,QAAQ,QAAQ,MAAM,EACjD,OAAO,MAAM,eAAe,QAAW,SAAS,QAAQ,YAAY,CAAE,GAAG,CAAC,CAAC,CAAC,CAC9E,OAAS,IAAK,CAGZ,MAFA,IAAI,MAAM,CAAE,GAAI,EAAG,OAAO,MAAM,GAAG,IAAI,KAAK,QAAQ,EACpD,YAAY,IAAK,CAAE,OAAQ,MAAO,QAAS,CAAE,MAAO,IAAK,IAAI,KAAM,GAAI,IAAI,GAAI,GAAG,MAAO,CAAE,CAAC,EACtF,GACR,CACF,CAiBA,MAAa,kBAAoB,gBAE3B,mBAAqB,IAAI,IAG/B,SAAgB,mBAAsB,QAAqC,CACzE,mBAAmB,IAAI,QAAQ,IAAK,OAA4B,CAClE,CAEA,MAAM,cAAiB,GACrB,CAAC,CAAC,GAAK,OAAO,GAAM,UAAY,OAAO,eAAe,CAAC,IAAM,OAAO,UAStE,SAAgB,gBAAsB,KAAkB,CACtD,GAAI,CAAC,cAAc,IAAI,EAAG,OAAO,KAGjC,GAAM,EAAG,mBAAoB,WAAY,GAAG,MAAS,KAC/C,QAAmC,CAAC,EAC1C,IAAK,GAAM,CAAC,IAAK,WAAY,mBAAoB,CAC/C,IAAM,MAAQ,QAAQ,QAAQ,EAC1B,QAAU,IAAA,KAAW,QAAQ,KAAO,MAC1C,CAEA,OADgB,OAAO,KAAK,OAAO,CAAC,CAAC,OAAS,EAAI,CAAE,GAAG,MAAO,mBAAoB,OAAQ,EAAI,IAEhG,CAGA,SAAS,eAAkB,IAAc,IAAuB,CAC9D,IAAM,KAAO,IAAI,KACjB,GAAI,CAAC,cAAc,IAAI,GAAK,EAAA,kBAAuB,MAAO,OAAO,IACjE,IAAM,QAAU,KAAK,mBAGrB,GAFA,OAAO,KAAK,mBAER,CAAC,cAAc,OAAO,EAAG,OAAO,IACpC,IAAI,QAAU,IACd,IAAK,GAAM,CAAC,IAAK,SAAU,OAAO,QAAQ,OAAO,EAAG,CAClD,IAAM,QAAU,mBAAmB,IAAI,GAAG,EAC1C,GAAI,CAAC,QAAS,SACd,IAAM,MAAQ,QACd,YAAgB,QAAQ,QAAQ,MAAO,KAAK,CAC9C,CACA,OAAO,OACT,CAgBA,MAAa,eAAiB,YAA2B,sBAAsB"}
1
+ {"version":3,"file":"jobs-dx-MTUUb.mjs","names":[],"sources":["../src/core/jobs.ts"],"sourcesContent":["/**\n * Background jobs, with whatever runs them.\n *\n * `@Job(queue)` / `@Process(name)` only record which method handles which\n * job — the same way `@Cron` only records a schedule. Any job tool turns that\n * into running code in a few lines: subscribe to each queue from\n * {@link listJobQueues}, and hand every job it receives to {@link runJob}.\n *\n * @Job('email')\n * export class EmailJobs {\n * @Process('welcome')\n * async welcome(job: JobLike<{ to: string }>) { await sendWelcome(job.data.to) }\n * }\n *\n * Enqueueing goes through {@link JOB_DISPATCHER}, which the active adapter\n * provides — code that dispatches never names the tool.\n *\n * `@forinda/kickjs-queue` ships a BullMQ adapter (plus RabbitMQ / Kafka /\n * Redis pub-sub providers); the web entry's `queue()` runs Cloudflare Queues.\n */\nimport { Service } from './decorators'\nimport { getClassMeta, getClassMetaOrUndefined, pushClassMeta, setClassMeta } from './metadata'\nimport { reportError } from './observers'\nimport { createLogger } from './logger'\nimport { createToken } from './token'\n\nconst log = createLogger('KickJobs')\n\n/** Metadata keys — the same ones `@forinda/kickjs-queue` used, so existing readers keep working. */\nexport const JOB_META = {\n JOB: 'kick/queue/job',\n PROCESS: 'kick/queue/process',\n} as const\n\n/** What a `@Process` method records. */\nexport interface ProcessDefinition {\n /** Method name on the class. */\n handlerName: string\n /** Job name it handles; `undefined` handles every job in the queue. */\n jobName?: string\n}\n\n/**\n * The least a job tool hands over. Runners pass their own job object through\n * unchanged — BullMQ's `Job`, a Cloudflare message — so a handler can still\n * reach tool-specific fields (`job.attemptsMade`, `job.updateProgress()`).\n */\nexport interface JobLike<Data = unknown> {\n name: string\n data: Data\n id?: string\n}\n\n/**\n * Every `@Job` class, keyed by class name like the DI registry: an HMR\n * re-evaluation replaces the old class instead of leaving both subscribed.\n */\nconst jobClasses = new Map<string, Function>()\n\n/** Mark a class as handling jobs on `queue`. The class is a DI singleton. */\nexport function Job(queue: string): ClassDecorator {\n return (target) => {\n Service()(target)\n setClassMeta(JOB_META.JOB, queue, target)\n jobClasses.set(target.name, target)\n }\n}\n\n/** Mark a method as handling `jobName` — or, without a name, every job its queue gets. */\nexport function Process(jobName?: string): MethodDecorator {\n return (target, propertyKey) => {\n pushClassMeta<ProcessDefinition>(JOB_META.PROCESS, target.constructor, {\n handlerName: propertyKey as string,\n jobName,\n })\n }\n}\n\n/** One handler: its queue, job name (absent for a catch-all), class and method. */\nexport interface JobHandler extends ProcessDefinition {\n queue: string\n target: Function\n}\n\n/**\n * Every `@Process` method of a `@Job` class the container can resolve.\n * Classes it doesn't know (not in a module, or from before an HMR reload)\n * are skipped.\n */\nexport function listJobHandlers(container: { has(token: unknown): boolean }): JobHandler[] {\n const handlers: JobHandler[] = []\n for (const target of jobClasses.values()) {\n if (!container.has(target)) continue\n const queue = getClassMetaOrUndefined<string>(JOB_META.JOB, target)\n if (queue === undefined) continue\n const processes = getClassMeta<ProcessDefinition[]>(JOB_META.PROCESS, target, [])\n if (processes.length === 0) {\n log.warn(`@Job('${queue}') class ${target.name} has no @Process methods`)\n }\n for (const process of processes) handlers.push({ ...process, queue, target })\n }\n return handlers\n}\n\n/** The queues something handles — what a runner subscribes to. */\nexport function listJobQueues(container: { has(token: unknown): boolean }): string[] {\n return [...new Set(listJobHandlers(container).map((h) => h.queue))]\n}\n\n/** Thrown when a queue receives a job no `@Process` method handles. */\nexport class NoJobHandlerError extends Error {\n constructor(\n readonly queue: string,\n readonly jobName: string,\n ) {\n super(`No @Process handler for job \"${jobName}\" on queue \"${queue}\"`)\n this.name = 'NoJobHandlerError'\n }\n}\n\n/**\n * Run one job: pick the `@Process` method for `job.name` (or the queue's\n * catch-all), resolve its class from the container and call it with `job`\n * as given. A failure is reported to the error observers (`source: 'job'`)\n * and rethrown, so the tool's own retry and dead-letter handling still\n * applies. A job nothing handles throws {@link NoJobHandlerError} rather\n * than being acknowledged and lost.\n */\nexport async function runJob(\n container: { has(token: unknown): boolean; resolve(token: unknown): unknown },\n queue: string,\n job: JobLike,\n /** Extra fields for the error report — e.g. the tool's attempt count. */\n report: Record<string, unknown> = {},\n): Promise<unknown> {\n const handlers = listJobHandlers(container).filter((h) => h.queue === queue)\n const handler =\n handlers.find((h) => h.jobName === job.name) ?? handlers.find((h) => h.jobName === undefined)\n try {\n if (!handler) throw new NoJobHandlerError(queue, job.name)\n const instance = container.resolve(handler.target) as Record<string, (j: JobLike) => unknown>\n return await withJobContext(job, () => instance[handler.handlerName]!(job))()\n } catch (err) {\n log.error({ err }, `Job ${queue}/${job.name} failed`)\n reportError(err, { source: 'job', context: { queue, job: job.name, id: job.id, ...report } })\n throw err\n }\n}\n\n/**\n * Something about where a job was dispatched from that its handler should\n * run with — the tenant, a trace id, the acting user. Captured when the job\n * is dispatched, carried in its data, and restored around the handler.\n */\nexport interface JobContextCarrier<T = unknown> {\n /** Unique: the field it travels under. */\n key: string\n /** The value to carry, or `undefined` for nothing. */\n capture(): T | undefined\n /** Run the handler with the value back in place. */\n restore<R>(value: T, run: () => R): R\n}\n\n/** The field a job's data carries its context in. Removed before the handler sees the data. */\nexport const JOB_CONTEXT_FIELD = '__kickContext'\n\nconst jobContextCarriers = new Map<string, JobContextCarrier>()\n\n/** Carry a value from dispatch to handler for every job. Registering a key again replaces it. */\nexport function registerJobContext<T>(carrier: JobContextCarrier<T>): void {\n jobContextCarriers.set(carrier.key, carrier as JobContextCarrier)\n}\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n !!v && typeof v === 'object' && Object.getPrototypeOf(v) === Object.prototype\n\n/**\n * `data` with the current job context added — for a {@link JobDispatcher}\n * implementation to call before enqueueing. Any `__kickContext` already in\n * `data` is removed first: only this call may set it, so a dispatcher that\n * enqueues caller-supplied data without it lets that data choose the context. Only plain-object data can carry\n * it; anything else, or nothing to carry, is returned as is.\n */\nexport function stampJobContext<Data>(data: Data): Data {\n if (!isPlainObject(data)) return data\n // Only the dispatcher's own context travels. A caller's data (a request\n // body, say) carrying the field would otherwise pick the job's tenant.\n const { [JOB_CONTEXT_FIELD]: _untrusted, ...rest } = data\n const context: Record<string, unknown> = {}\n for (const [key, carrier] of jobContextCarriers) {\n const value = carrier.capture()\n if (value !== undefined) context[key] = value\n }\n const stamped = Object.keys(context).length > 0 ? { ...rest, [JOB_CONTEXT_FIELD]: context } : rest\n return stamped as Data\n}\n\n/** Take the carried context off the job's data, and wrap `run` in every restore. */\nfunction withJobContext<R>(job: JobLike, run: () => R): () => R {\n const data = job.data\n if (!isPlainObject(data) || !(JOB_CONTEXT_FIELD in data)) return run\n const context = data[JOB_CONTEXT_FIELD]\n delete data[JOB_CONTEXT_FIELD]\n // Only an object of carrier keys is context; anything else is dropped.\n if (!isPlainObject(context)) return run\n let wrapped = run\n for (const [key, value] of Object.entries(context)) {\n const carrier = jobContextCarriers.get(key)\n if (!carrier) continue\n const inner = wrapped\n wrapped = () => carrier.restore(value, inner)\n }\n return wrapped\n}\n\n/** Enqueue a job — implemented by whichever adapter runs the jobs. */\nexport interface JobDispatcher {\n dispatch<Data = unknown>(\n queue: string,\n name: string,\n data: Data,\n options?: Record<string, unknown>,\n ): Promise<unknown>\n}\n\n/**\n * The active job dispatcher. Inject it to enqueue without naming the tool:\n * `@Inject(JOB_DISPATCHER) private jobs!: JobDispatcher`.\n */\nexport const JOB_DISPATCHER = createToken<JobDispatcher>('kick/jobs/Dispatcher')\n"],"mappings":";;;;;;;;;;8TA0BA,MAAM,IAAM,aAAa,UAAU,EAGtB,SAAW,CACtB,IAAK,iBACL,QAAS,oBACX,EAyBM,WAAa,IAAI,IAGvB,SAAgB,IAAI,MAA+B,CACjD,MAAQ,SAAW,CACjB,QAAQ,CAAC,CAAC,MAAM,EAChB,aAAa,SAAS,IAAK,MAAO,MAAM,EACxC,WAAW,IAAI,OAAO,KAAM,MAAM,CACpC,CACF,CAGA,SAAgB,QAAQ,QAAmC,CACzD,OAAQ,OAAQ,cAAgB,CAC9B,cAAiC,SAAS,QAAS,OAAO,YAAa,CACrE,YAAa,YACb,OACF,CAAC,CACH,CACF,CAaA,SAAgB,gBAAgB,UAA2D,CACzF,IAAM,SAAyB,CAAC,EAChC,IAAK,IAAM,UAAU,WAAW,OAAO,EAAG,CACxC,GAAI,CAAC,UAAU,IAAI,MAAM,EAAG,SAC5B,IAAM,MAAQ,wBAAgC,SAAS,IAAK,MAAM,EAClE,GAAI,QAAU,IAAA,GAAW,SACzB,IAAM,UAAY,aAAkC,SAAS,QAAS,OAAQ,CAAC,CAAC,EAC5E,UAAU,SAAW,GACvB,IAAI,KAAK,SAAS,MAAM,WAAW,OAAO,KAAK,yBAAyB,EAE1E,IAAK,IAAM,WAAW,UAAW,SAAS,KAAK,CAAE,GAAG,QAAS,MAAO,MAAO,CAAC,CAC9E,CACA,OAAO,QACT,CAGA,SAAgB,cAAc,UAAuD,CACnF,MAAO,CAAC,GAAG,IAAI,IAAI,gBAAgB,SAAS,CAAC,CAAC,IAAK,GAAM,EAAE,KAAK,CAAC,CAAC,CACpE,CAGA,IAAa,kBAAb,cAAuC,KAAM,CAEhC,MACA,QAFX,YACE,MACA,QACA,CACA,MAAM,gCAAgC,QAAQ,cAAc,MAAM,EAAE,EAH3D,KAAA,MAAA,MACA,KAAA,QAAA,QAGT,KAAK,KAAO,mBACd,CACF,EAUA,eAAsB,OACpB,UACA,MACA,IAEA,OAAkC,CAAC,EACjB,CAClB,IAAM,SAAW,gBAAgB,SAAS,CAAC,CAAC,OAAQ,GAAM,EAAE,QAAU,KAAK,EACrE,QACJ,SAAS,KAAM,GAAM,EAAE,UAAY,IAAI,IAAI,GAAK,SAAS,KAAM,GAAM,EAAE,UAAY,IAAA,EAAS,EAC9F,GAAI,CACF,GAAI,CAAC,QAAS,MAAM,IAAI,kBAAkB,MAAO,IAAI,IAAI,EACzD,IAAM,SAAW,UAAU,QAAQ,QAAQ,MAAM,EACjD,OAAO,MAAM,eAAe,QAAW,SAAS,QAAQ,YAAY,CAAE,GAAG,CAAC,CAAC,CAAC,CAC9E,OAAS,IAAK,CAGZ,MAFA,IAAI,MAAM,CAAE,GAAI,EAAG,OAAO,MAAM,GAAG,IAAI,KAAK,QAAQ,EACpD,YAAY,IAAK,CAAE,OAAQ,MAAO,QAAS,CAAE,MAAO,IAAK,IAAI,KAAM,GAAI,IAAI,GAAI,GAAG,MAAO,CAAE,CAAC,EACtF,GACR,CACF,CAiBA,MAAa,kBAAoB,gBAE3B,mBAAqB,IAAI,IAG/B,SAAgB,mBAAsB,QAAqC,CACzE,mBAAmB,IAAI,QAAQ,IAAK,OAA4B,CAClE,CAEA,MAAM,cAAiB,GACrB,CAAC,CAAC,GAAK,OAAO,GAAM,UAAY,OAAO,eAAe,CAAC,IAAM,OAAO,UAStE,SAAgB,gBAAsB,KAAkB,CACtD,GAAI,CAAC,cAAc,IAAI,EAAG,OAAO,KAGjC,GAAM,EAAG,mBAAoB,WAAY,GAAG,MAAS,KAC/C,QAAmC,CAAC,EAC1C,IAAK,GAAM,CAAC,IAAK,WAAY,mBAAoB,CAC/C,IAAM,MAAQ,QAAQ,QAAQ,EAC1B,QAAU,IAAA,KAAW,QAAQ,KAAO,MAC1C,CAEA,OADgB,OAAO,KAAK,OAAO,CAAC,CAAC,OAAS,EAAI,CAAE,GAAG,MAAO,mBAAoB,OAAQ,EAAI,IAEhG,CAGA,SAAS,eAAkB,IAAc,IAAuB,CAC9D,IAAM,KAAO,IAAI,KACjB,GAAI,CAAC,cAAc,IAAI,GAAK,EAAA,kBAAuB,MAAO,OAAO,IACjE,IAAM,QAAU,KAAK,mBAGrB,GAFA,OAAO,KAAK,mBAER,CAAC,cAAc,OAAO,EAAG,OAAO,IACpC,IAAI,QAAU,IACd,IAAK,GAAM,CAAC,IAAK,SAAU,OAAO,QAAQ,OAAO,EAAG,CAClD,IAAM,QAAU,mBAAmB,IAAI,GAAG,EAC1C,GAAI,CAAC,QAAS,SACd,IAAM,MAAQ,QACd,YAAgB,QAAQ,QAAQ,MAAO,KAAK,CAC9C,CACA,OAAO,OACT,CAgBA,MAAa,eAAiB,YAA2B,sBAAsB"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs v9.0.2
2
+ * @forinda/kickjs v9.1.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{n as assertFlagTest,s as matchesFlagTest}from"./route-flag-DEUYr5Br.mjs";var LazyMemoryStore=class{windowMs;hits=new Map;constructor(windowMs){this.windowMs=windowMs}async increment(key){let now=Date.now(),entry=this.hits.get(key);if(entry&&entry.reset>now)return entry.hits++,{totalHits:entry.hits,resetTime:new Date(entry.reset)};if(this.hits.size>1e4)for(let[k,e]of this.hits)e.reset<=now&&this.hits.delete(k);let fresh={hits:1,reset:now+this.windowMs};return this.hits.set(key,fresh),{totalHits:1,resetTime:new Date(fresh.reset)}}async decrement(key){let entry=this.hits.get(key);entry&&entry.hits>0&&entry.hits--}async reset(key){this.hits.delete(key)}};function defaultKey(ctx){return ctx.ip??`global`}function rateLimitGuard(options={}){let max=options.max??100,windowMs=options.windowMs??6e4,message=options.message??`Too Many Requests`,statusCode=options.statusCode??429,keyGenerator=options.keyGenerator??defaultKey,sendHeaders=options.headers??!0,store=options.store??new LazyMemoryStore(windowMs),exemptWhen=options.exemptWhen;return exemptWhen!==void 0&&assertFlagTest(exemptWhen,`rateLimitGuard({ exemptWhen })`),async(ctx,next)=>{if(options.skip?.(ctx)||exemptWhen!==void 0&&matchesFlagTest(exemptWhen,ctx.route?.flags,ctx.route))return next();let{totalHits,resetTime}=await store.increment(keyGenerator(ctx)),remaining=Math.max(0,max-totalHits);if(sendHeaders&&(ctx.setHeader(`X-RateLimit-Limit`,String(max)),ctx.setHeader(`X-RateLimit-Remaining`,String(remaining)),ctx.setHeader(`X-RateLimit-Reset`,String(Math.ceil(resetTime.getTime()/1e3)))),totalHits>max){let retryAfter=Math.max(1,Math.ceil((resetTime.getTime()-Date.now())/1e3));sendHeaders&&ctx.setHeader(`Retry-After`,String(retryAfter)),ctx.json({message},statusCode);return}next()}}function kvTtlSeconds(ms){return Math.max(60,Math.ceil(ms/1e3))}var KvRateLimitStore=class{kv;prefix;windowMs;constructor(kv,options){this.kv=kv,this.windowMs=options.windowMs,this.prefix=options.prefix??`rl:`}async increment(key){let now=Date.now(),entry=await this.read(key);if(entry&&entry.reset>now)return entry.hits++,await this.write(key,entry),{totalHits:entry.hits,resetTime:new Date(entry.reset)};let fresh={hits:1,reset:now+this.windowMs};return await this.write(key,fresh),{totalHits:1,resetTime:new Date(fresh.reset)}}async decrement(key){let entry=await this.read(key);entry&&entry.hits>0&&(entry.hits--,await this.write(key,entry))}async reset(key){await this.kv.delete(this.prefix+key)}async read(key){let raw=await this.kv.get(this.prefix+key);if(raw===null)return null;try{return JSON.parse(raw)}catch{return null}}async write(key,entry){await this.kv.put(this.prefix+key,JSON.stringify(entry),{expirationTtl:kvTtlSeconds(Math.max(entry.reset-Date.now(),1e3))})}},KvSessionStore=class{kv;prefix;constructor(kv,options={}){this.kv=kv,this.prefix=options.prefix??`sess:`}async get(sid){let raw=await this.kv.get(this.prefix+sid);if(raw===null)return null;try{return JSON.parse(raw)}catch{return null}}async set(sid,data,maxAge){await this.kv.put(this.prefix+sid,JSON.stringify(data),{expirationTtl:kvTtlSeconds(maxAge)})}async destroy(sid){await this.kv.delete(this.prefix+sid)}async touch(sid,maxAge){let data=await this.get(sid);data!==null&&await this.set(sid,data,maxAge)}};export{KvSessionStore as n,rateLimitGuard as r,KvRateLimitStore as t};
12
- //# sourceMappingURL=kv-stores-D4dmpn6D.mjs.map
11
+ import{n as assertFlagTest,s as matchesFlagTest}from"./route-flag-sIYXay3q.mjs";var LazyMemoryStore=class{windowMs;hits=new Map;constructor(windowMs){this.windowMs=windowMs}async increment(key){let now=Date.now(),entry=this.hits.get(key);if(entry&&entry.reset>now)return entry.hits++,{totalHits:entry.hits,resetTime:new Date(entry.reset)};if(this.hits.size>1e4)for(let[k,e]of this.hits)e.reset<=now&&this.hits.delete(k);let fresh={hits:1,reset:now+this.windowMs};return this.hits.set(key,fresh),{totalHits:1,resetTime:new Date(fresh.reset)}}async decrement(key){let entry=this.hits.get(key);entry&&entry.hits>0&&entry.hits--}async reset(key){this.hits.delete(key)}};function defaultKey(ctx){return ctx.ip??`global`}function rateLimitGuard(options={}){let max=options.max??100,windowMs=options.windowMs??6e4,message=options.message??`Too Many Requests`,statusCode=options.statusCode??429,keyGenerator=options.keyGenerator??defaultKey,sendHeaders=options.headers??!0,store=options.store??new LazyMemoryStore(windowMs),exemptWhen=options.exemptWhen;return exemptWhen!==void 0&&assertFlagTest(exemptWhen,`rateLimitGuard({ exemptWhen })`),async(ctx,next)=>{if(options.skip?.(ctx)||exemptWhen!==void 0&&matchesFlagTest(exemptWhen,ctx.route?.flags,ctx.route))return next();let{totalHits,resetTime}=await store.increment(keyGenerator(ctx)),remaining=Math.max(0,max-totalHits);if(sendHeaders&&(ctx.setHeader(`X-RateLimit-Limit`,String(max)),ctx.setHeader(`X-RateLimit-Remaining`,String(remaining)),ctx.setHeader(`X-RateLimit-Reset`,String(Math.ceil(resetTime.getTime()/1e3)))),totalHits>max){let retryAfter=Math.max(1,Math.ceil((resetTime.getTime()-Date.now())/1e3));sendHeaders&&ctx.setHeader(`Retry-After`,String(retryAfter)),ctx.json({message},statusCode);return}next()}}function kvTtlSeconds(ms){return Math.max(60,Math.ceil(ms/1e3))}var KvRateLimitStore=class{kv;prefix;windowMs;constructor(kv,options){this.kv=kv,this.windowMs=options.windowMs,this.prefix=options.prefix??`rl:`}async increment(key){let now=Date.now(),entry=await this.read(key);if(entry&&entry.reset>now)return entry.hits++,await this.write(key,entry),{totalHits:entry.hits,resetTime:new Date(entry.reset)};let fresh={hits:1,reset:now+this.windowMs};return await this.write(key,fresh),{totalHits:1,resetTime:new Date(fresh.reset)}}async decrement(key){let entry=await this.read(key);entry&&entry.hits>0&&(entry.hits--,await this.write(key,entry))}async reset(key){await this.kv.delete(this.prefix+key)}async read(key){let raw=await this.kv.get(this.prefix+key);if(raw===null)return null;try{return JSON.parse(raw)}catch{return null}}async write(key,entry){await this.kv.put(this.prefix+key,JSON.stringify(entry),{expirationTtl:kvTtlSeconds(Math.max(entry.reset-Date.now(),1e3))})}},KvSessionStore=class{kv;prefix;constructor(kv,options={}){this.kv=kv,this.prefix=options.prefix??`sess:`}async get(sid){let raw=await this.kv.get(this.prefix+sid);if(raw===null)return null;try{return JSON.parse(raw)}catch{return null}}async set(sid,data,maxAge){await this.kv.put(this.prefix+sid,JSON.stringify(data),{expirationTtl:kvTtlSeconds(maxAge)})}async destroy(sid){await this.kv.delete(this.prefix+sid)}async touch(sid,maxAge){let data=await this.get(sid);data!==null&&await this.set(sid,data,maxAge)}};export{KvSessionStore as n,rateLimitGuard as r,KvRateLimitStore as t};
12
+ //# sourceMappingURL=kv-stores-Ba5_rcz-.mjs.map