@fluojs/cli 2.0.1 → 3.0.0

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 (118) hide show
  1. package/README.ko.md +169 -21
  2. package/README.md +172 -21
  3. package/dist/cli.d.ts +5 -4
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +127 -35
  6. package/dist/commands/diagnostics.d.ts +35 -0
  7. package/dist/commands/diagnostics.d.ts.map +1 -1
  8. package/dist/commands/diagnostics.js +60 -0
  9. package/dist/commands/inspect.d.ts +5 -1
  10. package/dist/commands/inspect.d.ts.map +1 -1
  11. package/dist/commands/inspect.js +84 -17
  12. package/dist/commands/migrate.d.ts.map +1 -1
  13. package/dist/commands/migrate.js +27 -15
  14. package/dist/commands/migration-transform-tokens.d.ts +15 -0
  15. package/dist/commands/migration-transform-tokens.d.ts.map +1 -0
  16. package/dist/commands/migration-transform-tokens.js +41 -0
  17. package/dist/commands/new.d.ts.map +1 -1
  18. package/dist/commands/new.js +29 -9
  19. package/dist/commands/output-path-safety.d.ts +14 -0
  20. package/dist/commands/output-path-safety.d.ts.map +1 -0
  21. package/dist/commands/output-path-safety.js +34 -0
  22. package/dist/commands/scripts.js +2 -2
  23. package/dist/commands/typegen-artifact.d.ts +54 -0
  24. package/dist/commands/typegen-artifact.d.ts.map +1 -0
  25. package/dist/commands/typegen-artifact.js +117 -0
  26. package/dist/commands/typegen-generation-child.d.ts +2 -0
  27. package/dist/commands/typegen-generation-child.d.ts.map +1 -0
  28. package/dist/commands/typegen-generation-child.js +59 -0
  29. package/dist/commands/typegen-generation-process.d.ts +46 -0
  30. package/dist/commands/typegen-generation-process.d.ts.map +1 -0
  31. package/dist/commands/typegen-generation-process.js +131 -0
  32. package/dist/commands/typegen-generation-protocol.d.ts +16 -0
  33. package/dist/commands/typegen-generation-protocol.d.ts.map +1 -0
  34. package/dist/commands/typegen-generation-protocol.js +35 -0
  35. package/dist/commands/typegen-isolated-source.d.ts +10 -0
  36. package/dist/commands/typegen-isolated-source.d.ts.map +1 -0
  37. package/dist/commands/typegen-isolated-source.js +75 -0
  38. package/dist/commands/typegen-options.d.ts +20 -0
  39. package/dist/commands/typegen-options.d.ts.map +1 -0
  40. package/dist/commands/typegen-options.js +71 -0
  41. package/dist/commands/typegen-source.d.ts +59 -0
  42. package/dist/commands/typegen-source.d.ts.map +1 -0
  43. package/dist/commands/typegen-source.js +183 -0
  44. package/dist/commands/typegen-watch.d.ts +46 -0
  45. package/dist/commands/typegen-watch.d.ts.map +1 -0
  46. package/dist/commands/typegen-watch.js +212 -0
  47. package/dist/commands/typegen.d.ts +29 -0
  48. package/dist/commands/typegen.d.ts.map +1 -0
  49. package/dist/commands/typegen.js +119 -0
  50. package/dist/dev-runner/node-restart-runner.d.ts.map +1 -1
  51. package/dist/dev-runner/node-restart-runner.js +54 -7
  52. package/dist/fixtures/inspect-react-app.module.d.ts +4 -0
  53. package/dist/fixtures/inspect-react-app.module.d.ts.map +1 -0
  54. package/dist/fixtures/inspect-react-app.module.js +32 -0
  55. package/dist/fixtures/typegen-react-app.module.d.ts +4 -0
  56. package/dist/fixtures/typegen-react-app.module.d.ts.map +1 -0
  57. package/dist/fixtures/typegen-react-app.module.js +33 -0
  58. package/dist/index.d.ts +6 -5
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +3 -2
  61. package/dist/new/install.js +1 -1
  62. package/dist/new/package-spec-resolver.d.ts.map +1 -1
  63. package/dist/new/package-spec-resolver.js +50 -59
  64. package/dist/new/prompt.d.ts +1 -0
  65. package/dist/new/prompt.d.ts.map +1 -1
  66. package/dist/new/prompt.js +40 -12
  67. package/dist/new/published-internal-dependencies.d.ts +20 -0
  68. package/dist/new/published-internal-dependencies.d.ts.map +1 -0
  69. package/dist/new/published-internal-dependencies.js +20 -0
  70. package/dist/new/react-vite-ssr-scaffold.d.ts +19 -0
  71. package/dist/new/react-vite-ssr-scaffold.d.ts.map +1 -0
  72. package/dist/new/react-vite-ssr-scaffold.js +108 -0
  73. package/dist/new/resolver.d.ts +2 -2
  74. package/dist/new/resolver.d.ts.map +1 -1
  75. package/dist/new/resolver.js +5 -1
  76. package/dist/new/scaffold.d.ts.map +1 -1
  77. package/dist/new/scaffold.js +62 -31
  78. package/dist/new/starter-profiles.d.ts +8 -4
  79. package/dist/new/starter-profiles.d.ts.map +1 -1
  80. package/dist/new/starter-profiles.js +52 -18
  81. package/dist/new/templates/react-vite-ssr/README.md.ejs +74 -0
  82. package/dist/new/templates/react-vite-ssr/playwright.config.ts.ejs +26 -0
  83. package/dist/new/templates/react-vite-ssr/src/app.test.ts.ejs +82 -0
  84. package/dist/new/templates/react-vite-ssr/src/app.ts.ejs +91 -0
  85. package/dist/new/templates/react-vite-ssr/src/entry-client.tsx.ejs +29 -0
  86. package/dist/new/templates/react-vite-ssr/src/entry-server.tsx.ejs +52 -0
  87. package/dist/new/templates/react-vite-ssr/src/load-manifest.test.ts.ejs +55 -0
  88. package/dist/new/templates/react-vite-ssr/src/load-manifest.ts.ejs +53 -0
  89. package/dist/new/templates/react-vite-ssr/src/main.ts.ejs +18 -0
  90. package/dist/new/templates/react-vite-ssr/src/page.tsx.ejs +43 -0
  91. package/dist/new/templates/react-vite-ssr/src/react-app.test.tsx.ejs +67 -0
  92. package/dist/new/templates/react-vite-ssr/src/react-app.tsx.ejs +46 -0
  93. package/dist/new/templates/react-vite-ssr/src/styles.css.ejs +25 -0
  94. package/dist/new/templates/react-vite-ssr/src/styles.d.ts.ejs +1 -0
  95. package/dist/new/templates/react-vite-ssr/tests/production-hydration.spec.ts.ejs +54 -0
  96. package/dist/new/templates/react-vite-ssr/tsconfig.json.ejs +16 -0
  97. package/dist/new/templates/react-vite-ssr/vite.client.config.ts.ejs +24 -0
  98. package/dist/new/templates/react-vite-ssr/vite.server.config.ts.ejs +17 -0
  99. package/dist/new/templates/react-vite-ssr/vitest.config.ts.ejs +10 -0
  100. package/dist/new/types.d.ts +4 -0
  101. package/dist/new/types.d.ts.map +1 -1
  102. package/dist/public-typegen.d.ts +14 -0
  103. package/dist/public-typegen.d.ts.map +1 -0
  104. package/dist/public-typegen.js +17 -0
  105. package/dist/run-cli.d.ts +2 -1
  106. package/dist/run-cli.d.ts.map +1 -1
  107. package/dist/studio/sidecar.d.ts.map +1 -1
  108. package/dist/studio/sidecar.js +35 -9
  109. package/dist/transforms/nestjs-migrate.d.ts +4 -1
  110. package/dist/transforms/nestjs-migrate.d.ts.map +1 -1
  111. package/dist/transforms/nestjs-migrate.js +625 -65
  112. package/dist/typegen-contract.d.ts +10 -0
  113. package/dist/typegen-contract.d.ts.map +1 -0
  114. package/dist/typegen-contract.js +9 -0
  115. package/dist/usage.d.ts +6 -0
  116. package/dist/usage.d.ts.map +1 -1
  117. package/dist/usage.js +47 -0
  118. package/package.json +19 -10
package/README.ko.md CHANGED
@@ -1,8 +1,11 @@
1
1
  # @fluojs/cli
2
2
 
3
3
  <p><a href="./README.md"><kbd>English</kbd></a> <strong><kbd>한국어</kbd></strong></p>
4
+ <!-- fluo-cli-bootstrap-automation-boundary: explicit-platform-express, numeric-literal-single-argument-listen, manual-host-callback-string-env-multiple-listen -->
4
5
 
5
- fluo 공식 CLI — 새 애플리케이션 부트스트랩, 컴포넌트 생성, 런타임 검사 데이터 내보내기, 코드 변환을 지원합니다.
6
+ fluo 공식 CLI — 새 애플리케이션 부트스트랩, 컴포넌트와 React page type 생성, 런타임 검사 데이터 내보내기, 코드 변환을 지원합니다.
7
+
8
+ Coordinated Node 24 릴리스를 준비한다면 패키지 업그레이드 전에 [소비자 마이그레이션 가이드](../../docs/getting-started/migrate-node24.ko.md)를 따르세요.
6
9
 
7
10
  ## 목차
8
11
 
@@ -30,8 +33,11 @@ pnpm dlx @fluojs/cli new my-app
30
33
 
31
34
  ## 릴리스 계약
32
35
 
33
- - `@fluojs/cli`는 intended publish surface에 포함되는 공개 패키지입니다.
34
- - `@fluojs/cli`는 Node.js `>=20.0.0`을 요구합니다. 생성된 Bun, Deno, Cloudflare Workers starter가 비 Node runtime을 대상으로 할 수는 있지만 CLI process 자체는 Node.js에서 실행됩니다.
36
+ - `@fluojs/cli`와 생성된 모든 Node HTTP, mixed, microservice, React SSR + Fastify 프로젝트는 Node.js `>=24.0.0 <27`을 요구합니다. Node build target은 `node24`, Node starter typings는 `@types/node@^24.0.0`입니다. Bun과 Deno starter는 native engine을 유지하고 Workers의 Node engine은 로컬 CLI/Wrangler tooling만 제한합니다. 업그레이드 전에 [Node.js 마이그레이션](../../docs/reference/node-support.ko.md)을 적용하세요.
37
+ - `@fluojs/cli`는 Node.js `>=24.0.0 <27`을 요구합니다. 생성된 Bun, Deno, Cloudflare Workers starter가 비 Node runtime을 대상으로 할 수는 있지만 CLI process 자체는 Node.js에서 실행됩니다. 생성된 Node HTTP 및 mixed 프로젝트는 listener-level RFC `QUERY`가 framework dispatch에 도달하도록 Node.js `>=24.0.0 <27`을 선언합니다. Node 24 미만과 Node 27 이상은 제외되며, Node microservice-only 프로젝트는 독립적인 `>=24.0.0 <27` 하한을 유지합니다.
38
+ - `inspect`는 검사를 실행할 때만, 그리고 검사 대상 프로젝트의 dependency tree에서만 `@fluojs/runtime`을 해석합니다. `fluo inspect`를 사용하기 전에 현재 Node.js 버전과 호환되는 runtime 버전을 설치하세요. 다른 CLI 명령은 CLI 전체 Node.js `>=24.0.0 <27` 범위에서 계속 사용할 수 있습니다.
39
+ - 대화형 `new` 흐름과 선택적인 대화형 `inspect --mermaid` 안내는 필요할 때만 `@clack/prompts`를 해석합니다. CLI가 지원하는 Node.js `>=24.0.0 <27` 전체 범위에서 대화형 및 비대화형 명령을 사용할 수 있습니다.
40
+ - CLI와 생성된 Node.js starter toolchain은 `tsx@^4.23.1`을 사용하며, 생성된 gRPC starter는 `@grpc/grpc-js@^1.14.4`를 요구합니다. 이 패치된 floor를 적용할 때 기존 project lockfile을 갱신하세요.
35
41
  - 지원되는 설치 경로는 전역 패키지(`npm install -g @fluojs/cli`, `pnpm add -g @fluojs/cli`, `bun add -g @fluojs/cli`, `yarn global add @fluojs/cli`)와 무설치 실행 경로(`pnpm dlx @fluojs/cli ...`)입니다.
36
42
  - 배포되는 `fluo` bin은 `package.json`에 선언된 `./bin/fluo.mjs` wrapper이며, 이 wrapper가 dist 빌드 CLI 엔트리포인트인 `../dist/cli.js`를 로드합니다.
37
43
 
@@ -66,22 +72,45 @@ fluo -v
66
72
  몇 초 만에 완전한 스타터 애플리케이션을 스캐폴딩합니다.
67
73
 
68
74
  ```bash
69
- fluo new my-app
75
+ fluo new my-app --package-manager pnpm
70
76
  cd my-app
71
77
  pnpm dev
72
78
  ```
73
79
 
80
+ 이 예제는 `pnpm`을 명시하므로 성공한 모든 스캐폴드는 같은 완료 블록으로 끝납니다.
81
+
82
+ ```text
83
+ Done.
84
+ Next steps:
85
+ cd ./my-app
86
+ pnpm dev # runs fluo dev
87
+ ```
88
+
89
+ Non-interactive 출력에서는 이 블록 전에 설치 시 `Installing dependencies with pnpm...`과 package manager 출력이 나타나고, `--no-install` 사용 시 `Skipping dependency installation.`이 나타납니다. Interactive terminal에서는 wizard가 이러한 non-interactive stdout line 대신 status UI(`Dependencies installed` 또는 `Dependency installation skipped`)로 같은 설치 상태를 알린 뒤 공통 완료 블록을 출력합니다. pnpm 설치가 완료되면 `pnpm-lock.yaml`이 생성되며, `--no-install`을 사용하면 생성 프로젝트에서 `pnpm install`을 실행할 때까지 이 파일이 없습니다. `--package-manager pnpm`을 생략하면 CLI가 현재 invocation 또는 workspace signal을 바탕으로 manager를 선택하고 신호가 없으면 pnpm을 사용하므로, 다음 단계 명령과 lockfile도 선택된 manager에 맞게 달라집니다. 다른 manager는 설치 시 `pnpm-lock.yaml` 대신 각자의 lockfile을 생성합니다.
90
+
74
91
  `fluo create`는 `fluo new`의 alias입니다. 버전 확인, 명령 도움말, 진단, first-party package shortcut, upgrade 안내가 필요하면 `fluo version`, `fluo help <command>`, `fluo doctor`/`fluo info`/`fluo analyze`, `fluo add`, `fluo upgrade`를 사용하세요.
75
92
 
76
- 생성된 Node.js `dev`, `build`, `start` package script는 각각 `fluo dev`, `fluo build`, `fluo start`로 위임합니다. CLI가 Node 지향 lifecycle 명령을 소유하고 local toolchain binary를 실행할 때 project-local `node_modules/.bin`을 앞에 붙이며, 호출자가 명시하지 않은 경우 `dev`는 `NODE_ENV=development`, `build`/`start`는 `NODE_ENV=production`을 기본값으로 사용합니다. Bun, Deno, Workers의 생성된 `dev` script는 같은 `fluo dev` 추상성을 유지하되 Node-supervised dev process를 줄이도록 Bun, Deno, Wrangler의 native watch loop를 기본값으로 사용합니다. fluo가 소유한 restart boundary의 debounce/hash reporter 계약이 필요하면 `fluo dev --runner fluo` 또는 `FLUO_DEV_RUNNER=fluo`를 사용하세요. production/deployment script는 runtime-native입니다. Bun은 `bun build ./src/main.ts --outdir ./dist --target bun`과 `bun dist/main.js`를 사용하고, Deno는 `deno compile --allow-env --allow-net --output dist/app src/main.ts`와 `./dist/app`을 사용하며, Workers는 `start` 대신 Wrangler `preview`/`deploy` script를 노출합니다. 기본적으로 `fluo dev`와 `fluo start`는 CLI가 process boundary를 소유하는 경로에서 앱 로그만(애플리케이션 stdout/stderr) 표시합니다. Interactive terminal에서 fluo lifecycle status와 `app │` prefix가 붙은 애플리케이션 출력이 필요하면 `--reporter pretty`를 사용하고, 런타임/도구 watcher 원본 출력이 필요하면 `--verbose`(또는 `FLUO_VERBOSE=1`)를 사용하세요.
93
+ 생성된 Node.js `dev`, `build`, `start` package script는 각각 `fluo dev`, `fluo build`, `fluo start`로 위임합니다. CLI가 Node 지향 lifecycle 명령을 소유하고 local toolchain binary를 실행할 때 project-local `node_modules/.bin`을 앞에 붙이며, 호출자가 명시하지 않은 경우 `dev`는 `NODE_ENV=development`, `build`/`start`는 `NODE_ENV=production`을 기본값으로 사용합니다. Bun, Deno, Workers의 생성된 `dev` script는 같은 `fluo dev` 추상성을 유지하되 Node-supervised dev process를 줄이도록 Bun, Deno, Wrangler의 native watch loop를 기본값으로 사용합니다. fluo가 소유한 restart boundary의 debounce/hash reporter 계약이 필요하면 `fluo dev --runner fluo` 또는 `FLUO_DEV_RUNNER=fluo`를 사용하세요. production/deployment script는 runtime-native입니다. Bun은 `bun build ./src/main.ts --outdir ./dist --target bun`과 `bun dist/main.js`를 사용하고, Deno는 `deno compile --allow-env --allow-net --output dist/app src/main.ts`와 `./dist/app`을 사용하며, Workers는 `start` 대신 Wrangler `preview`/`deploy` script를 노출합니다. 생성된 Deno `AppModule`은 `Deno.env.toObject()`로 application-owned environment value를 snapshot하므로 dev와 compiled command는 광범위한 `--allow-env`를 유지합니다. Signal listener에는 별도의 Deno permission이 필요하지 않습니다. 기본적으로 `fluo dev`와 `fluo start`는 CLI가 process boundary를 소유하는 경로에서 앱 로그만(애플리케이션 stdout/stderr) 표시합니다. Interactive terminal에서 fluo lifecycle status와 `app │` prefix가 붙은 애플리케이션 출력이 필요하면 `--reporter pretty`를 사용하고, 런타임/도구 watcher 원본 출력이 필요하면 `--verbose`(또는 `FLUO_VERBOSE=1`)를 사용하세요.
77
94
 
78
95
  생성된 starter는 프로젝트를 만든 generator CLI package version을 기준으로 `@fluojs/cli` `devDependency`를 설정합니다. 따라서 `pnpm dev`, `pnpm build`, `pnpm start` 같은 lifecycle script는 오래된 hard-coded range가 아니라 starter를 스캐폴딩한 CLI 동작과 같은 기준을 사용합니다.
79
96
 
80
- 생성된 non-Deno starter의 `vite.config.ts`는 `@fluojs/vite`에서 `fluoDecoratorsPlugin()`을 import합니다. 따라서 decorator transform 업데이트는 신규 프로젝트에 inline 복사되는 대신 유지보수되는 Vite 패키지를 통해 전달됩니다.
97
+ Published mode에서 나머지 내부 `@fluojs/*` dependency와 dev dependency는
98
+ 패키지의 release manifest에서 얻은 `^<package version>`을 사용합니다. CLI build는
99
+ Changesets versioning 이후 이 metadata를 생성하여 `dist`에 포함하므로, unpack한
100
+ CLI도 monorepo나 registry 조회 없이 scaffold를 생성합니다. React의 `0.x`를 포함한
101
+ 버전은 패키지별로 독립적이며 CLI의 major로 통일하지 않습니다.
102
+ 모든 HTTP, microservice, mixed, React, Bun, Deno, Workers starter에 적용됩니다.
103
+ 내부 local sandbox의 tarball override는 계속 우선합니다.
104
+
105
+ 생성된 non-Deno standard starter의 `vite.config.ts`는 `@fluojs/vite`에서 `fluoDecoratorsPlugin()`을 import하고, React SSR + Vite starter는 같은 plugin을 `vite.server.config.ts`에 적용합니다. 따라서 decorator transform 업데이트는 각 신규 프로젝트에 inline 복사되는 대신 유지보수되는 Vite 패키지를 통해 전달됩니다.
106
+
107
+ 새 non-Deno 프로젝트는 Vite `^8.2.2`, Vitest `^4.1.11`, `@vitest/coverage-v8` `^4.1.11`을 선언합니다. 생성된 ESM Vite config는 `build.rolldownOptions`를 사용합니다. Rolldown/Oxc가 애플리케이션 코드를 처리하기 전에 `fluoDecoratorsPlugin()`을 통해 Babel이 표준 데코레이터를 변환하고, `vitest.config.ts`는 `@fluojs/testing/vitest`의 `fluoBabelDecoratorsPlugin()`을 유지합니다. Direct Oxc/esbuild decorator processing은 지원하지 않습니다. Node.js `>=24.0.0 <27`과 runtime-native starter metadata는 바뀌지 않습니다. 기존 프로젝트를 다시 쓰지는 않으므로 업그레이드 시 [생성 toolchain 기준선](../../docs/reference/toolchain-contract-matrix.ko.md)을 명시적으로 적용하세요.
108
+
109
+ 기존 starter를 업그레이드할 때는 `babel.config.cjs`에서 `ignore: ['src/**/*.test.ts']` 규칙을 제거하세요. 생성된 Babel config는 더 이상 test file을 제외하지 않으므로 testing plugin이 테스트 내부에 선언된 데코레이터도 Vitest 4 실행 전에 변환합니다.
81
110
 
82
- 생성된 non-Deno HTTP starter는 TDD-first Vitest 레이아웃을 사용합니다. 빠른 greeting unit test와 `greeting.slice.test.ts`는 `src/greeting/` 아래에 colocate하고, 앱 dispatch test는 `src/app.test.ts`에 유지하며, 기본 e2e 스타일 request-pipeline test는 `createTestApp({ rootModule })`와 `app.request(...).send()`를 사용해 `test/app.e2e.test.ts`에 둡니다. 생성된 `vitest.config.ts`는 `src/**/*.test.ts`와 `test/**/*.test.ts`를 모두 포함하고, package script는 `test`, `test:watch`, `test:cov`, `test:e2e`를 노출합니다. 기존 `src/app.e2e.test.ts` 테스트는 request helper바꾸지 않고 `test/app.e2e.test.ts`로 이동할 있습니다.
111
+ 생성된 standard non-Deno HTTP starter는 TDD-first Vitest 레이아웃을 사용합니다. 빠른 greeting unit test와 `greeting.slice.test.ts`는 `src/greeting/` 아래에 colocate하고, 앱 dispatch test는 `src/app.test.ts`에 유지하며, 기본 e2e 스타일 request-pipeline test는 `createTestApp({ rootModule })`와 `app.request(...).send()`를 사용해 `test/app.e2e.test.ts`에 둡니다. React starter는 대신 streamed SSR, DOM hydration, production Playwright hydration에 집중한 test 포함합니다. `test:browser` script는 build된 Fastify server시작하며 asset 누락, hydration warning, server-owned route를 우회하는 navigation이 있으면 실패합니다.
83
112
 
84
- 생성된 Node.js 애플리케이션 프로젝트에서 `fluo dev`는 기본적으로 fluo가 소유한 restart boundary를 거칩니다. 이 runner는 source와 주요 config 입력을 watch하고, atomic-save event burst를 debounce하며, restart 전에 파일 content hash를 비교하고, spawn하는 각 Node 앱 child process마다 `.env`를 로드하며, `node_modules`, `dist`, `.git`, `.fluo`, coverage, cache 폴더, editor swap file 같은 noisy output/cache 경로를 무시합니다. 파일 내용이 바뀌지 않은 Ctrl+S 저장은 앱을 재시작하지 않아야 합니다. 계획된 restart와 terminal shutdown은 현재 앱 child에 먼저 `SIGTERM`을 보내고, 제한된 grace period 뒤에도 종료되지 않으면 force-kill하므로 비협조적인 child가 restart supervisor를 무기한 멈추게 할 수 없습니다. 계획된 restart가 아닌 terminal 앱 child exit 또는 crash가 발생하면 runner는 watcher를 닫고, pending restart timer와 path를 비우며, `SIGINT`/`SIGTERM` handler를 등록 해제하고, child의 terminal code로 종료합니다. 이 동작은 full-process restart-on-watch이며 module-level HMR이 아닙니다. Config watch reload는 별도의 in-process config 관심사이고, 향후 HMR 작업은 어떤 모듈을 안전하게 hot-swap할 수 있는지 따로 문서화해야 합니다. 디버깅에 runtime-native Node watcher가 필요하면 `fluo dev --raw-watch` 또는 `FLUO_DEV_RAW_WATCH=1`을 사용하세요. 생성된 Bun/Deno/Workers 프로젝트는 기본적으로 watch/reload를 `bun --watch`, `deno run --watch`, `wrangler dev`에 위임합니다. 해당 프로젝트에서 fluo 소유 restart runner로 되돌리려면 `fluo dev --runner fluo` 또는 `FLUO_DEV_RUNNER=fluo`를 사용하고, 그 runner에 추가 ignore 경로가 필요하면 `FLUO_DEV_WATCH_IGNORE=path,pattern`으로 지정하세요.
113
+ 생성된 Node.js 애플리케이션 프로젝트에서 `fluo dev`는 기본적으로 fluo가 소유한 restart boundary를 거칩니다. 이 runner는 source와 주요 config 입력을 watch하고, atomic-save event burst를 debounce하며, restart 전에 파일 content hash를 비교하고, spawn하는 각 Node 앱 child process마다 `.env`를 로드하며, `node_modules`, `dist`, `.git`, `.fluo`, coverage, cache 폴더, editor swap file 같은 noisy output/cache 경로를 무시합니다. 파일 내용이 바뀌지 않은 Ctrl+S 저장은 앱을 재시작하지 않아야 합니다. 계획된 restart와 terminal shutdown은 현재 앱 child에 먼저 `SIGTERM`을 보내고, 제한된 grace period 뒤에도 종료되지 않으면 force-kill하므로 비협조적인 child가 restart supervisor를 무기한 멈추게 할 수 없습니다. 계획된 restart가 아닌 terminal 앱 child exit 또는 crash가 발생하면 runner는 watcher를 닫고, pending restart timer와 path를 비우며, `SIGINT`/`SIGTERM` handler를 등록 해제하고, child의 terminal code로 종료합니다. Primary recursive watcher 또는 fallback directory watcher에서 terminal error가 발생하거나 watcher 등록 전에 필수 source target없거나 접근할 수 없거나 recursive watch를 사용할 수 없을 때 필수 fallback source watcher를 획득하지 못하면 동일한 cleanup path를 따릅니다. 이는 fallback 획득이 전부 실패하는 경우, sibling watcher를 획득한 뒤 일부가 실패하는 경우, fallback watcher 실행 중 새로 발견된 directory의 획득이 실패하는 경우를 모두 포함하며, runner는 기존 제한 시간 안에 현재 앱 child를 종료하고 child나 sibling watcher를 남겨 두는 대신 exit code `1`로 종료합니다. 이 동작은 full-process restart-on-watch이며 module-level HMR이 아닙니다. Config watch reload는 별도의 in-process config 관심사이고, 향후 HMR 작업은 어떤 모듈을 안전하게 hot-swap할 수 있는지 따로 문서화해야 합니다. 디버깅에 runtime-native Node watcher가 필요하면 `fluo dev --raw-watch` 또는 `FLUO_DEV_RAW_WATCH=1`을 사용하세요. 생성된 Bun/Deno/Workers 프로젝트는 기본적으로 watch/reload를 `bun --watch`, `deno run --watch --allow-env --allow-net src/main.ts`, `wrangler dev`에 위임합니다. Deno command는 `Deno.env.toObject()`를 통해 소비되는 모든 application-owned environment key에 대한 접근을 보존합니다. 해당 프로젝트에서 fluo 소유 restart runner로 되돌리려면 `fluo dev --runner fluo` 또는 `FLUO_DEV_RUNNER=fluo`를 사용하고, 그 runner에 추가 ignore 경로가 필요하면 `FLUO_DEV_WATCH_IGNORE=path,pattern`으로 지정하세요.
85
114
 
86
115
  `fluo new`는 같은 Node 기반 설치/빌드 흐름 위에서 Node.js + Fastify, Express, raw Node.js HTTP 애플리케이션 스타터를 제공합니다.
87
116
 
@@ -99,6 +128,29 @@ fluo new my-deno-app --shape application --transport http --runtime deno --platf
99
128
  fluo new my-worker-app --shape application --transport http --runtime cloudflare-workers --platform cloudflare-workers
100
129
  ```
101
130
 
131
+ 공식 HTTP-first React SSR + Vite application은 named starter flag로 선택합니다.
132
+
133
+ ```bash
134
+ fluo new my-react-app --starter react-vite-ssr
135
+ ```
136
+
137
+ 이 starter는 schema를 Node.js + Fastify HTTP로 고정합니다. `pnpm dev`를 실행하고
138
+ `/products/sku-42?preview=true`를 연 뒤 `src/page.tsx`를 편집하세요. Page UI는 더 이상 Vite asset,
139
+ document shell, server/client route snapshot wiring을 함께 다루지 않습니다. `src/app.ts`의 명시적인
140
+ `@Router(...)` / `@Path(...)` handler가 page를 하나의 `ReactElement`로 반환하므로 기존 HTTP
141
+ dispatcher가 계속 authoritative합니다.
142
+
143
+ Generated application wiring은 framework abstraction에 숨지 않고 보이는 상태를 유지합니다.
144
+ `src/entry-server.tsx`는 교체 가능한 `ReactPageRenderer`와 `ReactServerEntry` 생성을 소유하고,
145
+ `src/react-app.tsx`는 server/client가 하나의 document 및 `ReactClientRouterProvider` composition을
146
+ 공유하게 하며, `src/entry-client.tsx`는 `hydrateRoot(...)`를 호출합니다. `src/main.ts`는
147
+ `src/load-manifest.ts`를 사용해 generated Vite manifest를 로드한 뒤 `@fluojs/react/vite`가 이를
148
+ parse하도록 전달합니다. Build output 누락, incompatible entry selector, hydration mismatch는 수정할
149
+ application file과 다시 실행할 lifecycle command를 정확히 가리킵니다. 생성된 `Link`는 real anchor로
150
+ 남고 `router.push(...)`는 HTTP dispatcher를 통과하는 full-document navigation을 수행합니다. 이 starter는
151
+ RSC, Server Functions, file routing, client route table, SPA document swapping, prefetch, data cache를
152
+ 의도적으로 제외합니다.
153
+
102
154
  `fluo new`는 microservice starter path도 제공합니다. `--transport`를 생략하면 TCP가 기본 경로로 사용되며, starter 매트릭스에는 transport별 dependency, env 템플릿, entrypoint를 갖춘 Redis Streams, NATS, Kafka, RabbitMQ, MQTT, gRPC 변형도 포함됩니다.
103
155
 
104
156
  ```bash
@@ -121,7 +173,7 @@ starter 매트릭스에는 mixed single-package starter도 포함됩니다. 하
121
173
  fluo new my-mixed-app --shape mixed --transport tcp --runtime node --platform fastify
122
174
  ```
123
175
 
124
- `fluo new`가 interactive TTY에서 실행되면 wizard는 기존 flags/config 모델을 그대로 사용합니다. wizard는 프로젝트 이름, shape-first 분기(`application` -> runtime + HTTP platform, `microservice` -> transport), 유지보수 가능한 tooling preset, package manager, 즉시 dependency 설치할지 여부, git 저장소를 초기화할지 여부를 묻습니다. non-interactive 플래그 경로와 프로그래밍 방식의 `runNewCommand(...)` 호출도 동일한 resolved defaults를 사용합니다.
176
+ `fluo new`가 interactive TTY에서 실행되면 wizard는 기존 flags/config 모델을 그대로 사용합니다. 먼저 standard backend와 React SSR + Vite named starter를 제시합니다. Standard 분기는 shape-first 경로(`application` -> runtime + HTTP platform, `microservice` -> transport) 이어서 묻고, React 분기는 고정된 Node.js + Fastify HTTP 계약을 사용합니다. 두 분기 모두 유지보수되는 tooling preset, package manager, dependency install, git initialization 선택을 이어갑니다. non-interactive 플래그 경로와 프로그래밍 방식의 `runNewCommand(...)` 호출도 동일한 resolved defaults를 사용합니다.
125
177
 
126
178
  기본적으로 `fluo new my-app`은 `./my-app`에 파일을 씁니다. 프로젝트 이름과 대상 경로가 달라야 하거나 자동화에서 명시적인 디렉터리에 써야 하면 `--target-directory <path>`를 사용하세요:
127
179
 
@@ -139,13 +191,14 @@ side effect 없이 완전히 resolved starter를 미리 확인하려면 `--print
139
191
 
140
192
  ```bash
141
193
  fluo new my-app --shape application --runtime node --platform fastify --print-plan
194
+ fluo new my-react-app --starter react-vite-ssr --print-plan
142
195
  fluo new my-service --shape microservice --transport tcp --print-plan
143
196
  fluo new my-mixed-app --shape mixed --print-plan
144
197
  ```
145
198
 
146
- plan preview 모드는 실제 scaffold와 같은 프로젝트 이름, shape, runtime, platform, transport, tooling preset, package manager, install 선택, git 선택을 resolve합니다. 선택된 starter recipe dependency 세트를 출력한 뒤 파일 생성, dependency 설치, git 저장소 초기화 없이 종료합니다.
199
+ plan preview 모드는 실제 scaffold와 같은 named starter, 프로젝트 이름, shape, runtime, platform, transport, tooling preset, package manager, install 선택, git 선택을 resolve합니다. 선택된 starter recipe, dependency 세트를 출력한 뒤 파일 생성, dependency 설치, git 저장소 초기화 없이 종료합니다.
147
200
 
148
- 현재 제공되는 스타터 매트릭스(Node.js Fastify/Express/raw Node.js HTTP, Bun, Deno, Cloudflare Workers, TCP/Redis Streams/NATS/Kafka/RabbitMQ/MQTT/gRPC microservice, 그리고 mixed)와 남아 있는 더 넓은 어댑터 생태계를 문서 수준에서 구분한 표는 [fluo new 지원 매트릭스](../../docs/reference/fluo-new-support-matrix.ko.md)를 확인하세요. `@fluojs/redis` 같은 패키지 수준 통합은 더 넓은 생태계에 남아 있지만, 추가 `fluo new --transport` 스타터 플래그는 아닙니다.
201
+ 현재 제공되는 스타터 매트릭스(standard Node.js Fastify/Express/raw Node.js HTTP, Node.js + Fastify 기반 React SSR + Vite, Bun, Deno, Cloudflare Workers, TCP/Redis Streams/NATS/Kafka/RabbitMQ/MQTT/gRPC microservice, 그리고 mixed)와 남아 있는 더 넓은 어댑터 생태계를 문서 수준에서 구분한 표는 [fluo new 지원 매트릭스](../../docs/reference/fluo-new-support-matrix.ko.md)를 확인하세요. `@fluojs/redis` 같은 패키지 수준 통합은 더 넓은 생태계에 남아 있지만, 추가 `fluo new --transport` 스타터 플래그는 아닙니다.
149
202
 
150
203
  ### 2. 기능 추가
151
204
  feature slice를 생성합니다. 일부 schematic은 모듈에 자동 등록되고, 일부는 파일만 생성하므로 직접 wiring해야 합니다.
@@ -209,14 +262,14 @@ fluo dev --studio --dry-run
209
262
 
210
263
  CLI는 local Studio sidecar를 시작하고, tokenized URL을 출력하며, restart lifecycle event를 sidecar로 계속 전달하고, 앱이 `@fluojs/runtime`을 import하기 전에 명시적인 Studio config를 Node 앱 child에 주입합니다. Studio live mode는 fluo가 소유한 Node restart runner를 요구합니다. 따라서 lifecycle event가 CLI restart boundary와 분리되지 않도록 `fluo dev --studio`는 `--raw-watch`, `--runner native`, `FLUO_DEV_RUNNER=native`를 거부합니다. Optional package인 `@fluojs/studio`가 설치되어 있으면 sidecar는 패키징된 `@fluojs/studio/viewer` React app을 제공합니다. Runtime package source는 `process.env`를 직접 읽지 않으며, CLI가 주입한 Studio config가 있을 때만 live graph/routes/request/timing/diagnostic event를 전송합니다.
211
264
 
212
- 보안 기본값은 local-only입니다. Sidecar는 `127.0.0.1`에 bind되고, runtime ingestion 및 browser state/SSE API는 generated token을 요구하며, CORS는 기본적으로 활성화하지 않고, request body는 기본적으로 수집하지 않습니다. Local client가 partial request body만 보내고 socket을 닫으면 sidecar는 bounded error completion으로 ingestion 요청을 settle하므로, malformed local client가 sidecar 작업을 무기한 대기시킬 수 없습니다.
265
+ 보안 기본값은 local-only입니다. Sidecar는 `127.0.0.1`에 bind되고, runtime ingestion 및 browser state/SSE API는 generated token을 요구하며, CORS는 기본적으로 활성화하지 않고, request body는 기본적으로 수집하지 않습니다. Local client가 partial request body만 보내고 socket을 닫으면 sidecar는 bounded error completion으로 ingestion 요청을 settle하므로, malformed local client가 sidecar 작업을 무기한 대기시킬 수 없습니다. 인증된 ingestion body가 아직 완료되지 않은 상태에서 `StudioSidecar.close()`가 시작되면 sidecar는 자신이 소유한 active ingestion socket만 닫고, 기존 close path를 통해 추적 중인 SSE response를 종료하며, 반복되거나 동시에 호출된 close가 하나의 결정적인 teardown을 공유하게 합니다. 완료된 일반 요청은 이 active-ingestion ownership set에 포함되지 않으며, partial body를 보낸 client가 연결을 계속 열어 두어도 CLI shutdown을 무기한 대기시킬 수 없습니다.
213
266
 
214
267
  MVP runtime support는 명시적으로 제한됩니다.
215
268
 
216
269
  | Runtime target | `fluo dev --studio` status |
217
270
  | --- | --- |
218
271
  | Node dev runner | Full support target입니다. |
219
- | Bun | 이번 MVP에서는 활성화하지 않습니다. Dedicated bridge를 구현하고 검증하기 전까지 `fluo dev --studio`는 Bun 프로젝트를 거부합니다. |
272
+ | Bun | 이번 MVP에서는 활성화하지 않습니다. Dedicated bridge를 구현하고 검증하기 전까지 `fluo dev --studio`는 Bun 프로젝트를 거부합니다. 대신 `fluo inspect <module-path> --json --output <path>` 또는 `fluo inspect <module-path> --report --output <path>`로 Studio 호환 static artifact를 내보내세요. |
220
273
  | Deno | 이번 MVP에서는 활성화하지 않습니다. Dedicated bridge를 구현하고 검증하기 전까지 `fluo dev --studio`는 Deno 프로젝트를 거부합니다. |
221
274
  | Cloudflare Workers | worker bridge를 추가하고 테스트하지 않는 한 이번 MVP에서는 unsupported입니다. |
222
275
 
@@ -238,7 +291,7 @@ FLUO_VERBOSE=1 fluo dev
238
291
  fluo build --reporter silent
239
292
  ```
240
293
 
241
- 런타임 애플리케이션 로그는 `ApplicationLogger`로 별도 설정합니다. 예를 들어 `@fluojs/runtime/node`의 `createConsoleApplicationLogger({ mode: 'minimal', level: 'warn' })` 또는 `createJsonApplicationLogger()`를 사용하세요.
294
+ 런타임 애플리케이션 로그는 `ApplicationLogger`로 별도 설정합니다. 예를 들어 `@fluojs/platform-nodejs`의 `createConsoleApplicationLogger({ mode: 'minimal', level: 'warn' })` 또는 `createJsonApplicationLogger()`를 사용하세요.
242
295
 
243
296
  first-party package 설치 shortcut에는 `fluo add <package>`를 사용하고, CLI/latest-version 및 migration 안내는 `fluo upgrade`로 확인합니다:
244
297
 
@@ -258,17 +311,28 @@ fluo migrate ./src --json
258
311
  # 변환 적용
259
312
  fluo migrate ./src --apply
260
313
  fluo migrate ./src --apply --json
261
- fluo migrate ./src --only imports,inject-params
262
- fluo migrate ./src --skip tests
314
+ fluo migrate ./src --only imports,injectable
315
+ fluo migrate ./src --skip testing
263
316
  ```
264
317
 
318
+ 정식 `--only` 및 `--skip` 토큰은 `imports`, `inject-params`, `scope`, `bootstrap`, `tests`, `tsconfig`입니다. 기존 `injectable` 및 `testing` 토큰은 각각 `inject-params` 및 `tests`의 허용되는 별칭으로 유지됩니다.
319
+
265
320
  CI 작업, 대시보드, migration report에서 안정적인 machine-readable 결과가 필요하면 `--json`을 사용하세요. 사람을 위한 출력은 기본값으로 유지됩니다. JSON 모드는 성공 시 stdout에 structured report만 기록하고, parser 오류나 잘못된 flag 조합은 기존처럼 stderr에 메시지를 기록한 뒤 exit code `1`을 반환하며 partial JSON을 출력하지 않습니다. Report에는 `mode`(`dry-run` 또는 `apply`), `dryRun`, `apply`, 활성화된 `transforms`, `scannedFiles`, `changedFiles`, 전체 `warningCount`, 그리고 `filePath`, `changed`, `appliedTransforms`, `warningCount`, category label과 source line number가 포함된 warnings per-file metadata가 포함됩니다.
266
321
 
267
322
  `--apply`로 다시 실행하기 전에는 모든 warning을 검토하세요. Warning은 자동 rewrite를 그대로 수락해도 된다는 뜻이 아니라 수동 follow-up 항목입니다. Warning category별 post-codemod checklist는 [NestJS migration guide](../../docs/getting-started/migrate-from-nestjs.ko.md)를 기준으로 확인하세요.
268
323
 
324
+ Adapter-independent transform(`imports`, `injectable`, `scope`, `testing`, `tsconfig`)은 HTTP adapter 없이 실행됩니다. Bootstrap 재작성은 platform을 추론하지 않습니다. Platform을 선택하지 않으면 codemod은 `NestFactory.create(AppModule)`와 `listen(port)` 호출을 유지하고 필요한 adapter-selection warning을 출력합니다. 자동 bootstrap 재작성은 명시적인 `--platform express`와 정확히 하나의 숫자 리터럴 단일 인자 `app.listen(port)`에서만 지원됩니다. host, callback, string, 환경 변수 기반, 여러 `listen` 형태는 warning과 함께 그대로 보존되며 수동 마이그레이션이 필요합니다. 마이그레이션한 애플리케이션을 컴파일하기 전에 `@fluojs/platform-express`와 `express`를 설치하세요:
325
+
326
+ ```bash
327
+ fluo migrate ./src --apply --platform express
328
+
329
+ # bootstrap은 그대로 두고 adapter-independent transform만 적용
330
+ fluo migrate ./src --apply --only imports,injectable,scope,testing,tsconfig
331
+ ```
332
+
269
333
  **주요 변환 사항:**
270
334
  - `@nestjs/common` 임포트를 `@fluojs/core` 또는 `@fluojs/http`로 재작성합니다.
271
- - bootstrap 패턴을 재작성하고 지원되는 `listen(port)` 호출을 fluo runtime startup 규칙으로 접습니다.
335
+ - 명시적으로 platform을 선택한 뒤에만 bootstrap 패턴을 재작성하고 지원되는 `listen(port)` 호출을 fluo runtime startup 규칙으로 접습니다.
272
336
  - constructor parameter `@Inject(...)` 사용을 fluo 호환 의존성 선언으로 migration합니다.
273
337
  - `@Injectable()`을 제거하고 스코프를 `@Scope()`로 매핑합니다.
274
338
  - 안전하게 변환 가능한 test template을 `@fluojs/testing` helper 쪽으로 migration합니다.
@@ -282,7 +346,7 @@ CLI가 그래프 렌더링을 소유하지 않으면서 애플리케이션 구
282
346
  fluo inspect ./src/app.module.ts --mermaid
283
347
 
284
348
  # @fluojs/studio용 snapshot 내보내기
285
- fluo inspect ./src/app.module.ts --json > snapshot.json
349
+ fluo inspect ./src/app.module.ts --format json > snapshot.json
286
350
 
287
351
  # shell redirection 없이 같은 JSON snapshot을 CI artifact 경로에 쓰기
288
352
  fluo inspect ./src/app.module.ts --json --output artifacts/inspect-snapshot.json
@@ -297,7 +361,16 @@ fluo inspect ./src/app.module.ts --report --output artifacts/inspect-report.json
297
361
  fluo inspect ./src/app.module.ts --export AdminModule --json
298
362
  ```
299
363
 
300
- 런타임이 inspection snapshot을 생산합니다. `fluo inspect`는 `./src/app.ts` 또는 `./src/app.module.ts` 같은 생성된 TypeScript source module을 명시적 TypeScript loader boundary로 받아들이며, 기존 `.js`와 `.mjs` module path는 계속 Node.js native ESM으로 로드합니다. CLI는 inspect orchestration, JSON serialization, report wrapping, `--output <path>` artifact write를 소유하고, Studio는 snapshot parsing, filtering, connection inspection, viewer rendering, Mermaid graph semantics를 소유합니다. `fluo inspect`는 output mode flag가 없을 때 기본적으로 그 snapshot을 JSON으로 직렬화하고, `fluo inspect --mermaid`는 snapshot-to-Mermaid 렌더링을 선택적 `@fluojs/studio` 계약에 위임합니다. `--export <name>`은 bootstrap할 module export를 선택하며 기본값은 `AppModule`입니다. `--timing`은 명시적인 `--json` flag 없이 제공된 경우를 포함해 JSON snapshot 출력 옆에 bootstrap timing diagnostics 기록하고, `--report`는 CI/support triage를 위해 런타임이 생산한 snapshot을 안정적인 요약과 함께 감쌉니다. `--timing`은 Mermaid 출력과 함께 사용할 수 없습니다. `--output <path>`는 선택한 inspect payload를 stdout 대신 명시적 artifact 경로에 씁니다. 이 동작은 검사 대상 애플리케이션을 writable하게 만들지 않으며, 일반 bootstrap/close cycle 외에 module graph state를 바꾸지 않습니다. Mermaid 출력이 필요하면 명령을 실행하는 프로젝트에 Studio를 설치하세요:
364
+ `--format json`은 명시적으로 `--json`과 동등합니다. option 모두 stdout에 정확히 하나의 JSON document를 쓰고 runtime diagnostics stderr로 보내며, 다른 `--format` 값은 거부합니다.
365
+
366
+ 런타임이 inspection snapshot을 생산합니다. `fluo inspect`는 `./src/app.ts` 또는 `./src/app.module.ts` 같은 생성된 TypeScript source module을 명시적 TypeScript loader boundary로 받아들이며, 기존 `.js`와 `.mjs` module path는 계속 Node.js native ESM으로 로드합니다. CLI는 authoritative HTTP dispatcher descriptor를 사용할 수 있도록 adapterless application을 bootstrap한 뒤 runtime-owned `routes` projection을 JSON, timing envelope, report snapshot에 추가합니다. CLI는 inspect orchestration, JSON serialization, report wrapping, `--output <path>` artifact write를 소유하고, Studio는 snapshot parsing, filtering, connection inspection, viewer rendering, Mermaid graph semantics를 소유합니다. `fluo inspect`는 output mode flag가 없을 때 기본적으로 그 snapshot을 JSON으로 직렬화하고, `fluo inspect --mermaid`는 snapshot-to-Mermaid 렌더링을 선택적 `@fluojs/studio` 계약에 위임합니다. `--export <name>`은 bootstrap할 module export를 선택하며 기본값은 `AppModule`입니다. `--timing`은 명시적인 `--json` flag 없이 제공된 경우를 포함해 JSON snapshot 출력 옆에 bootstrap timing diagnostics를 기록하고, `--report`는 CI/support triage를 위해 런타임이 생산한 snapshot을 안정적인 요약과 함께 감쌉니다. `--timing`은 Mermaid 출력과 함께 사용할 수 없습니다. `--output <path>`는 선택한 inspect payload를 stdout 대신 명시적 artifact 경로에 씁니다. 이 동작은 검사 대상 애플리케이션을 writable하게 만들지 않으며, 일반 bootstrap/close cycle 외에 module graph state를 바꾸지 않습니다.
367
+
368
+ 각 `routes[]` entry는 `id`, `kind`, `method`, effective `path`, optional effective `version`, `params`의
369
+ parameter name, originating `module`, `controller`, `handler`를 포함합니다. React `@Path(...)`
370
+ handler는 `kind: 'react-page'`, 일반 HTTP handler는 `kind: 'http'`를 사용합니다. Artifact에는 parameter
371
+ value, request body, cookie, header, query value가 포함되지 않으며 route projection은 matching, conflict
372
+ detection, dispatch에 관여하지 않습니다. Mermaid 출력이 필요하면 명령을 실행하는 프로젝트에 Studio를
373
+ 설치하세요:
301
374
 
302
375
  ```bash
303
376
  pnpm add -D @fluojs/studio
@@ -305,6 +378,76 @@ pnpm add -D @fluojs/studio
305
378
 
306
379
  Studio가 없으면 CI와 non-interactive 실행은 prompt나 package manager 실행 없이 설치 안내와 함께 빠르게 실패합니다. Interactive 실행에서는 Studio 설치 여부를 물을 수 있지만, 명시적으로 승인되고 구현된 설치 흐름이 없는 한 `fluo inspect`가 package manager install을 실행하지 않습니다.
307
380
 
381
+ ### React Page Type Generation
382
+
383
+ Bootstrap-resolved route catalog에서 application-owned path-only React page type과 absolute href
384
+ builder를 생성합니다.
385
+
386
+ ```bash
387
+ fluo typegen ./src/app.ts --output ./src/generated/react-pages.ts
388
+ fluo typegen ./src/admin.ts --export AdminModule --output ./src/generated/admin-pages.ts
389
+ fluo typegen ./src/app.ts --output ./src/generated/react-pages.ts --check
390
+ fluo typegen ./src/app.ts --output ./src/generated/react-pages.ts --watch
391
+ ```
392
+
393
+ `--export` 기본값은 `AppModule`입니다. 명령은 CLI loader로 TypeScript source를 로드하고 application을
394
+ bootstrap한 다음 `app.dispatcher.describeRoutes()`를 읽어 `createReactPageCatalog(...)`와
395
+ `generateReactPageTypes(...)`를 호출하고 application을 닫습니다. Output path는 현재 working
396
+ directory를 기준으로 resolve됩니다. 파일이 없으면 `CREATE`, content가 stale하면 `UPDATE`, byte 단위로
397
+ 같으면 `UNCHANGED`를 보고합니다. Write는 complete temporary file 하나를 atomic rename으로 publish하며
398
+ `UNCHANGED`는 target을 다시 쓰지 않습니다.
399
+
400
+ Default generation은 application과 일치하는 tooling namespace를 하나의 short-lived child process에서
401
+ 평가하고, 해당 process가 종료된 뒤에만 결과를 check하거나 publish합니다. 따라서 반복되는 watch
402
+ generation이 watcher process에 application module graph나 TypeScript loader resource를 유지하지 않습니다.
403
+ Programmatic caller가 `TypegenCommandRuntimeOptions.loadReactTypegenModules`를 제공하면 의도적으로 caller
404
+ process에서 generation하며, 반환된 namespace가 TypeScript, `.js`, `.mjs` input 모두에 authoritative합니다.
405
+
406
+ `--check`는 같은 authoritative bootstrap과 generation을 수행하지만 target을 쓰지 않습니다. Exact byte를
407
+ 비교해 stable status 하나를 보고합니다. `UNCHANGED`는 stdout과 exit code `0`, `MISSING`, `STALE`,
408
+ `MALFORMED`, `UNSUPPORTED_VERSION`은 stderr와 각각 exit code `2`, `3`, `4`, `5`를 사용합니다. Argument,
409
+ 현재 version의 target은 complete canonical generated body여야 합니다. Syntax 또는 structure가 손상되면
410
+ `MALFORMED`, 이전 catalog에서 생성된 complete artifact이면 `STALE`입니다. Argument, bootstrap,
411
+ generation, filesystem 및 그 밖의 command failure는 exit code `1`을 사용합니다. Programmatic caller는
412
+ root package가 export하는 `TYPEGEN_EXIT_CODES`를 사용할 수 있습니다.
413
+
414
+ `--watch`는 bounded development integration입니다. CLI는 startup generation 전에 application module
415
+ directory의 recursive watcher를 설치합니다. 해당 generation과 그 실행 중 관찰된 change를 한 번으로
416
+ coalesce한 rerun이 모두 성공한 뒤에만 `WATCHING <directory>`를 출력합니다. Readiness 이후 filesystem
417
+ burst는 100 ms 동안 coalesce되고 generation은 serialize되며 output과 그 temporary file event는
418
+ 무시됩니다. 각 generation은 authoritative bootstrap 전에 변경된 native `.js`와 `.mjs` dependency를
419
+ 포함한 현재 application module graph를 평가합니다. Regeneration failure는 `ERROR <output>: <message>`를
420
+ 출력하고 마지막 valid artifact를 보존한 채 다음 change를 기다립니다. Watcher failure는 cleanup 뒤 code
421
+ `1`로 종료됩니다. generation 또는 generation이 소유한 artifact commit이 active인 동안 수신한 모든 source
422
+ event는 해당 작업을 무효화하므로 coalesce된 후속 generation이 끝나기 전에는 그 output이 publish될 수
423
+ 없습니다. `SIGINT`와 `SIGTERM`은 watcher를 닫고 signal handler를 제거하며 active owned generation(child
424
+ process 또는 caller-process bootstrap)을 cancel하고 owned artifact commit을 abort하여 둘 중 어느 것도
425
+ publish하지 못하게 합니다. Caller-process cancellation은 asynchronous bootstrap과 application close가
426
+ settle될 때까지 기다린 뒤 code `0`으로 watch를 종료하며, `SIGTERM` 뒤에도 종료하지 않는 child는 제한된
427
+ grace period 뒤 force-kill됩니다.
428
+ Module directory 밖의 파일은 의도적으로 watch boundary 밖에
429
+ 있습니다. Source scanner나 두 번째 route discovery system을 기대하지 말고 command를 다시 실행하거나
430
+ 의도한 source root의 module path를 선택하세요.
431
+
432
+ 생성된 `reactPageRoutes` object는 stable catalog `id`를 key로 사용합니다. Dynamic `href(...)`,
433
+ `link(...)`, `push(...)`, `replace(...)` method는 모든 path param을 요구하고 각 값을 URI-encode하며
434
+ static method는 param을 받지 않습니다. `route.link(params)`를 기존 real-anchor `Link`에 spread하거나,
435
+ 기존 `ReactRouter`를 `route.push(router, params)` / `route.replace(router, params)`에 전달하세요.
436
+
437
+ ```tsx
438
+ const productRoute = reactPageRoutes['GET /products/:productId ProductRouter show'];
439
+
440
+ <Link {...productRoute.link({ productId })}>Product</Link>;
441
+ productRoute.push(router, { productId });
442
+ productRoute.replace(router, { productId });
443
+ ```
444
+
445
+ 이 generated method는 기존 HTTP-first client API가 실행되기 전에 일반 absolute href string으로 resolve됩니다.
446
+ Runtime route table, matcher, relative-route model, SPA navigation을 추가하지 않습니다. 기존 `href(...)`,
447
+ `Link href`, router string/`URL` 호출은 계속 지원됩니다. Versioned route는 명시적으로 실패합니다.
448
+ Catalog만으로는 URI versioning과 header, media-type, custom version strategy를 구분할 수 없기 때문입니다. 자세한 내용은
449
+ [@fluojs/react path-only typegen contract](../react/README.ko.md#path-only-page-type-generation)를 참고하세요.
450
+
308
451
  ## 공개 API
309
452
 
310
453
  다른 도구 내에서 CLI 동작을 트리거하기 위해 패키지를 프로그래밍 방식으로 사용할 수 있습니다.
@@ -325,10 +468,14 @@ Studio가 없으면 CI와 non-interactive 실행은 prompt나 package manager
325
468
  | `GeneratorKind` | 지원되는 모든 생성기 유형(예: `'controller'`, `'service'`)의 유니온 타입입니다. |
326
469
  | `ModuleRegistration` | generator 실행의 controller, provider, middleware module wiring metadata를 설명하는 타입입니다. |
327
470
  | `inspectUsage()` | help surface와 test에서 사용하는 현재 `fluo inspect` usage text를 반환합니다. |
328
- | `runInspectCommand(argv, options?)` | inspect orchestration, JSON/report emission, Studio Mermaid delegation에 대한 프로그래밍적 접근을 제공합니다. |
471
+ | `runInspectCommand(argv, options?)` | inspect orchestration, compiled route JSON/report emission, Studio Mermaid delegation에 대한 프로그래밍적 접근을 제공합니다. |
329
472
  | `InspectCommandRuntimeOptions` | cwd, stream, prompt, Studio renderer loading 같은 `runInspectCommand(...)`와 `runCli(...)` inspect runtime override 타입입니다. |
473
+ | `typegenUsage()` | help surface와 test에서 사용하는 현재 `fluo typegen` usage text를 반환합니다. |
474
+ | `TYPEGEN_EXIT_CODES` | Typegen automation이 사용하는 stable `SUCCESS`, `ERROR`, `MISSING`, `STALE`, `MALFORMED`, `UNSUPPORTED_VERSION` process code입니다. |
475
+ | `runTypegenCommand(argv, options?)` | bootstrap-resolved React page generation, non-mutating check, bounded watch mode에 대한 프로그래밍적 접근을 제공합니다. |
476
+ | `TypegenCommandRuntimeOptions` | cwd, stream, tooling module loading 같은 `runTypegenCommand(...)`와 `runCli(...)` typegen runtime override 타입입니다. `loadReactTypegenModules`를 제공하면 해당 namespace를 사용하는 caller-process generation을 선택하고, 생략하면 short-lived generation child를 사용합니다. |
330
477
 
331
- 프로그래밍 방식 진입점은 호출자 프로세스의 소유권을 보존합니다. `runCli(...)`, `runNewCommand(...)`, `runInspectCommand(...)`는 `process.exit(...)`를 호출하지 않고 숫자 exit code를 반환하며, prompt 취소는 command runner를 통해 exit code `0`으로 해석됩니다. dependency 설치나 git 초기화 같은 setup 작업은 해석된 `fluo new` 옵션이 요청한 경우에만 실행됩니다. `runGenerateCommand(...)`는 구조화된 `GenerateResult`를 반환합니다. 파일 쓰기 없이 생성 파일과 module-wiring action을 미리 보려면 `dryRun: true`를 전달하세요. 호출자가 제공한 prompt hook은 공개 패키지 엔트리포인트의 `CliPromptCancelledError`를 throw해 CLI 내부 파일에 의존하지 않고 정상 취소를 표현할 수 있습니다.
478
+ 프로그래밍 방식 진입점은 호출자 프로세스의 소유권을 보존합니다. `runCli(...)`, `runNewCommand(...)`, `runInspectCommand(...)`, `runTypegenCommand(...)`는 `process.exit(...)`를 호출하지 않고 숫자 exit code를 반환하며 typegen caller는 그 결과를 `TYPEGEN_EXIT_CODES`와 비교할 수 있습니다. Prompt 취소는 command runner를 통해 exit code `0`으로 해석됩니다. dependency 설치나 git 초기화 같은 setup 작업은 해석된 `fluo new` 옵션이 요청한 경우에만 실행됩니다. `runGenerateCommand(...)`는 구조화된 `GenerateResult`를 반환합니다. 파일 쓰기 없이 생성 파일과 module-wiring action을 미리 보려면 `dryRun: true`를 전달하세요. 호출자가 제공한 prompt hook은 공개 패키지 엔트리포인트의 `CliPromptCancelledError`를 throw해 CLI 내부 파일에 의존하지 않고 정상 취소를 표현할 수 있습니다.
332
479
 
333
480
  ## 관련 패키지
334
481
 
@@ -343,6 +490,7 @@ Studio가 없으면 CI와 non-interactive 실행은 prompt나 package manager
343
490
  - [cli.ts](./src/cli.ts) - 명령 디스패처 및 인자 파싱.
344
491
  - [commands/new.ts](./src/commands/new.ts) - 프로젝트 스캐폴딩 구현.
345
492
  - [commands/inspect.ts](./src/commands/inspect.ts) - 런타임 검사 export mode와 Studio 위임.
493
+ - [commands/typegen.ts](./src/commands/typegen.ts) - React page catalog bootstrap과 deterministic path-only artifact write.
346
494
  - [commands/migrate.ts](./src/commands/migrate.ts) - decorator codemod, JSON report, transform filter.
347
495
  - [commands/package-workflow.ts](./src/commands/package-workflow.ts) - `fluo add`와 `fluo upgrade` workflow.
348
496
  - [commands/scripts.ts](./src/commands/scripts.ts) - `dev`, `build`, `start` lifecycle command boundary.