@jeffreycao/copilot-api 2.1.4 → 2.1.6

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,12 +1,12 @@
1
- import { c as setProviderConfig, j as PATHS, k as isResponsesApiWebSocketEnabled, n as getRawProviderConfig } from "./config-CoMdcHDW.js";
1
+ import { A as isResponsesApiWebSocketEnabled, E as getResponsesTransportConfig, M as PATHS, c as setProviderConfig, n as getRawProviderConfig } from "./config-DMrKDHiF.js";
2
2
  import consola from "consola";
3
3
  import { createHash, randomBytes, randomUUID } from "node:crypto";
4
4
  import fs, { readFile } from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { createServer } from "node:http";
7
- import { events } from "fetch-event-stream";
8
7
  import { getProxyForUrl } from "proxy-from-env";
9
8
  import { WebSocket } from "undici";
9
+ import { events } from "fetch-event-stream";
10
10
  import { AsyncLocalStorage } from "node:async_hooks";
11
11
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
12
12
  import { exec } from "node:child_process";
@@ -19,6 +19,10 @@ var HTTPError = class extends Error {
19
19
  }
20
20
  };
21
21
  async function forwardError(c, error) {
22
+ if (c.req.raw.signal.aborted || isAbortError$1(error)) return new Response(null, {
23
+ status: 499,
24
+ statusText: "Client Closed Request"
25
+ });
22
26
  consola.error("Error occurred:", error);
23
27
  if (error instanceof HTTPError) {
24
28
  if (error.response.status === 429) for (const [name, value] of error.response.headers) {
@@ -43,6 +47,7 @@ async function forwardError(c, error) {
43
47
  type: "error"
44
48
  } }, 500);
45
49
  }
50
+ const isAbortError$1 = (error) => error instanceof Error && error.name === "AbortError";
46
51
  //#endregion
47
52
  //#region src/lib/state.ts
48
53
  const state = {
@@ -53,9 +58,72 @@ const state = {
53
58
  };
54
59
  //#endregion
55
60
  //#region src/services/responses-websocket.ts
56
- const DEFAULT_WEBSOCKET_IDLE_TIMEOUT_MS = 6e4;
57
61
  const websocketPool = /* @__PURE__ */ new Map();
58
62
  const websocketActiveRequests = /* @__PURE__ */ new Map();
63
+ var ResponsesWebSocketOpenTimeoutError = class extends Error {
64
+ constructor(timeoutMs) {
65
+ super(`Responses websocket did not open within ${timeoutMs}ms`);
66
+ this.name = "ResponsesWebSocketOpenTimeoutError";
67
+ }
68
+ };
69
+ var ResponsesWebSocketInactivityTimeoutError = class extends Error {
70
+ constructor(timeoutMs) {
71
+ super(`Responses websocket stream was inactive for ${timeoutMs}ms`);
72
+ this.name = "ResponsesWebSocketInactivityTimeoutError";
73
+ }
74
+ };
75
+ var ResponsesWebSocketBufferOverflowError = class extends Error {
76
+ constructor(maxBufferedBytes, maxBufferedMessages) {
77
+ super(`Responses websocket buffer exceeded ${maxBufferedBytes} bytes or ${maxBufferedMessages} messages; downstream consumption is too slow`);
78
+ this.name = "ResponsesWebSocketBufferOverflowError";
79
+ }
80
+ };
81
+ var WebSocketMessageBuffer = class {
82
+ entries = [];
83
+ head = 0;
84
+ maxBufferedBytes;
85
+ maxBufferedMessages;
86
+ sizeBytes = 0;
87
+ constructor(maxBufferedBytes, maxBufferedMessages) {
88
+ this.maxBufferedBytes = maxBufferedBytes;
89
+ this.maxBufferedMessages = maxBufferedMessages;
90
+ }
91
+ get bufferedBytes() {
92
+ return this.sizeBytes;
93
+ }
94
+ get bufferedMessages() {
95
+ return this.entries.length - this.head;
96
+ }
97
+ enqueue(data) {
98
+ const size = getWebSocketMessageSize(data);
99
+ if (this.sizeBytes + size > this.maxBufferedBytes || this.bufferedMessages + 1 > this.maxBufferedMessages) return false;
100
+ this.entries.push({
101
+ data: normalizeWebSocketMessageData(data),
102
+ size
103
+ });
104
+ this.sizeBytes += size;
105
+ return true;
106
+ }
107
+ dequeue() {
108
+ const entry = this.entries[this.head];
109
+ if (!entry) return void 0;
110
+ this.entries[this.head] = void 0;
111
+ this.head += 1;
112
+ this.sizeBytes -= entry.size;
113
+ this.compactIfNeeded();
114
+ return entry.data;
115
+ }
116
+ clear() {
117
+ this.entries.length = 0;
118
+ this.head = 0;
119
+ this.sizeBytes = 0;
120
+ }
121
+ compactIfNeeded() {
122
+ if (this.head < 256 || this.head * 2 < this.entries.length) return;
123
+ this.entries.splice(0, this.head);
124
+ this.head = 0;
125
+ }
126
+ };
59
127
  const createWebSocketUrl = (url) => {
60
128
  const websocketUrl = new URL(url);
61
129
  if (websocketUrl.protocol === "https:") websocketUrl.protocol = "wss:";
@@ -64,23 +132,34 @@ const createWebSocketUrl = (url) => {
64
132
  };
65
133
  const createPooledWebSocketStream = (request, options) => runPooledWebSocketRequest(request, options);
66
134
  const runPooledWebSocketRequest = async function* (request, options) {
135
+ throwIfAborted(request.signal);
67
136
  const { entry, pooled } = getPooledWebSocketRequestTarget(request, options);
68
- const release = acquirePooledWebSocketEntry(request.poolKey, entry, pooled, options);
137
+ const release = acquirePooledWebSocketEntry(request.poolKey, entry, pooled);
138
+ let messageStream = null;
139
+ let reusable = false;
69
140
  try {
70
141
  const websocket = await getReadyPooledWebSocket(request.poolKey, entry, pooled, options);
142
+ throwIfAborted(request.signal);
143
+ messageStream = createWebSocketMessageStream(websocket, request.signal, options);
144
+ messageStream.start();
71
145
  websocket.send(JSON.stringify(request.payload));
72
- for await (const data of createWebSocketMessageStream(websocket, options)) {
146
+ for await (const data of messageStream.iterable) {
73
147
  const chunk = options.createChunk(data);
148
+ const isTerminal = options.isTerminalChunk(chunk);
149
+ if (isTerminal) {
150
+ messageStream.complete();
151
+ reusable = true;
152
+ }
74
153
  yield chunk;
75
- if (options.isTerminalChunk(chunk)) return;
154
+ if (isTerminal) return;
76
155
  }
77
- removePooledWebSocketEntry(request.poolKey, entry);
78
156
  throw new Error(options.terminalChunkMissingMessage);
79
157
  } catch (error) {
80
- removePooledWebSocketEntry(request.poolKey, entry);
81
- throw toError(error);
158
+ throw toError$1(error);
82
159
  } finally {
83
- release();
160
+ messageStream?.dispose();
161
+ if (!reusable) removePooledWebSocketEntry(request.poolKey, entry);
162
+ release(reusable);
84
163
  }
85
164
  };
86
165
  const getPooledWebSocketRequestTarget = (request, options) => {
@@ -91,7 +170,7 @@ const getPooledWebSocketRequestTarget = (request, options) => {
91
170
  const existing = websocketPool.get(request.poolKey);
92
171
  if (existing && !existing.closed) {
93
172
  consola.debug("websocket from pool");
94
- clearPooledWebSocketIdleTimer(existing);
173
+ clearPooledWebSocketIdleState(existing);
95
174
  return {
96
175
  entry: existing,
97
176
  pooled: true
@@ -105,17 +184,24 @@ const getPooledWebSocketRequestTarget = (request, options) => {
105
184
  };
106
185
  };
107
186
  const createPooledWebSocketEntry = (request, options) => {
187
+ const websocketPromise = openWebSocket({
188
+ headers: request.headers,
189
+ openErrorMessage: options.openErrorMessage,
190
+ openTimeoutMs: options.openTimeoutMs,
191
+ signal: request.signal,
192
+ url: request.url
193
+ });
108
194
  const entry = {
109
195
  closed: false,
196
+ idleMessageListener: null,
110
197
  idleTimer: null,
198
+ poolIdleTimeoutMs: options.poolIdleTimeoutMs,
111
199
  requestCount: 0,
112
- websocketPromise: openWebSocket({
113
- headers: request.headers,
114
- openErrorMessage: options.openErrorMessage,
115
- url: request.url
116
- })
200
+ websocket: null,
201
+ websocketPromise
117
202
  };
118
203
  entry.websocketPromise.then((websocket) => {
204
+ entry.websocket = websocket;
119
205
  websocket.addEventListener("close", () => {
120
206
  removePooledWebSocketEntry(request.poolKey, entry);
121
207
  });
@@ -127,26 +213,30 @@ const createPooledWebSocketEntry = (request, options) => {
127
213
  });
128
214
  return entry;
129
215
  };
130
- const acquirePooledWebSocketEntry = (poolKey, entry, pooled, options) => {
131
- clearPooledWebSocketIdleTimer(entry);
216
+ const acquirePooledWebSocketEntry = (poolKey, entry, pooled) => {
217
+ clearPooledWebSocketIdleState(entry);
132
218
  incrementPooledWebSocketActiveRequestCount(poolKey);
133
219
  entry.requestCount += 1;
134
220
  let released = false;
135
- return () => {
221
+ return (reusable) => {
136
222
  if (released) return;
137
223
  released = true;
138
224
  entry.requestCount -= 1;
139
225
  decrementPooledWebSocketActiveRequestCount(poolKey);
226
+ if (!reusable) {
227
+ removePooledWebSocketEntry(poolKey, entry);
228
+ return;
229
+ }
140
230
  if (entry.closed || entry.requestCount > 0) return;
141
231
  if (pooled && websocketPool.get(poolKey) === entry) {
142
- schedulePooledWebSocketIdleClose(poolKey, entry, options);
232
+ schedulePooledWebSocketIdleClose(poolKey, entry);
143
233
  return;
144
234
  }
145
235
  removePooledWebSocketEntry(poolKey, entry);
146
236
  };
147
237
  };
148
238
  const getReadyPooledWebSocket = async (poolKey, entry, pooled, options) => {
149
- const unavailableErrorMessage = options?.unavailableErrorMessage ?? "Websocket connection became unavailable before the request started";
239
+ const unavailableErrorMessage = options.unavailableErrorMessage ?? "Websocket connection became unavailable before the request started";
150
240
  if (entry.closed) throw new Error(unavailableErrorMessage);
151
241
  const websocket = await entry.websocketPromise;
152
242
  if (entry.closed || pooled && websocketPool.get(poolKey) !== entry) throw new Error(unavailableErrorMessage);
@@ -156,18 +246,31 @@ const getReadyPooledWebSocket = async (poolKey, entry, pooled, options) => {
156
246
  }
157
247
  return websocket;
158
248
  };
159
- const schedulePooledWebSocketIdleClose = (poolKey, entry, options) => {
160
- clearPooledWebSocketIdleTimer(entry);
249
+ const schedulePooledWebSocketIdleClose = (poolKey, entry) => {
250
+ clearPooledWebSocketIdleState(entry);
251
+ const websocket = entry.websocket;
252
+ if (!websocket || websocket.readyState !== WebSocket.OPEN) {
253
+ removePooledWebSocketEntry(poolKey, entry);
254
+ return;
255
+ }
256
+ entry.idleMessageListener = () => {
257
+ removePooledWebSocketEntry(poolKey, entry);
258
+ };
259
+ websocket.addEventListener("message", entry.idleMessageListener);
161
260
  entry.idleTimer = setTimeout(() => {
162
261
  removePooledWebSocketEntry(poolKey, entry);
163
- }, options.idleTimeoutMs ?? DEFAULT_WEBSOCKET_IDLE_TIMEOUT_MS);
262
+ }, entry.poolIdleTimeoutMs);
164
263
  unrefTimer(entry.idleTimer);
165
264
  };
166
- const clearPooledWebSocketIdleTimer = (entry) => {
265
+ const clearPooledWebSocketIdleState = (entry) => {
167
266
  if (entry.idleTimer) {
168
267
  clearTimeout(entry.idleTimer);
169
268
  entry.idleTimer = null;
170
269
  }
270
+ if (entry.websocket && entry.idleMessageListener) {
271
+ entry.websocket.removeEventListener("message", entry.idleMessageListener);
272
+ entry.idleMessageListener = null;
273
+ }
171
274
  };
172
275
  const getPooledWebSocketActiveRequestCount = (poolKey) => websocketActiveRequests.get(poolKey) ?? 0;
173
276
  const incrementPooledWebSocketActiveRequestCount = (poolKey) => {
@@ -175,117 +278,193 @@ const incrementPooledWebSocketActiveRequestCount = (poolKey) => {
175
278
  };
176
279
  const decrementPooledWebSocketActiveRequestCount = (poolKey) => {
177
280
  const nextCount = getPooledWebSocketActiveRequestCount(poolKey) - 1;
178
- if (nextCount <= 0) {
179
- websocketActiveRequests.delete(poolKey);
180
- return;
181
- }
182
- websocketActiveRequests.set(poolKey, nextCount);
281
+ if (nextCount <= 0) websocketActiveRequests.delete(poolKey);
282
+ else websocketActiveRequests.set(poolKey, nextCount);
183
283
  };
184
284
  const removePooledWebSocketEntry = (poolKey, entry) => {
185
285
  if (websocketPool.get(poolKey) === entry) websocketPool.delete(poolKey);
186
286
  if (entry.closed) return;
187
287
  entry.closed = true;
188
- clearPooledWebSocketIdleTimer(entry);
288
+ clearPooledWebSocketIdleState(entry);
189
289
  entry.websocketPromise.then(closeWebSocket).catch(() => {});
190
290
  };
191
- const unrefTimer = (timer) => {
192
- if (typeof timer === "object" && "unref" in timer && typeof timer.unref === "function") timer.unref();
193
- };
194
291
  const createWebSocketError = (message, event) => {
195
292
  const reason = event?.error ?? event?.message;
196
293
  if (reason === void 0 || reason === "") return new Error(message);
197
- const cause = toError(reason);
294
+ const cause = toError$1(reason);
198
295
  return new Error(`${message}: ${cause.message}`, { cause });
199
296
  };
200
- const openWebSocket = async ({ headers, openErrorMessage, url }) => await new Promise((resolve, reject) => {
297
+ const openWebSocket = async ({ headers, openErrorMessage, openTimeoutMs, signal, url }) => await new Promise((resolve, reject) => {
298
+ if (signal?.aborted) {
299
+ reject(toAbortReason$1(signal.reason));
300
+ return;
301
+ }
201
302
  const proxy = typeof Bun === "undefined" ? void 0 : getProxyUrl(url);
202
303
  const websocket = new WebSocket(url, {
203
304
  headers,
204
305
  ...proxy ? { proxy } : {}
205
306
  });
307
+ let settled = false;
308
+ const timer = setTimeout(() => {
309
+ fail(new ResponsesWebSocketOpenTimeoutError(openTimeoutMs));
310
+ }, openTimeoutMs);
206
311
  const cleanup = () => {
312
+ clearTimeout(timer);
313
+ signal?.removeEventListener("abort", onAbort);
207
314
  websocket.removeEventListener("open", onOpen);
315
+ websocket.removeEventListener("close", onClose);
208
316
  websocket.removeEventListener("error", onError);
209
317
  };
318
+ const fail = (error) => {
319
+ if (settled) return;
320
+ settled = true;
321
+ cleanup();
322
+ closeWebSocket(websocket);
323
+ reject(error);
324
+ };
325
+ const onAbort = () => fail(toAbortReason$1(signal?.reason));
210
326
  const onOpen = () => {
327
+ if (settled) return;
328
+ settled = true;
211
329
  cleanup();
212
330
  resolve(websocket);
213
331
  };
332
+ const onClose = () => fail(new Error(openErrorMessage));
214
333
  const onError = (event) => {
215
- cleanup();
216
- reject(createWebSocketError(openErrorMessage, event));
334
+ fail(createWebSocketError(openErrorMessage, event));
217
335
  };
336
+ signal?.addEventListener("abort", onAbort, { once: true });
218
337
  websocket.addEventListener("open", onOpen);
338
+ websocket.addEventListener("close", onClose);
219
339
  websocket.addEventListener("error", onError);
220
340
  });
221
- const createWebSocketMessageStream = async function* (websocket, options) {
222
- const queue = [];
341
+ const createWebSocketMessageStream = (websocket, signal, options) => {
342
+ const buffer = new WebSocketMessageBuffer(options.maxBufferedBytes, options.maxBufferedMessages);
223
343
  let closed = false;
344
+ let disposed = false;
224
345
  let error = null;
346
+ let inactivityTimer = null;
225
347
  let notify = null;
226
348
  const wake = () => {
227
349
  notify?.();
228
350
  notify = null;
229
351
  };
352
+ const clearInactivityTimer = () => {
353
+ if (!inactivityTimer) return;
354
+ clearTimeout(inactivityTimer);
355
+ inactivityTimer = null;
356
+ };
357
+ const fail = (nextError, close = true) => {
358
+ if (error || disposed) return;
359
+ error = nextError;
360
+ clearInactivityTimer();
361
+ buffer.clear();
362
+ if (close) closeWebSocket(websocket);
363
+ wake();
364
+ };
365
+ const resetInactivityTimer = () => {
366
+ clearInactivityTimer();
367
+ if (disposed || closed || error) return;
368
+ inactivityTimer = setTimeout(() => {
369
+ fail(new ResponsesWebSocketInactivityTimeoutError(options.streamInactivityTimeoutMs));
370
+ }, options.streamInactivityTimeoutMs);
371
+ };
230
372
  const onMessage = (event) => {
231
- queue.push(normalizeWebSocketMessageData(event.data));
373
+ resetInactivityTimer();
374
+ if (!buffer.enqueue(event.data)) {
375
+ fail(new ResponsesWebSocketBufferOverflowError(options.maxBufferedBytes, options.maxBufferedMessages));
376
+ return;
377
+ }
232
378
  wake();
233
379
  };
234
380
  const onClose = () => {
235
381
  consola.debug("WebSocket closed");
236
382
  closed = true;
383
+ clearInactivityTimer();
237
384
  wake();
238
385
  };
239
386
  const onError = (event) => {
240
387
  consola.error("WebSocket error:", event, event.error);
241
- error = createWebSocketError(options.streamErrorMessage, event);
242
- wake();
388
+ fail(createWebSocketError(options.streamErrorMessage, event), false);
243
389
  };
390
+ const onAbort = () => fail(toAbortReason$1(signal?.reason));
244
391
  websocket.addEventListener("message", onMessage);
245
392
  websocket.addEventListener("close", onClose);
246
393
  websocket.addEventListener("error", onError);
247
- try {
248
- while (true) {
249
- const item = queue.shift();
250
- if (item) {
251
- yield await item;
252
- continue;
253
- }
254
- if (error) throw toError(error);
255
- if (closed) break;
256
- await new Promise((resolve) => {
257
- notify = resolve;
258
- });
259
- }
260
- } finally {
394
+ signal?.addEventListener("abort", onAbort, { once: true });
395
+ const dispose = () => {
396
+ if (disposed) return;
397
+ disposed = true;
398
+ clearInactivityTimer();
399
+ buffer.clear();
261
400
  websocket.removeEventListener("message", onMessage);
262
401
  websocket.removeEventListener("close", onClose);
263
402
  websocket.removeEventListener("error", onError);
264
- }
403
+ signal?.removeEventListener("abort", onAbort);
404
+ wake();
405
+ };
406
+ return {
407
+ complete: clearInactivityTimer,
408
+ dispose,
409
+ iterable: (async function* () {
410
+ try {
411
+ while (true) {
412
+ const item = buffer.dequeue();
413
+ if (item) {
414
+ yield await item;
415
+ continue;
416
+ }
417
+ if (error) throw toError$1(error);
418
+ if (closed) return;
419
+ await new Promise((resolve) => {
420
+ notify = resolve;
421
+ });
422
+ }
423
+ } finally {
424
+ dispose();
425
+ }
426
+ })(),
427
+ start: resetInactivityTimer
428
+ };
265
429
  };
266
430
  const normalizeWebSocketMessageData = async (data) => {
267
431
  if (typeof data === "string") return data;
268
432
  if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
269
- if (ArrayBuffer.isView(data)) {
270
- const view = data;
271
- return new TextDecoder().decode(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
272
- }
433
+ if (ArrayBuffer.isView(data)) return new TextDecoder().decode(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
273
434
  if (isTextReadable(data)) return await data.text();
274
435
  return String(data);
275
436
  };
276
- const isTextReadable = (value) => {
277
- if (!value || typeof value !== "object" || !("text" in value)) return false;
278
- return typeof value.text === "function";
279
- };
280
- const toError = (value) => {
437
+ const getWebSocketMessageSize = (data) => {
438
+ if (typeof data === "string") return new TextEncoder().encode(data).byteLength;
439
+ if (data instanceof ArrayBuffer) return data.byteLength;
440
+ if (ArrayBuffer.isView(data)) return data.byteLength;
441
+ if (isSized(data)) return data.size;
442
+ return new TextEncoder().encode(String(data)).byteLength;
443
+ };
444
+ const isTextReadable = (value) => Boolean(value && typeof value === "object" && "text" in value && typeof value.text === "function");
445
+ const isSized = (value) => Boolean(value && typeof value === "object" && "size" in value && typeof value.size === "number");
446
+ const toAbortReason$1 = (reason) => {
447
+ if (reason instanceof Error) return reason;
448
+ const error = /* @__PURE__ */ new Error("The operation was aborted");
449
+ error.name = "AbortError";
450
+ return error;
451
+ };
452
+ const throwIfAborted = (signal) => {
453
+ if (signal?.aborted) throw toAbortReason$1(signal.reason);
454
+ };
455
+ const toError$1 = (value) => {
281
456
  if (value instanceof Error) return value;
282
457
  return new Error(String(value));
283
458
  };
284
459
  const closeWebSocket = (websocket) => {
285
- if (websocket.readyState === WebSocket.CONNECTING || websocket.readyState === WebSocket.OPEN) websocket.close();
460
+ if (websocket.readyState !== WebSocket.CONNECTING && websocket.readyState !== WebSocket.OPEN) return;
461
+ try {
462
+ websocket.close();
463
+ } catch {}
286
464
  };
287
- const getProxyUrl = (url) => {
288
- return getProxyForUrl(url.replace(/^wss:/, "https:").replace(/^ws:/, "http:"));
465
+ const getProxyUrl = (url) => getProxyForUrl(url.replace(/^wss:/u, "https:").replace(/^ws:/u, "http:"));
466
+ const unrefTimer = (timer) => {
467
+ if (typeof timer === "object" && "unref" in timer && typeof timer.unref === "function") timer.unref();
289
468
  };
290
469
  //#endregion
291
470
  //#region src/services/responses-websocket-helpers.ts
@@ -316,13 +495,200 @@ const isTerminalResponsesStreamChunk = (chunk) => {
316
495
  return false;
317
496
  }
318
497
  };
319
- const createResponsesSafeStream = async function* (source) {
498
+ const createResponsesSafeStream = async function* (source, options = {}) {
320
499
  try {
321
500
  yield* source;
322
501
  } catch (error) {
502
+ if (options.signal?.aborted || isAbortError(error)) return;
323
503
  yield createResponsesErrorServerSentEventChunk(getErrorMessage(error));
324
504
  }
325
505
  };
506
+ const isAbortError = (error) => error instanceof Error && error.name === "AbortError";
507
+ //#endregion
508
+ //#region src/services/responses-http.ts
509
+ var ResponsesHeadersTimeoutError = class extends Error {
510
+ constructor(timeoutMs) {
511
+ super(`Responses upstream did not return headers within ${timeoutMs}ms`);
512
+ this.name = "ResponsesHeadersTimeoutError";
513
+ }
514
+ };
515
+ var ResponsesStreamInactivityTimeoutError = class extends Error {
516
+ constructor(timeoutMs) {
517
+ super(`Responses upstream stream was inactive for ${timeoutMs}ms`);
518
+ this.name = "ResponsesStreamInactivityTimeoutError";
519
+ }
520
+ };
521
+ async function fetchResponsesWithLifecycle(input, init, options) {
522
+ const lifecycle = createRequestLifecycle(options);
523
+ try {
524
+ const response = await fetch(input, {
525
+ ...init,
526
+ signal: lifecycle.signal
527
+ });
528
+ lifecycle.headersReceived();
529
+ return createManagedResponse(response, lifecycle, options);
530
+ } catch (error) {
531
+ throw lifecycle.finishWithError(error);
532
+ }
533
+ }
534
+ const createRequestLifecycle = (options) => {
535
+ const controller = new AbortController();
536
+ const downstreamSignal = options.signal;
537
+ let finished = false;
538
+ let headersTimer = null;
539
+ const abortFromDownstream = () => {
540
+ controller.abort(toAbortReason(downstreamSignal?.reason));
541
+ };
542
+ if (downstreamSignal?.aborted) abortFromDownstream();
543
+ else downstreamSignal?.addEventListener("abort", abortFromDownstream, { once: true });
544
+ if (!controller.signal.aborted) headersTimer = setTimeout(() => {
545
+ controller.abort(new ResponsesHeadersTimeoutError(options.headersTimeoutMs));
546
+ }, options.headersTimeoutMs);
547
+ const clearHeadersTimer = () => {
548
+ if (headersTimer === null) return;
549
+ clearTimeout(headersTimer);
550
+ headersTimer = null;
551
+ };
552
+ const finish = () => {
553
+ if (finished) return;
554
+ finished = true;
555
+ clearHeadersTimer();
556
+ downstreamSignal?.removeEventListener("abort", abortFromDownstream);
557
+ };
558
+ return {
559
+ abort: (reason) => {
560
+ if (!controller.signal.aborted) controller.abort(reason);
561
+ },
562
+ finish,
563
+ finishWithError: (error) => {
564
+ clearHeadersTimer();
565
+ const reason = controller.signal.reason;
566
+ finish();
567
+ return reason instanceof Error ? reason : toError(error);
568
+ },
569
+ headersReceived: clearHeadersTimer,
570
+ signal: controller.signal
571
+ };
572
+ };
573
+ const createManagedResponse = (response, lifecycle, options) => {
574
+ if (!response.body) {
575
+ lifecycle.finish();
576
+ return response;
577
+ }
578
+ const body = createManagedResponseBody(response.body, lifecycle, options);
579
+ return new Response(body, {
580
+ headers: response.headers,
581
+ status: response.status,
582
+ statusText: response.statusText
583
+ });
584
+ };
585
+ const createManagedResponseBody = (body, lifecycle, options) => {
586
+ const reader = body.getReader();
587
+ let finished = false;
588
+ let readerReleased = false;
589
+ const finish = () => {
590
+ if (finished) return;
591
+ finished = true;
592
+ lifecycle.finish();
593
+ };
594
+ const releaseReader = () => {
595
+ if (readerReleased) return;
596
+ readerReleased = true;
597
+ reader.releaseLock();
598
+ };
599
+ return new ReadableStream({
600
+ async pull(controller) {
601
+ try {
602
+ const result = await readWithLifecycle(reader, lifecycle, options);
603
+ if (result.done) {
604
+ finish();
605
+ releaseReader();
606
+ controller.close();
607
+ return;
608
+ }
609
+ controller.enqueue(result.value);
610
+ } catch (error) {
611
+ const reason = lifecycle.finishWithError(error);
612
+ finish();
613
+ await reader.cancel(reason).catch(() => {});
614
+ releaseReader();
615
+ controller.error(reason);
616
+ }
617
+ },
618
+ async cancel(reason) {
619
+ const error = toAbortReason(reason);
620
+ lifecycle.abort(error);
621
+ finish();
622
+ await reader.cancel(error).catch(() => {});
623
+ releaseReader();
624
+ }
625
+ });
626
+ };
627
+ const createResponsesHttpEventStream = async function* (response, signal) {
628
+ const responseBody = response.body;
629
+ if (!responseBody) return;
630
+ const reader = responseBody.getReader();
631
+ const readerBackedBody = new ReadableStream({
632
+ async pull(controller) {
633
+ const result = await reader.read();
634
+ if (result.done) {
635
+ controller.close();
636
+ return;
637
+ }
638
+ controller.enqueue(result.value);
639
+ },
640
+ async cancel(reason) {
641
+ await reader.cancel(reason);
642
+ }
643
+ });
644
+ try {
645
+ yield* events(new Response(readerBackedBody), signal);
646
+ } finally {
647
+ try {
648
+ await reader.cancel();
649
+ } catch {} finally {
650
+ reader.releaseLock();
651
+ }
652
+ }
653
+ };
654
+ const readWithLifecycle = async (reader, lifecycle, options) => await new Promise((resolve, reject) => {
655
+ let settled = false;
656
+ const signal = lifecycle.signal;
657
+ const timer = setTimeout(() => {
658
+ const error = new ResponsesStreamInactivityTimeoutError(options.streamInactivityTimeoutMs);
659
+ lifecycle.abort(error);
660
+ settle(() => reject(error));
661
+ }, options.streamInactivityTimeoutMs);
662
+ const onAbort = () => {
663
+ settle(() => reject(toAbortReason(signal.reason)));
664
+ };
665
+ const cleanup = () => {
666
+ clearTimeout(timer);
667
+ signal.removeEventListener("abort", onAbort);
668
+ };
669
+ const settle = (action) => {
670
+ if (settled) return;
671
+ settled = true;
672
+ cleanup();
673
+ action();
674
+ };
675
+ if (signal.aborted) {
676
+ onAbort();
677
+ return;
678
+ }
679
+ signal.addEventListener("abort", onAbort, { once: true });
680
+ reader.read().then((result) => settle(() => resolve(result)), (error) => settle(() => reject(toError(error))));
681
+ });
682
+ const toAbortReason = (reason) => {
683
+ if (reason instanceof Error) return reason;
684
+ const error = /* @__PURE__ */ new Error("The operation was aborted");
685
+ error.name = "AbortError";
686
+ return error;
687
+ };
688
+ const toError = (value) => {
689
+ if (value instanceof Error) return value;
690
+ return new Error(String(value));
691
+ };
326
692
  //#endregion
327
693
  //#region src/lib/request-context.ts
328
694
  const TRACE_ID_MAX_LENGTH = 64;
@@ -434,27 +800,33 @@ function buildCodexResponsesWebSocketPayload(payload) {
434
800
  function buildCodexResponsesWebSocketUrl(baseUrl = CODEX_API_BASE_URL) {
435
801
  return createWebSocketUrl(resolveCodexResponsesUrl(baseUrl));
436
802
  }
437
- function prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl = CODEX_API_BASE_URL) {
803
+ function prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl = CODEX_API_BASE_URL, signal) {
438
804
  const headers = buildCodexResponsesWebSocketHeaders(requestHeaders);
439
805
  return {
440
806
  headers,
441
807
  payload: buildCodexResponsesWebSocketPayload(payload),
442
808
  poolKey: buildCodexResponsesWebSocketPoolKey(payload, headers, baseUrl),
809
+ signal,
443
810
  url: buildCodexResponsesWebSocketUrl(baseUrl)
444
811
  };
445
812
  }
446
813
  async function forwardCodexResponses(payload, requestHeaders, baseUrl = CODEX_API_BASE_URL, options = {}) {
447
814
  consola.log(`<-- model: ${payload.model}`);
448
815
  const transport = resolveCodexResponsesTransport(options.transport);
449
- if (payload.stream && transport === "websocket") return forwardCodexResponsesOverWebSocket(payload, requestHeaders, baseUrl);
816
+ if (payload.stream && transport === "websocket") return forwardCodexResponsesOverWebSocket(payload, requestHeaders, baseUrl, options.signal);
450
817
  const normalizedPayload = normalizeCodexResponsesPayload(payload);
451
- const response = await fetch(resolveCodexResponsesUrl(baseUrl), {
818
+ const transportConfig = getResponsesTransportConfig();
819
+ const response = await fetchResponsesWithLifecycle(resolveCodexResponsesUrl(baseUrl), {
452
820
  method: "POST",
453
821
  headers: buildCodexResponsesHeaders(requestHeaders, { stream: normalizedPayload.stream }),
454
822
  body: JSON.stringify(normalizedPayload)
823
+ }, {
824
+ headersTimeoutMs: transportConfig.headersTimeoutMs,
825
+ signal: options.signal,
826
+ streamInactivityTimeoutMs: transportConfig.streamInactivityTimeoutMs
455
827
  });
456
828
  if (!response.ok) throw new HTTPError("Failed to create codex responses", response);
457
- if (normalizedPayload.stream) return events(response);
829
+ if (normalizedPayload.stream) return createResponsesSafeStream(createResponsesHttpEventStream(response, options.signal), { signal: options.signal });
458
830
  return await response.json();
459
831
  }
460
832
  const normalizeCodexResponsesPayload = (payload) => {
@@ -520,16 +892,24 @@ const buildCodexResponsesWebSocketPoolKey = (payload, headers, baseUrl) => {
520
892
  headerFingerprint
521
893
  ].map(encodePoolKeyPart).join("|");
522
894
  };
523
- const forwardCodexResponsesOverWebSocket = (payload, requestHeaders, baseUrl) => {
524
- return createCodexResponsesWebSocketStream(prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl));
895
+ const forwardCodexResponsesOverWebSocket = (payload, requestHeaders, baseUrl, signal) => {
896
+ return createCodexResponsesWebSocketStream(prepareCodexResponsesWebSocketRequest(payload, requestHeaders, baseUrl, signal));
897
+ };
898
+ const createCodexResponsesWebSocketStream = (request) => {
899
+ const transportConfig = getResponsesTransportConfig();
900
+ return createResponsesSafeStream(createPooledWebSocketStream(request, {
901
+ createChunk: createCodexResponsesWebSocketStreamChunk,
902
+ maxBufferedBytes: transportConfig.websocketMaxBufferedBytes,
903
+ maxBufferedMessages: transportConfig.websocketMaxBufferedMessages,
904
+ isTerminalChunk: isTerminalResponsesStreamChunk,
905
+ openErrorMessage: "Failed to create codex responses websocket",
906
+ openTimeoutMs: transportConfig.websocketOpenTimeoutMs,
907
+ poolIdleTimeoutMs: transportConfig.websocketPoolIdleTimeoutMs,
908
+ streamInactivityTimeoutMs: transportConfig.streamInactivityTimeoutMs,
909
+ streamErrorMessage: "Codex responses websocket stream error",
910
+ terminalChunkMissingMessage: "Codex responses websocket ended without a terminal response"
911
+ }), { signal: request.signal });
525
912
  };
526
- const createCodexResponsesWebSocketStream = (request) => createResponsesSafeStream(createPooledWebSocketStream(request, {
527
- createChunk: createCodexResponsesWebSocketStreamChunk,
528
- isTerminalChunk: isTerminalResponsesStreamChunk,
529
- openErrorMessage: "Failed to create codex responses websocket",
530
- streamErrorMessage: "Codex responses websocket stream error",
531
- terminalChunkMissingMessage: "Codex responses websocket ended without a terminal response"
532
- }));
533
913
  const createCodexResponsesWebSocketStreamChunk = (data) => {
534
914
  if (data === "[DONE]") return { data };
535
915
  try {
@@ -1500,6 +1880,6 @@ async function logUser() {
1500
1880
  state.tokenBasedBilling = copilotUser.token_based_billing;
1501
1881
  }
1502
1882
  //#endregion
1503
- export { buildCodexRequestHeaders as A, state as B, compactAutoContinuePromptStarts as C, compactTextOnlyGuard as D, compactSystemPromptStarts as E, createResponsesSafeStream as F, forwardError as H, encodePoolKeyPart as I, isTerminalResponsesStreamChunk as L, generateTraceId as M, requestContext as N, loginCodex as O, resolveTraceId as P, createPooledWebSocketStream as R, initOpencodeVersion as S, compactSummaryPromptStart as T, HTTPError as V, copilotModelsHeaders as _, setupGitHubToken as a, prepareInteractionHeaders as b, getUUID as c, isResponsesStream as d, parseUserIdMetadata as f, copilotHeaders as g, copilotBaseUrl as h, setupCopilotToken as i, forwardCodexResponses as j, CODEX_API_BASE_URL as k, isAsyncIterable as l, readGitHubToken as m, persistCodexCredentials as n, generateRequestIdFromPayload as o, getCopilotUsage as p, setupCodexToken as r, getRootSessionId as s, logUser as t, isNullish as u, copilotWebSocketHeaders as v, compactMessageSections as w, prepareMessageProxyHeaders as x, prepareForCompact as y, createWebSocketUrl as z };
1883
+ export { buildCodexRequestHeaders as A, createPooledWebSocketStream as B, compactAutoContinuePromptStarts as C, compactTextOnlyGuard as D, compactSystemPromptStarts as E, createResponsesHttpEventStream as F, state as H, fetchResponsesWithLifecycle as I, createResponsesSafeStream as L, generateTraceId as M, requestContext as N, loginCodex as O, resolveTraceId as P, encodePoolKeyPart as R, initOpencodeVersion as S, compactSummaryPromptStart as T, HTTPError as U, createWebSocketUrl as V, forwardError as W, copilotModelsHeaders as _, setupGitHubToken as a, prepareInteractionHeaders as b, getUUID as c, isResponsesStream as d, parseUserIdMetadata as f, copilotHeaders as g, copilotBaseUrl as h, setupCopilotToken as i, forwardCodexResponses as j, CODEX_API_BASE_URL as k, isAsyncIterable as l, readGitHubToken as m, persistCodexCredentials as n, generateRequestIdFromPayload as o, getCopilotUsage as p, setupCodexToken as r, getRootSessionId as s, logUser as t, isNullish as u, copilotWebSocketHeaders as v, compactMessageSections as w, prepareMessageProxyHeaders as x, prepareForCompact as y, isTerminalResponsesStreamChunk as z };
1504
1884
 
1505
- //# sourceMappingURL=token-_ZvkUtOA.js.map
1885
+ //# sourceMappingURL=token-DmNSTe37.js.map