Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
79a5b84
Version React typegen artifacts
ayden94 Aug 4, 2026
50cc80b
Make typegen artifact writes atomic
ayden94 Aug 4, 2026
9dbb5c0
Add bounded typegen watch lifecycle
ayden94 Aug 4, 2026
035d7b1
Add deterministic typegen check workflows
ayden94 Aug 4, 2026
ef0093e
Expose typegen modes in CLI help
ayden94 Aug 4, 2026
d9b53eb
Export stable typegen automation contracts
ayden94 Aug 4, 2026
2ceb74b
Add React consumer request and hydration fixtures
ayden94 Aug 4, 2026
5e0b6fc
Document the React typegen consumer workflow
ayden94 Aug 4, 2026
ff4bb44
Document CLI typegen automation contracts
ayden94 Aug 4, 2026
652d25f
Document the React testing recipe
ayden94 Aug 4, 2026
ac55b8b
Link React typegen testing guidance
ayden94 Aug 4, 2026
bfccc35
Record React typegen release intent
ayden94 Aug 4, 2026
bc7a3f4
Close typegen watch startup gaps
ayden94 Aug 4, 2026
82fe130
Reload native typegen module graphs
ayden94 Aug 4, 2026
ca41cb6
Validate complete React typegen artifacts
ayden94 Aug 4, 2026
ba067e3
Document CLI typegen remediation contracts
ayden94 Aug 4, 2026
c677740
Align React typegen remediation guidance
ayden94 Aug 4, 2026
6047c46
Record typegen remediation governance
ayden94 Aug 4, 2026
027ba39
Bound typegen child completion
ayden94 Aug 4, 2026
708dd30
Preserve custom typegen loader authority
ayden94 Aug 4, 2026
7d99b84
Isolate default typegen generation
ayden94 Aug 4, 2026
5c392f0
Document generated React page parsing
ayden94 Aug 4, 2026
ae5b2f1
Document CLI typegen process boundaries
ayden94 Aug 4, 2026
8ca22bd
Record typegen process governance
ayden94 Aug 4, 2026
9960f8b
Make typegen process regression buildless
ayden94 Aug 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/issue-2890-react-typegen-testing-loop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fluojs/cli": minor
"@fluojs/react": minor
---

Add deterministic React typegen check and watch workflows with versioned artifact diagnostics, atomic writes, stable exit codes, and a documented consumer testing loop.
2 changes: 1 addition & 1 deletion docs/CONTEXT.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ GraphQL package-surface discoverability는 `packages/graphql/README.ko.md`, [`do

React package discoverability는 `packages/react/README.ko.md`, [`docs/reference/package-surface.ko.md`](./reference/package-surface.ko.md), [`docs/reference/package-chooser.ko.md`](./reference/package-chooser.ko.md), [`docs/contracts/release-governance.ko.md`](./contracts/release-governance.ko.md), `examples/react-stable-ssr/README.ko.md`, `examples/react-vite-ssr/README.ko.md`로 나뉜다. Runtime-neutral root는 `ReactServerEntry`, `createReactServerEntry(...)`, `renderReactResponse(...)`를 노출하고, lazy `react-dom/server` `renderToReadableStream(...)`을 통해 stream하며, 명시적인 `bootstrapScripts`, `bootstrapModules`, trusted `bootstrapScriptContent`, `assetMap` hydration metadata를 받는다. `@fluojs/react/vite`는 이미 로드한 Vite manifest를 파싱하고, `@fluojs/react/client`는 request-scoped route snapshot을 사용하는 progressive real-anchor full-document navigation을 제공한다. 명시적으로 불안정한 `@fluojs/react/experimental/rsc` subpath는 root와 stable client에서 분리되고, React, React DOM, 선택한 Flight renderer를 정확히 `19.2.6`으로 고정하며, Web Streams/build capability를 검증하고, `createReactRscManifest(...)`로 client-reference 및 server-to-client module map을 snapshot하고, `createReactFlightResponse(...)`로 application-encoded Flight payload를 반환하며, `createReactServerFunctionRegistry(...)`와 `createReactServerFunctionClient(...)`로 signed Server Function reference 및 bounded JSON action transport를 prototype한다. Flight와 action은 모두 일반 fluo HTTP dispatch를 사용한다. Server Functions에는 explicit POST endpoint, exact origin allowlist, non-simple request marker, application-owned Web Crypto와 32 byte 이상의 secret, serialization/body/result limit, action 또는 guard authorization이 필요하다. 자동 Vite manifest discovery, 임의 inline serialization, 자동 `"use server"` transform/export discovery, built-in renderer/build plugin, file route, client route grammar, SPA document swapping, client data cache, prefetch, Next.js/TanStack/Angular router compatibility는 제공하지 않는다.

React page catalog 및 route diagnostics discoverability는 `packages/react/README.ko.md`, `packages/runtime/README.ko.md`, `packages/cli/README.ko.md`, `packages/studio/README.ko.md`, [`docs/reference/package-surface.ko.md`](./reference/package-surface.ko.md), [`docs/reference/toolchain-contract-matrix.ko.md`](./reference/toolchain-contract-matrix.ko.md)로 나뉜다. `@Path(...)`는 runtime-neutral `react-page` marker를 기록하고, runtime은 authoritative compiled `HandlerDescriptor` 값을 immutable route inspection entry로 투영하며, `createReactPageCatalog(...)`는 HTTP matching, conflict detection, dispatch에 참여하지 않고 marker가 있는 React page만 노출한다. Stable `@fluojs/react/typegen` tooling subpath는 이 catalog를 deterministic path-only TypeScript declaration, absolute href builder, route-bound real-anchor props, 기존 client API에 일반 href string을 resolve하는 typed `push`/`replace` method로 변환하고 versioned route를 거부한다. Adapterless `fluo inspect`는 같은 compiled route를 직렬화하고, Studio는 live/static artifact 양쪽에서 `kind`와 parameter name만 담는 `params` field를 검증하고 표시하며 legacy entry는 일반 HTTP diagnostics로 기본 처리한다.
React page catalog 및 route diagnostics discoverability는 `packages/react/README.ko.md`, `packages/runtime/README.ko.md`, `packages/cli/README.ko.md`, `packages/studio/README.ko.md`, [`docs/contracts/testing-guide.ko.md`](./contracts/testing-guide.ko.md), [`docs/reference/package-surface.ko.md`](./reference/package-surface.ko.md), [`docs/reference/toolchain-contract-matrix.ko.md`](./reference/toolchain-contract-matrix.ko.md)로 나뉜다. `@Path(...)`는 runtime-neutral `react-page` marker를 기록하고, runtime은 authoritative compiled `HandlerDescriptor` 값을 immutable route inspection entry로 투영하며, `createReactPageCatalog(...)`는 HTTP matching, conflict detection, dispatch에 참여하지 않고 marker가 있는 React page만 노출한다. Stable `@fluojs/react/typegen` tooling subpath는 이 catalog를 deterministic path-only TypeScript declaration, absolute href builder, route-bound real-anchor props, 기존 client API에 일반 href string을 resolve하는 typed `push`/`replace` method로 변환하고 versioned route를 거부한다. `fluo typegen --check`는 stable status code를 가진 exact non-mutating CI comparison을 제공하고 bounded `--watch` generation은 coalesced module-directory change를 serialize하며 마지막 valid atomic artifact를 보존한다. Canonical consumer testing loop는 React-specific testing runtime을 추가하지 않고 render-policy unit, real `createTestApp(...)` dispatch, generated-route compile fixture, hydration mismatch reporting, JavaScript-disabled native form coverage를 결합한다. Adapterless `fluo inspect`는 같은 compiled route를 직렬화하고, Studio는 live/static artifact 양쪽에서 `kind`와 parameter name만 담는 `params` field를 검증하고 표시하며 legacy entry는 일반 HTTP diagnostics로 기본 처리한다.

Serialization response-ownership discoverability는 `packages/serialization/README.ko.md`, `packages/runtime/README.ko.md`, [`docs/reference/package-surface.ko.md`](./reference/package-surface.ko.md), [`docs/getting-started/migrate-from-nestjs.ko.md`](./getting-started/migrate-from-nestjs.ko.md), [`book/beginner/ch07-serialization.ko.md`](../book/beginner/ch07-serialization.ko.md), package-local `packages/serialization/src/serializer-interceptor.test.ts` unit coverage, 그리고 `packages/runtime/src/application.test.ts`의 runtime request-pipeline coverage로 나뉜다. `@fluojs/serialization`은 decorator-aware response serialization, `excludeExtraneous` 같은 class-level `Expose(...)` option을 표현하는 `ExposeClassOptions`, `TransformFunction`, `serialize(value)`, HTTP `SerializerInterceptor` response-boundary 통합을 담당한다. Runtime은 commit되지 않은 framework-managed 결과를 소유하므로 success response를 쓰기 전에 `SerializerInterceptor`가 이를 shaping할 수 있다. Handler 또는 runtime response helper가 `RequestContext.response`를 commit한 뒤에는 `SerializerInterceptor`가 serialization을 우회하고 `next.handle()`에서 받은 값을 그대로 반환한다. 다른 interceptor는 chain 결과를 계속 변환할 수 있다. 이와 별개로 dispatcher는 commit된 response를 확인하고 두 번째 success-response write를 건너뛴다. Request-facing interceptor behavior는 serialization-to-testing workspace dependency edge를 추가하지 않고 `bootstrapApplication(...)`과 `app.dispatch(...)`를 쓰는 runtime request pipeline에서 계속 검증해야 한다.

Expand Down
2 changes: 1 addition & 1 deletion docs/CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ GraphQL package-surface discoverability is split across `packages/graphql/README

React package discoverability is split across `packages/react/README.md`, [`docs/reference/package-surface.md`](./reference/package-surface.md), [`docs/reference/package-chooser.md`](./reference/package-chooser.md), [`docs/contracts/release-governance.md`](./contracts/release-governance.md), `examples/react-stable-ssr/README.md`, and `examples/react-vite-ssr/README.md`: the runtime-neutral root exposes `ReactServerEntry`, `createReactServerEntry(...)`, and `renderReactResponse(...)`, streams through lazy `react-dom/server` `renderToReadableStream(...)`, and accepts explicit `bootstrapScripts`, `bootstrapModules`, trusted `bootstrapScriptContent`, and `assetMap` hydration metadata. `@fluojs/react/vite` parses already-loaded Vite manifests, and `@fluojs/react/client` provides progressive real-anchor, full-document navigation with request-scoped route snapshots. The explicitly unstable `@fluojs/react/experimental/rsc` subpath is isolated from the root and stable client, pins React, React DOM, and the selected Flight renderer to exact `19.2.6`, validates Web Streams/build capabilities, snapshots client-reference and server-to-client module maps with `createReactRscManifest(...)`, returns application-encoded Flight payloads with `createReactFlightResponse(...)`, and prototypes signed Server Function references plus bounded JSON action transport with `createReactServerFunctionRegistry(...)` and `createReactServerFunctionClient(...)`. Both Flight and actions stay on ordinary fluo HTTP dispatch. Server Functions require an explicit POST endpoint, exact origin allowlist, non-simple request marker, application-owned Web Crypto and 32-byte-or-longer secret, serialization/body/result limits, and action or guard authorization. The package does not provide automatic Vite manifest discovery, arbitrary inline serialization, automatic `"use server"` transforms/export discovery, a built-in renderer/build plugin, file routes, a client route grammar, SPA document swapping, client data caches, prefetch, or Next.js/TanStack/Angular router compatibility.

React page catalog and route diagnostics discoverability is split across `packages/react/README.md`, `packages/runtime/README.md`, `packages/cli/README.md`, `packages/studio/README.md`, [`docs/reference/package-surface.md`](./reference/package-surface.md), and [`docs/reference/toolchain-contract-matrix.md`](./reference/toolchain-contract-matrix.md): `@Path(...)` records a runtime-neutral `react-page` marker, runtime projects authoritative compiled `HandlerDescriptor` values into immutable route inspection entries, and `createReactPageCatalog(...)` exposes only the marked React pages without participating in HTTP matching, conflict detection, or dispatch. The stable `@fluojs/react/typegen` tooling subpath turns that catalog into deterministic path-only TypeScript declarations, absolute href builders, route-bound real-anchor props, and typed `push`/`replace` methods that resolve ordinary href strings into the existing client APIs while rejecting versioned routes. Adapterless `fluo inspect` serializes the same compiled routes, while Studio validates and displays their `kind` and parameter-name-only `params` fields in both live and static artifacts, defaulting legacy entries to ordinary HTTP diagnostics.
React page catalog and route diagnostics discoverability is split across `packages/react/README.md`, `packages/runtime/README.md`, `packages/cli/README.md`, `packages/studio/README.md`, [`docs/contracts/testing-guide.md`](./contracts/testing-guide.md), [`docs/reference/package-surface.md`](./reference/package-surface.md), and [`docs/reference/toolchain-contract-matrix.md`](./reference/toolchain-contract-matrix.md): `@Path(...)` records a runtime-neutral `react-page` marker, runtime projects authoritative compiled `HandlerDescriptor` values into immutable route inspection entries, and `createReactPageCatalog(...)` exposes only the marked React pages without participating in HTTP matching, conflict detection, or dispatch. The stable `@fluojs/react/typegen` tooling subpath turns that catalog into deterministic path-only TypeScript declarations, absolute href builders, route-bound real-anchor props, and typed `push`/`replace` methods that resolve ordinary href strings into the existing client APIs while rejecting versioned routes. `fluo typegen --check` provides exact non-mutating CI comparison with stable status codes, while bounded `--watch` generation serializes coalesced module-directory changes and preserves the last valid atomic artifact. The canonical consumer testing loop combines render-policy units, real `createTestApp(...)` dispatch, generated-route compile fixtures, hydration mismatch reporting, and JavaScript-disabled native form coverage without introducing a React-specific testing runtime. Adapterless `fluo inspect` serializes the same compiled routes, while Studio validates and displays their `kind` and parameter-name-only `params` fields in both live and static artifacts, defaulting legacy entries to ordinary HTTP diagnostics.

Serialization response-ownership discoverability is split across `packages/serialization/README.md`, `packages/runtime/README.md`, [`docs/reference/package-surface.md`](./reference/package-surface.md), [`docs/getting-started/migrate-from-nestjs.md`](./getting-started/migrate-from-nestjs.md), [`book/beginner/ch07-serialization.md`](../book/beginner/ch07-serialization.md), package-local `packages/serialization/src/serializer-interceptor.test.ts` unit coverage, and runtime request-pipeline coverage in `packages/runtime/src/application.test.ts`: `@fluojs/serialization` owns decorator-aware response serialization, `ExposeClassOptions` class-level `Expose(...)` options such as `excludeExtraneous`, `TransformFunction`, `serialize(value)`, and HTTP `SerializerInterceptor` response-boundary integration. The runtime owns uncommitted framework-managed results, allowing `SerializerInterceptor` to shape them before the success response is written. Once a handler or runtime response helper commits `RequestContext.response`, `SerializerInterceptor` bypasses serialization and returns the value it received from `next.handle()` unchanged. Other interceptors may still transform the chain result. Independently, the dispatcher sees the committed response and skips a second success-response write. Request-facing interceptor behavior should remain covered through the runtime request pipeline with `bootstrapApplication(...)` and `app.dispatch(...)`, rather than adding a serialization-to-testing workspace dependency edge.

Expand Down
18 changes: 18 additions & 0 deletions docs/contracts/testing-guide.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ fluo의 테스트 설정은 런타임 모델과 같습니다. 표준 decorator,

`@fluojs/testing`은 `engines.node >=20.0.0`을 선언합니다. Mock helper와 `DeepMocked<T>` type은 Vitest-compatible mock type boundary를 의도적으로 사용합니다. `DeepMocked<T>`는 root `@fluojs/testing` 패키지, `@fluojs/testing/types`, `@fluojs/testing/mock`에서 사용할 수 있습니다. Vitest를 실행하지 않는 소비자는 `@fluojs/testing/app`, `@fluojs/testing/module`, harness subpath 같은 non-mock entrypoint를 우선 사용하세요.

## React Consumer Loop

React consumer coverage는 synthetic React test runtime을 추가하지 않고 같은 ladder를 확장합니다.

1. Pure helper를 통해 render policy와 metadata composition을 unit test합니다.
2. Direct page return, missing-renderer diagnostic, DTO, request scope, response ownership을
`createTestApp({ rootModule })`와 `app.request(...).send()`로 검증합니다.
3. Positive/negative generated-route fixture를 TypeScript로 compile하고 CI에서 non-mutating
`fluo typegen ... --check`를 실행합니다.
4. Aligned hydration과 `onRecoverableError`로 보고되는 의도적인 mismatch를 검증합니다.
5. Production Playwright hydration과 JavaScript-disabled native form submit을 일반
`POST` → `303` → `GET` path로 실행합니다.

Evidence는 owning seam에 분산해 유지합니다. `@fluojs/react` unit, `@fluojs/cli` typegen 및 compile fixture,
`@fluojs/testing` request dispatch, official React example의 hydration/browser test가 각각 자기 boundary를
검증합니다. 일반 fixture가 이미 real HTTP dispatcher와 application renderer를 compose할 수 있으므로 반복
setup만으로 React-specific helper를 정당화하지 않습니다.

## 명령어 (Commands)

| 명령어 | 용도 |
Expand Down
18 changes: 18 additions & 0 deletions docs/contracts/testing-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ Keep manual `FrameworkRequest`/`FrameworkResponse` stubs, `makeRequest(...)`, ra

`@fluojs/testing` declares `engines.node >=20.0.0`. Its mock helpers and `DeepMocked<T>` type intentionally use a Vitest-compatible mock type boundary. `DeepMocked<T>` is available from the root `@fluojs/testing` package, `@fluojs/testing/types`, and `@fluojs/testing/mock`; consumers that do not run Vitest should prefer non-mock entrypoints such as `@fluojs/testing/app`, `@fluojs/testing/module`, or harness subpaths.

## React Consumer Loop

React consumer coverage extends the same ladder without adding a synthetic React test runtime:

1. Unit-test render policies and metadata composition through pure helpers.
2. Cover direct page returns, missing-renderer diagnostics, DTOs, request scopes, and response
ownership with `createTestApp({ rootModule })` and `app.request(...).send()`.
3. Compile positive and negative generated-route fixtures with TypeScript and run non-mutating
`fluo typegen ... --check` in CI.
4. Cover aligned hydration plus a deliberate mismatch reported through `onRecoverableError`.
5. Run production Playwright hydration and a JavaScript-disabled native form submission through the
ordinary `POST` → `303` → `GET` path.

Keep this evidence distributed at the owning seams: `@fluojs/react` units, `@fluojs/cli` typegen and
compile fixtures, `@fluojs/testing` request dispatch, and the official React example's hydration and
browser tests. Repeated setup alone does not justify a React-specific helper when ordinary fixtures
already compose the real HTTP dispatcher and application renderer.

## Commands

| Command | Use |
Expand Down
Loading