Skip to content
This repository was archived by the owner on Oct 22, 2025. It is now read-only.

Commit a600481

Browse files
committed
feat: add onAuth lifecycle hooks
1 parent 0a8dd91 commit a600481

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1721
-682
lines changed

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,7 @@ This ensures imports resolve correctly across different build environments and p
108108
- Run `yarn check-types` regularly during development to catch type errors early. Prefer `yarn check-types` instead of `yarn build`.
109109
- Use `tsx` CLI to execute TypeScript scripts directly (e.g., `tsx script.ts` instead of `node script.js`).
110110
- Do not auto-commit changes
111+
112+
## Test Guidelines
113+
114+
- Do not check if errors are an instanceOf WorkerError in tests. Many error types do not have the same prototype chain when sent over the network, but still have the same properties so you can safely cast with `as`.

docs/clients/python.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ The RivetKit Python client provides a way to connect to and interact with worker
4747
<CodeGroup>
4848
```python Async
4949
import asyncio
50-
from worker_core_client import AsyncClient
50+
from rivetkit_client import AsyncClient
5151

5252
async def main():
5353
# Replace with your endpoint URL after deployment
@@ -77,7 +77,7 @@ The RivetKit Python client provides a way to connect to and interact with worker
7777
```
7878

7979
```python Sync
80-
from worker_core_client import Client
80+
from rivetkit_client import Client
8181

8282
# Replace with your endpoint URL after deployment
8383
client = Client("http://localhost:6420")
@@ -128,4 +128,4 @@ The RivetKit Python client provides a way to connect to and interact with worker
128128
<StepDeploy />
129129
</Steps>
130130

131-
<SetupNextSteps />
131+
<SetupNextSteps />

docs/clients/rust.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ The RivetKit Rust client provides a way to connect to and interact with workers
4141
Modify `src/main.rs` to connect to your worker:
4242

4343
```rust src/main.rs
44-
use worker_core_client::{Client, GetOptions, TransportKind, EncodingKind};
44+
use rivetkit_client::{Client, GetOptions, TransportKind, EncodingKind};
4545
use serde_json::json;
4646
use std::time::Duration;
4747

docs/concepts/interacting-with-workers.mdx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const client = createClient<App>(/* CONNECTION ADDRESS */);
1919
```
2020

2121
```rust Rust
22-
use worker_core_client::{Client, TransportKind, EncodingKind};
22+
use rivetkit_client::{Client, TransportKind, EncodingKind};
2323

2424
// Create a client with connection address and configuration
2525
let client = Client::new(
@@ -30,7 +30,7 @@ let client = Client::new(
3030
```
3131

3232
```python Python (Callbacks)
33-
from worker_core_client import AsyncClient as WorkerClient
33+
from rivetkit_client import AsyncClient as WorkerClient
3434

3535
# Create a client with the connection address
3636
client = WorkerClient("http://localhost:6420")
@@ -60,7 +60,7 @@ await room.sendMessage("Alice", "Hello everyone!");
6060
```
6161

6262
```rust Rust
63-
use worker_core_client::GetOptions;
63+
use rivetkit_client::GetOptions;
6464
use serde_json::json;
6565

6666
// Connect to a chat room for the "general" channel
@@ -116,8 +116,8 @@ await doc.initializeDocument("My New Document");
116116
```
117117

118118
```rust Rust
119-
use worker_core_client::{CreateOptions};
120-
use worker_core_client::client::CreateRequestMetadata;
119+
use rivetkit_client::{CreateOptions};
120+
use rivetkit_client::client::CreateRequestMetadata;
121121
use serde_json::json;
122122

123123
// Create a new document worker
@@ -169,7 +169,7 @@ await doc.updateContent("Updated content");
169169
```
170170

171171
```rust Rust
172-
use worker_core_client::GetWithIdOptions;
172+
use rivetkit_client::GetWithIdOptions;
173173

174174
// Connect to a specific worker by its ID
175175
let my_worker_id = "55425f42-82f8-451f-82c1-6227c83c9372";
@@ -374,7 +374,7 @@ const chatRoom = await client.chatRoom.get({ channel: "super-secret" }, {
374374

375375
```rust Rust
376376
use serde_json::json;
377-
use worker_core_client::GetOptions;
377+
use rivetkit_client::GetOptions;
378378

379379
let tags = vec![
380380
("channel".to_string(), "super-secret".to_string()),
@@ -471,7 +471,7 @@ const client = createClient<App>(
471471
```
472472

473473
```rust Rust
474-
use worker_core_client::{Client, TransportKind, EncodingKind};
474+
use rivetkit_client::{Client, TransportKind, EncodingKind};
475475

476476
// Create client with specific options
477477
let client = Client::new(
@@ -484,7 +484,7 @@ let client = Client::new(
484484
```
485485

486486
```python Python (Callbacks)
487-
from worker_core_client import AsyncClient as WorkerClient
487+
from rivetkit_client import AsyncClient as WorkerClient
488488

489489
# Example with all client options
490490
client = WorkerClient(

docs/openapi.json

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -117,27 +117,6 @@
117117
},
118118
"/workers/connect/websocket": {
119119
"get": {
120-
"parameters": [
121-
{
122-
"schema": {
123-
"type": "string",
124-
"description": "The encoding format to use for the response (json, cbor)",
125-
"example": "json"
126-
},
127-
"required": true,
128-
"name": "encoding",
129-
"in": "query"
130-
},
131-
{
132-
"schema": {
133-
"type": "string",
134-
"description": "Worker query information"
135-
},
136-
"required": true,
137-
"name": "query",
138-
"in": "query"
139-
}
140-
],
141120
"responses": {
142121
"101": {
143122
"description": "WebSocket upgrade"

docs/workers/quickstart.mdx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ description: Start building awesome documentation in under 5 minutes
77
```ts registry.ts
88
import { setup } from "rivetkit";
99
import { worker } from "rivetkit/worker";
10-
import { workflow } from "rivetkit/workflow";
11-
import { realtime } from "rivetkit/realtime";
1210

1311
const counter = worker({
12+
onAuth: async () => {
13+
// Allow public access
14+
},
1415
state: {
1516
count: 0,
1617
},
@@ -36,18 +37,24 @@ export type Registry = typeof registry;
3637
```
3738

3839
```ts server.ts
40+
// With router
3941
import { registry } from "./registry";
4042

41-
const registry = new Hono();
42-
app.route("/registry", registry.handler);
43+
const app = new Hono();
44+
app.route("/registry", c => registry.handler(c.req.raw));
45+
serve(app);
46+
47+
// Without router
48+
import { serve } from "@rivetkit/node";
49+
4350
serve(registry);
4451
```
4552

4653
```ts client.ts
4754
import { createClient } from "rivetkit/client";
4855
import type { Registry } from "./registry";
4956

50-
const client = createClient<Registry>("http://localhost:8080/registry");
57+
const client = createClient<Registry>("http://localhost:8080");
5158
```
5259

5360
<Steps>

packages/core/fixtures/driver-test-suite/action-inputs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export interface State {
77

88
// Test worker that can capture input during creation
99
export const inputWorker = worker({
10+
onAuth: () => {},
1011
createState: (c, { input }): State => {
1112
return {
1213
initialInput: input,

packages/core/fixtures/driver-test-suite/action-timeout.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { worker } from "rivetkit";
22

33
// Short timeout worker
44
export const shortTimeoutWorker = worker({
5+
onAuth: () => {},
56
state: { value: 0 },
67
options: {
78
action: {
@@ -22,6 +23,7 @@ export const shortTimeoutWorker = worker({
2223

2324
// Long timeout worker
2425
export const longTimeoutWorker = worker({
26+
onAuth: () => {},
2527
state: { value: 0 },
2628
options: {
2729
action: {
@@ -39,6 +41,7 @@ export const longTimeoutWorker = worker({
3941

4042
// Default timeout worker
4143
export const defaultTimeoutWorker = worker({
44+
onAuth: () => {},
4245
state: { value: 0 },
4346
actions: {
4447
normalAction: async (c) => {
@@ -50,6 +53,7 @@ export const defaultTimeoutWorker = worker({
5053

5154
// Sync worker (timeout shouldn't apply)
5255
export const syncTimeoutWorker = worker({
56+
onAuth: () => {},
5357
state: { value: 0 },
5458
options: {
5559
action: {

packages/core/fixtures/driver-test-suite/action-types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { worker, UserError } from "rivetkit";
22

33
// Worker with synchronous actions
44
export const syncActionWorker = worker({
5+
onAuth: () => {},
56
state: { value: 0 },
67
actions: {
78
// Simple synchronous action that returns a value directly
@@ -25,6 +26,7 @@ export const syncActionWorker = worker({
2526

2627
// Worker with asynchronous actions
2728
export const asyncActionWorker = worker({
29+
onAuth: () => {},
2830
state: { value: 0, data: null as any },
2931
actions: {
3032
// Async action with a delay
@@ -57,6 +59,7 @@ export const asyncActionWorker = worker({
5759

5860
// Worker with promise actions
5961
export const promiseWorker = worker({
62+
onAuth: () => {},
6063
state: { results: [] as string[] },
6164
actions: {
6265
// Action that returns a resolved promise
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { worker, UserError } from "rivetkit";
2+
3+
// Basic auth worker - requires API key
4+
export const authWorker = worker({
5+
state: { requests: 0 },
6+
onAuth: (opts) => {
7+
const { req, intents, params } = opts;
8+
const apiKey = (params as any)?.apiKey;
9+
if (!apiKey) {
10+
throw new UserError("API key required", { code: "missing_auth" });
11+
}
12+
13+
if (apiKey !== "valid-api-key") {
14+
throw new UserError("Invalid API key", { code: "invalid_auth" });
15+
}
16+
17+
return { userId: "user123", token: apiKey };
18+
},
19+
actions: {
20+
getRequests: (c) => {
21+
c.state.requests++;
22+
return c.state.requests;
23+
},
24+
getUserAuth: (c) => c.conn.auth,
25+
},
26+
});
27+
28+
// Intent-specific auth worker - checks different permissions for different intents
29+
export const intentAuthWorker = worker({
30+
state: { value: 0 },
31+
onAuth: (opts) => {
32+
const { req, intents, params } = opts;
33+
console.log('intents', intents, params);
34+
const role = (params as any)?.role;
35+
36+
if (intents.has("create") && role !== "admin") {
37+
throw new UserError("Admin role required for create operations", { code: "insufficient_permissions" });
38+
}
39+
40+
if (intents.has("action") && !["admin", "user"].includes(role || "")) {
41+
throw new UserError("User or admin role required for actions", { code: "insufficient_permissions" });
42+
}
43+
44+
return { role, timestamp: Date.now() };
45+
},
46+
actions: {
47+
getValue: (c) => c.state.value,
48+
setValue: (c, value: number) => {
49+
c.state.value = value;
50+
return value;
51+
},
52+
getAuth: (c) => c.conn.auth,
53+
},
54+
});
55+
56+
// Public worker - empty onAuth to allow public access
57+
export const publicWorker = worker({
58+
state: { visitors: 0 },
59+
onAuth: () => {
60+
return null; // Allow public access
61+
},
62+
actions: {
63+
visit: (c) => {
64+
c.state.visitors++;
65+
return c.state.visitors;
66+
},
67+
},
68+
});
69+
70+
// No auth worker - should fail when accessed publicly (no onAuth defined)
71+
export const noAuthWorker = worker({
72+
state: { value: 42 },
73+
actions: {
74+
getValue: (c) => c.state.value,
75+
},
76+
});
77+
78+
// Async auth worker - tests promise-based authentication
79+
export const asyncAuthWorker = worker({
80+
state: { count: 0 },
81+
onAuth: async (opts) => {
82+
const { req, intents, params } = opts;
83+
// Simulate async auth check (e.g., database lookup)
84+
await new Promise(resolve => setTimeout(resolve, 10));
85+
86+
const token = (params as any)?.token;
87+
if (!token) {
88+
throw new UserError("Token required", { code: "missing_token" });
89+
}
90+
91+
// Simulate token validation
92+
if (token === "invalid") {
93+
throw new UserError("Token is invalid", { code: "invalid_token" });
94+
}
95+
96+
return { userId: `user-${token}`, validated: true };
97+
},
98+
actions: {
99+
increment: (c) => {
100+
c.state.count++;
101+
return c.state.count;
102+
},
103+
getAuthData: (c) => c.conn.auth,
104+
},
105+
});

0 commit comments

Comments
 (0)