@nymphjs/client 1.0.0-beta.132 → 1.0.0-beta.134

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/src/Entity.ts CHANGED
@@ -24,9 +24,7 @@ export type EntityDataType<T> =
24
24
  export type EntityInstanceType<T extends EntityConstructor> =
25
25
  T extends new () => infer E ? E & EntityDataType<E> : never;
26
26
 
27
- export default class Entity<
28
- T extends EntityData = EntityData,
29
- > implements EntityInterface {
27
+ export default class Entity<T extends {} = {}> implements EntityInterface {
30
28
  /**
31
29
  * The instance of Nymph to use for queries.
32
30
  */
@@ -174,7 +172,7 @@ export default class Entity<
174
172
  protected $proxy() {
175
173
  if (this.$existingProxy == null) {
176
174
  this.$existingProxy = new Proxy(this, {
177
- has: (entity: this, name: string) => {
175
+ has: (entity: Record<string, any>, name: string) => {
178
176
  if (
179
177
  typeof name !== 'string' ||
180
178
  name in entity ||
@@ -187,7 +185,7 @@ export default class Entity<
187
185
  return name in entity.$data;
188
186
  },
189
187
 
190
- get: (entity: this, name: string) => {
188
+ get: (entity: Record<string, any>, name: string) => {
191
189
  if (
192
190
  typeof name !== 'string' ||
193
191
  name in entity ||
@@ -206,7 +204,7 @@ export default class Entity<
206
204
  return undefined;
207
205
  },
208
206
 
209
- set: (entity: this, name: string, value: any) => {
207
+ set: (entity: Record<string, any>, name: string, value: any) => {
210
208
  if (
211
209
  typeof name !== 'string' ||
212
210
  name in entity ||
@@ -223,7 +221,7 @@ export default class Entity<
223
221
  return true;
224
222
  },
225
223
 
226
- deleteProperty: (entity: this, name: string) => {
224
+ deleteProperty: (entity: Record<string, any>, name: string) => {
227
225
  if (name in entity) {
228
226
  return delete (entity as any)[name];
229
227
  } else if (name in entity.$data) {
@@ -233,12 +231,12 @@ export default class Entity<
233
231
  return true;
234
232
  },
235
233
 
236
- getPrototypeOf: (entity: this) => {
234
+ getPrototypeOf: (entity: Record<string, any>) => {
237
235
  return entity.constructor.prototype;
238
236
  },
239
237
 
240
238
  defineProperty: (
241
- entity: this,
239
+ entity: Record<string, any>,
242
240
  name: string,
243
241
  descriptor: PropertyDescriptor,
244
242
  ) => {
@@ -258,7 +256,10 @@ export default class Entity<
258
256
  return true;
259
257
  },
260
258
 
261
- getOwnPropertyDescriptor: (entity: this, name: string) => {
259
+ getOwnPropertyDescriptor: (
260
+ entity: Record<string, any>,
261
+ name: string,
262
+ ) => {
262
263
  if (
263
264
  typeof name !== 'string' ||
264
265
  name in entity ||
@@ -274,7 +275,7 @@ export default class Entity<
274
275
  }
275
276
  },
276
277
 
277
- ownKeys: (entity: this) => {
278
+ ownKeys: (entity: Record<string, any>) => {
278
279
  this.$check();
279
280
  return Object.getOwnPropertyNames(entity).concat(
280
281
  Object.getOwnPropertyNames(entity.$data),
@@ -297,7 +298,7 @@ export default class Entity<
297
298
  new (): E;
298
299
  },
299
300
  guid?: string,
300
- ): Promise<E & EntityDataType<E>> {
301
+ ): Promise<E> {
301
302
  const cacheEntity = (
302
303
  guid
303
304
  ? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
@@ -307,7 +308,7 @@ export default class Entity<
307
308
  : null
308
309
  ) as Entity | null;
309
310
  if (cacheEntity) {
310
- return cacheEntity as E & EntityDataType<E>;
311
+ return cacheEntity as E;
311
312
  }
312
313
  const entity = new this();
313
314
  if (guid != null) {
@@ -320,16 +321,14 @@ export default class Entity<
320
321
  ];
321
322
  await entity.$wake();
322
323
  }
323
- return entity as E & EntityDataType<E>;
324
+ return entity as E;
324
325
  }
325
326
 
326
327
  /**
327
328
  * Create a new entity instance.
328
329
  */
329
- public static factorySync<E extends Entity>(this: {
330
- new (): E;
331
- }): E & EntityDataType<E> {
332
- return new this() as E & EntityDataType<E>;
330
+ public static factorySync<E extends Entity>(this: { new (): E }): E {
331
+ return new this() as E;
333
332
  }
334
333
 
335
334
  /**
@@ -346,7 +345,7 @@ export default class Entity<
346
345
  new (): E;
347
346
  },
348
347
  reference: EntityReference,
349
- ): E & EntityDataType<E> {
348
+ ): E {
350
349
  const cacheEntity = (
351
350
  reference[1]
352
351
  ? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
@@ -360,7 +359,7 @@ export default class Entity<
360
359
  if (!cacheEntity) {
361
360
  entity.$referenceSleep(reference);
362
361
  }
363
- return entity as E & EntityDataType<E>;
362
+ return entity as E;
364
363
  }
365
364
 
366
365
  /**
@@ -402,7 +401,9 @@ export default class Entity<
402
401
  }
403
402
 
404
403
  public toJSON() {
405
- this.$check();
404
+ if (this.$isASleepingReference && this.$sleepingReference) {
405
+ return this.$sleepingReference;
406
+ }
406
407
  const obj: EntityJson = {
407
408
  class: entityConstructorsToClassNames(this.constructor),
408
409
  guid: this.guid,
@@ -419,9 +420,9 @@ export default class Entity<
419
420
  return obj;
420
421
  }
421
422
 
422
- public $init(entityJson: EntityJson | null) {
423
+ public $init(entityJson: EntityJson | null, isFromSave: boolean) {
423
424
  if (entityJson == null) {
424
- return this.$proxy();
425
+ return this;
425
426
  }
426
427
 
427
428
  this.$isASleepingReference = false;
@@ -430,29 +431,54 @@ export default class Entity<
430
431
  this.guid = entityJson.guid;
431
432
  this.cdate = entityJson.cdate;
432
433
  this.mdate = entityJson.mdate;
433
- this.tags = entityJson.tags;
434
+ if (
435
+ // The instance is new.
436
+ !this.$originalTags.length ||
437
+ // The data is coming from a save.
438
+ isFromSave ||
439
+ // The tags haven't been modified.
440
+ JSON.stringify([...this.tags].sort()) ===
441
+ JSON.stringify([...this.$originalTags].sort())
442
+ ) {
443
+ this.tags = entityJson.tags;
444
+ }
434
445
  this.$originalTags = entityJson.tags.slice(0);
435
- this.$dirty = {};
436
- this.$dataStore = Object.entries(entityJson.data)
437
- .map(([key, value]) => {
438
- this.$dirty[key] = false;
439
- return {
440
- key,
441
- value: classNamesToEntityConstructors(
446
+
447
+ if (!this.$nymph.weakCache || !this.$nymph.weakCacheKeepDirtyData) {
448
+ // Clear dirty data tracker.
449
+ for (let name in this.$dirty) {
450
+ delete this.$dirty[name];
451
+ }
452
+ }
453
+
454
+ for (let name in this.$dataStore) {
455
+ if (!this.$dirty[name]) {
456
+ if (name in entityJson.data) {
457
+ this.$dataStore[name] = classNamesToEntityConstructors(
442
458
  this.$nymph,
443
- referencesToEntities(value, this.$nymph),
444
- ),
445
- };
446
- })
447
- .reduce(
448
- (obj, { key, value }) => Object.assign(obj, { [key]: value }),
449
- {},
450
- ) as T;
451
- this.$data = new Proxy(this.$dataStore, this.$dataHandler);
459
+ referencesToEntities(entityJson.data[name], this.$nymph),
460
+ );
461
+ this.$dirty[name] = false;
462
+ } else {
463
+ delete this.$dataStore[name];
464
+ delete this.$dirty[name];
465
+ }
466
+ }
467
+ }
468
+
469
+ for (let name in entityJson.data as T) {
470
+ if (!(name in this.$dataStore)) {
471
+ this.$dataStore[name] = classNamesToEntityConstructors(
472
+ this.$nymph,
473
+ referencesToEntities(entityJson.data[name], this.$nymph),
474
+ );
475
+ this.$dirty[name] = false;
476
+ }
477
+ }
452
478
 
453
479
  this.$nymph.setEntityToCache(this.constructor as EntityConstructor, this);
454
480
 
455
- return this.$proxy();
481
+ return this;
456
482
  }
457
483
 
458
484
  public $addTag(...tags: string[]) {
@@ -507,10 +533,14 @@ export default class Entity<
507
533
  return false;
508
534
  }
509
535
  const obData = sortObj(object.toJSON());
510
- obData.tags?.sort();
536
+ if ('tags' in obData) {
537
+ obData.tags?.sort();
538
+ }
511
539
  // obData.data = sortObj(obData.data);
512
540
  const myData = sortObj(this.toJSON());
513
- myData.tags?.sort();
541
+ if ('tags' in myData) {
542
+ myData.tags?.sort();
543
+ }
514
544
  // myData.data = sortObj(myData.data);
515
545
  return isEqual(obData, myData);
516
546
  }
@@ -540,7 +570,7 @@ export default class Entity<
540
570
  if (dirty) {
541
571
  if (key in this.$data) {
542
572
  patch.set[key] = entityConstructorsToClassNames(
543
- entitiesToReferences(this.$data[key]),
573
+ entitiesToReferences((this.$data as EntityData)[key]),
544
574
  );
545
575
  } else {
546
576
  patch.unset.push(key);
@@ -585,10 +615,14 @@ export default class Entity<
585
615
  return false;
586
616
  } else {
587
617
  const obData = sortObj(object.toJSON());
588
- obData.tags?.sort();
618
+ if ('tags' in obData) {
619
+ obData.tags?.sort();
620
+ }
589
621
  // obData.data = sortObj(obData.data);
590
622
  const myData = sortObj(this.toJSON());
591
- myData.tags?.sort();
623
+ if ('tags' in myData) {
624
+ myData.tags?.sort();
625
+ }
592
626
  // myData.data = sortObj(myData.data);
593
627
  return isEqual(obData, myData);
594
628
  }
@@ -629,7 +663,7 @@ export default class Entity<
629
663
  public $wake() {
630
664
  if (!this.$asleep()) {
631
665
  this.$wakePromise = null;
632
- return Promise.resolve(this.$proxy());
666
+ return Promise.resolve(this);
633
667
  }
634
668
  if (this.$sleepingReference?.[1] == null) {
635
669
  throw new InvalidStateError(
@@ -647,7 +681,7 @@ export default class Entity<
647
681
  const errObj = { data, textStatus: 'No data returned.' };
648
682
  return Promise.reject(errObj);
649
683
  }
650
- return this.$init(data);
684
+ return this.$init(data, false);
651
685
  })
652
686
  .finally(() => {
653
687
  this.$wakePromise = null;
@@ -667,7 +701,7 @@ export default class Entity<
667
701
  newLevel = level - 1;
668
702
  }
669
703
  if (newLevel !== undefined && newLevel < 0) {
670
- resolve(this.$proxy());
704
+ resolve(this);
671
705
  return;
672
706
  }
673
707
  const promises: Promise<any>[] = [];
@@ -701,11 +735,11 @@ export default class Entity<
701
735
  walkData(this.$data);
702
736
  if (promises.length) {
703
737
  Promise.all(promises).then(
704
- () => resolve(this.$proxy()),
738
+ () => resolve(this),
705
739
  (errObj) => reject(errObj),
706
740
  );
707
741
  } else {
708
- resolve(this.$proxy());
742
+ resolve(this);
709
743
  }
710
744
  };
711
745
 
@@ -744,7 +778,7 @@ export default class Entity<
744
778
  if (data == null) {
745
779
  throw new Error("The entity's data could not be refreshed.");
746
780
  }
747
- this.$init(data);
781
+ this.$init(data, false);
748
782
  return true;
749
783
  }
750
784
 
@@ -779,7 +813,7 @@ export default class Entity<
779
813
  stateless,
780
814
  );
781
815
  if (!stateless && data.entity) {
782
- this.$init(data.entity);
816
+ this.$init(data.entity, false);
783
817
  }
784
818
  return data.return;
785
819
  }
@@ -790,7 +824,7 @@ export default class Entity<
790
824
  }
791
825
 
792
826
  if (this.guid == null) {
793
- return this.$proxy();
827
+ return this;
794
828
  }
795
829
  return [
796
830
  'nymph_entity_reference',
@@ -97,17 +97,13 @@ export interface DataObjectInterface {
97
97
  * @returns False if the data has not been saved, true on success. An error is
98
98
  * thrown on failure.
99
99
  */
100
- $refresh(): Promise<boolean | 0>;
100
+ $refresh(): Promise<boolean>;
101
101
  /**
102
102
  * Save the object to storage.
103
103
  *
104
104
  * An error is thrown on failure.
105
105
  */
106
106
  $save(): Promise<void>;
107
- /**
108
- * The object's data.
109
- */
110
- [k: string]: any;
111
107
  }
112
108
 
113
109
  /**
@@ -176,8 +172,9 @@ export interface EntityInterface extends DataObjectInterface {
176
172
  * Initialize this entity from a JSON representation.
177
173
  *
178
174
  * @param entityJson The entity JSON.
175
+ * @param isFromSave True if the entity is being initialized with data just saved to the server.
179
176
  */
180
- $init(entityJson: EntityJson | null): EntityInterface;
177
+ $init(entityJson: EntityJson | null, isFromSave: boolean): EntityInterface;
181
178
  /**
182
179
  * Retrieve this entity's data from the server.
183
180
  *
@@ -223,6 +220,8 @@ export interface EntityInterface extends DataObjectInterface {
223
220
  * @returns A Nymph Entity Reference array as an unsaved entity.
224
221
  */
225
222
  $toReference(): EntityReference | EntityInterface;
223
+
224
+ toJSON(): EntityReference | EntityJson;
226
225
  }
227
226
 
228
227
  export type EntityConstructor<
@@ -1,6 +1,6 @@
1
1
  import { EntityConstructor, EntityInterface } from './Entity.types.js';
2
2
 
3
- export default class EntityWeakCache {
3
+ export class EntityWeakCache {
4
4
  private references: WeakMap<
5
5
  EntityConstructor,
6
6
  { [k: string]: WeakRef<EntityInterface> }
@@ -32,7 +32,7 @@ export interface AbortableAsyncIterator<
32
32
  abortController: AbortController;
33
33
  }
34
34
 
35
- export default class HttpRequester {
35
+ export class HttpRequester {
36
36
  private fetch: WindowOrWorkerGlobalScope['fetch'];
37
37
  private requestCallbacks: HttpRequesterRequestCallback[] = [];
38
38
  private responseCallbacks: HttpRequesterResponseCallback[] = [];
package/src/Nymph.ts CHANGED
@@ -6,9 +6,10 @@ import type {
6
6
  ServerCallResponse,
7
7
  ServerCallStaticResponse,
8
8
  } from './Entity.types.js';
9
- import EntityWeakCache from './EntityWeakCache.js';
9
+ import { EntityWeakCache } from './EntityWeakCache.js';
10
+ import { QueryWeakCache } from './QueryWeakCache.js';
10
11
  import type { AbortableAsyncIterator } from './HttpRequester.js';
11
- import HttpRequester, { ClientError } from './HttpRequester.js';
12
+ import { HttpRequester, ClientError } from './HttpRequester.js';
12
13
  import type {
13
14
  EventType,
14
15
  NymphOptions,
@@ -45,7 +46,8 @@ export default class Nymph {
45
46
  private requestCallbacks: RequestCallback[] = [];
46
47
  private responseCallbacks: ResponseCallback[] = [];
47
48
  private restUrl: string = '';
48
- private weakCache = false;
49
+ public weakCache = false;
50
+ public weakCacheKeepDirtyData = false;
49
51
  /**
50
52
  * Headers that will be sent with every request.
51
53
  *
@@ -55,7 +57,11 @@ export default class Nymph {
55
57
  /**
56
58
  * The entity cache.
57
59
  */
58
- public cache = new EntityWeakCache();
60
+ public entityCache = new EntityWeakCache();
61
+ /**
62
+ * The query cache.
63
+ */
64
+ public queryCache = new QueryWeakCache();
59
65
  /**
60
66
  * Return `null` or empty array instead of error when entity/ies not found.
61
67
  */
@@ -65,6 +71,7 @@ export default class Nymph {
65
71
  this.restUrl = NymphOptions.restUrl;
66
72
  // @ts-ignore TS doesn't know about WeakRef.
67
73
  this.weakCache = !!NymphOptions.weakCache && typeof WeakRef !== 'undefined';
74
+ this.weakCacheKeepDirtyData = !!NymphOptions.weakCacheKeepDirtyData;
68
75
  if (
69
76
  'returnNullOnNotFound' in NymphOptions &&
70
77
  NymphOptions.returnNullOnNotFound != null
@@ -156,12 +163,24 @@ export default class Nymph {
156
163
  }
157
164
 
158
165
  public async getUID(name: string) {
159
- const data = await requester.GET({
160
- url: this.restUrl,
161
- headers: { ...this.headers },
162
- dataType: 'text',
163
- data: { action: 'uid', data: name },
164
- });
166
+ const query = { action: 'uid', data: name };
167
+ let promise: Promise<any> | null = null;
168
+ const queryJSON = JSON.stringify(query);
169
+ if (this.weakCache) {
170
+ promise = this.queryCache.get(queryJSON);
171
+ }
172
+ if (promise == null) {
173
+ promise = requester.GET({
174
+ url: this.restUrl,
175
+ headers: { ...this.headers },
176
+ dataType: 'text',
177
+ data: query,
178
+ });
179
+ if (this.weakCache) {
180
+ this.queryCache.set(queryJSON, promise);
181
+ }
182
+ }
183
+ const data = await promise;
165
184
  return Number(data);
166
185
  }
167
186
 
@@ -259,11 +278,11 @@ export default class Nymph {
259
278
  response[i] &&
260
279
  response[i].guid != null &&
261
280
  (e.guid == null || e.guid === response[i].guid)
262
- ? e.$init(response[i])
281
+ ? e.$init(response[i], method !== 'GET')
263
282
  : e,
264
283
  ) as T[];
265
284
  } else if (!Array.isArray(entity) && response.guid != null) {
266
- return entity.$init(response) as T;
285
+ return entity.$init(response, method !== 'GET') as T;
267
286
  }
268
287
  throw new Error('Server error');
269
288
  }
@@ -320,7 +339,7 @@ export default class Nymph {
320
339
  if (options.return && options.return === 'guid') {
321
340
  return data as string;
322
341
  } else {
323
- return this.initEntity(data as EntityJson<T>);
342
+ return this.initEntity(data as EntityJson<T>, false);
324
343
  }
325
344
  }
326
345
 
@@ -364,18 +383,31 @@ export default class Nymph {
364
383
  if (typeof selectors[0] === 'string') {
365
384
  selectors = [{ type: '&', guid: selectors[0] }];
366
385
  }
367
- const data = await requester.GET({
368
- url: this.restUrl,
369
- headers: { ...this.headers },
370
- dataType: 'json',
371
- data: {
372
- action: 'entity',
373
- data: [
374
- entityConstructorsToClassNames(options),
375
- ...entityConstructorsToClassNames(entitiesToReferences(selectors)),
376
- ],
377
- },
378
- });
386
+ const query = {
387
+ action: 'entity',
388
+ data: [
389
+ entityConstructorsToClassNames(options),
390
+ ...entityConstructorsToClassNames(entitiesToReferences(selectors)),
391
+ ],
392
+ };
393
+ let promise: Promise<any> | null = null;
394
+ const queryJSON = JSON.stringify(query);
395
+ if (this.weakCache) {
396
+ promise = this.queryCache.get(queryJSON);
397
+ }
398
+ if (promise == null) {
399
+ promise = requester.GET({
400
+ url: this.restUrl,
401
+ headers: { ...this.headers },
402
+ dataType: 'json',
403
+ data: query,
404
+ });
405
+ if (this.weakCache) {
406
+ this.queryCache.set(queryJSON, promise);
407
+ }
408
+ }
409
+
410
+ const data = await promise;
379
411
 
380
412
  if (options.return === 'count' || typeof data.guid !== 'undefined') {
381
413
  return data;
@@ -401,18 +433,30 @@ export default class Nymph {
401
433
  ): Promise<EntityInstanceType<T>[] | string[] | number> {
402
434
  let data = null;
403
435
  try {
404
- data = await requester.GET({
405
- url: this.restUrl,
406
- headers: { ...this.headers },
407
- dataType: 'json',
408
- data: {
409
- action: 'entities',
410
- data: [
411
- entityConstructorsToClassNames(options),
412
- ...entityConstructorsToClassNames(entitiesToReferences(selectors)),
413
- ],
414
- },
415
- });
436
+ const query = {
437
+ action: 'entities',
438
+ data: [
439
+ entityConstructorsToClassNames(options),
440
+ ...entityConstructorsToClassNames(entitiesToReferences(selectors)),
441
+ ],
442
+ };
443
+ let promise: Promise<any> | null = null;
444
+ const queryJSON = JSON.stringify(query);
445
+ if (this.weakCache) {
446
+ promise = this.queryCache.get(queryJSON);
447
+ }
448
+ if (promise == null) {
449
+ promise = requester.GET({
450
+ url: this.restUrl,
451
+ headers: { ...this.headers },
452
+ dataType: 'json',
453
+ data: query,
454
+ });
455
+ if (this.weakCache) {
456
+ this.queryCache.set(queryJSON, promise);
457
+ }
458
+ }
459
+ data = await promise;
416
460
  } catch (e: any) {
417
461
  if (
418
462
  this.returnNullOnNotFound &&
@@ -434,11 +478,12 @@ export default class Nymph {
434
478
  if (options.return && options.return === 'guid') {
435
479
  return data;
436
480
  }
437
- return data.map((e: EntityJson<T>) => this.initEntity(e));
481
+ return data.map((e: EntityJson<T>) => this.initEntity(e, false));
438
482
  }
439
483
 
440
484
  public initEntity<T extends EntityConstructor = EntityConstructor>(
441
485
  entityJSON: EntityJson<T>,
486
+ isFromSave: boolean,
442
487
  ): EntityInstanceType<T> {
443
488
  const EntityClass = classNamesToEntityConstructors<T>(
444
489
  this,
@@ -452,7 +497,7 @@ export default class Nymph {
452
497
  let entity = EntityClass.factorySync();
453
498
  if (this.weakCache) {
454
499
  // Try to get it from cache.
455
- const entityFromCache = this.cache.get(
500
+ const entityFromCache = this.entityCache.get(
456
501
  EntityClass,
457
502
  entityJSON.guid || '',
458
503
  );
@@ -460,7 +505,7 @@ export default class Nymph {
460
505
  entity = entityFromCache as EntityInstanceType<T>;
461
506
  }
462
507
  }
463
- return entity.$init(entityJSON) as EntityInstanceType<T>;
508
+ return entity.$init(entityJSON, isFromSave) as EntityInstanceType<T>;
464
509
  }
465
510
 
466
511
  public getEntityFromCache<T extends EntityConstructor = EntityConstructor>(
@@ -470,7 +515,10 @@ export default class Nymph {
470
515
  if (!this.weakCache) {
471
516
  return null;
472
517
  }
473
- return this.cache.get(EntityClass, guid) as EntityInstanceType<T> | null;
518
+ return this.entityCache.get(
519
+ EntityClass,
520
+ guid,
521
+ ) as EntityInstanceType<T> | null;
474
522
  }
475
523
 
476
524
  public setEntityToCache(
@@ -480,13 +528,15 @@ export default class Nymph {
480
528
  if (!this.weakCache) {
481
529
  return;
482
530
  }
483
- return this.cache.set(EntityClass, entity);
531
+ return this.entityCache.set(EntityClass, entity);
484
532
  }
485
533
 
486
- public initEntitiesFromData<T extends any>(item: T): T {
534
+ public initEntitiesFromData<T extends any>(item: T, isFromSave: boolean): T {
487
535
  if (Array.isArray(item)) {
488
536
  // Recurse into lower arrays.
489
- return item.map((entry) => this.initEntitiesFromData(entry)) as T;
537
+ return item.map((entry) =>
538
+ this.initEntitiesFromData(entry, isFromSave),
539
+ ) as T;
490
540
  } else if (item instanceof Object && !(item instanceof Entity)) {
491
541
  if (
492
542
  item.hasOwnProperty('class') &&
@@ -500,11 +550,11 @@ export default class Nymph {
500
550
  (item as any as EntityJson).class,
501
551
  ) != null
502
552
  ) {
503
- return this.initEntity(item as any as EntityJson) as T;
553
+ return this.initEntity(item as any as EntityJson, isFromSave) as T;
504
554
  } else {
505
555
  for (let [key, value] of Object.entries(item)) {
506
556
  // @ts-ignore: Key comes from the object. It's fine.
507
- item[key] = this.initEntitiesFromData(value);
557
+ item[key] = this.initEntitiesFromData(value, isFromSave);
508
558
  }
509
559
  }
510
560
  }
@@ -563,7 +613,7 @@ export default class Nymph {
563
613
 
564
614
  return {
565
615
  ...data,
566
- return: this.initEntitiesFromData(data.return),
616
+ return: this.initEntitiesFromData(data.return, false),
567
617
  };
568
618
  }
569
619
 
@@ -587,7 +637,7 @@ export default class Nymph {
587
637
  },
588
638
  });
589
639
 
590
- return this.initEntitiesFromData(data);
640
+ return this.initEntitiesFromData(data, false);
591
641
  }
592
642
 
593
643
  public async serverCallStaticIterator(
@@ -619,7 +669,7 @@ export default class Nymph {
619
669
  if (response instanceof Error) {
620
670
  yield response;
621
671
  } else {
622
- yield that.initEntitiesFromData(response);
672
+ yield that.initEntitiesFromData(response, false);
623
673
  }
624
674
  }
625
675
  },