@nymphjs/client 1.0.0-beta.1 → 1.0.0-beta.100
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 +7 -7
- package/asyncitertest.js +53 -0
- package/dist/Entity.d.ts +156 -0
- package/dist/Entity.js +598 -0
- package/dist/Entity.js.map +1 -0
- package/dist/Entity.types.d.ts +218 -0
- package/dist/Entity.types.js +2 -0
- package/dist/Entity.types.js.map +1 -0
- package/dist/EntityWeakCache.d.ts +6 -0
- package/dist/EntityWeakCache.js +27 -0
- package/dist/EntityWeakCache.js.map +1 -0
- package/dist/HttpRequester.d.ts +78 -0
- package/dist/HttpRequester.js +365 -0
- package/dist/HttpRequester.js.map +1 -0
- package/dist/Nymph.d.ts +116 -0
- package/dist/Nymph.js +459 -0
- package/dist/Nymph.js.map +1 -0
- package/dist/Nymph.types.d.ts +177 -0
- package/dist/Nymph.types.js +2 -0
- package/dist/Nymph.types.js.map +1 -0
- package/dist/PubSub.d.ts +63 -0
- package/dist/PubSub.js +599 -0
- package/dist/PubSub.js.map +1 -0
- package/dist/PubSub.types.d.ts +31 -0
- package/dist/PubSub.types.js +2 -0
- package/dist/PubSub.types.js.map +1 -0
- package/dist/entityRefresh.d.ts +5 -0
- package/dist/entityRefresh.js +75 -0
- 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/dist/utils.d.ts +8 -0
- package/dist/utils.js +93 -0
- package/dist/utils.js.map +1 -0
- package/jest.config.js +11 -2
- package/lib/Entity.d.ts +112 -8
- package/lib/Entity.js +159 -77
- package/lib/Entity.js.map +1 -1
- package/lib/Entity.types.d.ts +144 -9
- package/lib/EntityWeakCache.js +3 -2
- package/lib/EntityWeakCache.js.map +1 -1
- package/lib/HttpRequester.d.ts +44 -8
- package/lib/HttpRequester.js +236 -21
- package/lib/HttpRequester.js.map +1 -1
- package/lib/Nymph.d.ts +43 -11
- package/lib/Nymph.js +102 -19
- package/lib/Nymph.js.map +1 -1
- package/lib/Nymph.types.d.ts +73 -1
- package/lib/PubSub.d.ts +15 -9
- package/lib/PubSub.js +148 -87
- package/lib/PubSub.js.map +1 -1
- package/lib/PubSub.types.d.ts +6 -1
- package/lib/entityRefresh.js +16 -0
- package/lib/entityRefresh.js.map +1 -1
- package/lib/utils.js +11 -0
- package/lib/utils.js.map +1 -1
- package/package.json +23 -27
- package/src/Entity.ts +171 -108
- package/src/Entity.types.ts +29 -47
- package/src/EntityWeakCache.ts +8 -6
- package/src/HttpRequester.ts +308 -35
- package/src/Nymph.ts +212 -96
- 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/webpack.config.js +0 -28
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
|
|
|
@@ -36,28 +39,48 @@ export default class Nymph {
|
|
|
36
39
|
/**
|
|
37
40
|
* The entity class for this instance of Nymph.
|
|
38
41
|
*/
|
|
39
|
-
public Entity: typeof Entity
|
|
42
|
+
public Entity: typeof Entity;
|
|
40
43
|
|
|
41
44
|
private requestCallbacks: RequestCallback[] = [];
|
|
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
|
-
|
|
53
|
-
NymphEntity.nymph = this;
|
|
54
|
-
this.Entity = NymphEntity;
|
|
55
|
-
this.addEntityClass(NymphEntity);
|
|
74
|
+
this.Entity = this.addEntityClass(Entity);
|
|
56
75
|
|
|
57
76
|
requester = new HttpRequester(
|
|
58
|
-
'fetch' in NymphOptions ? NymphOptions.fetch : undefined
|
|
77
|
+
'fetch' in NymphOptions ? NymphOptions.fetch : undefined,
|
|
59
78
|
);
|
|
60
79
|
|
|
80
|
+
if ('renewTokens' in NymphOptions && !NymphOptions.renewTokens) {
|
|
81
|
+
this.headers['X-Tilmeld-Token-Renewal'] = 'off';
|
|
82
|
+
}
|
|
83
|
+
|
|
61
84
|
requester.on('request', (_requester, url, options) => {
|
|
62
85
|
for (let i = 0; i < this.requestCallbacks.length; i++) {
|
|
63
86
|
this.requestCallbacks[i] && this.requestCallbacks[i](url, options);
|
|
@@ -71,25 +94,51 @@ export default class Nymph {
|
|
|
71
94
|
});
|
|
72
95
|
}
|
|
73
96
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Add your class to this instance.
|
|
99
|
+
*
|
|
100
|
+
* This will create a class that extends your class within this instance of
|
|
101
|
+
* Nymph and return it. You can then use this class's constructor and methods,
|
|
102
|
+
* which will use this instance of Nymph.
|
|
103
|
+
*
|
|
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.
|
|
107
|
+
*/
|
|
108
|
+
public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
|
|
109
|
+
const nymph = this;
|
|
110
|
+
class NymphEntity extends entityClass {
|
|
111
|
+
static nymph: Nymph = nymph;
|
|
112
|
+
|
|
113
|
+
constructor(...args: any[]) {
|
|
114
|
+
super(...args);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
this.entityClasses[entityClass.class] = NymphEntity;
|
|
118
|
+
return NymphEntity;
|
|
77
119
|
}
|
|
78
120
|
|
|
79
|
-
public getEntityClass(className:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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;
|
|
84
131
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
132
|
+
if (key in this.entityClasses) {
|
|
133
|
+
return this.entityClasses[key];
|
|
134
|
+
}
|
|
135
|
+
throw new ClassNotAvailableError('Tried to use class: ' + key);
|
|
88
136
|
}
|
|
89
137
|
|
|
90
138
|
public async newUID(name: string) {
|
|
91
139
|
const data = await requester.POST({
|
|
92
140
|
url: this.restUrl,
|
|
141
|
+
headers: { ...this.headers },
|
|
93
142
|
dataType: 'text',
|
|
94
143
|
data: { action: 'uid', data: name },
|
|
95
144
|
});
|
|
@@ -99,6 +148,7 @@ export default class Nymph {
|
|
|
99
148
|
public async setUID(name: string, value: number) {
|
|
100
149
|
return await requester.PUT({
|
|
101
150
|
url: this.restUrl,
|
|
151
|
+
headers: { ...this.headers },
|
|
102
152
|
dataType: 'json',
|
|
103
153
|
data: { action: 'uid', data: { name, value } },
|
|
104
154
|
});
|
|
@@ -107,6 +157,7 @@ export default class Nymph {
|
|
|
107
157
|
public async getUID(name: string) {
|
|
108
158
|
const data = await requester.GET({
|
|
109
159
|
url: this.restUrl,
|
|
160
|
+
headers: { ...this.headers },
|
|
110
161
|
dataType: 'text',
|
|
111
162
|
data: { action: 'uid', data: name },
|
|
112
163
|
});
|
|
@@ -116,6 +167,7 @@ export default class Nymph {
|
|
|
116
167
|
public async deleteUID(name: string) {
|
|
117
168
|
return await requester.DELETE({
|
|
118
169
|
url: this.restUrl,
|
|
170
|
+
headers: { ...this.headers },
|
|
119
171
|
dataType: 'text',
|
|
120
172
|
data: { action: 'uid', data: name },
|
|
121
173
|
});
|
|
@@ -139,7 +191,7 @@ export default class Nymph {
|
|
|
139
191
|
) {
|
|
140
192
|
throw new InvalidRequestError(
|
|
141
193
|
'Due to REST restriction, you can only create new entities or ' +
|
|
142
|
-
'update existing entities, not both at the same time.'
|
|
194
|
+
'update existing entities, not both at the same time.',
|
|
143
195
|
);
|
|
144
196
|
}
|
|
145
197
|
});
|
|
@@ -149,7 +201,7 @@ export default class Nymph {
|
|
|
149
201
|
public async patchEntity(entity: EntityInterface) {
|
|
150
202
|
if (entity.guid == null) {
|
|
151
203
|
throw new InvalidRequestError(
|
|
152
|
-
"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.",
|
|
153
205
|
);
|
|
154
206
|
}
|
|
155
207
|
|
|
@@ -166,7 +218,7 @@ export default class Nymph {
|
|
|
166
218
|
if (cur.guid == null) {
|
|
167
219
|
throw new InvalidRequestError(
|
|
168
220
|
'Due to REST restriction, you can only create new entities or ' +
|
|
169
|
-
'update existing entities, not both at the same time.'
|
|
221
|
+
'update existing entities, not both at the same time.',
|
|
170
222
|
);
|
|
171
223
|
}
|
|
172
224
|
});
|
|
@@ -178,22 +230,23 @@ export default class Nymph {
|
|
|
178
230
|
entity: T,
|
|
179
231
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
180
232
|
data: { [k: string]: any },
|
|
181
|
-
plural: false
|
|
233
|
+
plural: false,
|
|
182
234
|
): Promise<T>;
|
|
183
235
|
private async requestWithMethod<T extends EntityInterface>(
|
|
184
236
|
entity: T[],
|
|
185
237
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
186
238
|
data: { [k: string]: any },
|
|
187
|
-
plural: true
|
|
239
|
+
plural: true,
|
|
188
240
|
): Promise<T[]>;
|
|
189
241
|
private async requestWithMethod<T extends EntityInterface>(
|
|
190
242
|
entity: T | T[],
|
|
191
243
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
192
244
|
data: { [k: string]: any },
|
|
193
|
-
plural: boolean
|
|
245
|
+
plural: boolean,
|
|
194
246
|
): Promise<T | T[]> {
|
|
195
247
|
const response = await requester[method]({
|
|
196
248
|
url: this.restUrl,
|
|
249
|
+
headers: { ...this.headers },
|
|
197
250
|
dataType: 'json',
|
|
198
251
|
data: {
|
|
199
252
|
action: plural ? 'entities' : 'entity',
|
|
@@ -206,7 +259,7 @@ export default class Nymph {
|
|
|
206
259
|
typeof response[i].guid !== 'undefined' &&
|
|
207
260
|
(e.guid == null || e.guid === response[i].guid)
|
|
208
261
|
? e.$init(response[i])
|
|
209
|
-
: e
|
|
262
|
+
: e,
|
|
210
263
|
) as T[];
|
|
211
264
|
} else if (!Array.isArray(entity) && typeof response.guid !== 'undefined') {
|
|
212
265
|
return entity.$init(response) as T;
|
|
@@ -225,29 +278,42 @@ export default class Nymph {
|
|
|
225
278
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
226
279
|
options: Options<T>,
|
|
227
280
|
...selectors: Selector[]
|
|
228
|
-
): Promise<
|
|
281
|
+
): Promise<EntityInstanceType<T> | null>;
|
|
229
282
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
230
283
|
options: Options<T> & { return: 'count' },
|
|
231
|
-
guid: string
|
|
284
|
+
guid: string,
|
|
232
285
|
): Promise<number>;
|
|
233
286
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
234
287
|
options: Options<T> & { return: 'guid' },
|
|
235
|
-
guid: string
|
|
288
|
+
guid: string,
|
|
236
289
|
): Promise<string | null>;
|
|
237
290
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
238
291
|
options: Options<T>,
|
|
239
|
-
guid: string
|
|
240
|
-
): Promise<
|
|
292
|
+
guid: string,
|
|
293
|
+
): Promise<EntityInstanceType<T> | null>;
|
|
241
294
|
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
242
295
|
options: Options<T>,
|
|
243
296
|
...selectors: Selector[] | string[]
|
|
244
|
-
): Promise<
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
+
}
|
|
251
317
|
|
|
252
318
|
if (options.return && options.return === 'count') {
|
|
253
319
|
return Number(data ?? 0) as number;
|
|
@@ -277,23 +343,23 @@ export default class Nymph {
|
|
|
277
343
|
): Promise<EntityJson<T> | null>;
|
|
278
344
|
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
279
345
|
options: Options<T> & { return: 'count' },
|
|
280
|
-
guid: string
|
|
346
|
+
guid: string,
|
|
281
347
|
): Promise<number>;
|
|
282
348
|
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
283
349
|
options: Options<T> & { return: 'guid' },
|
|
284
|
-
guid: string
|
|
350
|
+
guid: string,
|
|
285
351
|
): Promise<string | null>;
|
|
286
352
|
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
287
353
|
options: Options<T>,
|
|
288
|
-
guid: string
|
|
354
|
+
guid: string,
|
|
289
355
|
): Promise<EntityJson<T> | null>;
|
|
290
356
|
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
291
357
|
options: Options<T>,
|
|
292
358
|
...selectors: Selector[] | string[]
|
|
293
359
|
): Promise<EntityJson<T> | string | number | null> {
|
|
294
|
-
if (options.class
|
|
360
|
+
if (options.class instanceof Entity) {
|
|
295
361
|
throw new InvalidRequestError(
|
|
296
|
-
"You can't make REST requests with the base Entity class."
|
|
362
|
+
"You can't make REST requests with the base Entity class.",
|
|
297
363
|
);
|
|
298
364
|
}
|
|
299
365
|
// Set up options and selectors.
|
|
@@ -302,6 +368,7 @@ export default class Nymph {
|
|
|
302
368
|
}
|
|
303
369
|
const data = await requester.GET({
|
|
304
370
|
url: this.restUrl,
|
|
371
|
+
headers: { ...this.headers },
|
|
305
372
|
dataType: 'json',
|
|
306
373
|
data: {
|
|
307
374
|
action: 'entity',
|
|
@@ -329,25 +396,42 @@ export default class Nymph {
|
|
|
329
396
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
330
397
|
options: Options<T>,
|
|
331
398
|
...selectors: Selector[]
|
|
332
|
-
): Promise<
|
|
399
|
+
): Promise<EntityInstanceType<T>[]>;
|
|
333
400
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
334
401
|
options: Options<T>,
|
|
335
402
|
...selectors: Selector[]
|
|
336
|
-
): Promise<
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
+
}
|
|
348
429
|
|
|
349
430
|
if (options.return && options.return === 'count') {
|
|
350
|
-
return Number(data);
|
|
431
|
+
return Number(data ?? 0) as number;
|
|
432
|
+
}
|
|
433
|
+
if (data == null) {
|
|
434
|
+
return [];
|
|
351
435
|
}
|
|
352
436
|
if (options.return && options.return === 'guid') {
|
|
353
437
|
return data;
|
|
@@ -356,12 +440,12 @@ export default class Nymph {
|
|
|
356
440
|
}
|
|
357
441
|
|
|
358
442
|
public initEntity<T extends EntityConstructor = EntityConstructor>(
|
|
359
|
-
entityJSON: EntityJson<T
|
|
360
|
-
):
|
|
443
|
+
entityJSON: EntityJson<T>,
|
|
444
|
+
): EntityInstanceType<T> {
|
|
361
445
|
const EntityClass = this.getEntityClass(entityJSON.class);
|
|
362
446
|
if (!EntityClass) {
|
|
363
447
|
throw new ClassNotAvailableError(
|
|
364
|
-
entityJSON.class + ' class cannot be found.'
|
|
448
|
+
entityJSON.class + ' class cannot be found.',
|
|
365
449
|
);
|
|
366
450
|
}
|
|
367
451
|
let entity = EntityClass.factorySync();
|
|
@@ -369,30 +453,28 @@ export default class Nymph {
|
|
|
369
453
|
// Try to get it from cache.
|
|
370
454
|
const entityFromCache = this.cache.get(
|
|
371
455
|
EntityClass,
|
|
372
|
-
entityJSON.guid || ''
|
|
456
|
+
entityJSON.guid || '',
|
|
373
457
|
);
|
|
374
458
|
if (entityFromCache != null) {
|
|
375
|
-
entity = entityFromCache
|
|
459
|
+
entity = entityFromCache as EntityInstanceType<T>;
|
|
376
460
|
}
|
|
377
461
|
}
|
|
378
|
-
return entity.$init(entityJSON) as
|
|
462
|
+
return entity.$init(entityJSON) as EntityInstanceType<T>;
|
|
379
463
|
}
|
|
380
464
|
|
|
381
465
|
public getEntityFromCache<T extends EntityConstructor = EntityConstructor>(
|
|
382
466
|
EntityClass: EntityConstructor,
|
|
383
|
-
guid: string
|
|
384
|
-
):
|
|
467
|
+
guid: string,
|
|
468
|
+
): EntityInstanceType<T> | null {
|
|
385
469
|
if (!this.weakCache) {
|
|
386
470
|
return null;
|
|
387
471
|
}
|
|
388
|
-
return this.cache.get(EntityClass, guid) as
|
|
389
|
-
T['factorySync']
|
|
390
|
-
> | null;
|
|
472
|
+
return this.cache.get(EntityClass, guid) as EntityInstanceType<T> | null;
|
|
391
473
|
}
|
|
392
474
|
|
|
393
475
|
public setEntityToCache(
|
|
394
476
|
EntityClass: EntityConstructor,
|
|
395
|
-
entity: EntityInterface
|
|
477
|
+
entity: EntityInterface,
|
|
396
478
|
) {
|
|
397
479
|
if (!this.weakCache) {
|
|
398
480
|
return;
|
|
@@ -404,10 +486,7 @@ export default class Nymph {
|
|
|
404
486
|
if (Array.isArray(item)) {
|
|
405
487
|
// Recurse into lower arrays.
|
|
406
488
|
return item.map((entry) => this.initEntitiesFromData(entry)) as T;
|
|
407
|
-
} else if (
|
|
408
|
-
item instanceof Object &&
|
|
409
|
-
!(item instanceof this.getEntityClass('Entity'))
|
|
410
|
-
) {
|
|
489
|
+
} else if (item instanceof Object && !(item instanceof Entity)) {
|
|
411
490
|
if (
|
|
412
491
|
item.hasOwnProperty('class') &&
|
|
413
492
|
item.hasOwnProperty('guid') &&
|
|
@@ -431,10 +510,11 @@ export default class Nymph {
|
|
|
431
510
|
|
|
432
511
|
public async deleteEntity(
|
|
433
512
|
entity: EntityInterface | EntityInterface[],
|
|
434
|
-
_plural = false
|
|
513
|
+
_plural = false,
|
|
435
514
|
) {
|
|
436
515
|
return await requester.DELETE({
|
|
437
516
|
url: this.restUrl,
|
|
517
|
+
headers: { ...this.headers },
|
|
438
518
|
dataType: 'json',
|
|
439
519
|
data: {
|
|
440
520
|
action: _plural ? 'entities' : 'entity',
|
|
@@ -460,10 +540,11 @@ export default class Nymph {
|
|
|
460
540
|
entity: EntityInterface,
|
|
461
541
|
method: string,
|
|
462
542
|
params: any[],
|
|
463
|
-
stateless = false
|
|
543
|
+
stateless = false,
|
|
464
544
|
): Promise<ServerCallResponse> {
|
|
465
545
|
const data = await requester.POST({
|
|
466
546
|
url: this.restUrl,
|
|
547
|
+
headers: { ...this.headers },
|
|
467
548
|
dataType: 'json',
|
|
468
549
|
data: {
|
|
469
550
|
action: 'method',
|
|
@@ -485,10 +566,11 @@ export default class Nymph {
|
|
|
485
566
|
public async serverCallStatic(
|
|
486
567
|
className: string,
|
|
487
568
|
method: string,
|
|
488
|
-
params: any[]
|
|
569
|
+
params: any[],
|
|
489
570
|
): Promise<ServerCallStaticResponse> {
|
|
490
571
|
const data = await requester.POST({
|
|
491
572
|
url: this.restUrl,
|
|
573
|
+
headers: { ...this.headers },
|
|
492
574
|
dataType: 'json',
|
|
493
575
|
data: {
|
|
494
576
|
action: 'method',
|
|
@@ -504,19 +586,57 @@ export default class Nymph {
|
|
|
504
586
|
return this.initEntitiesFromData(data);
|
|
505
587
|
}
|
|
506
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
|
+
|
|
507
627
|
public on<T extends EventType>(
|
|
508
628
|
event: T,
|
|
509
629
|
callback: T extends 'request'
|
|
510
630
|
? RequestCallback
|
|
511
631
|
: T extends 'response'
|
|
512
|
-
|
|
513
|
-
|
|
632
|
+
? ResponseCallback
|
|
633
|
+
: never,
|
|
514
634
|
) {
|
|
515
635
|
const prop = (event + 'Callbacks') as T extends 'request'
|
|
516
636
|
? 'requestCallbacks'
|
|
517
637
|
: T extends 'request'
|
|
518
|
-
|
|
519
|
-
|
|
638
|
+
? 'responseCallbacks'
|
|
639
|
+
: never;
|
|
520
640
|
if (!(prop in this)) {
|
|
521
641
|
throw new Error('Invalid event type.');
|
|
522
642
|
}
|
|
@@ -530,14 +650,14 @@ export default class Nymph {
|
|
|
530
650
|
callback: T extends 'request'
|
|
531
651
|
? RequestCallback
|
|
532
652
|
: T extends 'response'
|
|
533
|
-
|
|
534
|
-
|
|
653
|
+
? ResponseCallback
|
|
654
|
+
: never,
|
|
535
655
|
) {
|
|
536
656
|
const prop = (event + 'Callbacks') as T extends 'request'
|
|
537
657
|
? 'requestCallbacks'
|
|
538
658
|
: T extends 'request'
|
|
539
|
-
|
|
540
|
-
|
|
659
|
+
? 'responseCallbacks'
|
|
660
|
+
: never;
|
|
541
661
|
if (!(prop in this)) {
|
|
542
662
|
return false;
|
|
543
663
|
}
|
|
@@ -549,10 +669,6 @@ export default class Nymph {
|
|
|
549
669
|
}
|
|
550
670
|
return true;
|
|
551
671
|
}
|
|
552
|
-
|
|
553
|
-
public setXsrfToken(token: string | null) {
|
|
554
|
-
requester.setXsrfToken(token);
|
|
555
|
-
}
|
|
556
672
|
}
|
|
557
673
|
|
|
558
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", or the name of a
|
|
90
|
+
* property.
|
|
91
|
+
*/
|
|
92
|
+
sort?: 'cdate' | 'mdate' | string;
|
|
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
|
|