@communecter/cocolight-api-client 1.0.60 → 1.0.61
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/cocolight-api-client.browser.js +1 -1
- package/dist/cocolight-api-client.cjs +1 -1
- package/dist/cocolight-api-client.mjs.js +1 -1
- package/dist/cocolight-api-client.vite.mjs.js +1 -1
- package/dist/cocolight-api-client.vite.mjs.js.map +1 -1
- package/package.json +1 -1
- package/src/api/BaseEntity.ts +70 -16
- package/src/api/EntityRegistry.ts +29 -3
- package/types/api/BaseEntity.d.ts +12 -1
package/package.json
CHANGED
package/src/api/BaseEntity.ts
CHANGED
|
@@ -4,6 +4,7 @@ import objectId from "bson-objectid";
|
|
|
4
4
|
import * as pkg from "file-type";
|
|
5
5
|
|
|
6
6
|
import { ApiAuthenticationError, ApiError, ApiResponseError, ApiValidationError } from "../error.js";
|
|
7
|
+
import { fromEntityJSON } from "./EntityRegistry.js";
|
|
7
8
|
import { EJSON } from "../utils/compat.js";
|
|
8
9
|
import { isReactive, isSignal, reactive } from "../utils/reactive.js";
|
|
9
10
|
|
|
@@ -734,19 +735,8 @@ export class BaseEntity<TServerData = any> {
|
|
|
734
735
|
private _removeUnserializables(obj: any, seen = new WeakSet<object>()): any {
|
|
735
736
|
if (obj === null || typeof obj !== "object") return obj;
|
|
736
737
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
// Ignore les proxys réactifs
|
|
741
|
-
if (obj.__isReactive && typeof obj.__raw === "object") {
|
|
742
|
-
return this._removeUnserializables(obj.__raw, seen);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
if (Array.isArray(obj)) {
|
|
746
|
-
return obj.map((el) => this._removeUnserializables(el, seen));
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
// Preserve native types that EJSON handles natively
|
|
738
|
+
// Check for native types BEFORE adding to WeakSet and checking for reactive proxies
|
|
739
|
+
// This prevents Date objects from being processed as regular objects
|
|
750
740
|
if (obj instanceof Date) {
|
|
751
741
|
return obj;
|
|
752
742
|
}
|
|
@@ -765,6 +755,25 @@ export class BaseEntity<TServerData = any> {
|
|
|
765
755
|
return obj;
|
|
766
756
|
}
|
|
767
757
|
|
|
758
|
+
// If the object is a BaseEntity instance, serialize it via toJSON()
|
|
759
|
+
// This ensures nested entities (like author, target in News) are properly serialized
|
|
760
|
+
if (obj instanceof BaseEntity) {
|
|
761
|
+
return obj.toJSON();
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Now check for circular references
|
|
765
|
+
if (seen.has(obj)) return null;
|
|
766
|
+
seen.add(obj);
|
|
767
|
+
|
|
768
|
+
// Ignore les proxys réactifs
|
|
769
|
+
if (obj.__isReactive && typeof obj.__raw === "object") {
|
|
770
|
+
return this._removeUnserializables(obj.__raw, seen);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (Array.isArray(obj)) {
|
|
774
|
+
return obj.map((el) => this._removeUnserializables(el, seen));
|
|
775
|
+
}
|
|
776
|
+
|
|
768
777
|
const clean: Record<string, any> = {};
|
|
769
778
|
for (const key of Object.keys(obj)) {
|
|
770
779
|
const val = obj[key];
|
|
@@ -790,12 +799,57 @@ export class BaseEntity<TServerData = any> {
|
|
|
790
799
|
|
|
791
800
|
/**
|
|
792
801
|
* Restaure les données sérialisées en un objet d'origine.
|
|
802
|
+
* Désérialise récursivement les entités imbriquées qui ont le marqueur __isSerializedEntity.
|
|
793
803
|
*
|
|
794
804
|
* @param obj - L'objet à restaurer.
|
|
805
|
+
* @param parent - Instance parente optionnelle pour désérialiser les entités imbriquées.
|
|
795
806
|
* @returns L'objet restauré.
|
|
796
807
|
*/
|
|
797
|
-
static _revive(obj: object): any {
|
|
798
|
-
|
|
808
|
+
static _revive(obj: object, parent?: ApiClient | BaseEntity<any> | null): any {
|
|
809
|
+
// D'abord, restaurer les dates EJSON
|
|
810
|
+
const revived = EJSON.fromJSONValue(obj);
|
|
811
|
+
|
|
812
|
+
// Ensuite, parcourir récursivement pour désérialiser les entités imbriquées
|
|
813
|
+
return this._deserializeNestedEntities(revived, parent);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Parcourt récursivement un objet et désérialise les entités imbriquées.
|
|
818
|
+
*
|
|
819
|
+
* @param obj - L'objet à parcourir.
|
|
820
|
+
* @param parent - Instance parente pour les entités.
|
|
821
|
+
* @returns L'objet avec les entités désérialisées.
|
|
822
|
+
* @private
|
|
823
|
+
*/
|
|
824
|
+
private static _deserializeNestedEntities(obj: any, parent?: ApiClient | BaseEntity<any> | null): any {
|
|
825
|
+
if (obj === null || typeof obj !== "object") {
|
|
826
|
+
return obj;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Si c'est un objet Date, RegExp, ou autre type natif, le retourner tel quel
|
|
830
|
+
if (obj instanceof Date || obj instanceof RegExp) {
|
|
831
|
+
return obj;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Si c'est un array, parcourir chaque élément
|
|
835
|
+
if (Array.isArray(obj)) {
|
|
836
|
+
return obj.map(item => this._deserializeNestedEntities(item, parent));
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// Si c'est une entité sérialisée, la désérialiser
|
|
840
|
+
// On vérifie les marqueurs d'une entité sérialisée
|
|
841
|
+
if (obj.__isSerializedEntity && obj.__entityTag && obj.serverData) {
|
|
842
|
+
// Désérialiser l'entité imbriquée via EntityRegistry
|
|
843
|
+
return fromEntityJSON(obj, parent);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// Sinon, parcourir les propriétés de l'objet et désérialiser récursivement
|
|
847
|
+
const result: any = {};
|
|
848
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
849
|
+
result[key] = this._deserializeNestedEntities(value, parent);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
return result;
|
|
799
853
|
}
|
|
800
854
|
|
|
801
855
|
/**
|
|
@@ -816,7 +870,7 @@ export class BaseEntity<TServerData = any> {
|
|
|
816
870
|
}
|
|
817
871
|
const { serverData } = json as { serverData: object };
|
|
818
872
|
|
|
819
|
-
const instance = this.fromServerData(this._revive(serverData), parent as ApiClient | ParentLike, deps || {});
|
|
873
|
+
const instance = this.fromServerData(this._revive(serverData, parent), parent as ApiClient | ParentLike, deps || {});
|
|
820
874
|
|
|
821
875
|
return instance;
|
|
822
876
|
}
|
|
@@ -57,10 +57,18 @@ export function fromEntityJSON(json: unknown, parent: ApiClient | BaseEntity | n
|
|
|
57
57
|
// On gère null / non-objet / pas une entité → on renvoie tel quel (ou null si tu préfères)
|
|
58
58
|
if (!isEntityJSON(json)) return json;
|
|
59
59
|
|
|
60
|
-
//
|
|
61
|
-
|
|
60
|
+
// Récupérer la collection depuis serverData, ou la dériver depuis __entityTag
|
|
61
|
+
let collection: CollectionKey | null | undefined = json.serverData?.collection;
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
// Si collection est absente, essayer de la dériver depuis __entityTag
|
|
64
|
+
if (!collection) {
|
|
65
|
+
collection = _getCollectionFromTag(json.__entityTag);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Si on n'a toujours pas de collection, on ne peut pas désérialiser
|
|
69
|
+
if (!collection) return json;
|
|
70
|
+
|
|
71
|
+
const meta = _getEntityMeta(collection, json.__entityTag);
|
|
64
72
|
if (!meta) return json;
|
|
65
73
|
|
|
66
74
|
if (!meta.entityClass?.fromJSON) {
|
|
@@ -69,6 +77,24 @@ export function fromEntityJSON(json: unknown, parent: ApiClient | BaseEntity | n
|
|
|
69
77
|
return meta.entityClass.fromJSON(json, parent, meta.deps);
|
|
70
78
|
}
|
|
71
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Mappe un EntityTag vers son CollectionKey correspondant.
|
|
82
|
+
*/
|
|
83
|
+
function _getCollectionFromTag(tag: EntityTag): CollectionKey | null {
|
|
84
|
+
const map: Record<EntityTag, CollectionKey> = {
|
|
85
|
+
"User": "citoyens",
|
|
86
|
+
"Organization": "organizations",
|
|
87
|
+
"Project": "projects",
|
|
88
|
+
"Event": "events",
|
|
89
|
+
"Poi": "poi",
|
|
90
|
+
"News": "news",
|
|
91
|
+
"Badge": "badges",
|
|
92
|
+
"Comment": "comments",
|
|
93
|
+
"Answer": "answers"
|
|
94
|
+
};
|
|
95
|
+
return map[tag] || null;
|
|
96
|
+
}
|
|
97
|
+
|
|
72
98
|
/**
|
|
73
99
|
* Récupère la classe d'entité et ses dépendances à partir du type d'entité.
|
|
74
100
|
*/
|
|
@@ -328,11 +328,22 @@ export declare class BaseEntity<TServerData = any> {
|
|
|
328
328
|
private _removeUnserializables;
|
|
329
329
|
/**
|
|
330
330
|
* Restaure les données sérialisées en un objet d'origine.
|
|
331
|
+
* Désérialise récursivement les entités imbriquées qui ont le marqueur __isSerializedEntity.
|
|
331
332
|
*
|
|
332
333
|
* @param obj - L'objet à restaurer.
|
|
334
|
+
* @param parent - Instance parente optionnelle pour désérialiser les entités imbriquées.
|
|
333
335
|
* @returns L'objet restauré.
|
|
334
336
|
*/
|
|
335
|
-
static _revive(obj: object): any;
|
|
337
|
+
static _revive(obj: object, parent?: ApiClient | BaseEntity<any> | null): any;
|
|
338
|
+
/**
|
|
339
|
+
* Parcourt récursivement un objet et désérialise les entités imbriquées.
|
|
340
|
+
*
|
|
341
|
+
* @param obj - L'objet à parcourir.
|
|
342
|
+
* @param parent - Instance parente pour les entités.
|
|
343
|
+
* @returns L'objet avec les entités désérialisées.
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
346
|
+
private static _deserializeNestedEntities;
|
|
336
347
|
/**
|
|
337
348
|
* Crée une instance d'entité à partir de données JSON.
|
|
338
349
|
*
|