@nymphjs/client 1.0.0-alpha.2 → 1.0.0-alpha.23
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 +102 -0
- package/README.md +13 -32
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/lib/Entity.d.ts +6 -3
- package/lib/Entity.js +71 -18
- package/lib/Entity.js.map +1 -1
- package/lib/Entity.types.d.ts +3 -0
- package/lib/EntityWeakCache.d.ts +6 -0
- package/lib/EntityWeakCache.js +31 -0
- package/lib/EntityWeakCache.js.map +1 -0
- package/lib/Nymph.d.ts +44 -35
- package/lib/Nymph.js +69 -46
- package/lib/Nymph.js.map +1 -1
- package/lib/Nymph.types.d.ts +1 -0
- package/lib/PubSub.d.ts +40 -39
- package/lib/PubSub.js +54 -87
- package/lib/PubSub.js.map +1 -1
- package/lib/index.d.ts +0 -3
- package/lib/index.js +1 -4
- package/lib/index.js.map +1 -1
- package/lib/utils.d.ts +2 -1
- package/lib/utils.js +10 -13
- package/lib/utils.js.map +1 -1
- package/package.json +10 -10
- package/src/Entity.ts +120 -22
- package/src/Entity.types.ts +10 -0
- package/src/EntityWeakCache.ts +32 -0
- package/src/Nymph.ts +118 -98
- package/src/Nymph.types.ts +19 -0
- package/src/PubSub.ts +59 -102
- package/src/index.ts +0 -4
- package/src/utils.ts +7 -12
- package/lib/EntitySorter.d.ts +0 -16
- package/lib/EntitySorter.js +0 -134
- package/lib/EntitySorter.js.map +0 -1
- package/src/EntitySorter.ts +0 -186
package/src/Nymph.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import Entity from './Entity';
|
|
1
2
|
import {
|
|
2
3
|
EntityConstructor,
|
|
4
|
+
EntityData,
|
|
3
5
|
EntityInterface,
|
|
4
6
|
EntityJson,
|
|
5
7
|
ServerCallResponse,
|
|
6
8
|
ServerCallStaticResponse,
|
|
7
9
|
} from './Entity.types';
|
|
10
|
+
import EntityWeakCache from './EntityWeakCache';
|
|
8
11
|
import HttpRequester from './HttpRequester';
|
|
9
12
|
import {
|
|
10
13
|
EventType,
|
|
@@ -14,34 +17,42 @@ import {
|
|
|
14
17
|
ResponseCallback,
|
|
15
18
|
Selector,
|
|
16
19
|
} from './Nymph.types';
|
|
20
|
+
import PubSub from './PubSub';
|
|
17
21
|
import { entitiesToReferences, entityConstructorsToClassNames } from './utils';
|
|
18
22
|
|
|
19
23
|
let requester: HttpRequester;
|
|
20
24
|
|
|
21
25
|
export default class Nymph {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
public
|
|
26
|
+
/**
|
|
27
|
+
* And optional PubSub client instance.
|
|
28
|
+
*/
|
|
29
|
+
public pubsub: PubSub | undefined = undefined;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A simple map of names to Entity classes.
|
|
33
|
+
*/
|
|
34
|
+
private entityClasses: { [k: string]: EntityConstructor } = {};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The entity class for this instance of Nymph.
|
|
38
|
+
*/
|
|
39
|
+
public Entity: typeof Entity = Entity;
|
|
40
|
+
|
|
41
|
+
private requestCallbacks: RequestCallback[] = [];
|
|
42
|
+
private responseCallbacks: ResponseCallback[] = [];
|
|
43
|
+
private restUrl: string = '';
|
|
44
|
+
private weakCache = false;
|
|
45
|
+
public cache = new EntityWeakCache();
|
|
46
|
+
|
|
47
|
+
public constructor(NymphOptions: NymphOptions) {
|
|
44
48
|
this.restUrl = NymphOptions.restUrl;
|
|
49
|
+
// @ts-ignore TS doesn't know about WeakRef.
|
|
50
|
+
this.weakCache = !!NymphOptions.weakCache && typeof WeakRef !== 'undefined';
|
|
51
|
+
|
|
52
|
+
class NymphEntity<T extends EntityData = EntityData> extends Entity<T> {}
|
|
53
|
+
NymphEntity.nymph = this;
|
|
54
|
+
this.Entity = NymphEntity;
|
|
55
|
+
this.addEntityClass(NymphEntity);
|
|
45
56
|
|
|
46
57
|
requester = new HttpRequester(
|
|
47
58
|
'fetch' in NymphOptions ? NymphOptions.fetch : undefined
|
|
@@ -60,7 +71,23 @@ export default class Nymph {
|
|
|
60
71
|
});
|
|
61
72
|
}
|
|
62
73
|
|
|
63
|
-
public
|
|
74
|
+
public addEntityClass(entityClass: EntityConstructor) {
|
|
75
|
+
this.entityClasses[entityClass.class] = entityClass;
|
|
76
|
+
entityClass.nymph = this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public getEntityClass(className: string) {
|
|
80
|
+
if (this.entityClasses.hasOwnProperty(className)) {
|
|
81
|
+
const EntityClass = this.entityClasses[className];
|
|
82
|
+
EntityClass.nymph = this;
|
|
83
|
+
return EntityClass;
|
|
84
|
+
}
|
|
85
|
+
throw new ClassNotAvailableError(
|
|
86
|
+
"Tried to get class that's not available: " + className
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public async newUID(name: string) {
|
|
64
91
|
const data = await requester.POST({
|
|
65
92
|
url: this.restUrl,
|
|
66
93
|
dataType: 'text',
|
|
@@ -69,7 +96,7 @@ export default class Nymph {
|
|
|
69
96
|
return Number(data);
|
|
70
97
|
}
|
|
71
98
|
|
|
72
|
-
public
|
|
99
|
+
public async setUID(name: string, value: number) {
|
|
73
100
|
return await requester.PUT({
|
|
74
101
|
url: this.restUrl,
|
|
75
102
|
dataType: 'json',
|
|
@@ -77,7 +104,7 @@ export default class Nymph {
|
|
|
77
104
|
});
|
|
78
105
|
}
|
|
79
106
|
|
|
80
|
-
public
|
|
107
|
+
public async getUID(name: string) {
|
|
81
108
|
const data = await requester.GET({
|
|
82
109
|
url: this.restUrl,
|
|
83
110
|
dataType: 'text',
|
|
@@ -86,7 +113,7 @@ export default class Nymph {
|
|
|
86
113
|
return Number(data);
|
|
87
114
|
}
|
|
88
115
|
|
|
89
|
-
public
|
|
116
|
+
public async deleteUID(name: string) {
|
|
90
117
|
return await requester.DELETE({
|
|
91
118
|
url: this.restUrl,
|
|
92
119
|
dataType: 'text',
|
|
@@ -94,12 +121,12 @@ export default class Nymph {
|
|
|
94
121
|
});
|
|
95
122
|
}
|
|
96
123
|
|
|
97
|
-
public
|
|
124
|
+
public async saveEntity(entity: EntityInterface) {
|
|
98
125
|
let method: 'POST' | 'PUT' = entity.guid == null ? 'POST' : 'PUT';
|
|
99
126
|
return await this.requestWithMethod(entity, method, entity, false);
|
|
100
127
|
}
|
|
101
128
|
|
|
102
|
-
public
|
|
129
|
+
public async saveEntities(entities: EntityInterface[]) {
|
|
103
130
|
if (!entities.length) {
|
|
104
131
|
return Promise.resolve(false);
|
|
105
132
|
}
|
|
@@ -119,7 +146,7 @@ export default class Nymph {
|
|
|
119
146
|
return await this.requestWithMethod(entities, method, entities, true);
|
|
120
147
|
}
|
|
121
148
|
|
|
122
|
-
public
|
|
149
|
+
public async patchEntity(entity: EntityInterface) {
|
|
123
150
|
if (entity.guid == null) {
|
|
124
151
|
throw new InvalidRequestError(
|
|
125
152
|
"You can't patch an entity that hasn't yet been saved."
|
|
@@ -130,7 +157,7 @@ export default class Nymph {
|
|
|
130
157
|
return await this.requestWithMethod(entity, 'PATCH', patch, false);
|
|
131
158
|
}
|
|
132
159
|
|
|
133
|
-
public
|
|
160
|
+
public async patchEntities(entities: EntityInterface[]) {
|
|
134
161
|
if (!entities.length) {
|
|
135
162
|
return Promise.resolve(false);
|
|
136
163
|
}
|
|
@@ -147,19 +174,19 @@ export default class Nymph {
|
|
|
147
174
|
return await this.requestWithMethod(entities, 'PATCH', patch, true);
|
|
148
175
|
}
|
|
149
176
|
|
|
150
|
-
private
|
|
177
|
+
private async requestWithMethod<T extends EntityInterface>(
|
|
151
178
|
entity: T,
|
|
152
179
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
153
180
|
data: { [k: string]: any },
|
|
154
181
|
plural: false
|
|
155
182
|
): Promise<T>;
|
|
156
|
-
private
|
|
183
|
+
private async requestWithMethod<T extends EntityInterface>(
|
|
157
184
|
entity: T[],
|
|
158
185
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
159
186
|
data: { [k: string]: any },
|
|
160
187
|
plural: true
|
|
161
188
|
): Promise<T[]>;
|
|
162
|
-
private
|
|
189
|
+
private async requestWithMethod<T extends EntityInterface>(
|
|
163
190
|
entity: T | T[],
|
|
164
191
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
165
192
|
data: { [k: string]: any },
|
|
@@ -187,33 +214,23 @@ export default class Nymph {
|
|
|
187
214
|
throw new Error('Server error');
|
|
188
215
|
}
|
|
189
216
|
|
|
190
|
-
public
|
|
191
|
-
T extends EntityConstructor = EntityConstructor
|
|
192
|
-
>(
|
|
217
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
193
218
|
options: Options<T> & { return: 'guid' },
|
|
194
219
|
...selectors: Selector[]
|
|
195
220
|
): Promise<string | null>;
|
|
196
|
-
public
|
|
197
|
-
T extends EntityConstructor = EntityConstructor
|
|
198
|
-
>(
|
|
221
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
199
222
|
options: Options<T>,
|
|
200
223
|
...selectors: Selector[]
|
|
201
224
|
): Promise<ReturnType<T['factorySync']> | null>;
|
|
202
|
-
public
|
|
203
|
-
T extends EntityConstructor = EntityConstructor
|
|
204
|
-
>(
|
|
225
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
205
226
|
options: Options<T> & { return: 'guid' },
|
|
206
227
|
guid: string
|
|
207
228
|
): Promise<string | null>;
|
|
208
|
-
public
|
|
209
|
-
T extends EntityConstructor = EntityConstructor
|
|
210
|
-
>(
|
|
229
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
211
230
|
options: Options<T>,
|
|
212
231
|
guid: string
|
|
213
232
|
): Promise<ReturnType<T['factorySync']> | null>;
|
|
214
|
-
public
|
|
215
|
-
T extends EntityConstructor = EntityConstructor
|
|
216
|
-
>(
|
|
233
|
+
public async getEntity<T extends EntityConstructor = EntityConstructor>(
|
|
217
234
|
options: Options<T>,
|
|
218
235
|
...selectors: Selector[] | string[]
|
|
219
236
|
): Promise<ReturnType<T['factorySync']> | string | null> {
|
|
@@ -233,30 +250,23 @@ export default class Nymph {
|
|
|
233
250
|
return null;
|
|
234
251
|
}
|
|
235
252
|
|
|
236
|
-
public
|
|
237
|
-
T extends EntityConstructor = EntityConstructor
|
|
238
|
-
>(
|
|
253
|
+
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
239
254
|
options: Options<T> & { return: 'guid' },
|
|
240
255
|
...selectors: Selector[]
|
|
241
256
|
): Promise<string | null>;
|
|
242
|
-
public
|
|
243
|
-
T extends EntityConstructor = EntityConstructor
|
|
244
|
-
>(
|
|
257
|
+
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
245
258
|
options: Options<T>,
|
|
246
259
|
...selectors: Selector[]
|
|
247
260
|
): Promise<EntityJson<T> | null>;
|
|
248
|
-
public
|
|
249
|
-
T extends EntityConstructor = EntityConstructor
|
|
250
|
-
>(
|
|
261
|
+
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
251
262
|
options: Options<T> & { return: 'guid' },
|
|
252
263
|
guid: string
|
|
253
264
|
): Promise<string | null>;
|
|
254
|
-
public
|
|
255
|
-
T
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
>(
|
|
265
|
+
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
266
|
+
options: Options<T>,
|
|
267
|
+
guid: string
|
|
268
|
+
): Promise<EntityJson<T> | null>;
|
|
269
|
+
public async getEntityData<T extends EntityConstructor = EntityConstructor>(
|
|
260
270
|
options: Options<T>,
|
|
261
271
|
...selectors: Selector[] | string[]
|
|
262
272
|
): Promise<EntityJson<T> | string | null> {
|
|
@@ -287,21 +297,15 @@ export default class Nymph {
|
|
|
287
297
|
return null;
|
|
288
298
|
}
|
|
289
299
|
|
|
290
|
-
public
|
|
291
|
-
T extends EntityConstructor = EntityConstructor
|
|
292
|
-
>(
|
|
300
|
+
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
293
301
|
options: Options<T> & { return: 'guid' },
|
|
294
302
|
...selectors: Selector[]
|
|
295
303
|
): Promise<string[]>;
|
|
296
|
-
public
|
|
297
|
-
T extends EntityConstructor = EntityConstructor
|
|
298
|
-
>(
|
|
304
|
+
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
299
305
|
options: Options<T>,
|
|
300
306
|
...selectors: Selector[]
|
|
301
307
|
): Promise<ReturnType<T['factorySync']>[]>;
|
|
302
|
-
public
|
|
303
|
-
T extends EntityConstructor = EntityConstructor
|
|
304
|
-
>(
|
|
308
|
+
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
305
309
|
options: Options<T>,
|
|
306
310
|
...selectors: Selector[]
|
|
307
311
|
): Promise<ReturnType<T['factorySync']>[] | string[]> {
|
|
@@ -323,7 +327,7 @@ export default class Nymph {
|
|
|
323
327
|
return data.map((e: EntityJson<T>) => this.initEntity(e));
|
|
324
328
|
}
|
|
325
329
|
|
|
326
|
-
public
|
|
330
|
+
public initEntity<T extends EntityConstructor = EntityConstructor>(
|
|
327
331
|
entityJSON: EntityJson<T>
|
|
328
332
|
): ReturnType<T['factorySync']> {
|
|
329
333
|
const EntityClass = this.getEntityClass(entityJSON.class);
|
|
@@ -332,11 +336,43 @@ export default class Nymph {
|
|
|
332
336
|
entityJSON.class + ' class cannot be found.'
|
|
333
337
|
);
|
|
334
338
|
}
|
|
335
|
-
|
|
339
|
+
let entity = EntityClass.factorySync();
|
|
340
|
+
if (this.weakCache) {
|
|
341
|
+
// Try to get it from cache.
|
|
342
|
+
const entityFromCache = this.cache.get(
|
|
343
|
+
EntityClass,
|
|
344
|
+
entityJSON.guid || ''
|
|
345
|
+
);
|
|
346
|
+
if (entityFromCache != null) {
|
|
347
|
+
entity = entityFromCache;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
336
350
|
return entity.$init(entityJSON) as ReturnType<T['factorySync']>;
|
|
337
351
|
}
|
|
338
352
|
|
|
339
|
-
public
|
|
353
|
+
public getEntityFromCache<T extends EntityConstructor = EntityConstructor>(
|
|
354
|
+
EntityClass: EntityConstructor,
|
|
355
|
+
guid: string
|
|
356
|
+
): ReturnType<T['factorySync']> | null {
|
|
357
|
+
if (!this.weakCache) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
return this.cache.get(EntityClass, guid) as ReturnType<
|
|
361
|
+
T['factorySync']
|
|
362
|
+
> | null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
public setEntityToCache(
|
|
366
|
+
EntityClass: EntityConstructor,
|
|
367
|
+
entity: EntityInterface
|
|
368
|
+
) {
|
|
369
|
+
if (!this.weakCache) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
return this.cache.set(EntityClass, entity);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
public initEntitiesFromData<T extends any>(item: T): T {
|
|
340
376
|
if (Array.isArray(item)) {
|
|
341
377
|
// Recurse into lower arrays.
|
|
342
378
|
return item.map((entry) => this.initEntitiesFromData(entry)) as T;
|
|
@@ -365,7 +401,7 @@ export default class Nymph {
|
|
|
365
401
|
return item;
|
|
366
402
|
}
|
|
367
403
|
|
|
368
|
-
public
|
|
404
|
+
public async deleteEntity(
|
|
369
405
|
entity: EntityInterface | EntityInterface[],
|
|
370
406
|
_plural = false
|
|
371
407
|
) {
|
|
@@ -388,11 +424,11 @@ export default class Nymph {
|
|
|
388
424
|
});
|
|
389
425
|
}
|
|
390
426
|
|
|
391
|
-
public
|
|
427
|
+
public async deleteEntities(entities: EntityInterface[]) {
|
|
392
428
|
return await this.deleteEntity(entities, true);
|
|
393
429
|
}
|
|
394
430
|
|
|
395
|
-
public
|
|
431
|
+
public async serverCall(
|
|
396
432
|
entity: EntityInterface,
|
|
397
433
|
method: string,
|
|
398
434
|
params: any[],
|
|
@@ -418,7 +454,7 @@ export default class Nymph {
|
|
|
418
454
|
};
|
|
419
455
|
}
|
|
420
456
|
|
|
421
|
-
public
|
|
457
|
+
public async serverCallStatic(
|
|
422
458
|
className: string,
|
|
423
459
|
method: string,
|
|
424
460
|
params: any[]
|
|
@@ -440,7 +476,7 @@ export default class Nymph {
|
|
|
440
476
|
return this.initEntitiesFromData(data);
|
|
441
477
|
}
|
|
442
478
|
|
|
443
|
-
public
|
|
479
|
+
public on<T extends EventType>(
|
|
444
480
|
event: T,
|
|
445
481
|
callback: T extends 'request'
|
|
446
482
|
? RequestCallback
|
|
@@ -461,7 +497,7 @@ export default class Nymph {
|
|
|
461
497
|
return () => this.off(event, callback);
|
|
462
498
|
}
|
|
463
499
|
|
|
464
|
-
public
|
|
500
|
+
public off<T extends EventType>(
|
|
465
501
|
event: T,
|
|
466
502
|
callback: T extends 'request'
|
|
467
503
|
? RequestCallback
|
|
@@ -486,7 +522,7 @@ export default class Nymph {
|
|
|
486
522
|
return true;
|
|
487
523
|
}
|
|
488
524
|
|
|
489
|
-
public
|
|
525
|
+
public setXsrfToken(token: string | null) {
|
|
490
526
|
requester.setXsrfToken(token);
|
|
491
527
|
}
|
|
492
528
|
}
|
|
@@ -504,19 +540,3 @@ export class InvalidRequestError extends Error {
|
|
|
504
540
|
this.name = 'InvalidRequestError';
|
|
505
541
|
}
|
|
506
542
|
}
|
|
507
|
-
|
|
508
|
-
((global) => {
|
|
509
|
-
if (
|
|
510
|
-
typeof global !== 'undefined' &&
|
|
511
|
-
typeof (global as any as { NymphOptions: NymphOptions }).NymphOptions !==
|
|
512
|
-
'undefined'
|
|
513
|
-
) {
|
|
514
|
-
Nymph.init((global as any as { NymphOptions: NymphOptions }).NymphOptions);
|
|
515
|
-
}
|
|
516
|
-
})(
|
|
517
|
-
typeof window === 'undefined'
|
|
518
|
-
? typeof self === 'undefined'
|
|
519
|
-
? undefined
|
|
520
|
-
: self
|
|
521
|
-
: window
|
|
522
|
-
);
|
package/src/Nymph.types.ts
CHANGED
|
@@ -21,6 +21,25 @@ export type NymphOptions = {
|
|
|
21
21
|
* Whether to not output status messages to the console.
|
|
22
22
|
*/
|
|
23
23
|
noConsole?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Use a WeakRef based cache of entities.
|
|
26
|
+
*
|
|
27
|
+
* This ensures all entities returned are the same instance if they have the
|
|
28
|
+
* same class and GUID. This also means that whenever an entity is returned
|
|
29
|
+
* from the server, the single instance in memory will be refreshed. This
|
|
30
|
+
* could have annoying results, like destroying dirty data (the dreaded
|
|
31
|
+
* triple-D).
|
|
32
|
+
*
|
|
33
|
+
* This could also be a potential source of memory leaks. Although the
|
|
34
|
+
* entities themselves are referenced weakly so they get garbage collected,
|
|
35
|
+
* the GUID used as a key and the WeakRef object itself are not weak
|
|
36
|
+
* references, so not destroyed when the instance is garbage collected.
|
|
37
|
+
*
|
|
38
|
+
* However, even with these caveats, this might help you if you have a big app
|
|
39
|
+
* with the same entities stored in several different places in memory. This
|
|
40
|
+
* can help to synchronize them correctly and avoid data conflicts.
|
|
41
|
+
*/
|
|
42
|
+
weakCache?: boolean;
|
|
24
43
|
};
|
|
25
44
|
|
|
26
45
|
export type EventType = 'request' | 'response';
|