@prestizni-software/server-dem 0.5.6 → 0.5.8
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/dist/AutoUpdateManagerClass.d.ts +33 -18
- package/dist/AutoUpdateManagerClass.js +15 -27
- package/dist/AutoUpdateManagerClass.js.map +1 -1
- package/dist/AutoUpdateServerManagerClass.d.ts +61 -79
- package/dist/AutoUpdateServerManagerClass.js +344 -154
- package/dist/AutoUpdateServerManagerClass.js.map +1 -1
- package/dist/AutoUpdatedClientObjectClass.d.ts +33 -39
- package/dist/AutoUpdatedClientObjectClass.js +205 -289
- package/dist/AutoUpdatedClientObjectClass.js.map +1 -1
- package/dist/AutoUpdatedServerObjectClass.d.ts +10 -15
- package/dist/AutoUpdatedServerObjectClass.js +92 -99
- package/dist/AutoUpdatedServerObjectClass.js.map +1 -1
- package/dist/CommonTypes.d.ts +89 -36
- package/dist/CommonTypes.js +0 -2
- package/dist/CommonTypes.js.map +1 -1
- package/dist/CommonTypes_server.d.ts +9 -0
- package/dist/CommonTypes_server.js +1 -1
- package/dist/server.d.ts +6 -1
- package/dist/server.js +6 -10
- package/dist/server.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import _ from "lodash";
|
|
3
|
-
import { EVENT_INTERNAL_PRE_LOADED, EVENT_DELETE, EVENT_GET, EVENT_NEW, EVENT_UPDATE, globalCache, } from "./CommonTypes
|
|
3
|
+
import { EVENT_INTERNAL_PRE_LOADED, EVENT_DELETE, EVENT_GET, EVENT_NEW, EVENT_UPDATE, globalCache, } from "./CommonTypes";
|
|
4
4
|
import { ObjectId } from "bson";
|
|
5
5
|
export class AutoUpdatedClientObject {
|
|
6
6
|
entry;
|
|
7
|
-
preLoad;
|
|
8
|
-
registerSocket;
|
|
9
|
-
readyLoggers;
|
|
10
|
-
loadFromDB(a) {
|
|
11
|
-
return a;
|
|
12
|
-
}
|
|
13
7
|
socket;
|
|
14
8
|
data;
|
|
15
9
|
isServer = false;
|
|
16
10
|
loggers;
|
|
17
11
|
isLoading = true;
|
|
12
|
+
loadError;
|
|
18
13
|
isLoadingReferences = true;
|
|
19
14
|
checkedMissingRefs = false;
|
|
20
|
-
isDestroyed = false;
|
|
21
15
|
emitter;
|
|
22
16
|
properties;
|
|
23
17
|
classParam;
|
|
@@ -26,7 +20,6 @@ export class AutoUpdatedClientObject {
|
|
|
26
20
|
EmitterID = new ObjectId().toHexString();
|
|
27
21
|
toChangeOnParents = [];
|
|
28
22
|
callbacks;
|
|
29
|
-
preloadTimers = new Set();
|
|
30
23
|
loadReferencesAsync = async () => {
|
|
31
24
|
try {
|
|
32
25
|
if (!this.isLoaded) {
|
|
@@ -35,14 +28,11 @@ export class AutoUpdatedClientObject {
|
|
|
35
28
|
this.generateSettersAndGetters();
|
|
36
29
|
await this.loadForceReferences();
|
|
37
30
|
for (const thing of this.toChangeOnParents) {
|
|
38
|
-
await this.
|
|
39
|
-
silent: true,
|
|
40
|
-
isParentUpdate: true,
|
|
41
|
-
});
|
|
31
|
+
await this.setValue__(thing.key, thing.value, true, false, false, true);
|
|
42
32
|
}
|
|
43
33
|
}
|
|
44
34
|
catch (error) {
|
|
45
|
-
|
|
35
|
+
this.loggers.error?.("Error loading references: " + (error instanceof Error ? error.message : String(error)));
|
|
46
36
|
}
|
|
47
37
|
finally {
|
|
48
38
|
this.isLoadingReferences = false;
|
|
@@ -66,8 +56,18 @@ export class AutoUpdatedClientObject {
|
|
|
66
56
|
this.parentManager = parentManager;
|
|
67
57
|
this.callbacks = callback;
|
|
68
58
|
this.emitter = emitter;
|
|
69
|
-
this.properties =
|
|
70
|
-
|
|
59
|
+
this.properties = undefined;
|
|
60
|
+
if (!classParam &&
|
|
61
|
+
!socket &&
|
|
62
|
+
!data &&
|
|
63
|
+
!loggers &&
|
|
64
|
+
!className &&
|
|
65
|
+
!parentManager &&
|
|
66
|
+
!callback &&
|
|
67
|
+
!emitter)
|
|
68
|
+
return;
|
|
69
|
+
else
|
|
70
|
+
throw new Error("Missing arguments???");
|
|
71
71
|
}
|
|
72
72
|
this.classParam = classParam;
|
|
73
73
|
this.socket = socket;
|
|
@@ -78,126 +78,96 @@ export class AutoUpdatedClientObject {
|
|
|
78
78
|
this.parentManager = parentManager;
|
|
79
79
|
this.className = className;
|
|
80
80
|
const allProps = new Set();
|
|
81
|
-
let
|
|
82
|
-
while (
|
|
83
|
-
const props = Reflect.getOwnMetadata("props",
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
proto = Object.getPrototypeOf(proto);
|
|
81
|
+
let proto_ = classParam.prototype;
|
|
82
|
+
while (proto_ && proto_ !== Object.prototype) {
|
|
83
|
+
const props = Reflect.getOwnMetadata("props", proto_) || [];
|
|
84
|
+
for (const p of props)
|
|
85
|
+
allProps.add(p);
|
|
86
|
+
proto_ = Object.getPrototypeOf(proto_);
|
|
89
87
|
}
|
|
90
88
|
this.properties = Array.from(allProps);
|
|
91
|
-
this.callbacks = callback
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
this.callbacks = callback;
|
|
90
|
+
this.loggers = {
|
|
91
|
+
debug: (s) => loggers.debug?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
92
|
+
info: (s) => loggers.info?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
93
|
+
warn: (s) => loggers.warn?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
94
|
+
error: (s) => loggers.error?.(`[DEM - ${this.className}: ${this.data?._id ?? this._id ?? "not loaded"}] ${s}`),
|
|
96
95
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
if (typeof data === "string") {
|
|
97
|
+
this.data = { _id: data };
|
|
98
|
+
if (this.isServer) {
|
|
99
|
+
this.isLoading = false;
|
|
100
|
+
this.generateSettersAndGetters();
|
|
101
|
+
return;
|
|
103
102
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
debug: (s) => loggers.debug?.(`[${this.className}: ${currentId}] ${s}`),
|
|
107
|
-
info: (s) => loggers.info?.(`[${this.className}: ${currentId}] ${s}`),
|
|
108
|
-
warn: (s) => loggers.warn?.(`[${this.className}: ${currentId}] ${s}`),
|
|
109
|
-
error: (s) => loggers.error?.(`[${this.className}: ${currentId}] ${s}`),
|
|
110
|
-
};
|
|
111
|
-
if (typeof data === "string") {
|
|
112
|
-
if (this.isServer) {
|
|
103
|
+
this.socket.emit(EVENT_GET + this.className + data, null, (res) => {
|
|
104
|
+
if (!res.success) {
|
|
113
105
|
this.isLoading = false;
|
|
114
|
-
this.
|
|
115
|
-
this.
|
|
106
|
+
this.loadError = res.message;
|
|
107
|
+
this.loggers.error?.("Could not load data from server: " + res.message);
|
|
108
|
+
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, true, res.message);
|
|
116
109
|
return;
|
|
117
110
|
}
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
else {
|
|
135
|
-
const currentDataRec = this.data;
|
|
136
|
-
for (const key of this.properties) {
|
|
137
|
-
const isRef = getMetadataRecursive("isRef", this, key);
|
|
138
|
-
if (isRef && currentDataRec[key]) {
|
|
139
|
-
if (Array.isArray(currentDataRec[key])) {
|
|
140
|
-
currentDataRec[key] = currentDataRec[key].map((obj) => obj._id?.toString() ?? obj?.toString());
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
currentDataRec[key] =
|
|
144
|
-
currentDataRec[key]?._id?.toString() ??
|
|
145
|
-
currentDataRec[key]?.toString();
|
|
146
|
-
}
|
|
111
|
+
this.data = res.data;
|
|
112
|
+
this.generateSettersAndGetters();
|
|
113
|
+
this.isLoading = false;
|
|
114
|
+
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID);
|
|
115
|
+
this.openSockets();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
this.isLoading = true;
|
|
120
|
+
this.data = data;
|
|
121
|
+
for (const key of this.properties || []) {
|
|
122
|
+
const isRef = getMetadataRecursive("isRef", this, key);
|
|
123
|
+
const dataAsRecord = this.data;
|
|
124
|
+
if (isRef && dataAsRecord[key]) {
|
|
125
|
+
if (Array.isArray(dataAsRecord[key])) {
|
|
126
|
+
dataAsRecord[key] = dataAsRecord[key].map((obj) => obj?._id?.toString() ?? obj?.toString());
|
|
147
127
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.handleNewObject(this.data);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
this.isLoading = false;
|
|
156
|
-
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID);
|
|
157
|
-
if (!this.isServer) {
|
|
158
|
-
this.openSockets();
|
|
159
|
-
this.onUpdate();
|
|
128
|
+
else {
|
|
129
|
+
dataAsRecord[key] =
|
|
130
|
+
dataAsRecord[key]?._id?.toString() ??
|
|
131
|
+
dataAsRecord[key]?.toString();
|
|
160
132
|
}
|
|
161
133
|
}
|
|
162
134
|
}
|
|
163
|
-
this.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
135
|
+
if ((!this.data._id || this.data._id === "") &&
|
|
136
|
+
!this.isServer) {
|
|
137
|
+
this.handleNewObject(data);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
this.isLoading = false;
|
|
141
|
+
if (!this.isServer)
|
|
142
|
+
this.openSockets();
|
|
171
143
|
}
|
|
172
144
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
145
|
+
this.generateSettersAndGetters();
|
|
146
|
+
Promise.resolve().then(() => {
|
|
147
|
+
this.generateSettersAndGetters();
|
|
148
|
+
});
|
|
177
149
|
}
|
|
178
150
|
async waitForPreloaded() {
|
|
151
|
+
if (this.loadError)
|
|
152
|
+
throw new Error(this.loadError);
|
|
179
153
|
if (this.isLoaded)
|
|
180
154
|
return;
|
|
181
|
-
|
|
182
|
-
|
|
155
|
+
await new Promise((resolve, reject) => {
|
|
156
|
+
this.emitter.once(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, (failed, reason) => {
|
|
183
157
|
if (failed)
|
|
184
158
|
reject(new Error(reason));
|
|
185
159
|
else
|
|
186
160
|
resolve();
|
|
187
|
-
};
|
|
188
|
-
this.emitter.once(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, onPreloaded);
|
|
161
|
+
});
|
|
189
162
|
});
|
|
190
163
|
}
|
|
191
164
|
handleNewObject(data) {
|
|
192
165
|
this.isLoading = true;
|
|
193
|
-
if (!this.socket || typeof this.socket.emit !== "function") {
|
|
194
|
-
this.isLoading = false;
|
|
195
|
-
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, true, "Socket not available");
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
166
|
this.socket.emit(EVENT_NEW + this.className, data, (res) => {
|
|
199
167
|
if (!res.success) {
|
|
200
168
|
this.isLoading = false;
|
|
169
|
+
this.loadError = res.message;
|
|
170
|
+
this.loggers.error?.("Could not create data on server: " + res.message);
|
|
201
171
|
this.emitter.emit(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, true, res.message);
|
|
202
172
|
return;
|
|
203
173
|
}
|
|
@@ -211,13 +181,13 @@ export class AutoUpdatedClientObject {
|
|
|
211
181
|
}
|
|
212
182
|
get extractedData() {
|
|
213
183
|
const extracted = processIsRefProperties(this.data, this, null, [], {}, this.loggers).newData;
|
|
214
|
-
return extracted;
|
|
184
|
+
return _.cloneDeep(extracted);
|
|
215
185
|
}
|
|
216
186
|
get isLoaded() {
|
|
217
187
|
return !this.isLoading;
|
|
218
188
|
}
|
|
219
189
|
async isPreLoadedAsync() {
|
|
220
|
-
await this.
|
|
190
|
+
await this.loadShit();
|
|
221
191
|
return true;
|
|
222
192
|
}
|
|
223
193
|
async loadMissingReferences() {
|
|
@@ -225,33 +195,27 @@ export class AutoUpdatedClientObject {
|
|
|
225
195
|
this.generateSettersAndGetters();
|
|
226
196
|
}
|
|
227
197
|
openSockets() {
|
|
228
|
-
const
|
|
229
|
-
const id = dataRec["_id"];
|
|
230
|
-
if (!id || !this.socket || typeof this.socket.on !== "function")
|
|
231
|
-
return;
|
|
198
|
+
const id = this.data?._id ?? this._id;
|
|
232
199
|
const event = EVENT_UPDATE + this.className + id.toString();
|
|
233
200
|
this.socket.on(event, async (update, ack) => {
|
|
234
201
|
const res = await this.handleUpdateRequest(update);
|
|
235
|
-
if (ack)
|
|
202
|
+
if (ack && typeof ack === "function")
|
|
236
203
|
ack(res);
|
|
237
204
|
return res;
|
|
238
205
|
});
|
|
239
206
|
}
|
|
240
207
|
async handleUpdateRequest(update) {
|
|
241
208
|
try {
|
|
242
|
-
await this.
|
|
243
|
-
silent: true,
|
|
244
|
-
});
|
|
209
|
+
await this.setValue__(update.key, update.value, true);
|
|
245
210
|
if (this.isLoaded)
|
|
246
211
|
this.callbacks.update(this, update.key);
|
|
247
212
|
return { success: true, data: undefined, message: "" };
|
|
248
213
|
}
|
|
249
214
|
catch (error) {
|
|
250
|
-
|
|
251
|
-
this.loggers.error?.(`[${dataRec["_id"]?.toString()}] Error applying patch: ${error.message}`);
|
|
215
|
+
this.loggers.error?.(`[${this.data._id}] Error applying patch: ${error instanceof Error ? error.message : String(error)}`);
|
|
252
216
|
return {
|
|
253
217
|
success: false,
|
|
254
|
-
message: "Error applying update: " + error.message,
|
|
218
|
+
message: "Error applying update: " + (error instanceof Error ? error.message : String(error)),
|
|
255
219
|
};
|
|
256
220
|
}
|
|
257
221
|
}
|
|
@@ -262,10 +226,14 @@ export class AutoUpdatedClientObject {
|
|
|
262
226
|
if (typeof key !== "string")
|
|
263
227
|
continue;
|
|
264
228
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
229
|
+
delete this[key];
|
|
265
230
|
Object.defineProperty(this, key, {
|
|
266
231
|
get: () => {
|
|
267
|
-
|
|
268
|
-
|
|
232
|
+
if (!this.data)
|
|
233
|
+
return undefined;
|
|
234
|
+
let val = this.data[key];
|
|
235
|
+
if (val === null)
|
|
236
|
+
val = undefined;
|
|
269
237
|
if (isRef && val) {
|
|
270
238
|
if (Array.isArray(val)) {
|
|
271
239
|
return val
|
|
@@ -289,31 +257,43 @@ export class AutoUpdatedClientObject {
|
|
|
289
257
|
}
|
|
290
258
|
getValue(key_) {
|
|
291
259
|
const key = key_;
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
260
|
+
const parts = key.split(".");
|
|
261
|
+
let value = this;
|
|
262
|
+
for (const part of parts) {
|
|
263
|
+
if (value === undefined || value === null)
|
|
264
|
+
return undefined;
|
|
265
|
+
const nextValue = value[part];
|
|
266
|
+
if (nextValue !== undefined) {
|
|
267
|
+
value = nextValue;
|
|
268
|
+
}
|
|
269
|
+
else if (value.data && value.data[part] !== undefined) {
|
|
270
|
+
value = value.data[part];
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return value;
|
|
298
277
|
}
|
|
299
278
|
findReference(id, key) {
|
|
300
|
-
if (!id
|
|
279
|
+
if (!id)
|
|
301
280
|
return undefined;
|
|
302
281
|
const idStr = id.toString();
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return cacheRec[key].getObject(idStr);
|
|
282
|
+
if (this.parentManager.cache.references[key])
|
|
283
|
+
return this.parentManager.cache.references[key]?.getObject(idStr) ?? undefined;
|
|
306
284
|
for (const manager of Object.values(this.parentManager.managers)) {
|
|
307
285
|
const result = manager.getObject(idStr);
|
|
308
286
|
if (result) {
|
|
309
|
-
|
|
287
|
+
this.parentManager.cache.references[key] = manager;
|
|
310
288
|
return result;
|
|
311
289
|
}
|
|
312
290
|
}
|
|
313
291
|
return undefined;
|
|
314
292
|
}
|
|
315
|
-
async setValue(key, val
|
|
316
|
-
|
|
293
|
+
async setValue(key, val) {
|
|
294
|
+
return await this.setValue__(key, val);
|
|
295
|
+
}
|
|
296
|
+
async setValue__(key, val, silent = false, noGet = false, noUpdate = false, isParentUpdate = false) {
|
|
317
297
|
try {
|
|
318
298
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
319
299
|
const pointer = getMetadataRecursive("refsTo", this, key);
|
|
@@ -323,19 +303,41 @@ export class AutoUpdatedClientObject {
|
|
|
323
303
|
let valueToStore = val;
|
|
324
304
|
if (isRef) {
|
|
325
305
|
valueToStore = Array.isArray(val)
|
|
326
|
-
? val.map((v) => v
|
|
327
|
-
:
|
|
306
|
+
? val.map((v) => v?._id?.toString() ?? v?.toString() ?? v)
|
|
307
|
+
: val?._id?.toString() ?? val?.toString() ?? val;
|
|
328
308
|
}
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
|
|
309
|
+
const currentVal = this.getValue(key);
|
|
310
|
+
const currentValId = Array.isArray(currentVal)
|
|
311
|
+
? currentVal.map((v) => v?._id?.toString() ?? v?.toString() ?? v)
|
|
312
|
+
: currentVal?._id?.toString() ?? currentVal?.toString();
|
|
313
|
+
if (_.isEqual(currentValId, valueToStore))
|
|
332
314
|
return { success: true, msg: "Successfully set " + key + " to " + val };
|
|
315
|
+
const path = key.split(".");
|
|
316
|
+
if (path.length > 1) {
|
|
317
|
+
let obj = this.data;
|
|
318
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
319
|
+
const currentKey = path[i];
|
|
320
|
+
const valAtKey = obj[currentKey];
|
|
321
|
+
if (typeof valAtKey === "string" ||
|
|
322
|
+
(valAtKey && ObjectId.isValid(valAtKey))) {
|
|
323
|
+
const ref = await this.resolveReference(String(valAtKey));
|
|
324
|
+
if (!ref)
|
|
325
|
+
throw new Error("Could not resolve reference on path: " + key);
|
|
326
|
+
return await ref.setValue(path.slice(i + 1).join("."), val);
|
|
327
|
+
}
|
|
328
|
+
obj = obj[currentKey];
|
|
329
|
+
}
|
|
330
|
+
}
|
|
333
331
|
const res = await this.setValueInternal(key, valueToStore, silent, noUpdate);
|
|
334
332
|
if (res.success) {
|
|
335
|
-
|
|
336
|
-
|
|
333
|
+
const pathArr = key.split(".");
|
|
334
|
+
let obj = this.data;
|
|
335
|
+
for (let i = 0; i < pathArr.length - 1; i++) {
|
|
336
|
+
obj = obj[pathArr[i]];
|
|
337
|
+
}
|
|
338
|
+
obj[pathArr[pathArr.length - 1]] = valueToStore;
|
|
337
339
|
await this.findAndLoadReferences(key, valueToStore);
|
|
338
|
-
if (isRef && this.parentManager
|
|
340
|
+
if (isRef && this.parentManager.isLoaded)
|
|
339
341
|
await this.contactChildren();
|
|
340
342
|
if (this.isLoaded)
|
|
341
343
|
this.callbacks.update(this, key);
|
|
@@ -346,22 +348,16 @@ export class AutoUpdatedClientObject {
|
|
|
346
348
|
};
|
|
347
349
|
}
|
|
348
350
|
catch (error) {
|
|
349
|
-
this.loggers.error?.(`Error setting value ${key}: ${error.message}`);
|
|
350
|
-
return { success: false, msg: error.message };
|
|
351
|
+
this.loggers.error?.(`Error setting value ${key}: ${error instanceof Error ? error.message : String(error)}`);
|
|
352
|
+
return { success: false, msg: error instanceof Error ? error.message : String(error) };
|
|
351
353
|
}
|
|
352
354
|
}
|
|
353
355
|
async setValueInternal(key, value, silent = false, noUpdate = false) {
|
|
354
|
-
if (silent
|
|
355
|
-
return { success: true, msg: "Silent
|
|
356
|
+
if (silent)
|
|
357
|
+
return { success: true, msg: "Silent" };
|
|
356
358
|
return new Promise((resolve) => {
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
if (!id)
|
|
360
|
-
return resolve({ success: false, msg: "Missing _id" });
|
|
361
|
-
if (!this.socket || typeof this.socket.emit !== "function") {
|
|
362
|
-
return resolve({ success: false, msg: "Socket not available" });
|
|
363
|
-
}
|
|
364
|
-
this.socket.emit(EVENT_UPDATE + this.className + id.toString(), { _id: id.toString(), key, value }, (res) => {
|
|
359
|
+
const id = this.data?._id ?? this._id;
|
|
360
|
+
this.socket.emit(EVENT_UPDATE + this.className + id, { _id: id.toString(), key, value }, (res) => {
|
|
365
361
|
resolve({
|
|
366
362
|
success: res.success,
|
|
367
363
|
msg: res.message ?? (res.success ? "Success" : "Error"),
|
|
@@ -370,17 +366,14 @@ export class AutoUpdatedClientObject {
|
|
|
370
366
|
});
|
|
371
367
|
}
|
|
372
368
|
makeUpdate(key, value) {
|
|
373
|
-
const
|
|
374
|
-
const id = dataRec ? dataRec["_id"] : undefined;
|
|
369
|
+
const id = this.data?._id ?? this._id;
|
|
375
370
|
if (!id) {
|
|
376
371
|
this.loggers.error?.(`Probably missing the identifier ['_id'] again: ${key} = ${value}`);
|
|
377
372
|
throw new Error(`Cannot make update for ${this.className} because _id is missing.`);
|
|
378
373
|
}
|
|
379
|
-
return { _id: id, key, value };
|
|
374
|
+
return { _id: id.toString(), key, value };
|
|
380
375
|
}
|
|
381
376
|
async resolveReference(id) {
|
|
382
|
-
if (!this.parentManager)
|
|
383
|
-
return null;
|
|
384
377
|
for (const manager of Object.values(this.parentManager.managers)) {
|
|
385
378
|
const obj = manager.getObject(id);
|
|
386
379
|
if (obj)
|
|
@@ -390,7 +383,7 @@ export class AutoUpdatedClientObject {
|
|
|
390
383
|
}
|
|
391
384
|
async findAndLoadReferences(lastPath, value) {
|
|
392
385
|
const isRef = getMetadataRecursive("isRef", this, lastPath);
|
|
393
|
-
if (isRef
|
|
386
|
+
if (isRef) {
|
|
394
387
|
for (const id of Array.isArray(value) ? value : [value]) {
|
|
395
388
|
if (!id)
|
|
396
389
|
continue;
|
|
@@ -407,60 +400,48 @@ export class AutoUpdatedClientObject {
|
|
|
407
400
|
}
|
|
408
401
|
}
|
|
409
402
|
async wipeSelf() {
|
|
410
|
-
|
|
411
|
-
if (!dataRec || dataRec["Wiped"])
|
|
403
|
+
if (this.data.Wiped)
|
|
412
404
|
return;
|
|
413
|
-
const id =
|
|
405
|
+
const id = this.data?._id ?? this._id;
|
|
414
406
|
const _id = id ? id.toString() : "unknown";
|
|
415
|
-
for (const key of Object.keys(
|
|
416
|
-
delete
|
|
407
|
+
for (const key of Object.keys(this.data)) {
|
|
408
|
+
delete this.data[key];
|
|
417
409
|
}
|
|
418
|
-
|
|
410
|
+
this.data = { Wiped: true };
|
|
419
411
|
this.loggers.info?.(`[${_id}] ${this.className} object wiped`);
|
|
420
412
|
}
|
|
413
|
+
destroyImmediate() {
|
|
414
|
+
this.wipeSelf();
|
|
415
|
+
}
|
|
421
416
|
async loadForceReferences(obj = this.data, proto = this, alreadySeen = []) {
|
|
422
|
-
if (!obj)
|
|
423
|
-
return;
|
|
424
|
-
if (obj === this.data) {
|
|
425
|
-
const dataRec = this.data;
|
|
426
|
-
const myId = dataRec["_id"]?.toString();
|
|
427
|
-
if (myId && !alreadySeen.includes(myId))
|
|
428
|
-
alreadySeen.push(myId);
|
|
429
|
-
}
|
|
430
417
|
const props = Reflect.getMetadata("props", proto) || [];
|
|
431
418
|
for (const key of props) {
|
|
419
|
+
if (typeof key !== "string")
|
|
420
|
+
continue;
|
|
432
421
|
const isRef = Reflect.getMetadata("isRef", proto, key);
|
|
433
422
|
const pointer = Reflect.getMetadata("refsTo", proto, key);
|
|
434
|
-
const objRec = obj;
|
|
435
423
|
if (pointer &&
|
|
436
424
|
obj === this.data &&
|
|
437
|
-
|
|
438
|
-
!alreadySeen.includes(
|
|
439
|
-
await this.createdWithParent(pointer.split(":"),
|
|
425
|
+
obj[key] &&
|
|
426
|
+
!alreadySeen.includes(obj)) {
|
|
427
|
+
await this.createdWithParent(pointer.split(":"), obj[key]);
|
|
440
428
|
}
|
|
441
|
-
if (
|
|
442
|
-
alreadySeen.push(
|
|
429
|
+
if (obj[key] && !alreadySeen.includes(obj[key]))
|
|
430
|
+
alreadySeen.push(obj[key]);
|
|
443
431
|
if (isRef)
|
|
444
432
|
await this.handleLoad(obj, key, alreadySeen);
|
|
445
|
-
const val =
|
|
433
|
+
const val = obj[key];
|
|
446
434
|
if (val && typeof val === "object") {
|
|
447
435
|
const nestedProto = Object.getPrototypeOf(val);
|
|
448
|
-
if (nestedProto &&
|
|
449
|
-
|
|
450
|
-
!alreadySeen.includes(JSON.stringify(val))) {
|
|
451
|
-
alreadySeen.push(JSON.stringify(val));
|
|
436
|
+
if (nestedProto && !alreadySeen.includes(val)) {
|
|
437
|
+
alreadySeen.push(val);
|
|
452
438
|
await this.loadForceReferences(val, nestedProto, alreadySeen);
|
|
453
439
|
}
|
|
454
440
|
}
|
|
455
441
|
}
|
|
456
442
|
}
|
|
457
443
|
async handleLoad(obj, key, alreadySeen) {
|
|
458
|
-
|
|
459
|
-
return;
|
|
460
|
-
const objRec = obj;
|
|
461
|
-
const refIds = Array.isArray(objRec[key])
|
|
462
|
-
? objRec[key]
|
|
463
|
-
: [objRec[key]];
|
|
444
|
+
const refIds = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
|
|
464
445
|
for (const refId of refIds) {
|
|
465
446
|
if (refId) {
|
|
466
447
|
const idStr = refId.toString();
|
|
@@ -479,82 +460,38 @@ export class AutoUpdatedClientObject {
|
|
|
479
460
|
}
|
|
480
461
|
}
|
|
481
462
|
}
|
|
482
|
-
async onUpdate(noUpdate = false) {
|
|
483
|
-
if (noUpdate)
|
|
484
|
-
return;
|
|
485
|
-
try {
|
|
486
|
-
await this.callbacks?.onUpdate?.(this, (key, val) => {
|
|
487
|
-
return this.setValue(key, val, {
|
|
488
|
-
silent: false,
|
|
489
|
-
noGet: true,
|
|
490
|
-
noUpdate: true,
|
|
491
|
-
});
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
catch (error) {
|
|
495
|
-
this.loggers.error(`[onUpdate] ${error}`);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
463
|
async createdWithParent(pointer, parent) {
|
|
499
|
-
if (pointer.length !== 2
|
|
464
|
+
if (pointer.length !== 2)
|
|
500
465
|
return;
|
|
501
466
|
const parentId = parent._id?.toString() ?? parent.toString();
|
|
502
|
-
const
|
|
503
|
-
if (!ac)
|
|
504
|
-
return;
|
|
505
|
-
const obj = ac.getObject(parentId);
|
|
467
|
+
const obj = this.parentManager.managers[pointer[0]]?.getObject(parentId);
|
|
506
468
|
if (!obj)
|
|
507
469
|
return;
|
|
508
470
|
const val = obj.getValue(pointer[1]);
|
|
509
|
-
const
|
|
510
|
-
const myId = dataRec["_id"]?.toString();
|
|
511
|
-
if (!myId)
|
|
512
|
-
return;
|
|
471
|
+
const myId = this.data._id.toString();
|
|
513
472
|
if (Array.isArray(val)) {
|
|
514
|
-
const ids = val.map((v) => v
|
|
473
|
+
const ids = val.map((v) => v?._id?.toString() ?? v?.toString());
|
|
515
474
|
if (!ids.includes(myId)) {
|
|
516
|
-
await obj.
|
|
475
|
+
await obj.setValue__(pointer[1], [...val, myId], true, false, false, true);
|
|
517
476
|
}
|
|
518
477
|
}
|
|
519
478
|
else if ((val?._id?.toString() ?? val?.toString()) !== myId) {
|
|
520
|
-
await obj.
|
|
521
|
-
silent: true,
|
|
522
|
-
isParentUpdate: true,
|
|
523
|
-
});
|
|
479
|
+
await obj.setValue__(pointer[1], myId, true, false, false, true);
|
|
524
480
|
}
|
|
525
481
|
}
|
|
526
482
|
async destroy(once = false) {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
this.preloadTimers.clear();
|
|
531
|
-
const dataRec = this.data;
|
|
532
|
-
const id = dataRec ? dataRec["_id"] : undefined;
|
|
533
|
-
if (!id)
|
|
534
|
-
return { success: false, message: "Missing _id" };
|
|
535
|
-
if (!once && this.parentManager)
|
|
536
|
-
return await this.parentManager.deleteObject(id);
|
|
483
|
+
if (!once)
|
|
484
|
+
return await this.parentManager.deleteObject(this.data._id.toString());
|
|
537
485
|
return new Promise((resolve) => {
|
|
538
|
-
|
|
539
|
-
return resolve({ success: false, message: "Socket not available" });
|
|
540
|
-
}
|
|
541
|
-
this.socket.emit(EVENT_DELETE + this.className, id.toString(), (res) => {
|
|
486
|
+
this.socket.emit(EVENT_DELETE + this.className, this.data._id, (res) => {
|
|
542
487
|
resolve({ success: res.success, message: res.message ?? "" });
|
|
543
488
|
});
|
|
544
489
|
});
|
|
545
490
|
}
|
|
546
|
-
destroyImmediate() {
|
|
547
|
-
this.isDestroyed = true;
|
|
548
|
-
for (const timer of this.preloadTimers) {
|
|
549
|
-
clearTimeout(timer);
|
|
550
|
-
}
|
|
551
|
-
this.preloadTimers.clear();
|
|
552
|
-
this.isLoading = false;
|
|
553
|
-
}
|
|
554
491
|
async checkForMissingRefs() {
|
|
555
492
|
for (const prop of this.properties) {
|
|
556
493
|
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
557
|
-
if (
|
|
494
|
+
if (pointer) {
|
|
558
495
|
const parts = pointer.split(":");
|
|
559
496
|
if (parts.length === 2)
|
|
560
497
|
await this.findMissingObjectReference(prop, parts);
|
|
@@ -562,19 +499,14 @@ export class AutoUpdatedClientObject {
|
|
|
562
499
|
}
|
|
563
500
|
}
|
|
564
501
|
async findMissingObjectReference(prop, pointer) {
|
|
565
|
-
if (this.checkedMissingRefs
|
|
502
|
+
if (this.checkedMissingRefs)
|
|
566
503
|
return;
|
|
567
504
|
this.checkedMissingRefs = true;
|
|
568
505
|
const ac = this.parentManager.managers[pointer[0]];
|
|
569
506
|
if (!ac)
|
|
570
507
|
return;
|
|
571
|
-
const
|
|
572
|
-
const
|
|
573
|
-
? dataRec["_id"]?.toString()
|
|
574
|
-
: undefined;
|
|
575
|
-
if (!targetId)
|
|
576
|
-
return;
|
|
577
|
-
const allObjects = Object.values(ac.objects);
|
|
508
|
+
const targetId = this.data._id.toString();
|
|
509
|
+
const allObjects = Object.values(ac.objectsAsArray);
|
|
578
510
|
for (const obj of allObjects) {
|
|
579
511
|
if (!obj.isLoaded)
|
|
580
512
|
await obj.waitForPreloaded();
|
|
@@ -582,49 +514,33 @@ export class AutoUpdatedClientObject {
|
|
|
582
514
|
if (!val)
|
|
583
515
|
continue;
|
|
584
516
|
const ids = Array.isArray(val)
|
|
585
|
-
? val.map((v) => v
|
|
517
|
+
? val.map((v) => v?._id?.toString() ?? v.toString())
|
|
586
518
|
: [val._id?.toString() ?? val.toString()];
|
|
587
519
|
if (ids.includes(targetId)) {
|
|
588
|
-
|
|
520
|
+
this.data[prop] = obj._id;
|
|
589
521
|
return;
|
|
590
522
|
}
|
|
591
523
|
}
|
|
592
524
|
}
|
|
593
|
-
async resolveReferences() {
|
|
594
|
-
await this.loadMissingReferences();
|
|
595
|
-
await this.contactChildren();
|
|
596
|
-
}
|
|
597
525
|
async contactChildren() {
|
|
598
|
-
if (!this.parentManager)
|
|
599
|
-
return;
|
|
600
526
|
for (const prop of this.properties) {
|
|
601
527
|
const isRef = getMetadataRecursive("isRef", this, prop.toString());
|
|
602
528
|
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
603
529
|
if (!isRef || pointer)
|
|
604
530
|
continue;
|
|
605
|
-
const
|
|
606
|
-
if (!
|
|
531
|
+
const obj = this.getValue(prop);
|
|
532
|
+
if (!obj)
|
|
607
533
|
continue;
|
|
608
|
-
const
|
|
609
|
-
for (const
|
|
610
|
-
if (
|
|
611
|
-
|
|
612
|
-
let childObj = item;
|
|
613
|
-
if (typeof item === "string" || item instanceof ObjectId) {
|
|
614
|
-
const idStr = item.toString();
|
|
615
|
-
for (const manager of Object.values(this.parentManager.managers)) {
|
|
616
|
-
childObj = manager.getObject(idStr);
|
|
617
|
-
if (childObj)
|
|
618
|
-
break;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
if (childObj &&
|
|
622
|
-
typeof childObj.loadMissingReferences === "function") {
|
|
623
|
-
await childObj.loadMissingReferences();
|
|
534
|
+
const children = Array.isArray(obj) ? obj : [obj];
|
|
535
|
+
for (const child of children) {
|
|
536
|
+
if (child && typeof child.loadMissingReferences === "function") {
|
|
537
|
+
await child.loadMissingReferences();
|
|
624
538
|
}
|
|
625
539
|
}
|
|
626
540
|
}
|
|
627
|
-
|
|
541
|
+
}
|
|
542
|
+
async onUpdate() {
|
|
543
|
+
// Placeholder for server-side override
|
|
628
544
|
}
|
|
629
545
|
}
|
|
630
546
|
export function processIsRefProperties(instance, target, prefix, allProps, newData, loggers) {
|
|
@@ -632,9 +548,7 @@ export function processIsRefProperties(instance, target, prefix, allProps, newDa
|
|
|
632
548
|
for (const prop of props) {
|
|
633
549
|
const path = prefix ? `${prefix}.${prop}` : prop;
|
|
634
550
|
allProps.push(path);
|
|
635
|
-
|
|
636
|
-
continue;
|
|
637
|
-
newData[prop] = ObjectId.isValid(instance[prop])
|
|
551
|
+
newData[prop] = (instance[prop] && ObjectId.isValid(instance[prop]))
|
|
638
552
|
? instance[prop]?.toString()
|
|
639
553
|
: instance[prop];
|
|
640
554
|
if (Reflect.getMetadata("isRef", target, prop)) {
|
|
@@ -648,16 +562,18 @@ export function processIsRefProperties(instance, target, prefix, allProps, newDa
|
|
|
648
562
|
}
|
|
649
563
|
const type = Reflect.getMetadata("design:type", target, prop);
|
|
650
564
|
if (type?.prototype) {
|
|
651
|
-
|
|
565
|
+
const nestedProps = Reflect.getMetadata("props", type.prototype);
|
|
566
|
+
if (nestedProps && instance[prop]) {
|
|
567
|
+
newData[prop] = processIsRefProperties(instance[prop], type.prototype, path, allProps, {}, loggers).newData;
|
|
568
|
+
}
|
|
652
569
|
}
|
|
653
570
|
}
|
|
654
571
|
return { allProps, newData };
|
|
655
572
|
}
|
|
656
|
-
export function getMetadataRecursive(metaKey,
|
|
657
|
-
let proto = target;
|
|
573
|
+
export function getMetadataRecursive(metaKey, proto, prop) {
|
|
658
574
|
while (proto) {
|
|
659
575
|
const meta = Reflect.getMetadata(metaKey, proto, prop);
|
|
660
|
-
if (meta
|
|
576
|
+
if (meta)
|
|
661
577
|
return meta;
|
|
662
578
|
proto = Object.getPrototypeOf(proto);
|
|
663
579
|
}
|