Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ These variables configure how clients connect to your actors.
| `RIVET_RUN_ENGINE_HOST` | Host to bind the spawned local engine process to. Defaults to `127.0.0.1`. |
| `RIVET_RUN_ENGINE_PORT` | Port to bind the spawned local engine process to. Defaults to `6420`. |
| `RIVET_RUN_ENGINE_VERSION` | Version of engine to download |
| `RIVET_RUN_SERVICES` | Set to `1` to run Services with a local Engine, or `0` to disable it. By default, Services follows RivetKit's local-Engine decision. |
| `RIVET_SERVICES_BINARY` | Path to a local `rivet-services` binary. |

## Inspector

Expand Down
14 changes: 5 additions & 9 deletions vendor/actors/docs/content/docs/limits.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,9 @@ These limits affect actions that do not use `.connect()` and [low-level HTTP req
| Name | Soft Limit | Hard Limit | Description |
|------|------------|------------|-------------|
| Max request body size | — | 20 MiB | Maximum size of HTTP request bodies. |
| Max response body size | — | 20 MiB | Maximum size of HTTP response bodies. |
| Request timeout | 60 seconds | — | Maximum time for an `onRequest` handler to complete. Defaults to `actionTimeout`; configure with `actionTimeout`. |

### Actions

| Name | Soft Limit | Hard Limit | Description |
|------|------------|------------|-------------|
| Max actions per actor | 128 | None | Maximum number of action handlers defined on one actor. Nested action groups count each leaf handler. Configurable via `maxActions`. |
| Max buffered response body size | — | 20 MiB | Maximum size of a non-streaming HTTP response. Streaming responses may transfer more than 20 MiB over their lifetime and are flow controlled instead of buffered in full. |
| Response start timeout | — | 5 minutes by default | Maximum time for `onRequest` to return response headers. It does not limit the lifetime of a response stream after the headers arrive. Self-hosted operators can configure `pegboard.gateway_response_start_timeout_ms`. |
| Streaming response idle timeout | — | None by default | Rivet does not close an otherwise healthy stream because no body chunk was produced. Other proxies and hosting platforms may impose their own idle timeouts, so SSE handlers should send periodic comment heartbeats. |

### Networking

Expand Down Expand Up @@ -145,7 +140,8 @@ See [Actor Input](/actors/docs/input) for details.
| Name | Soft Limit | Hard Limit | Description |
|------|------------|------------|-------------|
| Action timeout | 60 seconds | — | Timeout for RPC actions. Configurable via `actionTimeout`. |
| On request timeout | 60 seconds | — | Timeout for raw `onRequest` handlers. Defaults to `actionTimeout`; configure with `actionTimeout`. |
| Raw HTTP response start timeout | — | 5 minutes by default | Time allowed for a raw `onRequest` handler to return response headers. `actionTimeout` does not apply to raw HTTP handlers, and a streaming response has no fixed total-duration timeout after it starts. Self-hosted operators can configure `pegboard.gateway_response_start_timeout_ms`. |
| Raw HTTP stream idle timeout | — | None by default | Time allowed between response chunks. Self-hosted operators can configure `pegboard.gateway_response_chunk_idle_timeout_ms`; send SSE heartbeats more frequently than that value when enabled. |
| On before connect timeout | 5 seconds | — | Timeout for the `onBeforeConnect` hook. Configurable via `onBeforeConnectTimeout`. |
| Create vars timeout | 5 seconds | — | Timeout for `createVars` hook. Configurable via `createVarsTimeout`. |
| Create conn state timeout | 5 seconds | — | Timeout for `createConnState` hook. Configurable via `createConnStateTimeout`. |
Expand Down
12 changes: 11 additions & 1 deletion vendor/actors/docs/content/docs/request-handler.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ The `onRequest` handler processes HTTP requests sent to your actor. It receives

See also the [raw fetch handler example](https://github.com/rivet-dev/rivet/tree/main/examples/raw-fetch-handler).

## Streaming Responses & Server-Sent Events

Return a `Response` with a `ReadableStream` body to stream data as it becomes available. For server-sent events (SSE), set `Content-Type` to `text/event-stream` and format each event as one or more fields followed by a blank line.

<CodeGroup>
<CodeSnippet file="examples/docs/actors-request-handler/sse.ts" title="actor.ts" />
<CodeSnippet file="examples/docs/actors-request-handler/sse-client.ts" title="client.ts" />
</CodeGroup>

Rivet keeps the actor and request lifecycle active until the response stream closes, errors, or the client disconnects. The request's `AbortSignal` is aborted when the downstream client disconnects, so stop producers and release request-scoped resources when `request.signal` fires. Also implement the stream's `cancel()` callback for cleanup.

## Sending Requests To Actors

### Via RivetKit Client
Expand Down Expand Up @@ -87,7 +98,6 @@ The `onRequest` handler is WinterTC compliant and will work with existing librar

## Limitations

- Does not support streaming responses & server-sent events at the moment. See the [tracking issue](https://github.com/rivet-dev/rivet/issues/3529).
- `OPTIONS` requests currently are handled by Rivet and are not passed to `onRequest`

## Advanced
Expand Down
121 changes: 121 additions & 0 deletions vendor/actors/docs/content/integrations/durable-streams.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
title: "Durable Streams"
description: "Run the Durable Streams protocol locally and deploy it with Rivet."
---

[Durable Streams](https://github.com/durable-streams/durable-streams) is an open standard for real-time streams with durable, replayable history. Rivet provides an implementation backed by Rivet Actors.

## Quickstart

<Steps>

<Step title="Run locally">

<Tabs>

<Tab title="Standalone">

Start the local Rivet control plane and the Durable Streams worker:

```sh
npx @rivet-dev/services dev
```

Durable Streams is available at `http://127.0.0.1:8642/durable-streams/v1/stream/<path>`.

</Tab>

<Tab title="RivetKit TypeScript SDK">

Already running Rivet Actors with the RivetKit TypeScript SDK? Durable Streams is already available to you on RivetKit 2.3.12. No separate server needed.

</Tab>

</Tabs>

</Step>

<Step title="Connect to a stream">

<Tabs>

<Tab title="TypeScript client">

Install the official client:

```sh
npm install @durable-streams/client
```

<CodeSnippet file="examples/docs/actors-integrations-durable-streams/client.ts" title="client.ts" />

</Tab>

<Tab title="HTTP">

Create a stream, append a record, and read its contents:

```sh
curl -i -X PUT \
-H 'content-type: application/json' \
--data '[{"message":"hello"}]' \
http://127.0.0.1:8642/durable-streams/v1/stream/demo

curl -i -X POST \
-H 'content-type: application/json' \
--data '{"message":"world"}' \
http://127.0.0.1:8642/durable-streams/v1/stream/demo

curl 'http://127.0.0.1:8642/durable-streams/v1/stream/demo?offset=-1'
```

</Tab>

</Tabs>

</Step>

<Step title="Deploy">

<Tabs>

<Tab title="Rivet Cloud">

1. Sign up at the [Rivet dashboard](https://dashboard.rivet.dev) and create a new project.
2. When creating the project, choose Durable Streams as the product.
3. Point your Durable Streams client at the services URL you're given, for example `https://xxxxx.rivet.run/durable-streams/`.

</Tab>

<Tab title="Self-hosted">

Run the Rivet control plane with the required feature flags enabled:

```sh
docker run -p 6420:6420 \
-e RIVET__FEATURES__GUARD_GATEWAY_V3__MODE=on \
-e RIVET__FEATURES__GUARD_GATEWAY_V3__PERCENTAGE=100 \
rivetdev/engine
```

See the [self-hosting guides](/actors/self-host/) for other ways to run it.

Run the Durable Streams worker. It runs your streams and connects to the control plane:

```sh
docker run -p 8642:8642 \
--add-host=host.docker.internal:host-gateway \
-e RIVET_ENDPOINT=http://host.docker.internal:6420 \
-e HOST=0.0.0.0 \
rivetdev/services
```

Your streams are at `http://<host>:8642/durable-streams/v1/stream/<path>`.

</Tab>

</Tabs>

</Step>

</Steps>
4 changes: 4 additions & 0 deletions vendor/actors/docs/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,10 @@
{
"title": "Integrations",
"pages": [
{
"title": "Durable Streams",
"href": "/actors/integrations/durable-streams"
},
{
"title": "Flue",
"href": "/actors/integrations/flue"
Expand Down
94 changes: 94 additions & 0 deletions vendor/actors/engine/artifacts/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@
}
]
},
"features": {
"default": null,
"anyOf": [
{
"$ref": "#/definitions/Features"
},
{
"type": "null"
}
]
},
"guard": {
"default": null,
"anyOf": [
Expand Down Expand Up @@ -465,6 +476,24 @@
}
]
},
"Features": {
"type": "object",
"properties": {
"guard_gateway_v3": {
"description": "Controls routing to the streaming Guard Gateway V3 implementation.",
"default": null,
"anyOf": [
{
"$ref": "#/definitions/GuardGatewayV3"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"FileSystem": {
"type": "object",
"required": [
Expand Down Expand Up @@ -675,6 +704,35 @@
},
"additionalProperties": false
},
"GuardGatewayV3": {
"type": "object",
"properties": {
"mode": {
"default": "off",
"allOf": [
{
"$ref": "#/definitions/GuardGatewayV3Mode"
}
]
},
"percentage": {
"default": 0,
"type": "integer",
"format": "uint8",
"maximum": 100.0,
"minimum": 0.0
}
},
"additionalProperties": false
},
"GuardGatewayV3Mode": {
"type": "string",
"enum": [
"off",
"opportunistic",
"on"
]
},
"Https": {
"type": "object",
"required": [
Expand Down Expand Up @@ -1008,6 +1066,24 @@
"format": "uint",
"minimum": 0.0
},
"gateway_http_response_body_channel_capacity": {
"description": "Number of body chunks buffered between a streaming response handler and its HTTP client.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0.0
},
"gateway_http_response_queue_max_messages": {
"description": "Maximum number of envoy response messages buffered per HTTP request.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0.0
},
"gateway_hws_max_pending_size": {
"description": "Max pending message buffer size for hibernating WebSockets in bytes.",
"type": [
Expand All @@ -1026,6 +1102,15 @@
"format": "uint64",
"minimum": 0.0
},
"gateway_response_chunk_idle_timeout_ms": {
"description": "Timeout between streaming HTTP response chunks in milliseconds.\n\nDisabled when unset so long-lived streams such as SSE may remain idle.",
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0.0
},
"gateway_response_start_timeout_ms": {
"description": "Timeout for response to start in milliseconds.",
"type": [
Expand All @@ -1035,6 +1120,15 @@
"format": "uint64",
"minimum": 0.0
},
"gateway_streaming_http_response_queue_max_bytes": {
"description": "Maximum streaming response bytes buffered per HTTP request.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0.0
},
"gateway_tunnel_ping_timeout_ms": {
"description": "Tunnel ping timeout in milliseconds.",
"type": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { DurableStream } from "@durable-streams/client";

const stream = await DurableStream.create({
url: "http://127.0.0.1:8642/durable-streams/v1/stream/demo",
contentType: "application/json",
});

await stream.append(JSON.stringify({ message: "hello" }));
1 change: 0 additions & 1 deletion vendor/actors/examples/docs/actors-limits/actor-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { actor } from "rivetkit";

const myActor = actor({
options: {
maxActions: 128,
maxQueueSize: 1000,
actionTimeout: 60_000,
stateSaveInterval: 1_000,
Expand Down
30 changes: 30 additions & 0 deletions vendor/actors/examples/docs/actors-request-handler/sse-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createClient } from "rivetkit/client";
import type { registry } from "./sse-server";

const client = createClient<typeof registry>("http://localhost:6420");
const notifications = client.notifications.getOrCreate(["status"]);
const response = await notifications.fetch("/", {
headers: { Accept: "text/event-stream" },
});

if (!response.ok || !response.body) {
throw new Error(`SSE request failed with status ${response.status}`);
}

const reader = response.body.getReader();
const decoder = new TextDecoder();
let pending = "";

for (;;) {
const chunk = await reader.read();
if (chunk.done) break;

pending += decoder.decode(chunk.value, { stream: true });
for (;;) {
const boundary = pending.indexOf("\n\n");
if (boundary === -1) break;
const event = pending.slice(0, boundary);
pending = pending.slice(boundary + 2);
console.log(event);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { setup } from "rivetkit";
import { notificationsActor } from "./sse";

export const registry = setup({
use: { notifications: notificationsActor },
});

registry.start();
Loading
Loading