diff --git a/build/prepare-sites-build.mjs b/build/prepare-sites-build.mjs index d842cd8..35ff203 100644 --- a/build/prepare-sites-build.mjs +++ b/build/prepare-sites-build.mjs @@ -10,6 +10,7 @@ const browserRoutes = [ 'privacy', 'proto', 'proto/docs', + 'rcc', 'support', 'terms', ]; diff --git a/public/sitemap.xml b/public/sitemap.xml index ed012af..4d22a04 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -8,10 +8,16 @@ https://rosetta.im/proto/ - 2026-07-30 + 2026-08-01 weekly 0.9 + + https://rosetta.im/rcc/ + 2026-08-01 + monthly + 0.8 + https://rosetta.im/proto/docs/ 2026-07-31 diff --git a/src/App.tsx b/src/App.tsx index b98b291..6978dfb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,6 +18,9 @@ const ProtoPage = lazy(() => const ProtoDocsPage = lazy(() => import('./pages/ProtoPage').then((module) => ({ default: module.ProtoDocsPage })), ); +const RccPage = lazy(() => + import('./pages/RccPage').then((module) => ({ default: module.RccPage })), +); const SupportPage = lazy(() => import('./pages/SupportPage').then((module) => ({ default: module.SupportPage })), ); @@ -87,6 +90,7 @@ export default function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/components/SiteFooter/SiteFooter.tsx b/src/components/SiteFooter/SiteFooter.tsx index 36f2628..8e8a64c 100644 --- a/src/components/SiteFooter/SiteFooter.tsx +++ b/src/components/SiteFooter/SiteFooter.tsx @@ -39,6 +39,9 @@ export function SiteFooter() { Proto + + RCC + Support diff --git a/src/pages/ProtoPage.module.css b/src/pages/ProtoPage.module.css index 3c75367..eba4502 100644 --- a/src/pages/ProtoPage.module.css +++ b/src/pages/ProtoPage.module.css @@ -26,6 +26,11 @@ font-weight: 650; } +.important { + color: light-dark(var(--mantine-color-orange-8), var(--mantine-color-orange-3)); + font-weight: 650; +} + .layerExamples { min-width: 0; margin: 18px 0 24px; @@ -40,9 +45,13 @@ margin-bottom: 0; } +.docsLinks { + margin-top: 44px; + gap: 28px; +} + .docsLink { display: inline-block; - margin-top: 44px; font-size: var(--mantine-font-size-sm); font-weight: 600; text-decoration: none; diff --git a/src/pages/ProtoPage.tsx b/src/pages/ProtoPage.tsx index dd3d913..98322c8 100644 --- a/src/pages/ProtoPage.tsx +++ b/src/pages/ProtoPage.tsx @@ -517,6 +517,57 @@ export class RccGeneratedPacketRegistry { + + + Rosetta Code Compiler (RCC) is the build-time compiler behind the protocol. + It reads every layer.N.yml snapshot, turns the YAML into a + typed protocol model, validates that the history is safe, and emits source + code for the selected language. Applications import generated models and + codecs; they do not parse the YAML at runtime. + + + {`proto/layer.*.yml + │ + ├─ parse packets, reusable types, enums and comments + ├─ validate references, required fields and stable field IDs + │ + ├─ mode=server → all layers + version-aware codecs + registry + └─ mode=client → latest layer + latest codecs + version constant`} + + + + Server generation preserves the protocol timeline. + Java codecs receive the negotiated layer, include only fields active in + that layer, and expose the compiled minimum and maximum versions. + + + Client generation{' '} + + selects the highest layer and creates the current packet, type, enum, + codec, and registry sources without carrying historical shapes into + the application. + + + + Schema validation fails the build for unknown types or + unsafe field-ID reuse, so incompatible protocol edits are caught before + generated sources reach a server or client package. + + + Generated documentation carries schema comments into + Javadoc or TSDoc, including field direction, wire type, optionality, and + accessor contracts. + + + + The RCC guide includes separate client and version-aware server examples.{' '} + + Run npx rcc --list-languages for the authoritative list of + language targets in the installed compiler version. + + + + RCC reads versioned files named layer.N.yml. The top-level @@ -664,9 +715,14 @@ packet field 1 · INT8 · SUCCESS (0)`} - - See docs of PROTO → - + + + See docs of PROTO → + + + Learn RCC → + + ); diff --git a/src/pages/RccPage.module.css b/src/pages/RccPage.module.css new file mode 100644 index 0000000..4e587ff --- /dev/null +++ b/src/pages/RccPage.module.css @@ -0,0 +1,114 @@ +.code { + margin: 18px 0; + padding: 16px; + border: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-5)); + border-radius: var(--mantine-radius-xs); + background: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-7)); + color: light-dark(var(--mantine-color-gray-8), var(--mantine-color-dark-0)); + font-size: 12px; + line-height: 1.65; + overflow-x: auto; + white-space: pre; +} + +.pipeline { + display: grid; + grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr); + gap: 12px; + align-items: center; + margin: 22px 0; +} + +.pipeline > span:nth-child(odd) { + padding: 14px; + border: 1px solid light-dark(var(--mantine-color-blue-2), var(--mantine-color-blue-9)); + border-radius: var(--mantine-radius-xs); + background: light-dark(var(--mantine-color-blue-0), rgba(25, 113, 194, 0.12)); + color: light-dark(var(--mantine-color-blue-9), var(--mantine-color-blue-1)); + font-size: var(--mantine-font-size-sm); + font-weight: 650; + line-height: 1.45; + text-align: center; +} + +.pipeline > span:nth-child(even) { + color: var(--mantine-color-blue-6); + font-weight: 700; +} + +.step { + display: grid; + grid-template-columns: 34px minmax(0, 1fr); + gap: 16px; + margin-top: 30px; +} + +.step:first-child { + margin-top: 0; +} + +.stepNumber { + display: grid; + width: 34px; + height: 34px; + place-items: center; + border-radius: 50%; + background: var(--mantine-color-blue-6); + color: var(--mantine-color-white); + font-size: var(--mantine-font-size-sm); + font-weight: 700; +} + +.stepBody { + min-width: 0; + padding-bottom: 24px; + border-bottom: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5)); +} + +.step:last-child .stepBody { + padding-bottom: 0; + border-bottom: 0; +} + +.subheading { + margin: 3px 0 12px; + color: light-dark(var(--mantine-color-dark-8), var(--mantine-color-dark-0)); + font-size: 17px; + font-weight: 650; +} + +.important { + color: light-dark(var(--mantine-color-orange-8), var(--mantine-color-orange-3)); + font-weight: 650; +} + +.note { + margin: 18px 0; + border: 1px solid light-dark(var(--mantine-color-orange-3), var(--mantine-color-orange-9)); + border-left: 3px solid var(--mantine-color-orange-6); + background: light-dark(var(--mantine-color-orange-0), rgba(253, 126, 20, 0.1)); + color: light-dark(var(--mantine-color-orange-9), var(--mantine-color-orange-2)); +} + +@media (max-width: 48em) { + .pipeline { + grid-template-columns: minmax(0, 1fr); + } + + .pipeline > span:nth-child(even) { + transform: rotate(90deg); + text-align: center; + } +} + +@media (max-width: 36em) { + .step { + grid-template-columns: 28px minmax(0, 1fr); + gap: 12px; + } + + .stepNumber { + width: 28px; + height: 28px; + } +} diff --git a/src/pages/RccPage.tsx b/src/pages/RccPage.tsx new file mode 100644 index 0000000..e24d926 --- /dev/null +++ b/src/pages/RccPage.tsx @@ -0,0 +1,239 @@ +import { Anchor, Box, Code, List, Paper, Text, Title } from '@mantine/core'; +import type { ReactNode } from 'react'; +import { + LegalList, + LegalPage, + LegalSection, + LegalText, +} from '../components/LegalPage/LegalPage'; +import { SEO } from '../components/SEO/SEO'; +import classes from './RccPage.module.css'; + +const GITEA_REPOSITORY = 'https://git.rosetta.im/Rosetta/rcc'; + +function TechnicalCode({ children }: { children: string }) { + return ( + + {children} + + ); +} + +function Step({ number, title, children }: { number: number; title: string; children: ReactNode }) { + return ( + + {number} + + + {title} + + {children} + + + ); +} + +export function RccPage() { + return ( + <> + + + + RCC compiles Rosetta's versioned YAML protocol into typed models, codecs, + and packet registries.{' '} + + A server build can retain the complete protocol history; a client build + stays small by generating only the latest layer. + + + + + + RCC treats proto/layer.*.yml as the protocol's source of + truth. Before writing code, it resolves primitive, enum, and reusable type + references and rejects incompatible reuse of a field ID between layers. + + + Versioned YAML schemas + + Parse + validate + + Models + codecs + registry + + + + Packets become typed packet classes; reusable schema types become model + classes; enums preserve their numeric wire values. + + + Codecs encode and decode TLV fields and verify required fields before + encoding and after decoding. + + + The generated registry maps packet IDs to codecs and exposes the + compiled protocol version or version range. + + + YAML comments become Javadoc or TSDoc for generated declarations and + accessors. + + + + + + + Add Rosetta's npm package registry to the project, then install RCC. The + registry setting can live in a project-level .npmrc so CI and + local builds resolve the same compiler package. + + {`# .npmrc +registry=https://git.rosetta.im/api/packages/Rosetta/npm/ + +# install the compiler +npm install rcc + +# query languages from the installed RCC version +npx rcc --list-languages + +# inspect the rest of the CLI +npx rcc --help`} + + RCC source is hosted in the{' '} + + Rosetta/rcc Gitea repository + + .{' '} + + Pin the dependency version in the project lockfile so generated output + remains reproducible. + + + + + + + + Put complete protocol snapshots in one directory and name them + layer.N.yml. Increment the top-level version, keep packet + and field IDs stable, and repeat definitions that remain part of the + protocol. + + {`proto/ +├── layer.1.yml +├── layer.2.yml +└── layer.3.yml`} + + + + + Use client for the current application package. RCC selects + the highest schema version. Use server when the runtime must + decode connections negotiated on older supported layers. Full + multi-version codec generation is currently implemented by the Java + backend. + + + + + + Server generation combines all layers and emits version-aware codecs, + models, enums, and a registry with MIN_VERSION and + MAX_VERSION. + + {`npx rcc \\ + --mode server \\ + --lang java \\ + --protoDir ./proto \\ + --outDir ./server/src/generated/java \\ + --basePackage im.rosetta.network \\ + --clean`} + + For a Java client, change the mode and output directory. The generated + sources describe only the latest layer. + + {`npx rcc \\ + --mode client \\ + --lang java \\ + --protoDir ./proto \\ + --outDir ./client/src/generated/java \\ + --basePackage im.rosetta.network \\ + --clean`} + + + + + TypeScript is the current latest-layer client target. It produces + models, enums, codecs, and RccGeneratedPacketRegistry.VERSION. + + {`npx rcc \\ + --mode client \\ + --lang typescript \\ + --protoDir ./proto \\ + --outDir ./client/src/generated/protocol \\ + --clean`} + + + Always run npx rcc --list-languages before configuring a + generator. The installed compiler's output is the source of truth + for available language targets. + + + + + + + Keep client and server generation together in + rcc-prebuild.yml. Paths are resolved relative to the + config file; clean: true clears only each configured output + directory. + + {`watch: false +protoDir: ./proto +clean: true + +compilers: + - name: TypeScript client + mode: client + lang: typescript + output: ./client/src/generated/protocol + + - name: Java server + mode: server + lang: java + output: ./server/src/generated/java + basePackage: im.rosetta.network`} + {`npx rcc -f ./rcc-prebuild.yml`} + + + + + Add the output directory to the language build, then run generation + before compilation in local development and CI. RCC writes source + files; the surrounding Gradle, npm, or application build is responsible + for compiling and publishing the final server or client package. + + + + + + {`npx rcc --mode [options] +npx rcc -f +npx rcc --list-languages + +--mode, -m client | server +--lang, -l language returned by --list-languages +--protoDir, -p schema directory (default: ./proto) +--outDir, -o generated source directory (default: ./generated) +--basePackage, -b Java base package (default: im.rosetta.generated) +--clean clean the output directory before generation +--file, -f prebuild YAML config`} + + + + ); +}