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

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 (72) hide show
  1. package/CHANGELOG.md +546 -0
  2. package/README.md +12 -8
  3. package/asyncitertest.js +53 -0
  4. package/dist/Entity.d.ts +156 -0
  5. package/{lib → dist}/Entity.js +244 -118
  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 +229 -129
  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.map +0 -1
  53. package/lib/Entity.types.d.ts +0 -65
  54. package/lib/Entity.types.js +0 -3
  55. package/lib/EntityWeakCache.js.map +0 -1
  56. package/lib/HttpRequester.js +0 -190
  57. package/lib/HttpRequester.js.map +0 -1
  58. package/lib/Nymph.js.map +0 -1
  59. package/lib/Nymph.types.d.ts +0 -98
  60. package/lib/Nymph.types.js +0 -3
  61. package/lib/Nymph.types.js.map +0 -1
  62. package/lib/PubSub.js.map +0 -1
  63. package/lib/PubSub.types.js +0 -3
  64. package/lib/entityRefresh.js.map +0 -1
  65. package/lib/index.d.ts +0 -13
  66. package/lib/index.js +0 -34
  67. package/lib/index.js.map +0 -1
  68. package/lib/utils.js +0 -86
  69. package/lib/utils.js.map +0 -1
  70. package/webpack.config.js +0 -28
  71. /package/{lib → dist}/Entity.types.js.map +0 -0
  72. /package/{lib → dist}/PubSub.types.js.map +0 -0
package/src/Nymph.ts CHANGED
@@ -1,24 +1,28 @@
1
- import Entity from './Entity';
2
- import {
1
+ import Entity, { type EntityInstanceType } from './Entity.js';
2
+ import type {
3
3
  EntityConstructor,
4
- EntityData,
5
4
  EntityInterface,
6
5
  EntityJson,
7
6
  ServerCallResponse,
8
7
  ServerCallStaticResponse,
9
- } from './Entity.types';
10
- import EntityWeakCache from './EntityWeakCache';
11
- import HttpRequester from './HttpRequester';
12
- import {
8
+ } from './Entity.types.js';
9
+ import EntityWeakCache from './EntityWeakCache.js';
10
+ import type { AbortableAsyncIterator } from './HttpRequester.js';
11
+ import HttpRequester, { ClientError } from './HttpRequester.js';
12
+ import type {
13
13
  EventType,
14
14
  NymphOptions,
15
15
  Options,
16
16
  RequestCallback,
17
17
  ResponseCallback,
18
18
  Selector,
19
- } from './Nymph.types';
20
- import PubSub from './PubSub';
21
- import { entitiesToReferences, entityConstructorsToClassNames } from './utils';
19
+ } from './Nymph.types.js';
20
+ import type PubSub from './PubSub.js';
21
+ import {
22
+ classNamesToEntityConstructors,
23
+ entitiesToReferences,
24
+ entityConstructorsToClassNames,
25
+ } from './utils.js';
22
26
 
23
27
  let requester: HttpRequester;
24
28
 
@@ -42,19 +46,42 @@ export default class Nymph {
42
46
  private responseCallbacks: ResponseCallback[] = [];
43
47
  private restUrl: string = '';
44
48
  private weakCache = false;
49
+ /**
50
+ * Headers that will be sent with every request.
51
+ *
52
+ * These are used by Tilmeld for authentication.
53
+ */
54
+ public headers: { [k: string]: string } = {};
55
+ /**
56
+ * The entity cache.
57
+ */
45
58
  public cache = new EntityWeakCache();
59
+ /**
60
+ * Return `null` or empty array instead of error when entity/ies not found.
61
+ */
62
+ public returnNullOnNotFound = false;
46
63
 
47
64
  public constructor(NymphOptions: NymphOptions) {
48
65
  this.restUrl = NymphOptions.restUrl;
49
66
  // @ts-ignore TS doesn't know about WeakRef.
50
67
  this.weakCache = !!NymphOptions.weakCache && typeof WeakRef !== 'undefined';
68
+ if (
69
+ 'returnNullOnNotFound' in NymphOptions &&
70
+ NymphOptions.returnNullOnNotFound != null
71
+ ) {
72
+ this.returnNullOnNotFound = NymphOptions.returnNullOnNotFound;
73
+ }
51
74
 
52
75
  this.Entity = this.addEntityClass(Entity);
53
76
 
54
77
  requester = new HttpRequester(
55
- 'fetch' in NymphOptions ? NymphOptions.fetch : undefined
78
+ 'fetch' in NymphOptions ? NymphOptions.fetch : undefined,
56
79
  );
57
80
 
81
+ if ('renewTokens' in NymphOptions && !NymphOptions.renewTokens) {
82
+ this.headers['X-Tilmeld-Token-Renewal'] = 'off';
83
+ }
84
+
58
85
  requester.on('request', (_requester, url, options) => {
59
86
  for (let i = 0; i < this.requestCallbacks.length; i++) {
60
87
  this.requestCallbacks[i] && this.requestCallbacks[i](url, options);
@@ -75,8 +102,9 @@ export default class Nymph {
75
102
  * Nymph and return it. You can then use this class's constructor and methods,
76
103
  * which will use this instance of Nymph.
77
104
  *
78
- * Because this creates a subclass, don't use the class
79
- * returned from `getEntityClass` to check with `instanceof`.
105
+ * Because this creates a subclass, don't use the class returned from
106
+ * `getEntityClass` to check with `instanceof`. Instead, use the base class
107
+ * that you passed into this method.
80
108
  */
81
109
  public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
82
110
  const nymph = this;
@@ -91,18 +119,27 @@ export default class Nymph {
91
119
  return NymphEntity;
92
120
  }
93
121
 
94
- public getEntityClass(className: string) {
95
- if (className in this.entityClasses) {
96
- return this.entityClasses[className];
122
+ public getEntityClass<T extends EntityConstructor>(className: T): T;
123
+ public getEntityClass(className: string): EntityConstructor;
124
+ public getEntityClass<T extends EntityConstructor = EntityConstructor>(
125
+ className: T | string,
126
+ ): T | EntityConstructor {
127
+ let key: string | null = null;
128
+ if (typeof className === 'string') {
129
+ key = className;
130
+ } else {
131
+ key = className.class;
97
132
  }
98
- throw new ClassNotAvailableError(
99
- "Tried to get class that's not available: " + className
100
- );
133
+ if (key in this.entityClasses) {
134
+ return this.entityClasses[key];
135
+ }
136
+ throw new ClassNotAvailableError('Tried to use class: ' + key);
101
137
  }
102
138
 
103
139
  public async newUID(name: string) {
104
140
  const data = await requester.POST({
105
141
  url: this.restUrl,
142
+ headers: { ...this.headers },
106
143
  dataType: 'text',
107
144
  data: { action: 'uid', data: name },
108
145
  });
@@ -112,6 +149,7 @@ export default class Nymph {
112
149
  public async setUID(name: string, value: number) {
113
150
  return await requester.PUT({
114
151
  url: this.restUrl,
152
+ headers: { ...this.headers },
115
153
  dataType: 'json',
116
154
  data: { action: 'uid', data: { name, value } },
117
155
  });
@@ -120,6 +158,7 @@ export default class Nymph {
120
158
  public async getUID(name: string) {
121
159
  const data = await requester.GET({
122
160
  url: this.restUrl,
161
+ headers: { ...this.headers },
123
162
  dataType: 'text',
124
163
  data: { action: 'uid', data: name },
125
164
  });
@@ -129,6 +168,7 @@ export default class Nymph {
129
168
  public async deleteUID(name: string) {
130
169
  return await requester.DELETE({
131
170
  url: this.restUrl,
171
+ headers: { ...this.headers },
132
172
  dataType: 'text',
133
173
  data: { action: 'uid', data: name },
134
174
  });
@@ -152,7 +192,7 @@ export default class Nymph {
152
192
  ) {
153
193
  throw new InvalidRequestError(
154
194
  'Due to REST restriction, you can only create new entities or ' +
155
- 'update existing entities, not both at the same time.'
195
+ 'update existing entities, not both at the same time.',
156
196
  );
157
197
  }
158
198
  });
@@ -162,7 +202,7 @@ export default class Nymph {
162
202
  public async patchEntity(entity: EntityInterface) {
163
203
  if (entity.guid == null) {
164
204
  throw new InvalidRequestError(
165
- "You can't patch an entity that hasn't yet been saved."
205
+ "You can't patch an entity that hasn't yet been saved.",
166
206
  );
167
207
  }
168
208
 
@@ -179,7 +219,7 @@ export default class Nymph {
179
219
  if (cur.guid == null) {
180
220
  throw new InvalidRequestError(
181
221
  'Due to REST restriction, you can only create new entities or ' +
182
- 'update existing entities, not both at the same time.'
222
+ 'update existing entities, not both at the same time.',
183
223
  );
184
224
  }
185
225
  });
@@ -191,22 +231,23 @@ export default class Nymph {
191
231
  entity: T,
192
232
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
193
233
  data: { [k: string]: any },
194
- plural: false
234
+ plural: false,
195
235
  ): Promise<T>;
196
236
  private async requestWithMethod<T extends EntityInterface>(
197
237
  entity: T[],
198
238
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
199
239
  data: { [k: string]: any },
200
- plural: true
240
+ plural: true,
201
241
  ): Promise<T[]>;
202
242
  private async requestWithMethod<T extends EntityInterface>(
203
243
  entity: T | T[],
204
244
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
205
245
  data: { [k: string]: any },
206
- plural: boolean
246
+ plural: boolean,
207
247
  ): Promise<T | T[]> {
208
248
  const response = await requester[method]({
209
249
  url: this.restUrl,
250
+ headers: { ...this.headers },
210
251
  dataType: 'json',
211
252
  data: {
212
253
  action: plural ? 'entities' : 'entity',
@@ -216,12 +257,12 @@ export default class Nymph {
216
257
  if (plural && Array.isArray(entity) && entity.length === response.length) {
217
258
  return entity.map((e, i) =>
218
259
  response[i] &&
219
- typeof response[i].guid !== 'undefined' &&
260
+ response[i].guid != null &&
220
261
  (e.guid == null || e.guid === response[i].guid)
221
262
  ? e.$init(response[i])
222
- : e
263
+ : e,
223
264
  ) as T[];
224
- } else if (!Array.isArray(entity) && typeof response.guid !== 'undefined') {
265
+ } else if (!Array.isArray(entity) && response.guid != null) {
225
266
  return entity.$init(response) as T;
226
267
  }
227
268
  throw new Error('Server error');
@@ -238,29 +279,39 @@ export default class Nymph {
238
279
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
239
280
  options: Options<T>,
240
281
  ...selectors: Selector[]
241
- ): Promise<ReturnType<T['factorySync']> | null>;
282
+ ): Promise<EntityInstanceType<T> | null>;
242
283
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
243
284
  options: Options<T> & { return: 'count' },
244
- guid: string
285
+ guid: string,
245
286
  ): Promise<number>;
246
287
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
247
288
  options: Options<T> & { return: 'guid' },
248
- guid: string
289
+ guid: string,
249
290
  ): Promise<string | null>;
250
291
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
251
292
  options: Options<T>,
252
- guid: string
253
- ): Promise<ReturnType<T['factorySync']> | null>;
293
+ guid: string,
294
+ ): Promise<EntityInstanceType<T> | null>;
254
295
  public async getEntity<T extends EntityConstructor = EntityConstructor>(
255
296
  options: Options<T>,
256
297
  ...selectors: Selector[] | string[]
257
- ): Promise<ReturnType<T['factorySync']> | string | number | null> {
258
- // @ts-ignore: Implementation signatures of overloads are not externally visible.
259
- const data = (await this.getEntityData(options, ...selectors)) as
260
- | EntityJson<T>
261
- | string
262
- | number
263
- | null;
298
+ ): Promise<EntityInstanceType<T> | string | number | null> {
299
+ let data: any = null;
300
+ try {
301
+ // @ts-ignore: Implementation signatures of overloads are not externally visible.
302
+ data = (await this.getEntityData(options, ...selectors)) as
303
+ EntityJson<T> | string | number | null;
304
+ } catch (e: any) {
305
+ if (
306
+ this.returnNullOnNotFound &&
307
+ e instanceof ClientError &&
308
+ e.status === 404
309
+ ) {
310
+ data = null;
311
+ } else {
312
+ throw e;
313
+ }
314
+ }
264
315
 
265
316
  if (options.return && options.return === 'count') {
266
317
  return Number(data ?? 0) as number;
@@ -290,23 +341,23 @@ export default class Nymph {
290
341
  ): Promise<EntityJson<T> | null>;
291
342
  public async getEntityData<T extends EntityConstructor = EntityConstructor>(
292
343
  options: Options<T> & { return: 'count' },
293
- guid: string
344
+ guid: string,
294
345
  ): Promise<number>;
295
346
  public async getEntityData<T extends EntityConstructor = EntityConstructor>(
296
347
  options: Options<T> & { return: 'guid' },
297
- guid: string
348
+ guid: string,
298
349
  ): Promise<string | null>;
299
350
  public async getEntityData<T extends EntityConstructor = EntityConstructor>(
300
351
  options: Options<T>,
301
- guid: string
352
+ guid: string,
302
353
  ): Promise<EntityJson<T> | null>;
303
354
  public async getEntityData<T extends EntityConstructor = EntityConstructor>(
304
355
  options: Options<T>,
305
356
  ...selectors: Selector[] | string[]
306
357
  ): Promise<EntityJson<T> | string | number | null> {
307
- if (options.class === this.getEntityClass('Entity')) {
358
+ if (options.class instanceof Entity) {
308
359
  throw new InvalidRequestError(
309
- "You can't make REST requests with the base Entity class."
360
+ "You can't make REST requests with the base Entity class.",
310
361
  );
311
362
  }
312
363
  // Set up options and selectors.
@@ -315,12 +366,13 @@ export default class Nymph {
315
366
  }
316
367
  const data = await requester.GET({
317
368
  url: this.restUrl,
369
+ headers: { ...this.headers },
318
370
  dataType: 'json',
319
371
  data: {
320
372
  action: 'entity',
321
373
  data: [
322
- { ...options, class: options.class.class },
323
- ...entityConstructorsToClassNames(selectors),
374
+ entityConstructorsToClassNames(options),
375
+ ...entityConstructorsToClassNames(entitiesToReferences(selectors)),
324
376
  ],
325
377
  },
326
378
  });
@@ -342,25 +394,42 @@ export default class Nymph {
342
394
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
343
395
  options: Options<T>,
344
396
  ...selectors: Selector[]
345
- ): Promise<ReturnType<T['factorySync']>[]>;
397
+ ): Promise<EntityInstanceType<T>[]>;
346
398
  public async getEntities<T extends EntityConstructor = EntityConstructor>(
347
399
  options: Options<T>,
348
400
  ...selectors: Selector[]
349
- ): Promise<ReturnType<T['factorySync']>[] | string[] | number> {
350
- const data = await requester.GET({
351
- url: this.restUrl,
352
- dataType: 'json',
353
- data: {
354
- action: 'entities',
355
- data: [
356
- { ...options, class: options.class.class },
357
- ...entityConstructorsToClassNames(selectors),
358
- ],
359
- },
360
- });
401
+ ): Promise<EntityInstanceType<T>[] | string[] | number> {
402
+ let data = null;
403
+ try {
404
+ data = await requester.GET({
405
+ url: this.restUrl,
406
+ headers: { ...this.headers },
407
+ dataType: 'json',
408
+ data: {
409
+ action: 'entities',
410
+ data: [
411
+ entityConstructorsToClassNames(options),
412
+ ...entityConstructorsToClassNames(entitiesToReferences(selectors)),
413
+ ],
414
+ },
415
+ });
416
+ } catch (e: any) {
417
+ if (
418
+ this.returnNullOnNotFound &&
419
+ e instanceof ClientError &&
420
+ e.status === 404
421
+ ) {
422
+ data = null;
423
+ } else {
424
+ throw e;
425
+ }
426
+ }
361
427
 
362
428
  if (options.return && options.return === 'count') {
363
- return Number(data);
429
+ return Number(data ?? 0) as number;
430
+ }
431
+ if (data == null) {
432
+ return [];
364
433
  }
365
434
  if (options.return && options.return === 'guid') {
366
435
  return data;
@@ -369,12 +438,15 @@ export default class Nymph {
369
438
  }
370
439
 
371
440
  public initEntity<T extends EntityConstructor = EntityConstructor>(
372
- entityJSON: EntityJson<T>
373
- ): ReturnType<T['factorySync']> {
374
- const EntityClass = this.getEntityClass(entityJSON.class);
441
+ entityJSON: EntityJson<T>,
442
+ ): EntityInstanceType<T> {
443
+ const EntityClass = classNamesToEntityConstructors<T>(
444
+ this,
445
+ entityJSON.class as unknown as T,
446
+ );
375
447
  if (!EntityClass) {
376
448
  throw new ClassNotAvailableError(
377
- entityJSON.class + ' class cannot be found.'
449
+ entityJSON.class + ' class cannot be found.',
378
450
  );
379
451
  }
380
452
  let entity = EntityClass.factorySync();
@@ -382,30 +454,28 @@ export default class Nymph {
382
454
  // Try to get it from cache.
383
455
  const entityFromCache = this.cache.get(
384
456
  EntityClass,
385
- entityJSON.guid || ''
457
+ entityJSON.guid || '',
386
458
  );
387
459
  if (entityFromCache != null) {
388
- entity = entityFromCache;
460
+ entity = entityFromCache as EntityInstanceType<T>;
389
461
  }
390
462
  }
391
- return entity.$init(entityJSON) as ReturnType<T['factorySync']>;
463
+ return entity.$init(entityJSON) as EntityInstanceType<T>;
392
464
  }
393
465
 
394
466
  public getEntityFromCache<T extends EntityConstructor = EntityConstructor>(
395
467
  EntityClass: EntityConstructor,
396
- guid: string
397
- ): ReturnType<T['factorySync']> | null {
468
+ guid: string,
469
+ ): EntityInstanceType<T> | null {
398
470
  if (!this.weakCache) {
399
471
  return null;
400
472
  }
401
- return this.cache.get(EntityClass, guid) as ReturnType<
402
- T['factorySync']
403
- > | null;
473
+ return this.cache.get(EntityClass, guid) as EntityInstanceType<T> | null;
404
474
  }
405
475
 
406
476
  public setEntityToCache(
407
477
  EntityClass: EntityConstructor,
408
- entity: EntityInterface
478
+ entity: EntityInterface,
409
479
  ) {
410
480
  if (!this.weakCache) {
411
481
  return;
@@ -417,10 +487,7 @@ export default class Nymph {
417
487
  if (Array.isArray(item)) {
418
488
  // Recurse into lower arrays.
419
489
  return item.map((entry) => this.initEntitiesFromData(entry)) as T;
420
- } else if (
421
- item instanceof Object &&
422
- !(item instanceof this.getEntityClass('Entity'))
423
- ) {
490
+ } else if (item instanceof Object && !(item instanceof Entity)) {
424
491
  if (
425
492
  item.hasOwnProperty('class') &&
426
493
  item.hasOwnProperty('guid') &&
@@ -428,7 +495,10 @@ export default class Nymph {
428
495
  item.hasOwnProperty('mdate') &&
429
496
  item.hasOwnProperty('tags') &&
430
497
  item.hasOwnProperty('data') &&
431
- this.getEntityClass((item as any as EntityJson).class)
498
+ classNamesToEntityConstructors(
499
+ this,
500
+ (item as any as EntityJson).class,
501
+ ) != null
432
502
  ) {
433
503
  return this.initEntity(item as any as EntityJson) as T;
434
504
  } else {
@@ -444,10 +514,11 @@ export default class Nymph {
444
514
 
445
515
  public async deleteEntity(
446
516
  entity: EntityInterface | EntityInterface[],
447
- _plural = false
517
+ _plural = false,
448
518
  ) {
449
519
  return await requester.DELETE({
450
520
  url: this.restUrl,
521
+ headers: { ...this.headers },
451
522
  dataType: 'json',
452
523
  data: {
453
524
  action: _plural ? 'entities' : 'entity',
@@ -473,10 +544,11 @@ export default class Nymph {
473
544
  entity: EntityInterface,
474
545
  method: string,
475
546
  params: any[],
476
- stateless = false
547
+ stateless = false,
477
548
  ): Promise<ServerCallResponse> {
478
549
  const data = await requester.POST({
479
550
  url: this.restUrl,
551
+ headers: { ...this.headers },
480
552
  dataType: 'json',
481
553
  data: {
482
554
  action: 'method',
@@ -484,7 +556,7 @@ export default class Nymph {
484
556
  entity,
485
557
  stateless,
486
558
  method,
487
- params: entitiesToReferences(entityConstructorsToClassNames(params)),
559
+ params: entityConstructorsToClassNames(entitiesToReferences(params)),
488
560
  },
489
561
  },
490
562
  });
@@ -498,10 +570,11 @@ export default class Nymph {
498
570
  public async serverCallStatic(
499
571
  className: string,
500
572
  method: string,
501
- params: any[]
573
+ params: any[],
502
574
  ): Promise<ServerCallStaticResponse> {
503
575
  const data = await requester.POST({
504
576
  url: this.restUrl,
577
+ headers: { ...this.headers },
505
578
  dataType: 'json',
506
579
  data: {
507
580
  action: 'method',
@@ -509,7 +582,7 @@ export default class Nymph {
509
582
  class: className,
510
583
  static: true,
511
584
  method: method,
512
- params: entitiesToReferences(entityConstructorsToClassNames(params)),
585
+ params: entityConstructorsToClassNames(entitiesToReferences(params)),
513
586
  },
514
587
  },
515
588
  });
@@ -517,19 +590,57 @@ export default class Nymph {
517
590
  return this.initEntitiesFromData(data);
518
591
  }
519
592
 
593
+ public async serverCallStaticIterator(
594
+ className: string,
595
+ method: string,
596
+ params: any[],
597
+ ): Promise<AbortableAsyncIterator<ServerCallStaticResponse>> {
598
+ const iterable = await requester.POST_ITERATOR({
599
+ url: this.restUrl,
600
+ headers: { ...this.headers },
601
+ dataType: 'json',
602
+ data: {
603
+ action: 'method',
604
+ data: {
605
+ class: className,
606
+ static: true,
607
+ method: method,
608
+ iterator: true,
609
+ params: entityConstructorsToClassNames(entitiesToReferences(params)),
610
+ },
611
+ },
612
+ });
613
+
614
+ const that = this;
615
+ const iterator: AbortableAsyncIterator = {
616
+ abortController: iterable.abortController,
617
+ async *[Symbol.asyncIterator]() {
618
+ for await (let response of iterable) {
619
+ if (response instanceof Error) {
620
+ yield response;
621
+ } else {
622
+ yield that.initEntitiesFromData(response);
623
+ }
624
+ }
625
+ },
626
+ };
627
+
628
+ return iterator;
629
+ }
630
+
520
631
  public on<T extends EventType>(
521
632
  event: T,
522
633
  callback: T extends 'request'
523
634
  ? RequestCallback
524
635
  : T extends 'response'
525
- ? ResponseCallback
526
- : never
636
+ ? ResponseCallback
637
+ : never,
527
638
  ) {
528
639
  const prop = (event + 'Callbacks') as T extends 'request'
529
640
  ? 'requestCallbacks'
530
641
  : T extends 'request'
531
- ? 'responseCallbacks'
532
- : never;
642
+ ? 'responseCallbacks'
643
+ : never;
533
644
  if (!(prop in this)) {
534
645
  throw new Error('Invalid event type.');
535
646
  }
@@ -543,14 +654,14 @@ export default class Nymph {
543
654
  callback: T extends 'request'
544
655
  ? RequestCallback
545
656
  : T extends 'response'
546
- ? ResponseCallback
547
- : never
657
+ ? ResponseCallback
658
+ : never,
548
659
  ) {
549
660
  const prop = (event + 'Callbacks') as T extends 'request'
550
661
  ? 'requestCallbacks'
551
662
  : T extends 'request'
552
- ? 'responseCallbacks'
553
- : never;
663
+ ? 'responseCallbacks'
664
+ : never;
554
665
  if (!(prop in this)) {
555
666
  return false;
556
667
  }
@@ -562,10 +673,6 @@ export default class Nymph {
562
673
  }
563
674
  return true;
564
675
  }
565
-
566
- public setXsrfToken(token: string | null) {
567
- requester.setXsrfToken(token);
568
- }
569
676
  }
570
677
 
571
678
  export class ClassNotAvailableError extends Error {