From fe63ee7ccdd2821c1c1a77ddb0020517f488ca7c Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Wed, 14 Jan 2026 14:22:37 -0800 Subject: [PATCH] doc: auto-generate docs for engine config and registry config --- Cargo.lock | 18 +- Cargo.toml | 6 +- engine/artifacts/config-schema.json | 865 ++++++++++++++++++ engine/artifacts/openapi.json | 21 +- .../Cargo.toml | 2 +- .../build.rs | 0 .../src/lib.rs | 0 engine/packages/config-schema-gen/Cargo.toml | 11 + engine/packages/config-schema-gen/build.rs | 26 + engine/packages/config-schema-gen/src/lib.rs | 2 + rivetkit-json-schema/registry-config.json | 210 +++++ .../artifacts/actor-config.json | 129 +++ .../artifacts/registry-config.json | 210 +++++ .../packages/rivetkit/package.json | 6 +- .../scripts/actor-config-schema-gen.ts | 32 + ...dump-openapi.ts => manager-openapi-gen.ts} | 0 .../scripts/registry-config-schema-gen.ts | 32 + .../packages/rivetkit/src/actor/config.ts | 47 + .../rivetkit/src/registry/config/index.ts | 68 ++ .../packages/rivetkit/src/utils/env-vars.ts | 5 +- .../packages/rivetkit/turbo.json | 22 +- website/astro.config.mjs | 6 + website/src/components/FoldableSchema.tsx | 25 +- website/src/components/JsonSchemaPreview.tsx | 70 +- .../src/components/docs/ActorConfigSchema.tsx | 11 + .../docs/ActorConfigSchemaClient.astro | 5 + .../components/docs/EngineConfigSchema.tsx | 11 + .../docs/EngineConfigSchemaClient.astro | 5 + .../components/docs/RegistryConfigSchema.tsx | 11 + .../docs/RegistryConfigSchemaClient.astro | 5 + .../marketing/cloud/ArchitectureSection.tsx | 2 +- .../marketing/cloud/FeaturesGrid.tsx | 2 +- .../docs/general/actor-configuration.mdx | 40 + .../docs/{connect => general}/endpoints.mdx | 8 +- .../endpoints/endpoint-env-vars.png | Bin .../docs/general/environment-variables.mdx | 57 ++ .../docs/general/registry-configuration.mdx | 97 ++ .../docs/self-hosting/configuration.mdx | 371 +------- .../content/docs/self-hosting/filesystem.mdx | 48 + .../src/content/docs/self-hosting/index.mdx | 2 +- .../content/docs/self-hosting/postgres.mdx | 220 +++++ website/src/pages/docs/[...slug].astro | 3 +- website/src/sitemap/mod.ts | 111 ++- 43 files changed, 2350 insertions(+), 472 deletions(-) create mode 100644 engine/artifacts/config-schema.json rename engine/packages/{dump-openapi => api-public-openapi-gen}/Cargo.toml (85%) rename engine/packages/{dump-openapi => api-public-openapi-gen}/build.rs (100%) rename engine/packages/{dump-openapi => api-public-openapi-gen}/src/lib.rs (100%) create mode 100644 engine/packages/config-schema-gen/Cargo.toml create mode 100644 engine/packages/config-schema-gen/build.rs create mode 100644 engine/packages/config-schema-gen/src/lib.rs create mode 100644 rivetkit-json-schema/registry-config.json create mode 100644 rivetkit-typescript/artifacts/actor-config.json create mode 100644 rivetkit-typescript/artifacts/registry-config.json create mode 100644 rivetkit-typescript/packages/rivetkit/scripts/actor-config-schema-gen.ts rename rivetkit-typescript/packages/rivetkit/scripts/{dump-openapi.ts => manager-openapi-gen.ts} (100%) create mode 100644 rivetkit-typescript/packages/rivetkit/scripts/registry-config-schema-gen.ts create mode 100644 website/src/components/docs/ActorConfigSchema.tsx create mode 100644 website/src/components/docs/ActorConfigSchemaClient.astro create mode 100644 website/src/components/docs/EngineConfigSchema.tsx create mode 100644 website/src/components/docs/EngineConfigSchemaClient.astro create mode 100644 website/src/components/docs/RegistryConfigSchema.tsx create mode 100644 website/src/components/docs/RegistryConfigSchemaClient.astro create mode 100644 website/src/content/docs/general/actor-configuration.mdx rename website/src/content/docs/{connect => general}/endpoints.mdx (94%) rename website/src/content/docs/{connect => general}/endpoints/endpoint-env-vars.png (100%) create mode 100644 website/src/content/docs/general/environment-variables.mdx create mode 100644 website/src/content/docs/general/registry-configuration.mdx create mode 100644 website/src/content/docs/self-hosting/filesystem.mdx create mode 100644 website/src/content/docs/self-hosting/postgres.mdx 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 (