feat(turbo): turbo gen feature generator (Phase 1, single-entity)

Adds `pnpm turbo gen feature` to scaffold a Lazar-conformant feature
package matching the navigation reference shape: entity + Zod schema,
single use case (`get<Entity>`), controller, mock + Payload-stub real
repository (with span + capture), DI module/container/symbols, and tRPC
router with full BAD_REQUEST/NOT_FOUND error mapping. The generated
`bind-production.ts` and `bind-dev-seed.ts` compose the post-R44
`withSpan(tracer, opts, withCapture(logger, tags, factory(deps)))`
sandwich at bind time.

Verified by generating a sample `packages/example/` feature and running
`pnpm --filter @repo/example lint typecheck test` — all three pass
(9 test files, 25 tests). Cleaned up after verification so no example
package is committed.

Phase-1 limitations (documented in `docs/guides/scaffolding-a-feature.md`
and printed by the generator on success): no Payload CMS templates, no
React Query helpers, faker-driven factories left as stubs, single
entity / single use case, and aggregator wiring (core-api/root,
apps/web-next bindAll) is left as a manual checklist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 01:09:22 +02:00
parent b4ec48f058
commit 019d4866a0
40 changed files with 1769 additions and 0 deletions

307
pnpm-lock.yaml generated
View File

@@ -8,6 +8,12 @@ importers:
.:
devDependencies:
'@turbo/gen':
specifier: ^2.4.0
version: 2.9.10(@types/node@22.19.17)
'@types/node':
specifier: ^22.0.0
version: 22.19.17
prettier:
specifier: ^3.5.0
version: 3.8.1
@@ -1951,6 +1957,140 @@ packages:
cpu: [x64]
os: [win32]
'@inquirer/ansi@1.0.2':
resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==}
engines: {node: '>=18'}
'@inquirer/checkbox@4.3.2':
resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/confirm@5.1.21':
resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/core@10.3.2':
resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/editor@4.2.23':
resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/expand@4.0.23':
resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/external-editor@1.0.3':
resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/figures@1.0.15':
resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==}
engines: {node: '>=18'}
'@inquirer/input@4.3.1':
resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/number@3.0.23':
resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/password@4.0.23':
resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/prompts@7.10.1':
resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/rawlist@4.1.11':
resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/search@3.2.2':
resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/select@4.4.2':
resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/type@3.0.10':
resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inversifyjs/common@1.4.0':
resolution: {integrity: sha512-qfRJ/3iOlCL/VfJq8+4o5X4oA14cZSBbpAmHsYj8EsIit1xDndoOl0xKOyglKtQD4u4gdNVxMHx4RWARk/I4QA==}
@@ -3487,6 +3627,10 @@ packages:
cpu: [arm64]
os: [darwin]
'@turbo/gen@2.9.10':
resolution: {integrity: sha512-o3bUtbZwgZvum1iWIjEE6pxtfKspb9T/3BXpPOXAkIf8Zvh1GTGfS5qk8K3ChOK1BrU4QAtmUtKG02ZykABO3g==}
hasBin: true
'@turbo/linux-64@2.9.4':
resolution: {integrity: sha512-Cl1GjxqBXQ+r9KKowmXG+lhD1gclLp48/SE7NxL//66iaMytRw0uiphWGOkccD92iPiRjHLRUaA9lOTtgr5OCA==}
cpu: [x64]
@@ -4107,6 +4251,9 @@ packages:
character-reference-invalid@2.0.1:
resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
chardet@2.1.1:
resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==}
charenc@0.0.2:
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
@@ -4144,6 +4291,10 @@ packages:
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
engines: {node: '>=6'}
cli-width@4.1.0:
resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
engines: {node: '>= 12'}
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
@@ -5082,6 +5233,10 @@ packages:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
iconv-lite@0.7.2:
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
engines: {node: '>=0.10.0'}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@@ -5889,6 +6044,10 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
mute-stream@2.0.0:
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
engines: {node: ^18.17.0 || >=20.5.0}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -7355,6 +7514,10 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
yoctocolors-cjs@2.1.3:
resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==}
engines: {node: '>=18'}
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
@@ -8240,6 +8403,131 @@ snapshots:
'@img/sharp-win32-x64@0.34.5':
optional: true
'@inquirer/ansi@1.0.2': {}
'@inquirer/checkbox@4.3.2(@types/node@22.19.17)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10(@types/node@22.19.17)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/confirm@5.1.21(@types/node@22.19.17)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/type': 3.0.10(@types/node@22.19.17)
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/core@10.3.2(@types/node@22.19.17)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10(@types/node@22.19.17)
cli-width: 4.1.0
mute-stream: 2.0.0
signal-exit: 4.1.0
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/editor@4.2.23(@types/node@22.19.17)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/external-editor': 1.0.3(@types/node@22.19.17)
'@inquirer/type': 3.0.10(@types/node@22.19.17)
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/expand@4.0.23(@types/node@22.19.17)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/type': 3.0.10(@types/node@22.19.17)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/external-editor@1.0.3(@types/node@22.19.17)':
dependencies:
chardet: 2.1.1
iconv-lite: 0.7.2
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/figures@1.0.15': {}
'@inquirer/input@4.3.1(@types/node@22.19.17)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/type': 3.0.10(@types/node@22.19.17)
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/number@3.0.23(@types/node@22.19.17)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/type': 3.0.10(@types/node@22.19.17)
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/password@4.0.23(@types/node@22.19.17)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/type': 3.0.10(@types/node@22.19.17)
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/prompts@7.10.1(@types/node@22.19.17)':
dependencies:
'@inquirer/checkbox': 4.3.2(@types/node@22.19.17)
'@inquirer/confirm': 5.1.21(@types/node@22.19.17)
'@inquirer/editor': 4.2.23(@types/node@22.19.17)
'@inquirer/expand': 4.0.23(@types/node@22.19.17)
'@inquirer/input': 4.3.1(@types/node@22.19.17)
'@inquirer/number': 3.0.23(@types/node@22.19.17)
'@inquirer/password': 4.0.23(@types/node@22.19.17)
'@inquirer/rawlist': 4.1.11(@types/node@22.19.17)
'@inquirer/search': 3.2.2(@types/node@22.19.17)
'@inquirer/select': 4.4.2(@types/node@22.19.17)
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/rawlist@4.1.11(@types/node@22.19.17)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/type': 3.0.10(@types/node@22.19.17)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/search@3.2.2(@types/node@22.19.17)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10(@types/node@22.19.17)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/select@4.4.2(@types/node@22.19.17)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/core': 10.3.2(@types/node@22.19.17)
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10(@types/node@22.19.17)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 22.19.17
'@inquirer/type@3.0.10(@types/node@22.19.17)':
optionalDependencies:
'@types/node': 22.19.17
'@inversifyjs/common@1.4.0': {}
'@inversifyjs/core@1.3.5(reflect-metadata@0.2.2)':
@@ -10298,6 +10586,13 @@ snapshots:
'@turbo/darwin-arm64@2.9.4':
optional: true
'@turbo/gen@2.9.10(@types/node@22.19.17)':
dependencies:
'@inquirer/prompts': 7.10.1(@types/node@22.19.17)
esbuild: 0.25.12
transitivePeerDependencies:
- '@types/node'
'@turbo/linux-64@2.9.4':
optional: true
@@ -11053,6 +11348,8 @@ snapshots:
character-reference-invalid@2.0.1: {}
chardet@2.1.1: {}
charenc@0.0.2: {}
check-error@2.1.3: {}
@@ -11085,6 +11382,8 @@ snapshots:
clean-stack@2.2.0: {}
cli-width@4.1.0: {}
client-only@0.0.1: {}
cliui@6.0.0:
@@ -12015,6 +12314,10 @@ snapshots:
dependencies:
safer-buffer: 2.1.2
iconv-lite@0.7.2:
dependencies:
safer-buffer: 2.1.2
ieee754@1.2.1: {}
ignore@5.3.2: {}
@@ -13131,6 +13434,8 @@ snapshots:
ms@2.1.3: {}
mute-stream@2.0.0: {}
nanoid@3.3.11: {}
natural-compare@1.4.0: {}
@@ -14807,6 +15112,8 @@ snapshots:
yocto-queue@0.1.0: {}
yoctocolors-cjs@2.1.3: {}
zod@3.25.76: {}
zwitch@2.0.4: {}