Description
Migrer le dépôt cloud-pi-native/console vers Zod 4 (actuellement zod@^3.25.76 via le catalog runtime), cible prioritaire apps/server-nestjs.
Problème : ce n'est pas un correctif de sécurité (Zod 3 reste maintenu, séries 3.25.x). Modernisation optionnelle, basse urgence. Le vrai verrou est la topologie des dépendances : server-nestjs compose des schémas Zod issus de @cpn-console/shared (zod 3) et @cpn-console/hooks (zod 3) — pas seulement il les valide.
Spécifications techniques
Constats vérifiés (commentaires de l'issue + expérimentation en workspace isolé zod4) :
zod = catalog partagé (catalogs.runtime, pnpm-workspace.yaml:118, catalogMode: strict). apps/server-nestjs compose des schémas Zod de @cpn-console/shared (ex. ProjectSchemaV2.omit().extend() dans project.utils.ts) et de @cpn-console/hooks (ex. editStrippersGenerator dans project-services.utils.ts), pas seulement il les passe au ZodValidationPipe.
ZodValidationPipe (zod-validation.pipe.ts) n'importe zod qu'en import type { ZodSchema } (effacé au runtime) et appelle schema.safeParse(...). → Le pipe seul est agnostique de version. Mais ce n'est pas le seul point de contact : les sites de composition (.extend(), .merge()) croisent réellement les deux majorités.
@ts-rest : core/fastify en RC 3.53.0-rc.1 ont supprimé le peer zod, mais @ts-rest/open-api@3.53.0-rc.1 garde peerDependencies.zod: "^3.22.3". open-api importé uniquement par apps/server/src (figé). → @ts-rest a été retiré de server-nestjs (0 import source) lors de l'expérimentation ; ce n'était pas le vrai verrou.
Résultat de l'expérimentation (workspace zod4, catalog zod4: { zod: ^4.4.3 } isolé sur server-nestjs)
- Build
pnpm build : VERT (0 erreur) après corrections mécaniques (catalog isolé, drop @ts-rest, pipe version-agnostique, retrait de ZodTypeDef, base.config .default(0), csv en .transform()).
- Tests
pnpm test : 572 passés / 2 échoués → en isolation 1 fail : project-services.service.spec.ts > servicesService > update stores project configuration through the real utility.
- Cause racine (runtime) :
@cpn-console/hooks est en zod 3.25.76. buildProjectEditStrippers (project-services.utils.ts:39-41) fait global = global.merge(z.object({ [service.name]: editZod.global.default({}) })) où editZod provient de editStrippersGenerator.parse(service.config) (hooks, zod-3). Zod 4 normalizeDef rejette le schéma zod-3 embarqué → Error: Invalid element at key "...": expected a Zod schema.
→ Path A REFUTÉ empiriquement : le build compile (l'alias ZodType de zod 4 est assez laxiste pour le typecheck), mais la frontière dual-major se manifeste AU RUNTIME. Isoler zod sur server-nestjs ne suffit pas : les schémas de shared/hooks (zod 3) y sont composés, pas seulement validés.
Chemins évalués
- Path A — catalog isolé
server-nestjs (zod 4) : ❌ NON viable. Build vert mais crash runtime via buildProjectEditStrippers / editStrippersGenerator (@cpn-console/hooks zod 3). Le pipe étant version-agnostique ne suffit pas ; les sites de composition croisent les deux majorités.
- Path B — bump workspace-wide (shared + hooks + server-nestjs, figer
apps/server) : seul chemin viable si migration, mais blast-radius maximal (doit migrer shared + hooks + server-nestjs ensemble, et résoudre le peer zod@^3 de @ts-rest/open-api consommé par apps/server figé).
- Path C — rester sur Zod 3 : aucun coût (série
3.25.x maintenue). Recommandé tant que la migration workspace-wide n'est pas planifiée.
Définition du fini
Description
Migrer le dépôt
cloud-pi-native/consolevers Zod 4 (actuellementzod@^3.25.76via le catalogruntime), cible prioritaireapps/server-nestjs.Problème : ce n'est pas un correctif de sécurité (Zod 3 reste maintenu, séries
3.25.x). Modernisation optionnelle, basse urgence. Le vrai verrou est la topologie des dépendances :server-nestjscompose des schémas Zod issus de@cpn-console/shared(zod 3) et@cpn-console/hooks(zod 3) — pas seulement il les valide.Spécifications techniques
Constats vérifiés (commentaires de l'issue + expérimentation en workspace isolé
zod4) :zod= catalog partagé (catalogs.runtime,pnpm-workspace.yaml:118,catalogMode: strict).apps/server-nestjscompose des schémas Zod de@cpn-console/shared(ex.ProjectSchemaV2.omit().extend()dansproject.utils.ts) et de@cpn-console/hooks(ex.editStrippersGeneratordansproject-services.utils.ts), pas seulement il les passe auZodValidationPipe.ZodValidationPipe(zod-validation.pipe.ts) n'importe zod qu'enimport type { ZodSchema }(effacé au runtime) et appelleschema.safeParse(...). → Le pipe seul est agnostique de version. Mais ce n'est pas le seul point de contact : les sites de composition (.extend(),.merge()) croisent réellement les deux majorités.@ts-rest:core/fastifyen RC3.53.0-rc.1ont supprimé le peerzod, mais@ts-rest/open-api@3.53.0-rc.1gardepeerDependencies.zod: "^3.22.3".open-apiimporté uniquement parapps/server/src(figé). →@ts-resta été retiré deserver-nestjs(0 import source) lors de l'expérimentation ; ce n'était pas le vrai verrou.Résultat de l'expérimentation (workspace
zod4, catalogzod4: { zod: ^4.4.3 }isolé surserver-nestjs)pnpm build: VERT (0 erreur) après corrections mécaniques (catalog isolé, drop@ts-rest, pipe version-agnostique, retrait deZodTypeDef,base.config.default(0),csven.transform()).pnpm test: 572 passés / 2 échoués → en isolation 1 fail :project-services.service.spec.ts > servicesService > update stores project configuration through the real utility.@cpn-console/hooksest en zod 3.25.76.buildProjectEditStrippers(project-services.utils.ts:39-41) faitglobal = global.merge(z.object({ [service.name]: editZod.global.default({}) }))oùeditZodprovient deeditStrippersGenerator.parse(service.config)(hooks, zod-3). Zod 4normalizeDefrejette le schéma zod-3 embarqué →Error: Invalid element at key "...": expected a Zod schema.→ Path A REFUTÉ empiriquement : le build compile (l'alias
ZodTypede zod 4 est assez laxiste pour le typecheck), mais la frontière dual-major se manifeste AU RUNTIME. Isolerzodsurserver-nestjsne suffit pas : les schémas deshared/hooks(zod 3) y sont composés, pas seulement validés.Chemins évalués
server-nestjs(zod 4) :❌ NON viable. Build vert mais crash runtime viabuildProjectEditStrippers/editStrippersGenerator(@cpn-console/hookszod 3). Le pipe étant version-agnostique ne suffit pas ; les sites de composition croisent les deux majorités.apps/server) : seul chemin viable si migration, mais blast-radius maximal (doit migrershared+hooks+server-nestjsensemble, et résoudre le peerzod@^3de@ts-rest/open-apiconsommé parapps/serverfigé).3.25.xmaintenue). Recommandé tant que la migration workspace-wide n'est pas planifiée.Définition du fini
zod-validation-error@5(si partagé) + audit enumbuildProjectEditStrippers/editStrippersGenerator(@cpn-console/hookszod 3.25.76)shared+hooks+server-nestjs, coordonnée) OU Path C (rester Zod 3)shared→zod4,hooks→zod4, puisserver-nestjs; résoudre le peer@ts-rest/open-api@^3(figerapps/serverou attendre@ts-reststable sans peer zod-3)tsc/pnpm buildverts +pnpm testverts sur l'ensemble des paquets migrés