@prestizni-software/server-dem 0.5.7 → 0.5.9
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 +60 -78
- package/dist/AutoUpdateServerManagerClass.js +343 -153
- package/dist/AutoUpdateServerManagerClass.js.map +1 -1
- package/dist/AutoUpdatedClientObjectClass.d.ts +33 -39
- package/dist/AutoUpdatedClientObjectClass.js +205 -308
- package/dist/AutoUpdatedClientObjectClass.js.map +1 -1
- package/dist/AutoUpdatedServerObjectClass.d.ts +9 -14
- package/dist/AutoUpdatedServerObjectClass.js +91 -98
- 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 +2 -6
- package/dist/server.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -4,20 +4,14 @@ import { EVENT_INTERNAL_PRE_LOADED, EVENT_DELETE, EVENT_GET, EVENT_NEW, EVENT_UP
|
|
|
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,48 +181,41 @@ 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() {
|
|
224
|
-
this.loggers.debug?.(`loadMissingReferences for ${this.className}:${this._id}`);
|
|
225
194
|
await this.checkForMissingRefs();
|
|
226
195
|
this.generateSettersAndGetters();
|
|
227
196
|
}
|
|
228
197
|
openSockets() {
|
|
229
|
-
const
|
|
230
|
-
const id = dataRec["_id"];
|
|
231
|
-
if (!id || !this.socket || typeof this.socket.on !== "function")
|
|
232
|
-
return;
|
|
198
|
+
const id = this.data?._id ?? this._id;
|
|
233
199
|
const event = EVENT_UPDATE + this.className + id.toString();
|
|
234
200
|
this.socket.on(event, async (update, ack) => {
|
|
235
201
|
const res = await this.handleUpdateRequest(update);
|
|
236
|
-
if (ack)
|
|
202
|
+
if (ack && typeof ack === "function")
|
|
237
203
|
ack(res);
|
|
238
204
|
return res;
|
|
239
205
|
});
|
|
240
206
|
}
|
|
241
207
|
async handleUpdateRequest(update) {
|
|
242
208
|
try {
|
|
243
|
-
await this.
|
|
244
|
-
silent: true,
|
|
245
|
-
});
|
|
209
|
+
await this.setValue__(update.key, update.value, true);
|
|
246
210
|
if (this.isLoaded)
|
|
247
211
|
this.callbacks.update(this, update.key);
|
|
248
212
|
return { success: true, data: undefined, message: "" };
|
|
249
213
|
}
|
|
250
214
|
catch (error) {
|
|
251
|
-
|
|
252
|
-
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)}`);
|
|
253
216
|
return {
|
|
254
217
|
success: false,
|
|
255
|
-
message: "Error applying update: " + error.message,
|
|
218
|
+
message: "Error applying update: " + (error instanceof Error ? error.message : String(error)),
|
|
256
219
|
};
|
|
257
220
|
}
|
|
258
221
|
}
|
|
@@ -263,10 +226,14 @@ export class AutoUpdatedClientObject {
|
|
|
263
226
|
if (typeof key !== "string")
|
|
264
227
|
continue;
|
|
265
228
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
229
|
+
delete this[key];
|
|
266
230
|
Object.defineProperty(this, key, {
|
|
267
231
|
get: () => {
|
|
268
|
-
|
|
269
|
-
|
|
232
|
+
if (!this.data)
|
|
233
|
+
return undefined;
|
|
234
|
+
let val = this.data[key];
|
|
235
|
+
if (val === null)
|
|
236
|
+
val = undefined;
|
|
270
237
|
if (isRef && val) {
|
|
271
238
|
if (Array.isArray(val)) {
|
|
272
239
|
return val
|
|
@@ -290,36 +257,43 @@ export class AutoUpdatedClientObject {
|
|
|
290
257
|
}
|
|
291
258
|
getValue(key_) {
|
|
292
259
|
const key = key_;
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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;
|
|
299
277
|
}
|
|
300
278
|
findReference(id, key) {
|
|
301
|
-
if (!id
|
|
279
|
+
if (!id)
|
|
302
280
|
return undefined;
|
|
303
281
|
const idStr = id.toString();
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const obj = cacheRec[key].getObject(idStr);
|
|
307
|
-
if (obj)
|
|
308
|
-
return obj;
|
|
309
|
-
}
|
|
282
|
+
if (this.parentManager.cache.references[key])
|
|
283
|
+
return this.parentManager.cache.references[key]?.getObject(idStr) ?? undefined;
|
|
310
284
|
for (const manager of Object.values(this.parentManager.managers)) {
|
|
311
285
|
const result = manager.getObject(idStr);
|
|
312
286
|
if (result) {
|
|
313
|
-
this.
|
|
314
|
-
cacheRec[key] = manager;
|
|
287
|
+
this.parentManager.cache.references[key] = manager;
|
|
315
288
|
return result;
|
|
316
289
|
}
|
|
317
290
|
}
|
|
318
|
-
this.loggers.warn?.(`findReference: Could NOT resolve ${idStr} for property ${key} in any manager.`);
|
|
319
291
|
return undefined;
|
|
320
292
|
}
|
|
321
|
-
async setValue(key, val
|
|
322
|
-
|
|
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) {
|
|
323
297
|
try {
|
|
324
298
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
325
299
|
const pointer = getMetadataRecursive("refsTo", this, key);
|
|
@@ -329,19 +303,41 @@ export class AutoUpdatedClientObject {
|
|
|
329
303
|
let valueToStore = val;
|
|
330
304
|
if (isRef) {
|
|
331
305
|
valueToStore = Array.isArray(val)
|
|
332
|
-
? val.map((v) => v
|
|
333
|
-
:
|
|
306
|
+
? val.map((v) => v?._id?.toString() ?? v?.toString() ?? v)
|
|
307
|
+
: val?._id?.toString() ?? val?.toString() ?? val;
|
|
334
308
|
}
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
-
|
|
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))
|
|
338
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
|
+
}
|
|
339
331
|
const res = await this.setValueInternal(key, valueToStore, silent, noUpdate);
|
|
340
332
|
if (res.success) {
|
|
341
|
-
|
|
342
|
-
|
|
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;
|
|
343
339
|
await this.findAndLoadReferences(key, valueToStore);
|
|
344
|
-
if (isRef && this.parentManager
|
|
340
|
+
if (isRef && this.parentManager.isLoaded)
|
|
345
341
|
await this.contactChildren();
|
|
346
342
|
if (this.isLoaded)
|
|
347
343
|
this.callbacks.update(this, key);
|
|
@@ -352,22 +348,16 @@ export class AutoUpdatedClientObject {
|
|
|
352
348
|
};
|
|
353
349
|
}
|
|
354
350
|
catch (error) {
|
|
355
|
-
this.loggers.error?.(`Error setting value ${key}: ${error.message}`);
|
|
356
|
-
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) };
|
|
357
353
|
}
|
|
358
354
|
}
|
|
359
355
|
async setValueInternal(key, value, silent = false, noUpdate = false) {
|
|
360
|
-
if (silent
|
|
361
|
-
return { success: true, msg: "Silent
|
|
356
|
+
if (silent)
|
|
357
|
+
return { success: true, msg: "Silent" };
|
|
362
358
|
return new Promise((resolve) => {
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
if (!id)
|
|
366
|
-
return resolve({ success: false, msg: "Missing _id" });
|
|
367
|
-
if (!this.socket || typeof this.socket.emit !== "function") {
|
|
368
|
-
return resolve({ success: false, msg: "Socket not available" });
|
|
369
|
-
}
|
|
370
|
-
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) => {
|
|
371
361
|
resolve({
|
|
372
362
|
success: res.success,
|
|
373
363
|
msg: res.message ?? (res.success ? "Success" : "Error"),
|
|
@@ -376,17 +366,14 @@ export class AutoUpdatedClientObject {
|
|
|
376
366
|
});
|
|
377
367
|
}
|
|
378
368
|
makeUpdate(key, value) {
|
|
379
|
-
const
|
|
380
|
-
const id = dataRec ? dataRec["_id"] : undefined;
|
|
369
|
+
const id = this.data?._id ?? this._id;
|
|
381
370
|
if (!id) {
|
|
382
371
|
this.loggers.error?.(`Probably missing the identifier ['_id'] again: ${key} = ${value}`);
|
|
383
372
|
throw new Error(`Cannot make update for ${this.className} because _id is missing.`);
|
|
384
373
|
}
|
|
385
|
-
return { _id: id, key, value };
|
|
374
|
+
return { _id: id.toString(), key, value };
|
|
386
375
|
}
|
|
387
376
|
async resolveReference(id) {
|
|
388
|
-
if (!this.parentManager)
|
|
389
|
-
return null;
|
|
390
377
|
for (const manager of Object.values(this.parentManager.managers)) {
|
|
391
378
|
const obj = manager.getObject(id);
|
|
392
379
|
if (obj)
|
|
@@ -396,7 +383,7 @@ export class AutoUpdatedClientObject {
|
|
|
396
383
|
}
|
|
397
384
|
async findAndLoadReferences(lastPath, value) {
|
|
398
385
|
const isRef = getMetadataRecursive("isRef", this, lastPath);
|
|
399
|
-
if (isRef
|
|
386
|
+
if (isRef) {
|
|
400
387
|
for (const id of Array.isArray(value) ? value : [value]) {
|
|
401
388
|
if (!id)
|
|
402
389
|
continue;
|
|
@@ -413,60 +400,48 @@ export class AutoUpdatedClientObject {
|
|
|
413
400
|
}
|
|
414
401
|
}
|
|
415
402
|
async wipeSelf() {
|
|
416
|
-
|
|
417
|
-
if (!dataRec || dataRec["Wiped"])
|
|
403
|
+
if (this.data.Wiped)
|
|
418
404
|
return;
|
|
419
|
-
const id =
|
|
405
|
+
const id = this.data?._id ?? this._id;
|
|
420
406
|
const _id = id ? id.toString() : "unknown";
|
|
421
|
-
for (const key of Object.keys(
|
|
422
|
-
delete
|
|
407
|
+
for (const key of Object.keys(this.data)) {
|
|
408
|
+
delete this.data[key];
|
|
423
409
|
}
|
|
424
|
-
|
|
410
|
+
this.data = { Wiped: true };
|
|
425
411
|
this.loggers.info?.(`[${_id}] ${this.className} object wiped`);
|
|
426
412
|
}
|
|
413
|
+
destroyImmediate() {
|
|
414
|
+
this.wipeSelf();
|
|
415
|
+
}
|
|
427
416
|
async loadForceReferences(obj = this.data, proto = this, alreadySeen = []) {
|
|
428
|
-
if (!obj)
|
|
429
|
-
return;
|
|
430
|
-
if (obj === this.data) {
|
|
431
|
-
const dataRec = this.data;
|
|
432
|
-
const myId = dataRec["_id"]?.toString();
|
|
433
|
-
if (myId && !alreadySeen.includes(myId))
|
|
434
|
-
alreadySeen.push(myId);
|
|
435
|
-
}
|
|
436
417
|
const props = Reflect.getMetadata("props", proto) || [];
|
|
437
418
|
for (const key of props) {
|
|
419
|
+
if (typeof key !== "string")
|
|
420
|
+
continue;
|
|
438
421
|
const isRef = Reflect.getMetadata("isRef", proto, key);
|
|
439
422
|
const pointer = Reflect.getMetadata("refsTo", proto, key);
|
|
440
|
-
const objRec = obj;
|
|
441
423
|
if (pointer &&
|
|
442
424
|
obj === this.data &&
|
|
443
|
-
|
|
444
|
-
!alreadySeen.includes(
|
|
445
|
-
await this.createdWithParent(pointer.split(":"),
|
|
425
|
+
obj[key] &&
|
|
426
|
+
!alreadySeen.includes(obj)) {
|
|
427
|
+
await this.createdWithParent(pointer.split(":"), obj[key]);
|
|
446
428
|
}
|
|
447
|
-
if (
|
|
448
|
-
alreadySeen.push(
|
|
429
|
+
if (obj[key] && !alreadySeen.includes(obj[key]))
|
|
430
|
+
alreadySeen.push(obj[key]);
|
|
449
431
|
if (isRef)
|
|
450
432
|
await this.handleLoad(obj, key, alreadySeen);
|
|
451
|
-
const val =
|
|
433
|
+
const val = obj[key];
|
|
452
434
|
if (val && typeof val === "object") {
|
|
453
435
|
const nestedProto = Object.getPrototypeOf(val);
|
|
454
|
-
if (nestedProto &&
|
|
455
|
-
|
|
456
|
-
!alreadySeen.includes(JSON.stringify(val))) {
|
|
457
|
-
alreadySeen.push(JSON.stringify(val));
|
|
436
|
+
if (nestedProto && !alreadySeen.includes(val)) {
|
|
437
|
+
alreadySeen.push(val);
|
|
458
438
|
await this.loadForceReferences(val, nestedProto, alreadySeen);
|
|
459
439
|
}
|
|
460
440
|
}
|
|
461
441
|
}
|
|
462
442
|
}
|
|
463
443
|
async handleLoad(obj, key, alreadySeen) {
|
|
464
|
-
|
|
465
|
-
return;
|
|
466
|
-
const objRec = obj;
|
|
467
|
-
const refIds = Array.isArray(objRec[key])
|
|
468
|
-
? objRec[key]
|
|
469
|
-
: [objRec[key]];
|
|
444
|
+
const refIds = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
|
|
470
445
|
for (const refId of refIds) {
|
|
471
446
|
if (refId) {
|
|
472
447
|
const idStr = refId.toString();
|
|
@@ -485,82 +460,38 @@ export class AutoUpdatedClientObject {
|
|
|
485
460
|
}
|
|
486
461
|
}
|
|
487
462
|
}
|
|
488
|
-
async onUpdate(noUpdate = false) {
|
|
489
|
-
if (noUpdate)
|
|
490
|
-
return;
|
|
491
|
-
try {
|
|
492
|
-
await this.callbacks?.onUpdate?.(this, (key, val) => {
|
|
493
|
-
return this.setValue(key, val, {
|
|
494
|
-
silent: false,
|
|
495
|
-
noGet: true,
|
|
496
|
-
noUpdate: true,
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
catch (error) {
|
|
501
|
-
this.loggers.error(`[onUpdate] ${error}`);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
463
|
async createdWithParent(pointer, parent) {
|
|
505
|
-
if (pointer.length !== 2
|
|
464
|
+
if (pointer.length !== 2)
|
|
506
465
|
return;
|
|
507
466
|
const parentId = parent._id?.toString() ?? parent.toString();
|
|
508
|
-
const
|
|
509
|
-
if (!ac)
|
|
510
|
-
return;
|
|
511
|
-
const obj = ac.getObject(parentId);
|
|
467
|
+
const obj = this.parentManager.managers[pointer[0]]?.getObject(parentId);
|
|
512
468
|
if (!obj)
|
|
513
469
|
return;
|
|
514
470
|
const val = obj.getValue(pointer[1]);
|
|
515
|
-
const
|
|
516
|
-
const myId = dataRec["_id"]?.toString();
|
|
517
|
-
if (!myId)
|
|
518
|
-
return;
|
|
471
|
+
const myId = this.data._id.toString();
|
|
519
472
|
if (Array.isArray(val)) {
|
|
520
|
-
const ids = val.map((v) => v
|
|
473
|
+
const ids = val.map((v) => v?._id?.toString() ?? v?.toString());
|
|
521
474
|
if (!ids.includes(myId)) {
|
|
522
|
-
await obj.
|
|
475
|
+
await obj.setValue__(pointer[1], [...val, myId], true, false, false, true);
|
|
523
476
|
}
|
|
524
477
|
}
|
|
525
478
|
else if ((val?._id?.toString() ?? val?.toString()) !== myId) {
|
|
526
|
-
await obj.
|
|
527
|
-
silent: true,
|
|
528
|
-
isParentUpdate: true,
|
|
529
|
-
});
|
|
479
|
+
await obj.setValue__(pointer[1], myId, true, false, false, true);
|
|
530
480
|
}
|
|
531
481
|
}
|
|
532
482
|
async destroy(once = false) {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
this.preloadTimers.clear();
|
|
537
|
-
const dataRec = this.data;
|
|
538
|
-
const id = dataRec ? dataRec["_id"] : undefined;
|
|
539
|
-
if (!id)
|
|
540
|
-
return { success: false, message: "Missing _id" };
|
|
541
|
-
if (!once && this.parentManager)
|
|
542
|
-
return await this.parentManager.deleteObject(id);
|
|
483
|
+
if (!once)
|
|
484
|
+
return await this.parentManager.deleteObject(this.data._id.toString());
|
|
543
485
|
return new Promise((resolve) => {
|
|
544
|
-
|
|
545
|
-
return resolve({ success: false, message: "Socket not available" });
|
|
546
|
-
}
|
|
547
|
-
this.socket.emit(EVENT_DELETE + this.className, id.toString(), (res) => {
|
|
486
|
+
this.socket.emit(EVENT_DELETE + this.className, this.data._id, (res) => {
|
|
548
487
|
resolve({ success: res.success, message: res.message ?? "" });
|
|
549
488
|
});
|
|
550
489
|
});
|
|
551
490
|
}
|
|
552
|
-
destroyImmediate() {
|
|
553
|
-
this.isDestroyed = true;
|
|
554
|
-
for (const timer of this.preloadTimers) {
|
|
555
|
-
clearTimeout(timer);
|
|
556
|
-
}
|
|
557
|
-
this.preloadTimers.clear();
|
|
558
|
-
this.isLoading = false;
|
|
559
|
-
}
|
|
560
491
|
async checkForMissingRefs() {
|
|
561
492
|
for (const prop of this.properties) {
|
|
562
493
|
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
563
|
-
if (
|
|
494
|
+
if (pointer) {
|
|
564
495
|
const parts = pointer.split(":");
|
|
565
496
|
if (parts.length === 2)
|
|
566
497
|
await this.findMissingObjectReference(prop, parts);
|
|
@@ -568,22 +499,14 @@ export class AutoUpdatedClientObject {
|
|
|
568
499
|
}
|
|
569
500
|
}
|
|
570
501
|
async findMissingObjectReference(prop, pointer) {
|
|
571
|
-
if (this.checkedMissingRefs
|
|
502
|
+
if (this.checkedMissingRefs)
|
|
572
503
|
return;
|
|
573
504
|
this.checkedMissingRefs = true;
|
|
574
505
|
const ac = this.parentManager.managers[pointer[0]];
|
|
575
|
-
if (!ac)
|
|
576
|
-
this.loggers.warn?.(`findMissingObjectReference: Manager ${pointer[0]} not found for pointer ${pointer.join(":")}`);
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const dataRec = this.data;
|
|
580
|
-
const targetId = dataRec
|
|
581
|
-
? dataRec["_id"]?.toString()
|
|
582
|
-
: undefined;
|
|
583
|
-
if (!targetId)
|
|
506
|
+
if (!ac)
|
|
584
507
|
return;
|
|
585
|
-
const
|
|
586
|
-
|
|
508
|
+
const targetId = this.data._id.toString();
|
|
509
|
+
const allObjects = Object.values(ac.objectsAsArray);
|
|
587
510
|
for (const obj of allObjects) {
|
|
588
511
|
if (!obj.isLoaded)
|
|
589
512
|
await obj.waitForPreloaded();
|
|
@@ -591,59 +514,33 @@ export class AutoUpdatedClientObject {
|
|
|
591
514
|
if (!val)
|
|
592
515
|
continue;
|
|
593
516
|
const ids = Array.isArray(val)
|
|
594
|
-
? val.map((v) => v
|
|
517
|
+
? val.map((v) => v?._id?.toString() ?? v.toString())
|
|
595
518
|
: [val._id?.toString() ?? val.toString()];
|
|
596
519
|
if (ids.includes(targetId)) {
|
|
597
|
-
this.
|
|
598
|
-
dataRec[prop] = obj._id;
|
|
520
|
+
this.data[prop] = obj._id;
|
|
599
521
|
return;
|
|
600
522
|
}
|
|
601
523
|
}
|
|
602
|
-
this.loggers.debug?.(`findMissingObjectReference: Finished checking ${pointer[0]} for ${targetId}, no parent found yet.`);
|
|
603
|
-
}
|
|
604
|
-
async resolveReferences() {
|
|
605
|
-
this.loggers.debug?.(`Starting resolveReferences for ${this.className}:${this._id}`);
|
|
606
|
-
await this.loadMissingReferences();
|
|
607
|
-
await this.contactChildren();
|
|
608
|
-
this.loggers.debug?.(`Finished resolveReferences for ${this.className}:${this._id}`);
|
|
609
524
|
}
|
|
610
525
|
async contactChildren() {
|
|
611
|
-
if (!this.parentManager)
|
|
612
|
-
return;
|
|
613
|
-
this.loggers.debug?.(`contactChildren for ${this.className}:${this._id}`);
|
|
614
526
|
for (const prop of this.properties) {
|
|
615
527
|
const isRef = getMetadataRecursive("isRef", this, prop.toString());
|
|
616
528
|
const pointer = getMetadataRecursive("refsTo", this, prop.toString());
|
|
617
529
|
if (!isRef || pointer)
|
|
618
530
|
continue;
|
|
619
|
-
const
|
|
620
|
-
if (!
|
|
531
|
+
const obj = this.getValue(prop);
|
|
532
|
+
if (!obj)
|
|
621
533
|
continue;
|
|
622
|
-
const
|
|
623
|
-
for (const
|
|
624
|
-
if (
|
|
625
|
-
|
|
626
|
-
let childObj = item;
|
|
627
|
-
if (typeof item === "string" || item instanceof ObjectId) {
|
|
628
|
-
const idStr = item.toString();
|
|
629
|
-
this.loggers.debug?.(`contactChildren searching for child ${idStr} (prop: ${prop})`);
|
|
630
|
-
for (const manager of Object.values(this.parentManager.managers)) {
|
|
631
|
-
childObj = manager.getObject(idStr);
|
|
632
|
-
if (childObj)
|
|
633
|
-
break;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
if (childObj &&
|
|
637
|
-
typeof childObj.loadMissingReferences === "function") {
|
|
638
|
-
this.loggers.debug?.(`contactChildren triggering resolution for child ${childObj.className}:${childObj._id}`);
|
|
639
|
-
await childObj.loadMissingReferences();
|
|
640
|
-
}
|
|
641
|
-
else if (!childObj) {
|
|
642
|
-
this.loggers.warn?.(`contactChildren could NOT find child ${item} for property ${prop}`);
|
|
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();
|
|
643
538
|
}
|
|
644
539
|
}
|
|
645
540
|
}
|
|
646
|
-
|
|
541
|
+
}
|
|
542
|
+
async onUpdate() {
|
|
543
|
+
// Placeholder for server-side override
|
|
647
544
|
}
|
|
648
545
|
}
|
|
649
546
|
export function processIsRefProperties(instance, target, prefix, allProps, newData, loggers) {
|
|
@@ -651,9 +548,7 @@ export function processIsRefProperties(instance, target, prefix, allProps, newDa
|
|
|
651
548
|
for (const prop of props) {
|
|
652
549
|
const path = prefix ? `${prefix}.${prop}` : prop;
|
|
653
550
|
allProps.push(path);
|
|
654
|
-
|
|
655
|
-
continue;
|
|
656
|
-
newData[prop] = ObjectId.isValid(instance[prop])
|
|
551
|
+
newData[prop] = (instance[prop] && ObjectId.isValid(instance[prop]))
|
|
657
552
|
? instance[prop]?.toString()
|
|
658
553
|
: instance[prop];
|
|
659
554
|
if (Reflect.getMetadata("isRef", target, prop)) {
|
|
@@ -667,16 +562,18 @@ export function processIsRefProperties(instance, target, prefix, allProps, newDa
|
|
|
667
562
|
}
|
|
668
563
|
const type = Reflect.getMetadata("design:type", target, prop);
|
|
669
564
|
if (type?.prototype) {
|
|
670
|
-
|
|
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
|
+
}
|
|
671
569
|
}
|
|
672
570
|
}
|
|
673
571
|
return { allProps, newData };
|
|
674
572
|
}
|
|
675
|
-
export function getMetadataRecursive(metaKey,
|
|
676
|
-
let proto = target;
|
|
573
|
+
export function getMetadataRecursive(metaKey, proto, prop) {
|
|
677
574
|
while (proto) {
|
|
678
575
|
const meta = Reflect.getMetadata(metaKey, proto, prop);
|
|
679
|
-
if (meta
|
|
576
|
+
if (meta)
|
|
680
577
|
return meta;
|
|
681
578
|
proto = Object.getPrototypeOf(proto);
|
|
682
579
|
}
|