@nymphjs/client 1.0.0-beta.13 → 1.0.0-beta.130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +546 -0
  2. package/README.md +12 -8
  3. package/asyncitertest.js +53 -0
  4. package/dist/Entity.d.ts +156 -0
  5. package/{lib → dist}/Entity.js +244 -118
  6. package/dist/Entity.js.map +1 -0
  7. package/dist/Entity.types.d.ts +216 -0
  8. package/dist/Entity.types.js +2 -0
  9. package/{lib → dist}/EntityWeakCache.d.ts +1 -1
  10. package/{lib → dist}/EntityWeakCache.js +5 -9
  11. package/dist/EntityWeakCache.js.map +1 -0
  12. package/{lib → dist}/HttpRequester.d.ts +18 -4
  13. package/dist/HttpRequester.js +365 -0
  14. package/dist/HttpRequester.js.map +1 -0
  15. package/{lib → dist}/Nymph.d.ts +48 -11
  16. package/{lib → dist}/Nymph.js +172 -56
  17. package/dist/Nymph.js.map +1 -0
  18. package/dist/Nymph.types.d.ts +227 -0
  19. package/dist/Nymph.types.js +45 -0
  20. package/dist/Nymph.types.js.map +1 -0
  21. package/{lib → dist}/PubSub.d.ts +16 -10
  22. package/{lib → dist}/PubSub.js +207 -135
  23. package/dist/PubSub.js.map +1 -0
  24. package/{lib → dist}/PubSub.types.d.ts +19 -6
  25. package/dist/PubSub.types.js +2 -0
  26. package/{lib → dist}/entityRefresh.d.ts +1 -1
  27. package/{lib → dist}/entityRefresh.js +21 -13
  28. package/dist/entityRefresh.js.map +1 -0
  29. package/dist/index.d.ts +13 -0
  30. package/dist/index.js +13 -2
  31. package/dist/index.js.map +1 -1
  32. package/{lib → dist}/utils.d.ts +2 -1
  33. package/dist/utils.js +145 -0
  34. package/dist/utils.js.map +1 -0
  35. package/jest.config.js +31 -5
  36. package/package.json +36 -32
  37. package/src/Entity.ts +229 -129
  38. package/src/Entity.types.ts +37 -57
  39. package/src/EntityWeakCache.ts +8 -6
  40. package/src/HttpRequester.ts +268 -31
  41. package/src/Nymph.ts +203 -96
  42. package/src/Nymph.types.ts +98 -2
  43. package/src/PubSub.ts +264 -181
  44. package/src/PubSub.types.ts +33 -19
  45. package/src/entityRefresh.ts +6 -6
  46. package/src/index.ts +10 -10
  47. package/src/utils.ts +67 -14
  48. package/tsconfig.json +7 -4
  49. package/typedoc.json +4 -0
  50. package/dist/index.js.LICENSE.txt +0 -8
  51. package/lib/Entity.d.ts +0 -51
  52. package/lib/Entity.js.map +0 -1
  53. package/lib/Entity.types.d.ts +0 -65
  54. package/lib/Entity.types.js +0 -3
  55. package/lib/EntityWeakCache.js.map +0 -1
  56. package/lib/HttpRequester.js +0 -190
  57. package/lib/HttpRequester.js.map +0 -1
  58. package/lib/Nymph.js.map +0 -1
  59. package/lib/Nymph.types.d.ts +0 -98
  60. package/lib/Nymph.types.js +0 -3
  61. package/lib/Nymph.types.js.map +0 -1
  62. package/lib/PubSub.js.map +0 -1
  63. package/lib/PubSub.types.js +0 -3
  64. package/lib/entityRefresh.js.map +0 -1
  65. package/lib/index.d.ts +0 -13
  66. package/lib/index.js +0 -34
  67. package/lib/index.js.map +0 -1
  68. package/lib/utils.js +0 -86
  69. package/lib/utils.js.map +0 -1
  70. package/webpack.config.js +0 -28
  71. /package/{lib → dist}/Entity.types.js.map +0 -0
  72. /package/{lib → dist}/PubSub.types.js.map +0 -0
package/src/Entity.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { difference, isEqual } from 'lodash';
1
+ import { difference, isEqual } from 'lodash-es';
2
2
 
3
- import type Nymph from './Nymph';
3
+ import type Nymph from './Nymph.js';
4
4
  import {
5
5
  EntityConstructor,
6
6
  EntityData,
@@ -8,21 +8,25 @@ import {
8
8
  EntityJson,
9
9
  EntityPatch,
10
10
  EntityReference,
11
- } from './Entity.types';
11
+ } from './Entity.types.js';
12
12
  import {
13
13
  uniqueStrings,
14
14
  entitiesToReferences,
15
15
  referencesToEntities,
16
16
  sortObj,
17
- } from './utils';
17
+ entityConstructorsToClassNames,
18
+ classNamesToEntityConstructors,
19
+ } from './utils.js';
18
20
 
19
- const sleepErr =
20
- 'This entity is in a sleeping reference state. ' +
21
- 'You must use .$ready() to wake it.';
21
+ export type EntityDataType<T> =
22
+ T extends Entity<infer DataType> ? DataType : never;
22
23
 
23
- export default class Entity<T extends EntityData = EntityData>
24
- implements EntityInterface
25
- {
24
+ export type EntityInstanceType<T extends EntityConstructor> =
25
+ T extends new () => infer E ? E & EntityDataType<E> : never;
26
+
27
+ export default class Entity<
28
+ T extends EntityData = EntityData,
29
+ > implements EntityInterface {
26
30
  /**
27
31
  * The instance of Nymph to use for queries.
28
32
  */
@@ -84,15 +88,14 @@ export default class Entity<T extends EntityData = EntityData>
84
88
  */
85
89
  protected $sleepingReference: EntityReference | null = null;
86
90
  /**
87
- * A promise that resolved when the entity's data is ready.
91
+ * A promise that resolved when the entity's data is wake.
88
92
  */
89
- protected $readyPromise: Promise<Entity<T>> | null = null;
93
+ protected $wakePromise: Promise<Entity<T>> | null = null;
90
94
 
91
95
  /**
92
- * Load an entity.
93
- * @param guid The ID of the entity to load, undefined for a new entity.
96
+ * Initialize an entity.
94
97
  */
95
- public constructor(guid?: string) {
98
+ public constructor(..._rest: any[]) {
96
99
  this.$nymph = (this.constructor as EntityConstructor).nymph;
97
100
  this.$dataHandler = {
98
101
  has: (data: EntityData, name: string) => {
@@ -129,7 +132,7 @@ export default class Entity<T extends EntityData = EntityData>
129
132
  deleteProperty: (data: EntityData, name: string) => {
130
133
  if (typeof name !== 'symbol' && this.$isASleepingReference) {
131
134
  console.error(
132
- `Tried to delete data on a sleeping reference: ${name}`
135
+ `Tried to delete data on a sleeping reference: ${name}`,
133
136
  );
134
137
  return false;
135
138
  }
@@ -143,11 +146,11 @@ export default class Entity<T extends EntityData = EntityData>
143
146
  defineProperty: (
144
147
  data: EntityData,
145
148
  name: string,
146
- descriptor: PropertyDescriptor
149
+ descriptor: PropertyDescriptor,
147
150
  ) => {
148
151
  if (typeof name !== 'symbol' && this.$isASleepingReference) {
149
152
  console.error(
150
- `Tried to define data on a sleeping reference: ${name}`
153
+ `Tried to define data on a sleeping reference: ${name}`,
151
154
  );
152
155
  return false;
153
156
  }
@@ -161,7 +164,7 @@ export default class Entity<T extends EntityData = EntityData>
161
164
  getOwnPropertyDescriptor: (data: EntityData, name: string) => {
162
165
  if (typeof name !== 'symbol' && this.$isASleepingReference) {
163
166
  console.error(
164
- `Tried to get property descriptor on a sleeping reference: ${name}`
167
+ `Tried to get property descriptor on a sleeping reference: ${name}`,
165
168
  );
166
169
  return undefined;
167
170
  }
@@ -179,17 +182,6 @@ export default class Entity<T extends EntityData = EntityData>
179
182
  this.$dataStore = {} as T;
180
183
  this.$data = new Proxy(this.$dataStore, this.$dataHandler);
181
184
 
182
- if (guid != null) {
183
- this.guid = guid;
184
- this.$isASleepingReference = true;
185
- this.$sleepingReference = [
186
- 'nymph_entity_reference',
187
- this.guid,
188
- (this.constructor as EntityConstructor).class,
189
- ];
190
- this.$ready();
191
- }
192
-
193
185
  return new Proxy(this, {
194
186
  has(entity: Entity, name: string) {
195
187
  if (
@@ -245,7 +237,7 @@ export default class Entity<T extends EntityData = EntityData>
245
237
  defineProperty(
246
238
  entity: Entity,
247
239
  name: string,
248
- descriptor: PropertyDescriptor
240
+ descriptor: PropertyDescriptor,
249
241
  ) {
250
242
  if (
251
243
  typeof name !== 'string' ||
@@ -273,59 +265,132 @@ export default class Entity<T extends EntityData = EntityData>
273
265
 
274
266
  ownKeys(entity: Entity) {
275
267
  return Object.getOwnPropertyNames(entity).concat(
276
- Object.getOwnPropertyNames(entity.$data)
268
+ Object.getOwnPropertyNames(entity.$data),
277
269
  );
278
270
  },
279
271
  }) as Entity<T>;
280
272
  }
281
273
 
282
- public static async factory(guid?: string) {
274
+ /**
275
+ * Create or retrieve a new entity instance.
276
+ *
277
+ * Note that this will always return an entity, even if the GUID is not found.
278
+ *
279
+ * @param guid An optional GUID to retrieve.
280
+ */
281
+ public static async factory<E extends Entity>(
282
+ this: {
283
+ new (): E;
284
+ },
285
+ guid?: string,
286
+ ): Promise<E & EntityDataType<E>> {
283
287
  const cacheEntity = (
284
- guid ? this.nymph.getEntityFromCache(this, guid) : null
288
+ guid
289
+ ? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
290
+ this as unknown as EntityConstructor,
291
+ guid,
292
+ )
293
+ : null
285
294
  ) as Entity | null;
286
- const entity = cacheEntity || new this(guid);
295
+ if (cacheEntity) {
296
+ return cacheEntity as E & EntityDataType<E>;
297
+ }
298
+ const entity = new this();
287
299
  if (guid != null) {
288
- await entity.$ready();
300
+ entity.guid = guid;
301
+ entity.$isASleepingReference = true;
302
+ entity.$sleepingReference = [
303
+ 'nymph_entity_reference',
304
+ guid,
305
+ (this as unknown as EntityConstructor).class,
306
+ ];
307
+ await entity.$wake();
289
308
  }
290
- return entity;
309
+ return entity as E & EntityDataType<E>;
291
310
  }
292
311
 
293
- public static factorySync(guid?: string) {
294
- const cacheEntity = (
295
- guid ? this.nymph.getEntityFromCache(this, guid) : null
296
- ) as Entity | null;
297
- return cacheEntity || new this(guid);
312
+ /**
313
+ * Create a new entity instance.
314
+ */
315
+ public static factorySync<E extends Entity>(this: {
316
+ new (): E;
317
+ }): E & EntityDataType<E> {
318
+ return new this() as E & EntityDataType<E>;
298
319
  }
299
320
 
300
- public static factoryReference(reference: EntityReference) {
321
+ /**
322
+ * Create a new sleeping reference instance.
323
+ *
324
+ * Sleeping references won't retrieve their data from the server until they
325
+ * are readied with `$wake()` or a parent's `$wakeAll()`.
326
+ *
327
+ * @param reference The Nymph Entity Reference to use to wake.
328
+ * @returns The new instance.
329
+ */
330
+ public static factoryReference<E extends Entity>(
331
+ this: {
332
+ new (): E;
333
+ },
334
+ reference: EntityReference,
335
+ ): E & EntityDataType<E> {
301
336
  const cacheEntity = (
302
- reference[1] ? this.nymph.getEntityFromCache(this, reference[1]) : null
337
+ reference[1]
338
+ ? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
339
+ this as unknown as EntityConstructor,
340
+ reference[1],
341
+ )
342
+ : null
303
343
  ) as Entity | null;
304
344
 
305
345
  const entity = cacheEntity || new this();
306
346
  if (!cacheEntity) {
307
347
  entity.$referenceSleep(reference);
308
348
  }
309
- return entity;
349
+ return entity as E & EntityDataType<E>;
310
350
  }
311
351
 
352
+ /**
353
+ * Call a static method on the server version of this entity.
354
+ *
355
+ * @param method The name of the method.
356
+ * @param params The parameters to call the method with.
357
+ * @returns The value that the method on the server returned.
358
+ */
312
359
  public static async serverCallStatic(method: string, params: Iterable<any>) {
313
360
  const data = await this.nymph.serverCallStatic(
314
361
  this.class,
315
362
  method,
316
363
  // Turn the params into a real array, in case an arguments object was
317
364
  // passed.
318
- Array.prototype.slice.call(params)
365
+ Array.prototype.slice.call(params),
319
366
  );
320
367
  return data.return;
321
368
  }
322
369
 
370
+ /**
371
+ * Call a static iterator method on the server version of this entity.
372
+ *
373
+ * @param method The name of the method.
374
+ * @param params The parameters to call the method with.
375
+ * @returns An iterator that iterates over values that the method on the server yields.
376
+ */
377
+ public static async serverCallStaticIterator(
378
+ method: string,
379
+ params: Iterable<any>,
380
+ ) {
381
+ return await this.nymph.serverCallStaticIterator(
382
+ this.class,
383
+ method,
384
+ // Turn the params into a real array, in case an arguments object was
385
+ // passed.
386
+ Array.prototype.slice.call(params),
387
+ );
388
+ }
389
+
323
390
  public toJSON() {
324
- if (this.$isASleepingReference) {
325
- throw new EntityIsSleepingReferenceError(sleepErr);
326
- }
391
+ this.$check();
327
392
  const obj: EntityJson = {
328
- class: (this.constructor as any).class as string,
393
+ class: entityConstructorsToClassNames(this.constructor),
329
394
  guid: this.guid,
330
395
  cdate: this.cdate,
331
396
  mdate: this.mdate,
@@ -333,7 +398,9 @@ export default class Entity<T extends EntityData = EntityData>
333
398
  data: {},
334
399
  };
335
400
  for (let [key, value] of Object.entries(this.$dataStore)) {
336
- obj.data[key] = entitiesToReferences(value);
401
+ obj.data[key] = entityConstructorsToClassNames(
402
+ entitiesToReferences(value),
403
+ );
337
404
  }
338
405
  return obj;
339
406
  }
@@ -355,11 +422,17 @@ export default class Entity<T extends EntityData = EntityData>
355
422
  this.$dataStore = Object.entries(entityJson.data)
356
423
  .map(([key, value]) => {
357
424
  this.$dirty[key] = false;
358
- return { key, value: referencesToEntities(value, this.$nymph) };
425
+ return {
426
+ key,
427
+ value: classNamesToEntityConstructors(
428
+ this.$nymph,
429
+ referencesToEntities(value, this.$nymph),
430
+ ),
431
+ };
359
432
  })
360
433
  .reduce(
361
434
  (obj, { key, value }) => Object.assign(obj, { [key]: value }),
362
- {}
435
+ {},
363
436
  ) as T;
364
437
  this.$data = new Proxy(this.$dataStore, this.$dataHandler);
365
438
 
@@ -369,9 +442,7 @@ export default class Entity<T extends EntityData = EntityData>
369
442
  }
370
443
 
371
444
  public $addTag(...tags: string[]) {
372
- if (this.$isASleepingReference) {
373
- throw new EntityIsSleepingReferenceError(sleepErr);
374
- }
445
+ this.$check();
375
446
 
376
447
  if (tags.length < 1) {
377
448
  return;
@@ -380,9 +451,7 @@ export default class Entity<T extends EntityData = EntityData>
380
451
  }
381
452
 
382
453
  public $arraySearch(array: any[], strict = false) {
383
- if (this.$isASleepingReference) {
384
- throw new EntityIsSleepingReferenceError(sleepErr);
385
- }
454
+ this.$check();
386
455
 
387
456
  if (!Array.isArray(array)) {
388
457
  return -1;
@@ -396,20 +465,18 @@ export default class Entity<T extends EntityData = EntityData>
396
465
  return -1;
397
466
  }
398
467
 
399
- public async $delete(): Promise<boolean> {
400
- if (this.$isASleepingReference) {
401
- throw new EntityIsSleepingReferenceError(sleepErr);
402
- }
468
+ public async $delete(): Promise<void> {
469
+ this.$check();
403
470
 
404
471
  const guid = this.guid;
405
472
 
406
- return (await this.$nymph.deleteEntity(this)) === guid;
473
+ if ((await this.$nymph.deleteEntity(this)) !== guid) {
474
+ throw new Error('Failed to delete entity.');
475
+ }
407
476
  }
408
477
 
409
478
  public $equals(object: any) {
410
- if (this.$isASleepingReference) {
411
- throw new EntityIsSleepingReferenceError(sleepErr);
412
- }
479
+ this.$check();
413
480
 
414
481
  if (!(object instanceof Entity)) {
415
482
  return false;
@@ -435,23 +502,21 @@ export default class Entity<T extends EntityData = EntityData>
435
502
  }
436
503
 
437
504
  public $getPatch(): EntityPatch {
438
- if (this.$isASleepingReference) {
439
- throw new EntityIsSleepingReferenceError(sleepErr);
440
- }
505
+ this.$check();
441
506
  if (this.guid == null) {
442
507
  throw new InvalidStateError(
443
- "You can't make a patch from an unsaved entity."
508
+ "You can't make a patch from an unsaved entity.",
444
509
  );
445
510
  }
446
511
  const patch: EntityPatch = {
447
512
  guid: this.guid,
448
513
  mdate: this.mdate,
449
- class: (this.constructor as EntityConstructor).class,
514
+ class: entityConstructorsToClassNames(this.constructor),
450
515
  addTags: this.tags.filter(
451
- (tag) => this.$originalTags.indexOf(tag) === -1
516
+ (tag) => this.$originalTags.indexOf(tag) === -1,
452
517
  ),
453
518
  removeTags: this.$originalTags.filter(
454
- (tag) => this.tags.indexOf(tag) === -1
519
+ (tag) => this.tags.indexOf(tag) === -1,
455
520
  ),
456
521
  unset: [],
457
522
  set: {},
@@ -460,7 +525,9 @@ export default class Entity<T extends EntityData = EntityData>
460
525
  for (let [key, dirty] of Object.entries(this.$dirty)) {
461
526
  if (dirty) {
462
527
  if (key in this.$data) {
463
- patch.set[key] = entitiesToReferences(this.$data[key]);
528
+ patch.set[key] = entityConstructorsToClassNames(
529
+ entitiesToReferences(this.$data[key]),
530
+ );
464
531
  } else {
465
532
  patch.unset.push(key);
466
533
  }
@@ -471,9 +538,7 @@ export default class Entity<T extends EntityData = EntityData>
471
538
  }
472
539
 
473
540
  public $hasTag(...tags: string[]) {
474
- if (this.$isASleepingReference) {
475
- throw new EntityIsSleepingReferenceError(sleepErr);
476
- }
541
+ this.$check();
477
542
 
478
543
  if (!tags.length) {
479
544
  return false;
@@ -486,14 +551,16 @@ export default class Entity<T extends EntityData = EntityData>
486
551
  return true;
487
552
  }
488
553
 
554
+ public $isDirty(property: string) {
555
+ return property in this.$dirty ? this.$dirty[property] : null;
556
+ }
557
+
489
558
  public $inArray(array: any[], strict = false) {
490
559
  return this.$arraySearch(array, strict) !== -1;
491
560
  }
492
561
 
493
562
  public $is(object: any) {
494
- if (this.$isASleepingReference) {
495
- throw new EntityIsSleepingReferenceError(sleepErr);
496
- }
563
+ this.$check();
497
564
 
498
565
  if (!(object instanceof Entity)) {
499
566
  return false;
@@ -514,31 +581,52 @@ export default class Entity<T extends EntityData = EntityData>
514
581
  }
515
582
 
516
583
  public async $patch() {
517
- if (this.$isASleepingReference) {
518
- throw new EntityIsSleepingReferenceError(sleepErr);
519
- }
584
+ this.$check();
520
585
 
521
586
  const mdate = this.mdate;
522
587
 
523
588
  await this.$nymph.patchEntity(this);
524
- return mdate !== this.mdate;
589
+ if (mdate === this.mdate) {
590
+ throw new Error('Failed to patch entity.');
591
+ }
592
+ }
593
+
594
+ /**
595
+ * Check if this is a sleeping reference and throw an error if so.
596
+ */
597
+ protected $check() {
598
+ if (this.$isASleepingReference || this.$sleepingReference != null) {
599
+ throw new EntityIsSleepingReferenceError(
600
+ 'This entity is in a sleeping reference state. You must use .$wake() to wake it.',
601
+ );
602
+ }
603
+ }
604
+
605
+ /**
606
+ * Check if this is a sleeping reference.
607
+ */
608
+ public $asleep() {
609
+ return this.$isASleepingReference || this.$sleepingReference != null;
525
610
  }
526
611
 
527
- public $ready() {
612
+ /**
613
+ * Wake from a sleeping reference.
614
+ */
615
+ public $wake() {
528
616
  if (!this.$isASleepingReference) {
529
- this.$readyPromise = null;
617
+ this.$wakePromise = null;
530
618
  return Promise.resolve(this);
531
619
  }
532
620
  if (this.$sleepingReference?.[1] == null) {
533
621
  throw new InvalidStateError(
534
- 'Tried to ready a sleeping reference with no GUID.'
622
+ 'Tried to wake a sleeping reference with no GUID.',
535
623
  );
536
624
  }
537
- if (!this.$readyPromise) {
538
- this.$readyPromise = this.$nymph
625
+ if (!this.$wakePromise) {
626
+ this.$wakePromise = this.$nymph
539
627
  .getEntityData(
540
628
  { class: this.constructor as EntityConstructor },
541
- { type: '&', guid: this.$sleepingReference[1] }
629
+ { type: '&', guid: this.$sleepingReference[1] },
542
630
  )
543
631
  .then((data) => {
544
632
  if (data == null) {
@@ -548,17 +636,17 @@ export default class Entity<T extends EntityData = EntityData>
548
636
  return this.$init(data);
549
637
  })
550
638
  .finally(() => {
551
- this.$readyPromise = null;
639
+ this.$wakePromise = null;
552
640
  });
553
641
  }
554
- return this.$readyPromise;
642
+ return this.$wakePromise;
555
643
  }
556
644
 
557
- public $readyAll(level?: number) {
645
+ public $wakeAll(level?: number) {
558
646
  return new Promise((resolve, reject) => {
559
- // Run this once this entity is ready.
560
- const readyProps = () => {
561
- let newLevel;
647
+ // Run this once this entity is awake.
648
+ const wakeProps = () => {
649
+ let newLevel: number | undefined;
562
650
  // If level is undefined, keep going forever, otherwise, stop once we've
563
651
  // gone deep enough.
564
652
  if (level !== undefined) {
@@ -568,26 +656,39 @@ export default class Entity<T extends EntityData = EntityData>
568
656
  resolve(this);
569
657
  return;
570
658
  }
571
- const promises = [];
572
- // Go through data looking for entities to ready.
573
- for (let [key, value] of Object.entries(this.$data)) {
574
- if (value instanceof Entity && value.$isASleepingReference) {
575
- promises.push(value.$readyAll(newLevel));
576
- } else if (Array.isArray(value)) {
577
- for (let i = 0; i < value.length; i++) {
578
- if (
579
- value[i] instanceof Entity &&
580
- value[i].$isASleepingReference
581
- ) {
582
- promises.push(value[i].$readyAll(newLevel));
583
- }
659
+ const promises: Promise<any>[] = [];
660
+ // Go through data looking for entities to wake.
661
+ const walkData = (data: any) => {
662
+ if (data == null) {
663
+ return;
664
+ } else if (
665
+ typeof data === 'function' &&
666
+ data.prototype instanceof Entity
667
+ ) {
668
+ // Ignore this, it is an entity class.
669
+ return;
670
+ } else if (data instanceof Entity) {
671
+ // Wake it up.
672
+ if (data.$isASleepingReference) {
673
+ promises.push(data.$wakeAll(newLevel));
674
+ }
675
+ } else if (Array.isArray(data)) {
676
+ // Recurse into lower arrays.
677
+ for (let i = 0; i < data.length; i++) {
678
+ walkData(data[i]);
679
+ }
680
+ } else if (data instanceof Object) {
681
+ // Recurse into objects.
682
+ for (let [key, value] of Object.entries(data)) {
683
+ walkData(value);
584
684
  }
585
685
  }
586
- }
686
+ };
687
+ walkData(this.$data);
587
688
  if (promises.length) {
588
689
  Promise.all(promises).then(
589
690
  () => resolve(this),
590
- (errObj) => reject(errObj)
691
+ (errObj) => reject(errObj),
591
692
  );
592
693
  } else {
593
694
  resolve(this);
@@ -595,9 +696,9 @@ export default class Entity<T extends EntityData = EntityData>
595
696
  };
596
697
 
597
698
  if (this.$isASleepingReference) {
598
- this.$ready().then(readyProps, (errObj) => reject(errObj));
699
+ this.$wake().then(wakeProps, (errObj) => reject(errObj));
599
700
  } else {
600
- readyProps();
701
+ wakeProps();
601
702
  }
602
703
  }) as Promise<Entity<T>>;
603
704
  }
@@ -610,7 +711,7 @@ export default class Entity<T extends EntityData = EntityData>
610
711
 
611
712
  public async $refresh() {
612
713
  if (this.$isASleepingReference) {
613
- await this.$ready();
714
+ await this.$wake();
614
715
  return true;
615
716
  }
616
717
 
@@ -624,37 +725,36 @@ export default class Entity<T extends EntityData = EntityData>
624
725
  {
625
726
  type: '&',
626
727
  guid: this.guid,
627
- }
728
+ },
628
729
  );
730
+ if (data == null) {
731
+ throw new Error("The entity's data could not be refreshed.");
732
+ }
629
733
  this.$init(data);
630
- return this.guid == null ? 0 : true;
734
+ return true;
631
735
  }
632
736
 
633
737
  public $removeTag(...tags: string[]) {
634
- if (this.$isASleepingReference) {
635
- throw new EntityIsSleepingReferenceError(sleepErr);
636
- }
738
+ this.$check();
637
739
 
638
740
  this.tags = difference(this.tags, tags);
639
741
  }
640
742
 
641
743
  public async $save() {
642
- if (this.$isASleepingReference) {
643
- throw new EntityIsSleepingReferenceError(sleepErr);
644
- }
744
+ this.$check();
645
745
 
646
746
  await this.$nymph.saveEntity(this);
647
- return !!this.guid;
747
+ if (!this.guid) {
748
+ throw new Error('Failed to save entity.');
749
+ }
648
750
  }
649
751
 
650
752
  public async $serverCall(
651
753
  method: string,
652
754
  params: Iterable<any>,
653
- stateless = false
755
+ stateless = false,
654
756
  ) {
655
- if (this.$isASleepingReference) {
656
- throw new EntityIsSleepingReferenceError(sleepErr);
657
- }
757
+ this.$check();
658
758
  // Turn the params into a real array, in case an arguments object was
659
759
  // passed.
660
760
  const paramArray = Array.prototype.slice.call(params);
@@ -662,7 +762,7 @@ export default class Entity<T extends EntityData = EntityData>
662
762
  this,
663
763
  method,
664
764
  paramArray,
665
- stateless
765
+ stateless,
666
766
  );
667
767
  if (!stateless && data.entity) {
668
768
  this.$init(data.entity);