@opendatalabs/personal-server-ts-lite 0.0.1-canary.00328bf
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridge.d.ts +23 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +53 -0
- package/dist/bridge.js.map +1 -0
- package/dist/browser-runtime.d.ts +58 -0
- package/dist/browser-runtime.d.ts.map +1 -0
- package/dist/browser-runtime.js +214 -0
- package/dist/browser-runtime.js.map +1 -0
- package/dist/browser-tls-rustls/browser_tls_rustls.d.ts +49 -0
- package/dist/browser-tls-rustls/browser_tls_rustls.js +401 -0
- package/dist/browser-tls-rustls/browser_tls_rustls_bg.wasm +0 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +408 -0
- package/dist/client.js.map +1 -0
- package/dist/derivatives.d.ts +51 -0
- package/dist/derivatives.d.ts.map +1 -0
- package/dist/derivatives.js +87 -0
- package/dist/derivatives.js.map +1 -0
- package/dist/diagnostics.d.ts +166 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +265 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-store.d.ts +35 -0
- package/dist/mcp-store.d.ts.map +1 -0
- package/dist/mcp-store.js +208 -0
- package/dist/mcp-store.js.map +1 -0
- package/dist/owner-binding.d.ts +7 -0
- package/dist/owner-binding.d.ts.map +1 -0
- package/dist/owner-binding.js +18 -0
- package/dist/owner-binding.js.map +1 -0
- package/dist/persistence.d.ts +69 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +58 -0
- package/dist/persistence.js.map +1 -0
- package/dist/relay-tls.d.ts +61 -0
- package/dist/relay-tls.d.ts.map +1 -0
- package/dist/relay-tls.js +316 -0
- package/dist/relay-tls.js.map +1 -0
- package/dist/relay.d.ts +149 -0
- package/dist/relay.d.ts.map +1 -0
- package/dist/relay.js +646 -0
- package/dist/relay.js.map +1 -0
- package/dist/runtime.d.ts +188 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1178 -0
- package/dist/runtime.js.map +1 -0
- package/dist/state.d.ts +72 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +366 -0
- package/dist/state.js.map +1 -0
- package/dist/storage-utils.d.ts +8 -0
- package/dist/storage-utils.d.ts.map +1 -0
- package/dist/storage-utils.js +67 -0
- package/dist/storage-utils.js.map +1 -0
- package/dist/storage.d.ts +61 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +718 -0
- package/dist/storage.js.map +1 -0
- package/dist/sync.d.ts +58 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +216 -0
- package/dist/sync.js.map +1 -0
- package/package.json +40 -0
package/dist/relay.js
ADDED
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
import { handlePsLiteBridgeRequest, } from "./bridge.js";
|
|
2
|
+
import { createRustlsPsLiteRelayTlsFactory } from "./relay-tls.js";
|
|
3
|
+
const DATA_FRAME_TYPE = 1;
|
|
4
|
+
const HEADER_BYTES = 5;
|
|
5
|
+
const RESPONSE_CHUNK_BYTES = 16 * 1024;
|
|
6
|
+
const DEFAULT_CONTROL_URL = "wss://control.34.16.49.200.sslip.io:8443";
|
|
7
|
+
const DEFAULT_PUBLIC_SUFFIX = "34.16.49.200.sslip.io";
|
|
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;
|
|
23
|
+
export function psLiteRelayControlUrl(sessionId, controlUrl = DEFAULT_CONTROL_URL) {
|
|
24
|
+
return `${controlUrl.replace(/\/+$/, "")}/browser/${sessionId}`;
|
|
25
|
+
}
|
|
26
|
+
export function psLiteRelayPublicUrl(sessionId, publicSuffix = DEFAULT_PUBLIC_SUFFIX) {
|
|
27
|
+
return `https://${sessionId}.${publicSuffix.replace(/^\./, "")}`;
|
|
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
|
+
}
|
|
51
|
+
export function startPsLiteRelayClient(options) {
|
|
52
|
+
const baseControlUrl = options.controlUrl ?? DEFAULT_CONTROL_URL;
|
|
53
|
+
const controlUrl = psLiteRelayControlUrl(options.sessionId, baseControlUrl);
|
|
54
|
+
const tls = options.tls === undefined
|
|
55
|
+
? createRustlsPsLiteRelayTlsFactory({
|
|
56
|
+
controlUrl: baseControlUrl,
|
|
57
|
+
publicSuffix: options.publicSuffix,
|
|
58
|
+
certIssuerUrl: options.certIssuerUrl,
|
|
59
|
+
identityStore: options.tlsIdentityStore,
|
|
60
|
+
logger: options.logger,
|
|
61
|
+
})
|
|
62
|
+
: options.tls;
|
|
63
|
+
const streams = new Map();
|
|
64
|
+
const pendingStreamData = new Map();
|
|
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;
|
|
73
|
+
let issueToken;
|
|
74
|
+
let closed = false;
|
|
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;
|
|
92
|
+
const log = (line) => options.logger?.(line);
|
|
93
|
+
const sendText = (message) => {
|
|
94
|
+
if (socket.readyState === socket.OPEN) {
|
|
95
|
+
socket.send(JSON.stringify(message));
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const sendData = (streamId, payload) => {
|
|
99
|
+
if (socket.readyState === socket.OPEN) {
|
|
100
|
+
socket.send(encodeDataFrame(streamId, payload));
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const closeStream = (streamId, reason) => {
|
|
104
|
+
const stream = streams.get(streamId);
|
|
105
|
+
stream?.tls?.close?.();
|
|
106
|
+
streams.delete(streamId);
|
|
107
|
+
pendingStreamData.delete(streamId);
|
|
108
|
+
sendText({ type: "stream.close", streamId, reason });
|
|
109
|
+
};
|
|
110
|
+
const writePlaintextResponse = (stream, responseBytes) => {
|
|
111
|
+
if (!stream.tls) {
|
|
112
|
+
for (const chunk of chunks(responseBytes, RESPONSE_CHUNK_BYTES)) {
|
|
113
|
+
sendData(stream.streamId, chunk);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
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
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const drainHttpRequests = async (stream) => {
|
|
128
|
+
while (true) {
|
|
129
|
+
const parsed = parseHttpRequest(stream.plaintext);
|
|
130
|
+
if (!parsed) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
stream.plaintext = stream.plaintext.slice(parsed.consumedBytes);
|
|
134
|
+
const response = await handleRelayHttpRequest(options.runtime, parsed.request, origin);
|
|
135
|
+
// `response` is a binary (latin1) string: buildHttpResponse appends the
|
|
136
|
+
// body via bytesToBinary, so each char code 0x00–0xFF is one body byte.
|
|
137
|
+
// It must be turned back into bytes the same way (binaryToBytes), NOT
|
|
138
|
+
// UTF-8 re-encoded — textToBytes would expand every byte >= 0x80 into a
|
|
139
|
+
// 2-byte sequence, corrupting binary payloads (e.g. OpenPGP-encrypted
|
|
140
|
+
// files fail downstream with "not a valid OpenPGP message"). ASCII/JSON
|
|
141
|
+
// bodies survive UTF-8, which is why only encrypted binary downloads broke.
|
|
142
|
+
writePlaintextResponse(stream, binaryToBytes(response));
|
|
143
|
+
closeStream(stream.streamId, "http_response_sent");
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const handlePlaintext = (stream, plaintext) => {
|
|
148
|
+
if (plaintext.length === 0) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
stream.plaintext += bytesToBinary(plaintext);
|
|
152
|
+
void drainHttpRequests(stream).catch((error) => {
|
|
153
|
+
log(error instanceof Error ? error.message : String(error));
|
|
154
|
+
closeStream(stream.streamId, "handler_error");
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
const processPayload = (stream, payload) => {
|
|
158
|
+
if (!stream.tls) {
|
|
159
|
+
handlePlaintext(stream, payload);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const step = stream.tls.processTls(payload);
|
|
164
|
+
if (step.tls.length > 0) {
|
|
165
|
+
sendData(stream.streamId, step.tls);
|
|
166
|
+
}
|
|
167
|
+
handlePlaintext(stream, step.plaintext);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
log(error instanceof Error ? error.message : String(error));
|
|
171
|
+
closeStream(stream.streamId, "tls_error");
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const openStream = async (streamId) => {
|
|
175
|
+
const stream = {
|
|
176
|
+
streamId,
|
|
177
|
+
plaintext: "",
|
|
178
|
+
};
|
|
179
|
+
if (tls) {
|
|
180
|
+
stream.tls = await tls.createStream({
|
|
181
|
+
sessionId: options.sessionId,
|
|
182
|
+
streamId,
|
|
183
|
+
issueToken,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
streams.set(streamId, stream);
|
|
187
|
+
const buffered = pendingStreamData.get(streamId) ?? [];
|
|
188
|
+
pendingStreamData.delete(streamId);
|
|
189
|
+
for (const payload of buffered) {
|
|
190
|
+
processPayload(stream, payload);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
const handleControl = (message) => {
|
|
194
|
+
if (message.type === "session.ready") {
|
|
195
|
+
issueToken = message.issueToken;
|
|
196
|
+
options.onStatus?.("connected");
|
|
197
|
+
if (tls && tls.prepare) {
|
|
198
|
+
void tls
|
|
199
|
+
.prepare({
|
|
200
|
+
sessionId: options.sessionId,
|
|
201
|
+
issueToken,
|
|
202
|
+
})
|
|
203
|
+
.catch((error) => {
|
|
204
|
+
log(error instanceof Error ? error.message : String(error));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (message.type === "pong") {
|
|
210
|
+
// Liveness is recorded for every frame in socket.onmessage; the pong
|
|
211
|
+
// carries no other payload.
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (message.type === "stream.open" &&
|
|
215
|
+
typeof message.streamId === "number") {
|
|
216
|
+
void openStream(message.streamId).catch((error) => {
|
|
217
|
+
log(error instanceof Error ? error.message : String(error));
|
|
218
|
+
if (typeof message.streamId === "number") {
|
|
219
|
+
closeStream(message.streamId, "stream_open_error");
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (message.type === "stream.close" &&
|
|
225
|
+
typeof message.streamId === "number") {
|
|
226
|
+
streams.get(message.streamId)?.tls?.close?.();
|
|
227
|
+
streams.delete(message.streamId);
|
|
228
|
+
pendingStreamData.delete(message.streamId);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
const handleDataFrame = (data) => {
|
|
232
|
+
const frame = decodeDataFrame(data);
|
|
233
|
+
if (!frame) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const stream = streams.get(frame.streamId);
|
|
237
|
+
if (!stream) {
|
|
238
|
+
const buffered = pendingStreamData.get(frame.streamId) ?? [];
|
|
239
|
+
buffered.push(frame.payload);
|
|
240
|
+
pendingStreamData.set(frame.streamId, buffered);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
processPayload(stream, frame.payload);
|
|
244
|
+
};
|
|
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
|
+
}
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
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);
|
|
303
|
+
};
|
|
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;
|
|
386
|
+
};
|
|
387
|
+
return {
|
|
388
|
+
sessionId: options.sessionId,
|
|
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
|
+
},
|
|
396
|
+
close(reason = "closed") {
|
|
397
|
+
closed = true;
|
|
398
|
+
stopHeartbeat();
|
|
399
|
+
if (reconnectTimer !== undefined) {
|
|
400
|
+
clearTimeout(reconnectTimer);
|
|
401
|
+
reconnectTimer = undefined;
|
|
402
|
+
}
|
|
403
|
+
streams.forEach((stream) => stream.tls?.close?.());
|
|
404
|
+
streams.clear();
|
|
405
|
+
pendingStreamData.clear();
|
|
406
|
+
socket.close(1000, reason);
|
|
407
|
+
},
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
async function handleRelayHttpRequest(runtime, request, origin) {
|
|
411
|
+
const bridgeRequest = {
|
|
412
|
+
requestId: crypto.randomUUID(),
|
|
413
|
+
method: request.method,
|
|
414
|
+
path: request.path,
|
|
415
|
+
query: request.query,
|
|
416
|
+
headers: request.headers,
|
|
417
|
+
body: encodeBase64(request.body),
|
|
418
|
+
};
|
|
419
|
+
const bridgeResponse = await handlePsLiteBridgeRequest(runtime, bridgeRequest, {
|
|
420
|
+
origin,
|
|
421
|
+
});
|
|
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;
|
|
472
|
+
}
|
|
473
|
+
export function buildHttpResponse(response, opts) {
|
|
474
|
+
const responseHeaders = {
|
|
475
|
+
"cache-control": "no-store",
|
|
476
|
+
connection: "close",
|
|
477
|
+
...response.headers,
|
|
478
|
+
};
|
|
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);
|
|
494
|
+
const head = [
|
|
495
|
+
`HTTP/1.1 ${response.status} ${httpStatusText(response.status)}`,
|
|
496
|
+
...Object.entries(responseHeaders).map(([key, value]) => `${key}: ${value}`),
|
|
497
|
+
`content-length: ${bodyBytes.length}`,
|
|
498
|
+
"",
|
|
499
|
+
"",
|
|
500
|
+
].join("\r\n");
|
|
501
|
+
return head + bytesToBinary(bodyBytes);
|
|
502
|
+
}
|
|
503
|
+
function createSocket(factory, url) {
|
|
504
|
+
if (factory) {
|
|
505
|
+
return factory(url);
|
|
506
|
+
}
|
|
507
|
+
if (typeof WebSocket === "undefined") {
|
|
508
|
+
throw new Error("WebSocket is required to start PS Lite relay client");
|
|
509
|
+
}
|
|
510
|
+
return new WebSocket(url);
|
|
511
|
+
}
|
|
512
|
+
export function encodeDataFrame(streamId, payload) {
|
|
513
|
+
const frame = new Uint8Array(HEADER_BYTES + payload.length);
|
|
514
|
+
frame[0] = DATA_FRAME_TYPE;
|
|
515
|
+
writeUint32(frame, 1, streamId);
|
|
516
|
+
frame.set(payload, HEADER_BYTES);
|
|
517
|
+
return frame;
|
|
518
|
+
}
|
|
519
|
+
export function decodeDataFrame(data) {
|
|
520
|
+
const frame = typeof data === "string"
|
|
521
|
+
? textToBytes(data)
|
|
522
|
+
: data instanceof Uint8Array
|
|
523
|
+
? data
|
|
524
|
+
: new Uint8Array(data);
|
|
525
|
+
if (frame.length < HEADER_BYTES || frame[0] !== DATA_FRAME_TYPE) {
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
return {
|
|
529
|
+
streamId: readUint32(frame, 1),
|
|
530
|
+
payload: frame.slice(HEADER_BYTES),
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function parseHttpRequest(buffer) {
|
|
534
|
+
const headerEnd = buffer.indexOf("\r\n\r\n");
|
|
535
|
+
if (headerEnd === -1) {
|
|
536
|
+
return undefined;
|
|
537
|
+
}
|
|
538
|
+
const headerBlock = buffer.slice(0, headerEnd);
|
|
539
|
+
const lines = headerBlock.split("\r\n");
|
|
540
|
+
const [method, target] = lines[0]?.split(" ") ?? [];
|
|
541
|
+
if (!method || !target) {
|
|
542
|
+
return undefined;
|
|
543
|
+
}
|
|
544
|
+
const headers = {};
|
|
545
|
+
for (const line of lines.slice(1)) {
|
|
546
|
+
const separator = line.indexOf(":");
|
|
547
|
+
if (separator === -1) {
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
headers[line.slice(0, separator).trim().toLowerCase()] = line
|
|
551
|
+
.slice(separator + 1)
|
|
552
|
+
.trim();
|
|
553
|
+
}
|
|
554
|
+
const bodyStart = headerEnd + 4;
|
|
555
|
+
const contentLength = Number(headers["content-length"] ?? "0");
|
|
556
|
+
const requestEnd = bodyStart + contentLength;
|
|
557
|
+
if (buffer.length < requestEnd) {
|
|
558
|
+
return undefined;
|
|
559
|
+
}
|
|
560
|
+
const url = new URL(target, DEFAULT_ORIGIN);
|
|
561
|
+
return {
|
|
562
|
+
consumedBytes: requestEnd,
|
|
563
|
+
request: {
|
|
564
|
+
method,
|
|
565
|
+
path: url.pathname,
|
|
566
|
+
query: url.searchParams.toString(),
|
|
567
|
+
headers,
|
|
568
|
+
body: binaryToBytes(buffer.slice(bodyStart, requestEnd)),
|
|
569
|
+
},
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
function encodeBase64(bytes) {
|
|
573
|
+
let binary = "";
|
|
574
|
+
for (const byte of bytes) {
|
|
575
|
+
binary += String.fromCharCode(byte);
|
|
576
|
+
}
|
|
577
|
+
return typeof globalThis.btoa === "function"
|
|
578
|
+
? globalThis.btoa(binary)
|
|
579
|
+
: Buffer.from(binary, "binary").toString("base64");
|
|
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
|
+
}
|
|
590
|
+
function decodeBase64(input) {
|
|
591
|
+
if (!input)
|
|
592
|
+
return new Uint8Array();
|
|
593
|
+
const binary = typeof globalThis.atob === "function"
|
|
594
|
+
? globalThis.atob(input)
|
|
595
|
+
: Buffer.from(input, "base64").toString("binary");
|
|
596
|
+
return binaryToBytes(binary);
|
|
597
|
+
}
|
|
598
|
+
function textToBytes(value) {
|
|
599
|
+
return new TextEncoder().encode(value);
|
|
600
|
+
}
|
|
601
|
+
function binaryToBytes(value) {
|
|
602
|
+
return Uint8Array.from(value, (char) => char.charCodeAt(0));
|
|
603
|
+
}
|
|
604
|
+
function bytesToBinary(bytes) {
|
|
605
|
+
let result = "";
|
|
606
|
+
for (const byte of bytes) {
|
|
607
|
+
result += String.fromCharCode(byte);
|
|
608
|
+
}
|
|
609
|
+
return result;
|
|
610
|
+
}
|
|
611
|
+
function writeUint32(bytes, offset, value) {
|
|
612
|
+
bytes[offset] = (value >>> 24) & 0xff;
|
|
613
|
+
bytes[offset + 1] = (value >>> 16) & 0xff;
|
|
614
|
+
bytes[offset + 2] = (value >>> 8) & 0xff;
|
|
615
|
+
bytes[offset + 3] = value & 0xff;
|
|
616
|
+
}
|
|
617
|
+
function readUint32(bytes, offset) {
|
|
618
|
+
return (bytes[offset] * 0x1000000 +
|
|
619
|
+
((bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]));
|
|
620
|
+
}
|
|
621
|
+
function httpStatusText(status) {
|
|
622
|
+
if (status === 200)
|
|
623
|
+
return "OK";
|
|
624
|
+
if (status === 201)
|
|
625
|
+
return "Created";
|
|
626
|
+
if (status === 204)
|
|
627
|
+
return "No Content";
|
|
628
|
+
if (status === 400)
|
|
629
|
+
return "Bad Request";
|
|
630
|
+
if (status === 401)
|
|
631
|
+
return "Unauthorized";
|
|
632
|
+
if (status === 403)
|
|
633
|
+
return "Forbidden";
|
|
634
|
+
if (status === 404)
|
|
635
|
+
return "Not Found";
|
|
636
|
+
if (status === 405)
|
|
637
|
+
return "Method Not Allowed";
|
|
638
|
+
if (status === 413)
|
|
639
|
+
return "Content Too Large";
|
|
640
|
+
if (status === 500)
|
|
641
|
+
return "Internal Server Error";
|
|
642
|
+
if (status === 503)
|
|
643
|
+
return "Service Unavailable";
|
|
644
|
+
return "Error";
|
|
645
|
+
}
|
|
646
|
+
//# sourceMappingURL=relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.js","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"}
|