diff --git a/Cargo.lock b/Cargo.lock
index 2c24b72012..efab3640ec 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4374,6 +4374,15 @@ dependencies = [
"utoipa",
]
+[[package]]
+name = "rivet-api-public-openapi-gen"
+version = "2.0.33"
+dependencies = [
+ "rivet-api-public",
+ "serde_json",
+ "utoipa",
+]
+
[[package]]
name = "rivet-api-types"
version = "2.0.33"
@@ -4509,15 +4518,6 @@ dependencies = [
"vbare-compiler",
]
-[[package]]
-name = "rivet-dump-openapi"
-version = "2.0.33"
-dependencies = [
- "rivet-api-public",
- "serde_json",
- "utoipa",
-]
-
[[package]]
name = "rivet-engine"
version = "2.0.33"
diff --git a/Cargo.toml b/Cargo.toml
index 9b0b56e5b9..5f620f6036 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,7 +14,7 @@ members = [
"engine/packages/clickhouse-inserter",
"engine/packages/clickhouse-user-query",
"engine/packages/config",
- "engine/packages/dump-openapi",
+ "engine/packages/api-public-openapi-gen",
"engine/packages/engine",
"engine/packages/env",
"engine/packages/epoxy",
@@ -375,8 +375,8 @@ members = [
[workspace.dependencies.rivet-config]
path = "engine/packages/config"
- [workspace.dependencies.rivet-dump-openapi]
- path = "engine/packages/dump-openapi"
+ [workspace.dependencies.rivet-api-public-openapi-gen]
+ path = "engine/packages/api-public-openapi-gen"
[workspace.dependencies.rivet-engine]
path = "engine/packages/engine"
diff --git a/engine/artifacts/config-schema.json b/engine/artifacts/config-schema.json
new file mode 100644
index 0000000000..1ca62c4d5d
--- /dev/null
+++ b/engine/artifacts/config-schema.json
@@ -0,0 +1,865 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Root",
+ "type": "object",
+ "oneOf": [
+ {
+ "type": "object",
+ "required": [
+ "postgres"
+ ],
+ "properties": {
+ "postgres": {
+ "$ref": "#/definitions/Postgres"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "required": [
+ "file_system"
+ ],
+ "properties": {
+ "file_system": {
+ "$ref": "#/definitions/FileSystem"
+ }
+ },
+ "additionalProperties": false
+ }
+ ],
+ "properties": {
+ "api_peer": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/ApiPeer"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "api_public": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/ApiPublic"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "auth": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Auth"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "cache": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Cache"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "clickhouse": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/ClickHouse"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "guard": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Guard"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "logs": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Logs"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "metrics": {
+ "default": {
+ "host": null,
+ "port": null
+ },
+ "allOf": [
+ {
+ "$ref": "#/definitions/Metrics"
+ }
+ ]
+ },
+ "pegboard": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Pegboard"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "runtime": {
+ "default": {
+ "allow_version_rollback": null,
+ "guard_shutdown_duration": null,
+ "worker_cpu_max": null,
+ "worker_shutdown_duration": null
+ },
+ "allOf": [
+ {
+ "$ref": "#/definitions/Runtime"
+ }
+ ]
+ },
+ "telemetry": {
+ "default": {
+ "enabled": true
+ },
+ "allOf": [
+ {
+ "$ref": "#/definitions/Telemetry"
+ }
+ ]
+ },
+ "topology": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Topology"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "vector_http": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/VectorHttp"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "definitions": {
+ "ApiPeer": {
+ "description": "Configuration for the private API service.",
+ "type": "object",
+ "properties": {
+ "host": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "ip"
+ },
+ "port": {
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint16",
+ "minimum": 0.0
+ }
+ },
+ "additionalProperties": false
+ },
+ "ApiPublic": {
+ "description": "Configuration for the public API service.",
+ "type": "object",
+ "properties": {
+ "respect_forwarded_for": {
+ "description": "Flag to respect the X-Forwarded-For header for client IP addresses.\n\nWill be ignored in favor of CF-Connecting-IP if DNS provider is configured as Cloudflare.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "verbose_errors": {
+ "description": "Flag to enable verbose error reporting.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "Auth": {
+ "type": "object",
+ "required": [
+ "admin_token"
+ ],
+ "properties": {
+ "admin_token": {
+ "$ref": "#/definitions/Secret"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Cache": {
+ "description": "Configuration for the cache layer.",
+ "type": "object",
+ "required": [
+ "driver"
+ ],
+ "properties": {
+ "driver": {
+ "$ref": "#/definitions/CacheDriver"
+ }
+ },
+ "additionalProperties": false
+ },
+ "CacheDriver": {
+ "type": "string",
+ "enum": [
+ "redis",
+ "in_memory"
+ ]
+ },
+ "ClickHouse": {
+ "type": "object",
+ "required": [
+ "http_url",
+ "native_url",
+ "username"
+ ],
+ "properties": {
+ "http_url": {
+ "description": "URL to the HTTP access port for ClickHouse.",
+ "type": "string",
+ "format": "uri"
+ },
+ "native_url": {
+ "description": "URL to the native access port for ClickHouse.",
+ "type": "string",
+ "format": "uri"
+ },
+ "password": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Secret"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "provision_users": {
+ "default": {},
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/ClickHouseUser"
+ }
+ },
+ "secure": {
+ "default": false,
+ "type": "boolean"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "ClickHouseUser": {
+ "type": "object",
+ "required": [
+ "password",
+ "role",
+ "username"
+ ],
+ "properties": {
+ "password": {
+ "$ref": "#/definitions/Secret"
+ },
+ "role": {
+ "$ref": "#/definitions/ClickHouseUserRole"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "ClickHouseUserRole": {
+ "type": "string",
+ "enum": [
+ "Admin",
+ "Write",
+ "ReadOnly"
+ ]
+ },
+ "Datacenter": {
+ "type": "object",
+ "required": [
+ "datacenter_label",
+ "is_leader",
+ "name",
+ "peer_url",
+ "public_url"
+ ],
+ "properties": {
+ "datacenter_label": {
+ "type": "integer",
+ "format": "uint16",
+ "minimum": 0.0
+ },
+ "is_leader": {
+ "type": "boolean"
+ },
+ "name": {
+ "type": "string"
+ },
+ "peer_url": {
+ "description": "URL of the api-peer service",
+ "type": "string",
+ "format": "uri"
+ },
+ "proxy_url": {
+ "description": "URL of the guard service that other datacenters can access privately. Goes to the same place as",
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri"
+ },
+ "public_url": {
+ "description": "Public origin that can be used to connect to this region.",
+ "type": "string",
+ "format": "uri"
+ },
+ "valid_hosts": {
+ "description": "List of hosts that are valid to connect to this region with. This is used in regional endpoints to validate that incoming requests to this datacenter are going to a region-specific domain.\n\nIMPORTANT: Do not use a global origin that routes to multiple different regions. This will cause unpredictable behavior when requests are expected to go to a specific region.",
+ "default": null,
+ "type": [
+ "array",
+ "null"
+ ],
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "FileSystem": {
+ "type": "object",
+ "required": [
+ "path"
+ ],
+ "properties": {
+ "path": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Guard": {
+ "type": "object",
+ "properties": {
+ "host": {
+ "description": "Host for HTTP traffic",
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "ip"
+ },
+ "https": {
+ "description": "Enable & configure HTTPS",
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Https"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "port": {
+ "description": "Port for HTTP traffic",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint16",
+ "minimum": 0.0
+ }
+ },
+ "additionalProperties": false
+ },
+ "Https": {
+ "type": "object",
+ "required": [
+ "port",
+ "tls"
+ ],
+ "properties": {
+ "port": {
+ "type": "integer",
+ "format": "uint16",
+ "minimum": 0.0
+ },
+ "tls": {
+ "$ref": "#/definitions/Tls"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Logs": {
+ "type": "object",
+ "properties": {
+ "redirect_logs_dir": {
+ "default": null,
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "Memory": {
+ "type": "object",
+ "properties": {
+ "channel": {
+ "default": "default",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Metrics": {
+ "description": "Configuration for the metrics service.",
+ "type": "object",
+ "properties": {
+ "host": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "ip"
+ },
+ "port": {
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint16",
+ "minimum": 0.0
+ }
+ },
+ "additionalProperties": false
+ },
+ "Nats": {
+ "type": "object",
+ "required": [
+ "addresses"
+ ],
+ "properties": {
+ "addresses": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "password": {
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/Secret"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "port": {
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint16",
+ "minimum": 0.0
+ },
+ "username": {
+ "default": null,
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "Pegboard": {
+ "type": "object",
+ "properties": {
+ "actor_start_threshold": {
+ "description": "How long to wait after creating and not receiving a starting state before setting actor as lost.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "int64"
+ },
+ "actor_stop_threshold": {
+ "description": "How long to wait after stopping and not receiving a stop state before setting actor as lost.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "int64"
+ },
+ "base_retry_timeout": {
+ "description": "Time to delay an actor from rescheduling after a rescheduling failure.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint",
+ "minimum": 0.0
+ },
+ "hibernating_request_eligible_threshold": {
+ "description": "How long after last ping before considering a hibernating request disconnected.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "int64"
+ },
+ "pool_desired_max_override": {
+ "description": "Global pool desired max.",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint32",
+ "minimum": 0.0
+ },
+ "reschedule_backoff_max_exponent": {
+ "description": "Maximum exponent for the reschedule backoff calculation.\n\nThis controls the maximum backoff duration when rescheduling actors.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint",
+ "minimum": 0.0
+ },
+ "retry_reset_duration": {
+ "description": "How long an actor goes without retries before it's retry count is reset to 0, effectively resetting its backoff to 0.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "int64"
+ },
+ "runner_eligible_threshold": {
+ "description": "How long after last ping before considering a runner ineligible for allocation.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "int64"
+ },
+ "runner_lost_threshold": {
+ "description": "How long to wait after last ping before forcibly removing a runner from the database and deleting its workflow, evicting all actors.\n\nNote that the runner may still be running and can reconnect.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "int64"
+ },
+ "runner_pool_consecutive_successes_to_clear_error": {
+ "description": "Number of consecutive successes required to clear an active runner pool error.\n\nThis prevents a single success from clearing an error during flapping conditions. Higher values provide more stability but slower recovery from transient errors.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint32",
+ "minimum": 0.0
+ },
+ "serverless_backoff_max_exponent": {
+ "description": "Maximum exponent for the serverless backoff calculation.\n\nThis controls the maximum backoff duration when serverlessly connecting to runners.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint",
+ "minimum": 0.0
+ },
+ "serverless_base_retry_timeout": {
+ "description": "Time to delay a serverless runner from attempting a new outbound connection after a connection failure.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint",
+ "minimum": 0.0
+ },
+ "serverless_retry_reset_duration": {
+ "description": "How long a serverless runner goes without connection failures before it's retry count is reset to 0, effectively resetting its backoff to 0.\n\nUnit is in milliseconds.\n\n**Experimental**",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "int64"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Postgres": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "ssl": {
+ "description": "SSL configuration options",
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/PostgresSsl"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "unstable_disable_lock_customization": {
+ "description": "UNSTABLE: Disable lock timeout customization\n\nWhen `false` (default), the driver sets `lock_timeout = '0'` and `deadlock_timeout = '10ms'` during transaction commits to optimize conflict detection.\n\nWhen `true`, these settings are NOT applied, which may be necessary for some PostgreSQL configurations or hosted services that don't support these settings.\n\n**This is an unstable feature and may change or be removed in future versions.**",
+ "default": false,
+ "type": "boolean"
+ },
+ "url": {
+ "description": "URL to connect to Postgres with\n\nSupports standard PostgreSQL connection parameters including `sslmode`. Supported sslmode values: `disable`, `prefer` (default), `require`. To verify server certificates, use `sslmode=require` with `ssl.root_cert_path`.\n\nExample with sslmode: `postgresql://user:pass@host:5432/db?sslmode=require`\n\nSee: https://docs.rs/postgres/0.19.10/postgres/config/struct.Config.html#url",
+ "allOf": [
+ {
+ "$ref": "#/definitions/Secret"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "Postgres2": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "memory_optimization": {
+ "default": true,
+ "type": "boolean"
+ },
+ "ssl": {
+ "description": "SSL configuration options",
+ "default": null,
+ "anyOf": [
+ {
+ "$ref": "#/definitions/PostgresSsl"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "url": {
+ "description": "URL to connect to Postgres with\n\nSupports standard PostgreSQL connection parameters including `sslmode`. Supported sslmode values: `disable`, `prefer` (default), `require`. To verify server certificates, use `sslmode=require` with `ssl.root_cert_path`.\n\nSee: https://docs.rs/postgres/0.19.10/postgres/config/struct.Config.html#url",
+ "allOf": [
+ {
+ "$ref": "#/definitions/Secret"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "PostgresSsl": {
+ "type": "object",
+ "properties": {
+ "client_cert_path": {
+ "description": "Path to the client certificate file\n\nUsed for client certificate authentication Equivalent to PostgreSQL's `sslcert` parameter",
+ "default": null,
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "client_key_path": {
+ "description": "Path to the client private key file\n\nUsed for client certificate authentication Equivalent to PostgreSQL's `sslkey` parameter",
+ "default": null,
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "root_cert_path": {
+ "description": "Path to the root certificate file for verifying the server's certificate\n\nRequired when using custom certificate authorities (e.g., Supabase) Equivalent to PostgreSQL's `sslrootcert` parameter",
+ "default": null,
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "Runtime": {
+ "type": "object",
+ "properties": {
+ "allow_version_rollback": {
+ "description": "Whether or not to allow running the engine when the previous version that was run is higher than the current version.",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "guard_shutdown_duration": {
+ "description": "Time (in seconds) to allow for guard to wait for pending requests after receiving SIGTERM. Defaults to 1 hour.",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint32",
+ "minimum": 0.0
+ },
+ "worker_cpu_max": {
+ "description": "Adjusts worker curve around this value (in millicores, i.e. 1000 = 1 core). Is not a hard limit. When unset, uses /sys/fs/cgroup/cpu.max, and if that is unset uses total host cpu.",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint",
+ "minimum": 0.0
+ },
+ "worker_shutdown_duration": {
+ "description": "Time (in seconds) to allow for the gasoline worker engine to stop gracefully after receiving SIGTERM. Defaults to 30 seconds.",
+ "type": [
+ "integer",
+ "null"
+ ],
+ "format": "uint32",
+ "minimum": 0.0
+ }
+ },
+ "additionalProperties": false
+ },
+ "Secret": {
+ "type": "string"
+ },
+ "Telemetry": {
+ "type": "object",
+ "required": [
+ "enabled"
+ ],
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Tls": {
+ "type": "object",
+ "required": [
+ "actor_cert_path",
+ "actor_key_path",
+ "api_cert_path",
+ "api_key_path"
+ ],
+ "properties": {
+ "actor_cert_path": {
+ "type": "string"
+ },
+ "actor_key_path": {
+ "type": "string"
+ },
+ "api_cert_path": {
+ "type": "string"
+ },
+ "api_key_path": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Topology": {
+ "type": "object",
+ "required": [
+ "datacenter_label",
+ "datacenters"
+ ],
+ "properties": {
+ "datacenter_label": {
+ "description": "Must be included in `datacenters`",
+ "type": "integer",
+ "format": "uint16",
+ "minimum": 0.0
+ },
+ "datacenters": {
+ "description": "List of all datacenters, including this datacenter.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Datacenter"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "VectorHttp": {
+ "type": "object",
+ "required": [
+ "host",
+ "port"
+ ],
+ "properties": {
+ "host": {
+ "type": "string"
+ },
+ "port": {
+ "type": "integer",
+ "format": "uint16",
+ "minimum": 0.0
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/engine/artifacts/openapi.json b/engine/artifacts/openapi.json
index 4f9a603ed1..261e7683f9 100644
--- a/engine/artifacts/openapi.json
+++ b/engine/artifacts/openapi.json
@@ -2097,29 +2097,28 @@
}
}
},
- {
- "type": "string",
- "description": "Serverless: Runner sent invalid base64 in SSE message",
- "enum": [
- "serverless_invalid_base64"
- ]
- },
{
"type": "object",
- "description": "Serverless: Runner sent invalid protocol payload",
+ "description": "Serverless: Runner sent invalid payload",
"required": [
- "serverless_invalid_payload"
+ "serverless_invalid_sse_payload"
],
"properties": {
- "serverless_invalid_payload": {
+ "serverless_invalid_sse_payload": {
"type": "object",
- "description": "Serverless: Runner sent invalid protocol payload",
+ "description": "Serverless: Runner sent invalid payload",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
+ },
+ "raw_payload": {
+ "type": [
+ "string",
+ "null"
+ ]
}
}
}
diff --git a/engine/packages/dump-openapi/Cargo.toml b/engine/packages/api-public-openapi-gen/Cargo.toml
similarity index 85%
rename from engine/packages/dump-openapi/Cargo.toml
rename to engine/packages/api-public-openapi-gen/Cargo.toml
index 5f0b9ded3d..6b7f0df385 100644
--- a/engine/packages/dump-openapi/Cargo.toml
+++ b/engine/packages/api-public-openapi-gen/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "rivet-dump-openapi"
+name = "rivet-api-public-openapi-gen"
version.workspace = true
edition.workspace = true
authors.workspace = true
diff --git a/engine/packages/dump-openapi/build.rs b/engine/packages/api-public-openapi-gen/build.rs
similarity index 100%
rename from engine/packages/dump-openapi/build.rs
rename to engine/packages/api-public-openapi-gen/build.rs
diff --git a/engine/packages/dump-openapi/src/lib.rs b/engine/packages/api-public-openapi-gen/src/lib.rs
similarity index 100%
rename from engine/packages/dump-openapi/src/lib.rs
rename to engine/packages/api-public-openapi-gen/src/lib.rs
diff --git a/engine/packages/config-schema-gen/Cargo.toml b/engine/packages/config-schema-gen/Cargo.toml
new file mode 100644
index 0000000000..08bf562c19
--- /dev/null
+++ b/engine/packages/config-schema-gen/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "rivet-config-schema-gen"
+version.workspace = true
+authors.workspace = true
+license.workspace = true
+edition.workspace = true
+
+[build-dependencies]
+rivet-config.workspace = true
+schemars.workspace = true
+serde_json.workspace = true
diff --git a/engine/packages/config-schema-gen/build.rs b/engine/packages/config-schema-gen/build.rs
new file mode 100644
index 0000000000..3b58253468
--- /dev/null
+++ b/engine/packages/config-schema-gen/build.rs
@@ -0,0 +1,26 @@
+use std::{fs, path::Path};
+
+fn main() {
+ let schema = schemars::schema_for!(rivet_config::config::Root);
+
+ // Create out directory at workspace root
+ let workspace_root = std::env::var("CARGO_MANIFEST_DIR")
+ .map(|dir| {
+ Path::new(&dir)
+ .parent()
+ .unwrap()
+ .parent()
+ .unwrap()
+ .parent()
+ .unwrap()
+ .to_path_buf()
+ })
+ .unwrap();
+ let out_dir = workspace_root.join("engine").join("artifacts");
+ fs::create_dir_all(&out_dir).unwrap();
+
+ // Write pretty-formatted JSON to out/config-schema.json
+ let json = serde_json::to_string_pretty(&schema).expect("Failed to serialize JSON Schema");
+ fs::write(out_dir.join("config-schema.json"), json)
+ .expect("Failed to write config-schema.json");
+}
diff --git a/engine/packages/config-schema-gen/src/lib.rs b/engine/packages/config-schema-gen/src/lib.rs
new file mode 100644
index 0000000000..40ef930344
--- /dev/null
+++ b/engine/packages/config-schema-gen/src/lib.rs
@@ -0,0 +1,2 @@
+// This crate exists only to trigger the build.rs script
+// which generates the JSON schema at build time.
diff --git a/rivetkit-json-schema/registry-config.json b/rivetkit-json-schema/registry-config.json
new file mode 100644
index 0000000000..f807f22cbb
--- /dev/null
+++ b/rivetkit-json-schema/registry-config.json
@@ -0,0 +1,210 @@
+{
+ "description": "Configuration schema for RivetKit registry. This is typically passed to the setup() function.",
+ "type": "object",
+ "properties": {
+ "use": {
+ "description": "Actor definitions. Keys are actor names, values are actor definitions.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {}
+ },
+ "maxIncomingMessageSize": {
+ "description": "Maximum size of incoming WebSocket messages in bytes. Default: 65536",
+ "type": "number"
+ },
+ "maxOutgoingMessageSize": {
+ "description": "Maximum size of outgoing WebSocket messages in bytes. Default: 1048576",
+ "type": "number"
+ },
+ "noWelcome": {
+ "description": "Disable the welcome message on startup. Default: false",
+ "type": "boolean"
+ },
+ "logging": {
+ "description": "Logging configuration.",
+ "type": "object",
+ "properties": {
+ "level": {
+ "description": "Log level for RivetKit. Default: 'warn'",
+ "type": "string",
+ "enum": [
+ "trace",
+ "debug",
+ "info",
+ "warn",
+ "error",
+ "fatal",
+ "silent"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "endpoint": {
+ "description": "Endpoint URL to connect to Rivet Engine. Supports URL auth syntax: https://namespace:token@api.rivet.dev. Can also be set via RIVET_ENDPOINT environment variable.",
+ "type": "string"
+ },
+ "token": {
+ "description": "Authentication token for Rivet Engine. Can also be set via RIVET_TOKEN environment variable.",
+ "type": "string"
+ },
+ "namespace": {
+ "description": "Namespace to use. Default: 'default'. Can also be set via RIVET_NAMESPACE environment variable.",
+ "type": "string"
+ },
+ "headers": {
+ "description": "Additional headers to include in requests to Rivet Engine.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "serveManager": {
+ "description": "Whether to start the local manager server. Auto-determined based on endpoint and NODE_ENV if not specified.",
+ "type": "boolean"
+ },
+ "managerBasePath": {
+ "description": "Base path for the manager API. Default: '/'",
+ "type": "string"
+ },
+ "managerPort": {
+ "description": "Port to run the manager on. Default: 6420",
+ "type": "number"
+ },
+ "inspector": {
+ "description": "Inspector configuration for debugging and development.",
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "description": "Whether to enable the Rivet Inspector. Defaults to true in development mode.",
+ "type": "boolean"
+ },
+ "token": {
+ "description": "Token used to access the Inspector.",
+ "type": "string"
+ },
+ "defaultEndpoint": {
+ "description": "Default RivetKit server endpoint for Rivet Inspector to connect to.",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "serverless": {
+ "description": "Configuration for serverless deployment mode.",
+ "type": "object",
+ "properties": {
+ "spawnEngine": {
+ "description": "Downloads and starts the full Rust engine process. Auto-enabled in development mode when no endpoint is provided. Default: false",
+ "type": "boolean"
+ },
+ "engineVersion": {
+ "description": "Version of the engine to download. Defaults to the current RivetKit version.",
+ "type": "string"
+ },
+ "configureRunnerPool": {
+ "description": "Automatically configure serverless runners in the engine.",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "Name of the runner pool.",
+ "type": "string"
+ },
+ "url": {
+ "description": "URL of the serverless platform to configure runners.",
+ "type": "string"
+ },
+ "headers": {
+ "description": "Headers to include in requests to the serverless platform.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "maxRunners": {
+ "description": "Maximum number of runners in the pool.",
+ "type": "number"
+ },
+ "minRunners": {
+ "description": "Minimum number of runners to keep warm.",
+ "type": "number"
+ },
+ "requestLifespan": {
+ "description": "Maximum lifespan of a request in milliseconds.",
+ "type": "number"
+ },
+ "runnersMargin": {
+ "description": "Buffer margin for scaling runners.",
+ "type": "number"
+ },
+ "slotsPerRunner": {
+ "description": "Number of actor slots per runner.",
+ "type": "number"
+ },
+ "metadata": {
+ "description": "Additional metadata to pass to the serverless platform.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {}
+ }
+ },
+ "required": [
+ "url"
+ ],
+ "additionalProperties": false
+ },
+ "basePath": {
+ "description": "Base path for serverless API routes. Default: '/api/rivet'",
+ "type": "string"
+ },
+ "publicEndpoint": {
+ "description": "The endpoint that clients should connect to. Supports URL auth syntax: https://namespace:token@api.rivet.dev",
+ "type": "string"
+ },
+ "publicToken": {
+ "description": "Token that clients should use when connecting via the public endpoint.",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "runner": {
+ "description": "Configuration for runner mode.",
+ "type": "object",
+ "properties": {
+ "totalSlots": {
+ "description": "Total number of actor slots available. Default: 100000",
+ "type": "number"
+ },
+ "runnerName": {
+ "description": "Name of this runner. Default: 'default'",
+ "type": "string"
+ },
+ "runnerKey": {
+ "description": "Authentication key for the runner.",
+ "type": "string"
+ },
+ "version": {
+ "description": "Version number of this runner. Default: 1",
+ "type": "number"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": [
+ "use"
+ ],
+ "additionalProperties": false,
+ "title": "RivetKit Registry Configuration"
+}
\ No newline at end of file
diff --git a/rivetkit-typescript/artifacts/actor-config.json b/rivetkit-typescript/artifacts/actor-config.json
new file mode 100644
index 0000000000..68748a8c5e
--- /dev/null
+++ b/rivetkit-typescript/artifacts/actor-config.json
@@ -0,0 +1,129 @@
+{
+ "description": "Configuration schema for RivetKit actors. This is passed to the actor() function.",
+ "type": "object",
+ "properties": {
+ "state": {
+ "description": "Initial state value for the actor. Cannot be used with createState."
+ },
+ "createState": {
+ "description": "Function to create initial state. Receives context and input. Cannot be used with state."
+ },
+ "connState": {
+ "description": "Initial connection state value. Cannot be used with createConnState."
+ },
+ "createConnState": {
+ "description": "Function to create connection state. Receives context and connection params. Cannot be used with connState."
+ },
+ "vars": {
+ "description": "Initial ephemeral variables value. Cannot be used with createVars."
+ },
+ "createVars": {
+ "description": "Function to create ephemeral variables. Receives context and driver context. Cannot be used with vars."
+ },
+ "db": {
+ "description": "Database provider instance for the actor."
+ },
+ "onCreate": {
+ "description": "Called when the actor is first initialized. Use to initialize state."
+ },
+ "onDestroy": {
+ "description": "Called when the actor is destroyed."
+ },
+ "onWake": {
+ "description": "Called when the actor wakes up and is ready to receive connections and actions."
+ },
+ "onSleep": {
+ "description": "Called when the actor is stopping or sleeping. Use to clean up resources."
+ },
+ "onStateChange": {
+ "description": "Called when the actor's state changes. State changes within this hook won't trigger recursion."
+ },
+ "onBeforeConnect": {
+ "description": "Called before a client connects. Throw an error to reject the connection."
+ },
+ "onConnect": {
+ "description": "Called when a client successfully connects."
+ },
+ "onDisconnect": {
+ "description": "Called when a client disconnects."
+ },
+ "onBeforeActionResponse": {
+ "description": "Called before sending an action response. Use to transform output."
+ },
+ "onRequest": {
+ "description": "Called for raw HTTP requests to /actors/{name}/http/* endpoints."
+ },
+ "onWebSocket": {
+ "description": "Called for raw WebSocket connections to /actors/{name}/websocket/* endpoints."
+ },
+ "actions": {
+ "description": "Map of action name to handler function.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {}
+ },
+ "options": {
+ "description": "Actor options for timeouts and behavior configuration.",
+ "type": "object",
+ "properties": {
+ "createVarsTimeout": {
+ "description": "Timeout in ms for createVars handler. Default: 5000",
+ "type": "number"
+ },
+ "createConnStateTimeout": {
+ "description": "Timeout in ms for createConnState handler. Default: 5000",
+ "type": "number"
+ },
+ "onConnectTimeout": {
+ "description": "Timeout in ms for onConnect handler. Default: 5000",
+ "type": "number"
+ },
+ "onSleepTimeout": {
+ "description": "Timeout in ms for onSleep handler. Must be less than ACTOR_STOP_THRESHOLD_MS. Default: 5000",
+ "type": "number"
+ },
+ "onDestroyTimeout": {
+ "description": "Timeout in ms for onDestroy handler. Default: 5000",
+ "type": "number"
+ },
+ "stateSaveInterval": {
+ "description": "Interval in ms between automatic state saves. Default: 10000",
+ "type": "number"
+ },
+ "actionTimeout": {
+ "description": "Timeout in ms for action handlers. Default: 60000",
+ "type": "number"
+ },
+ "waitUntilTimeout": {
+ "description": "Max time in ms to wait for waitUntil background promises during shutdown. Default: 15000",
+ "type": "number"
+ },
+ "connectionLivenessTimeout": {
+ "description": "Timeout in ms for connection liveness checks. Default: 2500",
+ "type": "number"
+ },
+ "connectionLivenessInterval": {
+ "description": "Interval in ms between connection liveness checks. Default: 5000",
+ "type": "number"
+ },
+ "noSleep": {
+ "description": "If true, the actor will never sleep. Default: false",
+ "type": "boolean"
+ },
+ "sleepTimeout": {
+ "description": "Time in ms of inactivity before the actor sleeps. Default: 30000",
+ "type": "number"
+ },
+ "canHibernateWebSocket": {
+ "description": "Whether WebSockets using onWebSocket can be hibernated. WebSockets using actions/events are hibernatable by default. Default: false",
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false,
+ "title": "RivetKit Actor Configuration"
+}
\ No newline at end of file
diff --git a/rivetkit-typescript/artifacts/registry-config.json b/rivetkit-typescript/artifacts/registry-config.json
new file mode 100644
index 0000000000..f807f22cbb
--- /dev/null
+++ b/rivetkit-typescript/artifacts/registry-config.json
@@ -0,0 +1,210 @@
+{
+ "description": "Configuration schema for RivetKit registry. This is typically passed to the setup() function.",
+ "type": "object",
+ "properties": {
+ "use": {
+ "description": "Actor definitions. Keys are actor names, values are actor definitions.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {}
+ },
+ "maxIncomingMessageSize": {
+ "description": "Maximum size of incoming WebSocket messages in bytes. Default: 65536",
+ "type": "number"
+ },
+ "maxOutgoingMessageSize": {
+ "description": "Maximum size of outgoing WebSocket messages in bytes. Default: 1048576",
+ "type": "number"
+ },
+ "noWelcome": {
+ "description": "Disable the welcome message on startup. Default: false",
+ "type": "boolean"
+ },
+ "logging": {
+ "description": "Logging configuration.",
+ "type": "object",
+ "properties": {
+ "level": {
+ "description": "Log level for RivetKit. Default: 'warn'",
+ "type": "string",
+ "enum": [
+ "trace",
+ "debug",
+ "info",
+ "warn",
+ "error",
+ "fatal",
+ "silent"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "endpoint": {
+ "description": "Endpoint URL to connect to Rivet Engine. Supports URL auth syntax: https://namespace:token@api.rivet.dev. Can also be set via RIVET_ENDPOINT environment variable.",
+ "type": "string"
+ },
+ "token": {
+ "description": "Authentication token for Rivet Engine. Can also be set via RIVET_TOKEN environment variable.",
+ "type": "string"
+ },
+ "namespace": {
+ "description": "Namespace to use. Default: 'default'. Can also be set via RIVET_NAMESPACE environment variable.",
+ "type": "string"
+ },
+ "headers": {
+ "description": "Additional headers to include in requests to Rivet Engine.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "serveManager": {
+ "description": "Whether to start the local manager server. Auto-determined based on endpoint and NODE_ENV if not specified.",
+ "type": "boolean"
+ },
+ "managerBasePath": {
+ "description": "Base path for the manager API. Default: '/'",
+ "type": "string"
+ },
+ "managerPort": {
+ "description": "Port to run the manager on. Default: 6420",
+ "type": "number"
+ },
+ "inspector": {
+ "description": "Inspector configuration for debugging and development.",
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "description": "Whether to enable the Rivet Inspector. Defaults to true in development mode.",
+ "type": "boolean"
+ },
+ "token": {
+ "description": "Token used to access the Inspector.",
+ "type": "string"
+ },
+ "defaultEndpoint": {
+ "description": "Default RivetKit server endpoint for Rivet Inspector to connect to.",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "serverless": {
+ "description": "Configuration for serverless deployment mode.",
+ "type": "object",
+ "properties": {
+ "spawnEngine": {
+ "description": "Downloads and starts the full Rust engine process. Auto-enabled in development mode when no endpoint is provided. Default: false",
+ "type": "boolean"
+ },
+ "engineVersion": {
+ "description": "Version of the engine to download. Defaults to the current RivetKit version.",
+ "type": "string"
+ },
+ "configureRunnerPool": {
+ "description": "Automatically configure serverless runners in the engine.",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "Name of the runner pool.",
+ "type": "string"
+ },
+ "url": {
+ "description": "URL of the serverless platform to configure runners.",
+ "type": "string"
+ },
+ "headers": {
+ "description": "Headers to include in requests to the serverless platform.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "maxRunners": {
+ "description": "Maximum number of runners in the pool.",
+ "type": "number"
+ },
+ "minRunners": {
+ "description": "Minimum number of runners to keep warm.",
+ "type": "number"
+ },
+ "requestLifespan": {
+ "description": "Maximum lifespan of a request in milliseconds.",
+ "type": "number"
+ },
+ "runnersMargin": {
+ "description": "Buffer margin for scaling runners.",
+ "type": "number"
+ },
+ "slotsPerRunner": {
+ "description": "Number of actor slots per runner.",
+ "type": "number"
+ },
+ "metadata": {
+ "description": "Additional metadata to pass to the serverless platform.",
+ "type": "object",
+ "propertyNames": {
+ "type": "string"
+ },
+ "additionalProperties": {}
+ }
+ },
+ "required": [
+ "url"
+ ],
+ "additionalProperties": false
+ },
+ "basePath": {
+ "description": "Base path for serverless API routes. Default: '/api/rivet'",
+ "type": "string"
+ },
+ "publicEndpoint": {
+ "description": "The endpoint that clients should connect to. Supports URL auth syntax: https://namespace:token@api.rivet.dev",
+ "type": "string"
+ },
+ "publicToken": {
+ "description": "Token that clients should use when connecting via the public endpoint.",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "runner": {
+ "description": "Configuration for runner mode.",
+ "type": "object",
+ "properties": {
+ "totalSlots": {
+ "description": "Total number of actor slots available. Default: 100000",
+ "type": "number"
+ },
+ "runnerName": {
+ "description": "Name of this runner. Default: 'default'",
+ "type": "string"
+ },
+ "runnerKey": {
+ "description": "Authentication key for the runner.",
+ "type": "string"
+ },
+ "version": {
+ "description": "Version number of this runner. Default: 1",
+ "type": "number"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": [
+ "use"
+ ],
+ "additionalProperties": false,
+ "title": "RivetKit Registry Configuration"
+}
\ No newline at end of file
diff --git a/rivetkit-typescript/packages/rivetkit/package.json b/rivetkit-typescript/packages/rivetkit/package.json
index 6de746da10..8b24e9d887 100644
--- a/rivetkit-typescript/packages/rivetkit/package.json
+++ b/rivetkit-typescript/packages/rivetkit/package.json
@@ -161,8 +161,10 @@
"format:write": "biome format --write .",
"test": "vitest run",
"test:watch": "vitest",
- "dump-openapi": "tsx scripts/dump-openapi.ts",
- "dump-asyncapi": "tsx scripts/dump-asyncapi.ts"
+ "manager-openapi-gen": "tsx scripts/manager-openapi-gen.ts",
+ "dump-asyncapi": "tsx scripts/dump-asyncapi.ts",
+ "registry-config-schema-gen": "tsx scripts/registry-config-schema-gen.ts",
+ "actor-config-schema-gen": "tsx scripts/actor-config-schema-gen.ts"
},
"dependencies": {
"@hono/standard-validator": "^0.1.3",
diff --git a/rivetkit-typescript/packages/rivetkit/scripts/actor-config-schema-gen.ts b/rivetkit-typescript/packages/rivetkit/scripts/actor-config-schema-gen.ts
new file mode 100644
index 0000000000..f6a4c7cbf5
--- /dev/null
+++ b/rivetkit-typescript/packages/rivetkit/scripts/actor-config-schema-gen.ts
@@ -0,0 +1,32 @@
+import * as fs from "node:fs/promises";
+import { resolve } from "node:path";
+import { DocActorConfigSchema } from "../src/actor/config";
+import { toJsonSchema } from "./schema-utils";
+
+async function main() {
+ const schema = toJsonSchema(DocActorConfigSchema);
+
+ // Clean up the schema
+ delete (schema as any).$schema;
+
+ // Add metadata
+ schema.title = "RivetKit Actor Configuration";
+ schema.description = "Configuration schema for RivetKit actors. This is passed to the actor() function.";
+
+ // Create output directory
+ const outputDir = resolve(
+ import.meta.dirname,
+ "..",
+ "..",
+ "..",
+ "artifacts",
+ );
+ await fs.mkdir(outputDir, { recursive: true });
+
+ // Write the schema
+ const outputPath = resolve(outputDir, "actor-config.json");
+ await fs.writeFile(outputPath, JSON.stringify(schema, null, 2));
+ console.log("Dumped actor config JSON schema to", outputPath);
+}
+
+main();
diff --git a/rivetkit-typescript/packages/rivetkit/scripts/dump-openapi.ts b/rivetkit-typescript/packages/rivetkit/scripts/manager-openapi-gen.ts
similarity index 100%
rename from rivetkit-typescript/packages/rivetkit/scripts/dump-openapi.ts
rename to rivetkit-typescript/packages/rivetkit/scripts/manager-openapi-gen.ts
diff --git a/rivetkit-typescript/packages/rivetkit/scripts/registry-config-schema-gen.ts b/rivetkit-typescript/packages/rivetkit/scripts/registry-config-schema-gen.ts
new file mode 100644
index 0000000000..2caa88c411
--- /dev/null
+++ b/rivetkit-typescript/packages/rivetkit/scripts/registry-config-schema-gen.ts
@@ -0,0 +1,32 @@
+import * as fs from "node:fs/promises";
+import { resolve } from "node:path";
+import { DocRegistryConfigSchema } from "../src/registry/config/index";
+import { toJsonSchema } from "./schema-utils";
+
+async function main() {
+ const schema = toJsonSchema(DocRegistryConfigSchema);
+
+ // Clean up the schema
+ delete (schema as any).$schema;
+
+ // Add metadata
+ schema.title = "RivetKit Registry Configuration";
+ schema.description = "Configuration schema for RivetKit registry. This is typically passed to the setup() function.";
+
+ // Create output directory
+ const outputDir = resolve(
+ import.meta.dirname,
+ "..",
+ "..",
+ "..",
+ "artifacts",
+ );
+ await fs.mkdir(outputDir, { recursive: true });
+
+ // Write the schema
+ const outputPath = resolve(outputDir, "registry-config.json");
+ await fs.writeFile(outputPath, JSON.stringify(schema, null, 2));
+ console.log("Dumped registry config JSON schema to", outputPath);
+}
+
+main();
diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/config.ts b/rivetkit-typescript/packages/rivetkit/src/actor/config.ts
index 95e338a414..257c3c4109 100644
--- a/rivetkit-typescript/packages/rivetkit/src/actor/config.ts
+++ b/rivetkit-typescript/packages/rivetkit/src/actor/config.ts
@@ -613,3 +613,50 @@ export function test<
>;
return config;
}
+
+// MARK: Documentation Schema
+// This schema is JSON-serializable for documentation generation.
+// It excludes function types and focuses on the configurable options.
+
+export const DocActorOptionsSchema = z
+ .object({
+ createVarsTimeout: z.number().optional().describe("Timeout in ms for createVars handler. Default: 5000"),
+ createConnStateTimeout: z.number().optional().describe("Timeout in ms for createConnState handler. Default: 5000"),
+ onConnectTimeout: z.number().optional().describe("Timeout in ms for onConnect handler. Default: 5000"),
+ onSleepTimeout: z.number().optional().describe("Timeout in ms for onSleep handler. Must be less than ACTOR_STOP_THRESHOLD_MS. Default: 5000"),
+ onDestroyTimeout: z.number().optional().describe("Timeout in ms for onDestroy handler. Default: 5000"),
+ stateSaveInterval: z.number().optional().describe("Interval in ms between automatic state saves. Default: 10000"),
+ actionTimeout: z.number().optional().describe("Timeout in ms for action handlers. Default: 60000"),
+ waitUntilTimeout: z.number().optional().describe("Max time in ms to wait for waitUntil background promises during shutdown. Default: 15000"),
+ connectionLivenessTimeout: z.number().optional().describe("Timeout in ms for connection liveness checks. Default: 2500"),
+ connectionLivenessInterval: z.number().optional().describe("Interval in ms between connection liveness checks. Default: 5000"),
+ noSleep: z.boolean().optional().describe("If true, the actor will never sleep. Default: false"),
+ sleepTimeout: z.number().optional().describe("Time in ms of inactivity before the actor sleeps. Default: 30000"),
+ canHibernateWebSocket: z.boolean().optional().describe("Whether WebSockets using onWebSocket can be hibernated. WebSockets using actions/events are hibernatable by default. Default: false"),
+ })
+ .describe("Actor options for timeouts and behavior configuration.");
+
+export const DocActorConfigSchema = z
+ .object({
+ state: z.unknown().optional().describe("Initial state value for the actor. Cannot be used with createState."),
+ createState: z.unknown().optional().describe("Function to create initial state. Receives context and input. Cannot be used with state."),
+ connState: z.unknown().optional().describe("Initial connection state value. Cannot be used with createConnState."),
+ createConnState: z.unknown().optional().describe("Function to create connection state. Receives context and connection params. Cannot be used with connState."),
+ vars: z.unknown().optional().describe("Initial ephemeral variables value. Cannot be used with createVars."),
+ createVars: z.unknown().optional().describe("Function to create ephemeral variables. Receives context and driver context. Cannot be used with vars."),
+ db: z.unknown().optional().describe("Database provider instance for the actor."),
+ onCreate: z.unknown().optional().describe("Called when the actor is first initialized. Use to initialize state."),
+ onDestroy: z.unknown().optional().describe("Called when the actor is destroyed."),
+ onWake: z.unknown().optional().describe("Called when the actor wakes up and is ready to receive connections and actions."),
+ onSleep: z.unknown().optional().describe("Called when the actor is stopping or sleeping. Use to clean up resources."),
+ onStateChange: z.unknown().optional().describe("Called when the actor's state changes. State changes within this hook won't trigger recursion."),
+ onBeforeConnect: z.unknown().optional().describe("Called before a client connects. Throw an error to reject the connection."),
+ onConnect: z.unknown().optional().describe("Called when a client successfully connects."),
+ onDisconnect: z.unknown().optional().describe("Called when a client disconnects."),
+ onBeforeActionResponse: z.unknown().optional().describe("Called before sending an action response. Use to transform output."),
+ onRequest: z.unknown().optional().describe("Called for raw HTTP requests to /actors/{name}/http/* endpoints."),
+ onWebSocket: z.unknown().optional().describe("Called for raw WebSocket connections to /actors/{name}/websocket/* endpoints."),
+ actions: z.record(z.string(), z.unknown()).optional().describe("Map of action name to handler function."),
+ options: DocActorOptionsSchema.optional(),
+ })
+ .describe("Actor configuration passed to the actor() function.");
diff --git a/rivetkit-typescript/packages/rivetkit/src/registry/config/index.ts b/rivetkit-typescript/packages/rivetkit/src/registry/config/index.ts
index e79c606464..c495728f62 100644
--- a/rivetkit-typescript/packages/rivetkit/src/registry/config/index.ts
+++ b/rivetkit-typescript/packages/rivetkit/src/registry/config/index.ts
@@ -264,3 +264,71 @@ export function buildActorNames(
Object.keys(config.use).map((name) => [name, { metadata: {} }]),
);
}
+
+// MARK: Documentation Schemas
+// These schemas are JSON-serializable versions used for documentation generation.
+// They exclude runtime-only fields (transforms, custom types, Logger instances).
+
+export const DocInspectorConfigSchema = z
+ .object({
+ enabled: z.boolean().optional().describe("Whether to enable the Rivet Inspector. Defaults to true in development mode."),
+ token: z.string().optional().describe("Token used to access the Inspector."),
+ defaultEndpoint: z.string().optional().describe("Default RivetKit server endpoint for Rivet Inspector to connect to."),
+ })
+ .optional()
+ .describe("Inspector configuration for debugging and development.");
+
+export const DocConfigureRunnerPoolSchema = z
+ .object({
+ name: z.string().optional().describe("Name of the runner pool."),
+ url: z.string().describe("URL of the serverless platform to configure runners."),
+ headers: z.record(z.string(), z.string()).optional().describe("Headers to include in requests to the serverless platform."),
+ maxRunners: z.number().optional().describe("Maximum number of runners in the pool."),
+ minRunners: z.number().optional().describe("Minimum number of runners to keep warm."),
+ requestLifespan: z.number().optional().describe("Maximum lifespan of a request in milliseconds."),
+ runnersMargin: z.number().optional().describe("Buffer margin for scaling runners."),
+ slotsPerRunner: z.number().optional().describe("Number of actor slots per runner."),
+ metadata: z.record(z.string(), z.unknown()).optional().describe("Additional metadata to pass to the serverless platform."),
+ })
+ .optional();
+
+export const DocServerlessConfigSchema = z.object({
+ spawnEngine: z.boolean().optional().describe("Downloads and starts the full Rust engine process. Auto-enabled in development mode when no endpoint is provided. Default: false"),
+ engineVersion: z.string().optional().describe("Version of the engine to download. Defaults to the current RivetKit version."),
+ configureRunnerPool: DocConfigureRunnerPoolSchema.describe("Automatically configure serverless runners in the engine."),
+ basePath: z.string().optional().describe("Base path for serverless API routes. Default: '/api/rivet'"),
+ publicEndpoint: z.string().optional().describe("The endpoint that clients should connect to. Supports URL auth syntax: https://namespace:token@api.rivet.dev"),
+ publicToken: z.string().optional().describe("Token that clients should use when connecting via the public endpoint."),
+}).describe("Configuration for serverless deployment mode.");
+
+export const DocRunnerConfigSchema = z.object({
+ totalSlots: z.number().optional().describe("Total number of actor slots available. Default: 100000"),
+ runnerName: z.string().optional().describe("Name of this runner. Default: 'default'"),
+ runnerKey: z.string().optional().describe("Authentication key for the runner."),
+ version: z.number().optional().describe("Version number of this runner. Default: 1"),
+}).describe("Configuration for runner mode.");
+
+export const DocRegistryConfigSchema = z
+ .object({
+ use: z.record(z.string(), z.unknown()).describe("Actor definitions. Keys are actor names, values are actor definitions."),
+ maxIncomingMessageSize: z.number().optional().describe("Maximum size of incoming WebSocket messages in bytes. Default: 65536"),
+ maxOutgoingMessageSize: z.number().optional().describe("Maximum size of outgoing WebSocket messages in bytes. Default: 1048576"),
+ noWelcome: z.boolean().optional().describe("Disable the welcome message on startup. Default: false"),
+ logging: z
+ .object({
+ level: LogLevelSchema.optional().describe("Log level for RivetKit. Default: 'warn'"),
+ })
+ .optional()
+ .describe("Logging configuration."),
+ endpoint: z.string().optional().describe("Endpoint URL to connect to Rivet Engine. Supports URL auth syntax: https://namespace:token@api.rivet.dev. Can also be set via RIVET_ENDPOINT environment variable."),
+ token: z.string().optional().describe("Authentication token for Rivet Engine. Can also be set via RIVET_TOKEN environment variable."),
+ namespace: z.string().optional().describe("Namespace to use. Default: 'default'. Can also be set via RIVET_NAMESPACE environment variable."),
+ headers: z.record(z.string(), z.string()).optional().describe("Additional headers to include in requests to Rivet Engine."),
+ serveManager: z.boolean().optional().describe("Whether to start the local manager server. Auto-determined based on endpoint and NODE_ENV if not specified."),
+ managerBasePath: z.string().optional().describe("Base path for the manager API. Default: '/'"),
+ managerPort: z.number().optional().describe("Port to run the manager on. Default: 6420"),
+ inspector: DocInspectorConfigSchema,
+ serverless: DocServerlessConfigSchema.optional(),
+ runner: DocRunnerConfigSchema.optional(),
+ })
+ .describe("RivetKit registry configuration.");
diff --git a/rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts b/rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts
index 56e71a8be6..8544d31374 100644
--- a/rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts
+++ b/rivetkit-typescript/packages/rivetkit/src/utils/env-vars.ts
@@ -1,4 +1,7 @@
-// TODO: briefly document this file is used for consolidating all env vars that affect rivet's behavior
+// This file consolidates all environment variables that affect RivetKit's behavior.
+//
+// IMPORTANT: When adding or modifying environment variables here, also update the
+// documentation at: docs/general/registry-configuration.mdx
import { getEnvUniversal } from "@/utils";
diff --git a/rivetkit-typescript/packages/rivetkit/turbo.json b/rivetkit-typescript/packages/rivetkit/turbo.json
index 8f63714485..647a65b2de 100644
--- a/rivetkit-typescript/packages/rivetkit/turbo.json
+++ b/rivetkit-typescript/packages/rivetkit/turbo.json
@@ -2,7 +2,7 @@
"$schema": "https://turbo.build/schema.json",
"extends": ["//"],
"tasks": {
- "dump-openapi": {
+ "manager-openapi-gen": {
"inputs": [
"package.json",
"packages/rivetkit/src/manager/router.ts"
@@ -16,6 +16,24 @@
],
"dependsOn": ["build:schema"]
},
+ "registry-config-schema-gen": {
+ "inputs": [
+ "package.json",
+ "scripts/registry-config-schema-gen.ts",
+ "scripts/schema-utils.ts",
+ "src/registry/config/index.ts"
+ ],
+ "dependsOn": []
+ },
+ "actor-config-schema-gen": {
+ "inputs": [
+ "package.json",
+ "scripts/actor-config-schema-gen.ts",
+ "scripts/schema-utils.ts",
+ "src/actor/config.ts"
+ ],
+ "dependsOn": []
+ },
"build:schema": {
"dependsOn": ["^build"],
"inputs": ["schemas/**/*.bare", "scripts/compile-bare.ts"],
@@ -24,7 +42,7 @@
"build": {
"dependsOn": [
"^build",
- "dump-openapi",
+ "manager-openapi-gen",
"dump-asyncapi",
"build:schema"
],
diff --git a/website/astro.config.mjs b/website/astro.config.mjs
index 9172c722c5..a362237b21 100644
--- a/website/astro.config.mjs
+++ b/website/astro.config.mjs
@@ -44,5 +44,11 @@ export default defineConfig({
ssr: {
noExternal: ['@rivet-gg/components', '@rivet-gg/icons'],
},
+ server: {
+ fs: {
+ // Allow serving files from the monorepo root for artifacts
+ allow: ['..'],
+ },
+ },
},
});
diff --git a/website/src/components/FoldableSchema.tsx b/website/src/components/FoldableSchema.tsx
index 9755afe5be..b65282f358 100644
--- a/website/src/components/FoldableSchema.tsx
+++ b/website/src/components/FoldableSchema.tsx
@@ -1,6 +1,7 @@
"use client";
-import { Button } from "@rivet-gg/components";
+import { cn } from "@rivet-gg/components";
+import { Icon, faChevronDown } from "@rivet-gg/icons";
import { motion } from "framer-motion";
import { useState } from "react";
@@ -12,13 +13,27 @@ export function Foldable({
const [isOpen, setIsOpen] = useState(false);
return (
<>
-
+
+
+
+
-
- {title ?? schema.title}
-
-
-
- );
- }
return (
= {
+ ...(schema.properties as Record ?? {}),
+ };
+ const oneOfKeys: Set = new Set();
+ if (schema.oneOf) {
+ for (const variant of schema.oneOf as JSONSchema7[]) {
+ const resolved = resolveSchema(variant, defs);
+ if (resolved.properties) {
+ for (const [key, value] of Object.entries(resolved.properties)) {
+ allProperties[key] = value as JSONSchema7;
+ oneOfKeys.add(key);
+ }
+ }
+ }
+ }
+
return (
- {Object.entries(schema.properties ?? {}).map(([key, property]) => {
+ {Object.entries(allProperties).map(([key, property]) => {
const resolved = resolveSchema(property as JSONSchema7, defs);
- const nullable = !schema.required?.some((r) => r === key);
+ // Properties from oneOf are always optional, others check required array
+ const nullable = oneOfKeys.has(key) || !schema.required?.some((r) => r === key);
const newParent = parent ? `${parent}.${key}` : key;
return (
-
+
+ -
Any of the following variants:
-
+
{schema.anyOf?.map((ref: JSONSchema7, index) => {
return (
Variant #{index + 1}
@@ -159,7 +159,7 @@ function Schema({ schema: baseSchema, defs, parent, foldable }: SchemaProps) {
} as JSONSchema7;
const inner = (
-
+
{schema.oneOf.map((item: JSONSchema7, index) => {
return (
-
+
{schema.enum.map((item, index) => {
return (
-
@@ -372,12 +372,12 @@ export function PropertyLabel({
{parent ? <>{parent}.> : null}
{name}
-
+
{getPropertyTypeLabel(schema, defs, nullable)}
-
{schema.description || ""}
+
{schema.description || ""}
>
);
@@ -398,7 +398,7 @@ function TypeLabel({ type, description }: TypeLabelProps) {
-
{description || ""}
+
{description || ""}
>
);
@@ -497,6 +497,16 @@ function resolveSchema(
throw new Error("unsupported");
}
+ // Handle anyOf with $ref and null (nullable types)
+ if (schema.anyOf?.length) {
+ const refItem = schema.anyOf.find(
+ (item: JSONSchema7) => item.$ref,
+ ) as JSONSchema7 | undefined;
+ if (refItem) {
+ return resolveSchema(refItem, defs);
+ }
+ }
+
if (schema.$ref) {
const cleanRef = schema.$ref.replace(
/#\/(definitions|components\/schemas)\//,
diff --git a/website/src/components/docs/ActorConfigSchema.tsx b/website/src/components/docs/ActorConfigSchema.tsx
new file mode 100644
index 0000000000..e467da0bcc
--- /dev/null
+++ b/website/src/components/docs/ActorConfigSchema.tsx
@@ -0,0 +1,11 @@
+import { JsonSchemaPreview } from "@/components/JsonSchemaPreview";
+import actorConfigSchema from "../../../../rivetkit-typescript/artifacts/actor-config.json";
+
+export function ActorConfigSchema() {
+ return (
+ No properties
}
+ />
+ );
+}
diff --git a/website/src/components/docs/ActorConfigSchemaClient.astro b/website/src/components/docs/ActorConfigSchemaClient.astro
new file mode 100644
index 0000000000..f04537ecd3
--- /dev/null
+++ b/website/src/components/docs/ActorConfigSchemaClient.astro
@@ -0,0 +1,5 @@
+---
+import { ActorConfigSchema } from "./ActorConfigSchema";
+---
+
+
diff --git a/website/src/components/docs/EngineConfigSchema.tsx b/website/src/components/docs/EngineConfigSchema.tsx
new file mode 100644
index 0000000000..9888ebe0f1
--- /dev/null
+++ b/website/src/components/docs/EngineConfigSchema.tsx
@@ -0,0 +1,11 @@
+import { JsonSchemaPreview } from "@/components/JsonSchemaPreview";
+import engineConfigSchema from "../../../../engine/artifacts/config-schema.json";
+
+export function EngineConfigSchema() {
+ return (
+ No properties}
+ />
+ );
+}
diff --git a/website/src/components/docs/EngineConfigSchemaClient.astro b/website/src/components/docs/EngineConfigSchemaClient.astro
new file mode 100644
index 0000000000..80baacfec7
--- /dev/null
+++ b/website/src/components/docs/EngineConfigSchemaClient.astro
@@ -0,0 +1,5 @@
+---
+import { EngineConfigSchema } from "./EngineConfigSchema";
+---
+
+
diff --git a/website/src/components/docs/RegistryConfigSchema.tsx b/website/src/components/docs/RegistryConfigSchema.tsx
new file mode 100644
index 0000000000..49606582a9
--- /dev/null
+++ b/website/src/components/docs/RegistryConfigSchema.tsx
@@ -0,0 +1,11 @@
+import { JsonSchemaPreview } from "@/components/JsonSchemaPreview";
+import registryConfigSchema from "../../../../rivetkit-typescript/artifacts/registry-config.json";
+
+export function RegistryConfigSchema() {
+ return (
+ No properties}
+ />
+ );
+}
diff --git a/website/src/components/docs/RegistryConfigSchemaClient.astro b/website/src/components/docs/RegistryConfigSchemaClient.astro
new file mode 100644
index 0000000000..780a7102b1
--- /dev/null
+++ b/website/src/components/docs/RegistryConfigSchemaClient.astro
@@ -0,0 +1,5 @@
+---
+import { RegistryConfigSchema } from "./RegistryConfigSchema";
+---
+
+
diff --git a/website/src/components/marketing/cloud/ArchitectureSection.tsx b/website/src/components/marketing/cloud/ArchitectureSection.tsx
index 746bb52d4e..5c495481e1 100644
--- a/website/src/components/marketing/cloud/ArchitectureSection.tsx
+++ b/website/src/components/marketing/cloud/ArchitectureSection.tsx
@@ -94,7 +94,7 @@ export const ArchitectureSection = () => {
{/* CTA */}
-
Learn how to connect your backend
diff --git a/website/src/components/marketing/cloud/FeaturesGrid.tsx b/website/src/components/marketing/cloud/FeaturesGrid.tsx
index 82edfe240b..bbb3bebbb5 100644
--- a/website/src/components/marketing/cloud/FeaturesGrid.tsx
+++ b/website/src/components/marketing/cloud/FeaturesGrid.tsx
@@ -211,7 +211,7 @@ export const FeaturesGrid = () => {
>
),
faIcon: faLayerGroup,
- href: "/docs/connect/endpoints",
+ href: "/docs/general/endpoints",
useCases: ["Railway", "Vercel", "any platform"],
},
//{
diff --git a/website/src/content/docs/general/actor-configuration.mdx b/website/src/content/docs/general/actor-configuration.mdx
new file mode 100644
index 0000000000..9577e6a003
--- /dev/null
+++ b/website/src/content/docs/general/actor-configuration.mdx
@@ -0,0 +1,40 @@
+import ActorConfigSchema from "@/components/docs/ActorConfigSchemaClient.astro";
+
+# Actor Configuration
+
+This page documents the configuration options available when defining a RivetKit actor. The actor configuration is passed to the `actor()` function.
+
+## Basic Example
+
+```typescript
+import { actor } from "rivetkit";
+
+const myActor = actor({
+ state: { count: 0 },
+
+ actions: {
+ increment: (c) => {
+ c.state.count++;
+ return c.state.count;
+ },
+ },
+ options: {
+ actionTimeout: 15_000,
+ }
+});
+
+const registry = setup({
+ use: { myActor },
+});
+```
+
+## Configuration Reference
+
+
+
+## Related
+
+- [Registry Configuration](/docs/general/registry-configuration): Configure the RivetKit registry
+- [State](/docs/actors/state): Managing actor state
+- [Actions](/docs/actors/actions): Defining actor actions
+- [Lifecycle](/docs/actors/lifecycle): Actor lifecycle hooks
diff --git a/website/src/content/docs/connect/endpoints.mdx b/website/src/content/docs/general/endpoints.mdx
similarity index 94%
rename from website/src/content/docs/connect/endpoints.mdx
rename to website/src/content/docs/general/endpoints.mdx
index 7a3020c9d7..ae32eb37dd 100644
--- a/website/src/content/docs/connect/endpoints.mdx
+++ b/website/src/content/docs/general/endpoints.mdx
@@ -76,16 +76,16 @@ const registry = setup({
## Advanced
-### Configuring Namespace and Token
+### URL Auth Syntax
-You can configure namespace and token in two ways:
+Endpoint URLs support embedding namespace and token directly in the URL:
-**Embedded in URL** (recommended for simplicity):
```
https://namespace:token@host/path
```
-**Separate environment variables** (useful when credentials are managed independently):
+This is the recommended approach for simplicity. Alternatively, you can use separate environment variables:
+
```bash
RIVET_ENDPOINT=https://api.rivet.dev
RIVET_NAMESPACE=my-namespace
diff --git a/website/src/content/docs/connect/endpoints/endpoint-env-vars.png b/website/src/content/docs/general/endpoints/endpoint-env-vars.png
similarity index 100%
rename from website/src/content/docs/connect/endpoints/endpoint-env-vars.png
rename to website/src/content/docs/general/endpoints/endpoint-env-vars.png
diff --git a/website/src/content/docs/general/environment-variables.mdx b/website/src/content/docs/general/environment-variables.mdx
new file mode 100644
index 0000000000..f9e4e50543
--- /dev/null
+++ b/website/src/content/docs/general/environment-variables.mdx
@@ -0,0 +1,57 @@
+# Environment Variables
+
+This page documents all environment variables that configure RivetKit behavior.
+
+## Connection
+
+| Environment Variable | Description |
+|---------------------|-------------|
+| `RIVET_ENDPOINT` | Endpoint URL to connect to Rivet Engine. Supports [URL auth syntax](/docs/general/endpoints#url-auth-syntax). |
+| `RIVET_ENGINE` | Alternative to `RIVET_ENDPOINT` for engine connection |
+| `RIVET_TOKEN` | Authentication token for Rivet Engine |
+| `RIVET_NAMESPACE` | Namespace to use (default: "default") |
+
+## Public Endpoint
+
+These variables configure how clients connect to your actors.
+
+| Environment Variable | Description |
+|---------------------|-------------|
+| `RIVET_PUBLIC_ENDPOINT` | Public endpoint for client connections. Supports [URL auth syntax](/docs/general/endpoints#url-auth-syntax). |
+| `RIVET_PUBLIC_TOKEN` | Public token for client authentication |
+
+## Runner Configuration
+
+| Environment Variable | Description |
+|---------------------|-------------|
+| `RIVET_RUNNER` | Runner name (default: "default") |
+| `RIVET_RUNNER_KEY` | Authentication key for the runner |
+| `RIVET_RUNNER_VERSION` | Version number for the runner. See [Versions & Upgrades](/docs/actors/versions). |
+| `RIVET_RUNNER_KIND` | Type of runner |
+| `RIVET_TOTAL_SLOTS` | Total actor slots available (default: 100000) |
+
+## Engine
+
+| Environment Variable | Description |
+|---------------------|-------------|
+| `RIVET_RUN_ENGINE` | Set to `1` to spawn the engine process |
+| `RIVET_RUN_ENGINE_VERSION` | Version of engine to download |
+
+## Inspector
+
+| Environment Variable | Description |
+|---------------------|-------------|
+| `RIVET_INSPECTOR_TOKEN` | Token for accessing the Rivet Inspector |
+| `RIVET_INSPECTOR_DISABLE` | Set to `1` to disable the inspector |
+
+## Logging
+
+| Environment Variable | Description |
+|---------------------|-------------|
+| `RIVET_LOG_LEVEL` | Log level: `trace`, `debug`, `info`, `warn`, `error`, `fatal`, `silent` |
+| `RIVET_LOG_TARGET` | Set to `1` to include log target |
+| `RIVET_LOG_TIMESTAMP` | Set to `1` to include timestamps |
+| `RIVET_LOG_MESSAGE` | Set to `1` to include message formatting |
+| `RIVET_LOG_ERROR_STACK` | Set to `1` to include error stack traces |
+| `RIVET_LOG_HEADERS` | Set to `1` to log request headers |
+
diff --git a/website/src/content/docs/general/registry-configuration.mdx b/website/src/content/docs/general/registry-configuration.mdx
new file mode 100644
index 0000000000..17d17a5dfd
--- /dev/null
+++ b/website/src/content/docs/general/registry-configuration.mdx
@@ -0,0 +1,97 @@
+import RegistryConfigSchema from "@/components/docs/RegistryConfigSchemaClient.astro";
+
+# Registry Configuration
+
+This page documents the configuration options available when setting up a RivetKit registry. The registry configuration is passed to the `setup()` function.
+
+
+## Example Configurations
+
+### Basic Setup
+
+```typescript
+import { setup, actor } from "rivetkit";
+
+const myActor = actor({ /* ... */ });
+
+const registry = setup({
+ use: { myActor },
+});
+```
+
+### Connecting to Rivet Engine
+
+
+
+```typescript {{"title":"Environment Variables"}}
+import { setup, actor } from "rivetkit";
+
+const myActor = actor({ /* ... */ });
+
+// Reads from RIVET_ENDPOINT, RIVET_TOKEN, and RIVET_NAMESPACE
+const registry = setup({
+ use: { myActor },
+});
+```
+
+```typescript {{"title":"Config"}}
+import { setup, actor } from "rivetkit";
+
+const myActor = actor({ /* ... */ });
+
+const registry = setup({
+ use: { myActor },
+ endpoint: "https://api.rivet.dev",
+ token: process.env.RIVET_TOKEN,
+ namespace: "production",
+});
+```
+
+
+
+## Starting Your App
+
+After configuring your registry, start it using one of two runtime modes:
+
+
+
+```typescript {{"title":"Serverless"}}
+import { registry } from "./actors";
+
+export default registry.serve();
+```
+
+```typescript {{"title":"Serverless with Router"}}
+import { registry } from "./actors";
+import { Hono } from "hono";
+
+const app = new Hono();
+app.all("/api/rivet/*", (c) => registry.handler(c.req.raw));
+
+export default app;
+```
+
+```typescript {{"title":"Runner"}}
+import { registry } from "./actors";
+
+registry.startRunner();
+```
+
+
+
+See [Runtime Modes](/docs/general/runtime-modes) for details on when to use each mode.
+
+## Environment Variables
+
+Many configuration options can be set via environment variables. See [Environment Variables](/docs/general/environment-variables) for a complete reference.
+
+
+## Configuration Reference
+
+
+
+## Related
+
+- [Actor Configuration](/docs/general/actor-configuration)- Configure individual actors
+- [HTTP Server Setup](/docs/general/http-server): Set up HTTP routing and middleware
+- [Architecture](/docs/general/architecture): Understand how RivetKit works
diff --git a/website/src/content/docs/self-hosting/configuration.mdx b/website/src/content/docs/self-hosting/configuration.mdx
index b886b425cf..e5ca0efe2c 100644
--- a/website/src/content/docs/self-hosting/configuration.mdx
+++ b/website/src/content/docs/self-hosting/configuration.mdx
@@ -1,8 +1,14 @@
+import EngineConfigSchema from "@/components/docs/EngineConfigSchemaClient.astro";
+
# Configuration
Rivet Engine can be configured through environment variables or configuration files.
-## Configuration
+
+The full JSON Schema for the configuration is available at [/docs/engine-config-schema.json](/docs/engine-config-schema.json).
+
+
+## Configuration Sources
Rivet supports JSON, JSON5, JSONC, YAML, YML, and environment variable configurations.
@@ -38,365 +44,12 @@ rivet-engine --config /etc/rivet/base.json --config /etc/rivet/override.json
```
-## Definition
-
-```typescript
-interface RivetConfig {
- // Authentication configuration
- auth?: {
- admin_token: string;
- };
-
- // HTTP/HTTPS traffic handling service
- guard?: {
- host?: string; // Default: "::" (IPv6 unspecified)
- port?: number; // Default: 6420
- https?: {
- port: number;
- tls: {
- actor_cert_path: string;
- actor_key_path: string;
- api_cert_path: string;
- api_key_path: string;
- };
- };
- };
-
- // Public API service configuration
- api_public?: {
- verbose_errors?: boolean; // Default: true
- respect_forwarded_for?: boolean; // Default: false
- };
-
- // Private API service configuration
- api_peer?: {
- host?: string; // Default: "::" (IPv6 unspecified)
- port?: number; // Default: 6421
- };
-
- // Actor orchestration configuration (experimental)
- pegboard?: {
- base_retry_timeout?: number; // Default: 2000 (ms)
- actor_start_threshold?: number; // Default: 30000 (ms)
- actor_stop_threshold?: number; // Default: 30000 (ms)
- retry_reset_duration?: number; // Default: 600000 (ms)
- reschedule_backoff_max_exponent?: number; // Default: 8
- runner_eligible_threshold?: number; // Default: 10000 (ms)
- runner_lost_threshold?: number; // Default: 15000 (ms)
- hibernating_request_eligible_threshold?: number; // Default: 90000 (ms)
- serverless_base_retry_timeout?: number; // Default: 2000 (ms)
- serverless_retry_reset_duration?: number; // Default: 600000 (ms)
- serverless_backoff_max_exponent?: number; // Default: 8
- pool_desired_max_override?: number;
- };
-
- // Logging configuration
- logs?: {
- redirect_logs_dir?: string; // Directory for log file redirection
- };
-
- // Multi-datacenter topology
- topology?: {
- datacenter_label: number; // Default: 1
- datacenters: Array<{
- name: string; // Default: "default"
- datacenter_label: number; // Default: 1
- is_leader: boolean; // Default: true
- public_url: string; // Default: "http://127.0.0.1:6420"
- peer_url: string; // Default: "http://127.0.0.1:6421"
- proxy_url?: string;
- valid_hosts?: string[]; // Required when multiple datacenters configured
- }>;
- };
-
- // Database backend configuration
- database?:
- | {
- postgres: {
- url: string; // Default: "postgresql://postgres:postgres@127.0.0.1:5432/postgres"
- // Supports standard PostgreSQL connection parameters
- // See SSL Configuration section below for details
- unstable_disable_lock_customization?: boolean; // Default: false
- // UNSTABLE: Required for some hosted platforms
- // See Postgres Configuration section below
- ssl?: {
- root_cert_path?: string;
- client_cert_path?: string;
- client_key_path?: string;
- };
- };
- }
- | {
- file_system: {
- path: string; // Default: "~/.local/share/rivet-engine/db" or "./data/db"
- };
- };
-
- // Message pub/sub system
- pubsub?:
- | {
- nats: {
- addresses: string[]; // Default: ["127.0.0.1:4222"]
- port?: number; // Default: 4222
- username?: string;
- password?: string;
- };
- }
- | {
- postgres_notify: {
- url: string; // Default: "postgresql://postgres:postgres@127.0.0.1:5432/postgres"
- memory_optimization?: boolean; // Default: true
- ssl?: {
- root_cert_path?: string;
- client_cert_path?: string;
- client_key_path?: string;
- };
- };
- }
- | {
- memory: {
- channel: string; // Default: "default"
- };
- };
-
- // Caching layer configuration
- cache?: {
- driver: "redis" | "in_memory"; // Default: "in_memory"
- };
-
- // ClickHouse analytics database (optional)
- clickhouse?: {
- http_url: string;
- native_url: string;
- username: string;
- password?: string;
- secure?: boolean; // Default: false
- provision_users?: {
- [key: string]: {
- username: string;
- password: string;
- role: "Admin" | "Write" | "ReadOnly";
- };
- };
- };
-
- // Vector HTTP endpoint (optional)
- vector_http?: {
- host: string; // Default: "127.0.0.1"
- port: number; // Default: 5022
- };
-
- // Telemetry configuration
- telemetry?: {
- enabled: boolean; // Default: true (opt-out)
- };
-
- // Runtime configuration
- runtime?: {
- worker_cpu_max?: number; // Worker CPU limit in millicores (1000 = 1 core)
- worker_shutdown_duration?: number; // Default: 30 (seconds)
- guard_shutdown_duration?: number; // Default: 3600 (seconds)
- allow_version_rollback?: boolean; // Default: false
- };
-}
-```
-
-## PostgreSQL Configuration
-
-### Managed Postgres Compatibility
-
-Some hosted PostgreSQL platforms require additional configuration due to platform-specific restrictions.
-
-
-
+## Configuration Reference
-Use direct connection (not connection pooler).
+
-
-
-```json {{"title":"Configuration file"}}
-{
- "database": {
- "postgres": {
- "url": "postgresql://pscale_api_.:@.pg.psdb.cloud:5432/postgres?sslmode=require",
- "unstable_disable_lock_customization": true
- }
- }
-}
-```
-
-```bash {{"title":"Environment variables"}}
-RIVET__database__postgres__url="postgresql://pscale_api_.:@.pg.psdb.cloud:5432/postgres?sslmode=require"
-RIVET__database__postgres__unstable_disable_lock_customization=true
-```
-
-
-
-
-For better performance, set `deadlock_timeout = 10ms` in the PlanetScale dashboard at **Clusters** → **Parameters** → **Query Tuning**.
-
-
-
-
-
-Use direct connection on port `5432` (not connection pooler).
-
-#### Without SSL
-
-
-
-```json {{"title":"Configuration file"}}
-{
- "database": {
- "postgres": {
- "url": "postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=disable",
- "unstable_disable_lock_customization": true
- }
- }
-}
-```
-
-```bash {{"title":"Environment variables"}}
-RIVET__database__postgres__url="postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=disable"
-RIVET__database__postgres__unstable_disable_lock_customization=true
-```
-
-
-
-#### With SSL
-
-Download the root certificate from your Supabase dashboard and specify its path. See [Supabase SSL Enforcement](https://supabase.com/docs/guides/platform/ssl-enforcement) for details.
-
-
-
-```json {{"title":"Configuration file"}}
-{
- "database": {
- "postgres": {
- "url": "postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=require",
- "unstable_disable_lock_customization": true,
- "ssl": {
- "root_cert_path": "/path/to/supabase-ca.crt"
- }
- }
- }
-}
-```
-
-```bash {{"title":"Environment variables"}}
-RIVET__database__postgres__url="postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=require"
-RIVET__database__postgres__unstable_disable_lock_customization=true
-RIVET__database__postgres__ssl__root_cert_path="/path/to/supabase-ca.crt"
-```
-
-
-
-
-
-
-
-### SSL/TLS Support
-
-To enable SSL for Postgres, add `sslmode=require` to your PostgreSQL connection URL:
-
-
-
-```json {{"title":"Configuration file"}}
-{
- "database": {
- "postgres": {
- "url": "postgresql://user:password@host.example.com:5432/database?sslmode=require"
- }
- }
-}
-```
-
-```bash {{"title":"Environment variables"}}
-RIVET__database__postgres__url="postgresql://user:password@host.example.com:5432/database?sslmode=require"
-```
-
-
-
-The `sslmode` parameter controls TLS usage:
-
-- `disable`: Do not use TLS
-- `prefer`: Use TLS if available, otherwise connect without TLS (default)
-- `require`: Require TLS connection (fails if TLS is not available)
-
-To verify the server certificate against a CA or verify the hostname, use custom SSL certificates (see below).
-
-#### Custom SSL Certificates
-
-For databases using custom certificate authorities (e.g., Supabase) or requiring client certificate authentication, you can specify certificate paths in the configuration:
-
-
-
-```json {{"title":"Configuration file"}}
-{
- "database": {
- "postgres": {
- "url": "postgresql://user:password@host:5432/database?sslmode=require",
- "ssl": {
- "root_cert_path": "/path/to/root-ca.crt",
- "client_cert_path": "/path/to/client.crt",
- "client_key_path": "/path/to/client.key"
- }
- }
- }
-}
-```
-
-```bash {{"title":"Environment variables"}}
-RIVET__database__postgres__url="postgresql://user:password@host:5432/database?sslmode=require"
-RIVET__database__postgres__ssl__root_cert_path="/path/to/root-ca.crt"
-RIVET__database__postgres__ssl__client_cert_path="/path/to/client.crt"
-RIVET__database__postgres__ssl__client_key_path="/path/to/client.key"
-```
-
-
-
-| Parameter | Description | PostgreSQL Equivalent |
-|-----------|-------------|----------------------|
-| `root_cert_path` | Path to the root certificate file for verifying the server's certificate | `sslrootcert` |
-| `client_cert_path` | Path to the client certificate file for client certificate authentication | `sslcert` |
-| `client_key_path` | Path to the client private key file for client certificate authentication | `sslkey` |
-
-All SSL paths are optional. If not specified, Rivet uses the default system root certificates from Mozilla's root certificate store.
-
-### Do Not Use Connection Poolers
-
-Rivet requires direct PostgreSQL connections for session-level features and does not support connection poolers.
-
-Do not use:
-
-- PgBouncer
-- Supavisor
-- AWS RDS Proxy
-
-
-### Troubleshooting
-
-#### Permission Denied Errors
-
-If you see errors like:
-
-```
-ERROR: permission denied to set parameter "deadlock_timeout"
-ERROR: current transaction is aborted, commands ignored until end of transaction block
-```
-
-Add `unstable_disable_lock_customization: true` to your configuration:
-
-```json
-{
- "database": {
- "postgres": {
- "url": "postgresql://...",
- "unstable_disable_lock_customization": true
- }
- }
-}
-```
+## Related
-This disables Rivet's attempt to set `lock_timeout = 0` and `deadlock_timeout = 10ms`. Since `lock_timeout` defaults to `0` in PostgreSQL, skipping these settings is safe. Deadlock detection will use the default `1s` timeout instead of `10ms`.
+- [PostgreSQL](/docs/self-hosting/postgres): Configure PostgreSQL for production
+- [File System](/docs/self-hosting/filesystem): Configure file system storage for development
diff --git a/website/src/content/docs/self-hosting/filesystem.mdx b/website/src/content/docs/self-hosting/filesystem.mdx
new file mode 100644
index 0000000000..147c7ff292
--- /dev/null
+++ b/website/src/content/docs/self-hosting/filesystem.mdx
@@ -0,0 +1,48 @@
+# File System
+
+The file system backend stores all data on the local disk. This is suitable for single-node deployments, development, and testing.
+
+
+The file system backend does not support multi-node deployments. Use [PostgreSQL](/docs/self-hosting/postgres) for production.
+
+
+## Configuration
+
+
+
+```json {{"title":"Configuration file"}}
+{
+ "database": {
+ "file_system": {
+ "path": "/var/lib/rivet/data"
+ }
+ }
+}
+```
+
+```bash {{"title":"Environment variables"}}
+RIVET__database__file_system__path="/var/lib/rivet/data"
+```
+
+
+
+## Default Paths
+
+If no path is specified, Rivet uses platform-specific default locations:
+
+- Linux: `~/.local/share/rivet-engine/db`
+- macOS: `~/Library/Application Support/rivet-engine/db`
+- Windows: `%APPDATA%\rivet-engine\db`
+
+When running in a container or as a service, the path defaults to `./data/db` relative to the working directory.
+
+## When to Use File System
+
+The file system backend is ideal for:
+
+- Local development
+- Single-node deployments
+- Testing and prototyping
+- Air-gapped environments without database infrastructure
+
+For production deployments with multiple nodes or high availability requirements, use [PostgreSQL](/docs/self-hosting/postgres) instead.
diff --git a/website/src/content/docs/self-hosting/index.mdx b/website/src/content/docs/self-hosting/index.mdx
index 7bbe1477c5..03f8736582 100644
--- a/website/src/content/docs/self-hosting/index.mdx
+++ b/website/src/content/docs/self-hosting/index.mdx
@@ -59,6 +59,6 @@ _Self-hosting guides coming soon._
## Next Steps
- [Install Rivet Engine](/docs/self-hosting/install)
-- [Connect your backend](/docs/connect/endpoints)
+- [Connect your backend](/docs/general/endpoints)
- [Configure your deployment](/docs/self-hosting/configuration)
- [Multi-region setup](/docs/self-hosting/multi-region)
diff --git a/website/src/content/docs/self-hosting/postgres.mdx b/website/src/content/docs/self-hosting/postgres.mdx
new file mode 100644
index 0000000000..626c0340dc
--- /dev/null
+++ b/website/src/content/docs/self-hosting/postgres.mdx
@@ -0,0 +1,220 @@
+# PostgreSQL
+
+PostgreSQL is the recommended database backend for production deployments.
+
+## Basic Configuration
+
+
+
+```json {{"title":"Configuration file"}}
+{
+ "database": {
+ "postgres": {
+ "url": "postgresql://user:password@host:5432/database"
+ }
+ }
+}
+```
+
+```bash {{"title":"Environment variables"}}
+RIVET__database__postgres__url="postgresql://user:password@host:5432/database"
+```
+
+
+
+## Managed Postgres Compatibility
+
+Some hosted PostgreSQL platforms require additional configuration due to platform-specific restrictions.
+
+
+
+
+Use direct connection (not connection pooler).
+
+
+
+```json {{"title":"Configuration file"}}
+{
+ "database": {
+ "postgres": {
+ "url": "postgresql://pscale_api_.:@.pg.psdb.cloud:5432/postgres?sslmode=require",
+ "unstable_disable_lock_customization": true
+ }
+ }
+}
+```
+
+```bash {{"title":"Environment variables"}}
+RIVET__database__postgres__url="postgresql://pscale_api_.:@.pg.psdb.cloud:5432/postgres?sslmode=require"
+RIVET__database__postgres__unstable_disable_lock_customization=true
+```
+
+
+
+
+For better performance, set `deadlock_timeout = 10ms` in the PlanetScale dashboard at **Clusters** → **Parameters** → **Query Tuning**.
+
+
+
+
+
+Use direct connection on port `5432` (not connection pooler).
+
+#### Without SSL
+
+
+
+```json {{"title":"Configuration file"}}
+{
+ "database": {
+ "postgres": {
+ "url": "postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=disable",
+ "unstable_disable_lock_customization": true
+ }
+ }
+}
+```
+
+```bash {{"title":"Environment variables"}}
+RIVET__database__postgres__url="postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=disable"
+RIVET__database__postgres__unstable_disable_lock_customization=true
+```
+
+
+
+#### With SSL
+
+Download the root certificate from your Supabase dashboard and specify its path. See [Supabase SSL Enforcement](https://supabase.com/docs/guides/platform/ssl-enforcement) for details.
+
+
+
+```json {{"title":"Configuration file"}}
+{
+ "database": {
+ "postgres": {
+ "url": "postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=require",
+ "unstable_disable_lock_customization": true,
+ "ssl": {
+ "root_cert_path": "/path/to/supabase-ca.crt"
+ }
+ }
+ }
+}
+```
+
+```bash {{"title":"Environment variables"}}
+RIVET__database__postgres__url="postgresql://postgres:@db..supabase.co:5432/postgres?sslmode=require"
+RIVET__database__postgres__unstable_disable_lock_customization=true
+RIVET__database__postgres__ssl__root_cert_path="/path/to/supabase-ca.crt"
+```
+
+
+
+
+
+
+
+## SSL/TLS Support
+
+To enable SSL for Postgres, add `sslmode=require` to your PostgreSQL connection URL:
+
+
+
+```json {{"title":"Configuration file"}}
+{
+ "database": {
+ "postgres": {
+ "url": "postgresql://user:password@host.example.com:5432/database?sslmode=require"
+ }
+ }
+}
+```
+
+```bash {{"title":"Environment variables"}}
+RIVET__database__postgres__url="postgresql://user:password@host.example.com:5432/database?sslmode=require"
+```
+
+
+
+The `sslmode` parameter controls TLS usage:
+
+- `disable`: Do not use TLS
+- `prefer`: Use TLS if available, otherwise connect without TLS (default)
+- `require`: Require TLS connection (fails if TLS is not available)
+
+To verify the server certificate against a CA or verify the hostname, use custom SSL certificates (see below).
+
+### Custom SSL Certificates
+
+For databases using custom certificate authorities (e.g., Supabase) or requiring client certificate authentication, you can specify certificate paths in the configuration:
+
+
+
+```json {{"title":"Configuration file"}}
+{
+ "database": {
+ "postgres": {
+ "url": "postgresql://user:password@host:5432/database?sslmode=require",
+ "ssl": {
+ "root_cert_path": "/path/to/root-ca.crt",
+ "client_cert_path": "/path/to/client.crt",
+ "client_key_path": "/path/to/client.key"
+ }
+ }
+ }
+}
+```
+
+```bash {{"title":"Environment variables"}}
+RIVET__database__postgres__url="postgresql://user:password@host:5432/database?sslmode=require"
+RIVET__database__postgres__ssl__root_cert_path="/path/to/root-ca.crt"
+RIVET__database__postgres__ssl__client_cert_path="/path/to/client.crt"
+RIVET__database__postgres__ssl__client_key_path="/path/to/client.key"
+```
+
+
+
+| Parameter | Description | PostgreSQL Equivalent |
+|-----------|-------------|----------------------|
+| `root_cert_path` | Path to the root certificate file for verifying the server's certificate | `sslrootcert` |
+| `client_cert_path` | Path to the client certificate file for client certificate authentication | `sslcert` |
+| `client_key_path` | Path to the client private key file for client certificate authentication | `sslkey` |
+
+All SSL paths are optional. If not specified, Rivet uses the default system root certificates from Mozilla's root certificate store.
+
+## Do Not Use Connection Poolers
+
+Rivet requires direct PostgreSQL connections for session-level features and does not support connection poolers.
+
+Do not use:
+
+- PgBouncer
+- Supavisor
+- AWS RDS Proxy
+
+
+## Troubleshooting
+
+### Permission Denied Errors
+
+If you see errors like:
+
+```
+ERROR: permission denied to set parameter "deadlock_timeout"
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+```
+
+Add `unstable_disable_lock_customization: true` to your configuration:
+
+```json
+{
+ "database": {
+ "postgres": {
+ "url": "postgresql://...",
+ "unstable_disable_lock_customization": true
+ }
+ }
+}
+```
+
+This disables Rivet's attempt to set `lock_timeout = 0` and `deadlock_timeout = 10ms`. Since `lock_timeout` defaults to `0` in PostgreSQL, skipping these settings is safe. Deadlock detection will use the default `1s` timeout instead of `10ms`.
diff --git a/website/src/pages/docs/[...slug].astro b/website/src/pages/docs/[...slug].astro
index 6d41fe2a31..509aef27c4 100644
--- a/website/src/pages/docs/[...slug].astro
+++ b/website/src/pages/docs/[...slug].astro
@@ -106,7 +106,8 @@ const componentSourcePath = `docs/${entry.id}.mdx`;
)}
-
+ {/* Comments intentionally disabled for now */}
+ {/* */}
{tableOfContents.length > 0 && (