rivetkit 2.3.5-rc.1 → 2.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/browser/client.d.ts +19 -5
  2. package/dist/browser/client.js +32 -9
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +12 -2
  5. package/dist/browser/inspector/client.js.map +1 -1
  6. package/dist/tsup/agent-os/index.cjs +115 -5
  7. package/dist/tsup/agent-os/index.cjs.map +1 -1
  8. package/dist/tsup/agent-os/index.d.cts +19 -5
  9. package/dist/tsup/agent-os/index.d.ts +19 -5
  10. package/dist/tsup/agent-os/index.js +115 -5
  11. package/dist/tsup/agent-os/index.js.map +1 -1
  12. package/dist/tsup/{chunk-6HQCLWAW.cjs → chunk-234EFKN2.cjs} +13 -3
  13. package/dist/tsup/chunk-234EFKN2.cjs.map +1 -0
  14. package/dist/tsup/{chunk-NIC3QLKL.js → chunk-3ZE5UDOA.js} +3 -3
  15. package/dist/tsup/{chunk-4XKED5P5.cjs → chunk-AXEGEUYB.cjs} +262 -252
  16. package/dist/tsup/chunk-AXEGEUYB.cjs.map +1 -0
  17. package/dist/tsup/{chunk-P4OGQ4JL.js → chunk-BX4G2O6M.js} +3 -3
  18. package/dist/tsup/{chunk-GAV4PKFT.js → chunk-F6ZW7JZQ.js} +130 -120
  19. package/dist/tsup/chunk-F6ZW7JZQ.js.map +1 -0
  20. package/dist/tsup/{chunk-TR5NLR5V.cjs → chunk-FNTTW25Q.cjs} +4 -4
  21. package/dist/tsup/{chunk-TR5NLR5V.cjs.map → chunk-FNTTW25Q.cjs.map} +1 -1
  22. package/dist/tsup/{chunk-G3CCRCTK.cjs → chunk-HNHLBM3Y.cjs} +108 -6
  23. package/dist/tsup/chunk-HNHLBM3Y.cjs.map +1 -0
  24. package/dist/tsup/{chunk-UJ2FQY63.cjs → chunk-HVOKIYUB.cjs} +7 -7
  25. package/dist/tsup/{chunk-UJ2FQY63.cjs.map → chunk-HVOKIYUB.cjs.map} +1 -1
  26. package/dist/tsup/{chunk-PAG6G46L.js → chunk-OH6CBWUD.js} +2 -2
  27. package/dist/tsup/{chunk-TNIWIUNV.cjs → chunk-PD7SZKHY.cjs} +9 -9
  28. package/dist/tsup/{chunk-TNIWIUNV.cjs.map → chunk-PD7SZKHY.cjs.map} +1 -1
  29. package/dist/tsup/{chunk-MGTSVSUC.js → chunk-PLLHHJWR.js} +2 -2
  30. package/dist/tsup/{chunk-SHBE77IT.js → chunk-QWLJCP3X.js} +106 -4
  31. package/dist/tsup/chunk-QWLJCP3X.js.map +1 -0
  32. package/dist/tsup/{chunk-B4IZU537.js → chunk-RDTFPGU2.js} +13 -3
  33. package/dist/tsup/chunk-RDTFPGU2.js.map +1 -0
  34. package/dist/tsup/{chunk-M3FCXL3Q.cjs → chunk-WS3PP253.cjs} +3 -3
  35. package/dist/tsup/{chunk-M3FCXL3Q.cjs.map → chunk-WS3PP253.cjs.map} +1 -1
  36. package/dist/tsup/client/mod.cjs +5 -5
  37. package/dist/tsup/client/mod.d.cts +2 -2
  38. package/dist/tsup/client/mod.d.ts +2 -2
  39. package/dist/tsup/client/mod.js +4 -4
  40. package/dist/tsup/common/log.cjs +2 -2
  41. package/dist/tsup/common/log.js +1 -1
  42. package/dist/tsup/common/websocket.cjs +3 -3
  43. package/dist/tsup/common/websocket.js +2 -2
  44. package/dist/tsup/{config-BzdqbLAP.d.ts → config-BRpVbJCD.d.ts} +20 -6
  45. package/dist/tsup/{config-CPPEwn_e.d.cts → config-BobvQpex.d.cts} +20 -6
  46. package/dist/tsup/{context-wWv-K2K_.d.ts → context-Cj-DFyiy.d.ts} +1 -1
  47. package/dist/tsup/{context-DSA9gFXB.d.cts → context-YEBNJrws.d.cts} +1 -1
  48. package/dist/tsup/db/drizzle.cjs +2 -2
  49. package/dist/tsup/db/drizzle.js +1 -1
  50. package/dist/tsup/db/mod.cjs +2 -2
  51. package/dist/tsup/db/mod.js +1 -1
  52. package/dist/tsup/dynamic/mod.cjs +2 -2
  53. package/dist/tsup/dynamic/mod.d.cts +1 -1
  54. package/dist/tsup/dynamic/mod.d.ts +1 -1
  55. package/dist/tsup/dynamic/mod.js +1 -1
  56. package/dist/tsup/inspector/mod.cjs +4 -4
  57. package/dist/tsup/inspector/mod.js +3 -3
  58. package/dist/tsup/inspector-tab/mod.cjs +2 -2
  59. package/dist/tsup/inspector-tab/mod.d.cts +2 -2
  60. package/dist/tsup/inspector-tab/mod.d.ts +2 -2
  61. package/dist/tsup/inspector-tab/mod.js +1 -1
  62. package/dist/tsup/mod.cjs +175 -85
  63. package/dist/tsup/mod.cjs.map +1 -1
  64. package/dist/tsup/mod.d.cts +3 -3
  65. package/dist/tsup/mod.d.ts +3 -3
  66. package/dist/tsup/mod.js +107 -17
  67. package/dist/tsup/mod.js.map +1 -1
  68. package/dist/tsup/test/mod.cjs +16 -13
  69. package/dist/tsup/test/mod.cjs.map +1 -1
  70. package/dist/tsup/test/mod.d.cts +1 -1
  71. package/dist/tsup/test/mod.d.ts +1 -1
  72. package/dist/tsup/test/mod.js +15 -12
  73. package/dist/tsup/test/mod.js.map +1 -1
  74. package/dist/tsup/unstable/migrations.cjs +101 -0
  75. package/dist/tsup/unstable/migrations.cjs.map +1 -0
  76. package/dist/tsup/unstable/migrations.d.cts +29 -0
  77. package/dist/tsup/unstable/migrations.d.ts +29 -0
  78. package/dist/tsup/unstable/migrations.js +101 -0
  79. package/dist/tsup/unstable/migrations.js.map +1 -0
  80. package/dist/tsup/utils.cjs +2 -2
  81. package/dist/tsup/utils.js +1 -1
  82. package/dist/tsup/workflow/mod.cjs +9 -9
  83. package/dist/tsup/workflow/mod.d.cts +3 -3
  84. package/dist/tsup/workflow/mod.d.ts +3 -3
  85. package/dist/tsup/workflow/mod.js +4 -4
  86. package/package.json +19 -9
  87. package/src/actor/actions.ts +119 -0
  88. package/src/actor/config.ts +61 -18
  89. package/src/actor/definition.ts +3 -0
  90. package/src/client/actor-common.ts +3 -1
  91. package/src/client/client.ts +24 -11
  92. package/src/registry/config/index.ts +2 -4
  93. package/src/registry/index.ts +86 -5
  94. package/src/registry/napi-runtime.ts +4 -0
  95. package/src/registry/native.ts +17 -16
  96. package/src/registry/runtime.ts +1 -0
  97. package/src/registry/wasm-runtime.ts +6 -0
  98. package/src/test/mod.ts +1 -19
  99. package/src/test/ready.ts +22 -0
  100. package/src/unstable/migrations.test.ts +170 -0
  101. package/src/unstable/migrations.ts +141 -0
  102. package/dist/tsup/chunk-4XKED5P5.cjs.map +0 -1
  103. package/dist/tsup/chunk-6HQCLWAW.cjs.map +0 -1
  104. package/dist/tsup/chunk-B4IZU537.js.map +0 -1
  105. package/dist/tsup/chunk-G3CCRCTK.cjs.map +0 -1
  106. package/dist/tsup/chunk-GAV4PKFT.js.map +0 -1
  107. package/dist/tsup/chunk-SHBE77IT.js.map +0 -1
  108. /package/dist/tsup/{chunk-NIC3QLKL.js.map → chunk-3ZE5UDOA.js.map} +0 -0
  109. /package/dist/tsup/{chunk-P4OGQ4JL.js.map → chunk-BX4G2O6M.js.map} +0 -0
  110. /package/dist/tsup/{chunk-PAG6G46L.js.map → chunk-OH6CBWUD.js.map} +0 -0
  111. /package/dist/tsup/{chunk-MGTSVSUC.js.map → chunk-PLLHHJWR.js.map} +0 -0
@@ -0,0 +1,22 @@
1
+ import pRetry from "p-retry";
2
+ import type { Registry } from "@/registry";
3
+
4
+ export async function waitForRegistryReady(
5
+ registry: Registry<any>,
6
+ ): Promise<void> {
7
+ await pRetry(
8
+ async () => {
9
+ const response = await registry.routes.health();
10
+ if (!response.ok) {
11
+ throw new Error(
12
+ `RivetKit registry is not ready: ${response.status} ${await response.text()}`,
13
+ );
14
+ }
15
+ },
16
+ {
17
+ retries: 120,
18
+ minTimeout: 50,
19
+ maxTimeout: 250,
20
+ },
21
+ );
22
+ }
@@ -0,0 +1,170 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { afterEach, describe, expect, test } from "vitest";
3
+ import {
4
+ DEFAULT_MIGRATION_TABLE_NAME,
5
+ migrations,
6
+ type MigrationDatabase,
7
+ } from "./migrations";
8
+
9
+ const databases: DatabaseSync[] = [];
10
+
11
+ afterEach(() => {
12
+ for (const database of databases.splice(0)) database.close();
13
+ });
14
+
15
+ function createDatabase(): { raw: DatabaseSync; db: MigrationDatabase } {
16
+ const raw = new DatabaseSync(":memory:");
17
+ databases.push(raw);
18
+ return {
19
+ raw,
20
+ db: {
21
+ execute: async <TRow extends Record<string, unknown>>(
22
+ sql: string,
23
+ ...args: unknown[]
24
+ ): Promise<TRow[]> => {
25
+ if (args.length > 0 || /^\s*SELECT\b/i.test(sql)) {
26
+ return raw.prepare(sql).all(...(args as never[])) as TRow[];
27
+ }
28
+ raw.exec(sql);
29
+ return [];
30
+ },
31
+ },
32
+ };
33
+ }
34
+
35
+ describe("migrations", () => {
36
+ test("applies SQL and function migrations once in order", async () => {
37
+ const { raw, db } = createDatabase();
38
+ const applied: number[] = [];
39
+ const migrate = migrations({
40
+ tableName: "app_schema_version",
41
+ migrations: [
42
+ {
43
+ version: 1,
44
+ sql: "CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT NOT NULL)",
45
+ },
46
+ {
47
+ version: 2,
48
+ up: async (database) => {
49
+ applied.push(2);
50
+ await database.execute(
51
+ "ALTER TABLE items ADD COLUMN active INTEGER NOT NULL DEFAULT 1",
52
+ );
53
+ },
54
+ },
55
+ ],
56
+ });
57
+
58
+ await migrate(db);
59
+ await migrate(db);
60
+
61
+ expect(applied).toEqual([2]);
62
+ expect(
63
+ raw
64
+ .prepare(
65
+ "SELECT schema_version FROM app_schema_version WHERE singleton = 1",
66
+ )
67
+ .get(),
68
+ ).toEqual({ schema_version: 2 });
69
+ expect(
70
+ raw
71
+ .prepare("PRAGMA table_info(items)")
72
+ .all()
73
+ .map((row) => row.name),
74
+ ).toEqual(["id", "name", "active"]);
75
+ });
76
+
77
+ test("uses the default migration table", async () => {
78
+ const { raw, db } = createDatabase();
79
+ await migrations({
80
+ migrations: [{ version: 1, sql: "CREATE TABLE item (id INTEGER)" }],
81
+ })(db);
82
+
83
+ expect(
84
+ raw
85
+ .prepare(
86
+ `SELECT schema_version FROM ${DEFAULT_MIGRATION_TABLE_NAME} WHERE singleton = 1`,
87
+ )
88
+ .get(),
89
+ ).toEqual({ schema_version: 1 });
90
+ });
91
+
92
+ test("adopts an unversioned schema before applying later migrations", async () => {
93
+ const { raw, db } = createDatabase();
94
+ raw.exec(
95
+ "CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT NOT NULL)",
96
+ );
97
+ const applied: number[] = [];
98
+
99
+ await migrations({
100
+ tableName: "app_schema_version",
101
+ adopt: async (database) => {
102
+ const tables = await database.execute<{ name: string }>(
103
+ "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'items'",
104
+ );
105
+ return tables.length === 0 ? 0 : 1;
106
+ },
107
+ migrations: [
108
+ {
109
+ version: 1,
110
+ up: () => {
111
+ throw new Error("already applied migration ran");
112
+ },
113
+ },
114
+ {
115
+ version: 2,
116
+ up: async (database) => {
117
+ applied.push(2);
118
+ await database.execute(
119
+ "ALTER TABLE items ADD COLUMN active INTEGER NOT NULL DEFAULT 1",
120
+ );
121
+ },
122
+ },
123
+ ],
124
+ })(db);
125
+
126
+ expect(applied).toEqual([2]);
127
+ expect(
128
+ raw
129
+ .prepare(
130
+ "SELECT schema_version FROM app_schema_version WHERE singleton = 1",
131
+ )
132
+ .get(),
133
+ ).toEqual({ schema_version: 2 });
134
+ });
135
+
136
+ test("rejects invalid ladders and table names before executing", () => {
137
+ expect(() => migrations({ migrations: [] })).toThrow(
138
+ "must not be empty",
139
+ );
140
+ expect(() =>
141
+ migrations({
142
+ migrations: [{ version: 2, sql: "SELECT 1" }],
143
+ }),
144
+ ).toThrow("expected version 1");
145
+ expect(() =>
146
+ migrations({
147
+ tableName: "schema; DROP TABLE items",
148
+ migrations: [{ version: 1, sql: "SELECT 1" }],
149
+ }),
150
+ ).toThrow("invalid migration table name");
151
+ });
152
+
153
+ test("rejects a database newer than the migration ladder", async () => {
154
+ const { raw, db } = createDatabase();
155
+ raw.exec(`
156
+ CREATE TABLE app_schema_version (
157
+ singleton INTEGER PRIMARY KEY,
158
+ schema_version INTEGER NOT NULL
159
+ ) STRICT;
160
+ INSERT INTO app_schema_version VALUES (1, 2);
161
+ `);
162
+
163
+ await expect(
164
+ migrations({
165
+ tableName: "app_schema_version",
166
+ migrations: [{ version: 1, sql: "SELECT 1" }],
167
+ })(db),
168
+ ).rejects.toThrow("newer than supported version 1");
169
+ });
170
+ });
@@ -0,0 +1,141 @@
1
+ import type { RawAccess } from "@/common/database/config";
2
+
3
+ export const DEFAULT_MIGRATION_TABLE_NAME = "rivetkit_schema_version";
4
+
5
+ export type MigrationDatabase = Pick<RawAccess, "execute">;
6
+
7
+ export type Migration =
8
+ | {
9
+ version: number;
10
+ sql: string;
11
+ up?: never;
12
+ }
13
+ | {
14
+ version: number;
15
+ sql?: never;
16
+ up: (db: MigrationDatabase) => Promise<void> | void;
17
+ };
18
+
19
+ export interface MigrationsOptions {
20
+ /** A table owned by this schema. Override this when multiple schemas share a database. */
21
+ tableName?: string;
22
+ /** Detect the version of a schema that predates its migration table. */
23
+ adopt?: (db: MigrationDatabase) => Promise<number> | number;
24
+ /** Contiguous migrations numbered from 1. */
25
+ migrations: readonly Migration[];
26
+ }
27
+
28
+ /**
29
+ * Creates an `onMigrate` callback that applies each unapplied migration in order.
30
+ * RivetKit runs the callback inside its migration savepoint, making the complete
31
+ * ladder atomic when used with `db({ onMigrate })`.
32
+ */
33
+ export function migrations({
34
+ tableName = DEFAULT_MIGRATION_TABLE_NAME,
35
+ adopt,
36
+ migrations: ladder,
37
+ }: MigrationsOptions): (db: MigrationDatabase) => Promise<void> {
38
+ validateTableName(tableName);
39
+ validateLadder(ladder);
40
+
41
+ return async (database) => {
42
+ const quotedTableName = `"${tableName}"`;
43
+ await database.execute(`
44
+ CREATE TABLE IF NOT EXISTS ${quotedTableName} (
45
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
46
+ schema_version INTEGER NOT NULL CHECK (
47
+ schema_version BETWEEN 0 AND ${Number.MAX_SAFE_INTEGER}
48
+ )
49
+ ) STRICT
50
+ `);
51
+
52
+ const rows = await database.execute<{ schema_version: unknown }>(
53
+ `SELECT schema_version FROM ${quotedTableName} WHERE singleton = 1`,
54
+ );
55
+ if (rows.length > 1) {
56
+ throw new Error(
57
+ `invalid migration table "${tableName}": expected at most one version row, received ${rows.length}`,
58
+ );
59
+ }
60
+
61
+ const rawCurrent = rows[0]?.schema_version;
62
+ let current = rows.length === 0 ? 0 : rawCurrent;
63
+ if (rows.length === 0 && adopt) {
64
+ current = await adopt(database);
65
+ }
66
+ if (
67
+ typeof current !== "number" ||
68
+ !Number.isSafeInteger(current) ||
69
+ current < 0
70
+ ) {
71
+ throw new Error(
72
+ `invalid schema version ${String(current)} in migration table "${tableName}"`,
73
+ );
74
+ }
75
+ if (current > ladder.length) {
76
+ throw new Error(
77
+ `migration version ${current} in "${tableName}" is newer than supported version ${ladder.length}`,
78
+ );
79
+ }
80
+ if (rows.length === 0 && current > 0) {
81
+ await writeVersion(database, quotedTableName, current);
82
+ }
83
+
84
+ for (const migration of ladder.slice(current)) {
85
+ if (migration.sql !== undefined) {
86
+ await database.execute(migration.sql);
87
+ } else {
88
+ await migration.up(database);
89
+ }
90
+ await writeVersion(database, quotedTableName, migration.version);
91
+ }
92
+ };
93
+ }
94
+
95
+ async function writeVersion(
96
+ database: MigrationDatabase,
97
+ quotedTableName: string,
98
+ version: number,
99
+ ): Promise<void> {
100
+ await database.execute(
101
+ `INSERT INTO ${quotedTableName} (singleton, schema_version)
102
+ VALUES (1, ?)
103
+ ON CONFLICT(singleton) DO UPDATE SET schema_version = excluded.schema_version`,
104
+ version,
105
+ );
106
+ }
107
+
108
+ function validateTableName(tableName: string): void {
109
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(tableName)) {
110
+ throw new Error(
111
+ `invalid migration table name "${tableName}": expected a SQLite identifier`,
112
+ );
113
+ }
114
+ }
115
+
116
+ function validateLadder(ladder: readonly Migration[]): void {
117
+ if (ladder.length === 0) {
118
+ throw new Error("migration ladder must not be empty");
119
+ }
120
+
121
+ for (const [index, migration] of ladder.entries()) {
122
+ const expectedVersion = index + 1;
123
+ if (migration.version !== expectedVersion) {
124
+ throw new Error(
125
+ `invalid migration ladder: expected version ${expectedVersion}, received ${migration.version}`,
126
+ );
127
+ }
128
+ const hasSql = typeof migration.sql === "string";
129
+ const hasUp = typeof migration.up === "function";
130
+ if (hasSql === hasUp) {
131
+ throw new Error(
132
+ `invalid migration ${migration.version}: expected exactly one of sql or up`,
133
+ );
134
+ }
135
+ if (hasSql && migration.sql.trim().length === 0) {
136
+ throw new Error(
137
+ `invalid migration ${migration.version}: SQL is empty`,
138
+ );
139
+ }
140
+ }
141
+ }