typedrest 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +2 -0
  2. package/endpoints/Endpoint.js +9 -22
  3. package/endpoints/EntryEndpoint.js +3 -14
  4. package/endpoints/generic/ETagEndpointBase.js +27 -42
  5. package/endpoints/generic/ElementEndpoint.js +39 -60
  6. package/endpoints/generic/GenericCollectionEndpoint.js +70 -44
  7. package/endpoints/generic/GenericCollectionEndpoint.test.ts +123 -0
  8. package/endpoints/generic/GenericCollectionEndpoint.ts +54 -1
  9. package/endpoints/generic/PartialResponse.js +33 -0
  10. package/endpoints/generic/PartialResponse.ts +28 -0
  11. package/endpoints/generic/index.js +2 -1
  12. package/endpoints/generic/index.ts +1 -0
  13. package/endpoints/index.js +3 -2
  14. package/endpoints/index.ts +1 -0
  15. package/endpoints/raw/BlobEndpoint.js +10 -27
  16. package/endpoints/raw/UploadEndpoint.js +11 -22
  17. package/endpoints/reactive/Delay.js +27 -0
  18. package/endpoints/reactive/Delay.ts +26 -0
  19. package/endpoints/reactive/GenericStreamingCollectionEndpoint.js +79 -0
  20. package/endpoints/reactive/GenericStreamingCollectionEndpoint.ts +73 -0
  21. package/endpoints/reactive/PollingEndpoint.js +67 -0
  22. package/endpoints/reactive/PollingEndpoint.test.ts +84 -0
  23. package/endpoints/reactive/PollingEndpoint.ts +66 -0
  24. package/endpoints/reactive/SseStreamingEndpoint.js +120 -0
  25. package/endpoints/reactive/SseStreamingEndpoint.test.ts +169 -0
  26. package/endpoints/reactive/SseStreamingEndpoint.ts +115 -0
  27. package/endpoints/reactive/StreamingCollectionEndpoint.js +23 -0
  28. package/endpoints/reactive/StreamingCollectionEndpoint.test.ts +110 -0
  29. package/endpoints/reactive/StreamingCollectionEndpoint.ts +20 -0
  30. package/endpoints/reactive/StreamingEndpoint.js +56 -0
  31. package/endpoints/reactive/StreamingEndpoint.test.ts +130 -0
  32. package/endpoints/reactive/StreamingEndpoint.ts +50 -0
  33. package/endpoints/reactive/index.js +22 -0
  34. package/endpoints/reactive/index.ts +5 -0
  35. package/endpoints/rpc/ActionEndpoint.js +3 -14
  36. package/endpoints/rpc/ConsumerEndpoint.js +5 -16
  37. package/endpoints/rpc/FunctionEndpoint.js +6 -17
  38. package/endpoints/rpc/ProducerEndpoint.js +4 -15
  39. package/endpoints/rpc/RpcEndpointBase.js +3 -14
  40. package/errors/DefaultErrorHandler.js +19 -27
  41. package/errors/DefaultErrorHandler.ts +4 -1
  42. package/errors/Errors.js +8 -2
  43. package/errors/Errors.ts +5 -0
  44. package/http/EntityStream.js +42 -0
  45. package/http/EntityStream.ts +40 -0
  46. package/http/HttpContentRange.js +39 -0
  47. package/http/HttpContentRange.ts +41 -0
  48. package/http/HttpHeader.js +6 -1
  49. package/http/HttpHeader.ts +6 -1
  50. package/http/HttpStatusCode.js +4 -1
  51. package/http/HttpStatusCode.ts +4 -1
  52. package/http/ResponseCache.js +4 -15
  53. package/http/RetryAfter.js +24 -0
  54. package/http/RetryAfter.ts +19 -0
  55. package/http/ServerSentEvents.js +140 -0
  56. package/http/ServerSentEvents.ts +145 -0
  57. package/http/index.js +5 -1
  58. package/http/index.ts +4 -0
  59. package/links/AggregateLinkExtractor.js +7 -18
  60. package/links/HalLinkExtractor.js +9 -20
  61. package/links/HeaderLinkExtractor.js +4 -15
  62. package/package.json +8 -8
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.DefaultErrorHandler = void 0;
13
4
  const Errors_1 = require("./Errors");
@@ -26,26 +17,25 @@ class DefaultErrorHandler {
26
17
  * @throws {@link errors!TimeoutError}: {@link http!HttpStatusCode.RequestTimeout}
27
18
  * @throws {@link errors!ConflictError}: {@link http!HttpStatusCode.Conflict}
28
19
  * @throws {@link errors!ConcurrencyError}: {@link http!HttpStatusCode.PreconditionFailed}
20
+ * @throws {@link errors!RangeNotSatisfiableError}: {@link http!HttpStatusCode.RangeNotSatisfiable}
29
21
  * @throws {@link errors!HttpError}: Other non-success status code
30
22
  */
31
- handle(response) {
32
- return __awaiter(this, void 0, void 0, function* () {
33
- var _a, _b;
34
- if (response.ok)
35
- return;
36
- const contentType = response.headers.get(http_1.HttpHeader.ContentType);
37
- let jsonBody;
38
- if ((contentType === null || contentType === void 0 ? void 0 : contentType.startsWith("application/json")) || (contentType === null || contentType === void 0 ? void 0 : contentType.includes("+json"))) {
39
- try {
40
- jsonBody = yield response.json();
41
- }
42
- catch (_c) {
43
- jsonBody = undefined;
44
- }
23
+ async handle(response) {
24
+ var _a, _b;
25
+ if (response.ok)
26
+ return;
27
+ const contentType = response.headers.get(http_1.HttpHeader.ContentType);
28
+ let jsonBody;
29
+ if ((contentType === null || contentType === void 0 ? void 0 : contentType.startsWith("application/json")) || (contentType === null || contentType === void 0 ? void 0 : contentType.includes("+json"))) {
30
+ try {
31
+ jsonBody = await response.json();
45
32
  }
46
- const errorType = DefaultErrorHandler.errorType(response.status);
47
- throw new errorType((_b = (_a = jsonBody === null || jsonBody === void 0 ? void 0 : jsonBody.message) !== null && _a !== void 0 ? _a : jsonBody === null || jsonBody === void 0 ? void 0 : jsonBody.details) !== null && _b !== void 0 ? _b : `HTTP ${response.status} ${response.statusText}`, response.status, jsonBody);
48
- });
33
+ catch (_c) {
34
+ jsonBody = undefined;
35
+ }
36
+ }
37
+ const errorType = DefaultErrorHandler.errorType(response.status);
38
+ throw new errorType((_b = (_a = jsonBody === null || jsonBody === void 0 ? void 0 : jsonBody.message) !== null && _a !== void 0 ? _a : jsonBody === null || jsonBody === void 0 ? void 0 : jsonBody.details) !== null && _b !== void 0 ? _b : `HTTP ${response.status} ${response.statusText}`, response.status, jsonBody);
49
39
  }
50
40
  static errorType(status) {
51
41
  switch (status) {
@@ -64,10 +54,12 @@ class DefaultErrorHandler {
64
54
  return Errors_1.ConflictError;
65
55
  case http_1.HttpStatusCode.PreconditionFailed:
66
56
  return Errors_1.ConcurrencyError;
57
+ case http_1.HttpStatusCode.RangeNotSatisfiable:
58
+ return Errors_1.RangeNotSatisfiableError;
67
59
  default:
68
60
  return Errors_1.HttpError;
69
61
  }
70
62
  }
71
63
  }
72
64
  exports.DefaultErrorHandler = DefaultErrorHandler;
73
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVmYXVsdEVycm9ySGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkRlZmF1bHRFcnJvckhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQ0EscUNBQTZKO0FBQzdKLGtDQUFxRDtBQUVyRDs7R0FFRztBQUNILE1BQWEsbUJBQW1CO0lBQzVCOzs7Ozs7Ozs7OztPQVdHO0lBQ0csTUFBTSxDQUFDLFFBQWtCOzs7WUFDM0IsSUFBSSxRQUFRLENBQUMsRUFBRTtnQkFBRSxPQUFPO1lBRXhCLE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDakUsSUFBSSxRQUFhLENBQUM7WUFDbEIsSUFBSSxDQUFBLFdBQVcsYUFBWCxXQUFXLHVCQUFYLFdBQVcsQ0FBRSxVQUFVLENBQUMsa0JBQWtCLENBQUMsTUFBSSxXQUFXLGFBQVgsV0FBVyx1QkFBWCxXQUFXLENBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFBLEVBQUUsQ0FBQztnQkFDaEYsSUFBSSxDQUFDO29CQUNELFFBQVEsR0FBRyxNQUFNLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDckMsQ0FBQztnQkFBQyxXQUFNLENBQUM7b0JBQ0wsUUFBUSxHQUFHLFNBQVMsQ0FBQztnQkFDekIsQ0FBQztZQUNMLENBQUM7WUFFRCxNQUFNLFNBQVMsR0FBRyxtQkFBbUIsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2pFLE1BQU0sSUFBSSxTQUFTLENBQ2YsTUFBQSxNQUFBLFFBQVEsYUFBUixRQUFRLHVCQUFSLFFBQVEsQ0FBRSxPQUFPLG1DQUFJLFFBQVEsYUFBUixRQUFRLHVCQUFSLFFBQVEsQ0FBRSxPQUFPLG1DQUFJLFFBQVEsUUFBUSxDQUFDLE1BQU0sSUFBSSxRQUFRLENBQUMsVUFBVSxFQUFFLEVBQzFGLFFBQVEsQ0FBQyxNQUFNLEVBQ2YsUUFBUSxDQUFDLENBQUM7UUFDbEIsQ0FBQztLQUFBO0lBRU8sTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFzQjtRQUMzQyxRQUFRLE1BQU0sRUFBRSxDQUFDO1lBQ2IsS0FBSyxxQkFBYyxDQUFDLFVBQVU7Z0JBQzFCLE9BQU8sd0JBQWUsQ0FBQztZQUMzQixLQUFLLHFCQUFjLENBQUMsWUFBWTtnQkFDNUIsT0FBTyw0QkFBbUIsQ0FBQztZQUMvQixLQUFLLHFCQUFjLENBQUMsU0FBUztnQkFDekIsT0FBTywyQkFBa0IsQ0FBQztZQUM5QixLQUFLLHFCQUFjLENBQUMsUUFBUSxDQUFDO1lBQzdCLEtBQUsscUJBQWMsQ0FBQyxJQUFJO2dCQUNwQixPQUFPLHNCQUFhLENBQUM7WUFDekIsS0FBSyxxQkFBYyxDQUFDLGNBQWM7Z0JBQzlCLE9BQU8scUJBQVksQ0FBQztZQUN4QixLQUFLLHFCQUFjLENBQUMsUUFBUTtnQkFDeEIsT0FBTyxzQkFBYSxDQUFDO1lBQ3pCLEtBQUsscUJBQWMsQ0FBQyxrQkFBa0I7Z0JBQ2xDLE9BQU8seUJBQWdCLENBQUM7WUFDNUI7Z0JBQ0ksT0FBTyxrQkFBUyxDQUFDO1FBQ3pCLENBQUM7SUFDTCxDQUFDO0NBQ0o7QUF0REQsa0RBc0RDIn0=
65
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVmYXVsdEVycm9ySGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkRlZmF1bHRFcnJvckhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EscUNBQXVMO0FBQ3ZMLGtDQUFxRDtBQUVyRDs7R0FFRztBQUNILE1BQWEsbUJBQW1CO0lBQzVCOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILEtBQUssQ0FBQyxNQUFNLENBQUMsUUFBa0I7O1FBQzNCLElBQUksUUFBUSxDQUFDLEVBQUU7WUFBRSxPQUFPO1FBRXhCLE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDakUsSUFBSSxRQUFhLENBQUM7UUFDbEIsSUFBSSxDQUFBLFdBQVcsYUFBWCxXQUFXLHVCQUFYLFdBQVcsQ0FBRSxVQUFVLENBQUMsa0JBQWtCLENBQUMsTUFBSSxXQUFXLGFBQVgsV0FBVyx1QkFBWCxXQUFXLENBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFBLEVBQUUsQ0FBQztZQUNoRixJQUFJLENBQUM7Z0JBQ0QsUUFBUSxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ3JDLENBQUM7WUFBQyxXQUFNLENBQUM7Z0JBQ0wsUUFBUSxHQUFHLFNBQVMsQ0FBQztZQUN6QixDQUFDO1FBQ0wsQ0FBQztRQUVELE1BQU0sU0FBUyxHQUFHLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakUsTUFBTSxJQUFJLFNBQVMsQ0FDZixNQUFBLE1BQUEsUUFBUSxhQUFSLFFBQVEsdUJBQVIsUUFBUSxDQUFFLE9BQU8sbUNBQUksUUFBUSxhQUFSLFFBQVEsdUJBQVIsUUFBUSxDQUFFLE9BQU8sbUNBQUksUUFBUSxRQUFRLENBQUMsTUFBTSxJQUFJLFFBQVEsQ0FBQyxVQUFVLEVBQUUsRUFDMUYsUUFBUSxDQUFDLE1BQU0sRUFDZixRQUFRLENBQUMsQ0FBQztJQUNsQixDQUFDO0lBRU8sTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFzQjtRQUMzQyxRQUFRLE1BQU0sRUFBRSxDQUFDO1lBQ2IsS0FBSyxxQkFBYyxDQUFDLFVBQVU7Z0JBQzFCLE9BQU8sd0JBQWUsQ0FBQztZQUMzQixLQUFLLHFCQUFjLENBQUMsWUFBWTtnQkFDNUIsT0FBTyw0QkFBbUIsQ0FBQztZQUMvQixLQUFLLHFCQUFjLENBQUMsU0FBUztnQkFDekIsT0FBTywyQkFBa0IsQ0FBQztZQUM5QixLQUFLLHFCQUFjLENBQUMsUUFBUSxDQUFDO1lBQzdCLEtBQUsscUJBQWMsQ0FBQyxJQUFJO2dCQUNwQixPQUFPLHNCQUFhLENBQUM7WUFDekIsS0FBSyxxQkFBYyxDQUFDLGNBQWM7Z0JBQzlCLE9BQU8scUJBQVksQ0FBQztZQUN4QixLQUFLLHFCQUFjLENBQUMsUUFBUTtnQkFDeEIsT0FBTyxzQkFBYSxDQUFDO1lBQ3pCLEtBQUsscUJBQWMsQ0FBQyxrQkFBa0I7Z0JBQ2xDLE9BQU8seUJBQWdCLENBQUM7WUFDNUIsS0FBSyxxQkFBYyxDQUFDLG1CQUFtQjtnQkFDbkMsT0FBTyxpQ0FBd0IsQ0FBQztZQUNwQztnQkFDSSxPQUFPLGtCQUFTLENBQUM7UUFDekIsQ0FBQztJQUNMLENBQUM7Q0FDSjtBQXpERCxrREF5REMifQ==
@@ -1,5 +1,5 @@
1
1
  import { ErrorHandler } from "./ErrorHandler";
2
- import { HttpError, BadRequestError, AuthenticationError, AuthorizationError, NotFoundError, TimeoutError, ConflictError, ConcurrencyError } from "./Errors";
2
+ import { HttpError, BadRequestError, AuthenticationError, AuthorizationError, NotFoundError, TimeoutError, ConflictError, ConcurrencyError, RangeNotSatisfiableError } from "./Errors";
3
3
  import { HttpStatusCode, HttpHeader } from "../http";
4
4
 
5
5
  /**
@@ -16,6 +16,7 @@ export class DefaultErrorHandler implements ErrorHandler {
16
16
  * @throws {@link errors!TimeoutError}: {@link http!HttpStatusCode.RequestTimeout}
17
17
  * @throws {@link errors!ConflictError}: {@link http!HttpStatusCode.Conflict}
18
18
  * @throws {@link errors!ConcurrencyError}: {@link http!HttpStatusCode.PreconditionFailed}
19
+ * @throws {@link errors!RangeNotSatisfiableError}: {@link http!HttpStatusCode.RangeNotSatisfiable}
19
20
  * @throws {@link errors!HttpError}: Other non-success status code
20
21
  */
21
22
  async handle(response: Response) {
@@ -55,6 +56,8 @@ export class DefaultErrorHandler implements ErrorHandler {
55
56
  return ConflictError;
56
57
  case HttpStatusCode.PreconditionFailed:
57
58
  return ConcurrencyError;
59
+ case HttpStatusCode.RangeNotSatisfiable:
60
+ return RangeNotSatisfiableError;
58
61
  default:
59
62
  return HttpError;
60
63
  }
package/errors/Errors.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConcurrencyError = exports.ConflictError = exports.TimeoutError = exports.NotFoundError = exports.AuthorizationError = exports.AuthenticationError = exports.BadRequestError = exports.HttpError = void 0;
3
+ exports.RangeNotSatisfiableError = exports.ConcurrencyError = exports.ConflictError = exports.TimeoutError = exports.NotFoundError = exports.AuthorizationError = exports.AuthenticationError = exports.BadRequestError = exports.HttpError = void 0;
4
4
  /**
5
5
  * Thrown on HTTP response with a non-successful status code (4xx or 5xx).
6
6
  */
@@ -60,4 +60,10 @@ exports.ConflictError = ConflictError;
60
60
  class ConcurrencyError extends HttpError {
61
61
  }
62
62
  exports.ConcurrencyError = ConcurrencyError;
63
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiRXJyb3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBOztHQUVHO0FBQ0gsTUFBYSxTQUFVLFNBQVEsS0FBSztJQUNoQzs7Ozs7T0FLRztJQUNILFlBQVksT0FBZSxFQUFTLE1BQXNCLEVBQVMsSUFBVTtRQUN6RSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFEaUIsV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFBUyxTQUFJLEdBQUosSUFBSSxDQUFNO0lBRTdFLENBQUM7Q0FDSjtBQVZELDhCQVVDO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLGVBQWdCLFNBQVEsU0FBUztDQUFHO0FBQWpELDBDQUFpRDtBQUVqRDs7R0FFRztBQUNILE1BQWEsbUJBQW9CLFNBQVEsU0FBUztDQUFHO0FBQXJELGtEQUFxRDtBQUVyRDs7R0FFRztBQUNILE1BQWEsa0JBQW1CLFNBQVEsU0FBUztDQUFHO0FBQXBELGdEQUFvRDtBQUVwRDs7R0FFRztBQUNILE1BQWEsYUFBYyxTQUFRLFNBQVM7Q0FBRztBQUEvQyxzQ0FBK0M7QUFFL0M7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxTQUFTO0NBQUc7QUFBOUMsb0NBQThDO0FBRTlDOztHQUVHO0FBQ0gsTUFBYSxhQUFjLFNBQVEsU0FBUztDQUFHO0FBQS9DLHNDQUErQztBQUUvQzs7R0FFRztBQUNILE1BQWEsZ0JBQWlCLFNBQVEsU0FBUztDQUFHO0FBQWxELDRDQUFrRCJ9
63
+ /**
64
+ * Thrown on HTTP response for a requested range that the server can not provide (usually {@link http!HttpStatusCode.RangeNotSatisfiable}).
65
+ */
66
+ class RangeNotSatisfiableError extends HttpError {
67
+ }
68
+ exports.RangeNotSatisfiableError = RangeNotSatisfiableError;
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiRXJyb3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBOztHQUVHO0FBQ0gsTUFBYSxTQUFVLFNBQVEsS0FBSztJQUNoQzs7Ozs7T0FLRztJQUNILFlBQVksT0FBZSxFQUFTLE1BQXNCLEVBQVMsSUFBVTtRQUN6RSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFEaUIsV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFBUyxTQUFJLEdBQUosSUFBSSxDQUFNO0lBRTdFLENBQUM7Q0FDSjtBQVZELDhCQVVDO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLGVBQWdCLFNBQVEsU0FBUztDQUFHO0FBQWpELDBDQUFpRDtBQUVqRDs7R0FFRztBQUNILE1BQWEsbUJBQW9CLFNBQVEsU0FBUztDQUFHO0FBQXJELGtEQUFxRDtBQUVyRDs7R0FFRztBQUNILE1BQWEsa0JBQW1CLFNBQVEsU0FBUztDQUFHO0FBQXBELGdEQUFvRDtBQUVwRDs7R0FFRztBQUNILE1BQWEsYUFBYyxTQUFRLFNBQVM7Q0FBRztBQUEvQyxzQ0FBK0M7QUFFL0M7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxTQUFTO0NBQUc7QUFBOUMsb0NBQThDO0FBRTlDOztHQUVHO0FBQ0gsTUFBYSxhQUFjLFNBQVEsU0FBUztDQUFHO0FBQS9DLHNDQUErQztBQUUvQzs7R0FFRztBQUNILE1BQWEsZ0JBQWlCLFNBQVEsU0FBUztDQUFHO0FBQWxELDRDQUFrRDtBQUVsRDs7R0FFRztBQUNILE1BQWEsd0JBQXlCLFNBQVEsU0FBUztDQUFHO0FBQTFELDREQUEwRCJ9
package/errors/Errors.ts CHANGED
@@ -49,3 +49,8 @@ export class ConflictError extends HttpError {}
49
49
  * Thrown on HTTP response for a failed precondition or mid-air collision (usually {@link http!HttpStatusCode.PreconditionFailed}).
50
50
  */
51
51
  export class ConcurrencyError extends HttpError {}
52
+
53
+ /**
54
+ * Thrown on HTTP response for a requested range that the server can not provide (usually {@link http!HttpStatusCode.RangeNotSatisfiable}).
55
+ */
56
+ export class RangeNotSatisfiableError extends HttpError {}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.entityStream = entityStream;
4
+ /**
5
+ * Exposes the body of a `Response` as a stream of deserialized entities.
6
+ * @typeParam TEntity The type of entity the stream provides.
7
+ * @param response The response to read the body from.
8
+ * @param serializer Controls the deserialization of the entities in the body.
9
+ * @param separator The character sequence used to detect that a new entity starts in the stream.
10
+ * @returns A stream that ends when the server closes the connection.
11
+ */
12
+ async function* entityStream(response, serializer, separator = "\n") {
13
+ if (!response.body)
14
+ return;
15
+ const reader = response.body.getReader();
16
+ const decoder = new TextDecoder();
17
+ let buffer = "";
18
+ try {
19
+ while (true) {
20
+ const { done, value } = await reader.read();
21
+ if (done)
22
+ break;
23
+ buffer += decoder.decode(value, { stream: true });
24
+ let index;
25
+ while ((index = buffer.indexOf(separator)) !== -1) {
26
+ const entity = buffer.slice(0, index);
27
+ buffer = buffer.slice(index + separator.length);
28
+ if (entity.trim())
29
+ yield serializer.deserialize(entity);
30
+ }
31
+ }
32
+ // Tolerate a missing separator after the last entity
33
+ buffer += decoder.decode();
34
+ if (buffer.trim())
35
+ yield serializer.deserialize(buffer);
36
+ }
37
+ finally {
38
+ // NOTE: Ignore errors here so that a failure that already ended the stream is not masked.
39
+ await reader.cancel().catch(() => { });
40
+ }
41
+ }
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRW50aXR5U3RyZWFtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiRW50aXR5U3RyZWFtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBVUEsb0NBNkJDO0FBckNEOzs7Ozs7O0dBT0c7QUFDSSxLQUFLLFNBQVMsQ0FBQyxDQUFDLFlBQVksQ0FBVSxRQUFrQixFQUFFLFVBQXNCLEVBQUUsWUFBb0IsSUFBSTtJQUM3RyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUk7UUFBRSxPQUFPO0lBRTNCLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7SUFDekMsTUFBTSxPQUFPLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztJQUNsQyxJQUFJLE1BQU0sR0FBRyxFQUFFLENBQUM7SUFFaEIsSUFBSSxDQUFDO1FBQ0QsT0FBTyxJQUFJLEVBQUUsQ0FBQztZQUNWLE1BQU0sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDNUMsSUFBSSxJQUFJO2dCQUFFLE1BQU07WUFFaEIsTUFBTSxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFFbEQsSUFBSSxLQUFhLENBQUM7WUFDbEIsT0FBTyxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDaEQsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ3RDLE1BQU0sR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2hELElBQUksTUFBTSxDQUFDLElBQUksRUFBRTtvQkFBRSxNQUFNLFVBQVUsQ0FBQyxXQUFXLENBQVUsTUFBTSxDQUFDLENBQUM7WUFDckUsQ0FBQztRQUNMLENBQUM7UUFFRCxxREFBcUQ7UUFDckQsTUFBTSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUMzQixJQUFJLE1BQU0sQ0FBQyxJQUFJLEVBQUU7WUFBRSxNQUFNLFVBQVUsQ0FBQyxXQUFXLENBQVUsTUFBTSxDQUFDLENBQUM7SUFDckUsQ0FBQztZQUFTLENBQUM7UUFDUCwwRkFBMEY7UUFDMUYsTUFBTSxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzNDLENBQUM7QUFDTCxDQUFDIn0=
@@ -0,0 +1,40 @@
1
+ import { Serializer } from "../serializers";
2
+
3
+ /**
4
+ * Exposes the body of a `Response` as a stream of deserialized entities.
5
+ * @typeParam TEntity The type of entity the stream provides.
6
+ * @param response The response to read the body from.
7
+ * @param serializer Controls the deserialization of the entities in the body.
8
+ * @param separator The character sequence used to detect that a new entity starts in the stream.
9
+ * @returns A stream that ends when the server closes the connection.
10
+ */
11
+ export async function* entityStream<TEntity>(response: Response, serializer: Serializer, separator: string = "\n"): AsyncIterableIterator<TEntity> {
12
+ if (!response.body) return;
13
+
14
+ const reader = response.body.getReader();
15
+ const decoder = new TextDecoder();
16
+ let buffer = "";
17
+
18
+ try {
19
+ while (true) {
20
+ const { done, value } = await reader.read();
21
+ if (done) break;
22
+
23
+ buffer += decoder.decode(value, { stream: true });
24
+
25
+ let index: number;
26
+ while ((index = buffer.indexOf(separator)) !== -1) {
27
+ const entity = buffer.slice(0, index);
28
+ buffer = buffer.slice(index + separator.length);
29
+ if (entity.trim()) yield serializer.deserialize<TEntity>(entity);
30
+ }
31
+ }
32
+
33
+ // Tolerate a missing separator after the last entity
34
+ buffer += decoder.decode();
35
+ if (buffer.trim()) yield serializer.deserialize<TEntity>(buffer);
36
+ } finally {
37
+ // NOTE: Ignore errors here so that a failure that already ended the stream is not masked.
38
+ await reader.cancel().catch(() => { });
39
+ }
40
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpContentRange = void 0;
4
+ const HttpHeader_1 = require("./HttpHeader");
5
+ /**
6
+ * Describes which subset of a set of elements a response contains.
7
+ */
8
+ class HttpContentRange {
9
+ /**
10
+ * Creates a new content range.
11
+ * @param unit The unit the range is expressed in, e.g. `elements`.
12
+ * @param from The index at which the data starts.
13
+ * @param to The index at which the data stops.
14
+ * @param length The total number of elements available on the server; `undefined` if unknown.
15
+ */
16
+ constructor(unit, from, to, length) {
17
+ this.unit = unit;
18
+ this.from = from;
19
+ this.to = to;
20
+ this.length = length;
21
+ }
22
+ /**
23
+ * Extracts the content range from a `Response`.
24
+ * @returns The content range; `undefined` if the response has no (valid) {@link HttpHeader.ContentRange} header.
25
+ */
26
+ static from(response) {
27
+ const header = response.headers.get(HttpHeader_1.HttpHeader.ContentRange);
28
+ if (!header)
29
+ return undefined;
30
+ const match = HttpContentRange.pattern.exec(header.trim());
31
+ if (!match)
32
+ return undefined;
33
+ const [, unit, from, to, length] = match;
34
+ return new HttpContentRange(unit, from === undefined ? undefined : parseInt(from), to === undefined ? undefined : parseInt(to), length === "*" ? undefined : parseInt(length));
35
+ }
36
+ }
37
+ exports.HttpContentRange = HttpContentRange;
38
+ HttpContentRange.pattern = /^(\w+) (?:(\d+)-(\d+)|\*)\/(\d+|\*)$/;
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cENvbnRlbnRSYW5nZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkh0dHBDb250ZW50UmFuZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQTBDO0FBRTFDOztHQUVHO0FBQ0gsTUFBYSxnQkFBZ0I7SUFDekI7Ozs7OztPQU1HO0lBQ0gsWUFDb0IsSUFBWSxFQUNaLElBQWEsRUFDYixFQUFXLEVBQ1gsTUFBZTtRQUhmLFNBQUksR0FBSixJQUFJLENBQVE7UUFDWixTQUFJLEdBQUosSUFBSSxDQUFTO1FBQ2IsT0FBRSxHQUFGLEVBQUUsQ0FBUztRQUNYLFdBQU0sR0FBTixNQUFNLENBQVM7SUFDbkMsQ0FBQztJQUlEOzs7T0FHRztJQUNILE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBa0I7UUFDMUIsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQVUsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUM3RCxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU8sU0FBUyxDQUFDO1FBRTlCLE1BQU0sS0FBSyxHQUFHLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPLFNBQVMsQ0FBQztRQUU3QixNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUM7UUFDekMsT0FBTyxJQUFJLGdCQUFnQixDQUN2QixJQUFJLEVBQ0osSUFBSSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQy9DLEVBQUUsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUMzQyxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ3ZELENBQUM7O0FBbENMLDRDQW1DQztBQXBCMkIsd0JBQU8sR0FBRyxzQ0FBc0MsQ0FBQyJ9
@@ -0,0 +1,41 @@
1
+ import { HttpHeader } from "./HttpHeader";
2
+
3
+ /**
4
+ * Describes which subset of a set of elements a response contains.
5
+ */
6
+ export class HttpContentRange {
7
+ /**
8
+ * Creates a new content range.
9
+ * @param unit The unit the range is expressed in, e.g. `elements`.
10
+ * @param from The index at which the data starts.
11
+ * @param to The index at which the data stops.
12
+ * @param length The total number of elements available on the server; `undefined` if unknown.
13
+ */
14
+ constructor(
15
+ public readonly unit: string,
16
+ public readonly from?: number,
17
+ public readonly to?: number,
18
+ public readonly length?: number) {
19
+ }
20
+
21
+ private static readonly pattern = /^(\w+) (?:(\d+)-(\d+)|\*)\/(\d+|\*)$/;
22
+
23
+ /**
24
+ * Extracts the content range from a `Response`.
25
+ * @returns The content range; `undefined` if the response has no (valid) {@link HttpHeader.ContentRange} header.
26
+ */
27
+ static from(response: Response): HttpContentRange | undefined {
28
+ const header = response.headers.get(HttpHeader.ContentRange);
29
+ if (!header) return undefined;
30
+
31
+ const match = HttpContentRange.pattern.exec(header.trim());
32
+ if (!match) return undefined;
33
+
34
+ const [, unit, from, to, length] = match;
35
+ return new HttpContentRange(
36
+ unit,
37
+ from === undefined ? undefined : parseInt(from),
38
+ to === undefined ? undefined : parseInt(to),
39
+ length === "*" ? undefined : parseInt(length));
40
+ }
41
+ }
@@ -12,5 +12,10 @@ var HttpHeader;
12
12
  HttpHeader["ETag"] = "ETag";
13
13
  HttpHeader["IfMatch"] = "If-Match";
14
14
  HttpHeader["IfNoneMatch"] = "If-None-Match";
15
+ HttpHeader["Range"] = "Range";
16
+ HttpHeader["ContentRange"] = "Content-Range";
17
+ HttpHeader["AcceptRanges"] = "Accept-Ranges";
18
+ HttpHeader["RetryAfter"] = "Retry-After";
19
+ HttpHeader["LastEventId"] = "Last-Event-ID";
15
20
  })(HttpHeader || (exports.HttpHeader = HttpHeader = {}));
16
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cEhlYWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkh0dHBIZWFkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsSUFBWSxVQVVYO0FBVkQsV0FBWSxVQUFVO0lBQ2xCLDZDQUErQixDQUFBO0lBQy9CLDBDQUE0QixDQUFBO0lBQzVCLCtCQUFpQixDQUFBO0lBQ2pCLDZCQUFlLENBQUE7SUFDZixtQ0FBcUIsQ0FBQTtJQUNyQiwyQkFBYSxDQUFBO0lBQ2IsMkJBQWEsQ0FBQTtJQUNiLGtDQUFvQixDQUFBO0lBQ3BCLDJDQUE2QixDQUFBO0FBQ2pDLENBQUMsRUFWVyxVQUFVLDBCQUFWLFVBQVUsUUFVckIifQ==
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cEhlYWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkh0dHBIZWFkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsSUFBWSxVQWVYO0FBZkQsV0FBWSxVQUFVO0lBQ2xCLDZDQUErQixDQUFBO0lBQy9CLDBDQUE0QixDQUFBO0lBQzVCLCtCQUFpQixDQUFBO0lBQ2pCLDZCQUFlLENBQUE7SUFDZixtQ0FBcUIsQ0FBQTtJQUNyQiwyQkFBYSxDQUFBO0lBQ2IsMkJBQWEsQ0FBQTtJQUNiLGtDQUFvQixDQUFBO0lBQ3BCLDJDQUE2QixDQUFBO0lBQzdCLDZCQUFlLENBQUE7SUFDZiw0Q0FBOEIsQ0FBQTtJQUM5Qiw0Q0FBOEIsQ0FBQTtJQUM5Qix3Q0FBMEIsQ0FBQTtJQUMxQiwyQ0FBNkIsQ0FBQTtBQUNqQyxDQUFDLEVBZlcsVUFBVSwwQkFBVixVQUFVLFFBZXJCIn0=
@@ -7,5 +7,10 @@ export enum HttpHeader {
7
7
  Link = "Link",
8
8
  ETag = "ETag",
9
9
  IfMatch = "If-Match",
10
- IfNoneMatch = "If-None-Match"
10
+ IfNoneMatch = "If-None-Match",
11
+ Range = "Range",
12
+ ContentRange = "Content-Range",
13
+ AcceptRanges = "Accept-Ranges",
14
+ RetryAfter = "Retry-After",
15
+ LastEventId = "Last-Event-ID"
11
16
  }
@@ -6,6 +6,8 @@ var HttpStatusCode;
6
6
  HttpStatusCode[HttpStatusCode["OK"] = 200] = "OK";
7
7
  HttpStatusCode[HttpStatusCode["Created"] = 201] = "Created";
8
8
  HttpStatusCode[HttpStatusCode["Accepted"] = 202] = "Accepted";
9
+ HttpStatusCode[HttpStatusCode["NoContent"] = 204] = "NoContent";
10
+ HttpStatusCode[HttpStatusCode["PartialContent"] = 206] = "PartialContent";
9
11
  HttpStatusCode[HttpStatusCode["NotModified"] = 304] = "NotModified";
10
12
  HttpStatusCode[HttpStatusCode["BadRequest"] = 400] = "BadRequest";
11
13
  HttpStatusCode[HttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
@@ -15,5 +17,6 @@ var HttpStatusCode;
15
17
  HttpStatusCode[HttpStatusCode["Conflict"] = 409] = "Conflict";
16
18
  HttpStatusCode[HttpStatusCode["Gone"] = 410] = "Gone";
17
19
  HttpStatusCode[HttpStatusCode["PreconditionFailed"] = 412] = "PreconditionFailed";
20
+ HttpStatusCode[HttpStatusCode["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
18
21
  })(HttpStatusCode || (exports.HttpStatusCode = HttpStatusCode = {}));
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cFN0YXR1c0NvZGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJIdHRwU3RhdHVzQ29kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxJQUFZLGNBYVg7QUFiRCxXQUFZLGNBQWM7SUFDdEIsaURBQVEsQ0FBQTtJQUNSLDJEQUFhLENBQUE7SUFDYiw2REFBYyxDQUFBO0lBQ2QsbUVBQWlCLENBQUE7SUFDakIsaUVBQWdCLENBQUE7SUFDaEIscUVBQWtCLENBQUE7SUFDbEIsK0RBQWUsQ0FBQTtJQUNmLDZEQUFjLENBQUE7SUFDZCx5RUFBb0IsQ0FBQTtJQUNwQiw2REFBYyxDQUFBO0lBQ2QscURBQVUsQ0FBQTtJQUNWLGlGQUF3QixDQUFBO0FBQzVCLENBQUMsRUFiVyxjQUFjLDhCQUFkLGNBQWMsUUFhekIifQ==
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cFN0YXR1c0NvZGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJIdHRwU3RhdHVzQ29kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxJQUFZLGNBZ0JYO0FBaEJELFdBQVksY0FBYztJQUN0QixpREFBUSxDQUFBO0lBQ1IsMkRBQWEsQ0FBQTtJQUNiLDZEQUFjLENBQUE7SUFDZCwrREFBZSxDQUFBO0lBQ2YseUVBQW9CLENBQUE7SUFDcEIsbUVBQWlCLENBQUE7SUFDakIsaUVBQWdCLENBQUE7SUFDaEIscUVBQWtCLENBQUE7SUFDbEIsK0RBQWUsQ0FBQTtJQUNmLDZEQUFjLENBQUE7SUFDZCx5RUFBb0IsQ0FBQTtJQUNwQiw2REFBYyxDQUFBO0lBQ2QscURBQVUsQ0FBQTtJQUNWLGlGQUF3QixDQUFBO0lBQ3hCLG1GQUF5QixDQUFBO0FBQzdCLENBQUMsRUFoQlcsY0FBYyw4QkFBZCxjQUFjLFFBZ0J6QiJ9
@@ -2,6 +2,8 @@ export enum HttpStatusCode {
2
2
  OK = 200,
3
3
  Created = 201,
4
4
  Accepted = 202,
5
+ NoContent = 204,
6
+ PartialContent = 206,
5
7
  NotModified = 304,
6
8
  BadRequest = 400,
7
9
  Unauthorized = 401,
@@ -10,5 +12,6 @@ export enum HttpStatusCode {
10
12
  RequestTimeout = 408,
11
13
  Conflict = 409,
12
14
  Gone = 410,
13
- PreconditionFailed = 412
15
+ PreconditionFailed = 412,
16
+ RangeNotSatisfiable = 416
14
17
  }
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.ResponseCache = void 0;
13
4
  const HttpHeader_1 = require("./HttpHeader");
@@ -29,12 +20,10 @@ class ResponseCache {
29
20
  /**
30
21
  * Creates a new cache from a `Response`.
31
22
  */
32
- static from(response) {
33
- return __awaiter(this, void 0, void 0, function* () {
34
- var _a, _b;
35
- return new ResponseCache(yield response.text(), (_a = response.headers.get(HttpHeader_1.HttpHeader.ContentType)) !== null && _a !== void 0 ? _a : undefined, (_b = response.headers.get(HttpHeader_1.HttpHeader.ETag)) !== null && _b !== void 0 ? _b : undefined);
36
- });
23
+ static async from(response) {
24
+ var _a, _b;
25
+ return new ResponseCache(await response.text(), (_a = response.headers.get(HttpHeader_1.HttpHeader.ContentType)) !== null && _a !== void 0 ? _a : undefined, (_b = response.headers.get(HttpHeader_1.HttpHeader.ETag)) !== null && _b !== void 0 ? _b : undefined);
37
26
  }
38
27
  }
39
28
  exports.ResponseCache = ResponseCache;
40
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVzcG9uc2VDYWNoZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIlJlc3BvbnNlQ2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsNkNBQTBDO0FBRTFDOztHQUVHO0FBQ0gsTUFBYSxhQUFhO0lBQ3RCOzs7OztPQUtHO0lBQ0gsWUFBNEIsT0FBZSxFQUFrQixXQUFvQixFQUFrQixJQUFhO1FBQXBGLFlBQU8sR0FBUCxPQUFPLENBQVE7UUFBa0IsZ0JBQVcsR0FBWCxXQUFXLENBQVM7UUFBa0IsU0FBSSxHQUFKLElBQUksQ0FBUztJQUNoSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQU8sSUFBSSxDQUFDLFFBQWtCOzs7WUFDaEMsT0FBTyxJQUFJLGFBQWEsQ0FDcEIsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQ3JCLE1BQUEsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQVUsQ0FBQyxXQUFXLENBQUMsbUNBQUksU0FBUyxFQUN6RCxNQUFBLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUFVLENBQUMsSUFBSSxDQUFDLG1DQUFJLFNBQVMsQ0FBQyxDQUFDO1FBQzVELENBQUM7S0FBQTtDQUNKO0FBbkJELHNDQW1CQyJ9
29
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVzcG9uc2VDYWNoZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIlJlc3BvbnNlQ2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQTBDO0FBRTFDOztHQUVHO0FBQ0gsTUFBYSxhQUFhO0lBQ3RCOzs7OztPQUtHO0lBQ0gsWUFBNEIsT0FBZSxFQUFrQixXQUFvQixFQUFrQixJQUFhO1FBQXBGLFlBQU8sR0FBUCxPQUFPLENBQVE7UUFBa0IsZ0JBQVcsR0FBWCxXQUFXLENBQVM7UUFBa0IsU0FBSSxHQUFKLElBQUksQ0FBUztJQUNoSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFrQjs7UUFDaEMsT0FBTyxJQUFJLGFBQWEsQ0FDcEIsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQ3JCLE1BQUEsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQVUsQ0FBQyxXQUFXLENBQUMsbUNBQUksU0FBUyxFQUN6RCxNQUFBLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUFVLENBQUMsSUFBSSxDQUFDLG1DQUFJLFNBQVMsQ0FBQyxDQUFDO0lBQzVELENBQUM7Q0FDSjtBQW5CRCxzQ0FtQkMifQ==
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.retryAfter = retryAfter;
4
+ const HttpHeader_1 = require("./HttpHeader");
5
+ /**
6
+ * Extracts the delay a server has asked clients to wait for before retrying a request.
7
+ * @param response The response to read the {@link HttpHeader.RetryAfter} header from.
8
+ * @returns The delay in milliseconds; `undefined` if the response has no (valid) header.
9
+ */
10
+ function retryAfter(response) {
11
+ var _a;
12
+ const header = (_a = response.headers.get(HttpHeader_1.HttpHeader.RetryAfter)) === null || _a === void 0 ? void 0 : _a.trim();
13
+ if (!header)
14
+ return undefined;
15
+ // Either a number of seconds ...
16
+ if (/^\d+$/.test(header))
17
+ return parseInt(header) * 1000;
18
+ // ... or an absolute point in time
19
+ const date = Date.parse(header);
20
+ if (Number.isNaN(date))
21
+ return undefined;
22
+ return Math.max(0, date - Date.now());
23
+ }
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmV0cnlBZnRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIlJldHJ5QWZ0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFPQSxnQ0FXQztBQWxCRCw2Q0FBMEM7QUFFMUM7Ozs7R0FJRztBQUNILFNBQWdCLFVBQVUsQ0FBQyxRQUFrQjs7SUFDekMsTUFBTSxNQUFNLEdBQUcsTUFBQSxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBVSxDQUFDLFVBQVUsQ0FBQywwQ0FBRSxJQUFJLEVBQUUsQ0FBQztJQUNuRSxJQUFJLENBQUMsTUFBTTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBRTlCLGlDQUFpQztJQUNqQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQUUsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBRXpELG1DQUFtQztJQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2hDLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUN6QyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUMxQyxDQUFDIn0=
@@ -0,0 +1,19 @@
1
+ import { HttpHeader } from "./HttpHeader";
2
+
3
+ /**
4
+ * Extracts the delay a server has asked clients to wait for before retrying a request.
5
+ * @param response The response to read the {@link HttpHeader.RetryAfter} header from.
6
+ * @returns The delay in milliseconds; `undefined` if the response has no (valid) header.
7
+ */
8
+ export function retryAfter(response: Response): number | undefined {
9
+ const header = response.headers.get(HttpHeader.RetryAfter)?.trim();
10
+ if (!header) return undefined;
11
+
12
+ // Either a number of seconds ...
13
+ if (/^\d+$/.test(header)) return parseInt(header) * 1000;
14
+
15
+ // ... or an absolute point in time
16
+ const date = Date.parse(header);
17
+ if (Number.isNaN(date)) return undefined;
18
+ return Math.max(0, date - Date.now());
19
+ }
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SseReader = exports.defaultEventType = exports.ServerSentEvent = void 0;
4
+ /**
5
+ * Yields the lines terminated by `\n`, `\r\n` or `\r` within the first `limit` characters of `buffer`.
6
+ * @returns The remaining characters that are not part of a terminated line.
7
+ */
8
+ function* splitLines(buffer, limit) {
9
+ let start = 0;
10
+ for (let index = 0; index < limit; index++) {
11
+ const char = buffer[index];
12
+ if (char !== "\n" && char !== "\r")
13
+ continue;
14
+ yield buffer.slice(start, index);
15
+ if (char === "\r" && buffer[index + 1] === "\n")
16
+ index++;
17
+ start = index + 1;
18
+ }
19
+ return buffer.slice(start);
20
+ }
21
+ /**
22
+ * A single event read from a Server-Sent Events (SSE) stream.
23
+ */
24
+ class ServerSentEvent {
25
+ /**
26
+ * Creates a new event.
27
+ * @param type The event type from the `event:` field. {@link defaultEventType} if the server did not specify one.
28
+ * @param data The concatenated content of the event's `data:` fields.
29
+ * @param id The id of the most recent `id:` field if any.
30
+ */
31
+ constructor(type, data, id) {
32
+ this.type = type;
33
+ this.data = data;
34
+ this.id = id;
35
+ }
36
+ }
37
+ exports.ServerSentEvent = ServerSentEvent;
38
+ /**
39
+ * The event type used for events without an explicit `event:` field.
40
+ */
41
+ exports.defaultEventType = "message";
42
+ /**
43
+ * Reads {@link ServerSentEvent}s from the body of a `Response` in the `text/event-stream` format.
44
+ */
45
+ class SseReader {
46
+ /**
47
+ * Creates a new reader.
48
+ * @param response The response to read the body from.
49
+ */
50
+ constructor(response) {
51
+ this.response = response;
52
+ }
53
+ /**
54
+ * The id of the most recent event that carried an `id:` field.<br>
55
+ * Send this back as a {@link HttpHeader.LastEventId} header when reconnecting to let the server resume where it left off.
56
+ */
57
+ get lastEventId() { return this._lastEventId; }
58
+ /**
59
+ * The reconnection interval in milliseconds most recently requested by the server via a `retry:` field if any.
60
+ */
61
+ get reconnectionInterval() { return this._reconnectionInterval; }
62
+ /**
63
+ * Reads events until the stream ends.<br>
64
+ * Any event that is still incomplete when the stream ends is discarded.
65
+ */
66
+ async *events() {
67
+ let type;
68
+ let data = "";
69
+ for await (const line of this.lines()) {
70
+ if (line === "") {
71
+ // A blank line dispatches the event collected so far
72
+ if (data !== "") {
73
+ // Every data field appended a trailing newline; the last one is not part of the payload
74
+ yield new ServerSentEvent(type !== null && type !== void 0 ? type : exports.defaultEventType, data.slice(0, -1), this._lastEventId);
75
+ data = "";
76
+ }
77
+ type = undefined;
78
+ continue;
79
+ }
80
+ // Lines starting with a colon are comments, e.g. the ":ping" some servers send to keep the connection alive
81
+ if (line.startsWith(":"))
82
+ continue;
83
+ const colonIndex = line.indexOf(":");
84
+ const field = (colonIndex === -1) ? line : line.slice(0, colonIndex);
85
+ const value = (colonIndex === -1) ? ""
86
+ : line.slice((line[colonIndex + 1] === " ") ? colonIndex + 2 : colonIndex + 1);
87
+ switch (field) {
88
+ case "event":
89
+ type = value;
90
+ break;
91
+ case "data":
92
+ data += value + "\n";
93
+ break;
94
+ case "id":
95
+ if (value.indexOf("\0") === -1)
96
+ this._lastEventId = value;
97
+ break;
98
+ case "retry":
99
+ if (/^\d+$/.test(value))
100
+ this._reconnectionInterval = parseInt(value);
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ /**
106
+ * Splits the response body into lines, accepting `\n`, `\r\n` and `\r` as terminators.
107
+ */
108
+ async *lines() {
109
+ if (!this.response.body)
110
+ return;
111
+ const reader = this.response.body.getReader();
112
+ const decoder = new TextDecoder();
113
+ let buffer = "";
114
+ let stripBom = true;
115
+ try {
116
+ while (true) {
117
+ const { done, value } = await reader.read();
118
+ if (done)
119
+ break;
120
+ buffer += decoder.decode(value, { stream: true });
121
+ if (stripBom && buffer !== "") {
122
+ if (buffer.charCodeAt(0) === 0xFEFF)
123
+ buffer = buffer.slice(1);
124
+ stripBom = false;
125
+ }
126
+ // NOTE: Keep a trailing "\r" buffered; it may still be followed by a "\n" in the next chunk.
127
+ buffer = yield* splitLines(buffer, buffer.endsWith("\r") ? buffer.length - 1 : buffer.length);
128
+ }
129
+ // NOTE: A line that is still unterminated once the stream ends is discarded.
130
+ buffer += decoder.decode();
131
+ yield* splitLines(buffer, buffer.length);
132
+ }
133
+ finally {
134
+ // NOTE: Ignore errors here so that a failure that already ended the stream is not masked.
135
+ await reader.cancel().catch(() => { });
136
+ }
137
+ }
138
+ }
139
+ exports.SseReader = SseReader;
140
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVyU2VudEV2ZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIlNlcnZlclNlbnRFdmVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUE7OztHQUdHO0FBQ0gsUUFBUSxDQUFDLENBQUMsVUFBVSxDQUFDLE1BQWMsRUFBRSxLQUFhO0lBQzlDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztJQUVkLEtBQUssSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUN6QyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDM0IsSUFBSSxJQUFJLEtBQUssSUFBSSxJQUFJLElBQUksS0FBSyxJQUFJO1lBQUUsU0FBUztRQUU3QyxNQUFNLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ2pDLElBQUksSUFBSSxLQUFLLElBQUksSUFBSSxNQUFNLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLElBQUk7WUFBRSxLQUFLLEVBQUUsQ0FBQztRQUN6RCxLQUFLLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQztJQUN0QixDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQy9CLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQWEsZUFBZTtJQUN4Qjs7Ozs7T0FLRztJQUNILFlBQTRCLElBQVksRUFBa0IsSUFBWSxFQUFrQixFQUFXO1FBQXZFLFNBQUksR0FBSixJQUFJLENBQVE7UUFBa0IsU0FBSSxHQUFKLElBQUksQ0FBUTtRQUFrQixPQUFFLEdBQUYsRUFBRSxDQUFTO0lBQ25HLENBQUM7Q0FDSjtBQVRELDBDQVNDO0FBRUQ7O0dBRUc7QUFDVSxRQUFBLGdCQUFnQixHQUFHLFNBQVMsQ0FBQztBQUUxQzs7R0FFRztBQUNILE1BQWEsU0FBUztJQUNsQjs7O09BR0c7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