@blaxel/core 0.2.80-preview.139 → 0.2.80
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.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/common/h2fetch.js +35 -33
- package/dist/cjs/common/h2pool.js +22 -2
- package/dist/cjs/common/settings.js +2 -2
- package/dist/cjs/types/common/h2fetch.d.ts +5 -2
- package/dist/cjs/types/common/h2pool.d.ts +7 -2
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/types/common/h2fetch.d.ts +5 -2
- package/dist/cjs-browser/types/common/h2pool.d.ts +7 -2
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/common/h2fetch.js +35 -33
- package/dist/esm/common/h2pool.js +21 -2
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/common/settings.js +2 -2
- package/package.json +1 -1
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createH2Fetch = createH2Fetch;
|
|
4
4
|
exports.createPoolBackedH2Fetch = createPoolBackedH2Fetch;
|
|
5
5
|
exports.h2RequestDirect = h2RequestDirect;
|
|
6
|
-
const H2_REQUEST_TIMEOUT_MS = 10_000;
|
|
7
6
|
/**
|
|
8
7
|
* Creates a fetch()-compatible function that sends requests over an existing
|
|
9
|
-
* HTTP/2 session. Falls back to
|
|
10
|
-
* destroyed
|
|
8
|
+
* HTTP/2 session. Falls back to globalThis.fetch() only when the session is
|
|
9
|
+
* closed/destroyed at call time (pre-flight, nothing sent on the wire).
|
|
10
|
+
*
|
|
11
|
+
* Any failure after session.request() succeeds propagates to the caller:
|
|
12
|
+
* this transport never retries. Retry and timeout policy are caller concerns.
|
|
11
13
|
*/
|
|
12
14
|
function createH2Fetch(session) {
|
|
13
15
|
return (input) => {
|
|
@@ -78,7 +80,8 @@ function h2RequestDirect(session, url, init) {
|
|
|
78
80
|
}
|
|
79
81
|
else {
|
|
80
82
|
// FormData, ReadableStream, Blob, etc. can't be serialized to Buffer
|
|
81
|
-
// for manual H2 framing — fall back to regular fetch
|
|
83
|
+
// for manual H2 framing — fall back to regular fetch (pre-flight,
|
|
84
|
+
// nothing has been sent on the wire yet).
|
|
82
85
|
return globalThis.fetch(url, init);
|
|
83
86
|
}
|
|
84
87
|
if (!h2Headers["content-length"]) {
|
|
@@ -116,42 +119,49 @@ async function _h2Request(session, input) {
|
|
|
116
119
|
}
|
|
117
120
|
function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit) {
|
|
118
121
|
return new Promise((resolve, reject) => {
|
|
122
|
+
let settled = false;
|
|
123
|
+
let responded = false;
|
|
124
|
+
let streamController = null;
|
|
125
|
+
let streamClosed = false;
|
|
119
126
|
let req;
|
|
120
127
|
try {
|
|
121
128
|
req = session.request(h2Headers);
|
|
122
129
|
}
|
|
123
130
|
catch {
|
|
124
|
-
|
|
131
|
+
// Pre-flight fallback: session.request() threw synchronously, so no
|
|
132
|
+
// H2 frames were sent. Safe to retry over globalThis.fetch.
|
|
133
|
+
globalThis.fetch(fallbackUrl, fallbackInit).then(resolve, reject);
|
|
134
|
+
return;
|
|
125
135
|
}
|
|
126
|
-
const
|
|
127
|
-
if (settled)
|
|
128
|
-
return;
|
|
129
|
-
settled = true;
|
|
136
|
+
const abort = () => {
|
|
130
137
|
req.close();
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
const abortError = new DOMException("The operation was aborted.", "AbortError");
|
|
139
|
+
if (!responded) {
|
|
140
|
+
if (!settled) {
|
|
141
|
+
settled = true;
|
|
142
|
+
reject(abortError);
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (!streamClosed) {
|
|
147
|
+
streamClosed = true;
|
|
148
|
+
streamController?.error(abortError);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
133
151
|
if (signal) {
|
|
134
152
|
if (signal.aborted) {
|
|
135
|
-
clearTimeout(timer);
|
|
136
153
|
req.close();
|
|
154
|
+
settled = true;
|
|
137
155
|
reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
138
156
|
return;
|
|
139
157
|
}
|
|
140
|
-
signal.addEventListener("abort",
|
|
141
|
-
clearTimeout(timer);
|
|
142
|
-
req.close();
|
|
143
|
-
if (!settled) {
|
|
144
|
-
settled = true;
|
|
145
|
-
reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
146
|
-
}
|
|
147
|
-
}, { once: true });
|
|
158
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
148
159
|
}
|
|
149
|
-
let settled = false;
|
|
150
160
|
req.on("response", (headers) => {
|
|
151
|
-
clearTimeout(timer);
|
|
152
161
|
if (settled)
|
|
153
162
|
return;
|
|
154
163
|
settled = true;
|
|
164
|
+
responded = true;
|
|
155
165
|
const status = headers[":status"] ?? 200;
|
|
156
166
|
const resHeaders = new Headers();
|
|
157
167
|
for (const [k, v] of Object.entries(headers)) {
|
|
@@ -161,9 +171,9 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit) {
|
|
|
161
171
|
continue;
|
|
162
172
|
resHeaders.set(k, Array.isArray(v) ? v.join(", ") : String(v));
|
|
163
173
|
}
|
|
164
|
-
let streamClosed = false;
|
|
165
174
|
const readable = new ReadableStream({
|
|
166
175
|
start(controller) {
|
|
176
|
+
streamController = controller;
|
|
167
177
|
req.on("data", (chunk) => {
|
|
168
178
|
if (!streamClosed)
|
|
169
179
|
controller.enqueue(new Uint8Array(chunk));
|
|
@@ -180,23 +190,15 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit) {
|
|
|
180
190
|
controller.error(err);
|
|
181
191
|
}
|
|
182
192
|
});
|
|
183
|
-
signal?.addEventListener("abort", () => {
|
|
184
|
-
req.close();
|
|
185
|
-
if (!streamClosed) {
|
|
186
|
-
streamClosed = true;
|
|
187
|
-
controller.error(new DOMException("The operation was aborted.", "AbortError"));
|
|
188
|
-
}
|
|
189
|
-
}, { once: true });
|
|
190
193
|
},
|
|
191
194
|
});
|
|
192
195
|
resolve(new Response(readable, { status, headers: resHeaders }));
|
|
193
196
|
});
|
|
194
|
-
req.on("error", () => {
|
|
195
|
-
clearTimeout(timer);
|
|
197
|
+
req.on("error", (err) => {
|
|
196
198
|
if (settled)
|
|
197
199
|
return;
|
|
198
200
|
settled = true;
|
|
199
|
-
|
|
201
|
+
reject(err);
|
|
200
202
|
});
|
|
201
203
|
if (body) {
|
|
202
204
|
req.end(body);
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.h2Pool = void 0;
|
|
36
|
+
exports.h2Pool = exports.H2Pool = void 0;
|
|
37
37
|
/**
|
|
38
38
|
* Singleton H2 session pool keyed by edge domain.
|
|
39
39
|
*
|
|
@@ -49,13 +49,32 @@ class H2Pool {
|
|
|
49
49
|
/**
|
|
50
50
|
* Lazily resolve the establish function so the http2 / tls / dns modules
|
|
51
51
|
* are only imported in Node.js environments.
|
|
52
|
+
*
|
|
53
|
+
* Wires up self-healing eviction: the session is removed from the cache
|
|
54
|
+
* as soon as it emits `goaway`, `error`, or `close`, so `tryGet()` never
|
|
55
|
+
* returns a dead session. This replaces the old behavior of papering
|
|
56
|
+
* over session failures at the fetch layer.
|
|
52
57
|
*/
|
|
53
58
|
async establish(domain) {
|
|
54
59
|
if (!this._establish) {
|
|
55
60
|
const { establishH2 } = await Promise.resolve().then(() => __importStar(require("./h2warm.js")));
|
|
56
61
|
this._establish = establishH2;
|
|
57
62
|
}
|
|
58
|
-
|
|
63
|
+
const session = await this._establish(domain);
|
|
64
|
+
this.attachEvictionListeners(domain, session);
|
|
65
|
+
return session;
|
|
66
|
+
}
|
|
67
|
+
attachEvictionListeners(domain, session) {
|
|
68
|
+
const evict = () => {
|
|
69
|
+
// Only evict if this specific session is still the cached one.
|
|
70
|
+
// A newer session may have taken its place after reconnect.
|
|
71
|
+
if (this.sessions.get(domain) === session) {
|
|
72
|
+
this.sessions.delete(domain);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
session.on("goaway", evict);
|
|
76
|
+
session.on("error", evict);
|
|
77
|
+
session.on("close", evict);
|
|
59
78
|
}
|
|
60
79
|
/**
|
|
61
80
|
* Fire-and-forget background warming. Safe to call multiple times for
|
|
@@ -134,4 +153,5 @@ class H2Pool {
|
|
|
134
153
|
this.inflight.clear();
|
|
135
154
|
}
|
|
136
155
|
}
|
|
156
|
+
exports.H2Pool = H2Pool;
|
|
137
157
|
exports.h2Pool = new H2Pool();
|
|
@@ -11,8 +11,8 @@ const index_js_1 = require("../authentication/index.js");
|
|
|
11
11
|
const env_js_1 = require("../common/env.js");
|
|
12
12
|
const node_js_1 = require("../common/node.js");
|
|
13
13
|
// Build info - these placeholders are replaced at build time by build:replace-imports
|
|
14
|
-
const BUILD_VERSION = "0.2.80
|
|
15
|
-
const BUILD_COMMIT = "
|
|
14
|
+
const BUILD_VERSION = "0.2.80";
|
|
15
|
+
const BUILD_COMMIT = "800934e57ec03de060b909ccb1f5599343cae9e5";
|
|
16
16
|
const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
|
|
17
17
|
// Cache for config.yaml tracking value
|
|
18
18
|
let configTrackingValue = null;
|
|
@@ -2,8 +2,11 @@ import http2 from "http2";
|
|
|
2
2
|
import type { h2Pool as H2PoolType } from "./h2pool.js";
|
|
3
3
|
/**
|
|
4
4
|
* Creates a fetch()-compatible function that sends requests over an existing
|
|
5
|
-
* HTTP/2 session. Falls back to
|
|
6
|
-
* destroyed
|
|
5
|
+
* HTTP/2 session. Falls back to globalThis.fetch() only when the session is
|
|
6
|
+
* closed/destroyed at call time (pre-flight, nothing sent on the wire).
|
|
7
|
+
*
|
|
8
|
+
* Any failure after session.request() succeeds propagates to the caller:
|
|
9
|
+
* this transport never retries. Retry and timeout policy are caller concerns.
|
|
7
10
|
*/
|
|
8
11
|
export declare function createH2Fetch(session: http2.ClientHttp2Session): (input: Request) => Promise<Response>;
|
|
9
12
|
/**
|
|
@@ -7,15 +7,21 @@ import type http2 from "http2";
|
|
|
7
7
|
* an in-flight warming, or establishes a fresh one.
|
|
8
8
|
* - Closed / destroyed sessions are automatically evicted.
|
|
9
9
|
*/
|
|
10
|
-
declare class H2Pool {
|
|
10
|
+
export declare class H2Pool {
|
|
11
11
|
private sessions;
|
|
12
12
|
private inflight;
|
|
13
13
|
private _establish;
|
|
14
14
|
/**
|
|
15
15
|
* Lazily resolve the establish function so the http2 / tls / dns modules
|
|
16
16
|
* are only imported in Node.js environments.
|
|
17
|
+
*
|
|
18
|
+
* Wires up self-healing eviction: the session is removed from the cache
|
|
19
|
+
* as soon as it emits `goaway`, `error`, or `close`, so `tryGet()` never
|
|
20
|
+
* returns a dead session. This replaces the old behavior of papering
|
|
21
|
+
* over session failures at the fetch layer.
|
|
17
22
|
*/
|
|
18
23
|
private establish;
|
|
24
|
+
private attachEvictionListeners;
|
|
19
25
|
/**
|
|
20
26
|
* Fire-and-forget background warming. Safe to call multiple times for
|
|
21
27
|
* the same domain — only one connection attempt per domain at a time.
|
|
@@ -35,4 +41,3 @@ declare class H2Pool {
|
|
|
35
41
|
closeAll(): void;
|
|
36
42
|
}
|
|
37
43
|
export declare const h2Pool: H2Pool;
|
|
38
|
-
export {};
|