@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,619 @@
1
+ import { c as P } from "./logger-CZn7QxCl.mjs";
2
+ import { H as L } from "./http.const-BKHG1Lsj.mjs";
3
+ import { existsSync as F, mkdirSync as I, createWriteStream as A } from "fs";
4
+ import { extname as z, join as G } from "path";
5
+ const E = P("rate-limit");
6
+ class K {
7
+ hits = /* @__PURE__ */ new Map();
8
+ windowMs;
9
+ constructor(e) {
10
+ this.windowMs = e, setInterval(() => this.cleanup(), e);
11
+ }
12
+ async increment(e) {
13
+ const t = Date.now(), s = this.hits.get(e);
14
+ if (s && s.resetTime > t)
15
+ return s.count++, s;
16
+ const i = {
17
+ count: 1,
18
+ resetTime: t + this.windowMs
19
+ };
20
+ return this.hits.set(e, i), i;
21
+ }
22
+ async decrement(e) {
23
+ const t = this.hits.get(e);
24
+ t && t.count > 0 && t.count--;
25
+ }
26
+ async resetKey(e) {
27
+ this.hits.delete(e);
28
+ }
29
+ async get(e) {
30
+ return this.hits.get(e) || null;
31
+ }
32
+ cleanup() {
33
+ const e = Date.now();
34
+ for (const [t, s] of this.hits.entries())
35
+ s.resetTime <= e && this.hits.delete(t);
36
+ }
37
+ }
38
+ class ce {
39
+ client;
40
+ windowMs;
41
+ prefix;
42
+ constructor(e, t, s = "rl:") {
43
+ this.client = e, this.windowMs = t, this.prefix = s;
44
+ }
45
+ async increment(e) {
46
+ const t = this.prefix + e, s = this.client.multi();
47
+ s.incr(t), s.pttl(t);
48
+ const i = await s.exec(), r = i[0][1];
49
+ let a = i[1][1];
50
+ return a === -1 && (await this.client.pexpire(t, this.windowMs), a = this.windowMs), {
51
+ count: r,
52
+ resetTime: Date.now() + a
53
+ };
54
+ }
55
+ async decrement(e) {
56
+ await this.client.decr(this.prefix + e);
57
+ }
58
+ async resetKey(e) {
59
+ await this.client.del(this.prefix + e);
60
+ }
61
+ async get(e) {
62
+ const t = this.prefix + e, [s, i] = await Promise.all([
63
+ this.client.get(t),
64
+ this.client.pttl(t)
65
+ ]);
66
+ return s === null ? null : {
67
+ count: parseInt(s, 10),
68
+ resetTime: Date.now() + Math.max(i, 0)
69
+ };
70
+ }
71
+ }
72
+ function le(n = {}) {
73
+ const {
74
+ windowMs: e = 15 * 60 * 1e3,
75
+ // 15 minutes
76
+ max: t = 100,
77
+ message: s = "Too many requests, please try again later.",
78
+ statusCode: i = L.TOO_MANY_REQUESTS,
79
+ keyGenerator: r = (l) => l.ip || l.connection?.remoteAddress || "unknown",
80
+ skip: a = () => !1,
81
+ onLimitReached: c,
82
+ headers: u = !0,
83
+ store: h = new K(e)
84
+ } = n;
85
+ return async (l, f, m) => {
86
+ if (a(l))
87
+ return m();
88
+ const p = r(l);
89
+ try {
90
+ const o = await h.increment(p), g = Math.max(0, t - o.count);
91
+ 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)
92
+ 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({
93
+ success: !1,
94
+ error: {
95
+ message: s,
96
+ retryAfter: Math.ceil((o.resetTime - Date.now()) / 1e3)
97
+ }
98
+ });
99
+ m();
100
+ } catch (o) {
101
+ const g = o;
102
+ E.error(`Rate limit error: ${g.message}`), m(g);
103
+ }
104
+ };
105
+ }
106
+ function ue(n = {}) {
107
+ const {
108
+ windowMs: e = 15 * 60 * 1e3,
109
+ max: t = 100,
110
+ message: s = "Too many requests, please try again later.",
111
+ statusCode: i = L.TOO_MANY_REQUESTS,
112
+ keyGenerator: r = (h) => h.ip || "unknown",
113
+ skip: a = () => !1,
114
+ headers: c = !0
115
+ } = n, u = /* @__PURE__ */ new Map();
116
+ return (h, l, f) => {
117
+ if (a(h))
118
+ return f();
119
+ const m = r(h), p = Date.now(), o = p - e;
120
+ let g = u.get(m) || [];
121
+ g = g.filter((M) => M > o), g.push(p), u.set(m, g);
122
+ const w = Math.max(0, t - g.length);
123
+ 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)
124
+ return E.warn(`Sliding window rate limit exceeded for ${m}`), l.status(i).json({
125
+ success: !1,
126
+ error: {
127
+ message: s,
128
+ retryAfter: Math.ceil(e / 1e3)
129
+ }
130
+ });
131
+ f();
132
+ };
133
+ }
134
+ const X = Date.now();
135
+ function he(n = {}) {
136
+ const {
137
+ checks: e = [],
138
+ timeout: t = 5e3,
139
+ onHealthCheck: s
140
+ } = n;
141
+ return async (i, r) => {
142
+ const a = [];
143
+ let c = "healthy";
144
+ const u = e.map(async (m) => {
145
+ const p = Date.now();
146
+ try {
147
+ const o = await Promise.race([
148
+ m.check(),
149
+ new Promise(
150
+ (g, w) => setTimeout(() => w(new Error("Timeout")), m.timeout || t)
151
+ )
152
+ ]);
153
+ return o.latency = Date.now() - p, o;
154
+ } catch (o) {
155
+ return {
156
+ name: m.name,
157
+ status: "unhealthy",
158
+ latency: Date.now() - p,
159
+ message: o instanceof Error ? o.message : "Unknown error"
160
+ };
161
+ }
162
+ }), h = await Promise.all(u);
163
+ a.push(...h);
164
+ for (const m of a)
165
+ if (m.status === "unhealthy")
166
+ if (e.find((o) => o.name === m.name)?.critical !== !1) {
167
+ c = "unhealthy";
168
+ break;
169
+ } else
170
+ c = "degraded";
171
+ else m.status === "degraded" && c === "healthy" && (c = "degraded");
172
+ const l = {
173
+ status: c,
174
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
175
+ uptime: Math.floor((Date.now() - X) / 1e3),
176
+ checks: a
177
+ };
178
+ s?.(a);
179
+ const f = c === "healthy" || c === "degraded" ? 200 : 503;
180
+ r.status(f).json(l);
181
+ };
182
+ }
183
+ function me(n, e = "mongodb") {
184
+ return {
185
+ name: e,
186
+ critical: !0,
187
+ check: async () => {
188
+ try {
189
+ return n.readyState === 1 ? (await n.db?.admin().ping(), { name: e, status: "healthy", message: "Connected" }) : { name: e, status: "unhealthy", message: "Not connected" };
190
+ } catch (t) {
191
+ return {
192
+ name: e,
193
+ status: "unhealthy",
194
+ message: t instanceof Error ? t.message : "Connection failed"
195
+ };
196
+ }
197
+ }
198
+ };
199
+ }
200
+ function fe(n, e = "redis") {
201
+ return {
202
+ name: e,
203
+ critical: !1,
204
+ check: async () => {
205
+ try {
206
+ return await n.ping() === "PONG" ? { name: e, status: "healthy", message: "Connected" } : { name: e, status: "unhealthy", message: "Invalid response" };
207
+ } catch (t) {
208
+ return {
209
+ name: e,
210
+ status: "unhealthy",
211
+ message: t instanceof Error ? t.message : "Connection failed"
212
+ };
213
+ }
214
+ }
215
+ };
216
+ }
217
+ function de(n = 512, e = "memory") {
218
+ return {
219
+ name: e,
220
+ critical: !1,
221
+ check: async () => {
222
+ const t = process.memoryUsage(), s = Math.round(t.heapUsed / 1024 / 1024), i = Math.round(t.heapTotal / 1024 / 1024), r = Math.round(t.rss / 1024 / 1024), a = s > n ? "degraded" : "healthy";
223
+ return {
224
+ name: e,
225
+ status: a,
226
+ message: `Heap: ${s}MB / ${i}MB`,
227
+ details: {
228
+ heapUsed: s,
229
+ heapTotal: i,
230
+ rss: r,
231
+ external: Math.round(t.external / 1024 / 1024)
232
+ }
233
+ };
234
+ }
235
+ };
236
+ }
237
+ function pe(n = "/", e = 1, t = "disk") {
238
+ return {
239
+ name: t,
240
+ critical: !1,
241
+ check: async () => ({
242
+ name: t,
243
+ status: "healthy",
244
+ message: "Disk check requires check-disk-space package"
245
+ })
246
+ };
247
+ }
248
+ function ge(n, e, t = !1) {
249
+ return {
250
+ name: n,
251
+ critical: t,
252
+ check: async () => {
253
+ try {
254
+ const s = await e();
255
+ return typeof s == "boolean" ? {
256
+ name: n,
257
+ status: s ? "healthy" : "unhealthy"
258
+ } : {
259
+ name: n,
260
+ status: s.healthy ? "healthy" : "unhealthy",
261
+ message: s.message
262
+ };
263
+ } catch (s) {
264
+ return {
265
+ name: n,
266
+ status: "unhealthy",
267
+ message: s instanceof Error ? s.message : "Check failed"
268
+ };
269
+ }
270
+ }
271
+ };
272
+ }
273
+ class Q {
274
+ metrics = /* @__PURE__ */ new Map();
275
+ prefix;
276
+ defaultLabels;
277
+ constructor(e = "harbor_", t = {}) {
278
+ this.prefix = e, this.defaultLabels = t;
279
+ }
280
+ // Counter - only goes up
281
+ counter(e, t) {
282
+ const s = this.prefix + e;
283
+ return this.metrics.has(s) || this.metrics.set(s, {
284
+ name: s,
285
+ help: t,
286
+ type: "counter",
287
+ values: /* @__PURE__ */ new Map()
288
+ }), new Y(this.metrics.get(s), this.defaultLabels);
289
+ }
290
+ // Gauge - can go up and down
291
+ gauge(e, t) {
292
+ const s = this.prefix + e;
293
+ return this.metrics.has(s) || this.metrics.set(s, {
294
+ name: s,
295
+ help: t,
296
+ type: "gauge",
297
+ values: /* @__PURE__ */ new Map()
298
+ }), new W(this.metrics.get(s), this.defaultLabels);
299
+ }
300
+ // Histogram - observations in buckets
301
+ histogram(e, t, s = [5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]) {
302
+ const i = this.prefix + e;
303
+ return this.metrics.has(i) || this.metrics.set(i, {
304
+ name: i,
305
+ help: t,
306
+ type: "histogram",
307
+ values: /* @__PURE__ */ new Map(),
308
+ buckets: s
309
+ }), new J(this.metrics.get(i), this.defaultLabels);
310
+ }
311
+ // Get all metrics in Prometheus format
312
+ getMetrics() {
313
+ const e = [];
314
+ for (const t of this.metrics.values())
315
+ if (e.push(`# HELP ${t.name} ${t.help}`), e.push(`# TYPE ${t.name} ${t.type}`), t.type === "histogram") {
316
+ const s = /* @__PURE__ */ new Map();
317
+ for (const [i, r] of t.values.entries()) {
318
+ const [a, c] = i.split("|");
319
+ s.has(a) || s.set(a, { sum: 0, count: 0, buckets: /* @__PURE__ */ new Map() });
320
+ const u = s.get(a);
321
+ c === "sum" ? u.sum = r : c === "count" ? u.count = r : u.buckets.set(parseFloat(c), r);
322
+ }
323
+ for (const [i, r] of s.entries()) {
324
+ const a = i ? `{${i}}` : "";
325
+ let c = 0;
326
+ for (const h of t.buckets || []) {
327
+ c += r.buckets.get(h) || 0;
328
+ const l = i ? `{${i},le="${h}"}` : `{le="${h}"}`;
329
+ e.push(`${t.name}_bucket${l} ${c}`);
330
+ }
331
+ const u = i ? `{${i},le="+Inf"}` : '{le="+Inf"}';
332
+ e.push(`${t.name}_bucket${u} ${r.count}`), e.push(`${t.name}_sum${a} ${r.sum}`), e.push(`${t.name}_count${a} ${r.count}`);
333
+ }
334
+ } else
335
+ for (const [s, i] of t.values.entries()) {
336
+ const r = s ? `{${s}}` : "";
337
+ e.push(`${t.name}${r} ${i}`);
338
+ }
339
+ return e.join(`
340
+ `);
341
+ }
342
+ reset() {
343
+ for (const e of this.metrics.values())
344
+ e.values.clear();
345
+ }
346
+ }
347
+ class Y {
348
+ metric;
349
+ defaultLabels;
350
+ constructor(e, t) {
351
+ this.metric = e, this.defaultLabels = t;
352
+ }
353
+ inc(e = {}, t = 1) {
354
+ const s = this.labelsToString({ ...this.defaultLabels, ...e }), i = this.metric.values.get(s) || 0;
355
+ this.metric.values.set(s, i + t);
356
+ }
357
+ labelsToString(e) {
358
+ return Object.entries(e).map(([t, s]) => `${t}="${s}"`).join(",");
359
+ }
360
+ }
361
+ class W {
362
+ metric;
363
+ defaultLabels;
364
+ constructor(e, t) {
365
+ this.metric = e, this.defaultLabels = t;
366
+ }
367
+ set(e, t = {}) {
368
+ const s = this.labelsToString({ ...this.defaultLabels, ...t });
369
+ this.metric.values.set(s, e);
370
+ }
371
+ inc(e = {}, t = 1) {
372
+ const s = this.labelsToString({ ...this.defaultLabels, ...e }), i = this.metric.values.get(s) || 0;
373
+ this.metric.values.set(s, i + t);
374
+ }
375
+ dec(e = {}, t = 1) {
376
+ const s = this.labelsToString({ ...this.defaultLabels, ...e }), i = this.metric.values.get(s) || 0;
377
+ this.metric.values.set(s, i - t);
378
+ }
379
+ labelsToString(e) {
380
+ return Object.entries(e).map(([t, s]) => `${t}="${s}"`).join(",");
381
+ }
382
+ }
383
+ class J {
384
+ metric;
385
+ defaultLabels;
386
+ constructor(e, t) {
387
+ this.metric = e, this.defaultLabels = t;
388
+ }
389
+ observe(e, t = {}) {
390
+ const s = this.labelsToString({ ...this.defaultLabels, ...t }), i = `${s}|sum`, r = this.metric.values.get(i) || 0;
391
+ this.metric.values.set(i, r + e);
392
+ const a = `${s}|count`, c = this.metric.values.get(a) || 0;
393
+ this.metric.values.set(a, c + 1);
394
+ for (const u of this.metric.buckets || [])
395
+ if (e <= u) {
396
+ const h = `${s}|${u}`, l = this.metric.values.get(h) || 0;
397
+ this.metric.values.set(h, l + 1);
398
+ }
399
+ }
400
+ startTimer(e = {}) {
401
+ const t = process.hrtime.bigint();
402
+ return () => {
403
+ const s = process.hrtime.bigint(), i = Number(s - t) / 1e9;
404
+ this.observe(i, e);
405
+ };
406
+ }
407
+ labelsToString(e) {
408
+ return Object.entries(e).map(([t, s]) => `${t}="${s}"`).join(",");
409
+ }
410
+ }
411
+ const $ = new Q(), V = $.counter(
412
+ "http_requests_total",
413
+ "Total number of HTTP requests"
414
+ ), Z = $.histogram(
415
+ "http_request_duration_seconds",
416
+ "HTTP request duration in seconds"
417
+ ), q = $.histogram(
418
+ "http_request_size_bytes",
419
+ "HTTP request size in bytes",
420
+ [100, 1e3, 1e4, 1e5, 1e6]
421
+ ), ee = $.histogram(
422
+ "http_response_size_bytes",
423
+ "HTTP response size in bytes",
424
+ [100, 1e3, 1e4, 1e5, 1e6]
425
+ );
426
+ function ye() {
427
+ return (n, e, t) => {
428
+ const s = Z.startTimer({
429
+ method: n.method,
430
+ path: n.route?.path || n.path
431
+ }), i = parseInt(n.get("content-length") || "0", 10);
432
+ i > 0 && q.observe(i, { method: n.method }), e.on("finish", () => {
433
+ s(), V.inc({
434
+ method: n.method,
435
+ path: n.route?.path || n.path,
436
+ status: e.statusCode.toString()
437
+ });
438
+ const r = parseInt(e.get("content-length") || "0", 10);
439
+ r > 0 && ee.observe(r, {
440
+ method: n.method,
441
+ status: e.statusCode.toString()
442
+ });
443
+ }), t();
444
+ };
445
+ }
446
+ function we(n = $) {
447
+ return (e, t) => {
448
+ t.set("Content-Type", "text/plain; version=0.0.4; charset=utf-8"), t.send(n.getMetrics());
449
+ };
450
+ }
451
+ const R = P("upload");
452
+ function te(n) {
453
+ const e = n.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
454
+ return e ? e[1] || e[2] : null;
455
+ }
456
+ function se(n, e) {
457
+ const t = [], s = Buffer.from(`--${e}`), i = Buffer.from(`--${e}--`);
458
+ let r = n.indexOf(s) + s.length + 2;
459
+ for (; r < n.length; ) {
460
+ const a = n.indexOf(s, r);
461
+ if (a === -1) break;
462
+ const c = n.slice(r, a - 2), u = c.indexOf(`\r
463
+ \r
464
+ `);
465
+ if (u !== -1) {
466
+ 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);
467
+ f && t.push({
468
+ fieldName: f[1],
469
+ filename: f[2],
470
+ mimeType: m ? m[1] : "application/octet-stream",
471
+ encoding: p ? p[1] : "7bit",
472
+ data: [l]
473
+ });
474
+ }
475
+ if (r = a + s.length + 2, n.slice(a, a + i.length).equals(i))
476
+ break;
477
+ }
478
+ return t;
479
+ }
480
+ function ne(n) {
481
+ const e = z(n), t = Date.now(), s = Math.random().toString(36).substring(2, 8);
482
+ return `${t}-${s}${e}`;
483
+ }
484
+ function be(n = {}) {
485
+ const {
486
+ dest: e = "./uploads",
487
+ limits: t = {},
488
+ allowedMimeTypes: s,
489
+ allowedExtensions: i,
490
+ filename: r = ne,
491
+ storage: a = "disk",
492
+ onFileBegin: c,
493
+ onFileEnd: u,
494
+ onError: h
495
+ } = n, {
496
+ fileSize: l = 10 * 1024 * 1024,
497
+ // 10MB default
498
+ files: f = 10,
499
+ fields: m = 100,
500
+ fieldSize: p = 1024 * 1024
501
+ // 1MB default
502
+ } = t;
503
+ return a === "disk" && !F(e) && I(e, { recursive: !0 }), async (o, g, w) => {
504
+ const M = o.get("content-type") || "";
505
+ if (!M.includes("multipart/form-data"))
506
+ return w();
507
+ const _ = te(M);
508
+ if (!_)
509
+ return g.status(L.BAD_REQUEST).json({
510
+ success: !1,
511
+ error: { message: "Missing boundary in content-type" }
512
+ });
513
+ const C = [];
514
+ let H = 0;
515
+ o.on("data", (y) => {
516
+ if (H += y.length, H > l * f) {
517
+ o.destroy();
518
+ return;
519
+ }
520
+ C.push(y);
521
+ }), o.on("end", async () => {
522
+ try {
523
+ const y = Buffer.concat(C), T = se(y, _), S = [], D = {};
524
+ let j = 0, B = 0;
525
+ for (const d of T)
526
+ if (d.filename) {
527
+ if (j >= f)
528
+ throw new Error(`Too many files. Maximum: ${f}`);
529
+ const b = Buffer.concat(d.data);
530
+ if (b.length > l)
531
+ throw new Error(`File too large: ${d.filename}. Maximum: ${l} bytes`);
532
+ if (s && !s.includes(d.mimeType))
533
+ throw new Error(`Invalid file type: ${d.mimeType}`);
534
+ if (i) {
535
+ const v = z(d.filename).toLowerCase().slice(1);
536
+ if (!i.includes(v))
537
+ throw new Error(`Invalid file extension: ${v}`);
538
+ }
539
+ const k = {
540
+ fieldName: d.fieldName,
541
+ originalName: d.filename,
542
+ mimeType: d.mimeType,
543
+ size: b.length,
544
+ encoding: d.encoding
545
+ };
546
+ if (c?.(d.fieldName, k), a === "disk") {
547
+ const v = r(d.filename, d.mimeType), N = G(e, v);
548
+ await new Promise((O, U) => {
549
+ const x = A(N);
550
+ x.write(b), x.end(), x.on("finish", O), x.on("error", U);
551
+ }), k.path = N;
552
+ } else
553
+ k.buffer = b;
554
+ u?.(d.fieldName, k), S.push(k), j++;
555
+ } else {
556
+ if (B >= m)
557
+ throw new Error(`Too many fields. Maximum: ${m}`);
558
+ const b = Buffer.concat(d.data).toString();
559
+ if (b.length > p)
560
+ throw new Error(`Field too large: ${d.fieldName}`);
561
+ D[d.fieldName] = b, B++;
562
+ }
563
+ o.files = S, o.file = S[0], o.body = { ...o.body, ...D }, R.debug(`Uploaded ${S.length} files`), w();
564
+ } catch (y) {
565
+ const T = y;
566
+ R.error(`Upload error: ${T.message}`), h?.(T), g.status(L.BAD_REQUEST).json({
567
+ success: !1,
568
+ error: { message: T.message }
569
+ });
570
+ }
571
+ }), o.on("error", (y) => {
572
+ R.error("Request error:", y), h?.(y), w(y);
573
+ });
574
+ };
575
+ }
576
+ function Te(n, e) {
577
+ return e.includes(n.mimeType);
578
+ }
579
+ function ke(n) {
580
+ return {
581
+ "image/jpeg": "jpg",
582
+ "image/png": "png",
583
+ "image/gif": "gif",
584
+ "image/webp": "webp",
585
+ "image/svg+xml": "svg",
586
+ "application/pdf": "pdf",
587
+ "application/json": "json",
588
+ "text/plain": "txt",
589
+ "text/csv": "csv",
590
+ "application/zip": "zip",
591
+ "application/x-rar-compressed": "rar"
592
+ }[n] || "bin";
593
+ }
594
+ export {
595
+ Y as C,
596
+ W as G,
597
+ J as H,
598
+ Q as M,
599
+ ce as R,
600
+ fe as a,
601
+ de as b,
602
+ ge as c,
603
+ pe as d,
604
+ $ as e,
605
+ V as f,
606
+ Z as g,
607
+ he as h,
608
+ q as i,
609
+ ee as j,
610
+ ye as k,
611
+ we as l,
612
+ me as m,
613
+ ke as n,
614
+ le as r,
615
+ ue as s,
616
+ be as u,
617
+ Te as v
618
+ };
619
+ //# sourceMappingURL=upload-DUjQiuq7.mjs.map