@forgedevstack/harbor 1.0.0 → 1.5.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 (123) hide show
  1. package/CHANGELOG.md +82 -101
  2. package/README.md +210 -794
  3. package/dist/auth/apiKey.d.ts +6 -0
  4. package/dist/auth/apiKey.d.ts.map +1 -0
  5. package/dist/auth/index.d.ts +7 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/index.js +2 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/auth/jwt.d.ts +21 -0
  10. package/dist/auth/jwt.d.ts.map +1 -0
  11. package/dist/auth/password.d.ts +6 -0
  12. package/dist/auth/password.d.ts.map +1 -0
  13. package/dist/auth/rbac.d.ts +6 -0
  14. package/dist/auth/rbac.d.ts.map +1 -0
  15. package/dist/auth/signing.d.ts +5 -0
  16. package/dist/auth/signing.d.ts.map +1 -0
  17. package/dist/auth/types/apiKey.types.d.ts +9 -0
  18. package/dist/auth/types/apiKey.types.d.ts.map +1 -0
  19. package/dist/auth/types/index.d.ts +5 -0
  20. package/dist/auth/types/index.d.ts.map +1 -0
  21. package/dist/auth/types/jwt.types.d.ts +17 -0
  22. package/dist/auth/types/jwt.types.d.ts.map +1 -0
  23. package/dist/auth/types/rbac.types.d.ts +8 -0
  24. package/dist/auth/types/rbac.types.d.ts.map +1 -0
  25. package/dist/auth/types/signing.types.d.ts +8 -0
  26. package/dist/auth/types/signing.types.d.ts.map +1 -0
  27. package/dist/cache/index.d.ts +4 -0
  28. package/dist/cache/index.d.ts.map +1 -0
  29. package/dist/cache/index.js +2 -0
  30. package/dist/cache/index.js.map +1 -0
  31. package/dist/cache/manager.d.ts +24 -0
  32. package/dist/cache/manager.d.ts.map +1 -0
  33. package/dist/cache/stores.d.ts +28 -0
  34. package/dist/cache/stores.d.ts.map +1 -0
  35. package/dist/cache/types.d.ts +23 -0
  36. package/dist/cache/types.d.ts.map +1 -0
  37. package/dist/cli/index.js +21 -22
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/core/config.d.ts.map +1 -1
  40. package/dist/core/router.d.ts +40 -2
  41. package/dist/core/router.d.ts.map +1 -1
  42. package/dist/core/server.d.ts.map +1 -1
  43. package/dist/database/connection.d.ts +1 -2
  44. package/dist/database/connection.d.ts.map +1 -1
  45. package/dist/database/index.js +2 -0
  46. package/dist/database/index.js.map +1 -0
  47. package/dist/database/model.d.ts +1 -4
  48. package/dist/database/model.d.ts.map +1 -1
  49. package/dist/docker/index.js +1 -1
  50. package/dist/http.const-BKHG1Lsj.mjs +62 -0
  51. package/dist/http.const-BKHG1Lsj.mjs.map +1 -0
  52. package/dist/http.const-Ckcy7OFp.js +2 -0
  53. package/dist/http.const-Ckcy7OFp.js.map +1 -0
  54. package/dist/index-Ca4WpLvw.js +2 -0
  55. package/dist/index-Ca4WpLvw.js.map +1 -0
  56. package/dist/index-DIVHd6rO.mjs +1054 -0
  57. package/dist/index-DIVHd6rO.mjs.map +1 -0
  58. package/dist/index.cjs.js +16 -16
  59. package/dist/index.cjs.js.map +1 -1
  60. package/dist/index.d.ts +11 -2
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.es.js +676 -1691
  63. package/dist/index.es.js.map +1 -1
  64. package/dist/logger-CZn7QxCl.mjs +102 -0
  65. package/dist/{logger-D7aJSi62.mjs.map → logger-CZn7QxCl.mjs.map} +1 -1
  66. package/dist/logger-D-lfaRWQ.js +3 -0
  67. package/dist/{logger-DEnWXtpk.js.map → logger-D-lfaRWQ.js.map} +1 -1
  68. package/dist/manager-CjcKb4P9.mjs +149 -0
  69. package/dist/{manager-B6vqJgEn.mjs.map → manager-CjcKb4P9.mjs.map} +1 -1
  70. package/dist/manager-DrF1vbJg.js +4 -0
  71. package/dist/{manager-B1UKMjXW.js.map → manager-DrF1vbJg.js.map} +1 -1
  72. package/dist/middleware/health.d.ts +65 -0
  73. package/dist/middleware/health.d.ts.map +1 -0
  74. package/dist/middleware/index.d.ts +5 -0
  75. package/dist/middleware/index.d.ts.map +1 -0
  76. package/dist/middleware/index.js +2 -0
  77. package/dist/middleware/index.js.map +1 -0
  78. package/dist/middleware/metrics.d.ts +68 -0
  79. package/dist/middleware/metrics.d.ts.map +1 -0
  80. package/dist/middleware/rateLimit.d.ts +52 -0
  81. package/dist/middleware/rateLimit.d.ts.map +1 -0
  82. package/dist/middleware/upload.d.ts +59 -0
  83. package/dist/middleware/upload.d.ts.map +1 -0
  84. package/dist/password-BXBkKbv3.js +2 -0
  85. package/dist/password-BXBkKbv3.js.map +1 -0
  86. package/dist/password-y4m307oa.mjs +223 -0
  87. package/dist/password-y4m307oa.mjs.map +1 -0
  88. package/dist/scheduler/index.d.ts +3 -0
  89. package/dist/scheduler/index.d.ts.map +1 -0
  90. package/dist/scheduler/index.js +2 -0
  91. package/dist/scheduler/index.js.map +1 -0
  92. package/dist/scheduler/scheduler.d.ts +30 -0
  93. package/dist/scheduler/scheduler.d.ts.map +1 -0
  94. package/dist/scheduler/types.d.ts +25 -0
  95. package/dist/scheduler/types.d.ts.map +1 -0
  96. package/dist/types/server.types.d.ts +7 -0
  97. package/dist/types/server.types.d.ts.map +1 -1
  98. package/dist/upload-9lCNnKK_.js +5 -0
  99. package/dist/upload-9lCNnKK_.js.map +1 -0
  100. package/dist/upload-DUjQiuq7.mjs +619 -0
  101. package/dist/upload-DUjQiuq7.mjs.map +1 -0
  102. package/dist/validation/index.js +1 -1
  103. package/dist/validation/index.js.map +1 -1
  104. package/dist/websocket/index.d.ts +3 -0
  105. package/dist/websocket/index.d.ts.map +1 -0
  106. package/dist/websocket/index.js +2 -0
  107. package/dist/websocket/index.js.map +1 -0
  108. package/dist/websocket/manager.d.ts +30 -0
  109. package/dist/websocket/manager.d.ts.map +1 -0
  110. package/dist/websocket/types.d.ts +27 -0
  111. package/dist/websocket/types.d.ts.map +1 -0
  112. package/package.json +58 -18
  113. package/templates/default/controllers/user.controller.ts +44 -64
  114. package/templates/default/package.json +9 -33
  115. package/templates/default/routes/index.ts +2 -12
  116. package/templates/default/routes/user.routes.ts +26 -19
  117. package/templates/default/server.ts +16 -35
  118. package/dist/logger-D7aJSi62.mjs +0 -102
  119. package/dist/logger-DEnWXtpk.js +0 -3
  120. package/dist/manager-B1UKMjXW.js +0 -4
  121. package/dist/manager-B6vqJgEn.mjs +0 -152
  122. package/dist/portal.d.ts +0 -13
  123. package/dist/portal.d.ts.map +0 -1
@@ -0,0 +1,25 @@
1
+ export interface Job {
2
+ id: string;
3
+ name: string;
4
+ schedule: string | number;
5
+ handler: () => void | Promise<void>;
6
+ enabled: boolean;
7
+ lastRun: Date | null;
8
+ nextRun: Date | null;
9
+ runCount: number;
10
+ errors: number;
11
+ }
12
+ export interface SchedulerOptions {
13
+ timezone?: string;
14
+ onJobStart?: (job: Job) => void;
15
+ onJobComplete?: (job: Job, duration: number) => void;
16
+ onJobError?: (job: Job, error: Error) => void;
17
+ }
18
+ export interface ParsedCron {
19
+ minute: number[];
20
+ hour: number[];
21
+ dayOfMonth: number[];
22
+ month: number[];
23
+ dayOfWeek: number[];
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scheduler/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/C;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB"}
@@ -14,6 +14,13 @@ export interface HarborServer {
14
14
  addRouteGroup: (group: RouteGroup) => void;
15
15
  addMiddleware: (middleware: RequestHandler) => void;
16
16
  getInfo: () => ServerInfo;
17
+ use: (...args: Parameters<Express['use']>) => void;
18
+ get: (path: string, ...handlers: RequestHandler[]) => void;
19
+ post: (path: string, ...handlers: RequestHandler[]) => void;
20
+ put: (path: string, ...handlers: RequestHandler[]) => void;
21
+ patch: (path: string, ...handlers: RequestHandler[]) => void;
22
+ delete: (path: string, ...handlers: RequestHandler[]) => void;
23
+ listen: (port?: number, callback?: () => void) => void;
17
24
  }
18
25
  export interface ServerInfo {
19
26
  port: number;
@@ -1 +1 @@
1
- {"version":3,"file":"server.types.d.ts","sourceRoot":"","sources":["../../src/types/server.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC3C,aAAa,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,OAAO,EAAE,MAAM,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAErF,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC"}
1
+ {"version":3,"file":"server.types.d.ts","sourceRoot":"","sources":["../../src/types/server.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ "use strict";const U=require("./logger-D-lfaRWQ.js"),R=require("./http.const-Ckcy7OFp.js"),L=require("fs"),_=require("path"),E=U.createLogger("rate-limit");class Y{hits=new Map;windowMs;constructor(e){this.windowMs=e,setInterval(()=>this.cleanup(),e)}async increment(e){const t=Date.now(),s=this.hits.get(e);if(s&&s.resetTime>t)return s.count++,s;const i={count:1,resetTime:t+this.windowMs};return this.hits.set(e,i),i}async decrement(e){const t=this.hits.get(e);t&&t.count>0&&t.count--}async resetKey(e){this.hits.delete(e)}async get(e){return this.hits.get(e)||null}cleanup(){const e=Date.now();for(const[t,s]of this.hits.entries())s.resetTime<=e&&this.hits.delete(t)}}class J{client;windowMs;prefix;constructor(e,t,s="rl:"){this.client=e,this.windowMs=t,this.prefix=s}async increment(e){const t=this.prefix+e,s=this.client.multi();s.incr(t),s.pttl(t);const i=await s.exec(),a=i[0][1];let r=i[1][1];return r===-1&&(await this.client.pexpire(t,this.windowMs),r=this.windowMs),{count:a,resetTime:Date.now()+r}}async decrement(e){await this.client.decr(this.prefix+e)}async resetKey(e){await this.client.del(this.prefix+e)}async get(e){const t=this.prefix+e,[s,i]=await Promise.all([this.client.get(t),this.client.pttl(t)]);return s===null?null:{count:parseInt(s,10),resetTime:Date.now()+Math.max(i,0)}}}function V(n={}){const{windowMs:e=15*60*1e3,max:t=100,message:s="Too many requests, please try again later.",statusCode:i=R.HTTP_STATUS.TOO_MANY_REQUESTS,keyGenerator:a=l=>l.ip||l.connection?.remoteAddress||"unknown",skip:r=()=>!1,onLimitReached:c,headers:u=!0,store:h=new Y(e)}=n;return async(l,f,m)=>{if(r(l))return m();const p=a(l);try{const o=await h.increment(p),g=Math.max(0,t-o.count);if(u&&(f.setHeader("X-RateLimit-Limit",t),f.setHeader("X-RateLimit-Remaining",g),f.setHeader("X-RateLimit-Reset",Math.ceil(o.resetTime/1e3))),o.count>t)return E.warn(`Rate limit exceeded for ${p}`),c?.(l,f),u&&f.setHeader("Retry-After",Math.ceil((o.resetTime-Date.now())/1e3)),f.status(i).json({success:!1,error:{message:s,retryAfter:Math.ceil((o.resetTime-Date.now())/1e3)}});m()}catch(o){const g=o;E.error(`Rate limit error: ${g.message}`),m(g)}}}function Z(n={}){const{windowMs:e=15*60*1e3,max:t=100,message:s="Too many requests, please try again later.",statusCode:i=R.HTTP_STATUS.TOO_MANY_REQUESTS,keyGenerator:a=h=>h.ip||"unknown",skip:r=()=>!1,headers:c=!0}=n,u=new Map;return(h,l,f)=>{if(r(h))return f();const m=a(h),p=Date.now(),o=p-e;let g=u.get(m)||[];g=g.filter(S=>S>o),g.push(p),u.set(m,g);const w=Math.max(0,t-g.length);if(c&&(l.setHeader("X-RateLimit-Limit",t),l.setHeader("X-RateLimit-Remaining",w),l.setHeader("X-RateLimit-Reset",Math.ceil((p+e)/1e3))),g.length>t)return E.warn(`Sliding window rate limit exceeded for ${m}`),l.status(i).json({success:!1,error:{message:s,retryAfter:Math.ceil(e/1e3)}});f()}}const ee=Date.now();function te(n={}){const{checks:e=[],timeout:t=5e3,onHealthCheck:s}=n;return async(i,a)=>{const r=[];let c="healthy";const u=e.map(async m=>{const p=Date.now();try{const o=await Promise.race([m.check(),new Promise((g,w)=>setTimeout(()=>w(new Error("Timeout")),m.timeout||t))]);return o.latency=Date.now()-p,o}catch(o){return{name:m.name,status:"unhealthy",latency:Date.now()-p,message:o instanceof Error?o.message:"Unknown error"}}}),h=await Promise.all(u);r.push(...h);for(const m of r)if(m.status==="unhealthy")if(e.find(o=>o.name===m.name)?.critical!==!1){c="unhealthy";break}else c="degraded";else m.status==="degraded"&&c==="healthy"&&(c="degraded");const l={status:c,timestamp:new Date().toISOString(),uptime:Math.floor((Date.now()-ee)/1e3),checks:r};s?.(r);const f=c==="healthy"||c==="degraded"?200:503;a.status(f).json(l)}}function se(n,e="mongodb"){return{name:e,critical:!0,check:async()=>{try{return n.readyState===1?(await n.db?.admin().ping(),{name:e,status:"healthy",message:"Connected"}):{name:e,status:"unhealthy",message:"Not connected"}}catch(t){return{name:e,status:"unhealthy",message:t instanceof Error?t.message:"Connection failed"}}}}}function ne(n,e="redis"){return{name:e,critical:!1,check:async()=>{try{return await n.ping()==="PONG"?{name:e,status:"healthy",message:"Connected"}:{name:e,status:"unhealthy",message:"Invalid response"}}catch(t){return{name:e,status:"unhealthy",message:t instanceof Error?t.message:"Connection failed"}}}}}function ie(n=512,e="memory"){return{name:e,critical:!1,check:async()=>{const t=process.memoryUsage(),s=Math.round(t.heapUsed/1024/1024),i=Math.round(t.heapTotal/1024/1024),a=Math.round(t.rss/1024/1024),r=s>n?"degraded":"healthy";return{name:e,status:r,message:`Heap: ${s}MB / ${i}MB`,details:{heapUsed:s,heapTotal:i,rss:a,external:Math.round(t.external/1024/1024)}}}}}function re(n="/",e=1,t="disk"){return{name:t,critical:!1,check:async()=>({name:t,status:"healthy",message:"Disk check requires check-disk-space package"})}}function ae(n,e,t=!1){return{name:n,critical:t,check:async()=>{try{const s=await e();return typeof s=="boolean"?{name:n,status:s?"healthy":"unhealthy"}:{name:n,status:s.healthy?"healthy":"unhealthy",message:s.message}}catch(s){return{name:n,status:"unhealthy",message:s instanceof Error?s.message:"Check failed"}}}}}class A{metrics=new Map;prefix;defaultLabels;constructor(e="harbor_",t={}){this.prefix=e,this.defaultLabels=t}counter(e,t){const s=this.prefix+e;return this.metrics.has(s)||this.metrics.set(s,{name:s,help:t,type:"counter",values:new Map}),new F(this.metrics.get(s),this.defaultLabels)}gauge(e,t){const s=this.prefix+e;return this.metrics.has(s)||this.metrics.set(s,{name:s,help:t,type:"gauge",values:new Map}),new O(this.metrics.get(s),this.defaultLabels)}histogram(e,t,s=[.005,.01,.025,.05,.1,.25,.5,1,2.5,5,10]){const i=this.prefix+e;return this.metrics.has(i)||this.metrics.set(i,{name:i,help:t,type:"histogram",values:new Map,buckets:s}),new I(this.metrics.get(i),this.defaultLabels)}getMetrics(){const e=[];for(const t of this.metrics.values())if(e.push(`# HELP ${t.name} ${t.help}`),e.push(`# TYPE ${t.name} ${t.type}`),t.type==="histogram"){const s=new Map;for(const[i,a]of t.values.entries()){const[r,c]=i.split("|");s.has(r)||s.set(r,{sum:0,count:0,buckets:new Map});const u=s.get(r);c==="sum"?u.sum=a:c==="count"?u.count=a:u.buckets.set(parseFloat(c),a)}for(const[i,a]of s.entries()){const r=i?`{${i}}`:"";let c=0;for(const h of t.buckets||[]){c+=a.buckets.get(h)||0;const l=i?`{${i},le="${h}"}`:`{le="${h}"}`;e.push(`${t.name}_bucket${l} ${c}`)}const u=i?`{${i},le="+Inf"}`:'{le="+Inf"}';e.push(`${t.name}_bucket${u} ${a.count}`),e.push(`${t.name}_sum${r} ${a.sum}`),e.push(`${t.name}_count${r} ${a.count}`)}}else for(const[s,i]of t.values.entries()){const a=s?`{${s}}`:"";e.push(`${t.name}${a} ${i}`)}return e.join(`
2
+ `)}reset(){for(const e of this.metrics.values())e.values.clear()}}class F{metric;defaultLabels;constructor(e,t){this.metric=e,this.defaultLabels=t}inc(e={},t=1){const s=this.labelsToString({...this.defaultLabels,...e}),i=this.metric.values.get(s)||0;this.metric.values.set(s,i+t)}labelsToString(e){return Object.entries(e).map(([t,s])=>`${t}="${s}"`).join(",")}}class O{metric;defaultLabels;constructor(e,t){this.metric=e,this.defaultLabels=t}set(e,t={}){const s=this.labelsToString({...this.defaultLabels,...t});this.metric.values.set(s,e)}inc(e={},t=1){const s=this.labelsToString({...this.defaultLabels,...e}),i=this.metric.values.get(s)||0;this.metric.values.set(s,i+t)}dec(e={},t=1){const s=this.labelsToString({...this.defaultLabels,...e}),i=this.metric.values.get(s)||0;this.metric.values.set(s,i-t)}labelsToString(e){return Object.entries(e).map(([t,s])=>`${t}="${s}"`).join(",")}}class I{metric;defaultLabels;constructor(e,t){this.metric=e,this.defaultLabels=t}observe(e,t={}){const s=this.labelsToString({...this.defaultLabels,...t}),i=`${s}|sum`,a=this.metric.values.get(i)||0;this.metric.values.set(i,a+e);const r=`${s}|count`,c=this.metric.values.get(r)||0;this.metric.values.set(r,c+1);for(const u of this.metric.buckets||[])if(e<=u){const h=`${s}|${u}`,l=this.metric.values.get(h)||0;this.metric.values.set(h,l+1)}}startTimer(e={}){const t=process.hrtime.bigint();return()=>{const s=process.hrtime.bigint(),i=Number(s-t)/1e9;this.observe(i,e)}}labelsToString(e){return Object.entries(e).map(([t,s])=>`${t}="${s}"`).join(",")}}const b=new A,G=b.counter("http_requests_total","Total number of HTTP requests"),K=b.histogram("http_request_duration_seconds","HTTP request duration in seconds"),X=b.histogram("http_request_size_bytes","HTTP request size in bytes",[100,1e3,1e4,1e5,1e6]),q=b.histogram("http_response_size_bytes","HTTP response size in bytes",[100,1e3,1e4,1e5,1e6]);function oe(){return(n,e,t)=>{const s=K.startTimer({method:n.method,path:n.route?.path||n.path}),i=parseInt(n.get("content-length")||"0",10);i>0&&X.observe(i,{method:n.method}),e.on("finish",()=>{s(),G.inc({method:n.method,path:n.route?.path||n.path,status:e.statusCode.toString()});const a=parseInt(e.get("content-length")||"0",10);a>0&&q.observe(a,{method:n.method,status:e.statusCode.toString()})}),t()}}function ce(n=b){return(e,t)=>{t.set("Content-Type","text/plain; version=0.0.4; charset=utf-8"),t.send(n.getMetrics())}}const C=U.createLogger("upload");function le(n){const e=n.match(/boundary=(?:"([^"]+)"|([^;]+))/i);return e?e[1]||e[2]:null}function ue(n,e){const t=[],s=Buffer.from(`--${e}`),i=Buffer.from(`--${e}--`);let a=n.indexOf(s)+s.length+2;for(;a<n.length;){const r=n.indexOf(s,a);if(r===-1)break;const c=n.slice(a,r-2),u=c.indexOf(`\r
3
+ \r
4
+ `);if(u!==-1){const h=c.slice(0,u).toString(),l=c.slice(u+4),f=h.match(/Content-Disposition:\s*form-data;\s*name="([^"]+)"(?:;\s*filename="([^"]+)")?/i),m=h.match(/Content-Type:\s*([^\r\n]+)/i),p=h.match(/Content-Transfer-Encoding:\s*([^\r\n]+)/i);f&&t.push({fieldName:f[1],filename:f[2],mimeType:m?m[1]:"application/octet-stream",encoding:p?p[1]:"7bit",data:[l]})}if(a=r+s.length+2,n.slice(r,r+i.length).equals(i))break}return t}function he(n){const e=_.extname(n),t=Date.now(),s=Math.random().toString(36).substring(2,8);return`${t}-${s}${e}`}function me(n={}){const{dest:e="./uploads",limits:t={},allowedMimeTypes:s,allowedExtensions:i,filename:a=he,storage:r="disk",onFileBegin:c,onFileEnd:u,onError:h}=n,{fileSize:l=10*1024*1024,files:f=10,fields:m=100,fieldSize:p=1024*1024}=t;return r==="disk"&&!L.existsSync(e)&&L.mkdirSync(e,{recursive:!0}),async(o,g,w)=>{const S=o.get("content-type")||"";if(!S.includes("multipart/form-data"))return w();const H=le(S);if(!H)return g.status(R.HTTP_STATUS.BAD_REQUEST).json({success:!1,error:{message:"Missing boundary in content-type"}});const D=[];let B=0;o.on("data",y=>{if(B+=y.length,B>l*f){o.destroy();return}D.push(y)}),o.on("end",async()=>{try{const y=Buffer.concat(D),k=ue(y,H),M=[],P={};let j=0,z=0;for(const d of k)if(d.filename){if(j>=f)throw new Error(`Too many files. Maximum: ${f}`);const T=Buffer.concat(d.data);if(T.length>l)throw new Error(`File too large: ${d.filename}. Maximum: ${l} bytes`);if(s&&!s.includes(d.mimeType))throw new Error(`Invalid file type: ${d.mimeType}`);if(i){const v=_.extname(d.filename).toLowerCase().slice(1);if(!i.includes(v))throw new Error(`Invalid file extension: ${v}`)}const $={fieldName:d.fieldName,originalName:d.filename,mimeType:d.mimeType,size:T.length,encoding:d.encoding};if(c?.(d.fieldName,$),r==="disk"){const v=a(d.filename,d.mimeType),N=_.join(e,v);await new Promise((Q,W)=>{const x=L.createWriteStream(N);x.write(T),x.end(),x.on("finish",Q),x.on("error",W)}),$.path=N}else $.buffer=T;u?.(d.fieldName,$),M.push($),j++}else{if(z>=m)throw new Error(`Too many fields. Maximum: ${m}`);const T=Buffer.concat(d.data).toString();if(T.length>p)throw new Error(`Field too large: ${d.fieldName}`);P[d.fieldName]=T,z++}o.files=M,o.file=M[0],o.body={...o.body,...P},C.debug(`Uploaded ${M.length} files`),w()}catch(y){const k=y;C.error(`Upload error: ${k.message}`),h?.(k),g.status(R.HTTP_STATUS.BAD_REQUEST).json({success:!1,error:{message:k.message}})}}),o.on("error",y=>{C.error("Request error:",y),h?.(y),w(y)})}}function fe(n,e){return e.includes(n.mimeType)}function de(n){return{"image/jpeg":"jpg","image/png":"png","image/gif":"gif","image/webp":"webp","image/svg+xml":"svg","application/pdf":"pdf","application/json":"json","text/plain":"txt","text/csv":"csv","application/zip":"zip","application/x-rar-compressed":"rar"}[n]||"bin"}exports.Counter=F;exports.Gauge=O;exports.Histogram=I;exports.MetricsRegistry=A;exports.RedisStore=J;exports.customHealthCheck=ae;exports.defaultRegistry=b;exports.diskHealthCheck=re;exports.healthCheck=te;exports.httpRequestDuration=K;exports.httpRequestSize=X;exports.httpRequestsTotal=G;exports.httpResponseSize=q;exports.memoryHealthCheck=ie;exports.metricsEndpoint=ce;exports.metricsMiddleware=oe;exports.mimeToExtension=de;exports.mongoHealthCheck=se;exports.rateLimit=V;exports.redisHealthCheck=ne;exports.slidingWindowRateLimit=Z;exports.upload=me;exports.validateFileType=fe;
5
+ //# sourceMappingURL=upload-9lCNnKK_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-9lCNnKK_.js","sources":["../src/middleware/rateLimit.ts","../src/middleware/health.ts","../src/middleware/metrics.ts","../src/middleware/upload.ts"],"sourcesContent":["// Rate Limiting Middleware for Harbor\nimport { RequestHandler } from 'express';\nimport { createLogger } from '../utils/logger';\nimport { HTTP_STATUS } from '../constants';\n\nconst logger = createLogger('rate-limit');\n\nexport interface RateLimitOptions {\n windowMs?: number;\n max?: number;\n message?: string;\n statusCode?: number;\n keyGenerator?: (req: any) => string;\n skip?: (req: any) => boolean;\n onLimitReached?: (req: any, res: any) => void;\n headers?: boolean;\n store?: RateLimitStore;\n}\n\nexport interface RateLimitStore {\n increment(key: string): Promise<RateLimitInfo>;\n decrement(key: string): Promise<void>;\n resetKey(key: string): Promise<void>;\n get(key: string): Promise<RateLimitInfo | null>;\n}\n\nexport interface RateLimitInfo {\n count: number;\n resetTime: number;\n}\n\n// In-memory store (default)\nclass MemoryStore implements RateLimitStore {\n private hits: Map<string, RateLimitInfo> = new Map();\n private windowMs: number;\n\n constructor(windowMs: number) {\n this.windowMs = windowMs;\n \n // Clean up expired entries periodically\n setInterval(() => this.cleanup(), windowMs);\n }\n\n async increment(key: string): Promise<RateLimitInfo> {\n const now = Date.now();\n const existing = this.hits.get(key);\n\n if (existing && existing.resetTime > now) {\n existing.count++;\n return existing;\n }\n\n const info: RateLimitInfo = {\n count: 1,\n resetTime: now + this.windowMs,\n };\n this.hits.set(key, info);\n return info;\n }\n\n async decrement(key: string): Promise<void> {\n const existing = this.hits.get(key);\n if (existing && existing.count > 0) {\n existing.count--;\n }\n }\n\n async resetKey(key: string): Promise<void> {\n this.hits.delete(key);\n }\n\n async get(key: string): Promise<RateLimitInfo | null> {\n return this.hits.get(key) || null;\n }\n\n private cleanup(): void {\n const now = Date.now();\n for (const [key, info] of this.hits.entries()) {\n if (info.resetTime <= now) {\n this.hits.delete(key);\n }\n }\n }\n}\n\n// Redis store for distributed rate limiting\nexport class RedisStore implements RateLimitStore {\n private client: any;\n private windowMs: number;\n private prefix: string;\n\n constructor(client: any, windowMs: number, prefix = 'rl:') {\n this.client = client;\n this.windowMs = windowMs;\n this.prefix = prefix;\n }\n\n async increment(key: string): Promise<RateLimitInfo> {\n const redisKey = this.prefix + key;\n const multi = this.client.multi();\n \n multi.incr(redisKey);\n multi.pttl(redisKey);\n \n const results = await multi.exec();\n const count = results[0][1];\n let ttl = results[1][1];\n\n if (ttl === -1) {\n await this.client.pexpire(redisKey, this.windowMs);\n ttl = this.windowMs;\n }\n\n return {\n count,\n resetTime: Date.now() + ttl,\n };\n }\n\n async decrement(key: string): Promise<void> {\n await this.client.decr(this.prefix + key);\n }\n\n async resetKey(key: string): Promise<void> {\n await this.client.del(this.prefix + key);\n }\n\n async get(key: string): Promise<RateLimitInfo | null> {\n const redisKey = this.prefix + key;\n const [count, ttl] = await Promise.all([\n this.client.get(redisKey),\n this.client.pttl(redisKey),\n ]);\n\n if (count === null) return null;\n\n return {\n count: parseInt(count, 10),\n resetTime: Date.now() + Math.max(ttl, 0),\n };\n }\n}\n\n/**\n * Create a rate limiting middleware\n * \n * @example\n * // Basic usage - 100 requests per 15 minutes\n * app.use(rateLimit({ max: 100 }));\n * \n * // Per-route rate limiting\n * app.post('/api/login', rateLimit({ max: 5, windowMs: 60000 }), loginHandler);\n * \n * // With Redis for distributed systems\n * app.use(rateLimit({ store: new RedisStore(redisClient, 900000) }));\n */\nexport function rateLimit(options: RateLimitOptions = {}): RequestHandler {\n const {\n windowMs = 15 * 60 * 1000, // 15 minutes\n max = 100,\n message = 'Too many requests, please try again later.',\n statusCode = HTTP_STATUS.TOO_MANY_REQUESTS,\n keyGenerator = (req) => req.ip || req.connection?.remoteAddress || 'unknown',\n skip = () => false,\n onLimitReached,\n headers = true,\n store = new MemoryStore(windowMs),\n } = options;\n\n return async (req, res, next) => {\n if (skip(req)) {\n return next();\n }\n\n const key = keyGenerator(req);\n\n try {\n const info = await store.increment(key);\n const remaining = Math.max(0, max - info.count);\n\n if (headers) {\n res.setHeader('X-RateLimit-Limit', max);\n res.setHeader('X-RateLimit-Remaining', remaining);\n res.setHeader('X-RateLimit-Reset', Math.ceil(info.resetTime / 1000));\n }\n\n if (info.count > max) {\n logger.warn(`Rate limit exceeded for ${key}`);\n onLimitReached?.(req, res);\n\n if (headers) {\n res.setHeader('Retry-After', Math.ceil((info.resetTime - Date.now()) / 1000));\n }\n\n return res.status(statusCode).json({\n success: false,\n error: {\n message,\n retryAfter: Math.ceil((info.resetTime - Date.now()) / 1000),\n },\n });\n }\n\n next();\n } catch (err) {\n const error = err as Error;\n logger.error(`Rate limit error: ${error.message}`);\n next(error);\n }\n };\n}\n\n/**\n * Sliding window rate limiter for more accurate limiting\n */\nexport function slidingWindowRateLimit(options: RateLimitOptions = {}): RequestHandler {\n const {\n windowMs = 15 * 60 * 1000,\n max = 100,\n message = 'Too many requests, please try again later.',\n statusCode = HTTP_STATUS.TOO_MANY_REQUESTS,\n keyGenerator = (req) => req.ip || 'unknown',\n skip = () => false,\n headers = true,\n } = options;\n\n const requests: Map<string, number[]> = new Map();\n\n return (req, res, next) => {\n if (skip(req)) {\n return next();\n }\n\n const key = keyGenerator(req);\n const now = Date.now();\n const windowStart = now - windowMs;\n\n // Get or create request timestamps array\n let timestamps = requests.get(key) || [];\n \n // Filter out old requests\n timestamps = timestamps.filter((t) => t > windowStart);\n \n // Add current request\n timestamps.push(now);\n requests.set(key, timestamps);\n\n const remaining = Math.max(0, max - timestamps.length);\n\n if (headers) {\n res.setHeader('X-RateLimit-Limit', max);\n res.setHeader('X-RateLimit-Remaining', remaining);\n res.setHeader('X-RateLimit-Reset', Math.ceil((now + windowMs) / 1000));\n }\n\n if (timestamps.length > max) {\n logger.warn(`Sliding window rate limit exceeded for ${key}`);\n \n return res.status(statusCode).json({\n success: false,\n error: {\n message,\n retryAfter: Math.ceil(windowMs / 1000),\n },\n });\n }\n\n next();\n };\n}\n\n","// Health Check Middleware for Harbor\nimport { RequestHandler } from 'express';\n// Health Check Middleware\n\nexport interface HealthCheckResult {\n name: string;\n status: 'healthy' | 'unhealthy' | 'degraded';\n latency?: number;\n message?: string;\n details?: Record<string, unknown>;\n}\n\nexport interface HealthCheck {\n name: string;\n check: () => Promise<HealthCheckResult>;\n critical?: boolean;\n timeout?: number;\n}\n\nexport interface HealthOptions {\n path?: string;\n checks?: HealthCheck[];\n timeout?: number;\n onHealthCheck?: (results: HealthCheckResult[]) => void;\n}\n\nexport interface HealthStatus {\n status: 'healthy' | 'unhealthy' | 'degraded';\n timestamp: string;\n uptime: number;\n version?: string;\n checks: HealthCheckResult[];\n}\n\nconst startTime = Date.now();\n\n/**\n * Create health check endpoint\n * \n * @example\n * app.use(healthCheck({\n * checks: [\n * mongoHealthCheck(connection),\n * redisHealthCheck(redisClient),\n * customHealthCheck('api', async () => { ... }),\n * ],\n * }));\n */\nexport function healthCheck(options: HealthOptions = {}): RequestHandler {\n const {\n checks = [],\n timeout = 5000,\n onHealthCheck,\n } = options;\n\n return async (_req, res) => {\n const results: HealthCheckResult[] = [];\n let overallStatus: 'healthy' | 'unhealthy' | 'degraded' = 'healthy';\n\n // Run all health checks in parallel with timeout\n const checkPromises = checks.map(async (check) => {\n const startTime = Date.now();\n \n try {\n const result = await Promise.race([\n check.check(),\n new Promise<HealthCheckResult>((_, reject) =>\n setTimeout(() => reject(new Error('Timeout')), check.timeout || timeout)\n ),\n ]);\n \n result.latency = Date.now() - startTime;\n return result;\n } catch (error) {\n return {\n name: check.name,\n status: 'unhealthy' as const,\n latency: Date.now() - startTime,\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n });\n\n const checkResults = await Promise.all(checkPromises);\n results.push(...checkResults);\n\n // Determine overall status\n for (const result of results) {\n if (result.status === 'unhealthy') {\n const check = checks.find((c) => c.name === result.name);\n if (check?.critical !== false) {\n overallStatus = 'unhealthy';\n break;\n } else {\n overallStatus = 'degraded';\n }\n } else if (result.status === 'degraded' && overallStatus === 'healthy') {\n overallStatus = 'degraded';\n }\n }\n\n const healthStatus: HealthStatus = {\n status: overallStatus,\n timestamp: new Date().toISOString(),\n uptime: Math.floor((Date.now() - startTime) / 1000),\n checks: results,\n };\n\n onHealthCheck?.(results);\n\n const statusCode = overallStatus === 'healthy' ? 200 : overallStatus === 'degraded' ? 200 : 503;\n res.status(statusCode).json(healthStatus);\n };\n}\n\n// Pre-built health checks\n\n/**\n * MongoDB health check\n */\nexport function mongoHealthCheck(connection: any, name = 'mongodb'): HealthCheck {\n return {\n name,\n critical: true,\n check: async () => {\n try {\n if (connection.readyState === 1) {\n await connection.db?.admin().ping();\n return { name, status: 'healthy', message: 'Connected' };\n }\n return { name, status: 'unhealthy', message: 'Not connected' };\n } catch (error) {\n return {\n name,\n status: 'unhealthy',\n message: error instanceof Error ? error.message : 'Connection failed',\n };\n }\n },\n };\n}\n\n/**\n * Redis health check\n */\nexport function redisHealthCheck(client: any, name = 'redis'): HealthCheck {\n return {\n name,\n critical: false,\n check: async () => {\n try {\n const pong = await client.ping();\n if (pong === 'PONG') {\n return { name, status: 'healthy', message: 'Connected' };\n }\n return { name, status: 'unhealthy', message: 'Invalid response' };\n } catch (error) {\n return {\n name,\n status: 'unhealthy',\n message: error instanceof Error ? error.message : 'Connection failed',\n };\n }\n },\n };\n}\n\n/**\n * Memory health check\n */\nexport function memoryHealthCheck(\n maxHeapMB = 512,\n name = 'memory'\n): HealthCheck {\n return {\n name,\n critical: false,\n check: async () => {\n const usage = process.memoryUsage();\n const heapUsedMB = Math.round(usage.heapUsed / 1024 / 1024);\n const heapTotalMB = Math.round(usage.heapTotal / 1024 / 1024);\n const rssMB = Math.round(usage.rss / 1024 / 1024);\n\n const status = heapUsedMB > maxHeapMB ? 'degraded' : 'healthy';\n\n return {\n name,\n status,\n message: `Heap: ${heapUsedMB}MB / ${heapTotalMB}MB`,\n details: {\n heapUsed: heapUsedMB,\n heapTotal: heapTotalMB,\n rss: rssMB,\n external: Math.round(usage.external / 1024 / 1024),\n },\n };\n },\n };\n}\n\n/**\n * Disk health check (requires 'check-disk-space' package)\n */\nexport function diskHealthCheck(\n _path = '/',\n _minFreeGB = 1,\n name = 'disk'\n): HealthCheck {\n return {\n name,\n critical: false,\n check: async () => {\n // Disk space check requires 'check-disk-space' package\n return {\n name,\n status: 'healthy',\n message: 'Disk check requires check-disk-space package',\n };\n },\n };\n}\n\n/**\n * Custom health check\n */\nexport function customHealthCheck(\n name: string,\n checkFn: () => Promise<boolean | { healthy: boolean; message?: string }>,\n critical = false\n): HealthCheck {\n return {\n name,\n critical,\n check: async () => {\n try {\n const result = await checkFn();\n if (typeof result === 'boolean') {\n return {\n name,\n status: result ? 'healthy' : 'unhealthy',\n };\n }\n return {\n name,\n status: result.healthy ? 'healthy' : 'unhealthy',\n message: result.message,\n };\n } catch (error) {\n return {\n name,\n status: 'unhealthy',\n message: error instanceof Error ? error.message : 'Check failed',\n };\n }\n },\n };\n}\n\n","// Prometheus-compatible Metrics for Harbor\nimport { RequestHandler } from 'express';\n// Prometheus-compatible Metrics for Harbor\n\nexport interface MetricsOptions {\n path?: string;\n prefix?: string;\n defaultLabels?: Record<string, string>;\n collectDefaultMetrics?: boolean;\n requestDurationBuckets?: number[];\n requestSizeBuckets?: number[];\n responseSizeBuckets?: number[];\n}\n\ninterface Metric {\n name: string;\n help: string;\n type: 'counter' | 'gauge' | 'histogram' | 'summary';\n values: Map<string, number | number[]>;\n buckets?: number[];\n}\n\nexport class MetricsRegistry {\n private metrics: Map<string, Metric> = new Map();\n private prefix: string;\n private defaultLabels: Record<string, string>;\n\n constructor(prefix = 'harbor_', defaultLabels: Record<string, string> = {}) {\n this.prefix = prefix;\n this.defaultLabels = defaultLabels;\n }\n\n // Counter - only goes up\n counter(name: string, help: string): Counter {\n const fullName = this.prefix + name;\n if (!this.metrics.has(fullName)) {\n this.metrics.set(fullName, {\n name: fullName,\n help,\n type: 'counter',\n values: new Map(),\n });\n }\n return new Counter(this.metrics.get(fullName)!, this.defaultLabels);\n }\n\n // Gauge - can go up and down\n gauge(name: string, help: string): Gauge {\n const fullName = this.prefix + name;\n if (!this.metrics.has(fullName)) {\n this.metrics.set(fullName, {\n name: fullName,\n help,\n type: 'gauge',\n values: new Map(),\n });\n }\n return new Gauge(this.metrics.get(fullName)!, this.defaultLabels);\n }\n\n // Histogram - observations in buckets\n histogram(name: string, help: string, buckets: number[] = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]): Histogram {\n const fullName = this.prefix + name;\n if (!this.metrics.has(fullName)) {\n this.metrics.set(fullName, {\n name: fullName,\n help,\n type: 'histogram',\n values: new Map(),\n buckets,\n });\n }\n return new Histogram(this.metrics.get(fullName)!, this.defaultLabels);\n }\n\n // Get all metrics in Prometheus format\n getMetrics(): string {\n const lines: string[] = [];\n\n for (const metric of this.metrics.values()) {\n lines.push(`# HELP ${metric.name} ${metric.help}`);\n lines.push(`# TYPE ${metric.name} ${metric.type}`);\n\n if (metric.type === 'histogram') {\n // Group by labels and output histogram format\n const labelGroups = new Map<string, { sum: number; count: number; buckets: Map<number, number> }>();\n \n for (const [key, value] of metric.values.entries()) {\n const [labelsStr, bucket] = key.split('|');\n if (!labelGroups.has(labelsStr)) {\n labelGroups.set(labelsStr, { sum: 0, count: 0, buckets: new Map() });\n }\n const group = labelGroups.get(labelsStr)!;\n \n if (bucket === 'sum') {\n group.sum = value as number;\n } else if (bucket === 'count') {\n group.count = value as number;\n } else {\n group.buckets.set(parseFloat(bucket), value as number);\n }\n }\n\n for (const [labelsStr, group] of labelGroups.entries()) {\n const labels = labelsStr ? `{${labelsStr}}` : '';\n let cumulative = 0;\n \n for (const bucket of metric.buckets || []) {\n cumulative += group.buckets.get(bucket) || 0;\n const bucketLabels = labelsStr ? `{${labelsStr},le=\"${bucket}\"}` : `{le=\"${bucket}\"}`;\n lines.push(`${metric.name}_bucket${bucketLabels} ${cumulative}`);\n }\n \n const infLabels = labelsStr ? `{${labelsStr},le=\"+Inf\"}` : `{le=\"+Inf\"}`;\n lines.push(`${metric.name}_bucket${infLabels} ${group.count}`);\n lines.push(`${metric.name}_sum${labels} ${group.sum}`);\n lines.push(`${metric.name}_count${labels} ${group.count}`);\n }\n } else {\n for (const [labels, value] of metric.values.entries()) {\n const labelsStr = labels ? `{${labels}}` : '';\n lines.push(`${metric.name}${labelsStr} ${value}`);\n }\n }\n }\n\n return lines.join('\\n');\n }\n\n reset(): void {\n for (const metric of this.metrics.values()) {\n metric.values.clear();\n }\n }\n}\n\nclass Counter {\n private metric: Metric;\n private defaultLabels: Record<string, string>;\n\n constructor(metric: Metric, defaultLabels: Record<string, string>) {\n this.metric = metric;\n this.defaultLabels = defaultLabels;\n }\n\n inc(labels: Record<string, string> = {}, value = 1): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n const current = (this.metric.values.get(key) as number) || 0;\n this.metric.values.set(key, current + value);\n }\n\n private labelsToString(labels: Record<string, string>): string {\n return Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v}\"`)\n .join(',');\n }\n}\n\nclass Gauge {\n private metric: Metric;\n private defaultLabels: Record<string, string>;\n\n constructor(metric: Metric, defaultLabels: Record<string, string>) {\n this.metric = metric;\n this.defaultLabels = defaultLabels;\n }\n\n set(value: number, labels: Record<string, string> = {}): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n this.metric.values.set(key, value);\n }\n\n inc(labels: Record<string, string> = {}, value = 1): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n const current = (this.metric.values.get(key) as number) || 0;\n this.metric.values.set(key, current + value);\n }\n\n dec(labels: Record<string, string> = {}, value = 1): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n const current = (this.metric.values.get(key) as number) || 0;\n this.metric.values.set(key, current - value);\n }\n\n private labelsToString(labels: Record<string, string>): string {\n return Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v}\"`)\n .join(',');\n }\n}\n\nclass Histogram {\n private metric: Metric;\n private defaultLabels: Record<string, string>;\n\n constructor(metric: Metric, defaultLabels: Record<string, string>) {\n this.metric = metric;\n this.defaultLabels = defaultLabels;\n }\n\n observe(value: number, labels: Record<string, string> = {}): void {\n const labelsStr = this.labelsToString({ ...this.defaultLabels, ...labels });\n \n // Update sum\n const sumKey = `${labelsStr}|sum`;\n const currentSum = (this.metric.values.get(sumKey) as number) || 0;\n this.metric.values.set(sumKey, currentSum + value);\n\n // Update count\n const countKey = `${labelsStr}|count`;\n const currentCount = (this.metric.values.get(countKey) as number) || 0;\n this.metric.values.set(countKey, currentCount + 1);\n\n // Update buckets\n for (const bucket of this.metric.buckets || []) {\n if (value <= bucket) {\n const bucketKey = `${labelsStr}|${bucket}`;\n const current = (this.metric.values.get(bucketKey) as number) || 0;\n this.metric.values.set(bucketKey, current + 1);\n }\n }\n }\n\n startTimer(labels: Record<string, string> = {}): () => void {\n const start = process.hrtime.bigint();\n return () => {\n const end = process.hrtime.bigint();\n const duration = Number(end - start) / 1e9; // Convert to seconds\n this.observe(duration, labels);\n };\n }\n\n private labelsToString(labels: Record<string, string>): string {\n return Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v}\"`)\n .join(',');\n }\n}\n\n// Global registry instance\nexport const defaultRegistry = new MetricsRegistry();\n\n// Pre-built metrics\nexport const httpRequestsTotal = defaultRegistry.counter(\n 'http_requests_total',\n 'Total number of HTTP requests'\n);\n\nexport const httpRequestDuration = defaultRegistry.histogram(\n 'http_request_duration_seconds',\n 'HTTP request duration in seconds'\n);\n\nexport const httpRequestSize = defaultRegistry.histogram(\n 'http_request_size_bytes',\n 'HTTP request size in bytes',\n [100, 1000, 10000, 100000, 1000000]\n);\n\nexport const httpResponseSize = defaultRegistry.histogram(\n 'http_response_size_bytes',\n 'HTTP response size in bytes',\n [100, 1000, 10000, 100000, 1000000]\n);\n\n/**\n * Metrics collection middleware\n */\nexport function metricsMiddleware(): RequestHandler {\n return (req, res, next) => {\n const timer = httpRequestDuration.startTimer({\n method: req.method,\n path: req.route?.path || req.path,\n });\n\n const requestSize = parseInt(req.get('content-length') || '0', 10);\n if (requestSize > 0) {\n httpRequestSize.observe(requestSize, { method: req.method });\n }\n\n res.on('finish', () => {\n timer();\n \n httpRequestsTotal.inc({\n method: req.method,\n path: req.route?.path || req.path,\n status: res.statusCode.toString(),\n });\n\n const responseSize = parseInt(res.get('content-length') || '0', 10);\n if (responseSize > 0) {\n httpResponseSize.observe(responseSize, {\n method: req.method,\n status: res.statusCode.toString(),\n });\n }\n });\n\n next();\n };\n}\n\n/**\n * Metrics endpoint handler\n */\nexport function metricsEndpoint(registry = defaultRegistry): RequestHandler {\n return (_req, res) => {\n res.set('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\n res.send(registry.getMetrics());\n };\n}\n\nexport { Counter, Gauge, Histogram };\n\n","// File Upload Middleware for Harbor\nimport { RequestHandler } from 'express';\nimport { createWriteStream, existsSync, mkdirSync } from 'fs';\nimport { join, extname } from 'path';\nimport { createLogger } from '../utils/logger';\nimport { HTTP_STATUS } from '../constants';\n\nconst logger = createLogger('upload');\n\nexport interface UploadOptions {\n dest?: string;\n limits?: {\n fileSize?: number;\n files?: number;\n fields?: number;\n fieldSize?: number;\n };\n allowedMimeTypes?: string[];\n allowedExtensions?: string[];\n filename?: (originalName: string, mimeType: string) => string;\n storage?: 'disk' | 'memory';\n onFileBegin?: (fieldName: string, file: UploadedFile) => void;\n onFileEnd?: (fieldName: string, file: UploadedFile) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface UploadedFile {\n fieldName: string;\n originalName: string;\n mimeType: string;\n size: number;\n path?: string;\n buffer?: Buffer;\n encoding: string;\n}\n\ninterface MultipartPart {\n fieldName: string;\n filename?: string;\n mimeType: string;\n encoding: string;\n data: Buffer[];\n}\n\n/**\n * Parse multipart boundary from content-type header\n */\nfunction getBoundary(contentType: string): string | null {\n const match = contentType.match(/boundary=(?:\"([^\"]+)\"|([^;]+))/i);\n return match ? match[1] || match[2] : null;\n}\n\n/**\n * Parse multipart form data\n */\nfunction parseMultipart(buffer: Buffer, boundary: string): MultipartPart[] {\n const parts: MultipartPart[] = [];\n const boundaryBuffer = Buffer.from(`--${boundary}`);\n const endBoundary = Buffer.from(`--${boundary}--`);\n \n let start = buffer.indexOf(boundaryBuffer) + boundaryBuffer.length + 2; // Skip CRLF\n \n while (start < buffer.length) {\n const end = buffer.indexOf(boundaryBuffer, start);\n if (end === -1) break;\n \n const partData = buffer.slice(start, end - 2); // Remove trailing CRLF\n const headerEnd = partData.indexOf('\\r\\n\\r\\n');\n \n if (headerEnd !== -1) {\n const headers = partData.slice(0, headerEnd).toString();\n const body = partData.slice(headerEnd + 4);\n \n const contentDisposition = headers.match(/Content-Disposition:\\s*form-data;\\s*name=\"([^\"]+)\"(?:;\\s*filename=\"([^\"]+)\")?/i);\n const contentType = headers.match(/Content-Type:\\s*([^\\r\\n]+)/i);\n const encoding = headers.match(/Content-Transfer-Encoding:\\s*([^\\r\\n]+)/i);\n \n if (contentDisposition) {\n parts.push({\n fieldName: contentDisposition[1],\n filename: contentDisposition[2],\n mimeType: contentType ? contentType[1] : 'application/octet-stream',\n encoding: encoding ? encoding[1] : '7bit',\n data: [body],\n });\n }\n }\n \n start = end + boundaryBuffer.length + 2;\n \n // Check for end boundary\n if (buffer.slice(end, end + endBoundary.length).equals(endBoundary)) {\n break;\n }\n }\n \n return parts;\n}\n\n/**\n * Generate unique filename\n */\nfunction generateFilename(originalName: string): string {\n const ext = extname(originalName);\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 8);\n return `${timestamp}-${random}${ext}`;\n}\n\n/**\n * File upload middleware\n * \n * @example\n * // Single file upload\n * app.post('/upload', upload({ dest: './uploads' }), (req, res) => {\n * console.log(req.file);\n * res.json({ uploaded: true });\n * });\n * \n * // Multiple files\n * app.post('/uploads', upload({ dest: './uploads', limits: { files: 10 } }), (req, res) => {\n * console.log(req.files);\n * res.json({ count: req.files.length });\n * });\n * \n * // Memory storage\n * app.post('/buffer', upload({ storage: 'memory' }), (req, res) => {\n * const buffer = req.file.buffer;\n * // Process buffer...\n * });\n */\nexport function upload(options: UploadOptions = {}): RequestHandler {\n const {\n dest = './uploads',\n limits = {},\n allowedMimeTypes,\n allowedExtensions,\n filename = generateFilename,\n storage = 'disk',\n onFileBegin,\n onFileEnd,\n onError,\n } = options;\n\n const {\n fileSize = 10 * 1024 * 1024, // 10MB default\n files = 10,\n fields = 100,\n fieldSize = 1024 * 1024, // 1MB default\n } = limits;\n\n // Ensure upload directory exists\n if (storage === 'disk' && !existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n return async (req, res, next) => {\n const contentType = req.get('content-type') || '';\n \n if (!contentType.includes('multipart/form-data')) {\n return next();\n }\n\n const boundary = getBoundary(contentType);\n if (!boundary) {\n return res.status(HTTP_STATUS.BAD_REQUEST).json({\n success: false,\n error: { message: 'Missing boundary in content-type' },\n });\n }\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n\n req.on('data', (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > fileSize * files) {\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n\n req.on('end', async () => {\n try {\n const buffer = Buffer.concat(chunks);\n const parts = parseMultipart(buffer, boundary);\n\n const uploadedFiles: UploadedFile[] = [];\n const formFields: Record<string, string> = {};\n let fileCount = 0;\n let fieldCount = 0;\n\n for (const part of parts) {\n if (part.filename) {\n // File upload\n if (fileCount >= files) {\n throw new Error(`Too many files. Maximum: ${files}`);\n }\n\n const fileBuffer = Buffer.concat(part.data);\n \n if (fileBuffer.length > fileSize) {\n throw new Error(`File too large: ${part.filename}. Maximum: ${fileSize} bytes`);\n }\n\n // Check mime type\n if (allowedMimeTypes && !allowedMimeTypes.includes(part.mimeType)) {\n throw new Error(`Invalid file type: ${part.mimeType}`);\n }\n\n // Check extension\n if (allowedExtensions) {\n const ext = extname(part.filename).toLowerCase().slice(1);\n if (!allowedExtensions.includes(ext)) {\n throw new Error(`Invalid file extension: ${ext}`);\n }\n }\n\n const file: UploadedFile = {\n fieldName: part.fieldName,\n originalName: part.filename,\n mimeType: part.mimeType,\n size: fileBuffer.length,\n encoding: part.encoding,\n };\n\n onFileBegin?.(part.fieldName, file);\n\n if (storage === 'disk') {\n const newFilename = filename(part.filename, part.mimeType);\n const filePath = join(dest, newFilename);\n \n await new Promise<void>((resolve, reject) => {\n const writeStream = createWriteStream(filePath);\n writeStream.write(fileBuffer);\n writeStream.end();\n writeStream.on('finish', resolve);\n writeStream.on('error', reject);\n });\n\n file.path = filePath;\n } else {\n file.buffer = fileBuffer;\n }\n\n onFileEnd?.(part.fieldName, file);\n uploadedFiles.push(file);\n fileCount++;\n } else {\n // Form field\n if (fieldCount >= fields) {\n throw new Error(`Too many fields. Maximum: ${fields}`);\n }\n\n const value = Buffer.concat(part.data).toString();\n if (value.length > fieldSize) {\n throw new Error(`Field too large: ${part.fieldName}`);\n }\n\n formFields[part.fieldName] = value;\n fieldCount++;\n }\n }\n\n // Attach to request\n (req as any).files = uploadedFiles;\n (req as any).file = uploadedFiles[0];\n (req as any).body = { ...(req as any).body, ...formFields };\n\n logger.debug(`Uploaded ${uploadedFiles.length} files`);\n next();\n } catch (err) {\n const error = err as Error;\n logger.error(`Upload error: ${error.message}`);\n onError?.(error);\n res.status(HTTP_STATUS.BAD_REQUEST).json({\n success: false,\n error: { message: error.message },\n });\n }\n });\n\n req.on('error', (err) => {\n logger.error('Request error:', err);\n onError?.(err as Error);\n next(err as Error);\n });\n };\n}\n\n/**\n * Validate file type helper\n */\nexport function validateFileType(\n file: UploadedFile,\n allowedTypes: string[]\n): boolean {\n return allowedTypes.includes(file.mimeType);\n}\n\n/**\n * Get file extension from mime type\n */\nexport function mimeToExtension(mimeType: string): string {\n const mimeMap: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/gif': 'gif',\n 'image/webp': 'webp',\n 'image/svg+xml': 'svg',\n 'application/pdf': 'pdf',\n 'application/json': 'json',\n 'text/plain': 'txt',\n 'text/csv': 'csv',\n 'application/zip': 'zip',\n 'application/x-rar-compressed': 'rar',\n };\n\n return mimeMap[mimeType] || 'bin';\n}\n\n"],"names":["logger","createLogger","MemoryStore","windowMs","key","now","existing","info","RedisStore","client","prefix","redisKey","multi","results","count","ttl","rateLimit","options","max","message","statusCode","HTTP_STATUS","keyGenerator","req","skip","onLimitReached","headers","store","res","next","remaining","err","error","slidingWindowRateLimit","requests","windowStart","timestamps","t","startTime","healthCheck","checks","timeout","onHealthCheck","_req","overallStatus","checkPromises","check","result","_","reject","checkResults","c","healthStatus","mongoHealthCheck","connection","name","redisHealthCheck","memoryHealthCheck","maxHeapMB","usage","heapUsedMB","heapTotalMB","rssMB","status","diskHealthCheck","_path","_minFreeGB","customHealthCheck","checkFn","critical","MetricsRegistry","defaultLabels","help","fullName","Counter","Gauge","buckets","Histogram","lines","metric","labelGroups","value","labelsStr","bucket","group","labels","cumulative","bucketLabels","infLabels","current","k","v","sumKey","currentSum","countKey","currentCount","bucketKey","start","end","duration","defaultRegistry","httpRequestsTotal","httpRequestDuration","httpRequestSize","httpResponseSize","metricsMiddleware","timer","requestSize","responseSize","metricsEndpoint","registry","getBoundary","contentType","match","parseMultipart","buffer","boundary","parts","boundaryBuffer","endBoundary","partData","headerEnd","body","contentDisposition","encoding","generateFilename","originalName","ext","extname","timestamp","random","upload","dest","limits","allowedMimeTypes","allowedExtensions","filename","storage","onFileBegin","onFileEnd","onError","fileSize","files","fields","fieldSize","existsSync","mkdirSync","chunks","totalSize","chunk","uploadedFiles","formFields","fileCount","fieldCount","part","fileBuffer","file","newFilename","filePath","join","resolve","writeStream","createWriteStream","validateFileType","allowedTypes","mimeToExtension","mimeType"],"mappings":"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"}