@prestizni-software/client-dem 0.7.2 → 0.7.5
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/AutoUpdateClientManagerClass.d.ts +92 -1
- package/dist/AutoUpdateClientManagerClass.js +106 -16
- package/dist/AutoUpdateClientManagerClass.js.map +1 -1
- package/dist/AutoUpdateManagerClass.d.ts +67 -1
- package/dist/AutoUpdateManagerClass.js +39 -2
- package/dist/AutoUpdateManagerClass.js.map +1 -1
- package/dist/AutoUpdatedClientObjectClass.d.ts +119 -1
- package/dist/AutoUpdatedClientObjectClass.js +127 -10
- package/dist/AutoUpdatedClientObjectClass.js.map +1 -1
- package/dist/CommonTypes.d.ts +56 -1
- package/dist/CommonTypes.js +48 -1
- package/dist/CommonTypes.js.map +1 -1
- package/dist/DEMErrors.d.ts +89 -0
- package/dist/DEMErrors.js +155 -0
- package/dist/DEMErrors.js.map +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -1
- package/dist/sync/ClientStateReconciler.d.ts +20 -0
- package/dist/sync/ClientStateReconciler.js +20 -0
- package/dist/sync/ClientStateReconciler.js.map +1 -1
- package/dist/sync/ServerChangeTracker.d.ts +46 -0
- package/dist/sync/ServerChangeTracker.js +46 -0
- package/dist/sync/ServerChangeTracker.js.map +1 -1
- package/dist/sync/storage/IndexedDbStorageAdapter.d.ts +31 -0
- package/dist/sync/storage/IndexedDbStorageAdapter.js +33 -1
- package/dist/sync/storage/IndexedDbStorageAdapter.js.map +1 -1
- package/dist/sync/storage/LocalStorageAdapter.d.ts +32 -0
- package/dist/sync/storage/LocalStorageAdapter.js +32 -0
- package/dist/sync/storage/LocalStorageAdapter.js.map +1 -1
- package/dist/sync/storage/MemoryStorageAdapter.d.ts +21 -0
- package/dist/sync/storage/MemoryStorageAdapter.js +21 -1
- package/dist/sync/storage/MemoryStorageAdapter.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { globalCache, } from "./CommonTypes.js";
|
|
1
|
+
import { globalCache, DEMError, DEMErrorCode, } from "./CommonTypes.js";
|
|
2
2
|
import "reflect-metadata";
|
|
3
3
|
export class AutoUpdateManager {
|
|
4
4
|
isLoaded_ = false;
|
|
@@ -19,9 +19,21 @@ export class AutoUpdateManager {
|
|
|
19
19
|
warn: () => { },
|
|
20
20
|
};
|
|
21
21
|
emitter;
|
|
22
|
+
/**
|
|
23
|
+
* Initializes the base AutoUpdateManager instance.
|
|
24
|
+
* Extracts registered property metadata from the class prototype.
|
|
25
|
+
*
|
|
26
|
+
* @param classParam - The constructor function of the managed object class.
|
|
27
|
+
* @param className - The name identifier of the managed class.
|
|
28
|
+
* @param socket - The socket instance (client Socket.IO or server Server).
|
|
29
|
+
* @param loggers - Logging interfaces for info, debug, warn, and error levels.
|
|
30
|
+
* @param managers - Registry of sibling managers.
|
|
31
|
+
* @param emitter - Event emitter for manager and lifecycle events.
|
|
32
|
+
* @throws {DEMError} Throws DEMErrorCode.MISSING_ARGUMENT when classParam is omitted.
|
|
33
|
+
*/
|
|
22
34
|
constructor(classParam, className, socket, loggers, managers, emitter) {
|
|
23
35
|
if (!classParam)
|
|
24
|
-
throw new
|
|
36
|
+
throw new DEMError(DEMErrorCode.MISSING_ARGUMENT, "Missing required argument: classParam");
|
|
25
37
|
this.className = className;
|
|
26
38
|
this.managers = managers;
|
|
27
39
|
this.emitter = emitter;
|
|
@@ -43,9 +55,17 @@ export class AutoUpdateManager {
|
|
|
43
55
|
this.loggers.error = (s) => loggers.error?.("[DEM - " + className + " MANAGER] " + s);
|
|
44
56
|
this.loggers.warn = (s) => loggers.warn?.("[DEM - " + className + " MANAGER] " + s);
|
|
45
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Indicates whether the manager has completed its initialization and reference loading.
|
|
60
|
+
*
|
|
61
|
+
* @returns True when the manager is fully loaded.
|
|
62
|
+
*/
|
|
46
63
|
get isLoaded() {
|
|
47
64
|
return this.isLoaded_;
|
|
48
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Closes the manager, purges cached objects, and disconnects the underlying socket.
|
|
68
|
+
*/
|
|
49
69
|
close() {
|
|
50
70
|
for (const id of this.objectIDs) {
|
|
51
71
|
delete this.objects_[id];
|
|
@@ -55,10 +75,22 @@ export class AutoUpdateManager {
|
|
|
55
75
|
this.socket.disconnectSockets?.(true);
|
|
56
76
|
this.loggers.info("Goodbye, see you next time!");
|
|
57
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Asynchronously loads unresolved references across all managed objects.
|
|
80
|
+
* Marks the manager as loaded upon completion.
|
|
81
|
+
*
|
|
82
|
+
* @returns A promise that resolves when all references are loaded.
|
|
83
|
+
*/
|
|
58
84
|
async loadReferences() {
|
|
59
85
|
await Promise.all(this.objectsAsArray.map((obj) => obj.loadMissingReferences()));
|
|
60
86
|
this.isLoaded_ = true;
|
|
61
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Deletes an object by its identifier, destroys the instance, and clears global caches.
|
|
90
|
+
*
|
|
91
|
+
* @param _id - The unique identifier of the object to delete.
|
|
92
|
+
* @returns A promise resolving to the deletion result object.
|
|
93
|
+
*/
|
|
62
94
|
async deleteObject(_id) {
|
|
63
95
|
const _idStr = _id.toString();
|
|
64
96
|
const o = this.objects_[_idStr];
|
|
@@ -73,6 +105,11 @@ export class AutoUpdateManager {
|
|
|
73
105
|
o?.callbacks?.delete?.(this);
|
|
74
106
|
return res ?? { success: true, message: "Already gone" };
|
|
75
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Retrieves an array of all managed object string identifiers.
|
|
110
|
+
*
|
|
111
|
+
* @returns Array of object ID strings.
|
|
112
|
+
*/
|
|
76
113
|
get objectIDs() {
|
|
77
114
|
return Object.keys(this.objects_);
|
|
78
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutoUpdateManagerClass.js","sourceRoot":"","sources":["../AutoUpdateManagerClass.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,WAAW,
|
|
1
|
+
{"version":3,"file":"AutoUpdateManagerClass.js","sourceRoot":"","sources":["../AutoUpdateManagerClass.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
|
-
import { Constructor, EventEmitter3, IsData, LoggersType, PathValueOf, ServerUpdateRequest, Paths, ExtractedData, MongoId, IAutoUpdatedClientObject, IAutoUpdatedClientObjectBase, IAutoUpdateManager, DEMCache } from "./CommonTypes.js";
|
|
2
|
+
import { Constructor, EventEmitter3, IsData, LoggersType, PathValueOf, ServerUpdateRequest, Paths, ExtractedData, MongoId, IAutoUpdatedClientObject, IAutoUpdatedClientObjectBase, IAutoUpdateManager, DEMCache, DEMErrorCode } from "./CommonTypes.js";
|
|
3
3
|
import { ObjectId } from "bson";
|
|
4
4
|
import { Socket } from "socket.io-client";
|
|
5
5
|
export type DEMClientCallbacks<T extends object> = {
|
|
@@ -36,13 +36,62 @@ export declare abstract class AutoUpdatedClientObject<T extends IAutoUpdatedClie
|
|
|
36
36
|
}[];
|
|
37
37
|
callbacks: DEMClientCallbacks<T>;
|
|
38
38
|
private readonly loadReferencesAsync;
|
|
39
|
+
/**
|
|
40
|
+
* Initializes an AutoUpdatedClientObject instance.
|
|
41
|
+
*
|
|
42
|
+
* @param classParam - Constructor of the client object entity.
|
|
43
|
+
* @param socket - Socket.IO client socket connection.
|
|
44
|
+
* @param data - Entity identifier string or initial data object.
|
|
45
|
+
* @param loggers - Logging interfaces.
|
|
46
|
+
* @param className - Managed entity class name.
|
|
47
|
+
* @param parentManager - Host client manager.
|
|
48
|
+
* @param callback - Event callbacks interface.
|
|
49
|
+
* @param emitter - Shared event emitter.
|
|
50
|
+
* @param isServer - Flag indicating whether running on server runtime.
|
|
51
|
+
* @throws {DEMError} Throws DEMErrorCode.MISSING_ARGUMENT when required parameters are omitted.
|
|
52
|
+
*/
|
|
39
53
|
constructor(classParam?: Constructor<T>, socket?: SocketType, data?: string | IsData<T>, loggers?: LoggersType, className?: string, parentManager?: IAutoUpdateManager<IAutoUpdatedClientObject<any>>, callback?: DEMClientCallbacks<T>, emitter?: EventEmitter3, isServer?: boolean);
|
|
54
|
+
/**
|
|
55
|
+
* Normalizes reference fields in entity data into string IDs.
|
|
56
|
+
*
|
|
57
|
+
* @param data - Entity data payload.
|
|
58
|
+
* @returns Cleaned entity data payload.
|
|
59
|
+
*/
|
|
40
60
|
protected handleDataCleanup(data: IsData<T>): IsData<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Pauses execution until the object finishes asynchronous preloading.
|
|
63
|
+
*
|
|
64
|
+
* @param timeoutMs - Maximum milliseconds to wait before rejecting.
|
|
65
|
+
* @throws {DEMError} Throws DEMErrorCode.PRELOAD_TIMEOUT on timeout or OBJECT_LOAD_FAILED on failure.
|
|
66
|
+
*/
|
|
41
67
|
waitForPreloaded(timeoutMs?: number): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Emits creation event to the server socket and awaits populated entity response.
|
|
70
|
+
*
|
|
71
|
+
* @param data - Initial data payload.
|
|
72
|
+
*/
|
|
42
73
|
protected handleNewObject(data: IsData<T>): void;
|
|
74
|
+
/**
|
|
75
|
+
* Returns a deep clone of the entity's extracted data with reference objects converted to IDs.
|
|
76
|
+
*
|
|
77
|
+
* @returns Serialized entity representation.
|
|
78
|
+
*/
|
|
43
79
|
get extractedData(): ExtractedData<T, IAutoUpdatedClientObject<any>>;
|
|
80
|
+
/**
|
|
81
|
+
* Indicates whether the entity has finished loading its data.
|
|
82
|
+
*
|
|
83
|
+
* @returns True if loaded.
|
|
84
|
+
*/
|
|
44
85
|
get isLoaded(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Asynchronously awaits preloading and loads all missing reference links.
|
|
88
|
+
*
|
|
89
|
+
* @returns Promise resolving to true when completed.
|
|
90
|
+
*/
|
|
45
91
|
isPreLoadedAsync(): Promise<boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* Identifies and connects missing cross-entity references on server startup.
|
|
94
|
+
*/
|
|
46
95
|
loadMissingReferences(): Promise<void>;
|
|
47
96
|
private openSockets;
|
|
48
97
|
private handleUpdateRequest;
|
|
@@ -51,21 +100,55 @@ export declare abstract class AutoUpdatedClientObject<T extends IAutoUpdatedClie
|
|
|
51
100
|
get updateEventName(): string;
|
|
52
101
|
getRawId(key: string): string | undefined;
|
|
53
102
|
generateSettersAndGetters(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Retrieves a property value by dot-notated or shallow key path.
|
|
105
|
+
*
|
|
106
|
+
* @param key_ - Property key or dot-delimited path.
|
|
107
|
+
* @returns Value at the requested path.
|
|
108
|
+
*/
|
|
54
109
|
getValue<K extends Paths<T, IAutoUpdatedClientObject<any>>>(key_: K): PathValueOf<T, K>;
|
|
55
110
|
getValue(key_: string): any;
|
|
111
|
+
/**
|
|
112
|
+
* Resolves reference pointer ID to instantiated entity instance across caches and managers.
|
|
113
|
+
*
|
|
114
|
+
* @param id - Entity ID or ObjectId.
|
|
115
|
+
* @param key - Property key referencing the entity.
|
|
116
|
+
* @returns Resolved entity instance or undefined.
|
|
117
|
+
*/
|
|
56
118
|
findReference(id: string | ObjectId, key: string): IAutoUpdatedClientObject<any> | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Mutates property value and synchronizes change to the server via socket.
|
|
121
|
+
*
|
|
122
|
+
* @param key - Property key to modify.
|
|
123
|
+
* @param val - Value to assign.
|
|
124
|
+
* @returns Promise resolving to modification result.
|
|
125
|
+
*/
|
|
57
126
|
setValue<K extends string>(key: K, val: PathValueOf<IsData<T>, K>): Promise<{
|
|
58
127
|
success: boolean;
|
|
59
128
|
msg: string;
|
|
129
|
+
code?: DEMErrorCode;
|
|
60
130
|
}>;
|
|
131
|
+
/**
|
|
132
|
+
* Internal setter with writeQueue serialization ensuring sequential updates.
|
|
133
|
+
*
|
|
134
|
+
* @param key - Property key.
|
|
135
|
+
* @param val - Value to assign.
|
|
136
|
+
* @param silent - Whether socket broadcast is bypassed.
|
|
137
|
+
* @param noGet - Whether local update bypasses get.
|
|
138
|
+
* @param noUpdate - Whether onUpdate hook is bypassed.
|
|
139
|
+
* @param isParentUpdate - Whether mutation originated from parent.
|
|
140
|
+
* @returns Promise resolving to operation outcome.
|
|
141
|
+
*/
|
|
61
142
|
protected setValue__(key: string, val: unknown, silent?: boolean, noGet?: boolean, noUpdate?: boolean, isParentUpdate?: boolean): Promise<{
|
|
62
143
|
success: boolean;
|
|
63
144
|
msg: string;
|
|
145
|
+
code?: DEMErrorCode;
|
|
64
146
|
}>;
|
|
65
147
|
private setValueQueueInternal;
|
|
66
148
|
protected setValueInternal(key: string, value: unknown, silent?: boolean, noUpdate?: boolean): Promise<{
|
|
67
149
|
success: boolean;
|
|
68
150
|
msg: string;
|
|
151
|
+
code?: DEMErrorCode;
|
|
69
152
|
}>;
|
|
70
153
|
protected makeUpdate(key: string, value: unknown): ServerUpdateRequest<T>;
|
|
71
154
|
protected resolveReference(id: string): Promise<IAutoUpdatedClientObject<any> | null>;
|
|
@@ -74,24 +157,59 @@ export declare abstract class AutoUpdatedClientObject<T extends IAutoUpdatedClie
|
|
|
74
157
|
destroyImmediate(): void;
|
|
75
158
|
private loadForceReferences;
|
|
76
159
|
protected createdWithParent(pointer: string[], parent: Record<string, unknown>): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Destroys the entity and notifies server socket of deletion.
|
|
162
|
+
*
|
|
163
|
+
* @param once - Internal flag preventing infinite recursion.
|
|
164
|
+
* @returns Promise resolving to deletion outcome.
|
|
165
|
+
*/
|
|
77
166
|
destroy(once?: boolean): Promise<{
|
|
78
167
|
success: boolean;
|
|
79
168
|
message: string;
|
|
169
|
+
code?: DEMErrorCode;
|
|
80
170
|
}>;
|
|
81
171
|
private checkForMissingRefs;
|
|
82
172
|
private findMissingObjectReference;
|
|
173
|
+
/**
|
|
174
|
+
* Triggers missing reference resolution on all child referenced entities.
|
|
175
|
+
*/
|
|
83
176
|
contactChildren(): Promise<void>;
|
|
84
177
|
protected onUpdate(noUpdate?: boolean, key?: string): Promise<void>;
|
|
85
178
|
protected onDeletion(): Promise<void>;
|
|
86
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Traverses entity object and transforms referenced objects into string identifiers.
|
|
182
|
+
*
|
|
183
|
+
* @param instance - Raw entity data record.
|
|
184
|
+
* @param target - Reflection prototype target.
|
|
185
|
+
* @param prefix - Dot-notated property key prefix.
|
|
186
|
+
* @param allProps - Accumulated array of discovered property paths.
|
|
187
|
+
* @param newData - Output object receiving sanitized data.
|
|
188
|
+
* @param loggers - Logging interfaces.
|
|
189
|
+
* @returns Object containing all property paths and transformed newData.
|
|
190
|
+
*/
|
|
87
191
|
export declare function processIsRefProperties(instance: Record<string, unknown>, target: object, prefix: string | null, allProps: string[], newData: Record<string, unknown>, loggers: LoggersType): {
|
|
88
192
|
allProps: string[];
|
|
89
193
|
newData: Record<string, unknown>;
|
|
90
194
|
};
|
|
195
|
+
/**
|
|
196
|
+
* Compiles V8 fast-shape property getters and setters on the class prototype.
|
|
197
|
+
*
|
|
198
|
+
* @param classParam - Constructor function of the target entity class.
|
|
199
|
+
* @returns Cached metadata object with properties list, refProps set, and refsToMap.
|
|
200
|
+
*/
|
|
91
201
|
export declare function setupClassAccessors(classParam: Constructor<any>): {
|
|
92
202
|
properties: string[];
|
|
93
203
|
refProps: Set<string>;
|
|
94
204
|
refsToMap: Map<string, string>;
|
|
95
205
|
};
|
|
206
|
+
/**
|
|
207
|
+
* Traverses prototype chain recursively to resolve metadata key.
|
|
208
|
+
*
|
|
209
|
+
* @param metaKey - Reflection metadata key.
|
|
210
|
+
* @param proto - Prototype object.
|
|
211
|
+
* @param prop - Property name on prototype.
|
|
212
|
+
* @returns Metadata value or undefined.
|
|
213
|
+
*/
|
|
96
214
|
export declare function getMetadataRecursive(metaKey: string, proto: object | null, prop: string): unknown;
|
|
97
215
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
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.js";
|
|
3
|
+
import { EVENT_INTERNAL_PRE_LOADED, EVENT_DELETE, EVENT_GET, EVENT_NEW, EVENT_UPDATE, globalCache, DEMError, DEMErrorCode, toDEMError, } from "./CommonTypes.js";
|
|
4
4
|
import { ObjectId } from "bson";
|
|
5
5
|
export class AutoUpdatedClientObject {
|
|
6
6
|
entry;
|
|
@@ -45,6 +45,20 @@ export class AutoUpdatedClientObject {
|
|
|
45
45
|
this.isLoadingReferences = false;
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Initializes an AutoUpdatedClientObject instance.
|
|
50
|
+
*
|
|
51
|
+
* @param classParam - Constructor of the client object entity.
|
|
52
|
+
* @param socket - Socket.IO client socket connection.
|
|
53
|
+
* @param data - Entity identifier string or initial data object.
|
|
54
|
+
* @param loggers - Logging interfaces.
|
|
55
|
+
* @param className - Managed entity class name.
|
|
56
|
+
* @param parentManager - Host client manager.
|
|
57
|
+
* @param callback - Event callbacks interface.
|
|
58
|
+
* @param emitter - Shared event emitter.
|
|
59
|
+
* @param isServer - Flag indicating whether running on server runtime.
|
|
60
|
+
* @throws {DEMError} Throws DEMErrorCode.MISSING_ARGUMENT when required parameters are omitted.
|
|
61
|
+
*/
|
|
48
62
|
constructor(classParam, socket, data, loggers, className, parentManager, callback, emitter, isServer = false) {
|
|
49
63
|
if (!classParam ||
|
|
50
64
|
!socket ||
|
|
@@ -72,7 +86,7 @@ export class AutoUpdatedClientObject {
|
|
|
72
86
|
!emitter)
|
|
73
87
|
return;
|
|
74
88
|
else
|
|
75
|
-
throw new
|
|
89
|
+
throw new DEMError(DEMErrorCode.MISSING_ARGUMENT, "Missing arguments for AutoUpdatedClientObject: " + className);
|
|
76
90
|
}
|
|
77
91
|
this.classParam = classParam;
|
|
78
92
|
this.socket = socket;
|
|
@@ -135,6 +149,12 @@ export class AutoUpdatedClientObject {
|
|
|
135
149
|
this.generateSettersAndGetters();
|
|
136
150
|
});
|
|
137
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Normalizes reference fields in entity data into string IDs.
|
|
154
|
+
*
|
|
155
|
+
* @param data - Entity data payload.
|
|
156
|
+
* @returns Cleaned entity data payload.
|
|
157
|
+
*/
|
|
138
158
|
handleDataCleanup(data) {
|
|
139
159
|
if (!data || typeof data !== "object")
|
|
140
160
|
return data;
|
|
@@ -169,9 +189,15 @@ export class AutoUpdatedClientObject {
|
|
|
169
189
|
}
|
|
170
190
|
return data;
|
|
171
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Pauses execution until the object finishes asynchronous preloading.
|
|
194
|
+
*
|
|
195
|
+
* @param timeoutMs - Maximum milliseconds to wait before rejecting.
|
|
196
|
+
* @throws {DEMError} Throws DEMErrorCode.PRELOAD_TIMEOUT on timeout or OBJECT_LOAD_FAILED on failure.
|
|
197
|
+
*/
|
|
172
198
|
async waitForPreloaded(timeoutMs = 15000) {
|
|
173
199
|
if (this.loadError)
|
|
174
|
-
throw new
|
|
200
|
+
throw new DEMError(DEMErrorCode.OBJECT_LOAD_FAILED, this.loadError);
|
|
175
201
|
if (this.isLoaded)
|
|
176
202
|
return;
|
|
177
203
|
await new Promise((resolve, reject) => {
|
|
@@ -179,17 +205,22 @@ export class AutoUpdatedClientObject {
|
|
|
179
205
|
const errorMsg = `Timeout waiting for object preloading (${this.className})`;
|
|
180
206
|
this.loadError = errorMsg;
|
|
181
207
|
this.isLoading = false;
|
|
182
|
-
reject(new
|
|
208
|
+
reject(new DEMError(DEMErrorCode.PRELOAD_TIMEOUT, errorMsg));
|
|
183
209
|
}, timeoutMs);
|
|
184
210
|
this.emitter.once(EVENT_INTERNAL_PRE_LOADED + this.EmitterID, (failed, reason) => {
|
|
185
211
|
clearTimeout(timer);
|
|
186
212
|
if (failed)
|
|
187
|
-
reject(new
|
|
213
|
+
reject(new DEMError(DEMErrorCode.OBJECT_LOAD_FAILED, reason));
|
|
188
214
|
else
|
|
189
215
|
resolve();
|
|
190
216
|
});
|
|
191
217
|
});
|
|
192
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Emits creation event to the server socket and awaits populated entity response.
|
|
221
|
+
*
|
|
222
|
+
* @param data - Initial data payload.
|
|
223
|
+
*/
|
|
193
224
|
handleNewObject(data) {
|
|
194
225
|
this.isLoading = true;
|
|
195
226
|
if (!this.socket) {
|
|
@@ -235,18 +266,36 @@ export class AutoUpdatedClientObject {
|
|
|
235
266
|
this.openSockets();
|
|
236
267
|
});
|
|
237
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Returns a deep clone of the entity's extracted data with reference objects converted to IDs.
|
|
271
|
+
*
|
|
272
|
+
* @returns Serialized entity representation.
|
|
273
|
+
*/
|
|
238
274
|
get extractedData() {
|
|
239
275
|
const extracted = processIsRefProperties(this.data, this, null, [], {}, this.loggers).newData;
|
|
240
276
|
return _.cloneDeep(extracted);
|
|
241
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Indicates whether the entity has finished loading its data.
|
|
280
|
+
*
|
|
281
|
+
* @returns True if loaded.
|
|
282
|
+
*/
|
|
242
283
|
get isLoaded() {
|
|
243
284
|
return !this.isLoading;
|
|
244
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Asynchronously awaits preloading and loads all missing reference links.
|
|
288
|
+
*
|
|
289
|
+
* @returns Promise resolving to true when completed.
|
|
290
|
+
*/
|
|
245
291
|
async isPreLoadedAsync() {
|
|
246
292
|
await this.loadReferencesAsync();
|
|
247
293
|
this.generateSettersAndGetters();
|
|
248
294
|
return true;
|
|
249
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Identifies and connects missing cross-entity references on server startup.
|
|
298
|
+
*/
|
|
250
299
|
async loadMissingReferences() {
|
|
251
300
|
if (!this.isServer)
|
|
252
301
|
return;
|
|
@@ -332,6 +381,13 @@ export class AutoUpdatedClientObject {
|
|
|
332
381
|
}
|
|
333
382
|
return value;
|
|
334
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Resolves reference pointer ID to instantiated entity instance across caches and managers.
|
|
386
|
+
*
|
|
387
|
+
* @param id - Entity ID or ObjectId.
|
|
388
|
+
* @param key - Property key referencing the entity.
|
|
389
|
+
* @returns Resolved entity instance or undefined.
|
|
390
|
+
*/
|
|
335
391
|
findReference(id, key) {
|
|
336
392
|
if (!id)
|
|
337
393
|
return undefined;
|
|
@@ -359,9 +415,27 @@ export class AutoUpdatedClientObject {
|
|
|
359
415
|
}
|
|
360
416
|
return undefined;
|
|
361
417
|
}
|
|
418
|
+
/**
|
|
419
|
+
* Mutates property value and synchronizes change to the server via socket.
|
|
420
|
+
*
|
|
421
|
+
* @param key - Property key to modify.
|
|
422
|
+
* @param val - Value to assign.
|
|
423
|
+
* @returns Promise resolving to modification result.
|
|
424
|
+
*/
|
|
362
425
|
async setValue(key, val) {
|
|
363
426
|
return await this.setValue__(key, val);
|
|
364
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Internal setter with writeQueue serialization ensuring sequential updates.
|
|
430
|
+
*
|
|
431
|
+
* @param key - Property key.
|
|
432
|
+
* @param val - Value to assign.
|
|
433
|
+
* @param silent - Whether socket broadcast is bypassed.
|
|
434
|
+
* @param noGet - Whether local update bypasses get.
|
|
435
|
+
* @param noUpdate - Whether onUpdate hook is bypassed.
|
|
436
|
+
* @param isParentUpdate - Whether mutation originated from parent.
|
|
437
|
+
* @returns Promise resolving to operation outcome.
|
|
438
|
+
*/
|
|
365
439
|
async setValue__(key, val, silent = false, noGet = false, noUpdate = false, isParentUpdate = false) {
|
|
366
440
|
this.writeQueue = this.writeQueue
|
|
367
441
|
.catch(() => { })
|
|
@@ -380,7 +454,7 @@ export class AutoUpdatedClientObject {
|
|
|
380
454
|
const isRef = getMetadataRecursive("isRef", this, key);
|
|
381
455
|
const pointer = getMetadataRecursive("refsTo", this, key);
|
|
382
456
|
if (pointer && !isParentUpdate && !silent && !this.isServer) {
|
|
383
|
-
throw new
|
|
457
|
+
throw new DEMError(DEMErrorCode.CANNOT_SET_REF_DIRECTLY, "Cannot set value of a reference pointer directly.");
|
|
384
458
|
}
|
|
385
459
|
let valueToStore = val;
|
|
386
460
|
if (isRef) {
|
|
@@ -411,7 +485,7 @@ export class AutoUpdatedClientObject {
|
|
|
411
485
|
(valAtKey && ObjectId.isValid(valAtKey))) {
|
|
412
486
|
const ref = await this.resolveReference(String(valAtKey));
|
|
413
487
|
if (!ref)
|
|
414
|
-
throw new
|
|
488
|
+
throw new DEMError(DEMErrorCode.REFERENCE_RESOLUTION_FAILED, "Could not resolve reference on path: " + key);
|
|
415
489
|
return await ref.setValue(path.slice(i + 1).join("."), val);
|
|
416
490
|
}
|
|
417
491
|
obj = obj[currentKey];
|
|
@@ -442,9 +516,13 @@ export class AutoUpdatedClientObject {
|
|
|
442
516
|
}
|
|
443
517
|
catch (error) {
|
|
444
518
|
this.loggers.error?.(`Error setting value ${key}: ${error instanceof Error ? error.message : String(error)}`);
|
|
519
|
+
const demErr = error instanceof DEMError
|
|
520
|
+
? error
|
|
521
|
+
: toDEMError(error, DEMErrorCode.DB_SAVE_FAILED);
|
|
445
522
|
return {
|
|
446
523
|
success: false,
|
|
447
|
-
|
|
524
|
+
code: demErr.code,
|
|
525
|
+
msg: demErr.message,
|
|
448
526
|
};
|
|
449
527
|
}
|
|
450
528
|
}
|
|
@@ -456,6 +534,7 @@ export class AutoUpdatedClientObject {
|
|
|
456
534
|
this.socket.emit(EVENT_UPDATE + this.className + id, { _id: id.toString(), key, value }, (res) => {
|
|
457
535
|
resolve({
|
|
458
536
|
success: res.success,
|
|
537
|
+
code: res.code,
|
|
459
538
|
msg: res.message ?? (res.success ? "Success" : "Error"),
|
|
460
539
|
});
|
|
461
540
|
});
|
|
@@ -465,7 +544,7 @@ export class AutoUpdatedClientObject {
|
|
|
465
544
|
const id = this.data?._id ?? this._id;
|
|
466
545
|
if (!id) {
|
|
467
546
|
this.loggers.error?.(`Probably missing the identifier ['_id'] again: ${key} = ${value}`);
|
|
468
|
-
throw new
|
|
547
|
+
throw new DEMError(DEMErrorCode.MISSING_ID, `Cannot make update for ${this.className} because _id is missing.`);
|
|
469
548
|
}
|
|
470
549
|
return { _id: id.toString(), key, value };
|
|
471
550
|
}
|
|
@@ -583,12 +662,22 @@ export class AutoUpdatedClientObject {
|
|
|
583
662
|
}
|
|
584
663
|
}
|
|
585
664
|
}
|
|
665
|
+
/**
|
|
666
|
+
* Destroys the entity and notifies server socket of deletion.
|
|
667
|
+
*
|
|
668
|
+
* @param once - Internal flag preventing infinite recursion.
|
|
669
|
+
* @returns Promise resolving to deletion outcome.
|
|
670
|
+
*/
|
|
586
671
|
async destroy(once = false) {
|
|
587
672
|
if (!once)
|
|
588
673
|
return await this.parentManager.deleteObject(this.data._id.toString());
|
|
589
674
|
return new Promise((resolve) => {
|
|
590
675
|
this.socket.emit(EVENT_DELETE + this.className, this.data._id, (res) => {
|
|
591
|
-
resolve({
|
|
676
|
+
resolve({
|
|
677
|
+
success: res.success,
|
|
678
|
+
code: res.code,
|
|
679
|
+
message: res.message ?? "",
|
|
680
|
+
});
|
|
592
681
|
});
|
|
593
682
|
});
|
|
594
683
|
}
|
|
@@ -638,6 +727,9 @@ export class AutoUpdatedClientObject {
|
|
|
638
727
|
}
|
|
639
728
|
}
|
|
640
729
|
}
|
|
730
|
+
/**
|
|
731
|
+
* Triggers missing reference resolution on all child referenced entities.
|
|
732
|
+
*/
|
|
641
733
|
async contactChildren() {
|
|
642
734
|
if (!this.isServer)
|
|
643
735
|
return;
|
|
@@ -667,6 +759,17 @@ export class AutoUpdatedClientObject {
|
|
|
667
759
|
// Placeholder for server-side override
|
|
668
760
|
}
|
|
669
761
|
}
|
|
762
|
+
/**
|
|
763
|
+
* Traverses entity object and transforms referenced objects into string identifiers.
|
|
764
|
+
*
|
|
765
|
+
* @param instance - Raw entity data record.
|
|
766
|
+
* @param target - Reflection prototype target.
|
|
767
|
+
* @param prefix - Dot-notated property key prefix.
|
|
768
|
+
* @param allProps - Accumulated array of discovered property paths.
|
|
769
|
+
* @param newData - Output object receiving sanitized data.
|
|
770
|
+
* @param loggers - Logging interfaces.
|
|
771
|
+
* @returns Object containing all property paths and transformed newData.
|
|
772
|
+
*/
|
|
670
773
|
export function processIsRefProperties(instance, target, prefix, allProps, newData, loggers) {
|
|
671
774
|
const props = Reflect.getMetadata("props", target) || [];
|
|
672
775
|
for (const prop of props) {
|
|
@@ -697,6 +800,12 @@ export function processIsRefProperties(instance, target, prefix, allProps, newDa
|
|
|
697
800
|
}
|
|
698
801
|
return { allProps, newData };
|
|
699
802
|
}
|
|
803
|
+
/**
|
|
804
|
+
* Compiles V8 fast-shape property getters and setters on the class prototype.
|
|
805
|
+
*
|
|
806
|
+
* @param classParam - Constructor function of the target entity class.
|
|
807
|
+
* @returns Cached metadata object with properties list, refProps set, and refsToMap.
|
|
808
|
+
*/
|
|
700
809
|
export function setupClassAccessors(classParam) {
|
|
701
810
|
if (!classParam) {
|
|
702
811
|
return { properties: [], refProps: new Set(), refsToMap: new Map() };
|
|
@@ -782,6 +891,14 @@ export function setupClassAccessors(classParam) {
|
|
|
782
891
|
classParam.__refPropsCache = Array.from(refProps);
|
|
783
892
|
return meta;
|
|
784
893
|
}
|
|
894
|
+
/**
|
|
895
|
+
* Traverses prototype chain recursively to resolve metadata key.
|
|
896
|
+
*
|
|
897
|
+
* @param metaKey - Reflection metadata key.
|
|
898
|
+
* @param proto - Prototype object.
|
|
899
|
+
* @param prop - Property name on prototype.
|
|
900
|
+
* @returns Metadata value or undefined.
|
|
901
|
+
*/
|
|
785
902
|
export function getMetadataRecursive(metaKey, proto, prop) {
|
|
786
903
|
while (proto) {
|
|
787
904
|
const meta = Reflect.getMetadata(metaKey, proto, prop);
|