@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.
- package/CHANGELOG.md +456 -0
- package/README.md +6 -6
- package/asyncitertest.js +53 -0
- package/dist/Entity.d.ts +156 -0
- package/{lib → dist}/Entity.js +202 -104
- package/dist/Entity.js.map +1 -0
- package/dist/Entity.types.d.ts +218 -0
- package/dist/Entity.types.js +2 -0
- package/{lib → dist}/EntityWeakCache.d.ts +1 -1
- package/{lib → dist}/EntityWeakCache.js +5 -9
- package/dist/EntityWeakCache.js.map +1 -0
- package/{lib → dist}/HttpRequester.d.ts +18 -4
- package/dist/HttpRequester.js +365 -0
- package/dist/HttpRequester.js.map +1 -0
- package/{lib → dist}/Nymph.d.ts +48 -11
- package/{lib → dist}/Nymph.js +167 -51
- package/dist/Nymph.js.map +1 -0
- package/{lib → dist}/Nymph.types.d.ts +82 -2
- package/dist/Nymph.types.js +2 -0
- package/{lib → dist}/PubSub.d.ts +16 -10
- package/{lib → dist}/PubSub.js +172 -108
- package/dist/PubSub.js.map +1 -0
- package/{lib → dist}/PubSub.types.d.ts +8 -3
- package/dist/PubSub.types.js +2 -0
- package/{lib → dist}/entityRefresh.d.ts +1 -1
- package/{lib → dist}/entityRefresh.js +21 -13
- package/dist/entityRefresh.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/{lib → dist}/utils.d.ts +1 -1
- package/{lib → dist}/utils.js +28 -21
- package/dist/utils.js.map +1 -0
- package/jest.config.js +11 -2
- package/package.json +23 -27
- package/src/Entity.ts +173 -107
- package/src/Entity.types.ts +29 -47
- package/src/EntityWeakCache.ts +8 -6
- package/src/HttpRequester.ts +268 -31
- package/src/Nymph.ts +191 -88
- package/src/Nymph.types.ts +51 -2
- package/src/PubSub.ts +214 -141
- package/src/PubSub.types.ts +10 -5
- package/src/entityRefresh.ts +6 -6
- package/src/index.ts +10 -10
- package/src/utils.ts +12 -5
- package/tsconfig.json +6 -4
- package/typedoc.json +4 -0
- package/dist/index.js.LICENSE.txt +0 -8
- package/lib/Entity.d.ts +0 -51
- package/lib/Entity.js.map +0 -1
- package/lib/Entity.types.d.ts +0 -65
- package/lib/Entity.types.js +0 -3
- package/lib/EntityWeakCache.js.map +0 -1
- package/lib/HttpRequester.js +0 -190
- package/lib/HttpRequester.js.map +0 -1
- package/lib/Nymph.js.map +0 -1
- package/lib/Nymph.types.js +0 -3
- package/lib/PubSub.js.map +0 -1
- package/lib/PubSub.types.js +0 -3
- package/lib/entityRefresh.js.map +0 -1
- package/lib/index.d.ts +0 -13
- package/lib/index.js +0 -34
- package/lib/index.js.map +0 -1
- package/lib/utils.js.map +0 -1
- package/webpack.config.js +0 -28
- /package/{lib → dist}/Entity.types.js.map +0 -0
- /package/{lib → dist}/Nymph.types.js.map +0 -0
- /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
|
|
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 {
|
|
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
|
-
*
|
|
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:
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
99
|
-
|
|
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<
|
|
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<
|
|
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<
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
|
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<
|
|
399
|
+
): Promise<EntityInstanceType<T>[]>;
|
|
346
400
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
347
401
|
options: Options<T>,
|
|
348
402
|
...selectors: Selector[]
|
|
349
|
-
): Promise<
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
):
|
|
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
|
|
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
|
-
):
|
|
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
|
|
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
|
-
|
|
526
|
-
|
|
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
|
-
|
|
532
|
-
|
|
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
|
-
|
|
547
|
-
|
|
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
|
-
|
|
553
|
-
|
|
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 {
|
package/src/Nymph.types.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|