@nodefony/orm-core 10.0.0-alpha.8 → 10.0.0-beta.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.
- package/dist/index.js +4 -3
- package/dist/nodefony/src/AbstractCrudService.js +7 -3
- package/dist/nodefony/src/ConnectionMonitor.js +41 -9
- package/dist/nodefony/src/EntityRegistry.js +9 -3
- package/dist/nodefony/src/Orm.js +19 -3
- package/dist/nodefony/src/OrmAdminApi.js +54 -12
- package/dist/nodefony/src/OrmRegistry.js +1 -1
- package/dist/nodefony/src/QueryFlowMonitor.js +2 -2
- package/dist/nodefony/src/connectDeadline.js +1 -1
- package/dist/nodefony/src/connectionDiagnosis.js +66 -6
- package/dist/nodefony/src/criteria.js +4 -3
- package/dist/nodefony/src/errors.js +59 -1
- package/dist/nodefony/src/omitUndefined.js +30 -0
- package/dist/nodefony/src/orphanEntities.js +63 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/nodefony/interfaces/IEntity.d.ts +23 -4
- package/dist/types/nodefony/interfaces/IOrm.d.ts +10 -1
- package/dist/types/nodefony/interfaces/IOrmFlow.d.ts +1 -1
- package/dist/types/nodefony/interfaces/IOrmGraph.d.ts +58 -13
- package/dist/types/nodefony/interfaces/IOrmProbe.d.ts +9 -9
- package/dist/types/nodefony/interfaces/IPage.d.ts +1 -1
- package/dist/types/nodefony/interfaces/IRepository.d.ts +12 -12
- package/dist/types/nodefony/interfaces/ITransaction.d.ts +3 -1
- package/dist/types/nodefony/interfaces/index.d.ts +2 -2
- package/dist/types/nodefony/src/AbstractCrudService.d.ts +9 -5
- package/dist/types/nodefony/src/ConnectionMonitor.d.ts +9 -2
- package/dist/types/nodefony/src/Entity.d.ts +1 -1
- package/dist/types/nodefony/src/Orm.d.ts +9 -1
- package/dist/types/nodefony/src/OrmAdminApi.d.ts +17 -1
- package/dist/types/nodefony/src/connectionDiagnosis.d.ts +29 -0
- package/dist/types/nodefony/src/decorators/entityDecorator.d.ts +1 -1
- package/dist/types/nodefony/src/decorators/metadataStore.d.ts +5 -5
- package/dist/types/nodefony/src/errors.d.ts +48 -0
- package/dist/types/nodefony/src/omitUndefined.d.ts +16 -0
- package/dist/types/nodefony/src/orphanEntities.d.ts +38 -0
- package/docs/index.md +64 -60
- package/docs/tutorial-entity.md +26 -23
- package/package.json +8 -8
|
@@ -21,7 +21,7 @@ export interface EntityOptions<S = unknown> {
|
|
|
21
21
|
*/
|
|
22
22
|
domain?: string;
|
|
23
23
|
/** Schéma natif du driver (schéma Mongoose, schéma Drizzle...). */
|
|
24
|
-
schema?: S;
|
|
24
|
+
schema?: S | undefined;
|
|
25
25
|
/** Relations déclaratives vers d'autres entités. */
|
|
26
26
|
relations?: ReadonlyArray<IEntityRelation>;
|
|
27
27
|
}
|
|
@@ -17,13 +17,13 @@ export interface EntityMetadata<S = unknown> {
|
|
|
17
17
|
/** Connexion nommée cible (clé du `ormRegistry`). */
|
|
18
18
|
readonly connector: string;
|
|
19
19
|
/** Module Nodefony propriétaire (regroupement graphe/ERD), si fourni. */
|
|
20
|
-
readonly module?: string;
|
|
20
|
+
readonly module?: string | undefined;
|
|
21
21
|
/** Classification (domaine fonctionnel), axe de regroupement distinct du module. */
|
|
22
|
-
readonly domain?: string;
|
|
22
|
+
readonly domain?: string | undefined;
|
|
23
23
|
/** Schéma natif du driver (forme libre), si fourni au décorateur. */
|
|
24
|
-
readonly schema?: S;
|
|
24
|
+
readonly schema?: S | undefined;
|
|
25
25
|
/** Relations déclaratives vers d'autres entités. */
|
|
26
|
-
readonly relations?: ReadonlyArray<IEntityRelation
|
|
26
|
+
readonly relations?: ReadonlyArray<IEntityRelation> | undefined;
|
|
27
27
|
/** Constructeur décoré (pour introspection / résolution lazy par le driver). */
|
|
28
28
|
readonly target: DecoratedClass;
|
|
29
29
|
}
|
|
@@ -36,7 +36,7 @@ export interface RepositoryMetadata {
|
|
|
36
36
|
/** Nom logique de l'entité gérée par ce repository. */
|
|
37
37
|
readonly entity: string;
|
|
38
38
|
/** Connecteur cible (lève l'ambiguïté si l'entité existe sur plusieurs connexions). */
|
|
39
|
-
readonly connector?: string;
|
|
39
|
+
readonly connector?: string | undefined;
|
|
40
40
|
/** Constructeur décoré. */
|
|
41
41
|
readonly target: DecoratedClass;
|
|
42
42
|
}
|
|
@@ -60,3 +60,51 @@ export declare class InvalidOrderOption extends Error {
|
|
|
60
60
|
*/
|
|
61
61
|
constructor(entity: string, received: string);
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Levée quand une suppression viserait une entité encore RÉFÉRENCÉE par une
|
|
65
|
+
* relation obligatoire d'une autre entité.
|
|
66
|
+
*
|
|
67
|
+
* C'est le pendant, pour un moteur sans clé étrangère (MongoDB), du `restrict`
|
|
68
|
+
* que le SQL généré pose sur une colonne de référence obligatoire : le parent
|
|
69
|
+
* ne part pas tant qu'un enfant le désigne. Sans cette garde, la suppression
|
|
70
|
+
* passait et `?include=` rendait ensuite `null` à la place du parent — une
|
|
71
|
+
* application passée du SQL à MongoDB perdait en silence une garantie qu'elle
|
|
72
|
+
* croyait avoir.
|
|
73
|
+
*
|
|
74
|
+
* Erreur de DONNÉES : c'est la surface API qui la projette (le rendu d'erreur
|
|
75
|
+
* HTTP la reconnaît par son `name` et répond 409).
|
|
76
|
+
*/
|
|
77
|
+
export declare class ReferencedEntityError extends Error {
|
|
78
|
+
/** Entité dont la suppression est refusée (nom logique). */
|
|
79
|
+
readonly entity: string;
|
|
80
|
+
/** Entité qui la référence encore (nom logique). */
|
|
81
|
+
readonly referencedBy: string;
|
|
82
|
+
/** Champ de référence de {@link ReferencedEntityError.referencedBy}. */
|
|
83
|
+
readonly field: string;
|
|
84
|
+
/**
|
|
85
|
+
* @param entity - entité dont la suppression est refusée.
|
|
86
|
+
* @param referencedBy - entité qui la référence encore.
|
|
87
|
+
* @param field - champ de référence obligatoire qui la désigne.
|
|
88
|
+
*/
|
|
89
|
+
constructor(entity: string, referencedBy: string, field: string);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Levée par `ITransaction.savepoint()` / `rollbackTo()` sur un moteur qui ne porte
|
|
93
|
+
* PAS de savepoints (MongoDB).
|
|
94
|
+
*
|
|
95
|
+
* Refuser vaut mieux que se taire : un `rollbackTo()` rendu en no-op laissait
|
|
96
|
+
* l'appelant croire ses écritures annulées alors qu'elles restaient en base. Le
|
|
97
|
+
* refus tombe dès `savepoint()`, pas au `rollbackTo()` : le chemin d'erreur, où
|
|
98
|
+
* l'on annule, est celui qu'on teste le moins — la faute doit se voir au premier
|
|
99
|
+
* essai. Pour annuler, terminer la transaction entière (`rollback()`, ou laisser
|
|
100
|
+
* le callback de `IOrm.transaction()` lever).
|
|
101
|
+
*/
|
|
102
|
+
export declare class SavepointNotSupportedError extends Error {
|
|
103
|
+
/** Moteur qui refuse (valeur de `describeConnection().driver`). */
|
|
104
|
+
readonly driver: string;
|
|
105
|
+
/**
|
|
106
|
+
* @param driver - moteur qui ne porte pas de savepoints.
|
|
107
|
+
* @param operation - opération refusée (`savepoint` ou `rollbackTo`).
|
|
108
|
+
*/
|
|
109
|
+
constructor(driver: string, operation: "savepoint" | "rollbackTo");
|
|
110
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PartialInput } from "nodefony";
|
|
2
|
+
/**
|
|
3
|
+
* Retire les clés qui valent `undefined` d'une donnée d'écriture partielle.
|
|
4
|
+
*
|
|
5
|
+
* `undefined` et clé absente veulent dire « ne pas toucher » : Drizzle ignore
|
|
6
|
+
* déjà une valeur `undefined`, Mongoose (≥ 6) la retire d'une mise à jour. La
|
|
7
|
+
* règle est posée ICI, une fois, au seuil de la persistance, au lieu d'être
|
|
8
|
+
* un comportement propre à chaque adaptateur.
|
|
9
|
+
*
|
|
10
|
+
* Rend l'objet reçu TEL QUEL quand aucune clé ne vaut `undefined` — le cas
|
|
11
|
+
* courant d'un corps JSON, qui ne peut pas en porter : aucune allocation.
|
|
12
|
+
*
|
|
13
|
+
* @param data - données d'écriture, clés `undefined` admises
|
|
14
|
+
* @returns les mêmes données, sans aucune clé `undefined`
|
|
15
|
+
*/
|
|
16
|
+
export declare function omitUndefined<T>(data: PartialInput<T>): Partial<T>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IEntity } from "../interfaces/IEntity.js";
|
|
2
|
+
/**
|
|
3
|
+
* Entités inscrites sur un connecteur qu'aucun ORM n'a ouvert.
|
|
4
|
+
*
|
|
5
|
+
* Une telle entité ne sera servie par rien : son dépôt lèvera au premier
|
|
6
|
+
* appel, loin de sa cause. Vécu : sur une infra MongoDB, le `User` d'une
|
|
7
|
+
* application restait écrit en table SQL sur `default` — un connecteur que
|
|
8
|
+
* Drizzle n'ouvre pas sur cette infra — et le boot n'en disait RIEN.
|
|
9
|
+
*
|
|
10
|
+
* @param entities - entités inscrites (registre des entités).
|
|
11
|
+
* @param connectors - connecteurs ouverts (registre des ORM).
|
|
12
|
+
* @returns les orphelines, dans l'ordre d'inscription.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findOrphanEntities(entities: readonly IEntity[], connectors: readonly string[]): IEntity[];
|
|
15
|
+
/**
|
|
16
|
+
* La phrase qui NOMME les orphelines et le remède — `null` s'il n'y en a pas.
|
|
17
|
+
*
|
|
18
|
+
* @param orphans - entités sans connecteur ouvert.
|
|
19
|
+
* @param connectors - connecteurs ouverts, cités pour situer la faute.
|
|
20
|
+
* @param declared - connecteurs DÉCLARÉS par les modules ORM (leur configuration).
|
|
21
|
+
*/
|
|
22
|
+
export declare function describeOrphanEntities(orphans: readonly IEntity[], connectors: readonly string[], declared?: readonly string[]): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Signale UNE fois par démarrage les entités orphelines, au moment où tous les
|
|
25
|
+
* ORM sont ouverts.
|
|
26
|
+
*
|
|
27
|
+
* Appelée par chaque module ORM (Drizzle, Mongoose) à `onReady` : la règle vit
|
|
28
|
+
* ici, une fois, et le premier appel la rend — le second se tait, sans quoi une
|
|
29
|
+
* application qui charge les deux ORM lirait deux fois le même avertissement.
|
|
30
|
+
* La garde porte sur le KERNEL et non sur le process : un process qui démarre
|
|
31
|
+
* plusieurs noyaux (une suite de tests) doit être prévenu à chacun.
|
|
32
|
+
*
|
|
33
|
+
* @param log - journal du module appelant.
|
|
34
|
+
* @param owner - le démarrage concerné (le Kernel), clé de la garde.
|
|
35
|
+
* @param declared - connecteurs que l'appelant a DÉCLARÉS (sa configuration).
|
|
36
|
+
* @returns le message rendu, ou `null` (rien à dire, ou déjà dit).
|
|
37
|
+
*/
|
|
38
|
+
export declare function reportOrphanEntities(log: (message: string, severity: "WARNING") => void, owner: object, declared?: readonly string[]): string | null;
|
package/docs/index.md
CHANGED
|
@@ -177,7 +177,7 @@ garantit que la dépendance va bien du concret vers l'abstrait, et jamais l'inve
|
|
|
177
177
|
> [!NOTE]
|
|
178
178
|
> `orm-core` n'est **pas un module bootable** : pas de classe `Module`, rien à mettre dans
|
|
179
179
|
> `modules: [...]`. C'est une bibliothèque pure. Les modules, ce sont les **drivers** — ce sont eux
|
|
180
|
-
> qui s'enregistrent dans `ormRegistry` (`OrmRegistry.ts:
|
|
180
|
+
> qui s'enregistrent dans `ormRegistry` (`OrmRegistry.ts:86`) à leur démarrage.
|
|
181
181
|
|
|
182
182
|
## La vision Nodefony
|
|
183
183
|
|
|
@@ -377,13 +377,13 @@ sequenceDiagram
|
|
|
377
377
|
Note over K: onServersReady → récap de boot
|
|
378
378
|
```
|
|
379
379
|
|
|
380
|
-
**`entityRegistry`** (`EntityRegistry.ts:
|
|
380
|
+
**`entityRegistry`** (`EntityRegistry.ts:145`) indexe les entités à **deux** niveaux — nom puis
|
|
381
381
|
connecteur — parce qu'une même entité logique (`User`) peut vivre sur plusieurs connexions. Demander
|
|
382
382
|
`get("User")` sans préciser le connecteur alors que deux le portent **lève** plutôt que de deviner
|
|
383
383
|
(`EntityRegistry.get()`, `EntityRegistry.ts:54`). Le stockage est un `Object.create(null)` alloué
|
|
384
384
|
**au premier enregistrement** : une application sans base ne paie rien.
|
|
385
385
|
|
|
386
|
-
**`ormRegistry`** (`OrmRegistry.ts:
|
|
386
|
+
**`ormRegistry`** (`OrmRegistry.ts:86`) associe un nom de connexion à son instance `IOrm`. Un doublon
|
|
387
387
|
de nom **lève** (`OrmRegistry.register()`, `OrmRegistry.ts:26`) : deux connexions homonymes seraient
|
|
388
388
|
un bug silencieux, jamais une intention.
|
|
389
389
|
|
|
@@ -393,8 +393,8 @@ l'ordre des écouteurs, la table existe ou non. `entities()` s'accroche à `onRe
|
|
|
393
393
|
(`entitiesDecorator.ts:66`), strictement antérieur — sûr par construction. C'est la différence de
|
|
394
394
|
comportement avec `@controllers`, qui lui reste à `onBoot`.
|
|
395
395
|
|
|
396
|
-
**`Orm.connect()`** (`Orm.ts:
|
|
397
|
-
moniteur de connexion, puis émet `onOrmReady`. Un adapter surcharge `onConnect()` (`Orm.ts:
|
|
396
|
+
**`Orm.connect()`** (`Orm.ts:118`) est une **template method** : elle mesure la latence, alimente le
|
|
397
|
+
moniteur de connexion, puis émet `onOrmReady`. Un adapter surcharge `onConnect()` (`Orm.ts:363`), et
|
|
398
398
|
**jamais** `connect()` — sinon l'événement et l'instrumentation disparaissent.
|
|
399
399
|
|
|
400
400
|
## 🧰 Les contrats — la surface publique
|
|
@@ -412,35 +412,37 @@ transaction (`IOrm.transaction()`, `IOrm.ts:41`) et expose la trappe native
|
|
|
412
412
|
|
|
413
413
|
Quatre méthodes sont **optionnelles** — un adapter qui ne les implémente pas dégrade proprement au
|
|
414
414
|
lieu d'échouer : `describeEntity()` (`IOrm.ts:78`, colonnes pour l'ERD), `describeConnection()`
|
|
415
|
-
(`IOrm.ts:
|
|
416
|
-
`probe()` (`IOrm.ts:
|
|
415
|
+
(`IOrm.ts:88`, driver et cible **sans credential**), `ping()` (`IOrm.ts:109`, aller-retour réel) et
|
|
416
|
+
`probe()` (`IOrm.ts:119`, métriques driver, qui ne doit **jamais** lever).
|
|
417
417
|
|
|
418
418
|
### [`IRepository`](tutorial-entity.md) — les quinze verbes
|
|
419
419
|
|
|
420
420
|
`IRepository<T>` (`IRepository.ts:197`) est la seule surface que ton métier devrait connaître. Les
|
|
421
421
|
verbes se choisissent sur **la garantie** qu'ils apportent, pas sur leur nom.
|
|
422
422
|
|
|
423
|
-
| Verbe | Ce qu'il garantit
|
|
424
|
-
| --------------------- |
|
|
425
|
-
| `find` / `findOne` | lecture filtrée + eager-load + tri + bornes
|
|
426
|
-
| `count`
|
|
427
|
-
| `
|
|
428
|
-
| `
|
|
429
|
-
| `
|
|
430
|
-
| `
|
|
431
|
-
| `
|
|
432
|
-
| `
|
|
433
|
-
| `
|
|
434
|
-
| `
|
|
435
|
-
| `
|
|
436
|
-
| `
|
|
423
|
+
| Verbe | Ce qu'il garantit | Ancre |
|
|
424
|
+
| --------------------- | ------------------------------------------------------------------------- | -------------------- |
|
|
425
|
+
| `find` / `findOne` | lecture filtrée + eager-load + tri + bornes | `IRepository.ts:230` |
|
|
426
|
+
| `count` | compter les entités qui correspondent au critère | `IRepository.ts:362` |
|
|
427
|
+
| `exists` | savoir s'il y en a au moins un, sans charger de colonne | `IRepository.ts:395` |
|
|
428
|
+
| `countDistinct` | compter les valeurs DISTINCTES et non nulles d'un champ, sans les charger | `IRepository.ts:381` |
|
|
429
|
+
| `create` | insertion d'une ligne, rend la version persistée (id, défauts) | `IRepository.ts:240` |
|
|
430
|
+
| `createMany` | N lignes en **une** requête — seed, import, ingestion par lots | `IRepository.ts:252` |
|
|
431
|
+
| `updateOne` | met à jour **au plus une** ligne, **atomiquement**, et la rend | `IRepository.ts:269` |
|
|
432
|
+
| `updateMany` | met à jour toutes les lignes du critère, rend le **nombre** | `IRepository.ts:312` |
|
|
433
|
+
| `upsert` | insère **ou** met à jour sur conflit de clé, en **une** instruction | `IRepository.ts:296` |
|
|
434
|
+
| `increment` | `SET f = f + ?` atomique — compteurs, quotas, rate-limit | `IRepository.ts:287` |
|
|
435
|
+
| `delete` | supprime tout ce qui matche, rend le nombre | `IRepository.ts:336` |
|
|
436
|
+
| `deleteOne` | supprime **au plus une** ligne, rend un booléen | `IRepository.ts:345` |
|
|
437
|
+
| `findOneAndDelete` | supprime **et rend** la ligne — file de jobs, outbox, `pop` atomique | `IRepository.ts:355` |
|
|
438
|
+
| `withTransaction(tx)` | une **vue** du repository liée à une transaction | `IRepository.ts:406` |
|
|
437
439
|
|
|
438
440
|
> [!IMPORTANT]
|
|
439
441
|
> `updateOne` est atomique **par construction** : une seule requête (`UPDATE … RETURNING` en SQL,
|
|
440
442
|
> `findOneAndUpdate` en Mongo), jamais un `UPDATE` suivi d'une relecture. La différence n'est pas
|
|
441
443
|
> cosmétique : la relecture rendrait `null` **à tort** dès que le critère porte sur un champ qu'on
|
|
442
444
|
> vient de modifier — `updateOne({ status: "pending" }, { status: "done" })` ne retrouve plus rien
|
|
443
|
-
> après coup (`IRepository.ts:
|
|
445
|
+
> après coup (`IRepository.ts:269`).
|
|
444
446
|
|
|
445
447
|
Quelques usages, un par garantie :
|
|
446
448
|
|
|
@@ -472,11 +474,13 @@ atomique sur les quatre backends.
|
|
|
472
474
|
|
|
473
475
|
### [`IEntity`](tutorial-entity.md) — la description d'une table
|
|
474
476
|
|
|
475
|
-
`IEntity` (`IEntity.ts:
|
|
477
|
+
`IEntity` (`IEntity.ts:51`) porte un nom logique, un `connector` (le nom d'une **connexion**, jamais
|
|
476
478
|
d'un moteur), un `schema` natif du driver, et des `relations` déclaratives (`IEntityRelation`,
|
|
477
479
|
`IEntity.ts:4`). Deux champs facultatifs servent la lisibilité d'un gros modèle : `module` (qui
|
|
478
|
-
apporte l'entité) et `domain` (`IEntity.ts:
|
|
479
|
-
une base de plusieurs centaines de tables).
|
|
480
|
+
apporte l'entité) et `domain` (`IEntity.ts:72`, la classification métier — l'axe qui rend navigable
|
|
481
|
+
une base de plusieurs centaines de tables). Un troisième, `indexes` (`IEntityIndex`), déclare les
|
|
482
|
+
index COMPOSITES qu'un adaptateur ne sait pas exprimer dans son schéma : Mongoose les applique
|
|
483
|
+
(`schema.index()`), Drizzle les ignore, puisqu'il les déclare dans sa table.
|
|
480
484
|
|
|
481
485
|
Dans une application, on ne construit pas un `IEntity` à la main : on écrit un `IEntityDefinition`
|
|
482
486
|
(`defineEntity.ts:15`) — le même objet **sans** `connector`, justement parce que le connecteur est
|
|
@@ -555,7 +559,7 @@ Deux décisions le rendent utilisable sur une grosse table :
|
|
|
555
559
|
`false`. C'est la distinction « Page » (avec total) et « Slice » (sans), reprise de Spring Data.
|
|
556
560
|
|
|
557
561
|
Les bornes sont normalisées plutôt que propagées : un `limit` de `0` ou un `offset` négatif est
|
|
558
|
-
ramené dans le domaine valide (`paginate.ts:
|
|
562
|
+
ramené dans le domaine valide (`paginate.ts:56`) — un `find({ limit: 0 })` a un comportement qui
|
|
559
563
|
dépend du dialecte, donc on ne le laisse pas sortir.
|
|
560
564
|
|
|
561
565
|
Le contrat de page lui-même (`IPage`, `IPageQuery`) vit dans le **cœur**
|
|
@@ -588,7 +592,7 @@ export class ArticleService extends AbstractCrudService<ArticleRow> {
|
|
|
588
592
|
- **Lectures** (`find`, `findOne`, `findById`, `count`, `findPage`) — **délégation pure**. Aucun
|
|
589
593
|
hook, aucun événement : c'est le chemin chaud, il ne doit rien payer.
|
|
590
594
|
- **Mutations** (`create`, `updateOne`, `delete`) — encadrées par des hooks _template method_
|
|
591
|
-
(`beforeCreate`, `AbstractCrudService.ts:
|
|
595
|
+
(`beforeCreate`, `AbstractCrudService.ts:212`, et ses six frères) puis un événement de cycle de vie
|
|
592
596
|
`onCreated` / `onUpdated` / `onDeleted`, **émis seulement si la mutation a eu lieu**
|
|
593
597
|
(`AbstractCrudService.ts:167`). L'audit, l'invalidation de cache ou une notification Studio s'y
|
|
594
598
|
abonnent sans toucher au service.
|
|
@@ -606,21 +610,22 @@ d'administration : elle ne charge qu'une page, quelle que soit la taille de la t
|
|
|
606
610
|
|
|
607
611
|
Deux drivers implémentent les contrats. Le contrat `IRepository` est tenu **en entier** par les
|
|
608
612
|
deux : les quinze verbes existent des deux côtés — par exemple l'upsert, avec
|
|
609
|
-
`DrizzleRepository.upsert()` (`DrizzleRepository.ts:
|
|
610
|
-
(`MongooseRepository.ts:
|
|
611
|
-
|
|
612
|
-
| Capacité | `@nodefony/drizzle` | `@nodefony/mongoose`
|
|
613
|
-
| -------------------------------------- | ----------------------------------- |
|
|
614
|
-
| Moteurs | SQLite, PostgreSQL, MySQL / MariaDB | MongoDB
|
|
615
|
-
| Contrat `IRepository` (15 verbes) | complet | complet
|
|
616
|
-
| Eager-load `{ relations }` | oui | oui (`populate`)
|
|
617
|
-
| Transactions
|
|
618
|
-
|
|
|
619
|
-
|
|
|
620
|
-
| Sonde
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
qu'il porte dans son `package.json`, clé
|
|
613
|
+
`DrizzleRepository.upsert()` (`DrizzleRepository.ts:866`) et `MongooseRepository.upsert()`
|
|
614
|
+
(`MongooseRepository.ts:422`).
|
|
615
|
+
|
|
616
|
+
| Capacité | `@nodefony/drizzle` | `@nodefony/mongoose` |
|
|
617
|
+
| -------------------------------------- | ----------------------------------- | -------------------------------------------- |
|
|
618
|
+
| Moteurs | SQLite, PostgreSQL, MySQL / MariaDB | MongoDB |
|
|
619
|
+
| Contrat `IRepository` (15 verbes) | complet | complet |
|
|
620
|
+
| Eager-load `{ relations }` | oui | oui (`populate`) |
|
|
621
|
+
| Transactions | oui | oui (replica set requis par Mongo) |
|
|
622
|
+
| Savepoints (rollback partiel) | oui | non — refusés (`SavepointNotSupportedError`) |
|
|
623
|
+
| Colonnes pour l'ERD (`describeEntity`) | oui (`DrizzleOrm.ts:1971`) | oui (`MongooseOrm.ts:649`) |
|
|
624
|
+
| Sonde de flux (requêtes/s, lentes) | oui — alimente `queryFlowMonitor` | non câblée |
|
|
625
|
+
| Sonde profonde (`probe`) | oui (`DrizzleOrm.ts:1873`) | oui (`MongooseOrm.ts:617`) |
|
|
626
|
+
|
|
627
|
+
**Les « stores » du framework** : chaque adapter déclare ce qu'il porte dans son `package.json`, clé
|
|
628
|
+
`nodefony.stores`. Les deux backends durables portent les huit :
|
|
624
629
|
|
|
625
630
|
| Store | drizzle | mongoose |
|
|
626
631
|
| ------------- | ------- | -------- |
|
|
@@ -629,22 +634,21 @@ qu'il porte dans son `package.json`, clé `nodefony.stores` :
|
|
|
629
634
|
| `tokens` | ✅ | ✅ |
|
|
630
635
|
| `passkeys` | ✅ | ✅ |
|
|
631
636
|
| `webhooks` | ✅ | ✅ |
|
|
632
|
-
| `totp` | ✅ |
|
|
633
|
-
| `audit` | ✅ |
|
|
634
|
-
| `idempotency` | ✅ |
|
|
637
|
+
| `totp` | ✅ | ✅ |
|
|
638
|
+
| `audit` | ✅ | ✅ |
|
|
639
|
+
| `idempotency` | ✅ | ✅ |
|
|
635
640
|
|
|
636
641
|
> [!NOTE]
|
|
637
|
-
> La couverture est **adaptée à la nature de chaque backend
|
|
638
|
-
>
|
|
639
|
-
>
|
|
640
|
-
>
|
|
641
|
-
> (`@nodefony/drizzle/package.json`, clé `nodefony.stores`) — elle n'est pas un commentaire.
|
|
642
|
+
> La couverture est **adaptée à la nature de chaque backend** : c'est `@nodefony/redis`, un cache,
|
|
643
|
+
> qui s'arrête à quatre stores (`session`, `tokens`, `passkeys`, `idempotency`) — il ne garde ni
|
|
644
|
+
> comptes ni journal. La liste fait autorité côté code (`nodefony.stores` du `package.json` de chaque
|
|
645
|
+
> adapter) — elle n'est pas un commentaire.
|
|
642
646
|
|
|
643
647
|
## 🧩 Extension — brancher son propre driver
|
|
644
648
|
|
|
645
649
|
Le contrat minimal tient en peu de choses, parce que `orm-core` fournit déjà la plomberie.
|
|
646
650
|
|
|
647
|
-
1. **Étendre `Orm`** (`Orm.ts:
|
|
651
|
+
1. **Étendre `Orm`** (`Orm.ts:46`) : implémenter `onConnect()`, `disconnect()`, `isConnected()`,
|
|
648
652
|
`getRepository()`, `transaction()`, `getNativeConnection()`. L'enregistrement dans `ormRegistry`
|
|
649
653
|
est fait par le constructeur de base — il n'y a rien à écrire. **Ne jamais surcharger
|
|
650
654
|
`connect()`** : c'est la template method qui émet `onOrmReady` et instrumente la latence.
|
|
@@ -672,10 +676,10 @@ la santé ne doit pas coûter le débit, et observer le débit ne doit pas réve
|
|
|
672
676
|
|
|
673
677
|
**`connectionMonitor`** (`ConnectionMonitor.ts:197`) suit le **cycle de vie** d'une connexion :
|
|
674
678
|
première connexion, reconnexions, erreurs récentes, et une fenêtre de latence de ping
|
|
675
|
-
(`ConnectionMonitor.recordPing()`, `ConnectionMonitor.ts:
|
|
679
|
+
(`ConnectionMonitor.recordPing()`, `ConnectionMonitor.ts:136`). Il est alimenté par `Orm.connect()`
|
|
676
680
|
sans que l'adapter ait à y penser.
|
|
677
681
|
|
|
678
|
-
**`queryFlowMonitor`** (`QueryFlowMonitor.ts:
|
|
682
|
+
**`queryFlowMonitor`** (`QueryFlowMonitor.ts:144`) suit le **débit** : total de requêtes, latence
|
|
679
683
|
moyenne et EWMA, pire latence, et un anneau borné à vingt requêtes lentes. Trois propriétés le
|
|
680
684
|
rendent sûr en production :
|
|
681
685
|
|
|
@@ -687,7 +691,7 @@ rendent sûr en production :
|
|
|
687
691
|
observe, et le débit par seconde est **dérivé côté lecteur** (delta entre deux relevés), donc rien
|
|
688
692
|
n'est muté à la lecture.
|
|
689
693
|
|
|
690
|
-
Le data plane `/nodefony/orm/api/*` (`createOrmAdminApi()`, `OrmAdminApi.ts:
|
|
694
|
+
Le data plane `/nodefony/orm/api/*` (`createOrmAdminApi()`, `OrmAdminApi.ts:541`) expose huit points
|
|
691
695
|
d'entrée, tous filtrables par `?connector=` :
|
|
692
696
|
|
|
693
697
|
| Point d'entrée | Ce qu'il rend |
|
|
@@ -695,11 +699,11 @@ d'entrée, tous filtrables par `?connector=` :
|
|
|
695
699
|
| `orms` | les connecteurs, leur état, leur nombre d'entités |
|
|
696
700
|
| `entities` | le modèle complet : colonnes + relations |
|
|
697
701
|
| `entity/{name}` | une entité (404 si inconnue) |
|
|
698
|
-
| `graph` | le graphe canonique (`buildOrmGraph()`, `OrmAdminApi.ts:
|
|
702
|
+
| `graph` | le graphe canonique (`buildOrmGraph()`, `OrmAdminApi.ts:227`) |
|
|
699
703
|
| `counts` | le nombre de lignes par entité — un `COUNT(*)` par table |
|
|
700
704
|
| `connection/health` | état, latence, erreurs, reconnexions, sondes |
|
|
701
|
-
| `flow` | débit et requêtes lentes (`buildOrmFlow()`, `OrmAdminApi.ts:
|
|
702
|
-
| `export/{format}` | `dbml` (`toDbml()`, `OrmAdminApi.ts:
|
|
705
|
+
| `flow` | débit et requêtes lentes (`buildOrmFlow()`, `OrmAdminApi.ts:360`) |
|
|
706
|
+
| `export/{format}` | `dbml` (`toDbml()`, `OrmAdminApi.ts:395`) ou `jsonschema` |
|
|
703
707
|
|
|
704
708
|
Ce graphe canonique est **la pièce maîtresse**, pas le diagramme : c'est une donnée sérialisable qui
|
|
705
709
|
sert à la fois l'ERD de Studio, un export vers un outil tiers, et le contexte d'un agent IA
|
|
@@ -730,14 +734,14 @@ deux, et pas de course).
|
|
|
730
734
|
| Symptôme | Cause | Correction |
|
|
731
735
|
| ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
732
736
|
| « no entity registered under "X" » au premier appel | l'entité n'a jamais été inscrite (fichier importé mais `defineEntity` est sans effet de bord) | l'ajouter à `@entities([...])` sur le module (`entitiesDecorator.ts:56`) |
|
|
733
|
-
| La table n'existe pas alors que l'entité est déclarée | inscription faite à `onBoot` → course avec `connect()` | inscrire à `onRegister` — c'est ce que fait `entities()` (`entitiesDecorator.ts:
|
|
737
|
+
| La table n'existe pas alors que l'entité est déclarée | inscription faite à `onBoot` → course avec `connect()` | inscrire à `onRegister` — c'est ce que fait `entities()` (`entitiesDecorator.ts:56`) |
|
|
734
738
|
| « entity "User" exists on multiple connectors … specify one » | la même entité vit sur plusieurs connecteurs | préciser le connecteur : `entityRegistry.get("User", "analytics")` (`EntityRegistry.ts:54`) |
|
|
735
739
|
| Un filtre « champ vide » ne remonte jamais rien | `colonne = NULL` est toujours faux en SQL | `{ champ: { $null: true } }` ou la valeur nue `{ champ: null }` (`IRepository.ts:65`) |
|
|
736
740
|
| `UnknownCriteriaField` sur un champ qui existe « pourtant » | faute de frappe, ou champ calculé absent du schéma | lire les champs connus dans le message ; pour du natif, passer par `getNativeConnection()` |
|
|
737
|
-
| `updateOne` rend `null` alors que la ligne a bien changé | ancien réflexe `UPDATE` + relecture (le critère porte sur le champ modifié) | utiliser `updateOne`, atomique par construction (`IRepository.ts:
|
|
741
|
+
| `updateOne` rend `null` alors que la ligne a bien changé | ancien réflexe `UPDATE` + relecture (le critère porte sur le champ modifié) | utiliser `updateOne`, atomique par construction (`IRepository.ts:269`) |
|
|
738
742
|
| Un `upsert` écrase une valeur qui devait progresser | le `DO UPDATE` est inconditionnel (contrainte MySQL) | poser la condition **dans** la valeur : `{ seuil: { $max: v } }` (`IRepository.ts:94`) |
|
|
739
743
|
| Un objet de critère est pris pour une égalité (colonne JSON) | comportement **voulu** : une valeur n'est un filtre que si **toutes** ses clés sont des opérateurs | c'est la protection ; pour filtrer dedans, passer au natif (`criteria.ts:42`) |
|
|
740
|
-
| `onOrmReady` ne part plus après un ajout dans l'adapter | `connect()` a été surchargé | surcharger `onConnect()` (`Orm.ts:
|
|
744
|
+
| `onOrmReady` ne part plus après un ajout dans l'adapter | `connect()` a été surchargé | surcharger `onConnect()` (`Orm.ts:363`), jamais `connect()` |
|
|
741
745
|
| Une entité déclarée dans un module reste invisible | le module embarque sa **propre copie** du registre (singleton dédoublé) | externaliser `@nodefony/orm-core` dans le `rolldown.config.ts` du module |
|
|
742
746
|
| Rien dans `flow` alors que la base travaille | la sonde est éteinte hors développement, ou le driver n'a pas de tap | `NF_ORM_FLOW=1` (`ormWiring.ts:96`) ; le tap n'est câblé que côté Drizzle |
|
|
743
747
|
|
package/docs/tutorial-entity.md
CHANGED
|
@@ -88,7 +88,7 @@ battre contre le cadre.
|
|
|
88
88
|
|
|
89
89
|
**1. Le connecteur est une donnée de configuration, jamais de code.** C'est pourquoi le
|
|
90
90
|
descripteur qu'on écrit (`IEntityDefinition`, `defineEntity.ts:15`) est un `IEntity`
|
|
91
|
-
(`IEntity.ts:
|
|
91
|
+
(`IEntity.ts:51`) **privé de son `connector`** : celui-ci est résolu au démarrage, avec `"default"`
|
|
92
92
|
pour valeur de repli (`DEFAULT_CONNECTOR`, `entitiesDecorator.ts:12`). Figer la connexion dans le
|
|
93
93
|
fichier d'entité interdirait de servir la même table depuis une base différente selon
|
|
94
94
|
l'environnement.
|
|
@@ -303,7 +303,7 @@ Cette absence d'effet de bord est délibérée : elle permet d'importer une enti
|
|
|
303
303
|
un script ou un autre module **sans** déclencher son inscription dans un singleton global.
|
|
304
304
|
|
|
305
305
|
Les champs facultatifs qui servent tôt : `module` (qui apporte l'entité) et `domain`
|
|
306
|
-
(`IEntity.ts:
|
|
306
|
+
(`IEntity.ts:72`), l'axe de classification qui rend navigable une base de plusieurs centaines de
|
|
307
307
|
tables dans l'ERD Studio.
|
|
308
308
|
|
|
309
309
|
### Étape 4 — brancher l'entité au module
|
|
@@ -318,7 +318,7 @@ d'être connues :
|
|
|
318
318
|
être instancié deux fois : tests, rechargement). Une vraie collision, elle, lève
|
|
319
319
|
(`EntityRegistry.register()`, `EntityRegistry.ts:24`).
|
|
320
320
|
3. **Connecteur commun** — `entities([...], { connector: "analytics" })` pose toute la liste sur
|
|
321
|
-
une autre base ; une entité qui porte son propre `connector` (`IEntity.ts:
|
|
321
|
+
une autre base ; une entité qui porte son propre `connector` (`IEntity.ts:56`) garde le sien.
|
|
322
322
|
|
|
323
323
|
### Le raccourci — `nodefony create entity`
|
|
324
324
|
|
|
@@ -339,32 +339,35 @@ que l'import plus la ligne du décorateur.
|
|
|
339
339
|
> [!WARNING]
|
|
340
340
|
> La commande refuse de générer si aucun module ORM n'est déclaré dans l'application. C'est
|
|
341
341
|
> volontaire : une entité sans driver produit du code mort qui ne compile même pas. Ajoute
|
|
342
|
-
> `
|
|
342
|
+
> `"@nodefony/drizzle"` (SQL) ou `"@nodefony/mongoose"` (MongoDB) au manifeste `modules`, puis
|
|
343
|
+
> relance. Sur MongoDB, la même commande écrit un schéma Mongoose au lieu d'une table.
|
|
343
344
|
|
|
344
345
|
## 🧰 Lire et écrire — le contrat complet
|
|
345
346
|
|
|
346
347
|
Le repository porte **quinze verbes**, pas cinq. Ils se choisissent sur la **garantie** qu'ils
|
|
347
348
|
apportent, jamais sur leur nom.
|
|
348
349
|
|
|
349
|
-
| Verbe | Ce qu'il garantit
|
|
350
|
-
| --------------------- |
|
|
351
|
-
| `find` / `findOne` | lecture filtrée, avec tri, bornes et eager-load
|
|
352
|
-
| `create` | insère une ligne et rend sa version persistée (id, défauts)
|
|
353
|
-
| `createMany` | N lignes en **une** requête — seed, import, ingestion par lots
|
|
354
|
-
| `updateOne` | modifie **au plus une** ligne, **atomiquement**, et la rend
|
|
355
|
-
| `updateMany` | modifie toutes les lignes du critère, rend le **nombre**
|
|
356
|
-
| `upsert` | insère **ou** met à jour sur conflit de clé, en une instruction
|
|
357
|
-
| `increment` | `SET f = f + ?` atomique — compteurs, quotas, limitation de débit
|
|
358
|
-
| `delete` | supprime tout ce qui matche, rend le nombre
|
|
359
|
-
| `deleteOne` | supprime **au plus une** ligne, rend un booléen
|
|
360
|
-
| `findOneAndDelete` | supprime **et rend** la ligne — file de jobs, `pop` atomique
|
|
361
|
-
| `count`
|
|
362
|
-
| `
|
|
350
|
+
| Verbe | Ce qu'il garantit | Ancre |
|
|
351
|
+
| --------------------- | ------------------------------------------------------------------------- | ---------------------------- |
|
|
352
|
+
| `find` / `findOne` | lecture filtrée, avec tri, bornes et eager-load | `IRepository.ts:230`, `:192` |
|
|
353
|
+
| `create` | insère une ligne et rend sa version persistée (id, défauts) | `IRepository.ts:240` |
|
|
354
|
+
| `createMany` | N lignes en **une** requête — seed, import, ingestion par lots | `IRepository.ts:252` |
|
|
355
|
+
| `updateOne` | modifie **au plus une** ligne, **atomiquement**, et la rend | `IRepository.ts:269` |
|
|
356
|
+
| `updateMany` | modifie toutes les lignes du critère, rend le **nombre** | `IRepository.ts:312` |
|
|
357
|
+
| `upsert` | insère **ou** met à jour sur conflit de clé, en une instruction | `IRepository.ts:296` |
|
|
358
|
+
| `increment` | `SET f = f + ?` atomique — compteurs, quotas, limitation de débit | `IRepository.ts:287` |
|
|
359
|
+
| `delete` | supprime tout ce qui matche, rend le nombre | `IRepository.ts:336` |
|
|
360
|
+
| `deleteOne` | supprime **au plus une** ligne, rend un booléen | `IRepository.ts:345` |
|
|
361
|
+
| `findOneAndDelete` | supprime **et rend** la ligne — file de jobs, `pop` atomique | `IRepository.ts:355` |
|
|
362
|
+
| `count` | compter les entités qui correspondent au critère | `IRepository.ts:362` |
|
|
363
|
+
| `exists` | savoir s'il y en a au moins une, sans charger de colonne | `IRepository.ts:395` |
|
|
364
|
+
| `countDistinct` | compter les valeurs DISTINCTES et non nulles d'un champ, sans les charger | `IRepository.ts:381` |
|
|
365
|
+
| `withTransaction(tx)` | une **vue** du repository liée à une transaction | `IRepository.ts:406` |
|
|
363
366
|
|
|
364
367
|
> [!IMPORTANT]
|
|
365
368
|
> **Il n'existe pas de méthode `update()`.** Le choix est explicite et il est intentionnel :
|
|
366
369
|
> `IRepository.updateOne()` (`IRepository.ts:269`) pour une ligne — atomique, et elle **rend** la
|
|
367
|
-
> ligne modifiée —, `IRepository.updateMany()` (`IRepository.ts:
|
|
370
|
+
> ligne modifiée —, `IRepository.updateMany()` (`IRepository.ts:312`) pour un lot — qui rend le
|
|
368
371
|
> **nombre** de lignes touchées. Un verbe unique masquerait cette différence de garantie, qui est
|
|
369
372
|
> précisément ce qu'on veut choisir en connaissance de cause.
|
|
370
373
|
|
|
@@ -393,7 +396,7 @@ await orm.transaction(async (tx) => {
|
|
|
393
396
|
```
|
|
394
397
|
|
|
395
398
|
Deux réflexes de performance, dès le premier jour : préférer `IRepository.exists()`
|
|
396
|
-
(`IRepository.ts:
|
|
399
|
+
(`IRepository.ts:395`) à `findOne(...) !== null` — aucune colonne n'est chargée —, et
|
|
397
400
|
`IRepository.increment()` (`IRepository.ts:325`) à une lecture suivie d'une écriture : une requête
|
|
398
401
|
au lieu de deux, et pas de course.
|
|
399
402
|
|
|
@@ -471,7 +474,7 @@ champs connus — le diagnostic d'une faute de frappe est immédiat.
|
|
|
471
474
|
|
|
472
475
|
## 📄 Pager les résultats
|
|
473
476
|
|
|
474
|
-
`find()` avec `limit`/`offset`/`order` (`RepositoryReadOptions`, `IRepository.ts:
|
|
477
|
+
`find()` avec `limit`/`offset`/`order` (`RepositoryReadOptions`, `IRepository.ts:174`) suffit pour
|
|
475
478
|
une tranche. Pour une vraie page — celle qui sait s'il y a une suite — utilise `paginate()`
|
|
476
479
|
(`paginate.ts:47`) :
|
|
477
480
|
|
|
@@ -524,9 +527,9 @@ d'administration, la primitive est `AbstractCrudService.findPage()` (`AbstractCr
|
|
|
524
527
|
|
|
525
528
|
| Symptôme | Cause | Correction |
|
|
526
529
|
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- |
|
|
527
|
-
| `posts.update is not a function` | la méthode `update()` n'existe pas dans le contrat | `updateOne` pour une ligne (`IRepository.ts:269`), `updateMany` pour un lot (`IRepository.ts:
|
|
530
|
+
| `posts.update is not a function` | la méthode `update()` n'existe pas dans le contrat | `updateOne` pour une ligne (`IRepository.ts:269`), `updateMany` pour un lot (`IRepository.ts:312`) |
|
|
528
531
|
| « no entity registered under "Post" » au premier appel | le fichier d'entité est importé, mais `defineEntity()` est **sans effet de bord** | ajouter l'entité à `@entities([...])` sur le module (`entitiesDecorator.ts:56`) |
|
|
529
|
-
| La table n'existe pas alors que l'entité est déclarée | inscription faite à `onBoot` → course avec l'ouverture du connecteur | inscrire à `onRegister` — c'est ce que fait `entities()` (`entitiesDecorator.ts:
|
|
532
|
+
| La table n'existe pas alors que l'entité est déclarée | inscription faite à `onBoot` → course avec l'ouverture du connecteur | inscrire à `onRegister` — c'est ce que fait `entities()` (`entitiesDecorator.ts:56`) |
|
|
530
533
|
| Une colonne ajoutée au schéma reste absente de la table | le DDL du boot est un `CREATE TABLE IF NOT EXISTS` : aucun `ALTER` n'est émis | supprimer la base de développement et redémarrer, ou passer par une migration |
|
|
531
534
|
| Un `DEFAULT` SQL ou un index déclaré n'apparaît pas | le DDL dérivé ne les émet pas | poser le défaut côté JavaScript (`$defaultFn`) ; créer l'index par migration |
|
|
532
535
|
| Un filtre « champ vide » ne remonte jamais rien | `colonne = NULL` est toujours faux en SQL | `{ champ: { $null: true } }` ou la valeur nue `{ champ: null }` (`IRepository.ts:65`) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodefony/orm-core",
|
|
3
|
-
"version": "10.0.0-
|
|
3
|
+
"version": "10.0.0-beta.1",
|
|
4
4
|
"description": "Un contrat de dépôt de données pour Nodefony, plusieurs moteurs : interfaces, registre et classes de base pour le support multi-ORM",
|
|
5
5
|
"contributors": [],
|
|
6
6
|
"type": "module",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"types": "./dist/types/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"nodefony-source": "./index.ts",
|
|
11
12
|
"types": "./dist/types/index.d.ts",
|
|
12
13
|
"import": "./dist/index.js",
|
|
13
14
|
"default": "./dist/index.js"
|
|
@@ -15,9 +16,9 @@
|
|
|
15
16
|
},
|
|
16
17
|
"scripts": {
|
|
17
18
|
"start": "node dist/index.js",
|
|
18
|
-
"build": "
|
|
19
|
+
"build": "rolldown -c rolldown.config.ts && tsgo -p tsconfig.declarations.json",
|
|
19
20
|
"dev": "rolldown -c rolldown.config.ts --watch",
|
|
20
|
-
"clean": "
|
|
21
|
+
"clean": "node --eval \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
21
22
|
"test": "vitest run",
|
|
22
23
|
"coverage": "vitest run --coverage",
|
|
23
24
|
"typecheck": "tsgo --noEmit -p tsconfig.json && tsgo --noEmit -p tsconfig.tests.json"
|
|
@@ -36,13 +37,12 @@
|
|
|
36
37
|
"esm"
|
|
37
38
|
],
|
|
38
39
|
"peerDependencies": {
|
|
39
|
-
"nodefony": "^10.0.0-
|
|
40
|
+
"nodefony": "^10.0.0-beta.1"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
|
-
"@types/node": "26.6.
|
|
43
|
-
"nodefony": "^10.0.0-
|
|
44
|
-
"
|
|
45
|
-
"vitest": "5.0.1"
|
|
43
|
+
"@types/node": "26.6.3",
|
|
44
|
+
"nodefony": "^10.0.0-beta.1",
|
|
45
|
+
"vitest": "5.0.2"
|
|
46
46
|
},
|
|
47
47
|
"repository": {
|
|
48
48
|
"type": "git",
|