Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .gitleaks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description = "Reviewed public source hashes in the immutable browser resource p
condition = "AND"
targetRules = ["generic-api-key"]
regexTarget = "line"
paths = ['''^eng/provenance/profiles/browser-resources-r[12345]\.json$''']
paths = ['''^eng/provenance/profiles/browser-resources-r[123456]\.json$''']
regexes = [
'''^\s*"(?:apps/site/)?node_modules/@bufbuild/protobuf/dist/esm/wkt/gen/google/protobuf/api_pb\.js": "73e489001027c703bc0224ae73f78ecefe028e88284bd06952e8603c3d81472c",?$''',
'''^\s*"node_modules/@connectrpc/connect-web/dist/esm/assert-fetch-api\.js": "bd56033776818aaa82959c12561dd084d3a730180e6e8f1e681f5d3d439b6474",?$''',
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ npm run hooks
npm run dev
```

Open the local URL printed by React Router. Public pages are rendered at build time; there is no request-time Node server in the deployed artifact.
Open the local URL printed by React Router. Public pages are rendered at build time; there is no request-time Node server in the deployed artifact. A small Cloudflare Worker redirects `www.arcforges.com` to the canonical HTTPS apex before serving pages; other requests use the static asset binding.

```sh
npm run check
Expand All @@ -31,6 +31,7 @@ The preview serves the actual candidate through local Wrangler at `http://127.0.
| `apps/site` | Prerendered home, local greeting and server connection pages |
| `apps/app` | Documented boundary for the future Account/Chat profiles |
| `packages/ui` | Shared components and Tailwind/CSS styles |
| `worker` | Private canonical-host redirect and static asset fallback |
| `tooling` | TypeScript build, provenance, policy and Cloudflare delivery commands |
| `tests` | Unit, published SDK wire fixtures, browser and accessibility tests |
| `artifacts/candidate` | Ignored immutable delivery artifact, manifest and SBOMs |
Expand All @@ -40,11 +41,11 @@ Baseline: TypeScript **7.0.2**, React **19.3.0**, React Router **8.4.0**, Vite *

## Delivery

PRs run source/static/offline checks, Windows IDE declaration evaluation, security scans and one Linux static candidate build. Main deploys those same bytes and records provider completion in a GitHub prerelease. CI does not install browsers, run E2E, fetch public assets or call Cloud. See [validation policy](docs/validation-policy.md). Private workspaces are not published to npm; Workers subdomains and preview URLs remain disabled.
PRs run source/static/offline checks, Windows IDE declaration evaluation, security scans and one Linux candidate build containing the prerendered assets and redirect Worker. Main deploys those same bytes and records provider completion in a GitHub prerelease. CI does not install browsers, run E2E, fetch public assets or call Cloud. See [validation policy](docs/validation-policy.md). Private workspaces are not published to npm; Workers subdomains and preview URLs remain disabled.

The main-only GitHub `cloudflare` environment contains the account variable and deployment secret. The custom-domain binding is managed in Cloudflare; CI verifies that it belongs to this Worker before deploying. PR checks remain credential-free. See [deployment setup and recovery](docs/deploying.md) and [evidence](docs/validation.md).
The main-only GitHub `cloudflare` environment contains the account variable and deployment secret. Domain bindings are managed in Cloudflare; CI verifies that the apex custom domain belongs to this Worker before deploying. Preserve the existing `www.arcforges.com/*` Web route and its proxied DNS record. The redirect retains the path and query, so a new visit to the www connection page reaches the apex before its same-origin Cloud call. PR checks remain credential-free. See [deployment setup and recovery](docs/deploying.md) and [evidence](docs/validation.md).

Workers Static Assets supports this static React build directly. Frameworks that need request-time server code require a Workers-compatible adapter/runtime. This setup does not host C# or provide an API proxy. The Cloud Worker owns the same-origin `/api/*` route and forwards to its Native AOT container; see the [Hello integration boundary and Cloud ownership](docs/cloud-hello.md). See also the [official React guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/react/) and [static assets guide](https://developers.cloudflare.com/workers/static-assets/get-started/).
Workers Static Assets serves the static React build behind the canonical-host redirect. Frameworks that need request-time rendering require a Workers-compatible adapter/runtime. This setup does not host C# or provide an API proxy. The Cloud Worker owns `arcforges.com/api/*` and forwards to its Native AOT container; see the [Hello integration boundary and Cloud ownership](docs/cloud-hello.md). See also the [official React guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/react/) and [static assets guide](https://developers.cloudflare.com/workers/static-assets/get-started/).

## Contribute

Expand Down
4 changes: 3 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"$schema": "https://biomejs.dev/schemas/2.5.13/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": { "includes": ["**/*.ts", "**/*.tsx", "!**/.react-router", "!**/build"] },
"files": {
"includes": ["**/*.ts", "**/*.tsx", "worker/**/*.js", "!**/.react-router", "!**/build"]
},
"formatter": { "enabled": false },
"assist": { "enabled": false },
"linter": { "enabled": true, "rules": { "preset": "recommended" } }
Expand Down
14 changes: 8 additions & 6 deletions docs/cloud-hello.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The Cloud repository deploys the API Worker and Native AOT container independent

| Item | Value |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Browser SDK | `@arcforges/api-client` and `@arcforges/proto`, both `1.0.0-ci.25.1` |
| Browser SDK | `@arcforges/api-client` and `@arcforges/proto`, both `1.0.0-ci.44.1` |
| Browser base URL | Same origin, `/api` |
| Public method | `POST https://arcforges.com/api/arcforges.hello.v1.HelloService/SayHello` |
| Container method after prefix removal | `/arcforges.hello.v1.HelloService/SayHello` |
Expand All @@ -19,22 +19,24 @@ The Cloud repository deploys the API Worker and Native AOT container independent
| Expected reply | Published `SayHelloResponse`, `message = "Hello, ArcForges!"` |
| Authority | [Contracts Hello schema](https://github.com/ArcForges/Contracts/blob/main/public/proto/arcforges/hello/v1/hello.proto), a packaging example, not a product API |

The Web origin stays `https://arcforges.com`; CSP keeps `connect-src 'self'` and no cross-origin exception is needed. A later account/authenticated API must define its own session behavior; this anonymous diagnostic must not silently start forwarding credentials.
The Web origin stays `https://arcforges.com`; CSP keeps `connect-src 'self'` and no cross-origin exception is needed. The Web Worker redirects www navigation to the HTTPS apex with HTTP 308, preserving path and query before serving HTML. This prevents a www page from calling an API path owned only on the apex. The existing www Web route and proxied DNS record remain in place; Cloud requires no additional www API route.

The browser client deliberately uses `redirect: "error"`. Reload a www page opened before the redirect deployment so navigation establishes the apex origin; the existing page's POST will not silently follow an API redirect. A later account/authenticated API must define its own session behavior; this anonymous diagnostic must not silently start forwarding credentials.

## Responsibilities owned by the Cloud repository

1. Build and test the actual C# Native AOT Linux container implementing this published wire contract. Cloudflare currently requires a `linux/amd64` image. Validate its AOT build, startup, gRPC-Web response/trailer framing, and failure statuses; the existing Contracts HelloHost example alone is not AOT evidence.
1. Build the actual C# Native AOT Linux container implementing this published wire contract. Cloudflare currently requires a `linux/amd64` image. CI compiles and packages it with static and offline checks; startup, gRPC-Web response/trailer framing and failure-status runtime tests remain explicit local diagnostics under the validation policy. The existing Contracts HelloHost example alone is not AOT evidence.
2. Deploy its Cloud Worker and Container binding in the same Cloudflare account. Forward to the container through that binding, removing only the leading `/api` from the public path. Preserve request/response protobuf bytes and gRPC-Web content type, statuses and framed trailers. Do not convert the payload to ad-hoc JSON or forward back to the public API URL.
3. Attach **Worker route** `arcforges.com/api/*` to the Cloud Worker. Keep the apex **Custom Domain** attached to `arcforges-web`. A route runs ahead of that custom-domain origin. The API route needs no second DNS hostname, browser token, Web service binding or Web rebuild. Unknown API methods must return an API error/404 rather than Web HTML.
4. Keep the example explicitly bounded: only the Hello diagnostic, with input/resource limits and no model call, paid user operation or database mutation. Authentication, quotas and commercial APIs remain a separate product increment. Cloud owns the Worker/Container account permissions and required plan availability.
5. Cloud's deployment gate must invoke the **public same-origin method using the published client**, verify the expected protobuf reply, and verify both success and failure behavior. Then check the button in the deployed Web page. A container health endpoint, mocked fixture or Web deployment alone does not establish this chain.
5. Promote the sealed Cloud candidate through its required deployment job. Do not run live RPC, browser or installed-consumer tests in CI. Local integration diagnostics may exercise an affected behavior once when supported by the existing environment. A container health endpoint, mocked fixture or successful Web deployment alone does not establish a real browser-to-Cloud round trip.

Cloud owns provisioning the Worker, container image, API route, billing plan and deployment credentials.

## Evidence and recovery

`cloud-hello-fixture.spec.ts` intercepts the browser API request with explicitly labelled protobuf wire fixtures. It verifies the actual published client's request, unavailable response and recovery. It is excluded from live Web verification so mocked success cannot be reported as a real C# integration. Live Web tests check that the new page loads and sends nothing automatically.
`cloud-hello-fixture.spec.ts` intercepts the browser API request with explicitly labelled protobuf wire fixtures. It verifies the actual published client's request, unavailable response and recovery. These browser fixtures are optional local diagnostics, excluded from live Web verification so mocked success cannot be reported as a real C# integration. No browser or live Cloud test runs in CI.

Web delivery still verifies its assets and Web-owned public 404 behavior. Candidate-only tests verify that the static Worker cannot fake a successful API response; the live Web gate does not require Web HTML at `/api/*`, because Cloud owns those paths. Cloud owns API/container deployment and its independent real integration gate. Removing Cloud's API route restores the static Worker's rejection of that API request; the connection page reports failure instead of silently falling back to a local greeting.
Web's candidate gate checks its assets, private redirect module and delivery configuration. Offline redirect tests distinguish canonical navigation from asset fallback; optional local candidate diagnostics can verify that Web cannot fake a successful API response. Cloud owns API/container deployment. Removing Cloud's apex API route restores Web's rejection of that API request; the connection page reports failure instead of silently falling back to a local greeting. No Web check requires its HTML at production `/api/*`.

References: [routes before a Custom Domain](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/#interaction-with-routes), [Cloudflare Containers setup](https://developers.cloudflare.com/containers/get-started/).
Loading
Loading