rivetkit 2.3.30 → 3.0.0-preview.2

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 (135) hide show
  1. package/dist/browser/client.d.ts +58 -9
  2. package/dist/browser/client.js +193 -20
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +1 -2
  5. package/dist/browser/inspector/client.js.map +1 -1
  6. package/dist/tsup/{chunk-P2PHHJMH.cjs → chunk-25MUHNWE.cjs} +326 -166
  7. package/dist/tsup/chunk-25MUHNWE.cjs.map +1 -0
  8. package/dist/tsup/{chunk-5SN6GAYX.cjs → chunk-3SPYZMME.cjs} +3 -3
  9. package/dist/tsup/{chunk-5SN6GAYX.cjs.map → chunk-3SPYZMME.cjs.map} +1 -1
  10. package/dist/tsup/{chunk-4SNS3PYZ.js → chunk-3URL73AV.js} +2 -2
  11. package/dist/tsup/{chunk-EKAQ7HG2.js → chunk-442XBCAF.js} +3 -3
  12. package/dist/tsup/{chunk-CORYIKDC.js → chunk-5F7FWAJI.js} +10 -11
  13. package/dist/tsup/chunk-5F7FWAJI.js.map +1 -0
  14. package/dist/tsup/{chunk-I472KTIC.js → chunk-6IGGYL2C.js} +185 -25
  15. package/dist/tsup/chunk-6IGGYL2C.js.map +1 -0
  16. package/dist/tsup/{chunk-JI6GZ2C2.js → chunk-A2CF6PFH.js} +18 -1
  17. package/dist/tsup/chunk-A2CF6PFH.js.map +1 -0
  18. package/dist/tsup/{chunk-OUB7SGSA.js → chunk-ANNVZW6B.js} +2 -2
  19. package/dist/tsup/{chunk-ZIIQQHC3.cjs → chunk-BCG7PTBS.cjs} +4 -4
  20. package/dist/tsup/{chunk-ZIIQQHC3.cjs.map → chunk-BCG7PTBS.cjs.map} +1 -1
  21. package/dist/tsup/{chunk-OJFVABRH.cjs → chunk-CJ3MX5MI.cjs} +7 -7
  22. package/dist/tsup/{chunk-OJFVABRH.cjs.map → chunk-CJ3MX5MI.cjs.map} +1 -1
  23. package/dist/tsup/{chunk-GEUBEODU.cjs → chunk-EPPV7WB2.cjs} +3 -3
  24. package/dist/tsup/{chunk-GEUBEODU.cjs.map → chunk-EPPV7WB2.cjs.map} +1 -1
  25. package/dist/tsup/{chunk-MXV26ZBB.js → chunk-OLZ4KAFL.js} +4 -4
  26. package/dist/tsup/{chunk-5UUOECX2.cjs → chunk-QDRZMCX5.cjs} +10 -10
  27. package/dist/tsup/{chunk-5UUOECX2.cjs.map → chunk-QDRZMCX5.cjs.map} +1 -1
  28. package/dist/tsup/{chunk-MYWZCDML.cjs → chunk-RTWH3AX3.cjs} +19 -2
  29. package/dist/tsup/chunk-RTWH3AX3.cjs.map +1 -0
  30. package/dist/tsup/{chunk-H3SGQEHZ.js → chunk-WGKL7HMH.js} +2 -2
  31. package/dist/tsup/{chunk-6LOYTFPZ.js → chunk-WGQHG26S.js} +2 -2
  32. package/dist/tsup/{chunk-2BIRGEIU.cjs → chunk-XSOHGU4G.cjs} +10 -11
  33. package/dist/tsup/chunk-XSOHGU4G.cjs.map +1 -0
  34. package/dist/tsup/{chunk-ABPZG7QV.cjs → chunk-YZVVID47.cjs} +3 -3
  35. package/dist/tsup/{chunk-ABPZG7QV.cjs.map → chunk-YZVVID47.cjs.map} +1 -1
  36. package/dist/tsup/client/mod.cjs +6 -6
  37. package/dist/tsup/client/mod.d.cts +15 -3
  38. package/dist/tsup/client/mod.d.ts +15 -3
  39. package/dist/tsup/client/mod.js +5 -5
  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-osdJqQwX.d.cts → config-8NgsxIcT.d.cts} +43 -12
  45. package/dist/tsup/{config-ey2I2zz5.d.ts → config-B2wlj9wx.d.cts} +7 -1
  46. package/dist/tsup/{config-ey2I2zz5.d.cts → config-B2wlj9wx.d.ts} +7 -1
  47. package/dist/tsup/{config-Cv6pjCt-.d.ts → config-DJ3KW-fe.d.ts} +43 -12
  48. package/dist/tsup/{context-CoVbKBuk.d.ts → context-BL8kUGjq.d.ts} +2 -2
  49. package/dist/tsup/{context-DpjrM7n7.d.cts → context-_RoE_YHL.d.cts} +2 -2
  50. package/dist/tsup/db/drizzle.cjs +2 -2
  51. package/dist/tsup/db/drizzle.d.cts +1 -1
  52. package/dist/tsup/db/drizzle.d.ts +1 -1
  53. package/dist/tsup/db/drizzle.js +1 -1
  54. package/dist/tsup/db/mod.cjs +3 -3
  55. package/dist/tsup/db/mod.d.cts +2 -2
  56. package/dist/tsup/db/mod.d.ts +2 -2
  57. package/dist/tsup/db/mod.js +2 -2
  58. package/dist/tsup/dynamic/mod.d.cts +2 -2
  59. package/dist/tsup/dynamic/mod.d.ts +2 -2
  60. package/dist/tsup/inspector/mod.cjs +5 -5
  61. package/dist/tsup/inspector/mod.js +4 -4
  62. package/dist/tsup/inspector/workflow.cjs +4 -4
  63. package/dist/tsup/inspector/workflow.js +3 -3
  64. package/dist/tsup/inspector-tab/mod.d.cts +3 -3
  65. package/dist/tsup/inspector-tab/mod.d.ts +3 -3
  66. package/dist/tsup/mod.cjs +254 -166
  67. package/dist/tsup/mod.cjs.map +1 -1
  68. package/dist/tsup/mod.d.cts +4 -4
  69. package/dist/tsup/mod.d.ts +4 -4
  70. package/dist/tsup/mod.js +168 -80
  71. package/dist/tsup/mod.js.map +1 -1
  72. package/dist/tsup/test/mod.cjs +7 -7
  73. package/dist/tsup/test/mod.d.cts +2 -2
  74. package/dist/tsup/test/mod.d.ts +2 -2
  75. package/dist/tsup/test/mod.js +5 -5
  76. package/dist/tsup/unstable/migrations.d.cts +1 -1
  77. package/dist/tsup/unstable/migrations.d.ts +1 -1
  78. package/dist/tsup/utils.cjs +2 -2
  79. package/dist/tsup/utils.js +1 -1
  80. package/dist/tsup/workflow/mod.cjs +17 -17
  81. package/dist/tsup/workflow/mod.d.cts +4 -4
  82. package/dist/tsup/workflow/mod.d.ts +4 -4
  83. package/dist/tsup/workflow/mod.js +5 -5
  84. package/package.json +9 -10
  85. package/src/actor/keys.ts +86 -0
  86. package/src/client/actor-conn.ts +92 -6
  87. package/src/client/actor-handle.ts +21 -3
  88. package/src/client/client.ts +6 -0
  89. package/src/client/config.ts +12 -1
  90. package/src/client/lifecycle-errors.ts +16 -1
  91. package/src/client/retry-budget.ts +78 -0
  92. package/src/client/utils.ts +13 -2
  93. package/src/common/database/config.ts +7 -1
  94. package/src/common/database/native-database.ts +17 -6
  95. package/src/common/router.ts +1 -1
  96. package/src/engine-api/actors.ts +3 -3
  97. package/src/engine-client/actor-websocket-client.ts +4 -2
  98. package/src/engine-client/api-endpoints.ts +44 -14
  99. package/src/engine-client/mod.ts +2 -2
  100. package/src/registry/config/envoy.ts +1 -1
  101. package/src/registry/config/index.ts +28 -31
  102. package/src/registry/index.ts +51 -19
  103. package/src/registry/napi-runtime.ts +3 -2
  104. package/src/registry/native.ts +126 -34
  105. package/src/registry/runtime.ts +27 -10
  106. package/src/registry/wasm-runtime.ts +6 -3
  107. package/src/utils/env-vars.ts +15 -10
  108. package/dist/tsup/chunk-2BIRGEIU.cjs.map +0 -1
  109. package/dist/tsup/chunk-CORYIKDC.js.map +0 -1
  110. package/dist/tsup/chunk-I472KTIC.js.map +0 -1
  111. package/dist/tsup/chunk-JI6GZ2C2.js.map +0 -1
  112. package/dist/tsup/chunk-MYWZCDML.cjs.map +0 -1
  113. package/dist/tsup/chunk-P2PHHJMH.cjs.map +0 -1
  114. package/src/actor/config.test.ts +0 -78
  115. package/src/actor/keys.test.ts +0 -275
  116. package/src/actor/utils.test.ts +0 -48
  117. package/src/client/test.ts +0 -44
  118. package/src/client/token-provider.test.ts +0 -86
  119. package/src/common/database/mod.test.ts +0 -364
  120. package/src/common/database/native-database.test.ts +0 -220
  121. package/src/common/inline-websocket-adapter.test.ts +0 -51
  122. package/src/db/drizzle.test.ts +0 -164
  123. package/src/registry/config/index.test.ts +0 -25
  124. package/src/registry/run-handler-coordinator.test.ts +0 -252
  125. package/src/registry/runtime.test.ts +0 -124
  126. package/src/unstable/migrations.test.ts +0 -170
  127. package/src/utils/endpoint-parser.test.ts +0 -206
  128. package/src/utils.test.ts +0 -34
  129. package/src/workflow/driver.test.ts +0 -62
  130. /package/dist/tsup/{chunk-4SNS3PYZ.js.map → chunk-3URL73AV.js.map} +0 -0
  131. /package/dist/tsup/{chunk-EKAQ7HG2.js.map → chunk-442XBCAF.js.map} +0 -0
  132. /package/dist/tsup/{chunk-OUB7SGSA.js.map → chunk-ANNVZW6B.js.map} +0 -0
  133. /package/dist/tsup/{chunk-MXV26ZBB.js.map → chunk-OLZ4KAFL.js.map} +0 -0
  134. /package/dist/tsup/{chunk-H3SGQEHZ.js.map → chunk-WGKL7HMH.js.map} +0 -0
  135. /package/dist/tsup/{chunk-6LOYTFPZ.js.map → chunk-WGQHG26S.js.map} +0 -0
@@ -1,164 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
- import type {
3
- DatabaseProviderContext,
4
- SqliteBatchStatement,
5
- SqliteBindings,
6
- SqliteDatabase,
7
- SqliteExecuteResult,
8
- SqliteTransactionDatabase,
9
- } from "@/common/database/config";
10
- import { db } from "./drizzle";
11
-
12
- class FakeSqliteDatabase implements SqliteDatabase {
13
- executeCalls: Array<{ sql: string; params?: SqliteBindings }> = [];
14
- transactionTimeouts: Array<number | undefined> = [];
15
- transactionNames: Array<string | undefined> = [];
16
-
17
- async exec(): Promise<void> {}
18
-
19
- async execute(
20
- sql: string,
21
- params?: SqliteBindings,
22
- ): Promise<SqliteExecuteResult> {
23
- this.executeCalls.push({ sql, params });
24
- return emptyResult();
25
- }
26
-
27
- async executeBatch(
28
- statements: SqliteBatchStatement[],
29
- ): Promise<SqliteExecuteResult[]> {
30
- const transaction = await this.beginTransaction();
31
- try {
32
- const results: SqliteExecuteResult[] = [];
33
- for (const statement of statements) {
34
- results.push(
35
- await transaction.execute(statement.sql, statement.params),
36
- );
37
- }
38
- await transaction.commit();
39
- return results;
40
- } catch (error) {
41
- await transaction.rollback();
42
- throw error;
43
- }
44
- }
45
-
46
- async beginTransaction(
47
- timeoutMs?: number,
48
- name?: string,
49
- ): Promise<SqliteTransactionDatabase> {
50
- this.transactionTimeouts.push(timeoutMs);
51
- this.transactionNames.push(name);
52
- this.executeCalls.push({ sql: "BEGIN" });
53
- return {
54
- exec: async () => {},
55
- execute: async (sql, params) => {
56
- this.executeCalls.push({ sql, params });
57
- return emptyResult();
58
- },
59
- commit: async () => {
60
- this.executeCalls.push({ sql: "COMMIT" });
61
- },
62
- rollback: async () => {
63
- this.executeCalls.push({ sql: "ROLLBACK" });
64
- },
65
- };
66
- }
67
-
68
- async run(sql: string, params?: SqliteBindings): Promise<void> {
69
- await this.execute(sql, params);
70
- }
71
-
72
- async query(sql: string, params?: SqliteBindings) {
73
- const { columns, rows } = await this.execute(sql, params);
74
- return { columns, rows };
75
- }
76
-
77
- async close(): Promise<void> {}
78
- }
79
-
80
- function emptyResult(): SqliteExecuteResult {
81
- return {
82
- columns: [],
83
- rows: [],
84
- changes: 0,
85
- lastInsertRowId: null,
86
- };
87
- }
88
-
89
- function testProviderContext(
90
- database: SqliteDatabase,
91
- ): DatabaseProviderContext {
92
- return {
93
- actorId: "actor-a",
94
- kv: {
95
- batchPut: async () => {},
96
- batchGet: async (keys) => keys.map(() => null),
97
- batchDelete: async () => {},
98
- deleteRange: async () => {},
99
- },
100
- nativeDatabaseProvider: { open: async () => database },
101
- };
102
- }
103
-
104
- describe("Drizzle database transactions", () => {
105
- test("runs migrations in the shared transaction with a generous timeout", async () => {
106
- const nativeDb = new FakeSqliteDatabase();
107
- const provider = db({
108
- onMigrate: async (client) => {
109
- await client.execute(
110
- "CREATE TABLE items(id INTEGER PRIMARY KEY)",
111
- );
112
- },
113
- });
114
- const client = await provider.createClient(
115
- testProviderContext(nativeDb),
116
- );
117
- await provider.onMigrate(client);
118
-
119
- expect(nativeDb.transactionTimeouts).toEqual([300_000]);
120
- expect(nativeDb.transactionNames).toEqual([
121
- "rivetkit-drizzle-migration",
122
- ]);
123
- expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
124
- "BEGIN",
125
- "SAVEPOINT __rivet_on_migrate",
126
- "CREATE TABLE items(id INTEGER PRIMARY KEY)",
127
- "RELEASE SAVEPOINT __rivet_on_migrate",
128
- "COMMIT",
129
- ]);
130
- });
131
-
132
- test("routes transaction work through the transaction handle", async () => {
133
- const nativeDb = new FakeSqliteDatabase();
134
- const client = await db().createClient(testProviderContext(nativeDb));
135
- await client.transaction(
136
- async (tx) => {
137
- await tx.execute(
138
- "INSERT INTO items(value) VALUES (?)",
139
- "inside",
140
- );
141
- },
142
- { name: "drizzle-insert", timeout: 120_000 },
143
- );
144
-
145
- expect(nativeDb.transactionTimeouts).toEqual([120_000]);
146
- expect(nativeDb.transactionNames).toEqual(["drizzle-insert"]);
147
- expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
148
- "BEGIN",
149
- "INSERT INTO items(value) VALUES (?)",
150
- "COMMIT",
151
- ]);
152
- });
153
-
154
- test("validates zero, negative, and non-finite transaction timeouts", async () => {
155
- const client = await db().createClient(
156
- testProviderContext(new FakeSqliteDatabase()),
157
- );
158
- for (const timeout of [0, -1, Number.NaN, Number.POSITIVE_INFINITY]) {
159
- await expect(
160
- client.transaction(async () => {}, { timeout }),
161
- ).rejects.toThrow("positive finite");
162
- }
163
- });
164
- });
@@ -1,25 +0,0 @@
1
- import { afterEach, describe, expect, test } from "vitest";
2
- import { RegistryConfigSchema } from "./index";
3
-
4
- const ORIGINAL_RIVET_TOKEN = process.env.RIVET_TOKEN;
5
-
6
- afterEach(() => {
7
- if (ORIGINAL_RIVET_TOKEN === undefined) {
8
- delete process.env.RIVET_TOKEN;
9
- } else {
10
- process.env.RIVET_TOKEN = ORIGINAL_RIVET_TOKEN;
11
- }
12
- });
13
-
14
- describe("RegistryConfigSchema", () => {
15
- test("defaults local Engine token", () => {
16
- delete process.env.RIVET_TOKEN;
17
-
18
- const config = RegistryConfigSchema.parse({
19
- use: {},
20
- startEngine: true,
21
- });
22
-
23
- expect(config.token).toBe("default");
24
- });
25
- });
@@ -1,252 +0,0 @@
1
- import { describe, expect, test, vi } from "vitest";
2
- import { defineRunHandler, type RunControl } from "@/actor/config";
3
- import { RunHandlerCoordinator } from "./run-handler-coordinator";
4
-
5
- class Deferred<T = void> {
6
- readonly promise: Promise<T>;
7
- resolve!: (value: T | PromiseLike<T>) => void;
8
- reject!: (reason?: unknown) => void;
9
-
10
- constructor() {
11
- this.promise = new Promise<T>((resolve, reject) => {
12
- this.resolve = resolve;
13
- this.reject = reject;
14
- });
15
- }
16
- }
17
-
18
- function createCoordinator() {
19
- let control: RunControl | undefined;
20
- const dispose = vi.fn();
21
- const createInspector = vi.fn((context: { control: RunControl }) => {
22
- control = context.control;
23
- return {
24
- inspector: {
25
- workflow: {
26
- getHistory: () => null,
27
- getState: async () => null,
28
- onHistoryUpdated: () => () => {},
29
- replayFromStep: async () => null,
30
- },
31
- },
32
- dispose,
33
- };
34
- });
35
- const run = defineRunHandler(async () => {}, {
36
- inspectorKind: "workflow",
37
- createInspector,
38
- });
39
- const coordinator = new RunHandlerCoordinator(run);
40
- const restart = vi.fn();
41
- const inspector = coordinator.getInspector("actor-1", restart);
42
-
43
- return {
44
- control: control as unknown as RunControl,
45
- coordinator,
46
- createInspector,
47
- dispose,
48
- inspector,
49
- restart,
50
- };
51
- }
52
-
53
- describe("RunHandlerCoordinator", () => {
54
- test("fails explicitly when a JavaScript factory omits required workflow controls", async () => {
55
- const coordinator = new RunHandlerCoordinator(
56
- defineRunHandler(async () => {}, {
57
- inspectorKind: "workflow",
58
- createInspector: (() => ({
59
- inspector: { workflow: { getHistory: () => null } },
60
- })) as never,
61
- }),
62
- );
63
-
64
- await expect(
65
- coordinator.run(
66
- "actor-1",
67
- () => {},
68
- async () => {},
69
- ),
70
- ).rejects.toThrow(
71
- "createInspector returned an invalid workflow adapter for actor actor-1",
72
- );
73
- });
74
-
75
- test("initializes and disposes Inspector state even when it is never queried", async () => {
76
- const dispose = vi.fn();
77
- const createInspector = vi.fn(() => ({
78
- inspector: {
79
- workflow: {
80
- getHistory: () => null,
81
- getState: async () => null,
82
- onHistoryUpdated: () => () => {},
83
- replayFromStep: async () => null,
84
- },
85
- },
86
- dispose,
87
- }));
88
- const coordinator = new RunHandlerCoordinator(
89
- defineRunHandler(async () => {}, {
90
- inspectorKind: "workflow",
91
- createInspector,
92
- }),
93
- );
94
-
95
- await coordinator.run(
96
- "actor-1",
97
- () => {},
98
- async () => {},
99
- );
100
- expect(createInspector).toHaveBeenCalledOnce();
101
- coordinator.destroy("actor-1");
102
- expect(dispose).toHaveBeenCalledOnce();
103
- });
104
-
105
- test("creates one inspector per live actor and disposes it exactly once", () => {
106
- const subject = createCoordinator();
107
- expect(
108
- subject.coordinator.getInspector("actor-1", subject.restart),
109
- ).toBe(subject.inspector);
110
- expect(subject.createInspector).toHaveBeenCalledOnce();
111
-
112
- subject.coordinator.destroy("actor-1");
113
- subject.coordinator.destroy("actor-1");
114
- expect(subject.dispose).toHaveBeenCalledOnce();
115
-
116
- const recreated = subject.coordinator.getInspector(
117
- "actor-1",
118
- subject.restart,
119
- );
120
- expect(recreated).not.toBe(subject.inspector);
121
- expect(subject.createInspector).toHaveBeenCalledTimes(2);
122
- });
123
-
124
- test("rejects replay while a run is active", async () => {
125
- const subject = createCoordinator();
126
- const active = new Deferred();
127
- const started = new Deferred();
128
- const running = subject.coordinator.run(
129
- "actor-1",
130
- subject.restart,
131
- async () => {
132
- started.resolve();
133
- await active.promise;
134
- },
135
- );
136
- await started.promise;
137
-
138
- await expect(
139
- subject.control.run.withInactive(
140
- { restartOnSuccess: true },
141
- async () => {},
142
- ),
143
- ).rejects.toMatchObject({
144
- group: "actor",
145
- code: "run_handler_unavailable",
146
- });
147
-
148
- active.resolve();
149
- await running;
150
- });
151
-
152
- test("uses a start queued during replay as the single restart", async () => {
153
- const subject = createCoordinator();
154
- const replay = new Deferred();
155
- const replayStarted = new Deferred();
156
- const events: string[] = [];
157
- subject.restart.mockImplementation(() => {
158
- events.push("restart");
159
- });
160
-
161
- const exclusive = subject.control.run.withInactive(
162
- { restartOnSuccess: true },
163
- async () => {
164
- events.push("replay");
165
- replayStarted.resolve();
166
- await replay.promise;
167
- },
168
- );
169
- await replayStarted.promise;
170
-
171
- const queued = subject.coordinator.run(
172
- "actor-1",
173
- subject.restart,
174
- async () => {
175
- events.push("run");
176
- },
177
- );
178
- await Promise.resolve();
179
- expect(events).toEqual(["replay"]);
180
-
181
- replay.resolve();
182
- await exclusive;
183
- await queued;
184
- expect(events).toEqual(["replay", "run"]);
185
- expect(subject.restart).not.toHaveBeenCalled();
186
- });
187
-
188
- test("drops starts queued behind a failed replay and leaves the run inactive", async () => {
189
- const subject = createCoordinator();
190
- const replay = new Deferred();
191
- const replayStarted = new Deferred();
192
- const run = vi.fn();
193
- const expected = new Error("rewrite failed");
194
-
195
- const exclusive = subject.control.run.withInactive(
196
- { restartOnSuccess: true },
197
- async () => {
198
- replayStarted.resolve();
199
- await replay.promise;
200
- throw expected;
201
- },
202
- );
203
- await replayStarted.promise;
204
- const queued = subject.coordinator.run("actor-1", subject.restart, run);
205
-
206
- replay.resolve();
207
- await expect(exclusive).rejects.toBe(expected);
208
- await expect(queued).resolves.toBe("suppressed");
209
- expect(run).not.toHaveBeenCalled();
210
- expect(subject.restart).not.toHaveBeenCalled();
211
- });
212
-
213
- test("restores a durable wake suppressed by a failed replay", async () => {
214
- const subject = createCoordinator();
215
- const replay = new Deferred();
216
- const replayStarted = new Deferred();
217
- const run = vi.fn();
218
-
219
- const exclusive = subject.control.run.withInactive({}, async () => {
220
- replayStarted.resolve();
221
- await replay.promise;
222
- throw new Error("rewrite failed");
223
- });
224
- await replayStarted.promise;
225
- const queued = subject.coordinator.run("actor-1", subject.restart, run);
226
-
227
- replay.resolve();
228
- await expect(exclusive).rejects.toThrow("rewrite failed");
229
- await expect(queued).resolves.toBe("suppressed");
230
- expect(run).not.toHaveBeenCalled();
231
- });
232
-
233
- test("allows only one concurrent replay and closes old controls on destroy", async () => {
234
- const subject = createCoordinator();
235
- const replay = new Deferred();
236
- const first = subject.control.run.withInactive({}, async () => {
237
- await replay.promise;
238
- });
239
-
240
- await expect(
241
- subject.control.run.withInactive({}, async () => {}),
242
- ).rejects.toMatchObject({ code: "run_handler_unavailable" });
243
- subject.coordinator.destroy("actor-1");
244
- replay.resolve();
245
- await expect(first).rejects.toMatchObject({
246
- code: "run_handler_unavailable",
247
- });
248
- await expect(
249
- subject.control.run.withInactive({}, async () => {}),
250
- ).rejects.toMatchObject({ code: "run_handler_unavailable" });
251
- });
252
- });
@@ -1,124 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
- import type { RegistryConfig } from "./config";
3
- import { loadAutoRuntime, type RuntimeLoaders } from "./native";
4
- import {
5
- type CoreRuntime,
6
- normalizeRuntimeSqlExecuteResult,
7
- type RuntimeSqlBindParam,
8
- type RuntimeSqlBindParams,
9
- } from "./runtime";
10
-
11
- describe("runtime SQL boundary", () => {
12
- test("accepts exact bind param variants", () => {
13
- const blob = new Uint8Array([1, 2, 3]);
14
- const params = [
15
- { kind: "null" },
16
- { kind: "int", intValue: 1 },
17
- { kind: "float", floatValue: 1.5 },
18
- { kind: "text", textValue: "text" },
19
- { kind: "blob", blobValue: blob },
20
- ] satisfies RuntimeSqlBindParams;
21
-
22
- expect(params).toEqual([
23
- { kind: "null" },
24
- { kind: "int", intValue: 1 },
25
- { kind: "float", floatValue: 1.5 },
26
- { kind: "text", textValue: "text" },
27
- { kind: "blob", blobValue: blob },
28
- ]);
29
- });
30
-
31
- test("rejects bind params with mismatched value fields at typecheck time", () => {
32
- const invalidIntParamCandidate = {
33
- kind: "int",
34
- intValue: 1,
35
- textValue: "extra",
36
- } as const;
37
- // @ts-expect-error Runtime SQL int params must only carry intValue.
38
- const invalidIntParam: RuntimeSqlBindParam = invalidIntParamCandidate;
39
-
40
- expect(invalidIntParam.kind).toBe("int");
41
- });
42
-
43
- test("normalizes execute result metadata", () => {
44
- const base = {
45
- columns: ["value"],
46
- rows: [[1]],
47
- changes: 1,
48
- lastInsertRowId: null,
49
- };
50
-
51
- expect(normalizeRuntimeSqlExecuteResult(base)).toEqual(base);
52
- });
53
- });
54
-
55
- describe("loadAutoRuntime failure reporting", () => {
56
- const wasmRuntime = { kind: "wasm" } as unknown as CoreRuntime;
57
- const nativeRuntime = { kind: "napi" } as unknown as CoreRuntime;
58
- const config = {} as RegistryConfig;
59
-
60
- function loaders(overrides: Partial<RuntimeLoaders>): RuntimeLoaders {
61
- return {
62
- detectHost: () => "node-like",
63
- loadNative: async () => ({ runtime: nativeRuntime }) as never,
64
- loadWasm: async () => ({ runtime: wasmRuntime }) as never,
65
- ...overrides,
66
- };
67
- }
68
-
69
- test("prefers native when it loads", async () => {
70
- const runtime = await loadAutoRuntime(config, loaders({}));
71
- expect(runtime).toBe(nativeRuntime);
72
- });
73
-
74
- test("falls back to wasm when native fails", async () => {
75
- const runtime = await loadAutoRuntime(
76
- config,
77
- loaders({
78
- loadNative: async () => {
79
- throw new Error("missing platform binding");
80
- },
81
- }),
82
- );
83
- expect(runtime).toBe(wasmRuntime);
84
- });
85
-
86
- test("reports the native cause when both runtimes fail", async () => {
87
- // The native failure is the actionable one. Before this was reported,
88
- // a skipped platform binding surfaced only as the wasm loader's
89
- // unrelated `file://` fetch error.
90
- const promise = loadAutoRuntime(
91
- config,
92
- loaders({
93
- loadNative: async () => {
94
- throw new Error(
95
- "Cannot find module '@rivetkit/rivetkit-napi-linux-x64-musl'",
96
- );
97
- },
98
- loadWasm: async () => {
99
- throw new Error("fetch failed");
100
- },
101
- }),
102
- );
103
- await expect(promise).rejects.toThrow(/rivetkit-napi-linux-x64-musl/);
104
- await expect(promise).rejects.toThrow(/fetch failed/);
105
- });
106
-
107
- test("uses wasm directly on an edge-like host without touching native", async () => {
108
- let nativeCalls = 0;
109
- const runtime = await loadAutoRuntime(
110
- config,
111
- loaders({
112
- detectHost: () => "edge-like",
113
- loadNative: async () => {
114
- nativeCalls += 1;
115
- throw new Error(
116
- "native must not be attempted on edge hosts",
117
- );
118
- },
119
- }),
120
- );
121
- expect(runtime).toBe(wasmRuntime);
122
- expect(nativeCalls).toBe(0);
123
- });
124
- });