rivetkit 2.3.12-rc.4 → 2.3.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 (121) hide show
  1. package/dist/browser/client.d.ts +17 -4
  2. package/dist/browser/client.js +32 -24
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.js +2 -1
  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 +3 -19
  9. package/dist/tsup/agent-os/index.cjs.map +1 -1
  10. package/dist/tsup/agent-os/index.d.cts +17 -4
  11. package/dist/tsup/agent-os/index.d.ts +17 -4
  12. package/dist/tsup/agent-os/index.js +3 -19
  13. package/dist/tsup/agent-os/index.js.map +1 -1
  14. package/dist/tsup/{chunk-SPJORZMM.cjs → chunk-2JSYYH6P.cjs} +1 -1
  15. package/dist/tsup/chunk-2JSYYH6P.cjs.map +1 -0
  16. package/dist/tsup/{chunk-IAH47VDZ.cjs → chunk-4KGXFC6M.cjs} +2 -19
  17. package/dist/tsup/chunk-4KGXFC6M.cjs.map +1 -0
  18. package/dist/tsup/{chunk-DLQSZ6Q7.js → chunk-6W5VGLFT.js} +2 -19
  19. package/dist/tsup/chunk-6W5VGLFT.js.map +1 -0
  20. package/dist/tsup/{chunk-JIOLC5I2.cjs → chunk-AN7WO7BM.cjs} +3 -3
  21. package/dist/tsup/{chunk-JIOLC5I2.cjs.map → chunk-AN7WO7BM.cjs.map} +1 -1
  22. package/dist/tsup/{chunk-AF2VKCFA.js → chunk-EBXARMGI.js} +2 -2
  23. package/dist/tsup/{chunk-4LRWLBTR.cjs → chunk-FGQABMXZ.cjs} +3 -3
  24. package/dist/tsup/{chunk-4LRWLBTR.cjs.map → chunk-FGQABMXZ.cjs.map} +1 -1
  25. package/dist/tsup/{chunk-BQ7YJ3PG.js → chunk-GEN4NHXM.js} +2 -2
  26. package/dist/tsup/{chunk-NVMHEG5J.js → chunk-JYTXOMM7.js} +2 -2
  27. package/dist/tsup/{chunk-NKLM6C5A.cjs → chunk-MEF7RVQ7.cjs} +10 -10
  28. package/dist/tsup/{chunk-NKLM6C5A.cjs.map → chunk-MEF7RVQ7.cjs.map} +1 -1
  29. package/dist/tsup/{chunk-64DT44V2.js → chunk-MF42PRF2.js} +9 -3
  30. package/dist/tsup/chunk-MF42PRF2.js.map +1 -0
  31. package/dist/tsup/{chunk-IXBD7BXC.js → chunk-OUQUIBVW.js} +1 -1
  32. package/dist/tsup/chunk-OUQUIBVW.js.map +1 -0
  33. package/dist/tsup/{chunk-S3GXVCIM.cjs → chunk-PW2VSGUR.cjs} +4 -4
  34. package/dist/tsup/{chunk-S3GXVCIM.cjs.map → chunk-PW2VSGUR.cjs.map} +1 -1
  35. package/dist/tsup/{chunk-GMBCKV6C.js → chunk-RBXJWAJB.js} +3 -3
  36. package/dist/tsup/{chunk-XDYECGCT.cjs → chunk-SSPTEGTX.cjs} +7 -7
  37. package/dist/tsup/{chunk-XDYECGCT.cjs.map → chunk-SSPTEGTX.cjs.map} +1 -1
  38. package/dist/tsup/{chunk-ARFTQ5HY.cjs → chunk-TAG6UEL5.cjs} +17 -11
  39. package/dist/tsup/chunk-TAG6UEL5.cjs.map +1 -0
  40. package/dist/tsup/{chunk-OCXHNHGQ.cjs → chunk-TXUHVBKH.cjs} +3 -3
  41. package/dist/tsup/{chunk-OCXHNHGQ.cjs.map → chunk-TXUHVBKH.cjs.map} +1 -1
  42. package/dist/tsup/{chunk-F7G5WHOD.cjs → chunk-TZPNSOG2.cjs} +203 -195
  43. package/dist/tsup/chunk-TZPNSOG2.cjs.map +1 -0
  44. package/dist/tsup/{chunk-O74736N5.js → chunk-VOYNLY57.js} +41 -33
  45. package/dist/tsup/chunk-VOYNLY57.js.map +1 -0
  46. package/dist/tsup/{chunk-3CBQIP37.js → chunk-XUODFCRJ.js} +4 -4
  47. package/dist/tsup/{chunk-P5JJG4KY.js → chunk-ZIPXAVKR.js} +2 -2
  48. package/dist/tsup/client/mod.cjs +6 -6
  49. package/dist/tsup/client/mod.d.cts +2 -2
  50. package/dist/tsup/client/mod.d.ts +2 -2
  51. package/dist/tsup/client/mod.js +5 -5
  52. package/dist/tsup/common/log.cjs +3 -3
  53. package/dist/tsup/common/log.js +2 -2
  54. package/dist/tsup/common/websocket.cjs +4 -4
  55. package/dist/tsup/common/websocket.js +3 -3
  56. package/dist/tsup/{config-DzaddF-j.d.ts → config-BGTanB_3.d.ts} +19 -10
  57. package/dist/tsup/{config-VxDc6yMu.d.cts → config-NHz6oMb9.d.cts} +19 -10
  58. package/dist/tsup/{context-Cn8CIrOR.d.cts → context-DB8zG_Ib.d.cts} +1 -1
  59. package/dist/tsup/{context-B6HYokje.d.ts → context-SHomdVV8.d.ts} +1 -1
  60. package/dist/tsup/db/drizzle.cjs +3 -3
  61. package/dist/tsup/db/drizzle.js +2 -2
  62. package/dist/tsup/db/mod.cjs +4 -4
  63. package/dist/tsup/db/mod.js +3 -3
  64. package/dist/tsup/dynamic/mod.cjs +2 -2
  65. package/dist/tsup/dynamic/mod.d.cts +1 -1
  66. package/dist/tsup/dynamic/mod.d.ts +1 -1
  67. package/dist/tsup/dynamic/mod.js +1 -1
  68. package/dist/tsup/inspector/mod.cjs +6 -6
  69. package/dist/tsup/inspector/mod.js +5 -5
  70. package/dist/tsup/inspector/workflow.cjs +5 -5
  71. package/dist/tsup/inspector/workflow.js +4 -4
  72. package/dist/tsup/inspector-tab/mod.cjs +2 -2
  73. package/dist/tsup/inspector-tab/mod.d.cts +2 -2
  74. package/dist/tsup/inspector-tab/mod.d.ts +2 -2
  75. package/dist/tsup/inspector-tab/mod.js +1 -1
  76. package/dist/tsup/mod.cjs +444 -199
  77. package/dist/tsup/mod.cjs.map +1 -1
  78. package/dist/tsup/mod.d.cts +3 -3
  79. package/dist/tsup/mod.d.ts +3 -3
  80. package/dist/tsup/mod.js +323 -78
  81. package/dist/tsup/mod.js.map +1 -1
  82. package/dist/tsup/test/mod.cjs +7 -7
  83. package/dist/tsup/test/mod.d.cts +1 -1
  84. package/dist/tsup/test/mod.d.ts +1 -1
  85. package/dist/tsup/test/mod.js +5 -5
  86. package/dist/tsup/utils.cjs +3 -3
  87. package/dist/tsup/utils.js +2 -2
  88. package/dist/tsup/workflow/mod.cjs +14 -14
  89. package/dist/tsup/workflow/mod.d.cts +3 -3
  90. package/dist/tsup/workflow/mod.d.ts +3 -3
  91. package/dist/tsup/workflow/mod.js +6 -6
  92. package/package.json +9 -8
  93. package/src/actor/config.test.ts +0 -8
  94. package/src/actor/config.ts +1 -24
  95. package/src/actor/errors.ts +2 -1
  96. package/src/client/actor-handle.ts +10 -3
  97. package/src/client/raw-utils.ts +8 -0
  98. package/src/common/actor-router-consts.ts +2 -0
  99. package/src/engine-client/actor-http-client.ts +6 -22
  100. package/src/engine-client/mod.ts +1 -1
  101. package/src/registry/config/index.ts +27 -1
  102. package/src/registry/index.ts +48 -14
  103. package/src/registry/napi-runtime.ts +32 -5
  104. package/src/registry/native-http.ts +225 -0
  105. package/src/registry/native.ts +130 -65
  106. package/src/registry/runtime.ts +30 -3
  107. package/src/utils/env-vars.ts +4 -0
  108. package/dist/tsup/chunk-64DT44V2.js.map +0 -1
  109. package/dist/tsup/chunk-ARFTQ5HY.cjs.map +0 -1
  110. package/dist/tsup/chunk-DLQSZ6Q7.js.map +0 -1
  111. package/dist/tsup/chunk-F7G5WHOD.cjs.map +0 -1
  112. package/dist/tsup/chunk-IAH47VDZ.cjs.map +0 -1
  113. package/dist/tsup/chunk-IXBD7BXC.js.map +0 -1
  114. package/dist/tsup/chunk-O74736N5.js.map +0 -1
  115. package/dist/tsup/chunk-SPJORZMM.cjs.map +0 -1
  116. /package/dist/tsup/{chunk-AF2VKCFA.js.map → chunk-EBXARMGI.js.map} +0 -0
  117. /package/dist/tsup/{chunk-BQ7YJ3PG.js.map → chunk-GEN4NHXM.js.map} +0 -0
  118. /package/dist/tsup/{chunk-NVMHEG5J.js.map → chunk-JYTXOMM7.js.map} +0 -0
  119. /package/dist/tsup/{chunk-GMBCKV6C.js.map → chunk-RBXJWAJB.js.map} +0 -0
  120. /package/dist/tsup/{chunk-3CBQIP37.js.map → chunk-XUODFCRJ.js.map} +0 -0
  121. /package/dist/tsup/{chunk-P5JJG4KY.js.map → chunk-ZIPXAVKR.js.map} +0 -0
@@ -16,8 +16,11 @@ import {
16
16
  } from "./config";
17
17
  import { logger } from "./log";
18
18
  import { buildConfiguredRegistry } from "./native";
19
+ import { convertNativeHttpResponse } from "./native-http";
19
20
  import type {
21
+ CoreRuntime,
20
22
  RuntimeApplicationFetch,
23
+ RuntimeHttpResponseBodyStream,
21
24
  RuntimeServerlessResponseHead,
22
25
  } from "./runtime";
23
26
 
@@ -43,18 +46,33 @@ function finishShutdownSignal(signal: ShutdownSignal): void {
43
46
 
44
47
  function createApplicationFetch(
45
48
  application: RegistryApplication,
49
+ runtime: CoreRuntime,
46
50
  ): RuntimeApplicationFetch {
47
- return async (request) => {
51
+ return async (
52
+ request,
53
+ responseBodyStream?: RuntimeHttpResponseBodyStream,
54
+ ) => {
48
55
  const method = request.method.toUpperCase();
49
56
  const body =
50
57
  method === "GET" || method === "HEAD" || request.body.length === 0
51
58
  ? undefined
52
59
  : Uint8Array.from(request.body).buffer;
60
+ const abortController = new AbortController();
61
+ if (request.cancelToken) {
62
+ if (runtime.cancellationTokenAborted(request.cancelToken)) {
63
+ abortController.abort();
64
+ } else {
65
+ runtime.onCancellationTokenCancelled(request.cancelToken, () =>
66
+ abortController.abort(),
67
+ );
68
+ }
69
+ }
53
70
  const response = await application.fetch(
54
71
  new Request(request.url, {
55
72
  method,
56
73
  headers: request.headers,
57
74
  body,
75
+ signal: abortController.signal,
58
76
  }),
59
77
  );
60
78
  if (!isResponseLike(response)) {
@@ -62,10 +80,25 @@ function createApplicationFetch(
62
80
  "registry.listen() application fetch must return a Response",
63
81
  );
64
82
  }
83
+ const conversion = await convertNativeHttpResponse(
84
+ response,
85
+ responseBodyStream,
86
+ );
87
+ if (conversion.bodyCompletion) {
88
+ void conversion.bodyCompletion.catch((error) => {
89
+ logger().error({
90
+ msg: "application response stream failed",
91
+ error,
92
+ });
93
+ });
94
+ }
65
95
  return {
66
- status: response.status,
67
- headers: Object.fromEntries(response.headers.entries()),
68
- body: new Uint8Array(await response.arrayBuffer()),
96
+ status: conversion.response.status ?? response.status,
97
+ headers:
98
+ conversion.response.headers ??
99
+ Object.fromEntries(response.headers.entries()),
100
+ body: conversion.response.body,
101
+ stream: conversion.response.stream,
69
102
  };
70
103
  };
71
104
  }
@@ -406,11 +439,8 @@ export class Registry<A extends RegistryActors> {
406
439
  const port = opts.port ?? parsePortEnv(process.env.RIVET_PORT) ?? 3000;
407
440
  const publicDir = opts.publicDir ?? getRivetkitPublicDir();
408
441
  const config = this.parseConfig();
409
- const application = opts.application
410
- ? createApplicationFetch(opts.application)
411
- : undefined;
412
442
 
413
- if (application && getRivetkitRuntimeMode() !== "serverless") {
443
+ if (opts.application && getRivetkitRuntimeMode() !== "serverless") {
414
444
  if (config.runtime === "wasm") {
415
445
  throw new Error(
416
446
  "registry.listen() requires the native runtime; use an application-owned HTTP server with WebAssembly",
@@ -431,6 +461,11 @@ export class Registry<A extends RegistryActors> {
431
461
  }
432
462
  const { runtime, registry, serveConfig } =
433
463
  await configuredRegistryPromise;
464
+ const application = createApplicationFetch(
465
+ opts.application,
466
+ runtime,
467
+ );
468
+ await readyPromise;
434
469
  const listenerPromise = runtime.serveApplicationListener(
435
470
  registry,
436
471
  {
@@ -448,16 +483,12 @@ export class Registry<A extends RegistryActors> {
448
483
  "registry envoy serve lifecycle did not initialize",
449
484
  );
450
485
  }
451
- await Promise.all([
452
- readyPromise,
453
- listenerPromise,
454
- serveLifecyclePromise,
455
- ]);
486
+ await Promise.all([listenerPromise, serveLifecyclePromise]);
456
487
  return;
457
488
  }
458
489
 
459
490
  // Cache on both promise fields so the shutdown drain sees Mode A and B.
460
- const configuredRegistryPromise = buildConfiguredRegistry(config);
491
+ const configuredRegistryPromise = this.#buildConfiguredRegistry(config);
461
492
  this.#runtimeServeConfiguredPromise = configuredRegistryPromise;
462
493
  this.#runtimeServerlessPromise = configuredRegistryPromise;
463
494
  this.#installSignalHandlers(config);
@@ -473,6 +504,9 @@ export class Registry<A extends RegistryActors> {
473
504
 
474
505
  const { runtime, registry, serveConfig } =
475
506
  await configuredRegistryPromise;
507
+ const application = opts.application
508
+ ? createApplicationFetch(opts.application, runtime)
509
+ : undefined;
476
510
  await runtime.serveListener(
477
511
  registry,
478
512
  {
@@ -4,6 +4,7 @@ import type {
4
4
  CancellationToken as NativeCancellationToken,
5
5
  ConnHandle as NativeConnHandle,
6
6
  CoreRegistry as NativeCoreRegistry,
7
+ HttpResponseBodyStream as NativeHttpResponseBodyStream,
7
8
  WebSocket as NativeWebSocket,
8
9
  } from "@rivetkit/rivetkit-napi";
9
10
  import type {
@@ -21,6 +22,7 @@ import type {
21
22
  RuntimeCronFire,
22
23
  RuntimeCronJobInfo,
23
24
  RuntimeHttpRequest,
25
+ RuntimeHttpResponseBodyStream,
24
26
  RuntimeKvEntry,
25
27
  RuntimeKvListOptions,
26
28
  RuntimeListenerConfig,
@@ -154,23 +156,48 @@ function toNapiApplication(application: RuntimeApplicationFetch) {
154
156
  url: string;
155
157
  headers: Record<string, string>;
156
158
  body: Buffer;
159
+ cancelToken?: NativeCancellationToken;
160
+ responseBodyStream?: RuntimeHttpResponseBodyStream;
157
161
  },
158
162
  ) => {
159
163
  if (error) throw error;
160
164
  if (!request) {
161
165
  throw new Error("application fetch callback received no request");
162
166
  }
163
- const response = await application({
164
- ...request,
165
- body: new Uint8Array(request.body),
166
- });
167
+ const response = await application(
168
+ {
169
+ ...request,
170
+ body: new Uint8Array(request.body),
171
+ cancelToken:
172
+ request.cancelToken as unknown as CancellationTokenHandle,
173
+ },
174
+ request.responseBodyStream
175
+ ? fromNapiHttpResponseBodyStream(
176
+ request.responseBodyStream as unknown as NativeHttpResponseBodyStream,
177
+ )
178
+ : undefined,
179
+ );
167
180
  return {
168
181
  ...response,
169
- body: toNapiBuffer(response.body),
182
+ body:
183
+ response.body === undefined
184
+ ? undefined
185
+ : toNapiBuffer(response.body),
170
186
  };
171
187
  };
172
188
  }
173
189
 
190
+ function fromNapiHttpResponseBodyStream(
191
+ stream: NativeHttpResponseBodyStream,
192
+ ): RuntimeHttpResponseBodyStream {
193
+ return {
194
+ cancelled: () => stream.cancelled(),
195
+ write: (chunk) => stream.write(Buffer.from(chunk)),
196
+ end: () => stream.end(),
197
+ error: (message) => stream.error(message),
198
+ };
199
+ }
200
+
174
201
  function toNapiHttpRequest(
175
202
  request?: RuntimeHttpRequest | undefined | null,
176
203
  ): Parameters<NativeActorContext["connectConn"]>[1] {
@@ -0,0 +1,225 @@
1
+ import type { ResponseLike } from "@/common/fetch-like";
2
+ import { HEADER_ORIGINAL_REQUEST_URL } from "@/common/actor-router-consts";
3
+ import { stringifyError } from "@/common/utils";
4
+ import { logger } from "./log";
5
+ import type { RuntimeBytes, RuntimeHttpResponse } from "./runtime";
6
+
7
+ const HTTP_BODY_CHUNK_SIZE = 64 * 1024;
8
+
9
+ // Structural types keep the HTTP adapter independent of the N-API package.
10
+ export interface NativeHttpResponseBodyStream {
11
+ cancelled(): Promise<void>;
12
+ write(chunk: Uint8Array): Promise<void>;
13
+ end(): Promise<void>;
14
+ error(message: string): Promise<void>;
15
+ }
16
+
17
+ export interface NativeHttpRequestBodyStream {
18
+ read(): Promise<Uint8Array | null | undefined>;
19
+ cancel(): Promise<void>;
20
+ }
21
+
22
+ interface NativeHttpRequestInit {
23
+ method: string;
24
+ uri: string;
25
+ headers?: Record<string, string>;
26
+ body?: RuntimeBytes;
27
+ bodyStream?: NativeHttpRequestBodyStream;
28
+ signal?: AbortSignal;
29
+ abortController?: AbortController;
30
+ }
31
+
32
+ interface NativeHttpResponseConversion {
33
+ response: RuntimeHttpResponse;
34
+ // Keeps request-scoped actor resources alive until the response body closes.
35
+ bodyCompletion?: Promise<void>;
36
+ }
37
+
38
+ function runtimeBytesToArrayBuffer(value: RuntimeBytes): ArrayBuffer {
39
+ return value.buffer.slice(
40
+ value.byteOffset,
41
+ value.byteOffset + value.byteLength,
42
+ ) as ArrayBuffer;
43
+ }
44
+
45
+ export function buildNativeHttpRequest(init: NativeHttpRequestInit): Request {
46
+ const headers = new Headers(init.headers);
47
+ const originalUrl = headers.get(HEADER_ORIGINAL_REQUEST_URL);
48
+ headers.delete(HEADER_ORIGINAL_REQUEST_URL);
49
+ const url =
50
+ originalUrl ??
51
+ (init.uri.startsWith("http")
52
+ ? init.uri
53
+ : new URL(init.uri, "http://127.0.0.1").toString());
54
+ const method = init.method.toUpperCase();
55
+ const bodyForbidden = method === "GET" || method === "HEAD";
56
+ const body = bodyForbidden
57
+ ? undefined
58
+ : init.bodyStream
59
+ ? new ReadableStream<Uint8Array>({
60
+ async pull(controller) {
61
+ try {
62
+ if (init.body && init.body.length > 0) {
63
+ controller.enqueue(new Uint8Array(init.body));
64
+ init.body = undefined;
65
+ return;
66
+ }
67
+ const chunk = await init.bodyStream?.read();
68
+ if (!chunk) {
69
+ controller.close();
70
+ } else {
71
+ controller.enqueue(new Uint8Array(chunk));
72
+ }
73
+ } catch (error) {
74
+ init.abortController?.abort(error);
75
+ controller.error(error);
76
+ }
77
+ },
78
+ async cancel() {
79
+ await init.bodyStream?.cancel();
80
+ },
81
+ })
82
+ : init.body && init.body.length > 0
83
+ ? runtimeBytesToArrayBuffer(init.body)
84
+ : undefined;
85
+ const streamInit =
86
+ init.bodyStream && !bodyForbidden ? { duplex: "half" } : {};
87
+ return new Request(url, {
88
+ method,
89
+ headers,
90
+ body,
91
+ signal: init.abortController?.signal ?? init.signal,
92
+ ...streamInit,
93
+ } as RequestInit);
94
+ }
95
+
96
+ export async function cancelNativeHttpRequestBody(
97
+ bodyStream?: NativeHttpRequestBodyStream,
98
+ ) {
99
+ await bodyStream?.cancel();
100
+ }
101
+
102
+ async function writeResponseChunk(
103
+ stream: NativeHttpResponseBodyStream,
104
+ chunk: Uint8Array,
105
+ ) {
106
+ for (
107
+ let offset = 0;
108
+ offset < chunk.byteLength;
109
+ offset += HTTP_BODY_CHUNK_SIZE
110
+ ) {
111
+ await stream.write(
112
+ chunk.subarray(offset, offset + HTTP_BODY_CHUNK_SIZE),
113
+ );
114
+ }
115
+ }
116
+
117
+ async function pumpResponseBody(
118
+ reader: ReadableStreamDefaultReader<Uint8Array>,
119
+ stream: NativeHttpResponseBodyStream,
120
+ ) {
121
+ // Awaiting each write applies native-side backpressure. Racing the next read
122
+ // against cancellation also stops an otherwise unbounded SSE response when
123
+ // its downstream receiver disappears.
124
+ const cancelled = stream
125
+ .cancelled()
126
+ .then(() => ({ cancelled: true }) as const);
127
+ try {
128
+ for (;;) {
129
+ const read = reader
130
+ .read()
131
+ .then((next) => ({ cancelled: false, next }) as const);
132
+ const result = await Promise.race([read, cancelled]);
133
+ if (result.cancelled) {
134
+ // Web Streams closes pending reads before waiting for the source's cancel
135
+ // callback. Do not let an arbitrary user cancel promise retain the native
136
+ // request and connection cleanup indefinitely.
137
+ void reader
138
+ .cancel(
139
+ new Error(
140
+ "native http response stream receiver dropped",
141
+ ),
142
+ )
143
+ .catch((error) => {
144
+ logger().debug({
145
+ msg: "failed to cancel native http response reader",
146
+ error,
147
+ });
148
+ });
149
+ return;
150
+ }
151
+ const { next } = result;
152
+ if (next.done) {
153
+ await stream.end();
154
+ return;
155
+ }
156
+ if (next.value?.byteLength) {
157
+ await writeResponseChunk(stream, next.value);
158
+ }
159
+ }
160
+ } catch (error) {
161
+ try {
162
+ await stream.error(stringifyError(error));
163
+ } catch (streamError) {
164
+ logger().debug({
165
+ msg: "failed to report native http response stream error",
166
+ error: streamError,
167
+ });
168
+ }
169
+ void reader.cancel(error).catch(() => {
170
+ // Reader may already be closed after a native-side disconnect.
171
+ });
172
+ } finally {
173
+ try {
174
+ reader.releaseLock();
175
+ } catch (error) {
176
+ logger().debug({
177
+ msg: "failed to release native http response reader lock",
178
+ error,
179
+ });
180
+ }
181
+ }
182
+ }
183
+
184
+ export async function convertNativeHttpResponse(
185
+ response: ResponseLike,
186
+ responseBodyStream?: NativeHttpResponseBodyStream,
187
+ ): Promise<NativeHttpResponseConversion> {
188
+ const headers = Object.fromEntries(response.headers.entries());
189
+ if (!response.body) {
190
+ return {
191
+ response: {
192
+ status: response.status,
193
+ headers,
194
+ body: new Uint8Array(),
195
+ },
196
+ };
197
+ }
198
+
199
+ if (responseBodyStream) {
200
+ const reader = response.body.getReader();
201
+ const bodyCompletion = pumpResponseBody(reader, responseBodyStream);
202
+ return {
203
+ response: {
204
+ status: response.status,
205
+ headers,
206
+ stream: true,
207
+ },
208
+ bodyCompletion,
209
+ };
210
+ }
211
+
212
+ return {
213
+ response: {
214
+ status: response.status,
215
+ headers,
216
+ body: new Uint8Array(await response.arrayBuffer()),
217
+ },
218
+ };
219
+ }
220
+
221
+ export const nativeHttpTestInternals = {
222
+ buildRequest: buildNativeHttpRequest,
223
+ cancelRequestBody: cancelNativeHttpRequestBody,
224
+ convertRuntimeHttpResponse: convertNativeHttpResponse,
225
+ };