@blaxel/core 0.2.83-preview.150 → 0.2.83

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.
@@ -1,3 +1,4 @@
1
+ import { refH2SessionForActiveRequest } from "./h2ref.js";
1
2
  const MIN_H2_SESSION_MAX_LISTENERS = 64;
2
3
  const sessionsWithListenerBudget = new WeakSet();
3
4
  /**
@@ -156,6 +157,8 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
156
157
  let streamController = null;
157
158
  let streamClosed = false;
158
159
  let req = null;
160
+ let releaseSessionRef = () => { };
161
+ let abort = null;
159
162
  try {
160
163
  req = session.request(h2Headers);
161
164
  }
@@ -165,6 +168,7 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
165
168
  globalThis.fetch(fallbackUrl, fallbackInit).then(resolve, reject);
166
169
  return;
167
170
  }
171
+ releaseSessionRef = refH2SessionForActiveRequest(session);
168
172
  options?.onH2RequestCreated?.();
169
173
  ensureH2SessionListenerBudget(session);
170
174
  const cleanupBeforeResponseListeners = () => {
@@ -172,11 +176,17 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
172
176
  session.off("goaway", onSessionGoaway);
173
177
  session.off("error", onSessionError);
174
178
  };
179
+ const cleanupActiveRequest = () => {
180
+ if (abort)
181
+ signal?.removeEventListener("abort", abort);
182
+ releaseSessionRef();
183
+ };
175
184
  const rejectBeforeResponse = (err) => {
176
185
  if (settled)
177
186
  return;
178
187
  settled = true;
179
188
  cleanupBeforeResponseListeners();
189
+ cleanupActiveRequest();
180
190
  req?.close();
181
191
  reject(err);
182
192
  };
@@ -192,19 +202,21 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
192
202
  session.once("close", onSessionClose);
193
203
  session.once("goaway", onSessionGoaway);
194
204
  session.once("error", onSessionError);
195
- const abort = () => {
205
+ abort = () => {
196
206
  req?.close();
197
207
  const abortError = new DOMException("The operation was aborted.", "AbortError");
198
208
  if (!responded) {
199
209
  if (!settled) {
200
210
  settled = true;
201
211
  cleanupBeforeResponseListeners();
212
+ cleanupActiveRequest();
202
213
  reject(abortError);
203
214
  }
204
215
  return;
205
216
  }
206
217
  if (!streamClosed) {
207
218
  streamClosed = true;
219
+ cleanupActiveRequest();
208
220
  streamController?.error(abortError);
209
221
  }
210
222
  };
@@ -213,6 +225,7 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
213
225
  req.close();
214
226
  cleanupBeforeResponseListeners();
215
227
  settled = true;
228
+ cleanupActiveRequest();
216
229
  reject(new DOMException("The operation was aborted.", "AbortError"));
217
230
  return;
218
231
  }
@@ -236,25 +249,31 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
236
249
  const readable = new ReadableStream({
237
250
  start(controller) {
238
251
  streamController = controller;
252
+ const finishStream = (finish) => {
253
+ if (streamClosed)
254
+ return;
255
+ streamClosed = true;
256
+ cleanupActiveRequest();
257
+ finish();
258
+ };
239
259
  req.on("data", (chunk) => {
240
260
  if (!streamClosed)
241
261
  controller.enqueue(new Uint8Array(chunk));
242
262
  });
243
263
  req.on("end", () => {
244
- if (!streamClosed) {
245
- streamClosed = true;
246
- signal?.removeEventListener("abort", abort);
247
- controller.close();
248
- }
264
+ finishStream(() => controller.close());
249
265
  });
250
266
  req.on("error", (err) => {
251
- if (!streamClosed) {
252
- streamClosed = true;
253
- signal?.removeEventListener("abort", abort);
254
- controller.error(err);
255
- }
267
+ finishStream(() => controller.error(err));
256
268
  });
257
269
  },
270
+ cancel() {
271
+ req?.close();
272
+ if (streamClosed)
273
+ return;
274
+ streamClosed = true;
275
+ cleanupActiveRequest();
276
+ },
258
277
  });
259
278
  resolve(new Response(readable, { status, headers: resHeaders }));
260
279
  });
@@ -263,6 +282,7 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit, op
263
282
  return;
264
283
  settled = true;
265
284
  cleanupBeforeResponseListeners();
285
+ cleanupActiveRequest();
266
286
  reject(err);
267
287
  });
268
288
  if (body) {
@@ -0,0 +1,29 @@
1
+ const idleUnrefSessions = new WeakSet();
2
+ const activeRequestCounts = new WeakMap();
3
+ export function markH2SessionIdleUnref(session) {
4
+ idleUnrefSessions.add(session);
5
+ if ((activeRequestCounts.get(session) ?? 0) === 0) {
6
+ session.unref();
7
+ }
8
+ }
9
+ export function refH2SessionForActiveRequest(session) {
10
+ if (!idleUnrefSessions.has(session))
11
+ return () => { };
12
+ const previousActiveRequests = activeRequestCounts.get(session) ?? 0;
13
+ activeRequestCounts.set(session, previousActiveRequests + 1);
14
+ if (previousActiveRequests === 0)
15
+ session.ref();
16
+ let released = false;
17
+ return () => {
18
+ if (released)
19
+ return;
20
+ released = true;
21
+ const activeRequests = activeRequestCounts.get(session);
22
+ if (activeRequests === undefined || activeRequests <= 1) {
23
+ activeRequestCounts.delete(session);
24
+ session.unref();
25
+ return;
26
+ }
27
+ activeRequestCounts.set(session, activeRequests - 1);
28
+ };
29
+ }
@@ -1,6 +1,7 @@
1
1
  import dns from "dns/promises";
2
2
  import http2 from "http2";
3
3
  import tls from "tls";
4
+ import { markH2SessionIdleUnref } from "./h2ref.js";
4
5
  export async function establishH2(sniHostname) {
5
6
  let timedOut = false;
6
7
  let timer;
@@ -36,13 +37,13 @@ async function _establishH2(sniHostname) {
36
37
  // Ensure the TLS socket is cleaned up on connection error
37
38
  if (!tlsSocket.destroyed)
38
39
  tlsSocket.destroy();
39
- reject(err);
40
+ reject(err instanceof Error ? err : new Error(String(err)));
40
41
  });
41
42
  });
42
43
  // Complete the SETTINGS exchange so the first real request has zero
43
44
  // protocol overhead. This RTT is hidden by the parallel createSandbox() call.
44
45
  await new Promise((resolve) => session.ping(() => resolve()));
45
- // Unref so the session doesn't prevent process exit
46
- session.unref();
46
+ // Unref so the idle session doesn't prevent process exit.
47
+ markH2SessionIdleUnref(session);
47
48
  return session;
48
49
  }
@@ -5,8 +5,8 @@ import { authentication } from "../authentication/index.js";
5
5
  import { env } from "../common/env.js";
6
6
  import { fs, os, path } from "../common/node.js";
7
7
  // Build info - these placeholders are replaced at build time by build:replace-imports
8
- const BUILD_VERSION = "0.2.83-preview.150";
9
- const BUILD_COMMIT = "73012d5f15da52b069b9cc136ca22126168ac7a8";
8
+ const BUILD_VERSION = "0.2.83";
9
+ const BUILD_COMMIT = "d6f07458e0f766e5ef3c547eec3b0e00cf3297f7";
10
10
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
11
11
  const BLAXEL_API_VERSION = "2026-04-16";
12
12
  // Cache for config.yaml tracking value