@vacbo/opencode-anthropic-fix 0.1.7 → 0.1.9
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/README.md +88 -88
- package/dist/opencode-anthropic-auth-cli.mjs +804 -507
- package/dist/opencode-anthropic-auth-plugin.js +4751 -4109
- package/package.json +67 -59
- package/src/__tests__/billing-edge-cases.test.ts +59 -59
- package/src/__tests__/bun-proxy.parallel.test.ts +388 -382
- package/src/__tests__/cc-comparison.test.ts +87 -87
- package/src/__tests__/cc-credentials.test.ts +254 -250
- package/src/__tests__/cch-drift-checker.test.ts +51 -51
- package/src/__tests__/cch-native-style.test.ts +56 -56
- package/src/__tests__/debug-gating.test.ts +42 -42
- package/src/__tests__/decomposition-smoke.test.ts +68 -68
- package/src/__tests__/fingerprint-regression.test.ts +575 -566
- package/src/__tests__/helpers/conversation-history.smoke.test.ts +271 -271
- package/src/__tests__/helpers/conversation-history.ts +119 -119
- package/src/__tests__/helpers/deferred.smoke.test.ts +103 -103
- package/src/__tests__/helpers/deferred.ts +69 -69
- package/src/__tests__/helpers/in-memory-storage.smoke.test.ts +155 -155
- package/src/__tests__/helpers/in-memory-storage.ts +88 -88
- package/src/__tests__/helpers/mock-bun-proxy.smoke.test.ts +68 -68
- package/src/__tests__/helpers/mock-bun-proxy.ts +189 -189
- package/src/__tests__/helpers/plugin-fetch-harness.smoke.test.ts +273 -273
- package/src/__tests__/helpers/plugin-fetch-harness.ts +288 -288
- package/src/__tests__/helpers/sse.smoke.test.ts +236 -236
- package/src/__tests__/helpers/sse.ts +209 -209
- package/src/__tests__/index.parallel.test.ts +605 -595
- package/src/__tests__/sanitization-regex.test.ts +112 -112
- package/src/__tests__/state-bounds.test.ts +90 -90
- package/src/account-identity.test.ts +197 -192
- package/src/account-identity.ts +69 -67
- package/src/account-state.test.ts +86 -86
- package/src/account-state.ts +25 -25
- package/src/accounts/matching.test.ts +335 -0
- package/src/accounts/matching.ts +167 -0
- package/src/accounts/persistence.test.ts +345 -0
- package/src/accounts/persistence.ts +432 -0
- package/src/accounts/repair.test.ts +276 -0
- package/src/accounts/repair.ts +407 -0
- package/src/accounts.dedup.test.ts +621 -621
- package/src/accounts.test.ts +933 -929
- package/src/accounts.ts +633 -989
- package/src/backoff.test.ts +345 -345
- package/src/backoff.ts +219 -219
- package/src/betas.ts +124 -124
- package/src/bun-fetch.test.ts +345 -342
- package/src/bun-fetch.ts +424 -424
- package/src/bun-proxy.test.ts +25 -25
- package/src/bun-proxy.ts +209 -209
- package/src/cc-credentials.ts +111 -111
- package/src/circuit-breaker.test.ts +184 -184
- package/src/circuit-breaker.ts +169 -169
- package/src/cli/commands/auth.ts +963 -0
- package/src/cli/commands/config.ts +547 -0
- package/src/cli/formatting.test.ts +406 -0
- package/src/cli/formatting.ts +219 -0
- package/src/cli.ts +255 -2022
- package/src/commands/handlers/betas.ts +100 -0
- package/src/commands/handlers/config.ts +99 -0
- package/src/commands/handlers/files.ts +375 -0
- package/src/commands/oauth-flow.ts +181 -166
- package/src/commands/prompts.ts +61 -61
- package/src/commands/router.test.ts +421 -0
- package/src/commands/router.ts +143 -635
- package/src/config.test.ts +482 -482
- package/src/config.ts +412 -404
- package/src/constants.ts +48 -48
- package/src/drift/cch-constants.ts +95 -95
- package/src/env.ts +111 -105
- package/src/headers/billing.ts +33 -33
- package/src/headers/builder.ts +130 -130
- package/src/headers/cch.ts +75 -75
- package/src/headers/stainless.ts +25 -25
- package/src/headers/user-agent.ts +23 -23
- package/src/index.ts +436 -828
- package/src/models.ts +27 -27
- package/src/oauth.test.ts +102 -102
- package/src/oauth.ts +178 -178
- package/src/parent-pid-watcher.test.ts +148 -148
- package/src/parent-pid-watcher.ts +69 -69
- package/src/plugin-helpers.ts +82 -82
- package/src/refresh-helpers.ts +145 -139
- package/src/refresh-lock.test.ts +94 -94
- package/src/refresh-lock.ts +93 -93
- package/src/request/body.history.test.ts +579 -571
- package/src/request/body.ts +255 -255
- package/src/request/metadata.ts +65 -65
- package/src/request/retry.test.ts +156 -156
- package/src/request/retry.ts +67 -67
- package/src/request/url.ts +21 -21
- package/src/request-orchestration-helpers.ts +648 -0
- package/src/response/index.ts +5 -5
- package/src/response/mcp.ts +58 -58
- package/src/response/streaming.test.ts +313 -311
- package/src/response/streaming.ts +412 -410
- package/src/rotation.test.ts +304 -301
- package/src/rotation.ts +205 -205
- package/src/storage.test.ts +547 -547
- package/src/storage.ts +315 -291
- package/src/system-prompt/builder.ts +38 -38
- package/src/system-prompt/index.ts +5 -5
- package/src/system-prompt/normalize.ts +60 -60
- package/src/system-prompt/sanitize.ts +30 -30
- package/src/thinking.ts +21 -20
- package/src/token-refresh.test.ts +265 -265
- package/src/token-refresh.ts +219 -214
- package/src/types.ts +30 -30
- package/dist/bun-proxy.mjs +0 -291
package/src/bun-fetch.ts
CHANGED
|
@@ -17,107 +17,107 @@ type FetchInput = string | URL | Request;
|
|
|
17
17
|
type ForwardFetch = (input: FetchInput, init?: RequestInit) => Promise<Response>;
|
|
18
18
|
|
|
19
19
|
type ProxyChildProcess = ChildProcess & {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
stdout: NodeJS.ReadableStream | null;
|
|
21
|
+
stderr: NodeJS.ReadableStream | null;
|
|
22
|
+
forwardFetch?: ForwardFetch;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
export interface BunFetchStatus {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
status: "state" | "fallback";
|
|
27
|
+
mode: "native" | "starting" | "proxy";
|
|
28
|
+
port: number | null;
|
|
29
|
+
bunAvailable: boolean | null;
|
|
30
|
+
childPid: number | null;
|
|
31
|
+
circuitState: CircuitState;
|
|
32
|
+
circuitFailureCount: number;
|
|
33
|
+
reason: string;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export interface BunFetchOptions {
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
debug?: boolean;
|
|
38
|
+
onProxyStatus?: (status: BunFetchStatus) => void;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export interface BunFetchInstance {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
fetch: (input: FetchInput, init?: RequestInit) => Promise<Response>;
|
|
43
|
+
shutdown: () => Promise<void>;
|
|
44
|
+
getStatus: () => BunFetchStatus;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
interface BunFetchInternal extends BunFetchInstance {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
ensureProxy: (debugOverride?: boolean) => Promise<number | null>;
|
|
49
|
+
fetchWithDebug: (input: FetchInput, init?: RequestInit, debugOverride?: boolean) => Promise<Response>;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
interface StartProxyResult {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
child: ProxyChildProcess;
|
|
54
|
+
port: number;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
interface InstanceState {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
activeChild: ProxyChildProcess | null;
|
|
59
|
+
activePort: number | null;
|
|
60
|
+
startingChild: ProxyChildProcess | null;
|
|
61
|
+
startPromise: Promise<number | null> | null;
|
|
62
|
+
bunAvailable: boolean | null;
|
|
63
|
+
pendingFetches: Array<{
|
|
64
|
+
runProxy: (useForwardFetch: boolean) => void;
|
|
65
|
+
runNative: (reason: string) => void;
|
|
66
|
+
}>;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function findProxyScript(): string | null {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
const dir = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
71
|
+
|
|
72
|
+
for (const candidate of [
|
|
73
|
+
join(dir, "bun-proxy.mjs"),
|
|
74
|
+
join(dir, "..", "dist", "bun-proxy.mjs"),
|
|
75
|
+
join(dir, "bun-proxy.ts"),
|
|
76
|
+
]) {
|
|
77
|
+
if (existsSync(candidate)) {
|
|
78
|
+
return candidate;
|
|
79
|
+
}
|
|
79
80
|
}
|
|
80
|
-
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
return null;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
function detectBunAvailability(): boolean {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
try {
|
|
87
|
+
execFileSync("bun", ["--version"], { stdio: "ignore" });
|
|
88
|
+
return true;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function toHeaders(headersInit?: RequestInit["headers"]): Headers {
|
|
95
|
-
|
|
95
|
+
return new Headers(headersInit ?? undefined);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
function toRequestUrl(input: FetchInput): string {
|
|
99
|
-
|
|
99
|
+
return typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function resolveProxySignal(input: FetchInput, init?: RequestInit): AbortSignal | undefined {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
if (init?.signal) {
|
|
104
|
+
return init.signal;
|
|
105
|
+
}
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
return input instanceof Request ? input.signal : undefined;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
function buildProxyRequestInit(input: FetchInput, init?: RequestInit): RequestInit {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
111
|
+
const targetUrl = toRequestUrl(input);
|
|
112
|
+
const headers = toHeaders(init?.headers);
|
|
113
|
+
const signal = resolveProxySignal(input, init);
|
|
114
|
+
headers.set("x-proxy-url", targetUrl);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
...init,
|
|
118
|
+
headers,
|
|
119
|
+
...(signal ? { signal } : {}),
|
|
120
|
+
};
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
const DEBUG_DUMP_DIR = "/tmp";
|
|
@@ -125,420 +125,420 @@ const DEBUG_LATEST_REQUEST_PATH = `${DEBUG_DUMP_DIR}/opencode-last-request.json`
|
|
|
125
125
|
const DEBUG_LATEST_HEADERS_PATH = `${DEBUG_DUMP_DIR}/opencode-last-headers.json`;
|
|
126
126
|
|
|
127
127
|
interface DebugDumpPaths {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
requestPath: string;
|
|
129
|
+
headersPath: string;
|
|
130
|
+
latestRequestPath: string;
|
|
131
|
+
latestHeadersPath: string;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
function makeDebugDumpId(): string {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
const filesystemSafeTimestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
136
|
+
const subMillisecondCollisionGuard = randomUUID().slice(0, 8);
|
|
137
|
+
return `${filesystemSafeTimestamp}-${subMillisecondCollisionGuard}`;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
async function writeDebugArtifacts(url: string, init: RequestInit): Promise<DebugDumpPaths | null> {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const { writeFileSync } = await import("node:fs");
|
|
146
|
-
const id = makeDebugDumpId();
|
|
147
|
-
const requestPath = `${DEBUG_DUMP_DIR}/opencode-request-${id}.json`;
|
|
148
|
-
const headersPath = `${DEBUG_DUMP_DIR}/opencode-headers-${id}.json`;
|
|
149
|
-
|
|
150
|
-
const bodyText = typeof init.body === "string" ? init.body : JSON.stringify(init.body);
|
|
151
|
-
|
|
152
|
-
const logHeaders: Record<string, string> = {};
|
|
153
|
-
toHeaders(init.headers).forEach((value, key) => {
|
|
154
|
-
logHeaders[key] = key === "authorization" ? "Bearer ***" : value;
|
|
155
|
-
});
|
|
156
|
-
const headersText = JSON.stringify(logHeaders, null, 2);
|
|
157
|
-
|
|
158
|
-
writeFileSync(requestPath, bodyText);
|
|
159
|
-
writeFileSync(headersPath, headersText);
|
|
160
|
-
writeFileSync(DEBUG_LATEST_REQUEST_PATH, bodyText);
|
|
161
|
-
writeFileSync(DEBUG_LATEST_HEADERS_PATH, headersText);
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
requestPath,
|
|
165
|
-
headersPath,
|
|
166
|
-
latestRequestPath: DEBUG_LATEST_REQUEST_PATH,
|
|
167
|
-
latestHeadersPath: DEBUG_LATEST_HEADERS_PATH,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function createBunFetch(options: BunFetchOptions = {}): BunFetchInstance {
|
|
172
|
-
const breaker = createCircuitBreaker({
|
|
173
|
-
failureThreshold: DEFAULT_BREAKER_FAILURE_THRESHOLD,
|
|
174
|
-
resetTimeoutMs: DEFAULT_BREAKER_RESET_TIMEOUT_MS,
|
|
175
|
-
});
|
|
176
|
-
const closingChildren = new WeakSet<ProxyChildProcess>();
|
|
177
|
-
const defaultDebug = options.debug ?? false;
|
|
178
|
-
const onProxyStatus = options.onProxyStatus;
|
|
179
|
-
const state: InstanceState = {
|
|
180
|
-
activeChild: null,
|
|
181
|
-
activePort: null,
|
|
182
|
-
startingChild: null,
|
|
183
|
-
startPromise: null,
|
|
184
|
-
bunAvailable: null,
|
|
185
|
-
pendingFetches: [],
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
const getStatus = (reason = "idle", status: BunFetchStatus["status"] = "state"): BunFetchStatus => ({
|
|
189
|
-
status,
|
|
190
|
-
mode: state.activePort !== null ? "proxy" : state.startPromise ? "starting" : "native",
|
|
191
|
-
port: state.activePort,
|
|
192
|
-
bunAvailable: state.bunAvailable,
|
|
193
|
-
childPid: state.activeChild?.pid ?? state.startingChild?.pid ?? null,
|
|
194
|
-
circuitState: breaker.getState(),
|
|
195
|
-
circuitFailureCount: breaker.getFailureCount(),
|
|
196
|
-
reason,
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const reportStatus = (reason: string): void => {
|
|
200
|
-
onProxyStatus?.(getStatus(reason));
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
const reportFallback = (reason: string, _debugOverride?: boolean): void => {
|
|
204
|
-
onProxyStatus?.(getStatus(reason, "fallback"));
|
|
205
|
-
// eslint-disable-next-line no-console -- startup diagnostic for Bun unavailability; user-facing fallback notice
|
|
206
|
-
console.error(
|
|
207
|
-
`[opencode-anthropic-auth] Native fetch fallback engaged (${reason}); Bun proxy fingerprint mimicry disabled for this request`,
|
|
208
|
-
);
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
const resolveDebug = (debugOverride?: boolean): boolean => debugOverride ?? defaultDebug;
|
|
212
|
-
|
|
213
|
-
const clearActiveProxy = (child: ProxyChildProcess | null): void => {
|
|
214
|
-
if (child && state.activeChild === child) {
|
|
215
|
-
state.activeChild = null;
|
|
216
|
-
state.activePort = null;
|
|
141
|
+
if (!init.body || !url.includes("/v1/messages") || url.includes("count_tokens")) {
|
|
142
|
+
return null;
|
|
217
143
|
}
|
|
218
144
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const flushPendingFetches = (mode: "proxy" | "native", reason = "proxy-unavailable"): void => {
|
|
225
|
-
const pendingFetches = state.pendingFetches.splice(0, state.pendingFetches.length);
|
|
226
|
-
const useForwardFetch = pendingFetches.length <= 2;
|
|
227
|
-
for (const pendingFetch of pendingFetches) {
|
|
228
|
-
if (mode === "proxy") {
|
|
229
|
-
pendingFetch.runProxy(useForwardFetch);
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
pendingFetch.runNative(reason);
|
|
234
|
-
}
|
|
235
|
-
};
|
|
145
|
+
const { writeFileSync } = await import("node:fs");
|
|
146
|
+
const id = makeDebugDumpId();
|
|
147
|
+
const requestPath = `${DEBUG_DUMP_DIR}/opencode-request-${id}.json`;
|
|
148
|
+
const headersPath = `${DEBUG_DUMP_DIR}/opencode-headers-${id}.json`;
|
|
236
149
|
|
|
237
|
-
|
|
238
|
-
if (state.activeChild && state.activePort !== null && !state.activeChild.killed) {
|
|
239
|
-
return state.activePort;
|
|
240
|
-
}
|
|
150
|
+
const bodyText = typeof init.body === "string" ? init.body : JSON.stringify(init.body);
|
|
241
151
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
152
|
+
const logHeaders: Record<string, string> = {};
|
|
153
|
+
toHeaders(init.headers).forEach((value, key) => {
|
|
154
|
+
logHeaders[key] = key === "authorization" ? "Bearer ***" : value;
|
|
155
|
+
});
|
|
156
|
+
const headersText = JSON.stringify(logHeaders, null, 2);
|
|
157
|
+
|
|
158
|
+
writeFileSync(requestPath, bodyText);
|
|
159
|
+
writeFileSync(headersPath, headersText);
|
|
160
|
+
writeFileSync(DEBUG_LATEST_REQUEST_PATH, bodyText);
|
|
161
|
+
writeFileSync(DEBUG_LATEST_HEADERS_PATH, headersText);
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
requestPath,
|
|
165
|
+
headersPath,
|
|
166
|
+
latestRequestPath: DEBUG_LATEST_REQUEST_PATH,
|
|
167
|
+
latestHeadersPath: DEBUG_LATEST_HEADERS_PATH,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
245
170
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
171
|
+
export function createBunFetch(options: BunFetchOptions = {}): BunFetchInstance {
|
|
172
|
+
const breaker = createCircuitBreaker({
|
|
173
|
+
failureThreshold: DEFAULT_BREAKER_FAILURE_THRESHOLD,
|
|
174
|
+
resetTimeoutMs: DEFAULT_BREAKER_RESET_TIMEOUT_MS,
|
|
175
|
+
});
|
|
176
|
+
const closingChildren = new WeakSet<ProxyChildProcess>();
|
|
177
|
+
const defaultDebug = options.debug ?? false;
|
|
178
|
+
const onProxyStatus = options.onProxyStatus;
|
|
179
|
+
const state: InstanceState = {
|
|
180
|
+
activeChild: null,
|
|
181
|
+
activePort: null,
|
|
182
|
+
startingChild: null,
|
|
183
|
+
startPromise: null,
|
|
184
|
+
bunAvailable: null,
|
|
185
|
+
pendingFetches: [],
|
|
186
|
+
};
|
|
251
187
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
188
|
+
const getStatus = (reason = "idle", status: BunFetchStatus["status"] = "state"): BunFetchStatus => ({
|
|
189
|
+
status,
|
|
190
|
+
mode: state.activePort !== null ? "proxy" : state.startPromise ? "starting" : "native",
|
|
191
|
+
port: state.activePort,
|
|
192
|
+
bunAvailable: state.bunAvailable,
|
|
193
|
+
childPid: state.activeChild?.pid ?? state.startingChild?.pid ?? null,
|
|
194
|
+
circuitState: breaker.getState(),
|
|
195
|
+
circuitFailureCount: breaker.getFailureCount(),
|
|
196
|
+
reason,
|
|
197
|
+
});
|
|
257
198
|
|
|
258
|
-
const
|
|
259
|
-
|
|
199
|
+
const reportStatus = (reason: string): void => {
|
|
200
|
+
onProxyStatus?.(getStatus(reason));
|
|
201
|
+
};
|
|
260
202
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
203
|
+
const reportFallback = (reason: string, _debugOverride?: boolean): void => {
|
|
204
|
+
onProxyStatus?.(getStatus(reason, "fallback"));
|
|
205
|
+
// eslint-disable-next-line no-console -- startup diagnostic for Bun unavailability; user-facing fallback notice
|
|
206
|
+
console.error(
|
|
207
|
+
`[opencode-anthropic-auth] Native fetch fallback engaged (${reason}); Bun proxy fingerprint mimicry disabled for this request`,
|
|
208
|
+
);
|
|
209
|
+
};
|
|
267
210
|
|
|
268
|
-
|
|
269
|
-
const debugEnabled = resolveDebug(debugOverride);
|
|
270
|
-
|
|
271
|
-
let child: ProxyChildProcess;
|
|
272
|
-
|
|
273
|
-
try {
|
|
274
|
-
child = spawn("bun", ["run", script, "--parent-pid", String(process.pid)], {
|
|
275
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
276
|
-
env: {
|
|
277
|
-
...process.env,
|
|
278
|
-
OPENCODE_ANTHROPIC_DEBUG: debugEnabled ? "1" : "0",
|
|
279
|
-
},
|
|
280
|
-
}) as ProxyChildProcess;
|
|
281
|
-
} catch {
|
|
282
|
-
breaker.recordFailure();
|
|
283
|
-
reportStatus("spawn-failed");
|
|
284
|
-
flushPendingFetches("native", "spawn-failed");
|
|
285
|
-
resolve(null);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
state.startingChild = child;
|
|
290
|
-
reportStatus("starting");
|
|
291
|
-
|
|
292
|
-
const stdout = child.stdout;
|
|
293
|
-
if (!stdout) {
|
|
294
|
-
clearActiveProxy(child);
|
|
295
|
-
breaker.recordFailure();
|
|
296
|
-
reportStatus("stdout-missing");
|
|
297
|
-
flushPendingFetches("native", "stdout-missing");
|
|
298
|
-
resolve(null);
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
let settled = false;
|
|
303
|
-
const stdoutLines = readline.createInterface({ input: stdout });
|
|
304
|
-
const startupTimeout = setTimeout(() => {
|
|
305
|
-
finalize(null, "startup-timeout");
|
|
306
|
-
}, DEFAULT_STARTUP_TIMEOUT_MS);
|
|
307
|
-
|
|
308
|
-
startupTimeout.unref?.();
|
|
309
|
-
|
|
310
|
-
const cleanupStartupResources = (): void => {
|
|
311
|
-
clearTimeout(startupTimeout);
|
|
312
|
-
stdoutLines.close();
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
const finalize = (result: StartProxyResult | null, reason: string): void => {
|
|
316
|
-
if (settled) {
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
211
|
+
const resolveDebug = (debugOverride?: boolean): boolean => debugOverride ?? defaultDebug;
|
|
319
212
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
state.startingChild = null;
|
|
325
|
-
state.activeChild = result.child;
|
|
326
|
-
state.activePort = result.port;
|
|
327
|
-
breaker.recordSuccess();
|
|
328
|
-
reportStatus(reason);
|
|
329
|
-
flushPendingFetches("proxy");
|
|
330
|
-
resolve(result.port);
|
|
331
|
-
return;
|
|
213
|
+
const clearActiveProxy = (child: ProxyChildProcess | null): void => {
|
|
214
|
+
if (child && state.activeChild === child) {
|
|
215
|
+
state.activeChild = null;
|
|
216
|
+
state.activePort = null;
|
|
332
217
|
}
|
|
333
218
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
reportStatus(reason);
|
|
337
|
-
flushPendingFetches("native", reason);
|
|
338
|
-
resolve(null);
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
stdoutLines.on("line", (line) => {
|
|
342
|
-
const match = line.match(/^BUN_PROXY_PORT=(\d+)$/);
|
|
343
|
-
if (!match) {
|
|
344
|
-
return;
|
|
219
|
+
if (child && state.startingChild === child) {
|
|
220
|
+
state.startingChild = null;
|
|
345
221
|
}
|
|
222
|
+
};
|
|
346
223
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
child.once("error", () => {
|
|
357
|
-
finalize(null, "child-error");
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
child.once("exit", () => {
|
|
361
|
-
const shutdownOwned = closingChildren.has(child);
|
|
362
|
-
const isCurrentChild = state.activeChild === child || state.startingChild === child;
|
|
224
|
+
const flushPendingFetches = (mode: "proxy" | "native", reason = "proxy-unavailable"): void => {
|
|
225
|
+
const pendingFetches = state.pendingFetches.splice(0, state.pendingFetches.length);
|
|
226
|
+
const useForwardFetch = pendingFetches.length <= 2;
|
|
227
|
+
for (const pendingFetch of pendingFetches) {
|
|
228
|
+
if (mode === "proxy") {
|
|
229
|
+
pendingFetch.runProxy(useForwardFetch);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
363
232
|
|
|
364
|
-
|
|
233
|
+
pendingFetch.runNative(reason);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
365
236
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
237
|
+
const startProxy = async (debugOverride?: boolean): Promise<number | null> => {
|
|
238
|
+
if (state.activeChild && state.activePort !== null && !state.activeChild.killed) {
|
|
239
|
+
return state.activePort;
|
|
369
240
|
}
|
|
370
241
|
|
|
371
|
-
if (
|
|
372
|
-
|
|
373
|
-
reportStatus("child-exited");
|
|
242
|
+
if (state.startPromise) {
|
|
243
|
+
return state.startPromise;
|
|
374
244
|
}
|
|
375
|
-
});
|
|
376
|
-
}).finally(() => {
|
|
377
|
-
state.startPromise = null;
|
|
378
|
-
});
|
|
379
245
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const children = [state.startingChild, state.activeChild].filter(
|
|
385
|
-
(child): child is ProxyChildProcess => child !== null,
|
|
386
|
-
);
|
|
387
|
-
|
|
388
|
-
state.startPromise = null;
|
|
389
|
-
state.startingChild = null;
|
|
390
|
-
state.activeChild = null;
|
|
391
|
-
state.activePort = null;
|
|
392
|
-
|
|
393
|
-
for (const child of children) {
|
|
394
|
-
closingChildren.add(child);
|
|
395
|
-
if (!child.killed) {
|
|
396
|
-
try {
|
|
397
|
-
child.kill("SIGTERM");
|
|
398
|
-
} catch {
|
|
399
|
-
// Process may have already exited; ignore kill failures
|
|
246
|
+
if (!breaker.canExecute()) {
|
|
247
|
+
reportStatus("breaker-open");
|
|
248
|
+
flushPendingFetches("native", "breaker-open");
|
|
249
|
+
return null;
|
|
400
250
|
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
251
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
252
|
+
if (state.bunAvailable === false) {
|
|
253
|
+
reportStatus("bun-unavailable");
|
|
254
|
+
flushPendingFetches("native", "bun-unavailable");
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
407
257
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
init: RequestInit | undefined,
|
|
411
|
-
debugOverride?: boolean,
|
|
412
|
-
): Promise<Response> => {
|
|
413
|
-
const url = toRequestUrl(input);
|
|
414
|
-
const fetchNative = async (reason: string): Promise<Response> => {
|
|
415
|
-
reportFallback(reason, debugOverride);
|
|
416
|
-
|
|
417
|
-
return globalThis.fetch(input, init);
|
|
418
|
-
};
|
|
258
|
+
const script = findProxyScript();
|
|
259
|
+
state.bunAvailable = detectBunAvailability();
|
|
419
260
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if (resolveDebug(debugOverride)) {
|
|
427
|
-
// eslint-disable-next-line no-console -- debug-gated proxy status log; only emits when OPENCODE_ANTHROPIC_DEBUG=1
|
|
428
|
-
console.error(`[opencode-anthropic-auth] Routing through Bun proxy at :${port} → ${url}`);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (resolveDebug(debugOverride)) {
|
|
432
|
-
try {
|
|
433
|
-
const dumped = await writeDebugArtifacts(url, init ?? {});
|
|
434
|
-
if (dumped) {
|
|
435
|
-
// eslint-disable-next-line no-console -- debug-gated diagnostic; confirms request artifact dump location
|
|
436
|
-
console.error(
|
|
437
|
-
`[opencode-anthropic-auth] Dumped request to ${dumped.requestPath} (latest alias: ${dumped.latestRequestPath})`,
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
|
-
} catch (error) {
|
|
441
|
-
// eslint-disable-next-line no-console -- error-path diagnostic surfaced to stderr for operator visibility
|
|
442
|
-
console.error("[opencode-anthropic-auth] Failed to dump request:", error);
|
|
261
|
+
if (!script || !state.bunAvailable) {
|
|
262
|
+
breaker.recordFailure();
|
|
263
|
+
reportStatus(script ? "bun-unavailable" : "proxy-script-missing");
|
|
264
|
+
flushPendingFetches("native", script ? "bun-unavailable" : "proxy-script-missing");
|
|
265
|
+
return null;
|
|
443
266
|
}
|
|
444
|
-
}
|
|
445
267
|
|
|
446
|
-
|
|
447
|
-
|
|
268
|
+
state.startPromise = new Promise<number | null>((resolve) => {
|
|
269
|
+
const debugEnabled = resolveDebug(debugOverride);
|
|
270
|
+
|
|
271
|
+
let child: ProxyChildProcess;
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
child = spawn("bun", ["run", script, "--parent-pid", String(process.pid)], {
|
|
275
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
276
|
+
env: {
|
|
277
|
+
...process.env,
|
|
278
|
+
OPENCODE_ANTHROPIC_DEBUG: debugEnabled ? "1" : "0",
|
|
279
|
+
},
|
|
280
|
+
}) as ProxyChildProcess;
|
|
281
|
+
} catch {
|
|
282
|
+
breaker.recordFailure();
|
|
283
|
+
reportStatus("spawn-failed");
|
|
284
|
+
flushPendingFetches("native", "spawn-failed");
|
|
285
|
+
resolve(null);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
state.startingChild = child;
|
|
290
|
+
reportStatus("starting");
|
|
291
|
+
|
|
292
|
+
const stdout = child.stdout;
|
|
293
|
+
if (!stdout) {
|
|
294
|
+
clearActiveProxy(child);
|
|
295
|
+
breaker.recordFailure();
|
|
296
|
+
reportStatus("stdout-missing");
|
|
297
|
+
flushPendingFetches("native", "stdout-missing");
|
|
298
|
+
resolve(null);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
let settled = false;
|
|
303
|
+
const stdoutLines = readline.createInterface({ input: stdout });
|
|
304
|
+
const startupTimeout = setTimeout(() => {
|
|
305
|
+
finalize(null, "startup-timeout");
|
|
306
|
+
}, DEFAULT_STARTUP_TIMEOUT_MS);
|
|
307
|
+
|
|
308
|
+
startupTimeout.unref?.();
|
|
309
|
+
|
|
310
|
+
const cleanupStartupResources = (): void => {
|
|
311
|
+
clearTimeout(startupTimeout);
|
|
312
|
+
stdoutLines.close();
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const finalize = (result: StartProxyResult | null, reason: string): void => {
|
|
316
|
+
if (settled) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
settled = true;
|
|
321
|
+
cleanupStartupResources();
|
|
322
|
+
|
|
323
|
+
if (result) {
|
|
324
|
+
state.startingChild = null;
|
|
325
|
+
state.activeChild = result.child;
|
|
326
|
+
state.activePort = result.port;
|
|
327
|
+
breaker.recordSuccess();
|
|
328
|
+
reportStatus(reason);
|
|
329
|
+
flushPendingFetches("proxy");
|
|
330
|
+
resolve(result.port);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
clearActiveProxy(child);
|
|
335
|
+
breaker.recordFailure();
|
|
336
|
+
reportStatus(reason);
|
|
337
|
+
flushPendingFetches("native", reason);
|
|
338
|
+
resolve(null);
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
stdoutLines.on("line", (line) => {
|
|
342
|
+
const match = line.match(/^BUN_PROXY_PORT=(\d+)$/);
|
|
343
|
+
if (!match) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
finalize(
|
|
348
|
+
{
|
|
349
|
+
child,
|
|
350
|
+
port: Number.parseInt(match[1], 10),
|
|
351
|
+
},
|
|
352
|
+
"proxy-ready",
|
|
353
|
+
);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
child.once("error", () => {
|
|
357
|
+
finalize(null, "child-error");
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
child.once("exit", () => {
|
|
361
|
+
const shutdownOwned = closingChildren.has(child);
|
|
362
|
+
const isCurrentChild = state.activeChild === child || state.startingChild === child;
|
|
363
|
+
|
|
364
|
+
clearActiveProxy(child);
|
|
365
|
+
|
|
366
|
+
if (!settled) {
|
|
367
|
+
finalize(null, shutdownOwned ? "shutdown-complete" : "child-exit-before-ready");
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (!shutdownOwned && isCurrentChild) {
|
|
372
|
+
breaker.recordFailure();
|
|
373
|
+
reportStatus("child-exited");
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
}).finally(() => {
|
|
377
|
+
state.startPromise = null;
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
return state.startPromise;
|
|
381
|
+
};
|
|
448
382
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
383
|
+
const shutdown = async (): Promise<void> => {
|
|
384
|
+
const children = [state.startingChild, state.activeChild].filter(
|
|
385
|
+
(child): child is ProxyChildProcess => child !== null,
|
|
386
|
+
);
|
|
452
387
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
388
|
+
state.startPromise = null;
|
|
389
|
+
state.startingChild = null;
|
|
390
|
+
state.activeChild = null;
|
|
391
|
+
state.activePort = null;
|
|
392
|
+
|
|
393
|
+
for (const child of children) {
|
|
394
|
+
closingChildren.add(child);
|
|
395
|
+
if (!child.killed) {
|
|
396
|
+
try {
|
|
397
|
+
child.kill("SIGTERM");
|
|
398
|
+
} catch {
|
|
399
|
+
// Process may have already exited; ignore kill failures
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
457
403
|
|
|
458
|
-
|
|
404
|
+
breaker.dispose();
|
|
405
|
+
reportStatus("shutdown-requested");
|
|
459
406
|
};
|
|
460
407
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
return;
|
|
471
|
-
|
|
408
|
+
const fetchThroughProxy = async (
|
|
409
|
+
input: FetchInput,
|
|
410
|
+
init: RequestInit | undefined,
|
|
411
|
+
debugOverride?: boolean,
|
|
412
|
+
): Promise<Response> => {
|
|
413
|
+
const url = toRequestUrl(input);
|
|
414
|
+
const fetchNative = async (reason: string): Promise<Response> => {
|
|
415
|
+
reportFallback(reason, debugOverride);
|
|
416
|
+
|
|
417
|
+
return globalThis.fetch(input, init);
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const fetchFromActiveProxy = async (useForwardFetch: boolean): Promise<Response> => {
|
|
421
|
+
const port = state.activePort;
|
|
422
|
+
if (port === null) {
|
|
423
|
+
return fetchNative("proxy-port-missing");
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (resolveDebug(debugOverride)) {
|
|
427
|
+
// eslint-disable-next-line no-console -- debug-gated proxy status log; only emits when OPENCODE_ANTHROPIC_DEBUG=1
|
|
428
|
+
console.error(`[opencode-anthropic-auth] Routing through Bun proxy at :${port} → ${url}`);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (resolveDebug(debugOverride)) {
|
|
432
|
+
try {
|
|
433
|
+
const dumped = await writeDebugArtifacts(url, init ?? {});
|
|
434
|
+
if (dumped) {
|
|
435
|
+
// eslint-disable-next-line no-console -- debug-gated diagnostic; confirms request artifact dump location
|
|
436
|
+
console.error(
|
|
437
|
+
`[opencode-anthropic-auth] Dumped request to ${dumped.requestPath} (latest alias: ${dumped.latestRequestPath})`,
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
} catch (error) {
|
|
441
|
+
// eslint-disable-next-line no-console -- error-path diagnostic surfaced to stderr for operator visibility
|
|
442
|
+
console.error("[opencode-anthropic-auth] Failed to dump request:", error);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const proxyInit = buildProxyRequestInit(input, init);
|
|
447
|
+
const forwardFetch = state.activeChild?.forwardFetch;
|
|
448
|
+
|
|
449
|
+
const response = await (useForwardFetch && typeof forwardFetch === "function"
|
|
450
|
+
? forwardFetch(`http://${DEFAULT_PROXY_HOST}:${port}/`, proxyInit)
|
|
451
|
+
: fetch(`http://${DEFAULT_PROXY_HOST}:${port}/`, proxyInit));
|
|
452
|
+
|
|
453
|
+
if (response.status === 502) {
|
|
454
|
+
const errorText = await response.text();
|
|
455
|
+
throw new Error(`Bun proxy upstream error: ${errorText}`);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return response;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
if (state.activeChild && state.activePort !== null && !state.activeChild.killed) {
|
|
462
|
+
return fetchFromActiveProxy(true);
|
|
463
|
+
}
|
|
472
464
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
465
|
+
return new Promise<Response>((resolve, reject) => {
|
|
466
|
+
let settled = false;
|
|
467
|
+
const pendingFetch: InstanceState["pendingFetches"][number] = {
|
|
468
|
+
runProxy: (useForwardFetch: boolean) => {
|
|
469
|
+
if (settled) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
settled = true;
|
|
474
|
+
void fetchFromActiveProxy(useForwardFetch).then(resolve, reject);
|
|
475
|
+
},
|
|
476
|
+
runNative: (reason: string) => {
|
|
477
|
+
if (settled) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
settled = true;
|
|
482
|
+
void fetchNative(reason).then(resolve, reject);
|
|
483
|
+
},
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
state.pendingFetches.push(pendingFetch);
|
|
487
|
+
|
|
488
|
+
void startProxy(debugOverride).catch(() => {
|
|
489
|
+
state.pendingFetches = state.pendingFetches.filter((candidate) => candidate !== pendingFetch);
|
|
490
|
+
pendingFetch.runNative("proxy-start-error");
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
};
|
|
480
494
|
|
|
481
|
-
|
|
482
|
-
|
|
495
|
+
const instance: BunFetchInternal = {
|
|
496
|
+
fetch(input, init) {
|
|
497
|
+
return fetchThroughProxy(input, init);
|
|
483
498
|
},
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
499
|
+
ensureProxy: startProxy,
|
|
500
|
+
fetchWithDebug: fetchThroughProxy,
|
|
501
|
+
shutdown,
|
|
502
|
+
getStatus: () => getStatus(),
|
|
503
|
+
};
|
|
487
504
|
|
|
488
|
-
|
|
489
|
-
state.pendingFetches = state.pendingFetches.filter((candidate) => candidate !== pendingFetch);
|
|
490
|
-
pendingFetch.runNative("proxy-start-error");
|
|
491
|
-
});
|
|
492
|
-
});
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
const instance: BunFetchInternal = {
|
|
496
|
-
fetch(input, init) {
|
|
497
|
-
return fetchThroughProxy(input, init);
|
|
498
|
-
},
|
|
499
|
-
ensureProxy: startProxy,
|
|
500
|
-
fetchWithDebug: fetchThroughProxy,
|
|
501
|
-
shutdown,
|
|
502
|
-
getStatus: () => getStatus(),
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
return instance;
|
|
505
|
+
return instance;
|
|
506
506
|
}
|
|
507
507
|
|
|
508
508
|
const defaultBunFetch = (() => {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
509
|
+
let instance: BunFetchInternal | null = null;
|
|
510
|
+
|
|
511
|
+
return {
|
|
512
|
+
get(): BunFetchInternal {
|
|
513
|
+
if (!instance) {
|
|
514
|
+
instance = createBunFetch() as BunFetchInternal;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return instance;
|
|
518
|
+
},
|
|
519
|
+
async reset(): Promise<void> {
|
|
520
|
+
if (!instance) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
await instance.shutdown();
|
|
525
|
+
instance = null;
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
528
|
})();
|
|
529
529
|
|
|
530
530
|
export async function ensureBunProxy(debug: boolean): Promise<number | null> {
|
|
531
|
-
|
|
531
|
+
return defaultBunFetch.get().ensureProxy(debug);
|
|
532
532
|
}
|
|
533
533
|
|
|
534
534
|
export const stopBunProxy = (): void => {
|
|
535
|
-
|
|
535
|
+
void defaultBunFetch.reset();
|
|
536
536
|
};
|
|
537
537
|
|
|
538
538
|
export async function fetchViaBun(
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
539
|
+
input: FetchInput,
|
|
540
|
+
init: { headers: Headers; body?: string | null; method?: string; [key: string]: unknown },
|
|
541
|
+
debug: boolean,
|
|
542
542
|
): Promise<Response> {
|
|
543
|
-
|
|
543
|
+
return defaultBunFetch.get().fetchWithDebug(input, init as RequestInit & { headers: Headers }, debug);
|
|
544
544
|
}
|