@opendatalabs/personal-server-ts-lite 0.0.1-canary.01ca694 → 0.0.1-canary.052d47e

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 (44) hide show
  1. package/dist/browser-runtime.d.ts +26 -1
  2. package/dist/browser-runtime.d.ts.map +1 -1
  3. package/dist/browser-runtime.js +130 -26
  4. package/dist/browser-runtime.js.map +1 -1
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +40 -8
  7. package/dist/client.js.map +1 -1
  8. package/dist/derivatives.d.ts +51 -0
  9. package/dist/derivatives.d.ts.map +1 -0
  10. package/dist/derivatives.js +85 -0
  11. package/dist/derivatives.js.map +1 -0
  12. package/dist/index.d.ts +8 -5
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +8 -3
  15. package/dist/index.js.map +1 -1
  16. package/dist/persistence.d.ts +69 -0
  17. package/dist/persistence.d.ts.map +1 -0
  18. package/dist/persistence.js +58 -0
  19. package/dist/persistence.js.map +1 -0
  20. package/dist/relay-tls.d.ts +42 -0
  21. package/dist/relay-tls.d.ts.map +1 -1
  22. package/dist/relay-tls.js +176 -86
  23. package/dist/relay-tls.js.map +1 -1
  24. package/dist/relay.d.ts +83 -4
  25. package/dist/relay.d.ts.map +1 -1
  26. package/dist/relay.js +299 -21
  27. package/dist/relay.js.map +1 -1
  28. package/dist/runtime.d.ts +97 -4
  29. package/dist/runtime.d.ts.map +1 -1
  30. package/dist/runtime.js +208 -44
  31. package/dist/runtime.js.map +1 -1
  32. package/dist/state.d.ts +11 -1
  33. package/dist/state.d.ts.map +1 -1
  34. package/dist/state.js +77 -7
  35. package/dist/state.js.map +1 -1
  36. package/dist/storage.d.ts +6 -2
  37. package/dist/storage.d.ts.map +1 -1
  38. package/dist/storage.js +182 -39
  39. package/dist/storage.js.map +1 -1
  40. package/dist/sync.d.ts +23 -0
  41. package/dist/sync.d.ts.map +1 -1
  42. package/dist/sync.js +56 -6
  43. package/dist/sync.js.map +1 -1
  44. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"relay-tls.js","sourceRoot":"","sources":["../src/relay-tls.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relay-tls.js","sourceRoot":"","sources":["../src/relay-tls.ts"],"names":[],"mappings":"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"}
package/dist/relay.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ import type { PersonalServerReadFulfillmentReporter } from "@opendatalabs/personal-server-ts-core/api";
1
2
  import { type PsLiteBridgeResponse } from "./bridge.js";
3
+ import type { PsLiteRelayTlsIdentityStore } from "./relay-tls.js";
2
4
  import type { PsLiteRuntime } from "./runtime.js";
3
5
  export interface PsLiteRelayClientOptions {
4
6
  sessionId: string;
@@ -9,28 +11,87 @@ export interface PsLiteRelayClientOptions {
9
11
  origin?: string;
10
12
  webSocketFactory?: PsLiteRelayWebSocketFactory;
11
13
  tls?: PsLiteRelayTlsFactory | false;
14
+ /** Host-owned cache for the issued relay certificate identity. */
15
+ tlsIdentityStore?: PsLiteRelayTlsIdentityStore;
12
16
  logger?: (line: string) => void;
13
- onStatus?: (status: PsLiteRelayStatus) => void;
17
+ onStatus?: (status: PsLiteRelayStatus, detail?: PsLiteRelayStatusDetail) => void;
18
+ /** Heartbeat ping cadence (ms). Default 20_000. */
19
+ heartbeatIntervalMs?: number;
20
+ /**
21
+ * Force-reconnect when a ping the client actually sent goes unanswered by
22
+ * ANY relay frame for this long, measured by wall clock (ms). Default 45_000.
23
+ */
24
+ heartbeatTimeoutMs?: number;
25
+ /** First reconnect backoff delay (ms); doubles up to the max. Default 1_000. */
26
+ reconnectInitialDelayMs?: number;
27
+ /** Max reconnect backoff delay (ms). Default 30_000. */
28
+ reconnectMaxDelayMs?: number;
14
29
  }
15
- export type PsLiteRelayStatus = "connecting" | "connected" | "disconnected" | "closed" | "error";
30
+ export type PsLiteRelayStatus = "connecting" | "connected" | "disconnected" | "closed" | "replaced" | "error";
31
+ /**
32
+ * Extra context for a relay status transition — the WebSocket close code/reason
33
+ * on `disconnected` / `closed` / `replaced`. Lets consumers distinguish an
34
+ * abnormal drop (1006) from a takeover (1012) or a clean close (1000) for
35
+ * reliability telemetry. Optional and additive: 1-arg `onStatus` handlers stay
36
+ * valid.
37
+ */
38
+ export interface PsLiteRelayStatusDetail {
39
+ code?: number;
40
+ reason?: string;
41
+ }
42
+ /**
43
+ * Close code the relay sends to the losing side when a new connection claims
44
+ * the same sessionId. Terminal for this client: reconnecting would evict the
45
+ * winner right back and the two tabs would trade the session every backoff
46
+ * tick (observed live as a 1012 eviction loop every ~2s with two app tabs).
47
+ */
48
+ export declare const RELAY_CLOSE_SESSION_REPLACED = 1012;
16
49
  export interface PsLiteRelayClient {
17
50
  readonly sessionId: string;
18
51
  readonly url: string;
19
52
  close(reason?: string): void;
53
+ /**
54
+ * Resolves once the relay has finished delivering everything in flight: no
55
+ * HTTP streams open and the socket's send buffer empty. A non-OPEN socket
56
+ * counts as drained (its buffered bytes died with it and reconnect starts
57
+ * from a clean slate). Resolves after `timeoutMs` regardless, so callers can
58
+ * never deadlock on a wedged tunnel.
59
+ */
60
+ whenDrained(options?: {
61
+ /** Max time to wait before resolving anyway (ms). Default 20_000. */
62
+ timeoutMs?: number;
63
+ /** Drain-state poll cadence (ms). Default 50. */
64
+ pollIntervalMs?: number;
65
+ }): Promise<void>;
20
66
  }
21
67
  export interface PsLiteRelayWebSocketFactory {
22
68
  (url: string): PsLiteRelayWebSocket;
23
69
  }
70
+ /**
71
+ * Subset of the standard CloseEvent the relay client reads. Browser
72
+ * WebSockets pass a full CloseEvent here; fakes may call onclose with
73
+ * nothing (treated as an abnormal close).
74
+ */
75
+ export interface PsLiteRelayCloseEvent {
76
+ code?: number;
77
+ reason?: string;
78
+ }
24
79
  export interface PsLiteRelayWebSocket {
25
80
  binaryType: string;
26
81
  readonly readyState: number;
27
82
  readonly OPEN: number;
28
83
  readonly CONNECTING: number;
84
+ /**
85
+ * Bytes accepted by send() but not yet flushed to the network (standard
86
+ * WebSocket.bufferedAmount). Optional so lightweight fakes can omit it;
87
+ * treated as 0 when absent.
88
+ */
89
+ readonly bufferedAmount?: number;
29
90
  onopen: (() => void) | null;
30
91
  onmessage: ((event: {
31
92
  data: string | ArrayBuffer | Uint8Array;
32
93
  }) => void) | null;
33
- onclose: (() => void) | null;
94
+ onclose: ((event?: PsLiteRelayCloseEvent) => void) | null;
34
95
  onerror: (() => void) | null;
35
96
  send(data: string | Uint8Array): void;
36
97
  close(code?: number, reason?: string): void;
@@ -60,8 +121,26 @@ export interface PsLiteRelayTlsStep {
60
121
  }
61
122
  export declare function psLiteRelayControlUrl(sessionId: string, controlUrl?: string): string;
62
123
  export declare function psLiteRelayPublicUrl(sessionId: string, publicSuffix?: string): string;
124
+ /**
125
+ * Defers read-fulfillment reports until the relay has delivered the in-flight
126
+ * response. The core data handler reports fulfillment as soon as it BUILDS the
127
+ * response, but over the relay the (potentially multi-MB) body still has to be
128
+ * pumped through TLS over the WebSocket. Consumers act on the report
129
+ * immediately — the DCR approval page closes the tab hosting this PS — so an
130
+ * eager report kills the tunnel mid-transfer and the builder gets a truncated
131
+ * body (UND_ERR_RES_CONTENT_LENGTH_MISMATCH) after escrow already settled.
132
+ * Gating the report on relay drain makes "fulfilled" mean "delivered".
133
+ *
134
+ * `getRelayClient` is late-bound: the runtime needs the reporter at
135
+ * construction time, before the relay client exists. When it returns
136
+ * undefined (relay disabled / not started yet), reports pass straight through.
137
+ */
138
+ export declare function createRelayDrainGatedReadFulfillmentReporter(reporter: PersonalServerReadFulfillmentReporter, getRelayClient: () => Pick<PsLiteRelayClient, "whenDrained"> | undefined): PersonalServerReadFulfillmentReporter;
63
139
  export declare function startPsLiteRelayClient(options: PsLiteRelayClientOptions): PsLiteRelayClient;
64
- export declare function buildHttpResponse(response: PsLiteBridgeResponse): string;
140
+ export declare function buildHttpResponse(response: PsLiteBridgeResponse, opts?: {
141
+ bodyOverride?: Uint8Array;
142
+ contentEncoding?: string;
143
+ }): string;
65
144
  export declare function encodeDataFrame(streamId: number, payload: Uint8Array): Uint8Array;
66
145
  export declare function decodeDataFrame(data: string | ArrayBuffer | Uint8Array): {
67
146
  streamId: number;
@@ -1 +1 @@
1
- {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"}
package/dist/relay.js CHANGED
@@ -2,34 +2,93 @@ import { handlePsLiteBridgeRequest, } from "./bridge.js";
2
2
  import { createRustlsPsLiteRelayTlsFactory } from "./relay-tls.js";
3
3
  const DATA_FRAME_TYPE = 1;
4
4
  const HEADER_BYTES = 5;
5
+ const RESPONSE_CHUNK_BYTES = 16 * 1024;
5
6
  const DEFAULT_CONTROL_URL = "wss://control.34.16.49.200.sslip.io:8443";
6
7
  const DEFAULT_PUBLIC_SUFFIX = "34.16.49.200.sslip.io";
7
8
  const DEFAULT_ORIGIN = "https://ps-lite.local";
9
+ /**
10
+ * Close code the relay sends to the losing side when a new connection claims
11
+ * the same sessionId. Terminal for this client: reconnecting would evict the
12
+ * winner right back and the two tabs would trade the session every backoff
13
+ * tick (observed live as a 1012 eviction loop every ~2s with two app tabs).
14
+ */
15
+ export const RELAY_CLOSE_SESSION_REPLACED = 1012;
16
+ /**
17
+ * A heartbeat tick arriving more than this many intervals after the previous
18
+ * one means the tab's timers were throttled (Chrome backgrounds clamp them to
19
+ * >= 1/min), not that the tunnel is dead. Such a tick probes with a fresh ping
20
+ * instead of closing on stale elapsed time (BUI-665).
21
+ */
22
+ const HEARTBEAT_LATE_FIRE_FACTOR = 2;
8
23
  export function psLiteRelayControlUrl(sessionId, controlUrl = DEFAULT_CONTROL_URL) {
9
24
  return `${controlUrl.replace(/\/+$/, "")}/browser/${sessionId}`;
10
25
  }
11
26
  export function psLiteRelayPublicUrl(sessionId, publicSuffix = DEFAULT_PUBLIC_SUFFIX) {
12
27
  return `https://${sessionId}.${publicSuffix.replace(/^\./, "")}`;
13
28
  }
29
+ /**
30
+ * Defers read-fulfillment reports until the relay has delivered the in-flight
31
+ * response. The core data handler reports fulfillment as soon as it BUILDS the
32
+ * response, but over the relay the (potentially multi-MB) body still has to be
33
+ * pumped through TLS over the WebSocket. Consumers act on the report
34
+ * immediately — the DCR approval page closes the tab hosting this PS — so an
35
+ * eager report kills the tunnel mid-transfer and the builder gets a truncated
36
+ * body (UND_ERR_RES_CONTENT_LENGTH_MISMATCH) after escrow already settled.
37
+ * Gating the report on relay drain makes "fulfilled" mean "delivered".
38
+ *
39
+ * `getRelayClient` is late-bound: the runtime needs the reporter at
40
+ * construction time, before the relay client exists. When it returns
41
+ * undefined (relay disabled / not started yet), reports pass straight through.
42
+ */
43
+ export function createRelayDrainGatedReadFulfillmentReporter(reporter, getRelayClient) {
44
+ return {
45
+ async report(event) {
46
+ await getRelayClient()?.whenDrained();
47
+ return reporter.report(event);
48
+ },
49
+ };
50
+ }
14
51
  export function startPsLiteRelayClient(options) {
15
52
  const baseControlUrl = options.controlUrl ?? DEFAULT_CONTROL_URL;
16
53
  const controlUrl = psLiteRelayControlUrl(options.sessionId, baseControlUrl);
17
- const socket = createSocket(options.webSocketFactory, controlUrl);
18
54
  const tls = options.tls === undefined
19
55
  ? createRustlsPsLiteRelayTlsFactory({
20
56
  controlUrl: baseControlUrl,
21
57
  publicSuffix: options.publicSuffix,
22
58
  certIssuerUrl: options.certIssuerUrl,
59
+ identityStore: options.tlsIdentityStore,
23
60
  logger: options.logger,
24
61
  })
25
62
  : options.tls;
26
63
  const streams = new Map();
27
64
  const pendingStreamData = new Map();
28
65
  const origin = options.origin ?? DEFAULT_ORIGIN;
66
+ // Resilience knobs. Defaults chosen so a backgrounded mobile tab whose socket
67
+ // went half-open (no `onclose` ever fires) is detected within ~1 missed
68
+ // heartbeat and reconnected with capped exponential backoff.
69
+ const heartbeatIntervalMs = options.heartbeatIntervalMs ?? 20_000;
70
+ const heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45_000;
71
+ const reconnectInitialDelayMs = options.reconnectInitialDelayMs ?? 1_000;
72
+ const reconnectMaxDelayMs = options.reconnectMaxDelayMs ?? 30_000;
29
73
  let issueToken;
30
74
  let closed = false;
31
- socket.binaryType = "arraybuffer";
32
- options.onStatus?.("connecting");
75
+ // `socket` is reassigned on every (re)connect; all the closures below read it
76
+ // lazily at call time, so they always act on the current socket.
77
+ let socket;
78
+ let reconnectAttempts = 0;
79
+ let heartbeatTimer;
80
+ let reconnectTimer;
81
+ // Liveness is evidence-based (BUI-665): ANY frame from the relay — data,
82
+ // control, pong — proves the tunnel is alive. The heartbeat declares it dead
83
+ // only when a ping it actually SENT went unanswered by any frame for the
84
+ // full timeout window, measured by wall clock. A late-firing throttled timer
85
+ // that finds recent frames must never kill a healthy socket.
86
+ let lastFrameReceivedAt = 0;
87
+ // Wall-clock send time of the oldest ping not yet answered by any frame;
88
+ // undefined when the tunnel has proven itself since the last ping.
89
+ let unansweredPingSentAt;
90
+ let lastHeartbeatCheckAt = 0;
91
+ let heartbeatGraceUsed = false;
33
92
  const log = (line) => options.logger?.(line);
34
93
  const sendText = (message) => {
35
94
  if (socket.readyState === socket.OPEN) {
@@ -50,12 +109,19 @@ export function startPsLiteRelayClient(options) {
50
109
  };
51
110
  const writePlaintextResponse = (stream, responseBytes) => {
52
111
  if (!stream.tls) {
53
- sendData(stream.streamId, responseBytes);
112
+ for (const chunk of chunks(responseBytes, RESPONSE_CHUNK_BYTES)) {
113
+ sendData(stream.streamId, chunk);
114
+ }
54
115
  return;
55
116
  }
56
- const step = stream.tls.writePlaintext(responseBytes, true);
57
- if (step.tls.length > 0) {
58
- sendData(stream.streamId, step.tls);
117
+ const responseChunks = chunks(responseBytes, RESPONSE_CHUNK_BYTES);
118
+ for (let index = 0; index < responseChunks.length; index += 1) {
119
+ const step = stream.tls.writePlaintext(responseChunks[index], index === responseChunks.length - 1);
120
+ for (const chunk of chunks(step.tls, RESPONSE_CHUNK_BYTES)) {
121
+ if (chunk.length > 0) {
122
+ sendData(stream.streamId, chunk);
123
+ }
124
+ }
59
125
  }
60
126
  };
61
127
  const drainHttpRequests = async (stream) => {
@@ -141,6 +207,8 @@ export function startPsLiteRelayClient(options) {
141
207
  return;
142
208
  }
143
209
  if (message.type === "pong") {
210
+ // Liveness is recorded for every frame in socket.onmessage; the pong
211
+ // carries no other payload.
144
212
  return;
145
213
  }
146
214
  if (message.type === "stream.open" &&
@@ -174,26 +242,164 @@ export function startPsLiteRelayClient(options) {
174
242
  }
175
243
  processPayload(stream, frame.payload);
176
244
  };
177
- socket.onopen = () => options.onStatus?.("connected");
178
- socket.onmessage = (event) => {
179
- if (typeof event.data === "string") {
180
- handleControl(JSON.parse(event.data));
245
+ const stopHeartbeat = () => {
246
+ if (heartbeatTimer !== undefined) {
247
+ clearInterval(heartbeatTimer);
248
+ heartbeatTimer = undefined;
249
+ }
250
+ };
251
+ const heartbeatTick = () => {
252
+ if (socket.readyState !== socket.OPEN) {
253
+ return;
254
+ }
255
+ const now = Date.now();
256
+ // A tick arriving well past its cadence means the tab's timers were
257
+ // throttled — the elapsed time says nothing about the tunnel.
258
+ const firedLate = now - lastHeartbeatCheckAt >
259
+ heartbeatIntervalMs * HEARTBEAT_LATE_FIRE_FACTOR;
260
+ lastHeartbeatCheckAt = now;
261
+ if (unansweredPingSentAt !== undefined &&
262
+ lastFrameReceivedAt >= unansweredPingSentAt) {
263
+ // A frame arrived since the ping went out — pong, data, or control all
264
+ // count as proof of life.
265
+ unansweredPingSentAt = undefined;
266
+ heartbeatGraceUsed = false;
267
+ }
268
+ const pingUnansweredForFullWindow = unansweredPingSentAt !== undefined &&
269
+ now - unansweredPingSentAt > heartbeatTimeoutMs;
270
+ if (pingUnansweredForFullWindow && firedLate && !heartbeatGraceUsed) {
271
+ // Throttling, not deadness: the ping (and its answer) may have been
272
+ // stalled along with the tab. Probe with a fresh ping and re-check on
273
+ // the next tick instead of killing a usually-healthy socket.
274
+ heartbeatGraceUsed = true;
275
+ unansweredPingSentAt = undefined;
276
+ }
277
+ else if (pingUnansweredForFullWindow) {
278
+ // A backgrounded/suspended tab can leave the socket half-open: it never
279
+ // fires `onclose`, so reconnect-on-close alone never triggers. A ping we
280
+ // actually sent drew no frame at all for the full wall-clock window —
281
+ // the tunnel really is dead; force it closed → onclose → reconnect.
282
+ log("relay heartbeat timeout — forcing reconnect");
283
+ try {
284
+ socket.close(4000, "heartbeat_timeout");
285
+ }
286
+ catch {
287
+ // Ignore: a socket that can't be closed will be replaced on reconnect.
288
+ }
181
289
  return;
182
290
  }
183
- handleDataFrame(event.data);
291
+ sendText({ type: "ping" });
292
+ if (unansweredPingSentAt === undefined) {
293
+ unansweredPingSentAt = now;
294
+ }
295
+ };
296
+ const startHeartbeat = () => {
297
+ stopHeartbeat();
298
+ lastFrameReceivedAt = Date.now();
299
+ lastHeartbeatCheckAt = Date.now();
300
+ unansweredPingSentAt = undefined;
301
+ heartbeatGraceUsed = false;
302
+ heartbeatTimer = setInterval(heartbeatTick, heartbeatIntervalMs);
184
303
  };
185
- socket.onclose = () => {
186
- streams.forEach((stream) => stream.tls?.close?.());
187
- streams.clear();
188
- pendingStreamData.clear();
189
- options.onStatus?.(closed ? "closed" : "disconnected");
304
+ const scheduleReconnect = () => {
305
+ if (closed || reconnectTimer !== undefined) {
306
+ return;
307
+ }
308
+ const delay = Math.min(reconnectMaxDelayMs, reconnectInitialDelayMs * 2 ** reconnectAttempts);
309
+ reconnectAttempts += 1;
310
+ reconnectTimer = setTimeout(() => {
311
+ reconnectTimer = undefined;
312
+ connect();
313
+ }, delay);
314
+ };
315
+ function connect() {
316
+ // Terminal states (intentional close, or a 1012 session takeover) must
317
+ // never re-open a socket, even if a stale timer or event slips through.
318
+ if (closed) {
319
+ return;
320
+ }
321
+ issueToken = undefined;
322
+ socket = createSocket(options.webSocketFactory, controlUrl);
323
+ socket.binaryType = "arraybuffer";
324
+ options.onStatus?.("connecting");
325
+ socket.onopen = () => {
326
+ reconnectAttempts = 0;
327
+ startHeartbeat();
328
+ options.onStatus?.("connected");
329
+ };
330
+ socket.onmessage = (event) => {
331
+ lastFrameReceivedAt = Date.now();
332
+ if (typeof event.data === "string") {
333
+ handleControl(JSON.parse(event.data));
334
+ return;
335
+ }
336
+ handleDataFrame(event.data);
337
+ };
338
+ socket.onclose = (event) => {
339
+ stopHeartbeat();
340
+ streams.forEach((stream) => stream.tls?.close?.());
341
+ streams.clear();
342
+ pendingStreamData.clear();
343
+ issueToken = undefined;
344
+ const detail = { code: event?.code, reason: event?.reason };
345
+ if (closed) {
346
+ options.onStatus?.("closed", detail);
347
+ return;
348
+ }
349
+ if (event?.code === RELAY_CLOSE_SESSION_REPLACED) {
350
+ // Another connection (typically a second tab) now owns this session.
351
+ // Reconnecting would evict it and start a session tug-of-war, so this
352
+ // client steps down for good and lets the host surface the handoff.
353
+ closed = true;
354
+ // Cancel any reconnect already scheduled by an earlier drop so a
355
+ // pending timer can't fire connect() after we've stepped down.
356
+ if (reconnectTimer !== undefined) {
357
+ clearTimeout(reconnectTimer);
358
+ reconnectTimer = undefined;
359
+ }
360
+ log("relay session replaced by another connection — not reconnecting");
361
+ options.onStatus?.("replaced", detail);
362
+ return;
363
+ }
364
+ options.onStatus?.("disconnected", detail);
365
+ scheduleReconnect();
366
+ };
367
+ socket.onerror = () => {
368
+ if (closed) {
369
+ return;
370
+ }
371
+ options.onStatus?.("error");
372
+ };
373
+ }
374
+ connect();
375
+ // Drained = no HTTP streams in flight and nothing queued in the socket's
376
+ // send buffer. Only an OPEN socket can still be flushing; a closed or
377
+ // reconnecting socket's buffered bytes are gone either way.
378
+ const isDrained = () => {
379
+ if (streams.size > 0) {
380
+ return false;
381
+ }
382
+ if (!closed && socket.readyState === socket.OPEN) {
383
+ return (socket.bufferedAmount ?? 0) === 0;
384
+ }
385
+ return true;
190
386
  };
191
- socket.onerror = () => options.onStatus?.("error");
192
387
  return {
193
388
  sessionId: options.sessionId,
194
389
  url: controlUrl,
390
+ async whenDrained({ timeoutMs = 20_000, pollIntervalMs = 50 } = {}) {
391
+ const deadline = Date.now() + timeoutMs;
392
+ while (!isDrained() && Date.now() < deadline) {
393
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
394
+ }
395
+ },
195
396
  close(reason = "closed") {
196
397
  closed = true;
398
+ stopHeartbeat();
399
+ if (reconnectTimer !== undefined) {
400
+ clearTimeout(reconnectTimer);
401
+ reconnectTimer = undefined;
402
+ }
197
403
  streams.forEach((stream) => stream.tls?.close?.());
198
404
  streams.clear();
199
405
  pendingStreamData.clear();
@@ -213,15 +419,78 @@ async function handleRelayHttpRequest(runtime, request, origin) {
213
419
  const bridgeResponse = await handlePsLiteBridgeRequest(runtime, bridgeRequest, {
214
420
  origin,
215
421
  });
216
- return buildHttpResponse(bridgeResponse);
422
+ // Large exports (e.g. chatgpt.conversations) are big JSON streamed over the
423
+ // relay's WebSocket tunnel; an uncompressed body inflates transfer time and the
424
+ // window for a mid-stream drop (truncated read → UND_ERR_RES_CONTENT_LENGTH_MISMATCH).
425
+ // gzip when the client accepts it and the payload is large enough to be worth it;
426
+ // the SDK/undici sends Accept-Encoding and auto-decompresses. See BUI-591.
427
+ const bodyBytes = decodeBase64(bridgeResponse.body);
428
+ const acceptsGzip = (request.headers["accept-encoding"] ?? "").includes("gzip");
429
+ const alreadyEncoded = Boolean(bridgeResponse.headers?.["content-encoding"]);
430
+ if (acceptsGzip &&
431
+ !alreadyEncoded &&
432
+ bodyBytes.length >= GZIP_MIN_BYTES &&
433
+ typeof CompressionStream !== "undefined") {
434
+ const gzipped = await gzipBytes(bodyBytes);
435
+ return buildHttpResponse(bridgeResponse, {
436
+ bodyOverride: gzipped,
437
+ contentEncoding: "gzip",
438
+ });
439
+ }
440
+ return buildHttpResponse(bridgeResponse, { bodyOverride: bodyBytes });
441
+ }
442
+ // Responses below this size aren't worth the gzip overhead, and small reads
443
+ // already complete reliably over the relay.
444
+ const GZIP_MIN_BYTES = 1024;
445
+ async function gzipBytes(input) {
446
+ const cs = new CompressionStream("gzip");
447
+ const writer = cs.writable.getWriter();
448
+ // Copy into a fresh ArrayBuffer-backed view: TS types the stream's chunk as
449
+ // BufferSource, which excludes the generic Uint8Array<ArrayBufferLike>.
450
+ const chunk = new Uint8Array(input);
451
+ const writeDone = writer.write(chunk).then(() => writer.close());
452
+ const reader = cs.readable.getReader();
453
+ const chunks = [];
454
+ let total = 0;
455
+ for (;;) {
456
+ const { value, done } = await reader.read();
457
+ if (done)
458
+ break;
459
+ if (value) {
460
+ chunks.push(value);
461
+ total += value.length;
462
+ }
463
+ }
464
+ await writeDone;
465
+ const out = new Uint8Array(total);
466
+ let offset = 0;
467
+ for (const chunk of chunks) {
468
+ out.set(chunk, offset);
469
+ offset += chunk.length;
470
+ }
471
+ return out;
217
472
  }
218
- export function buildHttpResponse(response) {
473
+ export function buildHttpResponse(response, opts) {
219
474
  const responseHeaders = {
220
475
  "cache-control": "no-store",
221
476
  connection: "close",
222
477
  ...response.headers,
223
478
  };
224
- const bodyBytes = decodeBase64(response.body);
479
+ // We always emit an authoritative content-length below, computed from the
480
+ // exact bytes we write (gzip changes the length vs. the upstream value). Drop
481
+ // any upstream copy first — the core raw-data path sets Content-Length and the
482
+ // bridge lowercases it, so without this the head would carry two conflicting
483
+ // content-length values and clients reject that (the same mismatch class this
484
+ // change fixes). Match case-insensitively in case the name wasn't normalized.
485
+ for (const key of Object.keys(responseHeaders)) {
486
+ if (key.toLowerCase() === "content-length") {
487
+ delete responseHeaders[key];
488
+ }
489
+ }
490
+ if (opts?.contentEncoding) {
491
+ responseHeaders["content-encoding"] = opts.contentEncoding;
492
+ }
493
+ const bodyBytes = opts?.bodyOverride ?? decodeBase64(response.body);
225
494
  const head = [
226
495
  `HTTP/1.1 ${response.status} ${httpStatusText(response.status)}`,
227
496
  ...Object.entries(responseHeaders).map(([key, value]) => `${key}: ${value}`),
@@ -309,6 +578,15 @@ function encodeBase64(bytes) {
309
578
  ? globalThis.btoa(binary)
310
579
  : Buffer.from(binary, "binary").toString("base64");
311
580
  }
581
+ function chunks(bytes, chunkBytes) {
582
+ if (bytes.length === 0)
583
+ return [bytes];
584
+ const result = [];
585
+ for (let offset = 0; offset < bytes.length; offset += chunkBytes) {
586
+ result.push(bytes.slice(offset, offset + chunkBytes));
587
+ }
588
+ return result;
589
+ }
312
590
  function decodeBase64(input) {
313
591
  if (!input)
314
592
  return new Uint8Array();