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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@rivetkit/cloudflare-workers": "workspace:*",
"@rivetkit/next-js": "workspace:*",
"@rivetkit/db": "workspace:*",
"@rivetkit/sqlite-vfs": "workspace:*",
"@rivetkit/engine-api-full": "workspace:*",
"@types/react": "^19",
"@types/react-dom": "^19",
Expand Down
71 changes: 53 additions & 18 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions rivetkit-typescript/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# rivetkit-typescript/CLAUDE.md

## Tree-Shaking Boundaries

- Do not import `@rivetkit/workflow-engine` outside the `rivetkit/workflow` entrypoint so it remains tree-shakeable.
- Do not import SQLite VFS or `wa-sqlite` outside the `rivetkit/db` (or `@rivetkit/sqlite-vfs`) entrypoint so SQLite support remains tree-shakeable.
- Importing `rivetkit/db` (or `@rivetkit/sqlite-vfs`) is the explicit opt-in for SQLite. Do not lazily load SQLite from `rivetkit/db`; it may be imported eagerly inside that entrypoint.
- Core drivers must remain SQLite-agnostic. Any SQLite-specific wiring belongs behind the `rivetkit/db` or `@rivetkit/sqlite-vfs` boundary.
2 changes: 1 addition & 1 deletion rivetkit-typescript/packages/rivetkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
"@rivetkit/engine-runner": "workspace:*",
"@rivetkit/fast-json-patch": "^3.1.2",
"@rivetkit/on-change": "^6.0.2-rc.1",
"@rivetkit/sqlite-vfs": "workspace:*",
"@rivetkit/traces": "workspace:*",
"@rivetkit/virtual-websocket": "workspace:*",
"cbor-x": "^1.6.0",
Expand All @@ -225,7 +226,6 @@
"pino": "^9.5.0",
"uuid": "^12.0.0",
"vbare": "^0.0.4",
"wa-sqlite": "^1.0.0",
"zod": "^4.1.0"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import { ActorKv } from "../../instance/kv";
import { ActorQueue } from "../../instance/queue";
import type { Schedule } from "../../schedule";

export const ACTOR_CONTEXT_INTERNAL_SYMBOL = Symbol("actorContextInternal");
export const ACTOR_CONTEXT_INTERNAL_SYMBOL = Symbol.for(
"rivetkit.actorContextInternal",
);

/**
* ActorContext class that provides access to actor methods and state
Expand Down
36 changes: 34 additions & 2 deletions rivetkit-typescript/packages/rivetkit/src/actor/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,43 @@ export class ActorDefinition<
instantiate(): ActorInstance<S, CP, CS, V, I, DB> {
// Lazy import to avoid pulling server-only dependencies (traces, fdb-tuple, etc.)
// into browser bundles. This method is only called on the server.
const { ActorInstance: ActorInstanceClass } = require("./instance/mod");
return new ActorInstanceClass(this.#config);
const requireFn = typeof require === "undefined" ? undefined : require;
if (!requireFn) {
throw new Error(
"ActorDefinition.instantiate requires a Node.js environment",
);
}

try {
const { ActorInstance: ActorInstanceClass } =
requireFn("./instance/mod");
return new ActorInstanceClass(this.#config);
} catch (error) {
if (!isInstanceModuleNotFound(error)) {
throw error;
}

try {
// In tests, register tsx so require() can resolve .ts files.
requireFn("tsx/cjs");
} catch {
throw error;
}

const { ActorInstance: ActorInstanceClass } =
requireFn("./instance/mod");
return new ActorInstanceClass(this.#config);
}
}
}

function isInstanceModuleNotFound(error: unknown): boolean {
if (!error || typeof error !== "object") return false;
const err = error as { code?: string; message?: string };
if (err.code !== "MODULE_NOT_FOUND") return false;
return (err.message ?? "").includes("./instance/mod");
}

export function lookupInRegistry(
config: RegistryConfig,
name: string,
Expand Down
9 changes: 0 additions & 9 deletions rivetkit-typescript/packages/rivetkit/src/actor/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type { RegistryConfig } from "@/registry/config";
import type {
RawDatabaseClient,
} from "@/db/config";
import type { SqliteVfs } from "@/db/vfs/mod";
import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";

export type ActorDriverBuilder = (
Expand Down Expand Up @@ -68,14 +67,6 @@ export interface ActorDriver {
actorId: string,
): Promise<BaseSQLiteDatabase<any,any,any,any> | undefined>;

/**
* SQLite VFS instance for creating KV-backed databases.
* Each driver should create its own instance to avoid concurrency issues.
* If not provided, the db() provider will throw an error.
* @experimental
*/
sqliteVfs?: SqliteVfs;

/**
* Requests the actor to go to sleep.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {

// MARK: - Inspector
#inspectorToken?: string;
#inspector = new ActorInspector(this);
#inspector!: ActorInspector;

// MARK: - Tracing
#traces!: Traces<OtlpExportTraceServiceRequestJson>;
Expand All @@ -164,6 +164,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
constructor(config: ActorConfig<S, CP, CS, V, I, DB>) {
this.#config = config;
this.actorContext = new ActorContext(this);
this.#inspector = new ActorInspector(this);
}

// MARK: - Public Getters
Expand Down Expand Up @@ -1280,7 +1281,6 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
batchDelete: (keys) =>
this.driver.kvBatchDelete(this.#actorId, keys),
},
sqliteVfs: this.driver.sqliteVfs,
});
this.#rLog.info({ msg: "database migration starting" });
await this.#config.db.onMigrate?.(client);
Expand Down
Loading
Loading