@nymphjs/client 1.0.0-beta.13 → 1.0.0-beta.131

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 (73) hide show
  1. package/CHANGELOG.md +552 -0
  2. package/README.md +12 -8
  3. package/asyncitertest.js +53 -0
  4. package/dist/Entity.d.ts +158 -0
  5. package/dist/Entity.js +643 -0
  6. package/dist/Entity.js.map +1 -0
  7. package/dist/Entity.types.d.ts +216 -0
  8. package/dist/Entity.types.js +2 -0
  9. package/{lib → dist}/EntityWeakCache.d.ts +1 -1
  10. package/{lib → dist}/EntityWeakCache.js +5 -9
  11. package/dist/EntityWeakCache.js.map +1 -0
  12. package/{lib → dist}/HttpRequester.d.ts +18 -4
  13. package/dist/HttpRequester.js +365 -0
  14. package/dist/HttpRequester.js.map +1 -0
  15. package/{lib → dist}/Nymph.d.ts +48 -11
  16. package/{lib → dist}/Nymph.js +172 -56
  17. package/dist/Nymph.js.map +1 -0
  18. package/dist/Nymph.types.d.ts +227 -0
  19. package/dist/Nymph.types.js +45 -0
  20. package/dist/Nymph.types.js.map +1 -0
  21. package/{lib → dist}/PubSub.d.ts +16 -10
  22. package/{lib → dist}/PubSub.js +207 -135
  23. package/dist/PubSub.js.map +1 -0
  24. package/{lib → dist}/PubSub.types.d.ts +19 -6
  25. package/dist/PubSub.types.js +2 -0
  26. package/{lib → dist}/entityRefresh.d.ts +1 -1
  27. package/{lib → dist}/entityRefresh.js +21 -13
  28. package/dist/entityRefresh.js.map +1 -0
  29. package/dist/index.d.ts +13 -0
  30. package/dist/index.js +13 -2
  31. package/dist/index.js.map +1 -1
  32. package/{lib → dist}/utils.d.ts +2 -1
  33. package/dist/utils.js +145 -0
  34. package/dist/utils.js.map +1 -0
  35. package/jest.config.js +31 -5
  36. package/package.json +36 -32
  37. package/src/Entity.ts +361 -247
  38. package/src/Entity.types.ts +37 -57
  39. package/src/EntityWeakCache.ts +8 -6
  40. package/src/HttpRequester.ts +268 -31
  41. package/src/Nymph.ts +203 -96
  42. package/src/Nymph.types.ts +98 -2
  43. package/src/PubSub.ts +264 -181
  44. package/src/PubSub.types.ts +33 -19
  45. package/src/entityRefresh.ts +6 -6
  46. package/src/index.ts +10 -10
  47. package/src/utils.ts +67 -14
  48. package/tsconfig.json +7 -4
  49. package/typedoc.json +4 -0
  50. package/dist/index.js.LICENSE.txt +0 -8
  51. package/lib/Entity.d.ts +0 -51
  52. package/lib/Entity.js +0 -500
  53. package/lib/Entity.js.map +0 -1
  54. package/lib/Entity.types.d.ts +0 -65
  55. package/lib/Entity.types.js +0 -3
  56. package/lib/EntityWeakCache.js.map +0 -1
  57. package/lib/HttpRequester.js +0 -190
  58. package/lib/HttpRequester.js.map +0 -1
  59. package/lib/Nymph.js.map +0 -1
  60. package/lib/Nymph.types.d.ts +0 -98
  61. package/lib/Nymph.types.js +0 -3
  62. package/lib/Nymph.types.js.map +0 -1
  63. package/lib/PubSub.js.map +0 -1
  64. package/lib/PubSub.types.js +0 -3
  65. package/lib/entityRefresh.js.map +0 -1
  66. package/lib/index.d.ts +0 -13
  67. package/lib/index.js +0 -34
  68. package/lib/index.js.map +0 -1
  69. package/lib/utils.js +0 -86
  70. package/lib/utils.js.map +0 -1
  71. package/webpack.config.js +0 -28
  72. /package/{lib → dist}/Entity.types.js.map +0 -0
  73. /package/{lib → dist}/PubSub.types.js.map +0 -0
@@ -0,0 +1,216 @@
1
+ import type Nymph from './Nymph.js';
2
+ import type Entity from './Entity.js';
3
+ export type ServerCallResponse = {
4
+ return: any;
5
+ entity?: EntityJson;
6
+ };
7
+ export type ServerCallStaticResponse = any;
8
+ export type EntityReference = ['nymph_entity_reference', string, string];
9
+ export type EntityData = {
10
+ [k: string]: any;
11
+ };
12
+ export type SerializedEntityData = {
13
+ [k: string]: string;
14
+ };
15
+ export type EntityJson<T extends EntityConstructor = EntityConstructor> = {
16
+ class: T['class'];
17
+ guid: string | null;
18
+ cdate: number | null;
19
+ mdate: number | null;
20
+ tags: string[];
21
+ data: EntityData;
22
+ };
23
+ export type EntityPatch = {
24
+ class: string;
25
+ guid: string;
26
+ mdate: number | null;
27
+ set: EntityData;
28
+ unset: string[];
29
+ addTags: string[];
30
+ removeTags: string[];
31
+ };
32
+ /**
33
+ * Data Object interface.
34
+ *
35
+ * Objects which hold data from some type of storage.
36
+ */
37
+ export interface DataObjectInterface {
38
+ /**
39
+ * Search the array for this object and return the corresponding index.
40
+ *
41
+ * If `strict` is false, `is()` is used to compare. If `strict` is true,
42
+ * `equals()` is used.
43
+ *
44
+ * @param array The array to search.
45
+ * @param strict Whether to use stronger comparison.
46
+ * @returns The index if the object is in the array, -1 if it isn't.
47
+ */
48
+ $arraySearch(array: any[], strict?: boolean): number;
49
+ /**
50
+ * Delete the object from storage.
51
+ *
52
+ * An error is thrown on failure.
53
+ */
54
+ $delete(): Promise<void>;
55
+ /**
56
+ * Perform a more strict comparison of this object to another.
57
+ *
58
+ * @param object The object to compare.
59
+ * @returns True or false.
60
+ */
61
+ $equals(object: any): boolean;
62
+ /**
63
+ * Check whether this object is in an array.
64
+ *
65
+ * If `strict` is false, `is()` is used to compare. If `strict` is true,
66
+ * `equals()` is used.
67
+ *
68
+ * @param array The array to search.
69
+ * @param strict Whether to use stronger comparison.
70
+ * @returns True if the object is in the array, false if it isn't.
71
+ */
72
+ $inArray(array: any[], strict?: boolean): boolean;
73
+ /**
74
+ * Perform a less strict comparison of this object to another.
75
+ *
76
+ * @param object The object to compare.
77
+ * @returns True or false.
78
+ */
79
+ $is(object: any): boolean;
80
+ /**
81
+ * Save the object's dirty data to storage.
82
+ *
83
+ * An error is thrown on failure.
84
+ */
85
+ $patch(): Promise<void>;
86
+ /**
87
+ * Refresh the object from storage. (Bypasses Nymph's cache.)
88
+ *
89
+ * @returns False if the data has not been saved, true on success. An error is
90
+ * thrown on failure.
91
+ */
92
+ $refresh(): Promise<boolean | 0>;
93
+ /**
94
+ * Save the object to storage.
95
+ *
96
+ * An error is thrown on failure.
97
+ */
98
+ $save(): Promise<void>;
99
+ /**
100
+ * The object's data.
101
+ */
102
+ [k: string]: any;
103
+ }
104
+ /**
105
+ * Entity interface.
106
+ */
107
+ export interface EntityInterface extends DataObjectInterface {
108
+ /**
109
+ * The instance of Nymph to use for queries.
110
+ */
111
+ $nymph: Nymph;
112
+ /**
113
+ * The entity's Globally Unique ID.
114
+ *
115
+ * This is a 12 byte number represented as a lower case HEX string (24
116
+ * characters).
117
+ */
118
+ guid: string | null;
119
+ /**
120
+ * The creation date of the entity as a Unix timestamp in milliseconds.
121
+ */
122
+ cdate: number | null;
123
+ /**
124
+ * The modified date of the entity as a Unix timestamp in milliseconds.
125
+ */
126
+ mdate: number | null;
127
+ /**
128
+ * Array of the entity's tags.
129
+ */
130
+ tags: string[];
131
+ /**
132
+ * Add one or more tags.
133
+ *
134
+ * @param tags List of tags.
135
+ */
136
+ $addTag(...tags: string[]): void;
137
+ /**
138
+ * Get a patch of this entity's dirty data to be applied on the server.
139
+ */
140
+ $getPatch(): EntityPatch;
141
+ /**
142
+ * Check that the entity has all of the given tags.
143
+ *
144
+ * @param tags List of tags.
145
+ * @returns True or false.
146
+ */
147
+ $hasTag(...tags: string[]): boolean;
148
+ /**
149
+ * Check whether a property is dirty.
150
+ *
151
+ * To be a dirty property, it must have been set or deleted since the entity
152
+ * was initialized. A clean property existed on initialization and hasn't been
153
+ * set or deleted. An untracked property didn't exist on initialization and
154
+ * hasn't been set or deleted.
155
+ *
156
+ * Note that this doesn't necessarily mean the property has changed. It could
157
+ * have been set to the same value, or created and then deleted.
158
+ *
159
+ * Entities are initialized when they are pulled from the server or saved.
160
+ * This is done with the `$init` method.
161
+ *
162
+ * @param property The name of a property.
163
+ * @returns True if it's dirty, false if not, and null if it's not tracked.
164
+ */
165
+ $isDirty(property: string): boolean | null;
166
+ /**
167
+ * Initialize this entity from a JSON representation.
168
+ *
169
+ * @param entityJson The entity JSON.
170
+ */
171
+ $init(entityJson: EntityJson | null): EntityInterface;
172
+ /**
173
+ * Retrieve this entity's data from the server.
174
+ *
175
+ * @returns The entity.
176
+ */
177
+ $wake(): Promise<EntityInterface>;
178
+ /**
179
+ * Ready this entity's data, and the data of entity's within this one's.
180
+ *
181
+ * @param level The number of levels deep to wake. If undefined, it will keep going until there are no more entities. (Careful of infinite loops.)
182
+ * @returns The entity.
183
+ */
184
+ $wakeAll(level?: number): Promise<EntityInterface>;
185
+ /**
186
+ * Remove one or more tags.
187
+ *
188
+ * @param tags List of tags.
189
+ */
190
+ $removeTag(...tags: string[]): void;
191
+ /**
192
+ * Call an instance method on the server version of this entity.
193
+ *
194
+ * The entity's data will be sent up to the server as well, so the server's
195
+ * state can match the client's state. It won't be propagated into the DB,
196
+ * though.
197
+ *
198
+ * @param method The name of the method.
199
+ * @param params The parameters to call the method with.
200
+ * @param stateless Whether the server should return, and the client update, the data in the entity after the method has run.
201
+ * @returns The value that the method on the server returned.
202
+ */
203
+ $serverCall(method: string, params: Iterable<any>, stateless: boolean): Promise<any>;
204
+ /**
205
+ * Return a Nymph Entity Reference for this entity.
206
+ *
207
+ * If the entity hasn't been saved yet (and has no GUID), it will be
208
+ * returned instead.
209
+ *
210
+ * @returns A Nymph Entity Reference array as an unsaved entity.
211
+ */
212
+ $toReference(): EntityReference | EntityInterface;
213
+ }
214
+ export type EntityConstructor<D extends EntityData = EntityData, E extends Entity<D> = Entity<D>> = (new (...args: any[]) => E) & {
215
+ [k in keyof typeof Entity]: (typeof Entity)[k];
216
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Entity.types.js.map
@@ -1,4 +1,4 @@
1
- import { EntityConstructor, EntityInterface } from './Entity.types';
1
+ import { EntityConstructor, EntityInterface } from './Entity.types.js';
2
2
  export default class EntityWeakCache {
3
3
  private references;
4
4
  get(EntityClass: EntityConstructor, guid: string): EntityInterface | null;
@@ -1,15 +1,12 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- class EntityWeakCache {
4
- constructor() {
5
- this.references = new WeakMap();
6
- }
1
+ export default class EntityWeakCache {
2
+ references = new WeakMap();
7
3
  get(EntityClass, guid) {
8
4
  const classMap = this.references.get(EntityClass);
9
5
  if (classMap && guid in classMap) {
10
6
  const weakRef = classMap[guid];
11
- if (weakRef && weakRef.deref() != null) {
12
- return weakRef.deref();
7
+ const deref = weakRef && weakRef.deref();
8
+ if (deref != null) {
9
+ return deref;
13
10
  }
14
11
  else {
15
12
  delete classMap[guid];
@@ -27,5 +24,4 @@ class EntityWeakCache {
27
24
  classMap[entity.guid] = weakRef;
28
25
  }
29
26
  }
30
- exports.default = EntityWeakCache;
31
27
  //# sourceMappingURL=EntityWeakCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityWeakCache.js","sourceRoot":"","sources":["../src/EntityWeakCache.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,OAAO,eAAe;IAC1B,UAAU,GAGd,IAAI,OAAO,EAAE,CAAC;IAElB,GAAG,CAAC,WAA8B,EAAE,IAAY;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAClD,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/B,MAAM,KAAK,GAAG,OAAO,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACzC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBAClB,OAAO,KAAK,CAAC;YACf,CAAC;iBAAM,CAAC;gBACN,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,WAA8B,EAAE,MAAuB;QACzD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;QAEpC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QACxD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC3C,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IAClC,CAAC;CACF"}
@@ -1,35 +1,49 @@
1
1
  export type HttpRequesterEventType = 'request' | 'response';
2
2
  export type HttpRequesterRequestCallback = (requester: HttpRequester, url: string, options: RequestInit) => void;
3
3
  export type HttpRequesterResponseCallback = (requester: HttpRequester, response: Response, text: string) => void;
4
+ export type HttpRequesterIteratorCallback = (requester: HttpRequester, url: string, headers: Record<string, string>) => void;
4
5
  export type HttpRequesterRequestOptions = {
5
6
  url: string;
7
+ headers?: {
8
+ [k: string]: any;
9
+ };
6
10
  data: {
7
11
  [k: string]: any;
8
12
  };
9
13
  dataType: string;
10
14
  };
15
+ export interface AbortableAsyncIterator<T extends any = any> extends AsyncIterable<T> {
16
+ abortController: AbortController;
17
+ }
11
18
  export default class HttpRequester {
12
19
  private fetch;
13
- private xsrfToken;
14
20
  private requestCallbacks;
15
21
  private responseCallbacks;
22
+ private iteratorCallbacks;
16
23
  static makeUrl(url: string, data: {
17
24
  [k: string]: any;
18
25
  }): string;
19
26
  constructor(ponyFetch?: WindowOrWorkerGlobalScope['fetch']);
20
- on<T extends HttpRequesterEventType>(event: T, callback: T extends 'request' ? HttpRequesterRequestCallback : T extends 'response' ? HttpRequesterResponseCallback : never): () => boolean;
21
- off<T extends HttpRequesterEventType>(event: T, callback: T extends 'request' ? HttpRequesterRequestCallback : T extends 'response' ? HttpRequesterResponseCallback : never): boolean;
22
- setXsrfToken(xsrfToken: string | null): void;
27
+ on<T extends HttpRequesterEventType>(event: T, callback: T extends 'request' ? HttpRequesterRequestCallback : T extends 'response' ? HttpRequesterResponseCallback : T extends 'iterator' ? HttpRequesterIteratorCallback : never): () => boolean;
28
+ off<T extends HttpRequesterEventType>(event: T, callback: T extends 'request' ? HttpRequesterRequestCallback : T extends 'response' ? HttpRequesterResponseCallback : T extends 'iterator' ? HttpRequesterIteratorCallback : never): boolean;
23
29
  GET(opt: HttpRequesterRequestOptions): Promise<any>;
24
30
  POST(opt: HttpRequesterRequestOptions): Promise<any>;
31
+ POST_ITERATOR(opt: HttpRequesterRequestOptions): Promise<AbortableAsyncIterator<any>>;
25
32
  PUT(opt: HttpRequesterRequestOptions): Promise<any>;
26
33
  PATCH(opt: HttpRequesterRequestOptions): Promise<any>;
27
34
  DELETE(opt: HttpRequesterRequestOptions): Promise<any>;
28
35
  _httpRequest(method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', opt: HttpRequesterRequestOptions): Promise<any>;
36
+ _iteratorRequest(method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', opt: HttpRequesterRequestOptions): Promise<AbortableAsyncIterator>;
29
37
  }
30
38
  export declare class InvalidResponseError extends Error {
31
39
  constructor(message: string);
32
40
  }
41
+ export declare class ConnectionClosedUnexpectedlyError extends Error {
42
+ constructor(message: string);
43
+ }
44
+ export declare class ConnectionError extends Error {
45
+ constructor(message: string);
46
+ }
33
47
  export declare class HttpError extends Error {
34
48
  status: number;
35
49
  statusText: string;
@@ -0,0 +1,365 @@
1
+ import { fetchEventSource, EventStreamContentType, } from 'fetch-event-source-hperrin';
2
+ export default class HttpRequester {
3
+ fetch;
4
+ requestCallbacks = [];
5
+ responseCallbacks = [];
6
+ iteratorCallbacks = [];
7
+ static makeUrl(url, data) {
8
+ if (!data) {
9
+ return url;
10
+ }
11
+ for (let [key, value] of Object.entries(data)) {
12
+ url =
13
+ url +
14
+ (url.indexOf('?') !== -1 ? '&' : '?') +
15
+ encodeURIComponent(key) +
16
+ '=' +
17
+ encodeURIComponent(JSON.stringify(value));
18
+ }
19
+ return url;
20
+ }
21
+ constructor(ponyFetch) {
22
+ this.fetch = ponyFetch ? ponyFetch : (...args) => fetch(...args);
23
+ }
24
+ on(event, callback) {
25
+ const prop = (event + 'Callbacks');
26
+ if (!(prop in this)) {
27
+ throw new Error('Invalid event type.');
28
+ }
29
+ // @ts-ignore: The callback should always be the right type here.
30
+ this[prop].push(callback);
31
+ return () => this.off(event, callback);
32
+ }
33
+ off(event, callback) {
34
+ const prop = (event + 'Callbacks');
35
+ if (!(prop in this)) {
36
+ return false;
37
+ }
38
+ // @ts-ignore: The callback should always be the right type here.
39
+ const i = this[prop].indexOf(callback);
40
+ if (i > -1) {
41
+ // @ts-ignore: The callback should always be the right type here.
42
+ this[prop].splice(i, 1);
43
+ }
44
+ return true;
45
+ }
46
+ async GET(opt) {
47
+ return await this._httpRequest('GET', opt);
48
+ }
49
+ async POST(opt) {
50
+ return await this._httpRequest('POST', opt);
51
+ }
52
+ async POST_ITERATOR(opt) {
53
+ return await this._iteratorRequest('POST', opt);
54
+ }
55
+ async PUT(opt) {
56
+ return await this._httpRequest('PUT', opt);
57
+ }
58
+ async PATCH(opt) {
59
+ return await this._httpRequest('PATCH', opt);
60
+ }
61
+ async DELETE(opt) {
62
+ return await this._httpRequest('DELETE', opt);
63
+ }
64
+ async _httpRequest(method, opt) {
65
+ const dataString = JSON.stringify(opt.data);
66
+ let url = opt.url;
67
+ if (method === 'GET') {
68
+ // TODO: what should this size be?
69
+ // && dataString.length < 1) {
70
+ url = HttpRequester.makeUrl(opt.url, opt.data);
71
+ }
72
+ const options = {
73
+ method,
74
+ headers: opt.headers ?? {},
75
+ credentials: 'include',
76
+ };
77
+ if (method !== 'GET' && opt.data) {
78
+ options.headers['Content-Type'] =
79
+ 'application/json';
80
+ options.body = dataString;
81
+ }
82
+ for (let i = 0; i < this.requestCallbacks.length; i++) {
83
+ this.requestCallbacks[i] && this.requestCallbacks[i](this, url, options);
84
+ }
85
+ const response = await this.fetch(url, options);
86
+ let text;
87
+ try {
88
+ text = await response.text();
89
+ }
90
+ catch (e) {
91
+ throw new InvalidResponseError('Server response did not contain valid text body.');
92
+ }
93
+ if (!response.ok) {
94
+ let errObj;
95
+ try {
96
+ errObj = JSON.parse(text);
97
+ }
98
+ catch (e) {
99
+ if (!(e instanceof SyntaxError)) {
100
+ throw e;
101
+ }
102
+ }
103
+ if (typeof errObj !== 'object') {
104
+ errObj = {
105
+ textStatus: response.statusText,
106
+ };
107
+ }
108
+ errObj.status = response.status;
109
+ throw response.status < 200
110
+ ? new InformationalError(response, errObj)
111
+ : response.status < 300
112
+ ? new SuccessError(response, errObj)
113
+ : response.status < 400
114
+ ? new RedirectError(response, errObj)
115
+ : response.status < 500
116
+ ? new ClientError(response, errObj)
117
+ : new ServerError(response, errObj);
118
+ }
119
+ for (let i = 0; i < this.responseCallbacks.length; i++) {
120
+ this.responseCallbacks[i] &&
121
+ this.responseCallbacks[i](this, response, text);
122
+ }
123
+ if (opt.dataType === 'json') {
124
+ if (!text.length) {
125
+ throw new InvalidResponseError('Server response was empty.');
126
+ }
127
+ try {
128
+ return JSON.parse(text);
129
+ }
130
+ catch (e) {
131
+ if (!(e instanceof SyntaxError)) {
132
+ throw e;
133
+ }
134
+ throw new InvalidResponseError('Server response was invalid: ' + JSON.stringify(text));
135
+ }
136
+ }
137
+ else {
138
+ return text;
139
+ }
140
+ }
141
+ async _iteratorRequest(method, opt) {
142
+ const dataString = JSON.stringify(opt.data);
143
+ let url = opt.url;
144
+ if (method === 'GET') {
145
+ // TODO: what should this size be?
146
+ // && dataString.length < 1) {
147
+ url = HttpRequester.makeUrl(opt.url, opt.data);
148
+ }
149
+ const hasBody = method !== 'GET' && opt.data;
150
+ const headers = opt.headers ?? {};
151
+ if (hasBody) {
152
+ headers['Content-Type'] = 'application/json';
153
+ }
154
+ for (let i = 0; i < this.iteratorCallbacks.length; i++) {
155
+ this.iteratorCallbacks[i] &&
156
+ this.iteratorCallbacks[i](this, url, headers);
157
+ }
158
+ const responses = [];
159
+ let nextResponseResolve;
160
+ let nextResponseReadyPromise = new Promise((res) => {
161
+ nextResponseResolve = res;
162
+ });
163
+ let responsesDone = false;
164
+ let serverResponse;
165
+ const ctrl = new AbortController();
166
+ fetchEventSource(url, {
167
+ openWhenHidden: true,
168
+ fetch: this.fetch,
169
+ method,
170
+ headers,
171
+ credentials: 'include',
172
+ body: hasBody ? dataString : undefined,
173
+ signal: ctrl.signal,
174
+ async onopen(response) {
175
+ serverResponse = response;
176
+ if (response.ok) {
177
+ if (response.headers.get('content-type') === EventStreamContentType) {
178
+ throw new InvalidResponseError('Server response is not an event stream.');
179
+ }
180
+ // Response is ok, wait for messages.
181
+ return;
182
+ }
183
+ let text = '';
184
+ try {
185
+ text = await response.text();
186
+ }
187
+ catch (e) {
188
+ // Ignore error here.
189
+ }
190
+ let errObj;
191
+ try {
192
+ errObj = JSON.parse(text);
193
+ }
194
+ catch (e) {
195
+ if (!(e instanceof SyntaxError)) {
196
+ throw e;
197
+ }
198
+ }
199
+ if (typeof errObj !== 'object') {
200
+ errObj = {
201
+ textStatus: response.statusText,
202
+ };
203
+ }
204
+ errObj.status = response.status;
205
+ throw response.status < 200
206
+ ? new InformationalError(response, errObj)
207
+ : response.status < 300
208
+ ? new SuccessError(response, errObj)
209
+ : response.status < 400
210
+ ? new RedirectError(response, errObj)
211
+ : response.status < 500
212
+ ? new ClientError(response, errObj)
213
+ : new ServerError(response, errObj);
214
+ },
215
+ onmessage(event) {
216
+ if (event.event === 'next') {
217
+ let text = event.data;
218
+ if (opt.dataType === 'json') {
219
+ if (!text.length) {
220
+ responses.push(new InvalidResponseError('Server response was empty.'));
221
+ }
222
+ else {
223
+ try {
224
+ responses.push(JSON.parse(text));
225
+ }
226
+ catch (e) {
227
+ if (!(e instanceof SyntaxError)) {
228
+ responses.push(e);
229
+ }
230
+ else {
231
+ responses.push(new InvalidResponseError('Server response was invalid: ' + JSON.stringify(text)));
232
+ }
233
+ }
234
+ }
235
+ }
236
+ else {
237
+ responses.push(text);
238
+ }
239
+ }
240
+ else if (event.event === 'error') {
241
+ let text = event.data;
242
+ let errObj;
243
+ try {
244
+ errObj = JSON.parse(text);
245
+ }
246
+ catch (e) {
247
+ if (!(e instanceof SyntaxError)) {
248
+ throw e;
249
+ }
250
+ }
251
+ if (typeof errObj !== 'object') {
252
+ errObj = {
253
+ status: 500,
254
+ textStatus: 'Iterator Error',
255
+ };
256
+ }
257
+ responses.push(errObj.status < 200
258
+ ? new InformationalError(serverResponse, errObj)
259
+ : errObj.status < 300
260
+ ? new SuccessError(serverResponse, errObj)
261
+ : errObj.status < 400
262
+ ? new RedirectError(serverResponse, errObj)
263
+ : errObj.status < 500
264
+ ? new ClientError(serverResponse, errObj)
265
+ : new ServerError(serverResponse, errObj));
266
+ }
267
+ else if (event.event === 'finished') {
268
+ responsesDone = true;
269
+ }
270
+ else if (event.event === 'ping') {
271
+ // Ignore keep-alive pings.
272
+ return;
273
+ }
274
+ const resolve = nextResponseResolve;
275
+ if (!responsesDone) {
276
+ nextResponseReadyPromise = new Promise((res) => {
277
+ nextResponseResolve = res;
278
+ });
279
+ }
280
+ // Resolve the promise to continue any waiting iterator.
281
+ resolve();
282
+ },
283
+ onclose() {
284
+ responses.push(new ConnectionClosedUnexpectedlyError('The connection to the server was closed unexpectedly.'));
285
+ responsesDone = true;
286
+ nextResponseResolve();
287
+ },
288
+ onerror(err) {
289
+ // Rethrow to stop the operation.
290
+ throw err;
291
+ },
292
+ }).catch((err) => {
293
+ responses.push(new ConnectionError('The connection could not be established: ' + err));
294
+ responsesDone = true;
295
+ nextResponseResolve();
296
+ });
297
+ const iterator = {
298
+ abortController: ctrl,
299
+ async *[Symbol.asyncIterator]() {
300
+ do {
301
+ await nextResponseReadyPromise;
302
+ while (responses.length) {
303
+ yield responses.shift();
304
+ }
305
+ } while (!responsesDone);
306
+ },
307
+ };
308
+ return iterator;
309
+ }
310
+ }
311
+ export class InvalidResponseError extends Error {
312
+ constructor(message) {
313
+ super(message);
314
+ this.name = 'InvalidResponseError';
315
+ }
316
+ }
317
+ export class ConnectionClosedUnexpectedlyError extends Error {
318
+ constructor(message) {
319
+ super(message);
320
+ this.name = 'ConnectionClosedUnexpectedlyError';
321
+ }
322
+ }
323
+ export class ConnectionError extends Error {
324
+ constructor(message) {
325
+ super(message);
326
+ this.name = 'ConnectionError';
327
+ }
328
+ }
329
+ export class HttpError extends Error {
330
+ status;
331
+ statusText;
332
+ constructor(name, response, errObj) {
333
+ super(errObj.textStatus);
334
+ this.name = name;
335
+ this.status = response.status;
336
+ this.statusText = response.statusText;
337
+ Object.assign(this, errObj);
338
+ }
339
+ }
340
+ export class InformationalError extends HttpError {
341
+ constructor(response, errObj) {
342
+ super('InformationalError', response, errObj);
343
+ }
344
+ }
345
+ export class SuccessError extends HttpError {
346
+ constructor(response, errObj) {
347
+ super('SuccessError', response, errObj);
348
+ }
349
+ }
350
+ export class RedirectError extends HttpError {
351
+ constructor(response, errObj) {
352
+ super('RedirectError', response, errObj);
353
+ }
354
+ }
355
+ export class ClientError extends HttpError {
356
+ constructor(response, errObj) {
357
+ super('ClientError', response, errObj);
358
+ }
359
+ }
360
+ export class ServerError extends HttpError {
361
+ constructor(response, errObj) {
362
+ super('ServerError', response, errObj);
363
+ }
364
+ }
365
+ //# sourceMappingURL=HttpRequester.js.map