@nymphjs/client 1.0.0-beta.11 → 1.0.0-beta.111

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