rivetkit 2.3.0-rc.10 → 2.3.0-rc.12

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 (205) hide show
  1. package/dist/browser/client.d.ts +448 -62
  2. package/dist/browser/client.js +131 -89
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +40 -20
  5. package/dist/browser/inspector/client.js.map +1 -1
  6. package/dist/tsup/actor/errors.cjs +2 -2
  7. package/dist/tsup/actor/errors.js +1 -1
  8. package/dist/tsup/agent-os/index.cjs +2103 -2090
  9. package/dist/tsup/agent-os/index.cjs.map +1 -1
  10. package/dist/tsup/agent-os/index.d.cts +446 -69
  11. package/dist/tsup/agent-os/index.d.ts +446 -69
  12. package/dist/tsup/agent-os/index.js +2102 -2089
  13. package/dist/tsup/agent-os/index.js.map +1 -1
  14. package/dist/tsup/{chunk-TE4VCDNY.cjs → chunk-2U6RLFKX.cjs} +219 -234
  15. package/dist/tsup/chunk-2U6RLFKX.cjs.map +1 -0
  16. package/dist/tsup/{chunk-4K3MV2MW.cjs → chunk-2ZTBRZRS.cjs} +10 -10
  17. package/dist/tsup/chunk-2ZTBRZRS.cjs.map +1 -0
  18. package/dist/tsup/{chunk-KU6VKVEK.js → chunk-3EVVOYFD.js} +19 -7
  19. package/dist/tsup/chunk-3EVVOYFD.js.map +1 -0
  20. package/dist/tsup/{chunk-3LGP4JSO.cjs → chunk-6KTMKPNU.cjs} +8 -8
  21. package/dist/tsup/{chunk-3LGP4JSO.cjs.map → chunk-6KTMKPNU.cjs.map} +1 -1
  22. package/dist/tsup/{chunk-WU2O2KIE.js → chunk-7UZF56RS.js} +63 -78
  23. package/dist/tsup/chunk-7UZF56RS.js.map +1 -0
  24. package/dist/tsup/{chunk-KIWH5H3K.js → chunk-BRP62GZC.js} +3 -3
  25. package/dist/tsup/chunk-BRP62GZC.js.map +1 -0
  26. package/dist/tsup/{chunk-G5RULGYQ.cjs → chunk-C7AAIILH.cjs} +24 -9
  27. package/dist/tsup/chunk-C7AAIILH.cjs.map +1 -0
  28. package/dist/tsup/{chunk-XV52XUWU.js → chunk-EWVOWEMD.js} +4 -4
  29. package/dist/tsup/chunk-EWVOWEMD.js.map +1 -0
  30. package/dist/tsup/{chunk-3YY5S6TV.js → chunk-HXUEHHJF.js} +2 -2
  31. package/dist/tsup/chunk-HXUEHHJF.js.map +1 -0
  32. package/dist/tsup/{chunk-PCBNKI2J.js → chunk-JZ7TWV65.js} +1 -1
  33. package/dist/tsup/chunk-JZ7TWV65.js.map +1 -0
  34. package/dist/tsup/{chunk-QAZLM4WT.cjs → chunk-KORQB2IR.cjs} +3 -3
  35. package/dist/tsup/{chunk-QAZLM4WT.cjs.map → chunk-KORQB2IR.cjs.map} +1 -1
  36. package/dist/tsup/{chunk-CMYS77J6.js → chunk-OLIJHKLL.js} +3 -3
  37. package/dist/tsup/{chunk-BM3EOY7M.js → chunk-OOB32JVG.js} +134 -20
  38. package/dist/tsup/chunk-OOB32JVG.js.map +1 -0
  39. package/dist/tsup/{chunk-G34LIR7S.js → chunk-QKSGGKGQ.js} +22 -7
  40. package/dist/tsup/chunk-QKSGGKGQ.js.map +1 -0
  41. package/dist/tsup/{chunk-PWFGP2US.cjs → chunk-SS56HFM2.cjs} +138 -24
  42. package/dist/tsup/chunk-SS56HFM2.cjs.map +1 -0
  43. package/dist/tsup/{chunk-Z4C3W2CQ.cjs → chunk-UETC5RF7.cjs} +3 -3
  44. package/dist/tsup/{chunk-Z4C3W2CQ.cjs.map → chunk-UETC5RF7.cjs.map} +1 -1
  45. package/dist/tsup/{chunk-LD5YASJU.cjs → chunk-VE2X4KMG.cjs} +2 -2
  46. package/dist/tsup/{chunk-LD5YASJU.cjs.map → chunk-VE2X4KMG.cjs.map} +1 -1
  47. package/dist/tsup/{chunk-6BI2MS3S.js → chunk-VLXRFJ7P.js} +2 -2
  48. package/dist/tsup/{chunk-J5P6S2LC.cjs → chunk-VNMIAPPF.cjs} +26 -14
  49. package/dist/tsup/chunk-VNMIAPPF.cjs.map +1 -0
  50. package/dist/tsup/{chunk-WQ4HNA4W.cjs → chunk-WHYBAEWG.cjs} +4 -2
  51. package/dist/tsup/chunk-WHYBAEWG.cjs.map +1 -0
  52. package/dist/tsup/{chunk-T6YVRM4K.js → chunk-WIMUFZVJ.js} +3 -1
  53. package/dist/tsup/chunk-WIMUFZVJ.js.map +1 -0
  54. package/dist/tsup/{chunk-2NDZ7JCR.cjs → chunk-ZA7FLHKH.cjs} +1 -1
  55. package/dist/tsup/chunk-ZA7FLHKH.cjs.map +1 -0
  56. package/dist/tsup/client/mod.cjs +9 -9
  57. package/dist/tsup/client/mod.d.cts +4 -4
  58. package/dist/tsup/client/mod.d.ts +4 -4
  59. package/dist/tsup/client/mod.js +8 -8
  60. package/dist/tsup/common/log.cjs +3 -3
  61. package/dist/tsup/common/log.js +2 -2
  62. package/dist/tsup/common/websocket.cjs +4 -4
  63. package/dist/tsup/common/websocket.js +3 -3
  64. package/dist/tsup/{config-Ca8dN4cS.d.cts → config-BtAh7oBu.d.cts} +409 -22
  65. package/dist/tsup/{config-CxjGYf4K.d.cts → config-D49x8NpL.d.cts} +1 -2
  66. package/dist/tsup/{config-CxjGYf4K.d.ts → config-D49x8NpL.d.ts} +1 -2
  67. package/dist/tsup/{config-0Ta55UV0.d.ts → config-DKgPGC0f.d.ts} +409 -22
  68. package/dist/tsup/{context-B_IWbWne.d.ts → context-C-6dGebY.d.ts} +8 -8
  69. package/dist/tsup/{context-CUrQ9MHc.d.cts → context-Cfjl5pgz.d.cts} +8 -8
  70. package/dist/tsup/db/drizzle.cjs +3 -3
  71. package/dist/tsup/db/drizzle.d.cts +1 -1
  72. package/dist/tsup/db/drizzle.d.ts +1 -1
  73. package/dist/tsup/db/drizzle.js +1 -1
  74. package/dist/tsup/db/mod.cjs +2 -2
  75. package/dist/tsup/db/mod.d.cts +2 -2
  76. package/dist/tsup/db/mod.d.ts +2 -2
  77. package/dist/tsup/db/mod.js +1 -1
  78. package/dist/tsup/dynamic/mod.cjs +24 -0
  79. package/dist/tsup/dynamic/mod.cjs.map +1 -0
  80. package/dist/tsup/dynamic/mod.d.cts +37 -0
  81. package/dist/tsup/dynamic/mod.d.ts +37 -0
  82. package/dist/tsup/dynamic/mod.js +24 -0
  83. package/dist/tsup/dynamic/mod.js.map +1 -0
  84. package/dist/tsup/inspector/mod.cjs +6 -6
  85. package/dist/tsup/inspector/mod.js +5 -5
  86. package/dist/tsup/mod.cjs +606 -325
  87. package/dist/tsup/mod.cjs.map +1 -1
  88. package/dist/tsup/mod.d.cts +4 -4
  89. package/dist/tsup/mod.d.ts +4 -4
  90. package/dist/tsup/mod.js +510 -229
  91. package/dist/tsup/mod.js.map +1 -1
  92. package/dist/tsup/test/mod.cjs +21 -18
  93. package/dist/tsup/test/mod.cjs.map +1 -1
  94. package/dist/tsup/test/mod.d.cts +3 -3
  95. package/dist/tsup/test/mod.d.ts +3 -3
  96. package/dist/tsup/test/mod.js +18 -15
  97. package/dist/tsup/test/mod.js.map +1 -1
  98. package/dist/tsup/utils.cjs +3 -3
  99. package/dist/tsup/utils.d.cts +1 -1
  100. package/dist/tsup/utils.d.ts +1 -1
  101. package/dist/tsup/utils.js +2 -2
  102. package/dist/tsup/workflow/mod.cjs +307 -282
  103. package/dist/tsup/workflow/mod.cjs.map +1 -1
  104. package/dist/tsup/workflow/mod.d.cts +5 -5
  105. package/dist/tsup/workflow/mod.d.ts +5 -5
  106. package/dist/tsup/workflow/mod.js +501 -476
  107. package/dist/tsup/workflow/mod.js.map +1 -1
  108. package/package.json +22 -11
  109. package/src/actor/config.ts +68 -51
  110. package/src/actor/contexts/index.ts +7 -2
  111. package/src/actor/definition.ts +17 -19
  112. package/src/actor/driver.ts +3 -3
  113. package/src/actor/errors.ts +9 -3
  114. package/src/actor/instance/mod.ts +22 -30
  115. package/src/actor/keys.ts +1 -1
  116. package/src/actor/mod.ts +20 -20
  117. package/src/actor/schema.ts +2 -2
  118. package/src/agent-os/actor/index.ts +38 -18
  119. package/src/agent-os/actor/preview.ts +1 -2
  120. package/src/agent-os/actor/session.ts +2 -2
  121. package/src/agent-os/config.ts +1 -1
  122. package/src/agent-os/fs/database-vfs.ts +1 -1
  123. package/src/agent-os/index.ts +16 -15
  124. package/src/client/actor-common.ts +87 -54
  125. package/src/client/actor-conn.ts +8 -36
  126. package/src/client/actor-handle.ts +69 -51
  127. package/src/client/actor-query.ts +5 -5
  128. package/src/client/errors.ts +1 -1
  129. package/src/client/lifecycle-errors.ts +2 -4
  130. package/src/client/query.ts +1 -1
  131. package/src/client/queue.ts +8 -3
  132. package/src/client/raw-utils.ts +8 -6
  133. package/src/client/resolve-gateway-target.ts +1 -1
  134. package/src/client/utils.ts +2 -7
  135. package/src/common/actor-websocket.ts +3 -1
  136. package/src/common/bare/actor-persist/v1.ts +205 -163
  137. package/src/common/bare/actor-persist/v2.ts +265 -213
  138. package/src/common/bare/actor-persist/v3.ts +176 -172
  139. package/src/common/bare/actor-persist/v4.ts +254 -253
  140. package/src/common/bare/transport/v1.ts +659 -543
  141. package/src/common/client-protocol-versioned.ts +66 -64
  142. package/src/common/database/config.ts +2 -8
  143. package/src/common/database/native-database.ts +1 -1
  144. package/src/common/database/shared.ts +1 -0
  145. package/src/common/encoding.ts +250 -16
  146. package/src/common/eventsource.ts +1 -1
  147. package/src/common/inline-websocket-adapter.ts +14 -13
  148. package/src/common/log.ts +1 -0
  149. package/src/common/router.ts +13 -17
  150. package/src/common/utils.ts +1 -150
  151. package/src/common/websocket-interface.ts +1 -1
  152. package/src/db/mod.ts +1 -1
  153. package/src/drivers/engine/actor-driver.ts +58 -56
  154. package/src/dynamic/instance.ts +32 -0
  155. package/src/dynamic/internal.ts +50 -0
  156. package/src/dynamic/isolate-runtime.ts +66 -0
  157. package/src/dynamic/mod.ts +32 -0
  158. package/src/engine-client/actor-http-client.ts +1 -1
  159. package/src/engine-client/actor-websocket-client.ts +6 -5
  160. package/src/engine-client/api-endpoints.ts +51 -2
  161. package/src/engine-client/api-utils.ts +2 -2
  162. package/src/engine-client/driver.ts +1 -1
  163. package/src/engine-client/mod.ts +6 -3
  164. package/src/engine-client/ws-proxy.ts +4 -4
  165. package/src/inspector/client.browser.ts +5 -11
  166. package/src/inspector/mod.ts +1 -3
  167. package/src/registry/config/envoy.ts +1 -2
  168. package/src/registry/config/index.ts +3 -9
  169. package/src/registry/index.ts +150 -72
  170. package/src/registry/napi-runtime.ts +13 -2
  171. package/src/registry/native-validation.ts +10 -12
  172. package/src/registry/native.ts +231 -173
  173. package/src/registry/process-metrics.ts +250 -0
  174. package/src/registry/runtime.ts +4 -0
  175. package/src/registry/wasm-runtime.ts +18 -2
  176. package/src/registry/write-through-proxy.ts +40 -0
  177. package/src/serde.ts +2 -2
  178. package/src/serverless/configure.ts +18 -7
  179. package/src/test/mod.ts +11 -8
  180. package/src/utils/endpoint-parser.ts +1 -1
  181. package/src/utils/router.ts +1 -1
  182. package/src/utils/serve.ts +4 -5
  183. package/src/utils.ts +1 -2
  184. package/src/workflow/context.ts +61 -33
  185. package/src/workflow/driver.ts +4 -6
  186. package/src/workflow/inspector.ts +4 -3
  187. package/src/workflow/mod.ts +15 -17
  188. package/dist/tsup/chunk-2NDZ7JCR.cjs.map +0 -1
  189. package/dist/tsup/chunk-3YY5S6TV.js.map +0 -1
  190. package/dist/tsup/chunk-4K3MV2MW.cjs.map +0 -1
  191. package/dist/tsup/chunk-BM3EOY7M.js.map +0 -1
  192. package/dist/tsup/chunk-G34LIR7S.js.map +0 -1
  193. package/dist/tsup/chunk-G5RULGYQ.cjs.map +0 -1
  194. package/dist/tsup/chunk-J5P6S2LC.cjs.map +0 -1
  195. package/dist/tsup/chunk-KIWH5H3K.js.map +0 -1
  196. package/dist/tsup/chunk-KU6VKVEK.js.map +0 -1
  197. package/dist/tsup/chunk-PCBNKI2J.js.map +0 -1
  198. package/dist/tsup/chunk-PWFGP2US.cjs.map +0 -1
  199. package/dist/tsup/chunk-T6YVRM4K.js.map +0 -1
  200. package/dist/tsup/chunk-TE4VCDNY.cjs.map +0 -1
  201. package/dist/tsup/chunk-WQ4HNA4W.cjs.map +0 -1
  202. package/dist/tsup/chunk-WU2O2KIE.js.map +0 -1
  203. package/dist/tsup/chunk-XV52XUWU.js.map +0 -1
  204. /package/dist/tsup/{chunk-CMYS77J6.js.map → chunk-OLIJHKLL.js.map} +0 -0
  205. /package/dist/tsup/{chunk-6BI2MS3S.js.map → chunk-VLXRFJ7P.js.map} +0 -0
@@ -23,8 +23,8 @@ import type {
23
23
  RuntimeQueueNextBatchOptions,
24
24
  RuntimeQueueTryNextBatchOptions,
25
25
  RuntimeQueueWaitOptions,
26
- RuntimeRequestSaveOpts,
27
26
  RuntimeRegistryRouteResponse,
27
+ RuntimeRequestSaveOpts,
28
28
  RuntimeServeConfig,
29
29
  RuntimeServerlessRequest,
30
30
  RuntimeServerlessResponseHead,
@@ -452,6 +452,12 @@ export class NapiCoreRuntime implements CoreRuntime {
452
452
  return await asNativeActorContext(ctx).waitForTrackedShutdownWork();
453
453
  }
454
454
 
455
+ async actorWaitForTrackedShutdownWorkUnbounded(
456
+ ctx: ActorContextHandle,
457
+ ): Promise<void> {
458
+ await asNativeActorContext(ctx).waitForTrackedShutdownWorkUnbounded();
459
+ }
460
+
455
461
  actorKeepAwake(ctx: ActorContextHandle, promise: Promise<unknown>): void {
456
462
  asNativeActorContext(ctx).keepAwake(promise);
457
463
  }
@@ -677,10 +683,15 @@ export class NapiCoreRuntime implements CoreRuntime {
677
683
  ctx: ActorContextHandle,
678
684
  names: string[],
679
685
  options?: RuntimeQueueWaitOptions | undefined | null,
686
+ signal?: CancellationTokenHandle | undefined | null,
680
687
  ): Promise<void> {
681
688
  await asNativeActorContext(ctx)
682
689
  .queue()
683
- .waitForNamesAvailable(names, options);
690
+ .waitForNamesAvailable(
691
+ names,
692
+ options,
693
+ signal ? asNativeCancellationToken(signal) : signal,
694
+ );
684
695
  }
685
696
 
686
697
  async actorQueueEnqueueAndWait(
@@ -1,12 +1,12 @@
1
1
  import { RivetError } from "@/actor/errors";
2
2
  import {
3
+ type EventSchemaConfig,
3
4
  isEventSchemaDefinition,
4
5
  isQueueSchemaDefinition,
5
6
  isStandardSchema,
6
- validateSchemaSync,
7
- type EventSchemaConfig,
8
7
  type PrimitiveSchema,
9
8
  type QueueSchemaConfig,
9
+ validateSchemaSync,
10
10
  } from "@/actor/schema";
11
11
 
12
12
  const CONN_PARAMS_KEY = "__conn_params__";
@@ -126,19 +126,17 @@ export function validateQueueComplete(
126
126
  response,
127
127
  );
128
128
  if (!result.success) {
129
- throw validationError(`queue \`${name}\` completion response`, result.issues);
129
+ throw validationError(
130
+ `queue \`${name}\` completion response`,
131
+ result.issues,
132
+ );
130
133
  }
131
134
  return result.data;
132
135
  }
133
136
 
134
137
  function validationError(target: string, issues: unknown[]): RivetError {
135
- return new RivetError(
136
- "actor",
137
- "validation_error",
138
- `Invalid ${target}`,
139
- {
140
- public: true,
141
- metadata: { issues },
142
- },
143
- );
138
+ return new RivetError("actor", "validation_error", `Invalid ${target}`, {
139
+ public: true,
140
+ metadata: { issues },
141
+ });
144
142
  }
@@ -4,6 +4,7 @@ import {
4
4
  CONN_STATE_MANAGER_SYMBOL,
5
5
  getRunFunction,
6
6
  getRunInspectorConfig,
7
+ RAW_STATE_SYMBOL,
7
8
  type WorkflowInspectorConfig,
8
9
  } from "@/actor/config";
9
10
  import type { AnyActorDefinition } from "@/actor/definition";
@@ -32,6 +33,7 @@ import { convertRegistryConfigToClientConfig } from "@/client/config";
32
33
  import { HEADER_CONN_PARAMS } from "@/common/actor-router-consts";
33
34
  import type { AnyDatabaseProvider } from "@/common/database/config";
34
35
  import { wrapJsNativeDatabase } from "@/common/database/native-database";
36
+ import { assertJsonCompatValue, type JsonCompatValue } from "@/common/encoding";
35
37
  import { decodeWorkflowHistoryTransport } from "@/common/inspector-transport";
36
38
  import { deconstructError, stringifyError } from "@/common/utils";
37
39
  import type {
@@ -47,11 +49,7 @@ import type {
47
49
  RuntimeKind,
48
50
  SqliteBackend,
49
51
  } from "@/registry/config";
50
- import {
51
- decodeCborCompat,
52
- decodeCborJsonCompat,
53
- encodeCborCompat,
54
- } from "@/serde";
52
+ import { decodeCborCompat, encodeCborCompat } from "@/serde";
55
53
  import { getEnvUniversal, VERSION } from "@/utils";
56
54
  import { logger } from "./log";
57
55
  import { loadNapiRuntime } from "./napi-runtime";
@@ -79,6 +77,7 @@ import type {
79
77
  WebSocketHandle,
80
78
  } from "./runtime";
81
79
  import { loadWasmRuntime } from "./wasm-runtime";
80
+ import { createWriteThroughProxy } from "./write-through-proxy";
82
81
 
83
82
  const textEncoder = new TextEncoder();
84
83
  const textDecoder = new TextDecoder();
@@ -345,6 +344,15 @@ function databaseNotConfiguredError(): RivetError {
345
344
  );
346
345
  }
347
346
 
347
+ function databaseClientNotReadyError(): RivetError {
348
+ return new RivetError(
349
+ "actor",
350
+ "database_client_not_ready",
351
+ "actor database client was not initialized before user code ran. this is an internal lifecycle error; the migration callback should have pre-warmed the client. file an issue if you can reproduce.",
352
+ { public: true },
353
+ );
354
+ }
355
+
348
356
  function stateNotEnabledError(): RivetError {
349
357
  return new RivetError(
350
358
  "actor",
@@ -413,8 +421,33 @@ function clearNativeRuntimeState(
413
421
  async function cleanupNativeSleepRuntimeState(
414
422
  runtime: CoreRuntime,
415
423
  ctx: ActorContextHandle,
424
+ afterTrackedWorkDrained?: () => Promise<void>,
416
425
  ): Promise<void> {
417
- await runtime.actorWaitForTrackedShutdownWork(ctx);
426
+ // The bounded wait gives shutdown work one grace-period chance to finish.
427
+ // Drained means all tracked shutdown work completed before the deadline, so
428
+ // we can save final state and clear runtime state immediately. If it did not
429
+ // drain, close database handles now, then defer the final save and clear until
430
+ // the tracked work finishes without a deadline.
431
+ const drained = await runtime.actorWaitForTrackedShutdownWork(ctx);
432
+ if (!drained) {
433
+ await closeNativeDatabaseClient(runtime, ctx);
434
+ await closeNativeSqlDatabase(runtime, ctx);
435
+ void runtime
436
+ .actorWaitForTrackedShutdownWorkUnbounded(ctx)
437
+ .then(async () => {
438
+ await afterTrackedWorkDrained?.();
439
+ clearNativeRuntimeState(runtime, ctx);
440
+ })
441
+ .catch((error) => {
442
+ logger().warn({
443
+ msg: "deferred native sleep cleanup failed",
444
+ error: stringifyError(error),
445
+ });
446
+ });
447
+ return;
448
+ }
449
+
450
+ await afterTrackedWorkDrained?.();
418
451
  await closeNativeDatabaseClient(runtime, ctx);
419
452
  await closeNativeSqlDatabase(runtime, ctx);
420
453
  clearNativeRuntimeState(runtime, ctx);
@@ -587,11 +620,11 @@ function decodeValue<T>(value?: RuntimeBytes | null): T {
587
620
  return undefined as T;
588
621
  }
589
622
 
590
- return decodeCborJsonCompat(value);
623
+ return decodeCborCompat(value);
591
624
  }
592
625
 
593
626
  function encodeValue(value: unknown): RuntimeBytes {
594
- return encodeCborCompat(value);
627
+ return encodeCborCompat(value as JsonCompatValue);
595
628
  }
596
629
 
597
630
  function unwrapTsfnPayload<T>(error: unknown, payload: T): T {
@@ -924,6 +957,7 @@ function serializeWorkflowEntryKind(
924
957
  }
925
958
  }
926
959
 
960
+ // TODO: Switch inspector routes to CBOR encoding
927
961
  function serializeWorkflowHistoryForJson(data: ArrayBuffer | null): {
928
962
  nameRegistry: string[];
929
963
  entries: Array<{
@@ -957,7 +991,7 @@ function serializeWorkflowHistoryForJson(data: ArrayBuffer | null): {
957
991
 
958
992
  const history = decodeWorkflowHistoryTransport(data);
959
993
 
960
- return {
994
+ return jsonSafe({
961
995
  nameRegistry: [...history.nameRegistry],
962
996
  entries: history.entries.map((entry) => ({
963
997
  id: entry.id,
@@ -987,7 +1021,7 @@ function serializeWorkflowHistoryForJson(data: ArrayBuffer | null): {
987
1021
  ],
988
1022
  ),
989
1023
  ),
990
- };
1024
+ });
991
1025
  }
992
1026
 
993
1027
  function toHttpJsonCompatible<T>(value: T): T {
@@ -1066,55 +1100,6 @@ function decodeArgs(value?: RuntimeBytes | null): unknown[] {
1066
1100
  : [decoded];
1067
1101
  }
1068
1102
 
1069
- function createWriteThroughProxy<T>(
1070
- value: T,
1071
- commit: (next: T) => void,
1072
- beforeChange?: () => void,
1073
- ): T {
1074
- if (!value || typeof value !== "object") {
1075
- return value;
1076
- }
1077
-
1078
- const proxies = new WeakMap<object, object>();
1079
- const wrap = (target: object): object => {
1080
- const cached = proxies.get(target);
1081
- if (cached) {
1082
- return cached;
1083
- }
1084
-
1085
- const proxy = new Proxy(target, {
1086
- get(innerTarget, property, receiver) {
1087
- const result = Reflect.get(innerTarget, property, receiver);
1088
- return result && typeof result === "object"
1089
- ? wrap(result as object)
1090
- : result;
1091
- },
1092
- set(innerTarget, property, nextValue, receiver) {
1093
- beforeChange?.();
1094
- const updated = Reflect.set(
1095
- innerTarget,
1096
- property,
1097
- nextValue,
1098
- receiver,
1099
- );
1100
- commit(value);
1101
- return updated;
1102
- },
1103
- deleteProperty(innerTarget, property) {
1104
- beforeChange?.();
1105
- const updated = Reflect.deleteProperty(innerTarget, property);
1106
- commit(value);
1107
- return updated;
1108
- },
1109
- });
1110
-
1111
- proxies.set(target, proxy);
1112
- return proxy;
1113
- };
1114
-
1115
- return wrap(value as object) as T;
1116
- }
1117
-
1118
1103
  function buildRequest(init: {
1119
1104
  method: string;
1120
1105
  uri: string;
@@ -1204,14 +1189,25 @@ class NativeConnAdapter {
1204
1189
  );
1205
1190
  }
1206
1191
 
1192
+ [RAW_STATE_SYMBOL](): unknown {
1193
+ return this.#readState();
1194
+ }
1195
+
1207
1196
  get state(): unknown {
1208
1197
  const nextState = this.#readState();
1209
- return createWriteThroughProxy(nextState, (nextValue) => {
1210
- this.#writeState(nextValue, { writeNative: true });
1211
- });
1198
+ return createWriteThroughProxy(
1199
+ nextState,
1200
+ (nextValue) => {
1201
+ this.#writeState(nextValue, { writeNative: true });
1202
+ },
1203
+ (newValue) => {
1204
+ assertJsonCompatValue(newValue);
1205
+ },
1206
+ );
1212
1207
  }
1213
1208
 
1214
1209
  set state(value: unknown) {
1210
+ assertJsonCompatValue(value);
1215
1211
  this.#writeState(value, { writeNative: true });
1216
1212
  }
1217
1213
 
@@ -1683,7 +1679,12 @@ class NativeQueueAdapter {
1683
1679
  signal?: AbortSignal;
1684
1680
  },
1685
1681
  ) {
1686
- if (!options?.signal) {
1682
+ const { token, cleanup } = await createCancellationTokenHandle(
1683
+ this.#runtime,
1684
+ options?.signal,
1685
+ );
1686
+
1687
+ try {
1687
1688
  await callNative(() =>
1688
1689
  this.#runtime.actorQueueWaitForNamesAvailable(
1689
1690
  this.#ctx,
@@ -1691,57 +1692,11 @@ class NativeQueueAdapter {
1691
1692
  {
1692
1693
  timeoutMs: options?.timeout,
1693
1694
  },
1695
+ token,
1694
1696
  ),
1695
1697
  );
1696
- return;
1697
- }
1698
-
1699
- const deadline =
1700
- options.timeout === undefined
1701
- ? undefined
1702
- : Date.now() + options.timeout;
1703
-
1704
- for (;;) {
1705
- if (options.signal.aborted) {
1706
- throw actorAbortedError();
1707
- }
1708
-
1709
- const remainingTimeout =
1710
- deadline === undefined
1711
- ? undefined
1712
- : Math.max(0, deadline - Date.now());
1713
- const sliceTimeout =
1714
- remainingTimeout === undefined
1715
- ? 100
1716
- : Math.min(remainingTimeout, 100);
1717
-
1718
- try {
1719
- await callNative(() =>
1720
- this.#runtime.actorQueueWaitForNamesAvailable(
1721
- this.#ctx,
1722
- [...names],
1723
- {
1724
- timeoutMs: sliceTimeout,
1725
- },
1726
- ),
1727
- );
1728
- return;
1729
- } catch (error) {
1730
- if (
1731
- (error as { group?: string; code?: string }).group ===
1732
- "queue" &&
1733
- (error as { group?: string; code?: string }).code ===
1734
- "timed_out"
1735
- ) {
1736
- if (
1737
- remainingTimeout === undefined ||
1738
- remainingTimeout > 100
1739
- ) {
1740
- continue;
1741
- }
1742
- }
1743
- throw error;
1744
- }
1698
+ } finally {
1699
+ cleanup?.();
1745
1700
  }
1746
1701
  }
1747
1702
 
@@ -2323,6 +2278,104 @@ class TrackedWebSocketHandleAdapter implements UniversalWebSocket {
2323
2278
  }
2324
2279
  }
2325
2280
 
2281
+ class NativeConnectionMap implements ReadonlyMap<string, NativeConnAdapter> {
2282
+ #runtime: CoreRuntime;
2283
+ #ctx: ActorContextHandle;
2284
+ #schemas: NativeValidationConfig;
2285
+
2286
+ constructor(
2287
+ runtime: CoreRuntime,
2288
+ ctx: ActorContextHandle,
2289
+ schemas: NativeValidationConfig,
2290
+ ) {
2291
+ this.#runtime = runtime;
2292
+ this.#ctx = ctx;
2293
+ this.#schemas = schemas;
2294
+ }
2295
+
2296
+ #connToAdapter(conn: ConnHandle): NativeConnAdapter {
2297
+ return new NativeConnAdapter(
2298
+ this.#runtime,
2299
+ conn,
2300
+ this.#schemas,
2301
+ this.#ctx,
2302
+ (connId) =>
2303
+ callNativeSync(() =>
2304
+ this.#runtime.actorQueueHibernationRemoval(
2305
+ this.#ctx,
2306
+ connId,
2307
+ ),
2308
+ ),
2309
+ );
2310
+ }
2311
+
2312
+ get size(): number {
2313
+ return callNativeSync(() => this.#runtime.actorConns(this.#ctx)).length;
2314
+ }
2315
+
2316
+ get(key: string): NativeConnAdapter | undefined {
2317
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
2318
+ const conn = conns.find((c) => this.#runtime.connId(c) === key);
2319
+ if (!conn) return undefined;
2320
+ return this.#connToAdapter(conn);
2321
+ }
2322
+
2323
+ has(key: string): boolean {
2324
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
2325
+ return conns.some((c) => this.#runtime.connId(c) === key);
2326
+ }
2327
+
2328
+ keys(): MapIterator<string> {
2329
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
2330
+ return conns
2331
+ .map((c) => this.#runtime.connId(c))
2332
+ [Symbol.iterator]() satisfies MapIterator<string>;
2333
+ }
2334
+
2335
+ values(): MapIterator<NativeConnAdapter> {
2336
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
2337
+ return conns
2338
+ .map((c) => this.#connToAdapter(c))
2339
+ [Symbol.iterator]() satisfies MapIterator<NativeConnAdapter>;
2340
+ }
2341
+
2342
+ entries(): MapIterator<[string, NativeConnAdapter]> {
2343
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
2344
+ return conns
2345
+ .map(
2346
+ (c) =>
2347
+ [this.#runtime.connId(c), this.#connToAdapter(c)] as [
2348
+ string,
2349
+ NativeConnAdapter,
2350
+ ],
2351
+ )
2352
+ [Symbol.iterator]() satisfies MapIterator<
2353
+ [string, NativeConnAdapter]
2354
+ >;
2355
+ }
2356
+
2357
+ forEach(
2358
+ callback: (
2359
+ value: NativeConnAdapter,
2360
+ key: string,
2361
+ map: ReadonlyMap<string, NativeConnAdapter>,
2362
+ ) => void,
2363
+ thisArg?: unknown,
2364
+ ): void {
2365
+ const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
2366
+ for (const conn of conns) {
2367
+ const id = this.#runtime.connId(conn);
2368
+ callback.call(thisArg, this.#connToAdapter(conn), id, this);
2369
+ }
2370
+ }
2371
+
2372
+ [Symbol.iterator](): MapIterator<[string, NativeConnAdapter]> {
2373
+ return this.entries();
2374
+ }
2375
+
2376
+ readonly [Symbol.toStringTag] = "NativeConnectionMap";
2377
+ }
2378
+
2326
2379
  export class ActorContextHandleAdapter {
2327
2380
  #runtime: CoreRuntime;
2328
2381
  #ctx: ActorContextHandle;
@@ -2331,9 +2384,9 @@ export class ActorContextHandleAdapter {
2331
2384
  #abortSignalCleanup?: () => void;
2332
2385
  #client?: AnyClient;
2333
2386
  #clientFactory?: () => AnyClient;
2387
+ #connMap?: NativeConnectionMap;
2334
2388
  #databaseProvider?: Exclude<AnyDatabaseProvider, undefined>;
2335
2389
  #db?: unknown;
2336
- #dbProxy?: unknown;
2337
2390
  #dispatchCancelToken?: CancellationTokenHandle;
2338
2391
  #kv?: NativeKvAdapter;
2339
2392
  #queue?: NativeQueueAdapter;
@@ -2396,32 +2449,25 @@ export class ActorContextHandleAdapter {
2396
2449
  throw databaseNotConfiguredError();
2397
2450
  }
2398
2451
 
2399
- if (!this.#dbProxy) {
2400
- this.#dbProxy = new Proxy(
2401
- {},
2402
- {
2403
- get: (_target, property) => {
2404
- if (property === "then") {
2405
- return undefined;
2406
- }
2452
+ if (this.#db) {
2453
+ return this.#db;
2454
+ }
2407
2455
 
2408
- return async (...args: Array<unknown>) => {
2409
- const client = await this.ensureDatabaseClient();
2410
- const value = Reflect.get(
2411
- client as object,
2412
- property,
2413
- );
2414
- if (typeof value !== "function") {
2415
- return value;
2416
- }
2417
- return await value.apply(client, args);
2418
- };
2419
- },
2420
- },
2421
- );
2456
+ const runtimeState = getNativeRuntimeState(this.#runtime, this.#ctx);
2457
+ const cachedClient = runtimeState.databaseClient;
2458
+ if (cachedClient) {
2459
+ this.#db = cachedClient.client;
2460
+ return this.#db;
2422
2461
  }
2423
2462
 
2424
- return this.#dbProxy;
2463
+ throw databaseClientNotReadyError();
2464
+ }
2465
+
2466
+ [RAW_STATE_SYMBOL](): unknown {
2467
+ if (!this.#stateEnabled) {
2468
+ throw stateNotEnabledError();
2469
+ }
2470
+ return this.#readState();
2425
2471
  }
2426
2472
 
2427
2473
  get state(): unknown {
@@ -2444,8 +2490,9 @@ export class ActorContextHandleAdapter {
2444
2490
  (nextValue) => {
2445
2491
  this.#writeState(nextValue, { scheduleSave: true });
2446
2492
  },
2447
- () => {
2493
+ (newValue) => {
2448
2494
  this.#assertCanMutateState();
2495
+ assertJsonCompatValue(newValue);
2449
2496
  },
2450
2497
  );
2451
2498
  }
@@ -2457,6 +2504,7 @@ export class ActorContextHandleAdapter {
2457
2504
  throw stateNotEnabledError();
2458
2505
  }
2459
2506
  this.#assertCanMutateState();
2507
+ assertJsonCompatValue(value);
2460
2508
  this.#writeState(value, { scheduleSave: true });
2461
2509
  }
2462
2510
 
@@ -2523,27 +2571,15 @@ export class ActorContextHandleAdapter {
2523
2571
  return callNativeSync(() => this.#runtime.actorRegion(this.#ctx));
2524
2572
  }
2525
2573
 
2526
- get conns(): Map<string, NativeConnAdapter> {
2527
- return new Map(
2528
- callNativeSync(() => this.#runtime.actorConns(this.#ctx)).map(
2529
- (conn) => [
2530
- this.#runtime.connId(conn),
2531
- new NativeConnAdapter(
2532
- this.#runtime,
2533
- conn,
2534
- this.#schemas,
2535
- this.#ctx,
2536
- (connId) =>
2537
- callNativeSync(() =>
2538
- this.#runtime.actorQueueHibernationRemoval(
2539
- this.#ctx,
2540
- connId,
2541
- ),
2542
- ),
2543
- ),
2544
- ],
2545
- ),
2546
- );
2574
+ get conns(): ReadonlyMap<string, NativeConnAdapter> {
2575
+ if (!this.#connMap) {
2576
+ this.#connMap = new NativeConnectionMap(
2577
+ this.#runtime,
2578
+ this.#ctx,
2579
+ this.#schemas,
2580
+ );
2581
+ }
2582
+ return this.#connMap;
2547
2583
  }
2548
2584
 
2549
2585
  get log() {
@@ -2862,6 +2898,7 @@ export class ActorContextHandleAdapter {
2862
2898
  }
2863
2899
 
2864
2900
  sleep(): void {
2901
+ this.#flushStateChange();
2865
2902
  callNativeSync(() => this.#runtime.actorSleep(this.#ctx));
2866
2903
  }
2867
2904
 
@@ -3548,6 +3585,10 @@ export function buildNativeFactory(
3548
3585
  getNativeWorkflowInspector(ctx) !== undefined,
3549
3586
  });
3550
3587
  } catch (error) {
3588
+ logger().error({
3589
+ msg: "error replaying workflow history",
3590
+ error,
3591
+ });
3551
3592
  return errorResponse(error);
3552
3593
  }
3553
3594
  }
@@ -3727,6 +3768,10 @@ export function buildNativeFactory(
3727
3768
  );
3728
3769
  return jsonResponse({ output });
3729
3770
  } catch (error) {
3771
+ logger().error({
3772
+ msg: "Error handling inspector action request",
3773
+ error,
3774
+ });
3730
3775
  return errorResponse(error);
3731
3776
  }
3732
3777
  }
@@ -3741,6 +3786,10 @@ export function buildNativeFactory(
3741
3786
  { status: 404 },
3742
3787
  );
3743
3788
  } catch (error) {
3789
+ logger().error({
3790
+ msg: "Error handling inspector request",
3791
+ error,
3792
+ });
3744
3793
  return errorResponse(error);
3745
3794
  } finally {
3746
3795
  await actorCtx.dispose();
@@ -3913,26 +3962,35 @@ export function buildNativeFactory(
3913
3962
  async (error: unknown, payload: { ctx: ActorContextHandle }) => {
3914
3963
  const { ctx } = unwrapTsfnPayload(error, payload);
3915
3964
  const actorCtx = makeActorCtx(ctx);
3965
+ // TODO: Move this save hook into cleanupNativeSleepRuntimeState
3966
+ // so immediate and deferred sleep cleanup share one save-state
3967
+ // path instead of passing a callback through cleanup.
3968
+ const saveActorState = async () => {
3969
+ if (runtime.kind === "wasm") {
3970
+ // Wasm cannot use the native context save helper here because
3971
+ // the runtime owns the serialized state handoff.
3972
+ await runtime.actorSaveState(
3973
+ ctx,
3974
+ actorCtx.serializeForTick("save"),
3975
+ );
3976
+ } else {
3977
+ await actorCtx.saveState({
3978
+ immediate: true,
3979
+ });
3980
+ }
3981
+ };
3916
3982
  try {
3917
3983
  if (onSleep) {
3918
- try {
3919
- await onSleep(actorCtx);
3920
- } finally {
3921
- if (runtime.kind === "wasm") {
3922
- // Wasm cannot use the native context save helper here because
3923
- // the runtime owns the serialized state handoff.
3924
- await runtime.actorSaveState(
3925
- ctx,
3926
- actorCtx.serializeForTick("save"),
3927
- );
3928
- } else {
3929
- await actorCtx.saveState({ immediate: true });
3930
- }
3931
- }
3984
+ await onSleep(actorCtx);
3932
3985
  }
3986
+ await saveActorState();
3933
3987
  } finally {
3934
3988
  try {
3935
- await cleanupNativeSleepRuntimeState(runtime, ctx);
3989
+ await cleanupNativeSleepRuntimeState(
3990
+ runtime,
3991
+ ctx,
3992
+ saveActorState,
3993
+ );
3936
3994
  } finally {
3937
3995
  await actorCtx.dispose();
3938
3996
  }