@nodefony/mongoose 10.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +544 -0
  2. package/README.md +97 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
  5. package/dist/index.js +90 -0
  6. package/dist/nodefony/config/config.js +57 -0
  7. package/dist/nodefony/config/defineModuleConfig.js +60 -0
  8. package/dist/nodefony/entity/sessionEntity.js +63 -0
  9. package/dist/nodefony/entity/tokenEntity.js +184 -0
  10. package/dist/nodefony/entity/userEntity.js +106 -0
  11. package/dist/nodefony/entity/webAuthnCredentialEntity.js +97 -0
  12. package/dist/nodefony/entity/webhookEndpointEntity.js +109 -0
  13. package/dist/nodefony/interfaces/IMongooseConfig.js +1 -0
  14. package/dist/nodefony/interfaces/index.js +1 -0
  15. package/dist/nodefony/registerStores.js +89 -0
  16. package/dist/nodefony/service/MongooseService.js +95 -0
  17. package/dist/nodefony/src/MongooseTokenStore.js +237 -0
  18. package/dist/nodefony/src/MongooseUserRepository.js +205 -0
  19. package/dist/nodefony/src/MongooseWebAuthnCredentialStore.js +144 -0
  20. package/dist/nodefony/src/MongooseWebhookStore.js +181 -0
  21. package/dist/nodefony/src/SessionStorage.js +241 -0
  22. package/dist/nodefony/src/mongoOrder.js +49 -0
  23. package/dist/nodefony/src/orm-core/MongooseOrm.js +440 -0
  24. package/dist/nodefony/src/orm-core/MongooseRepository.js +300 -0
  25. package/dist/nodefony/src/orm-core/MongooseTransaction.js +53 -0
  26. package/dist/nodefony/src/orm-core/index.js +4 -0
  27. package/dist/types/index.d.ts +74 -0
  28. package/dist/types/nodefony/config/config.d.ts +21 -0
  29. package/dist/types/nodefony/config/defineModuleConfig.d.ts +26 -0
  30. package/dist/types/nodefony/entity/sessionEntity.d.ts +42 -0
  31. package/dist/types/nodefony/entity/tokenEntity.d.ts +59 -0
  32. package/dist/types/nodefony/entity/userEntity.d.ts +54 -0
  33. package/dist/types/nodefony/entity/webAuthnCredentialEntity.d.ts +61 -0
  34. package/dist/types/nodefony/entity/webhookEndpointEntity.d.ts +62 -0
  35. package/dist/types/nodefony/interfaces/IMongooseConfig.d.ts +17 -0
  36. package/dist/types/nodefony/interfaces/index.d.ts +1 -0
  37. package/dist/types/nodefony/registerStores.d.ts +37 -0
  38. package/dist/types/nodefony/service/MongooseService.d.ts +48 -0
  39. package/dist/types/nodefony/src/MongooseTokenStore.d.ts +126 -0
  40. package/dist/types/nodefony/src/MongooseUserRepository.d.ts +82 -0
  41. package/dist/types/nodefony/src/MongooseWebAuthnCredentialStore.d.ts +52 -0
  42. package/dist/types/nodefony/src/MongooseWebhookStore.d.ts +72 -0
  43. package/dist/types/nodefony/src/SessionStorage.d.ts +63 -0
  44. package/dist/types/nodefony/src/mongoOrder.d.ts +40 -0
  45. package/dist/types/nodefony/src/orm-core/MongooseOrm.d.ts +132 -0
  46. package/dist/types/nodefony/src/orm-core/MongooseRepository.d.ts +51 -0
  47. package/dist/types/nodefony/src/orm-core/MongooseTransaction.d.ts +37 -0
  48. package/dist/types/nodefony/src/orm-core/index.d.ts +9 -0
  49. package/docs/configuration.md +776 -0
  50. package/docs/index.md +881 -0
  51. package/package.json +97 -0
@@ -0,0 +1,40 @@
1
+ import type { IPageQuery } from "nodefony";
2
+ /**
3
+ * **La** table d'alias du dialecte Mongo — `id` public → `_id` au repos.
4
+ *
5
+ * Elle vit ici, chez l'adapter qui possède la convention, et non dans le
6
+ * vocabulaire de chaque ressource : ce n'est pas une propriété des jetons ni des
7
+ * endpoints, c'est une propriété de **Mongo**, où la clé primaire s'appelle
8
+ * `_id` et où aucun champ `id` n'existe au repos (`id` n'est qu'un virtuel de
9
+ * lecture). Trois copies de cette même règle vivaient auparavant dans trois
10
+ * fichiers de vocabulaire, une par ressource.
11
+ *
12
+ * Ce que la traduction évite : Mongo ne se plaint **pas** d'un tri sur un champ
13
+ * absent — il rend les documents dans un ordre arbitraire. Sans elle, un
14
+ * `?order=id` serait donc silencieusement inerte sur Mongo et correct partout
15
+ * ailleurs, et l'écart ne se verrait qu'en production, chez un tiers.
16
+ */
17
+ export declare const MONGO_ORDER_ALIASES: Readonly<Record<string, string>>;
18
+ /**
19
+ * Borne un `order` reçu à ce que le store DÉCLARE savoir trier, puis l'exprime
20
+ * dans le schéma Mongo — les deux gestes que tout store Mongo doit faire, dans
21
+ * cet ordre, avant de descendre le tri au driver.
22
+ *
23
+ * L'ordre compte : filtrer d'abord (sur le vocabulaire **public**, celui que le
24
+ * store annonce), traduire ensuite. L'inverse comparerait des noms de colonnes à
25
+ * une liste de noms publics, et laisserait passer ce qu'elle est censée refuser.
26
+ *
27
+ * @param order - l'ordre demandé, en vocabulaire public.
28
+ * @param sortable - ce que le store déclare ({@link ISortableSource}).
29
+ * @param fallback - l'ordre contractuel appliqué à défaut, en vocabulaire public.
30
+ * @returns l'ordre prêt pour `.sort()` / `paginate()`, en noms de champs Mongo.
31
+ */
32
+ export declare function mongoOrder(order: IPageQuery["order"], sortable: readonly string[] | undefined, fallback: NonNullable<IPageQuery["order"]>): NonNullable<IPageQuery["order"]>;
33
+ /**
34
+ * Forme `{ champ: 1 | -1 }` attendue par `Model.sort()` — le dernier maillon,
35
+ * pour les stores qui parlent au driver Mongo directement plutôt que par
36
+ * `paginate()`.
37
+ *
38
+ * @param order - un ordre déjà borné et traduit (sortie de {@link mongoOrder}).
39
+ */
40
+ export declare function toMongoSort(order: NonNullable<IPageQuery["order"]>): Record<string, 1 | -1>;
@@ -0,0 +1,132 @@
1
+ import type { ConnectOptions } from "mongoose";
2
+ import { Orm } from "@nodefony/orm-core";
3
+ import type { IColumnInfo, IConnectionInfo, IOrmProbe, IRepository, ITransaction } from "@nodefony/orm-core";
4
+ /**
5
+ * Verdict d'index d'une entité — l'écart entre ce que le schéma DÉCLARE et ce
6
+ * que la base PORTE réellement.
7
+ *
8
+ * C'est le pendant documentaire de l'écart de schéma SQL : MongoDB n'a pas de
9
+ * DDL, mais un index unique qui n'existe pas est exactement une contrainte
10
+ * absente. Le verdict est rendu structuré parce qu'il a deux publics — le
11
+ * journal pour l'exploitant, et l'appelant (banc, sonde d'administration) qui
12
+ * doit pouvoir en décider.
13
+ */
14
+ export interface IIndexAudit {
15
+ /** Nom de l'entité (clé du `entityRegistry`). */
16
+ entity: string;
17
+ /** Collection MongoDB sous-jacente. */
18
+ collection: string;
19
+ /** Index déclarés au schéma et ABSENTS de la base — la vraie alerte. */
20
+ missing: string[];
21
+ /** Index présents en base et non déclarés — informatif, jamais supprimé. */
22
+ extra: string[];
23
+ /** Motif d'un échec de construction, quand la base l'a refusée. */
24
+ error?: string;
25
+ }
26
+ /**
27
+ * Adapter Mongoose **branché sur `@nodefony/orm-core`** (P5.4).
28
+ *
29
+ * 2ᵉ adapter, **hétérogène** au SQL : valide que le contrat enrichi
30
+ * (`relations`/`withTransaction`) est réellement portable sur un store
31
+ * documentaire. Distinct du service legacy `nodefony/service/orm.ts`.
32
+ *
33
+ * Spécificités MongoDB exposées par l'implémentation :
34
+ * - **connexion isolée** via `mongoose.createConnection` (pas le singleton global)
35
+ * → indispensable au multi-ORM (plusieurs connexions logiques) ;
36
+ * - relations sans clé étrangère SQL : `one-to-many` = **virtual populate**
37
+ * (réf ObjectId injectée sur l'enfant + virtuel sur le parent), `many-to-one`/
38
+ * `one-to-one` = champ réf sur la source. `many-to-many` → natif ;
39
+ * - transactions = **sessions** (requièrent un replica set).
40
+ */
41
+ export declare class MongooseOrm extends Orm {
42
+ #private;
43
+ /**
44
+ * Mongoose traduit les signaux de topologie du driver MongoDB (SDAM) : il
45
+ * SAIT qu'un serveur est tombé, même sans le moindre trafic — d'où
46
+ * `"events"`. C'est la seule des trois familles d'adapters du dépôt qui
47
+ * dispose d'une surveillance de serveur indépendante des requêtes.
48
+ */
49
+ get liveness(): "events" | "assumed";
50
+ /**
51
+ * @param name - clé unique de l'ORM dans le `ormRegistry`.
52
+ * @param uri - URI de connexion MongoDB (replica set requis pour les tx).
53
+ * @param options - options de connexion Mongoose (auth, pool, timeouts).
54
+ */
55
+ constructor(name: string, uri: string, options?: ConnectOptions);
56
+ protected onConnect(): Promise<void>;
57
+ /** Constat d'index de la connexion courante, ou `null` hors connexion. */
58
+ get pendingIndexAudit(): Promise<IIndexAudit[]> | null;
59
+ /**
60
+ * Constate l'écart entre les index DÉCLARÉS par les schémas et ceux que la
61
+ * base porte réellement, et journalise tout manque en `CRITIC`.
62
+ *
63
+ * **Pourquoi c'est nécessaire.** Mongoose construit les index en tâche de
64
+ * fond à la compilation des modèles, et l'issue de cette construction n'était
65
+ * écoutée par personne. Or plusieurs de ces index portent des contraintes
66
+ * d'unicité dont dépend l'authentification. Reproduit sur un serveur réel :
67
+ * une collection portant déjà des doublons fait échouer la construction de
68
+ * l'index unique — et le process continue, code de sortie 0, **sans un seul
69
+ * message**, avec pour seul index `_id_`. La contrainte n'existe pas, et rien
70
+ * ne le dit : c'est la dégradation silencieuse que la doctrine interdit.
71
+ *
72
+ * **Pourquoi APRÈS `init()`.** Un `diffIndexes()` lancé aussitôt après la
73
+ * compilation annonce comme manquants des index dont la construction est
74
+ * simplement en cours — mesuré. `init()` est le point où la construction est
75
+ * terminée, en succès comme en échec ; c'est donc là, et pas avant, que
76
+ * l'écart veut dire quelque chose.
77
+ *
78
+ * **Pourquoi ce n'est pas attendu au démarrage.** Construire un index sur une
79
+ * grosse collection prend des minutes ; faire patienter le pod changerait son
80
+ * comportement bien au-delà de ce défaut. Le constat court donc en tâche de
81
+ * fond et parle dès qu'il sait — {@link MongooseOrm.pendingIndexAudit} permet
82
+ * de l'attendre quand il le faut.
83
+ *
84
+ * **Ce que cette méthode ne fait PAS** : réparer. `syncIndexes()` de mongoose
85
+ * SUPPRIME les index non déclarés — irréversible, et catastrophique sur une
86
+ * base qu'un exploitant a indexée à la main. Réparer reste un geste explicite.
87
+ *
88
+ * @returns un verdict par entité (vide si la connexion est déjà close).
89
+ */
90
+ verifyIndexes(): Promise<IIndexAudit[]>;
91
+ disconnect(): Promise<void>;
92
+ getRepository<T = unknown>(name: string): IRepository<T>;
93
+ transaction<R>(work: (tx: ITransaction) => Promise<R>): Promise<R>;
94
+ getNativeConnection<C = unknown>(): C;
95
+ /**
96
+ * Ping bas-coût : commande `{ ping: 1 }` sur la base native (`admin().command`)
97
+ * — round-trip réel vers MongoDB pour le diagnostic du data plane.
98
+ *
99
+ * @throws si la connexion (ou sa base native) n'est pas prête, ou si la base
100
+ * ne répond pas.
101
+ */
102
+ ping(): Promise<void>;
103
+ /**
104
+ * Sonde Mongo (best-effort) : connexions du serveur (`serverStatus`) → pool.
105
+ * Round-trip réseau → uniquement pendant un abonnement actif. `{}` si indispo.
106
+ *
107
+ * @returns sonde `pool` + `extra`, ou `{}`.
108
+ */
109
+ probe(): Promise<IOrmProbe>;
110
+ /**
111
+ * Colonnes normalisées d'une entité depuis les `paths` du schéma Mongoose —
112
+ * alimente le graphe canonique / ERD / contexte IA. Pas de PK SQL : `_id` est
113
+ * la clé primaire implicite de tout document.
114
+ *
115
+ * @param name - nom logique de l'entité.
116
+ * @returns colonnes (`[]` si l'entité n'est pas connue de cet ORM).
117
+ */
118
+ describeEntity(name: string): IColumnInfo[];
119
+ /**
120
+ * Décrit la connexion : driver `mongodb` + cible (hôte:port/base, **sans
121
+ * credentials**) + version de la lib `mongoose`. Aucun secret n'est exposé
122
+ * dans le data plane (l'URI est nettoyée de tout `user:pass@`).
123
+ *
124
+ * @returns driver + cible nettoyée + version de l'ORM.
125
+ */
126
+ describeConnection(): IConnectionInfo;
127
+ /**
128
+ * Cible affichable de l'URI, **sans credentials** : `hôte:port/base`. Jamais
129
+ * de `user:pass@` (anti info-leak dans le data plane / les logs).
130
+ */
131
+ safeTarget(): string;
132
+ }
@@ -0,0 +1,51 @@
1
+ import type { ClientSession, Model } from "mongoose";
2
+ import type { Criteria, UpdateData, IRepository, ITransaction, RepositoryReadOptions } from "@nodefony/orm-core";
3
+ /** Modèle Mongoose à document libre (boundary — typé finement côté repo). */
4
+ type LooseModel = Model<Record<string, unknown>>;
5
+ /**
6
+ * Repository portable (contrat {@link IRepository}) au-dessus d'un modèle Mongoose.
7
+ *
8
+ * Démontre la portabilité du contrat sur un **store documentaire hétérogène** :
9
+ * - `options.relations` → `populate()` (virtuels/refs déclarés), pas `include` ;
10
+ * - **clé primaire `_id`** (MongoDB) ↔ `id` (contrat) : le critère `{ id }` est
11
+ * traduit en `{ _id }`, et la sortie (`toObject({ virtuals: true })`) porte le
12
+ * virtuel `id` (string hex de l'ObjectId) → contrat `id: string` respecté ;
13
+ * - liaison transactionnelle via {@link MongooseRepository.withTransaction}
14
+ * (`{ session }` sur toutes les ops ; requiert un replica set).
15
+ *
16
+ * @typeParam T - forme plate de l'entité gérée.
17
+ */
18
+ export declare class MongooseRepository<T = unknown> implements IRepository<T> {
19
+ #private;
20
+ /**
21
+ * @param model - modèle Mongoose compilé.
22
+ * @param connector - nom de la connexion (clé du registre) — défaut `"nodefony"`.
23
+ * @param session - session transactionnelle à laquelle lier les ops (ou `null`).
24
+ */
25
+ constructor(model: LooseModel, connector?: string, session?: ClientSession | null);
26
+ find(criteria?: Criteria<T>, options?: RepositoryReadOptions): Promise<T[]>;
27
+ findOne(criteria: Criteria<T>, options?: RepositoryReadOptions): Promise<T | null>;
28
+ create(data: Partial<T>): Promise<T>;
29
+ createMany(data: Partial<T>[]): Promise<T[]>;
30
+ updateOne(criteria: Criteria<T>, data: Partial<T>): Promise<T | null>;
31
+ upsert(criteria: Criteria<T>, update: UpdateData<T>, insertOnly?: Partial<T>): Promise<T>;
32
+ updateMany(criteria: Criteria<T>, data: Partial<T>): Promise<number>;
33
+ increment(criteria: Criteria<T>, changes: Partial<Record<keyof T, number>>): Promise<T | null>;
34
+ delete(criteria: Criteria<T>): Promise<number>;
35
+ deleteOne(criteria: Criteria<T>): Promise<boolean>;
36
+ findOneAndDelete(criteria: Criteria<T>): Promise<T | null>;
37
+ count(criteria?: Criteria<T>): Promise<number>;
38
+ /**
39
+ * `COUNT(DISTINCT …)` en agrégation — `$group` puis `$count`, donc la
40
+ * déduplication reste dans le serveur. `Model.distinct()` aurait rapatrié
41
+ * toutes les valeurs pour n'en mesurer que la longueur.
42
+ *
43
+ * `{$ne: null}` écarte à la fois la valeur nulle et le champ absent, ce qui
44
+ * aligne le résultat sur le `COUNT(DISTINCT col)` SQL — sans lui, les
45
+ * documents sans valeur formeraient un groupe `null` compté comme une valeur.
46
+ */
47
+ countDistinct(field: keyof T & string, criteria?: Criteria<T>): Promise<number>;
48
+ exists(criteria: Criteria<T>): Promise<boolean>;
49
+ withTransaction(tx: ITransaction): IRepository<T>;
50
+ }
51
+ export {};
@@ -0,0 +1,37 @@
1
+ import type { ClientSession } from "mongoose";
2
+ import type { ITransaction } from "@nodefony/orm-core";
3
+ /**
4
+ * Adapte une `ClientSession` MongoDB au contrat portable {@link ITransaction}.
5
+ *
6
+ * Obtenue dans le callback de `MongooseOrm.transaction()`, qui gère le
7
+ * commit/abort automatique via `session.withTransaction()`. Les transactions
8
+ * MongoDB **exigent un replica set** (un standalone ne les supporte pas).
9
+ *
10
+ * MongoDB n'a **pas de savepoints** : {@link MongooseTransaction.savepoint} /
11
+ * {@link MongooseTransaction.rollbackTo} sont des no-op documentés (limite du
12
+ * driver, prévue par le contrat).
13
+ */
14
+ export declare class MongooseTransaction implements ITransaction {
15
+ #private;
16
+ /**
17
+ * @param session - session MongoDB transactionnelle sous-jacente.
18
+ */
19
+ constructor(session: ClientSession);
20
+ /** Indique si la transaction est déjà terminée (commit ou rollback). */
21
+ isDone(): boolean;
22
+ /**
23
+ * Valide la transaction (no-op si déjà terminée — idempotent, parité avec
24
+ * `DrizzleTransaction`). En mode managé (défaut via `IOrm.transaction`), le
25
+ * commit/abort est piloté par `session.withTransaction` : un appel manuel est
26
+ * inutile, et l'idempotence évite un double-commit accidentel.
27
+ */
28
+ commit(): Promise<void>;
29
+ /** Annule la transaction (no-op si déjà terminée — idempotent). */
30
+ rollback(): Promise<void>;
31
+ /** No-op : MongoDB ne gère pas les savepoints. */
32
+ savepoint(_name: string): Promise<void>;
33
+ /** No-op : MongoDB ne gère pas les savepoints. */
34
+ rollbackTo(_name: string): Promise<void>;
35
+ /** Expose la `ClientSession` native (trappe bas niveau). */
36
+ getNative<C = unknown>(): C;
37
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Adapter Mongoose sur `@nodefony/orm-core` (P5.4).
3
+ *
4
+ * 2ᵉ adapter (store documentaire hétérogène), distinct du service legacy.
5
+ */
6
+ export { MongooseOrm } from "./MongooseOrm.js";
7
+ export type { IIndexAudit } from "./MongooseOrm.js";
8
+ export { MongooseRepository } from "./MongooseRepository.js";
9
+ export { MongooseTransaction } from "./MongooseTransaction.js";