Добавлена докуметация по RCC

This commit is contained in:
2026-08-01 07:58:52 -07:00
parent 12f6384856
commit 94bc883205
8 changed files with 437 additions and 5 deletions

View File

@@ -10,6 +10,7 @@ const browserRoutes = [
'privacy', 'privacy',
'proto', 'proto',
'proto/docs', 'proto/docs',
'rcc',
'support', 'support',
'terms', 'terms',
]; ];

View File

@@ -8,10 +8,16 @@
</url> </url>
<url> <url>
<loc>https://rosetta.im/proto/</loc> <loc>https://rosetta.im/proto/</loc>
<lastmod>2026-07-30</lastmod> <lastmod>2026-08-01</lastmod>
<changefreq>weekly</changefreq> <changefreq>weekly</changefreq>
<priority>0.9</priority> <priority>0.9</priority>
</url> </url>
<url>
<loc>https://rosetta.im/rcc/</loc>
<lastmod>2026-08-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url> <url>
<loc>https://rosetta.im/proto/docs/</loc> <loc>https://rosetta.im/proto/docs/</loc>
<lastmod>2026-07-31</lastmod> <lastmod>2026-07-31</lastmod>

View File

@@ -18,6 +18,9 @@ const ProtoPage = lazy(() =>
const ProtoDocsPage = lazy(() => const ProtoDocsPage = lazy(() =>
import('./pages/ProtoPage').then((module) => ({ default: module.ProtoDocsPage })), import('./pages/ProtoPage').then((module) => ({ default: module.ProtoDocsPage })),
); );
const RccPage = lazy(() =>
import('./pages/RccPage').then((module) => ({ default: module.RccPage })),
);
const SupportPage = lazy(() => const SupportPage = lazy(() =>
import('./pages/SupportPage').then((module) => ({ default: module.SupportPage })), import('./pages/SupportPage').then((module) => ({ default: module.SupportPage })),
); );
@@ -87,6 +90,7 @@ export default function App() {
<Route path="/encryption" element={<EncryptionPage />} /> <Route path="/encryption" element={<EncryptionPage />} />
<Route path="/proto" element={<ProtoPage />} /> <Route path="/proto" element={<ProtoPage />} />
<Route path="/proto/docs" element={<ProtoDocsPage />} /> <Route path="/proto/docs" element={<ProtoDocsPage />} />
<Route path="/rcc" element={<RccPage />} />
<Route path="/support" element={<SupportPage />} /> <Route path="/support" element={<SupportPage />} />
<Route path="/privacy" element={<PrivacyPage />} /> <Route path="/privacy" element={<PrivacyPage />} />
<Route path="/terms" element={<TermsPage />} /> <Route path="/terms" element={<TermsPage />} />

View File

@@ -39,6 +39,9 @@ export function SiteFooter() {
<Anchor component={Link} to="/proto" c="dimmed" size="sm"> <Anchor component={Link} to="/proto" c="dimmed" size="sm">
Proto Proto
</Anchor> </Anchor>
<Anchor component={Link} to="/rcc" c="dimmed" size="sm">
RCC
</Anchor>
<Anchor component={Link} to="/support" c="dimmed" size="sm"> <Anchor component={Link} to="/support" c="dimmed" size="sm">
Support Support
</Anchor> </Anchor>

View File

@@ -26,6 +26,11 @@
font-weight: 650; font-weight: 650;
} }
.important {
color: light-dark(var(--mantine-color-orange-8), var(--mantine-color-orange-3));
font-weight: 650;
}
.layerExamples { .layerExamples {
min-width: 0; min-width: 0;
margin: 18px 0 24px; margin: 18px 0 24px;
@@ -40,9 +45,13 @@
margin-bottom: 0; margin-bottom: 0;
} }
.docsLinks {
margin-top: 44px;
gap: 28px;
}
.docsLink { .docsLink {
display: inline-block; display: inline-block;
margin-top: 44px;
font-size: var(--mantine-font-size-sm); font-size: var(--mantine-font-size-sm);
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;

View File

@@ -517,6 +517,57 @@ export class RccGeneratedPacketRegistry {
</Code> </Code>
</LegalSection> </LegalSection>
<LegalSection title="RCC: one schema contract, two generation modes">
<LegalText>
Rosetta Code Compiler (RCC) is the build-time compiler behind the protocol.
It reads every <Code>layer.N.yml</Code> 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.
</LegalText>
<Code block className={classes.protoCode}>
{`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`}
</Code>
<LegalList>
<List.Item>
<strong>Server generation</strong> 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.
</List.Item>
<List.Item>
<strong>Client generation</strong>{' '}
<Text component="span" className={classes.important}>
selects the highest layer and creates the current packet, type, enum,
codec, and registry sources without carrying historical shapes into
the application.
</Text>
</List.Item>
<List.Item>
<strong>Schema validation</strong> 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.
</List.Item>
<List.Item>
<strong>Generated documentation</strong> carries schema comments into
Javadoc or TSDoc, including field direction, wire type, optionality, and
accessor contracts.
</List.Item>
</LegalList>
<LegalText>
The RCC guide includes separate client and version-aware server examples.{' '}
<Text component="span" className={classes.important}>
Run <Code>npx rcc --list-languages</Code> for the authoritative list of
language targets in the installed compiler version.
</Text>
</LegalText>
</LegalSection>
<LegalSection title="How an RCC YAML layer is structured"> <LegalSection title="How an RCC YAML layer is structured">
<LegalText> <LegalText>
RCC reads versioned files named <Code>layer.N.yml</Code>. The top-level RCC reads versioned files named <Code>layer.N.yml</Code>. The top-level
@@ -664,9 +715,14 @@ packet field 1 · INT8 · SUCCESS (0)`}
</LegalText> </LegalText>
</LegalSection> </LegalSection>
<Anchor component={Link} to="/proto/docs" className={classes.docsLink}> <Group className={classes.docsLinks}>
See docs of PROTO → <Anchor component={Link} to="/proto/docs" className={classes.docsLink}>
</Anchor> See docs of PROTO →
</Anchor>
<Anchor component={Link} to="/rcc" className={classes.docsLink}>
Learn RCC →
</Anchor>
</Group>
</LegalPage> </LegalPage>
</> </>
); );

View File

@@ -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;
}
}

239
src/pages/RccPage.tsx Normal file
View File

@@ -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 (
<Code block className={classes.code}>
{children}
</Code>
);
}
function Step({ number, title, children }: { number: number; title: string; children: ReactNode }) {
return (
<Box className={classes.step}>
<Text className={classes.stepNumber}>{number}</Text>
<Box className={classes.stepBody}>
<Title order={3} className={classes.subheading}>
{title}
</Title>
{children}
</Box>
</Box>
);
}
export function RccPage() {
return (
<>
<SEO
title="Rosetta Code Compiler (RCC)"
description="Install RCC and generate validated protocol models, codecs, and registries from versioned Rosetta YAML schemas."
canonical="https://rosetta.im/rcc/"
keywords="RCC, Rosetta Code Compiler, code generation, protocol codecs, YAML protocol"
/>
<LegalPage eyebrow="Developer tooling" title="Rosetta Code Compiler">
<LegalText lead>
RCC compiles Rosetta&apos;s versioned YAML protocol into typed models, codecs,
and packet registries.{' '}
<Text component="span" className={classes.important}>
A server build can retain the complete protocol history; a client build
stays small by generating only the latest layer.
</Text>
</LegalText>
<LegalSection title="What RCC produces">
<LegalText>
RCC treats <Code>proto/layer.*.yml</Code> as the protocol&apos;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.
</LegalText>
<Box className={classes.pipeline}>
<Text component="span">Versioned YAML schemas</Text>
<Text component="span" aria-hidden="true">→</Text>
<Text component="span">Parse + validate</Text>
<Text component="span" aria-hidden="true">→</Text>
<Text component="span">Models + codecs + registry</Text>
</Box>
<LegalList>
<List.Item>
Packets become typed packet classes; reusable schema types become model
classes; enums preserve their numeric wire values.
</List.Item>
<List.Item>
Codecs encode and decode TLV fields and verify required fields before
encoding and after decoding.
</List.Item>
<List.Item>
The generated registry maps packet IDs to codecs and exposes the
compiled protocol version or version range.
</List.Item>
<List.Item>
YAML comments become Javadoc or TSDoc for generated declarations and
accessors.
</List.Item>
</LegalList>
</LegalSection>
<LegalSection title="Install RCC from Rosetta Gitea">
<LegalText>
Add Rosetta&apos;s npm package registry to the project, then install RCC. The
registry setting can live in a project-level <Code>.npmrc</Code> so CI and
local builds resolve the same compiler package.
</LegalText>
<TechnicalCode>{`# .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`}</TechnicalCode>
<LegalText>
RCC source is hosted in the{' '}
<Anchor href={GITEA_REPOSITORY} target="_blank" rel="noreferrer">
Rosetta/rcc Gitea repository
</Anchor>
.{' '}
<Text component="span" className={classes.important}>
Pin the dependency version in the project lockfile so generated output
remains reproducible.
</Text>
</LegalText>
</LegalSection>
<LegalSection title="Generate from schemas, step by step">
<Step number={1} title="Create versioned schema layers">
<LegalText>
Put complete protocol snapshots in one directory and name them
<Code> layer.N.yml</Code>. Increment the top-level version, keep packet
and field IDs stable, and repeat definitions that remain part of the
protocol.
</LegalText>
<TechnicalCode>{`proto/
├── layer.1.yml
├── layer.2.yml
└── layer.3.yml`}</TechnicalCode>
</Step>
<Step number={2} title="Choose client or server output">
<LegalText>
Use <Code>client</Code> for the current application package. RCC selects
the highest schema version. Use <Code>server</Code> when the runtime must
decode connections negotiated on older supported layers. Full
multi-version codec generation is currently implemented by the Java
backend.
</LegalText>
</Step>
<Step number={3} title="Generate Java sources">
<LegalText>
Server generation combines all layers and emits version-aware codecs,
models, enums, and a registry with <Code>MIN_VERSION</Code> and
<Code> MAX_VERSION</Code>.
</LegalText>
<TechnicalCode>{`npx rcc \\
--mode server \\
--lang java \\
--protoDir ./proto \\
--outDir ./server/src/generated/java \\
--basePackage im.rosetta.network \\
--clean`}</TechnicalCode>
<LegalText>
For a Java client, change the mode and output directory. The generated
sources describe only the latest layer.
</LegalText>
<TechnicalCode>{`npx rcc \\
--mode client \\
--lang java \\
--protoDir ./proto \\
--outDir ./client/src/generated/java \\
--basePackage im.rosetta.network \\
--clean`}</TechnicalCode>
</Step>
<Step number={4} title="Generate TypeScript sources">
<LegalText>
TypeScript is the current latest-layer client target. It produces
models, enums, codecs, and <Code>RccGeneratedPacketRegistry.VERSION</Code>.
</LegalText>
<TechnicalCode>{`npx rcc \\
--mode client \\
--lang typescript \\
--protoDir ./proto \\
--outDir ./client/src/generated/protocol \\
--clean`}</TechnicalCode>
<Paper className={classes.note} radius="sm" p="md">
<Text size="sm" lh={1.7}>
Always run <Code>npx rcc --list-languages</Code> before configuring a
generator. The installed compiler&apos;s output is the source of truth
for available language targets.
</Text>
</Paper>
</Step>
<Step number={5} title="Run all targets from one prebuild config">
<LegalText>
Keep client and server generation together in
<Code> rcc-prebuild.yml</Code>. Paths are resolved relative to the
config file; <Code>clean: true</Code> clears only each configured output
directory.
</LegalText>
<TechnicalCode>{`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`}</TechnicalCode>
<TechnicalCode>{`npx rcc -f ./rcc-prebuild.yml`}</TechnicalCode>
</Step>
<Step number={6} title="Compile and package the generated sources">
<LegalText>
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.
</LegalText>
</Step>
</LegalSection>
<LegalSection title="CLI reference">
<TechnicalCode>{`npx rcc --mode <client|server> [options]
npx rcc -f <filename.yml>
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`}</TechnicalCode>
</LegalSection>
</LegalPage>
</>
);
}