@d1g1tal/transportr 1.2.1 → 1.3.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.
@@ -23,38 +23,6 @@ var Transportr = (() => {
23
23
  default: () => Transportr
24
24
  });
25
25
 
26
- // node_modules/@d1g1tal/chrysalis/src/esm/object-type.js
27
- var _type = (object) => object?.constructor ?? object?.prototype?.constructor ?? globalThis[Object.prototype.toString.call(object).slice(8, -1)] ?? object;
28
- var object_type_default = _type;
29
-
30
- // node_modules/@d1g1tal/chrysalis/src/esm/object-is-empty.js
31
- var _objectIsEmpty = (object) => !!object && Object.keys(object).length === 0 && object.constructor === Object;
32
- var object_is_empty_default = _objectIsEmpty;
33
-
34
- // node_modules/@d1g1tal/chrysalis/src/esm/object-merge.js
35
- var _objectMerge = (...objects) => {
36
- const target = {};
37
- for (const source of objects) {
38
- if (object_type_default(source) != Object)
39
- return void 0;
40
- let descriptor, sourceType;
41
- for (const property of Object.getOwnPropertyNames(source)) {
42
- descriptor = Object.getOwnPropertyDescriptor(source, property);
43
- if (descriptor.enumerable) {
44
- sourceType = object_type_default(source[property]);
45
- if (sourceType == Object) {
46
- descriptor.value = object_type_default(target[property]) == Object ? _objectMerge(target[property], source[property]) : { ...source[property] };
47
- } else if (sourceType == Array) {
48
- descriptor.value = Array.isArray(target[property]) ? [.../* @__PURE__ */ new Set([...source[property], ...target[property]])] : [...source[property]];
49
- }
50
- target[property] = descriptor.value;
51
- }
52
- }
53
- }
54
- return target;
55
- };
56
- var object_merge_default = _objectMerge;
57
-
58
26
  // node_modules/@d1g1tal/collections/src/set-multi-map.js
59
27
  var SetMultiMap = class extends Map {
60
28
  /**
@@ -101,602 +69,176 @@ var Transportr = (() => {
101
69
  };
102
70
  var set_multi_map_default = SetMultiMap;
103
71
 
104
- // node_modules/@d1g1tal/media-type/src/utils.js
105
- var whitespaceCharacters = [" ", " ", "\n", "\r"];
106
- var leadingWhitespace = /^[ \t\n\r]+/u;
107
- var trailingWhitespace = /[ \t\n\r]+$/u;
108
- var httpTokenCodePoints = /^[-!#$%&'*+.^_`|~A-Za-z0-9]*$/u;
109
- var httpQuotedTokenCodePoints = /^[\t\u0020-\u007E\u0080-\u00FF]*$/u;
110
- var removeLeadingAndTrailingHTTPWhitespace = (string) => string.replace(leadingWhitespace, "").replace(trailingWhitespace, "");
111
- var removeTrailingHTTPWhitespace = (string) => string.replace(trailingWhitespace, "");
112
- var isHTTPWhitespaceChar = (char) => whitespaceCharacters.includes(char);
113
- var solelyContainsHTTPTokenCodePoints = (string) => httpTokenCodePoints.test(string);
114
- var solelyContainsHTTPQuotedStringTokenCodePoints = (string) => httpQuotedTokenCodePoints.test(string);
115
- var asciiLowercase = (string) => {
116
- let result = "";
117
- for (const [char, charCode = char.charCodeAt(0)] of string) {
118
- result += charCode >= 65 && charCode <= 90 ? String.fromCharCode(charCode + 32) : char;
72
+ // node_modules/@d1g1tal/subscribr/node_modules/@d1g1tal/collections/src/set-multi-map.js
73
+ var SetMultiMap2 = class extends Map {
74
+ /**
75
+ * Adds a new element with a specified key and value to the SetMultiMap. If an element with the same key already exists, the value will be added to the underlying {@link Set}.
76
+ *
77
+ * @param {*} key The key to set.
78
+ * @param {*} value The value to add to the SetMultiMap
79
+ * @returns {SetMultiMap} The SetMultiMap with the updated key and value.
80
+ */
81
+ set(key, value) {
82
+ super.set(key, (super.get(key) ?? /* @__PURE__ */ new Set()).add(value));
83
+ return this;
119
84
  }
120
- return result;
121
- };
122
- var collectAnHTTPQuotedString = (input, position) => {
123
- let value = "";
124
- for (let length = input.length, char; ++position < length; ) {
125
- char = input[position];
126
- if (char == "\\") {
127
- value += ++position < length ? input[position] : char;
128
- } else if (char == '"') {
129
- break;
130
- } else {
131
- value += char;
132
- }
85
+ [Symbol.toStringTag]() {
86
+ return "SetMultiMap";
133
87
  }
134
- return [value, position];
135
88
  };
136
89
 
137
- // node_modules/@d1g1tal/media-type/src/media-type-parameters.js
138
- var MediaTypeParameters = class {
139
- /** @type {Map<string, string>} */
140
- #map;
90
+ // node_modules/@d1g1tal/subscribr/src/context-event-handler.js
91
+ var ContextEventHandler = class {
92
+ #context;
93
+ #eventHandler;
141
94
  /**
142
- * Create a new MediaTypeParameters instance.
143
- *
144
- * @param {Array<Array<string>>} entries An array of [name, value] tuples.
95
+ * @param {*} context The context to bind to the event handler.
96
+ * @param {function(*): void} eventHandler The event handler to call when the event is published.
145
97
  */
146
- constructor(entries) {
147
- this.#map = new Map(entries);
98
+ constructor(context, eventHandler) {
99
+ this.#context = context;
100
+ this.#eventHandler = eventHandler;
148
101
  }
149
102
  /**
150
- * Gets the number of media type parameters.
103
+ * Call the event handler for the provided event.
151
104
  *
152
- * @returns {number} The number of media type parameters
105
+ * @param {Event} event The event to handle
106
+ * @param {*} [data] The value to be passed to the event handler as a parameter.
153
107
  */
154
- get size() {
155
- return this.#map.size;
108
+ handle(event, data) {
109
+ this.#eventHandler.call(this.#context, event, data);
110
+ }
111
+ get [Symbol.toStringTag]() {
112
+ return "ContextEventHandler";
156
113
  }
114
+ };
115
+
116
+ // node_modules/@d1g1tal/subscribr/src/subscription.js
117
+ var Subscription = class {
118
+ #eventName;
119
+ #contextEventHandler;
157
120
  /**
158
- * Gets the media type parameter value for the supplied name.
159
- *
160
- * @param {string} name The name of the media type parameter to retrieve.
161
- * @returns {string} The media type parameter value.
121
+ * @param {string} eventName The event name.
122
+ * @param {ContextEventHandler} contextEventHandler Then context event handler.
162
123
  */
163
- get(name) {
164
- return this.#map.get(asciiLowercase(String(name)));
124
+ constructor(eventName, contextEventHandler) {
125
+ this.#eventName = eventName;
126
+ this.#contextEventHandler = contextEventHandler;
165
127
  }
166
128
  /**
167
- * Indicates whether the media type parameter with the specified name exists or not.
129
+ * Gets the event name for the subscription.
168
130
  *
169
- * @param {string} name The name of the media type parameter to check.
170
- * @returns {boolean} true if the media type parameter exists, false otherwise.
131
+ * @returns {string} The event name.
171
132
  */
172
- has(name) {
173
- return this.#map.has(asciiLowercase(String(name)));
133
+ get eventName() {
134
+ return this.#eventName;
174
135
  }
175
136
  /**
176
- * Adds a new media type parameter using the specified name and value to the MediaTypeParameters.
177
- * If an parameter with the same name already exists, the parameter will be updated.
137
+ * Gets the context event handler.
178
138
  *
179
- * @param {string} name The name of the media type parameter to set.
180
- * @param {string} value The media type parameter value.
181
- * @returns {MediaTypeParameters} This instance.
139
+ * @returns {ContextEventHandler} The context event handler
182
140
  */
183
- set(name, value) {
184
- name = asciiLowercase(String(name));
185
- value = String(value);
186
- if (!solelyContainsHTTPTokenCodePoints(name)) {
187
- throw new Error(`Invalid media type parameter name "${name}": only HTTP token code points are valid.`);
188
- }
189
- if (!solelyContainsHTTPQuotedStringTokenCodePoints(value)) {
190
- throw new Error(`Invalid media type parameter value "${value}": only HTTP quoted-string token code points are valid.`);
191
- }
192
- this.#map.set(name, value);
193
- return this;
141
+ get contextEventHandler() {
142
+ return this.#contextEventHandler;
194
143
  }
195
- /**
196
- * Clears all the media type parameters.
197
- */
198
- clear() {
199
- this.#map.clear();
144
+ get [Symbol.toStringTag]() {
145
+ return "Subscription";
146
+ }
147
+ };
148
+
149
+ // node_modules/@d1g1tal/subscribr/src/subscribr.js
150
+ var Subscribr = class {
151
+ /** @type {SetMultiMap<string, ContextEventHandler>} */
152
+ #subscribers;
153
+ constructor() {
154
+ this.#subscribers = new SetMultiMap2();
200
155
  }
201
156
  /**
202
- * Removes the media type parameter using the specified name.
157
+ * Subscribe to an event
203
158
  *
204
- * @param {string} name The name of the media type parameter to delete.
205
- * @returns {boolean} true if the parameter existed and has been removed, or false if the parameter does not exist.
159
+ * @param {string} eventName The event name to subscribe to.
160
+ * @param {function(Event, *): void} eventHandler The event handler to call when the event is published.
161
+ * @param {*} [context] The context to bind to the event handler.
162
+ * @returns {Subscription} An object used to check if the subscription still exists and to unsubscribe from the event.
206
163
  */
207
- delete(name) {
208
- name = asciiLowercase(String(name));
209
- return this.#map.delete(name);
164
+ subscribe(eventName, eventHandler, context = eventHandler) {
165
+ const contextEventHandler = new ContextEventHandler(context, eventHandler);
166
+ this.#subscribers.set(eventName, contextEventHandler);
167
+ return new Subscription(eventName, contextEventHandler);
210
168
  }
211
169
  /**
212
- * Executes a provided function once per each name/value pair in the MediaTypeParameters, in insertion order.
170
+ * Unsubscribe from the event
213
171
  *
214
- * @param {function(string, string): void} callback The function called on each iteration.
215
- * @param {*} [thisArg] Optional object when binding 'this' to the callback.
172
+ * @param {Subscription} subscription The subscription to unsubscribe.
173
+ * @param {string} subscription.eventName The event name to subscribe to.
174
+ * @param {ContextEventHandler} subscription.contextEventHandler The event handler to call when the event is published.
175
+ * @returns {boolean} true if eventListener has been removed successfully. false if the value is not found or if the value is not an object.
216
176
  */
217
- forEach(callback, thisArg) {
218
- this.#map.forEach(callback, thisArg);
177
+ unsubscribe({ eventName, contextEventHandler }) {
178
+ const contextEventHandlers = this.#subscribers.get(eventName);
179
+ const removed = contextEventHandlers?.delete(contextEventHandler);
180
+ if (removed && contextEventHandlers.size == 0) {
181
+ this.#subscribers.delete(eventName);
182
+ }
183
+ return removed;
219
184
  }
220
185
  /**
221
- * Returns an iterable of parameter names.
186
+ * Publish an event
222
187
  *
223
- * @returns {IterableIterator<string>} The {@link IterableIterator} of media type parameter names.
188
+ * @param {string} eventName The name of the event.
189
+ * @param {Event} event The event to be handled.
190
+ * @param {*} [data] The value to be passed to the event handler as a parameter.
224
191
  */
225
- keys() {
226
- return this.#map.keys();
192
+ publish(eventName, event = new CustomEvent(eventName), data) {
193
+ if (data == null && !(event instanceof Event)) {
194
+ [data, event] = [event, new CustomEvent(eventName)];
195
+ }
196
+ this.#subscribers.get(eventName)?.forEach((contextEventHandler) => contextEventHandler.handle(event, data));
227
197
  }
228
198
  /**
229
- * Returns an iterable of parameter values.
199
+ * Check if the event and handler are subscribed.
230
200
  *
231
- * @returns {IterableIterator<string>} The {@link IterableIterator} of media type parameter values.
201
+ * @param {Subscription} subscription The subscription object.
202
+ * @param {string} subscription.eventName The name of the event to check.
203
+ * @param {ContextEventHandler} subscription.contextEventHandler The event handler to check.
204
+ * @returns {boolean} true if the event name and handler are subscribed, false otherwise.
232
205
  */
233
- values() {
234
- return this.#map.values();
206
+ isSubscribed({ eventName, contextEventHandler }) {
207
+ return this.#subscribers.get(eventName)?.has(contextEventHandler);
235
208
  }
209
+ get [Symbol.toStringTag]() {
210
+ return "Subscribr";
211
+ }
212
+ };
213
+
214
+ // src/http-error.js
215
+ var HttpError = class extends Error {
216
+ /** @type {ResponseBody} */
217
+ #entity;
218
+ /** @type {ResponseStatus} */
219
+ #responseStatus;
236
220
  /**
237
- * Returns an iterable of name, value pairs for every parameter entry in the media type parameters.
238
- *
239
- * @returns {IterableIterator<Array<Array<string>>>} The media type parameter entries.
221
+ * @param {string} [message] The error message.
222
+ * @param {HttpErrorOptions} [httpErrorOptions] The http error options.
223
+ * @param {any} [httpErrorOptions.cause] The cause of the error.
224
+ * @param {ResponseStatus} [httpErrorOptions.status] The response status.
225
+ * @param {ResponseBody} [httpErrorOptions.entity] The error entity from the server, if any.
240
226
  */
241
- entries() {
242
- return this.#map.entries();
227
+ constructor(message, { cause, status, entity }) {
228
+ super(message, { cause });
229
+ this.#entity = entity;
230
+ this.#responseStatus = status;
243
231
  }
244
232
  /**
245
- * A method that returns the default iterator for the {@link MediaTypeParameters}. Called by the semantics of the for-of statement.
233
+ * It returns the value of the private variable #entity.
246
234
  *
247
- * @returns {Iterator<string, string, undefined>} The {@link Symbol.iterator} for the media type parameters.
235
+ * @returns {ResponseBody} The entity property of the class.
248
236
  */
249
- [Symbol.iterator]() {
250
- return this.#map[Symbol.iterator]();
237
+ get entity() {
238
+ return this.#entity;
251
239
  }
252
240
  /**
253
- * Returns a string representation of the media type parameters.
254
- * This method is called by the `String()` function.
255
- *
256
- * @example
257
- * const parameters = new MediaTypeParameters(new Map([['charset', 'utf-8']]));
258
- * String(parameters); // 'charset=utf-8'
259
- * parameters.toString(); // 'charset=utf-8'
260
- * parameters + ''; // 'charset=utf-8'
261
- * `${parameters}`; // 'charset=utf-8'
262
- * parameters[Symbol.toStringTag]; // 'MediaTypeParameters'
263
- * parameters[Symbol.toStringTag](); // 'MediaTypeParameters'
264
- * Object.prototype.toString.call(parameters); // '[object MediaTypeParameters]'
265
- * parameters + ''; // 'charset=utf-8'
266
- * @returns {string} The string representation of the media type parameters.
267
- */
268
- [Symbol.toStringTag]() {
269
- return "MediaTypeParameters";
270
- }
271
- };
272
-
273
- // node_modules/@d1g1tal/media-type/src/parser.js
274
- var parse = (input) => {
275
- input = removeLeadingAndTrailingHTTPWhitespace(input);
276
- let position = 0;
277
- let type = "";
278
- while (position < input.length && input[position] != "/") {
279
- type += input[position];
280
- ++position;
281
- }
282
- if (type.length === 0 || !solelyContainsHTTPTokenCodePoints(type)) {
283
- return null;
284
- }
285
- if (position >= input.length) {
286
- return null;
287
- }
288
- ++position;
289
- let subtype = "";
290
- while (position < input.length && input[position] != ";") {
291
- subtype += input[position];
292
- ++position;
293
- }
294
- subtype = removeTrailingHTTPWhitespace(subtype);
295
- if (subtype.length === 0 || !solelyContainsHTTPTokenCodePoints(subtype)) {
296
- return null;
297
- }
298
- const mediaType = {
299
- type: asciiLowercase(type),
300
- subtype: asciiLowercase(subtype),
301
- parameters: /* @__PURE__ */ new Map()
302
- };
303
- while (position < input.length) {
304
- ++position;
305
- while (isHTTPWhitespaceChar(input[position])) {
306
- ++position;
307
- }
308
- let parameterName = "";
309
- while (position < input.length && input[position] != ";" && input[position] != "=") {
310
- parameterName += input[position];
311
- ++position;
312
- }
313
- parameterName = asciiLowercase(parameterName);
314
- if (position < input.length) {
315
- if (input[position] == ";") {
316
- continue;
317
- }
318
- ++position;
319
- }
320
- let parameterValue = null;
321
- if (input[position] == '"') {
322
- [parameterValue, position] = collectAnHTTPQuotedString(input, position);
323
- while (position < input.length && input[position] != ";") {
324
- ++position;
325
- }
326
- } else {
327
- parameterValue = "";
328
- while (position < input.length && input[position] != ";") {
329
- parameterValue += input[position];
330
- ++position;
331
- }
332
- parameterValue = removeTrailingHTTPWhitespace(parameterValue);
333
- if (parameterValue === "") {
334
- continue;
335
- }
336
- }
337
- if (parameterName.length > 0 && solelyContainsHTTPTokenCodePoints(parameterName) && solelyContainsHTTPQuotedStringTokenCodePoints(parameterValue) && !mediaType.parameters.has(parameterName)) {
338
- mediaType.parameters.set(parameterName, parameterValue);
339
- }
340
- }
341
- return mediaType;
342
- };
343
- var parser_default = parse;
344
-
345
- // node_modules/@d1g1tal/media-type/src/serializer.js
346
- var serialize = (mediaType) => {
347
- let serialization = `${mediaType.type}/${mediaType.subtype}`;
348
- if (mediaType.parameters.size === 0) {
349
- return serialization;
350
- }
351
- for (let [name, value] of mediaType.parameters) {
352
- serialization += `;${name}=`;
353
- if (!solelyContainsHTTPTokenCodePoints(value) || value.length === 0) {
354
- value = `"${value.replace(/(["\\])/ug, "\\$1")}"`;
355
- }
356
- serialization += value;
357
- }
358
- return serialization;
359
- };
360
- var serializer_default = serialize;
361
-
362
- // node_modules/@d1g1tal/media-type/src/media-type.js
363
- var MediaType = class _MediaType {
364
- /** @type {string} */
365
- #type;
366
- /** @type {string} */
367
- #subtype;
368
- /** @type {MediaTypeParameters} */
369
- #parameters;
370
- /**
371
- * Create a new MediaType instance from a string representation.
372
- *
373
- * @param {string} mediaType The media type to parse.
374
- * @param {Object} [parameters] Optional parameters.
375
- */
376
- constructor(mediaType, parameters = {}) {
377
- const { type, subtype, parameters: parsedParameters } = parser_default(mediaType);
378
- this.#type = type;
379
- this.#subtype = subtype;
380
- this.#parameters = new MediaTypeParameters([...parsedParameters, ...Object.entries(parameters).map(([name, value]) => [asciiLowercase(name), asciiLowercase(value)])]);
381
- }
382
- /**
383
- * Static factory method for parsing a media type.
384
- *
385
- * @param {string} string The media type to parse.
386
- * @returns {MediaType} The parsed {@link MediaType} object or null if the string could not be parsed.
387
- */
388
- static parse(string) {
389
- try {
390
- return new _MediaType(string);
391
- } catch (e) {
392
- throw new Error(`Could not parse media type string '${string}'`);
393
- }
394
- }
395
- /**
396
- * Gets the media type essence (type/subtype).
397
- *
398
- * @returns {string} The media type without any parameters
399
- */
400
- get essence() {
401
- return `${this.#type}/${this.#subtype}`;
402
- }
403
- /**
404
- * Gets the type.
405
- *
406
- * @returns {string} The type.
407
- */
408
- get type() {
409
- return this.#type;
410
- }
411
- /**
412
- * Sets the type.
413
- */
414
- set type(value) {
415
- value = asciiLowercase(String(value));
416
- if (value.length === 0) {
417
- throw new Error("Invalid type: must be a non-empty string");
418
- }
419
- if (!solelyContainsHTTPTokenCodePoints(value)) {
420
- throw new Error(`Invalid type ${value}: must contain only HTTP token code points`);
421
- }
422
- this.#type = value;
423
- }
424
- /**
425
- * Gets the subtype.
426
- *
427
- * @returns {string} The subtype.
428
- */
429
- get subtype() {
430
- return this.#subtype;
431
- }
432
- /**
433
- * Sets the subtype.
434
- */
435
- set subtype(value) {
436
- value = asciiLowercase(String(value));
437
- if (value.length === 0) {
438
- throw new Error("Invalid subtype: must be a non-empty string");
439
- }
440
- if (!solelyContainsHTTPTokenCodePoints(value)) {
441
- throw new Error(`Invalid subtype ${value}: must contain only HTTP token code points`);
442
- }
443
- this.#subtype = value;
444
- }
445
- /**
446
- * Gets the parameters.
447
- *
448
- * @returns {MediaTypeParameters} The media type parameters.
449
- */
450
- get parameters() {
451
- return this.#parameters;
452
- }
453
- /**
454
- * Gets the serialized version of the media type.
455
- *
456
- * @returns {string} The serialized media type.
457
- */
458
- toString() {
459
- return serializer_default(this);
460
- }
461
- /**
462
- * Determines if this instance is a JavaScript media type.
463
- *
464
- * @param {Object} [options] Optional options.
465
- * @param {boolean} [options.prohibitParameters=false] The option to prohibit parameters when checking if the media type is JavaScript.
466
- * @returns {boolean} true if this instance represents a JavaScript media type, false otherwise.
467
- */
468
- isJavaScript({ prohibitParameters = false } = {}) {
469
- switch (this.#type) {
470
- case "text": {
471
- switch (this.#subtype) {
472
- case "ecmascript":
473
- case "javascript":
474
- case "javascript1.0":
475
- case "javascript1.1":
476
- case "javascript1.2":
477
- case "javascript1.3":
478
- case "javascript1.4":
479
- case "javascript1.5":
480
- case "jscript":
481
- case "livescript":
482
- case "x-ecmascript":
483
- case "x-javascript":
484
- return !prohibitParameters || this.#parameters.size === 0;
485
- default:
486
- return false;
487
- }
488
- }
489
- case "application": {
490
- switch (this.#subtype) {
491
- case "ecmascript":
492
- case "javascript":
493
- case "x-ecmascript":
494
- case "x-javascript":
495
- return !prohibitParameters || this.#parameters.size === 0;
496
- default:
497
- return false;
498
- }
499
- }
500
- default:
501
- return false;
502
- }
503
- }
504
- /**
505
- * Determines if this instance is an XML media type.
506
- *
507
- * @returns {boolean} true if this instance represents an XML media type, false otherwise.
508
- */
509
- isXML() {
510
- return this.#subtype === "xml" && (this.#type === "text" || this.#type === "application") || this.#subtype.endsWith("+xml");
511
- }
512
- /**
513
- * Determines if this instance is an HTML media type.
514
- *
515
- * @returns {boolean} true if this instance represents an HTML media type, false otherwise.
516
- */
517
- isHTML() {
518
- return this.#subtype === "html" && this.#type === "text";
519
- }
520
- /**
521
- * Gets the name of the class.
522
- *
523
- * @returns {string} The class name
524
- */
525
- get [Symbol.toStringTag]() {
526
- return "MediaType";
527
- }
528
- };
529
-
530
- // node_modules/@d1g1tal/subscribr/node_modules/@d1g1tal/collections/src/set-multi-map.js
531
- var SetMultiMap2 = class extends Map {
532
- /**
533
- * Adds a new element with a specified key and value to the SetMultiMap. If an element with the same key already exists, the value will be added to the underlying {@link Set}.
534
- *
535
- * @param {*} key The key to set.
536
- * @param {*} value The value to add to the SetMultiMap
537
- * @returns {SetMultiMap} The SetMultiMap with the updated key and value.
538
- */
539
- set(key, value) {
540
- super.set(key, (super.get(key) ?? /* @__PURE__ */ new Set()).add(value));
541
- return this;
542
- }
543
- [Symbol.toStringTag]() {
544
- return "SetMultiMap";
545
- }
546
- };
547
-
548
- // node_modules/@d1g1tal/subscribr/src/context-event-handler.js
549
- var ContextEventHandler = class {
550
- #context;
551
- #eventHandler;
552
- /**
553
- * @param {*} context The context to bind to the event handler.
554
- * @param {function(*): void} eventHandler The event handler to call when the event is published.
555
- */
556
- constructor(context, eventHandler) {
557
- this.#context = context;
558
- this.#eventHandler = eventHandler;
559
- }
560
- /**
561
- * Call the event handler for the provided event.
562
- *
563
- * @param {Event} event The event to handle
564
- * @param {*} [data] The value to be passed to the event handler as a parameter.
565
- */
566
- handle(event, data) {
567
- this.#eventHandler.call(this.#context, event, data);
568
- }
569
- get [Symbol.toStringTag]() {
570
- return "ContextEventHandler";
571
- }
572
- };
573
-
574
- // node_modules/@d1g1tal/subscribr/src/subscription.js
575
- var Subscription = class {
576
- #eventName;
577
- #contextEventHandler;
578
- /**
579
- * @param {string} eventName The event name.
580
- * @param {ContextEventHandler} contextEventHandler Then context event handler.
581
- */
582
- constructor(eventName, contextEventHandler) {
583
- this.#eventName = eventName;
584
- this.#contextEventHandler = contextEventHandler;
585
- }
586
- /**
587
- * Gets the event name for the subscription.
588
- *
589
- * @returns {string} The event name.
590
- */
591
- get eventName() {
592
- return this.#eventName;
593
- }
594
- /**
595
- * Gets the context event handler.
596
- *
597
- * @returns {ContextEventHandler} The context event handler
598
- */
599
- get contextEventHandler() {
600
- return this.#contextEventHandler;
601
- }
602
- get [Symbol.toStringTag]() {
603
- return "Subscription";
604
- }
605
- };
606
-
607
- // node_modules/@d1g1tal/subscribr/src/subscribr.js
608
- var Subscribr = class {
609
- /** @type {SetMultiMap<string, ContextEventHandler>} */
610
- #subscribers;
611
- constructor() {
612
- this.#subscribers = new SetMultiMap2();
613
- }
614
- /**
615
- * Subscribe to an event
616
- *
617
- * @param {string} eventName The event name to subscribe to.
618
- * @param {function(Event, *): void} eventHandler The event handler to call when the event is published.
619
- * @param {*} [context] The context to bind to the event handler.
620
- * @returns {Subscription} An object used to check if the subscription still exists and to unsubscribe from the event.
621
- */
622
- subscribe(eventName, eventHandler, context = eventHandler) {
623
- const contextEventHandler = new ContextEventHandler(context, eventHandler);
624
- this.#subscribers.set(eventName, contextEventHandler);
625
- return new Subscription(eventName, contextEventHandler);
626
- }
627
- /**
628
- * Unsubscribe from the event
629
- *
630
- * @param {Subscription} subscription The subscription to unsubscribe.
631
- * @param {string} subscription.eventName The event name to subscribe to.
632
- * @param {ContextEventHandler} subscription.contextEventHandler The event handler to call when the event is published.
633
- * @returns {boolean} true if eventListener has been removed successfully. false if the value is not found or if the value is not an object.
634
- */
635
- unsubscribe({ eventName, contextEventHandler }) {
636
- const contextEventHandlers = this.#subscribers.get(eventName);
637
- const removed = contextEventHandlers?.delete(contextEventHandler);
638
- if (removed && contextEventHandlers.size == 0) {
639
- this.#subscribers.delete(eventName);
640
- }
641
- return removed;
642
- }
643
- /**
644
- * Publish an event
645
- *
646
- * @param {string} eventName The name of the event.
647
- * @param {Event} event The event to be handled.
648
- * @param {*} [data] The value to be passed to the event handler as a parameter.
649
- */
650
- publish(eventName, event = new CustomEvent(eventName), data) {
651
- if (data == null && !(event instanceof Event)) {
652
- [data, event] = [event, new CustomEvent(eventName)];
653
- }
654
- this.#subscribers.get(eventName)?.forEach((contextEventHandler) => contextEventHandler.handle(event, data));
655
- }
656
- /**
657
- * Check if the event and handler are subscribed.
658
- *
659
- * @param {Subscription} subscription The subscription object.
660
- * @param {string} subscription.eventName The name of the event to check.
661
- * @param {ContextEventHandler} subscription.contextEventHandler The event handler to check.
662
- * @returns {boolean} true if the event name and handler are subscribed, false otherwise.
663
- */
664
- isSubscribed({ eventName, contextEventHandler }) {
665
- return this.#subscribers.get(eventName)?.has(contextEventHandler);
666
- }
667
- get [Symbol.toStringTag]() {
668
- return "Subscribr";
669
- }
670
- };
671
-
672
- // src/http-error.js
673
- var HttpError = class extends Error {
674
- /** @type {ResponseBody} */
675
- #entity;
676
- /** @type {ResponseStatus} */
677
- #responseStatus;
678
- /**
679
- * @param {string} [message] The error message.
680
- * @param {HttpErrorOptions} [httpErrorOptions] The http error options.
681
- * @param {any} [httpErrorOptions.cause] The cause of the error.
682
- * @param {ResponseStatus} [httpErrorOptions.status] The response status.
683
- * @param {ResponseBody} [httpErrorOptions.entity] The error entity from the server, if any.
684
- */
685
- constructor(message, { cause, status, entity }) {
686
- super(message, { cause });
687
- this.#entity = entity;
688
- this.#responseStatus = status;
689
- }
690
- /**
691
- * It returns the value of the private variable #entity.
692
- *
693
- * @returns {ResponseBody} The entity property of the class.
694
- */
695
- get entity() {
696
- return this.#entity;
697
- }
698
- /**
699
- * It returns the status code of the {@link Response}.
241
+ * It returns the status code of the {@link Response}.
700
242
  *
701
243
  * @returns {number} The status code of the {@link Response}.
702
244
  */
@@ -783,6 +325,8 @@ var Transportr = (() => {
783
325
  JSON: "application/json",
784
326
  /** JavaScript Object Notation LD Format */
785
327
  JSON_LD: "application/ld+json",
328
+ /** JavaScript Object Notation (JSON) Merge Patch */
329
+ JSON_MERGE_PATCH: "application/merge-patch+json",
786
330
  /** Musical Instrument Digital Interface (MIDI) */
787
331
  MID: "audio/midi",
788
332
  /** Musical Instrument Digital Interface (MIDI) */
@@ -1462,455 +1006,1231 @@ var Transportr = (() => {
1462
1006
  // src/http-response-headers.js
1463
1007
  var HttpResponseHeader = {
1464
1008
  /**
1465
- * Implemented as a misunderstanding of the HTTP specifications. Common because of mistakes in implementations of early HTTP versions. Has exactly the same functionality as standard Connection field.
1009
+ * Implemented as a misunderstanding of the HTTP specifications. Common because of mistakes in implementations of early HTTP versions. Has exactly the same functionality as standard Connection field.
1010
+ *
1011
+ * @example
1012
+ * proxy-connection: keep-alive
1013
+ */
1014
+ PROXY_CONNECTION: "proxy-connection",
1015
+ /**
1016
+ * Server-side deep packet insertion of a unique ID identifying customers of Verizon Wireless, also known as "perma-cookie" or "supercookie"
1017
+ *
1018
+ * @example
1019
+ * x-uidh: ...
1020
+ */
1021
+ X_UIDH: "x-uidh",
1022
+ /**
1023
+ * Used to prevent cross-site request forgery. Alternative header names are: X-CSRFToken and X-XSRF-TOKEN
1024
+ *
1025
+ * @example
1026
+ * x-csrf-token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
1027
+ */
1028
+ X_CSRF_TOKEN: "x-csrf-token",
1029
+ /**
1030
+ * Specifying which web sites can participate in cross-origin resource sharing
1031
+ *
1032
+ * @example
1033
+ * access-control-allow-origin: *
1034
+ * Provisional
1035
+ */
1036
+ ACCESS_CONTROL_ALLOW_ORIGIN: "access-control-allow-origin",
1037
+ /**
1038
+ * Specifies which patch document formats this server supports
1039
+ *
1040
+ * @example
1041
+ * accept-patch: text/example,charset=utf-8
1042
+ * Permanent
1043
+ */
1044
+ ACCEPT_PATCH: "accept-patch",
1045
+ /**
1046
+ * What partial content range types this server supports via byte serving
1047
+ *
1048
+ * @example
1049
+ * accept-ranges: bytes
1050
+ * Permanent
1051
+ */
1052
+ ACCEPT_RANGES: "accept-ranges",
1053
+ /**
1054
+ * The age the object has been in a proxy cache in seconds
1055
+ *
1056
+ * @example
1057
+ * age: 12
1058
+ * Permanent
1059
+ */
1060
+ AGE: "age",
1061
+ /**
1062
+ * Valid actions for a specified resource. To be used for a 405 Method not allowed
1063
+ *
1064
+ * @example
1065
+ * allow: GET, HEAD
1066
+ * Permanent
1067
+ */
1068
+ ALLOW: "allow",
1069
+ /**
1070
+ * Tells all caching mechanisms from server to client whether they may cache this object. It is measured in seconds
1071
+ *
1072
+ * @example
1073
+ * cache-control: max-age=3600
1074
+ * Permanent
1075
+ */
1076
+ CACHE_CONTROL: "cache-control",
1077
+ /**
1078
+ * Control options for the current connection and list of hop-by-hop response fields
1079
+ *
1080
+ * @example
1081
+ * connection: close
1082
+ * Permanent
1083
+ */
1084
+ CONNECTION: "connection",
1085
+ /**
1086
+ * An opportunity to raise a "File Download" dialogue box for a known MIME type with binary format or suggest a filename for dynamic content. Quotes are necessary with special characters.
1087
+ *
1088
+ * @example
1089
+ * content-disposition: attachment, filename="fname.ext"
1090
+ * Permanent
1091
+ */
1092
+ CONTENT_DISPOSITION: "content-disposition",
1093
+ /**
1094
+ * The type of encoding used on the data. See HTTP compression.
1095
+ *
1096
+ * @example
1097
+ * content-encoding: gzip
1098
+ * Permanent
1099
+ */
1100
+ CONTENT_ENCODING: "content-encoding",
1101
+ /**
1102
+ * The natural language or languages of the intended audience for the enclosed content
1103
+ *
1104
+ * @example
1105
+ * content-language: da
1106
+ * Permanent
1107
+ */
1108
+ CONTENT_LANGUAGE: "content-language",
1109
+ /**
1110
+ * The length of the response body in octets (8-bit bytes)
1111
+ *
1112
+ * @example
1113
+ * content-length: 348
1114
+ * Permanent
1115
+ */
1116
+ CONTENT_LENGTH: "content-length",
1117
+ /**
1118
+ * An alternate location for the returned data
1119
+ *
1120
+ * @example
1121
+ * content-location: /index.htm
1122
+ * Permanent
1123
+ */
1124
+ CONTENT_LOCATION: "content-location",
1125
+ /**
1126
+ * Where in a full body message this partial message belongs
1127
+ *
1128
+ * @example
1129
+ * content-range: bytes 21010-47021/47022
1130
+ * Permanent
1131
+ */
1132
+ CONTENT_RANGE: "content-range",
1133
+ /**
1134
+ * The MIME type of this content
1135
+ *
1136
+ * @example
1137
+ * content-type: text/html, charset=utf-8
1138
+ * Permanent
1139
+ */
1140
+ CONTENT_TYPE: "content-type",
1141
+ /**
1142
+ * The date and time that the message was sent (in "HTTP-date" format as defined by RFC 7231)
1143
+ *
1144
+ * @example
1145
+ * date: Tue, 15 Nov 1994 08:12:31 GMT
1146
+ * Permanent
1147
+ */
1148
+ DATE: "date",
1149
+ /**
1150
+ * An identifier for a specific version of a resource, often a message digest
1151
+ *
1152
+ * @example
1153
+ * etag: "737060cd8c284d8af7ad3082f209582d"
1154
+ * Permanent
1155
+ */
1156
+ ETAG: "etag",
1157
+ /**
1158
+ * Gives the date/time after which the response is considered stale (in "HTTP-date" format as defined by RFC 7231)
1159
+ *
1160
+ * @example
1161
+ * expires: Thu, 01 Dec 1994 16:00:00 GMT
1162
+ * Permanent
1163
+ */
1164
+ EXPIRES: "expires",
1165
+ /**
1166
+ * The last modified date for the requested object (in "HTTP-date" format as defined by RFC 7231)
1167
+ *
1168
+ * @example
1169
+ * last-modified: Tue, 15 Nov 1994 12:45:26 GMT
1170
+ * Permanent
1171
+ */
1172
+ LAST_MODIFIED: "last-modified",
1173
+ /**
1174
+ * Used to express a typed relationship with another resource, where the relation type is defined by RFC 5988
1175
+ *
1176
+ * @example
1177
+ * link: </feed>, rel="alternate"
1178
+ * Permanent
1179
+ */
1180
+ LINK: "link",
1181
+ /**
1182
+ * Used in redirection, or when a new resource has been created.
1183
+ *
1184
+ * @example
1185
+ * location: http://www.w3.org/pub/WWW/People.html
1186
+ * Permanent
1187
+ */
1188
+ LOCATION: "location",
1189
+ /**
1190
+ * This field is supposed to set P3P policy, in the form of P3P:CP="your_compact_policy". However, P3P did not take off, most browsers have never fully
1191
+ * implemented it, a lot of websites set this field with fake policy text, that was enough to fool browsers the existence of P3P policy and grant permissions for third party cookies.
1192
+ *
1193
+ * @example
1194
+ * p3p: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
1195
+ * Permanent
1196
+ */
1197
+ P3P: "p3p",
1198
+ /**
1199
+ * Implementation-specific fields that may have various effects anywhere along the request-response chain.
1200
+ *
1201
+ * @example
1202
+ * pragma: no-cache
1203
+ * Permanent
1204
+ */
1205
+ PRAGMA: "pragma",
1206
+ /**
1207
+ * Request authentication to access the proxy.
1208
+ *
1209
+ * @example
1210
+ * proxy-authenticate: Basic
1211
+ * Permanent
1212
+ */
1213
+ PROXY_AUTHENTICATION: "proxy-authenticate",
1214
+ /**
1215
+ * HTTP Public Key Pinning, announces hash of website's authentic TLS certificate
1216
+ *
1217
+ * @example
1218
+ * public-key-pins: max-age=2592000, pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=",
1219
+ * Permanent
1220
+ */
1221
+ PUBLIC_KEY_PINS: "public-key-pins",
1222
+ /**
1223
+ * If an entity is temporarily unavailable, this instructs the client to try again later. Value could be a specified period of time (in seconds) or a HTTP-date.
1224
+ *
1225
+ * @example
1226
+ * retry-after: 120
1227
+ * retry-after: Fri, 07 Nov 2014 23:59:59 GMT
1228
+ * Permanent
1229
+ */
1230
+ RETRY_AFTER: "retry-after",
1231
+ /**
1232
+ * A name for the server
1233
+ *
1234
+ * @example
1235
+ * server: Apache/2.4.1 (Unix)
1236
+ * Permanent
1237
+ */
1238
+ SERVER: "server",
1239
+ /**
1240
+ * An HTTP cookie
1466
1241
  *
1467
1242
  * @example
1468
- * proxy-connection: keep-alive
1243
+ * set-cookie: UserID=JohnDoe, Max-Age=3600, Version=1
1244
+ * Permanent
1469
1245
  */
1470
- PROXY_CONNECTION: "proxy-connection",
1246
+ SET_COOKIE: "set-cookie",
1471
1247
  /**
1472
- * Server-side deep packet insertion of a unique ID identifying customers of Verizon Wireless, also known as "perma-cookie" or "supercookie"
1248
+ * CGI header field specifying the status of the HTTP response. Normal HTTP responses use a separate "Status-Line" instead, defined by RFC 7230.
1473
1249
  *
1474
1250
  * @example
1475
- * x-uidh: ...
1251
+ * status: 200 OK
1476
1252
  */
1477
- X_UIDH: "x-uidh",
1253
+ STATUS: "status",
1478
1254
  /**
1479
- * Used to prevent cross-site request forgery. Alternative header names are: X-CSRFToken and X-XSRF-TOKEN
1255
+ * A HSTS Policy informing the HTTP client how long to cache the HTTPS only policy and whether this applies to subdomains.
1480
1256
  *
1481
1257
  * @example
1482
- * x-csrf-token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
1258
+ * strict-transport-security: max-age=16070400, includeSubDomains
1259
+ * Permanent
1483
1260
  */
1484
- X_CSRF_TOKEN: "x-csrf-token",
1261
+ STRICT_TRANSPORT_SECURITY: "strict-transport-security",
1485
1262
  /**
1486
- * Specifying which web sites can participate in cross-origin resource sharing
1263
+ * The Trailer general field value indicates that the given set of header fields is present in the trailer of a message encoded with chunked transfer coding.
1487
1264
  *
1488
1265
  * @example
1489
- * access-control-allow-origin: *
1490
- * Provisional
1266
+ * trailer: Max-Forwards
1267
+ * Permanent
1491
1268
  */
1492
- ACCESS_CONTROL_ALLOW_ORIGIN: "access-control-allow-origin",
1269
+ TRAILER: "trailer",
1493
1270
  /**
1494
- * Specifies which patch document formats this server supports
1271
+ * The form of encoding used to safely transfer the entity to the user. Currently defined methods are: chunked, compress, deflate, gzip, identity.
1495
1272
  *
1496
1273
  * @example
1497
- * accept-patch: text/example,charset=utf-8
1274
+ * transfer-encoding: chunked
1498
1275
  * Permanent
1499
1276
  */
1500
- ACCEPT_PATCH: "accept-patch",
1277
+ TRANSFER_ENCODING: "transfer-encoding",
1501
1278
  /**
1502
- * What partial content range types this server supports via byte serving
1279
+ * Ask the client to upgrade to another protocol.
1503
1280
  *
1504
1281
  * @example
1505
- * accept-ranges: bytes
1282
+ * upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
1506
1283
  * Permanent
1507
1284
  */
1508
- ACCEPT_RANGES: "accept-ranges",
1285
+ UPGRADE: "upgrade",
1509
1286
  /**
1510
- * The age the object has been in a proxy cache in seconds
1287
+ * Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server.
1511
1288
  *
1512
1289
  * @example
1513
- * age: 12
1290
+ * vary: *
1514
1291
  * Permanent
1515
1292
  */
1516
- AGE: "age",
1293
+ VARY: "vary",
1517
1294
  /**
1518
- * Valid actions for a specified resource. To be used for a 405 Method not allowed
1295
+ * Informs the client of proxies through which the response was sent.
1519
1296
  *
1520
1297
  * @example
1521
- * allow: GET, HEAD
1298
+ * via: 1.0 fred, 1.1 example.com (Apache/1.1)
1522
1299
  * Permanent
1523
1300
  */
1524
- ALLOW: "allow",
1301
+ VIA: "via",
1525
1302
  /**
1526
- * Tells all caching mechanisms from server to client whether they may cache this object. It is measured in seconds
1303
+ * A general warning about possible problems with the entity body.
1527
1304
  *
1528
1305
  * @example
1529
- * cache-control: max-age=3600
1306
+ * warning: 199 Miscellaneous warning
1530
1307
  * Permanent
1531
1308
  */
1532
- CACHE_CONTROL: "cache-control",
1309
+ WARNING: "warning",
1533
1310
  /**
1534
- * Control options for the current connection and list of hop-by-hop response fields
1311
+ * Indicates the authentication scheme that should be used to access the requested entity.
1535
1312
  *
1536
1313
  * @example
1537
- * connection: close
1314
+ * www-authenticate: Basic
1538
1315
  * Permanent
1539
1316
  */
1540
- CONNECTION: "connection",
1317
+ WWW_AUTHENTICATE: "www-authenticate",
1541
1318
  /**
1542
- * An opportunity to raise a "File Download" dialogue box for a known MIME type with binary format or suggest a filename for dynamic content. Quotes are necessary with special characters.
1319
+ * Cross-site scripting (XSS) filter
1543
1320
  *
1544
1321
  * @example
1545
- * content-disposition: attachment, filename="fname.ext"
1546
- * Permanent
1322
+ * x-xss-protection: 1, mode=block
1547
1323
  */
1548
- CONTENT_DISPOSITION: "content-disposition",
1324
+ X_XSS_PROTECTION: "x-xss-protection",
1549
1325
  /**
1550
- * The type of encoding used on the data. See HTTP compression.
1326
+ * The HTTP Content-Security-Policy response header allows web site administrators to control resources the user agent is allowed
1327
+ * to load for a given page. With a few exceptions, policies mostly involve specifying server origins and script endpoints.
1328
+ * This helps guard against cross-site scripting attacks (Cross-site_scripting).
1551
1329
  *
1552
1330
  * @example
1553
- * content-encoding: gzip
1554
- * Permanent
1331
+ * content-security-policy: default-src
1555
1332
  */
1556
- CONTENT_ENCODING: "content-encoding",
1333
+ CONTENT_SECURITY_POLICY: "content-security-policy",
1557
1334
  /**
1558
- * The natural language or languages of the intended audience for the enclosed content
1335
+ * The only defined value, "nosniff", prevents Internet Explorer from MIME-sniffing a response away from the declared content-type. This also applies to Google Chrome, when downloading extensions.
1559
1336
  *
1560
1337
  * @example
1561
- * content-language: da
1562
- * Permanent
1338
+ * x-content-type-options: nosniff
1563
1339
  */
1564
- CONTENT_LANGUAGE: "content-language",
1340
+ X_CONTENT_TYPE_OPTIONS: "x-content-type-options",
1565
1341
  /**
1566
- * The length of the response body in octets (8-bit bytes)
1342
+ * specifies the technology (e.g. ASP.NET, PHP, JBoss) supporting the web application (version details are often in X-Runtime, X-Version, or X-AspNet-Version)
1567
1343
  *
1568
1344
  * @example
1569
- * content-length: 348
1570
- * Permanent
1345
+ * x-powered-by: PHP/5.4.0
1571
1346
  */
1572
- CONTENT_LENGTH: "content-length",
1347
+ X_POWERED_BY: "x-powered-by"
1348
+ };
1349
+ var http_response_headers_default = HttpResponseHeader;
1350
+
1351
+ // src/response-status.js
1352
+ var ResponseStatus = class {
1353
+ /** @type {number} */
1354
+ #code;
1355
+ /** @type {string} */
1356
+ #text;
1357
+ /**
1358
+ *
1359
+ * @param {number} code The status code from the {@link Response}
1360
+ * @param {string} text The status text from the {@link Response}
1361
+ */
1362
+ constructor(code, text) {
1363
+ this.#code = code;
1364
+ this.#text = text;
1365
+ }
1366
+ /**
1367
+ * Returns the status code from the {@link Response}
1368
+ *
1369
+ * @returns {number} The status code.
1370
+ */
1371
+ get code() {
1372
+ return this.#code;
1373
+ }
1374
+ /**
1375
+ * Returns the status text from the {@link Response}.
1376
+ *
1377
+ * @returns {string} The status text.
1378
+ */
1379
+ get text() {
1380
+ return this.#text;
1381
+ }
1382
+ /**
1383
+ * A String value that is used in the creation of the default string
1384
+ * description of an object. Called by the built-in method {@link Object.prototype.toString}.
1385
+ *
1386
+ * @override
1387
+ * @returns {string} The default string description of this object.
1388
+ */
1389
+ get [Symbol.toStringTag]() {
1390
+ return "ResponseStatus";
1391
+ }
1392
+ /**
1393
+ * tostring method for the class.
1394
+ *
1395
+ * @override
1396
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString|Object.prototype.toString}
1397
+ * @returns {string} The status code and status text.
1398
+ */
1399
+ toString() {
1400
+ return `${this.#code} ${this.#text}`;
1401
+ }
1402
+ };
1403
+
1404
+ // src/parameter-map.js
1405
+ var ParameterMap = class _ParameterMap extends Map {
1406
+ /**
1407
+ * @param {Iterable<[string, *]>|Object} parameters The initial parameters to set.
1408
+ * @returns {ParameterMap<string, *>} The ParameterMap with the updated key and value.
1409
+ */
1410
+ constructor(parameters = {}) {
1411
+ super();
1412
+ for (const [key, value] of _ParameterMap.#entries(parameters)) {
1413
+ this.append(key, value);
1414
+ }
1415
+ }
1416
+ /**
1417
+ * Adds a new element with a specified key and value to the ParameterMap.
1418
+ * If an element with the same key already exists, the value will be replaced in the underlying {@link Set}.
1419
+ *
1420
+ * @override
1421
+ * @param {string} key The key to set.
1422
+ * @param {*} value The value to add to the ParameterMap
1423
+ * @returns {ParameterMap<string, *>} The ParameterMap with the updated key and value.
1424
+ */
1425
+ set(key, value) {
1426
+ const array = super.get(key);
1427
+ if (array?.length > 0) {
1428
+ array.length = 0;
1429
+ array[0] = value;
1430
+ } else {
1431
+ super.set(key, [value]);
1432
+ }
1433
+ return this;
1434
+ }
1435
+ /**
1436
+ * Adds all key-value pairs from an iterable or object to the ParameterMap.
1437
+ * If a key already exists, the value will be replaced in the underlying {@link Array}.
1438
+ *
1439
+ * @param {Iterable<[string, *]>|Object} parameters The parameters to set.
1440
+ * @returns {ParameterMap<string, *>} The ParameterMap with the updated key and value.
1441
+ */
1442
+ setAll(parameters) {
1443
+ for (const [key, value] of _ParameterMap.#entries(parameters)) {
1444
+ this.set(key, value);
1445
+ }
1446
+ return this;
1447
+ }
1448
+ /**
1449
+ * Returns the value associated to the key, or undefined if there is none.
1450
+ * If the key has multiple values, the first value will be returned.
1451
+ * If the key has no values, undefined will be returned.
1452
+ *
1453
+ * @override
1454
+ * @param {string} key The key to get.
1455
+ * @returns {*} The value associated to the key, or undefined if there is none.
1456
+ */
1457
+ get(key) {
1458
+ return super.get(key)?.[0];
1459
+ }
1460
+ /**
1461
+ * Returns an array of all values associated to the key, or undefined if there are none.
1462
+ *
1463
+ * @param {string} key The key to get.
1464
+ * @returns {Array<*>} An array of all values associated to the key, or undefined if there are none.
1465
+ */
1466
+ getAll(key) {
1467
+ return super.get(key);
1468
+ }
1469
+ /**
1470
+ * Appends a new value to an existing key inside a ParameterMap, or adds the new key if it does not exist.
1471
+ *
1472
+ * @param {string} key The key to append.
1473
+ * @param {*} value The value to append.
1474
+ * @returns {ParameterMap<string, *>} The ParameterMap with the updated key and value to allow chaining.
1475
+ */
1476
+ append(key, value) {
1477
+ const array = super.get(key);
1478
+ if (array?.length > 0) {
1479
+ array.push(value);
1480
+ } else {
1481
+ super.set(key, [value]);
1482
+ }
1483
+ return this;
1484
+ }
1485
+ /**
1486
+ * Appends all key-value pairs from an iterable or object to the ParameterMap.
1487
+ * If a key already exists, the value will be appended to the underlying {@link Array}.
1488
+ * If a key does not exist, the key and value will be added to the ParameterMap.
1489
+ *
1490
+ * @param {Iterable<[string, *]>|Object} parameters The parameters to append.
1491
+ * @returns {ParameterMap<string, *>} The ParameterMap with the updated key and value.
1492
+ */
1493
+ appendAll(parameters) {
1494
+ for (const [key, value] of _ParameterMap.#entries(parameters)) {
1495
+ this.append(key, value);
1496
+ }
1497
+ return this;
1498
+ }
1499
+ /**
1500
+ * Checks if a specific key has a specific value.
1501
+ *
1502
+ * @param {*} value The value to check.
1503
+ * @returns {boolean} True if the key has the value, false otherwise.
1504
+ */
1505
+ hasValue(value) {
1506
+ for (const array of super.values()) {
1507
+ if (array.includes(value)) {
1508
+ return true;
1509
+ }
1510
+ }
1511
+ return false;
1512
+ }
1513
+ /**
1514
+ * Removes a specific value from a specific key.
1515
+ *
1516
+ * @param {*} value The value to remove.
1517
+ * @returns {boolean} True if the value was removed, false otherwise.
1518
+ */
1519
+ deleteValue(value) {
1520
+ for (const array of this.values()) {
1521
+ if (array.includes(value)) {
1522
+ return array.splice(array.indexOf(value), 1).length > 0;
1523
+ }
1524
+ }
1525
+ return false;
1526
+ }
1527
+ /**
1528
+ * Determines whether the ParameterMap contains anything.
1529
+ *
1530
+ * @returns {boolean} True if the ParameterMap size is greater than 0, false otherwise.
1531
+ */
1532
+ isEmpty() {
1533
+ return this.size === 0;
1534
+ }
1535
+ /**
1536
+ * Returns an Object that can be serialized to JSON.
1537
+ * If a key has only one value, the value will be a single value.
1538
+ * If a key has multiple values, the value will be an array of values.
1539
+ * If a key has no values, the value will be undefined.
1540
+ *
1541
+ * @override
1542
+ * @returns {Object} The Object to be serialized to JSON.
1543
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON_behavior}
1544
+ */
1545
+ toJSON() {
1546
+ const obj = /* @__PURE__ */ Object.create(null);
1547
+ for (const [key, values] of super.entries()) {
1548
+ obj[key] = values.length === 1 ? values[0] : values;
1549
+ }
1550
+ return obj;
1551
+ }
1552
+ /**
1553
+ * Returns an iterator that yields all key-value pairs in the map as arrays in their insertion order.
1554
+ *
1555
+ * @override
1556
+ * @yields {[string, *]} An iterator for the key-value pairs in the map.
1557
+ */
1558
+ *entries() {
1559
+ for (const [key, array] of super.entries()) {
1560
+ for (const value of array) {
1561
+ yield [key, value];
1562
+ }
1563
+ }
1564
+ }
1565
+ /**
1566
+ * Returns an iterator that yields all key-value pairs in the map as arrays in their insertion order.
1567
+ *
1568
+ * @override
1569
+ * @yields {[string, *]} An iterator for the key-value pairs in the map.
1570
+ */
1571
+ *[Symbol.iterator]() {
1572
+ yield* this.entries();
1573
+ }
1574
+ /**
1575
+ * Returns an iterable of key, value pairs for every entry in the parameters object.
1576
+ *
1577
+ * @private
1578
+ * @static
1579
+ * @param {Iterable<[string, *]>|Object} parameters The parameters to set.
1580
+ * @returns {Iterable<[string, *]>} An iterable of key, value pairs for every entry in the parameters object.
1581
+ */
1582
+ static #entries(parameters) {
1583
+ return parameters[Symbol.iterator] ? parameters : Object.entries(parameters);
1584
+ }
1585
+ /**
1586
+ * A String value that is used in the creation of the default string description of an object.
1587
+ * Called by the built-in method {@link Object.prototype.toString}.
1588
+ *
1589
+ * @override
1590
+ * @returns {string} The default string description of this object.
1591
+ */
1592
+ get [Symbol.toStringTag]() {
1593
+ return "ParameterMap";
1594
+ }
1595
+ };
1596
+
1597
+ // node_modules/@d1g1tal/media-type/src/utils.js
1598
+ var whitespaceCharacters = [" ", " ", "\n", "\r"];
1599
+ var leadingWhitespace = /^[ \t\n\r]+/u;
1600
+ var trailingWhitespace = /[ \t\n\r]+$/u;
1601
+ var httpTokenCodePoints = /^[-!#$%&'*+.^_`|~A-Za-z0-9]*$/u;
1602
+ var httpQuotedTokenCodePoints = /^[\t\u0020-\u007E\u0080-\u00FF]*$/u;
1603
+ var removeLeadingAndTrailingHTTPWhitespace = (string) => string.replace(leadingWhitespace, "").replace(trailingWhitespace, "");
1604
+ var removeTrailingHTTPWhitespace = (string) => string.replace(trailingWhitespace, "");
1605
+ var isHTTPWhitespaceChar = (char) => whitespaceCharacters.includes(char);
1606
+ var solelyContainsHTTPTokenCodePoints = (string) => httpTokenCodePoints.test(string);
1607
+ var solelyContainsHTTPQuotedStringTokenCodePoints = (string) => httpQuotedTokenCodePoints.test(string);
1608
+ var asciiLowercase = (string) => {
1609
+ let result = "";
1610
+ for (const [char, charCode = char.charCodeAt(0)] of string) {
1611
+ result += charCode >= 65 && charCode <= 90 ? String.fromCharCode(charCode + 32) : char;
1612
+ }
1613
+ return result;
1614
+ };
1615
+ var collectAnHTTPQuotedString = (input, position) => {
1616
+ let value = "";
1617
+ for (let length = input.length, char; ++position < length; ) {
1618
+ char = input[position];
1619
+ if (char == "\\") {
1620
+ value += ++position < length ? input[position] : char;
1621
+ } else if (char == '"') {
1622
+ break;
1623
+ } else {
1624
+ value += char;
1625
+ }
1626
+ }
1627
+ return [value, position];
1628
+ };
1629
+
1630
+ // node_modules/@d1g1tal/media-type/src/media-type-parameters.js
1631
+ var MediaTypeParameters = class {
1632
+ /** @type {Map<string, string>} */
1633
+ #map;
1573
1634
  /**
1574
- * An alternate location for the returned data
1635
+ * Create a new MediaTypeParameters instance.
1575
1636
  *
1576
- * @example
1577
- * content-location: /index.htm
1578
- * Permanent
1637
+ * @param {Array<Array<string>>} entries An array of [name, value] tuples.
1579
1638
  */
1580
- CONTENT_LOCATION: "content-location",
1639
+ constructor(entries) {
1640
+ this.#map = new Map(entries);
1641
+ }
1581
1642
  /**
1582
- * Where in a full body message this partial message belongs
1643
+ * Gets the number of media type parameters.
1583
1644
  *
1584
- * @example
1585
- * content-range: bytes 21010-47021/47022
1586
- * Permanent
1645
+ * @returns {number} The number of media type parameters
1587
1646
  */
1588
- CONTENT_RANGE: "content-range",
1647
+ get size() {
1648
+ return this.#map.size;
1649
+ }
1589
1650
  /**
1590
- * The MIME type of this content
1651
+ * Gets the media type parameter value for the supplied name.
1591
1652
  *
1592
- * @example
1593
- * content-type: text/html, charset=utf-8
1594
- * Permanent
1653
+ * @param {string} name The name of the media type parameter to retrieve.
1654
+ * @returns {string} The media type parameter value.
1595
1655
  */
1596
- CONTENT_TYPE: "content-type",
1656
+ get(name) {
1657
+ return this.#map.get(asciiLowercase(String(name)));
1658
+ }
1597
1659
  /**
1598
- * The date and time that the message was sent (in "HTTP-date" format as defined by RFC 7231)
1660
+ * Indicates whether the media type parameter with the specified name exists or not.
1599
1661
  *
1600
- * @example
1601
- * date: Tue, 15 Nov 1994 08:12:31 GMT
1602
- * Permanent
1662
+ * @param {string} name The name of the media type parameter to check.
1663
+ * @returns {boolean} true if the media type parameter exists, false otherwise.
1603
1664
  */
1604
- DATE: "date",
1665
+ has(name) {
1666
+ return this.#map.has(asciiLowercase(String(name)));
1667
+ }
1605
1668
  /**
1606
- * An identifier for a specific version of a resource, often a message digest
1669
+ * Adds a new media type parameter using the specified name and value to the MediaTypeParameters.
1670
+ * If an parameter with the same name already exists, the parameter will be updated.
1607
1671
  *
1608
- * @example
1609
- * etag: "737060cd8c284d8af7ad3082f209582d"
1610
- * Permanent
1672
+ * @param {string} name The name of the media type parameter to set.
1673
+ * @param {string} value The media type parameter value.
1674
+ * @returns {MediaTypeParameters} This instance.
1611
1675
  */
1612
- ETAG: "etag",
1676
+ set(name, value) {
1677
+ name = asciiLowercase(String(name));
1678
+ value = String(value);
1679
+ if (!solelyContainsHTTPTokenCodePoints(name)) {
1680
+ throw new Error(`Invalid media type parameter name "${name}": only HTTP token code points are valid.`);
1681
+ }
1682
+ if (!solelyContainsHTTPQuotedStringTokenCodePoints(value)) {
1683
+ throw new Error(`Invalid media type parameter value "${value}": only HTTP quoted-string token code points are valid.`);
1684
+ }
1685
+ this.#map.set(name, value);
1686
+ return this;
1687
+ }
1613
1688
  /**
1614
- * Gives the date/time after which the response is considered stale (in "HTTP-date" format as defined by RFC 7231)
1615
- *
1616
- * @example
1617
- * expires: Thu, 01 Dec 1994 16:00:00 GMT
1618
- * Permanent
1689
+ * Clears all the media type parameters.
1619
1690
  */
1620
- EXPIRES: "expires",
1691
+ clear() {
1692
+ this.#map.clear();
1693
+ }
1621
1694
  /**
1622
- * The last modified date for the requested object (in "HTTP-date" format as defined by RFC 7231)
1695
+ * Removes the media type parameter using the specified name.
1623
1696
  *
1624
- * @example
1625
- * last-modified: Tue, 15 Nov 1994 12:45:26 GMT
1626
- * Permanent
1697
+ * @param {string} name The name of the media type parameter to delete.
1698
+ * @returns {boolean} true if the parameter existed and has been removed, or false if the parameter does not exist.
1627
1699
  */
1628
- LAST_MODIFIED: "last-modified",
1700
+ delete(name) {
1701
+ name = asciiLowercase(String(name));
1702
+ return this.#map.delete(name);
1703
+ }
1629
1704
  /**
1630
- * Used to express a typed relationship with another resource, where the relation type is defined by RFC 5988
1705
+ * Executes a provided function once per each name/value pair in the MediaTypeParameters, in insertion order.
1631
1706
  *
1632
- * @example
1633
- * link: </feed>, rel="alternate"
1634
- * Permanent
1707
+ * @param {function(string, string): void} callback The function called on each iteration.
1708
+ * @param {*} [thisArg] Optional object when binding 'this' to the callback.
1635
1709
  */
1636
- LINK: "link",
1710
+ forEach(callback, thisArg) {
1711
+ this.#map.forEach(callback, thisArg);
1712
+ }
1637
1713
  /**
1638
- * Used in redirection, or when a new resource has been created.
1714
+ * Returns an iterable of parameter names.
1639
1715
  *
1640
- * @example
1641
- * location: http://www.w3.org/pub/WWW/People.html
1642
- * Permanent
1716
+ * @returns {IterableIterator<string>} The {@link IterableIterator} of media type parameter names.
1643
1717
  */
1644
- LOCATION: "location",
1718
+ keys() {
1719
+ return this.#map.keys();
1720
+ }
1645
1721
  /**
1646
- * This field is supposed to set P3P policy, in the form of P3P:CP="your_compact_policy". However, P3P did not take off, most browsers have never fully
1647
- * implemented it, a lot of websites set this field with fake policy text, that was enough to fool browsers the existence of P3P policy and grant permissions for third party cookies.
1722
+ * Returns an iterable of parameter values.
1648
1723
  *
1649
- * @example
1650
- * p3p: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
1651
- * Permanent
1724
+ * @returns {IterableIterator<string>} The {@link IterableIterator} of media type parameter values.
1652
1725
  */
1653
- P3P: "p3p",
1726
+ values() {
1727
+ return this.#map.values();
1728
+ }
1654
1729
  /**
1655
- * Implementation-specific fields that may have various effects anywhere along the request-response chain.
1730
+ * Returns an iterable of name, value pairs for every parameter entry in the media type parameters.
1656
1731
  *
1657
- * @example
1658
- * pragma: no-cache
1659
- * Permanent
1732
+ * @returns {IterableIterator<Array<Array<string>>>} The media type parameter entries.
1660
1733
  */
1661
- PRAGMA: "pragma",
1734
+ entries() {
1735
+ return this.#map.entries();
1736
+ }
1662
1737
  /**
1663
- * Request authentication to access the proxy.
1738
+ * A method that returns the default iterator for the {@link MediaTypeParameters}. Called by the semantics of the for-of statement.
1664
1739
  *
1665
- * @example
1666
- * proxy-authenticate: Basic
1667
- * Permanent
1740
+ * @returns {Iterator<string, string, undefined>} The {@link Symbol.iterator} for the media type parameters.
1668
1741
  */
1669
- PROXY_AUTHENTICATION: "proxy-authenticate",
1742
+ [Symbol.iterator]() {
1743
+ return this.#map[Symbol.iterator]();
1744
+ }
1670
1745
  /**
1671
- * HTTP Public Key Pinning, announces hash of website's authentic TLS certificate
1746
+ * Returns a string representation of the media type parameters.
1747
+ * This method is called by the `String()` function.
1672
1748
  *
1673
1749
  * @example
1674
- * public-key-pins: max-age=2592000, pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=",
1675
- * Permanent
1750
+ * const parameters = new MediaTypeParameters(new Map([['charset', 'utf-8']]));
1751
+ * String(parameters); // 'charset=utf-8'
1752
+ * parameters.toString(); // 'charset=utf-8'
1753
+ * parameters + ''; // 'charset=utf-8'
1754
+ * `${parameters}`; // 'charset=utf-8'
1755
+ * parameters[Symbol.toStringTag]; // 'MediaTypeParameters'
1756
+ * parameters[Symbol.toStringTag](); // 'MediaTypeParameters'
1757
+ * Object.prototype.toString.call(parameters); // '[object MediaTypeParameters]'
1758
+ * parameters + ''; // 'charset=utf-8'
1759
+ * @returns {string} The string representation of the media type parameters.
1676
1760
  */
1677
- PUBLIC_KEY_PINS: "public-key-pins",
1761
+ [Symbol.toStringTag]() {
1762
+ return "MediaTypeParameters";
1763
+ }
1764
+ };
1765
+
1766
+ // node_modules/@d1g1tal/media-type/src/parser.js
1767
+ var parse = (input) => {
1768
+ input = removeLeadingAndTrailingHTTPWhitespace(input);
1769
+ let position = 0;
1770
+ let type = "";
1771
+ while (position < input.length && input[position] != "/") {
1772
+ type += input[position];
1773
+ ++position;
1774
+ }
1775
+ if (type.length === 0 || !solelyContainsHTTPTokenCodePoints(type)) {
1776
+ return null;
1777
+ }
1778
+ if (position >= input.length) {
1779
+ return null;
1780
+ }
1781
+ ++position;
1782
+ let subtype = "";
1783
+ while (position < input.length && input[position] != ";") {
1784
+ subtype += input[position];
1785
+ ++position;
1786
+ }
1787
+ subtype = removeTrailingHTTPWhitespace(subtype);
1788
+ if (subtype.length === 0 || !solelyContainsHTTPTokenCodePoints(subtype)) {
1789
+ return null;
1790
+ }
1791
+ const mediaType = {
1792
+ type: asciiLowercase(type),
1793
+ subtype: asciiLowercase(subtype),
1794
+ parameters: /* @__PURE__ */ new Map()
1795
+ };
1796
+ while (position < input.length) {
1797
+ ++position;
1798
+ while (isHTTPWhitespaceChar(input[position])) {
1799
+ ++position;
1800
+ }
1801
+ let parameterName = "";
1802
+ while (position < input.length && input[position] != ";" && input[position] != "=") {
1803
+ parameterName += input[position];
1804
+ ++position;
1805
+ }
1806
+ parameterName = asciiLowercase(parameterName);
1807
+ if (position < input.length) {
1808
+ if (input[position] == ";") {
1809
+ continue;
1810
+ }
1811
+ ++position;
1812
+ }
1813
+ let parameterValue = null;
1814
+ if (input[position] == '"') {
1815
+ [parameterValue, position] = collectAnHTTPQuotedString(input, position);
1816
+ while (position < input.length && input[position] != ";") {
1817
+ ++position;
1818
+ }
1819
+ } else {
1820
+ parameterValue = "";
1821
+ while (position < input.length && input[position] != ";") {
1822
+ parameterValue += input[position];
1823
+ ++position;
1824
+ }
1825
+ parameterValue = removeTrailingHTTPWhitespace(parameterValue);
1826
+ if (parameterValue === "") {
1827
+ continue;
1828
+ }
1829
+ }
1830
+ if (parameterName.length > 0 && solelyContainsHTTPTokenCodePoints(parameterName) && solelyContainsHTTPQuotedStringTokenCodePoints(parameterValue) && !mediaType.parameters.has(parameterName)) {
1831
+ mediaType.parameters.set(parameterName, parameterValue);
1832
+ }
1833
+ }
1834
+ return mediaType;
1835
+ };
1836
+ var parser_default = parse;
1837
+
1838
+ // node_modules/@d1g1tal/media-type/src/serializer.js
1839
+ var serialize = (mediaType) => {
1840
+ let serialization = `${mediaType.type}/${mediaType.subtype}`;
1841
+ if (mediaType.parameters.size === 0) {
1842
+ return serialization;
1843
+ }
1844
+ for (let [name, value] of mediaType.parameters) {
1845
+ serialization += `;${name}=`;
1846
+ if (!solelyContainsHTTPTokenCodePoints(value) || value.length === 0) {
1847
+ value = `"${value.replace(/(["\\])/ug, "\\$1")}"`;
1848
+ }
1849
+ serialization += value;
1850
+ }
1851
+ return serialization;
1852
+ };
1853
+ var serializer_default = serialize;
1854
+
1855
+ // node_modules/@d1g1tal/media-type/src/media-type.js
1856
+ var MediaType = class _MediaType {
1857
+ /** @type {string} */
1858
+ #type;
1859
+ /** @type {string} */
1860
+ #subtype;
1861
+ /** @type {MediaTypeParameters} */
1862
+ #parameters;
1678
1863
  /**
1679
- * If an entity is temporarily unavailable, this instructs the client to try again later. Value could be a specified period of time (in seconds) or a HTTP-date.
1864
+ * Create a new MediaType instance from a string representation.
1680
1865
  *
1681
- * @example
1682
- * retry-after: 120
1683
- * retry-after: Fri, 07 Nov 2014 23:59:59 GMT
1684
- * Permanent
1866
+ * @param {string} mediaType The media type to parse.
1867
+ * @param {Object} [parameters] Optional parameters.
1685
1868
  */
1686
- RETRY_AFTER: "retry-after",
1869
+ constructor(mediaType, parameters = {}) {
1870
+ const { type, subtype, parameters: parsedParameters } = parser_default(mediaType);
1871
+ this.#type = type;
1872
+ this.#subtype = subtype;
1873
+ this.#parameters = new MediaTypeParameters([...parsedParameters, ...Object.entries(parameters).map(([name, value]) => [asciiLowercase(name), asciiLowercase(value)])]);
1874
+ }
1687
1875
  /**
1688
- * A name for the server
1876
+ * Static factory method for parsing a media type.
1689
1877
  *
1690
- * @example
1691
- * server: Apache/2.4.1 (Unix)
1692
- * Permanent
1878
+ * @param {string} string The media type to parse.
1879
+ * @returns {MediaType} The parsed {@link MediaType} object or null if the string could not be parsed.
1693
1880
  */
1694
- SERVER: "server",
1881
+ static parse(string) {
1882
+ try {
1883
+ return new _MediaType(string);
1884
+ } catch (e) {
1885
+ throw new Error(`Could not parse media type string '${string}'`);
1886
+ }
1887
+ }
1695
1888
  /**
1696
- * An HTTP cookie
1889
+ * Gets the media type essence (type/subtype).
1697
1890
  *
1698
- * @example
1699
- * set-cookie: UserID=JohnDoe, Max-Age=3600, Version=1
1700
- * Permanent
1891
+ * @returns {string} The media type without any parameters
1701
1892
  */
1702
- SET_COOKIE: "set-cookie",
1893
+ get essence() {
1894
+ return `${this.#type}/${this.#subtype}`;
1895
+ }
1703
1896
  /**
1704
- * CGI header field specifying the status of the HTTP response. Normal HTTP responses use a separate "Status-Line" instead, defined by RFC 7230.
1897
+ * Gets the type.
1705
1898
  *
1706
- * @example
1707
- * status: 200 OK
1899
+ * @returns {string} The type.
1708
1900
  */
1709
- STATUS: "status",
1901
+ get type() {
1902
+ return this.#type;
1903
+ }
1710
1904
  /**
1711
- * A HSTS Policy informing the HTTP client how long to cache the HTTPS only policy and whether this applies to subdomains.
1712
- *
1713
- * @example
1714
- * strict-transport-security: max-age=16070400, includeSubDomains
1715
- * Permanent
1905
+ * Sets the type.
1716
1906
  */
1717
- STRICT_TRANSPORT_SECURITY: "strict-transport-security",
1907
+ set type(value) {
1908
+ value = asciiLowercase(String(value));
1909
+ if (value.length === 0) {
1910
+ throw new Error("Invalid type: must be a non-empty string");
1911
+ }
1912
+ if (!solelyContainsHTTPTokenCodePoints(value)) {
1913
+ throw new Error(`Invalid type ${value}: must contain only HTTP token code points`);
1914
+ }
1915
+ this.#type = value;
1916
+ }
1718
1917
  /**
1719
- * The Trailer general field value indicates that the given set of header fields is present in the trailer of a message encoded with chunked transfer coding.
1918
+ * Gets the subtype.
1720
1919
  *
1721
- * @example
1722
- * trailer: Max-Forwards
1723
- * Permanent
1920
+ * @returns {string} The subtype.
1724
1921
  */
1725
- TRAILER: "trailer",
1922
+ get subtype() {
1923
+ return this.#subtype;
1924
+ }
1726
1925
  /**
1727
- * The form of encoding used to safely transfer the entity to the user. Currently defined methods are: chunked, compress, deflate, gzip, identity.
1728
- *
1729
- * @example
1730
- * transfer-encoding: chunked
1731
- * Permanent
1926
+ * Sets the subtype.
1732
1927
  */
1733
- TRANSFER_ENCODING: "transfer-encoding",
1928
+ set subtype(value) {
1929
+ value = asciiLowercase(String(value));
1930
+ if (value.length === 0) {
1931
+ throw new Error("Invalid subtype: must be a non-empty string");
1932
+ }
1933
+ if (!solelyContainsHTTPTokenCodePoints(value)) {
1934
+ throw new Error(`Invalid subtype ${value}: must contain only HTTP token code points`);
1935
+ }
1936
+ this.#subtype = value;
1937
+ }
1734
1938
  /**
1735
- * Ask the client to upgrade to another protocol.
1939
+ * Gets the parameters.
1736
1940
  *
1737
- * @example
1738
- * upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
1739
- * Permanent
1941
+ * @returns {MediaTypeParameters} The media type parameters.
1740
1942
  */
1741
- UPGRADE: "upgrade",
1943
+ get parameters() {
1944
+ return this.#parameters;
1945
+ }
1742
1946
  /**
1743
- * Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather than requesting a fresh one from the origin server.
1947
+ * Gets the serialized version of the media type.
1744
1948
  *
1745
- * @example
1746
- * vary: *
1747
- * Permanent
1949
+ * @returns {string} The serialized media type.
1748
1950
  */
1749
- VARY: "vary",
1951
+ toString() {
1952
+ return serializer_default(this);
1953
+ }
1750
1954
  /**
1751
- * Informs the client of proxies through which the response was sent.
1955
+ * Determines if this instance is a JavaScript media type.
1752
1956
  *
1753
- * @example
1754
- * via: 1.0 fred, 1.1 example.com (Apache/1.1)
1755
- * Permanent
1957
+ * @param {Object} [options] Optional options.
1958
+ * @param {boolean} [options.prohibitParameters=false] The option to prohibit parameters when checking if the media type is JavaScript.
1959
+ * @returns {boolean} true if this instance represents a JavaScript media type, false otherwise.
1756
1960
  */
1757
- VIA: "via",
1961
+ isJavaScript({ prohibitParameters = false } = {}) {
1962
+ switch (this.#type) {
1963
+ case "text": {
1964
+ switch (this.#subtype) {
1965
+ case "ecmascript":
1966
+ case "javascript":
1967
+ case "javascript1.0":
1968
+ case "javascript1.1":
1969
+ case "javascript1.2":
1970
+ case "javascript1.3":
1971
+ case "javascript1.4":
1972
+ case "javascript1.5":
1973
+ case "jscript":
1974
+ case "livescript":
1975
+ case "x-ecmascript":
1976
+ case "x-javascript":
1977
+ return !prohibitParameters || this.#parameters.size === 0;
1978
+ default:
1979
+ return false;
1980
+ }
1981
+ }
1982
+ case "application": {
1983
+ switch (this.#subtype) {
1984
+ case "ecmascript":
1985
+ case "javascript":
1986
+ case "x-ecmascript":
1987
+ case "x-javascript":
1988
+ return !prohibitParameters || this.#parameters.size === 0;
1989
+ default:
1990
+ return false;
1991
+ }
1992
+ }
1993
+ default:
1994
+ return false;
1995
+ }
1996
+ }
1758
1997
  /**
1759
- * A general warning about possible problems with the entity body.
1998
+ * Determines if this instance is an XML media type.
1760
1999
  *
1761
- * @example
1762
- * warning: 199 Miscellaneous warning
1763
- * Permanent
2000
+ * @returns {boolean} true if this instance represents an XML media type, false otherwise.
1764
2001
  */
1765
- WARNING: "warning",
2002
+ isXML() {
2003
+ return this.#subtype === "xml" && (this.#type === "text" || this.#type === "application") || this.#subtype.endsWith("+xml");
2004
+ }
1766
2005
  /**
1767
- * Indicates the authentication scheme that should be used to access the requested entity.
2006
+ * Determines if this instance is an HTML media type.
1768
2007
  *
1769
- * @example
1770
- * www-authenticate: Basic
1771
- * Permanent
2008
+ * @returns {boolean} true if this instance represents an HTML media type, false otherwise.
1772
2009
  */
1773
- WWW_AUTHENTICATE: "www-authenticate",
2010
+ isHTML() {
2011
+ return this.#subtype === "html" && this.#type === "text";
2012
+ }
1774
2013
  /**
1775
- * Cross-site scripting (XSS) filter
2014
+ * Gets the name of the class.
1776
2015
  *
1777
- * @example
1778
- * x-xss-protection: 1, mode=block
2016
+ * @returns {string} The class name
1779
2017
  */
1780
- X_XSS_PROTECTION: "x-xss-protection",
2018
+ get [Symbol.toStringTag]() {
2019
+ return "MediaType";
2020
+ }
2021
+ };
2022
+
2023
+ // src/constants.js
2024
+ var defaultCharset = "utf-8";
2025
+ var endsWithSlashRegEx = /\/$/;
2026
+ var mediaTypes = /* @__PURE__ */ new Map([
2027
+ [http_media_type_default.PNG, new MediaType(http_media_type_default.PNG)],
2028
+ [http_media_type_default.TEXT, new MediaType(http_media_type_default.TEXT, { defaultCharset })],
2029
+ [http_media_type_default.JSON, new MediaType(http_media_type_default.JSON, { defaultCharset })],
2030
+ [http_media_type_default.HTML, new MediaType(http_media_type_default.HTML, { defaultCharset })],
2031
+ [http_media_type_default.JAVA_SCRIPT, new MediaType(http_media_type_default.JAVA_SCRIPT, { defaultCharset })],
2032
+ [http_media_type_default.CSS, new MediaType(http_media_type_default.CSS, { defaultCharset })],
2033
+ [http_media_type_default.XML, new MediaType(http_media_type_default.XML, { defaultCharset })],
2034
+ [http_media_type_default.BIN, new MediaType(http_media_type_default.BIN)]
2035
+ ]);
2036
+ var RequestEvents = Object.freeze({
2037
+ CONFIGURED: "configured",
2038
+ SUCCESS: "success",
2039
+ ERROR: "error",
2040
+ ABORTED: "aborted",
2041
+ TIMEOUT: "timeout",
2042
+ COMPLETE: "complete",
2043
+ ALL_COMPLETE: "all-complete"
2044
+ });
2045
+ var SignalEvents = Object.freeze({
2046
+ ABORT: "abort",
2047
+ TIMEOUT: "timeout"
2048
+ });
2049
+ var _abortEvent = new CustomEvent(SignalEvents.ABORT, { detail: { cause: new DOMException("The request was aborted", "AbortError") } });
2050
+ var requestBodyMethods = [http_request_methods_default.POST, http_request_methods_default.PUT, http_request_methods_default.PATCH];
2051
+
2052
+ // src/abort-signal.js
2053
+ var NativeAbortSignal = globalThis.AbortSignal;
2054
+ var AbortSignal = class _AbortSignal extends EventTarget {
2055
+ /** @type {AbortController} */
2056
+ #abortController;
2057
+ /** @type {number} */
2058
+ #timeoutId;
1781
2059
  /**
1782
- * The HTTP Content-Security-Policy response header allows web site administrators to control resources the user agent is allowed
1783
- * to load for a given page. With a few exceptions, policies mostly involve specifying server origins and script endpoints.
1784
- * This helps guard against cross-site scripting attacks (Cross-site_scripting).
1785
- *
1786
- * @example
1787
- * content-security-policy: default-src
2060
+ * @param {AbortSignal} signal The signal to listen to
1788
2061
  */
1789
- CONTENT_SECURITY_POLICY: "content-security-policy",
2062
+ constructor(signal) {
2063
+ super();
2064
+ this.#abortController = new AbortController();
2065
+ signal?.addEventListener(SignalEvents.ABORT, (event) => this.#abort(event));
2066
+ }
1790
2067
  /**
1791
- * The only defined value, "nosniff", prevents Internet Explorer from MIME-sniffing a response away from the declared content-type. This also applies to Google Chrome, when downloading extensions.
2068
+ * Returns an {@link AbortSignal} instance that is already set as aborted.
1792
2069
  *
1793
- * @example
1794
- * x-content-type-options: nosniff
2070
+ * @static
2071
+ * @returns {AbortSignal} The abort signal
1795
2072
  */
1796
- X_CONTENT_TYPE_OPTIONS: "x-content-type-options",
2073
+ static abort() {
2074
+ return NativeAbortSignal.abort();
2075
+ }
1797
2076
  /**
1798
- * specifies the technology (e.g. ASP.NET, PHP, JBoss) supporting the web application (version details are often in X-Runtime, X-Version, or X-AspNet-Version)
2077
+ * Returns an AbortSignal instance that will automatically abort after a specified time.
1799
2078
  *
1800
- * @example
1801
- * x-powered-by: PHP/5.4.0
2079
+ * @static
2080
+ * @param {number} time The time in milliseconds to wait before aborting
2081
+ * @returns {AbortSignal} The abort signal
1802
2082
  */
1803
- X_POWERED_BY: "x-powered-by"
1804
- };
1805
- var http_response_headers_default = HttpResponseHeader;
1806
-
1807
- // src/response-status.js
1808
- var ResponseStatus = class {
1809
- /** @type {number} */
1810
- #code;
1811
- /** @type {string} */
1812
- #text;
2083
+ static timeout(time) {
2084
+ return NativeAbortSignal.timeout(time);
2085
+ }
1813
2086
  /**
2087
+ * The aborted property is a Boolean that indicates whether the request has been aborted (true) or not (false).
1814
2088
  *
1815
- * @param {number} code The status code from the {@link Response}
1816
- * @param {string} text The status text from the {@link Response}
2089
+ * @returns {boolean} Whether the signal was aborted or not
1817
2090
  */
1818
- constructor(code, text) {
1819
- this.#code = code;
1820
- this.#text = text;
2091
+ get aborted() {
2092
+ return this.#abortController.signal.aborted;
1821
2093
  }
1822
2094
  /**
1823
- * Returns the status code from the {@link Response}
2095
+ * The reason property returns a DOMException object indicating the reason the operation was aborted, or null if the operation is not aborted.
1824
2096
  *
1825
- * @returns {number} The status code.
2097
+ * @returns {DOMException} The reason the signal was aborted
1826
2098
  */
1827
- get code() {
1828
- return this.#code;
2099
+ get reason() {
2100
+ return this.#abortController.signal.reason;
1829
2101
  }
1830
2102
  /**
1831
- * Returns the status text from the {@link Response}.
2103
+ * throws the signal's abort reason if the signal has been aborted; otherwise it does nothing.
1832
2104
  *
1833
- * @returns {string} The status text.
2105
+ * @returns {void}
1834
2106
  */
1835
- get text() {
1836
- return this.#text;
2107
+ throwIfAborted() {
2108
+ this.#abortController.signal.throwIfAborted();
1837
2109
  }
1838
2110
  /**
1839
- * A String value that is used in the creation of the default string
1840
- * description of an object. Called by the built-in method {@link Object.prototype.toString}.
2111
+ * Returns an AbortSignal instance that will be aborted when the provided amount of milliseconds have passed.
2112
+ * A value of -1 (which is the default) means there is no timeout.
2113
+ * Note: You can't set this property to a value less than 0.
1841
2114
  *
1842
- * @override
1843
- * @returns {string} The default string description of this object.
2115
+ * @param {number} timeout The timeout in milliseconds
2116
+ * @returns {AbortSignal} The abort signal
1844
2117
  */
1845
- get [Symbol.toStringTag]() {
1846
- return "ResponseStatus";
2118
+ withTimeout(timeout) {
2119
+ if (timeout < 0) {
2120
+ throw new RangeError("The timeout cannot be negative");
2121
+ }
2122
+ this.#timeoutId ??= setTimeout(() => this.#abort(_AbortSignal.#generateTimeoutEvent(timeout), true), timeout);
2123
+ return this.#abortController.signal;
1847
2124
  }
1848
2125
  /**
1849
- * tostring method for the class.
2126
+ * Clears the timeout.
2127
+ * Note: This does not abort the signal, dispatch the timeout event, or reset the timeout.
2128
+ *
2129
+ * @returns {void}
2130
+ */
2131
+ clearTimeout() {
2132
+ clearTimeout(this.#timeoutId);
2133
+ }
2134
+ /**
2135
+ * Adds an event listener for the specified event type.
1850
2136
  *
1851
2137
  * @override
1852
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString|Object.prototype.toString}
1853
- * @returns {string} The status code and status text.
2138
+ * @param {string} eventName The name of the event to listen to
2139
+ * @param {EventListener} listener The listener to add
2140
+ * @returns {void}
1854
2141
  */
1855
- toString() {
1856
- return `${this.#code} ${this.#text}`;
2142
+ addEventListener(eventName, listener) {
2143
+ this.#abortController.signal.addEventListener(eventName, listener);
1857
2144
  }
1858
- };
1859
-
1860
- // src/signal-controller.js
1861
- var SignalController = class {
1862
- /** @type {AbortController} */
1863
- #abortController;
1864
2145
  /**
1865
- * @param {AbortSignal} [signal] The signal to be used to abort the request.
2146
+ * Dispatches an event to this EventTarget.
2147
+ *
2148
+ * @override
2149
+ * @param {Event} event The event to dispatch
2150
+ * @returns {boolean} Whether the event was dispatched or not
1866
2151
  */
1867
- constructor(signal) {
1868
- this.#abortController = new AbortController();
1869
- signal?.addEventListener("abort", () => this.#abortController.abort());
2152
+ dispatchEvent(event) {
2153
+ return this.#abortController.signal.dispatchEvent(event);
1870
2154
  }
1871
2155
  /**
1872
- * Returns the {@link AbortSignal} object associated with this object.
2156
+ * Removes an event listener for the specified event type.
1873
2157
  *
1874
- * @returns {AbortSignal} The {@link AbortSignal} object associated with this object.
2158
+ * @override
2159
+ * @param {string} eventName The name of the event to listen to
2160
+ * @param {EventListener} listener The listener to remove
2161
+ * @returns {void}
1875
2162
  */
1876
- get signal() {
1877
- return this.#abortController.signal;
2163
+ removeEventListener(eventName, listener) {
2164
+ this.#abortController.signal.removeEventListener(eventName, listener);
1878
2165
  }
1879
2166
  /**
1880
- * Aborts a DOM request before it has completed.
1881
- * This is able to abort fetch requests, data sent using the XMLHttpRequest API, and Web Sockets.
2167
+ * Aborts the signal. This is so naughty. ¯\_(ツ)_/¯
1882
2168
  *
1883
- * @param {DOMException} [reason] The reason for aborting the request.
2169
+ * @param {Event} event The event to abort with
1884
2170
  * @returns {void}
1885
2171
  */
1886
- abort(reason) {
1887
- this.#abortController.abort(reason);
2172
+ abort(event) {
2173
+ this.#abort(event);
1888
2174
  }
1889
2175
  /**
1890
- * A String value that is used in the creation of the default string
1891
- * description of an object. Called by the built-in method {@link Object.prototype.toString}.
2176
+ * Aborts the signal.
1892
2177
  *
1893
- * @override
1894
- * @returns {string} The default string description of this object.
2178
+ * @private
2179
+ * @param {Event} event The event to abort with
2180
+ * @param {boolean} [dispatchEvent = false] Whether to dispatch the event or not
2181
+ * @returns {void}
2182
+ * @fires SignalEvents.ABORT When the signal is aborted
2183
+ * @fires SignalEvents.TIMEOUT When the signal times out
2184
+ */
2185
+ #abort(event = _abortEvent, dispatchEvent = false) {
2186
+ clearTimeout(this.#timeoutId);
2187
+ this.#abortController.abort(event.detail?.cause);
2188
+ if (dispatchEvent) {
2189
+ this.#abortController.signal.dispatchEvent(event);
2190
+ }
2191
+ }
2192
+ /**
2193
+ * Generates a timeout event.
2194
+ *
2195
+ * @private
2196
+ * @static
2197
+ * @param {number} timeout The timeout in milliseconds
2198
+ * @returns {CustomEvent} The timeout event
1895
2199
  */
1896
- get [Symbol.toStringTag]() {
1897
- return "SignalController";
2200
+ static #generateTimeoutEvent(timeout) {
2201
+ return new CustomEvent(SignalEvents.TIMEOUT, { detail: { timeout, cause: new DOMException(`The request timed-out after ${timeout / 1e3} seconds`, "TimeoutError") } });
2202
+ }
2203
+ };
2204
+
2205
+ // node_modules/@d1g1tal/chrysalis/src/esm/object-type.js
2206
+ var _type = (object) => object?.constructor ?? object?.prototype?.constructor ?? globalThis[Object.prototype.toString.call(object).slice(8, -1)] ?? object;
2207
+ var object_type_default = _type;
2208
+
2209
+ // node_modules/@d1g1tal/chrysalis/src/esm/object-merge.js
2210
+ var _objectMerge = (...objects) => {
2211
+ const target = {};
2212
+ for (const source of objects) {
2213
+ if (object_type_default(source) != Object)
2214
+ return void 0;
2215
+ let descriptor, sourceType;
2216
+ for (const property of Object.getOwnPropertyNames(source)) {
2217
+ descriptor = Object.getOwnPropertyDescriptor(source, property);
2218
+ if (descriptor.enumerable) {
2219
+ sourceType = object_type_default(source[property]);
2220
+ if (sourceType == Object) {
2221
+ descriptor.value = object_type_default(target[property]) == Object ? _objectMerge(target[property], source[property]) : { ...source[property] };
2222
+ } else if (sourceType == Array) {
2223
+ descriptor.value = Array.isArray(target[property]) ? [.../* @__PURE__ */ new Set([...source[property], ...target[property]])] : [...source[property]];
2224
+ }
2225
+ target[property] = descriptor.value;
2226
+ }
2227
+ }
1898
2228
  }
2229
+ return target;
1899
2230
  };
2231
+ var object_merge_default = _objectMerge;
1900
2232
 
1901
2233
  // src/transportr.js
1902
- var endsWithSlashRegEx = /\/$/;
1903
- var charset = "utf-8";
1904
- var _mediaTypes = /* @__PURE__ */ new Map([
1905
- [http_media_type_default.PNG, new MediaType(http_media_type_default.PNG)],
1906
- [http_media_type_default.TEXT, new MediaType(http_media_type_default.TEXT, { charset })],
1907
- [http_media_type_default.JSON, new MediaType(http_media_type_default.JSON, { charset })],
1908
- [http_media_type_default.HTML, new MediaType(http_media_type_default.HTML, { charset })],
1909
- [http_media_type_default.JAVA_SCRIPT, new MediaType(http_media_type_default.JAVA_SCRIPT, { charset })],
1910
- [http_media_type_default.CSS, new MediaType(http_media_type_default.CSS, { charset })],
1911
- [http_media_type_default.XML, new MediaType(http_media_type_default.XML, { charset })],
1912
- [http_media_type_default.BIN, new MediaType(http_media_type_default.BIN)]
1913
- ]);
1914
2234
  var _handleText = async (response) => await response.text();
1915
2235
  var _handleScript = async (response) => {
1916
2236
  const objectURL = URL.createObjectURL(await response.blob());
@@ -1932,7 +2252,6 @@ var Transportr = (() => {
1932
2252
  var _handleXml = async (response) => new DOMParser().parseFromString(await response.text(), http_media_type_default.XML);
1933
2253
  var _handleHtml = async (response) => new DOMParser().parseFromString(await response.text(), http_media_type_default.HTML);
1934
2254
  var _handleHtmlFragment = async (response) => document.createRange().createContextualFragment(await response.text());
1935
- var _typeConverter = (data) => Object.fromEntries(Array.from(data.keys()).map((key, index, keys, value = data.getAll(key)) => [key, value.length > 1 ? value : value[0]]));
1936
2255
  var Transportr = class _Transportr {
1937
2256
  /** @type {URL} */
1938
2257
  #baseUrl;
@@ -1942,32 +2261,18 @@ var Transportr = (() => {
1942
2261
  #subscribr;
1943
2262
  /** @type {Subscribr} */
1944
2263
  static #globalSubscribr = new Subscribr();
1945
- /** @type {Array<SignalController>} */
1946
- static #activeRequests = [];
1947
- /**
1948
- * @private
1949
- * @static
1950
- * @type {SetMultiMap<ResponseHandler<ResponseBody>, string>}
1951
- */
2264
+ /** @type {Set<AbortSignal>} */
2265
+ static #activeRequests = /* @__PURE__ */ new Set();
2266
+ /** @type {SetMultiMap<ResponseHandler<ResponseBody>, string>} */
1952
2267
  static #contentTypeHandlers = new set_multi_map_default([
1953
- [_handleImage, _mediaTypes.get(http_media_type_default.PNG).type],
1954
- [_handleText, _mediaTypes.get(http_media_type_default.TEXT).type],
1955
- [_handleJson, _mediaTypes.get(http_media_type_default.JSON).subtype],
1956
- [_handleHtml, _mediaTypes.get(http_media_type_default.HTML).subtype],
1957
- [_handleScript, _mediaTypes.get(http_media_type_default.JAVA_SCRIPT).subtype],
1958
- [_handleCss, _mediaTypes.get(http_media_type_default.CSS).subtype],
1959
- [_handleXml, _mediaTypes.get(http_media_type_default.XML).subtype],
1960
- [_handleReadableStream, _mediaTypes.get(http_media_type_default.BIN).subtype]
1961
- ]);
1962
- /**
1963
- * @private
1964
- * @static
1965
- * @type {Set<PropertyTypeConverter>}
1966
- */
1967
- static #propertyTypeConverters = /* @__PURE__ */ new Set([
1968
- [{ property: "body", type: FormData, converter: _typeConverter }],
1969
- [{ property: "searchParams", type: URLSearchParams, converter: _typeConverter }],
1970
- [{ property: "headers", type: Headers, converter: Object.fromEntries }]
2268
+ [_handleImage, mediaTypes.get(http_media_type_default.PNG).type],
2269
+ [_handleText, mediaTypes.get(http_media_type_default.TEXT).type],
2270
+ [_handleJson, mediaTypes.get(http_media_type_default.JSON).subtype],
2271
+ [_handleHtml, mediaTypes.get(http_media_type_default.HTML).subtype],
2272
+ [_handleScript, mediaTypes.get(http_media_type_default.JAVA_SCRIPT).subtype],
2273
+ [_handleCss, mediaTypes.get(http_media_type_default.CSS).subtype],
2274
+ [_handleXml, mediaTypes.get(http_media_type_default.XML).subtype],
2275
+ [_handleReadableStream, mediaTypes.get(http_media_type_default.BIN).subtype]
1971
2276
  ]);
1972
2277
  /**
1973
2278
  * Create a new Transportr instance with the provided location or origin and context path.
@@ -1975,65 +2280,14 @@ var Transportr = (() => {
1975
2280
  * @param {URL|string|RequestOptions} [url=location.origin] The URL for {@link fetch} requests.
1976
2281
  * @param {RequestOptions} [options={}] The default {@link RequestOptions} for this instance.
1977
2282
  */
1978
- constructor(url = location.origin, options = {}) {
1979
- const type = object_type_default(url);
1980
- if (type == Object) {
1981
- options = url;
1982
- url = location.origin;
1983
- } else if (type != URL) {
1984
- url = url.startsWith("/") ? new URL(url, location.origin) : new URL(url);
2283
+ constructor(url = globalThis.location.origin, options = {}) {
2284
+ if (object_type_default(url) == Object) {
2285
+ [url, options] = [globalThis.location.origin, url];
1985
2286
  }
1986
- this.#baseUrl = url;
1987
- this.#options = object_merge_default(_Transportr.#defaultRequestOptions, _Transportr.#convertRequestOptions(options));
2287
+ this.#baseUrl = _Transportr.#getBaseUrl(url);
2288
+ this.#options = _Transportr.#createOptions(options, _Transportr.#defaultRequestOptions);
1988
2289
  this.#subscribr = new Subscribr();
1989
2290
  }
1990
- /**
1991
- * Returns a {@link SignalController} used for aborting requests.
1992
- *
1993
- * @static
1994
- * @param {AbortSignal} [signal] The optional {@link AbortSignal} to used for chaining.
1995
- * @returns {SignalController} A new {@link SignalController} instance.
1996
- */
1997
- static signalController(signal) {
1998
- return new SignalController(signal);
1999
- }
2000
- /**
2001
- * Returns a {@link EventRegistration} used for subscribing to global events.
2002
- *
2003
- * @static
2004
- * @param {TransportrEvent} event The event to subscribe to.
2005
- * @param {function(Event, *): void} handler The event handler.
2006
- * @param {*} context The context to bind the handler to.
2007
- * @returns {EventRegistration} A new {@link EventRegistration} instance.
2008
- */
2009
- static register(event, handler, context) {
2010
- return _Transportr.#globalSubscribr.subscribe(event, handler, context);
2011
- }
2012
- /**
2013
- * Removes a {@link EventRegistration} from the global event handler.
2014
- *
2015
- * @static
2016
- * @param {EventRegistration} eventRegistration The {@link EventRegistration} to remove.
2017
- * @returns {boolean} True if the {@link EventRegistration} was removed, false otherwise.
2018
- */
2019
- static unregister(eventRegistration) {
2020
- return _Transportr.#globalSubscribr.unsubscribe(eventRegistration);
2021
- }
2022
- /**
2023
- * Aborts all active requests.
2024
- * This is useful for when the user navigates away from the current page.
2025
- * This will also clear the {@link Transportr#activeRequests} array.
2026
- * This is called automatically when the {@link Transportr#abort} method is called.
2027
- *
2028
- * @static
2029
- * @returns {void}
2030
- */
2031
- static abortAll() {
2032
- for (const signalController of this.#activeRequests) {
2033
- signalController.abort();
2034
- }
2035
- this.#activeRequests = [];
2036
- }
2037
2291
  /**
2038
2292
  * @static
2039
2293
  * @constant {Object<string, HttpRequestMethod>}
@@ -2113,15 +2367,7 @@ var Transportr = (() => {
2113
2367
  * @static
2114
2368
  * @constant {Object<string, TransportrEvent>}
2115
2369
  */
2116
- static Events = Object.freeze({
2117
- CONFIGURED: "configured",
2118
- SUCCESS: "success",
2119
- ERROR: "error",
2120
- ABORTED: "aborted",
2121
- TIMEOUT: "timeout",
2122
- COMPLETE: "complete",
2123
- ALL_COMPLETE: "all-complete"
2124
- });
2370
+ static RequestEvents = RequestEvents;
2125
2371
  /**
2126
2372
  * @private
2127
2373
  * @static
@@ -2131,7 +2377,7 @@ var Transportr = (() => {
2131
2377
  body: null,
2132
2378
  cache: _Transportr.CachingPolicy.NO_STORE,
2133
2379
  credentials: _Transportr.CredentialsPolicy.SAME_ORIGIN,
2134
- headers: { [http_request_headers_default.CONTENT_TYPE]: _mediaTypes.get(http_media_type_default.JSON).toString(), [http_request_headers_default.ACCEPT]: _mediaTypes.get(http_media_type_default.JSON).toString() },
2380
+ headers: { [http_request_headers_default.CONTENT_TYPE]: mediaTypes.get(http_media_type_default.JSON).toString(), [http_request_headers_default.ACCEPT]: mediaTypes.get(http_media_type_default.JSON).toString() },
2135
2381
  searchParams: {},
2136
2382
  integrity: void 0,
2137
2383
  keepalive: void 0,
@@ -2151,9 +2397,54 @@ var Transportr = (() => {
2151
2397
  * @type {Map<TransportrEvent, ResponseStatus>}
2152
2398
  */
2153
2399
  static #eventResponseStatuses = /* @__PURE__ */ new Map([
2154
- [_Transportr.Events.ABORTED, new ResponseStatus(499, "Aborted")],
2155
- [_Transportr.Events.TIMEOUT, new ResponseStatus(504, "Gateway Timeout")]
2400
+ [RequestEvents.ABORTED, new ResponseStatus(499, "Aborted")],
2401
+ [RequestEvents.TIMEOUT, new ResponseStatus(504, "Gateway Timeout")]
2156
2402
  ]);
2403
+ /**
2404
+ * Returns a {@link AbortSignal} used for aborting requests.
2405
+ *
2406
+ * @static
2407
+ * @returns {AbortSignal} A new {@link AbortSignal} instance.
2408
+ */
2409
+ static abortSignal() {
2410
+ return new AbortSignal();
2411
+ }
2412
+ /**
2413
+ * Returns a {@link EventRegistration} used for subscribing to global events.
2414
+ *
2415
+ * @static
2416
+ * @param {TransportrEvent} event The event to subscribe to.
2417
+ * @param {function(Event, *): void} handler The event handler.
2418
+ * @param {*} context The context to bind the handler to.
2419
+ * @returns {EventRegistration} A new {@link EventRegistration} instance.
2420
+ */
2421
+ static register(event, handler, context) {
2422
+ return _Transportr.#globalSubscribr.subscribe(event, handler, context);
2423
+ }
2424
+ /**
2425
+ * Removes a {@link EventRegistration} from the global event handler.
2426
+ *
2427
+ * @static
2428
+ * @param {EventRegistration} eventRegistration The {@link EventRegistration} to remove.
2429
+ * @returns {boolean} True if the {@link EventRegistration} was removed, false otherwise.
2430
+ */
2431
+ static unregister(eventRegistration) {
2432
+ return _Transportr.#globalSubscribr.unsubscribe(eventRegistration);
2433
+ }
2434
+ /**
2435
+ * Aborts all active requests.
2436
+ * This is useful for when the user navigates away from the current page.
2437
+ * This will also clear the {@link Transportr#activeRequests} set.
2438
+ *
2439
+ * @static
2440
+ * @returns {void}
2441
+ */
2442
+ static abortAll() {
2443
+ for (const abortSignal of this.#activeRequests) {
2444
+ abortSignal.abort(_abortEvent);
2445
+ }
2446
+ this.#activeRequests.clear();
2447
+ }
2157
2448
  /**
2158
2449
  * It returns the base {@link URL} for the API.
2159
2450
  *
@@ -2187,8 +2478,8 @@ var Transportr = (() => {
2187
2478
  * the specified options, where the method is GET.
2188
2479
  *
2189
2480
  * @async
2190
- * @param {string} path - The path to the resource you want to get.
2191
- * @param {RequestOptions} [options] - The options for the request.
2481
+ * @param {string} [path] The path to the resource you want to get.
2482
+ * @param {RequestOptions} [options] The options for the request.
2192
2483
  * @returns {Promise<ResponseBody>} A promise that resolves to the response of the request.
2193
2484
  */
2194
2485
  async get(path, options) {
@@ -2198,9 +2489,9 @@ var Transportr = (() => {
2198
2489
  * This function makes a POST request to the given path with the given body and options.
2199
2490
  *
2200
2491
  * @async
2201
- * @param {string} path - The path to the endpoint you want to call.
2202
- * @param {RequestBody} body - The body of the request.
2203
- * @param {RequestOptions} [options] - The options for the request.
2492
+ * @param {string} [path] The path to the endpoint you want to call.
2493
+ * @param {RequestBody} body The body of the request.
2494
+ * @param {RequestOptions} [options] The options for the request.
2204
2495
  * @returns {Promise<ResponseBody>} A promise that resolves to the response body.
2205
2496
  */
2206
2497
  async post(path, body, options) {
@@ -2211,8 +2502,8 @@ var Transportr = (() => {
2211
2502
  * the specified options, where the method is PUT.
2212
2503
  *
2213
2504
  * @async
2214
- * @param {string} path - The path to the endpoint you want to call.
2215
- * @param {RequestOptions} [options] - The options for the request.
2505
+ * @param {string} [path] The path to the endpoint you want to call.
2506
+ * @param {RequestOptions} [options] The options for the request.
2216
2507
  * @returns {Promise<ResponseBody>} The return value of the #request method.
2217
2508
  */
2218
2509
  async put(path, options) {
@@ -2222,8 +2513,8 @@ var Transportr = (() => {
2222
2513
  * It takes a path and options, and returns a request with the method set to PATCH.
2223
2514
  *
2224
2515
  * @async
2225
- * @param {string} path - The path to the endpoint you want to hit.
2226
- * @param {RequestOptions} [options] - The options for the request.
2516
+ * @param {string} [path] The path to the endpoint you want to hit.
2517
+ * @param {RequestOptions} [options] The options for the request.
2227
2518
  * @returns {Promise<ResponseBody>} A promise that resolves to the response of the request.
2228
2519
  */
2229
2520
  async patch(path, options) {
@@ -2233,8 +2524,8 @@ var Transportr = (() => {
2233
2524
  * It takes a path and options, and returns a request with the method set to DELETE.
2234
2525
  *
2235
2526
  * @async
2236
- * @param {string} path - The path to the resource you want to access.
2237
- * @param {RequestOptions} [options] - The options for the request.
2527
+ * @param {string} [path] The path to the resource you want to access.
2528
+ * @param {RequestOptions} [options] The options for the request.
2238
2529
  * @returns {Promise<ResponseBody>} The result of the request.
2239
2530
  */
2240
2531
  async delete(path, options) {
@@ -2244,111 +2535,112 @@ var Transportr = (() => {
2244
2535
  * Returns the response headers of a request to the given path.
2245
2536
  *
2246
2537
  * @async
2247
- * @param {string} path - The path to the resource you want to access.
2248
- * @param {RequestOptions} [options] - The options for the request.
2538
+ * @param {string} [path] The path to the resource you want to access.
2539
+ * @param {RequestOptions} [options] The options for the request.
2249
2540
  * @returns {Promise<ResponseBody>} A promise that resolves to the response object.
2250
2541
  */
2251
2542
  async head(path, options) {
2252
2543
  return this.#request(path, options, { method: http_request_methods_default.HEAD });
2253
2544
  }
2254
2545
  /**
2255
- * It takes a path and options, and returns a request with the method set to OPTIONS.
2546
+ * It returns a promise that resolves to the allowed request methods for the given resource path.
2256
2547
  *
2257
2548
  * @async
2258
- * @param {string} path - The path to the resource.
2259
- * @param {RequestOptions} [options] - The options for the request.
2260
- * @returns {Promise<ResponseBody>} The return value of the #request method.
2549
+ * @param {string} [path] The path to the resource.
2550
+ * @param {RequestOptions} [options] The options for the request.
2551
+ * @returns {Promise<string[]>} A promise that resolves to an array of allowed request methods for this resource.
2261
2552
  */
2262
2553
  async options(path, options) {
2263
- return this.#request(path, options, { method: http_request_methods_default.OPTIONS });
2554
+ const response = await this.#request(path, options, { method: http_request_methods_default.OPTIONS });
2555
+ return response.headers.get("allow").split(",").map((method) => method.trim());
2264
2556
  }
2265
2557
  /**
2266
2558
  * It takes a path and options, and makes a request to the server.
2267
2559
  *
2268
2560
  * @async
2269
- * @param {string} path - The path to the endpoint you want to hit.
2270
- * @param {RequestOptions} [options] - The options for the request.
2561
+ * @param {string} [path] The path to the endpoint you want to hit.
2562
+ * @param {RequestOptions} [userOptions] The options for the request.
2271
2563
  * @returns {Promise<ResponseBody>} The return value of the function is the return value of the function that is passed to the `then` method of the promise returned by the `fetch` method.
2272
2564
  */
2273
- async request(path, options) {
2274
- return this.#request(path, options);
2565
+ async request(path, userOptions) {
2566
+ return this.#request(path, userOptions, {}, (response) => response);
2275
2567
  }
2276
2568
  /**
2277
2569
  * It gets a JSON resource from the server.
2278
2570
  *
2279
2571
  * @async
2280
- * @param {string} path - The path to the resource.
2281
- * @param {RequestOptions} [options] - The options object to pass to the request.
2572
+ * @param {string} [path] The path to the resource.
2573
+ * @param {RequestOptions} [options] The options object to pass to the request.
2282
2574
  * @returns {Promise<JsonObject>} A promise that resolves to the response body as a JSON object.
2283
2575
  */
2284
2576
  async getJson(path, options) {
2285
- return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: _mediaTypes.get(http_media_type_default.JSON).toString() } }, _handleJson);
2577
+ return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: mediaTypes.get(http_media_type_default.JSON).toString() } }, _handleJson);
2286
2578
  }
2287
2579
  /**
2288
2580
  * It gets the XML representation of the resource at the given path.
2289
2581
  *
2290
2582
  * @async
2291
- * @param {string} path - The path to the resource you want to get.
2292
- * @param {RequestOptions} [options] - The options for the request.
2583
+ * @param {string} [path] The path to the resource you want to get.
2584
+ * @param {RequestOptions} [options] The options for the request.
2293
2585
  * @returns {Promise<Document>} The result of the function call to #get.
2294
2586
  */
2295
2587
  async getXml(path, options) {
2296
- return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: _mediaTypes.get(http_media_type_default.XML).toString() } }, _handleXml);
2588
+ return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: mediaTypes.get(http_media_type_default.XML).toString() } }, _handleXml);
2297
2589
  }
2298
2590
  /**
2299
2591
  * Get the HTML content of the specified path.
2300
2592
  *
2301
2593
  * @todo Add way to return portion of the retrieved HTML using a selector. Like jQuery.
2302
2594
  * @async
2303
- * @param {string} path - The path to the resource.
2304
- * @param {RequestOptions} [options] - The options for the request.
2595
+ * @param {string} [path] The path to the resource.
2596
+ * @param {RequestOptions} [options] The options for the request.
2305
2597
  * @returns {Promise<Document>} The return value of the function is the return value of the function passed to the `then`
2306
2598
  * method of the promise returned by the `#get` method.
2307
2599
  */
2308
2600
  async getHtml(path, options) {
2309
- return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: _mediaTypes.get(http_media_type_default.HTML).toString() } }, _handleHtml);
2601
+ return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: mediaTypes.get(http_media_type_default.HTML).toString() } }, _handleHtml);
2310
2602
  }
2311
2603
  /**
2312
2604
  * It returns a promise that resolves to the HTML fragment at the given path.
2313
2605
  *
2314
- * @todo - Add way to return portion of the retrieved HTML using a selector. Like jQuery.
2606
+ * @todo Add way to return portion of the retrieved HTML using a selector. Like jQuery.
2315
2607
  * @async
2316
- * @param {string} path - The path to the resource.
2317
- * @param {RequestOptions} [options] - The options for the request.
2608
+ * @param {string} [path] The path to the resource.
2609
+ * @param {RequestOptions} [options] The options for the request.
2318
2610
  * @returns {Promise<DocumentFragment>} A promise that resolves to an HTML fragment.
2319
2611
  */
2320
2612
  async getHtmlFragment(path, options) {
2321
- return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: _mediaTypes.get(http_media_type_default.HTML).toString() } }, _handleHtmlFragment);
2613
+ return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: mediaTypes.get(http_media_type_default.HTML).toString() } }, _handleHtmlFragment);
2322
2614
  }
2323
2615
  /**
2324
2616
  * It gets a script from the server, and appends the script to the {@link Document} {@link HTMLHeadElement}
2325
2617
  * CORS is enabled by default.
2326
2618
  *
2327
2619
  * @async
2328
- * @param {string} path - The path to the script.
2329
- * @param {RequestOptions} [options] - The options for the request.
2620
+ * @param {string} [path] The path to the script.
2621
+ * @param {RequestOptions} [options] The options for the request.
2330
2622
  * @returns {Promise<void>} A promise that has been resolved.
2331
2623
  */
2332
2624
  async getScript(path, options) {
2333
- return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: _mediaTypes.get(http_media_type_default.JAVA_SCRIPT).toString() } }, _handleScript);
2625
+ return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: mediaTypes.get(http_media_type_default.JAVA_SCRIPT).toString() } }, _handleScript);
2334
2626
  }
2335
2627
  /**
2336
2628
  * Gets a stylesheet from the server, and adds it as a {@link Blob} {@link URL}.
2337
2629
  *
2338
2630
  * @async
2339
- * @param {string} path - The path to the stylesheet.
2340
- * @param {RequestOptions} [options] - The options for the request.
2631
+ * @param {string} [path] The path to the stylesheet.
2632
+ * @param {RequestOptions} [options] The options for the request.
2341
2633
  * @returns {Promise<void>} A promise that has been resolved.
2342
2634
  */
2343
2635
  async getStylesheet(path, options) {
2344
- return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: _mediaTypes.get(http_media_type_default.CSS).toString() } }, _handleCss);
2636
+ return this.#get(path, options, { headers: { [http_request_headers_default.ACCEPT]: mediaTypes.get(http_media_type_default.CSS).toString() } }, _handleCss);
2345
2637
  }
2346
2638
  /**
2347
2639
  * It returns a blob from the specified path.
2348
2640
  *
2349
2641
  * @async
2350
- * @param {string} path - The path to the resource.
2351
- * @param {RequestOptions} [options] - The options for the request.
2642
+ * @param {string} [path] The path to the resource.
2643
+ * @param {RequestOptions} [options] The options for the request.
2352
2644
  * @returns {Promise<Blob>} A promise that resolves to a blob.
2353
2645
  */
2354
2646
  async getBlob(path, options) {
@@ -2358,8 +2650,8 @@ var Transportr = (() => {
2358
2650
  * It returns a promise that resolves to an object URL.
2359
2651
  *
2360
2652
  * @async
2361
- * @param {string} path - The path to the resource.
2362
- * @param {RequestOptions} [options] - The options for the request.
2653
+ * @param {string|RequestOptions} [path] The path to the resource.
2654
+ * @param {RequestOptions} [options] The options for the request.
2363
2655
  * @returns {Promise<string>} A promise that resolves to an object URL.
2364
2656
  */
2365
2657
  async getImage(path, options) {
@@ -2369,8 +2661,8 @@ var Transportr = (() => {
2369
2661
  * It gets a buffer from the specified path
2370
2662
  *
2371
2663
  * @async
2372
- * @param {string} path - The path to the resource.
2373
- * @param {RequestOptions} [options] - The options for the request.
2664
+ * @param {string} [path] The path to the resource.
2665
+ * @param {RequestOptions} [options] The options for the request.
2374
2666
  * @returns {Promise<ArrayBuffer>} A promise that resolves to a buffer.
2375
2667
  */
2376
2668
  async getBuffer(path, options) {
@@ -2380,8 +2672,8 @@ var Transportr = (() => {
2380
2672
  * It returns a readable stream of the response body from the specified path.
2381
2673
  *
2382
2674
  * @async
2383
- * @param {string} path - The path to the resource.
2384
- * @param {RequestOptions} [options] - The options for the request.
2675
+ * @param {string} [path] The path to the resource.
2676
+ * @param {RequestOptions} [options] The options for the request.
2385
2677
  * @returns {Promise<ReadableStream<Uint8Array>>} A readable stream.
2386
2678
  */
2387
2679
  async getStream(path, options) {
@@ -2393,14 +2685,14 @@ var Transportr = (() => {
2393
2685
  *
2394
2686
  * @private
2395
2687
  * @async
2396
- * @param {string} path - The path to the endpoint you want to call.
2397
- * @param {RequestOptions} [userOptions] - The options passed to the public function to use for the request.
2398
- * @param {RequestOptions} [options] - The options for the request.
2399
- * @param {ResponseHandler<ResponseBody>} [responseHandler] - A function that will be called with the response object.
2688
+ * @param {string} [path] The path to the endpoint you want to call.
2689
+ * @param {RequestOptions} [userOptions] The options passed to the public function to use for the request.
2690
+ * @param {RequestOptions} [options] The options for the request.
2691
+ * @param {ResponseHandler<ResponseBody>} [responseHandler] A function that will be called with the response object.
2400
2692
  * @returns {Promise<ResponseBody>} The result of the #request method.
2401
2693
  */
2402
2694
  async #get(path, userOptions, options, responseHandler) {
2403
- return this.#request(path, userOptions, options, responseHandler);
2695
+ return this.#request(path, userOptions, { ...options, method: http_request_methods_default.GET }, responseHandler);
2404
2696
  }
2405
2697
  /**
2406
2698
  * It takes a path, options, and a response handler, and returns a promise that resolves to the
@@ -2408,90 +2700,175 @@ var Transportr = (() => {
2408
2700
  *
2409
2701
  * @private
2410
2702
  * @async
2411
- * @param {string} path - The path to the resource you want to access.
2412
- * @param {RequestOptions} [userOptions={}] - The options passed to the public function to use for the request.
2413
- * @param {RequestOptions} [options={}] - The options to use for the request.
2414
- * @param {ResponseHandler<ResponseBody>} [responseHandler] - A function that will be called with the response body as a parameter. This
2703
+ * @param {string} [path] The path to the resource you want to access.
2704
+ * @param {RequestOptions} [userOptions={}] The options passed to the public function to use for the request.
2705
+ * @param {RequestOptions} [options={}] The options to use for the request.
2706
+ * @param {ResponseHandler<ResponseBody>} [responseHandler] A function that will be called with the response body as a parameter. This
2415
2707
  * is useful if you want to do something with the response body before returning it.
2416
2708
  * @returns {Promise<ResponseBody>} The response from the API call.
2417
2709
  */
2418
2710
  async #request(path, userOptions = {}, options = {}, responseHandler) {
2419
- const requestOptions = object_merge_default(this.#options, _Transportr.#convertRequestOptions(userOptions), options);
2420
- const url = _Transportr.#createUrl(this.#baseUrl, path, requestOptions.searchParams);
2421
- const signalController = new SignalController(requestOptions.signal);
2422
- _Transportr.#activeRequests.push(signalController);
2423
- requestOptions.signal = signalController.signal;
2424
- if (_Transportr.#needsSerialization(requestOptions.method, requestOptions.headers[http_request_headers_default.CONTENT_TYPE])) {
2425
- try {
2426
- requestOptions.body = JSON.stringify(requestOptions.body);
2427
- } catch (error) {
2428
- return Promise.reject(new HttpError(url, { cause: error }));
2429
- }
2430
- } else if (requestOptions.method == http_request_methods_default.GET && requestOptions.headers[http_request_headers_default.CONTENT_TYPE] != "") {
2431
- delete requestOptions.headers[http_request_headers_default.CONTENT_TYPE];
2432
- delete requestOptions.body;
2711
+ if (object_type_default(path) == Object) {
2712
+ [path, userOptions] = [void 0, path];
2713
+ }
2714
+ try {
2715
+ options = this.#processRequestOptions(userOptions, options);
2716
+ } catch (cause) {
2717
+ return Promise.reject(new HttpError("Unable to process request options", { cause }));
2433
2718
  }
2434
- requestOptions.signal.addEventListener("abort", (event) => this.#publish(_Transportr.Events.ABORTED, requestOptions.global, event));
2435
- requestOptions.signal.addEventListener("timeout", (event) => this.#publish(_Transportr.Events.TIMEOUT, requestOptions.global, event));
2436
- this.#publish(_Transportr.Events.CONFIGURED, requestOptions.global, requestOptions);
2437
- let result, timeoutId, response;
2719
+ this.#publish({ name: RequestEvents.CONFIGURED, data: options, global: options.global });
2720
+ const url = _Transportr.#createUrl(this.#baseUrl, path);
2721
+ if (object_type_default(options.signal) != AbortSignal) {
2722
+ options.signal = new AbortSignal(options.signal);
2723
+ }
2724
+ options.signal.addEventListener(SignalEvents.ABORT, (event) => this.#publish({ name: RequestEvents.ABORTED, event, global: options.global }));
2725
+ options.signal.addEventListener(SignalEvents.TIMEOUT, (event) => this.#publish({ name: RequestEvents.TIMEOUT, event, global: options.global }));
2726
+ _Transportr.#activeRequests.add(options.signal);
2727
+ let response, result;
2438
2728
  try {
2439
- timeoutId = setTimeout(() => {
2440
- const cause = new DOMException(`The call to '${url}' timed-out after ${requestOptions.timeout / 1e3} seconds`, "TimeoutError");
2441
- signalController.abort(cause);
2442
- requestOptions.signal.dispatchEvent(new CustomEvent(_Transportr.Events.TIMEOUT, { detail: { url, options: requestOptions, cause } }));
2443
- }, requestOptions.timeout);
2444
- response = await fetch(url, requestOptions);
2729
+ response = await fetch(url, new Proxy(options, { get: _Transportr.#requestOptionsProxyHandler(options.timeout) }));
2730
+ if (!responseHandler && response.status != 204 && response.headers.has(http_response_headers_default.CONTENT_TYPE)) {
2731
+ responseHandler = this.#getResponseHandler(response.headers.get(http_response_headers_default.CONTENT_TYPE));
2732
+ }
2733
+ result = await responseHandler?.(response) ?? response;
2445
2734
  if (!response.ok) {
2446
- return Promise.reject(this.#handleError(url, { status: _Transportr.#generateResponseStatusFromError("ResponseError", response), entity: await this.#processResponse(response, url) }));
2735
+ return Promise.reject(this.#handleError(url, { status: _Transportr.#generateResponseStatusFromError("ResponseError", response), entity: result }));
2447
2736
  }
2448
- result = await this.#processResponse(response, url, responseHandler);
2449
- this.#publish(_Transportr.Events.SUCCESS, requestOptions.global, result);
2737
+ this.#publish({ name: RequestEvents.SUCCESS, data: result, global: options.global });
2450
2738
  } catch (error) {
2451
2739
  return Promise.reject(this.#handleError(url, { cause: error, status: _Transportr.#generateResponseStatusFromError(error.name, response) }));
2452
2740
  } finally {
2453
- clearTimeout(timeoutId);
2454
- if (!requestOptions.signal.aborted) {
2455
- this.#publish(_Transportr.Events.COMPLETE, requestOptions.global, response);
2456
- const index = _Transportr.#activeRequests.indexOf(signalController);
2457
- if (index > -1) {
2458
- _Transportr.#activeRequests.splice(index, 1);
2459
- }
2460
- if (_Transportr.#activeRequests.length === 0) {
2461
- this.#publish(_Transportr.Events.ALL_COMPLETE, requestOptions.global, response);
2741
+ options.signal.clearTimeout();
2742
+ if (!options.signal.aborted) {
2743
+ this.#publish({ name: RequestEvents.COMPLETE, data: response, global: options.global });
2744
+ _Transportr.#activeRequests.delete(options.signal);
2745
+ if (_Transportr.#activeRequests.size === 0) {
2746
+ this.#publish({ name: RequestEvents.ALL_COMPLETE, global: options.global });
2462
2747
  }
2463
2748
  }
2464
2749
  }
2465
2750
  return result;
2466
2751
  }
2467
2752
  /**
2468
- * Handles an error by logging it and throwing it.
2753
+ * Creates the options for a {@link Transportr} instance.
2469
2754
  *
2470
2755
  * @private
2471
- * @param {URL} url The path to the resource you want to access.
2472
- * @param {import('./http-error.js').HttpErrorOptions} options The options for the HttpError.
2473
- * @returns {HttpError} The HttpError.
2756
+ * @static
2757
+ * @param {RequestOptions} userOptions The {@link RequestOptions} to convert.
2758
+ * @param {RequestOptions} options The default {@link RequestOptions}.
2759
+ * @returns {RequestOptions} The converted {@link RequestOptions}.
2474
2760
  */
2475
- #handleError(url, options) {
2476
- const error = new HttpError(`An error has occurred with your request to: '${url}'`, options);
2477
- this.#publish(_Transportr.Events.ERROR, true, error);
2478
- return error;
2761
+ static #createOptions({ body, headers: userHeaders, searchParams: userSearchParams, ...userOptions }, { headers, searchParams, ...options }) {
2762
+ return object_merge_default(options, userOptions, {
2763
+ body: [FormData, URLSearchParams, Object].includes(object_type_default(body)) ? new ParameterMap(body) : body,
2764
+ headers: _Transportr.#mergeOptions(new Headers(), userHeaders, headers),
2765
+ searchParams: _Transportr.#mergeOptions(new URLSearchParams(), userSearchParams, searchParams)
2766
+ });
2479
2767
  }
2480
2768
  /**
2481
- * Publishes an event to the global and instance subscribers.
2769
+ * Merge the user options and request options into the target.
2482
2770
  *
2483
2771
  * @private
2484
- * @param {string} eventName The name of the event.
2485
- * @param {boolean} global Whether or not to publish the event to the global subscribers.
2486
- * @param {Event} [event] The event object.
2487
- * @param {*} [data] The data to pass to the subscribers.
2488
- * @returns {void}
2772
+ * @static
2773
+ * @param {Headers|URLSearchParams|FormData} target The target to merge the options into.
2774
+ * @param {Headers|URLSearchParams|FormData|Object} userOption The user options to merge into the target.
2775
+ * @param {Headers|URLSearchParams|FormData|Object} requestOption The request options to merge into the target.
2776
+ * @returns {Headers|URLSearchParams} The target.
2777
+ */
2778
+ static #mergeOptions(target, userOption = {}, requestOption = {}) {
2779
+ for (const option of [userOption, requestOption]) {
2780
+ for (const [name, value] of option.entries?.() ?? Object.entries(option)) {
2781
+ target.set(name, value);
2782
+ }
2783
+ }
2784
+ return target;
2785
+ }
2786
+ /**
2787
+ * Merges the user options and request options with the instance options into a new object that is used for the request.
2788
+ *
2789
+ * @private
2790
+ * @param {RequestOptions} userOptions The user options to merge into the request options.
2791
+ * @param {RequestOptions} options The request options to merge into the user options.
2792
+ * @returns {RequestOptions} The merged options.
2793
+ */
2794
+ #processRequestOptions({ body: userBody, headers: userHeaders, searchParams: userSearchParams, ...userOptions }, { headers, searchParams, ...options }) {
2795
+ const requestOptions = object_merge_default(this.#options, userOptions, options, {
2796
+ headers: _Transportr.#mergeOptions(new Headers(this.#options.headers), userHeaders, headers),
2797
+ searchParams: _Transportr.#mergeOptions(new URLSearchParams(this.#options.searchParams), userSearchParams, searchParams)
2798
+ });
2799
+ if (requestBodyMethods.includes(requestOptions.method)) {
2800
+ if ([ParameterMap, FormData, URLSearchParams, Object].includes(object_type_default(userBody))) {
2801
+ const contentType = requestOptions.headers.get(http_request_headers_default.CONTENT_TYPE);
2802
+ const mediaType = (mediaTypes.get(contentType) ?? MediaType.parse(contentType))?.subtype;
2803
+ if (mediaType == http_media_type_default.MULTIPART_FORM_DATA) {
2804
+ requestOptions.body = _Transportr.#mergeOptions(new FormData(requestOptions.body), userBody);
2805
+ } else if (mediaType == http_media_type_default.FORM) {
2806
+ requestOptions.body = _Transportr.#mergeOptions(new URLSearchParams(requestOptions.body), userBody);
2807
+ } else if (mediaType.includes("json")) {
2808
+ requestOptions.body = JSON.stringify(_Transportr.#mergeOptions(new ParameterMap(requestOptions.body), userBody));
2809
+ } else {
2810
+ requestOptions.body = _Transportr.#mergeOptions(new ParameterMap(requestOptions.body), userBody);
2811
+ }
2812
+ } else {
2813
+ requestOptions.body = userBody;
2814
+ }
2815
+ } else {
2816
+ requestOptions.headers.delete(http_request_headers_default.CONTENT_TYPE);
2817
+ if (!requestOptions.body?.isEmpty()) {
2818
+ _Transportr.#mergeOptions(requestOptions.searchParams, requestOptions.body);
2819
+ }
2820
+ requestOptions.body = void 0;
2821
+ }
2822
+ return requestOptions;
2823
+ }
2824
+ /**
2825
+ * Returns a Proxy of the options object that traps for 'signal' access.
2826
+ * If the signal has not been aborted, then it will return a new signal with a timeout.
2827
+ *
2828
+ * @private
2829
+ * @static
2830
+ * @param {number} timeout The timeout in milliseconds before the signal is aborted.
2831
+ * @returns {Proxy<RequestOptions>} A proxy for the options object.
2489
2832
  */
2490
- #publish(eventName, global, event, data) {
2491
- if (global) {
2492
- _Transportr.#globalSubscribr.publish(eventName, event, data);
2833
+ static #requestOptionsProxyHandler(timeout) {
2834
+ return (target, property) => {
2835
+ const value = Reflect.get(target, property);
2836
+ return property == "signal" && !value.aborted ? value.withTimeout(timeout) : value;
2837
+ };
2838
+ }
2839
+ /**
2840
+ * It takes a url or a string, and returns a {@link URL} instance.
2841
+ * If the url is a string and starts with a slash, then the origin of the current page is used as the base url.
2842
+ *
2843
+ * @private
2844
+ * @static
2845
+ * @param {URL|string} url The URL to convert to a {@link URL} instance.
2846
+ * @returns {URL} A {@link URL} instance.
2847
+ * @throws {TypeError} If the url is not a string or {@link URL} instance.
2848
+ */
2849
+ static #getBaseUrl(url) {
2850
+ switch (object_type_default(url)) {
2851
+ case URL:
2852
+ return url;
2853
+ case String:
2854
+ return new URL(url, url.startsWith("/") ? globalThis.location.origin : void 0);
2855
+ default:
2856
+ throw new TypeError("Invalid URL");
2493
2857
  }
2494
- this.#subscribr.publish(eventName, event, data);
2858
+ }
2859
+ /**
2860
+ * It takes a URL, a path, and a set of search parameters, and returns a new URL with the path and
2861
+ * search parameters applied.
2862
+ *
2863
+ * @private
2864
+ * @static
2865
+ * @param {URL} url The URL to use as a base.
2866
+ * @param {string} [path] The optional, relative path to the resource. This MUST be a relative path, otherwise, you should create a new {@link Transportr} instance.
2867
+ * @returns {URL} A new URL object with the pathname and origin of the url parameter, and the path parameter
2868
+ * appended to the end of the pathname.
2869
+ */
2870
+ static #createUrl(url, path) {
2871
+ return path ? new URL(`${url.pathname.replace(endsWithSlashRegEx, "")}${path}`, url.origin) : new URL(url);
2495
2872
  }
2496
2873
  /**
2497
2874
  * Generates a ResponseStatus object based on the error name and the response.
@@ -2505,91 +2882,62 @@ var Transportr = (() => {
2505
2882
  static #generateResponseStatusFromError(errorName, response) {
2506
2883
  switch (errorName) {
2507
2884
  case "AbortError":
2508
- return _Transportr.#eventResponseStatuses.get(_Transportr.Events.ABORTED);
2885
+ return _Transportr.#eventResponseStatuses.get(RequestEvents.ABORTED);
2509
2886
  case "TimeoutError":
2510
- return _Transportr.#eventResponseStatuses.get(_Transportr.Events.TIMEOUT);
2887
+ return _Transportr.#eventResponseStatuses.get(RequestEvents.TIMEOUT);
2511
2888
  default:
2512
2889
  return response ? new ResponseStatus(response.status, response.statusText) : new ResponseStatus(500, "Internal Server Error");
2513
2890
  }
2514
2891
  }
2515
2892
  /**
2516
- * It takes a response and a handler, and if the handler is not defined, it tries to find a handler
2517
- * based on the response's content type
2893
+ * Handles an error by logging it and throwing it.
2518
2894
  *
2519
2895
  * @private
2520
- * @static
2521
- * @async
2522
- * @param {Response} response - The response object returned by the fetch API.
2523
- * @param {URL} url - The path to the resource you want to access. Used for error handling.
2524
- * @param {ResponseHandler<ResponseBody>} [handler] - The handler to use for processing the response.
2525
- * @returns {Promise<ResponseBody>} The response is being returned.
2896
+ * @param {URL} url The path to the resource you want to access.
2897
+ * @param {import('./http-error.js').HttpErrorOptions} options The options for the HttpError.
2898
+ * @returns {HttpError} The HttpError.
2526
2899
  */
2527
- async #processResponse(response, url, handler) {
2528
- try {
2529
- let mediaType;
2530
- if (!handler) {
2531
- mediaType = MediaType.parse(response.headers.get(http_response_headers_default.CONTENT_TYPE));
2532
- if (mediaType) {
2533
- for (const [responseHandler, contentTypes] of _Transportr.#contentTypeHandlers) {
2534
- if (contentTypes.has(mediaType.type) || contentTypes.has(mediaType.subtype)) {
2535
- handler = responseHandler;
2536
- break;
2537
- }
2538
- }
2539
- }
2540
- }
2541
- return (handler ?? _handleText)(response);
2542
- } catch (error) {
2543
- console.error("Unable to process response.", error, response);
2544
- return Promise.reject(this.#handleError(url, { cause: error }));
2545
- }
2900
+ #handleError(url, options) {
2901
+ const error = new HttpError(`An error has occurred with your request to: '${url}'`, options);
2902
+ this.#publish({ name: RequestEvents.ERROR, data: error });
2903
+ return error;
2546
2904
  }
2547
2905
  /**
2548
- * It takes a URL, a path, and a set of search parameters, and returns a new URL with the path and
2549
- * search parameters applied.
2906
+ * Publishes an event to the global and instance subscribers.
2550
2907
  *
2551
2908
  * @private
2552
- * @static
2553
- * @param {URL} url - The URL to use as a base.
2554
- * @param {string} path - The path to the resource. This can be a relative path or a full URL.
2555
- * @param {Object<string, string>} [searchParams={}] - An object containing the query parameters to be added to the URL.
2556
- * @returns {URL} A new URL object with the pathname and origin of the url parameter, and the path parameter
2557
- * appended to the end of the pathname.
2909
+ * @param {Object} options The options for the event.
2910
+ * @param {string} options.name The name of the event.
2911
+ * @param {Event} [options.event] The event object.
2912
+ * @param {*} [options.data] The data to pass to the subscribers.
2913
+ * @param {boolean} [options.global=true] Whether or not to publish the event to the global subscribers.
2914
+ * @returns {void}
2558
2915
  */
2559
- static #createUrl(url, path, searchParams = {}) {
2560
- if (path) {
2561
- url = path.startsWith("/") ? new URL(`${url.pathname.replace(endsWithSlashRegEx, "")}${path}`, url.origin) : new URL(path);
2916
+ #publish({ name, event = new CustomEvent(name), data, global = true } = {}) {
2917
+ if (global) {
2918
+ _Transportr.#globalSubscribr.publish(name, event, data);
2562
2919
  }
2563
- Object.entries(searchParams).forEach(([key, value]) => url.searchParams.append(key, value));
2564
- return url;
2920
+ this.#subscribr.publish(name, event, data);
2565
2921
  }
2566
2922
  /**
2567
- * If the request method is POST, PUT, or PATCH, and the content type is JSON, then the request body
2568
- * needs to be serialized.
2923
+ * Returns a response handler for the given content type.
2569
2924
  *
2570
2925
  * @private
2571
- * @static
2572
- * @param {RequestMethod} method - The HTTP request method.
2573
- * @param {HttpMediaType} contentType - The headers of the request.
2574
- * @returns {boolean} `true` if the request body needs to be serialized, `false` otherwise.
2575
- */
2576
- static #needsSerialization(method, contentType) {
2577
- return (_mediaTypes.get(contentType) ?? new MediaType(contentType)).essence == http_media_type_default.JSON && [http_request_methods_default.POST, http_request_methods_default.PUT, http_request_methods_default.PATCH].includes(method);
2578
- }
2579
- /**
2580
- *
2581
- * @param {RequestOptions} options - The options passed to the public function to use for the request.
2582
- * @returns {RequestOptions} The options to use for the request.
2583
- */
2584
- static #convertRequestOptions(options) {
2585
- if (!object_is_empty_default(options)) {
2586
- for (const [{ property, type, converter }, option = options[property]] of _Transportr.#propertyTypeConverters) {
2587
- if (option instanceof type) {
2588
- options[property] = converter(option);
2926
+ * @param {string} contentType The content type of the response.
2927
+ * @returns {ResponseHandler<ResponseBody>} The response handler.
2928
+ */
2929
+ #getResponseHandler(contentType) {
2930
+ let handler;
2931
+ const mediaType = MediaType.parse(contentType);
2932
+ if (mediaType) {
2933
+ for (const [responseHandler, contentTypes] of _Transportr.#contentTypeHandlers) {
2934
+ if (contentTypes.has(mediaType.type) || contentTypes.has(mediaType.subtype)) {
2935
+ handler = responseHandler;
2936
+ break;
2589
2937
  }
2590
2938
  }
2591
2939
  }
2592
- return options;
2940
+ return handler;
2593
2941
  }
2594
2942
  /**
2595
2943
  * A String value that is used in the creation of the default string