@h3ravel/http 11.4.3 → 11.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.
package/dist/index.cjs CHANGED
@@ -1,4 +1,8 @@
1
1
  const require_chunk = require('./chunk-BncF-t-1.cjs');
2
+ let fs_promises = require("fs/promises");
3
+ fs_promises = require_chunk.__toESM(fs_promises);
4
+ let __h3ravel_support = require("@h3ravel/support");
5
+ __h3ravel_support = require_chunk.__toESM(__h3ravel_support);
2
6
  let __h3ravel_musket = require("@h3ravel/musket");
3
7
  __h3ravel_musket = require_chunk.__toESM(__h3ravel_musket);
4
8
  let __h3ravel_shared = require("@h3ravel/shared");
@@ -35,9 +39,696 @@ let node_buffer = require("node:buffer");
35
39
  node_buffer = require_chunk.__toESM(node_buffer);
36
40
  let h3 = require("h3");
37
41
  h3 = require_chunk.__toESM(h3);
38
- let __h3ravel_support = require("@h3ravel/support");
39
- __h3ravel_support = require_chunk.__toESM(__h3ravel_support);
40
42
 
43
+ //#region src/Exceptions/BadRequestException.ts
44
+ var BadRequestException = class extends Error {
45
+ constructor(message) {
46
+ super(message);
47
+ this.name = "BadRequestException";
48
+ }
49
+ };
50
+
51
+ //#endregion
52
+ //#region src/Exceptions/UnexpectedValueException.ts
53
+ var UnexpectedValueException = class extends Error {
54
+ constructor(message) {
55
+ super(message);
56
+ this.name = "UnexpectedValueException";
57
+ }
58
+ };
59
+
60
+ //#endregion
61
+ //#region src/Bags/ParamBag.ts
62
+ /**
63
+ * ParamBag is a container for key/value pairs
64
+ * for Node/H3 environments.
65
+ */
66
+ var ParamBag = class {
67
+ constructor(parameters = {}, event) {
68
+ this.parameters = parameters;
69
+ this.event = event;
70
+ this.parameters = { ...parameters };
71
+ }
72
+ /**
73
+ * Returns the parameters.
74
+ * @
75
+ * @param key The name of the parameter to return or null to get them all
76
+ *
77
+ * @throws BadRequestException if the value is not an array
78
+ */
79
+ all(key) {
80
+ if (key === null) return { ...this.parameters };
81
+ const value = key ? this.parameters[key] : void 0;
82
+ if (value && typeof value !== "object") throw new BadRequestException(`Unexpected value for parameter "${key}": expected object, got ${typeof value}`);
83
+ return value || {};
84
+ }
85
+ get(key, defaultValue) {
86
+ return key in this.parameters ? this.parameters[key] : defaultValue;
87
+ }
88
+ set(key, value) {
89
+ this.parameters[key] = value;
90
+ }
91
+ /**
92
+ * Returns true if the parameter is defined.
93
+ *
94
+ * @param key
95
+ */
96
+ has(key) {
97
+ return Object.prototype.hasOwnProperty.call(this.parameters, key);
98
+ }
99
+ /**
100
+ * Removes a parameter.
101
+ *
102
+ * @param key
103
+ */
104
+ remove(key) {
105
+ delete this.parameters[key];
106
+ }
107
+ /**
108
+ *
109
+ * Returns the parameter as string.
110
+ *
111
+ * @param key
112
+ * @param defaultValue
113
+ * @throws UnexpectedValueException if the value cannot be converted to string
114
+ * @returns
115
+ */
116
+ getString(key, defaultValue = "") {
117
+ const value = this.get(key, defaultValue);
118
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
119
+ throw new UnexpectedValueException(`Parameter "${key}" cannot be converted to string`);
120
+ }
121
+ /**
122
+ * Returns the parameter value converted to integer.
123
+ *
124
+ * @param key
125
+ * @param defaultValue
126
+ * @throws UnexpectedValueException if the value cannot be converted to integer
127
+ */
128
+ getInt(key, defaultValue = 0) {
129
+ const value = parseInt(this.get(key, defaultValue), 10);
130
+ if (isNaN(value)) throw new Error(`Parameter "${key}" is not an integer`);
131
+ return value;
132
+ }
133
+ /**
134
+ * Returns the parameter value converted to boolean.
135
+ *
136
+ * @param key
137
+ * @param defaultValue
138
+ * @throws UnexpectedValueException if the value cannot be converted to a boolean
139
+ */
140
+ getBoolean(key, defaultValue = false) {
141
+ const value = this.get(key, defaultValue);
142
+ if (typeof value === "boolean") return value;
143
+ if ([
144
+ "1",
145
+ "true",
146
+ "yes"
147
+ ].includes(String(value).toLowerCase())) return true;
148
+ if ([
149
+ "0",
150
+ "false",
151
+ "no"
152
+ ].includes(String(value).toLowerCase())) return false;
153
+ throw new Error(`Parameter "${key}" cannot be converted to boolean`);
154
+ }
155
+ /**
156
+ * Returns the alphabetic characters of the parameter value.
157
+ *
158
+ * @param key
159
+ * @param defaultValue
160
+ * @throws UnexpectedValueException if the value cannot be converted to string
161
+ */
162
+ getAlpha(key, defaultValue = "") {
163
+ return this.getString(key, defaultValue).replace(/[^a-z]/gi, "");
164
+ }
165
+ /**
166
+ * Returns the alphabetic characters and digits of the parameter value.
167
+ *
168
+ * @param key
169
+ * @param defaultValue
170
+ * @throws UnexpectedValueException if the value cannot be converted to string
171
+ */
172
+ getAlnum(key, defaultValue = "") {
173
+ return this.getString(key, defaultValue).replace(/[^a-z0-9]/gi, "");
174
+ }
175
+ /**
176
+ * Returns the digits of the parameter value.
177
+ *
178
+ * @param key
179
+ * @param defaultValue
180
+ * @throws UnexpectedValueException if the value cannot be converted to string
181
+ * @returns
182
+ **/
183
+ getDigits(key, defaultValue = "") {
184
+ return this.getString(key, defaultValue).replace(/\D/g, "");
185
+ }
186
+ /**
187
+ * Returns the parameter keys.
188
+ */
189
+ keys() {
190
+ return Object.keys(this.parameters);
191
+ }
192
+ /**
193
+ * Replaces the current parameters by a new set.
194
+ */
195
+ replace(parameters = {}) {
196
+ this.parameters = { ...parameters };
197
+ }
198
+ /**
199
+ * Adds parameters.
200
+ */
201
+ add(parameters = {}) {
202
+ this.parameters = {
203
+ ...this.parameters,
204
+ ...parameters
205
+ };
206
+ }
207
+ /**
208
+ * Returns the number of parameters.
209
+ */
210
+ count() {
211
+ return Object.keys(this.parameters).length;
212
+ }
213
+ /**
214
+ * Returns an iterator for parameters.
215
+ *
216
+ * @returns
217
+ */
218
+ [Symbol.iterator]() {
219
+ return Object.entries(this.parameters)[Symbol.iterator]();
220
+ }
221
+ };
222
+
223
+ //#endregion
224
+ //#region src/UploadedFile.ts
225
+ var UploadedFile = class UploadedFile {
226
+ constructor(originalName, mimeType, size, content) {
227
+ this.originalName = originalName;
228
+ this.mimeType = mimeType;
229
+ this.size = size;
230
+ this.content = content;
231
+ }
232
+ static createFromBase(file) {
233
+ return new UploadedFile(file.name, file.type, file.size, file);
234
+ }
235
+ /**
236
+ * Save to disk (Node environment only)
237
+ */
238
+ async moveTo(destination) {
239
+ await (0, fs_promises.writeFile)(destination, Buffer.from(await this.content.arrayBuffer()));
240
+ }
241
+ };
242
+
243
+ //#endregion
244
+ //#region src/Bags/FileBag.ts
245
+ /**
246
+ * FileBag is a container for uploaded files
247
+ * for Node/H3 environments.
248
+ */
249
+ var FileBag = class extends ParamBag {
250
+ parameters = {};
251
+ constructor(parameters = {}, event) {
252
+ super(parameters, event);
253
+ this.replace(parameters);
254
+ }
255
+ /**
256
+ * Replace all stored files.
257
+ */
258
+ replace(files = {}) {
259
+ this.parameters = {};
260
+ this.add(files);
261
+ }
262
+ /**
263
+ * Set a file or array of files.
264
+ */
265
+ set(key, value) {
266
+ if (Array.isArray(value)) this.parameters[key] = value.map((v) => v ? this.convertFileInformation(v) : null).filter(Boolean);
267
+ else if (value) this.parameters[key] = this.convertFileInformation(value);
268
+ else this.parameters[key] = null;
269
+ }
270
+ /**
271
+ * Add multiple files.
272
+ */
273
+ add(files = {}) {
274
+ for (const [key, file] of Object.entries(files)) this.set(key, file);
275
+ }
276
+ /**
277
+ * Get all stored files.
278
+ */
279
+ all() {
280
+ return this.parameters;
281
+ }
282
+ /**
283
+ * Normalize file input into UploadedFile instances.
284
+ */
285
+ convertFileInformation(file) {
286
+ if (!file) return null;
287
+ if (file instanceof UploadedFile) return file;
288
+ if (file instanceof File) return UploadedFile.createFromBase(file);
289
+ throw new TypeError("Invalid file input — expected File or UploadedFile instance.");
290
+ }
291
+ };
292
+
293
+ //#endregion
294
+ //#region src/Bags/HeaderBag.ts
295
+ /**
296
+ * HeaderBag — A container for HTTP headers
297
+ * for Node/H3 environments.
298
+ */
299
+ var HeaderBag = class HeaderBag {
300
+ static UPPER = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
301
+ static LOWER = "-abcdefghijklmnopqrstuvwxyz";
302
+ headers = {};
303
+ cacheControl = {};
304
+ constructor(headers = {}) {
305
+ for (const [key, values] of Object.entries(headers)) this.set(key, values);
306
+ }
307
+ /**
308
+ * Returns all headers as string (for debugging / toString)
309
+ *
310
+ * @returns
311
+ */
312
+ toString() {
313
+ const headers = this.all();
314
+ if (!Object.keys(headers).length) return "";
315
+ const sortedKeys = Object.keys(headers).sort();
316
+ const max = Math.max(...sortedKeys.map((k) => k.length)) + 1;
317
+ let content = "";
318
+ for (const name of sortedKeys) {
319
+ const values = headers[name] ?? [];
320
+ const displayName = name.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("-");
321
+ for (const value of values) content += `${displayName + ":"}`.padEnd(max + 1, " ") + `${value ?? ""}\r\n`;
322
+ }
323
+ return content;
324
+ }
325
+ /**
326
+ * Returns all headers or specific header list
327
+ *
328
+ * @param key
329
+ * @returns
330
+ */
331
+ all(key) {
332
+ if (key !== void 0) return this.headers[this.normalizeKey(key)] ?? [];
333
+ return this.headers;
334
+ }
335
+ /**
336
+ * Returns header keys
337
+ *
338
+ * @returns
339
+ */
340
+ keys() {
341
+ return Object.keys(this.headers);
342
+ }
343
+ /**
344
+ * Replace all headers with new set
345
+ *
346
+ * @param headers
347
+ */
348
+ replace(headers = {}) {
349
+ this.headers = {};
350
+ this.add(headers);
351
+ }
352
+ /**
353
+ * Add multiple headers
354
+ *
355
+ * @param headers
356
+ */
357
+ add(headers) {
358
+ for (const [key, values] of Object.entries(headers)) this.set(key, values);
359
+ }
360
+ /**
361
+ * Returns first header value by name or default
362
+ *
363
+ * @param key
364
+ * @param defaultValue
365
+ * @returns
366
+ */
367
+ get(key, defaultValue = null) {
368
+ const headers = this.all(key);
369
+ if (!headers.length) return defaultValue;
370
+ return headers[0];
371
+ }
372
+ /**
373
+ * Sets a header by name.
374
+ *
375
+ * @param replace Whether to replace existing values (default true)
376
+ */
377
+ set(key, values, replace = true) {
378
+ const normalized = this.normalizeKey(key);
379
+ if (Array.isArray(values)) {
380
+ const valList = values.map((v) => v === void 0 ? null : v);
381
+ if (replace || !this.headers[normalized]) this.headers[normalized] = valList;
382
+ else this.headers[normalized].push(...valList);
383
+ } else {
384
+ const val = values === void 0 ? null : values;
385
+ if (replace || !this.headers[normalized]) this.headers[normalized] = [val];
386
+ else this.headers[normalized].push(val);
387
+ }
388
+ if (normalized === "cache-control") this.cacheControl = this.parseCacheControl((this.headers[normalized] ?? []).join(", "));
389
+ }
390
+ /**
391
+ * Returns true if header exists
392
+ *
393
+ * @param key
394
+ * @returns
395
+ */
396
+ has(key) {
397
+ return Object.prototype.hasOwnProperty.call(this.headers, this.normalizeKey(key));
398
+ }
399
+ /**
400
+ * Returns true if header contains value
401
+ *
402
+ * @param key
403
+ * @param value
404
+ * @returns
405
+ */
406
+ contains(key, value) {
407
+ return this.all(key).includes(value);
408
+ }
409
+ /**
410
+ * Removes a header
411
+ *
412
+ * @param key
413
+ */
414
+ remove(key) {
415
+ const normalized = this.normalizeKey(key);
416
+ delete this.headers[normalized];
417
+ if (normalized === "cache-control") this.cacheControl = {};
418
+ }
419
+ /**
420
+ * Returns parsed date from header
421
+ *
422
+ * @param key
423
+ * @param defaultValue
424
+ * @returns
425
+ */
426
+ getDate(key, defaultValue = null) {
427
+ const value = this.get(key);
428
+ if (!value) return defaultValue ? new Date(defaultValue) : null;
429
+ const parsed = new Date(value);
430
+ if (isNaN(parsed.getTime())) throw new Error(`The "${key}" HTTP header is not parseable (${value}).`);
431
+ return parsed;
432
+ }
433
+ /**
434
+ * Adds a Cache-Control directive
435
+ *
436
+ * @param key
437
+ * @param value
438
+ */
439
+ addCacheControlDirective(key, value = true) {
440
+ this.cacheControl[key] = value;
441
+ this.set("Cache-Control", this.getCacheControlHeader());
442
+ }
443
+ /**
444
+ * Returns true if Cache-Control directive is defined
445
+ *
446
+ * @param key
447
+ * @returns
448
+ */
449
+ hasCacheControlDirective(key) {
450
+ return Object.prototype.hasOwnProperty.call(this.cacheControl, key);
451
+ }
452
+ /**
453
+ * Returns a Cache-Control directive value by name
454
+ *
455
+ * @param key
456
+ * @returns
457
+ */
458
+ getCacheControlDirective(key) {
459
+ return this.cacheControl[key] ?? null;
460
+ }
461
+ /**
462
+ * Removes a Cache-Control directive
463
+ *
464
+ * @param key
465
+ * @returns
466
+ */
467
+ removeCacheControlDirective(key) {
468
+ delete this.cacheControl[key];
469
+ this.set("Cache-Control", this.getCacheControlHeader());
470
+ }
471
+ /**
472
+ * Number of headers
473
+ *
474
+ * @param key
475
+ * @returns
476
+ */
477
+ count() {
478
+ return Object.keys(this.headers).length;
479
+ }
480
+ /**
481
+ * Normalize header name to lowercase with hyphens
482
+ *
483
+ * @param key
484
+ * @returns
485
+ */
486
+ normalizeKey(key) {
487
+ return key.replace(/[A-Z_]/g, (ch) => {
488
+ const idx = HeaderBag.UPPER.indexOf(ch);
489
+ return idx === -1 ? ch : HeaderBag.LOWER[idx];
490
+ }).toLowerCase();
491
+ }
492
+ /**
493
+ * Generates Cache-Control header string
494
+ *
495
+ * @param header
496
+ * @returns
497
+ */
498
+ getCacheControlHeader() {
499
+ return Object.entries(this.cacheControl).sort(([a$1], [b]) => a$1.localeCompare(b)).map(([k, v]) => v === true ? k : v === false ? "" : `${k}=${v}`).filter(Boolean).join(", ");
500
+ }
501
+ /**
502
+ * Parses Cache-Control header
503
+ *
504
+ * @param header
505
+ * @returns
506
+ */
507
+ parseCacheControl(header) {
508
+ const directives = {};
509
+ const parts = header.split(",").map((p) => p.trim()).filter(Boolean);
510
+ for (const part of parts) {
511
+ const [key, val] = part.split("=", 2);
512
+ directives[key.trim()] = val !== void 0 ? val.trim() : true;
513
+ }
514
+ return directives;
515
+ }
516
+ /**
517
+ * Iterator support
518
+ * @returns
519
+ */
520
+ [Symbol.iterator]() {
521
+ return Object.entries(this.headers)[Symbol.iterator]();
522
+ }
523
+ };
524
+
525
+ //#endregion
526
+ //#region src/Bags/InputBag.ts
527
+ /**
528
+ * InputBag is a container for user input values
529
+ * (e.g., query params, body, cookies)
530
+ * for Node/H3 environments.
531
+ */
532
+ var InputBag = class extends ParamBag {
533
+ constructor(inputs = {}, event) {
534
+ super(inputs, event);
535
+ this.add(inputs);
536
+ }
537
+ /**
538
+ * Returns a scalar input value by name.
539
+ *
540
+ * @param key
541
+ * @param defaultValue
542
+ * @throws BadRequestException if the input contains a non-scalar value
543
+ * @returns
544
+ */
545
+ get(key, defaultValue = null) {
546
+ if (defaultValue !== null && typeof defaultValue !== "string" && typeof defaultValue !== "number" && typeof defaultValue !== "boolean") throw new TypeError(`Expected a scalar value as 2nd argument to get(), got ${typeof defaultValue}`);
547
+ const value = __h3ravel_support.Obj.get(this.parameters, key, defaultValue);
548
+ if (value !== null && typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") throw new BadRequestException(`Input value "${key}" contains a non-scalar value.`);
549
+ return value;
550
+ }
551
+ /**
552
+ * Replaces all current input values.
553
+ *
554
+ * @param inputs
555
+ * @returns
556
+ */
557
+ replace(inputs = {}) {
558
+ this.parameters = {};
559
+ this.add(inputs);
560
+ }
561
+ /**
562
+ * Adds multiple input values.
563
+ *
564
+ * @param inputs
565
+ * @returns
566
+ */
567
+ add(inputs = {}) {
568
+ Object.entries(inputs).forEach(([key, value]) => this.set(key, value));
569
+ }
570
+ /**
571
+ * Sets an input by name.
572
+ *
573
+ * @param key
574
+ * @param value
575
+ * @throws TypeError if value is not scalar or array
576
+ * @returns
577
+ */
578
+ set(key, value) {
579
+ if (value !== null && typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean" && !Array.isArray(value) && typeof value !== "object") throw new TypeError(`Expected scalar, array, object, or null as value for set(), got ${typeof value}`);
580
+ this.parameters[key] = value;
581
+ }
582
+ /**
583
+ * Returns true if a key exists.
584
+ *
585
+ * @param key
586
+ * @returns
587
+ */
588
+ has(key) {
589
+ return Object.prototype.hasOwnProperty.call(this.parameters, key);
590
+ }
591
+ /**
592
+ * Returns all parameters.
593
+ *
594
+ * @returns
595
+ */
596
+ all() {
597
+ return { ...this.parameters };
598
+ }
599
+ /**
600
+ * Converts a parameter value to string.
601
+ *
602
+ * @param key
603
+ * @param defaultValue
604
+ * @throws BadRequestException if input contains a non-scalar value
605
+ * @returns
606
+ */
607
+ getString(key, defaultValue = "") {
608
+ const value = this.get(key, defaultValue);
609
+ return String(value ?? "");
610
+ }
611
+ /**
612
+ * Filters input value with a predicate.
613
+ * Mimics PHP’s filter_var() in spirit, but simpler.
614
+ *
615
+ * @param key
616
+ * @param defaultValue
617
+ * @param filterFn
618
+ * @throws BadRequestException if validation fails
619
+ * @returns
620
+ */
621
+ filter(key, defaultValue = null, filterFn) {
622
+ const value = this.has(key) ? this.parameters[key] : defaultValue;
623
+ if (Array.isArray(value)) throw new BadRequestException(`Input value "${key}" contains an array, but array filtering not allowed.`);
624
+ if (filterFn && !filterFn(value)) throw new BadRequestException(`Input value "${key}" is invalid and did not pass filter.`);
625
+ return value;
626
+ }
627
+ /**
628
+ * Returns an enum value by key.
629
+ *
630
+ * @param key
631
+ * @param EnumClass
632
+ * @param defaultValue
633
+ * @throws BadRequestException if conversion fails
634
+ * @returns
635
+ */
636
+ getEnum(key, EnumClass, defaultValue = null) {
637
+ const value = this.get(key, defaultValue);
638
+ if (value === null) return defaultValue;
639
+ if (!Object.values(EnumClass).includes(value)) throw new BadRequestException(`Input "${key}" cannot be converted to enum.`);
640
+ return value;
641
+ }
642
+ /**
643
+ * Removes a key.
644
+ *
645
+ * @param key
646
+ */
647
+ remove(key) {
648
+ delete this.parameters[key];
649
+ }
650
+ /**
651
+ * Returns all keys.
652
+ *
653
+ * @returns
654
+ */
655
+ keys() {
656
+ return Object.keys(this.parameters);
657
+ }
658
+ /**
659
+ * Returns number of parameters.
660
+ *
661
+ * @returns
662
+ */
663
+ count() {
664
+ return this.keys().length;
665
+ }
666
+ };
667
+
668
+ //#endregion
669
+ //#region src/Bags/ServerBag.ts
670
+ /**
671
+ * ServerBag — a simplified version of Symfony's ServerBag
672
+ * for Node/H3 environments.
673
+ *
674
+ * Responsible for extracting and normalizing HTTP headers
675
+ * from the incoming request.
676
+ */
677
+ var ServerBag = class extends ParamBag {
678
+ constructor(parameters = {}, event) {
679
+ super(Object.fromEntries(Object.entries(parameters).map(([k, v]) => [k.toLowerCase(), v])), event);
680
+ }
681
+ /**
682
+ * Returns all request headers, normalized to uppercase with underscores.
683
+ * Example: content-type → CONTENT_TYPE
684
+ */
685
+ getHeaders() {
686
+ const headers = {};
687
+ for (const [key, value] of Object.entries(this.parameters)) {
688
+ if (value === void 0 || value === "") continue;
689
+ switch (key) {
690
+ case "accept":
691
+ case "content-type":
692
+ case "content-length":
693
+ case "content-md5":
694
+ case "authorization":
695
+ headers[key.toUpperCase().replace(/-/g, "_")] = value;
696
+ break;
697
+ default: headers[`HTTP_${key.toUpperCase().replace(/-/g, "_")}`] = value;
698
+ }
699
+ }
700
+ if (headers["HTTP_AUTHORIZATION"] || headers["AUTHORIZATION"]) {
701
+ const auth = headers["HTTP_AUTHORIZATION"] || headers["AUTHORIZATION"] || "";
702
+ if (auth.toLowerCase().startsWith("basic ")) {
703
+ const [user, pass] = Buffer.from(auth.slice(6), "base64").toString().split(":", 2);
704
+ headers["AUTH_TYPE"] = "Basic";
705
+ headers["AUTH_USER"] = user;
706
+ headers["AUTH_PASS"] = pass;
707
+ } else if (auth.toLowerCase().startsWith("bearer ")) {
708
+ headers["AUTH_TYPE"] = "Bearer";
709
+ headers["AUTH_TOKEN"] = auth.slice(7);
710
+ } else if (auth.toLowerCase().startsWith("digest ")) {
711
+ headers["AUTH_TYPE"] = "Digest";
712
+ headers["AUTH_DIGEST"] = auth;
713
+ }
714
+ }
715
+ return headers;
716
+ }
717
+ /**
718
+ * Returns a specific header by name, case-insensitive.
719
+ */
720
+ get(name) {
721
+ return this.parameters[name.toLowerCase()];
722
+ }
723
+ /**
724
+ * Returns true if a header exists.
725
+ */
726
+ has(name) {
727
+ return name.toLowerCase() in this.parameters;
728
+ }
729
+ };
730
+
731
+ //#endregion
41
732
  //#region ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
42
733
  function isPlainObject(value) {
43
734
  if (typeof value !== "object" || value === null) return false;
@@ -10246,8 +10937,8 @@ var require_graceful_fs = /* @__PURE__ */ require_chunk.__commonJS({ "../../node
10246
10937
  }
10247
10938
  }
10248
10939
  var fs$writeFile = fs$9.writeFile;
10249
- fs$9.writeFile = writeFile;
10250
- function writeFile(path$16, data, options, cb) {
10940
+ fs$9.writeFile = writeFile$1;
10941
+ function writeFile$1(path$16, data, options, cb) {
10251
10942
  if (typeof options === "function") cb = options, options = null;
10252
10943
  return go$writeFile(path$16, data, options, cb);
10253
10944
  function go$writeFile(path$17, data$1, options$1, cb$1, startTime) {
@@ -18058,7 +18749,7 @@ var require_dumper = /* @__PURE__ */ require_chunk.__commonJS({ "../../node_modu
18058
18749
  }
18059
18750
  }
18060
18751
  }
18061
- function dump(input, options) {
18752
+ function dump$1(input, options) {
18062
18753
  options = options || {};
18063
18754
  var state = new State(options);
18064
18755
  if (!state.noRefs) getDuplicateReferences(input, state);
@@ -18066,9 +18757,9 @@ var require_dumper = /* @__PURE__ */ require_chunk.__commonJS({ "../../node_modu
18066
18757
  return "";
18067
18758
  }
18068
18759
  function safeDump(input, options) {
18069
- return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
18760
+ return dump$1(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
18070
18761
  }
18071
- module.exports.dump = dump;
18762
+ module.exports.dump = dump$1;
18072
18763
  module.exports.safeDump = safeDump;
18073
18764
  }) });
18074
18765
 
@@ -18279,6 +18970,68 @@ var FireCommand = class extends __h3ravel_musket.Command {
18279
18970
  }
18280
18971
  };
18281
18972
 
18973
+ //#endregion
18974
+ //#region src/Exceptions/SuspiciousOperationException.ts
18975
+ var SuspiciousOperationException = class extends Error {
18976
+ constructor(message) {
18977
+ super(message);
18978
+ this.name = "SuspiciousOperationException";
18979
+ }
18980
+ };
18981
+
18982
+ //#endregion
18983
+ //#region src/FormRequest.ts
18984
+ var FormRequest = class {
18985
+ dataset;
18986
+ constructor(data) {
18987
+ this.initialize(data);
18988
+ }
18989
+ /**
18990
+ * Initialize the data
18991
+ * @param data
18992
+ */
18993
+ initialize(data) {
18994
+ this.dataset = {
18995
+ files: {},
18996
+ input: {}
18997
+ };
18998
+ for (const [rawKey, value] of data.entries()) {
18999
+ const key = rawKey.endsWith("[]") ? rawKey.slice(0, -2) : rawKey;
19000
+ if (value instanceof File) {
19001
+ const uploaded = value instanceof UploadedFile ? value : UploadedFile.createFromBase(value);
19002
+ if (this.dataset.files[key]) {
19003
+ const existing = this.dataset.files[key];
19004
+ if (Array.isArray(existing)) existing.push(uploaded);
19005
+ else this.dataset.files[key] = [existing, uploaded];
19006
+ } else this.dataset.files[key] = uploaded;
19007
+ } else if (this.dataset.input[key]) {
19008
+ const existing = this.dataset.input[key];
19009
+ if (Array.isArray(existing)) existing.push(value);
19010
+ else this.dataset.input[key] = [existing, value];
19011
+ } else this.dataset.input[key] = value;
19012
+ }
19013
+ }
19014
+ /**
19015
+ * Get all uploaded files
19016
+ */
19017
+ files() {
19018
+ return this.dataset.files;
19019
+ }
19020
+ /**
19021
+ * Get all input fields
19022
+ */
19023
+ input() {
19024
+ return this.dataset.input;
19025
+ }
19026
+ /**
19027
+ * Get combined input and files
19028
+ * File entries take precedence if names overlap.
19029
+ */
19030
+ all() {
19031
+ return Object.assign({}, this.dataset.input, this.dataset.files);
19032
+ }
19033
+ };
19034
+
18282
19035
  //#endregion
18283
19036
  //#region src/Middleware.ts
18284
19037
  var Middleware = class {};
@@ -18325,50 +19078,586 @@ var HttpServiceProvider = class {
18325
19078
 
18326
19079
  //#endregion
18327
19080
  //#region src/Request.ts
18328
- var Request = class {
19081
+ var Request = class Request {
19082
+ /**
19083
+ * Parsed request body
19084
+ */
19085
+ body;
19086
+ /**
19087
+ * The decoded JSON content for the request.
19088
+ */
19089
+ #json;
19090
+ #uri;
19091
+ #method = void 0;
18329
19092
  /**
18330
19093
  * Gets route parameters.
18331
19094
  * @returns An object containing route parameters.
18332
19095
  */
18333
19096
  params;
18334
19097
  /**
18335
- * Gets query parameters.
18336
- * @returns An object containing query parameters.
19098
+ * All of the converted files for the request.
19099
+ */
19100
+ convertedFiles;
19101
+ /**
19102
+ * Form data from incoming request.
19103
+ * @returns The FormRequest object.
19104
+ */
19105
+ formData;
19106
+ /**
19107
+ * Request body parameters (POST).
19108
+ *
19109
+ * @see getPayload() for portability between content types
19110
+ */
19111
+ request;
19112
+ /**
19113
+ * Query string parameters (GET).
18337
19114
  */
18338
19115
  query;
18339
19116
  /**
19117
+ * Uploaded files (FILES).
19118
+ */
19119
+ files;
19120
+ /**
19121
+ * Server and execution environment parameters
19122
+ */
19123
+ server;
19124
+ /**
19125
+ * Cookies
19126
+ */
19127
+ cookies;
19128
+ /**
19129
+ * The request attributes (parameters parsed from the PATH_INFO, ...).
19130
+ */
19131
+ attributes;
19132
+ /**
18340
19133
  * Gets the request headers.
18341
19134
  * @returns An object containing request headers.
18342
19135
  */
18343
19136
  headers;
19137
+ content = void 0;
19138
+ static formats = void 0;
19139
+ static httpMethodParameterOverride = false;
18344
19140
  /**
18345
- * The current H3 H3Event instance
19141
+ * List of Acceptable Content Types
18346
19142
  */
18347
- event;
19143
+ acceptableContentTypes = [];
18348
19144
  constructor(event, app) {
18349
- this.app = app;
18350
19145
  this.event = event;
18351
- this.query = (0, h3.getQuery)(this.event);
19146
+ this.app = app;
19147
+ }
19148
+ /**
19149
+ * Factory method to create a Request instance from an H3Event.
19150
+ */
19151
+ static async create(event, app) {
19152
+ const instance = new Request(event, app);
19153
+ await instance.setBody();
19154
+ await instance.initialize();
19155
+ globalThis.request = () => instance;
19156
+ return instance;
19157
+ }
19158
+ /**
19159
+ * Sets the parameters for this request.
19160
+ *
19161
+ * This method also re-initializes all properties.
19162
+ *
19163
+ * @param attributes
19164
+ * @param cookies The COOKIE parameters
19165
+ * @param files The FILES parameters
19166
+ * @param server The SERVER parameters
19167
+ * @param content The raw body data
19168
+ */
19169
+ async initialize() {
18352
19170
  this.params = (0, h3.getRouterParams)(this.event);
18353
- this.headers = this.event.req.headers;
19171
+ this.request = new InputBag(this.formData ? this.formData.input() : {}, this.event);
19172
+ this.query = new InputBag((0, h3.getQuery)(this.event), this.event);
19173
+ this.attributes = new ParamBag((0, h3.getRouterParams)(this.event), this.event);
19174
+ this.cookies = new InputBag((0, h3.parseCookies)(this.event), this.event);
19175
+ this.files = new FileBag(this.formData ? this.formData.files() : {}, this.event);
19176
+ this.server = new ServerBag(Object.fromEntries(this.event.req.headers.entries()), this.event);
19177
+ this.headers = new HeaderBag(this.server.getHeaders());
19178
+ this.acceptableContentTypes = [];
19179
+ this.#method = void 0;
19180
+ this.#uri = (await import(String("@h3ravel/url"))).Url.of((0, h3.getRequestURL)(this.event).toString(), this.app);
19181
+ }
19182
+ async setBody() {
19183
+ const type = this.event.req.headers.get("content-type") || "";
19184
+ if (this.body) return;
19185
+ if (type.includes("application/json")) {
19186
+ this.body = await this.event.req.json().catch(() => ({}));
19187
+ this.content = this.body;
19188
+ } else if (type.includes("form-data") || type.includes("x-www-form-urlencoded")) {
19189
+ this.formData = new FormRequest(await this.event.req.formData());
19190
+ this.body = this.formData.all();
19191
+ this.content = JSON.stringify(this.formData.input());
19192
+ } else if (type.startsWith("text/")) {
19193
+ this.body = await this.event.req.text();
19194
+ this.content = this.body;
19195
+ } else {
19196
+ const content = this.event.req.body;
19197
+ this.content = content;
19198
+ if (content instanceof ReadableStream) {
19199
+ const reader = content.getReader();
19200
+ const chunks = [];
19201
+ let done = false;
19202
+ while (!done) {
19203
+ const { value, done: isDone } = await reader.read();
19204
+ if (value) chunks.push(value);
19205
+ done = isDone;
19206
+ }
19207
+ this.body = new TextDecoder().decode(new Uint8Array(chunks.flatMap((chunk) => Array.from(chunk))));
19208
+ } else this.body = content;
19209
+ }
18354
19210
  }
18355
19211
  /**
18356
- * Get all input data (query + body).
19212
+ * Retrieve all data from the instance (query + body).
19213
+ */
19214
+ all(keys) {
19215
+ const input = __h3ravel_support.Obj.deepMerge({}, this.input(), this.allFiles());
19216
+ if (!keys) return input;
19217
+ const results = {};
19218
+ const list = Array.isArray(keys) ? keys : [keys];
19219
+ for (const key of list) (0, __h3ravel_support.data_set)(results, key, __h3ravel_support.Obj.get(input, key));
19220
+ return results;
19221
+ }
19222
+ /**
19223
+ * Retrieve an input item from the request.
19224
+ *
19225
+ * @param key
19226
+ * @param defaultValue
19227
+ * @returns
18357
19228
  */
18358
- async all() {
18359
- let data = {
18360
- ...(0, h3.getRouterParams)(this.event),
18361
- ...(0, h3.getQuery)(this.event)
19229
+ input(key, defaultValue) {
19230
+ const source = {
19231
+ ...this.getInputSource().all(),
19232
+ ...this.query.all()
18362
19233
  };
18363
- if (this.event.req.method === "POST") data = Object.assign({}, data, Object.fromEntries((await this.event.req.formData()).entries()));
18364
- else if (this.event.req.method === "PUT") data = Object.fromEntries(Object.entries(await (0, h3.readBody)(this.event)));
18365
- return data;
19234
+ return key ? (0, __h3ravel_support.data_get)(source, key, defaultValue) : __h3ravel_support.Arr.except(source, ["_method"]);
19235
+ }
19236
+ /**
19237
+ * Retrieve a file from the request.
19238
+ *
19239
+ * @param key
19240
+ * @param defaultValue
19241
+ * @returns
19242
+ */
19243
+ file(key, defaultValue) {
19244
+ const source = this.allFiles();
19245
+ return key ? (0, __h3ravel_support.data_get)(source, key, defaultValue) : source;
19246
+ }
19247
+ /**
19248
+ * Get an array of all of the files on the request.
19249
+ */
19250
+ allFiles() {
19251
+ if (this.convertedFiles) return this.convertedFiles;
19252
+ const entries = Object.entries(this.files.all()).filter((e) => e[1] != null);
19253
+ const files = Object.fromEntries(entries);
19254
+ this.convertedFiles = this.convertUploadedFiles(files);
19255
+ return this.convertedFiles;
19256
+ }
19257
+ /**
19258
+ * Extract and convert uploaded files from FormData.
19259
+ */
19260
+ convertUploadedFiles(files) {
19261
+ if (!this.formData) return files;
19262
+ for (const [key, value] of Object.entries(this.formData.files())) {
19263
+ if (!(value instanceof File)) continue;
19264
+ if (key.endsWith("[]")) {
19265
+ const normalizedKey = key.slice(0, -2);
19266
+ if (!files[normalizedKey]) files[normalizedKey] = [];
19267
+ files[normalizedKey].push(UploadedFile.createFromBase(value));
19268
+ } else files[key] = UploadedFile.createFromBase(value);
19269
+ }
19270
+ return files;
19271
+ }
19272
+ /**
19273
+ * Determine if the data contains a given key.
19274
+ *
19275
+ * @param keys
19276
+ * @returns
19277
+ */
19278
+ has(keys) {
19279
+ return __h3ravel_support.Obj.has(this.all(), keys);
19280
+ }
19281
+ /**
19282
+ * Determine if the instance is missing a given key.
19283
+ */
19284
+ missing(key) {
19285
+ const keys = Array.isArray(key) ? key : [key];
19286
+ return !this.has(keys);
19287
+ }
19288
+ /**
19289
+ * Get a subset containing the provided keys with values from the instance data.
19290
+ *
19291
+ * @param keys
19292
+ * @returns
19293
+ */
19294
+ only(keys) {
19295
+ const data = Object.entries(this.all()).filter(([key]) => keys.includes(key));
19296
+ return Object.fromEntries(data);
19297
+ }
19298
+ /**
19299
+ * Get all of the data except for a specified array of items.
19300
+ *
19301
+ * @param keys
19302
+ * @returns
19303
+ */
19304
+ except(keys) {
19305
+ const data = Object.entries(this.all()).filter(([key]) => !keys.includes(key));
19306
+ return Object.fromEntries(data);
19307
+ }
19308
+ /**
19309
+ * Merges new input data into the current request's input source.
19310
+ *
19311
+ * @param input - An object containing key-value pairs to merge.
19312
+ * @returns this - For fluent chaining.
19313
+ */
19314
+ merge(input) {
19315
+ const source = this.getInputSource();
19316
+ for (const [key, value] of Object.entries(input)) source.set(key, value);
19317
+ return this;
19318
+ }
19319
+ /**
19320
+ * Merge new input into the request's input, but only when that key is missing from the request.
19321
+ *
19322
+ * @param input
19323
+ */
19324
+ mergeIfMissing(input) {
19325
+ return this.merge(Object.fromEntries(Object.entries(input).filter(([key]) => this.missing(key))));
19326
+ }
19327
+ /**
19328
+ * Get the keys for all of the input and files.
19329
+ */
19330
+ keys() {
19331
+ return [...Object.keys(this.input()), ...this.files.keys()];
19332
+ }
19333
+ /**
19334
+ * Determine if the request is sending JSON.
19335
+ *
19336
+ * @return bool
19337
+ */
19338
+ isJson() {
19339
+ return __h3ravel_support.Str.contains(this.getHeader("CONTENT_TYPE") ?? "", ["/json", "+json"]);
19340
+ }
19341
+ /**
19342
+ * Determine if the current request probably expects a JSON response.
19343
+ *
19344
+ * @returns
19345
+ */
19346
+ expectsJson() {
19347
+ return __h3ravel_support.Str.contains(this.getHeader("Accept") ?? "", "application/json");
19348
+ }
19349
+ /**
19350
+ * Determine if the current request is asking for JSON.
19351
+ *
19352
+ * @returns
19353
+ */
19354
+ wantsJson() {
19355
+ const acceptable = this.getAcceptableContentTypes();
19356
+ return !!acceptable[0] && __h3ravel_support.Str.contains(acceptable[0].toLowerCase(), ["/json", "+json"]);
19357
+ }
19358
+ /**
19359
+ * Gets a list of content types acceptable by the client browser in preferable order.
19360
+ * @returns {string[]}
19361
+ */
19362
+ getAcceptableContentTypes() {
19363
+ if (this.acceptableContentTypes.length > 0) return this.acceptableContentTypes;
19364
+ const accept = this.getHeader("accept");
19365
+ if (!accept) return [];
19366
+ return this.acceptableContentTypes = accept.split(",").map((type) => type.trim()).map((type) => type.split(";")[0]).filter(Boolean);
19367
+ }
19368
+ /**
19369
+ * Determine if the request is the result of a PJAX call.
19370
+ *
19371
+ * @return bool
19372
+ */
19373
+ pjax() {
19374
+ return this.headers.get("X-PJAX") == true;
19375
+ }
19376
+ /**
19377
+ * Returns true if the request is an XMLHttpRequest (AJAX).
19378
+ *
19379
+ * @alias isXmlHttpRequest()
19380
+ * @returns {boolean}
19381
+ */
19382
+ ajax() {
19383
+ return this.isXmlHttpRequest();
19384
+ }
19385
+ /**
19386
+ * Returns true if the request is an XMLHttpRequest (AJAX).
19387
+ */
19388
+ isXmlHttpRequest() {
19389
+ return "XMLHttpRequest" === this.getHeader("X-Requested-With");
19390
+ }
19391
+ /**
19392
+ * Returns the value of the requested header.
19393
+ */
19394
+ getHeader(name) {
19395
+ return this.headers.get(name);
19396
+ }
19397
+ /**
19398
+ * Checks if the request method is of specified type.
19399
+ *
19400
+ * @param method Uppercase request method (GET, POST etc)
19401
+ */
19402
+ isMethod(method) {
19403
+ return this.getMethod() === method.toUpperCase();
19404
+ }
19405
+ /**
19406
+ * Checks whether or not the method is safe.
19407
+ *
19408
+ * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
19409
+ */
19410
+ isMethodSafe() {
19411
+ return [
19412
+ "GET",
19413
+ "HEAD",
19414
+ "OPTIONS",
19415
+ "TRACE"
19416
+ ].includes(this.getMethod());
19417
+ }
19418
+ /**
19419
+ * Checks whether or not the method is idempotent.
19420
+ */
19421
+ isMethodIdempotent() {
19422
+ return [
19423
+ "HEAD",
19424
+ "GET",
19425
+ "PUT",
19426
+ "DELETE",
19427
+ "TRACE",
19428
+ "OPTIONS",
19429
+ "PURGE"
19430
+ ].includes(this.getMethod());
19431
+ }
19432
+ /**
19433
+ * Checks whether the method is cacheable or not.
19434
+ *
19435
+ * @see https://tools.ietf.org/html/rfc7231#section-4.2.3
19436
+ */
19437
+ isMethodCacheable() {
19438
+ return ["GET", "HEAD"].includes(this.getMethod());
19439
+ }
19440
+ /**
19441
+ * Initializes HTTP request formats.
19442
+ */
19443
+ static initializeFormats() {
19444
+ this.formats = {
19445
+ html: ["text/html", "application/xhtml+xml"],
19446
+ txt: ["text/plain"],
19447
+ js: [
19448
+ "application/javascript",
19449
+ "application/x-javascript",
19450
+ "text/javascript"
19451
+ ],
19452
+ css: ["text/css"],
19453
+ json: ["application/json", "application/x-json"],
19454
+ jsonld: ["application/ld+json"],
19455
+ xml: [
19456
+ "text/xml",
19457
+ "application/xml",
19458
+ "application/x-xml"
19459
+ ],
19460
+ rdf: ["application/rdf+xml"],
19461
+ atom: ["application/atom+xml"],
19462
+ rss: ["application/rss+xml"],
19463
+ form: ["application/x-www-form-urlencoded", "multipart/form-data"]
19464
+ };
19465
+ }
19466
+ /**
19467
+ * Gets the request "intended" method.
19468
+ *
19469
+ * If the X-HTTP-Method-Override header is set, and if the method is a POST,
19470
+ * then it is used to determine the "real" intended HTTP method.
19471
+ *
19472
+ * The _method request parameter can also be used to determine the HTTP method,
19473
+ * but only if enableHttpMethodParameterOverride() has been called.
19474
+ *
19475
+ * The method is always an uppercased string.
19476
+ *
19477
+ * @see getRealMethod()
19478
+ */
19479
+ getMethod() {
19480
+ if (this.#method) return this.#method;
19481
+ this.#method = this.getRealMethod();
19482
+ if ("POST" !== this.#method) return this.#method;
19483
+ let method = this.event.req.headers.get("X-HTTP-METHOD-OVERRIDE");
19484
+ if (!method && Request.httpMethodParameterOverride) method = this.request.get("_method", this.query.get("_method", "POST"));
19485
+ if (typeof method !== "string") return this.#method;
19486
+ method = method.toUpperCase();
19487
+ if ([
19488
+ "GET",
19489
+ "HEAD",
19490
+ "POST",
19491
+ "PUT",
19492
+ "DELETE",
19493
+ "CONNECT",
19494
+ "OPTIONS",
19495
+ "PATCH",
19496
+ "PURGE",
19497
+ "TRACE"
19498
+ ].includes(method)) {
19499
+ this.#method = method;
19500
+ return this.#method;
19501
+ }
19502
+ if (!/^[A-Z]+$/.test(method)) throw new SuspiciousOperationException("Invalid HTTP method override.");
19503
+ this.#method = method;
19504
+ return this.#method;
19505
+ }
19506
+ /**
19507
+ * Gets the "real" request method.
19508
+ *
19509
+ * @see getMethod()
19510
+ */
19511
+ getRealMethod() {
19512
+ return this.event.req.method.toUpperCase();
19513
+ }
19514
+ /**
19515
+ * Get the client IP address.
19516
+ */
19517
+ ip() {
19518
+ return (0, h3.getRequestIP)(this.event);
19519
+ }
19520
+ /**
19521
+ * Get a URI instance for the request.
19522
+ */
19523
+ uri() {
19524
+ return this.#uri;
19525
+ }
19526
+ /**
19527
+ * Get the full URL for the request.
19528
+ */
19529
+ fullUrl() {
19530
+ return this.event.req.url;
19531
+ }
19532
+ /**
19533
+ * Return the Request instance.
19534
+ */
19535
+ instance() {
19536
+ return this;
19537
+ }
19538
+ /**
19539
+ * Get the request method.
19540
+ */
19541
+ method() {
19542
+ return this.getMethod();
19543
+ }
19544
+ /**
19545
+ * Get the JSON payload for the request.
19546
+ *
19547
+ * @param key
19548
+ * @param defaultValue
19549
+ * @return {InputBag}
19550
+ */
19551
+ json(key, defaultValue) {
19552
+ if (!this.#json) {
19553
+ let json = this.getContent();
19554
+ if (typeof json == "string") json = JSON.parse(json || "{}");
19555
+ this.#json = new InputBag(json, this.event);
19556
+ }
19557
+ if (!key) return this.#json;
19558
+ return __h3ravel_support.Obj.get(this.#json.all(), key, defaultValue);
19559
+ }
19560
+ /**
19561
+ * Get the input source for the request.
19562
+ *
19563
+ * @return {InputBag}
19564
+ */
19565
+ getInputSource() {
19566
+ if (this.isJson()) return this.json();
19567
+ return ["GET", "HEAD"].includes(this.getRealMethod()) ? this.query : this.request;
19568
+ }
19569
+ /**
19570
+ * Returns the request body content.
19571
+ *
19572
+ * @param asStream If true, returns a ReadableStream instead of the parsed string
19573
+ * @return {string | ReadableStream | Promise<string | ReadableStream>}
19574
+ */
19575
+ getContent(asStream = false) {
19576
+ let content = this.body;
19577
+ if (content !== void 0 && content !== null) {
19578
+ if (asStream) {
19579
+ if (content instanceof ReadableStream) return content;
19580
+ const encoder = new TextEncoder();
19581
+ return new ReadableStream({ start(controller) {
19582
+ controller.enqueue(encoder.encode(String(content)));
19583
+ controller.close();
19584
+ } });
19585
+ }
19586
+ if (typeof content === "string") return content;
19587
+ }
19588
+ if (asStream) return this.content;
19589
+ content = this.content;
19590
+ this.body = content;
19591
+ return content;
19592
+ }
19593
+ /**
19594
+ * Determine if the uploaded data contains a file.
19595
+ *
19596
+ * @param key
19597
+ * @return boolean
19598
+ */
19599
+ hasFile(key) {
19600
+ let files = this.file(key);
19601
+ if (!Array.isArray(files)) files = [files];
19602
+ return files.some((e) => this.isValidFile(e));
19603
+ }
19604
+ /**
19605
+ * Check that the given file is a valid file instance.
19606
+ *
19607
+ * @param file
19608
+ * @return boolean
19609
+ */
19610
+ isValidFile(file) {
19611
+ return file.content instanceof File && file.size > 0;
18366
19612
  }
18367
19613
  /**
18368
- * Get a single input field from query or body.
19614
+ * Gets a "parameter" value from any bag.
19615
+ *
19616
+ * This method is mainly useful for libraries that want to provide some flexibility. If you don't need the
19617
+ * flexibility in controllers, it is better to explicitly get request parameters from the appropriate
19618
+ * public property instead (attributes, query, request).
19619
+ *
19620
+ * Order of precedence: PATH (routing placeholders or custom attributes), GET, POST
19621
+ *
19622
+ * @internal use explicit input sources instead
19623
+ */
19624
+ get(key, defaultValue) {
19625
+ const result = this.attributes.get(key, this);
19626
+ if (this !== result) return result;
19627
+ if (this.query.has(key)) return this.query.all()[key];
19628
+ if (this.request.has(key)) return this.request.all()[key];
19629
+ return defaultValue;
19630
+ }
19631
+ /**
19632
+ * Enables support for the _method request parameter to determine the intended HTTP method.
19633
+ *
19634
+ * Be warned that enabling this feature might lead to CSRF issues in your code.
19635
+ * Check that you are using CSRF tokens when required.
19636
+ * If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered
19637
+ * and used to send a "PUT" or "DELETE" request via the _method request parameter.
19638
+ * If these methods are not protected against CSRF, this presents a possible vulnerability.
19639
+ *
19640
+ * The HTTP method can only be overridden when the real HTTP method is POST.
18369
19641
  */
18370
- async input(key, defaultValue) {
18371
- return (await this.all())[key] ?? defaultValue;
19642
+ static enableHttpMethodParameterOverride() {
19643
+ this.httpMethodParameterOverride = true;
19644
+ }
19645
+ /**
19646
+ * Checks whether support for the _method request parameter is enabled.
19647
+ */
19648
+ static getHttpMethodParameterOverride() {
19649
+ return this.httpMethodParameterOverride;
19650
+ }
19651
+ /**
19652
+ * Dump the items.
19653
+ *
19654
+ * @param keys
19655
+ * @return this
19656
+ */
19657
+ dump(...keys) {
19658
+ if (keys.length > 0) this.only(keys).then(dump);
19659
+ else this.all().then(dump);
19660
+ return this;
18372
19661
  }
18373
19662
  getEvent(key) {
18374
19663
  return (0, __h3ravel_support.safeDot)(this.event, key);
@@ -18553,7 +19842,7 @@ var Response = class {
18553
19842
  }
18554
19843
  html(content) {
18555
19844
  this.applyHeaders();
18556
- return (0, h3.html)(this.event, content);
19845
+ return (0, h3.html)(content);
18557
19846
  }
18558
19847
  /**
18559
19848
  * Send a JSON response.
@@ -18574,9 +19863,9 @@ var Response = class {
18574
19863
  /**
18575
19864
  * Redirect to another URL.
18576
19865
  */
18577
- redirect(url, status = 302) {
19866
+ redirect(location, status = 302, statusText) {
18578
19867
  this.setStatusCode(status);
18579
- return (0, h3.redirect)(this.event, url, this.statusCode);
19868
+ return (0, h3.redirect)(location, this.statusCode, statusText);
18580
19869
  }
18581
19870
  /**
18582
19871
  * Apply headers before sending response.
@@ -18593,7 +19882,11 @@ var Response = class {
18593
19882
 
18594
19883
  //#endregion
18595
19884
  exports.ApiResource = ApiResource;
19885
+ exports.BadRequestException = BadRequestException;
19886
+ exports.FileBag = FileBag;
18596
19887
  exports.FireCommand = FireCommand;
19888
+ exports.FormRequest = FormRequest;
19889
+ exports.HeaderBag = HeaderBag;
18597
19890
  Object.defineProperty(exports, 'HttpContext', {
18598
19891
  enumerable: true,
18599
19892
  get: function () {
@@ -18601,8 +19894,14 @@ Object.defineProperty(exports, 'HttpContext', {
18601
19894
  }
18602
19895
  });
18603
19896
  exports.HttpServiceProvider = HttpServiceProvider;
19897
+ exports.InputBag = InputBag;
18604
19898
  exports.JsonResource = JsonResource;
18605
19899
  exports.LogRequests = LogRequests;
18606
19900
  exports.Middleware = Middleware;
19901
+ exports.ParamBag = ParamBag;
18607
19902
  exports.Request = Request;
18608
- exports.Response = Response;
19903
+ exports.Response = Response;
19904
+ exports.ServerBag = ServerBag;
19905
+ exports.SuspiciousOperationException = SuspiciousOperationException;
19906
+ exports.UnexpectedValueException = UnexpectedValueException;
19907
+ exports.UploadedFile = UploadedFile;