diff --git a/examples/trpc/package.json b/examples/trpc/package.json index c9a7cb014..9a42fc20a 100644 --- a/examples/trpc/package.json +++ b/examples/trpc/package.json @@ -17,7 +17,7 @@ "dependencies": { "@trpc/client": "^11.3.1", "@trpc/server": "^11.4.2", - "zod": "^3.24.1" + "zod": "^3.25.67" }, "stableVersion": "0.8.0" } diff --git a/packages/core/fixtures/driver-test-suite/action-inputs.ts b/packages/core/fixtures/driver-test-suite/action-inputs.ts index fd4caa654..b910a0522 100644 --- a/packages/core/fixtures/driver-test-suite/action-inputs.ts +++ b/packages/core/fixtures/driver-test-suite/action-inputs.ts @@ -28,4 +28,3 @@ export const inputActor = actor({ }, }, }); - diff --git a/packages/core/fixtures/driver-test-suite/action-timeout.ts b/packages/core/fixtures/driver-test-suite/action-timeout.ts index f3b32ffa7..73e7e8180 100644 --- a/packages/core/fixtures/driver-test-suite/action-timeout.ts +++ b/packages/core/fixtures/driver-test-suite/action-timeout.ts @@ -66,5 +66,3 @@ export const syncTimeoutActor = actor({ }, }, }); - - diff --git a/packages/core/fixtures/driver-test-suite/action-types.ts b/packages/core/fixtures/driver-test-suite/action-types.ts index da34b99e7..b8200be27 100644 --- a/packages/core/fixtures/driver-test-suite/action-types.ts +++ b/packages/core/fixtures/driver-test-suite/action-types.ts @@ -1,4 +1,4 @@ -import { actor, UserError } from "@rivetkit/core"; +import { UserError, actor } from "@rivetkit/core"; // Actor with synchronous actions export const syncActionActor = actor({ @@ -6,7 +6,7 @@ export const syncActionActor = actor({ state: { value: 0 }, actions: { // Simple synchronous action that returns a value directly - increment: (c, amount: number = 1) => { + increment: (c, amount = 1) => { c.state.value += amount; return c.state.value; }, @@ -30,7 +30,7 @@ export const asyncActionActor = actor({ state: { value: 0, data: null as any }, actions: { // Async action with a delay - delayedIncrement: async (c, amount: number = 1) => { + delayedIncrement: async (c, amount = 1) => { await Promise.resolve(); c.state.value += amount; return c.state.value; @@ -83,4 +83,3 @@ export const promiseActor = actor({ }, }, }); - diff --git a/packages/core/fixtures/driver-test-suite/auth.ts b/packages/core/fixtures/driver-test-suite/auth.ts index b50ef8a0b..f6f7993b5 100644 --- a/packages/core/fixtures/driver-test-suite/auth.ts +++ b/packages/core/fixtures/driver-test-suite/auth.ts @@ -1,4 +1,4 @@ -import { actor, UserError } from "@rivetkit/core"; +import { UserError, actor } from "@rivetkit/core"; // Basic auth actor - requires API key export const authActor = actor({ @@ -9,11 +9,11 @@ export const authActor = actor({ if (!apiKey) { throw new UserError("API key required", { code: "missing_auth" }); } - + if (apiKey !== "valid-api-key") { throw new UserError("Invalid API key", { code: "invalid_auth" }); } - + return { userId: "user123", token: apiKey }; }, actions: { @@ -30,17 +30,21 @@ export const intentAuthActor = actor({ state: { value: 0 }, onAuth: (opts) => { const { req, intents, params } = opts; - console.log('intents', intents, params); + console.log("intents", intents, params); const role = (params as any)?.role; - + if (intents.has("create") && role !== "admin") { - throw new UserError("Admin role required for create operations", { code: "insufficient_permissions" }); + throw new UserError("Admin role required for create operations", { + code: "insufficient_permissions", + }); } - + if (intents.has("action") && !["admin", "user"].includes(role || "")) { - throw new UserError("User or admin role required for actions", { code: "insufficient_permissions" }); + throw new UserError("User or admin role required for actions", { + code: "insufficient_permissions", + }); } - + return { role, timestamp: Date.now() }; }, actions: { @@ -79,20 +83,18 @@ export const noAuthActor = actor({ export const asyncAuthActor = actor({ state: { count: 0 }, onAuth: async (opts) => { - const { req, intents, params } = opts; - // Simulate async auth check (e.g., database lookup) - await new Promise(resolve => setTimeout(resolve, 10)); - + const { params } = opts; + const token = (params as any)?.token; if (!token) { throw new UserError("Token required", { code: "missing_token" }); } - + // Simulate token validation if (token === "invalid") { throw new UserError("Token is invalid", { code: "invalid_token" }); } - + return { userId: `user-${token}`, validated: true }; }, actions: { diff --git a/packages/core/fixtures/driver-test-suite/conn-params.ts b/packages/core/fixtures/driver-test-suite/conn-params.ts index 352d3fc9c..9904d5f69 100644 --- a/packages/core/fixtures/driver-test-suite/conn-params.ts +++ b/packages/core/fixtures/driver-test-suite/conn-params.ts @@ -26,4 +26,3 @@ export const counterWithParams = actor({ }, }, }); - diff --git a/packages/core/fixtures/driver-test-suite/conn-state.ts b/packages/core/fixtures/driver-test-suite/conn-state.ts index 8f7096936..0be9e2445 100644 --- a/packages/core/fixtures/driver-test-suite/conn-state.ts +++ b/packages/core/fixtures/driver-test-suite/conn-state.ts @@ -43,12 +43,12 @@ export const connStateActor = actor({ }, actions: { // Action to increment the connection's counter - incrementConnCounter: (c, amount: number = 1) => { + incrementConnCounter: (c, amount = 1) => { c.conn.state.counter += amount; }, // Action to increment the shared counter - incrementSharedCounter: (c, amount: number = 1) => { + incrementSharedCounter: (c, amount = 1) => { c.state.sharedCounter += amount; return c.state.sharedCounter; }, @@ -70,13 +70,18 @@ export const connStateActor = actor({ // Get all active connection states getAllConnectionStates: (c) => { - return c.conns.entries().map(([id, conn]) => ({ id, ...conn.state })).toArray(); + return c.conns + .entries() + .map(([id, conn]) => ({ id, ...conn.state })) + .toArray(); }, // Send message to a specific connection with matching ID sendToConnection: (c, targetId: string, message: string) => { if (c.conns.has(targetId)) { - c.conns.get(targetId)!.send("directMessage", { from: c.conn.id, message }); + c.conns + .get(targetId)! + .send("directMessage", { from: c.conn.id, message }); return true; } else { return false; @@ -90,8 +95,7 @@ export const connStateActor = actor({ ) => { if (updates.username) c.conn.state.username = updates.username; if (updates.role) c.conn.state.role = updates.role; - return c.conn.state; + return c.conn.state; }, }, }); - diff --git a/packages/core/fixtures/driver-test-suite/error-handling.ts b/packages/core/fixtures/driver-test-suite/error-handling.ts index 4f91c9a43..157900a68 100644 --- a/packages/core/fixtures/driver-test-suite/error-handling.ts +++ b/packages/core/fixtures/driver-test-suite/error-handling.ts @@ -1,4 +1,4 @@ -import { actor, UserError } from "@rivetkit/core"; +import { UserError, actor } from "@rivetkit/core"; export const errorHandlingActor = actor({ onAuth: () => {}, @@ -95,4 +95,3 @@ export const customTimeoutActor = actor({ }, }, }); - diff --git a/packages/core/fixtures/driver-test-suite/lifecycle.ts b/packages/core/fixtures/driver-test-suite/lifecycle.ts index 23faf6f8b..e30af1948 100644 --- a/packages/core/fixtures/driver-test-suite/lifecycle.ts +++ b/packages/core/fixtures/driver-test-suite/lifecycle.ts @@ -34,4 +34,3 @@ export const counterWithLifecycle = actor({ }, }, }); - diff --git a/packages/core/fixtures/driver-test-suite/metadata.ts b/packages/core/fixtures/driver-test-suite/metadata.ts index ebba5e6cf..ff5878203 100644 --- a/packages/core/fixtures/driver-test-suite/metadata.ts +++ b/packages/core/fixtures/driver-test-suite/metadata.ts @@ -74,5 +74,3 @@ export const metadataActor = actor({ }, }, }); - - diff --git a/packages/core/fixtures/driver-test-suite/registry.ts b/packages/core/fixtures/driver-test-suite/registry.ts index 06bdcca40..e9d135e8f 100644 --- a/packages/core/fixtures/driver-test-suite/registry.ts +++ b/packages/core/fixtures/driver-test-suite/registry.ts @@ -1,39 +1,39 @@ import { setup } from "@rivetkit/core"; -// Import actors from individual files -import { counter } from "./counter"; -import { counterWithLifecycle } from "./lifecycle"; -import { scheduled } from "./scheduled"; -import { errorHandlingActor, customTimeoutActor } from "./error-handling"; import { inputActor } from "./action-inputs"; import { - shortTimeoutActor, - longTimeoutActor, defaultTimeoutActor, + longTimeoutActor, + shortTimeoutActor, syncTimeoutActor, } from "./action-timeout"; import { - syncActionActor, asyncActionActor, promiseActor, + syncActionActor, } from "./action-types"; +import { + asyncAuthActor, + authActor, + intentAuthActor, + noAuthActor, + publicActor, +} from "./auth"; import { counterWithParams } from "./conn-params"; import { connStateActor } from "./conn-state"; +// Import actors from individual files +import { counter } from "./counter"; +import { customTimeoutActor, errorHandlingActor } from "./error-handling"; +import { counterWithLifecycle } from "./lifecycle"; import { metadataActor } from "./metadata"; +import { scheduled } from "./scheduled"; import { - staticVarActor, - nestedVarActor, + driverCtxActor, dynamicVarActor, + nestedVarActor, + staticVarActor, uniqueVarActor, - driverCtxActor, } from "./vars"; -import { - authActor, - intentAuthActor, - publicActor, - noAuthActor, - asyncAuthActor, -} from "./auth"; // Consolidated setup with all actors export const registry = setup({ diff --git a/packages/core/fixtures/driver-test-suite/scheduled.ts b/packages/core/fixtures/driver-test-suite/scheduled.ts index 58ce8b698..10ad94a75 100644 --- a/packages/core/fixtures/driver-test-suite/scheduled.ts +++ b/packages/core/fixtures/driver-test-suite/scheduled.ts @@ -75,5 +75,3 @@ export const scheduled = actor({ }, }, }); - - diff --git a/packages/core/fixtures/driver-test-suite/vars.ts b/packages/core/fixtures/driver-test-suite/vars.ts index e5deb77d6..4ac2d879e 100644 --- a/packages/core/fixtures/driver-test-suite/vars.ts +++ b/packages/core/fixtures/driver-test-suite/vars.ts @@ -94,5 +94,3 @@ export const driverCtxActor = actor({ }, }, }); - - diff --git a/packages/core/package.json b/packages/core/package.json index 1c66882af..68c882412 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -157,7 +157,7 @@ "invariant": "^2.2.4", "on-change": "^5.0.1", "p-retry": "^6.2.1", - "zod": "^3.24.1" + "zod": "^3.25.67" }, "devDependencies": { "@hono/node-server": "^1.14.0", diff --git a/packages/core/scripts/dump-openapi.ts b/packages/core/scripts/dump-openapi.ts index 66eb7642b..9dc189d6f 100644 --- a/packages/core/scripts/dump-openapi.ts +++ b/packages/core/scripts/dump-openapi.ts @@ -1,25 +1,16 @@ +import * as fs from "node:fs/promises"; +import { resolve } from "node:path"; +import type { ConnectionHandlers } from "@/actor/router-endpoints"; +import type { ClientDriver } from "@/client/client"; import { createManagerRouter } from "@/manager/router"; -import { RegistryConfig, RegistryConfigSchema, Encoding, setup } from "@/mod"; -import { ConnectionHandlers } from "@/actor/router-endpoints"; +import { type RegistryConfig, RegistryConfigSchema, setup } from "@/mod"; +import { type RunConfig, RunConfigSchema } from "@/registry/run-config"; import { - TestGlobalState, TestActorDriver, + TestGlobalState, TestManagerDriver, } from "@/test/driver/mod"; -import { OpenAPIHono } from "@hono/zod-openapi"; import { VERSION } from "@/utils"; -import * as fs from "node:fs/promises"; -import { resolve } from "node:path"; -import { ClientDriver } from "@/client/client"; -import { ActorQuery } from "@/manager/protocol/query"; -import { ToServer } from "@/actor/protocol/message/to-server"; -import { EventSource } from "eventsource"; -import { Context } from "hono"; -import { - DriverConfig, - RunConfig, - RunConfigSchema, -} from "@/registry/run-config"; function main() { const registryConfig: RegistryConfig = RegistryConfigSchema.parse({ diff --git a/packages/core/src/actor/action.ts b/packages/core/src/actor/action.ts index d2addd431..c30c283b0 100644 --- a/packages/core/src/actor/action.ts +++ b/packages/core/src/actor/action.ts @@ -1,10 +1,10 @@ -import type { Conn } from "./connection"; import type { Logger } from "@/common/log"; -import type { ActorKey } from "@/common/utils"; -import type { Schedule } from "./schedule"; +import type { ActorKey } from "@/actor/mod"; +import type { Conn } from "./connection"; import type { ConnId } from "./connection"; -import type { SaveStateOptions } from "./instance"; import type { ActorContext } from "./context"; +import type { SaveStateOptions } from "./instance"; +import type { Schedule } from "./schedule"; /** * Context for a remote procedure call. diff --git a/packages/core/src/actor/config.ts b/packages/core/src/actor/config.ts index cf178c500..17d42b5df 100644 --- a/packages/core/src/actor/config.ts +++ b/packages/core/src/actor/config.ts @@ -1,7 +1,7 @@ -import type { Conn } from "./connection"; +import { z } from "zod"; import type { ActionContext } from "./action"; +import type { Conn } from "./connection"; import type { ActorContext } from "./context"; -import { z } from "zod"; // This schema is used to validate the input at runtime. The generic types are defined below in `ActorConfig`. // diff --git a/packages/core/src/actor/conn-routing-handler.ts b/packages/core/src/actor/conn-routing-handler.ts index 6b82138f4..0d1f48b05 100644 --- a/packages/core/src/actor/conn-routing-handler.ts +++ b/packages/core/src/actor/conn-routing-handler.ts @@ -1,7 +1,7 @@ import type { UpgradeWebSocket } from "@/utils"; +import type { Context as HonoContext } from "hono"; import type { Encoding } from "./protocol/serde"; import type { ConnectionHandlers as ConnHandlers } from "./router-endpoints"; -import type { Context as HonoContext } from "hono"; /** * Deterines how requests to actors should be routed. @@ -37,7 +37,7 @@ export type SendRequestHandler = ( export type OpenWebSocketHandler = ( actorId: string, encodingKind: Encoding, - params: unknown + params: unknown, ) => Promise; export type ProxyRequestHandler = ( diff --git a/packages/core/src/actor/connection.ts b/packages/core/src/actor/connection.ts index e4f305585..d4dde5695 100644 --- a/packages/core/src/actor/connection.ts +++ b/packages/core/src/actor/connection.ts @@ -1,11 +1,11 @@ -import type { ActorInstance } from "./instance"; -import * as errors from "./errors"; -import { generateSecureToken } from "./utils"; -import { CachedSerializer } from "./protocol/serde"; +import type * as messageToClient from "@/actor/protocol/message/to-client"; +import type * as wsToClient from "@/actor/protocol/message/to-client"; import type { ConnDriver } from "./driver"; -import type * as messageToClient from "@/actor/protocol/message/to-client"; +import * as errors from "./errors"; +import type { ActorInstance } from "./instance"; import type { PersistedConn } from "./persisted"; -import type * as wsToClient from "@/actor/protocol/message/to-client"; +import { CachedSerializer } from "./protocol/serde"; +import { generateSecureToken } from "./utils"; export function generateConnId(): string { return crypto.randomUUID(); @@ -157,11 +157,6 @@ export class Conn { * @param reason - The reason for disconnection. */ public async disconnect(reason?: string) { - await this.#driver.disconnect( - this.#actor, - this, - this.__persist.ds, - reason, - ); + await this.#driver.disconnect(this.#actor, this, this.__persist.ds, reason); } } diff --git a/packages/core/src/actor/context.ts b/packages/core/src/actor/context.ts index 6d10aa036..9bd90c33c 100644 --- a/packages/core/src/actor/context.ts +++ b/packages/core/src/actor/context.ts @@ -1,7 +1,7 @@ import type { Logger } from "@/common/log"; -import type { ActorInstance, SaveStateOptions } from "./instance"; +import type { ActorKey } from "@/actor/mod"; import type { Conn, ConnId } from "./connection"; -import type { ActorKey } from "@/common/utils"; +import type { ActorInstance, SaveStateOptions } from "./instance"; import type { Schedule } from "./schedule"; /** diff --git a/packages/core/src/actor/definition.ts b/packages/core/src/actor/definition.ts index dd2d05fa0..c4426772f 100644 --- a/packages/core/src/actor/definition.ts +++ b/packages/core/src/actor/definition.ts @@ -1,7 +1,7 @@ -import type { ActorConfig, Actions } from "./config"; -import { ActorInstance } from "./instance"; -import type { ActorContext } from "./context"; import type { ActionContext } from "./action"; +import type { Actions, ActorConfig } from "./config"; +import type { ActorContext } from "./context"; +import { ActorInstance } from "./instance"; export type AnyActorDefinition = ActorDefinition< any, diff --git a/packages/core/src/actor/driver.ts b/packages/core/src/actor/driver.ts index 35873f05d..364cd1592 100644 --- a/packages/core/src/actor/driver.ts +++ b/packages/core/src/actor/driver.ts @@ -1,7 +1,7 @@ -import type * as messageToClient from "@/actor/protocol/message/to-client"; -import type { CachedSerializer } from "@/actor/protocol/serde"; +import type * as messageToClient from "@/actor/protocol/message/to-client"; +import type { CachedSerializer } from "@/actor/protocol/serde"; +import type { AnyConn } from "./connection"; import type { AnyActorInstance } from "./instance"; -import { AnyConn } from "./connection"; export type ConnDrivers = Record; diff --git a/packages/core/src/actor/errors.ts b/packages/core/src/actor/errors.ts index 4eb8cd02b..d474334a3 100644 --- a/packages/core/src/actor/errors.ts +++ b/packages/core/src/actor/errors.ts @@ -1,4 +1,4 @@ -import { DeconstructedError } from "@/common/utils"; +import type { DeconstructedError } from "@/common/utils"; export const INTERNAL_ERROR_CODE = "internal_error"; export const INTERNAL_ERROR_DESCRIPTION = diff --git a/packages/core/src/actor/instance.ts b/packages/core/src/actor/instance.ts index 948ec711f..6c6c10f28 100644 --- a/packages/core/src/actor/instance.ts +++ b/packages/core/src/actor/instance.ts @@ -1,30 +1,27 @@ -import type { Logger } from "@/common//log"; -import { - type ActorKey, - isJsonSerializable, - stringifyError, -} from "@/common//utils"; +import type * as wsToClient from "@/actor/protocol/message/to-client"; +import type * as wsToServer from "@/actor/protocol/message/to-server"; +import type { Logger } from "@/common/log"; +import type { ActorKey } from "@/actor/mod"; +import { isJsonSerializable, stringifyError } from "@/common/utils"; +import invariant from "invariant"; import onChange from "on-change"; +import type { ActionContext } from "./action"; import type { ActorConfig } from "./config"; import { Conn, type ConnId } from "./connection"; +import { ActorContext } from "./context"; import type { ActorDriver, ConnDrivers } from "./driver"; import type { ConnDriver } from "./driver"; import * as errors from "./errors"; -import { processMessage } from "./protocol/message/mod"; import { instanceLogger, logger } from "./log"; -import type { ActionContext } from "./action"; -import { DeadlineError, Lock, deadline } from "./utils"; -import { Schedule } from "./schedule"; -import type * as wsToClient from "@/actor/protocol/message/to-client"; -import type * as wsToServer from "@/actor/protocol/message/to-server"; -import { CachedSerializer } from "./protocol/serde"; -import { ActorContext } from "./context"; -import invariant from "invariant"; import type { PersistedActor, PersistedConn, PersistedScheduleEvents, } from "./persisted"; +import { processMessage } from "./protocol/message/mod"; +import { CachedSerializer } from "./protocol/serde"; +import { Schedule } from "./schedule"; +import { DeadlineError, Lock, deadline } from "./utils"; /** * Options for the `_saveState` method. diff --git a/packages/core/src/actor/log.ts b/packages/core/src/actor/log.ts index 6f97702ca..05f92cc5e 100644 --- a/packages/core/src/actor/log.ts +++ b/packages/core/src/actor/log.ts @@ -13,4 +13,3 @@ export function logger() { export function instanceLogger() { return getLogger(ACTOR_LOGGER_NAME); } - diff --git a/packages/core/src/actor/mod.ts b/packages/core/src/actor/mod.ts index 857579462..e4d7f30c4 100644 --- a/packages/core/src/actor/mod.ts +++ b/packages/core/src/actor/mod.ts @@ -1,8 +1,8 @@ import { - type ActorConfigInput, - ActorConfigSchema, type Actions, type ActorConfig, + type ActorConfigInput, + ActorConfigSchema, } from "./config"; import { ActorDefinition } from "./definition"; @@ -11,8 +11,7 @@ export { UserError, type UserErrorOptions } from "./errors"; export type { Conn } from "./connection"; export type { ActionContext } from "./action"; export type { ActorConfig, OnConnectOptions } from "./config"; -export type { Encoding } from "@/actor/protocol/serde"; -export type { ActorKey } from "@/common/utils"; +export type { Encoding } from "@/actor/protocol/serde"; export type { ActorDefinition, AnyActorDefinition, @@ -43,3 +42,4 @@ export function actor< >; return new ActorDefinition(config); } +export type { ActorKey } from "@/manager/protocol/query"; diff --git a/packages/core/src/actor/protocol/http/action.ts b/packages/core/src/actor/protocol/http/action.ts index b9e8aa873..1d8cb736a 100644 --- a/packages/core/src/actor/protocol/http/action.ts +++ b/packages/core/src/actor/protocol/http/action.ts @@ -10,6 +10,5 @@ export const ActionResponseSchema = z.object({ o: z.unknown(), }); - export type ActionRequest = z.infer; export type ActionResponse = z.infer; diff --git a/packages/core/src/actor/protocol/message/mod.ts b/packages/core/src/actor/protocol/message/mod.ts index b50381471..3cfcb35c1 100644 --- a/packages/core/src/actor/protocol/message/mod.ts +++ b/packages/core/src/actor/protocol/message/mod.ts @@ -1,19 +1,19 @@ -import type * as wsToClient from "@/actor/protocol/message/to-client"; -import * as wsToServer from "@/actor/protocol/message/to-server"; -import type { ActorInstance } from "../../instance"; -import type { Conn } from "../../connection"; -import * as errors from "../../errors"; -import { logger } from "../../log"; -import { ActionContext } from "../../action"; -import { assertUnreachable } from "../../utils"; -import { z } from "zod"; +import type * as wsToClient from "@/actor/protocol/message/to-client"; +import * as wsToServer from "@/actor/protocol/message/to-server"; import { - deserialize, + CachedSerializer, type Encoding, type InputData, - CachedSerializer, -} from "@/actor/protocol/serde"; + deserialize, +} from "@/actor/protocol/serde"; import { deconstructError } from "@/common/utils"; +import { z } from "zod"; +import { ActionContext } from "../../action"; +import type { Conn } from "../../connection"; +import * as errors from "../../errors"; +import type { ActorInstance } from "../../instance"; +import { logger } from "../../log"; +import { assertUnreachable } from "../../utils"; export const TransportSchema = z.enum(["websocket", "sse"]); diff --git a/packages/core/src/actor/protocol/serde.ts b/packages/core/src/actor/protocol/serde.ts index cc2e31022..ed1991426 100644 --- a/packages/core/src/actor/protocol/serde.ts +++ b/packages/core/src/actor/protocol/serde.ts @@ -1,8 +1,8 @@ +import * as errors from "@/actor/errors"; +import * as cbor from "cbor-x"; import { z } from "zod"; -import * as errors from "@/actor/errors"; import { logger } from "../log"; import { assertUnreachable } from "../utils"; -import * as cbor from "cbor-x"; /** Data that can be deserialized. */ export type InputData = string | Buffer | Blob | ArrayBufferLike | Uint8Array; diff --git a/packages/core/src/actor/router-endpoints.ts b/packages/core/src/actor/router-endpoints.ts index 429439d8f..439a73a41 100644 --- a/packages/core/src/actor/router-endpoints.ts +++ b/packages/core/src/actor/router-endpoints.ts @@ -1,22 +1,22 @@ -import type { HonoRequest, Context as HonoContext } from "hono"; -import { type SSEStreamingApi, streamSSE } from "hono/streaming"; -import type { WSContext } from "hono/ws"; -import * as errors from "./errors"; -import { logger } from "./log"; +import * as protoHttpAction from "@/actor/protocol/http/action"; +import { parseMessage } from "@/actor/protocol/message/mod"; +import type * as messageToServer from "@/actor/protocol/message/to-server"; import { type Encoding, EncodingSchema, - serialize, deserialize, -} from "@/actor/protocol/serde"; -import { parseMessage } from "@/actor/protocol/message/mod"; -import * as protoHttpAction from "@/actor/protocol/http/action"; -import type * as messageToServer from "@/actor/protocol/message/to-server"; -import type { InputData } from "@/actor/protocol/serde"; -import { assertUnreachable } from "./utils"; + serialize, +} from "@/actor/protocol/serde"; +import type { InputData } from "@/actor/protocol/serde"; import { deconstructError, stringifyError } from "@/common/utils"; import type { RegistryConfig } from "@/registry/config"; -import { DriverConfig, RunConfig } from "@/registry/run-config"; +import type { RunConfig } from "@/registry/run-config"; +import type { Context as HonoContext, HonoRequest } from "hono"; +import { type SSEStreamingApi, streamSSE } from "hono/streaming"; +import type { WSContext } from "hono/ws"; +import * as errors from "./errors"; +import { logger } from "./log"; +import { assertUnreachable } from "./utils"; export interface ConnectWebSocketOpts { req?: HonoRequest; diff --git a/packages/core/src/client/actor-common.ts b/packages/core/src/client/actor-common.ts index 0a5082c7c..efe23dc79 100644 --- a/packages/core/src/client/actor-common.ts +++ b/packages/core/src/client/actor-common.ts @@ -1,7 +1,4 @@ -import type { - AnyActorDefinition, - ActorDefinition, -} from "@/actor/definition"; +import type { ActorDefinition, AnyActorDefinition } from "@/actor/definition"; /** * Action function returned by Actor connections and handles. diff --git a/packages/core/src/client/actor-conn.ts b/packages/core/src/client/actor-conn.ts index a2b690c98..df19644d5 100644 --- a/packages/core/src/client/actor-conn.ts +++ b/packages/core/src/client/actor-conn.ts @@ -1,19 +1,17 @@ -import type { AnyActorDefinition } from "@/actor/definition"; -import type { Transport } from "@/actor/protocol/message/mod"; -import type * as wsToClient from "@/actor/protocol/message/to-client"; -import type * as wsToServer from "@/actor/protocol/message/to-server"; -import type { Encoding } from "@/actor/protocol/serde"; -import { importEventSource } from "@/common/eventsource"; -import { MAX_CONN_PARAMS_SIZE } from "@/common/network"; -import { httpUserAgent } from "@/utils"; +import type { AnyActorDefinition } from "@/actor/definition"; +import type * as wsToClient from "@/actor/protocol/message/to-client"; +import type * as wsToServer from "@/actor/protocol/message/to-server"; +import type { Encoding } from "@/actor/protocol/serde"; import { assertUnreachable, stringifyError } from "@/common/utils"; -import { importWebSocket } from "@/common/websocket"; import type { ActorQuery } from "@/manager/protocol/query"; import * as cbor from "cbor-x"; +import type { EventSource } from "eventsource"; import pRetry from "p-retry"; +import type { CloseEvent, WebSocket } from "ws"; +import type { ActorDefinitionActions } from "./actor-common"; import { ACTOR_CONNS_SYMBOL, - ClientDriver, + type ClientDriver, type ClientRaw, TRANSPORT_SYMBOL, } from "./client"; @@ -24,17 +22,6 @@ import { messageLength, serializeWithEncoding, } from "./utils"; -import { - HEADER_ACTOR_ID, - HEADER_ACTOR_QUERY, - HEADER_CONN_ID, - HEADER_CONN_TOKEN, - HEADER_ENCODING, - HEADER_CONN_PARAMS, -} from "@/actor/router-endpoints"; -import type { EventSource } from "eventsource"; -import { ActorDefinitionActions } from "./actor-common"; -import type { WebSocket, CloseEvent, ErrorEvent } from "ws"; interface ActionInFlight { name: string; diff --git a/packages/core/src/client/actor-handle.ts b/packages/core/src/client/actor-handle.ts index 07cd708fa..16c71283f 100644 --- a/packages/core/src/client/actor-handle.ts +++ b/packages/core/src/client/actor-handle.ts @@ -1,16 +1,16 @@ -import type { AnyActorDefinition } from "@/actor/definition"; -import type { Encoding } from "@/actor/protocol/serde"; +import type { AnyActorDefinition } from "@/actor/definition"; +import type { Encoding } from "@/actor/protocol/serde"; +import { assertUnreachable } from "@/actor/utils"; import type { ActorQuery } from "@/manager/protocol/query"; -import { type ActorDefinitionActions } from "./actor-common"; -import { type ActorConn, ActorConnRaw } from "./actor-conn"; +import invariant from "invariant"; +import type { ActorDefinitionActions } from "./actor-common"; +import { type ActorConn, ActorConnRaw } from "./actor-conn"; import { - ClientDriver, CREATE_ACTOR_CONN_PROXY, + type ClientDriver, type ClientRaw, } from "./client"; import { logger } from "./log"; -import invariant from "invariant"; -import { assertUnreachable } from "@/actor/utils"; /** * Provides underlying functions for stateless {@link ActorHandle} for action calls. diff --git a/packages/core/src/client/client.ts b/packages/core/src/client/client.ts index 52ea01f6d..0b9aab888 100644 --- a/packages/core/src/client/client.ts +++ b/packages/core/src/client/client.ts @@ -1,16 +1,20 @@ -import type { Transport } from "@/actor/protocol/message/mod"; -import type { Encoding } from "@/actor/protocol/serde"; +import type { AnyActorDefinition } from "@/actor/definition"; +import type { Transport } from "@/actor/protocol/message/mod"; +import type * as wsToServer from "@/actor/protocol/message/to-server"; +import type { Encoding } from "@/actor/protocol/serde"; import type { ActorQuery } from "@/manager/protocol/query"; -import { ActorConn, ActorConnRaw, CONNECT_SYMBOL } from "./actor-conn"; -import { ActorHandle, ActorHandleRaw } from "./actor-handle"; -import { ActorActionFunction } from "./actor-common"; -import { logger } from "./log"; import type { Registry } from "@/mod"; -import type { AnyActorDefinition } from "@/actor/definition"; -import type * as wsToServer from "@/actor/protocol/message/to-server"; import type { EventSource } from "eventsource"; import type { Context as HonoContext } from "hono"; import type { WebSocket } from "ws"; +import type { ActorActionFunction } from "./actor-common"; +import { + type ActorConn, + type ActorConnRaw, + CONNECT_SYMBOL, +} from "./actor-conn"; +import { type ActorHandle, ActorHandleRaw } from "./actor-handle"; +import { logger } from "./log"; /** Extract the actor registry from the registry definition. */ export type ExtractActorsFromRegistry> = diff --git a/packages/core/src/client/http-client-driver.ts b/packages/core/src/client/http-client-driver.ts index 9338d355b..61bde1d97 100644 --- a/packages/core/src/client/http-client-driver.ts +++ b/packages/core/src/client/http-client-driver.ts @@ -1,11 +1,8 @@ -import * as cbor from "cbor-x"; -import type { Encoding } from "@/actor/protocol/serde"; -import type { ActorQuery } from "@/manager/protocol/query"; -import * as errors from "./errors"; -import { logger } from "./log"; -import type * as wsToServer from "@/actor/protocol/message/to-server"; -import type * as protoHttpResolve from "@/actor/protocol/http/resolve"; -import { assertUnreachable, httpUserAgent } from "@/utils"; +import type { ActionRequest } from "@/actor/protocol/http/action"; +import type * as protoHttpResolve from "@/actor/protocol/http/resolve"; +import type { ActionResponse } from "@/actor/protocol/message/to-client"; +import type * as wsToServer from "@/actor/protocol/message/to-server"; +import type { Encoding } from "@/actor/protocol/serde"; import { HEADER_ACTOR_ID, HEADER_ACTOR_QUERY, @@ -13,20 +10,18 @@ import { HEADER_CONN_PARAMS, HEADER_CONN_TOKEN, HEADER_ENCODING, -} from "@/actor/router-endpoints"; -import type { EventSource } from "eventsource"; -import { importWebSocket } from "@/common/websocket"; +} from "@/actor/router-endpoints"; import { importEventSource } from "@/common/eventsource"; -import { - sendHttpRequest, - serializeWithEncoding, - type WebSocketMessage, -} from "./utils"; -import type { ActionRequest } from "@/actor/protocol/http/action"; -import type { ActionResponse } from "@/actor/protocol/message/to-client"; -import { ClientDriver } from "./client"; -import { HonoRequest, Context as HonoContext } from "hono"; +import { importWebSocket } from "@/common/websocket"; +import type { ActorQuery } from "@/manager/protocol/query"; +import { assertUnreachable, httpUserAgent } from "@/utils"; +import type { EventSource } from "eventsource"; +import type { Context as HonoContext } from "hono"; import type { WebSocket } from "ws"; +import type { ClientDriver } from "./client"; +import * as errors from "./errors"; +import { logger } from "./log"; +import { sendHttpRequest, serializeWithEncoding } from "./utils"; /** * Client driver that communicates with the manager via HTTP. diff --git a/packages/core/src/client/mod.ts b/packages/core/src/client/mod.ts index 5e6300f6a..82bcff2ec 100644 --- a/packages/core/src/client/mod.ts +++ b/packages/core/src/client/mod.ts @@ -1,5 +1,9 @@ import type { Registry } from "@/registry/mod"; -import { type Client, type ClientOptions, createClientWithDriver } from "./client"; +import { + type Client, + type ClientOptions, + createClientWithDriver, +} from "./client"; import { createHttpClientDriver } from "./http-client-driver"; export type { @@ -15,14 +19,14 @@ export type { ExtractRegistryFromClient, ClientRaw, } from "./client"; -export type { ActorConn } from "./actor-conn"; -export { ActorConnRaw } from "./actor-conn"; -export type { EventUnsubscribe } from "./actor-conn"; -export type { ActorHandle } from "./actor-handle"; -export { ActorHandleRaw } from "./actor-handle"; -export type { ActorActionFunction } from "./actor-common"; -export type { Transport } from "@/actor/protocol/message/mod"; -export type { Encoding } from "@/actor/protocol/serde"; +export type { ActorConn } from "./actor-conn"; +export { ActorConnRaw } from "./actor-conn"; +export type { EventUnsubscribe } from "./actor-conn"; +export type { ActorHandle } from "./actor-handle"; +export { ActorHandleRaw } from "./actor-handle"; +export type { ActorActionFunction } from "./actor-common"; +export type { Transport } from "@/actor/protocol/message/mod"; +export type { Encoding } from "@/actor/protocol/serde"; export type { CreateRequest } from "@/manager/protocol/query"; export { ActorClientError, @@ -35,7 +39,7 @@ export { export { AnyActorDefinition, ActorDefinition, -} from "@/actor/definition"; +} from "@/actor/definition"; /** * Creates a client with the actor accessor proxy. diff --git a/packages/core/src/client/utils.ts b/packages/core/src/client/utils.ts index 5773425b5..1dc9c55b5 100644 --- a/packages/core/src/client/utils.ts +++ b/packages/core/src/client/utils.ts @@ -1,9 +1,9 @@ +import type { ResponseError } from "@/actor/protocol/http/error"; import { assertUnreachable } from "@/common/utils"; +import type { Encoding } from "@/mod"; import { httpUserAgent } from "@/utils"; -import { Encoding } from "@/mod"; import * as cbor from "cbor-x"; import { ActorError, HttpRequestError } from "./errors"; -import { ResponseError } from "@/actor/protocol/http/error"; import { logger } from "./log"; export type WebSocketMessage = string | Blob | ArrayBuffer | Uint8Array; diff --git a/packages/core/src/common/log.ts b/packages/core/src/common/log.ts index 7cecb75ba..6e9aea889 100644 --- a/packages/core/src/common/log.ts +++ b/packages/core/src/common/log.ts @@ -76,7 +76,9 @@ export class Logger { const loggers: Record = {}; export function getLogger(name = "default"): Logger { - const defaultLogLevelEnv: LogLevel | undefined = getEnvUniversal("_LOG_LEVEL") as LogLevel | undefined; + const defaultLogLevelEnv: LogLevel | undefined = getEnvUniversal( + "_LOG_LEVEL", + ) as LogLevel | undefined; const defaultLogLevel: LogLevel = defaultLogLevelEnv ?? "INFO"; if (!loggers[name]) { diff --git a/packages/core/src/common/router.ts b/packages/core/src/common/router.ts index 83e4bebe8..25668af64 100644 --- a/packages/core/src/common/router.ts +++ b/packages/core/src/common/router.ts @@ -1,12 +1,12 @@ -import type { Context as HonoContext, Next } from "hono"; -import { getLogger, Logger } from "./log"; -import { deconstructError, stringifyError } from "./utils"; +import type { ResponseError } from "@/actor/protocol/http/error"; +import { type Encoding, serialize } from "@/actor/protocol/serde"; import { getRequestEncoding, getRequestExposeInternalError, -} from "@/actor/router-endpoints"; -import { Encoding, serialize } from "@/actor/protocol/serde"; -import { ResponseError } from "@/actor/protocol/http/error"; +} from "@/actor/router-endpoints"; +import type { Context as HonoContext, Next } from "hono"; +import { type Logger, getLogger } from "./log"; +import { deconstructError, stringifyError } from "./utils"; export function logger() { return getLogger("router"); @@ -47,8 +47,7 @@ export function handleRouteError( c: HonoContext, ) { const exposeInternalError = - opts.enableExposeInternalError && - getRequestExposeInternalError(c.req); + opts.enableExposeInternalError && getRequestExposeInternalError(c.req); const { statusCode, code, message, metadata } = deconstructError( error, diff --git a/packages/core/src/common/utils.ts b/packages/core/src/common/utils.ts index 6e707e6f8..7303973f4 100644 --- a/packages/core/src/common/utils.ts +++ b/packages/core/src/common/utils.ts @@ -1,22 +1,7 @@ -import { z } from "zod"; +import * as errors from "@/actor/errors"; +import { getEnvUniversal } from "@/utils"; import type { ContentfulStatusCode } from "hono/utils/http-status"; -import * as errors from "@/actor/errors"; import type { Logger } from "./log"; -import { getEnvUniversal } from "@/utils"; - -// Maximum size of a key component in bytes -// Set to 128 bytes to allow for separators and escape characters in the full key -// Cloudflare's maximum key size is 512 bytes, so we need to be significantly smaller -export const MAX_KEY_SIZE = 128; - -export const ActorKeySchema = z.array(z.string().max(MAX_KEY_SIZE)); - -export type ActorKey = z.infer; - -export interface RivetEnvironment { - project?: string; - environment?: string; -} export function assertUnreachable(x: never): never { throw new Error(`Unreachable case: ${x}`); diff --git a/packages/core/src/driver-helpers/mod.ts b/packages/core/src/driver-helpers/mod.ts index 064432f1f..dd8cfebab 100644 --- a/packages/core/src/driver-helpers/mod.ts +++ b/packages/core/src/driver-helpers/mod.ts @@ -1,4 +1,4 @@ -export type { ActorInstance, AnyActorInstance } from "@/actor/instance"; +export type { ActorInstance, AnyActorInstance } from "@/actor/instance"; export type { AttemptAcquireLease, ExtendLeaseOutput, @@ -7,7 +7,7 @@ export type { CoordinateDriver, StartActorAndAcquireLeaseOutput, } from "@/topologies/coordinate/driver"; -export type { ActorDriver } from "@/actor/driver"; +export type { ActorDriver } from "@/actor/driver"; export type { ManagerDriver, CreateInput, @@ -25,5 +25,5 @@ export { HEADER_ACTOR_ID, HEADER_CONN_ID, HEADER_CONN_TOKEN, -} from "@/actor/router-endpoints"; +} from "@/actor/router-endpoints"; export { RunConfigSchema, DriverConfigSchema } from "@/registry/run-config"; diff --git a/packages/core/src/driver-test-suite/mod.ts b/packages/core/src/driver-test-suite/mod.ts index a64367828..3640f8ac7 100644 --- a/packages/core/src/driver-test-suite/mod.ts +++ b/packages/core/src/driver-test-suite/mod.ts @@ -1,28 +1,28 @@ -import { serve as honoServe } from "@hono/node-server"; -import { runActorDriverTests } from "./tests/actor-driver"; -import { runManagerDriverTests } from "./tests/manager-driver"; -import { describe } from "vitest"; +import type { Transport } from "@/client/mod"; import { CoordinateTopology, + type DriverConfig, + type Registry, + type RunConfig, StandaloneTopology, - Registry, - RunConfig, - DriverConfig, } from "@/mod"; -import { createNodeWebSocket, type NodeWebSocket } from "@hono/node-ws"; -import invariant from "invariant"; -import { bundleRequire } from "bundle-require"; +import { RunConfigSchema } from "@/registry/run-config"; import { getPort } from "@/test/mod"; -import { Transport } from "@/client/mod"; -import { runActorConnTests } from "./tests/actor-conn"; -import { runActorHandleTests } from "./tests/actor-handle"; +import { serve as honoServe } from "@hono/node-server"; +import { type NodeWebSocket, createNodeWebSocket } from "@hono/node-ws"; +import { bundleRequire } from "bundle-require"; +import invariant from "invariant"; +import { describe } from "vitest"; import { runActionFeaturesTests } from "./tests/action-features"; -import { runActorVarsTests } from "./tests/actor-vars"; -import { runActorConnStateTests } from "./tests/actor-conn-state"; -import { runActorMetadataTests } from "./tests/actor-metadata"; -import { runActorErrorHandlingTests } from "./tests/actor-error-handling"; -import { runActorAuthTests } from "./tests/actor-auth"; -import { RunConfigSchema } from "@/registry/run-config"; +import { runActorAuthTests } from "./tests/actor-auth"; +import { runActorConnTests } from "./tests/actor-conn"; +import { runActorConnStateTests } from "./tests/actor-conn-state"; +import { runActorDriverTests } from "./tests/actor-driver"; +import { runActorErrorHandlingTests } from "./tests/actor-error-handling"; +import { runActorHandleTests } from "./tests/actor-handle"; +import { runActorMetadataTests } from "./tests/actor-metadata"; +import { runActorVarsTests } from "./tests/actor-vars"; +import { runManagerDriverTests } from "./tests/manager-driver"; export interface DriverTestConfig { /** Deploys an registry and returns the connection endpoint. */ diff --git a/packages/core/src/driver-test-suite/test-inline-client-driver.ts b/packages/core/src/driver-test-suite/test-inline-client-driver.ts index b6beec864..bf61c0a0e 100644 --- a/packages/core/src/driver-test-suite/test-inline-client-driver.ts +++ b/packages/core/src/driver-test-suite/test-inline-client-driver.ts @@ -1,20 +1,20 @@ -import { ClientDriver } from "@/client/client"; -import { type Encoding } from "@/actor/protocol/serde"; -import type * as wsToServer from "@/actor/protocol/message/to-server"; +import type * as wsToServer from "@/actor/protocol/message/to-server"; +import type { Encoding } from "@/actor/protocol/serde"; +import { assertUnreachable } from "@/actor/utils"; +import type { ClientDriver } from "@/client/client"; +import { ActorError as ClientActorError } from "@/client/errors"; +import type { Transport } from "@/client/mod"; +import { importWebSocket } from "@/common/websocket"; import type { ActorQuery } from "@/manager/protocol/query"; -import { Context as HonoContext } from "hono"; -import type { EventSource } from "eventsource"; -import { Transport } from "@/client/mod"; -import { logger } from "./log"; -import { +import type { TestInlineDriverCallRequest, TestInlineDriverCallResponse, } from "@/manager/router"; -import { assertUnreachable } from "@/actor/utils"; import * as cbor from "cbor-x"; -import { ActorError as ClientActorError } from "@/client/errors"; +import type { EventSource } from "eventsource"; +import type { Context as HonoContext } from "hono"; import type { WebSocket } from "ws"; -import { importWebSocket } from "@/common/websocket"; +import { logger } from "./log"; /** * Creates a client driver used for testing the inline client driver. This will send a request to the HTTP server which will then internally call the internal client and return the response. @@ -30,7 +30,7 @@ export function createTestInlineClientDriver( encoding: Encoding, params: unknown, name: string, - args: Args + args: Args, ): Promise => { return makeInlineRequest( endpoint, diff --git a/packages/core/src/driver-test-suite/tests/action-features.ts b/packages/core/src/driver-test-suite/tests/action-features.ts index cb1500999..65f59f0d6 100644 --- a/packages/core/src/driver-test-suite/tests/action-features.ts +++ b/packages/core/src/driver-test-suite/tests/action-features.ts @@ -1,20 +1,16 @@ -import { describe, test, expect } from "vitest"; +import type { ActorError } from "@/client/errors"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; -import { ActorError } from "@/client/errors"; export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) { describe("Action Features", () => { // TODO: These do not work with fake timers describe.skip("Action Timeouts", () => { - let usesFakeTimers = !driverTestConfig.useRealTimers; + const usesFakeTimers = !driverTestConfig.useRealTimers; test("should timeout actions that exceed the configured timeout", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // The quick action should complete successfully const quickResult = await client.shortTimeoutActor @@ -29,11 +25,7 @@ export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) { }); test("should respect the default timeout", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // This action should complete within the default timeout const result = await client.defaultTimeoutActor @@ -43,11 +35,7 @@ export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) { }); test("non-promise action results should not be affected by timeout", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Synchronous action should not be affected by timeout const result = await client.syncTimeoutActor.getOrCreate().syncAction(); @@ -55,11 +43,7 @@ export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) { }); test("should allow configuring different timeouts for different actors", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // The short timeout actor should fail await expect( @@ -76,11 +60,7 @@ export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) { describe("Action Sync & Async", () => { test("should support synchronous actions", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); const instance = client.syncActionActor.getOrCreate(); @@ -103,11 +83,7 @@ export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) { }); test("should support asynchronous actions", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); const instance = client.asyncActionActor.getOrCreate(); @@ -134,11 +110,7 @@ export function runActionFeaturesTests(driverTestConfig: DriverTestConfig) { }); test("should handle promises returned from actions correctly", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); const instance = client.promiseActor.getOrCreate(); diff --git a/packages/core/src/driver-test-suite/tests/actor-auth.ts b/packages/core/src/driver-test-suite/tests/actor-auth.ts index 4a4775015..4d8917944 100644 --- a/packages/core/src/driver-test-suite/tests/actor-auth.ts +++ b/packages/core/src/driver-test-suite/tests/actor-auth.ts @@ -1,7 +1,7 @@ -import { describe, test, expect } from "vitest"; +import type { ActorError } from "@/client/errors"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; -import { ActorError } from "@/client/errors"; export function runActorAuthTests(driverTestConfig: DriverTestConfig) { describe("Actor Authentication Tests", () => { @@ -21,7 +21,10 @@ export function runActorAuthTests(driverTestConfig: DriverTestConfig) { expect(authData).toBeUndefined(); } else { // HTTP clients should have auth data - expect(authData).toEqual({ userId: "user123", token: "valid-api-key" }); + expect(authData).toEqual({ + userId: "user123", + token: "valid-api-key", + }); } // Should be able to call actions @@ -183,7 +186,9 @@ export function runActorAuthTests(driverTestConfig: DriverTestConfig) { // HTTP clients should enforce authentication try { await instance.getValue(); - expect.fail("Expected access to be denied for actor without onAuth"); + expect.fail( + "Expected access to be denied for actor without onAuth", + ); } catch (error) { expect((error as ActorError).code).toBe("forbidden"); } diff --git a/packages/core/src/driver-test-suite/tests/actor-conn-state.ts b/packages/core/src/driver-test-suite/tests/actor-conn-state.ts index 5cafd69df..08bc1e3fc 100644 --- a/packages/core/src/driver-test-suite/tests/actor-conn-state.ts +++ b/packages/core/src/driver-test-suite/tests/actor-conn-state.ts @@ -1,4 +1,4 @@ -import { describe, test, expect, vi } from "vitest"; +import { describe, expect, test, vi } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; diff --git a/packages/core/src/driver-test-suite/tests/actor-conn.ts b/packages/core/src/driver-test-suite/tests/actor-conn.ts index 8da9485d5..2ea32b907 100644 --- a/packages/core/src/driver-test-suite/tests/actor-conn.ts +++ b/packages/core/src/driver-test-suite/tests/actor-conn.ts @@ -1,4 +1,4 @@ -import { describe, test, expect, vi } from "vitest"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; @@ -27,9 +27,7 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) { const { client } = await setupDriverTest(c, driverTestConfig); // Create a actor first to get its ID - const handle = client.counter.getOrCreate([ - "test-get-for-id", - ]); + const handle = client.counter.getOrCreate(["test-get-for-id"]); await handle.increment(3); const actorId = await handle.resolve(); @@ -49,9 +47,7 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) { const { client } = await setupDriverTest(c, driverTestConfig); // Get or create actor and connect - const handle = client.counter.getOrCreate([ - "test-get-or-create", - ]); + const handle = client.counter.getOrCreate(["test-get-or-create"]); const connection = handle.connect(); // Verify connection works @@ -133,9 +129,7 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) { const { client } = await setupDriverTest(c, driverTestConfig); // Create actor and connect - const handle = client.counter.getOrCreate([ - "test-unsubscribe", - ]); + const handle = client.counter.getOrCreate(["test-unsubscribe"]); const connection = handle.connect(); // Set up event listener with unsubscribe @@ -198,7 +192,9 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) { test("should trigger lifecycle hooks", async (c) => { const { client } = await setupDriverTest(c, driverTestConfig); - const handle = client.counterWithLifecycle.getOrCreate(["test-lifecycle"]); + const handle = client.counterWithLifecycle.getOrCreate([ + "test-lifecycle", + ]); // Create and connect const connHandle = client.counterWithLifecycle.getOrCreate( diff --git a/packages/core/src/driver-test-suite/tests/actor-driver.ts b/packages/core/src/driver-test-suite/tests/actor-driver.ts index 9417b47e3..7626cd0d0 100644 --- a/packages/core/src/driver-test-suite/tests/actor-driver.ts +++ b/packages/core/src/driver-test-suite/tests/actor-driver.ts @@ -1,16 +1,14 @@ import { describe } from "vitest"; import type { DriverTestConfig } from "../mod"; -import { runActorStateTests } from "./actor-state"; -import { runActorScheduleTests } from "./actor-schedule"; +import { runActorScheduleTests } from "./actor-schedule"; +import { runActorStateTests } from "./actor-state"; -export function runActorDriverTests( - driverTestConfig: DriverTestConfig -) { - describe("Actor Driver Tests", () => { - // Run state persistence tests - runActorStateTests(driverTestConfig); - - // Run scheduled alarms tests - runActorScheduleTests(driverTestConfig); - }); +export function runActorDriverTests(driverTestConfig: DriverTestConfig) { + describe("Actor Driver Tests", () => { + // Run state persistence tests + runActorStateTests(driverTestConfig); + + // Run scheduled alarms tests + runActorScheduleTests(driverTestConfig); + }); } diff --git a/packages/core/src/driver-test-suite/tests/actor-error-handling.ts b/packages/core/src/driver-test-suite/tests/actor-error-handling.ts index 1a2913e1a..3a9962159 100644 --- a/packages/core/src/driver-test-suite/tests/actor-error-handling.ts +++ b/packages/core/src/driver-test-suite/tests/actor-error-handling.ts @@ -1,23 +1,17 @@ -import { describe, test, expect } from "vitest"; -import type { DriverTestConfig } from "../mod"; -import { setupDriverTest } from "../utils"; -import { assertUnreachable } from "@/actor/utils"; import { INTERNAL_ERROR_CODE, INTERNAL_ERROR_DESCRIPTION, -} from "@/actor/errors"; +} from "@/actor/errors"; +import { assertUnreachable } from "@/actor/utils"; +import { describe, expect, test } from "vitest"; +import type { DriverTestConfig } from "../mod"; +import { setupDriverTest } from "../utils"; -export function runActorErrorHandlingTests( - driverTestConfig: DriverTestConfig, -) { +export function runActorErrorHandlingTests(driverTestConfig: DriverTestConfig) { describe("Actor Error Handling Tests", () => { describe("UserError Handling", () => { test("should handle simple UserError with message", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Try to call an action that throws a simple UserError const handle = client.errorHandlingActor.getOrCreate(); @@ -37,11 +31,7 @@ export function runActorErrorHandlingTests( }); test("should handle detailed UserError with code and metadata", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Try to call an action that throws a detailed UserError const handle = client.errorHandlingActor.getOrCreate(); @@ -63,11 +53,7 @@ export function runActorErrorHandlingTests( describe("Internal Error Handling", () => { test("should convert internal errors to safe format", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Try to call an action that throws an internal error const handle = client.errorHandlingActor.getOrCreate(); @@ -96,11 +82,7 @@ export function runActorErrorHandlingTests( // TODO: Does not work with fake timers describe.skip("Action Timeout", () => { test("should handle action timeouts with custom duration", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Call an action that should time out const handle = client.errorHandlingActor.getOrCreate(); @@ -120,11 +102,7 @@ export function runActorErrorHandlingTests( }); test("should successfully run actions within timeout", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Call an action with a delay shorter than the timeout const handle = client.errorHandlingActor.getOrCreate(); @@ -135,11 +113,7 @@ export function runActorErrorHandlingTests( }); test("should respect different timeouts for different actors", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // The following actors have different timeout settings: // customTimeoutActor: 200ms timeout @@ -164,11 +138,7 @@ export function runActorErrorHandlingTests( describe("Error Recovery", () => { test("should continue working after errors", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); const handle = client.errorHandlingActor.getOrCreate(); diff --git a/packages/core/src/driver-test-suite/tests/actor-handle.ts b/packages/core/src/driver-test-suite/tests/actor-handle.ts index 3d7842ee0..d278d2aab 100644 --- a/packages/core/src/driver-test-suite/tests/actor-handle.ts +++ b/packages/core/src/driver-test-suite/tests/actor-handle.ts @@ -1,6 +1,6 @@ -import { describe, test, expect, vi } from "vitest"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; -import { setupDriverTest, waitFor } from "../utils"; +import { setupDriverTest } from "../utils"; export function runActorHandleTests(driverTestConfig: DriverTestConfig) { describe("Actor Handle Tests", () => { diff --git a/packages/core/src/driver-test-suite/tests/actor-metadata.ts b/packages/core/src/driver-test-suite/tests/actor-metadata.ts index 377889e47..1e24145fb 100644 --- a/packages/core/src/driver-test-suite/tests/actor-metadata.ts +++ b/packages/core/src/driver-test-suite/tests/actor-metadata.ts @@ -1,142 +1,116 @@ -import { describe, test, expect } from "vitest"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; -export function runActorMetadataTests( - driverTestConfig: DriverTestConfig -) { - describe("Actor Metadata Tests", () => { - describe("Actor Name", () => { - test("should provide access to actor name", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Get the actor name - const handle = client.metadataActor.getOrCreate(); - const actorName = await handle.getActorName(); - - // Verify it matches the expected name - expect(actorName).toBe("metadataActor"); - }); - - test("should preserve actor name in state during onStart", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Get the stored actor name - const handle = client.metadataActor.getOrCreate(); - const storedName = await handle.getStoredActorName(); - - // Verify it was stored correctly - expect(storedName).toBe("metadataActor"); - }); - }); - - describe("Actor Tags", () => { - test("should provide access to tags", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create actor and set up test tags - const handle = client.metadataActor.getOrCreate(); - await handle.setupTestTags({ - "env": "test", - "purpose": "metadata-test" - }); - - // Get the tags - const tags = await handle.getTags(); - - // Verify the tags are accessible - expect(tags).toHaveProperty("env"); - expect(tags.env).toBe("test"); - expect(tags).toHaveProperty("purpose"); - expect(tags.purpose).toBe("metadata-test"); - }); - - test("should allow accessing individual tags", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create actor and set up test tags - const handle = client.metadataActor.getOrCreate(); - await handle.setupTestTags({ - "category": "test-actor", - "version": "1.0" - }); - - // Get individual tags - const category = await handle.getTag("category"); - const version = await handle.getTag("version"); - const nonexistent = await handle.getTag("nonexistent"); - - // Verify the tag values - expect(category).toBe("test-actor"); - expect(version).toBe("1.0"); - expect(nonexistent).toBeNull(); - }); - }); - - describe("Metadata Structure", () => { - test("should provide complete metadata object", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create actor and set up test metadata - const handle = client.metadataActor.getOrCreate(); - await handle.setupTestTags({ "type": "metadata-test" }); - await handle.setupTestRegion("us-west-1"); - - // Get all metadata - const metadata = await handle.getMetadata(); - - // Verify structure of metadata - expect(metadata).toHaveProperty("name"); - expect(metadata.name).toBe("metadataActor"); - - expect(metadata).toHaveProperty("tags"); - expect(metadata.tags).toHaveProperty("type"); - expect(metadata.tags.type).toBe("metadata-test"); - - // Region should be set to our test value - expect(metadata).toHaveProperty("region"); - expect(metadata.region).toBe("us-west-1"); - }); - }); - - describe("Region Information", () => { - test("should retrieve region information", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create actor and set up test region - const handle = client.metadataActor.getOrCreate(); - await handle.setupTestRegion("eu-central-1"); - - // Get the region - const region = await handle.getRegion(); - - // Verify the region is set correctly - expect(region).toBe("eu-central-1"); - }); - }); - }); +export function runActorMetadataTests(driverTestConfig: DriverTestConfig) { + describe("Actor Metadata Tests", () => { + describe("Actor Name", () => { + test("should provide access to actor name", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Get the actor name + const handle = client.metadataActor.getOrCreate(); + const actorName = await handle.getActorName(); + + // Verify it matches the expected name + expect(actorName).toBe("metadataActor"); + }); + + test("should preserve actor name in state during onStart", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Get the stored actor name + const handle = client.metadataActor.getOrCreate(); + const storedName = await handle.getStoredActorName(); + + // Verify it was stored correctly + expect(storedName).toBe("metadataActor"); + }); + }); + + describe("Actor Tags", () => { + test("should provide access to tags", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create actor and set up test tags + const handle = client.metadataActor.getOrCreate(); + await handle.setupTestTags({ + env: "test", + purpose: "metadata-test", + }); + + // Get the tags + const tags = await handle.getTags(); + + // Verify the tags are accessible + expect(tags).toHaveProperty("env"); + expect(tags.env).toBe("test"); + expect(tags).toHaveProperty("purpose"); + expect(tags.purpose).toBe("metadata-test"); + }); + + test("should allow accessing individual tags", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create actor and set up test tags + const handle = client.metadataActor.getOrCreate(); + await handle.setupTestTags({ + category: "test-actor", + version: "1.0", + }); + + // Get individual tags + const category = await handle.getTag("category"); + const version = await handle.getTag("version"); + const nonexistent = await handle.getTag("nonexistent"); + + // Verify the tag values + expect(category).toBe("test-actor"); + expect(version).toBe("1.0"); + expect(nonexistent).toBeNull(); + }); + }); + + describe("Metadata Structure", () => { + test("should provide complete metadata object", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create actor and set up test metadata + const handle = client.metadataActor.getOrCreate(); + await handle.setupTestTags({ type: "metadata-test" }); + await handle.setupTestRegion("us-west-1"); + + // Get all metadata + const metadata = await handle.getMetadata(); + + // Verify structure of metadata + expect(metadata).toHaveProperty("name"); + expect(metadata.name).toBe("metadataActor"); + + expect(metadata).toHaveProperty("tags"); + expect(metadata.tags).toHaveProperty("type"); + expect(metadata.tags.type).toBe("metadata-test"); + + // Region should be set to our test value + expect(metadata).toHaveProperty("region"); + expect(metadata.region).toBe("us-west-1"); + }); + }); + + describe("Region Information", () => { + test("should retrieve region information", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create actor and set up test region + const handle = client.metadataActor.getOrCreate(); + await handle.setupTestRegion("eu-central-1"); + + // Get the region + const region = await handle.getRegion(); + + // Verify the region is set correctly + expect(region).toBe("eu-central-1"); + }); + }); + }); } diff --git a/packages/core/src/driver-test-suite/tests/actor-schedule.ts b/packages/core/src/driver-test-suite/tests/actor-schedule.ts index fa7d323e3..8a655e9f3 100644 --- a/packages/core/src/driver-test-suite/tests/actor-schedule.ts +++ b/packages/core/src/driver-test-suite/tests/actor-schedule.ts @@ -1,123 +1,105 @@ -import { describe, test, expect } from "vitest"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest, waitFor } from "../utils"; -export function runActorScheduleTests( - driverTestConfig: DriverTestConfig -) { - describe("Actor Schedule Tests", () => { - describe("Scheduled Alarms", () => { - test("executes c.schedule.at() with specific timestamp", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create instance - const scheduled = client.scheduled.getOrCreate(); - - // Schedule a task to run in 100ms using timestamp - const timestamp = Date.now() + 100; - await scheduled.scheduleTaskAt(timestamp); - - // Wait for longer than the scheduled time - await waitFor(driverTestConfig, 150); - - // Verify the scheduled task ran - const lastRun = await scheduled.getLastRun(); - const scheduledCount = await scheduled.getScheduledCount(); - - expect(lastRun).toBeGreaterThan(0); - expect(scheduledCount).toBe(1); - }); - - test("executes c.schedule.after() with delay", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create instance - const scheduled = client.scheduled.getOrCreate(); - - // Schedule a task to run in 100ms using delay - await scheduled.scheduleTaskAfter(100); - - // Wait for longer than the scheduled time - await waitFor(driverTestConfig, 150); - - // Verify the scheduled task ran - const lastRun = await scheduled.getLastRun(); - const scheduledCount = await scheduled.getScheduledCount(); - - expect(lastRun).toBeGreaterThan(0); - expect(scheduledCount).toBe(1); - }); - - test("scheduled tasks persist across actor restarts", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create instance and schedule - const scheduled = client.scheduled.getOrCreate(); - await scheduled.scheduleTaskAfter(200); - - // Wait a little so the schedule is stored but hasn't triggered yet - await waitFor(driverTestConfig, 50); - - // Get a new reference to simulate actor restart - const newInstance = client.scheduled.getOrCreate(); - - // Verify the schedule still exists but hasn't run yet - const initialCount = await newInstance.getScheduledCount(); - expect(initialCount).toBe(0); - - // Wait for the scheduled task to execute - await waitFor(driverTestConfig, 200); - - // Verify the scheduled task ran after "restart" - const scheduledCount = await newInstance.getScheduledCount(); - expect(scheduledCount).toBe(1); - }); - - test("multiple scheduled tasks execute in order", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create instance - const scheduled = client.scheduled.getOrCreate(); - - // Reset history to start fresh - await scheduled.clearHistory(); - - // Schedule multiple tasks with different delays - await scheduled.scheduleTaskAfterWithId("first", 50); - await scheduled.scheduleTaskAfterWithId("second", 150); - await scheduled.scheduleTaskAfterWithId("third", 250); - - // Wait for first task only - await waitFor(driverTestConfig, 100); - const history1 = await scheduled.getTaskHistory(); - expect(history1).toEqual(["first"]); - - // Wait for second task - await waitFor(driverTestConfig, 100); - const history2 = await scheduled.getTaskHistory(); - expect(history2).toEqual(["first", "second"]); - - // Wait for third task - await waitFor(driverTestConfig, 100); - const history3 = await scheduled.getTaskHistory(); - expect(history3).toEqual(["first", "second", "third"]); - }); - }); - }); +export function runActorScheduleTests(driverTestConfig: DriverTestConfig) { + describe("Actor Schedule Tests", () => { + describe("Scheduled Alarms", () => { + test("executes c.schedule.at() with specific timestamp", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create instance + const scheduled = client.scheduled.getOrCreate(); + + // Schedule a task to run in 100ms using timestamp + const timestamp = Date.now() + 100; + await scheduled.scheduleTaskAt(timestamp); + + // Wait for longer than the scheduled time + await waitFor(driverTestConfig, 150); + + // Verify the scheduled task ran + const lastRun = await scheduled.getLastRun(); + const scheduledCount = await scheduled.getScheduledCount(); + + expect(lastRun).toBeGreaterThan(0); + expect(scheduledCount).toBe(1); + }); + + test("executes c.schedule.after() with delay", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create instance + const scheduled = client.scheduled.getOrCreate(); + + // Schedule a task to run in 100ms using delay + await scheduled.scheduleTaskAfter(100); + + // Wait for longer than the scheduled time + await waitFor(driverTestConfig, 150); + + // Verify the scheduled task ran + const lastRun = await scheduled.getLastRun(); + const scheduledCount = await scheduled.getScheduledCount(); + + expect(lastRun).toBeGreaterThan(0); + expect(scheduledCount).toBe(1); + }); + + test("scheduled tasks persist across actor restarts", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create instance and schedule + const scheduled = client.scheduled.getOrCreate(); + await scheduled.scheduleTaskAfter(200); + + // Wait a little so the schedule is stored but hasn't triggered yet + await waitFor(driverTestConfig, 50); + + // Get a new reference to simulate actor restart + const newInstance = client.scheduled.getOrCreate(); + + // Verify the schedule still exists but hasn't run yet + const initialCount = await newInstance.getScheduledCount(); + expect(initialCount).toBe(0); + + // Wait for the scheduled task to execute + await waitFor(driverTestConfig, 200); + + // Verify the scheduled task ran after "restart" + const scheduledCount = await newInstance.getScheduledCount(); + expect(scheduledCount).toBe(1); + }); + + test("multiple scheduled tasks execute in order", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create instance + const scheduled = client.scheduled.getOrCreate(); + + // Reset history to start fresh + await scheduled.clearHistory(); + + // Schedule multiple tasks with different delays + await scheduled.scheduleTaskAfterWithId("first", 50); + await scheduled.scheduleTaskAfterWithId("second", 150); + await scheduled.scheduleTaskAfterWithId("third", 250); + + // Wait for first task only + await waitFor(driverTestConfig, 100); + const history1 = await scheduled.getTaskHistory(); + expect(history1).toEqual(["first"]); + + // Wait for second task + await waitFor(driverTestConfig, 100); + const history2 = await scheduled.getTaskHistory(); + expect(history2).toEqual(["first", "second"]); + + // Wait for third task + await waitFor(driverTestConfig, 100); + const history3 = await scheduled.getTaskHistory(); + expect(history3).toEqual(["first", "second", "third"]); + }); + }); + }); } diff --git a/packages/core/src/driver-test-suite/tests/actor-state.ts b/packages/core/src/driver-test-suite/tests/actor-state.ts index a6c25390e..07a8028c8 100644 --- a/packages/core/src/driver-test-suite/tests/actor-state.ts +++ b/packages/core/src/driver-test-suite/tests/actor-state.ts @@ -1,68 +1,54 @@ -import { describe, test, expect } from "vitest"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; -export function runActorStateTests( - driverTestConfig: DriverTestConfig -) { - describe("Actor State Tests", () => { - describe("State Persistence", () => { - test("persists state between actor instances", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create instance and increment - const counterInstance = client.counter.getOrCreate(); - const initialCount = await counterInstance.increment(5); - expect(initialCount).toBe(5); - - // Get a fresh reference to the same actor and verify state persisted - const sameInstance = client.counter.getOrCreate(); - const persistedCount = await sameInstance.increment(3); - expect(persistedCount).toBe(8); - }); - - test("restores state after actor disconnect/reconnect", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create actor and set initial state - const counterInstance = client.counter.getOrCreate(); - await counterInstance.increment(5); - - // Reconnect to the same actor - const reconnectedInstance = client.counter.getOrCreate(); - const persistedCount = await reconnectedInstance.increment(0); - expect(persistedCount).toBe(5); - }); - - test("maintains separate state for different actors", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create first counter with specific key - const counterA = client.counter.getOrCreate(["counter-a"]); - await counterA.increment(5); - - // Create second counter with different key - const counterB = client.counter.getOrCreate(["counter-b"]); - await counterB.increment(10); - - // Verify state is separate - const countA = await counterA.increment(0); - const countB = await counterB.increment(0); - expect(countA).toBe(5); - expect(countB).toBe(10); - }); - }); - }); +export function runActorStateTests(driverTestConfig: DriverTestConfig) { + describe("Actor State Tests", () => { + describe("State Persistence", () => { + test("persists state between actor instances", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create instance and increment + const counterInstance = client.counter.getOrCreate(); + const initialCount = await counterInstance.increment(5); + expect(initialCount).toBe(5); + + // Get a fresh reference to the same actor and verify state persisted + const sameInstance = client.counter.getOrCreate(); + const persistedCount = await sameInstance.increment(3); + expect(persistedCount).toBe(8); + }); + + test("restores state after actor disconnect/reconnect", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create actor and set initial state + const counterInstance = client.counter.getOrCreate(); + await counterInstance.increment(5); + + // Reconnect to the same actor + const reconnectedInstance = client.counter.getOrCreate(); + const persistedCount = await reconnectedInstance.increment(0); + expect(persistedCount).toBe(5); + }); + + test("maintains separate state for different actors", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create first counter with specific key + const counterA = client.counter.getOrCreate(["counter-a"]); + await counterA.increment(5); + + // Create second counter with different key + const counterB = client.counter.getOrCreate(["counter-b"]); + await counterB.increment(10); + + // Verify state is separate + const countA = await counterA.increment(0); + const countB = await counterB.increment(0); + expect(countA).toBe(5); + expect(countB).toBe(10); + }); + }); + }); } diff --git a/packages/core/src/driver-test-suite/tests/actor-vars.ts b/packages/core/src/driver-test-suite/tests/actor-vars.ts index d51f2fbbf..7002bc9b2 100644 --- a/packages/core/src/driver-test-suite/tests/actor-vars.ts +++ b/packages/core/src/driver-test-suite/tests/actor-vars.ts @@ -1,113 +1,93 @@ -import { describe, test, expect } from "vitest"; +import { describe, expect, test } from "vitest"; import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; export function runActorVarsTests(driverTestConfig: DriverTestConfig) { - describe("Actor Variables", () => { - describe("Static vars", () => { - test("should provide access to static vars", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - const instance = client.staticVarActor.getOrCreate(); - - // Test accessing vars - const result = await instance.getVars(); - expect(result).toEqual({ counter: 42, name: "test-actor" }); - - // Test accessing specific var property - const name = await instance.getName(); - expect(name).toBe("test-actor"); - }); - }); - - describe("Deep cloning of static vars", () => { - test("should deep clone static vars between actor instances", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create two separate instances - const instance1 = client.nestedVarActor.getOrCreate(["instance1"]); - const instance2 = client.nestedVarActor.getOrCreate(["instance2"]); - - // Modify vars in the first instance - const modifiedVars = await instance1.modifyNested(); - expect(modifiedVars.nested.value).toBe("modified"); - expect(modifiedVars.nested.array).toContain(4); - expect(modifiedVars.nested.obj.key).toBe("new-value"); - - // Check that the second instance still has the original values - const instance2Vars = await instance2.getVars(); - expect(instance2Vars.nested.value).toBe("original"); - expect(instance2Vars.nested.array).toEqual([1, 2, 3]); - expect(instance2Vars.nested.obj.key).toBe("value"); - }); - }); - - describe("createVars", () => { - test("should support dynamic vars creation", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create an instance - const instance = client.dynamicVarActor.getOrCreate(); - - // Test accessing dynamically created vars - const vars = await instance.getVars(); - expect(vars).toHaveProperty("random"); - expect(vars).toHaveProperty("computed"); - expect(typeof vars.random).toBe("number"); - expect(typeof vars.computed).toBe("string"); - expect(vars.computed).toMatch(/^Actor-\d+$/); - }); - - test("should create different vars for different instances", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create two separate instances - const instance1 = client.uniqueVarActor.getOrCreate(["test1"]); - const instance2 = client.uniqueVarActor.getOrCreate(["test2"]); - - // Get vars from both instances - const vars1 = await instance1.getVars(); - const vars2 = await instance2.getVars(); - - // Verify they have different values - expect(vars1.id).not.toBe(vars2.id); - }); - }); - - describe("Driver Context", () => { - test("should provide access to driver context", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); - - // Create an instance - const instance = client.driverCtxActor.getOrCreate(); - - // Test accessing driver context through vars - const vars = await instance.getVars(); - - // Driver context might or might not be available depending on the driver - // But the test should run without errors - expect(vars).toHaveProperty('hasDriverCtx'); - }); - }); - }); + describe("Actor Variables", () => { + describe("Static vars", () => { + test("should provide access to static vars", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + const instance = client.staticVarActor.getOrCreate(); + + // Test accessing vars + const result = await instance.getVars(); + expect(result).toEqual({ counter: 42, name: "test-actor" }); + + // Test accessing specific var property + const name = await instance.getName(); + expect(name).toBe("test-actor"); + }); + }); + + describe("Deep cloning of static vars", () => { + test("should deep clone static vars between actor instances", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create two separate instances + const instance1 = client.nestedVarActor.getOrCreate(["instance1"]); + const instance2 = client.nestedVarActor.getOrCreate(["instance2"]); + + // Modify vars in the first instance + const modifiedVars = await instance1.modifyNested(); + expect(modifiedVars.nested.value).toBe("modified"); + expect(modifiedVars.nested.array).toContain(4); + expect(modifiedVars.nested.obj.key).toBe("new-value"); + + // Check that the second instance still has the original values + const instance2Vars = await instance2.getVars(); + expect(instance2Vars.nested.value).toBe("original"); + expect(instance2Vars.nested.array).toEqual([1, 2, 3]); + expect(instance2Vars.nested.obj.key).toBe("value"); + }); + }); + + describe("createVars", () => { + test("should support dynamic vars creation", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create an instance + const instance = client.dynamicVarActor.getOrCreate(); + + // Test accessing dynamically created vars + const vars = await instance.getVars(); + expect(vars).toHaveProperty("random"); + expect(vars).toHaveProperty("computed"); + expect(typeof vars.random).toBe("number"); + expect(typeof vars.computed).toBe("string"); + expect(vars.computed).toMatch(/^Actor-\d+$/); + }); + + test("should create different vars for different instances", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create two separate instances + const instance1 = client.uniqueVarActor.getOrCreate(["test1"]); + const instance2 = client.uniqueVarActor.getOrCreate(["test2"]); + + // Get vars from both instances + const vars1 = await instance1.getVars(); + const vars2 = await instance2.getVars(); + + // Verify they have different values + expect(vars1.id).not.toBe(vars2.id); + }); + }); + + describe("Driver Context", () => { + test("should provide access to driver context", async (c) => { + const { client } = await setupDriverTest(c, driverTestConfig); + + // Create an instance + const instance = client.driverCtxActor.getOrCreate(); + + // Test accessing driver context through vars + const vars = await instance.getVars(); + + // Driver context might or might not be available depending on the driver + // But the test should run without errors + expect(vars).toHaveProperty("hasDriverCtx"); + }); + }); + }); } diff --git a/packages/core/src/driver-test-suite/tests/manager-driver.ts b/packages/core/src/driver-test-suite/tests/manager-driver.ts index e2ce7641f..29c42a96d 100644 --- a/packages/core/src/driver-test-suite/tests/manager-driver.ts +++ b/packages/core/src/driver-test-suite/tests/manager-driver.ts @@ -1,17 +1,13 @@ -import { describe, test, expect, vi } from "vitest"; +import type { ActorError } from "@/client/mod"; +import { describe, expect, test } from "vitest"; +import type { DriverTestConfig } from "../mod"; import { setupDriverTest } from "../utils"; -import { ActorError } from "@/client/mod"; -import { DriverTestConfig } from "../mod"; export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { describe("Manager Driver Tests", () => { describe("Client Connection Methods", () => { test("connect() - finds or creates a actor", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Basic connect() with no parameters creates a default actor const counterA = client.counter.getOrCreate(); @@ -31,11 +27,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("throws ActorAlreadyExists when creating duplicate actors", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create a unique actor with specific key const uniqueKey = ["duplicate-actor-test", crypto.randomUUID()]; @@ -58,11 +50,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { describe("Connection Options", () => { test("get without create prevents actor creation", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Try to get a nonexistent actor with no create const nonexistentId = `nonexistent-${crypto.randomUUID()}`; @@ -87,11 +75,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("connection params are passed to actors", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create a actor with connection params // Note: In a real test we'd verify these are received by the actor, @@ -113,11 +97,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { describe("Actor Creation & Retrieval", () => { test("creates and retrieves actors by ID", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create a unique ID for this test const uniqueId = `test-counter-${crypto.randomUUID()}`; @@ -133,11 +113,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("passes input to actor during creation", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Test data to pass as input const testInput = { @@ -162,11 +138,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("input is undefined when not provided", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create actor without providing input const actor = await client.inputActor.create(); @@ -182,11 +154,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("getOrCreate passes input to actor during creation", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create a unique key for this test const uniqueKey = [`input-test-${crypto.randomUUID()}`]; @@ -251,11 +219,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { describe("Key Matching", () => { test("matches actors only with exactly the same keys", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create actor with multiple keys const originalCounter = client.counter.getOrCreate([ @@ -289,11 +253,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("string key matches array with single string key", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create actor with string key const stringKeyCounter = client.counter.getOrCreate("string-key-test"); @@ -306,11 +266,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("undefined key matches empty array key and no key", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create actor with undefined key const undefinedKeyCounter = client.counter.getOrCreate(undefined); @@ -328,11 +284,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("no keys does not match actors with keys", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create counter with keys const keyedCounter = client.counter.getOrCreate([ @@ -348,11 +300,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("actors with keys match actors with no keys", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create a counter with no keys const noKeysCounter = client.counter.getOrCreate(); @@ -373,11 +321,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { describe("Multiple Actor Instances", () => { // TODO: This test is flakey https://github.com/rivet-gg/rivetkit/issues/873 test("creates multiple actor instances of the same type", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Create multiple instances with different IDs const instance1 = client.counter.getOrCreate(["multi-1"]); @@ -401,11 +345,7 @@ export function runManagerDriverTests(driverTestConfig: DriverTestConfig) { }); test("handles default instance with no explicit ID", async (c) => { - const { client } = await setupDriverTest( - c, - driverTestConfig, - - ); + const { client } = await setupDriverTest(c, driverTestConfig); // Get default instance (no ID specified) const defaultCounter = client.counter.getOrCreate(); diff --git a/packages/core/src/driver-test-suite/utils.ts b/packages/core/src/driver-test-suite/utils.ts index 33d72f3de..f402a2b96 100644 --- a/packages/core/src/driver-test-suite/utils.ts +++ b/packages/core/src/driver-test-suite/utils.ts @@ -1,11 +1,11 @@ +import { resolve } from "node:path"; +import { assertUnreachable } from "@/actor/utils"; +import { createClientWithDriver } from "@/client/client"; +import { type Client, createClient } from "@/client/mod"; import { type TestContext, vi } from "vitest"; -import { createClient, type Client } from "@/client/mod"; +import type { Registry } from "../../fixtures/driver-test-suite/registry"; import type { DriverTestConfig } from "./mod"; -import { assertUnreachable } from "@/actor/utils"; -import { createClientWithDriver } from "@/client/client"; import { createTestInlineClientDriver } from "./test-inline-client-driver"; -import { resolve } from "node:path"; -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( diff --git a/packages/core/src/drivers/memory/global-state.ts b/packages/core/src/drivers/memory/global-state.ts index ddfb449c4..5aafc9770 100644 --- a/packages/core/src/drivers/memory/global-state.ts +++ b/packages/core/src/drivers/memory/global-state.ts @@ -1,4 +1,4 @@ -import type { ActorKey } from "@/common/utils"; +import type { ActorKey } from "@/actor/mod"; export interface ActorState { id: string; @@ -51,9 +51,7 @@ export class MemoryGlobalState { } } - findActor( - filter: (actor: ActorState) => boolean, - ): ActorState | undefined { + findActor(filter: (actor: ActorState) => boolean): ActorState | undefined { for (const actor of this.#actors.values()) { if (filter(actor)) { return actor; diff --git a/packages/core/src/drivers/memory/log.ts b/packages/core/src/drivers/memory/log.ts index e690d2e40..d66d17087 100644 --- a/packages/core/src/drivers/memory/log.ts +++ b/packages/core/src/drivers/memory/log.ts @@ -3,5 +3,5 @@ import { getLogger } from "@/common/log"; export const LOGGER_NAME = "driver-memory"; export function logger() { - return getLogger(LOGGER_NAME); + return getLogger(LOGGER_NAME); } diff --git a/packages/core/src/drivers/memory/manager.ts b/packages/core/src/drivers/memory/manager.ts index 23d10ae91..ebd1c77c0 100644 --- a/packages/core/src/drivers/memory/manager.ts +++ b/packages/core/src/drivers/memory/manager.ts @@ -1,14 +1,14 @@ +import * as crypto from "node:crypto"; +import { ActorAlreadyExists } from "@/actor/errors"; import type { + ActorOutput, CreateInput, GetForIdInput, - GetWithKeyInput, GetOrCreateWithKeyInput, - ActorOutput, + GetWithKeyInput, ManagerDriver, } from "@/driver-helpers/mod"; -import { ActorAlreadyExists } from "@/actor/errors"; import type { MemoryGlobalState } from "./global-state"; -import * as crypto from "node:crypto"; export class MemoryManagerDriver implements ManagerDriver { #state: MemoryGlobalState; @@ -22,9 +22,7 @@ export class MemoryManagerDriver implements ManagerDriver { this.#state = state; } - async getForId({ - actorId, - }: GetForIdInput): Promise { + async getForId({ actorId }: GetForIdInput): Promise { // Validate the actor exists const actor = this.#state.getActor(actorId); if (!actor) { diff --git a/packages/core/src/drivers/memory/mod.ts b/packages/core/src/drivers/memory/mod.ts index 07a87f28b..934fe91a1 100644 --- a/packages/core/src/drivers/memory/mod.ts +++ b/packages/core/src/drivers/memory/mod.ts @@ -1,7 +1,7 @@ import type { DriverConfig } from "@/registry/run-config"; -import { MemoryManagerDriver } from "./manager"; +import { MemoryActorDriver } from "./actor"; import { MemoryGlobalState } from "./global-state"; -import { MemoryActorDriver } from "./actor"; +import { MemoryManagerDriver } from "./manager"; export function createMemoryDriver(): DriverConfig { const state = new MemoryGlobalState(); diff --git a/packages/core/src/drivers/rivet/actor-driver.ts b/packages/core/src/drivers/rivet/actor-driver.ts index 5bdb4c7f0..2debd89c5 100644 --- a/packages/core/src/drivers/rivet/actor-driver.ts +++ b/packages/core/src/drivers/rivet/actor-driver.ts @@ -1,5 +1,5 @@ -import { ActorContext } from "@rivet-gg/actor-core"; import type { ActorDriver, AnyActorInstance } from "@/driver-helpers/mod"; +import type { ActorContext } from "@rivet-gg/actor-core"; export interface ActorDriverContext { ctx: ActorContext; diff --git a/packages/core/src/drivers/rivet/actor-meta.ts b/packages/core/src/drivers/rivet/actor-meta.ts index 2c225b679..d0167fe18 100644 --- a/packages/core/src/drivers/rivet/actor-meta.ts +++ b/packages/core/src/drivers/rivet/actor-meta.ts @@ -1,7 +1,11 @@ import { assertUnreachable } from "@/utils"; -import { RivetActor, RivetClientConfig, rivetRequest } from "./rivet-client"; -import { deserializeKeyFromTag, convertKeyToRivetTags } from "./util"; import invariant from "invariant"; +import { + type RivetActor, + type RivetClientConfig, + rivetRequest, +} from "./rivet-client"; +import { convertKeyToRivetTags, deserializeKeyFromTag } from "./util"; interface ActorMeta { name: string; diff --git a/packages/core/src/drivers/rivet/actor.ts b/packages/core/src/drivers/rivet/actor.ts index 2deb5055c..d4576ff3a 100644 --- a/packages/core/src/drivers/rivet/actor.ts +++ b/packages/core/src/drivers/rivet/actor.ts @@ -1,19 +1,19 @@ import { setupLogging } from "@/common/log"; -import { logger } from "./log"; -import { deserializeKeyFromTag, type RivetHandler } from "./util"; +import { stringifyError } from "@/common/utils"; +import type { Registry, RunConfig } from "@/registry/mod"; import { PartitionTopologyActor } from "@/topologies/partition/mod"; -import { RivetActorDriver } from "./actor-driver"; -import invariant from "invariant"; import type { ActorContext } from "@rivet-gg/actor-core"; -import { Registry, RunConfig } from "@/registry/mod"; +import invariant from "invariant"; +import { RivetActorDriver } from "./actor-driver"; import { type Config, ConfigSchema, type InputConfig } from "./config"; -import { stringifyError } from "@/common/utils"; +import { logger } from "./log"; import { RivetManagerDriver } from "./manager-driver"; -import { getRivetClientConfig, RivetClientConfig } from "./rivet-client"; +import { type RivetClientConfig, getRivetClientConfig } from "./rivet-client"; +import { type RivetHandler, deserializeKeyFromTag } from "./util"; export function createActorHandler( registry: Registry, - inputConfig?: InputConfig + inputConfig?: InputConfig, ): RivetHandler { let config: Config; try { @@ -122,10 +122,7 @@ async function startActor( //}; // Create actor topology - const actorTopology = new PartitionTopologyActor( - registry.config, - runConfig, - ); + const actorTopology = new PartitionTopologyActor(registry.config, runConfig); // Set a catch-all route const router = actorTopology.router; diff --git a/packages/core/src/drivers/rivet/config.ts b/packages/core/src/drivers/rivet/config.ts index 83fd50de0..b5844a912 100644 --- a/packages/core/src/drivers/rivet/config.ts +++ b/packages/core/src/drivers/rivet/config.ts @@ -1,9 +1,11 @@ import { RunConfigSchema } from "@/driver-helpers/mod"; -import { z } from "zod"; +import type { z } from "zod"; -export const ConfigSchema = RunConfigSchema.removeDefault().omit({ - driver: true, - getUpgradeWebSocket: true, -}).default({}) +export const ConfigSchema = RunConfigSchema.removeDefault() + .omit({ + driver: true, + getUpgradeWebSocket: true, + }) + .default({}); export type InputConfig = z.input; export type Config = z.infer; diff --git a/packages/core/src/drivers/rivet/conn-routing-handler.ts b/packages/core/src/drivers/rivet/conn-routing-handler.ts index ed561d01f..68d7bf8cc 100644 --- a/packages/core/src/drivers/rivet/conn-routing-handler.ts +++ b/packages/core/src/drivers/rivet/conn-routing-handler.ts @@ -1,17 +1,17 @@ -import { logger } from "./log"; -import { type RivetClientConfig } from "./rivet-client"; -import { getActorMeta } from "./actor-meta"; -import invariant from "invariant"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import type { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import { importWebSocket } from "@/common/websocket"; import { HEADER_AUTH_DATA, HEADER_CONN_PARAMS, HEADER_ENCODING, HEADER_EXPOSE_INTERNAL_ERROR, } from "@/driver-helpers/mod"; -import { importWebSocket } from "@/common/websocket"; -import { createWebSocketProxy } from "./ws-proxy"; import { proxy } from "hono/proxy"; +import invariant from "invariant"; +import { getActorMeta } from "./actor-meta"; +import { logger } from "./log"; +import type { RivetClientConfig } from "./rivet-client"; +import { createWebSocketProxy } from "./ws-proxy"; export function createRivetConnRoutingHandler( clientConfig: RivetClientConfig, diff --git a/packages/core/src/drivers/rivet/manager-driver.ts b/packages/core/src/drivers/rivet/manager-driver.ts index 7ca3efc9d..f322e58f1 100644 --- a/packages/core/src/drivers/rivet/manager-driver.ts +++ b/packages/core/src/drivers/rivet/manager-driver.ts @@ -1,32 +1,31 @@ -import { assertUnreachable } from "@/common/utils"; -import { ActorAlreadyExists, InternalError } from "@/actor/errors"; +import type { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import { ActorAlreadyExists, InternalError } from "@/actor/errors"; import type { - ManagerDriver, - GetForIdInput, - GetWithKeyInput, ActorOutput, - GetOrCreateWithKeyInput, CreateInput, + GetForIdInput, + GetOrCreateWithKeyInput, + GetWithKeyInput, + ManagerDriver, } from "@/driver-helpers/mod"; -import { logger } from "./log"; -import { - RivetActor, - type RivetClientConfig, - rivetRequest, -} from "./rivet-client"; -import { convertKeyToRivetTags } from "./util"; +import type { RegistryConfig } from "@/registry/mod"; +import { getEnvUniversal } from "@/utils"; +import type { Hono } from "hono"; +import invariant from "invariant"; import { flushCache, getActorMeta, getActorMetaWithKey, populateCache, -} from "./actor-meta"; -import invariant from "invariant"; -import { getEnvUniversal } from "@/utils"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +} from "./actor-meta"; import { createRivetConnRoutingHandler } from "./conn-routing-handler"; -import { Hono } from "hono"; -import { Registry, RegistryConfig } from "@/registry/mod"; +import { logger } from "./log"; +import { + type RivetActor, + type RivetClientConfig, + rivetRequest, +} from "./rivet-client"; +import { convertKeyToRivetTags } from "./util"; export interface ActorState { key: string[]; @@ -48,9 +47,7 @@ export class RivetManagerDriver implements ManagerDriver { this.connRoutingHandler = createRivetConnRoutingHandler(clientConfig); } - async getForId({ - actorId, - }: GetForIdInput): Promise { + async getForId({ actorId }: GetForIdInput): Promise { try { const meta = await getActorMeta(this.#clientConfig, actorId); if (!meta) return undefined; @@ -104,7 +101,7 @@ export class RivetManagerDriver implements ManagerDriver { } // Create the actor request - let actorLogLevel: string | undefined = + const actorLogLevel: string | undefined = getEnvUniversal("_ACTOR_LOG_LEVEL"); const createRequest = { diff --git a/packages/core/src/drivers/rivet/manager.ts b/packages/core/src/drivers/rivet/manager.ts index 2bb1ef670..b89efbb23 100644 --- a/packages/core/src/drivers/rivet/manager.ts +++ b/packages/core/src/drivers/rivet/manager.ts @@ -1,13 +1,12 @@ import { setupLogging } from "@/common/log"; +import type { Registry, RunConfig } from "@/registry/mod"; +import { PartitionTopologyManager } from "@/topologies/partition/mod"; import { serve as honoServe } from "@hono/node-server"; -import { createNodeWebSocket, NodeWebSocket } from "@hono/node-ws"; +import { type NodeWebSocket, createNodeWebSocket } from "@hono/node-ws"; +import { ConfigSchema, type InputConfig } from "./config"; import { logger } from "./log"; -import { GetActorMeta, RivetManagerDriver } from "./manager-driver"; +import { RivetManagerDriver } from "./manager-driver"; import type { RivetClientConfig } from "./rivet-client"; -import { PartitionTopologyManager } from "@/topologies/partition/mod"; -import { ConfigSchema, InputConfig } from "./config"; -import type { Registry, RunConfig } from "@/registry/mod"; -import { flushCache, getActorMeta } from "./actor-meta"; export async function startManager( registry: Registry, diff --git a/packages/core/src/drivers/rivet/mod.ts b/packages/core/src/drivers/rivet/mod.ts index 1e97718ff..fddeb2288 100644 --- a/packages/core/src/drivers/rivet/mod.ts +++ b/packages/core/src/drivers/rivet/mod.ts @@ -12,4 +12,4 @@ export function createRivetManagerDriver(): DriverConfig { }; } -export { createActorHandler } from "./actor"; +export { createActorHandler } from "./actor"; diff --git a/packages/core/src/drivers/rivet/ws-proxy.ts b/packages/core/src/drivers/rivet/ws-proxy.ts index f87981eda..4a57fcaec 100644 --- a/packages/core/src/drivers/rivet/ws-proxy.ts +++ b/packages/core/src/drivers/rivet/ws-proxy.ts @@ -1,8 +1,8 @@ -import { WSContext } from "hono/ws"; -import { logger } from "./log"; -import invariant from "invariant"; -import type { WebSocket, CloseEvent } from "ws"; import { importWebSocket } from "@/common/websocket"; +import type { WSContext } from "hono/ws"; +import invariant from "invariant"; +import type { CloseEvent } from "ws"; +import { logger } from "./log"; /** * Creates a WebSocket proxy to forward connections to a target endpoint diff --git a/packages/core/src/inline-client-driver/fake-event-source.ts b/packages/core/src/inline-client-driver/fake-event-source.ts index 148a35a4e..f9fba771b 100644 --- a/packages/core/src/inline-client-driver/fake-event-source.ts +++ b/packages/core/src/inline-client-driver/fake-event-source.ts @@ -1,219 +1,234 @@ -import { logger } from "./log"; -import type { SSEStreamingApi } from "hono/streaming"; import type { EventListener, EventSource } from "eventsource"; +import type { SSEStreamingApi } from "hono/streaming"; +import { logger } from "./log"; /** * FakeEventSource provides a minimal implementation of an SSE stream * that handles events for the inline client driver */ export class FakeEventSource { - url = "http://internal-sse-endpoint"; - readyState = 1; // OPEN - withCredentials = false; - - // Event handlers - onopen: ((this: EventSource, ev: Event) => any) | null = null; - onmessage: ((this: EventSource, ev: MessageEvent) => any) | null = null; - onerror: ((this: EventSource, ev: Event) => any) | null = null; - - // Private event listeners - #listeners: Record> = { - open: new Set(), - message: new Set(), - error: new Set(), - close: new Set() - }; - - // Stream that will be passed to the handler - #stream: SSEStreamingApi; - #onCloseCallback: () => Promise; - - /** - * Creates a new FakeEventSource - */ - constructor(onCloseCallback: () => Promise) { - this.#onCloseCallback = onCloseCallback; - - this.#stream = this.#createStreamApi(); - - // Trigger open event on next tick - setTimeout(() => { - if (this.readyState === 1) { - this.#dispatchEvent('open'); - } - }, 0); - - logger().debug("FakeEventSource created"); - } - - // Creates the SSE streaming API implementation - #createStreamApi(): SSEStreamingApi { - // Create self-reference for closures - const self = this; - - const streamApi: SSEStreamingApi = { - write: async (input) => { - const data = typeof input === "string" ? input : new TextDecoder().decode(input); - self.#dispatchEvent('message', { data }); - return streamApi; - }, - - writeln: async (input: string) => { - await streamApi.write(input + "\n"); - return streamApi; - }, - - writeSSE: async (message: { data: string | Promise, event?: string, id?: string, retry?: number }): Promise => { - const data = await message.data; - - if (message.event) { - self.#dispatchEvent(message.event, { data }); - } else { - self.#dispatchEvent('message', { data }); - } - }, - - sleep: async (ms: number) => { - await new Promise(resolve => setTimeout(resolve, ms)); - return streamApi; - }, - - close: async () => { - self.close(); - }, - - pipe: async (_body: ReadableStream) => { - // No-op implementation - }, - - onAbort: async (cb: () => void) => { - self.addEventListener("error", () => { - cb(); - }); - return streamApi; - }, - - abort: async () => { - self.#dispatchEvent('error'); - return streamApi; - }, - - // Additional required properties - get responseReadable() { - return null as unknown as ReadableStream; - }, - - get aborted() { - return self.readyState === 2; // CLOSED - }, - - get closed() { - return self.readyState === 2; // CLOSED - } - }; - - return streamApi; - } - - /** - * Closes the connection - */ - close(): void { - if (this.readyState === 2) { // CLOSED - return; - } - - logger().debug("closing FakeEventSource"); - this.readyState = 2; // CLOSED - - // Call the close callback - this.#onCloseCallback().catch(err => { - logger().error("error in onClose callback", { error: err }); - }); - - // Dispatch close event - this.#dispatchEvent('close'); - } - - /** - * Get the stream API to pass to the handler - */ - getStream(): SSEStreamingApi { - return this.#stream; - } - - // Implementation of EventTarget-like interface - addEventListener(type: string, listener: EventListener): void { - if (!this.#listeners[type]) { - this.#listeners[type] = new Set(); - } - this.#listeners[type].add(listener); - - // Map to onX properties as well - if (type === "open" && typeof listener === "function" && !this.onopen) { - this.onopen = listener as any; - } else if (type === "message" && typeof listener === "function" && !this.onmessage) { - this.onmessage = listener as any; - } else if (type === "error" && typeof listener === "function" && !this.onerror) { - this.onerror = listener as any; - } - } - - removeEventListener(type: string, listener: EventListener): void { - if (this.#listeners[type]) { - this.#listeners[type].delete(listener); - } - - // Unset onX property if it matches - if (type === "open" && this.onopen === listener) { - this.onopen = null; - } else if (type === "message" && this.onmessage === listener) { - this.onmessage = null; - } else if (type === "error" && this.onerror === listener) { - this.onerror = null; - } - } - - // Internal method to dispatch events - #dispatchEvent(type: string, detail?: Record): void { - // Create appropriate event - let event: Event; - if (type === 'message' || detail) { - event = new MessageEvent(type, detail); - } else { - event = new Event(type); - } - - // Call specific handler - if (type === 'open' && this.onopen) { - try { - this.onopen.call(this as any, event); - } catch (err) { - logger().error("error in onopen handler", { error: err }); - } - } else if (type === 'message' && this.onmessage) { - try { - this.onmessage.call(this as any, event as MessageEvent); - } catch (err) { - logger().error("error in onmessage handler", { error: err }); - } - } else if (type === 'error' && this.onerror) { - try { - this.onerror.call(this as any, event); - } catch (err) { - logger().error("error in onerror handler", { error: err }); - } - } - - // Call all listeners - if (this.#listeners[type]) { - for (const listener of this.#listeners[type]) { - try { - listener.call(this, event); - } catch (err) { - logger().error(`error in ${type} event listener`, { error: err }); - } - } - } - } + url = "http://internal-sse-endpoint"; + readyState = 1; // OPEN + withCredentials = false; + + // Event handlers + onopen: ((this: EventSource, ev: Event) => any) | null = null; + onmessage: ((this: EventSource, ev: MessageEvent) => any) | null = null; + onerror: ((this: EventSource, ev: Event) => any) | null = null; + + // Private event listeners + #listeners: Record> = { + open: new Set(), + message: new Set(), + error: new Set(), + close: new Set(), + }; + + // Stream that will be passed to the handler + #stream: SSEStreamingApi; + #onCloseCallback: () => Promise; + + /** + * Creates a new FakeEventSource + */ + constructor(onCloseCallback: () => Promise) { + this.#onCloseCallback = onCloseCallback; + + this.#stream = this.#createStreamApi(); + + // Trigger open event on next tick + setTimeout(() => { + if (this.readyState === 1) { + this.#dispatchEvent("open"); + } + }, 0); + + logger().debug("FakeEventSource created"); + } + + // Creates the SSE streaming API implementation + #createStreamApi(): SSEStreamingApi { + // Create self-reference for closures + const self = this; + + const streamApi: SSEStreamingApi = { + write: async (input) => { + const data = + typeof input === "string" ? input : new TextDecoder().decode(input); + self.#dispatchEvent("message", { data }); + return streamApi; + }, + + writeln: async (input: string) => { + await streamApi.write(input + "\n"); + return streamApi; + }, + + writeSSE: async (message: { + data: string | Promise; + event?: string; + id?: string; + retry?: number; + }): Promise => { + const data = await message.data; + + if (message.event) { + self.#dispatchEvent(message.event, { data }); + } else { + self.#dispatchEvent("message", { data }); + } + }, + + sleep: async (ms: number) => { + await new Promise((resolve) => setTimeout(resolve, ms)); + return streamApi; + }, + + close: async () => { + self.close(); + }, + + pipe: async (_body: ReadableStream) => { + // No-op implementation + }, + + onAbort: async (cb: () => void) => { + self.addEventListener("error", () => { + cb(); + }); + return streamApi; + }, + + abort: async () => { + self.#dispatchEvent("error"); + return streamApi; + }, + + // Additional required properties + get responseReadable() { + return null as unknown as ReadableStream; + }, + + get aborted() { + return self.readyState === 2; // CLOSED + }, + + get closed() { + return self.readyState === 2; // CLOSED + }, + }; + + return streamApi; + } + + /** + * Closes the connection + */ + close(): void { + if (this.readyState === 2) { + // CLOSED + return; + } + + logger().debug("closing FakeEventSource"); + this.readyState = 2; // CLOSED + + // Call the close callback + this.#onCloseCallback().catch((err) => { + logger().error("error in onClose callback", { error: err }); + }); + + // Dispatch close event + this.#dispatchEvent("close"); + } + + /** + * Get the stream API to pass to the handler + */ + getStream(): SSEStreamingApi { + return this.#stream; + } + + // Implementation of EventTarget-like interface + addEventListener(type: string, listener: EventListener): void { + if (!this.#listeners[type]) { + this.#listeners[type] = new Set(); + } + this.#listeners[type].add(listener); + + // Map to onX properties as well + if (type === "open" && typeof listener === "function" && !this.onopen) { + this.onopen = listener as any; + } else if ( + type === "message" && + typeof listener === "function" && + !this.onmessage + ) { + this.onmessage = listener as any; + } else if ( + type === "error" && + typeof listener === "function" && + !this.onerror + ) { + this.onerror = listener as any; + } + } + + removeEventListener(type: string, listener: EventListener): void { + if (this.#listeners[type]) { + this.#listeners[type].delete(listener); + } + + // Unset onX property if it matches + if (type === "open" && this.onopen === listener) { + this.onopen = null; + } else if (type === "message" && this.onmessage === listener) { + this.onmessage = null; + } else if (type === "error" && this.onerror === listener) { + this.onerror = null; + } + } + + // Internal method to dispatch events + #dispatchEvent(type: string, detail?: Record): void { + // Create appropriate event + let event: Event; + if (type === "message" || detail) { + event = new MessageEvent(type, detail); + } else { + event = new Event(type); + } + + // Call specific handler + if (type === "open" && this.onopen) { + try { + this.onopen.call(this as any, event); + } catch (err) { + logger().error("error in onopen handler", { error: err }); + } + } else if (type === "message" && this.onmessage) { + try { + this.onmessage.call(this as any, event as MessageEvent); + } catch (err) { + logger().error("error in onmessage handler", { error: err }); + } + } else if (type === "error" && this.onerror) { + try { + this.onerror.call(this as any, event); + } catch (err) { + logger().error("error in onerror handler", { error: err }); + } + } + + // Call all listeners + if (this.#listeners[type]) { + for (const listener of this.#listeners[type]) { + try { + listener.call(this, event); + } catch (err) { + logger().error(`error in ${type} event listener`, { error: err }); + } + } + } + } } diff --git a/packages/core/src/inline-client-driver/fake-websocket.ts b/packages/core/src/inline-client-driver/fake-websocket.ts index 9d6c98f1e..eb4904b33 100644 --- a/packages/core/src/inline-client-driver/fake-websocket.ts +++ b/packages/core/src/inline-client-driver/fake-websocket.ts @@ -1,10 +1,10 @@ -import { WSContext } from "hono/ws"; -import { logger } from "@/registry/log"; -import type { ConnectWebSocketOutput } from "@/actor/router-endpoints"; -import type * as messageToServer from "@/actor/protocol/message/to-server"; import { parseMessage } from "@/actor/protocol/message/mod"; +import type * as messageToServer from "@/actor/protocol/message/to-server"; import type { InputData } from "@/actor/protocol/serde"; -import type { Event, CloseEvent, MessageEvent } from "ws"; +import type { ConnectWebSocketOutput } from "@/actor/router-endpoints"; +import { logger } from "@/registry/log"; +import { WSContext } from "hono/ws"; +import type { CloseEvent, Event, MessageEvent } from "ws"; /** * FakeWebSocket implements a WebSocket-like interface diff --git a/packages/core/src/inline-client-driver/mod.ts b/packages/core/src/inline-client-driver/mod.ts index a518ca4bd..0a52e00d3 100644 --- a/packages/core/src/inline-client-driver/mod.ts +++ b/packages/core/src/inline-client-driver/mod.ts @@ -1,37 +1,35 @@ -import * as errors from "@/actor/errors"; -import * as protoHttpAction from "@/actor/protocol/http/action"; -import { logger } from "./log"; -import type { EventSource } from "eventsource"; -import type * as wsToServer from "@/actor/protocol/message/to-server"; -import { type Encoding, serialize } from "@/actor/protocol/serde"; +import type { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import * as errors from "@/actor/errors"; +import type { + ActionRequest, + ActionResponse, +} from "@/actor/protocol/http/action"; +import type * as wsToServer from "@/actor/protocol/message/to-server"; +import type { Encoding } from "@/actor/protocol/serde"; import { - ConnectWebSocketOutput, - HEADER_CONN_PARAMS, - HEADER_ENCODING, HEADER_CONN_ID, + HEADER_CONN_PARAMS, HEADER_CONN_TOKEN, - type ConnectionHandlers, + HEADER_ENCODING, HEADER_EXPOSE_INTERNAL_ERROR, -} from "@/actor/router-endpoints"; -import type { SSEStreamingApi } from "hono/streaming"; -import { HonoRequest, type Context as HonoContext, type Next } from "hono"; -import invariant from "invariant"; -import { ClientDriver } from "@/client/client"; -import { ManagerDriver } from "@/manager/driver"; -import { ActorQuery } from "@/manager/protocol/query"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; -import { sendHttpRequest, serializeWithEncoding } from "@/client/utils"; -import { ActionRequest, ActionResponse } from "@/actor/protocol/http/action"; -import { assertUnreachable } from "@/actor/utils"; -import { FakeWebSocket } from "./fake-websocket"; -import { FakeEventSource } from "./fake-event-source"; -import { importWebSocket } from "@/common/websocket"; -import { importEventSource } from "@/common/eventsource"; -import onChange from "on-change"; -import { httpUserAgent } from "@/utils"; +} from "@/actor/router-endpoints"; +import { assertUnreachable } from "@/actor/utils"; +import type { ClientDriver } from "@/client/client"; import { ActorError as ClientActorError } from "@/client/errors"; +import { sendHttpRequest } from "@/client/utils"; +import { importEventSource } from "@/common/eventsource"; import { deconstructError } from "@/common/utils"; +import type { ManagerDriver } from "@/manager/driver"; +import type { ActorQuery } from "@/manager/protocol/query"; +import { httpUserAgent } from "@/utils"; +import type { EventSource } from "eventsource"; +import type { Context as HonoContext } from "hono"; +import invariant from "invariant"; +import onChange from "on-change"; import type { WebSocket } from "ws"; +import { FakeEventSource } from "./fake-event-source"; +import { FakeWebSocket } from "./fake-websocket"; +import { logger } from "./log"; /** * Client driver that calls the manager driver inline. diff --git a/packages/core/src/manager/auth.ts b/packages/core/src/manager/auth.ts index 3b7d24c7d..47738a42d 100644 --- a/packages/core/src/manager/auth.ts +++ b/packages/core/src/manager/auth.ts @@ -1,12 +1,12 @@ -import * as errors from "@/actor/errors"; -import type { Context as HonoContext } from "hono"; -import type { ActorQuery } from "./protocol/query"; -import type { AuthIntent } from "@/actor/config"; -import type { AnyActorDefinition } from "@/actor/definition"; +import type { AuthIntent } from "@/actor/config"; +import type { AnyActorDefinition } from "@/actor/definition"; +import * as errors from "@/actor/errors"; import type { RegistryConfig } from "@/registry/config"; -import { ManagerDriver } from "./driver"; import { stringifyError } from "@/utils"; +import type { Context as HonoContext } from "hono"; +import type { ManagerDriver } from "./driver"; import { logger } from "./log"; +import type { ActorQuery } from "./protocol/query"; /** * Get authentication intents from a actor query diff --git a/packages/core/src/manager/driver.ts b/packages/core/src/manager/driver.ts index 9a3fec698..c4c96f7d6 100644 --- a/packages/core/src/manager/driver.ts +++ b/packages/core/src/manager/driver.ts @@ -1,7 +1,6 @@ -import { ClientDriver } from "@/client/client"; -import type { ActorKey } from "@/common/utils"; -import { RegistryConfig } from "@/registry/config"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import type { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import type { ActorKey } from "@/actor/mod"; +import type { RegistryConfig } from "@/registry/config"; import type { Env, Hono, Context as HonoContext } from "hono"; export interface ManagerDriver { diff --git a/packages/core/src/manager/protocol/mod.ts b/packages/core/src/manager/protocol/mod.ts index 8ef6b6fa9..52b94fd6c 100644 --- a/packages/core/src/manager/protocol/mod.ts +++ b/packages/core/src/manager/protocol/mod.ts @@ -1,6 +1,6 @@ +import { TransportSchema } from "@/actor/protocol/message/mod"; import { z } from "zod"; import { ActorQuerySchema } from "./query"; -import { TransportSchema } from "@/actor/protocol/message/mod"; export * from "./query"; export const ActorsRequestSchema = z.object({ @@ -21,4 +21,3 @@ export const ActorsResponseSchema = z.object({ export type ActorsRequest = z.infer; export type ActorsResponse = z.infer; //export type RivetConfigResponse = z.infer; - diff --git a/packages/core/src/manager/protocol/query.ts b/packages/core/src/manager/protocol/query.ts index a89632a9f..2dacf3734 100644 --- a/packages/core/src/manager/protocol/query.ts +++ b/packages/core/src/manager/protocol/query.ts @@ -1,14 +1,22 @@ -import { ActorKeySchema } from "@/common//utils"; -import { z } from "zod"; -import { EncodingSchema } from "@/actor/protocol/serde"; +import { EncodingSchema } from "@/actor/protocol/serde"; import { HEADER_ACTOR_ID, + HEADER_ACTOR_QUERY, HEADER_CONN_ID, HEADER_CONN_PARAMS, HEADER_CONN_TOKEN, HEADER_ENCODING, - HEADER_ACTOR_QUERY, -} from "@/actor/router-endpoints"; +} from "@/actor/router-endpoints"; +import { z } from "zod"; + +// Maximum size of a key component in bytes +// Set to 128 bytes to allow for separators and escape characters in the full key +// Cloudflare's maximum key size is 512 bytes, so we need to be significantly smaller +export const MAX_ACTOR_KEY_SIZE = 128; + +export const ActorKeySchema = z.array(z.string().max(MAX_ACTOR_KEY_SIZE)); + +export type ActorKey = z.infer; export const CreateRequestSchema = z.object({ name: z.string(), diff --git a/packages/core/src/manager/router.ts b/packages/core/src/manager/router.ts index e8bb9d429..96f4767f1 100644 --- a/packages/core/src/manager/router.ts +++ b/packages/core/src/manager/router.ts @@ -1,65 +1,60 @@ -import * as errors from "@/actor/errors"; -import * as cbor from "cbor-x"; -import type * as protoHttpResolve from "@/actor/protocol/http/resolve"; -import type { ToClient } from "@/actor/protocol/message/to-client"; -import { - type Encoding, - EncodingSchema, - serialize, -} from "@/actor/protocol/serde"; +import type { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import * as errors from "@/actor/errors"; +import type * as protoHttpResolve from "@/actor/protocol/http/resolve"; +import type { Transport } from "@/actor/protocol/message/mod"; +import type { ToClient } from "@/actor/protocol/message/to-client"; +import { type Encoding, serialize } from "@/actor/protocol/serde"; import { - type ConnectionHandlers, - getRequestEncoding, - handleConnectionMessage, - handleAction, - handleSseConnect, - handleWebSocketConnect, + ALL_PUBLIC_HEADERS, HEADER_ACTOR_ID, + HEADER_ACTOR_QUERY, + HEADER_AUTH_DATA, HEADER_CONN_ID, HEADER_CONN_PARAMS, HEADER_CONN_TOKEN, HEADER_ENCODING, - HEADER_ACTOR_QUERY, - ALL_PUBLIC_HEADERS, + getRequestEncoding, getRequestQuery, - HEADER_AUTH_DATA, -} from "@/actor/router-endpoints"; -import { assertUnreachable } from "@/actor/utils"; -import type { RegistryConfig } from "@/registry/config"; + handleAction, + handleConnectionMessage, + handleSseConnect, + handleWebSocketConnect, +} from "@/actor/router-endpoints"; +import { assertUnreachable } from "@/actor/utils"; +import type { ClientDriver } from "@/client/client"; import { handleRouteError, handleRouteNotFound, loggerMiddleware, } from "@/common/router"; import { - DeconstructedError, + type DeconstructedError, deconstructError, stringifyError, } from "@/common/utils"; -import { Hono, type Context as HonoContext, type Next } from "hono"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; +import { VERSION } from "@/utils"; import { OpenAPIHono } from "@hono/zod-openapi"; -import { z } from "@hono/zod-openapi"; import { createRoute } from "@hono/zod-openapi"; +import * as cbor from "cbor-x"; +import { Hono, type Context as HonoContext, type Next } from "hono"; import { cors } from "hono/cors"; import { streamSSE } from "hono/streaming"; import type { WSContext } from "hono/ws"; import invariant from "invariant"; +import type { CloseEvent, MessageEvent, WebSocket } from "ws"; +import { z } from "zod"; +import { authenticateEndpoint } from "./auth"; import type { ManagerDriver } from "./driver"; import { logger } from "./log"; import { + ConnMessageRequestSchema, ConnectRequestSchema, ConnectWebSocketRequestSchema, - ConnMessageRequestSchema, ResolveRequestSchema, } from "./protocol/query"; import type { ActorQuery } from "./protocol/query"; -import { VERSION } from "@/utils"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; -import { ClientDriver } from "@/client/client"; -import { Transport } from "@/actor/protocol/message/mod"; -import { authenticateEndpoint } from "./auth"; -import type { WebSocket, MessageEvent, CloseEvent } from "ws"; -import { RunConfig } from "@/registry/run-config"; type ManagerRouterHandler = { // onConnectInspector?: ManagerInspectorConnHandler; @@ -1163,7 +1158,7 @@ async function handleActionRequest( assertUnreachable(handler.routingHandler); } } catch (error) { - logger().error("error in action handler", { error }); + logger().error("error in action handler", { error: stringifyError(error) }); // Use ProxyError if it's not already an ActorError if (!errors.ActorError.isActorError(error)) { diff --git a/packages/core/src/mod.ts b/packages/core/src/mod.ts index 997c65b09..7d82219aa 100644 --- a/packages/core/src/mod.ts +++ b/packages/core/src/mod.ts @@ -1,3 +1,3 @@ export * from "@/registry/mod"; -export * from "@/actor/mod"; +export * from "@/actor/mod"; export * from "@/topologies/mod"; diff --git a/packages/core/src/registry/config.ts b/packages/core/src/registry/config.ts index 2759ba639..08a6b4719 100644 --- a/packages/core/src/registry/config.ts +++ b/packages/core/src/registry/config.ts @@ -1,6 +1,6 @@ //! These configs configs hold anything that's not platform-specific about running actors. -import { AnyActorDefinition, ActorDefinition } from "@/actor/definition"; +import type { ActorDefinition, AnyActorDefinition } from "@/actor/definition"; import { z } from "zod"; export const ActorsSchema = z.record( diff --git a/packages/core/src/registry/mod.ts b/packages/core/src/registry/mod.ts index 5c58118c3..638a9e474 100644 --- a/packages/core/src/registry/mod.ts +++ b/packages/core/src/registry/mod.ts @@ -1,4 +1,13 @@ -import { Client, ClientDriver, createClientWithDriver } from "@/client/client"; +import { + type Client, + type ClientDriver, + createClientWithDriver, +} from "@/client/client"; +import { PartitionTopologyActor, PartitionTopologyManager } from "@/mod"; +import { StandaloneTopology } from "@/topologies/standalone/mod"; +import { assertUnreachable } from "@/utils"; +import type { Hono } from "hono"; +import invariant from "invariant"; import { type RegistryActors, type RegistryConfig, @@ -6,17 +15,11 @@ import { RegistryConfigSchema, } from "./config"; import { - RunConfigSchema, type DriverConfig, type RunConfig, type RunConfigInput, + RunConfigSchema, } from "./run-config"; -import { StandaloneTopology } from "@/topologies/standalone/mod"; -import invariant from "invariant"; -import { Hono } from "hono"; -import { assertUnreachable } from "@/utils"; -import { PartitionTopologyManager, PartitionTopologyActor } from "@/mod"; -import { logger } from "./log"; import { crossPlatformServe } from "./serve"; interface ServerOutput> { diff --git a/packages/core/src/registry/run-config.ts b/packages/core/src/registry/run-config.ts index 60d6e03b9..a12b07c52 100644 --- a/packages/core/src/registry/run-config.ts +++ b/packages/core/src/registry/run-config.ts @@ -1,11 +1,11 @@ -import { z } from "zod"; -import type { Hono } from "hono"; -import type { CoordinateDriver } from "@/topologies/coordinate/driver"; +import type { ActorDriver } from "@/actor/driver"; +import { createMemoryDriver } from "@/drivers/memory/mod"; import type { ManagerDriver } from "@/manager/driver"; -import type { ActorDriver } from "@/actor/driver"; +import type { CoordinateDriver } from "@/topologies/coordinate/driver"; import type { UpgradeWebSocket } from "@/utils"; +import type { Hono } from "hono"; import type { cors } from "hono/cors"; -import { createMemoryDriver } from "@/drivers/memory/mod"; +import { z } from "zod"; type CorsOptions = NonNullable[0]>; @@ -74,7 +74,8 @@ export const RunConfigSchema = z actorPeer: ActorPeerConfigSchema.optional().default({}), // inspector: InspectorConfigSchema.optional().default({ enabled: false }), - }).default({}); + }) + .default({}); export type RunConfig = z.infer; export type RunConfigInput = z.input; diff --git a/packages/core/src/registry/serve.ts b/packages/core/src/registry/serve.ts index 4c2b48aa9..25ed34f94 100644 --- a/packages/core/src/registry/serve.ts +++ b/packages/core/src/registry/serve.ts @@ -1,7 +1,7 @@ +import { getEnvUniversal } from "@/utils"; import { Hono } from "hono"; import { logger } from "./log"; -import { RunConfig } from "./run-config"; -import { getEnvUniversal } from "@/utils"; +import type { RunConfig } from "./run-config"; export async function crossPlatformServe( config: RunConfig, @@ -51,7 +51,7 @@ export async function crossPlatformServe( config.getUpgradeWebSocket = () => upgradeWebSocket; // Start server - const port = parseInt( + const port = Number.parseInt( getEnvUniversal("PORT") ?? getEnvUniversal("PORT_HTTP") ?? "8080", ); const server = serve({ fetch: app.fetch, port }, () => diff --git a/packages/core/src/test/driver/global-state.ts b/packages/core/src/test/driver/global-state.ts index 0f3d69fb0..232855748 100644 --- a/packages/core/src/test/driver/global-state.ts +++ b/packages/core/src/test/driver/global-state.ts @@ -1,4 +1,4 @@ -import type { ActorKey } from "@/mod"; +import type { ActorKey } from "@/actor/mod"; export interface ActorState { id: string; diff --git a/packages/core/src/test/driver/log.ts b/packages/core/src/test/driver/log.ts index 678f89ff8..cc3404df5 100644 --- a/packages/core/src/test/driver/log.ts +++ b/packages/core/src/test/driver/log.ts @@ -3,5 +3,5 @@ import { getLogger } from "@/common/log"; export const LOGGER_NAME = "driver-test"; export function logger() { - return getLogger(LOGGER_NAME); + return getLogger(LOGGER_NAME); } diff --git a/packages/core/src/test/driver/manager.ts b/packages/core/src/test/driver/manager.ts index 668fdced5..1b9bbfda5 100644 --- a/packages/core/src/test/driver/manager.ts +++ b/packages/core/src/test/driver/manager.ts @@ -1,14 +1,14 @@ +import * as crypto from "node:crypto"; +import { ActorAlreadyExists } from "@/actor/errors"; import type { + CreateInput, GetForIdInput, - GetWithKeyInput, GetOrCreateWithKeyInput, + GetWithKeyInput, ManagerDriver, - CreateInput, } from "@/driver-helpers/mod"; -import { ActorAlreadyExists } from "@/actor/errors"; +import type { ActorOutput } from "@/manager/driver"; import type { TestGlobalState } from "./global-state"; -import * as crypto from "node:crypto"; -import { ActorOutput } from "@/manager/driver"; export class TestManagerDriver implements ManagerDriver { #state: TestGlobalState; @@ -18,9 +18,7 @@ export class TestManagerDriver implements ManagerDriver { // getAllTypesOfActors: () => Object.keys(this.registry.config.actors), // }); - constructor( - state: TestGlobalState, - ) { + constructor(state: TestGlobalState) { this.#state = state; } diff --git a/packages/core/src/test/driver/mod.ts b/packages/core/src/test/driver/mod.ts index b3276ffb8..dffab797a 100644 --- a/packages/core/src/test/driver/mod.ts +++ b/packages/core/src/test/driver/mod.ts @@ -1,10 +1,10 @@ -import { DriverConfig } from "@/mod"; +import type { DriverConfig } from "@/mod"; +import { TestActorDriver } from "./actor"; import { TestGlobalState } from "./global-state"; import { TestManagerDriver } from "./manager"; -import { TestActorDriver } from "./actor"; export { TestGlobalState } from "./global-state"; -export { TestActorDriver } from "./actor"; +export { TestActorDriver } from "./actor"; export { TestManagerDriver } from "./manager"; export function createTestDriver(): DriverConfig { diff --git a/packages/core/src/test/mod.ts b/packages/core/src/test/mod.ts index 74fe4879f..438b1b934 100644 --- a/packages/core/src/test/mod.ts +++ b/packages/core/src/test/mod.ts @@ -1,20 +1,20 @@ -import { serve as honoServe, type ServerType } from "@hono/node-server"; -import { createNodeWebSocket, type NodeWebSocket } from "@hono/node-ws"; -import { assertUnreachable } from "@/utils"; +import { createServer } from "node:net"; +import { type Client, createClient } from "@/client/mod"; +import { type Registry, StandaloneTopology } from "@/mod"; +import { RunConfigSchema } from "@/registry/run-config"; import { CoordinateTopology } from "@/topologies/coordinate/mod"; -import { logger } from "./log"; +import { assertUnreachable } from "@/utils"; +import { type ServerType, serve as honoServe } from "@hono/node-server"; +import { type NodeWebSocket, createNodeWebSocket } from "@hono/node-ws"; import type { Hono } from "hono"; -import { StandaloneTopology, type Registry } from "@/mod"; +import { type TestContext, vi } from "vitest"; +import { ConfigSchema, type InputConfig } from "./config"; import { + TestActorDriver, TestGlobalState, TestManagerDriver, - TestActorDriver, } from "./driver/mod"; -import { type InputConfig, ConfigSchema } from "./config"; -import { type TestContext, vi } from "vitest"; -import { type Client, createClient } from "@/client/mod"; -import { createServer } from "node:net"; -import { RunConfigSchema } from "@/registry/run-config"; +import { logger } from "./log"; function createRouter( registry: Registry, @@ -102,7 +102,7 @@ export async function setupTest>( // Set up mock driver for testing createVars context const mockDriverContext: any = {}; - let setDriverContextFn = (ctx: any) => { + const setDriverContextFn = (ctx: any) => { mockDriverContext.current = ctx; }; diff --git a/packages/core/src/topologies/common/generic-conn-driver.ts b/packages/core/src/topologies/common/generic-conn-driver.ts index ba5153ad0..84e987b3d 100644 --- a/packages/core/src/topologies/common/generic-conn-driver.ts +++ b/packages/core/src/topologies/common/generic-conn-driver.ts @@ -1,13 +1,13 @@ -import type { AnyActorInstance } from "@/actor/instance"; -import { AnyConn, Conn } from "@/actor/connection"; -import { logger } from "./log"; -import { CachedSerializer, Encoding } from "@/actor/protocol/serde"; -import { ConnDriver } from "@/actor/driver"; -import * as messageToClient from "@/actor/protocol/message/to-client"; -import { encodeDataToString } from "@/actor/protocol/serde"; -import { WSContext } from "hono/ws"; -import { SSEStreamingApi } from "hono/streaming"; +import type { AnyConn } from "@/actor/connection"; +import type { ConnDriver } from "@/actor/driver"; +import type { AnyActorInstance } from "@/actor/instance"; +import type * as messageToClient from "@/actor/protocol/message/to-client"; +import type { CachedSerializer, Encoding } from "@/actor/protocol/serde"; +import { encodeDataToString } from "@/actor/protocol/serde"; +import type { SSEStreamingApi } from "hono/streaming"; +import type { WSContext } from "hono/ws"; import type { WebSocket } from "ws"; +import { logger } from "./log"; // This state is different than `PersistedConn` state since the connection-specific state is persisted & must be serializable. This is also part of the connection driver, not part of the core actor. // diff --git a/packages/core/src/topologies/coordinate/actor-peer.ts b/packages/core/src/topologies/coordinate/actor-peer.ts index 7ca65902a..79f8de012 100644 --- a/packages/core/src/topologies/coordinate/actor-peer.ts +++ b/packages/core/src/topologies/coordinate/actor-peer.ts @@ -1,15 +1,15 @@ +import type { ActorDriver } from "@/actor/driver"; +import type { AnyActorInstance } from "@/actor/instance"; +import type { ActorKey } from "@/actor/mod"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; import type { GlobalState } from "@/topologies/coordinate/topology"; -import { logger } from "./log"; -import type { CoordinateDriver } from "./driver"; -import type { ActorInstance, AnyActorInstance } from "@/actor/instance"; -import type { ActorKey } from "@/common/utils"; -import { ActorDriver } from "@/actor/driver"; import { CONN_DRIVER_COORDINATE_RELAY, createCoordinateRelayDriver, } from "./conn/driver"; -import { RegistryConfig, RegistryConfigSchema } from "@/registry/config"; -import { DriverConfig, RunConfig } from "@/registry/run-config"; +import type { CoordinateDriver } from "./driver"; +import { logger } from "./log"; export class ActorPeer { #registryConfig: RegistryConfig; @@ -203,14 +203,16 @@ export class ActorPeer { } async #convertToLeader() { - if (!this.#actorName || !this.#actorKey) throw new Error("missing name or key"); + if (!this.#actorName || !this.#actorKey) + throw new Error("missing name or key"); logger().debug("peer acquired leadership", { actorId: this.#actorId }); // Build actor const actorName = this.#actorName; const definition = this.#registryConfig.actors[actorName]; - if (!definition) throw new Error(`no actor definition for name ${definition}`); + if (!definition) + throw new Error(`no actor definition for name ${definition}`); // Create leader actor const actor = definition.instantiate(); diff --git a/packages/core/src/topologies/coordinate/conn/driver.ts b/packages/core/src/topologies/coordinate/conn/driver.ts index 1e01aa079..b2a5a6d53 100644 --- a/packages/core/src/topologies/coordinate/conn/driver.ts +++ b/packages/core/src/topologies/coordinate/conn/driver.ts @@ -1,12 +1,12 @@ -import type { ConnDriver } from "@/actor/driver"; -import type { GlobalState } from "../topology"; -import type { AnyActorInstance } from "@/actor/instance"; -import type { AnyConn, Conn } from "@/actor/connection"; -import type { CachedSerializer } from "@/actor/protocol/serde"; -import type * as messageToClient from "@/actor/protocol/message/to-client"; +import type { AnyConn } from "@/actor/connection"; +import type { ConnDriver } from "@/actor/driver"; +import type { AnyActorInstance } from "@/actor/instance"; +import type * as messageToClient from "@/actor/protocol/message/to-client"; +import type { CachedSerializer } from "@/actor/protocol/serde"; +import type { CoordinateDriver } from "../driver"; import { logger } from "../log"; import type { NodeMessage } from "../node/protocol"; -import type { CoordinateDriver } from "../driver"; +import type { GlobalState } from "../topology"; export const CONN_DRIVER_COORDINATE_RELAY = "coordinateRelay"; diff --git a/packages/core/src/topologies/coordinate/conn/mod.ts b/packages/core/src/topologies/coordinate/conn/mod.ts index a40db21af..e2548c497 100644 --- a/packages/core/src/topologies/coordinate/conn/mod.ts +++ b/packages/core/src/topologies/coordinate/conn/mod.ts @@ -1,15 +1,14 @@ +import { generateConnId, generateConnToken } from "@/actor/connection"; +import type { ActorDriver } from "@/actor/driver"; +import * as errors from "@/actor/errors"; +import type * as messageToClient from "@/actor/protocol/message/to-client"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; import type { GlobalState } from "@/topologies/coordinate/topology"; -import type * as messageToClient from "@/actor/protocol/message/to-client"; -import * as errors from "@/actor/errors"; +import { ActorPeer } from "../actor-peer"; import type { CoordinateDriver } from "../driver"; import { logger } from "../log"; -import { ActorPeer } from "../actor-peer"; import { publishMessageToLeader } from "../node/message"; -import { generateConnId, generateConnToken } from "@/actor/connection"; -import type { ActorDriver } from "@/actor/driver"; -import { RegistryConfig } from "@/registry/config"; -import { unknown } from "zod"; -import { RunConfig } from "@/registry/run-config"; export interface RelayConnDriver { sendMessage(message: messageToClient.ToClient): void; @@ -163,7 +162,7 @@ export class RelayConn { }, }, }, - undefined + undefined, ); } diff --git a/packages/core/src/topologies/coordinate/driver.ts b/packages/core/src/topologies/coordinate/driver.ts index b569c5c39..619c08a06 100644 --- a/packages/core/src/topologies/coordinate/driver.ts +++ b/packages/core/src/topologies/coordinate/driver.ts @@ -1,4 +1,4 @@ -import type { ActorKey } from "@/common/utils"; +import type { ActorKey } from "@/actor/mod"; export type NodeMessageCallback = (message: string) => void; @@ -52,4 +52,4 @@ export interface CoordinateDriver { leaseDuration: number, ): Promise; releaseLease(actorId: string, nodeId: string): Promise; -} \ No newline at end of file +} diff --git a/packages/core/src/topologies/coordinate/node/message.ts b/packages/core/src/topologies/coordinate/node/message.ts index 91e0c8603..846604bae 100644 --- a/packages/core/src/topologies/coordinate/node/message.ts +++ b/packages/core/src/topologies/coordinate/node/message.ts @@ -1,10 +1,10 @@ +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; import type { GlobalState } from "@/topologies/coordinate/topology"; -import { logger } from "../log"; import pRetry, { AbortError } from "p-retry"; import type { CoordinateDriver } from "../driver"; +import { logger } from "../log"; import type { NodeMessage } from "./protocol"; -import { RegistryConfig } from "@/registry/config"; -import { DriverConfig, RunConfig } from "@/registry/run-config"; /** * Publishes a message and waits for an ack. If no ack is received, then retries accordingly. diff --git a/packages/core/src/topologies/coordinate/node/mod.ts b/packages/core/src/topologies/coordinate/node/mod.ts index a80223d3f..09784701c 100644 --- a/packages/core/src/topologies/coordinate/node/mod.ts +++ b/packages/core/src/topologies/coordinate/node/mod.ts @@ -1,19 +1,22 @@ -import type { GlobalState } from "../topology"; +import { assertUnreachable } from "@/common/utils"; +import { ActorPeer } from "../actor-peer"; +import { + CONN_DRIVER_COORDINATE_RELAY, + type CoordinateRelayState, +} from "../conn/driver"; +import type { CoordinateDriver } from "../driver"; import { logger } from "../log"; +import type { GlobalState } from "../topology"; import { + type Ack, type NodeMessage, NodeMessageSchema, type ToFollowerConnectionClose, type ToFollowerMessage, - type Ack, type ToLeaderConnectionClose, type ToLeaderConnectionOpen, type ToLeaderMessage, } from "./protocol"; -import { ActorPeer } from "../actor-peer"; -import type { CoordinateDriver } from "../driver"; -import { CONN_DRIVER_COORDINATE_RELAY, type CoordinateRelayState } from "../conn/driver"; -import { assertUnreachable } from "@/common/utils"; export class Node { #CoordinateDriver: CoordinateDriver; diff --git a/packages/core/src/topologies/coordinate/node/protocol.ts b/packages/core/src/topologies/coordinate/node/protocol.ts index f80bb6e74..3b252949c 100644 --- a/packages/core/src/topologies/coordinate/node/protocol.ts +++ b/packages/core/src/topologies/coordinate/node/protocol.ts @@ -1,6 +1,6 @@ +import * as messageToClient from "@/actor/protocol/message/to-client"; +import * as messageToServer from "@/actor/protocol/message/to-server"; import { z } from "zod"; -import * as messageToServer from "@/actor/protocol/message/to-server" -import * as messageToClient from "@/actor/protocol/message/to-client" export const AckSchema = z.object({ // Message ID @@ -22,7 +22,9 @@ export const ToLeaderConnectionOpenSchema = z.object({ ad: z.unknown(), }); -export type ToLeaderConnectionOpen = z.infer; +export type ToLeaderConnectionOpen = z.infer< + typeof ToLeaderConnectionOpenSchema +>; export const ToLeaderConnectionCloseSchema = z.object({ // Actor ID @@ -31,7 +33,9 @@ export const ToLeaderConnectionCloseSchema = z.object({ ci: z.string(), }); -export type ToLeaderConnectionClose = z.infer; +export type ToLeaderConnectionClose = z.infer< + typeof ToLeaderConnectionCloseSchema +>; export const ToLeaderMessageSchema = z.object({ // Actor ID @@ -53,7 +57,9 @@ export const ToFollowerConnectionCloseSchema = z.object({ r: z.string().optional(), }); -export type ToFollowerConnectionClose = z.infer; +export type ToFollowerConnectionClose = z.infer< + typeof ToFollowerConnectionCloseSchema +>; export const ToFollowerMessageSchema = z.object({ // Connection ID diff --git a/packages/core/src/topologies/coordinate/router/sse.ts b/packages/core/src/topologies/coordinate/router/sse.ts index 9623166f1..dd035ddce 100644 --- a/packages/core/src/topologies/coordinate/router/sse.ts +++ b/packages/core/src/topologies/coordinate/router/sse.ts @@ -1,12 +1,15 @@ +import type { ActorDriver } from "@/actor/driver"; +import { encodeDataToString, serialize } from "@/actor/protocol/serde"; +import type { + ConnectSseOpts, + ConnectSseOutput, +} from "@/actor/router-endpoints"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; import type { GlobalState } from "@/topologies/coordinate/topology"; -import { logger } from "../log"; -import { encodeDataToString, serialize } from "@/actor/protocol/serde"; -import type { CoordinateDriver } from "../driver"; import { RelayConn } from "../conn/mod"; -import type { ActorDriver } from "@/actor/driver"; -import { RegistryConfig } from "@/registry/config"; -import { ConnectSseOpts, ConnectSseOutput } from "@/actor/router-endpoints"; -import { RunConfig } from "@/registry/run-config"; +import type { CoordinateDriver } from "../driver"; +import { logger } from "../log"; export async function serveSse( registryConfig: RegistryConfig, diff --git a/packages/core/src/topologies/coordinate/router/websocket.ts b/packages/core/src/topologies/coordinate/router/websocket.ts index c62874a14..e5fb3e2ca 100644 --- a/packages/core/src/topologies/coordinate/router/websocket.ts +++ b/packages/core/src/topologies/coordinate/router/websocket.ts @@ -1,19 +1,19 @@ +import type { ActorDriver } from "@/actor/driver"; +import * as errors from "@/actor/errors"; +import type * as messageToServer from "@/actor/protocol/message/to-server"; +import { serialize } from "@/actor/protocol/serde"; +import type { + ConnectWebSocketOpts, + ConnectWebSocketOutput, +} from "@/actor/router-endpoints"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; import type { GlobalState } from "@/topologies/coordinate/topology"; import type { WSContext } from "hono/ws"; -import { logger } from "../log"; -import { serialize } from "@/actor/protocol/serde"; -import type * as messageToServer from "@/actor/protocol/message/to-server"; -import * as errors from "@/actor/errors"; -import type { CoordinateDriver } from "../driver"; import { RelayConn } from "../conn/mod"; +import type { CoordinateDriver } from "../driver"; +import { logger } from "../log"; import { publishMessageToLeader } from "../node/message"; -import type { ActorDriver } from "@/actor/driver"; -import type { RegistryConfig } from "@/registry/config"; -import { - ConnectWebSocketOpts, - ConnectWebSocketOutput, -} from "@/actor/router-endpoints"; -import { DriverConfig, RunConfig } from "@/registry/run-config"; export async function serveWebSocket( registryConfig: RegistryConfig, diff --git a/packages/core/src/topologies/coordinate/topology.ts b/packages/core/src/topologies/coordinate/topology.ts index ce0810107..7947d7182 100644 --- a/packages/core/src/topologies/coordinate/topology.ts +++ b/packages/core/src/topologies/coordinate/topology.ts @@ -1,30 +1,29 @@ -import { Node } from "./node/mod"; -import type { ActorPeer } from "./actor-peer"; -import * as errors from "@/actor/errors"; import * as events from "node:events"; -import { publishMessageToLeader } from "./node/message"; -import type { RelayConn } from "./conn/mod"; -import { Hono } from "hono"; -import { handleRouteError, handleRouteNotFound } from "@/common/router"; -import type { RegistryConfig } from "@/registry/config"; -import { createManagerRouter } from "@/manager/router"; +import type { ConnRoutingHandler } from "@/actor/conn-routing-handler"; +import * as errors from "@/actor/errors"; import type { - ConnectWebSocketOpts, - ConnectSseOpts, ActionOpts, - ConnsMessageOpts, - ConnectWebSocketOutput, - ConnectSseOutput, ActionOutput, + ConnectSseOpts, + ConnectSseOutput, + ConnectWebSocketOpts, + ConnectWebSocketOutput, ConnectionHandlers, -} from "@/actor/router-endpoints"; -import invariant from "invariant"; + ConnsMessageOpts, +} from "@/actor/router-endpoints"; +import type { ClientDriver } from "@/client/client"; import { createInlineClientDriver } from "@/inline-client-driver/mod"; -import { serveWebSocket } from "./router/websocket"; +import { createManagerRouter } from "@/manager/router"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; +import { Hono } from "hono"; +import invariant from "invariant"; +import type { ActorPeer } from "./actor-peer"; +import type { RelayConn } from "./conn/mod"; +import { publishMessageToLeader } from "./node/message"; +import { Node } from "./node/mod"; import { serveSse } from "./router/sse"; -import { ClientDriver } from "@/client/client"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; -import { DriverConfig, RunConfig } from "@/registry/run-config"; +import { serveWebSocket } from "./router/websocket"; export interface GlobalState { nodeId: string; diff --git a/packages/core/src/topologies/partition/actor-router.ts b/packages/core/src/topologies/partition/actor-router.ts index 98e28bba8..23a02c8f7 100644 --- a/packages/core/src/topologies/partition/actor-router.ts +++ b/packages/core/src/topologies/partition/actor-router.ts @@ -1,35 +1,32 @@ -import { Hono, type Context as HonoContext } from "hono"; -import { logger } from "./log"; -import { cors } from "hono/cors"; -import { - handleRouteError, - handleRouteNotFound, - loggerMiddleware, -} from "@/common/router"; -import type { RegistryConfig } from "@/registry/config"; +import { EncodingSchema } from "@/actor/protocol/serde"; import { - type ConnectWebSocketOpts, - type ConnectWebSocketOutput, - type ConnectSseOpts, - type ConnectSseOutput, type ActionOpts, type ActionOutput, - type ConnsMessageOpts, + type ConnectSseOpts, + type ConnectSseOutput, + type ConnectWebSocketOpts, + type ConnectWebSocketOutput, type ConnectionHandlers, - handleWebSocketConnect, - handleSseConnect, - handleAction, - handleConnectionMessage, - HEADER_CONN_TOKEN, + type ConnsMessageOpts, + HEADER_AUTH_DATA, HEADER_CONN_ID, - ALL_PUBLIC_HEADERS, HEADER_CONN_PARAMS, - HEADER_AUTH_DATA, + HEADER_CONN_TOKEN, HEADER_ENCODING, -} from "@/actor/router-endpoints"; -import invariant from "invariant"; -import { EncodingSchema } from "@/actor/protocol/serde"; -import { DriverConfig, RunConfig } from "@/registry/run-config"; + handleAction, + handleConnectionMessage, + handleSseConnect, + handleWebSocketConnect, +} from "@/actor/router-endpoints"; +import { + handleRouteError, + handleRouteNotFound, + loggerMiddleware, +} from "@/common/router"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; +import { Hono, type Context as HonoContext } from "hono"; +import { logger } from "./log"; export type { ConnectWebSocketOpts, diff --git a/packages/core/src/topologies/partition/topology.ts b/packages/core/src/topologies/partition/topology.ts index 5fff363ab..79ed3c7d0 100644 --- a/packages/core/src/topologies/partition/topology.ts +++ b/packages/core/src/topologies/partition/topology.ts @@ -1,43 +1,42 @@ -import { Hono, HonoRequest } from "hono"; -import { createActorRouter } from "@/topologies/partition/actor-router"; -import type { AnyActorInstance } from "@/actor/instance"; -import * as errors from "@/actor/errors"; +import { ActionContext } from "@/actor/action"; import { type AnyConn, generateConnId, generateConnToken, -} from "@/actor/connection"; -import { logger } from "./log"; -import { ActionContext } from "@/actor/action"; +} from "@/actor/connection"; +import type { ConnDriver } from "@/actor/driver"; +import * as errors from "@/actor/errors"; +import type { AnyActorInstance } from "@/actor/instance"; +import type { + ActionOpts, + ActionOutput, + ConnectSseOpts, + ConnectSseOutput, + ConnectWebSocketOpts, + ConnectWebSocketOutput, + ConnsMessageOpts, +} from "@/actor/router-endpoints"; +import type { ClientDriver } from "@/client/client"; +import type { ActorKey } from "@/actor/mod"; +import { createInlineClientDriver } from "@/inline-client-driver/mod"; +import { createManagerRouter } from "@/manager/router"; +import type { RegistryConfig } from "@/registry/config"; +import type { RunConfig } from "@/registry/run-config"; +import { createActorRouter } from "@/topologies/partition/actor-router"; +import type { Hono } from "hono"; +import invariant from "invariant"; +import type { WebSocket } from "ws"; import { CONN_DRIVER_GENERIC_HTTP, CONN_DRIVER_GENERIC_SSE, CONN_DRIVER_GENERIC_WEBSOCKET, - createGenericConnDrivers, GenericConnGlobalState, type GenericHttpDriverState, type GenericSseDriverState, type GenericWebSocketDriverState, + createGenericConnDrivers, } from "../common/generic-conn-driver"; -import type { ConnDriver } from "@/actor/driver"; -import type { ActorKey } from "@/common/utils"; -import type { RegistryConfig } from "@/registry/config"; -import { createManagerRouter } from "@/manager/router"; -import type { - ConnectWebSocketOpts, - ConnectSseOpts, - ActionOpts, - ConnsMessageOpts, - ConnectWebSocketOutput, - ConnectSseOutput, - ActionOutput, -} from "@/actor/router-endpoints"; -import { ClientDriver } from "@/client/client"; -import { createInlineClientDriver } from "@/inline-client-driver/mod"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; -import invariant from "invariant"; -import type { WebSocket } from "ws"; -import type { RunConfig } from "@/registry/run-config"; +import { logger } from "./log"; export type SendRequestHandler = ( actorRequest: Request, @@ -64,7 +63,7 @@ export class PartitionTopologyManager { invariant(managerDriver, "missing manager driver"); this.clientDriver = createInlineClientDriver(managerDriver, routingHandler); - const {router}= createManagerRouter( + const { router } = createManagerRouter( registryConfig, runConfig, this.clientDriver, @@ -129,8 +128,7 @@ export class PartitionTopologyActor { // TODO: Store this actor router globally so we're not re-initializing it for every DO this.router = createActorRouter(registryConfig, runConfig, { getActorId: async () => { - if (this.#actorStartedPromise) - await this.#actorStartedPromise.promise; + if (this.#actorStartedPromise) await this.#actorStartedPromise.promise; return this.actor.id; }, connectionHandlers: { @@ -145,10 +143,7 @@ export class PartitionTopologyActor { const connId = generateConnId(); const connToken = generateConnToken(); - const connState = await actor.prepareConn( - opts.params, - opts.req?.raw, - ); + const connState = await actor.prepareConn(opts.params, opts.req?.raw); let conn: AnyConn | undefined; return { @@ -199,10 +194,7 @@ export class PartitionTopologyActor { const connId = generateConnId(); const connToken = generateConnToken(); - const connState = await actor.prepareConn( - opts.params, - opts.req?.raw, - ); + const connState = await actor.prepareConn(opts.params, opts.req?.raw); let conn: AnyConn | undefined; return { diff --git a/packages/core/src/topologies/standalone/conn-routing-handlers.ts b/packages/core/src/topologies/standalone/conn-routing-handlers.ts index ed7c5685e..e69de29bb 100644 --- a/packages/core/src/topologies/standalone/conn-routing-handlers.ts +++ b/packages/core/src/topologies/standalone/conn-routing-handlers.ts @@ -1,29 +0,0 @@ -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; -import { - type AnyConn, - generateConnId, - generateConnToken, -} from "@/actor/connection"; -import * as errors from "@/actor/errors"; -import { - CONN_DRIVER_GENERIC_HTTP, - CONN_DRIVER_GENERIC_SSE, - CONN_DRIVER_GENERIC_WEBSOCKET, - type GenericHttpDriverState, - type GenericSseDriverState, - type GenericWebSocketDriverState, -} from "../common/generic-conn-driver"; -import { ActionContext } from "@/actor/action"; -import type { - ConnectWebSocketOpts, - ConnectWebSocketOutput, - ConnectSseOpts, - ConnectSseOutput, - ConnsMessageOpts, - ActionOpts, - ActionOutput, - ConnectionHandlers, -} from "@/actor/router-endpoints"; -import { StandaloneTopology } from "@/mod"; -import { logger } from "./log"; - diff --git a/packages/core/src/topologies/standalone/topology.ts b/packages/core/src/topologies/standalone/topology.ts index b3917ae7e..2ce7f33a9 100644 --- a/packages/core/src/topologies/standalone/topology.ts +++ b/packages/core/src/topologies/standalone/topology.ts @@ -1,40 +1,40 @@ -import type { AnyActorInstance } from "@/actor/instance"; -import { Hono } from "hono"; +import { ActionContext } from "@/actor/action"; +import type { ConnRoutingHandler } from "@/actor/conn-routing-handler"; import { type AnyConn, generateConnId, generateConnToken, -} from "@/actor/connection"; -import { logger } from "./log"; -import * as errors from "@/actor/errors"; +} from "@/actor/connection"; +import * as errors from "@/actor/errors"; +import type { AnyActorInstance } from "@/actor/instance"; +import type { + ActionOpts, + ActionOutput, + ConnectSseOpts, + ConnectSseOutput, + ConnectWebSocketOpts, + ConnectWebSocketOutput, + ConnectionHandlers, + ConnsMessageOpts, +} from "@/actor/router-endpoints"; +import type { ClientDriver } from "@/client/client"; +import { createInlineClientDriver } from "@/inline-client-driver/mod"; +import { createManagerRouter } from "@/manager/router"; +import type { RunConfig } from "@/mod"; +import type { RegistryConfig } from "@/registry/config"; +import { Hono } from "hono"; +import invariant from "invariant"; import { CONN_DRIVER_GENERIC_HTTP, CONN_DRIVER_GENERIC_SSE, CONN_DRIVER_GENERIC_WEBSOCKET, - createGenericConnDrivers, GenericConnGlobalState, type GenericHttpDriverState, type GenericSseDriverState, type GenericWebSocketDriverState, + createGenericConnDrivers, } from "../common/generic-conn-driver"; -import { ActionContext } from "@/actor/action"; -import type { RegistryConfig } from "@/registry/config"; -import { createManagerRouter } from "@/manager/router"; -import type { - ConnectWebSocketOpts, - ConnectWebSocketOutput, - ConnectSseOpts, - ConnectSseOutput, - ConnsMessageOpts, - ActionOpts, - ActionOutput, - ConnectionHandlers, -} from "@/actor/router-endpoints"; -import { createInlineClientDriver } from "@/inline-client-driver/mod"; -import invariant from "invariant"; -import { ClientDriver } from "@/client/client"; -import { ConnRoutingHandler } from "@/actor/conn-routing-handler"; -import { DriverConfig, RunConfig } from "@/mod"; +import { logger } from "./log"; class ActorHandler { /** Will be undefined if not yet loaded. */ @@ -252,10 +252,7 @@ export class StandaloneTopology { const { actor } = await this.#getActor(opts.actorId); // Create conn - const connState = await actor.prepareConn( - opts.params, - opts.req?.raw, - ); + const connState = await actor.prepareConn(opts.params, opts.req?.raw); conn = await actor.createConn( generateConnId(), generateConnToken(), diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 88a293a7d..d8d6c0f4b 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,12 +1,12 @@ export { assertUnreachable } from "./common/utils"; export { stringifyError } from "@/common/utils"; -import { Context as HonoContext, Handler as HonoHandler } from "hono"; +import type { Context as HonoContext, Handler as HonoHandler } from "hono"; import pkgJson from "../package.json" with { type: "json" }; -import { DriverConfig, UserError } from "./mod"; +import { logger } from "./actor/log"; import { createMemoryDriver } from "./drivers/memory/mod"; import { createRivetManagerDriver } from "./drivers/rivet/mod"; -import { logger } from "./actor/log"; +import { type DriverConfig, UserError } from "./mod"; export const VERSION = pkgJson.version; diff --git a/packages/core/tests/actor-types.test.ts b/packages/core/tests/actor-types.test.ts index a26e3ec76..b7a8be8f8 100644 --- a/packages/core/tests/actor-types.test.ts +++ b/packages/core/tests/actor-types.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect, expectTypeOf } from "vitest"; -import { ActorDefinition, type ActorContextOf } from "@/actor/definition"; -import type { ActorContext } from "@/actor/context"; +import type { ActorContext } from "@/actor/context"; +import type { ActorContextOf, ActorDefinition } from "@/actor/definition"; +import { describe, expectTypeOf, it } from "vitest"; describe("ActorDefinition", () => { describe("ActorContextOf type utility", () => { diff --git a/packages/core/tests/driver-test-suite.test.ts b/packages/core/tests/driver-test-suite.test.ts index dd2c241c6..70849135d 100644 --- a/packages/core/tests/driver-test-suite.test.ts +++ b/packages/core/tests/driver-test-suite.test.ts @@ -1,6 +1,6 @@ -import { runDriverTests, createTestRuntime } from "@/driver-test-suite/mod"; -import { createTestDriver } from "@/test/driver/mod"; import { join } from "node:path"; +import { createTestRuntime, runDriverTests } from "@/driver-test-suite/mod"; +import { createTestDriver } from "@/test/driver/mod"; runDriverTests({ async start(projectPath: string) { diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index d07004658..820cb0f5b 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -8,5 +8,10 @@ "@rivetkit/core": ["./src/mod.ts"] } }, - "include": ["src/**/*", "tests/**/*", "scripts/**/*", "fixtures/driver-test-suite/**/*"] + "include": [ + "src/**/*", + "tests/**/*", + "scripts/**/*", + "fixtures/driver-test-suite/**/*" + ] } diff --git a/packages/core/tsup.config.bundled_an4diesgzb.mjs b/packages/core/tsup.config.bundled_an4diesgzb.mjs index f4f2243ae..c3903cd71 100644 --- a/packages/core/tsup.config.bundled_an4diesgzb.mjs +++ b/packages/core/tsup.config.bundled_an4diesgzb.mjs @@ -1,22 +1,20 @@ // ../../tsup.base.ts var tsup_base_default = { - target: "node16", - platform: "node", - format: ["cjs", "esm"], - sourcemap: true, - clean: true, - dts: true, - minify: false, - // IMPORTANT: Splitting is required to fix a bug with ESM (https://github.com/egoist/tsup/issues/992#issuecomment-1763540165) - splitting: true, - skipNodeModulesBundle: true, - publicDir: true + target: "node16", + platform: "node", + format: ["cjs", "esm"], + sourcemap: true, + clean: true, + dts: true, + minify: false, + // IMPORTANT: Splitting is required to fix a bug with ESM (https://github.com/egoist/tsup/issues/992#issuecomment-1763540165) + splitting: true, + skipNodeModulesBundle: true, + publicDir: true, }; // tsup.config.ts import { defineConfig } from "tsup"; var tsup_config_default = defineConfig(tsup_base_default); -export { - tsup_config_default as default -}; +export { tsup_config_default as default }; //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vdHN1cC5iYXNlLnRzIiwgInRzdXAuY29uZmlnLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX2luamVjdGVkX2ZpbGVuYW1lX18gPSBcIi9ob21lL25hdGhhbi9yaXZldGtpdC90c3VwLmJhc2UudHNcIjtjb25zdCBfX2luamVjdGVkX2Rpcm5hbWVfXyA9IFwiL2hvbWUvbmF0aGFuL3JpdmV0a2l0XCI7Y29uc3QgX19pbmplY3RlZF9pbXBvcnRfbWV0YV91cmxfXyA9IFwiZmlsZTovLy9ob21lL25hdGhhbi9yaXZldGtpdC90c3VwLmJhc2UudHNcIjtpbXBvcnQgdHlwZSB7IE9wdGlvbnMgfSBmcm9tIFwidHN1cFwiO1xuXG5leHBvcnQgZGVmYXVsdCB7XG5cdHRhcmdldDogXCJub2RlMTZcIixcblx0cGxhdGZvcm06IFwibm9kZVwiLFxuXHRmb3JtYXQ6IFtcImNqc1wiLCBcImVzbVwiXSxcblx0c291cmNlbWFwOiB0cnVlLFxuXHRjbGVhbjogdHJ1ZSxcblx0ZHRzOiB0cnVlLFxuXHRtaW5pZnk6IGZhbHNlLFxuXHQvLyBJTVBPUlRBTlQ6IFNwbGl0dGluZyBpcyByZXF1aXJlZCB0byBmaXggYSBidWcgd2l0aCBFU00gKGh0dHBzOi8vZ2l0aHViLmNvbS9lZ29pc3QvdHN1cC9pc3N1ZXMvOTkyI2lzc3VlY29tbWVudC0xNzYzNTQwMTY1KVxuXHRzcGxpdHRpbmc6IHRydWUsXG5cdHNraXBOb2RlTW9kdWxlc0J1bmRsZTogdHJ1ZSxcblx0cHVibGljRGlyOiB0cnVlLFxufSBzYXRpc2ZpZXMgT3B0aW9ucztcbiIsICJjb25zdCBfX2luamVjdGVkX2ZpbGVuYW1lX18gPSBcIi9ob21lL25hdGhhbi9yaXZldGtpdC9wYWNrYWdlcy9jb3JlL3RzdXAuY29uZmlnLnRzXCI7Y29uc3QgX19pbmplY3RlZF9kaXJuYW1lX18gPSBcIi9ob21lL25hdGhhbi9yaXZldGtpdC9wYWNrYWdlcy9jb3JlXCI7Y29uc3QgX19pbmplY3RlZF9pbXBvcnRfbWV0YV91cmxfXyA9IFwiZmlsZTovLy9ob21lL25hdGhhbi9yaXZldGtpdC9wYWNrYWdlcy9jb3JlL3RzdXAuY29uZmlnLnRzXCI7aW1wb3J0IGRlZmF1bHRDb25maWcgZnJvbSBcIi4uLy4uL3RzdXAuYmFzZS50c1wiO1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInRzdXBcIjtcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKGRlZmF1bHRDb25maWcpO1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUVBLElBQU8sb0JBQVE7QUFBQSxFQUNkLFFBQVE7QUFBQSxFQUNSLFVBQVU7QUFBQSxFQUNWLFFBQVEsQ0FBQyxPQUFPLEtBQUs7QUFBQSxFQUNyQixXQUFXO0FBQUEsRUFDWCxPQUFPO0FBQUEsRUFDUCxLQUFLO0FBQUEsRUFDTCxRQUFRO0FBQUE7QUFBQSxFQUVSLFdBQVc7QUFBQSxFQUNYLHVCQUF1QjtBQUFBLEVBQ3ZCLFdBQVc7QUFDWjs7O0FDYkEsU0FBUyxvQkFBb0I7QUFFN0IsSUFBTyxzQkFBUSxhQUFhLGlCQUFhOyIsCiAgIm5hbWVzIjogW10KfQo= diff --git a/packages/core/tsup.config.bundled_xvi1jgwbzx.mjs b/packages/core/tsup.config.bundled_xvi1jgwbzx.mjs index e01a2a057..4b87c09d0 100644 --- a/packages/core/tsup.config.bundled_xvi1jgwbzx.mjs +++ b/packages/core/tsup.config.bundled_xvi1jgwbzx.mjs @@ -1,22 +1,20 @@ // ../../tsup.base.ts var tsup_base_default = { - target: "node16", - platform: "node", - format: ["cjs", "esm"], - sourcemap: true, - clean: true, - dts: true, - minify: false, - // IMPORTANT: Splitting is required to fix a bug with ESM (https://github.com/egoist/tsup/issues/992#issuecomment-1763540165) - splitting: true, - skipNodeModulesBundle: true, - publicDir: true + target: "node16", + platform: "node", + format: ["cjs", "esm"], + sourcemap: true, + clean: true, + dts: true, + minify: false, + // IMPORTANT: Splitting is required to fix a bug with ESM (https://github.com/egoist/tsup/issues/992#issuecomment-1763540165) + splitting: true, + skipNodeModulesBundle: true, + publicDir: true, }; // tsup.config.ts import { defineConfig } from "tsup"; var tsup_config_default = defineConfig(tsup_base_default); -export { - tsup_config_default as default -}; +export { tsup_config_default as default }; //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vdHN1cC5iYXNlLnRzIiwgInRzdXAuY29uZmlnLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX2luamVjdGVkX2ZpbGVuYW1lX18gPSBcIi9Vc2Vycy9uYXRoYW4vcml2ZXQvYWN0b3ItY29yZS90c3VwLmJhc2UudHNcIjtjb25zdCBfX2luamVjdGVkX2Rpcm5hbWVfXyA9IFwiL1VzZXJzL25hdGhhbi9yaXZldC9hY3Rvci1jb3JlXCI7Y29uc3QgX19pbmplY3RlZF9pbXBvcnRfbWV0YV91cmxfXyA9IFwiZmlsZTovLy9Vc2Vycy9uYXRoYW4vcml2ZXQvYWN0b3ItY29yZS90c3VwLmJhc2UudHNcIjtpbXBvcnQgdHlwZSB7IE9wdGlvbnMgfSBmcm9tIFwidHN1cFwiO1xuXG5leHBvcnQgZGVmYXVsdCB7XG5cdHRhcmdldDogXCJub2RlMTZcIixcblx0cGxhdGZvcm06IFwibm9kZVwiLFxuXHRmb3JtYXQ6IFtcImNqc1wiLCBcImVzbVwiXSxcblx0c291cmNlbWFwOiB0cnVlLFxuXHRjbGVhbjogdHJ1ZSxcblx0ZHRzOiB0cnVlLFxuXHRtaW5pZnk6IGZhbHNlLFxuXHQvLyBJTVBPUlRBTlQ6IFNwbGl0dGluZyBpcyByZXF1aXJlZCB0byBmaXggYSBidWcgd2l0aCBFU00gKGh0dHBzOi8vZ2l0aHViLmNvbS9lZ29pc3QvdHN1cC9pc3N1ZXMvOTkyI2lzc3VlY29tbWVudC0xNzYzNTQwMTY1KVxuXHRzcGxpdHRpbmc6IHRydWUsXG5cdHNraXBOb2RlTW9kdWxlc0J1bmRsZTogdHJ1ZSxcblx0cHVibGljRGlyOiB0cnVlLFxufSBzYXRpc2ZpZXMgT3B0aW9ucztcbiIsICJjb25zdCBfX2luamVjdGVkX2ZpbGVuYW1lX18gPSBcIi9Vc2Vycy9uYXRoYW4vcml2ZXQvYWN0b3ItY29yZS9wYWNrYWdlcy9hY3Rvci1jb3JlL3RzdXAuY29uZmlnLnRzXCI7Y29uc3QgX19pbmplY3RlZF9kaXJuYW1lX18gPSBcIi9Vc2Vycy9uYXRoYW4vcml2ZXQvYWN0b3ItY29yZS9wYWNrYWdlcy9hY3Rvci1jb3JlXCI7Y29uc3QgX19pbmplY3RlZF9pbXBvcnRfbWV0YV91cmxfXyA9IFwiZmlsZTovLy9Vc2Vycy9uYXRoYW4vcml2ZXQvYWN0b3ItY29yZS9wYWNrYWdlcy9hY3Rvci1jb3JlL3RzdXAuY29uZmlnLnRzXCI7aW1wb3J0IGRlZmF1bHRDb25maWcgZnJvbSBcIi4uLy4uL3RzdXAuYmFzZS50c1wiO1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInRzdXBcIjtcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKGRlZmF1bHRDb25maWcpO1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUVBLElBQU8sb0JBQVE7QUFBQSxFQUNkLFFBQVE7QUFBQSxFQUNSLFVBQVU7QUFBQSxFQUNWLFFBQVEsQ0FBQyxPQUFPLEtBQUs7QUFBQSxFQUNyQixXQUFXO0FBQUEsRUFDWCxPQUFPO0FBQUEsRUFDUCxLQUFLO0FBQUEsRUFDTCxRQUFRO0FBQUE7QUFBQSxFQUVSLFdBQVc7QUFBQSxFQUNYLHVCQUF1QjtBQUFBLEVBQ3ZCLFdBQVc7QUFDWjs7O0FDYkEsU0FBUyxvQkFBb0I7QUFFN0IsSUFBTyxzQkFBUSxhQUFhLGlCQUFhOyIsCiAgIm5hbWVzIjogW10KfQo= diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts index 0eea6200a..b935a0a8e 100644 --- a/packages/core/tsup.config.ts +++ b/packages/core/tsup.config.ts @@ -1,4 +1,4 @@ -import defaultConfig from "../../tsup.base.ts"; import { defineConfig } from "tsup"; +import defaultConfig from "../../tsup.base.ts"; export default defineConfig(defaultConfig); diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts index 807e9fd0e..fa98d6b42 100644 --- a/packages/core/vitest.config.ts +++ b/packages/core/vitest.config.ts @@ -1,6 +1,6 @@ -import defaultConfig from "../../vitest.base.ts"; -import { defineConfig } from "vitest/config"; import { resolve } from "path"; +import { defineConfig } from "vitest/config"; +import defaultConfig from "../../vitest.base.ts"; export default defineConfig({ ...defaultConfig, diff --git a/packages/platforms/cloudflare-workers/package.json b/packages/platforms/cloudflare-workers/package.json index 858dea366..ce0486f67 100644 --- a/packages/platforms/cloudflare-workers/package.json +++ b/packages/platforms/cloudflare-workers/package.json @@ -43,7 +43,7 @@ "dependencies": { "hono": "^4.7.2", "invariant": "^2.2.4", - "zod": "^3.24.2" + "zod": "^3.25.67" }, "stableVersion": "0.8.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be1963608..32ed89e97 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -388,7 +388,7 @@ importers: specifier: ^11.4.2 version: 11.4.2(typescript@5.8.3) zod: - specifier: ^3.24.1 + specifier: ^3.25.67 version: 3.25.67 devDependencies: '@rivetkit/actor': @@ -441,7 +441,7 @@ importers: specifier: ^6.2.1 version: 6.2.1 zod: - specifier: ^3.24.1 + specifier: ^3.25.67 version: 3.25.67 devDependencies: '@hono/node-server': @@ -667,7 +667,7 @@ importers: specifier: ^2.2.4 version: 2.2.4 zod: - specifier: ^3.24.2 + specifier: ^3.25.67 version: 3.25.67 devDependencies: '@cloudflare/workers-types': @@ -5365,6 +5365,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 6.3.5(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0) + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@24.0.4)(tsx@4.20.3)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.2.4 @@ -7504,7 +7512,7 @@ snapshots: dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@24.0.4)(tsx@4.20.3)(yaml@2.8.0)) + '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.15.32)(tsx@3.14.0)(yaml@2.8.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 diff --git a/vitest.base.ts b/vitest.base.ts index 260f56afd..b45ace23d 100644 --- a/vitest.base.ts +++ b/vitest.base.ts @@ -4,7 +4,8 @@ export default { test: { // Enable parallelism sequence: { - concurrent: true, + // TODO: This breaks fake timers, unsure how to make tests run in parallel within the same file + // concurrent: true, }, env: { // Enable logging