From ba3e30a0ae8cf79ae424b1717daf9b7ca8f07b6a Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Sun, 9 Nov 2025 17:43:10 -0800 Subject: [PATCH] chore(site): fix generating examples --- pnpm-lock.yaml | 32 ++++ website/scripts/examplesData.mjs | 2 +- website/scripts/generateExamples.mjs | 95 ++++++---- website/scripts/generateReadme.mjs | 169 ------------------ website/src/components/v2/Header.tsx | 2 +- website/src/content/docs/index.mdx | 75 ++------ website/src/content/docs/quickstart/index.mdx | 21 --- website/src/sitemap/mod.ts | 92 ++++------ 8 files changed, 142 insertions(+), 346 deletions(-) delete mode 100755 website/scripts/generateReadme.mjs delete mode 100644 website/src/content/docs/quickstart/index.mdx diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9ed13666f..4841394a77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,6 +46,12 @@ importers: specifier: ^8.8.5 version: 8.8.5 + engine: + dependencies: + '@vbare/compiler': + specifier: ^0.0.3 + version: 0.0.3(@bare-ts/lib@0.4.0) + engine/docker/template: dependencies: '@types/js-yaml': @@ -2331,6 +2337,9 @@ importers: '@bare-ts/tools': specifier: ^0.13.0 version: 0.13.0(@bare-ts/lib@0.3.0) + '@biomejs/biome': + specifier: ^2.2.3 + version: 2.2.3 '@hono/node-server': specifier: ^1.18.2 version: 1.19.1(hono@4.9.8) @@ -3253,6 +3262,13 @@ packages: peerDependencies: '@bare-ts/lib': '>=0.3.0 <=0.4.0' + '@bare-ts/tools@0.16.1': + resolution: {integrity: sha512-eKXTnVqzuKDxr1ozKsFSZfM1wcN4g/iMRnG9GB2fA8oyUcHxwokJC50CANfuSLe6rLnjhZ8Ave1Y2TnZqUqGcQ==} + engines: {node: '>=20.0.0'} + hasBin: true + peerDependencies: + '@bare-ts/lib': '>=0.3.0 <=0.4.0' + '@base-org/account@2.0.1': resolution: {integrity: sha512-tySVNx+vd6XEynZL0uvB10uKiwnAfThr8AbKTwILVG86mPbLAhEOInQIk+uDnvpTvfdUhC1Bi5T/46JvFoLZQQ==} @@ -7024,6 +7040,11 @@ packages: peerDependencies: '@urql/core': ^5.0.0 + '@vbare/compiler@0.0.3': + resolution: {integrity: sha512-Dhz0iwYjIhyGAPsNpiqDmDqgwLXfEonjFJLVQ0m/s4Tt9CsTjY0WV3KiQtJi5BdPt9481HR+0uwExH36FuuR2A==} + engines: {node: '>=18.0.0'} + hasBin: true + '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -14439,6 +14460,10 @@ snapshots: '@bare-ts/lib': 0.4.0 commander: 11.1.0 + '@bare-ts/tools@0.16.1(@bare-ts/lib@0.4.0)': + dependencies: + '@bare-ts/lib': 0.4.0 + '@base-org/account@2.0.1(@types/react@19.2.2)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(zod@3.25.76)': dependencies: '@noble/hashes': 1.4.0 @@ -18690,6 +18715,13 @@ snapshots: '@urql/core': 5.2.0 wonka: 6.3.5 + '@vbare/compiler@0.0.3(@bare-ts/lib@0.4.0)': + dependencies: + '@bare-ts/tools': 0.16.1(@bare-ts/lib@0.4.0) + commander: 11.1.0 + transitivePeerDependencies: + - '@bare-ts/lib' + '@vitejs/plugin-react@4.7.0(vite@5.4.20(@types/node@20.19.13)(less@4.4.1)(lightningcss@1.30.2)(sass@1.93.2)(stylus@0.62.0)(terser@5.44.0))': dependencies: '@babel/core': 7.28.4 diff --git a/website/scripts/examplesData.mjs b/website/scripts/examplesData.mjs index b1439a763a..28f2267aa4 100644 --- a/website/scripts/examplesData.mjs +++ b/website/scripts/examplesData.mjs @@ -1,4 +1,4 @@ -// Shared example metadata used by both generateExamples.mjs and generateReadme.mjs +// Shared example metadata used by both generateExamples.mjs export const EXAMPLE_METADATA = { "ai-agent": { diff --git a/website/scripts/generateExamples.mjs b/website/scripts/generateExamples.mjs index c1d54f0732..49267c7c92 100644 --- a/website/scripts/generateExamples.mjs +++ b/website/scripts/generateExamples.mjs @@ -2,12 +2,12 @@ import { execSync } from 'node:child_process'; import { readFileSync, writeFileSync, existsSync, mkdirSync, cpSync, rmSync } from 'node:fs'; -import { join } from 'node:path'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { EXAMPLE_METADATA } from './examplesData.mjs'; -const REPO_URL = 'https://github.com/rivet-dev/rivetkit.git'; -const BRANCH = 'main'; -const TEMP_DIR = '/tmp/rivetkit-examples'; +const __dirname = dirname(fileURLToPath(import.meta.url)); +const EXAMPLES_DIR = join(__dirname, '../../examples'); const TEMP_EXAMPLE_DIR = '/tmp/rivet-example-temp'; const OUTPUT_DIR = './src/data/examples'; const OUTPUT_FILE = 'examples.ts'; @@ -17,57 +17,78 @@ if (!existsSync(OUTPUT_DIR)) { mkdirSync(OUTPUT_DIR, { recursive: true }); } -// Clone or update the repository -function updateRepo() { - if (existsSync(TEMP_DIR)) { - console.log('Updating existing repository...'); - execSync('git clean -fd', { cwd: TEMP_DIR }); - execSync('git reset --hard', { cwd: TEMP_DIR }); - execSync('git fetch origin', { cwd: TEMP_DIR }); - execSync(`git checkout ${BRANCH}`, { cwd: TEMP_DIR }); - execSync(`git pull origin ${BRANCH}`, { cwd: TEMP_DIR }); - } else { - console.log('Cloning repository...'); - execSync(`git clone -b ${BRANCH} ${REPO_URL} ${TEMP_DIR}`); +// Verify examples directory exists +function verifyExamplesDir() { + if (!existsSync(EXAMPLES_DIR)) { + throw new Error(`Examples directory not found at ${EXAMPLES_DIR}`); } + console.log(`Using examples from: ${EXAMPLES_DIR}`); } -// Replace workspace dependencies with version numbers +// Get latest version from npm +function getLatestVersion(packageName) { + try { + const result = execSync(`npm view ${packageName} version`, { encoding: 'utf-8' }); + return result.trim(); + } catch (error) { + console.warn(`Warning: Could not fetch version for ${packageName}, using ^0.9.1`); + return '0.9.1'; + } +} + +// Cache for npm versions to avoid repeated lookups +const versionCache = {}; + +// Replace workspace dependencies with latest npm versions function replaceWorkspaceDependencies(content) { - return content - .replace(/@rivetkit\/([^"]+)": "workspace:\*"/g, '@rivetkit/$1": "^0.9.1"') - .replace(/"workspace:\*"/g, '"^0.9.1"'); + const packageJson = JSON.parse(content); + + // Process both dependencies and devDependencies + for (const depType of ['dependencies', 'devDependencies']) { + if (packageJson[depType]) { + for (const [pkgName, pkgVersion] of Object.entries(packageJson[depType])) { + if (pkgVersion === 'workspace:*') { + // Get version from cache or fetch from npm + if (!versionCache[pkgName]) { + console.log(`Fetching latest version for ${pkgName}...`); + versionCache[pkgName] = getLatestVersion(pkgName); + } + packageJson[depType][pkgName] = `^${versionCache[pkgName]}`; + } + } + } + } + + return JSON.stringify(packageJson, null, '\t'); } // Get only the examples defined in metadata function getExamplesToProcess() { - const examplesDir = join(TEMP_DIR, 'examples'); - - if (!existsSync(examplesDir)) { + if (!existsSync(EXAMPLES_DIR)) { throw new Error('Examples directory not found'); } - + const definedExamples = Object.keys(EXAMPLE_METADATA); const availableExamples = []; - + // Check which defined examples actually exist in the repository for (const exampleName of definedExamples) { - const examplePath = join(examplesDir, exampleName); + const examplePath = join(EXAMPLES_DIR, exampleName); if (existsSync(examplePath)) { availableExamples.push(exampleName); } else { throw new Error(`Example defined in metadata but not found in repo: ${exampleName}`); } } - + console.log(`Processing ${availableExamples.length} examples: ${availableExamples.join(', ')}`); return availableExamples; } // Copy example to temp folder, install dependencies, then process files function processExample(exampleName) { - const exampleDir = join(TEMP_DIR, 'examples', exampleName); - + const exampleDir = join(EXAMPLES_DIR, exampleName); + if (!existsSync(exampleDir)) { throw new Error(`Example directory not found: ${exampleName}`); } @@ -95,14 +116,14 @@ function processExample(exampleName) { // Run npm install to generate lockfile console.log(`Running npm install for ${exampleName}...`); try { - execSync('npm install', { + execSync('npm install', { cwd: tempExampleDir, - stdio: 'inherit' + stdio: 'inherit' }); } catch (error) { throw new Error(`npm install failed for ${exampleName}: ${error.message}`); } - + // Remove node_modules after npm install console.log(`Removing node_modules for ${exampleName}...`); const nodeModulesPath = join(tempExampleDir, 'node_modules'); @@ -166,15 +187,15 @@ function processExample(exampleName) { // Main function function main() { console.log('Generating examples...'); - - // Update the repository - updateRepo(); - + + // Verify examples directory exists + verifyExamplesDir(); + // Ensure temp example directory exists if (!existsSync(TEMP_EXAMPLE_DIR)) { mkdirSync(TEMP_EXAMPLE_DIR, { recursive: true }); } - + // Get examples to process (only those defined in metadata) const exampleNames = getExamplesToProcess(); diff --git a/website/scripts/generateReadme.mjs b/website/scripts/generateReadme.mjs deleted file mode 100755 index 40d59a92f7..0000000000 --- a/website/scripts/generateReadme.mjs +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env node - -import { readFileSync, writeFileSync, existsSync } from 'node:fs'; -import { join } from 'node:path'; -import { EXAMPLE_METADATA } from './examplesData.mjs'; - -const RIVET_TEMPLATE_PATH = join(process.cwd(), '..', 'README.rivet.tpl.md'); -const RIVET_OUTPUT_PATH = join(process.cwd(), '..', 'README.md'); - -const RIVETKIT_TEMPLATE_PATH = join(process.cwd(), '..', 'README.rivetkit.tpl.md'); - -const RIVET_QUICKSTART = `Get started with Rivet by following a quickstart guide: - -- [Node.js & Bun](https://www.rivet.dev/docs/actors/quickstart/backend/) -- [React](https://www.rivet.dev/docs/actors/quickstart/react/) -` - -// Content chunks -const RIVET_FEATURES_CONTENT = `## Features - -Rivet Actors are a primitive of RivetKit provide everything you need to build fast, scalable, and real-time applications without the complexity. Rivet Engine is the core of self-hosting and is used for orchestrating actors at scale. - -- **Long-Lived, Stateful Compute**: Like AWS Lambda but with memory and no timeouts -- **Blazing-Fast Reads & Writes**: State stored on same machine as compute -- **Realtime, Made Simple**: Built-in WebSockets and SSE support -- **Store Data Near Your Users**: Deploy to the edge for low-latency access -- **Infinitely Scalable**: Auto-scale from zero to millions without configuration -- **Fault Tolerant**: Automatic error handling and recovery built-in - -## BYO DB (Bring Your Own Database) -The Rivet Engine supports: - -- **PostgreSQL**: For production deployments -- **FoundationDB**: For enterprise-scale distributed systems -- **Filesystem**: For single-node deployments`; - -const RIVETKIT_FEATURES_CONTENT = `## Features - -RivetKit provides everything you need to build fast, scalable, and real-time applications without the complexity. - -- **Long-Lived, Stateful Compute**: Like AWS Lambda but with memory and no timeouts -- **Blazing-Fast Reads & Writes**: State stored on same machine as compute -- **Realtime, Made Simple**: Built-in WebSockets and SSE support -- **Store Data Near Your Users**: Deploy to the edge for low-latency access -- **Infinitely Scalable**: Auto-scale from zero to millions without configuration -- **Fault Tolerant**: Automatic error handling and recovery built-in`; - -const RIVET_COMMUNITY_CONTENT = `## Community & Support - -Join thousands of developers building with Rivet Actors today: - -- [Discord](https://rivet.dev/discord) - Chat with the community -- [X/Twitter](https://x.com/rivet_dev) - Follow for updates -- [Bluesky](https://bsky.app/profile/rivet.dev) - Follow for updates -- [GitHub Discussions](https://github.com/rivet-dev/rivetkit/discussions) - Ask questions and share ideas -- [GitHub Issues](https://github.com/rivet-dev/rivetkit/issues) - Report bugs and request features -- [Talk to an engineer](https://rivet.dev/talk-to-an-engineer) - Discuss your technical needs, current stack, and how Rivet can help with your infrastructure challenges`; - -const RIVETKIT_COMMUNITY_CONTENT = `## Community & Support - -Join thousands of developers building with RivetKit today: - -- [Discord](https://rivet.dev/discord) - Chat with the community -- [X/Twitter](https://x.com/rivet_dev) - Follow for updates -- [Bluesky](https://bsky.app/profile/rivet.dev) - Follow for updates -- [GitHub Discussions](https://github.com/rivet-dev/rivetkit/discussions) - Ask questions and share ideas -- [GitHub Issues](https://github.com/rivet-dev/rivetkit/issues) - Report bugs and request features -- [Talk to an engineer](https://rivet.dev/talk-to-an-engineer) - Discuss your technical needs, current stack, and how Rivet can help with your infrastructure challenges`; - -const LICENSE_CONTENT = `## License - -[Apache 2.0](LICENSE)`; - -const RIVET_HEADER = ` - -`; - -const RIVETKIT_HEADER = ` - -`; - -function generateExamplesList() { - return Object.entries(EXAMPLE_METADATA) - .map(([id, example]) => { - const githubUrl = `https://github.com/rivet-dev/rivetkit/tree/main/examples/${id}`; - const stackblitzUrl = `https://stackblitz.com/github/rivet-dev/rivetkit/tree/main/examples/${id}`; - return `- ${example.title} — [GitHub](${githubUrl}) · [StackBlitz](${stackblitzUrl})`; - }) - .join('\n'); -} - -function generateRivetReadme() { - console.log('Generating Rivet README.md...'); - - // Generate examples list - const examplesList = generateExamplesList(); - - // Read template - const template = readFileSync(RIVET_TEMPLATE_PATH, 'utf-8'); - - // Replace placeholders - let content = template.replace('__EXAMPLES__', examplesList); - content = content.replace('__QUICKSTART__', RIVET_QUICKSTART); - content = content.replace('__FEATURES__', RIVET_FEATURES_CONTENT); - content = content.replace('__COMMUNITY__', RIVET_COMMUNITY_CONTENT); - content = content.replace('__LICENSE__', LICENSE_CONTENT); - - const readmeContent = RIVET_HEADER + content; - - writeFileSync(RIVET_OUTPUT_PATH, readmeContent); - console.log(`✓ Generated Rivet README.md at ${RIVET_OUTPUT_PATH}`); -} - -function generateRivetKitReadme() { - const rivetKitPath = process.env.RIVETKIT_PATH; - - if (!rivetKitPath) { - console.warn('⚠️ Warning: RIVETKIT_PATH environment variable is not set'); - console.warn(' Skipping RivetKit README generation'); - console.warn(' Set RIVETKIT_PATH to the path of your rivetkit repository'); - return; - } - - // Check if RivetKit path exists - if (!existsSync(rivetKitPath)) { - console.error(`❌ Error: RIVETKIT_PATH directory does not exist: ${rivetKitPath}`); - return; - } - - console.log('Generating RivetKit README.md...'); - - const rivetKitOutputPath = join(rivetKitPath, 'README.md'); - - // Generate examples list - const examplesList = generateExamplesList(); - - // Read template - const template = readFileSync(RIVETKIT_TEMPLATE_PATH, 'utf-8'); - - // Replace placeholders - let content = template.replace('__EXAMPLES__', examplesList); - content = content.replace('__QUICKSTART__', RIVET_QUICKSTART); - content = content.replace('__FEATURES__', RIVETKIT_FEATURES_CONTENT); - content = content.replace('__COMMUNITY__', RIVETKIT_COMMUNITY_CONTENT); - content = content.replace('__LICENSE__', LICENSE_CONTENT); - - const readmeContent = RIVETKIT_HEADER + content; - - writeFileSync(rivetKitOutputPath, readmeContent); - console.log(`✓ Generated RivetKit README.md at ${rivetKitOutputPath}`); -} - -function main() { - // Always generate Rivet README - generateRivetReadme(); - - // Generate RivetKit README if RIVETKIT_PATH is set - generateRivetKitReadme(); -} - -main(); diff --git a/website/src/components/v2/Header.tsx b/website/src/components/v2/Header.tsx index 9d21b8b31a..23028f4a74 100644 --- a/website/src/components/v2/Header.tsx +++ b/website/src/components/v2/Header.tsx @@ -269,7 +269,7 @@ function DocsMobileNavigation({ tree }) { const sections = [ { id: "overview", label: "Overview", href: "/docs" }, - { id: "quickstart", label: "Quickstart", href: "/docs/quickstart" }, + { id: "quickstart", label: "Quickstart", href: "/docs" }, { id: "actors", label: "Actors", href: "/docs/actors" }, { id: "integrations", label: "Integrations", href: "/docs/integrations" }, { id: "api", label: "API Reference", href: "/docs/api" }, diff --git a/website/src/content/docs/index.mdx b/website/src/content/docs/index.mdx index 3163386bfd..722db7e699 100644 --- a/website/src/content/docs/index.mdx +++ b/website/src/content/docs/index.mdx @@ -9,73 +9,22 @@ import { Rivet is a library for long-lived processes with durable state, realtime, and scalability. It is easily self-hostable and works with your infrastructure. -## Libraries +# Quickstart + +Get started with Rivet in minutes. Choose your preferred framework or runtime to begin building with actors. - - Long-lived processes with durable state, realtime, and hibernation - -{/* + Set up actors with Node.js, Bun, and web frameworks - - Set up actors with Node.js, Bun, and web frameworks -*/} - - -## Use Cases - - -{useCases.map((useCase) => ( - - {useCase.description} - -))} - - -## Deploy Options - - -{deployOptions.map((option) => ( - -))} - - -## Integrations - -{integrationGroups.map((group) => ( -
-

{group.title}

- - {group.items.map((integration) => ( - - ))} - -
-))} - -## Support - - - - Chat with the community and get realtime help from Rivet engineers + + Build real-time React applications with actors - - File bugs or request features directly in our tracker + + Build server-rendered Next.js experiences backed by actors + + + Deploy actors on Cloudflare Workers with zero infrastructure + diff --git a/website/src/content/docs/quickstart/index.mdx b/website/src/content/docs/quickstart/index.mdx deleted file mode 100644 index 2ab45d7911..0000000000 --- a/website/src/content/docs/quickstart/index.mdx +++ /dev/null @@ -1,21 +0,0 @@ -import { faNodeJs, faReact, faNextjs, faCloudflare } from "@rivet-gg/icons"; - -# Quickstart - -Get started with Rivet in minutes. Choose your preferred framework or runtime to begin building with actors. - - - - Set up actors with Node.js, Bun, and web frameworks - - - Build real-time React applications with actors - - - Build server-rendered Next.js experiences backed by actors - - - Deploy actors on Cloudflare Workers with zero infrastructure - - - diff --git a/website/src/sitemap/mod.ts b/website/src/sitemap/mod.ts index 15725770c4..2ca9ed8390 100644 --- a/website/src/sitemap/mod.ts +++ b/website/src/sitemap/mod.ts @@ -111,24 +111,49 @@ export const sitemap = [ ] }, { - title: "Use Cases", + title: "Quickstart", pages: [ - ...useCases.slice(0, 3).map(({ title, href, icon }) => ({ - title, - href, - icon, - })), { - title: "More", - collapsible: true, - pages: useCases.slice(3).map(({ title, href, icon }) => ({ - title, - href, - icon, - })), + title: "Node.js & Bun", + href: "/docs/actors/quickstart/backend", + icon: faNodeJs, + }, + { + title: "React", + href: "/docs/actors/quickstart/react", + icon: faReact, + }, + { + title: "Next.js", + href: "/docs/actors/quickstart/next-js", + icon: faNextjs, + }, + { + title: "Cloudflare Workers", + href: "/docs/actors/quickstart/cloudflare-workers", + icon: faCloudflare, }, ], }, + // { + // title: "Use Cases", + // pages: [ + // ...useCases.slice(0, 3).map(({ title, href, icon }) => ({ + // title, + // href, + // icon, + // })), + // { + // title: "More", + // collapsible: true, + // pages: useCases.slice(3).map(({ title, href, icon }) => ({ + // title, + // href, + // icon, + // })), + // }, + // ], + // }, { title: "Concepts", pages: [ @@ -330,47 +355,6 @@ export const sitemap = [ }, ], }, - { - title: "Quickstart", - href: "/docs/quickstart", - sidebar: [ - { - title: "General", - pages: [ - { - title: "Overview", - href: "/docs/quickstart", - icon: faForward, - }, - ], - }, - { - title: "Guides", - pages: [ - { - title: "Node.js & Bun", - href: "/docs/actors/quickstart/backend", - icon: faNodeJs, - }, - { - title: "React", - href: "/docs/actors/quickstart/react", - icon: faReact, - }, - { - title: "Next.js", - href: "/docs/actors/quickstart/next-js", - icon: faNextjs, - }, - { - title: "Cloudflare Workers", - href: "/docs/actors/quickstart/cloudflare-workers", - icon: faCloudflare, - }, - ], - }, - ], - }, { title: "Integrations", href: "/docs/integrations",