@nymphjs/nymph 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 (123) hide show
  1. package/CHANGELOG.md +644 -0
  2. package/README.md +34 -24
  3. package/dist/Entity.d.ts +304 -15
  4. package/dist/Entity.js +609 -154
  5. package/dist/Entity.js.map +1 -1
  6. package/dist/Entity.test.js +75 -29
  7. package/dist/Entity.test.js.map +1 -1
  8. package/dist/Entity.types.d.ts +275 -28
  9. package/dist/Entity.types.js +1 -2
  10. package/dist/Nymph.d.ts +575 -11
  11. package/dist/Nymph.js +825 -288
  12. package/dist/Nymph.js.map +1 -1
  13. package/dist/Nymph.types.d.ts +117 -7
  14. package/dist/Nymph.types.js +47 -5
  15. package/dist/Nymph.types.js.map +1 -1
  16. package/dist/conf/defaults.d.ts +1 -1
  17. package/dist/conf/defaults.js +26 -3
  18. package/dist/conf/defaults.js.map +1 -1
  19. package/dist/conf/index.d.ts +50 -2
  20. package/dist/conf/index.js +2 -8
  21. package/dist/conf/index.js.map +1 -1
  22. package/dist/decorators/index.d.ts +1 -0
  23. package/dist/decorators/index.js +2 -0
  24. package/dist/decorators/index.js.map +1 -0
  25. package/dist/decorators/transactional.d.ts +12 -0
  26. package/dist/decorators/transactional.js +45 -0
  27. package/dist/decorators/transactional.js.map +1 -0
  28. package/dist/driver/NymphDriver.d.ts +209 -41
  29. package/dist/driver/NymphDriver.js +737 -242
  30. package/dist/driver/NymphDriver.js.map +1 -1
  31. package/dist/driver/index.d.ts +1 -2
  32. package/dist/driver/index.js +2 -23
  33. package/dist/driver/index.js.map +1 -1
  34. package/dist/driver/testArtifacts.d.ts +4 -4
  35. package/dist/driver/testArtifacts.js +2016 -1086
  36. package/dist/driver/testArtifacts.js.map +1 -1
  37. package/dist/errors/ClassNotAvailableError.js +1 -5
  38. package/dist/errors/ClassNotAvailableError.js.map +1 -1
  39. package/dist/errors/EntityConflictError.js +1 -5
  40. package/dist/errors/EntityConflictError.js.map +1 -1
  41. package/dist/errors/EntityInvalidDataError.d.ts +6 -0
  42. package/dist/errors/EntityInvalidDataError.js +8 -6
  43. package/dist/errors/EntityInvalidDataError.js.map +1 -1
  44. package/dist/errors/EntityIsSleepingReferenceError.js +1 -5
  45. package/dist/errors/EntityIsSleepingReferenceError.js.map +1 -1
  46. package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
  47. package/dist/errors/EntityUniqueConstraintError.js +7 -0
  48. package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
  49. package/dist/errors/HttpError.d.ts +5 -0
  50. package/dist/errors/HttpError.js +11 -0
  51. package/dist/errors/HttpError.js.map +1 -0
  52. package/dist/errors/InvalidParametersError.js +1 -5
  53. package/dist/errors/InvalidParametersError.js.map +1 -1
  54. package/dist/errors/InvalidStateError.d.ts +3 -0
  55. package/dist/errors/InvalidStateError.js +7 -0
  56. package/dist/errors/InvalidStateError.js.map +1 -0
  57. package/dist/errors/MethodFailedError.d.ts +3 -0
  58. package/dist/errors/MethodFailedError.js +7 -0
  59. package/dist/errors/MethodFailedError.js.map +1 -0
  60. package/dist/errors/NotConfiguredError.js +1 -5
  61. package/dist/errors/NotConfiguredError.js.map +1 -1
  62. package/dist/errors/QueryFailedError.d.ts +2 -1
  63. package/dist/errors/QueryFailedError.js +5 -6
  64. package/dist/errors/QueryFailedError.js.map +1 -1
  65. package/dist/errors/UnableToConnectError.js +1 -5
  66. package/dist/errors/UnableToConnectError.js.map +1 -1
  67. package/dist/errors/index.d.ts +12 -8
  68. package/dist/errors/index.js +12 -24
  69. package/dist/errors/index.js.map +1 -1
  70. package/dist/helpers/index.d.ts +1 -0
  71. package/dist/helpers/index.js +2 -0
  72. package/dist/helpers/index.js.map +1 -0
  73. package/dist/helpers/transaction.d.ts +15 -0
  74. package/dist/helpers/transaction.js +47 -0
  75. package/dist/helpers/transaction.js.map +1 -0
  76. package/dist/index.d.ts +13 -11
  77. package/dist/index.js +16 -34
  78. package/dist/index.js.map +1 -1
  79. package/dist/nymphJoiProps.d.ts +1 -1
  80. package/dist/nymphJoiProps.js +10 -15
  81. package/dist/nymphJoiProps.js.map +1 -1
  82. package/dist/testArtifacts.d.ts +21 -6
  83. package/dist/testArtifacts.js +124 -50
  84. package/dist/testArtifacts.js.map +1 -1
  85. package/dist/testMocks.d.ts +27 -12
  86. package/dist/testMocks.js +44 -33
  87. package/dist/testMocks.js.map +1 -1
  88. package/dist/utils.d.ts +5 -5
  89. package/dist/utils.js +106 -68
  90. package/dist/utils.js.map +1 -1
  91. package/jest.config.js +31 -5
  92. package/package.json +43 -24
  93. package/src/Entity.test.ts +73 -23
  94. package/src/Entity.ts +555 -169
  95. package/src/Entity.types.ts +102 -90
  96. package/src/Nymph.ts +930 -517
  97. package/src/Nymph.types.ts +145 -39
  98. package/src/conf/defaults.ts +34 -1
  99. package/src/conf/index.ts +50 -2
  100. package/src/decorators/index.ts +1 -0
  101. package/src/decorators/transactional.ts +63 -0
  102. package/src/driver/NymphDriver.ts +987 -417
  103. package/src/driver/index.ts +1 -3
  104. package/src/driver/testArtifacts.ts +2699 -1628
  105. package/src/errors/EntityUniqueConstraintError.ts +6 -0
  106. package/src/errors/HttpError.ts +12 -0
  107. package/src/errors/InvalidStateError.ts +6 -0
  108. package/src/errors/MethodFailedError.ts +6 -0
  109. package/src/errors/QueryFailedError.ts +3 -1
  110. package/src/errors/index.ts +16 -8
  111. package/src/helpers/index.ts +1 -0
  112. package/src/helpers/transaction.ts +65 -0
  113. package/src/index.ts +13 -11
  114. package/src/nymphJoiProps.ts +2 -2
  115. package/src/testArtifacts.ts +69 -20
  116. package/src/testMocks.ts +107 -41
  117. package/src/utils.ts +102 -67
  118. package/tsconfig.json +6 -3
  119. package/typedoc.json +4 -0
  120. package/dist/conf/d.d.ts +0 -6
  121. package/dist/conf/d.js +0 -3
  122. package/dist/conf/d.js.map +0 -1
  123. package/src/conf/d.ts +0 -24
package/dist/Entity.js CHANGED
@@ -1,32 +1,228 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const lodash_1 = require("lodash");
4
- const errors_1 = require("./errors");
5
- const utils_1 = require("./utils");
6
- class Entity {
7
- constructor(guid) {
8
- this.guid = null;
9
- this.cdate = null;
10
- this.mdate = null;
11
- this.tags = [];
12
- this.$isASleepingReference = false;
13
- this.$sleepingReference = null;
14
- this.$privateData = [];
15
- this.$protectedData = [];
16
- this.$protectedTags = [];
17
- this.$clientEnabledMethods = [];
18
- this.$skipAc = false;
19
- this.$originalAcValues = null;
1
+ import { difference, intersection, isEqual } from 'lodash-es';
2
+ import { guid } from '@nymphjs/guid';
3
+ import { EntityConflictError, EntityIsSleepingReferenceError, InvalidParametersError, InvalidStateError, MethodFailedError, } from './errors/index.js';
4
+ import { classNamesToEntityConstructors, entitiesToReferences, entityConstructorsToClassNames, referencesToEntities, uniqueStrings, } from './utils.js';
5
+ /**
6
+ * Database abstraction object.
7
+ *
8
+ * Provides a way to access, manipulate, and store data in Nymph.
9
+ *
10
+ * The GUID is not set until the entity is saved. GUIDs must be unique forever,
11
+ * even after deletion. It's the job of the Nymph DB driver to make sure no two
12
+ * entities ever have the same GUID. This is generally done by using a large
13
+ * randomly generated ID.
14
+ *
15
+ * Each entity class has an etype that determines which table(s) in the database
16
+ * it belongs to. If two entity classes have the same etype, their data will be
17
+ * stored in the same table(s). This isn't a good idea, however, because
18
+ * references to an entity store a class name, not an etype.
19
+ *
20
+ * Tags are used to classify entities. Where an etype is used to separate data
21
+ * by tables, tags can be used to separate entities within a table. You can
22
+ * define specific tags to be protected, meaning they cannot be added/removed
23
+ * from the client. It can be useful to allow user defined tags, such as for
24
+ * blog posts.
25
+ *
26
+ * Simply calling $delete() will not unset the entity. It will still take up
27
+ * memory. Likewise, simply calling unset will not delete the entity from the
28
+ * DB.
29
+ *
30
+ * Some notes about $equals() and $is(), the replacements for "==":
31
+ *
32
+ * The == operator will likely not give you the result you want, since two
33
+ * instances of the same entity will fail that check, even though they represent
34
+ * the same data in the database.
35
+ *
36
+ * $equals() performs a more strict comparison of the entity to another. Use
37
+ * $equals() instead of the == operator when you want to check both the entities
38
+ * they represent, and the data inside them. In order to return true for
39
+ * $equals(), the entity and object must meet the following criteria:
40
+ *
41
+ * - They must be entities.
42
+ * - They must have equal GUIDs, or both must have no GUID.
43
+ * - Their data and tags must be equal.
44
+ *
45
+ * $is() performs a less strict comparison of the entity to another. Use $is()
46
+ * instead of the == operator when the entity's data may have been changed, but
47
+ * you only care if they represent the same entity. In order to return true, the
48
+ * entity and object must meet the following criteria:
49
+ *
50
+ * - They must be entities.
51
+ * - They must have equal GUIDs, or both must have no GUID.
52
+ * - If they have no GUIDs, their data and tags must be equal.
53
+ *
54
+ * Some notes about saving entities in other entity's properties:
55
+ *
56
+ * Entities use references in the DB to store an entity in their properties. The
57
+ * reference is stored as an array with the values:
58
+ *
59
+ * - 0 => The string 'nymph_entity_reference'
60
+ * - 1 => The referenced entity's GUID.
61
+ * - 2 => The referenced entity's class name.
62
+ *
63
+ * Since the referenced entity's class name (meaning the `class` static
64
+ * property, not the name of the class itself) is stored in the reference on the
65
+ * parent entity, if you change the class name in an update, you need to
66
+ * reassign all referenced entities of that class and resave.
67
+ *
68
+ * When an entity is loaded, it does not request its referenced entities from
69
+ * Nymph. Instead, it creates instances without data called sleeping references.
70
+ * When you first access an entity's data, if it is a sleeping reference, it
71
+ * will fill its data from the DB. You can call clearCache() to turn all the
72
+ * entities back into sleeping references.
73
+ */
74
+ export default class Entity {
75
+ /**
76
+ * The instance of Nymph to use for queries.
77
+ */
78
+ static nymph = {};
79
+ /**
80
+ * A unique name for this type of entity used to separate its data from other
81
+ * types of entities in the database.
82
+ */
83
+ static ETYPE = 'entity';
84
+ /**
85
+ * The lookup name for this entity.
86
+ *
87
+ * This is used for reference arrays (and sleeping references) and client
88
+ * requests.
89
+ */
90
+ static class = 'Entity';
91
+ $nymph;
92
+ guid = null;
93
+ cdate = null;
94
+ mdate = null;
95
+ tags = [];
96
+ /**
97
+ * The data proxy handler.
98
+ */
99
+ $dataHandler;
100
+ /**
101
+ * The actual data store.
102
+ */
103
+ $dataStore;
104
+ /**
105
+ * The actual sdata store.
106
+ */
107
+ $sdata;
108
+ /**
109
+ * The data proxy object.
110
+ */
111
+ $data;
112
+ /**
113
+ * Whether this instance is a sleeping reference.
114
+ */
115
+ $isASleepingReference = false;
116
+ /**
117
+ * The reference to use to wake.
118
+ */
119
+ $sleepingReference = null;
120
+ /**
121
+ * A promise that resolved when the entity's data is wake.
122
+ */
123
+ $wakePromise = null;
124
+ /**
125
+ * Properties that will not be serialized into JSON with toJSON(). This
126
+ * can be considered a denylist, because these properties will not be set
127
+ * with incoming JSON.
128
+ *
129
+ * Clients CAN still determine what is in these properties, unless they are
130
+ * also listed in searchRestrictedData.
131
+ */
132
+ $privateData = [];
133
+ /**
134
+ * Whether this entity should publish changes to PubSub servers.
135
+ */
136
+ static pubSubEnabled = true;
137
+ /**
138
+ * Whether this entity should be accessible on the frontend through the REST
139
+ * server.
140
+ *
141
+ * If this is false, any request from the client that attempts to use this
142
+ * entity will fail.
143
+ */
144
+ static restEnabled = true;
145
+ /**
146
+ * Properties that will not be searchable from the frontend. If the frontend
147
+ * includes any of these properties in any of their clauses, they will be
148
+ * filtered out before the search is executed.
149
+ */
150
+ static searchRestrictedData = [];
151
+ /**
152
+ * Properties that can only be modified by server side code. They will still
153
+ * be visible on the frontend, unlike $privateData, but any changes to them
154
+ * that come from the frontend will be ignored.
155
+ *
156
+ * In addition to what's listed here, all of the access control properties
157
+ * will be included when Tilmeld is being used. These are:
158
+ *
159
+ * - acUser
160
+ * - acGroup
161
+ * - acOther
162
+ * - acRead
163
+ * - acWrite
164
+ * - acFull
165
+ * - user
166
+ * - group
167
+ *
168
+ * You should modify these through client enabled methods or the $save method
169
+ * instead, for safety.
170
+ */
171
+ $protectedData = [];
172
+ /**
173
+ * If this is defined, then it lists the only properties that will be
174
+ * accepted from incoming JSON. Any other properties will be ignored.
175
+ *
176
+ * If you use an allowlist, you don't need to use protectedData, since you
177
+ * can simply leave those entries out of allowlistData.
178
+ */
179
+ $allowlistData;
180
+ /**
181
+ * Tags that can only be added/removed by server side code. They will still be
182
+ * visible on the frontend, but any changes to them that come from the
183
+ * frontend will be ignored.
184
+ */
185
+ $protectedTags = [];
186
+ /**
187
+ * If this is defined, then it lists the only tags that will be accepted from
188
+ * incoming JSON. Any other tags will be ignored.
189
+ */
190
+ $allowlistTags;
191
+ /**
192
+ * The names of methods allowed to be called by the frontend with serverCall.
193
+ */
194
+ $clientEnabledMethods = [];
195
+ /**
196
+ * The names of static methods allowed to be called by the frontend with
197
+ * serverCallStatic.
198
+ */
199
+ static clientEnabledStaticMethods = [];
200
+ /**
201
+ * Whether to use "skipAc" when accessing entity references.
202
+ */
203
+ $skipAc = false;
204
+ /**
205
+ * The AC properties' values when the entity was loaded.
206
+ */
207
+ $originalAcValues = null;
208
+ /**
209
+ * This is used to hold a generated GUID for a new entity.
210
+ */
211
+ $guaranteedGUID = null;
212
+ /**
213
+ * Initialize an entity.
214
+ */
215
+ constructor(..._rest) {
20
216
  this.$nymph = this.constructor.nymph;
21
217
  this.$dataHandler = {
22
218
  has: (data, name) => {
23
- this.$referenceWake();
219
+ this.$check();
24
220
  return name in data || name in this.$sdata;
25
221
  },
26
222
  get: (data, name) => {
27
- this.$referenceWake();
223
+ this.$check();
28
224
  if (this.$sdata.hasOwnProperty(name)) {
29
- data[name] = (0, utils_1.referencesToEntities)(JSON.parse(this.$sdata[name]), this.$nymph, this.$skipAc);
225
+ data[name] = referencesToEntities(classNamesToEntityConstructors(this.$nymph, JSON.parse(this.$sdata[name]), false), this.$nymph, this.$skipAc);
30
226
  delete this.$sdata[name];
31
227
  }
32
228
  if (data.hasOwnProperty(name)) {
@@ -35,7 +231,7 @@ class Entity {
35
231
  return undefined;
36
232
  },
37
233
  set: (data, name, value) => {
38
- this.$referenceWake();
234
+ this.$check();
39
235
  if (this.$sdata.hasOwnProperty(name)) {
40
236
  delete this.$sdata[name];
41
237
  }
@@ -43,7 +239,7 @@ class Entity {
43
239
  return true;
44
240
  },
45
241
  deleteProperty: (data, name) => {
46
- this.$referenceWake();
242
+ this.$check();
47
243
  if (this.$sdata.hasOwnProperty(name)) {
48
244
  return delete this.$sdata[name];
49
245
  }
@@ -53,7 +249,7 @@ class Entity {
53
249
  return true;
54
250
  },
55
251
  defineProperty: (data, name, descriptor) => {
56
- this.$referenceWake();
252
+ this.$check();
57
253
  if (this.$sdata.hasOwnProperty(name)) {
58
254
  delete this.$sdata[name];
59
255
  }
@@ -61,31 +257,21 @@ class Entity {
61
257
  return true;
62
258
  },
63
259
  getOwnPropertyDescriptor: (data, name) => {
64
- this.$referenceWake();
260
+ this.$check();
65
261
  if (this.$sdata.hasOwnProperty(name)) {
66
- data[name] = (0, utils_1.referencesToEntities)(JSON.parse(this.$sdata[name]), this.$nymph, this.$skipAc);
262
+ data[name] = referencesToEntities(classNamesToEntityConstructors(this.$nymph, JSON.parse(this.$sdata[name]), false), this.$nymph, this.$skipAc);
67
263
  delete this.$sdata[name];
68
264
  }
69
265
  return Object.getOwnPropertyDescriptor(data, name);
70
266
  },
71
267
  ownKeys: (data) => {
72
- this.$referenceWake();
268
+ this.$check();
73
269
  return Object.getOwnPropertyNames(data).concat(Object.getOwnPropertyNames(this.$sdata));
74
270
  },
75
271
  };
76
272
  this.$dataStore = {};
77
273
  this.$sdata = {};
78
274
  this.$data = new Proxy(this.$dataStore, this.$dataHandler);
79
- if (guid != null) {
80
- const entity = this.$nymph.driver.getEntitySync({ class: this.constructor }, { type: '&', guid });
81
- if (entity) {
82
- this.guid = entity.guid;
83
- this.tags = entity.tags;
84
- this.cdate = entity.cdate;
85
- this.mdate = entity.mdate;
86
- this.$putData(entity.$getData(), entity.$getSData());
87
- }
88
- }
89
275
  return new Proxy(this, {
90
276
  has: (entity, name) => {
91
277
  if (typeof name !== 'string' ||
@@ -93,7 +279,7 @@ class Entity {
93
279
  name.substring(0, 1) === '$') {
94
280
  return name in entity;
95
281
  }
96
- this.$referenceWake();
282
+ this.$check();
97
283
  return name in entity.$data;
98
284
  },
99
285
  get: (entity, name) => {
@@ -101,11 +287,11 @@ class Entity {
101
287
  name in entity ||
102
288
  name.substring(0, 1) === '$') {
103
289
  if (name === 'tags' || name === 'cdate' || name === 'mdate') {
104
- this.$referenceWake();
290
+ this.$check();
105
291
  }
106
292
  return entity[name];
107
293
  }
108
- this.$referenceWake();
294
+ this.$check();
109
295
  if (name in entity.$data) {
110
296
  return entity.$data[name];
111
297
  }
@@ -116,12 +302,12 @@ class Entity {
116
302
  name in entity ||
117
303
  name.substring(0, 1) === '$') {
118
304
  if (name === 'tags' || name === 'cdate' || name === 'mdate') {
119
- this.$referenceWake();
305
+ this.$check();
120
306
  }
121
307
  entity[name] = value;
122
308
  }
123
309
  else {
124
- this.$referenceWake();
310
+ this.$check();
125
311
  entity.$data[name] = value;
126
312
  }
127
313
  return true;
@@ -131,7 +317,7 @@ class Entity {
131
317
  return delete entity[name];
132
318
  }
133
319
  else if (name in entity.$data) {
134
- this.$referenceWake();
320
+ this.$check();
135
321
  return delete entity.$data[name];
136
322
  }
137
323
  return true;
@@ -144,12 +330,12 @@ class Entity {
144
330
  name in entity ||
145
331
  name.substring(0, 1) === '$') {
146
332
  if (name === 'tags' || name === 'cdate' || name === 'mdate') {
147
- this.$referenceWake();
333
+ this.$check();
148
334
  }
149
335
  Object.defineProperty(entity, name, descriptor);
150
336
  }
151
337
  else {
152
- this.$referenceWake();
338
+ this.$check();
153
339
  Object.defineProperty(entity.$data, name, descriptor);
154
340
  }
155
341
  return true;
@@ -159,21 +345,28 @@ class Entity {
159
345
  name in entity ||
160
346
  name.substring(0, 1) === '$') {
161
347
  if (name === 'tags' || name === 'cdate' || name === 'mdate') {
162
- this.$referenceWake();
348
+ this.$check();
163
349
  }
164
350
  return Object.getOwnPropertyDescriptor(entity, name);
165
351
  }
166
352
  else {
167
- this.$referenceWake();
353
+ this.$check();
168
354
  return Object.getOwnPropertyDescriptor(entity.$data, name);
169
355
  }
170
356
  },
171
357
  ownKeys: (entity) => {
172
- this.$referenceWake();
358
+ this.$check();
173
359
  return Object.getOwnPropertyNames(entity).concat(Object.getOwnPropertyNames(entity.$data));
174
360
  },
175
361
  });
176
362
  }
363
+ /**
364
+ * Create or retrieve a new entity instance.
365
+ *
366
+ * Note that this will always return an entity, even if the GUID is not found.
367
+ *
368
+ * @param guid An optional GUID to retrieve.
369
+ */
177
370
  static async factory(guid) {
178
371
  const entity = new this();
179
372
  if (guid != null) {
@@ -186,43 +379,143 @@ class Entity {
186
379
  }
187
380
  return entity;
188
381
  }
189
- static factorySync(guid) {
190
- return new this(guid);
382
+ /**
383
+ * Create a new entity instance.
384
+ */
385
+ static factorySync() {
386
+ return new this();
191
387
  }
388
+ /**
389
+ * Create a new sleeping reference instance.
390
+ *
391
+ * Sleeping references won't retrieve their data from the database until they
392
+ * are readied with `$wake()` or a parent's `$wakeAll()`.
393
+ *
394
+ * @param reference The Nymph Entity Reference to use to wake.
395
+ * @returns The new instance.
396
+ */
192
397
  static factoryReference(reference) {
193
398
  const entity = new this();
194
399
  entity.$referenceSleep(reference);
195
400
  return entity;
196
401
  }
402
+ /**
403
+ * Get an array of strings that **must** be unique across the current etype.
404
+ *
405
+ * When you try to save another entity with any of the same unique strings,
406
+ * Nymph will throw an error.
407
+ *
408
+ * The default implementation of this static method instantiates the entity,
409
+ * assigns all of the given data, then calls `$getUniques` and returns its
410
+ * output. This can have a performance impact if a lot of extra processing
411
+ * happens during any of these steps. You can override this method to
412
+ * calculate the unique strings faster, but you must return the same strings
413
+ * that would be returned by `$getUniques`.
414
+ *
415
+ * @returns Resolves to an array of entity's unique constraint strings.
416
+ */
417
+ static async getUniques({ guid, cdate, mdate, tags, data, sdata, }) {
418
+ const entity = new this();
419
+ if (guid != null) {
420
+ entity.guid = guid;
421
+ }
422
+ if (cdate != null) {
423
+ entity.cdate = cdate;
424
+ }
425
+ if (mdate != null) {
426
+ entity.mdate = mdate;
427
+ }
428
+ entity.tags = tags;
429
+ entity.$putData(data, sdata);
430
+ return await entity.$getUniques();
431
+ }
432
+ /**
433
+ * Get a string for full text search for one of an entity's properties.
434
+ *
435
+ * The result will be tokenized and stored as the full text search index for
436
+ * use with "search" clauses.
437
+ *
438
+ * Return null to not include any tokens in the full text search storage.
439
+ *
440
+ * You shouldn't use any other entity data to transform the text, as it won't
441
+ * always be available. This function is meant for things like stripping HTML
442
+ * tags.
443
+ *
444
+ * @returns By default, returns the value if it is a string.
445
+ */
446
+ static getFTSText(_name, value) {
447
+ if (typeof value === 'string') {
448
+ return value;
449
+ }
450
+ return null;
451
+ }
197
452
  toJSON() {
198
453
  if (this.$isASleepingReference) {
199
454
  return this.$sleepingReference;
200
455
  }
201
456
  const obj = {
202
- class: this.constructor.class,
457
+ class: entityConstructorsToClassNames(this.constructor),
203
458
  guid: this.guid,
204
459
  cdate: this.cdate,
205
460
  mdate: this.mdate,
206
461
  tags: [...this.tags],
207
462
  data: {},
208
463
  };
209
- const data = this.$getData(true);
210
- for (const key in data) {
464
+ for (const key of [
465
+ ...Object.keys(this.$dataStore),
466
+ ...Object.keys(this.$sdata),
467
+ ]) {
211
468
  if (this.$privateData.indexOf(key) === -1) {
212
- obj.data[key] = (0, utils_1.entitiesToReferences)(data[key]);
469
+ obj.data[key] = entityConstructorsToClassNames(entitiesToReferences(this.$data[key], true));
213
470
  }
214
471
  }
215
472
  return obj;
216
473
  }
474
+ $setNymph(nymph) {
475
+ this.$nymph = nymph;
476
+ if (!this.$asleep()) {
477
+ const recurseData = (data) => {
478
+ if (Array.isArray(data)) {
479
+ for (let name in data) {
480
+ recurseData(data[name]);
481
+ }
482
+ }
483
+ else if (data instanceof Entity) {
484
+ if (data.$nymph !== nymph) {
485
+ data.$setNymph(nymph);
486
+ }
487
+ }
488
+ else if (typeof data === 'function' &&
489
+ data.prototype instanceof Entity) {
490
+ data.nymph = nymph;
491
+ }
492
+ else if (typeof data === 'object') {
493
+ for (let name in data) {
494
+ recurseData(data[name]);
495
+ }
496
+ }
497
+ };
498
+ recurseData(this.$data);
499
+ }
500
+ }
501
+ $getGuaranteedGUID() {
502
+ if (this.guid !== null) {
503
+ return this.guid;
504
+ }
505
+ if (this.$guaranteedGUID == null) {
506
+ this.$guaranteedGUID = guid();
507
+ }
508
+ return this.$guaranteedGUID;
509
+ }
217
510
  $addTag(...tags) {
218
- this.$referenceWake();
511
+ this.$check();
219
512
  if (tags.length < 1) {
220
513
  return;
221
514
  }
222
- this.tags = (0, utils_1.uniqueStrings)([...this.tags, ...tags]);
515
+ this.tags = uniqueStrings([...this.tags, ...tags]);
223
516
  }
224
517
  $arraySearch(array, strict = false) {
225
- this.$referenceWake();
518
+ this.$check();
226
519
  if (!Array.isArray(array)) {
227
520
  return -1;
228
521
  }
@@ -235,18 +528,20 @@ class Entity {
235
528
  return -1;
236
529
  }
237
530
  $clearCache() {
238
- this.$referenceWake();
239
- this.$putData(this.$getData(), this.$getSData());
531
+ this.$check();
532
+ this.$putData(this.$getData(false), this.$getSData());
240
533
  }
241
534
  $getClientEnabledMethods() {
242
535
  return this.$clientEnabledMethods;
243
536
  }
244
537
  async $delete() {
245
- this.$referenceWake();
246
- return await this.$nymph.deleteEntity(this);
538
+ await this.$wake();
539
+ if (!(await this.$nymph.deleteEntity(this))) {
540
+ throw new MethodFailedError('Failed to delete entity.');
541
+ }
247
542
  }
248
543
  $equals(object) {
249
- this.$referenceWake();
544
+ this.$check();
250
545
  if (!(object instanceof Entity)) {
251
546
  return false;
252
547
  }
@@ -263,41 +558,79 @@ class Entity {
263
558
  }
264
559
  const obTags = [...object.tags].sort();
265
560
  const myTags = [...this.tags].sort();
266
- if (!(0, lodash_1.isEqual)(obTags, myTags)) {
561
+ if (!isEqual(obTags, myTags)) {
267
562
  return false;
268
563
  }
269
- const obData = object.$getData(true);
270
- const myData = this.$getData(true);
271
- return (0, lodash_1.isEqual)(obData, myData);
564
+ const obData = entityConstructorsToClassNames(entitiesToReferences(object.$getData(true), true));
565
+ const myData = entityConstructorsToClassNames(entitiesToReferences(this.$getData(true), true));
566
+ return isEqual(obData, myData);
272
567
  }
273
568
  $getData(includeSData = false) {
274
- this.$referenceWake();
569
+ this.$check();
275
570
  if (includeSData) {
571
+ // Access all the serialized properties to initialize them.
276
572
  for (const key in this.$sdata) {
277
573
  const _unused = this[key];
278
574
  }
279
575
  }
280
- return (0, utils_1.entitiesToReferences)({ ...this.$dataStore });
576
+ return { ...this.$dataStore };
281
577
  }
282
578
  $getSData() {
283
- this.$referenceWake();
579
+ this.$check();
284
580
  return this.$sdata;
285
581
  }
582
+ async $getUniques() {
583
+ return [];
584
+ }
286
585
  $getOriginalAcValues() {
287
- this.$referenceWake();
288
- return (this.$originalAcValues ?? {
289
- user: this.$data.user,
290
- group: this.$data.group,
291
- acUser: this.$data.acUser,
292
- acGroup: this.$data.acGroup,
293
- acOther: this.$data.acOther,
294
- acRead: this.$data.acRead,
295
- acWrite: this.$data.acWrite,
296
- acFull: this.$data.acFull,
297
- });
586
+ this.$check();
587
+ return this.$originalAcValues ?? this.$getCurrentAcValues();
588
+ }
589
+ $getCurrentAcValues() {
590
+ this.$check();
591
+ return {
592
+ user: this.$getAcUid(),
593
+ group: this.$getAcGid(),
594
+ acUser: this.$data.acUser ?? null,
595
+ acGroup: this.$data.acGroup ?? null,
596
+ acOther: this.$data.acOther ?? null,
597
+ acRead: this.$getAcReadIds(),
598
+ acWrite: this.$getAcWriteIds(),
599
+ acFull: this.$getAcFullIds(),
600
+ };
601
+ }
602
+ $getAcUid() {
603
+ if ('user' in this.$sdata) {
604
+ const userValue = JSON.parse(this.$sdata.user);
605
+ if (Array.isArray(userValue) &&
606
+ userValue[0] === 'nymph_entity_reference') {
607
+ return userValue[1];
608
+ }
609
+ }
610
+ return (this.$data.user?.guid ?? null);
611
+ }
612
+ $getAcGid() {
613
+ if ('group' in this.$sdata) {
614
+ const groupValue = JSON.parse(this.$sdata.group);
615
+ if (Array.isArray(groupValue) &&
616
+ groupValue[0] === 'nymph_entity_reference') {
617
+ return groupValue[1];
618
+ }
619
+ }
620
+ return (this.$data.group?.guid ?? null);
621
+ }
622
+ $getAcReadIds() {
623
+ return (this.$data.acRead?.map((entity) => typeof entity === 'string' ? entity : entity.guid) ?? null);
624
+ }
625
+ $getAcWriteIds() {
626
+ return (this.$data.acWrite?.map((entity) => typeof entity === 'string' ? entity : entity.guid) ?? null);
627
+ }
628
+ $getAcFullIds() {
629
+ return (this.$data.acFull?.map((entity) => typeof entity === 'string' ? entity : entity.guid) ?? null);
298
630
  }
299
631
  $getValidatable() {
300
- this.$referenceWake();
632
+ this.$check();
633
+ // Access all the serialized properties to initialize them.
301
634
  for (const key in this.$sdata) {
302
635
  const _unused = this[key];
303
636
  }
@@ -306,15 +639,15 @@ class Entity {
306
639
  cdate: this.cdate,
307
640
  mdate: this.mdate,
308
641
  tags: this.tags,
309
- ...(0, utils_1.referencesToEntities)(this.$dataStore, this.$nymph, this.$skipAc),
642
+ ...this.$dataStore,
310
643
  };
311
644
  }
312
645
  $getTags() {
313
- this.$referenceWake();
646
+ this.$check();
314
647
  return this.tags;
315
648
  }
316
649
  $hasTag(...tags) {
317
- this.$referenceWake();
650
+ this.$check();
318
651
  if (!tags.length) {
319
652
  return false;
320
653
  }
@@ -332,44 +665,50 @@ class Entity {
332
665
  if (!(object instanceof Entity)) {
333
666
  return false;
334
667
  }
335
- if (this.guid || object.guid) {
668
+ if (this === object) {
669
+ return true;
670
+ }
671
+ if (this.guid != null || object.guid != null) {
336
672
  return this.guid === object.guid;
337
673
  }
338
- this.$referenceWake();
674
+ this.$check();
339
675
  if (typeof object.$getData !== 'function') {
340
676
  return false;
341
677
  }
342
678
  else {
343
679
  const obTags = [...object.tags].sort();
344
680
  const myTags = [...this.tags].sort();
345
- if (!(0, lodash_1.isEqual)(obTags, myTags)) {
681
+ if (!isEqual(obTags, myTags)) {
346
682
  return false;
347
683
  }
348
- const obData = object.$getData(true);
349
- const myData = this.$getData(true);
350
- return (0, lodash_1.isEqual)(obData, myData);
684
+ const obData = entityConstructorsToClassNames(entitiesToReferences(object.$getData(true), true));
685
+ const myData = entityConstructorsToClassNames(entitiesToReferences(this.$getData(true), true));
686
+ return isEqual(obData, myData);
351
687
  }
352
688
  }
353
689
  $jsonAcceptData(input, allowConflict = false) {
354
- this.$referenceWake();
690
+ this.$check();
355
691
  if (this.guid != input.guid) {
356
- throw new errors_1.EntityConflictError('Tried to accept JSON input for the wrong entity.');
692
+ throw new EntityConflictError('Tried to accept JSON input for the wrong entity.');
357
693
  }
694
+ // Accept the modified date.
358
695
  const mdate = input.mdate ?? 0;
359
696
  const thismdate = this.mdate ?? 0;
360
697
  if (mdate < thismdate && !allowConflict) {
361
- throw new errors_1.EntityConflictError('This entity is newer than JSON input.');
698
+ throw new EntityConflictError('This entity is newer than JSON input.');
362
699
  }
363
700
  this.mdate = input.mdate;
701
+ // Accept the tags.
364
702
  const currentTags = this.$getTags();
365
- const protectedTags = (0, lodash_1.intersection)(this.$protectedTags, currentTags);
366
- let tags = (0, lodash_1.difference)(input.tags, this.$protectedTags);
703
+ const protectedTags = intersection(this.$protectedTags, currentTags);
704
+ let tags = difference(input.tags, this.$protectedTags);
367
705
  if (this.$allowlistTags != null) {
368
- tags = (0, lodash_1.intersection)(tags, this.$allowlistTags);
706
+ tags = intersection(tags, this.$allowlistTags);
369
707
  }
370
708
  this.$removeTag(...currentTags);
371
709
  this.$addTag(...protectedTags, ...tags);
372
- const data = input.data;
710
+ // Accept the data.
711
+ const data = { ...input.data };
373
712
  const privateData = {};
374
713
  for (const name of this.$privateData) {
375
714
  if (name in this.$data) {
@@ -381,10 +720,21 @@ class Entity {
381
720
  }
382
721
  const protectedData = {};
383
722
  const protectedProps = [...this.$protectedData];
384
- if (this.$nymph.tilmeld &&
385
- !this.$nymph.tilmeld.gatekeeper('tilmeld/admin')) {
386
- protectedProps.push('user');
387
- protectedProps.push('group');
723
+ if (this.$nymph.tilmeld) {
724
+ protectedProps.push('acUser');
725
+ protectedProps.push('acGroup');
726
+ protectedProps.push('acOther');
727
+ protectedProps.push('acRead');
728
+ protectedProps.push('acWrite');
729
+ protectedProps.push('acFull');
730
+ if ((this.constructor.class !== 'User' &&
731
+ this.constructor.class !== 'Group') ||
732
+ !this.$nymph.tilmeld.currentUser ||
733
+ (!this.$nymph.tilmeld.currentUser.abilities?.includes('tilmeld/admin') &&
734
+ !this.$nymph.tilmeld.currentUser.abilities?.includes('system/admin'))) {
735
+ protectedProps.push('user');
736
+ protectedProps.push('group');
737
+ }
388
738
  }
389
739
  for (const name of protectedProps) {
390
740
  if (name in this.$data) {
@@ -414,29 +764,47 @@ class Entity {
414
764
  });
415
765
  }
416
766
  $jsonAcceptPatch(patch, allowConflict = false) {
417
- this.$referenceWake();
767
+ this.$check();
418
768
  if (this.guid != patch.guid) {
419
- throw new errors_1.EntityConflictError('Tried to accept JSON patch for the wrong entity.');
769
+ throw new EntityConflictError('Tried to accept JSON patch for the wrong entity.');
420
770
  }
771
+ // Accept the modified date.
421
772
  const mdate = patch.mdate ?? 0;
422
773
  const thismdate = this.mdate ?? 0;
423
774
  if (mdate < thismdate && !allowConflict) {
424
- throw new errors_1.EntityConflictError('This entity is newer than JSON patch.');
775
+ throw new EntityConflictError('This entity is newer than JSON patch.');
425
776
  }
426
777
  this.mdate = patch.mdate;
778
+ const protectedProps = [...this.$protectedData];
779
+ if (this.$nymph.tilmeld) {
780
+ protectedProps.push('acUser');
781
+ protectedProps.push('acGroup');
782
+ protectedProps.push('acOther');
783
+ protectedProps.push('acRead');
784
+ protectedProps.push('acWrite');
785
+ protectedProps.push('acFull');
786
+ if ((this.constructor.class !== 'User' &&
787
+ this.constructor.class !== 'Group') ||
788
+ !this.$nymph.tilmeld.currentUser ||
789
+ (!this.$nymph.tilmeld.currentUser.abilities?.includes('tilmeld/admin') &&
790
+ !this.$nymph.tilmeld.currentUser.abilities?.includes('system/admin'))) {
791
+ protectedProps.push('user');
792
+ protectedProps.push('group');
793
+ }
794
+ }
427
795
  for (const name in patch.set) {
428
796
  if ((this.$allowlistData != null &&
429
797
  this.$allowlistData.indexOf(name) === -1) ||
430
- this.$protectedData.indexOf(name) !== -1 ||
798
+ protectedProps.indexOf(name) !== -1 ||
431
799
  this.$privateData.indexOf(name) !== -1) {
432
800
  continue;
433
801
  }
434
- this.$data[name] = (0, utils_1.referencesToEntities)(patch.set[name], this.$nymph, this.$skipAc);
802
+ this.$data[name] = patch.set[name];
435
803
  }
436
804
  for (const name of patch.unset) {
437
805
  if ((this.$allowlistData != null &&
438
806
  this.$allowlistData.indexOf(name) === -1) ||
439
- this.$protectedData.indexOf(name) !== -1 ||
807
+ protectedProps.indexOf(name) !== -1 ||
440
808
  this.$privateData.indexOf(name) !== -1) {
441
809
  continue;
442
810
  }
@@ -459,63 +827,154 @@ class Entity {
459
827
  this.$removeTag(tag);
460
828
  }
461
829
  }
462
- $putData(data, sdata) {
463
- this.$referenceWake();
464
- const mySdata = sdata ?? this.$getSData();
465
- for (const name in data) {
466
- delete mySdata[name];
467
- }
830
+ $putData(data, sdata, _source) {
831
+ this.$check();
468
832
  for (const name in this.$dataStore) {
469
833
  delete this.$dataStore[name];
470
834
  }
471
835
  for (const name in data) {
472
- this.$dataStore[name] = (0, utils_1.referencesToEntities)(data[name], this.$nymph, this.$skipAc);
836
+ this.$dataStore[name] = data[name];
473
837
  }
474
- this.$sdata = mySdata;
838
+ this.$sdata = sdata ?? {};
839
+ // Set original AC values if not set..
475
840
  if (this.$originalAcValues == null) {
476
- this.$originalAcValues = this.$getOriginalAcValues();
841
+ this.$originalAcValues = this.$getCurrentAcValues();
477
842
  }
478
843
  }
844
+ /**
845
+ * Set up a sleeping reference.
846
+ * @param array $reference The reference to use to wake.
847
+ */
479
848
  $referenceSleep(reference) {
480
849
  if (reference.length !== 3 ||
481
850
  reference[0] !== 'nymph_entity_reference' ||
482
851
  typeof reference[1] !== 'string' ||
483
852
  typeof reference[2] !== 'string') {
484
- throw new errors_1.InvalidParametersError('referenceSleep expects parameter 1 to be a valid Nymph entity ' +
853
+ throw new InvalidParametersError('referenceSleep expects parameter 1 to be a valid Nymph entity ' +
485
854
  'reference.');
486
855
  }
487
856
  const thisClass = this.constructor.class;
488
857
  if (reference[2] !== thisClass) {
489
- throw new errors_1.InvalidParametersError('referenceSleep can only be called with an entity reference of the ' +
858
+ throw new InvalidParametersError('referenceSleep can only be called with an entity reference of the ' +
490
859
  `same class. Given class: ${reference[2]}; this class: ${thisClass}.`);
491
860
  }
492
861
  this.$isASleepingReference = true;
493
862
  this.guid = reference[1];
494
863
  this.$sleepingReference = reference;
495
864
  }
496
- $referenceWake() {
497
- if (!this.$isASleepingReference || this.$sleepingReference == null) {
498
- return true;
499
- }
500
- const EntityClass = this.$nymph.getEntityClass(this.$sleepingReference[2]);
501
- const entity = this.$nymph.driver.getEntitySync({
502
- class: EntityClass,
503
- skipAc: this.$skipAc,
504
- }, { type: '&', guid: this.$sleepingReference[1] });
505
- if (entity == null) {
506
- return false;
865
+ /**
866
+ * Check if this is a sleeping reference and throw an error if so.
867
+ */
868
+ $check() {
869
+ if (this.$isASleepingReference || this.$sleepingReference != null) {
870
+ throw new EntityIsSleepingReferenceError('This entity is in a sleeping reference state. You must use .$wake() to wake it.');
507
871
  }
508
- this.$isASleepingReference = false;
509
- this.$sleepingReference = null;
510
- this.guid = entity.guid;
511
- this.tags = entity.tags;
512
- this.cdate = entity.cdate;
513
- this.mdate = entity.mdate;
514
- this.$putData(entity.$getData(), entity.$getSData());
515
- return true;
872
+ }
873
+ /**
874
+ * Check if this is a sleeping reference.
875
+ */
876
+ $asleep() {
877
+ return this.$isASleepingReference || this.$sleepingReference != null;
878
+ }
879
+ /**
880
+ * Wake from a sleeping reference.
881
+ */
882
+ $wake() {
883
+ if (!this.$isASleepingReference || this.$sleepingReference == null) {
884
+ this.$wakePromise = null;
885
+ return Promise.resolve(this);
886
+ }
887
+ if (this.$sleepingReference?.[1] == null) {
888
+ throw new InvalidStateError('Tried to wake a sleeping reference with no GUID.');
889
+ }
890
+ if (!this.$wakePromise) {
891
+ const EntityClass = this.$nymph.getEntityClass(this.$sleepingReference[2]);
892
+ this.$wakePromise = this.$nymph
893
+ .getEntity({
894
+ class: EntityClass,
895
+ skipAc: this.$skipAc,
896
+ }, { type: '&', guid: this.$sleepingReference[1] })
897
+ .then((entity) => {
898
+ if (entity == null || entity.guid == null) {
899
+ return Promise.reject(new InvalidStateError('The sleeping reference could not be retrieved.'));
900
+ }
901
+ this.$isASleepingReference = false;
902
+ this.$sleepingReference = null;
903
+ this.guid = entity.guid;
904
+ this.tags = entity.tags;
905
+ this.cdate = entity.cdate;
906
+ this.mdate = entity.mdate;
907
+ this.$putData(entity.$getData(false), entity.$getSData(), 'server');
908
+ return this;
909
+ })
910
+ .finally(() => {
911
+ this.$wakePromise = null;
912
+ });
913
+ }
914
+ return this.$wakePromise;
915
+ }
916
+ $wakeAll(level) {
917
+ return new Promise((resolve, reject) => {
918
+ // Run this once this entity is wake.
919
+ const wakeProps = () => {
920
+ let newLevel;
921
+ // If level is undefined, keep going forever, otherwise, stop once we've
922
+ // gone deep enough.
923
+ if (level !== undefined) {
924
+ newLevel = level - 1;
925
+ }
926
+ if (newLevel !== undefined && newLevel < 0) {
927
+ resolve(this);
928
+ return;
929
+ }
930
+ const promises = [];
931
+ // Go through data looking for entities to wake.
932
+ const walkData = (data) => {
933
+ if (data == null) {
934
+ return;
935
+ }
936
+ else if (typeof data === 'function' &&
937
+ data.prototype instanceof Entity) {
938
+ // Ignore this, it is an entity class.
939
+ return;
940
+ }
941
+ else if (data instanceof Entity) {
942
+ // Wake it up.
943
+ if (data.$isASleepingReference) {
944
+ promises.push(data.$wakeAll(newLevel));
945
+ }
946
+ }
947
+ else if (Array.isArray(data)) {
948
+ // Recurse into lower arrays.
949
+ for (let i = 0; i < data.length; i++) {
950
+ walkData(data[i]);
951
+ }
952
+ }
953
+ else if (data instanceof Object) {
954
+ // Recurse into objects.
955
+ for (let [key, value] of Object.entries(data)) {
956
+ walkData(value);
957
+ }
958
+ }
959
+ };
960
+ walkData(this.$data);
961
+ if (promises.length) {
962
+ Promise.all(promises).then(() => resolve(this), (errObj) => reject(errObj));
963
+ }
964
+ else {
965
+ resolve(this);
966
+ }
967
+ };
968
+ if (this.$isASleepingReference) {
969
+ this.$wake().then(wakeProps, (errObj) => reject(errObj));
970
+ }
971
+ else {
972
+ wakeProps();
973
+ }
974
+ });
516
975
  }
517
976
  async $refresh() {
518
- this.$referenceWake();
977
+ await this.$wake();
519
978
  if (this.guid == null) {
520
979
  return false;
521
980
  }
@@ -525,32 +984,34 @@ class Entity {
525
984
  skipAc: this.$skipAc,
526
985
  }, { type: '&', guid: this.guid });
527
986
  if (refresh == null) {
528
- return 0;
987
+ throw new MethodFailedError("The entity's data could not be refreshed.");
529
988
  }
530
989
  this.tags = refresh.tags;
531
990
  this.cdate = refresh.cdate;
532
991
  this.mdate = refresh.mdate;
533
- this.$putData(refresh.$getData(), refresh.$getSData());
992
+ this.$putData(refresh.$getData(false), refresh.$getSData(), 'server');
534
993
  return true;
535
994
  }
536
995
  $removeTag(...tags) {
537
- this.$referenceWake();
538
- this.tags = (0, lodash_1.difference)(this.tags, tags);
996
+ this.$check();
997
+ this.tags = difference(this.tags, tags);
539
998
  }
540
999
  async $save() {
541
- this.$referenceWake();
542
- return await this.$nymph.saveEntity(this);
1000
+ await this.$wake();
1001
+ if (!(await this.$nymph.saveEntity(this))) {
1002
+ throw new MethodFailedError('Failed to save entity.');
1003
+ }
543
1004
  }
544
- $toReference() {
1005
+ $toReference(existingOnly) {
545
1006
  if (this.$isASleepingReference && this.$sleepingReference != null) {
546
1007
  return this.$sleepingReference;
547
1008
  }
548
- if (this.guid == null) {
1009
+ if (existingOnly && this.guid == null) {
549
1010
  return this;
550
1011
  }
551
1012
  return [
552
1013
  'nymph_entity_reference',
553
- this.guid,
1014
+ this.$getGuaranteedGUID(),
554
1015
  this.constructor.class,
555
1016
  ];
556
1017
  }
@@ -558,10 +1019,4 @@ class Entity {
558
1019
  this.$skipAc = !!skipAc;
559
1020
  }
560
1021
  }
561
- exports.default = Entity;
562
- Entity.nymph = {};
563
- Entity.ETYPE = 'entity';
564
- Entity.class = 'Entity';
565
- Entity.searchRestrictedData = [];
566
- Entity.clientEnabledStaticMethods = [];
567
1022
  //# sourceMappingURL=Entity.js.map