diff --git a/frontend/src/app/dialogs/tokens-frame.tsx b/frontend/src/app/dialogs/tokens-frame.tsx index 39a3e9f31c..b20812658a 100644 --- a/frontend/src/app/dialogs/tokens-frame.tsx +++ b/frontend/src/app/dialogs/tokens-frame.tsx @@ -18,6 +18,20 @@ import { import { RegionSelect } from "@/components/actors/region-select"; import { cloudEnv } from "@/lib/env"; +/** + * Creates a unified endpoint URL with embedded namespace and token credentials. + */ +function createUnifiedEndpoint( + endpoint: string, + namespace: string, + token: string, +): string { + const url = new URL(endpoint); + url.username = encodeURIComponent(namespace); + url.password = encodeURIComponent(token); + return url.toString(); +} + interface TokensFrameContentProps extends DialogContentProps {} export default function TokensFrameContent({ @@ -87,9 +101,7 @@ function SecretToken() { throw new Error("Not in a valid context"); }); - const envVars = `RIVET_ENDPOINT=${endpoint} -RIVET_NAMESPACE=${namespace} -RIVET_TOKEN=${token || ""}`; + const envVars = `RIVET_ENDPOINT=${createUnifiedEndpoint(endpoint, namespace, token || "")}`; const codeSnippet = `// Configuration will automatically be read from env registry.start();`; diff --git a/frontend/src/app/env-variables.tsx b/frontend/src/app/env-variables.tsx index 4504c97925..f5b44fdd91 100644 --- a/frontend/src/app/env-variables.tsx +++ b/frontend/src/app/env-variables.tsx @@ -7,10 +7,12 @@ export function EnvVariables({ prefix, runnerName, endpoint, + unified = true, }: { prefix?: string; runnerName?: string; endpoint: string; + unified?: boolean; }) { return (
@@ -24,9 +26,15 @@ export function EnvVariables({ - - - + {unified ? ( + + ) : ( + <> + + + + + )}
@@ -57,6 +65,39 @@ export function EnvVariables({ ); } +function RivetEndpointEnvUnified({ + prefix, + endpoint, +}: { + prefix?: string; + endpoint: string; +}) { + const dataProvider = useEngineCompatDataProvider(); + const token = usePublishableToken(); + const namespace = dataProvider.engineNamespace || "default"; + + // Create unified endpoint with embedded credentials + const url = new URL(endpoint); + url.username = encodeURIComponent(namespace); + url.password = encodeURIComponent(token || ""); + const unifiedEndpoint = url.toString(); + + return ( + <> + + + + ); +} + function RivetRunnerEnv({ prefix, runnerName, diff --git a/frontend/src/app/publishable-token-code-group.tsx b/frontend/src/app/publishable-token-code-group.tsx index 394cdea30d..e64e803252 100644 --- a/frontend/src/app/publishable-token-code-group.tsx +++ b/frontend/src/app/publishable-token-code-group.tsx @@ -115,6 +115,24 @@ export function PublishableTokenCodeGroup({ ); } +/** + * Creates a unified endpoint URL with embedded namespace and token credentials. + * @param endpoint - Base endpoint URL + * @param namespace - Namespace to embed + * @param token - Token to embed + * @returns URL string with embedded credentials in format: https://namespace:token@endpoint + */ +function createUnifiedEndpoint( + endpoint: string, + namespace: string, + token: string, +): string { + const url = new URL(endpoint); + url.username = encodeURIComponent(namespace); + url.password = encodeURIComponent(token); + return url.toString(); +} + const javascriptCode = ({ token, endpoint, @@ -123,15 +141,17 @@ const javascriptCode = ({ token: string; endpoint: string; namespace: string; -}) => `import { createClient } from "rivetkit/client"; +}) => { + const unifiedEndpoint = createUnifiedEndpoint(endpoint, namespace, token); + + return `import { createClient } from "rivetkit/client"; import type { registry } from "./registry"; const client = createClient({ - endpoint: "${endpoint}", - namespace: "${namespace}", - // This token is safe to publish on your frontend - token: "${token}", + // Unified endpoint with embedded namespace and token + endpoint: "${unifiedEndpoint}", });`; +}; const reactCode = ({ token, @@ -141,15 +161,17 @@ const reactCode = ({ token: string; endpoint: string; namespace: string; -}) => `import { createRivetKit } from "@rivetkit/react"; +}) => { + const unifiedEndpoint = createUnifiedEndpoint(endpoint, namespace, token); + + return `import { createRivetKit } from "@rivetkit/react"; import type { registry } from "./registry"; export const { useActor } = createRivetKit({ - endpoint: "${endpoint}", - namespace: "${namespace}", - // This token is safe to publish on your frontend - token: "${token}", + // Unified endpoint with embedded namespace and token + endpoint: "${unifiedEndpoint}", });`; +}; const nextJsCode = ({ token, @@ -159,13 +181,15 @@ const nextJsCode = ({ token: string; endpoint: string; namespace: string; -}) => `"use client"; +}) => { + const unifiedEndpoint = createUnifiedEndpoint(endpoint, namespace, token); + + return `"use client"; import { createRivetKit } from "@rivetkit/next-js/client"; import type { registry } from "@/rivet/registry"; export const { useActor } = createRivetKit({ - endpoint: "${endpoint}", - namespace: "${namespace}", - // This token is safe to publish on your frontend - token: "${token}", + // Unified endpoint with embedded namespace and token + endpoint: "${unifiedEndpoint}", });`; +}; diff --git a/frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx b/frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx index 97c2b9b219..43b1f00789 100644 --- a/frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx +++ b/frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx @@ -48,6 +48,20 @@ import { cloudEnv } from "@/lib/env"; import { usePublishableToken } from "@/queries/accessors"; import { queryClient } from "@/queries/global"; +/** + * Creates a unified endpoint URL with embedded namespace and token credentials. + */ +function createUnifiedEndpoint( + endpoint: string, + namespace: string, + token: string, +): string { + const url = new URL(endpoint); + url.username = encodeURIComponent(namespace); + url.password = encodeURIComponent(token); + return url.toString(); +} + export const Route = createFileRoute( "/_context/_cloud/orgs/$organization/projects/$project/ns/$namespace/tokens", )({ @@ -111,7 +125,8 @@ function PublishableToken() {

Connect to your actors using the Rivet client token. This can be - used either on your frontend or backend. + used either on your frontend or backend. The code examples below show + the unified endpoint format with embedded credentials (namespace:token@endpoint).

@@ -204,32 +219,13 @@ registry.start();`; value="RIVET_ENDPOINT" show /> - - - - {isTokenLoading ? ( ) : ( )}
@@ -238,9 +234,7 @@ registry.start();`; variant="outline" size="sm" onClick={() => { - const envVars = `RIVET_ENDPOINT=${endpoint} -RIVET_NAMESPACE=${namespace} -RIVET_TOKEN=${token || ""}`; + const envVars = `RIVET_ENDPOINT=${createUnifiedEndpoint(endpoint, namespace, token || "")}`; navigator.clipboard.writeText(envVars); toast.success("Copied to clipboard"); }} diff --git a/website/src/content/docs/actors/ai-and-user-generated-actors.mdx b/website/src/content/docs/actors/ai-and-user-generated-actors.mdx index a1fade23bf..5222190490 100644 --- a/website/src/content/docs/actors/ai-and-user-generated-actors.mdx +++ b/website/src/content/docs/actors/ai-and-user-generated-actors.mdx @@ -119,6 +119,7 @@ The deployment process involves four key steps: cwd: projectDir, env: { ...process.env, + // Using separate variables (both formats work) VITE_RIVET_ENDPOINT: "https://api.rivet.dev", VITE_RIVET_NAMESPACE: engineNamespaceName, VITE_RIVET_TOKEN: publishableToken, @@ -133,6 +134,7 @@ The deployment process involves four key steps: const { deploymentId } = await freestyle.deployWeb(deploymentSource, { envVars: { + // Using separate variables (both formats work) RIVET_ENDPOINT: "https://api.rivet.dev", RIVET_NAMESPACE: engineNamespaceName, RIVET_TOKEN: runnerToken, @@ -242,6 +244,7 @@ The deployment process involves four key steps: cwd: projectDir, env: { ...process.env, + // Using separate variables (both formats work) VITE_RIVET_ENDPOINT: RIVET_ENDPOINT, VITE_RIVET_NAMESPACE: namespace.name, VITE_RIVET_TOKEN: RIVET_TOKEN, @@ -256,6 +259,7 @@ The deployment process involves four key steps: const { deploymentId } = await freestyle.deployWeb(deploymentSource, { envVars: { + // Using separate variables (both formats work) RIVET_ENDPOINT, RIVET_NAMESPACE: namespace.name, RIVET_TOKEN, diff --git a/website/src/content/docs/clients/react.mdx b/website/src/content/docs/clients/react.mdx index 56a443d05c..4cb7ed676a 100644 --- a/website/src/content/docs/clients/react.mdx +++ b/website/src/content/docs/clients/react.mdx @@ -23,7 +23,7 @@ const { useActor } = createRivetKit(); #### Parameters -- `endpoint`: Optional endpoint URL (defaults to `http://localhost:6420` or `process.env.RIVET_ENDPOINT`) +- `endpoint`: Optional endpoint URL (defaults to `http://localhost:6420` or `process.env.RIVET_ENDPOINT`). Supports unified format with embedded credentials: `https://namespace:token@api.rivet.dev` - `options`: Optional configuration object #### Returns diff --git a/website/src/content/docs/connect/aws-ecs.mdx b/website/src/content/docs/connect/aws-ecs.mdx index e85bcbb7d2..adf775c269 100644 --- a/website/src/content/docs/connect/aws-ecs.mdx +++ b/website/src/content/docs/connect/aws-ecs.mdx @@ -15,8 +15,14 @@ Run your backend on Amazon ECS with Fargate using a simple container image and s -Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used in the task definition. They should look something like this: +Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used in the task definition. You can use either the unified endpoint format or separate variables: +**Unified Format (Recommended):** +```bash +RIVET_ENDPOINT=https://your-namespace-id:your-token@api-us-west-1.rivet.dev +``` + +**Separate Variables:** ```bash RIVET_ENDPOINT=https://api-us-west-1.rivet.dev RIVET_NAMESPACE=your-namespace-id @@ -55,6 +61,28 @@ docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/backend:latest Create `backend-task.json` describing the ECS task. Update the ARNs, subnets, and security groups for your environment. +**With Unified Format (Recommended):** +```json +{ + "family": "backend", + "networkMode": "awsvpc", + "cpu": "256", + "memory": "512", + "requiresCompatibilities": ["FARGATE"], + "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole", + "containerDefinitions": [ + { + "name": "backend", + "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/backend:latest", + "environment": [ + { "name": "RIVET_ENDPOINT", "value": "https://your-namespace-id:your-token@api-us-west-1.rivet.dev" } + ] + } + ] +} +``` + +**Or With Separate Variables:** ```json { "family": "backend", diff --git a/website/src/content/docs/connect/gcp-cloud-run.mdx b/website/src/content/docs/connect/gcp-cloud-run.mdx index 7bb36f9891..d5ab650de7 100644 --- a/website/src/content/docs/connect/gcp-cloud-run.mdx +++ b/website/src/content/docs/connect/gcp-cloud-run.mdx @@ -15,8 +15,14 @@ Run your backend on Cloud Run with a lightweight container image and one command -Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used when deploying. They should look something like this: +Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used when deploying. You can use either the unified endpoint format or separate variables: +**Unified Format (Recommended):** +```bash +RIVET_ENDPOINT=https://your-namespace-id:your-token@api-us-west-1.rivet.dev +``` + +**Separate Variables:** ```bash RIVET_ENDPOINT=https://api-us-west-1.rivet.dev RIVET_NAMESPACE=your-namespace-id @@ -52,6 +58,17 @@ gcloud builds submit --tag us-central1-docker.pkg.dev/YOUR_PROJECT/backend/backe Deploy the service to Cloud Run, passing the Rivet environment variables. Adjust the region, image, and VPC connector settings as needed. +**With Unified Format (Recommended):** +```bash +gcloud run deploy backend \ + --image us-central1-docker.pkg.dev/YOUR_PROJECT/backend/backend:latest \ + --region us-central1 \ + --allow-unauthenticated \ + --min-instances 1 \ + --set-env-vars RIVET_ENDPOINT=https://your-namespace-id:your-token@api-us-west-1.rivet.dev +``` + +**Or With Separate Variables:** ```bash gcloud run deploy backend \ --image us-central1-docker.pkg.dev/YOUR_PROJECT/backend/backend:latest \ diff --git a/website/src/content/docs/connect/kubernetes.mdx b/website/src/content/docs/connect/kubernetes.mdx index 35a56fa464..8026dba745 100644 --- a/website/src/content/docs/connect/kubernetes.mdx +++ b/website/src/content/docs/connect/kubernetes.mdx @@ -14,8 +14,14 @@ Run your backend on any Kubernetes cluster with a simple container image and dep -Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used in later manifests. They should look something like this: +Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used in later manifests. You can use either the unified endpoint format or separate variables: +**Unified Format (Recommended):** +```bash +RIVET_ENDPOINT=https://your-namespace-id:your-token@api-us-west-1.rivet.dev +``` + +**Separate Variables:** ```bash RIVET_ENDPOINT=https://api-us-west-1.rivet.dev RIVET_NAMESPACE=your-namespace-id @@ -52,6 +58,18 @@ Replace `registry.example.com/your-team` with your registry path. Auth with `doc Create a `backend-secrets.yaml` for your environment variables: +**With Unified Format (Recommended):** +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: backend-secrets +type: Opaque +stringData: + RIVET_ENDPOINT: https://your-namespace-id:your-token@api-us-west-1.rivet.dev +``` + +**Or With Separate Variables:** ```yaml apiVersion: v1 kind: Secret diff --git a/website/src/content/docs/connect/vm-and-bare-metal.mdx b/website/src/content/docs/connect/vm-and-bare-metal.mdx index a0efe54446..ab40a74a90 100644 --- a/website/src/content/docs/connect/vm-and-bare-metal.mdx +++ b/website/src/content/docs/connect/vm-and-bare-metal.mdx @@ -19,8 +19,14 @@ Place the files somewhere readable by the service user, such as `/opt/backend`. -Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used in the next step. They should look something like this: +Navigate to Rivet and click _Connect > Manual_. Copy the environment variables provided, they will be used in the next step. You can use either the unified endpoint format or separate variables: +**Unified Format (Recommended):** +```bash +RIVET_ENDPOINT=https://your-namespace-id:your-token@api-us-west-1.rivet.dev +``` + +**Separate Variables:** ```bash RIVET_ENDPOINT=https://api-us-west-1.rivet.dev RIVET_NAMESPACE=your-namespace-id @@ -32,6 +38,24 @@ RIVET_TOKEN=your-token Create `/etc/systemd/system/backend.service`: +**With Unified Format (Recommended):** +```ini +[Unit] +Description=Backend Service +After=network.target + +[Service] +Type=simple +WorkingDirectory=/opt/backend +ExecStart=/usr/bin/node server.js +Restart=on-failure +Environment=RIVET_ENDPOINT=https://your-namespace-id:your-token@api.rivet.dev + +[Install] +WantedBy=multi-user.target +``` + +**Or With Separate Variables:** ```ini [Unit] Description=Backend Service diff --git a/website/src/content/docs/self-hosting/connect-backend.mdx b/website/src/content/docs/self-hosting/connect-backend.mdx index a35afcad17..e595d83cfa 100644 --- a/website/src/content/docs/self-hosting/connect-backend.mdx +++ b/website/src/content/docs/self-hosting/connect-backend.mdx @@ -23,19 +23,69 @@ Once connected: ## Environment Variables -### `RIVET_ENGINE` -The endpoint of your Rivet Engine instance. +RivetKit supports two formats for configuration: + +1. **Unified Endpoint Format** (Recommended): Embed namespace and token in the endpoint URL +2. **Separate Variables**: Use individual environment variables for each config + +### Unified Endpoint Format (Recommended) + +The unified format allows you to specify the endpoint, namespace, and token in a single URL using HTTP Basic Auth syntax: + +```bash +# Format: https://namespace:token@endpoint +RIVET_ENDPOINT=https://my-namespace:pub_abc123@api.rivet.dev +``` + +This format is more concise and reduces configuration complexity. The namespace and token are automatically extracted from the URL. + +### Separate Variables + +You can also use separate environment variables: + +```bash +RIVET_ENDPOINT=https://api.rivet.dev +RIVET_NAMESPACE=my-namespace +RIVET_TOKEN=pub_abc123 +``` + + +Both formats are supported. Choose the one that works best for your deployment workflow. + + +### Configuration Details + +### `RIVET_ENDPOINT` or `RIVET_ENGINE` +The endpoint of your Rivet Engine instance. Can include namespace and token in unified format. ```bash -# Local development +# Unified format (recommended) - only supported by RIVET_ENDPOINT +RIVET_ENDPOINT=https://my-namespace:pub_abc123@api.rivet.dev + +# Or separate endpoint only +RIVET_ENDPOINT=https://api.rivet.dev + +# Legacy alias RIVET_ENGINE (endpoint only, no unified format) RIVET_ENGINE=http://localhost:6420 +``` + + +`RIVET_ENGINE` is a legacy alias for `RIVET_ENDPOINT` that only supports endpoint-only configuration. Use `RIVET_ENDPOINT` for the unified format with embedded credentials. + + +### `RIVET_TOKEN` +Authentication token for accessing the Rivet Engine (when not using unified endpoint format). -# Production -RIVET_ENGINE=https://engine.your-domain.com +```bash +# Client/publishable token (safe for frontend) +RIVET_TOKEN=pub_abc123 + +# Runner/secret token (backend only) +RIVET_TOKEN=sec_xyz789 ``` ### `RIVET_NAMESPACE` -The namespace to run actors in. Useful for multi-tenant deployments. +The namespace to run actors in (when not using unified endpoint format). Useful for multi-tenant deployments. ```bash RIVET_NAMESPACE=production @@ -61,26 +111,45 @@ RIVET_RUNNER_KEY=unique-runner-key-123 ## Connection Examples -### Testing Setup +### Local Development (No Engine) -You do not need the engine for local development, but it can be helpful for testing your production-readiness: +You do not need the engine for local development: + +```bash +npm run dev +``` + +### Local Development (With Engine) + +For testing production-readiness: ```bash # Start the engine docker run -p 6420:6420 rivetkit/engine -# In another terminal, start your runner -RIVET_ENGINE=http://localhost:6420 npm run dev +# In another terminal, start your runner with unified endpoint +RIVET_ENDPOINT=http://default:your-token@localhost:6420 npm run dev + +# Or with separate variables +RIVET_ENDPOINT=http://localhost:6420 \ +RIVET_NAMESPACE=default \ +RIVET_TOKEN=your-token \ +npm run dev ``` ### Production Setup ```bash -# Assume the engine is running at 1.2.3.4 +# With unified endpoint (recommended) +RIVET_ENDPOINT=https://my-namespace:pub_abc123@api.rivet.dev \ +RIVET_RUNNER=worker-$(hostname) \ +RIVET_RUNNER_KEY=$(cat /etc/machine-id) \ +npm run start -# On runner nodes -RIVET_ENGINE=http://1.2.3.4 \ -RIVET_NAMESPACE=production \ +# Or with separate variables +RIVET_ENDPOINT=https://api.rivet.dev \ +RIVET_NAMESPACE=my-namespace \ +RIVET_TOKEN=pub_abc123 \ RIVET_RUNNER=worker-$(hostname) \ RIVET_RUNNER_KEY=$(cat /etc/machine-id) \ npm run start