rivetkit 2.3.18 → 2.3.19

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 (136) hide show
  1. package/dist/browser/client.d.ts +723 -616
  2. package/dist/browser/client.js +184 -28
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +3 -1
  5. package/dist/browser/inspector/client.js.map +1 -1
  6. package/dist/tsup/actor/errors.cjs +6 -2
  7. package/dist/tsup/actor/errors.cjs.map +1 -1
  8. package/dist/tsup/actor/errors.d.cts +1 -1
  9. package/dist/tsup/actor/errors.d.ts +1 -1
  10. package/dist/tsup/actor/errors.js +5 -1
  11. package/dist/tsup/agent-os/index.cjs +3 -1
  12. package/dist/tsup/agent-os/index.cjs.map +1 -1
  13. package/dist/tsup/agent-os/index.d.cts +110 -3
  14. package/dist/tsup/agent-os/index.d.ts +110 -3
  15. package/dist/tsup/agent-os/index.js +3 -1
  16. package/dist/tsup/agent-os/index.js.map +1 -1
  17. package/dist/tsup/{chunk-4XECVATQ.js → chunk-464WE4RF.js} +2 -2
  18. package/dist/tsup/{chunk-QIFZELUQ.js → chunk-4SC2NSAV.js} +2 -2
  19. package/dist/tsup/{chunk-ZRTESY7V.cjs → chunk-7A5EIXJJ.cjs} +7 -7
  20. package/dist/tsup/{chunk-ZRTESY7V.cjs.map → chunk-7A5EIXJJ.cjs.map} +1 -1
  21. package/dist/tsup/{chunk-O7RSU3UC.cjs → chunk-7BRRGBRY.cjs} +10 -10
  22. package/dist/tsup/{chunk-O7RSU3UC.cjs.map → chunk-7BRRGBRY.cjs.map} +1 -1
  23. package/dist/tsup/{chunk-IPXIZSE7.js → chunk-7HTST3NX.js} +3 -3
  24. package/dist/tsup/{chunk-PXKNBNVU.js → chunk-BKX7UDTA.js} +188 -31
  25. package/dist/tsup/chunk-BKX7UDTA.js.map +1 -0
  26. package/dist/tsup/{chunk-2MK75JFR.js → chunk-DK3L22R6.js} +4 -4
  27. package/dist/tsup/{chunk-7EPLADKM.js → chunk-DN6MD3KK.js} +7 -7
  28. package/dist/tsup/chunk-DN6MD3KK.js.map +1 -0
  29. package/dist/tsup/{chunk-6W5VGLFT.js → chunk-EB77NZL4.js} +1 -1
  30. package/dist/tsup/chunk-EB77NZL4.js.map +1 -0
  31. package/dist/tsup/{chunk-4KGXFC6M.cjs → chunk-EO5UOXXY.cjs} +1 -1
  32. package/dist/tsup/chunk-EO5UOXXY.cjs.map +1 -0
  33. package/dist/tsup/{chunk-25Z2RK7C.cjs → chunk-G4U5L6AX.cjs} +3 -3
  34. package/dist/tsup/{chunk-25Z2RK7C.cjs.map → chunk-G4U5L6AX.cjs.map} +1 -1
  35. package/dist/tsup/{chunk-NRIRV3Z2.cjs → chunk-IJUXBWH4.cjs} +352 -195
  36. package/dist/tsup/chunk-IJUXBWH4.cjs.map +1 -0
  37. package/dist/tsup/{chunk-2JSYYH6P.cjs → chunk-JX2ITWAV.cjs} +13 -2
  38. package/dist/tsup/chunk-JX2ITWAV.cjs.map +1 -0
  39. package/dist/tsup/{chunk-OKVVWOC3.cjs → chunk-OGPFN6BT.cjs} +3 -3
  40. package/dist/tsup/{chunk-OKVVWOC3.cjs.map → chunk-OGPFN6BT.cjs.map} +1 -1
  41. package/dist/tsup/{chunk-OUQUIBVW.js → chunk-P2OFXH4G.js} +12 -1
  42. package/dist/tsup/chunk-P2OFXH4G.js.map +1 -0
  43. package/dist/tsup/{chunk-IKZ6DJMP.cjs → chunk-PPEIPCW4.cjs} +4 -4
  44. package/dist/tsup/{chunk-IKZ6DJMP.cjs.map → chunk-PPEIPCW4.cjs.map} +1 -1
  45. package/dist/tsup/{chunk-2IDK6NX3.cjs → chunk-RJC5O2SD.cjs} +13 -13
  46. package/dist/tsup/chunk-RJC5O2SD.cjs.map +1 -0
  47. package/dist/tsup/{chunk-TNSLNSQH.js → chunk-WME6KOXW.js} +2 -2
  48. package/dist/tsup/{chunk-LAITPJRA.js → chunk-X7RMJQGY.js} +2 -2
  49. package/dist/tsup/{chunk-T6JUXRNI.cjs → chunk-Z4RAXFSD.cjs} +3 -3
  50. package/dist/tsup/{chunk-T6JUXRNI.cjs.map → chunk-Z4RAXFSD.cjs.map} +1 -1
  51. package/dist/tsup/client/mod.cjs +6 -6
  52. package/dist/tsup/client/mod.d.cts +5 -5
  53. package/dist/tsup/client/mod.d.ts +5 -5
  54. package/dist/tsup/client/mod.js +5 -5
  55. package/dist/tsup/common/log.cjs +3 -3
  56. package/dist/tsup/common/log.js +2 -2
  57. package/dist/tsup/common/websocket.cjs +4 -4
  58. package/dist/tsup/common/websocket.js +3 -3
  59. package/dist/tsup/{config-gvHwMas-.d.cts → config-8n2AOhXK.d.cts} +114 -10
  60. package/dist/tsup/{config-Ug5M2MOr.d.ts → config-DEm0yIVV.d.ts} +114 -10
  61. package/dist/tsup/{context-DererUCI.d.ts → context-DGg2-IOm.d.ts} +1 -1
  62. package/dist/tsup/{context-BSCBvbfM.d.cts → context-DwjOVvlE.d.cts} +1 -1
  63. package/dist/tsup/db/drizzle.cjs +3 -3
  64. package/dist/tsup/db/drizzle.js +2 -2
  65. package/dist/tsup/db/mod.cjs +4 -4
  66. package/dist/tsup/db/mod.js +3 -3
  67. package/dist/tsup/dynamic/mod.cjs +2 -2
  68. package/dist/tsup/dynamic/mod.d.cts +3 -3
  69. package/dist/tsup/dynamic/mod.d.ts +3 -3
  70. package/dist/tsup/dynamic/mod.js +1 -1
  71. package/dist/tsup/inspector/mod.cjs +6 -6
  72. package/dist/tsup/inspector/mod.js +5 -5
  73. package/dist/tsup/inspector/workflow.cjs +5 -5
  74. package/dist/tsup/inspector/workflow.js +4 -4
  75. package/dist/tsup/inspector-tab/mod.cjs +2 -2
  76. package/dist/tsup/inspector-tab/mod.d.cts +4 -4
  77. package/dist/tsup/inspector-tab/mod.d.ts +4 -4
  78. package/dist/tsup/inspector-tab/mod.js +1 -1
  79. package/dist/tsup/mod.cjs +492 -319
  80. package/dist/tsup/mod.cjs.map +1 -1
  81. package/dist/tsup/mod.d.cts +5 -5
  82. package/dist/tsup/mod.d.ts +5 -5
  83. package/dist/tsup/mod.js +367 -194
  84. package/dist/tsup/mod.js.map +1 -1
  85. package/dist/tsup/test/mod.cjs +7 -7
  86. package/dist/tsup/test/mod.d.cts +3 -3
  87. package/dist/tsup/test/mod.d.ts +3 -3
  88. package/dist/tsup/test/mod.js +5 -5
  89. package/dist/tsup/{utils-Bbz-3411.d.cts → utils-CNFeS-Dk.d.cts} +1 -1
  90. package/dist/tsup/{utils-vvJQyygr.d.ts → utils-DsoDinPz.d.cts} +9 -1
  91. package/dist/tsup/{utils-vvJQyygr.d.cts → utils-DsoDinPz.d.ts} +9 -1
  92. package/dist/tsup/{utils-BqdWVlzm.d.ts → utils-OQHBjfcM.d.ts} +1 -1
  93. package/dist/tsup/utils.cjs +3 -3
  94. package/dist/tsup/utils.d.cts +2 -2
  95. package/dist/tsup/utils.d.ts +2 -2
  96. package/dist/tsup/utils.js +2 -2
  97. package/dist/tsup/workflow/mod.cjs +33 -27
  98. package/dist/tsup/workflow/mod.cjs.map +1 -1
  99. package/dist/tsup/workflow/mod.d.cts +5 -5
  100. package/dist/tsup/workflow/mod.d.ts +5 -5
  101. package/dist/tsup/workflow/mod.js +25 -19
  102. package/dist/tsup/workflow/mod.js.map +1 -1
  103. package/package.json +10 -8
  104. package/src/actor/config.ts +38 -0
  105. package/src/actor/errors.ts +31 -0
  106. package/src/client/actor-conn.ts +7 -0
  107. package/src/client/actor-handle.ts +57 -17
  108. package/src/client/client.ts +26 -6
  109. package/src/client/outbound-telemetry.ts +66 -0
  110. package/src/client/queue.ts +3 -0
  111. package/src/client/raw-utils.ts +3 -0
  112. package/src/common/actor-router-consts.ts +3 -0
  113. package/src/common/actor-telemetry-context.ts +19 -0
  114. package/src/common/otel-context.ts +99 -0
  115. package/src/common/utils.ts +1 -19
  116. package/src/engine-client/actor-http-client.ts +15 -0
  117. package/src/registry/index.ts +6 -0
  118. package/src/registry/napi-runtime.ts +155 -35
  119. package/src/registry/native.ts +277 -191
  120. package/src/registry/runtime.ts +66 -0
  121. package/src/registry/wasm-runtime.ts +40 -0
  122. package/src/workflow/driver.ts +20 -12
  123. package/dist/tsup/chunk-2IDK6NX3.cjs.map +0 -1
  124. package/dist/tsup/chunk-2JSYYH6P.cjs.map +0 -1
  125. package/dist/tsup/chunk-4KGXFC6M.cjs.map +0 -1
  126. package/dist/tsup/chunk-6W5VGLFT.js.map +0 -1
  127. package/dist/tsup/chunk-7EPLADKM.js.map +0 -1
  128. package/dist/tsup/chunk-NRIRV3Z2.cjs.map +0 -1
  129. package/dist/tsup/chunk-OUQUIBVW.js.map +0 -1
  130. package/dist/tsup/chunk-PXKNBNVU.js.map +0 -1
  131. /package/dist/tsup/{chunk-4XECVATQ.js.map → chunk-464WE4RF.js.map} +0 -0
  132. /package/dist/tsup/{chunk-QIFZELUQ.js.map → chunk-4SC2NSAV.js.map} +0 -0
  133. /package/dist/tsup/{chunk-IPXIZSE7.js.map → chunk-7HTST3NX.js.map} +0 -0
  134. /package/dist/tsup/{chunk-2MK75JFR.js.map → chunk-DK3L22R6.js.map} +0 -0
  135. /package/dist/tsup/{chunk-TNSLNSQH.js.map → chunk-WME6KOXW.js.map} +0 -0
  136. /package/dist/tsup/{chunk-LAITPJRA.js.map → chunk-X7RMJQGY.js.map} +0 -0
@@ -8,6 +8,8 @@ import {
8
8
  type ActorCron,
9
9
  type ActorCronEveryOptions,
10
10
  type ActorCronSetOptions,
11
+ type ActorLogger,
12
+ type ActorRun,
11
13
  type ActorSchedule,
12
14
  CONN_STATE_MANAGER_SYMBOL,
13
15
  type CronFire,
@@ -46,6 +48,7 @@ import {
46
48
  } from "@/client/client";
47
49
  import { convertRegistryConfigToClientConfig } from "@/client/config";
48
50
  import { HEADER_CONN_PARAMS } from "@/common/actor-router-consts";
51
+ import type { ActorInvocationTraceContext } from "@/common/actor-telemetry-context";
49
52
  import type {
50
53
  AnyDatabaseProvider,
51
54
  SqliteProfilingOptions,
@@ -2706,6 +2709,9 @@ class NativeConnectionMap implements ReadonlyMap<string, NativeConnAdapter> {
2706
2709
  readonly [Symbol.toStringTag] = "NativeConnectionMap";
2707
2710
  }
2708
2711
 
2712
+ /** Logger cache key for code that runs outside any invocation. */
2713
+ const NO_INVOCATION_SCOPE = {};
2714
+
2709
2715
  export class ActorContextHandleAdapter {
2710
2716
  #runtime: CoreRuntime;
2711
2717
  #ctx: ActorContextHandle;
@@ -2720,10 +2726,11 @@ export class ActorContextHandleAdapter {
2720
2726
  #db?: unknown;
2721
2727
  #dispatchCancelToken?: CancellationTokenHandle;
2722
2728
  #kv?: NativeKvAdapter;
2729
+ #logByInvocationScope = new WeakMap<object, ActorLogger>();
2723
2730
  #queue?: NativeQueueAdapter;
2724
2731
  #request?: Request;
2725
2732
  #schedule?: NativeScheduleAdapter;
2726
- #run?: { setWakeAt(timestamp: number | null): Promise<void> };
2733
+ #run?: ActorRun;
2727
2734
  #runHandlerConfigured: boolean;
2728
2735
  #onStateChange?: NativeOnStateChangeHandler;
2729
2736
  #stateEnabled: boolean;
@@ -2904,6 +2911,12 @@ export class ActorContextHandleAdapter {
2904
2911
  this.#runtime.actorSetRunWakeAt(this.#ctx, timestamp),
2905
2912
  );
2906
2913
  },
2914
+ startWorkflowSpan: () =>
2915
+ callNative(() =>
2916
+ this.#runtime.startWorkflowSpan(this.#ctx),
2917
+ ),
2918
+ runOutsideWorkflowSpan: (body) =>
2919
+ this.#runtime.runOutsideActorInvocationContext(body),
2907
2920
  };
2908
2921
  }
2909
2922
  return this.#run;
@@ -2956,8 +2969,32 @@ export class ActorContextHandleAdapter {
2956
2969
  return this.#connMap;
2957
2970
  }
2958
2971
 
2972
+ #invocationTraceContext(): ActorInvocationTraceContext | undefined {
2973
+ return callNativeSync(() =>
2974
+ this.#runtime.actorInvocationTraceContext(this.#ctx),
2975
+ );
2976
+ }
2977
+
2978
+ /** Cached per invocation, because the `run` context outlives workflow runs and steps. */
2959
2979
  get log() {
2960
- return logger();
2980
+ const scope =
2981
+ this.#runtime.currentInvocationScope() ?? NO_INVOCATION_SCOPE;
2982
+ const cached = this.#logByInvocationScope.get(scope);
2983
+ if (cached) return cached;
2984
+
2985
+ const invocation = this.#invocationTraceContext();
2986
+ const log = logger().child({
2987
+ actorId: this.actorId,
2988
+ actorName: this.name,
2989
+ actorKey: this.key,
2990
+ ...(invocation?.rayId && { rayId: invocation.rayId }),
2991
+ ...(invocation?.span && {
2992
+ traceId: invocation.span.traceId,
2993
+ spanId: invocation.span.spanId,
2994
+ }),
2995
+ });
2996
+ this.#logByInvocationScope.set(scope, log);
2997
+ return log;
2961
2998
  }
2962
2999
 
2963
3000
  get abortSignal(): AbortSignal {
@@ -3995,12 +4032,22 @@ export function buildNativeFactory(
3995
4032
  events: config.events,
3996
4033
  queues: config.queues,
3997
4034
  };
3998
- const createClient = () =>
4035
+ const createClient = (ctx: ActorContextHandle) =>
3999
4036
  createClientWithDriver(
4000
4037
  new RemoteEngineControlClient(
4001
4038
  convertRegistryConfigToClientConfig(registryConfig),
4002
4039
  ),
4003
- { encoding: "bare" },
4040
+ {
4041
+ encoding: "bare",
4042
+ currentActorInvocation: () =>
4043
+ callNativeSync(() =>
4044
+ runtime.actorInvocationTraceContext(ctx),
4045
+ ),
4046
+ startCallSpan: (actorName, actionName) =>
4047
+ callNativeSync(() =>
4048
+ runtime.startCallSpan(ctx, actorName, actionName),
4049
+ ),
4050
+ },
4004
4051
  );
4005
4052
  const run = getRunFunction(config.run);
4006
4053
  const runHandlerCoordinator =
@@ -4044,7 +4091,7 @@ export function buildNativeFactory(
4044
4091
  new ActorContextHandleAdapter(
4045
4092
  runtime,
4046
4093
  ctx,
4047
- createClient,
4094
+ () => createClient(ctx),
4048
4095
  schemaConfig,
4049
4096
  databaseProvider,
4050
4097
  request,
@@ -4063,7 +4110,7 @@ export function buildNativeFactory(
4063
4110
  runtime,
4064
4111
  ctx,
4065
4112
  conn,
4066
- createClient,
4113
+ () => createClient(ctx),
4067
4114
  schemaConfig,
4068
4115
  databaseProvider,
4069
4116
  request,
@@ -5041,129 +5088,147 @@ export function buildNativeFactory(
5041
5088
  try {
5042
5089
  const { ctx, request, cancelToken, responseBodyStream } =
5043
5090
  unwrapTsfnPayload(error, payload);
5044
- const inspectorResponse =
5045
- await maybeHandleNativeInspectorRequest(ctx, request);
5046
- if (inspectorResponse) {
5047
- await cancelNativeHttpRequestBody(request.bodyStream);
5048
- return (
5049
- await convertNativeHttpResponse(
5050
- inspectorResponse,
5051
- responseBodyStream,
5052
- )
5053
- ).response;
5054
- }
5055
-
5056
- if (typeof config.onRequest !== "function") {
5057
- await cancelNativeHttpRequestBody(request.bodyStream);
5058
- return (
5059
- await convertNativeHttpResponse(
5060
- new Response(null, { status: 404 }),
5061
- responseBodyStream,
5062
- )
5063
- ).response;
5064
- }
5091
+ return await runtime.runWithActorInvocationContext(
5092
+ ctx,
5093
+ async () => {
5094
+ const inspectorResponse =
5095
+ await maybeHandleNativeInspectorRequest(
5096
+ ctx,
5097
+ request,
5098
+ );
5099
+ if (inspectorResponse) {
5100
+ await cancelNativeHttpRequestBody(
5101
+ request.bodyStream,
5102
+ );
5103
+ return (
5104
+ await convertNativeHttpResponse(
5105
+ inspectorResponse,
5106
+ responseBodyStream,
5107
+ )
5108
+ ).response;
5109
+ }
5065
5110
 
5066
- const requestAbortController = new AbortController();
5067
- const handlerRequest = buildNativeHttpRequest({
5068
- ...request,
5069
- abortController: requestAbortController,
5070
- });
5071
- const rawConnParams =
5072
- handlerRequest.headers.get(HEADER_CONN_PARAMS);
5073
- let requestCtx:
5074
- | ReturnType<typeof withConnContext>
5075
- | undefined;
5076
- let conn: ConnHandle | undefined;
5077
- let removeRequestAbortListener: (() => void) | undefined;
5078
- let cleanupDeferredToBody = false;
5079
- let cleanedUp = false;
5080
- const cleanupRequest = async () => {
5081
- if (cleanedUp) return;
5082
- cleanedUp = true;
5083
- removeRequestAbortListener?.();
5084
- try {
5085
- await requestCtx?.dispose();
5086
- } finally {
5087
- if (conn) {
5088
- await runtime.connDisconnect(conn);
5111
+ if (typeof config.onRequest !== "function") {
5112
+ await cancelNativeHttpRequestBody(
5113
+ request.bodyStream,
5114
+ );
5115
+ return (
5116
+ await convertNativeHttpResponse(
5117
+ new Response(null, { status: 404 }),
5118
+ responseBodyStream,
5119
+ )
5120
+ ).response;
5089
5121
  }
5090
- }
5091
- };
5092
- try {
5093
- const connParams = validateConnParams(
5094
- schemaConfig.connParamsSchema,
5095
- rawConnParams
5096
- ? JSON.parse(rawConnParams)
5097
- : undefined,
5098
- );
5099
- conn = await callNative(() =>
5100
- runtime.actorConnectConn(
5101
- ctx,
5102
- encodeValue(connParams),
5103
- request,
5104
- ),
5105
- );
5106
- requestCtx = makeConnCtx(
5107
- ctx,
5108
- conn,
5109
- handlerRequest,
5110
- cancelToken,
5111
- );
5112
- const ctxAbortSignal = requestCtx.abortSignal;
5113
- const abortRequest = () =>
5114
- requestAbortController.abort(ctxAbortSignal.reason);
5115
- if (ctxAbortSignal.aborted) {
5116
- abortRequest();
5117
- } else {
5118
- ctxAbortSignal.addEventListener(
5119
- "abort",
5120
- abortRequest,
5121
- { once: true },
5122
- );
5123
- removeRequestAbortListener = () =>
5124
- ctxAbortSignal.removeEventListener(
5125
- "abort",
5126
- abortRequest,
5122
+
5123
+ const requestAbortController =
5124
+ new AbortController();
5125
+ const handlerRequest = buildNativeHttpRequest({
5126
+ ...request,
5127
+ abortController: requestAbortController,
5128
+ });
5129
+ const rawConnParams =
5130
+ handlerRequest.headers.get(HEADER_CONN_PARAMS);
5131
+ let requestCtx:
5132
+ | ReturnType<typeof withConnContext>
5133
+ | undefined;
5134
+ let conn: ConnHandle | undefined;
5135
+ let removeRequestAbortListener:
5136
+ | (() => void)
5137
+ | undefined;
5138
+ let cleanupDeferredToBody = false;
5139
+ let cleanedUp = false;
5140
+ const cleanupRequest = async () => {
5141
+ if (cleanedUp) return;
5142
+ cleanedUp = true;
5143
+ removeRequestAbortListener?.();
5144
+ try {
5145
+ await requestCtx?.dispose();
5146
+ } finally {
5147
+ if (conn) {
5148
+ await runtime.connDisconnect(conn);
5149
+ }
5150
+ }
5151
+ };
5152
+ try {
5153
+ const connParams = validateConnParams(
5154
+ schemaConfig.connParamsSchema,
5155
+ rawConnParams
5156
+ ? JSON.parse(rawConnParams)
5157
+ : undefined,
5127
5158
  );
5128
- }
5129
- const response = await config.onRequest(
5130
- requestCtx,
5131
- handlerRequest,
5132
- );
5133
- if (!isResponseLike(response)) {
5134
- throw new Error(
5135
- "onRequest handler must return a Response",
5136
- );
5137
- }
5138
- const conversion = await convertNativeHttpResponse(
5139
- response,
5140
- responseBodyStream,
5141
- );
5142
- if (conversion.bodyCompletion) {
5143
- cleanupDeferredToBody = true;
5144
- void conversion.bodyCompletion
5145
- .then(cleanupRequest)
5146
- .catch((cleanupError) => {
5147
- logger().error({
5148
- msg: "failed to clean up native streaming http request",
5149
- error: cleanupError,
5150
- });
5151
- });
5152
- }
5153
- return conversion.response;
5154
- } finally {
5155
- try {
5156
- // Handler completion ends upload ownership even when
5157
- // the Web Request body is locked or partly consumed.
5158
- await cancelNativeHttpRequestBody(
5159
- request.bodyStream,
5160
- );
5161
- } finally {
5162
- if (!cleanupDeferredToBody) {
5163
- await cleanupRequest();
5159
+ conn = await callNative(() =>
5160
+ runtime.actorConnectConn(
5161
+ ctx,
5162
+ encodeValue(connParams),
5163
+ request,
5164
+ ),
5165
+ );
5166
+ requestCtx = makeConnCtx(
5167
+ ctx,
5168
+ conn,
5169
+ handlerRequest,
5170
+ cancelToken,
5171
+ );
5172
+ const ctxAbortSignal = requestCtx.abortSignal;
5173
+ const abortRequest = () =>
5174
+ requestAbortController.abort(
5175
+ ctxAbortSignal.reason,
5176
+ );
5177
+ if (ctxAbortSignal.aborted) {
5178
+ abortRequest();
5179
+ } else {
5180
+ ctxAbortSignal.addEventListener(
5181
+ "abort",
5182
+ abortRequest,
5183
+ { once: true },
5184
+ );
5185
+ removeRequestAbortListener = () =>
5186
+ ctxAbortSignal.removeEventListener(
5187
+ "abort",
5188
+ abortRequest,
5189
+ );
5190
+ }
5191
+ const response = await config.onRequest(
5192
+ requestCtx,
5193
+ handlerRequest,
5194
+ );
5195
+ if (!isResponseLike(response)) {
5196
+ throw new Error(
5197
+ "onRequest handler must return a Response",
5198
+ );
5199
+ }
5200
+ const conversion =
5201
+ await convertNativeHttpResponse(
5202
+ response,
5203
+ responseBodyStream,
5204
+ );
5205
+ if (conversion.bodyCompletion) {
5206
+ cleanupDeferredToBody = true;
5207
+ void conversion.bodyCompletion
5208
+ .then(cleanupRequest)
5209
+ .catch((cleanupError) => {
5210
+ logger().error({
5211
+ msg: "failed to clean up native streaming http request",
5212
+ error: cleanupError,
5213
+ });
5214
+ });
5215
+ }
5216
+ return conversion.response;
5217
+ } finally {
5218
+ try {
5219
+ // Handler completion ends upload ownership even when
5220
+ // the Web Request body is locked or partly consumed.
5221
+ await cancelNativeHttpRequestBody(
5222
+ request.bodyStream,
5223
+ );
5224
+ } finally {
5225
+ if (!cleanupDeferredToBody) {
5226
+ await cleanupRequest();
5227
+ }
5228
+ }
5164
5229
  }
5165
- }
5166
- }
5230
+ },
5231
+ );
5167
5232
  } catch (error) {
5168
5233
  logger().error({
5169
5234
  msg: "native onRequest failed",
@@ -5312,21 +5377,29 @@ export function buildNativeFactory(
5312
5377
  conn != null
5313
5378
  ? makeConnCtx(ctx, conn, undefined, cancelToken)
5314
5379
  : makeActorCtx(ctx, undefined, cancelToken);
5315
- try {
5316
- return encodeValue(
5317
- await handler(
5318
- actorCtx,
5319
- ...validateActionArgs(
5320
- schemaConfig.actionInputSchemas,
5321
- name,
5322
- decodeArgs(args),
5380
+ const runAction = async () => {
5381
+ try {
5382
+ return encodeValue(
5383
+ await handler(
5384
+ actorCtx,
5385
+ ...validateActionArgs(
5386
+ schemaConfig.actionInputSchemas,
5387
+ name,
5388
+ decodeArgs(args),
5389
+ ),
5390
+ ...(scheduledFire
5391
+ ? [scheduledFire]
5392
+ : []),
5323
5393
  ),
5324
- ...(scheduledFire ? [scheduledFire] : []),
5325
- ),
5326
- );
5327
- } finally {
5328
- await actorCtx.dispose();
5329
- }
5394
+ );
5395
+ } finally {
5396
+ await actorCtx.dispose();
5397
+ }
5398
+ };
5399
+ return await runtime.runWithActorInvocationContext(
5400
+ ctx,
5401
+ runAction,
5402
+ );
5330
5403
  },
5331
5404
  ),
5332
5405
  ]),
@@ -5365,7 +5438,7 @@ export function buildNativeFactory(
5365
5438
  runtime,
5366
5439
  ctx,
5367
5440
  conn,
5368
- createClient,
5441
+ () => createClient(ctx),
5369
5442
  schemaConfig,
5370
5443
  databaseProvider,
5371
5444
  jsRequest,
@@ -5374,62 +5447,75 @@ export function buildNativeFactory(
5374
5447
  cancelToken,
5375
5448
  run !== undefined,
5376
5449
  );
5377
- try {
5378
- if (
5379
- !schemaConfig.queues ||
5380
- !hasSchemaConfigKey(schemaConfig.queues, name)
5381
- ) {
5382
- return { status: "completed" };
5383
- }
5384
-
5385
- const canPublish = getQueueCanPublish(
5386
- schemaConfig.queues,
5387
- name,
5388
- );
5389
- if (canPublish && !(await canPublish(actorCtx))) {
5390
- throw forbiddenError();
5391
- }
5392
-
5393
- const decodedBody = decodeValue(body);
5394
- if (wait) {
5450
+ return await runtime.runWithActorInvocationContext(
5451
+ ctx,
5452
+ async () => {
5395
5453
  try {
5396
- const response =
5397
- await actorCtx.queue.enqueueAndWait(
5398
- name,
5399
- decodedBody,
5400
- {
5401
- timeout:
5402
- timeoutMs === undefined ||
5403
- timeoutMs === null
5404
- ? undefined
5405
- : Number(timeoutMs),
5406
- },
5407
- );
5408
- return {
5409
- status: "completed",
5410
- response:
5411
- response === undefined
5412
- ? undefined
5413
- : encodeValue(response),
5414
- };
5415
- } catch (error) {
5416
5454
  if (
5417
- (error as { group?: string; code?: string })
5418
- .group === "queue" &&
5419
- (error as { group?: string; code?: string })
5420
- .code === "timed_out"
5455
+ !schemaConfig.queues ||
5456
+ !hasSchemaConfigKey(schemaConfig.queues, name)
5421
5457
  ) {
5422
- return { status: "timedOut" };
5458
+ return { status: "completed" };
5423
5459
  }
5424
- throw error;
5425
- }
5426
- }
5427
5460
 
5428
- await actorCtx.queue.send(name, decodedBody);
5429
- return { status: "completed" };
5430
- } finally {
5431
- await actorCtx.dispose();
5432
- }
5461
+ const canPublish = getQueueCanPublish(
5462
+ schemaConfig.queues,
5463
+ name,
5464
+ );
5465
+ if (canPublish && !(await canPublish(actorCtx))) {
5466
+ throw forbiddenError();
5467
+ }
5468
+
5469
+ const decodedBody = decodeValue(body);
5470
+ if (wait) {
5471
+ try {
5472
+ const response =
5473
+ await actorCtx.queue.enqueueAndWait(
5474
+ name,
5475
+ decodedBody,
5476
+ {
5477
+ timeout:
5478
+ timeoutMs === undefined ||
5479
+ timeoutMs === null
5480
+ ? undefined
5481
+ : Number(timeoutMs),
5482
+ },
5483
+ );
5484
+ return {
5485
+ status: "completed",
5486
+ response:
5487
+ response === undefined
5488
+ ? undefined
5489
+ : encodeValue(response),
5490
+ };
5491
+ } catch (error) {
5492
+ if (
5493
+ (
5494
+ error as {
5495
+ group?: string;
5496
+ code?: string;
5497
+ }
5498
+ ).group === "queue" &&
5499
+ (
5500
+ error as {
5501
+ group?: string;
5502
+ code?: string;
5503
+ }
5504
+ ).code === "timed_out"
5505
+ ) {
5506
+ return { status: "timedOut" };
5507
+ }
5508
+ throw error;
5509
+ }
5510
+ }
5511
+
5512
+ await actorCtx.queue.send(name, decodedBody);
5513
+ return { status: "completed" };
5514
+ } finally {
5515
+ await actorCtx.dispose();
5516
+ }
5517
+ },
5518
+ );
5433
5519
  },
5434
5520
  ),
5435
5521
  serializeState: wrapNativeCallback(
@@ -1,3 +1,8 @@
1
+ import type { WorkflowSpan } from "@/actor/config";
2
+ import type {
3
+ ActorInvocationSpanContext,
4
+ ActorInvocationTraceContext,
5
+ } from "@/common/actor-telemetry-context";
1
6
  import type {
2
7
  SqliteNativeMetrics,
3
8
  SqliteProfilingOptions,
@@ -29,6 +34,35 @@ export interface RuntimeActorKeySegment {
29
34
  numberValue?: number;
30
35
  }
31
36
 
37
+ /** Resolves correlation at operation time so retained clients cannot freeze stale context. */
38
+ export type CurrentActorInvocation = () =>
39
+ | ActorInvocationTraceContext
40
+ | undefined;
41
+
42
+ /** One open call from an actor out to another actor. */
43
+ export interface RuntimeOutboundCall {
44
+ /**
45
+ * W3C context of the call's own span, to send to the callee so it parents to
46
+ * the call. Absent when tracing is disabled.
47
+ */
48
+ readonly span?: ActorInvocationSpanContext;
49
+ /**
50
+ * Records the call's outcome. `error` is the failure encoded the way the
51
+ * bridge encodes errors, so a structured error keeps its group and code.
52
+ */
53
+ finish(error?: string): void;
54
+ }
55
+
56
+ /**
57
+ * Opens the span covering one call out to another actor, or returns `undefined`
58
+ * outside an invocation or on a runtime without invocation telemetry. Callers
59
+ * send their own context when it returns nothing.
60
+ */
61
+ export type StartCallSpan = (
62
+ actorName: string,
63
+ actionName: string,
64
+ ) => RuntimeOutboundCall | undefined;
65
+
32
66
  export interface RuntimeHttpRequest {
33
67
  method: string;
34
68
  uri: string;
@@ -452,6 +486,7 @@ export interface CoreRuntime {
452
486
  ): Promise<void>;
453
487
  waitRegistryReady(registry: RegistryHandle): Promise<void>;
454
488
  shutdownRegistry(registry: RegistryHandle): Promise<void>;
489
+ shutdownTelemetry?(): Promise<void>;
455
490
  registryActorStopThresholdMs?(
456
491
  registry: RegistryHandle,
457
492
  ): Promise<number | undefined>;
@@ -540,6 +575,37 @@ export interface CoreRuntime {
540
575
  writes: RuntimeWorkflowKvWrite[],
541
576
  ): Promise<void>;
542
577
  actorId(ctx: ActorContextHandle): string;
578
+ /**
579
+ * Runs one actor callback with `ctx` as the current invocation: operations
580
+ * on retained handles for the same actor resolve to it, and its Core span
581
+ * is the active OpenTelemetry span for the duration of `run`. Only actions,
582
+ * raw requests, and queue dispatch run this way; other callbacks have no
583
+ * invocation span.
584
+ */
585
+ runWithActorInvocationContext<T>(ctx: ActorContextHandle, run: () => T): T;
586
+ /**
587
+ * Correlation of the invocation currently executing for this actor, or
588
+ * `undefined` outside an invocation or after it finished. A sampled-out
589
+ * invocation can still expose valid span context for propagation.
590
+ */
591
+ actorInvocationTraceContext(
592
+ ctx: ActorContextHandle,
593
+ ): ActorInvocationTraceContext | undefined;
594
+ /**
595
+ * Opens the span covering one call this actor makes to another actor. See
596
+ * `StartCallSpan` for when this returns nothing.
597
+ */
598
+ startCallSpan(
599
+ ctx: ActorContextHandle,
600
+ actorName: string,
601
+ actionName: string,
602
+ ): RuntimeOutboundCall | undefined;
603
+ /** Backs `ActorRun.startWorkflowSpan`. */
604
+ startWorkflowSpan(ctx: ActorContextHandle): Promise<WorkflowSpan>;
605
+ /** Backs `ActorRun.runOutsideWorkflowSpan`. */
606
+ runOutsideActorInvocationContext<T>(run: () => T): T;
607
+ /** Identity of the invocation the caller runs in, usable as a cache key. */
608
+ currentInvocationScope(): object | undefined;
543
609
  actorName(ctx: ActorContextHandle): string;
544
610
  actorKey(ctx: ActorContextHandle): RuntimeActorKeySegment[];
545
611
  actorRegion(ctx: ActorContextHandle): string;