@openchambery/web 2.1.9-beta.1 → 2.1.9-beta.2

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 (84) hide show
  1. package/dist/assets/{AgentAvatar-CJQwq8UM.js → AgentAvatar-qLxaEaDh.js} +1 -1
  2. package/dist/assets/{AssistantView-j9aI8OWI.js → AssistantView-CeP8V0X-.js} +3 -3
  3. package/dist/assets/{DiagramView-EsIuVPrU.js → DiagramView-DRCsjVx9.js} +1 -1
  4. package/dist/assets/{FadeInOnReveal-BNVExwoL.js → FadeInOnReveal-CX8Bkq-l.js} +1 -1
  5. package/dist/assets/{Icon-B4xKSuz3.js → Icon-BCFeHDWx.js} +1 -1
  6. package/dist/assets/{ImageLoadingPlaceholder-xB8WeKks.js → ImageLoadingPlaceholder-DEpMJXzV.js} +1 -1
  7. package/dist/assets/{LoadingImage-CoT3GWhg.js → LoadingImage-BAT9D9wN.js} +1 -1
  8. package/dist/assets/{MarkdownRenderer-TmfHeWHu.js → MarkdownRenderer-BvKaN2KX.js} +2 -2
  9. package/dist/assets/{MarkdownRendererImpl-vkv1QLTd.js → MarkdownRendererImpl-D6iUJhtT.js} +1 -1
  10. package/dist/assets/{MarkstreamRendererImpl-BbnksqWU.js → MarkstreamRendererImpl-B14yVm7-.js} +1 -1
  11. package/dist/assets/{MobileDetailNavigation-CtGncmBY.js → MobileDetailNavigation-e4vO0lXT.js} +1 -1
  12. package/dist/assets/{MobileShareBridge-pYQFFYmm.js → MobileShareBridge-BnA02Mps.js} +2 -2
  13. package/dist/assets/{MobileTabPageHeader-D7NAfatx.js → MobileTabPageHeader-nApqJ-1X.js} +1 -1
  14. package/dist/assets/{MultiRunWindow-gZk-f5lA.js → MultiRunWindow-C7Vgvpoz.js} +1 -1
  15. package/dist/assets/{OnboardingScreen-BiLurnX5.js → OnboardingScreen-CqcZEptL.js} +1 -1
  16. package/dist/assets/{OverlayScrollbar-DIsrS93m.js → OverlayScrollbar-BY5HaNrb.js} +1 -1
  17. package/dist/assets/{SettingsView-D7Ykm-CM.js → SettingsView-Be7_mr8t.js} +1 -1
  18. package/dist/assets/{SettingsWindow-CyPZw4xx.js → SettingsWindow-ZnWK6Itb.js} +1 -1
  19. package/dist/assets/{TerminalView-D-X0mGO4.js → TerminalView-BluEtXH8.js} +1 -1
  20. package/dist/assets/{ToolOutputDialog-C4vQBg3z.js → ToolOutputDialog-6gouT_GS.js} +1 -1
  21. package/dist/assets/{appThemeRegistry-DUH4Fprj.js → appThemeRegistry-D59Upe3t.js} +1 -1
  22. package/dist/assets/{assistant-attachment-cache-Bzewqov4.js → assistant-attachment-cache-B2UAUHUZ.js} +1 -1
  23. package/dist/assets/{button-BupmKVUs.js → button-CWSs9Baz.js} +1 -1
  24. package/dist/assets/{collapsible-BAPWS6G-.js → collapsible-ngtoKADo.js} +1 -1
  25. package/dist/assets/{desktopHosts-BZ7iYE-l.js → desktopHosts-C0e7Nes2.js} +1 -1
  26. package/dist/assets/{desktopRelayRestore-S9wEiY2U.js → desktopRelayRestore-DckkHKsi.js} +1 -1
  27. package/dist/assets/{diagram-0a7vH45N.js → diagram-DmlTCkmV.js} +1 -1
  28. package/dist/assets/{dialog-BYLD4Cm3.js → dialog-BMa16qrs.js} +1 -1
  29. package/dist/assets/{dropdown-menu.styles-HOWSubFF.js → dropdown-menu.styles-BNwZmBRp.js} +1 -1
  30. package/dist/assets/{fileMentionTouchSelection-BcqQPEDT.js → fileMentionTouchSelection-DbICTM0g.js} +1 -1
  31. package/dist/assets/{fileQueries-DZR-mK8h.js → fileQueries-DVpZC5ha.js} +1 -1
  32. package/dist/assets/{gitApi-BtJfaFQy.js → gitApi-Bq2BWLAz.js} +1 -1
  33. package/dist/assets/{image-loading-CsxDGgek.js → image-loading-Bj11k4gM.js} +1 -1
  34. package/dist/assets/{input-DgrLdIys.js → input-CALwaZEB.js} +1 -1
  35. package/dist/assets/{insertionBoundaries-z2K9a6oY.js → insertionBoundaries-n7dVxiuI.js} +1 -1
  36. package/dist/assets/{main-DAHeBbJJ.js → main-BlZ-gMwg.js} +2 -2
  37. package/dist/assets/{main-BDCqUxWf.js → main-DRGmBqpD.js} +4 -4
  38. package/dist/assets/{markdownHeightCache-Dyctmwqv.js → markdownHeightCache-DXM_5jTe.js} +1 -1
  39. package/dist/assets/{mcpQueries-BSwb38Pz.js → mcpQueries-BxICKLst.js} +1 -1
  40. package/dist/assets/miniChat-PxCQIMUm.js +2 -0
  41. package/dist/assets/mobile-Bs5d4s3_.js +2 -0
  42. package/dist/assets/{multirun-DldZm-Aq.js → multirun-BxUSBUb_.js} +1 -1
  43. package/dist/assets/{persistence-B4Ni3Gmv.js → persistence-BKszKaoQ.js} +1 -1
  44. package/dist/assets/{platform-BQPsr8Zl.js → platform-CgwxwfA4.js} +1 -1
  45. package/dist/assets/{projectMeta-zESSNFVw.js → projectMeta-dZJ-hOil.js} +1 -1
  46. package/dist/assets/{relay-image-stream-qI2NTXbG.js → relay-image-stream-SV0lH6aG.js} +1 -1
  47. package/dist/assets/{renderElectronMiniChatApp-t1IsnPfc.js → renderElectronMiniChatApp-CGWfxiDc.js} +2 -2
  48. package/dist/assets/{renderMobileApp-BrC28EkU.js → renderMobileApp-DJmWaXgS.js} +4 -4
  49. package/dist/assets/runtime-auth-BpCQ-dPr.js +1 -0
  50. package/dist/assets/{runtime-fetch-QCWYlAx0.js → runtime-fetch-WgH0pROs.js} +1 -1
  51. package/dist/assets/{runtime-switch-3ad3yzM7.js → runtime-switch-CMiMO5Yj.js} +1 -1
  52. package/dist/assets/{runtimeConfig-5NAbSrPI.js → runtimeConfig-B-2tboUz.js} +1 -1
  53. package/dist/assets/{runtimeEndpointReset-CxreCHBU.js → runtimeEndpointReset-BbJRibgL.js} +2 -2
  54. package/dist/assets/{scheduledTaskNavigation-C1PrFEhV.js → scheduledTaskNavigation-DQcLqQ52.js} +1 -1
  55. package/dist/assets/{sessionChangeSummary-CUMpXSiU.js → sessionChangeSummary-DTeJLaNT.js} +1 -1
  56. package/dist/assets/{sessionLookup-DD8YnthC.js → sessionLookup-_U9nCuBN.js} +1 -1
  57. package/dist/assets/{sortable-tabs-strip-DogWaIrG.js → sortable-tabs-strip-CscHgCaq.js} +1 -1
  58. package/dist/assets/{speechSettingsQueries-PsDvs5QG.js → speechSettingsQueries-CdlOc_sI.js} +2 -2
  59. package/dist/assets/{terminalApi-kRMttlcP.js → terminalApi-rxsMWL0o.js} +1 -1
  60. package/dist/assets/{textarea-Boj9axpc.js → textarea-ClV5sMS-.js} +1 -1
  61. package/dist/assets/{tooltip-Dbgnq-Mh.js → tooltip-CV6dvLBp.js} +1 -1
  62. package/dist/assets/{url-Bd61gNgl.js → url-nBOUbtV_.js} +1 -1
  63. package/dist/assets/{useAppFontEffects-Ba6H7bLU.js → useAppFontEffects-YhyFj8z3.js} +5 -5
  64. package/dist/assets/{useAssistantUIStore-Dlvb7P0q.js → useAssistantUIStore-OyPm_4M_.js} +1 -1
  65. package/dist/assets/{useDesktopWindowControlsLayout-CbeUwtDM.js → useDesktopWindowControlsLayout-jdIXqoD8.js} +1 -1
  66. package/dist/assets/{useEffectiveDirectory-wtPL_zdo.js → useEffectiveDirectory-COgvBW0Q.js} +1 -1
  67. package/dist/assets/{useFontPreferences-lAw0Cbza.js → useFontPreferences-DqEIKMEW.js} +1 -1
  68. package/dist/assets/{useMobileNavigationStore-DXpdkzw_.js → useMobileNavigationStore-CuOiHjP1.js} +11 -11
  69. package/dist/assets/{useUIStore-CDMI_Yzu.js → useUIStore-CEqU9Ujv.js} +1 -1
  70. package/dist/assets/{useWorkerHighlightedLines-BXDSKlPX.js → useWorkerHighlightedLines-DGH-O6ZJ.js} +1 -1
  71. package/dist/index.html +11 -11
  72. package/dist/mini-chat.html +11 -11
  73. package/dist/mobile.html +11 -11
  74. package/package.json +1 -1
  75. package/server/lib/git/DOCUMENTATION.md +1 -1
  76. package/server/lib/git/branches.test.js +39 -0
  77. package/server/lib/git/service.js +3 -43
  78. package/server/lib/relay/DOCUMENTATION.md +20 -0
  79. package/server/lib/relay/relay-server.e2e.test.ts +35 -0
  80. package/server/lib/relay/tunnel-host.js +14 -4
  81. package/server/lib/relay/tunnel-host.test.js +37 -1
  82. package/dist/assets/miniChat-DEIx3C4R.js +0 -2
  83. package/dist/assets/mobile-DmNNI21w.js +0 -2
  84. package/dist/assets/runtime-auth-C8w0nlKy.js +0 -1
@@ -75,6 +75,26 @@ See also `packages/web/server/lib/opencode/DOCUMENTATION.md` (“Catalog / OpenC
75
75
  4. **Handshake.** Over that connection pair, client and host run the E2EE handshake and derive a shared encrypted channel the relay cannot read.
76
76
  5. **Traffic.** All normal app traffic is multiplexed and encrypted through that channel. On the host, decrypted requests are dispatched to the local server over loopback; responses stream back encrypted. Reconnects re-establish a fresh channel and the app's existing retry machinery recovers.
77
77
 
78
+ ## Negotiated JSON response compression
79
+
80
+ Each HTTP request may advertise `acceptEncoding: 'gzip'` in its tunnel JSON head
81
+ when the client supports `DecompressionStream`. The Host may then set
82
+ `encoding: 'gzip'` on the response head and stream gzip bytes as ordinary HttpBody
83
+ frames **before encryption**. The client decompresses before exposing its Fetch
84
+ Response; HTTP headers describe the decoded body, with no compressed content-length
85
+ or content-encoding leaked to callers. Wire framing, batching and crypto counters
86
+ are unchanged. Old Hosts ignore the opt-in; old clients (including native Android
87
+ notifications) omit it and receive uncompressed bodies.
88
+
89
+ Only application/json and application/*+json bodies qualify. Known decoded bodies
90
+ under 1 KiB, HEAD/no-body responses, SSE and binary assets are not compressed.
91
+ Unknown-length JSON is streamed rather than buffered in full; loopback fetch's
92
+ automatic decompression is accounted for before checking length. Cancellation and
93
+ errors propagate through the stream pipeline. Host tests cover negotiation and
94
+ legacy/SSE/binary exclusions; client tests cover malformed gzip and cancellation;
95
+ the authenticated compiled-Relay integration test checks decoded snapshot fidelity
96
+ and encrypted wire-byte reduction on 4,000 session summaries.
97
+
78
98
  ## Candidate refresh (staying off the relay when direct works)
79
99
 
80
100
  Pairing-payload transport candidates are a snapshot: when DHCP hands the host
@@ -36,6 +36,9 @@ import { requestSpeechSession } from '../../../../ui/src/lib/voice/direct-sessio
36
36
 
37
37
  const timeoutMs = 10_000;
38
38
  const previewPng = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aD1sAAAAASUVORK5CYII=', 'base64');
39
+ const initializationSnapshot = { sessions: Array.from({ length: 4000 }, (_, id) => ({
40
+ id: `session-${id}`, title: `Session ${id}`, directory: '/repo/project', time: { created: 1000, updated: 2000 },
41
+ })) };
39
42
  const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
40
43
 
41
44
  const eventually = async (predicate: () => boolean | Promise<boolean>, message: string, timeout = timeoutMs) => {
@@ -215,6 +218,10 @@ const startOrigin = async () => {
215
218
  });
216
219
  return;
217
220
  }
221
+ if (pathname === '/api/e2e/initialization' && req.method === 'GET') {
222
+ await uiAuth.requireAuth(req, res, () => res.json(initializationSnapshot));
223
+ return;
224
+ }
218
225
  if (pathname === '/api/agent' && req.method === 'GET') {
219
226
  await uiAuth.requireAuth(req, res, () => {
220
227
  const directory = new URL(req.url ?? '/', 'http://origin').searchParams.get('location[directory]');
@@ -401,10 +408,32 @@ describe('private relay compiled-process boundary', () => {
401
408
  origin = await startOrigin();
402
409
  const identity = await buildIdentity();
403
410
  host = startRelayHost({ relayUrl: relay.url, identity, getLocalPort: () => origin.port, onStatus: () => {}, logger: { warn: () => {}, info: () => {} } });
411
+ let receivedBytes = 0;
404
412
  client = createRelayTunnelClient({
405
413
  relayUrl: relay.url, serverId: identity.serverId, hostEncPubJwk: identity.hostEncPubJwk,
406
414
  helloRetryMs: 50, helloTimeoutMs: 2_000, pingIntervalMs: 500, pingTimeoutMs: 250,
407
415
  reconnectBaseDelayMs: 50, reconnectMaxDelayMs: 250, batchWindowMs: 5,
416
+ createWireSocket: (url) => {
417
+ const socket = new globalThis.WebSocket(url);
418
+ socket.binaryType = 'arraybuffer';
419
+ const wire = {
420
+ get readyState() { return socket.readyState; },
421
+ send: (data: string | ArrayBuffer | Uint8Array) => socket.send(data as string | ArrayBuffer),
422
+ close: (code?: number, reason?: string) => socket.close(code, reason),
423
+ onopen: null as (() => void) | null,
424
+ onmessage: null as ((event: { data: unknown }) => void) | null,
425
+ onclose: null as ((event: { code: number; reason: string }) => void) | null,
426
+ onerror: null as (() => void) | null,
427
+ };
428
+ socket.onopen = () => wire.onopen?.();
429
+ socket.onmessage = (event) => {
430
+ receivedBytes += typeof event.data === 'string' ? Buffer.byteLength(event.data) : event.data.byteLength;
431
+ wire.onmessage?.({ data: event.data });
432
+ };
433
+ socket.onclose = (event) => wire.onclose?.({ code: event.code, reason: event.reason });
434
+ socket.onerror = () => wire.onerror?.();
435
+ return wire;
436
+ },
408
437
  });
409
438
 
410
439
  await eventually(() => host!.getStatus().state === 'connected' && client!.getStatus().state === 'connected', 'host and TypeScript client did not connect');
@@ -415,6 +444,12 @@ describe('private relay compiled-process boundary', () => {
415
444
  expect(httpResponse.status).toBe(200);
416
445
  expect(await httpResponse.json()).toEqual({ body: 'stream-body', hasRelayConnection: true });
417
446
 
447
+ const beforeSnapshot = receivedBytes;
448
+ const compressed = await client.fetch('/api/e2e/initialization', { headers: { authorization: 'Bearer client-token' } });
449
+ expect(compressed.status).toBe(200);
450
+ expect(await compressed.json()).toEqual(initializationSnapshot);
451
+ expect(receivedBytes - beforeSnapshot).toBeLessThan(Buffer.byteLength(JSON.stringify(initializationSnapshot)) / 4);
452
+
418
453
  const sseResponse = await client.fetch('/api/e2e/sse', { headers: { authorization: 'Bearer client-token' } });
419
454
  const reader = sseResponse.body!.getReader();
420
455
  const chunks: Uint8Array[] = [];
@@ -258,11 +258,21 @@ export const createTunnelHost = ({
258
258
  if (STRIPPED_RESPONSE_HEADERS.has(name)) continue;
259
259
  responseHeaders[name] = value;
260
260
  }
261
- await sendJson(TunnelFrameType.HttpResponse, streamId, { status: response.status, headers: responseHeaders });
262
-
263
261
  try {
264
- if (response.body) {
265
- for await (const chunk of response.body) {
262
+ const contentType = (response.headers.get('content-type') ?? '').split(';', 1)[0].trim().toLowerCase();
263
+ const contentLength = response.headers.has('content-encoding') ? null : response.headers.get('content-length');
264
+ // Compress finite JSON responses before encryption, never SSE or binary assets.
265
+ // Old clients omit acceptEncoding and old hosts ignore it, preserving v1 framing.
266
+ const gzip = request.acceptEncoding === 'gzip' && typeof CompressionStream === 'function'
267
+ && method !== 'HEAD' && response.body !== null
268
+ && (contentType === 'application/json' || /^application\/[^/]+\+json$/.test(contentType))
269
+ && (contentLength === null || Number(contentLength) >= 1024);
270
+ const body = gzip ? response.body.pipeThrough(new CompressionStream('gzip')) : response.body;
271
+ await sendJson(TunnelFrameType.HttpResponse, streamId, {
272
+ status: response.status, headers: responseHeaders, ...(gzip ? { encoding: 'gzip' } : {}),
273
+ });
274
+ if (body) {
275
+ for await (const chunk of body) {
266
276
  if (closed || stream.abort.signal.aborted) return;
267
277
  const bytes = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
268
278
  for (const piece of chunkPayload(bytes, MAX_TUNNEL_PAYLOAD_BYTES)) {
@@ -7,7 +7,7 @@
7
7
  // corrupted payload. This test must stay red until send serialization is fixed.
8
8
  // Production send path is intentionally not changed here.
9
9
 
10
- import { describe, expect, it } from 'bun:test';
10
+ import { describe, expect, it, vi } from 'vitest';
11
11
 
12
12
  import {
13
13
  MAX_TUNNEL_PAYLOAD_BYTES,
@@ -68,6 +68,42 @@ const waitFor = async (predicate, { timeoutMs = 2000, intervalMs = 5 } = {}) =>
68
68
  throw new Error('waitFor timed out');
69
69
  };
70
70
 
71
+ describe('negotiated JSON response compression', () => {
72
+ it.each([
73
+ { acceptEncoding: 'gzip', contentType: 'application/json', compressed: true },
74
+ { acceptEncoding: 'gzip', contentType: 'application/problem+json', compressed: true },
75
+ { acceptEncoding: undefined, contentType: 'application/json', compressed: false },
76
+ { acceptEncoding: 'gzip', contentType: 'text/event-stream', compressed: false },
77
+ { acceptEncoding: 'gzip', contentType: 'image/png', compressed: false },
78
+ { acceptEncoding: 'gzip', contentType: 'application/json', small: true, compressed: false },
79
+ ])('preserves body and legacy/SSE behavior for $contentType / $acceptEncoding / small=$small', async ({ acceptEncoding, contentType, small, compressed }) => {
80
+ const text = JSON.stringify({ rows: Array.from({ length: small ? 1 : 4000 }, (_, id) => ({ id, title: 'Session summary', directory: '/repo/project' })) });
81
+ const raw = textEncoder.encode(text);
82
+ const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response(raw, {
83
+ headers: { 'content-type': contentType, 'content-length': String(raw.byteLength) },
84
+ }));
85
+ const frames = [];
86
+ const host = createTunnelHost({ connectionId: 'compression-test', getLocalPort: () => 9,
87
+ sendFrame: (frame) => { frames.push(decodeTunnelFrame(frame)); }, getBufferedAmount: () => 0 });
88
+ try {
89
+ await host.handleFrame(encodeTunnelFrame(TunnelFrameType.HttpRequest, 1, encodeJsonPayload({
90
+ method: 'GET', path: '/api/test', query: '', headers: {}, ...(acceptEncoding ? { acceptEncoding } : {}),
91
+ })));
92
+ await waitFor(() => frames.some((frame) => frame.frameType === TunnelFrameType.StreamEnd));
93
+ const head = JSON.parse(textDecoder.decode(frames.find((frame) => frame.frameType === TunnelFrameType.HttpResponse).payload));
94
+ expect(head.encoding).toBe(compressed ? 'gzip' : undefined);
95
+ expect(head.headers['content-length']).toBeUndefined();
96
+ const body = new Blob(frames.filter((frame) => frame.frameType === TunnelFrameType.HttpBody).map((frame) => frame.payload));
97
+ if (compressed) {
98
+ expect(body.size).toBeLessThan(raw.byteLength / 4);
99
+ expect(await new Response(body.stream().pipeThrough(new DecompressionStream('gzip'))).text()).toBe(text);
100
+ } else {
101
+ expect(await body.text()).toBe(text);
102
+ }
103
+ } finally { host.close(); fetchMock.mockRestore(); }
104
+ });
105
+ });
106
+
71
107
  describe('isTunnelWsPathAllowed', () => {
72
108
  it('allows exact terminal/dictation/event sockets and preview proxy prefix', () => {
73
109
  expect(isTunnelWsPathAllowed('/api/terminal/ws')).toBe(true);
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/renderElectronMiniChatApp-t1IsnPfc.js","assets/rolldown-runtime-hePW80VL.js","assets/persistence-B4Ni3Gmv.js","assets/runtime-auth-C8w0nlKy.js","assets/runtime-switch-3ad3yzM7.js","assets/runtime-fetch-QCWYlAx0.js","assets/vendor-zustand-o69pgTEK.js","assets/vendor-base-ui-CdzJ6My_.js","assets/useUIStore-CDMI_Yzu.js","assets/vendor-react-BP2cRVqX.js","assets/vendor-pathe-vBmvQE8f.js","assets/vendor-tanstack-query-core-BWz0ose6.js","assets/platform-BQPsr8Zl.js","assets/vendor-opencode-client-MF2GBrFx.js","assets/vendor-aparajita-capacitor-secure-storage-xol_6BsB.js","assets/vendor-reactuses-core-BpfIZ1tg.js","assets/vendor-lodash-es-DfLbG5Af.js","assets/vendor-js-cookie-hSOiFTtX.js","assets/button-BupmKVUs.js","assets/store-CG7Ytsg9.js","assets/vendor-class-variance-authority-BLUaYARZ.js","assets/vendor-tailwind-merge-BicNWLTg.js","assets/useMobileNavigationStore-DXpdkzw_.js","assets/vendor-tanstack-react-query-CdqCAt40.js","assets/vendor-sonner-ZS8XIOVl.js","assets/useAssistantUIStore-Dlvb7P0q.js","assets/vendor-zod-Dzk5kdUU.js","assets/vendor-fuse.js-DB5wDJbI.js","assets/Icon-B4xKSuz3.js","assets/useAppFontEffects-Ba6H7bLU.js","assets/desktopHosts-BZ7iYE-l.js","assets/desktopRelayRestore-S9wEiY2U.js","assets/vendor-pierre-diffs-DPBtNDJ5.js","assets/vendor-hast-util-to-html-Bw_SgZ1t.js","assets/vendor-character-entities-legacy-Wut6vMuj.js","assets/vendor-character-entities-html4-DlN_yAFd.js","assets/vendor-ccount-CyGsA0u7.js","assets/vendor-comma-separated-tokens-B9ouxNNS.js","assets/vendor-oniguruma-to-es-CrHzjjSU.js","assets/vendor-oniguruma-parser-D2DIvhSP.js","assets/vendor-diff-Dq7CZNim.js","assets/vendor-lru_map-BMOrLc9L.js","assets/rasterizePng-CpK-xCkB.js","assets/dualLimitLru-D8Sphgua.js","assets/AgentAvatar-CJQwq8UM.js","assets/vendor-dicebear-core-CV95S5Pg.js","assets/vendor-dicebear-styles-7lEG-JsF.js","assets/useThemeSystem-8jhE4Zyk.js","assets/dialog-BYLD4Cm3.js","assets/gitApi-BtJfaFQy.js","assets/vendor-simplewebauthn-browser-Dwhcdg_5.js","assets/projectMeta-zESSNFVw.js","assets/input-DgrLdIys.js","assets/tooltip-Dbgnq-Mh.js","assets/OverlayScrollbar-DIsrS93m.js","assets/textarea-Boj9axpc.js","assets/vendor-framer-motion-D-oiwsxL.js","assets/vendor-dnd-kit-core-5pNnzVdw.js","assets/vendor-dnd-kit-accessibility-COSwgjFs.js","assets/vendor-dnd-kit-sortable-Dm50I0m7.js","assets/speechSettingsQueries-PsDvs5QG.js","assets/dropdown-menu.styles-HOWSubFF.js","assets/image-loading-CsxDGgek.js","assets/fileQueries-DZR-mK8h.js","assets/useRuntimeAPIs-Cx8S1HLz.js","assets/relay-image-stream-qI2NTXbG.js","assets/image-loading-CObM4tcX.css","assets/sessionChangeSummary-CUMpXSiU.js","assets/LoadingImage-CoT3GWhg.js","assets/ImageLoadingPlaceholder-xB8WeKks.js","assets/sessionChangeSummary-vC84qM3v.css","assets/insertionBoundaries-z2K9a6oY.js","assets/fileMentionTouchSelection-BcqQPEDT.js","assets/appThemeRegistry-DUH4Fprj.js","assets/MarkdownRenderer-TmfHeWHu.js","assets/markdownHeightCache-Dyctmwqv.js","assets/url-Bd61gNgl.js","assets/markdown-worker-DFNZ3KJ_.js","assets/useEffectiveDirectory-wtPL_zdo.js","assets/FadeInOnReveal-BNVExwoL.js","assets/markdownTheme-CV7_0QAL.js","assets/useWorkerHighlightedLines-BXDSKlPX.js","assets/vendor-tanstack-react-virtual-B_EO--9t.js","assets/vendor-cmdk-RDxC-9Iz.js","assets/vendor-aria-hidden-BbL3cEyI.js","assets/sortable-tabs-strip-DogWaIrG.js","assets/vendor-motion-88WXBOBf.js","assets/vendor-legendapp-list-CNxU_ALy.js","assets/useFontPreferences-lAw0Cbza.js","assets/terminalApi-kRMttlcP.js","assets/useDesktopWindowControlsLayout-CbeUwtDM.js","assets/src-CdGit3gf.css"])))=>i.map(i=>d[i]);
2
- import{t as e}from"./runtimeConfig-5NAbSrPI.js";import{o as t}from"./vendor-aparajita-capacitor-secure-storage-xol_6BsB.js";/* empty css */window.__OPENCHAMBER_RUNTIME_APIS__=e(),t(async()=>{let{renderElectronMiniChatApp:e}=await import(`./renderElectronMiniChatApp-t1IsnPfc.js`);return{renderElectronMiniChatApp:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91])).then(({renderElectronMiniChatApp:t})=>{t(window.__OPENCHAMBER_RUNTIME_APIS__??e())});
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/renderMobileApp-BrC28EkU.js","assets/rolldown-runtime-hePW80VL.js","assets/runtime-auth-C8w0nlKy.js","assets/runtime-switch-3ad3yzM7.js","assets/runtime-fetch-QCWYlAx0.js","assets/persistence-B4Ni3Gmv.js","assets/vendor-zustand-o69pgTEK.js","assets/vendor-base-ui-CdzJ6My_.js","assets/useUIStore-CDMI_Yzu.js","assets/vendor-react-BP2cRVqX.js","assets/vendor-pathe-vBmvQE8f.js","assets/vendor-tanstack-query-core-BWz0ose6.js","assets/platform-BQPsr8Zl.js","assets/vendor-opencode-client-MF2GBrFx.js","assets/vendor-aparajita-capacitor-secure-storage-xol_6BsB.js","assets/capgoAdapter-KNLHDj7G.js","assets/types-BuiqMmh_.js","assets/vendor-pierre-diffs-DPBtNDJ5.js","assets/vendor-hast-util-to-html-Bw_SgZ1t.js","assets/vendor-character-entities-legacy-Wut6vMuj.js","assets/vendor-character-entities-html4-DlN_yAFd.js","assets/vendor-ccount-CyGsA0u7.js","assets/vendor-comma-separated-tokens-B9ouxNNS.js","assets/vendor-oniguruma-to-es-CrHzjjSU.js","assets/vendor-oniguruma-parser-D2DIvhSP.js","assets/vendor-diff-Dq7CZNim.js","assets/vendor-lru_map-BMOrLc9L.js","assets/vendor-sonner-ZS8XIOVl.js","assets/vendor-reactuses-core-BpfIZ1tg.js","assets/vendor-lodash-es-DfLbG5Af.js","assets/vendor-js-cookie-hSOiFTtX.js","assets/button-BupmKVUs.js","assets/store-CG7Ytsg9.js","assets/vendor-class-variance-authority-BLUaYARZ.js","assets/vendor-tailwind-merge-BicNWLTg.js","assets/MobileShareBridge-pYQFFYmm.js","assets/MobileDetailNavigation-CtGncmBY.js","assets/vendor-tanstack-react-query-CdqCAt40.js","assets/useMobileNavigationStore-DXpdkzw_.js","assets/useAssistantUIStore-Dlvb7P0q.js","assets/vendor-zod-Dzk5kdUU.js","assets/vendor-fuse.js-DB5wDJbI.js","assets/Icon-B4xKSuz3.js","assets/rasterizePng-CpK-xCkB.js","assets/AgentAvatar-CJQwq8UM.js","assets/vendor-dicebear-core-CV95S5Pg.js","assets/vendor-dicebear-styles-7lEG-JsF.js","assets/dualLimitLru-D8Sphgua.js","assets/useThemeSystem-8jhE4Zyk.js","assets/dialog-BYLD4Cm3.js","assets/gitApi-BtJfaFQy.js","assets/useAppFontEffects-Ba6H7bLU.js","assets/desktopHosts-BZ7iYE-l.js","assets/desktopRelayRestore-S9wEiY2U.js","assets/vendor-simplewebauthn-browser-Dwhcdg_5.js","assets/projectMeta-zESSNFVw.js","assets/input-DgrLdIys.js","assets/tooltip-Dbgnq-Mh.js","assets/OverlayScrollbar-DIsrS93m.js","assets/textarea-Boj9axpc.js","assets/vendor-framer-motion-D-oiwsxL.js","assets/vendor-dnd-kit-core-5pNnzVdw.js","assets/vendor-dnd-kit-accessibility-COSwgjFs.js","assets/vendor-dnd-kit-sortable-Dm50I0m7.js","assets/speechSettingsQueries-PsDvs5QG.js","assets/dropdown-menu.styles-HOWSubFF.js","assets/image-loading-CsxDGgek.js","assets/fileQueries-DZR-mK8h.js","assets/useRuntimeAPIs-Cx8S1HLz.js","assets/relay-image-stream-qI2NTXbG.js","assets/image-loading-CObM4tcX.css","assets/sessionChangeSummary-CUMpXSiU.js","assets/LoadingImage-CoT3GWhg.js","assets/ImageLoadingPlaceholder-xB8WeKks.js","assets/sessionChangeSummary-vC84qM3v.css","assets/insertionBoundaries-z2K9a6oY.js","assets/fileMentionTouchSelection-BcqQPEDT.js","assets/appThemeRegistry-DUH4Fprj.js","assets/MarkdownRenderer-TmfHeWHu.js","assets/markdownHeightCache-Dyctmwqv.js","assets/url-Bd61gNgl.js","assets/markdown-worker-DFNZ3KJ_.js","assets/useEffectiveDirectory-wtPL_zdo.js","assets/FadeInOnReveal-BNVExwoL.js","assets/markdownTheme-CV7_0QAL.js","assets/useWorkerHighlightedLines-BXDSKlPX.js","assets/vendor-tanstack-react-virtual-B_EO--9t.js","assets/vendor-cmdk-RDxC-9Iz.js","assets/vendor-aria-hidden-BbL3cEyI.js","assets/sortable-tabs-strip-DogWaIrG.js","assets/vendor-motion-88WXBOBf.js","assets/vendor-legendapp-list-CNxU_ALy.js","assets/useFontPreferences-lAw0Cbza.js","assets/terminalApi-kRMttlcP.js","assets/MobileTabPageHeader-D7NAfatx.js","assets/vendor-codemirror-autocomplete-7c2L_4dM.js","assets/vendor-codemirror-lang-angular-DXOgWEVj.js","assets/vendor-codemirror-lang-json-mLulNbwB.js","assets/vendor-codemirror-lang-markdown-CV1IO6Qs.js","assets/vendor-codemirror-lang-python-YM2WVLHF.js","assets/vendor-codemirror-legacy-modes-DwltVFbT.js","assets/mcpQueries-BSwb38Pz.js","assets/collapsible-BAPWS6G-.js","assets/vendor-codemirror-commands-B8KrBQ9B.js","assets/vendor-codemirror-search-ZqtrPLjU.js","assets/vendor-replit-codemirror-vim-DDj0dSVY.js","assets/vendor-codemirror-language-data-Ctd4WxgW.js","assets/projectActions-CWvNGKfA.js","assets/runtimeEndpointReset-CxreCHBU.js","assets/scheduledTaskNavigation-C1PrFEhV.js","assets/sessionLookup-DD8YnthC.js","assets/vendor-cron-parser-BmO80h0C.js","assets/runtimeEndpointReset-ByXtaeWD.css","assets/SettingsView-D7Ykm-CM.js","assets/vendor-yaml-C9KlJAlj.js","assets/vendor-qrcode-D7jBCyl-.js","assets/vendor-dijkstrajs-BAzPDGZM.js","assets/AssistantView-j9aI8OWI.js","assets/assistant-attachment-cache-Bzewqov4.js","assets/src-CdGit3gf.css"])))=>i.map(i=>d[i]);
2
- import{t as e}from"./runtimeConfig-5NAbSrPI.js";import{o as t}from"./vendor-aparajita-capacitor-secure-storage-xol_6BsB.js";/* empty css */window.__OPENCHAMBER_RUNTIME_APIS__=e(),t(async()=>{let{renderMobileApp:e}=await import(`./renderMobileApp-BrC28EkU.js`);return{renderMobileApp:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119])).then(({renderMobileApp:t})=>{t(window.__OPENCHAMBER_RUNTIME_APIS__??e())});
@@ -1 +0,0 @@
1
- import{n as e}from"./rolldown-runtime-hePW80VL.js";var t=`openchamber-relay-v1`,n=65526,r={HttpRequest:1,HttpBody:2,HttpResponse:3,StreamEnd:4,StreamAbort:5,WsOpen:6,WsOpened:7,WsText:8,WsBinary:9,WsClose:10,Ping:11,Pong:12},i=new Set(Object.values(r)),a=e=>i.has(e),o={ControlReplaced:4001,DuplicateClient:4002,StuckControlReset:4003,HostUnavailable:4008,AuthFailed:4010,LimitExceeded:4029,HostWentAway:1012,RekeyMismatch:1008,ChannelFailure:1011},s=globalThis.crypto.subtle,c={name:`ECDH`,namedCurve:`P-256`},l=16,u=32,d=16,f=4,p=8,m=class extends Error{constructor(e){super(e),this.name=`RelayCryptoError`}},h=()=>s.generateKey(c,!0,[`deriveBits`]),g=async e=>{let t=await s.exportKey(`jwk`,e);return{kty:t.kty,crv:t.crv,x:t.x,y:t.y}},_=async e=>{if(e.kty!==`EC`||e.crv!==`P-256`||typeof e.x!=`string`||typeof e.y!=`string`)throw new m(`invalid ECDH public key JWK`);try{return await s.importKey(`jwk`,{kty:e.kty,crv:e.crv,x:e.x,y:e.y,ext:!0},c,!0,[])}catch{throw new m(`invalid ECDH public key JWK`)}},v=()=>{let e=new Uint8Array(l);return globalThis.crypto.getRandomValues(e),e},y=async(e,n,r)=>{if(r.length!==l)throw new m(`invalid handshake nonce length`);let i=await s.deriveBits({name:`ECDH`,public:n},e,256),a=await s.importKey(`raw`,i,`HKDF`,!1,[`deriveBits`]),o=new Uint8Array(await s.deriveBits({name:`HKDF`,hash:`SHA-256`,salt:r,info:new TextEncoder().encode(t)},a,512)),c=(e,t)=>s.importKey(`raw`,e,{name:`AES-GCM`},!1,t);return{clientToHost:await c(o.slice(0,u),[`encrypt`,`decrypt`]),hostToClient:await c(o.slice(u),[`encrypt`,`decrypt`])}},b=(e,t,n)=>{for(let r=7;r>=0;--r)e[t+r]=Number(n&255n),n>>=8n},x=(e,t)=>{let n=0n;for(let r=0;r<p;r+=1)n=n<<8n|BigInt(e[t+r]);return n},S=e=>{let t=new Uint8Array(f);globalThis.crypto.getRandomValues(t);let n=0n;return{async encrypt(r){if(r.length>65536)throw new m(`plaintext frame exceeds maximum size`);n+=1n;let i=new Uint8Array(12);i.set(t,0),b(i,f,n);let a=new Uint8Array(await s.encrypt({name:`AES-GCM`,iv:i},e,r)),o=new Uint8Array(13+a.length);return o[0]=1,o.set(i,1),o.set(a,13),o}}},C=e=>{let t=0n;return{async decrypt(n){if(n.length<13+d)throw new m(`encrypted frame too short`);if(n[0]!==1)throw new m(`unsupported encrypted frame version`);let r=n.slice(1,13),i=x(r,f);if(i<=t)throw new m(`frame counter regression`);let a;try{a=await s.decrypt({name:`AES-GCM`,iv:r},e,n.slice(13))}catch{throw new m(`frame decryption failed`)}return t=i,new Uint8Array(a)}}},w=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`,ee=e=>{let t=``;for(let n=0;n<e.length;n+=3){let r=e[n],i=n+1<e.length?e[n+1]:void 0,a=n+2<e.length?e[n+2]:void 0;t+=w[r>>2],t+=w[(r&3)<<4|(i??0)>>4],i!==void 0&&(t+=w[(i&15)<<2|(a??0)>>6]),a!==void 0&&(t+=w[a&63])}return t},te=e=>{let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=`object`||!t)return null;let n=t;if(n.v!==1)return null;let r=n.batch===!0;return n.t===`ready`?{t:`ready`,v:1,batch:r}:n.t===`hello`&&typeof n.nonce==`string`&&typeof n.clientPubJwk==`object`&&n.clientPubJwk!==null?{t:`hello`,v:1,clientPubJwk:n.clientPubJwk,nonce:n.nonce,batch:r}:null},ne=e=>({type:`fail`,closeCode:o.ChannelFailure,reason:e}),re=async(e,t={})=>{let n=t.batch!==!1,r=await _(e),i=await h(),a=v(),o={t:`hello`,v:1,clientPubJwk:await g(i.publicKey),nonce:ee(a),...n?{batch:!0}:{}},s=!1;return{helloText:JSON.stringify(o),get established(){return s},async handleText(e){if(s)return te(e)?.t===`ready`?{type:`ignore`}:ne(`plaintext frame on established channel`);let t=te(e);if(t?.t!==`ready`)return{type:`ignore`};let o=await y(i.privateKey,r,a);return s=!0,{type:`established`,batch:n&&t.batch===!0,channel:{encryptor:S(o.clientToHost),decryptor:C(o.hostToClient)}}}}},T=4294967295,E=class extends Error{constructor(e){super(e),this.name=`TunnelCodecError`}},D=(e,t,n,r=!1)=>{if(!Number.isInteger(t)||t<0||t>T)throw new E(`invalid stream id`);if(n.length>65526)throw new E(`tunnel payload exceeds maximum size`);let i=new Uint8Array(5+n.length);return i[0]=r?e|128:e,i[1]=t>>>24&255,i[2]=t>>>16&255,i[3]=t>>>8&255,i[4]=t&255,i.set(n,5),i},ie=e=>{if(e.length<5)throw new E(`tunnel frame too short`);let t=e[0],n=!!(t&128),r=t&-129;if(!a(r))throw new E(`unknown tunnel frame type ${r}`);return{frameType:r,streamId:(e[1]<<24|e[2]<<16|e[3]<<8|e[4])>>>0,payload:e.slice(5),hasMoreFragments:n}},O=new TextEncoder,k=new TextDecoder,A=e=>O.encode(JSON.stringify(e)),j=(e,t)=>{let n;try{n=JSON.parse(k.decode(e))}catch{throw new E(`malformed JSON tunnel payload`)}if(!t(n))throw new E(`unexpected JSON tunnel payload shape`);return n},M=(e,t=n)=>{if(t<=0||t>65526)throw new E(`invalid chunk size`);if(e.length===0)return[new Uint8Array];let r=[];for(let n=0;n<e.length;n+=t)r.push(e.slice(n,n+t));return r},N=(e,t,n)=>{let r=M(n);return r.map((n,i)=>D(e,t,n,i<r.length-1))},ae=(e=16777216)=>{let t=new Map;return{push(n){let r=`${n.streamId}:${n.frameType}`,i=t.get(r);if(!n.hasMoreFragments&&!i)return n.payload;let a=i?.chunks??[],o=(i?.totalBytes??0)+n.payload.length;if(o>e)throw t.delete(r),new E(`fragmented message exceeds maximum size`);if(a.push(n.payload),n.hasMoreFragments)return t.set(r,{chunks:a,totalBytes:o}),null;t.delete(r);let s=new Uint8Array(o),c=0;for(let e of a)s.set(e,c),c+=e.length;return s},dropStream(e){for(let n of t.keys())n.startsWith(`${e}:`)&&t.delete(n)}}},oe=e=>{if(e.length===0)throw new E(`cannot encode an empty frame batch`);if(e.length===1){let t=e[0],n=new Uint8Array(1+t.length);if(n[0]=0,n.set(t,1),n.length>65536)throw new E(`frame batch exceeds maximum plaintext size`);return n}let t=1;for(let n of e)t+=4+n.length;if(t>65536)throw new E(`frame batch exceeds maximum plaintext size`);let n=new Uint8Array(t);n[0]=1;let r=1;for(let t of e)n[r]=t.length>>>24&255,n[r+1]=t.length>>>16&255,n[r+2]=t.length>>>8&255,n[r+3]=t.length&255,r+=4,n.set(t,r),r+=t.length;return n},se=e=>{if(e.length<1)throw new E(`empty batch plaintext`);let t=e[0];if(t===0)return[e.slice(1)];if(t!==1)throw new E(`unknown batch container tag ${t}`);let n=[],r=1;for(;r<e.length;){if(r+4>e.length)throw new E(`truncated batch frame length`);let t=(e[r]<<24|e[r+1]<<16|e[r+2]<<8|e[r+3])>>>0;if(r+=4,r+t>e.length)throw new E(`truncated batch frame body`);n.push(e.slice(r,r+t)),r+=t}if(n.length===0)throw new E(`empty frame batch`);return n},ce=new Set([r.HttpBody,r.WsText,r.WsBinary]),le=e=>{let t=e.windowMs??150,n=e.maxBatchBytes??24576,r=e.maxBatchFrames??32,i=e.now??(()=>Date.now()),a=e.setTimer??((e,t)=>setTimeout(e,t)),o=e.clearTimer??(e=>clearTimeout(e)),s=[],c=0,l=null,u=0,d=!1,f=()=>{l!==null&&(o(l),l=null)},p=()=>{if(f(),s.length===0)return;let t=s;s=[],c=0,u=i(),e.sendBatch(oe(t))};return{enqueue:e=>{if(d)return;let o=e[0]&-129;if(!ce.has(o)){s.push(e),p();return}let f=i();if(s.length===0&&f-u>=t){s.push(e),p();return}let m=4+e.length;if(s.length>0&&1+c+m>65536&&p(),s.push(e),c+=m,c>=n||s.length>=r){p();return}l===null&&(l=a(p,t))},flush:p,dispose(){d=!0,f(),s=[],c=0}}},ue=()=>{let e=1;return{next(){if(e>T)throw new E(`stream id space exhausted`);let t=e;return e+=2,t}}},P=e=>typeof e==`object`&&!!e&&!Array.isArray(e),F=e=>P(e)&&Object.values(e).every(e=>typeof e==`string`),de=e=>P(e)&&typeof e.status==`number`&&F(e.headers),I=e=>P(e)&&typeof e.reason==`string`,fe=e=>P(e)&&typeof e.code==`number`&&typeof e.reason==`string`,pe=/^[a-z][a-z\d+.-]*:\/\//i,L=`http://tunnel.invalid`,me=e=>{try{let t=pe.test(e)?new URL(e):new URL(e,L);return`${t.pathname}${t.search}`}catch{return e}},R=e=>({async*[Symbol.asyncIterator](){yield e}}),he=e=>({async*[Symbol.asyncIterator](){let t=e.getReader();try{for(;;){let{done:e,value:n}=await t.read();if(e)return;n&&(yield n)}}finally{t.releaseLock()}}}),ge=e=>{let t=new Uint8Array(e.byteLength);return t.set(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)),t},_e=async e=>{if(e==null)return{body:null};if(e instanceof ReadableStream)return{body:he(e)};if(typeof e==`string`)return{body:R(new TextEncoder().encode(e))};if(e instanceof ArrayBuffer)return{body:R(new Uint8Array(e.slice(0)))};if(ArrayBuffer.isView(e))return{body:R(ge(e))};let t=new Response(e),n=t.headers.get(`content-type`)??void 0;return{body:R(new Uint8Array(await t.arrayBuffer())),contentType:n}},ve=async(e,t)=>{let n,r=new Headers,i=`GET`,a=null,o;e instanceof Request?(n=e.url,i=e.method,e.headers.forEach((e,t)=>r.set(t,e)),o=e.signal,a=e.body):n=e.toString(),t&&(t.method&&(i=t.method),t.headers&&new Headers(t.headers).forEach((e,t)=>r.set(t,e)),t.body!==void 0&&(a=t.body),t.signal&&(o=t.signal));let s=pe.test(n)?new URL(n):new URL(n,L),{body:c,contentType:l}=await _e(a);l&&!r.has(`content-type`)&&r.set(`content-type`,l);let u={};return r.forEach((e,t)=>{u[t]=e}),{method:i.toUpperCase(),path:s.pathname,query:s.search.startsWith(`?`)?s.search.slice(1):s.search,headers:u,body:c,signal:o}},ye=new Uint8Array,be=new TextEncoder,xe=new TextDecoder,z=e=>e instanceof Error?e:Error(String(e)),B=()=>new DOMException(`The operation was aborted.`,`AbortError`),Se=e=>{e.binaryType=`arraybuffer`;let t={get readyState(){return e.readyState},send(t){e.send(t)},close(t,n){e.close(t,n)},onopen:null,onmessage:null,onclose:null,onerror:null};return e.onopen=()=>t.onopen?.(),e.onmessage=e=>t.onmessage?.({data:e.data}),e.onclose=e=>t.onclose?.({code:e.code,reason:e.reason}),e.onerror=()=>t.onerror?.(),t},Ce=e=>{let t={get readyState(){return e.readyState},get binaryType(){return e.binaryType},set binaryType(t){t&&(e.binaryType=t)},onopen:null,onmessage:null,onerror:null,onclose:null,send(t){e.send(t)},close(t,n){e.close(t,n)}};return e.onopen=()=>t.onopen?.(),e.onmessage=e=>{let n=e.data;(typeof n==`string`||n instanceof ArrayBuffer)&&t.onmessage?.({data:n})},e.onerror=()=>t.onerror?.(),e.onclose=e=>t.onclose?.({code:e.code,reason:e.reason}),t},we=0,Te=1,Ee=2,De=3,Oe=new Set([o.AuthFailed,o.DuplicateClient,o.LimitExceeded]),ke={[o.AuthFailed]:`relay authentication failed`,[o.DuplicateClient]:`relay connection replaced by another client`,[o.LimitExceeded]:`relay connection limit reached`},Ae=()=>{let e=typeof navigator<`u`&&navigator.onLine===!1,t=typeof document<`u`&&document.visibilityState===`hidden`;return e||t},je=e=>{let t=e.helloRetryMs??1e3,n=e.helloTimeoutMs??3e4,i=e.pingIntervalMs??3e4,a=e.pingTimeoutMs??15e3,o=e.batchWindowMs??150,s=e.batch!==!1,c=e.reconnectBaseDelayMs??1e3,l=e.reconnectMaxDelayMs??3e4,u=e.hiddenOrOfflineMaxDelayMs??6e4,d=e.createWireSocket??(e=>Se(new WebSocket(e))),f=!1,p={state:`idle`},m=new Set,h=null,g=null,_=null,v=0,y=0,b=null,x=[],S=!1,C=e=>{if(p.state!==e.state||p.lastError!==e.lastError){p=e;for(let e of m)try{e(p)}catch{}}},w=e=>{let t=x;x=[];for(let n of t)n.reject(e)},ee=e=>{let t=x;x=[];for(let n of t)n.resolve(e)},te=(e,t)=>{e.dead=!0;let n=Array.from(e.streams.values());e.streams.clear();for(let e of n)try{e.fail(t)}catch{}},ne=()=>{b!==null&&(clearTimeout(b),b=null)},T=()=>{f||b===null||Ae()||(ne(),k(),P())},E=()=>{typeof document<`u`&&document.visibilityState===`visible`&&T()},O=()=>{S||typeof window>`u`||(S=!0,window.addEventListener(`online`,T),typeof document<`u`&&document.addEventListener(`visibilitychange`,E))},k=()=>{!S||typeof window>`u`||(S=!1,window.removeEventListener(`online`,T),typeof document<`u`&&document.removeEventListener(`visibilitychange`,E))},oe=()=>{if(f||b!==null)return;let e=Math.max(0,y-1),t=c*2**Math.min(e,10),n=Ae()?u:l,r=Math.min(n,t);O(),b=setTimeout(()=>{b=null,k(),P()},r)},ce=()=>{let t=new URL(e.relayUrl);return t.searchParams.set(`v`,`1`),t.searchParams.set(`role`,`client`),t.searchParams.set(`serverId`,e.serverId),e.grant&&t.searchParams.set(`grant`,e.grant),t.toString()},P=async()=>{if(f)return;ne(),v+=1;let c=v;C({state:y>0?`reconnecting`:`connecting`,lastError:p.lastError});let l;try{l=await re(e.hostEncPubJwk,{batch:s})}catch(e){if(c!==v||f)return;fe(c,z(e),!0);return}if(c!==v||f)return;let u;try{u=d(ce())}catch(e){fe(c,z(e));return}g=u;let m=!1,b=null,x=null,S=null,T=null,E=Promise.resolve(),O=null,k=null,A=!1,j=null,M=Date.now(),N=()=>{b!==null&&(clearInterval(b),b=null),x!==null&&(clearTimeout(x),x=null),S!==null&&(clearInterval(S),S=null),T!==null&&(clearTimeout(T),T=null),j!==null&&(j.dispose(),j=null)};_=N;function P(e,t=!1,n=!1){if(!(m||c!==v)){m=!0,N(),O&&(h=null,te(O,Error(`relay tunnel reset: ${e.message}`))),w(e);try{u.close()}catch{}if(g===u&&(g=null),!f){if(y+=1,n){C({state:`error`,lastError:e.message});return}C({state:t?`error`:`reconnecting`,lastError:e.message}),oe()}}}let F=()=>{try{u.send(l.helloText)}catch{}},de=(e,t)=>{k=e,A=t,b!==null&&(clearInterval(b),b=null),x!==null&&(clearTimeout(x),x=null);let n=new Map,s=ue(),c=ae(),l=Promise.resolve(),d=t=>{l=l.then(async()=>{if(p.dead)return;let n=await e.encryptor.encrypt(t);u.send(n)}).catch(()=>{})},f=t?le({windowMs:o,sendBatch:d}):null;j=f;let p={streams:n,assembler:c,nextStreamId:()=>s.next(),dead:!1,send(e){if(p.dead)return;let t=e[0]&-129;t!==r.Ping&&t!==r.Pong&&(M=Date.now()),f?f.enqueue(e):d(e)}};O=p,h=p,y=0,M=Date.now(),C({state:`connected`}),ee(p),S=setInterval(()=>{Date.now()-M<i||(p.send(D(r.Ping,0,ye)),T===null&&(T=setTimeout(()=>{T=null,P(Error(`relay keepalive timeout`))},a)))},i)},I=(e,t)=>{let n;try{n=ie(t)}catch(e){P(z(e));return}if(T!==null&&(clearTimeout(T),T=null),n.frameType===r.Ping){e.send(D(r.Pong,n.streamId,ye));return}if(n.frameType===r.Pong)return;M=Date.now();let i=n.payload;if(n.frameType===r.WsText||n.frameType===r.WsBinary){let t;try{t=e.assembler.push(n)}catch(e){P(z(e));return}if(t===null)return;i=t}else if(n.hasMoreFragments){P(Error(`unexpected fragmented tunnel frame`));return}let a=e.streams.get(n.streamId);a&&a.handleFrame(n.frameType,i)};u.onopen=()=>{m||c!==v||(F(),b=setInterval(F,t))},u.onmessage=e=>{if(m||c!==v)return;let t=e.data;if(typeof t==`string`){E=E.then(async()=>{if(m||c!==v)return;let e=await l.handleText(t);if(e.type===`established`){if(k)return;de(e.channel,e.batch)}else e.type===`fail`&&P(Error(`relay handshake failed: ${e.reason}`))}).catch(e=>{P(z(e))});return}let n=t instanceof ArrayBuffer?new Uint8Array(t):t instanceof Uint8Array?t:null;n&&(E=E.then(async()=>{if(m||c!==v)return;let e=O,t=k;if(!e||!t){P(Error(`encrypted frame before handshake completed`));return}let r;try{r=await t.decryptor.decrypt(n)}catch(e){P(z(e));return}if(A){let t;try{t=se(r)}catch(e){P(z(e));return}for(let n of t){if(m||c!==v||e.dead)return;I(e,n)}return}I(e,r)}).catch(e=>{P(z(e))}))},u.onclose=e=>{let t=Oe.has(e.code);P(Error(ke[e.code]??`relay socket closed (code ${e.code})`),t,t)},u.onerror=()=>{},x=setTimeout(()=>{x=null,P(Error(`relay handshake timeout`),!0)},n);function fe(e,t,n=!1){e!==v||f||(w(t),y+=1,C({state:n?`error`:`reconnecting`,lastError:t.message}),oe())}},F=e=>f?Promise.reject(Error(`relay tunnel closed`)):e?.aborted?Promise.reject(B()):h&&!h.dead?Promise.resolve(h):new Promise((t,n)=>{let r=null,i={resolve(n){r&&e&&e.removeEventListener(`abort`,r),t(n)},reject(t){r&&e&&e.removeEventListener(`abort`,r),n(t)}};e&&(r=()=>{x=x.filter(e=>e!==i),n(B())},e.addEventListener(`abort`,r,{once:!0})),x.push(i)}),pe=async(e,t)=>{let n=await ve(e,t),i=n.signal;if(i?.aborted)throw B();let a=await F(i),o=a.nextStreamId();return await new Promise((e,t)=>{let s=!1,c=!1,l=null,u=null,d=()=>{a.streams.delete(o),a.assembler.dropStream(o),u&&i&&i.removeEventListener(`abort`,u)},f=e=>{if(!c){if(c=!0,d(),!s){t(e);return}try{l?.error(e)}catch{}}},p=e=>{a.dead||a.send(D(r.StreamAbort,o,A({reason:e})))};u=()=>{p(`aborted`),f(B())},a.streams.set(o,{handleFrame(t,n){if(t===r.HttpResponse){if(s||c)return;let t;try{t=j(n,de)}catch(e){p(`malformed response head`),f(z(e));return}let r=t.status===204||t.status===205||t.status===304,i=null;r||(i=new ReadableStream({start(e){l=e},cancel(){c||(c=!0,d(),p(`response body cancelled`))}})),s=!0,e(new Response(i,{status:t.status,headers:t.headers})),r&&(c=!0,d());return}if(t===r.HttpBody){if(!s||c)return;try{l?.enqueue(n)}catch{}return}if(t===r.StreamEnd){if(c)return;if(!s){f(Error(`tunnel stream ended before response head`));return}c=!0,d();try{l?.close()}catch{}return}if(t===r.StreamAbort){let e=`stream aborted by host`;try{e=j(n,I).reason}catch{}f(Error(e))}},fail(e){f(e)}}),i&&i.addEventListener(`abort`,u,{once:!0});let m={method:n.method,path:n.path,query:n.query,headers:n.headers};a.send(D(r.HttpRequest,o,A(m))),(async()=>{try{if(n.body)for await(let e of n.body){if(c||a.dead)return;for(let t of M(e))a.send(D(r.HttpBody,o,t))}!c&&!a.dead&&a.send(D(r.StreamEnd,o,ye))}catch(e){p(`request body failed`),f(z(e))}})()})},L=e=>{let t=e.indexOf(`?`);return t===-1?{path:e,query:``}:{path:e.slice(0,t),query:e.slice(t+1)}};return P(),{fetch:pe,openWebSocket:(e,t,n)=>{let i=we,a=null,o=0,s=!1,c={get readyState(){return i},onopen:null,onmessage:null,onerror:null,onclose:null,send(e){if(i!==Te||!a||a.dead)throw Error(`relay tunnel socket is not open`);if(typeof e==`string`){for(let t of N(r.WsText,o,be.encode(e)))a.send(t);return}let t=e instanceof ArrayBuffer?new Uint8Array(e.slice(0)):(()=>{let t=new Uint8Array(e.byteLength);return t.set(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)),t})();for(let e of N(r.WsBinary,o,t))a.send(e)},close(e=1e3,t=``){i!==De&&i!==Ee&&(i===Te&&a&&!a.dead&&(i=Ee,a.send(D(r.WsClose,o,A({code:e,reason:t})))),l(e,t))}},l=(e,t,n=!1)=>{if(!s){if(s=!0,a&&(a.streams.delete(o),a.assembler.dropStream(o)),i=De,n)try{c.onerror?.()}catch{}try{c.onclose?.({code:e,reason:t})}catch{}}};return(async()=>{let u;try{u=await F()}catch(e){l(1006,z(e).message,!0);return}if(s)return;a=u,o=u.nextStreamId(),u.streams.set(o,{handleFrame(e,t){if(e===r.WsOpened){if(i===we){i=Te;try{c.onopen?.()}catch{}}return}if(e===r.WsText){try{c.onmessage?.({data:xe.decode(t)})}catch{}return}if(e===r.WsBinary){let e=new ArrayBuffer(t.byteLength);new Uint8Array(e).set(t);try{c.onmessage?.({data:e})}catch{}return}if(e===r.WsClose){let e=1e3,n=``;try{let r=j(t,fe);e=r.code,n=r.reason}catch{}l(e,n);return}if(e===r.StreamAbort){let e=`stream aborted`;try{e=j(t,I).reason}catch{}l(1006,e,!0)}},fail(e){l(1012,e.message,!0)}});let{path:d,query:f}=L(e),p={path:d,query:f,...t&&t.length>0?{protocols:t}:{},...n&&Object.keys(n).length>0?{headers:n}:{}};u.send(D(r.WsOpen,o,A(p)))})(),c},getStatus:()=>p,subscribeStatus(e){return m.add(e),()=>{m.delete(e)}},close:()=>{if(f)return;f=!0,v+=1,ne(),k(),_?.(),_=null;let e=h;h=null;let t=Error(`relay tunnel closed`);e&&te(e,t),w(t);try{g?.close()}catch{}g=null,C({state:`idle`})}}},V=null,H=null,Me=(e,t)=>e.relayUrl===t.relayUrl&&e.serverId===t.serverId&&e.grant===t.grant&&JSON.stringify(e.hostEncPubJwk)===JSON.stringify(t.hostEncPubJwk),Ne=()=>V,Pe=()=>H,Fe=()=>V!==null,Ie=()=>V?.getStatus().state===`connected`,Le=e=>V&&H&&Me(H,e)?V:(V?.close(),H=e,V=je(e),V),Re=(e,t)=>{V!==t&&(V?.close(),H=e,V=t)},ze=()=>{V?.close(),V=null,H=null},Be=e({acquireRuntimeUrlAuthToken:()=>kt,beginRuntimeAuthEndpointSwitch:()=>ot,buildRuntimeAuthHeaders:()=>jt,clearRuntimeUrlAuthToken:()=>X,endRuntimeAuthEndpointSwitch:()=>st,getLocalRuntimeUrlAuthTokenSync:()=>_t,getRuntimeAuthGeneration:()=>Ge,getRuntimeBearerTokenSync:()=>Z,getRuntimeExtraHeadersSync:()=>ft,getRuntimeUrlAuthTokenSync:()=>gt,invalidateRuntimeAuthSession:()=>lt,refreshLocalRuntimeUrlAuthToken:()=>St,refreshRuntimeUrlAuthToken:()=>xt,setRuntimeBearerToken:()=>ut,setRuntimeExtraHeaders:()=>dt,setRuntimeUrlAuthToken:()=>pt,subscribeRuntimeAuthGeneration:()=>ct,subscribeRuntimeUrlAuthToken:()=>At}),Ve=()=>null,He=``,Ue={},U=``,W=0,G=null,K=``,q=0,J=null,Y=0,We=1e4,Ge=()=>Y,Ke=e=>e.toLowerCase()===`authorization`,qe=e=>{let t={};for(let[n,r]of Object.entries(e||{})){let e=n.trim(),i=r.trim();e&&i&&!Ke(e)&&(t[e]=i)}return t},Je=(e,t)=>{let n=Object.entries(e);return n.length===Object.keys(t).length&&n.every(([e,n])=>t[e]===n)},Ye=e=>typeof e==`string`?e.trim():``,Xe=()=>{if(typeof window>`u`)return``;let e=window.__OPENCHAMBER_CLIENT_TOKEN__;return Ye(e)},Ze=()=>{if(typeof window>`u`)return``;let e=window.__OPENCHAMBER_API_BASE_URL__;return typeof e==`string`?e.trim():``},Qe=(e,t)=>{let n=typeof e==`string`&&e.trim()?e.trim():Ze();if(!n)return t;try{return new URL(t,`${n.replace(/\/+$/,``)}/`).toString()}catch{return t}},X=()=>{U=``,W=0,K=``,q=0},$e=new Set,et=null,tt=0,nt=async e=>{let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t);return[...new Uint8Array(n)].map(e=>e.toString(16).padStart(2,`0`)).join(``)},rt=e=>{for(let t of $e)try{t(e)}catch{}},it=e=>e||(tt>0?`endpoint-switch`:`credential`),at=(e={})=>{let t=e.previousBearerDigest===void 0?et??void 0:e.previousBearerDigest||void 0;Y+=1,G=null,X(),Ot(),rt({generation:Y,reason:it(e.reason),...t?{previousBearerDigest:t}:{}})},ot=()=>{tt+=1},st=()=>{tt=Math.max(0,tt-1)},ct=e=>($e.add(e),()=>{$e.delete(e)}),lt=()=>{at({reason:`invalidate`})},ut=e=>{let t=Ye(e),n=t===Z(),r=et;He=t,Ve=()=>t?{type:`bearer`,token:t}:null,!n&&(et=null,at({previousBearerDigest:r}),t&&nt(t).then(e=>{Z()===t&&(et=e)}).catch(()=>void 0))},dt=e=>{let t=qe(e);Je(Ue,t)||(Ue=t,at({previousBearerDigest:null}))},ft=()=>{if(Object.keys(Ue).length>0)return Ue;if(typeof window>`u`)return{};let e=window.__OPENCHAMBER_RUNTIME_HEADERS__;return e&&typeof e==`object`?qe(e):{}},Z=()=>He||Xe(),pt=(e,t)=>{let n=Ye(e);if(!n||typeof t!=`number`||!Number.isFinite(t)){X();return}let r=U;U=n,W=t,r&&r!==n&&Et()},mt=()=>!U||W<=Date.now()+We?(X(),``):U,ht=()=>!K||q<=Date.now()+We?(K=``,q=0,``):K,gt=()=>{let e=mt();return!e&&(Z()||typeof window<`u`)&&xt().catch(()=>{}),e},_t=e=>{let t=ht();return!t&&e&&typeof window<`u`&&St(e).catch(()=>{}),t},vt=async()=>{let e=await Ve(),t=e?.type===`bearer`?Ye(e.token):Z();return t?{type:`bearer`,token:t}:null},yt=e=>{if(G)return G;let t=Y,n=(async()=>{let n=await vt(),r=new Headers;for(let[e,t]of Object.entries(ft()))r.set(e,t);n?.type===`bearer`&&r.set(`Authorization`,`Bearer ${n.token}`);let i=Ne(),a=i?await i.fetch(`/auth/url-token`,{method:`POST`,headers:r}):await fetch(Qe(e,`/auth/url-token`),{method:`POST`,headers:r,credentials:`include`});if(!a.ok)throw t===Y&&X(),Error(`Failed to mint runtime URL auth token (${a.status})`);let o=await a.json().catch(()=>null),s=typeof o?.token==`string`?o.token.trim():``,c=typeof o?.expiresAt==`number`?o.expiresAt:0;if(t!==Y)throw Error(`Runtime URL auth token response is stale`);if(pt(s,c),!U)throw Error(`Runtime URL auth token response was invalid`);return U})().finally(()=>{G===n&&(G=null)});return G=n,G},bt=e=>{if(J)return J;let t=(async()=>{let t=await fetch(Qe(e,`/auth/url-token`),{method:`POST`,credentials:`include`});if(!t.ok)throw K=``,q=0,Error(`Failed to mint local runtime URL auth token (${t.status})`);let n=await t.json().catch(()=>null),r=typeof n?.token==`string`?n.token.trim():``,i=typeof n?.expiresAt==`number`?n.expiresAt:0;if(!r||!Number.isFinite(i))throw Error(`Local runtime URL auth token response was invalid`);return K=r,q=i,r})().finally(()=>{J===t&&(J=null)});return J=t,J},xt=async e=>mt()||yt(e),St=async e=>ht()||bt(e),Q=0,$=null,Ct=null,wt=new Set,Tt=5e3,Et=()=>{for(let e of wt)try{e()}catch{}},Dt=()=>{$!==null&&(clearTimeout($),$=null)},Ot=()=>{if(Dt(),Q<=0||typeof window>`u`)return;let e=W-We-Tt,t=W>0?Math.max(0,e-Date.now()):0;$=setTimeout(()=>{$=null,!(Q<=0)&&yt(Ct).catch(()=>{}).finally(()=>{Ot()})},t)},kt=e=>{typeof e==`string`&&e.trim()&&(Ct=e.trim()),Q+=1,Ot();let t=!1;return()=>{t||(t=!0,Q=Math.max(0,Q-1),Q===0&&Dt())}},At=e=>(wt.add(e),()=>{wt.delete(e)}),jt=async e=>{let t=new Headers(e);for(let[e,n]of Object.entries(ft()))t.has(e)||t.set(e,n);if(t.has(`Authorization`))return t;let n=await vt();return n?.type===`bearer`&&t.set(`Authorization`,`Bearer ${n.token}`),t};export{Ne as C,Ce as D,je as E,L as O,Pe as S,Ie as T,ct as _,st as a,Re as b,Z as c,lt as d,St as f,dt as g,ut as h,X as i,me as k,ft as l,Be as m,ot as n,_t as o,xt as p,jt as r,Ge as s,kt as t,gt as u,At as v,Fe as w,ze as x,Le as y};