import { DISCORD_INVITE, ISSUES_URL, PRIVACY_EMAIL, SOURCE_REPO } from './links' /** * The privacy policy, served on www at `/privacy`. * * Rendered by the Worker rather than by the React SPA on purpose. The Meta Horizon * Store's VRC.Privacy.1 check fetches this URL periodically and looks for a live page * whose text contains "Privacy Policy"; a client-rendered route would answer that fetch * with an empty `
` and could be flagged non-compliant even though a * browser renders it fine. Server-rendering also means the policy survives a JS error * or a blocked script, which is the one page on this site that has to. * * `/privacy` must therefore stay listed in `run_worker_first` in wrangler.jsonc — * without it a top-level navigation is served index.html and never reaches this module. * * The four VRCs this is written against (developers.meta.com/horizon/resources/): * Privacy.1 — the URL is live, public, HTTPS, and owned by the app's team. * Privacy.2 — states what data is processed, collected and stored. * Privacy.3 — states what that data is used for. * Privacy.4 — states how any user, in any region, can request deletion, for free. * Keep the "What we collect" section honest against the schemas it describes * (packages/domain/src/accounts-db.ts and the per-worker migrations) — that section is * the claim Privacy.2 is judged on, and it goes stale the moment a worker stores * something new. * * "How you sign in" describes Meta SSO (PlatformType.Oculus), now implemented in * apps/auth/src/meta-nonce.ts. What that integration actually sends Meta is the login * nonce plus the user id it is claimed for, and all it gets back is valid/not valid — * so the disclosure's claim that Meta "learns that a sign-in happened" is right, but it * over-discloses on two points that should be squared with the Data Use Checkup filed * for the app: we do NOT retrieve a display name (only the user id is stored, see * accounts-db.ts), and nonce validation does not check app entitlement. Privacy.2 asks * for extra detail about platform features specifically, so keep this exact. */ /** Last substantive revision, shown in the header. Bump when the text changes. */ const EFFECTIVE_DATE = '26 July 2026' /** The palette and type of the main site, inlined — this page loads no stylesheet. */ const STYLES = ` :root { color-scheme: dark light; --bg: #14100c; --surface: #1e1813; --line: #33291f; --text: #f5ede1; --muted: #a8927c; --accent: #fe7101; } @media (prefers-color-scheme: light) { :root { --bg: #f7f5f2; --surface: #ffffff; --line: #e2ddd6; --text: #201a14; --muted: #736656; --accent: #e05f00; } } * { box-sizing: border-box; } body { margin: 0; background: var(--bg); color: var(--text); font-family: 'IBM Plex Sans', system-ui, -apple-system, Segoe UI, Roboto, sans-serif; font-size: 1rem; line-height: 1.65; -webkit-font-smoothing: antialiased; } a { color: var(--accent); } .nav { display: flex; justify-content: space-between; align-items: center; gap: 16px; max-width: 760px; margin: 0 auto; padding: 20px; border-bottom: 1px solid var(--line); } .brand { font-family: Archivo, system-ui, sans-serif; font-weight: 800; font-size: 1.2rem; letter-spacing: -0.015em; color: var(--text); text-decoration: none; } .nav a.back { color: var(--muted); text-decoration: none; font-size: 0.95rem; } .nav a.back:hover { color: var(--text); } main { max-width: 760px; margin: 0 auto; padding: 40px 20px 8px; } h1 { font-family: Archivo, system-ui, sans-serif; font-weight: 800; font-size: clamp(1.9rem, 4vw, 2.6rem); line-height: 1.1; letter-spacing: -0.03em; margin: 0 0 8px; } h2 { font-family: Archivo, system-ui, sans-serif; font-weight: 700; font-size: 1.3rem; letter-spacing: -0.02em; margin: 40px 0 10px; } h3 { font-size: 1rem; font-weight: 600; margin: 24px 0 6px; } p, li { max-width: 68ch; } .updated { color: var(--muted); font-size: 0.9rem; margin: 0 0 8px; } .lede { font-size: 1.075rem; } ul { padding-left: 22px; } li { margin-bottom: 8px; } li > strong { font-weight: 600; } .callout { background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: 10px; padding: 18px 22px; margin: 20px 0; } .callout p:first-child { margin-top: 0; } .callout p:last-child { margin-bottom: 0; } footer { max-width: 760px; margin: 0 auto; padding: 24px 20px 48px; border-top: 1px solid var(--line); color: var(--muted); font-size: 0.875rem; } footer a { color: var(--muted); } ` /** * How to reach a human about a privacy or deletion request. Rendered in both the * deletion section and the footer, so the mailbox (when there is one — see * PRIVACY_EMAIL) can't be listed in one place and forgotten in the other. */ function contactList(): string { const email = PRIVACY_EMAIL ? `
  • Email${PRIVACY_EMAIL}.
  • ` : '' return `` } /** The `/privacy` HTML page. Static text — nothing here is interpolated from a request. */ export function privacyPage(): string { return ` Privacy Policy — RecFlare

    Privacy Policy

    Last updated ${EFFECTIVE_DATE}

    RecFlare is a free, open source, fan-run game server. It is not a business, it sells nothing, and it has no interest in your data beyond making the game work. This page explains exactly what we store, why we store it, and how to make us delete it.

    The short version. We store your account, the things you make in game (photos, rooms, messages, inventory), and the technical details needed to log you in and keep the server from being abused. We don't sell anything, we run no advertising, and we've integrated no third-party analytics or tracking. Ask us and we'll delete your account and its data, free, wherever you live.

    Who runs this

    RecFlare is maintained by a volunteer community, and its source code is public at github.com/djdevin/recflare. This policy covers the RecFlare game servers and this website. It is a fan project, not affiliated with, endorsed by, or connected to Rec Room Inc.

    Because the server code is open source, anyone can read exactly how the data described below is handled, and anyone can run their own separate copy of RecFlare. This policy applies only to the servers we operate. If you play on someone else's instance, their operator is responsible for your data, not us.

    What we collect

    Almost all of it is data you create by playing. We do not buy data about you from anyone, and we do not combine what's here with data from other services.

    Your account

    How you sign in

    You can sign in with an account from the platform you play on, or with a password. Whichever you use, we store the minimum needed to recognise you next time.

    Linking a platform account is how you log in — we don't use it to look you up on that platform, post anything there, or match you to advertising.

    Device and technical data

    What you make and do in game

    Why we use it

    We do not use your data for advertising or profiling, we do not sell or rent it, and we do not share it for anyone else's marketing. There are no advertising SDKs, analytics SDKs or tracking pixels in the game client or on this website.

    Who else sees it

    Our community Discord server and our GitHub repository are run by Discord and GitHub under their own privacy policies. Anything you post there is covered by their terms, not this one.

    Cookies

    This website sets one cookie, rf_token, which holds your sign-in session. It is strictly necessary to stay signed in, it is not readable by page scripts, and it is cleared when you sign out. We set no advertising or analytics cookies. The game client itself uses no cookies.

    How long we keep it

    Account and game data is kept for as long as your account exists, so your progress is there when you come back. Presence records expire within minutes. Session tokens expire on their own schedule. Server logs are retained for a short period and then age out automatically. When you ask us to delete your account, we delete it as described below.

    Deleting your data

    You can ask us to delete your account and the data we hold about you at any time, from anywhere in the world. There is no charge for this, and you don't need to give a reason. Contact us by any of these routes:

    ${contactList()}

    Tell us your RecFlare username, and be ready to prove the account is yours — normally by signing in to it, or by sending the request from the email address on the account. We ask because otherwise anyone could delete anyone else's account. We'll confirm when it's done, and we aim to complete every request within 30 days.

    Deleting your account removes:

    Two honest limits. Messages you sent live in shared conversations, so copies already delivered to other players may remain in their message history, no longer attached to an account. And routine server logs and backups age out on their own timers rather than being edited, so a record of a request may persist for a short period after deletion. Beyond those, if there's ever a reason we can't complete a deletion request, we'll tell you what it is.

    You can also change or correct most of your details yourself, either in game or on the account page of this website, and you can ask us for a copy of the data we hold about you using the same contact routes above.

    Security

    All traffic between the game client, this website and our servers is encrypted in transit. Passwords are stored only as salted hashes and refresh tokens only as one-way hashes, so a copy of our database would not reveal either. Access to the production data is limited to the maintainers who operate the service. No system is perfectly secure, and we won't pretend otherwise — but this is a hobby server, so please don't reuse a password here that you use anywhere important.

    Children

    RecFlare is not directed at children under 13, and we don't knowingly collect data from them. If you believe a child under 13 has created an account, contact us using any of the routes above and we will delete the account and its data.

    Changes to this policy

    If this policy changes we'll update the date at the top of this page, and the change will be visible in the project's public commit history. Significant changes will be announced in our Discord server.

    Contact

    Questions about this policy, or about any data we hold:

    ${contactList()}
    ` }