diff --git a/docs/concepts/cors.mdx b/docs/concepts/cors.mdx index 4a2d9af4c..546ae19c9 100644 --- a/docs/concepts/cors.mdx +++ b/docs/concepts/cors.mdx @@ -8,8 +8,8 @@ Cross-Origin Resource Sharing (CORS) is a security mechanism that allows a web a You'll need to configure CORS when: -- **Local Development:** You're developing locally and your client runs on a different port than your worker service -- **Different Domain:** Your frontend application is hosted on a different domain than your worker service +- **Local Development**: You're developing locally and your client runs on a different port than your worker service +- **Different Domain**: Your frontend application is hosted on a different domain than your worker service ## Example @@ -17,7 +17,7 @@ You'll need to configure CORS when: import { setup } from "rivetkit"; import counter from "./counter"; -const app = setup({ +const registry = setup({ workers: { counter }, // Change this to match your frontend's origin cors: { origin: "https://yourdomain.com" } diff --git a/docs/concepts/overview.mdx b/docs/concepts/overview.mdx index d7ca96a45..b15637a1b 100644 --- a/docs/concepts/overview.mdx +++ b/docs/concepts/overview.mdx @@ -57,15 +57,15 @@ import { setup, serve } from "rivetkit"; import chatRoom from "./chat_room"; // Create the application -const app = setup({ +const registry = setup({ workers: { chatRoom } }); // Start serving on default port -serve(app); +serve(registry); // Export the app type for client usage -export type App = typeof app; +export type Registry = typeof registry; ``` ## Key Worker Components diff --git a/docs/concepts/testing.mdx b/docs/concepts/testing.mdx index a5520435e..7b0a37ee5 100644 --- a/docs/concepts/testing.mdx +++ b/docs/concepts/testing.mdx @@ -58,11 +58,11 @@ const myWorker = worker({ } }); -export const app = setup({ +export const registry = setup({ workers: { myWorker } }); -export type App = typeof app; +export type Registry = typeof registry; ``` @@ -108,11 +108,11 @@ const counter = worker({ } }); -export const app = setup({ +export const registry = setup({ workers: { counter } }); -export type App = typeof app; +export type Registry = typeof registry; ``` @@ -163,12 +163,12 @@ export const chatRoom = worker({ }); // Create and export the app -export const app = setup({ +export const registry = setup({ workers: { chatRoom } }); // Export type for client type checking -export type App = typeof app; +export type Registry = typeof registry; ``` @@ -224,11 +224,11 @@ const scheduler = worker({ } }); -export const app = setup({ +export const registry = setup({ workers: { scheduler } }); -export type App = typeof app; +export type Registry = typeof registry; ``` diff --git a/docs/integrations/hono.mdx b/docs/integrations/hono.mdx index 44809d670..9993b4179 100644 --- a/docs/integrations/hono.mdx +++ b/docs/integrations/hono.mdx @@ -10,7 +10,7 @@ When mounting the RivetKit router at a custom path, you **must** specify the sam ```typescript // Setup the RivetKit app -const app = setup({ +const registry = setup({ workers: { counter }, // IMPORTANT: Must specify the same basePath where your router is mounted basePath: "/my-path" @@ -45,7 +45,7 @@ honoApp.get("/", (c) => c.text("Welcome to my app!")); honoApp.get("/hello", (c) => c.text("Hello, world!")); // Setup the RivetKit app -const app = setup({ +const registry = setup({ workers: { counter }, // IMPORTANT: Must specify the same basePath where your router is mounted basePath: "/my-path" @@ -58,7 +58,7 @@ const { router: workerRouter, WorkerHandler } = createRouter(app); honoApp.route("/my-path", workerRouter); // Export the app type for client usage -export type App = typeof app; +export type Registry = typeof registry; // IMPORTANT: Must export `WorkerHandler` as this exact name export { honoApp as default, WorkerHandler }; @@ -121,7 +121,7 @@ honoApp.get("/", (c) => c.text("Welcome to my app!")); honoApp.get("/hello", (c) => c.text("Hello, world!")); // Setup the RivetKit app -const app = setup({ +const registry = setup({ workers: { counter }, // IMPORTANT: Must specify the same basePath where your router is mounted basePath: "/my-path" @@ -134,7 +134,7 @@ const { router: workerRouter, injectWebSocket } = createRouter(app); honoApp.route("/my-path", workerRouter); // Export the app type for client usage -export type App = typeof app; +export type Registry = typeof registry; // Create server with the combined app const server = serve({ @@ -173,7 +173,7 @@ honoApp.get("/", (c) => c.text("Welcome to my app!")); honoApp.get("/hello", (c) => c.text("Hello, world!")); // Setup the RivetKit app -const app = setup({ +const registry = setup({ workers: { counter }, // IMPORTANT: Must specify the same basePath where your router is mounted basePath: "/my-path" @@ -186,7 +186,7 @@ const { router: workerRouter, webSocketHandler } = createRouter(app); honoApp.route("/my-path", workerRouter); // Export the app type for client usage -export type App = typeof app; +export type Registry = typeof registry; // Create and start the server export default { diff --git a/docs/integrations/resend.mdx b/docs/integrations/resend.mdx index a6fea2101..33276da5e 100644 --- a/docs/integrations/resend.mdx +++ b/docs/integrations/resend.mdx @@ -51,8 +51,8 @@ const user = worker({ }, }); -export const app = setup({ workers: { user } }); -export type App = typeof app; +export const registry = setup({ workers: { user } }); +export type Registry = typeof registry; ``` diff --git a/docs/llm/prompt.mdx b/docs/llm/prompt.mdx index ddb9e31c6..9aa306867 100644 --- a/docs/llm/prompt.mdx +++ b/docs/llm/prompt.mdx @@ -134,7 +134,7 @@ When importing from workspace packages, always check the package's `package.json ## Worker Management -- App is configured with workers using `setup({ workers: { workerName }})` followed by `serve(app)` +- App is configured with workers using `setup({ workers: { workerName }})` followed by `serve(registry)` - Workers are accessed by client using `client.workerName.get()` - Workers can pass an ID parameter or object with `client.workerName.get(id)` or `client.workerName.get({key: value})` - Workers can be shut down with `c.shutdown()` from within the worker diff --git a/docs/openapi.json b/docs/openapi.json index 40ccdb53d..dd55f79fb 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -325,4 +325,4 @@ } } } -} +} \ No newline at end of file diff --git a/docs/platforms/bun.mdx b/docs/platforms/bun.mdx index a6dab0475..be9378d69 100644 --- a/docs/platforms/bun.mdx +++ b/docs/platforms/bun.mdx @@ -33,7 +33,7 @@ Bun provides a fast runtime environment for running RivetKit, with excellent per import { app } from "../workers/app"; // Start the server with file-system driver (default) - serve(app); + serve(registry); ``` diff --git a/docs/platforms/nodejs.mdx b/docs/platforms/nodejs.mdx index 768beca7e..9e9b392fe 100644 --- a/docs/platforms/nodejs.mdx +++ b/docs/platforms/nodejs.mdx @@ -47,7 +47,7 @@ Node.js provides a robust environment for running RivetKit, ideal for developmen import { app } from "../workers/app"; // Start the server with file-system driver (default) - serve(app); + serve(registry); ``` diff --git a/docs/snippets/setup-actor.mdx b/docs/snippets/setup-actor.mdx index b062f0612..e78ba7863 100644 --- a/docs/snippets/setup-actor.mdx +++ b/docs/snippets/setup-actor.mdx @@ -14,12 +14,12 @@ const counter = worker({ }); // Create the application -export const app = setup({ +export const registry = setup({ workers: { counter }, cors: { origin: "http://localhost:8080" } }); // Export app type for client usage -export type App = typeof app; +export type Registry = typeof registry; ``` diff --git a/docs/snippets/step-define-actor.mdx b/docs/snippets/step-define-actor.mdx index 1c5a157fb..4241d157d 100644 --- a/docs/snippets/step-define-actor.mdx +++ b/docs/snippets/step-define-actor.mdx @@ -17,12 +17,12 @@ }); // Create the application - export const app = setup({ + export const registry = setup({ workers: { counter }, cors: { origin: "*" } // Configure CORS for your production domains in production }); // Export app type for client usage - export type App = typeof app; + export type Registry = typeof registry; ``` diff --git a/docs/workers/actions.mdx b/docs/workers/actions.mdx index d1585b12e..04fd2c7b3 100644 --- a/docs/workers/actions.mdx +++ b/docs/workers/actions.mdx @@ -103,11 +103,11 @@ const counter = worker({ }); // Create and export the app -const app = setup({ +const registry = setup({ workers: { counter } }); -export type App = typeof app; +export type Registry = typeof registry; ``` ```typescript client.ts diff --git a/docs/workers/overview.mdx b/docs/workers/overview.mdx index 0caeb64f6..ae23ef28b 100644 --- a/docs/workers/overview.mdx +++ b/docs/workers/overview.mdx @@ -70,15 +70,15 @@ import { setup, serve } from "rivetkit"; import chatRoom from "./chat_room"; // Create the application -const app = setup({ +const registry = setup({ workers: { chatRoom } }); // Start serving on default port -serve(app); +serve(registry); // Export the app type for client usage -export type App = typeof app; +export type Registry = typeof registry; ``` ## Key Worker Components @@ -278,4 +278,4 @@ Learn more about Rivet Workers: Schedule tasks and alarms with workers for time-based operations. - \ No newline at end of file + diff --git a/docs/workers/quickstart.mdx b/docs/workers/quickstart.mdx index c26393c90..c10e17c91 100644 --- a/docs/workers/quickstart.mdx +++ b/docs/workers/quickstart.mdx @@ -4,6 +4,52 @@ icon: forward description: Start building awesome documentation in under 5 minutes --- +```ts registry.ts +import { setup } from "rivetkit"; +import { worker } from "rivetkit/worker"; +import { workflow } from "rivetkit/workflow"; +import { realtime } from "rivetkit/realtime"; + +const counter = worker({ + state: { + count: 0, + }, + actions: { + foo: (c) => c.state.count++, + }, +}); + +const myWorkflow = workflow({ + run: () => {} +}); + +const myRealtime = realtime({ + run: () => {} +}); + +const registry = setup({ + registry: { counter, myWorkflow, myRealtime }, + maxConnParamLength: 123 +}); + +export type Registry = typeof registry; +``` + +```ts server.ts +import { registry } from "./registry"; + +const registry = new Hono(); +app.route("/registry", registry.handler); +serve(registry); +``` + +```ts client.ts +import { createClient } from "rivetkit/client"; +import type { Registry } from "./registry"; + +const client = createClient("http://localhost:8080/registry"); +``` + @@ -51,15 +97,15 @@ const myWorker = worker({ ```ts Hono -const app = new Hono(); +const registry = new Hono(); app.route("rivetkit", setup({ myWf, myWorker })); -serve(app); +serve(registry); ``` ```ts Express.js -const app = new Hono(); +const registry = new Hono(); app.route("rivetkit", setup({ myWf, myWorker })); -serve(app); +serve(registry); ``` diff --git a/examples/chat-room-python/src/server.ts b/examples/chat-room-python/src/server.ts index b19f6afd9..4bf6ba53b 100644 --- a/examples/chat-room-python/src/server.ts +++ b/examples/chat-room-python/src/server.ts @@ -1,4 +1,4 @@ import { serve } from "@rivetkit/nodejs"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -serve(app); \ No newline at end of file +serve(registry); diff --git a/examples/chat-room-python/src/workers/app.ts b/examples/chat-room-python/src/workers/registry.ts similarity index 90% rename from examples/chat-room-python/src/workers/app.ts rename to examples/chat-room-python/src/workers/registry.ts index 271185181..b242ecd20 100644 --- a/examples/chat-room-python/src/workers/app.ts +++ b/examples/chat-room-python/src/workers/registry.ts @@ -27,9 +27,9 @@ export const chatRoom = worker({ }); // Create and export the app -export const app = setup({ +export const registry = setup({ workers: { chatRoom }, }); // Export type for client type checking -export type App = typeof app; +export type Registry = typeof registry; diff --git a/examples/chat-room/scripts/cli.ts b/examples/chat-room/scripts/cli.ts index d1e17713c..9e7b9637b 100644 --- a/examples/chat-room/scripts/cli.ts +++ b/examples/chat-room/scripts/cli.ts @@ -1,12 +1,12 @@ import { createClient } from "rivetkit/client"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; import prompts from "prompts"; async function main() { const { username, room } = await initPrompt(); // Create type-aware client - const client = createClient("http://localhost:6420"); + const client = createClient("http://localhost:6420"); // connect to chat room - now accessed via property // can still pass parameters like room diff --git a/examples/chat-room/scripts/connect.ts b/examples/chat-room/scripts/connect.ts index 922ece3a4..3d8fdb8b1 100644 --- a/examples/chat-room/scripts/connect.ts +++ b/examples/chat-room/scripts/connect.ts @@ -1,10 +1,10 @@ /// import { createClient } from "rivetkit/client"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; async function main() { // Create type-aware client - const client = createClient(process.env.ENDPOINT ?? "http://localhost:6420"); + const client = createClient(process.env.ENDPOINT ?? "http://localhost:6420"); // connect to chat room - now accessed via property const chatRoom = client.chatRoom.getOrCreate().connect(); diff --git a/examples/chat-room/src/server.ts b/examples/chat-room/src/server.ts index b19f6afd9..4bf6ba53b 100644 --- a/examples/chat-room/src/server.ts +++ b/examples/chat-room/src/server.ts @@ -1,4 +1,4 @@ import { serve } from "@rivetkit/nodejs"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -serve(app); \ No newline at end of file +serve(registry); diff --git a/examples/chat-room/src/workers/app.ts b/examples/chat-room/src/workers/registry.ts similarity index 90% rename from examples/chat-room/src/workers/app.ts rename to examples/chat-room/src/workers/registry.ts index 271185181..b242ecd20 100644 --- a/examples/chat-room/src/workers/app.ts +++ b/examples/chat-room/src/workers/registry.ts @@ -27,9 +27,9 @@ export const chatRoom = worker({ }); // Create and export the app -export const app = setup({ +export const registry = setup({ workers: { chatRoom }, }); // Export type for client type checking -export type App = typeof app; +export type Registry = typeof registry; diff --git a/examples/chat-room/tests/chat-room.test.ts b/examples/chat-room/tests/chat-room.test.ts index 6fc01ff1f..04ebf493a 100644 --- a/examples/chat-room/tests/chat-room.test.ts +++ b/examples/chat-room/tests/chat-room.test.ts @@ -1,9 +1,9 @@ import { test, expect } from "vitest"; import { setupTest } from "rivetkit/test"; -import { app } from "../src/workers/app"; +import { registry } from "../src/workers/registry"; test("chat room should handle messages", async (test) => { - const { client } = await setupTest(test, app); + const { client } = await setupTest(test, registry); // Connect to chat room const chatRoom = client.chatRoom.getOrCreate().connect(); diff --git a/examples/counter/scripts/connect.ts b/examples/counter/scripts/connect.ts index ca865a603..6ac56f893 100644 --- a/examples/counter/scripts/connect.ts +++ b/examples/counter/scripts/connect.ts @@ -1,9 +1,9 @@ /// import { createClient } from "rivetkit/client"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; async function main() { - const client = createClient(process.env.ENDPOINT ?? "http://localhost:6420"); + const client = createClient(process.env.ENDPOINT ?? "http://localhost:6420"); const counter = client.counter.connect() diff --git a/examples/counter/src/server.ts b/examples/counter/src/server.ts index b19f6afd9..4bf6ba53b 100644 --- a/examples/counter/src/server.ts +++ b/examples/counter/src/server.ts @@ -1,4 +1,4 @@ import { serve } from "@rivetkit/nodejs"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -serve(app); \ No newline at end of file +serve(registry); diff --git a/examples/counter/src/workers/app.ts b/examples/counter/src/workers/registry.ts similarity index 81% rename from examples/counter/src/workers/app.ts rename to examples/counter/src/workers/registry.ts index 5b91c482f..717b2b917 100644 --- a/examples/counter/src/workers/app.ts +++ b/examples/counter/src/workers/registry.ts @@ -14,8 +14,8 @@ const counter = worker({ }, }); -export const app = setup({ +export const registry = setup({ workers: { counter }, }); -export type App = typeof app; +export type Registry = typeof registry; diff --git a/examples/counter/tests/counter.test.ts b/examples/counter/tests/counter.test.ts index fc739a3f6..4504750f7 100644 --- a/examples/counter/tests/counter.test.ts +++ b/examples/counter/tests/counter.test.ts @@ -1,9 +1,9 @@ import { test, expect } from "vitest"; import { setupTest } from "rivetkit/test"; -import { app } from "../src/workers/app"; +import { registry } from "../src/workers/registry"; test("it should count", async (test) => { - const { client } = await setupTest(test, app); + const { client } = await setupTest(test, registry); const counter = client.counter.getOrCreate().connect(); // Test initial count diff --git a/examples/linear-coding-agent/README.md b/examples/linear-coding-agent/README.md index c742b32f4..67b77d20f 100644 --- a/examples/linear-coding-agent/README.md +++ b/examples/linear-coding-agent/README.md @@ -70,7 +70,7 @@ This starts the RivetKit server that hosts the coding agent: ``` npm run dev # Or using the RivetKit CLI -npx rivetkit/cli dev src/actors/app.ts +npx rivetkit/cli dev src/workers/registry.ts ``` ##### Running the Webhook Server (for Linear integration) diff --git a/examples/linear-coding-agent/package.json b/examples/linear-coding-agent/package.json index eaf0954f5..d8838d4ab 100644 --- a/examples/linear-coding-agent/package.json +++ b/examples/linear-coding-agent/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "concurrently --raw \"yarn dev:actors\" \"yarn dev:server\" \"yarn dev:ngrok\"", - "dev:actors": "npx rivetkit/cli@latest dev src/workers/app.ts", + "dev:actors": "npx rivetkit/cli@latest dev src/workers/registry.ts", "dev:server": "tsx --watch src/server/index.ts", "dev:ngrok": "ngrok http 3000", "check-types": "tsc --noEmit" diff --git a/examples/linear-coding-agent/src/server.ts b/examples/linear-coding-agent/src/server.ts index b19f6afd9..4bf6ba53b 100644 --- a/examples/linear-coding-agent/src/server.ts +++ b/examples/linear-coding-agent/src/server.ts @@ -1,4 +1,4 @@ import { serve } from "@rivetkit/nodejs"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -serve(app); \ No newline at end of file +serve(registry); diff --git a/examples/linear-coding-agent/src/server/index.ts b/examples/linear-coding-agent/src/server/index.ts index 04185e328..21e610451 100644 --- a/examples/linear-coding-agent/src/server/index.ts +++ b/examples/linear-coding-agent/src/server/index.ts @@ -2,8 +2,8 @@ import { Hono } from "hono"; import { serve } from "@hono/node-server"; import dotenv from "dotenv"; import { createClient } from "rivetkit/client"; -import { app } from "../workers/app"; -import type { App } from "../workers/app"; +import { registry } from "../workers/registry"; +import type { Registry } from "../workers/registry"; import type { LinearWebhookEvent } from "../types"; // Load environment variables @@ -16,7 +16,7 @@ const PORT = process.env.PORT || 8080; // Create actor client const ACTOR_SERVER_URL = process.env.ACTOR_SERVER_URL || "http://localhost:6420"; -const client = createClient(ACTOR_SERVER_URL); +const client = createClient(ACTOR_SERVER_URL); // Middleware to initialize agent server.use("*", async (c, next) => { diff --git a/examples/linear-coding-agent/src/workers/app.ts b/examples/linear-coding-agent/src/workers/registry.ts similarity index 79% rename from examples/linear-coding-agent/src/workers/app.ts rename to examples/linear-coding-agent/src/workers/registry.ts index 6fa245d7a..69b77e1df 100644 --- a/examples/linear-coding-agent/src/workers/app.ts +++ b/examples/linear-coding-agent/src/workers/registry.ts @@ -6,9 +6,9 @@ import { codingAgent } from "./coding-agent/mod"; dotenv.config(); // Create and export the app -export const app = setup({ +export const registry = setup({ workers: { codingAgent }, }); // Export type for client type checking -export type App = typeof app; +export type Registry = typeof registry; diff --git a/examples/resend-streaks/src/server.ts b/examples/resend-streaks/src/server.ts index b19f6afd9..4bf6ba53b 100644 --- a/examples/resend-streaks/src/server.ts +++ b/examples/resend-streaks/src/server.ts @@ -1,4 +1,4 @@ import { serve } from "@rivetkit/nodejs"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -serve(app); \ No newline at end of file +serve(registry); diff --git a/examples/resend-streaks/src/workers/app.ts b/examples/resend-streaks/src/workers/registry.ts similarity index 97% rename from examples/resend-streaks/src/workers/app.ts rename to examples/resend-streaks/src/workers/registry.ts index 1a71ff5eb..0f580eee4 100644 --- a/examples/resend-streaks/src/workers/app.ts +++ b/examples/resend-streaks/src/workers/registry.ts @@ -104,8 +104,8 @@ function isSameDay(a: TZDate, b: TZDate) { ); } -export const app = setup({ +export const registry = setup({ workers: { user }, }); -export type App = typeof app; +export type Registry = typeof registry; diff --git a/examples/resend-streaks/tests/user.test.ts b/examples/resend-streaks/tests/user.test.ts index ac4313cb3..4df35cc61 100644 --- a/examples/resend-streaks/tests/user.test.ts +++ b/examples/resend-streaks/tests/user.test.ts @@ -1,6 +1,6 @@ import { test, expect, vi, beforeEach } from "vitest"; import { setupTest } from "rivetkit/test"; -import { app } from "../src/workers/app"; +import { registry } from "../src/workers/registry"; // Create mock for send method const mockSendEmail = vi.fn().mockResolvedValue({ success: true }); @@ -25,7 +25,7 @@ beforeEach(() => { }); test("streak tracking with time zone signups", async (t) => { - const { client } = await setupTest(t, app); + const { client } = await setupTest(t, registry); const actor = client.user.getOrCreate().connect(); // Sign up with specific time zone diff --git a/examples/snippets/README.md b/examples/snippets/README.md index 25d6293ab..17b861a27 100644 --- a/examples/snippets/README.md +++ b/examples/snippets/README.md @@ -7,5 +7,5 @@ These snippets are not intended to be complete examples. Each example has these files in a single folder: - `actor-json.ts` - Server implementation with JavaScript state - `actor-sqlite.ts` - Server implementation with SQLite state -- `App.tsx` - React client implementation +- `Registry.tsx` - React client implementation diff --git a/examples/snippets/ai-agent/App.tsx b/examples/snippets/ai-agent/App.tsx index cf8eb050f..ebb59628a 100644 --- a/examples/snippets/ai-agent/App.tsx +++ b/examples/snippets/ai-agent/App.tsx @@ -1,10 +1,10 @@ import { createClient } from "rivetkit/client"; import { createReactActorCore } from "@rivetkit/react"; import { useState, useEffect } from "react"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; import type { Message } from "./actor"; -const client = createClient("http://localhost:6420"); +const client = createClient("http://localhost:6420"); const { useActor, useActorEvent } = createReactActorCore(client); export function AIAssistant() { diff --git a/examples/snippets/chat-room/App.tsx b/examples/snippets/chat-room/App.tsx index 9aa3b04b0..9bdd9ee56 100644 --- a/examples/snippets/chat-room/App.tsx +++ b/examples/snippets/chat-room/App.tsx @@ -1,10 +1,10 @@ import { createClient } from "rivetkit/client"; import { createReactActorCore } from "@rivetkit/react"; import { useState, useEffect } from "react"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; import type { Message } from "./actor"; -const client = createClient("http://localhost:6420"); +const client = createClient("http://localhost:6420"); const { useActor, useActorEvent } = createReactActorCore(client); export function ChatRoom({ roomId = "general" }) { diff --git a/examples/snippets/crdt/App.tsx b/examples/snippets/crdt/App.tsx index f63c33a6f..d42dfac1b 100644 --- a/examples/snippets/crdt/App.tsx +++ b/examples/snippets/crdt/App.tsx @@ -3,9 +3,9 @@ import { createReactActorCore } from "@rivetkit/react"; import { useState, useEffect, useRef } from "react"; import * as Y from 'yjs'; import { applyUpdate, encodeStateAsUpdate } from 'yjs'; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; -const client = createClient("http://localhost:6420"); +const client = createClient("http://localhost:6420"); const { useActor, useActorEvent } = createReactActorCore(client); export function YjsEditor({ documentId = "shared-doc" }) { diff --git a/examples/snippets/document/App.tsx b/examples/snippets/document/App.tsx index 591aa7a74..251757171 100644 --- a/examples/snippets/document/App.tsx +++ b/examples/snippets/document/App.tsx @@ -1,9 +1,9 @@ import { createClient } from "rivetkit/client"; import { createReactActorCore } from "@rivetkit/react"; import { useState, useEffect } from "react"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; -const client = createClient("http://localhost:6420"); +const client = createClient("http://localhost:6420"); const { useActor, useActorEvent } = createReactActorCore(client); export function DocumentEditor() { diff --git a/examples/snippets/rate/App.tsx b/examples/snippets/rate/App.tsx index e9a83ff0e..e3ef7f5cd 100644 --- a/examples/snippets/rate/App.tsx +++ b/examples/snippets/rate/App.tsx @@ -1,9 +1,9 @@ import { createClient } from "rivetkit/client"; import { createReactActorCore } from "@rivetkit/react"; import { useState } from "react"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; -const client = createClient("http://localhost:6420"); +const client = createClient("http://localhost:6420"); const { useActor } = createReactActorCore(client); export function RateLimiter() { diff --git a/examples/snippets/stream/App.tsx b/examples/snippets/stream/App.tsx index 260702d89..e748d203b 100644 --- a/examples/snippets/stream/App.tsx +++ b/examples/snippets/stream/App.tsx @@ -1,10 +1,10 @@ import { createClient } from "rivetkit/client"; import { createReactActorCore } from "@rivetkit/react"; import { useState, useEffect } from "react"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; import type { StreamState } from "./actor"; // Import shared types from actor -const client = createClient("http://localhost:6420"); +const client = createClient("http://localhost:6420"); const { useActor, useActorEvent } = createReactActorCore(client); export function StreamExample() { diff --git a/examples/snippets/tenant/App.tsx b/examples/snippets/tenant/App.tsx index b1d5132a5..441015e32 100644 --- a/examples/snippets/tenant/App.tsx +++ b/examples/snippets/tenant/App.tsx @@ -1,10 +1,10 @@ import { createClient } from "rivetkit/client"; import { createReactActorCore } from "@rivetkit/react"; import { useState, useEffect } from "react"; -import type { App } from "../actors/app"; +import type { Registry } from "../workers/registry"; // Create client and hooks -const client = createClient("http://localhost:6420"); +const client = createClient("http://localhost:6420"); const { useActor } = createReactActorCore(client); export function OrgDashboard({ orgId }: { orgId: string }) { diff --git a/packages/core/fixtures/driver-test-suite/app.ts b/packages/core/fixtures/driver-test-suite/registry.ts similarity index 95% rename from packages/core/fixtures/driver-test-suite/app.ts rename to packages/core/fixtures/driver-test-suite/registry.ts index aba2fbe3e..1b1e5ca1b 100644 --- a/packages/core/fixtures/driver-test-suite/app.ts +++ b/packages/core/fixtures/driver-test-suite/registry.ts @@ -29,7 +29,7 @@ import { } from "./vars"; // Consolidated setup with all workers -export const app = setup({ +export const registry = setup({ workers: { // From counter.ts counter, @@ -66,4 +66,4 @@ export const app = setup({ }, }); -export type App = typeof app; +export type Registry = typeof registry; diff --git a/packages/core/scripts/dump-openapi.ts b/packages/core/scripts/dump-openapi.ts index 416bbb545..d5f35a6bd 100644 --- a/packages/core/scripts/dump-openapi.ts +++ b/packages/core/scripts/dump-openapi.ts @@ -1,5 +1,5 @@ import { createManagerRouter } from "@/manager/router"; -import { AppConfig, AppConfigSchema, Encoding, setup } from "@/mod"; +import { RegistryConfig, RegistryConfigSchema, Encoding, setup } from "@/mod"; import { ConnectionHandlers } from "@/worker/router-endpoints"; import { DriverConfig } from "@/driver-helpers/config"; import { @@ -18,14 +18,14 @@ import { EventSource } from "eventsource"; import { Context } from "hono"; function main() { - const appConfig: AppConfig = AppConfigSchema.parse({ workers: {} }); - const app = setup(appConfig); + const registryConfig: RegistryConfig = RegistryConfigSchema.parse({ workers: {} }); + const registry = setup(registryConfig); const memoryState = new TestGlobalState(); const driverConfig: DriverConfig = { drivers: { worker: new TestWorkerDriver(memoryState), - manager: new TestManagerDriver(app, memoryState), + manager: new TestManagerDriver(registry, memoryState), }, getUpgradeWebSocket: () => () => unimplemented(), }; @@ -54,7 +54,7 @@ function main() { }; const managerRouter = createManagerRouter( - appConfig, + registryConfig, driverConfig, inlineClientDriver, { diff --git a/packages/core/src/app/mod.ts b/packages/core/src/app/mod.ts deleted file mode 100644 index ab26a3c5c..000000000 --- a/packages/core/src/app/mod.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - type Workers, - type AppConfig, - type AppConfigInput, - AppConfigSchema, -} from "./config"; - -export class App { - #config: AppConfig; - - public get config(): AppConfig { - return this.#config; - } - - constructor(config: AppConfig) { - this.#config = config; - } -} - -export function setup( - input: AppConfigInput, -): App { - const config = AppConfigSchema.parse(input); - return new App(config); -} - -export type { AppConfig }; -export { AppConfigSchema }; diff --git a/packages/core/src/client/client.ts b/packages/core/src/client/client.ts index 44f4879a6..63458c8e7 100644 --- a/packages/core/src/client/client.ts +++ b/packages/core/src/client/client.ts @@ -10,7 +10,7 @@ import { import { WorkerHandle, WorkerHandleRaw } from "./worker-handle"; import { WorkerActionFunction } from "./worker-common"; import { logger } from "./log"; -import type { App } from "@/mod"; +import type { Registry } from "@/mod"; import type { AnyWorkerDefinition } from "@/worker/definition"; import type * as wsToServer from "@/worker/protocol/message/to-server"; import type { EventSource } from "eventsource"; @@ -18,12 +18,12 @@ import type { Context as HonoContext } from "hono"; import { createHttpClientDriver } from "./http-client-driver"; import { HonoRequest } from "hono"; -/** Extract the worker registry from the app definition. */ -export type ExtractWorkersFromApp> = - A extends App ? Workers : never; +/** Extract the worker registry from the registry definition. */ +export type ExtractWorkersFromRegistry> = + A extends Registry ? Workers : never; -/** Extract the app definition from the client. */ -export type ExtractAppFromClient>> = +/** Extract the registry definition from the client. */ +export type ExtractRegistryFromClient>> = C extends Client ? A : never; /** @@ -435,15 +435,15 @@ export class ClientRaw { * Client type with worker accessors. * This adds property accessors for worker names to the ClientRaw base class. * - * @template A The worker application type. + * @template A The worker registry type. */ -export type Client> = ClientRaw & { - [K in keyof ExtractWorkersFromApp]: WorkerAccessor< - ExtractWorkersFromApp[K] +export type Client> = ClientRaw & { + [K in keyof ExtractWorkersFromRegistry]: WorkerAccessor< + ExtractWorkersFromRegistry[K] >; }; -export function createClientWithDriver>( +export function createClientWithDriver>( driver: ClientDriver, opts?: ClientOptions, ): Client { @@ -470,8 +470,8 @@ export function createClientWithDriver>( get: ( key?: string | string[], opts?: GetWithIdOptions, - ): WorkerHandle[typeof prop]> => { - return target.get[typeof prop]>( + ): WorkerHandle[typeof prop]> => { + return target.get[typeof prop]>( prop, key, opts, @@ -480,8 +480,8 @@ export function createClientWithDriver>( getOrCreate: ( key?: string | string[], opts?: GetOptions, - ): WorkerHandle[typeof prop]> => { - return target.getOrCreate[typeof prop]>( + ): WorkerHandle[typeof prop]> => { + return target.getOrCreate[typeof prop]>( prop, key, opts, @@ -490,8 +490,8 @@ export function createClientWithDriver>( getForId: ( workerId: string, opts?: GetWithIdOptions, - ): WorkerHandle[typeof prop]> => { - return target.getForId[typeof prop]>( + ): WorkerHandle[typeof prop]> => { + return target.getForId[typeof prop]>( prop, workerId, opts, @@ -500,14 +500,14 @@ export function createClientWithDriver>( create: async ( key: string | string[], opts: CreateOptions = {}, - ): Promise[typeof prop]>> => { - return await target.create[typeof prop]>( + ): Promise[typeof prop]>> => { + return await target.create[typeof prop]>( prop, key, opts, ); }, - } as WorkerAccessor[typeof prop]>; + } as WorkerAccessor[typeof prop]>; } return undefined; diff --git a/packages/core/src/client/mod.ts b/packages/core/src/client/mod.ts index 35854d608..0e69f896c 100644 --- a/packages/core/src/client/mod.ts +++ b/packages/core/src/client/mod.ts @@ -1,4 +1,4 @@ -import type { App } from "@/app/mod"; +import type { Registry } from "@/registry/mod"; import { type Client, type ClientOptions, createClientWithDriver } from "./client"; import { createHttpClientDriver } from "./http-client-driver"; @@ -11,8 +11,8 @@ export type { GetWithIdOptions, QueryOptions, Region, - ExtractWorkersFromApp, - ExtractAppFromClient, + ExtractWorkersFromRegistry, + ExtractRegistryFromClient, ClientRaw, } from "./client"; export type { WorkerConn } from "./worker-conn"; @@ -45,7 +45,7 @@ export { * @param {ClientOptions} [opts] - Options for configuring the client. * @returns {Client} - A proxied client that supports the `client.myWorker.connect()` syntax. */ -export function createClient>( +export function createClient>( endpoint: string, opts?: ClientOptions, ): Client { diff --git a/packages/core/src/driver-helpers/config.ts b/packages/core/src/driver-helpers/config.ts index e96a9be9b..7df67882b 100644 --- a/packages/core/src/driver-helpers/config.ts +++ b/packages/core/src/driver-helpers/config.ts @@ -18,7 +18,7 @@ import { UpgradeWebSocket } from "@/utils"; export const TopologySchema = z.enum(["standalone", "partition", "coordinate"]); export type Topology = z.infer; -export type GetUpgradeWebSocket = (app: Hono) => UpgradeWebSocket; +export type GetUpgradeWebSocket = (router: Hono) => UpgradeWebSocket; /** Base config used for the worker config across all platforms. */ export const DriverConfigSchema = z.object({ @@ -31,7 +31,7 @@ export const DriverConfigSchema = z.object({ }) .optional() .default({}), - // This is dynamic since NodeJS requires a reference to the app to initialize WebSockets + // This is dynamic since NodeJS requires a reference to the router to initialize WebSockets getUpgradeWebSocket: z.custom().optional(), }); export type DriverConfig = z.infer; diff --git a/packages/core/src/driver-test-suite/mod.ts b/packages/core/src/driver-test-suite/mod.ts index 484ea98ba..455a7b220 100644 --- a/packages/core/src/driver-test-suite/mod.ts +++ b/packages/core/src/driver-test-suite/mod.ts @@ -8,7 +8,7 @@ import { import { runWorkerDriverTests } from "./tests/worker-driver"; import { runManagerDriverTests } from "./tests/manager-driver"; import { describe } from "vitest"; -import { CoordinateTopology, StandaloneTopology, App } from "@/mod"; +import { CoordinateTopology, StandaloneTopology, Registry } from "@/mod"; import { createNodeWebSocket, type NodeWebSocket } from "@hono/node-ws"; import invariant from "invariant"; import { bundleRequire } from "bundle-require"; @@ -23,8 +23,8 @@ import { runWorkerMetadataTests } from "./tests/worker-metadata"; import { runWorkerErrorHandlingTests } from "./tests/worker-error-handling"; export interface DriverTestConfig { - /** Deploys an app and returns the connection endpoint. */ - start(appPath: string): Promise; + /** Deploys an registry and returns the connection endpoint. */ + start(projectDir: string): Promise; /** * If we're testing with an external system, we should use real timers @@ -100,8 +100,8 @@ export function runDriverTests( * This is helpful for drivers that run in-process as opposed to drivers that rely on external tools. */ export async function createTestRuntime( - appPath: string, - driverFactory: (app: App) => Promise<{ + registryPath: string, + driverFactory: (registry: Registry) => Promise<{ workerDriver: WorkerDriver; managerDriver: ManagerDriver; coordinateDriver?: CoordinateDriver; @@ -109,14 +109,14 @@ export async function createTestRuntime( }>, ): Promise { const { - mod: { app }, - } = await bundleRequire<{ app: App }>({ - filepath: appPath, + mod: { registry }, + } = await bundleRequire<{ registry: Registry }>({ + filepath: registryPath, }); - // TODO: Find a cleaner way of flagging an app as test mode (ideally not in the config itself) + // TODO: Find a cleaner way of flagging an registry as test mode (ideally not in the config itself) // Force enable test - app.config.test.enabled = true; + registry.config.test.enabled = true; // Build drivers const { @@ -124,7 +124,7 @@ export async function createTestRuntime( managerDriver, coordinateDriver, cleanup: driverCleanup, - } = await driverFactory(app); + } = await driverFactory(registry); // Build driver config let injectWebSocket: NodeWebSocket["injectWebSocket"] | undefined; @@ -134,8 +134,8 @@ export async function createTestRuntime( manager: managerDriver, coordinate: coordinateDriver, }, - getUpgradeWebSocket: (app) => { - const webSocket = createNodeWebSocket({ app }); + getUpgradeWebSocket: (router) => { + const webSocket = createNodeWebSocket({ app: router }); injectWebSocket = webSocket.injectWebSocket; return webSocket.upgradeWebSocket; }, @@ -143,8 +143,8 @@ export async function createTestRuntime( // Build topology const topology = coordinateDriver - ? new CoordinateTopology(app.config, config) - : new StandaloneTopology(app.config, config); + ? new CoordinateTopology(registry.config, config) + : new StandaloneTopology(registry.config, config); if (!injectWebSocket) throw new Error("injectWebSocket not defined"); // Start server diff --git a/packages/core/src/driver-test-suite/utils.ts b/packages/core/src/driver-test-suite/utils.ts index 5b7ba1c52..14bf45c45 100644 --- a/packages/core/src/driver-test-suite/utils.ts +++ b/packages/core/src/driver-test-suite/utils.ts @@ -5,14 +5,14 @@ import { assertUnreachable } from "@/worker/utils"; import { createClientWithDriver } from "@/client/client"; import { createTestInlineClientDriver } from "./test-inline-client-driver"; import { resolve } from "node:path"; -import type { App } from "../../fixtures/driver-test-suite/app"; +import type { Registry } from "../../fixtures/driver-test-suite/registry"; // Must use `TestContext` since global hooks do not work when running concurrently export async function setupDriverTest( c: TestContext, driverTestConfig: DriverTestConfig, ): Promise<{ - client: Client; + client: Client; }> { if (!driverTestConfig.useRealTimers) { vi.useFakeTimers(); @@ -23,10 +23,10 @@ export async function setupDriverTest( const { endpoint, cleanup } = await driverTestConfig.start(projectPath); c.onTestFinished(cleanup); - let client: Client; + let client: Client; if (driverTestConfig.clientType === "http") { // Create client - client = createClient(endpoint, { + client = createClient(endpoint, { transport: driverTestConfig.transport, }); } else if (driverTestConfig.clientType === "inline") { diff --git a/packages/core/src/app/fake-event-source.ts b/packages/core/src/inline-client-driver/fake-event-source.ts similarity index 99% rename from packages/core/src/app/fake-event-source.ts rename to packages/core/src/inline-client-driver/fake-event-source.ts index ecbb826fc..7ca6dcaa3 100644 --- a/packages/core/src/app/fake-event-source.ts +++ b/packages/core/src/inline-client-driver/fake-event-source.ts @@ -216,4 +216,4 @@ export class FakeEventSource { } } } -} \ No newline at end of file +} diff --git a/packages/core/src/app/fake-websocket.ts b/packages/core/src/inline-client-driver/fake-websocket.ts similarity index 99% rename from packages/core/src/app/fake-websocket.ts rename to packages/core/src/inline-client-driver/fake-websocket.ts index 28492ef0f..bd1184e39 100644 --- a/packages/core/src/app/fake-websocket.ts +++ b/packages/core/src/inline-client-driver/fake-websocket.ts @@ -1,5 +1,5 @@ import { WSContext } from "hono/ws"; -import { logger } from "@/app/log"; +import { logger } from "@/registry/log"; import type { ConnectWebSocketOutput } from "@/worker/router-endpoints"; import type * as messageToServer from "@/worker/protocol/message/to-server"; import { parseMessage } from "@/worker/protocol/message/mod"; diff --git a/packages/core/src/inline-client-driver/log.ts b/packages/core/src/inline-client-driver/log.ts new file mode 100644 index 000000000..5d041248e --- /dev/null +++ b/packages/core/src/inline-client-driver/log.ts @@ -0,0 +1,7 @@ +import { getLogger } from "@/common//log"; + +export const LOGGER_NAME = "inline-client-driver"; + +export function logger() { + return getLogger(LOGGER_NAME); +} diff --git a/packages/core/src/app/inline-client-driver.ts b/packages/core/src/inline-client-driver/mod.ts similarity index 100% rename from packages/core/src/app/inline-client-driver.ts rename to packages/core/src/inline-client-driver/mod.ts diff --git a/packages/core/src/inspector/common.ts b/packages/core/src/inspector/common.ts index 8833fe480..ab8e0bc67 100644 --- a/packages/core/src/inspector/common.ts +++ b/packages/core/src/inspector/common.ts @@ -121,17 +121,17 @@ export function createInspectorRoute< logger: Logger; serverMessageSchema: ZodSchema; }) { - const app = new Hono(); + const router = new Hono(); if (!upgradeWebSocket || !onConnect || !config.enabled) { - return app.get("/", async (c) => { + return router.get("/", async (c) => { return c.json({ error: "Inspector disabled. Only available on WebSocket connections.", }); }); } - return app.get( + return router.get( "/", async (c, next) => { const result = diff --git a/packages/core/src/manager/router.ts b/packages/core/src/manager/router.ts index 7d2e864a8..57fac9c79 100644 --- a/packages/core/src/manager/router.ts +++ b/packages/core/src/manager/router.ts @@ -24,7 +24,7 @@ import { getRequestQuery, } from "@/worker/router-endpoints"; import { assertUnreachable } from "@/worker/utils"; -import type { AppConfig } from "@/app/config"; +import type { RegistryConfig } from "@/registry/config"; import { handleRouteError, handleRouteNotFound, @@ -110,7 +110,7 @@ function buildOpenApiResponses(schema: T) { } export function createManagerRouter( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, inlineClientDriver: ClientDriver, handler: ManagerRouterHandler, @@ -120,18 +120,18 @@ export function createManagerRouter( throw new Error("config.drivers.manager is not defined."); } const driver = driverConfig.drivers.manager; - const app = new OpenAPIHono(); + const router = new OpenAPIHono(); const upgradeWebSocket = driverConfig.getUpgradeWebSocket?.( - app as unknown as Hono, + router as unknown as Hono, ); - app.use("*", loggerMiddleware(logger())); + router.use("*", loggerMiddleware(logger())); - if (appConfig.cors) { - const corsConfig = appConfig.cors; + if (registryConfig.cors) { + const corsConfig = registryConfig.cors; - app.use("*", async (c, next) => { + router.use("*", async (c, next) => { const path = c.req.path; // Don't apply to WebSocket routes @@ -141,20 +141,20 @@ export function createManagerRouter( return cors({ ...corsConfig, - allowHeaders: [...(appConfig.cors?.allowHeaders ?? []), ...ALL_HEADERS], + allowHeaders: [...(registryConfig.cors?.allowHeaders ?? []), ...ALL_HEADERS], })(c, next); }); } // GET / - app.get("/", (c) => { + router.get("/", (c) => { return c.text( "This is an RivetKit server.\n\nLearn more at https://rivetkit.org", ); }); // GET /health - app.get("/health", (c) => { + router.get("/health", (c) => { return c.text("ok"); }); @@ -194,7 +194,7 @@ export function createManagerRouter( responses: buildOpenApiResponses(ResolveResponseSchema), }); - app.openapi(resolveRoute, (c) => handleResolveRequest(c, driver)); + router.openapi(resolveRoute, (c) => handleResolveRequest(c, driver)); } // GET /workers/connect/websocket @@ -215,11 +215,11 @@ export function createManagerRouter( }, }); - app.openapi(wsRoute, (c) => + router.openapi(wsRoute, (c) => handleWebSocketConnectRequest( c, upgradeWebSocket, - appConfig, + registryConfig, driverConfig, driver, handler, @@ -251,8 +251,8 @@ export function createManagerRouter( }, }); - app.openapi(sseRoute, (c) => - handleSseConnectRequest(c, appConfig, driverConfig, driver, handler), + router.openapi(sseRoute, (c) => + handleSseConnectRequest(c, registryConfig, driverConfig, driver, handler), ); } @@ -306,8 +306,8 @@ export function createManagerRouter( responses: buildOpenApiResponses(ActionResponseSchema), }); - app.openapi(actionRoute, (c) => - handleActionRequest(c, appConfig, driverConfig, driver, handler), + router.openapi(actionRoute, (c) => + handleActionRequest(c, registryConfig, driverConfig, driver, handler), ); } @@ -346,27 +346,27 @@ export function createManagerRouter( responses: buildOpenApiResponses(ConnectionMessageResponseSchema), }); - app.openapi(messageRoute, (c) => - handleMessageRequest(c, appConfig, handler), + router.openapi(messageRoute, (c) => + handleMessageRequest(c, registryConfig, handler), ); } - if (appConfig.inspector.enabled) { - app.route( + if (registryConfig.inspector.enabled) { + router.route( "/inspect", createManagerInspectorRouter( upgradeWebSocket, handler.onConnectInspector, - appConfig.inspector, + registryConfig.inspector, ), ); } - if (appConfig.test.enabled) { + if (registryConfig.test.enabled) { // Add HTTP endpoint to test the inline client // - // We have to do this in a router since this needs to run in the same server as the RivetKit app. Some test contexts to not run in the same server. - app.post(".test/inline-driver/call", async (c) => { + // We have to do this in a router since this needs to run in the same server as the RivetKit registry. Some test contexts to not run in the same server. + router.post(".test/inline-driver/call", async (c) => { // TODO: use openapi instead const buffer = await c.req.arrayBuffer(); const { encoding, transport, method, args }: TestInlineDriverCallRequest = @@ -395,7 +395,7 @@ export function createManagerRouter( }); if (upgradeWebSocket) { - app.get( + router.get( ".test/inline-driver/connect-websocket", upgradeWebSocket(async (c) => { const { @@ -536,7 +536,7 @@ export function createManagerRouter( }), ); } else { - app.get(".test/inline-driver/connect-websocket", (c) => { + router.get(".test/inline-driver/connect-websocket", (c) => { throw new Error( "websocket unsupported, fix the test to exclude websockets for this platform", ); @@ -544,7 +544,7 @@ export function createManagerRouter( } } - app.doc("/openapi.json", { + router.doc("/openapi.json", { openapi: "3.0.0", info: { version: VERSION, @@ -552,10 +552,10 @@ export function createManagerRouter( }, }); - app.notFound(handleRouteNotFound); - app.onError(handleRouteError.bind(undefined, {})); + router.notFound(handleRouteNotFound); + router.onError(handleRouteError.bind(undefined, {})); - return app as unknown as Hono; + return router as unknown as Hono; } export interface TestInlineDriverCallRequest { @@ -642,7 +642,7 @@ export async function queryWorker( */ async function handleSseConnectRequest( c: HonoContext, - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, driver: ManagerDriver, handler: ManagerRouterHandler, @@ -678,7 +678,7 @@ async function handleSseConnectRequest( // Use the shared SSE handler return await handleSseConnect( c, - appConfig, + registryConfig, driverConfig, handler.routingHandler.inline.handlers.onConnectSse, workerId, @@ -765,7 +765,7 @@ async function handleWebSocketConnectRequest( createEvents: (c: HonoContext) => any, ) => (c: HonoContext, next: Next) => Promise) | undefined, - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, driver: ManagerDriver, handler: ManagerRouterHandler, @@ -807,7 +807,7 @@ async function handleWebSocketConnectRequest( return upgradeWebSocket((c) => { return handleWebSocketConnect( c, - appConfig, + registryConfig, driverConfig, onConnectWebSocket, workerId, @@ -881,7 +881,7 @@ async function handleWebSocketConnectRequest( */ async function handleMessageRequest( c: HonoContext, - appConfig: AppConfig, + registryConfig: RegistryConfig, handler: ManagerRouterHandler, ): Promise { logger().debug("connection message request received"); @@ -906,7 +906,7 @@ async function handleMessageRequest( // Use shared connection message handler with direct parameters return handleConnectionMessage( c, - appConfig, + registryConfig, handler.routingHandler.inline.handlers.onConnMessage, connId, connToken as string, @@ -950,7 +950,7 @@ async function handleMessageRequest( */ async function handleActionRequest( c: HonoContext, - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, driver: ManagerDriver, handler: ManagerRouterHandler, @@ -983,7 +983,7 @@ async function handleActionRequest( // Use shared action handler with direct parameter return handleAction( c, - appConfig, + registryConfig, driverConfig, handler.routingHandler.inline.handlers.onAction, actionName, diff --git a/packages/core/src/mod.ts b/packages/core/src/mod.ts index d83cfe810..a327cf4ba 100644 --- a/packages/core/src/mod.ts +++ b/packages/core/src/mod.ts @@ -1,3 +1,3 @@ -export * from "@/app/mod"; +export * from "@/registry/mod"; export * from "@/worker/mod"; export * from "@/topologies/mod"; diff --git a/packages/core/src/app/config.ts b/packages/core/src/registry/config.ts similarity index 92% rename from packages/core/src/app/config.ts rename to packages/core/src/registry/config.ts index 49cccf4a4..d265ecb0f 100644 --- a/packages/core/src/app/config.ts +++ b/packages/core/src/registry/config.ts @@ -51,7 +51,7 @@ export const TestConfigSchema = z.object({ enabled: z.boolean() }); export type TestConfig = z.infer; /** Base config used for the worker config across all platforms. */ -export const AppConfigSchema = z.object({ +export const RegistryConfigSchema = z.object({ workers: z.record(z.string(), z.custom()), /** CORS configuration for the router. Uses Hono's CORS middleware options. */ @@ -82,8 +82,8 @@ export const AppConfigSchema = z.object({ **/ test: TestConfigSchema.optional().default({ enabled: false }), }); -export type AppConfig = z.infer; -export type AppConfigInput = Omit< - z.input, +export type RegistryConfig = z.infer; +export type RegistryConfigInput = Omit< + z.input, "workers" > & { workers: A }; diff --git a/packages/core/src/app/log.ts b/packages/core/src/registry/log.ts similarity index 72% rename from packages/core/src/app/log.ts rename to packages/core/src/registry/log.ts index 539a71f50..2fd1f8377 100644 --- a/packages/core/src/app/log.ts +++ b/packages/core/src/registry/log.ts @@ -1,6 +1,6 @@ import { getLogger } from "@/common//log"; -export const LOGGER_NAME = "worker-app"; +export const LOGGER_NAME = "registry"; export function logger() { return getLogger(LOGGER_NAME); diff --git a/packages/core/src/registry/mod.ts b/packages/core/src/registry/mod.ts new file mode 100644 index 000000000..47acebd51 --- /dev/null +++ b/packages/core/src/registry/mod.ts @@ -0,0 +1,28 @@ +import { + type Workers, + type RegistryConfig, + type RegistryConfigInput, + RegistryConfigSchema, +} from "./config"; + +export class Registry { + #config: RegistryConfig; + + public get config(): RegistryConfig { + return this.#config; + } + + constructor(config: RegistryConfig) { + this.#config = config; + } +} + +export function setup( + input: RegistryConfigInput, +): Registry { + const config = RegistryConfigSchema.parse(input); + return new Registry(config); +} + +export type { RegistryConfig }; +export { RegistryConfigSchema }; diff --git a/packages/core/src/test/driver/manager.ts b/packages/core/src/test/driver/manager.ts index 062b4b131..21df8fafd 100644 --- a/packages/core/src/test/driver/manager.ts +++ b/packages/core/src/test/driver/manager.ts @@ -9,7 +9,7 @@ import { WorkerAlreadyExists } from "@/worker/errors"; import type { TestGlobalState } from "./global-state"; import * as crypto from "node:crypto"; import { ManagerInspector } from "@/inspector/manager"; -import type { App } from "@/app/mod"; +import type { Registry } from "@/registry/mod"; import { WorkerOutput } from "@/manager/driver"; export class TestManagerDriver implements ManagerDriver { @@ -20,11 +20,11 @@ export class TestManagerDriver implements ManagerDriver { */ inspector: ManagerInspector = new ManagerInspector(this, { getAllWorkers: () => this.#state.getAllWorkers(), - getAllTypesOfWorkers: () => Object.keys(this.app.config.workers), + getAllTypesOfWorkers: () => Object.keys(this.registry.config.workers), }); constructor( - private readonly app: App, + private readonly registry: Registry, state: TestGlobalState, ) { this.#state = state; diff --git a/packages/core/src/test/mod.ts b/packages/core/src/test/mod.ts index a6c0c66b3..bc207091e 100644 --- a/packages/core/src/test/mod.ts +++ b/packages/core/src/test/mod.ts @@ -4,7 +4,7 @@ import { assertUnreachable } from "@/utils"; import { CoordinateTopology } from "@/topologies/coordinate/mod"; import { logger } from "./log"; import type { Hono } from "hono"; -import { StandaloneTopology, type App } from "@/mod"; +import { StandaloneTopology, type Registry } from "@/mod"; import { TestGlobalState, TestManagerDriver, @@ -16,7 +16,7 @@ import { type Client, createClient } from "@/client/mod"; import { createServer } from "node:net"; function createRouter( - app: App, + registry: Registry, inputConfig?: InputConfig, ): { router: Hono; @@ -29,7 +29,7 @@ function createRouter( if (!config.drivers.manager || !config.drivers.worker) { const memoryState = new TestGlobalState(); if (!config.drivers.manager) { - config.drivers.manager = new TestManagerDriver(app, memoryState); + config.drivers.manager = new TestManagerDriver(registry, memoryState); } if (!config.drivers.worker) { config.drivers.worker = new TestWorkerDriver(memoryState); @@ -41,8 +41,8 @@ function createRouter( // Save `injectWebSocket` for after server is created let injectWebSocket: NodeWebSocket["injectWebSocket"] | undefined; if (!config.getUpgradeWebSocket) { - config.getUpgradeWebSocket = (app) => { - const webSocket = createNodeWebSocket({ app }); + config.getUpgradeWebSocket = (router) => { + const webSocket = createNodeWebSocket({ app: router }); injectWebSocket = webSocket.injectWebSocket; return webSocket.upgradeWebSocket; }; @@ -50,13 +50,13 @@ function createRouter( // Setup topology if (config.topology === "standalone") { - const topology = new StandaloneTopology(app.config, config); + const topology = new StandaloneTopology(registry.config, config); if (!injectWebSocket) throw new Error("injectWebSocket not defined"); return { router: topology.router, injectWebSocket }; } else if (config.topology === "partition") { throw new Error("Node.js only supports standalone & coordinate topology."); } else if (config.topology === "coordinate") { - const topology = new CoordinateTopology(app.config, config); + const topology = new CoordinateTopology(registry.config, config); if (!injectWebSocket) throw new Error("injectWebSocket not defined"); return { router: topology.router, injectWebSocket }; } else { @@ -64,10 +64,10 @@ function createRouter( } } -function serve(app: App, inputConfig?: InputConfig): ServerType { +function serve(registry: Registry, inputConfig?: InputConfig): ServerType { const config = ConfigSchema.parse(inputConfig); - const { router, injectWebSocket } = createRouter(app, config); + const { router, injectWebSocket } = createRouter(registry, config); const server = honoServe({ fetch: router.fetch, @@ -84,7 +84,7 @@ function serve(app: App, inputConfig?: InputConfig): ServerType { return server; } -export interface SetupTestResult> { +export interface SetupTestResult> { client: Client; mockDriver: { workerDriver: { @@ -94,9 +94,9 @@ export interface SetupTestResult> { } // Must use `TestContext` since global hooks do not work when running concurrently -export async function setupTest>( +export async function setupTest>( c: TestContext, - app: A, + registry: A, ): Promise> { vi.useFakeTimers(); @@ -110,7 +110,7 @@ export async function setupTest>( // Start server with a random port const port = await getPort(); - const server = serve(app, { port }); + const server = serve(registry, { port }); c.onTestFinished( async () => await new Promise((resolve) => server.close(() => resolve())), ); diff --git a/packages/core/src/topologies/coordinate/conn/mod.ts b/packages/core/src/topologies/coordinate/conn/mod.ts index e489bf9d5..4890dd5a5 100644 --- a/packages/core/src/topologies/coordinate/conn/mod.ts +++ b/packages/core/src/topologies/coordinate/conn/mod.ts @@ -8,7 +8,7 @@ import { publishMessageToLeader } from "../node/message"; import { generateConnId, generateConnToken } from "@/worker/connection"; import type { WorkerDriver } from "@/worker/driver"; import { DriverConfig } from "@/driver-helpers/config"; -import { AppConfig } from "@/app/config"; +import { RegistryConfig } from "@/registry/config"; export interface RelayConnDriver { sendMessage(message: messageToClient.ToClient): void; @@ -19,7 +19,7 @@ export interface RelayConnDriver { * This is different than `Connection`. `Connection` represents the data of the connection state on the worker itself, `RelayConnection` supports managing a connection for a worker running on another machine over pubsub. */ export class RelayConn { - #appConfig: AppConfig; + #registryConfig: RegistryConfig; #driverConfig: DriverConfig; #coordinateDriver: CoordinateDriver; #workerDriver: WorkerDriver; @@ -48,7 +48,7 @@ export class RelayConn { } constructor( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, workerDriver: WorkerDriver, CoordinateDriver: CoordinateDriver, @@ -57,7 +57,7 @@ export class RelayConn { workerId: string, parameters: unknown, ) { - this.#appConfig = appConfig; + this.#registryConfig = registryConfig; this.#driverConfig = driverConfig; this.#coordinateDriver = CoordinateDriver; this.#workerDriver = workerDriver; @@ -83,7 +83,7 @@ export class RelayConn { // Create worker peer this.#workerPeer = await WorkerPeer.acquire( - this.#appConfig, + this.#registryConfig, this.#driverConfig, this.#workerDriver, this.#coordinateDriver, @@ -96,7 +96,7 @@ export class RelayConn { // Publish connection open await publishMessageToLeader( - this.#appConfig, + this.#registryConfig, this.#driverConfig, this.#coordinateDriver, this.#globalState, @@ -145,7 +145,7 @@ export class RelayConn { if (!fromLeader && this.#workerPeer?.leaderNodeId) { // Publish connection close await publishMessageToLeader( - this.#appConfig, + this.#registryConfig, this.#driverConfig, this.#coordinateDriver, this.#globalState, diff --git a/packages/core/src/topologies/coordinate/node/message.ts b/packages/core/src/topologies/coordinate/node/message.ts index 090db4d63..f98a297a4 100644 --- a/packages/core/src/topologies/coordinate/node/message.ts +++ b/packages/core/src/topologies/coordinate/node/message.ts @@ -4,7 +4,7 @@ import pRetry, { AbortError } from "p-retry"; import type { CoordinateDriver } from "../driver"; import type { NodeMessage } from "./protocol"; import { DriverConfig } from "@/driver-helpers/config"; -import { AppConfig } from "@/app/config"; +import { RegistryConfig } from "@/registry/config"; /** * Publishes a message and waits for an ack. If no ack is received, then retries accordingly. @@ -12,7 +12,7 @@ import { AppConfig } from "@/app/config"; * This should be used any time a message to the leader is being published since it correctly handles leadership transfer edge cases. */ export async function publishMessageToLeader( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, CoordinateDriver: CoordinateDriver, globalState: GlobalState, @@ -31,7 +31,7 @@ export async function publishMessageToLeader( await pRetry( () => publishMessageToLeaderInner( - appConfig, + registryConfig, driverConfig, CoordinateDriver, globalState, @@ -55,7 +55,7 @@ export async function publishMessageToLeader( } async function publishMessageToLeaderInner( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, CoordinateDriver: CoordinateDriver, globalState: GlobalState, @@ -92,7 +92,7 @@ async function publishMessageToLeaderInner( // Throw error on timeout const timeoutId = setTimeout( () => ackReject(new Error("Ack timed out")), - appConfig.workerPeer.messageAckTimeout, + registryConfig.workerPeer.messageAckTimeout, ); try { diff --git a/packages/core/src/topologies/coordinate/router/sse.ts b/packages/core/src/topologies/coordinate/router/sse.ts index 4f136ebaa..19e6df9a0 100644 --- a/packages/core/src/topologies/coordinate/router/sse.ts +++ b/packages/core/src/topologies/coordinate/router/sse.ts @@ -5,11 +5,11 @@ import type { CoordinateDriver } from "../driver"; import { RelayConn } from "../conn/mod"; import type { WorkerDriver } from "@/worker/driver"; import { DriverConfig } from "@/driver-helpers/config"; -import { AppConfig } from "@/app/config"; +import { RegistryConfig } from "@/registry/config"; import { ConnectSseOpts, ConnectSseOutput } from "@/worker/router-endpoints"; export async function serveSse( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, workerDriver: WorkerDriver, CoordinateDriver: CoordinateDriver, @@ -21,7 +21,7 @@ export async function serveSse( return { onOpen: async (stream) => { conn = new RelayConn( - appConfig, + registryConfig, driverConfig, workerDriver, CoordinateDriver, diff --git a/packages/core/src/topologies/coordinate/router/websocket.ts b/packages/core/src/topologies/coordinate/router/websocket.ts index abbbeb481..59e4d92c6 100644 --- a/packages/core/src/topologies/coordinate/router/websocket.ts +++ b/packages/core/src/topologies/coordinate/router/websocket.ts @@ -9,11 +9,11 @@ import { RelayConn } from "../conn/mod"; import { publishMessageToLeader } from "../node/message"; import type { WorkerDriver } from "@/worker/driver"; import type { DriverConfig } from "@/driver-helpers/config"; -import type { AppConfig } from "@/app/config"; +import type { RegistryConfig } from "@/registry/config"; import { ConnectWebSocketOpts, ConnectWebSocketOutput } from "@/worker/router-endpoints"; export async function serveWebSocket( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, workerDriver: WorkerDriver, CoordinateDriver: CoordinateDriver, @@ -25,7 +25,7 @@ export async function serveWebSocket( return { onOpen: async (ws: WSContext) => { conn = new RelayConn( - appConfig, + registryConfig, driverConfig, workerDriver, CoordinateDriver, @@ -50,7 +50,7 @@ export async function serveWebSocket( } await publishMessageToLeader( - appConfig, + registryConfig, driverConfig, CoordinateDriver, globalState, diff --git a/packages/core/src/topologies/coordinate/topology.ts b/packages/core/src/topologies/coordinate/topology.ts index 3b7d1af9c..8bd3e93b8 100644 --- a/packages/core/src/topologies/coordinate/topology.ts +++ b/packages/core/src/topologies/coordinate/topology.ts @@ -7,7 +7,7 @@ import type { RelayConn } from "./conn/mod"; import { Hono } from "hono"; import { handleRouteError, handleRouteNotFound } from "@/common/router"; import type { DriverConfig } from "@/driver-helpers/config"; -import type { AppConfig } from "@/app/config"; +import type { RegistryConfig } from "@/registry/config"; import { createManagerRouter } from "@/manager/router"; import type { ConnectWebSocketOpts, @@ -20,7 +20,7 @@ import type { ConnectionHandlers, } from "@/worker/router-endpoints"; import invariant from "invariant"; -import { createInlineClientDriver } from "@/app/inline-client-driver"; +import { createInlineClientDriver } from "@/inline-client-driver/mod"; import { serveWebSocket } from "./router/websocket"; import { serveSse } from "./router/sse"; import { ClientDriver } from "@/client/client"; @@ -40,7 +40,7 @@ export class CoordinateTopology { public readonly clientDriver: ClientDriver; public readonly router: Hono; - constructor(appConfig: AppConfig, driverConfig: DriverConfig) { + constructor(registryConfig: RegistryConfig, driverConfig: DriverConfig) { if (!driverConfig.drivers) throw new Error("config.drivers not defined."); const { worker: workerDriver, coordinate: CoordinateDriver } = driverConfig.drivers; @@ -62,10 +62,10 @@ export class CoordinateTopology { const node = new Node(CoordinateDriver, globalState); node.start(); - // Build app - const app = new Hono(); + // Build router + const router = new Hono(); - const upgradeWebSocket = driverConfig.getUpgradeWebSocket?.(app); + const upgradeWebSocket = driverConfig.getUpgradeWebSocket?.(router); // Share connection handlers for both routers const connectionHandlers: ConnectionHandlers = { @@ -73,7 +73,7 @@ export class CoordinateTopology { opts: ConnectWebSocketOpts, ): Promise => { return await serveWebSocket( - appConfig, + registryConfig, driverConfig, workerDriver, CoordinateDriver, @@ -84,7 +84,7 @@ export class CoordinateTopology { }, onConnectSse: async (opts: ConnectSseOpts): Promise => { return await serveSse( - appConfig, + registryConfig, driverConfig, workerDriver, CoordinateDriver, @@ -99,7 +99,7 @@ export class CoordinateTopology { }, onConnMessage: async (opts: ConnsMessageOpts): Promise => { await publishMessageToLeader( - appConfig, + registryConfig, driverConfig, CoordinateDriver, globalState, @@ -130,7 +130,7 @@ export class CoordinateTopology { // Build manager router const managerRouter = createManagerRouter( - appConfig, + registryConfig, driverConfig, this.clientDriver, { @@ -141,8 +141,8 @@ export class CoordinateTopology { }, ); - app.route("/", managerRouter); + router.route("/", managerRouter); - this.router = app; + this.router = router; } } diff --git a/packages/core/src/topologies/coordinate/worker-peer.ts b/packages/core/src/topologies/coordinate/worker-peer.ts index 21065cede..39b290ef6 100644 --- a/packages/core/src/topologies/coordinate/worker-peer.ts +++ b/packages/core/src/topologies/coordinate/worker-peer.ts @@ -9,10 +9,10 @@ import { createCoordinateRelayDriver, } from "./conn/driver"; import { DriverConfig } from "@/driver-helpers/config"; -import { AppConfig, AppConfigSchema } from "@/app/config"; +import { RegistryConfig, RegistryConfigSchema } from "@/registry/config"; export class WorkerPeer { - #appConfig: AppConfig; + #registryConfig: RegistryConfig; #driverConfig: DriverConfig; #coordinateDriver: CoordinateDriver; #workerDriver: WorkerDriver; @@ -43,14 +43,14 @@ export class WorkerPeer { } constructor( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, CoordinateDriver: CoordinateDriver, workerDriver: WorkerDriver, globalState: GlobalState, workerId: string, ) { - this.#appConfig = appConfig; + this.#registryConfig = registryConfig; this.#driverConfig = driverConfig; this.#coordinateDriver = CoordinateDriver; this.#workerDriver = workerDriver; @@ -60,7 +60,7 @@ export class WorkerPeer { /** Acquires a `WorkerPeer` for a connection and includes the connection ID in the references. */ static async acquire( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, workerDriver: WorkerDriver, CoordinateDriver: CoordinateDriver, @@ -73,7 +73,7 @@ export class WorkerPeer { // Create peer if needed if (!peer) { peer = new WorkerPeer( - appConfig, + registryConfig, driverConfig, CoordinateDriver, workerDriver, @@ -133,7 +133,7 @@ export class WorkerPeer { const { worker } = await this.#coordinateDriver.startWorkerAndAcquireLease( this.#workerId, this.#globalState.nodeId, - this.#appConfig.workerPeer.leaseDuration, + this.#registryConfig.workerPeer.leaseDuration, ); // Log logger().debug("starting worker peer", { @@ -189,13 +189,13 @@ export class WorkerPeer { let hbTimeout: number; if (this.#isLeader) { hbTimeout = - this.#appConfig.workerPeer.leaseDuration - - this.#appConfig.workerPeer.renewLeaseGrace; + this.#registryConfig.workerPeer.leaseDuration - + this.#registryConfig.workerPeer.renewLeaseGrace; } else { // TODO: Add jitter hbTimeout = - this.#appConfig.workerPeer.checkLeaseInterval + - Math.random() * this.#appConfig.workerPeer.checkLeaseJitter; + this.#registryConfig.workerPeer.checkLeaseInterval + + Math.random() * this.#registryConfig.workerPeer.checkLeaseJitter; } if (hbTimeout < 0) throw new Error("Worker peer heartbeat timeout is negative, check config"); @@ -209,7 +209,7 @@ export class WorkerPeer { // Build worker const workerName = this.#workerName; - const definition = this.#appConfig.workers[workerName]; + const definition = this.#registryConfig.workers[workerName]; if (!definition) throw new Error(`no worker definition for name ${definition}`); // Create leader worker @@ -240,7 +240,7 @@ export class WorkerPeer { const { leaseValid } = await this.#coordinateDriver.extendLease( this.#workerId, this.#globalState.nodeId, - this.#appConfig.workerPeer.leaseDuration, + this.#registryConfig.workerPeer.leaseDuration, ); if (leaseValid) { logger().debug("lease is valid", { workerId: this.#workerId }); @@ -260,7 +260,7 @@ export class WorkerPeer { await this.#coordinateDriver.attemptAcquireLease( this.#workerId, this.#globalState.nodeId, - this.#appConfig.workerPeer.leaseDuration, + this.#registryConfig.workerPeer.leaseDuration, ); // Check if the lease was successfully acquired and promoted to leader diff --git a/packages/core/src/topologies/partition/topology.ts b/packages/core/src/topologies/partition/topology.ts index 009d3ea0d..a40d158c2 100644 --- a/packages/core/src/topologies/partition/topology.ts +++ b/packages/core/src/topologies/partition/topology.ts @@ -22,7 +22,7 @@ import { import type { ConnDriver } from "@/worker/driver"; import type { WorkerKey } from "@/common/utils"; import type { DriverConfig } from "@/driver-helpers/config"; -import type { AppConfig } from "@/app/config"; +import type { RegistryConfig } from "@/registry/config"; import type { WorkerInspectorConnection } from "@/inspector/worker"; import { createManagerRouter } from "@/manager/router"; import type { ManagerInspectorConnection } from "@/inspector/manager"; @@ -40,7 +40,7 @@ import { ToServer } from "@/worker/protocol/message/to-server"; import { WorkerQuery } from "@/manager/protocol/query"; import { Encoding } from "@/mod"; import { EventSource } from "eventsource"; -import { createInlineClientDriver } from "@/app/inline-client-driver"; +import { createInlineClientDriver } from "@/inline-client-driver/mod"; import { ConnRoutingHandler, ConnRoutingHandlerCustom, @@ -64,7 +64,7 @@ export class PartitionTopologyManager { router: Hono; constructor( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, customRoutingHandlers: ConnRoutingHandlerCustom, ) { @@ -77,7 +77,7 @@ export class PartitionTopologyManager { this.clientDriver = createInlineClientDriver(managerDriver, routingHandler); this.router = createManagerRouter( - appConfig, + registryConfig, driverConfig, this.clientDriver, { @@ -115,7 +115,7 @@ export class PartitionTopologyManager { export class PartitionTopologyWorker { router: Hono; - #appConfig: AppConfig; + #registryConfig: RegistryConfig; #driverConfig: DriverConfig; #connDrivers: Record; #worker?: AnyWorkerInstance; @@ -130,15 +130,15 @@ export class PartitionTopologyWorker { **/ #workerStartedPromise?: PromiseWithResolvers = Promise.withResolvers(); - constructor(appConfig: AppConfig, driverConfig: DriverConfig) { - this.#appConfig = appConfig; + constructor(registryConfig: RegistryConfig, driverConfig: DriverConfig) { + this.#registryConfig = registryConfig; this.#driverConfig = driverConfig; const genericConnGlobalState = new GenericConnGlobalState(); this.#connDrivers = createGenericConnDrivers(genericConnGlobalState); // TODO: Store this worker router globally so we're not re-initializing it for every DO - this.router = createWorkerRouter(appConfig, driverConfig, { + this.router = createWorkerRouter(registryConfig, driverConfig, { getWorkerId: async () => { if (this.#workerStartedPromise) await this.#workerStartedPromise.promise; @@ -336,7 +336,7 @@ export class PartitionTopologyWorker { if (!workerDriver) throw new Error("config.drivers.worker not defined."); // Find worker prototype - const definition = this.#appConfig.workers[name]; + const definition = this.#registryConfig.workers[name]; // TODO: Handle error here gracefully somehow if (!definition) throw new Error(`no worker in registry for name ${definition}`); diff --git a/packages/core/src/topologies/partition/worker-router.ts b/packages/core/src/topologies/partition/worker-router.ts index a83375e62..22585803f 100644 --- a/packages/core/src/topologies/partition/worker-router.ts +++ b/packages/core/src/topologies/partition/worker-router.ts @@ -7,7 +7,7 @@ import { loggerMiddleware, } from "@/common/router"; import type { DriverConfig } from "@/driver-helpers/config"; -import type { AppConfig } from "@/app/config"; +import type { RegistryConfig } from "@/registry/config"; import { type WorkerInspectorConnHandler, createWorkerInspectorRouter, @@ -53,23 +53,23 @@ export interface WorkerRouterHandler { * Creates a router that runs on the partitioned instance. */ export function createWorkerRouter( - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, handler: WorkerRouterHandler, ): Hono { - const app = new Hono(); + const router = new Hono(); - const upgradeWebSocket = driverConfig.getUpgradeWebSocket?.(app); + const upgradeWebSocket = driverConfig.getUpgradeWebSocket?.(router); - app.use("*", loggerMiddleware(logger())); + router.use("*", loggerMiddleware(logger())); // Apply CORS middleware if configured // //This is only relevant if the worker is exposed directly publicly - if (appConfig.cors) { - const corsConfig = appConfig.cors; + if (registryConfig.cors) { + const corsConfig = registryConfig.cors; - app.use("*", async (c, next) => { + router.use("*", async (c, next) => { const path = c.req.path; // Don't apply to WebSocket routes, see https://hono.dev/docs/helpers/websocket#upgradewebsocket @@ -79,18 +79,18 @@ export function createWorkerRouter( return cors({ ...corsConfig, - allowHeaders: [...(appConfig.cors?.allowHeaders ?? []), ...ALL_HEADERS], + allowHeaders: [...(registryConfig.cors?.allowHeaders ?? []), ...ALL_HEADERS], })(c, next); }); } - app.get("/", (c) => { + router.get("/", (c) => { return c.text( "This is an RivetKit server.\n\nLearn more at https://rivetkit.org", ); }); - app.get("/health", (c) => { + router.get("/health", (c) => { return c.text("ok"); }); @@ -98,13 +98,13 @@ export function createWorkerRouter( const handlers = handler.connectionHandlers; if (upgradeWebSocket && handlers.onConnectWebSocket) { - app.get( + router.get( "/connect/websocket", upgradeWebSocket(async (c) => { const workerId = await handler.getWorkerId(); return handleWebSocketConnect( c as HonoContext, - appConfig, + registryConfig, driverConfig, handlers.onConnectWebSocket!, workerId, @@ -112,7 +112,7 @@ export function createWorkerRouter( }), ); } else { - app.get("/connect/websocket", (c) => { + router.get("/connect/websocket", (c) => { return c.text( "WebSockets are not enabled for this driver. Use SSE instead.", 400, @@ -120,21 +120,21 @@ export function createWorkerRouter( }); } - app.get("/connect/sse", async (c) => { + router.get("/connect/sse", async (c) => { if (!handlers.onConnectSse) { throw new Error("onConnectSse handler is required"); } const workerId = await handler.getWorkerId(); return handleSseConnect( c, - appConfig, + registryConfig, driverConfig, handlers.onConnectSse, workerId, ); }); - app.post("/action/:action", async (c) => { + router.post("/action/:action", async (c) => { if (!handlers.onAction) { throw new Error("onAction handler is required"); } @@ -142,7 +142,7 @@ export function createWorkerRouter( const workerId = await handler.getWorkerId(); return handleAction( c, - appConfig, + registryConfig, driverConfig, handlers.onAction, actionName, @@ -150,7 +150,7 @@ export function createWorkerRouter( ); }); - app.post("/connections/message", async (c) => { + router.post("/connections/message", async (c) => { if (!handlers.onConnMessage) { throw new Error("onConnMessage handler is required"); } @@ -162,7 +162,7 @@ export function createWorkerRouter( } return handleConnectionMessage( c, - appConfig, + registryConfig, handlers.onConnMessage, connId, connToken, @@ -170,24 +170,24 @@ export function createWorkerRouter( ); }); - if (appConfig.inspector.enabled) { - app.route( + if (registryConfig.inspector.enabled) { + router.route( "/inspect", createWorkerInspectorRouter( upgradeWebSocket, handler.onConnectInspector, - appConfig.inspector, + registryConfig.inspector, ), ); } - app.notFound(handleRouteNotFound); - app.onError( + router.notFound(handleRouteNotFound); + router.onError( handleRouteError.bind(undefined, { // All headers to this endpoint are considered secure, so we can enable the expose internal error header for requests from the internal client enableExposeInternalError: true, }), ); - return app; + return router; } diff --git a/packages/core/src/topologies/standalone/topology.ts b/packages/core/src/topologies/standalone/topology.ts index f4a9498cc..a74ff0547 100644 --- a/packages/core/src/topologies/standalone/topology.ts +++ b/packages/core/src/topologies/standalone/topology.ts @@ -19,7 +19,7 @@ import { } from "../common/generic-conn-driver"; import { ActionContext } from "@/worker/action"; import type { DriverConfig } from "@/driver-helpers/config"; -import type { AppConfig } from "@/app/config"; +import type { RegistryConfig } from "@/registry/config"; import { createManagerRouter } from "@/manager/router"; import type { ManagerInspectorConnection } from "@/inspector/manager"; import type { @@ -32,7 +32,7 @@ import type { ActionOutput, ConnectionHandlers, } from "@/worker/router-endpoints"; -import { createInlineClientDriver } from "@/app/inline-client-driver"; +import { createInlineClientDriver } from "@/inline-client-driver/mod"; import invariant from "invariant"; import { ClientDriver } from "@/client/client"; import { ConnRoutingHandler } from "@/worker/conn-routing-handler"; @@ -55,7 +55,7 @@ export class StandaloneTopology { clientDriver: ClientDriver; router: Hono; - #appConfig: AppConfig; + #registryConfig: RegistryConfig; #driverConfig: DriverConfig; #workers = new Map(); @@ -90,7 +90,7 @@ export class StandaloneTopology { if (!workerMetadata) throw new Error(`No worker found for ID ${workerId}`); // Build worker - const definition = this.#appConfig.workers[workerMetadata.name]; + const definition = this.#registryConfig.workers[workerMetadata.name]; if (!definition) throw new Error(`no worker in registry for name ${definition}`); @@ -120,17 +120,17 @@ export class StandaloneTopology { return { handler, worker }; } - constructor(appConfig: AppConfig, driverConfig: DriverConfig) { - this.#appConfig = appConfig; + constructor(registryConfig: RegistryConfig, driverConfig: DriverConfig) { + this.#registryConfig = registryConfig; this.#driverConfig = driverConfig; if (!driverConfig.drivers?.worker) throw new Error("config.drivers.worker not defined."); // Build router - const app = new Hono(); + const router = new Hono(); - const upgradeWebSocket = driverConfig.getUpgradeWebSocket?.(app); + const upgradeWebSocket = driverConfig.getUpgradeWebSocket?.(router); // Create shared connection handlers that will be used by both manager and worker routers const sharedConnectionHandlers: ConnectionHandlers = { @@ -271,7 +271,7 @@ export class StandaloneTopology { this.clientDriver = createInlineClientDriver(managerDriver, routingHandler); // Build manager router - const managerRouter = createManagerRouter(appConfig, driverConfig, this.clientDriver, { + const managerRouter = createManagerRouter(registryConfig, driverConfig, this.clientDriver, { routingHandler, onConnectInspector: async () => { const inspector = driverConfig.drivers?.manager?.inspector; @@ -299,8 +299,8 @@ export class StandaloneTopology { }, }); - app.route("/", managerRouter); + router.route("/", managerRouter); - this.router = app; + this.router = router; } } diff --git a/packages/core/src/worker/router-endpoints.ts b/packages/core/src/worker/router-endpoints.ts index 6fadaf418..15fb105f4 100644 --- a/packages/core/src/worker/router-endpoints.ts +++ b/packages/core/src/worker/router-endpoints.ts @@ -16,7 +16,7 @@ import type * as messageToServer from "@/worker/protocol/message/to-server"; import type { InputData, OutputData } from "@/worker/protocol/serde"; import { assertUnreachable } from "./utils"; import { deconstructError, stringifyError } from "@/common/utils"; -import type { AppConfig } from "@/app/config"; +import type { RegistryConfig } from "@/registry/config"; import type { DriverConfig } from "@/driver-helpers/config"; import invariant from "invariant"; @@ -82,7 +82,7 @@ export interface ConnectionHandlers { */ export function handleWebSocketConnect( context: HonoContext, - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, handler: (opts: ConnectWebSocketOpts) => Promise, workerId: string, @@ -113,7 +113,7 @@ export function handleWebSocketConnect( sharedWs?.close(1001, "timed out waiting for init message"); didTimeOut = true; onInitReject("init timed out"); - }, appConfig.webSocketInitTimeout); + }, registryConfig.webSocketInitTimeout); return { onOpen: async (_evt: any, ws: WSContext) => { @@ -129,7 +129,7 @@ export function handleWebSocketConnect( const value = evt.data.valueOf() as InputData; const message = await parseMessage(value, { encoding: encoding, - maxIncomingMessageSize: appConfig.maxIncomingMessageSize, + maxIncomingMessageSize: registryConfig.maxIncomingMessageSize, }); if ("i" in message.b) { @@ -251,13 +251,13 @@ export function handleWebSocketConnect( */ export async function handleSseConnect( c: HonoContext, - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, handler: (opts: ConnectSseOpts) => Promise, workerId: string, ) { const encoding = getRequestEncoding(c.req, false); - const parameters = getRequestConnParams(c.req, appConfig, driverConfig); + const parameters = getRequestConnParams(c.req, registryConfig, driverConfig); const sseHandler = await handler({ req: c.req, @@ -307,14 +307,14 @@ export async function handleSseConnect( */ export async function handleAction( c: HonoContext, - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, handler: (opts: ActionOpts) => Promise, actionName: string, workerId: string, ) { const encoding = getRequestEncoding(c.req, false); - const parameters = getRequestConnParams(c.req, appConfig, driverConfig); + const parameters = getRequestConnParams(c.req, registryConfig, driverConfig); logger().debug("handling action", { actionName, encoding }); @@ -390,7 +390,7 @@ export async function handleAction( */ export async function handleConnectionMessage( c: HonoContext, - appConfig: AppConfig, + registryConfig: RegistryConfig, handler: (opts: ConnsMessageOpts) => Promise, connId: string, connToken: string, @@ -412,7 +412,7 @@ export async function handleConnectionMessage( const uint8Array = new Uint8Array(value); message = await parseMessage(uint8Array as unknown as InputData, { encoding, - maxIncomingMessageSize: appConfig.maxIncomingMessageSize, + maxIncomingMessageSize: registryConfig.maxIncomingMessageSize, }); } catch (err) { throw new errors.InvalidRequest( @@ -514,7 +514,7 @@ export const ALL_HEADERS = [ // Helper to get connection parameters for the request export function getRequestConnParams( req: HonoRequest, - appConfig: AppConfig, + registryConfig: RegistryConfig, driverConfig: DriverConfig, ): unknown { const paramsParam = req.header(HEADER_CONN_PARAMS); diff --git a/packages/core/tests/driver-test-suite.test.ts b/packages/core/tests/driver-test-suite.test.ts index 729a14ce3..da8becd01 100644 --- a/packages/core/tests/driver-test-suite.test.ts +++ b/packages/core/tests/driver-test-suite.test.ts @@ -6,11 +6,11 @@ import { join } from "node:path"; runDriverTests({ async start(projectPath: string) { - return await createTestRuntime(join(projectPath, "app.ts"), async (app) => { + return await createTestRuntime(join(projectPath, "registry.ts"), async (registry) => { const memoryState = new TestGlobalState(); return { workerDriver: new TestWorkerDriver(memoryState), - managerDriver: new TestManagerDriver(app, memoryState), + managerDriver: new TestManagerDriver(registry, memoryState), }; }); }, diff --git a/packages/drivers/file-system/src/manager.ts b/packages/drivers/file-system/src/manager.ts index b0795aaeb..4ea8d2653 100644 --- a/packages/drivers/file-system/src/manager.ts +++ b/packages/drivers/file-system/src/manager.ts @@ -11,7 +11,7 @@ import { WorkerAlreadyExists } from "rivetkit/errors"; import { logger } from "./log"; import type { FileSystemGlobalState } from "./global-state"; import { WorkerState } from "./global-state"; -import type { App } from "rivetkit"; +import type { Registry } from "rivetkit"; import { ManagerInspector } from "rivetkit/inspector"; export class FileSystemManagerDriver implements ManagerDriver { @@ -22,11 +22,11 @@ export class FileSystemManagerDriver implements ManagerDriver { */ inspector: ManagerInspector = new ManagerInspector(this, { getAllWorkers: () => this.#state.getAllWorkers(), - getAllTypesOfWorkers: () => Object.keys(this.app.config.workers), + getAllTypesOfWorkers: () => Object.keys(this.registry.config.workers), }); constructor( - private readonly app: App, + private readonly registry: Registry, state: FileSystemGlobalState, ) { this.#state = state; diff --git a/packages/drivers/file-system/tests/driver-tests.test.ts b/packages/drivers/file-system/tests/driver-tests.test.ts index 94cc5e858..ebc429ae6 100644 --- a/packages/drivers/file-system/tests/driver-tests.test.ts +++ b/packages/drivers/file-system/tests/driver-tests.test.ts @@ -13,7 +13,7 @@ import * as fs from "node:fs/promises"; runDriverTests({ async start(appPath: string) { - return await createTestRuntime(appPath, async (app) => { + return await createTestRuntime(appPath, async (registry) => { // Create a unique temp directory for each test const testDir = path.join( os.tmpdir(), @@ -24,7 +24,7 @@ runDriverTests({ const fileSystemState = new FileSystemGlobalState(testDir); return { workerDriver: new FileSystemWorkerDriver(fileSystemState), - managerDriver: new FileSystemManagerDriver(app, fileSystemState), + managerDriver: new FileSystemManagerDriver(registry, fileSystemState), async cleanup() { await fs.rmdir(testDir, { recursive: true }); diff --git a/packages/drivers/memory/src/manager.ts b/packages/drivers/memory/src/manager.ts index d37e1883d..afbe5735f 100644 --- a/packages/drivers/memory/src/manager.ts +++ b/packages/drivers/memory/src/manager.ts @@ -10,7 +10,7 @@ import { WorkerAlreadyExists } from "rivetkit/errors"; import type { MemoryGlobalState } from "./global-state"; import * as crypto from "node:crypto"; import { ManagerInspector } from "rivetkit/inspector"; -import type { App } from "rivetkit"; +import type { Registry } from "rivetkit"; export class MemoryManagerDriver implements ManagerDriver { #state: MemoryGlobalState; @@ -20,11 +20,11 @@ export class MemoryManagerDriver implements ManagerDriver { */ inspector: ManagerInspector = new ManagerInspector(this, { getAllWorkers: () => this.#state.getAllWorkers(), - getAllTypesOfWorkers: () => Object.keys(this.app.config.workers), + getAllTypesOfWorkers: () => Object.keys(this.registry.config.workers), }); constructor( - private readonly app: App, + private readonly registry: Registry, state: MemoryGlobalState, ) { this.#state = state; diff --git a/packages/drivers/memory/tests/driver-tests.test.ts b/packages/drivers/memory/tests/driver-tests.test.ts index 41964dd31..21c434e18 100644 --- a/packages/drivers/memory/tests/driver-tests.test.ts +++ b/packages/drivers/memory/tests/driver-tests.test.ts @@ -7,11 +7,11 @@ import { runDriverTests({ async start(appPath: string) { - return await createTestRuntime(appPath, async (app) => { + return await createTestRuntime(appPath, async (registry) => { const memoryState = new MemoryGlobalState(); return { workerDriver: new MemoryWorkerDriver(memoryState), - managerDriver: new MemoryManagerDriver(app, memoryState), + managerDriver: new MemoryManagerDriver(registry, memoryState), }; }); }, diff --git a/packages/drivers/redis/src/manager.ts b/packages/drivers/redis/src/manager.ts index 54d8b4d74..ad5e4e853 100644 --- a/packages/drivers/redis/src/manager.ts +++ b/packages/drivers/redis/src/manager.ts @@ -11,7 +11,7 @@ import type Redis from "ioredis"; import * as crypto from "node:crypto"; import { KEYS } from "./keys"; import { ManagerInspector } from "rivetkit/inspector"; -import type { App } from "rivetkit"; +import type { Registry } from "rivetkit"; interface Worker { id: string; @@ -24,7 +24,7 @@ interface Worker { export class RedisManagerDriver implements ManagerDriver { #redis: Redis; - #app?: App; + #registry?: Registry; /** * @internal @@ -40,14 +40,14 @@ export class RedisManagerDriver implements ManagerDriver { return workers; }, getAllTypesOfWorkers: () => { - if (!this.#app) return []; - return Object.keys(this.#app.config.workers); + if (!this.#registry) return []; + return Object.keys(this.#registry.config.workers); }, }); - constructor(redis: Redis, app?: App) { + constructor(redis: Redis, registry?: Registry) { this.#redis = redis; - this.#app = app; + this.#registry = registry; } async getForId({ workerId }: GetForIdInput): Promise { diff --git a/packages/drivers/redis/tests/driver-tests.test.ts b/packages/drivers/redis/tests/driver-tests.test.ts index 590ac9387..575652c1a 100644 --- a/packages/drivers/redis/tests/driver-tests.test.ts +++ b/packages/drivers/redis/tests/driver-tests.test.ts @@ -73,7 +73,7 @@ // // Causes odd connectoin issues when disabled // useRealTimers: true, // async start(appPath: string) { -// return await createTestRuntime(appPath, async (app) => { +// return await createTestRuntime(appPath, async (registry) => { // const { port, containerId } = await startValkeyContainer(); // // // Create a new Redis client for this test (we still use ioredis for client) @@ -88,7 +88,7 @@ // // return { // workerDriver: new RedisWorkerDriver(redisClient), -// managerDriver: new RedisManagerDriver(redisClient, app), +// managerDriver: new RedisManagerDriver(redisClient, registry), // coordinateDriver: new RedisCoordinateDriver(redisClient), // async cleanup() { // // TODO: This causes an error diff --git a/packages/frameworks/framework-base/src/mod.ts b/packages/frameworks/framework-base/src/mod.ts index 31b901095..a7e179ef5 100644 --- a/packages/frameworks/framework-base/src/mod.ts +++ b/packages/frameworks/framework-base/src/mod.ts @@ -70,8 +70,8 @@ // //export class WorkerManager< // C extends ClientRaw, -// App extends ExtractAppFromClient, -// Registry extends ExtractWorkersFromApp, +// Registry extends ExtractAppFromClient, +// Registry extends ExtractWorkersFromRegistry, // WorkerName extends keyof Registry, // AD extends Registry[WorkerName], //> { diff --git a/packages/frameworks/react/README.md b/packages/frameworks/react/README.md index 522899c83..e9b490d68 100644 --- a/packages/frameworks/react/README.md +++ b/packages/frameworks/react/README.md @@ -26,11 +26,11 @@ bun add rivetkit/react ```tsx import { createClient } from "rivetkit/client"; import { createReactActorCore } from "@rivetkit/react"; -import type { App } from "../counter/src/index"; +import type { Registry } from "../counter/src/index"; import React, { useState } from "react"; // Create a client -const client = createClient("http://your-rivetkit-server.com"); +const client = createClient("http://your-rivetkit-server.com"); // Create React hooks for your actors const { useActor, useActorEvent } = createReactActorCore(client); diff --git a/packages/frameworks/react/src/mod.tsx b/packages/frameworks/react/src/mod.tsx index 27c0a3264..f04ae2c6b 100644 --- a/packages/frameworks/react/src/mod.tsx +++ b/packages/frameworks/react/src/mod.tsx @@ -16,8 +16,8 @@ //} from "react"; // //export function createReactActorCore(client: Client) { -// type App = ExtractAppFromClient; -// type Registry = ExtractActorsFromApp; +// type Registry = ExtractAppFromClient; +// type Registry = ExtractActorsFromRegistry; // return { // useActor: function useActor< // N extends keyof Registry, @@ -28,7 +28,7 @@ // ) { // const [manager] = useState( // () => -// new ActorManager(client, name, options), +// new ActorManager(client, name, options), // ); // // const state = useSyncExternalStore( diff --git a/packages/platforms/bun/src/mod.ts b/packages/platforms/bun/src/mod.ts index 994538213..fe678cbaa 100644 --- a/packages/platforms/bun/src/mod.ts +++ b/packages/platforms/bun/src/mod.ts @@ -5,7 +5,7 @@ import { ConfigSchema, type InputConfig } from "./config"; import { logger } from "./log"; import { createBunWebSocket } from "hono/bun"; import type { Hono } from "hono"; -import { type App, StandaloneTopology } from "rivetkit"; +import { type Registry, StandaloneTopology } from "rivetkit"; import { MemoryGlobalState, MemoryManagerDriver, @@ -16,7 +16,7 @@ import { FileSystemWorkerDriver, FileSystemGlobalState, FileSystemManagerDriver export { InputConfig as Config } from "./config"; export function createRouter( - app: App, + registry: Registry, inputConfig?: InputConfig, ): { router: Hono; @@ -39,7 +39,7 @@ export function createRouter( if (config.mode === "file-system") { const fsState = new FileSystemGlobalState(); if (!config.drivers.manager) { - config.drivers.manager = new FileSystemManagerDriver(app, fsState); + config.drivers.manager = new FileSystemManagerDriver(registry, fsState); } if (!config.drivers.worker) { config.drivers.worker = new FileSystemWorkerDriver(fsState); @@ -47,7 +47,7 @@ export function createRouter( } else if (config.mode === "memory") { const memoryState = new MemoryGlobalState(); if (!config.drivers.manager) { - config.drivers.manager = new MemoryManagerDriver(app, memoryState); + config.drivers.manager = new MemoryManagerDriver(registry, memoryState); } if (!config.drivers.worker) { config.drivers.worker = new MemoryWorkerDriver(memoryState); @@ -59,12 +59,12 @@ export function createRouter( // Setup topology if (config.topology === "standalone") { - const topology = new StandaloneTopology(app.config, config); + const topology = new StandaloneTopology(registry.config, config); return { router: topology.router, webSocketHandler }; } else if (config.topology === "partition") { throw new Error("Bun only supports standalone & coordinate topology."); } else if (config.topology === "coordinate") { - const topology = new CoordinateTopology(app.config, config); + const topology = new CoordinateTopology(registry.config, config); return { router: topology.router, webSocketHandler }; } else { assertUnreachable(config.topology); @@ -72,12 +72,12 @@ export function createRouter( } export function createHandler( - app: App, + registry: Registry, inputConfig?: InputConfig, ): Serve { const config = ConfigSchema.parse(inputConfig); - const { router, webSocketHandler } = createRouter(app, config); + const { router, webSocketHandler } = createRouter(registry, config); return { hostname: config.hostname, @@ -88,12 +88,12 @@ export function createHandler( } export function serve( - app: App, + registry: Registry, inputConfig: InputConfig, ): Server { const config = ConfigSchema.parse(inputConfig); - const handler = createHandler(app, config); + const handler = createHandler(registry, config); const server = Bun.serve(handler); logger().info("rivetkit started", { diff --git a/packages/platforms/cloudflare-workers/src/handler.ts b/packages/platforms/cloudflare-workers/src/handler.ts index a8ffc3c82..522383d6c 100644 --- a/packages/platforms/cloudflare-workers/src/handler.ts +++ b/packages/platforms/cloudflare-workers/src/handler.ts @@ -9,7 +9,7 @@ import type { Hono } from "hono"; import { PartitionTopologyManager } from "rivetkit/topologies/partition"; import { logger } from "./log"; import { CloudflareWorkersManagerDriver } from "./manager-driver"; -import { Encoding, App } from "rivetkit"; +import { Encoding, Registry } from "rivetkit"; import { upgradeWebSocket } from "./websocket"; import invariant from "invariant"; import { AsyncLocalStorage } from "node:async_hooks"; @@ -35,14 +35,14 @@ export function getCloudflareAmbientEnv(): Bindings { } export function createHandler( - app: App, + registry: Registry, inputConfig?: InputConfig, ): { handler: ExportedHandler; WorkerHandler: DurableObjectConstructor; } { // Create router - const { router, WorkerHandler } = createRouter(app, inputConfig); + const { router, WorkerHandler } = createRouter(registry, inputConfig); // Create Cloudflare handler const handler = { @@ -55,7 +55,7 @@ export function createHandler( } export function createRouter( - app: App, + registry: Registry, inputConfig?: InputConfig, ): { router: Hono<{ Bindings: Bindings }>; @@ -75,12 +75,12 @@ export function createRouter( driverConfig.getUpgradeWebSocket = () => upgradeWebSocket; // Create Durable Object - const WorkerHandler = createWorkerDurableObject(app, driverConfig); + const WorkerHandler = createWorkerDurableObject(registry, driverConfig); driverConfig.topology = driverConfig.topology ?? "partition"; if (driverConfig.topology === "partition") { const managerTopology = new PartitionTopologyManager( - app.config, + registry.config, driverConfig, { sendRequest: async ( diff --git a/packages/platforms/cloudflare-workers/src/worker-handler-do.ts b/packages/platforms/cloudflare-workers/src/worker-handler-do.ts index 03ad7b55e..384577238 100644 --- a/packages/platforms/cloudflare-workers/src/worker-handler-do.ts +++ b/packages/platforms/cloudflare-workers/src/worker-handler-do.ts @@ -1,5 +1,5 @@ import { DurableObject } from "cloudflare:workers"; -import type { App, WorkerKey } from "rivetkit"; +import type { Registry, WorkerKey } from "rivetkit"; import { logger } from "./log"; import type { Config } from "./config"; import { PartitionTopologyWorker } from "rivetkit/topologies/partition"; @@ -42,7 +42,7 @@ interface LoadedWorker { } export function createWorkerDurableObject( - app: App, + registry: Registry, config: Config, ): DurableObjectConstructor { const globalState = new CloudflareDurableObjectGlobalState(); @@ -105,7 +105,7 @@ export function createWorkerDurableObject( if (!config.drivers.worker) { config.drivers.worker = new CloudflareWorkersWorkerDriver(globalState); } - const workerTopology = new PartitionTopologyWorker(app.config, config); + const workerTopology = new PartitionTopologyWorker(registry.config, config); // Register DO with global state // HACK: This leaks the DO context, but DO does not provide a native way diff --git a/packages/platforms/cloudflare-workers/tests/driver-tests.test.ts b/packages/platforms/cloudflare-workers/tests/driver-tests.test.ts index 9b00bb07a..054937e78 100644 --- a/packages/platforms/cloudflare-workers/tests/driver-tests.test.ts +++ b/packages/platforms/cloudflare-workers/tests/driver-tests.test.ts @@ -180,14 +180,14 @@ async function setupProject(projectPath: string) { // Write script const indexContent = `import { createHandler } from "@rivetkit/cloudflare-workers"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -// TODO: Find a cleaner way of flagging an app as test mode (ideally not in the config itself) +// TODO: Find a cleaner way of flagging an registry as test mode (ideally not in the config itself) // Force enable test -app.config.test.enabled = true; +registry.config.test.enabled = true; // Create handlers for Cloudflare Workers -const { handler, WorkerHandler } = createHandler(app); +const { handler, WorkerHandler } = createHandler(registry); // Export the handlers for Cloudflare export { handler as default, WorkerHandler }; diff --git a/packages/platforms/nodejs/src/mod.ts b/packages/platforms/nodejs/src/mod.ts index aa02f78c0..043d1ef44 100644 --- a/packages/platforms/nodejs/src/mod.ts +++ b/packages/platforms/nodejs/src/mod.ts @@ -4,7 +4,7 @@ import { assertUnreachable } from "rivetkit/utils"; import { CoordinateTopology } from "rivetkit/topologies/coordinate"; import { logger } from "./log"; import type { Hono } from "hono"; -import { StandaloneTopology, type App } from "rivetkit"; +import { StandaloneTopology, type Registry } from "rivetkit"; import { MemoryGlobalState, MemoryManagerDriver, @@ -20,7 +20,7 @@ import { export { InputConfig as Config } from "./config"; export function createRouter( - app: App, + registry: Registry, inputConfig?: InputConfig, ): { router: Hono; @@ -34,7 +34,7 @@ export function createRouter( if (config.mode === "file-system") { const fsState = new FileSystemGlobalState(); if (!config.drivers.manager) { - config.drivers.manager = new FileSystemManagerDriver(app, fsState); + config.drivers.manager = new FileSystemManagerDriver(registry, fsState); } if (!config.drivers.worker) { config.drivers.worker = new FileSystemWorkerDriver(fsState); @@ -42,7 +42,7 @@ export function createRouter( } else if (config.mode === "memory") { const memoryState = new MemoryGlobalState(); if (!config.drivers.manager) { - config.drivers.manager = new MemoryManagerDriver(app, memoryState); + config.drivers.manager = new MemoryManagerDriver(registry, memoryState); } if (!config.drivers.worker) { config.drivers.worker = new MemoryWorkerDriver(memoryState); @@ -57,8 +57,8 @@ export function createRouter( // Save `injectWebSocket` for after server is created let injectWebSocket: NodeWebSocket["injectWebSocket"] | undefined; if (!config.getUpgradeWebSocket) { - config.getUpgradeWebSocket = (app) => { - const webSocket = createNodeWebSocket({ app }); + config.getUpgradeWebSocket = (router) => { + const webSocket = createNodeWebSocket({ app: router }); injectWebSocket = webSocket.injectWebSocket; return webSocket.upgradeWebSocket; }; @@ -66,13 +66,13 @@ export function createRouter( // Setup topology if (config.topology === "standalone") { - const topology = new StandaloneTopology(app.config, config); + const topology = new StandaloneTopology(registry.config, config); if (!injectWebSocket) throw new Error("injectWebSocket not defined"); return { router: topology.router, injectWebSocket }; } else if (config.topology === "partition") { throw new Error("Node.js only supports standalone & coordinate topology."); } else if (config.topology === "coordinate") { - const topology = new CoordinateTopology(app.config, config); + const topology = new CoordinateTopology(registry.config, config); if (!injectWebSocket) throw new Error("injectWebSocket not defined"); return { router: topology.router, injectWebSocket }; } else { @@ -81,12 +81,12 @@ export function createRouter( } export function serve( - app: App, + registry: Registry, inputConfig?: InputConfig, ): ServerType { const config = ConfigSchema.parse(inputConfig); - const { router, injectWebSocket } = createRouter(app, config); + const { router, injectWebSocket } = createRouter(registry, config); const server = honoServe({ fetch: router.fetch, diff --git a/packages/platforms/rivet/src/manager.ts b/packages/platforms/rivet/src/manager.ts index f7307c8e1..4f0ca3d99 100644 --- a/packages/platforms/rivet/src/manager.ts +++ b/packages/platforms/rivet/src/manager.ts @@ -8,11 +8,11 @@ import { PartitionTopologyManager } from "rivetkit/topologies/partition"; import { proxy } from "hono/proxy"; import invariant from "invariant"; import { ConfigSchema, InputConfig } from "./config"; -import type { App } from "rivetkit"; +import type { Registry } from "rivetkit"; import { createWebSocketProxy } from "./ws-proxy"; export async function startManager( - app: App, + registry: Registry, inputConfig?: InputConfig, ): Promise { setupLogging(); @@ -45,15 +45,15 @@ export async function startManager( }; //// Force disable inspector - //driverConfig.app.config.inspector = { + //driverConfig.registry.config.inspector = { // enabled: false, //}; - //const corsConfig = driverConfig.app.config.cors; + //const corsConfig = driverConfig.registry.config.cors; // //// Enable CORS for Rivet domains - //driverConfig.app.config.cors = { - // ...driverConfig.app.config.cors, + //driverConfig.registry.config.cors = { + // ...driverConfig.registry.config.cors, // origin: (origin, c) => { // const isRivetOrigin = // origin.endsWith(".rivet.gg") || origin.includes("localhost:"); @@ -93,7 +93,7 @@ export async function startManager( // Create manager topology driverConfig.topology = driverConfig.topology ?? "partition"; const managerTopology = new PartitionTopologyManager( - app.config, + registry.config, driverConfig, { sendRequest: async (workerId, meta, workerRequest) => { @@ -181,7 +181,7 @@ export async function startManager( // import { logger as honoLogger } from "hono/logger"; // // export async function startManager( -// app: App, +// registry: Registry, // inputConfig?: InputConfig, // ): Promise { // const port = parseInt(process.env.PORT_HTTP!); diff --git a/packages/platforms/rivet/src/worker.ts b/packages/platforms/rivet/src/worker.ts index 31cfa878e..9b53ae007 100644 --- a/packages/platforms/rivet/src/worker.ts +++ b/packages/platforms/rivet/src/worker.ts @@ -6,12 +6,12 @@ import { PartitionTopologyWorker } from "rivetkit/topologies/partition"; import { RivetWorkerDriver } from "./worker-driver"; import invariant from "invariant"; import type { ActorContext } from "@rivet-gg/actor-core"; -import { App } from "rivetkit"; +import { Registry } from "rivetkit"; import { type Config, ConfigSchema, type InputConfig } from "./config"; import { stringifyError } from "rivetkit/utils"; export function createWorkerHandler( - app: App, + registry: Registry, inputConfig?: InputConfig, ): RivetHandler { let driverConfig: Config; @@ -26,7 +26,7 @@ export function createWorkerHandler( async start(ctx: ActorContext) { const role = ctx.metadata.actor.tags.role; if (role === "worker") { - await startWorker(ctx, app, driverConfig); + await startWorker(ctx, registry, driverConfig); } else { throw new Error(`Unexpected role (must be worker): ${role}`); } @@ -36,7 +36,7 @@ export function createWorkerHandler( async function startWorker( ctx: ActorContext, - app: App, + registry: Registry, driverConfig: Config, ): Promise { setupLogging(); @@ -70,7 +70,7 @@ async function startWorker( driverConfig.getUpgradeWebSocket = () => upgradeWebSocket; } - //app.config.inspector = { + //registry.config.inspector = { // enabled: true, // onRequest: async (c) => { // const url = new URL(c.req.url); @@ -93,11 +93,11 @@ async function startWorker( // }, //}; - //const corsConfig = app.config.cors; + //const corsConfig = registry.config.cors; // //// Enable CORS for Rivet domains - //app.config.cors = { - // ...app.config.cors, + //registry.config.cors = { + // ...registry.config.cors, // origin: (origin, c) => { // const isRivetOrigin = // origin.endsWith(".rivet.gg") || origin.includes("localhost:"); @@ -118,7 +118,7 @@ async function startWorker( // Create worker topology driverConfig.topology = driverConfig.topology ?? "partition"; - const workerTopology = new PartitionTopologyWorker(app.config, driverConfig); + const workerTopology = new PartitionTopologyWorker(registry.config, driverConfig); // Set a catch-all route const router = workerTopology.router; diff --git a/packages/platforms/rivet/tests/deployment.test.ts b/packages/platforms/rivet/tests/deployment.test.ts index 2da3790aa..b8be2e214 100644 --- a/packages/platforms/rivet/tests/deployment.test.ts +++ b/packages/platforms/rivet/tests/deployment.test.ts @@ -26,15 +26,15 @@ const counter = worker({ }, }); -export const app = setup({ +export const registry = setup({ workers: { counter }, }); -export type App = typeof app; +export type Registry = typeof registry; `; test("Rivet deployment tests", async () => { - const tempFilePath = path.join(os.tmpdir(), `app-${randomUUID()}`); + const tempFilePath = path.join(os.tmpdir(), `registry-${randomUUID()}`); await fs.writeFile(tempFilePath, COUNTER_WORKER); - await deployToRivet("test-app", tempFilePath, true); + await deployToRivet("test-registry", tempFilePath, true); }); diff --git a/packages/platforms/rivet/tests/rivet-deploy.ts b/packages/platforms/rivet/tests/rivet-deploy.ts index 32160e0fd..f4a27ac4d 100644 --- a/packages/platforms/rivet/tests/rivet-deploy.ts +++ b/packages/platforms/rivet/tests/rivet-deploy.ts @@ -72,7 +72,7 @@ async function packPackage( */ export async function deployToRivet(projectPath: string) { console.log("=== START deployToRivet ==="); - console.log(`Deploying app from path: ${projectPath}`); + console.log(`Deploying registry from path: ${projectPath}`); // Create a temporary directory for the test const uuid = crypto.randomUUID(); @@ -232,24 +232,24 @@ node_modules await fs.cp(projectPath, projectDestDir, { recursive: true }); const serverTsContent = `import { startManager } from "@rivetkit/rivet/manager"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -// TODO: Find a cleaner way of flagging an app as test mode (ideally not in the config itself) +// TODO: Find a cleaner way of flagging an registry as test mode (ideally not in the config itself) // Force enable test -app.config.test.enabled = true; +registry.config.test.enabled = true; -startManager(app); +startManager(registry); `; await writeFile(tmpDir, "src/server.ts", serverTsContent); const workerTsContent = `import { createWorkerHandler } from "@rivetkit/rivet/worker"; -import { app } from "./workers/app"; +import { registry } from "./workers/registry"; -// TODO: Find a cleaner way of flagging an app as test mode (ideally not in the config itself) +// TODO: Find a cleaner way of flagging an registry as test mode (ideally not in the config itself) // Force enable test -app.config.test.enabled = true; +registry.config.test.enabled = true; -export default createWorkerHandler(app);`; +export default createWorkerHandler(registry);`; await writeFile(tmpDir, "src/worker.ts", workerTsContent); // Build and deploy to Rivet