@bodhiapp/bodhi-js-ext 0.0.30 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
- import { DirectClientBase as M, createStoragePrefixWithBasePath as N, STORAGE_PREFIXES as v, AccessRequestBuilder as P, unwrapResponse as X, DEFAULT_POLL_TIMEOUT_MS as b, DEFAULT_POLL_INTERVAL_MS as O, createOperationError as l, generateCodeVerifier as C, generateCodeChallenge as U, PENDING_EXTENSION_READY as f, Logger as w, NOOP_STATE_CALLBACK as D, createExtensionStateNotInitialized as $, BACKEND_SERVER_NOT_REACHABLE as B, createExtensionStateNotFound as K, BodhiError as T, INITIAL_AUTH_STATE as V, BodhiApiError as z, Chat as F, Models as G, Embeddings as Q, Mcps as H, pollAccessRequestUntilResolved as L, isAuthError as W, BaseFacadeClient as J, refreshAccessToken as Y } from "@bodhiapp/bodhi-js-core";
2
- import { isExtError as x, isApiSuccessResponse as Z, MESSAGE_TYPES as _, EXT_ACTIONS as j, BODHI_STREAM_PORT as ee, isStreamChunk as te, isStreamApiError as re, isStreamError as se } from "@bodhiapp/bodhi-browser-types";
1
+ import { DirectClientBase as $, createStoragePrefixWithBasePath as X, STORAGE_PREFIXES as N, AccessRequestBuilder as v, unwrapResponse as L, DEFAULT_POLL_TIMEOUT_MS as P, DEFAULT_POLL_INTERVAL_MS as b, createOperationError as l, generateCodeVerifier as A, generateCodeChallenge as B, PENDING_EXTENSION_READY as f, Logger as x, NOOP_STATE_CALLBACK as V, createExtensionStateNotInitialized as z, BACKEND_SERVER_NOT_REACHABLE as K, createExtensionStateNotFound as F, BodhiError as T, INITIAL_AUTH_STATE as G, BodhiApiError as Q, Chat as H, Models as W, Embeddings as J, Mcps as Y, pollAccessRequestUntilResolved as k, isAuthError as Z, BaseFacadeClient as j, refreshAccessToken as ee } from "@bodhiapp/bodhi-js-core";
2
+ import { InMemoryStorage as Ce } from "@bodhiapp/bodhi-js-core";
3
+ import { isExtError as I, isApiSuccessResponse as te, MESSAGE_TYPES as _, EXT_ACTIONS as re, BODHI_STREAM_PORT as se, isStreamChunk as oe, isStreamApiError as ne, isStreamError as ie, BODHI_STREAM_TEXT_PORT as ae } from "@bodhiapp/bodhi-browser-types";
3
4
  const c = {
4
5
  EXT2EXT_CLIENT_REQUEST: "EXT2EXT_CLIENT_REQUEST",
5
6
  EXT2EXT_CLIENT_RESPONSE: "EXT2EXT_CLIENT_RESPONSE",
@@ -11,32 +12,52 @@ const c = {
11
12
  EXT2EXT_CLIENT_STREAM_CHUNK: "EXT2EXT_CLIENT_STREAM_CHUNK",
12
13
  EXT2EXT_CLIENT_STREAM_ERROR: "EXT2EXT_CLIENT_STREAM_ERROR",
13
14
  EXT2EXT_CLIENT_STREAM_API_ERROR: "EXT2EXT_CLIENT_STREAM_API_ERROR",
14
- EXT2EXT_CLIENT_STREAM_DONE: "EXT2EXT_CLIENT_STREAM_DONE"
15
- }, k = "ext2ext-client-stream", m = {
15
+ EXT2EXT_CLIENT_STREAM_DONE: "EXT2EXT_CLIENT_STREAM_DONE",
16
+ // Stream text message types (raw text streaming, no SSE/JSON parsing)
17
+ EXT2EXT_CLIENT_STREAM_TEXT_REQUEST: "EXT2EXT_CLIENT_STREAM_TEXT_REQUEST",
18
+ EXT2EXT_CLIENT_STREAM_TEXT_START: "EXT2EXT_CLIENT_STREAM_TEXT_START",
19
+ EXT2EXT_CLIENT_STREAM_TEXT_CHUNK: "EXT2EXT_CLIENT_STREAM_TEXT_CHUNK",
20
+ EXT2EXT_CLIENT_STREAM_TEXT_DONE: "EXT2EXT_CLIENT_STREAM_TEXT_DONE",
21
+ EXT2EXT_CLIENT_STREAM_TEXT_ERROR: "EXT2EXT_CLIENT_STREAM_TEXT_ERROR"
22
+ }, M = "ext2ext-client-stream", O = "ext2ext-client-stream-text", p = {
16
23
  LOGIN: "login",
17
24
  LOGOUT: "logout",
18
25
  GET_AUTH_STATE: "getAuthState",
19
26
  DISCOVER_EXTENSION: "discoverBodhiExtension",
20
27
  GET_EXTENSION_ID: "get_extension_id",
21
28
  SET_EXTENSION_ID: "setExtensionId"
22
- }, oe = 5e3, ie = 3, ne = 500, ae = 500, ce = 3e4;
23
- function he(y) {
24
- return "error" in y;
29
+ }, ce = 5e3, he = 3, Ee = 500, ue = 500, de = 3e4;
30
+ function le(R) {
31
+ return "error" in R;
25
32
  }
26
- class ue extends M {
33
+ class Te {
34
+ async get(e) {
35
+ const r = (await chrome.storage.session.get(e))[e];
36
+ return r !== void 0 ? String(r) : null;
37
+ }
38
+ async set(e) {
39
+ await chrome.storage.session.set(e);
40
+ }
41
+ async remove(e) {
42
+ await chrome.storage.session.remove(e);
43
+ }
44
+ }
45
+ class ge extends $ {
27
46
  constructor(e, t) {
28
- const r = N(
47
+ const r = X(
29
48
  e.basePath,
30
- v.EXT_DIRECT
31
- ), i = {
49
+ N.EXT_DIRECT
50
+ ), n = {
32
51
  authClientId: e.authClientId,
33
52
  authServerUrl: e.authServerUrl,
34
53
  storagePrefix: r,
35
54
  logLevel: e.logLevel,
36
55
  loggerPrefix: "DirectExtClient",
37
- apiTimeoutMs: e.apiTimeoutMs
56
+ apiTimeoutMs: e.apiTimeoutMs,
57
+ storage: e.storage ?? new Te(),
58
+ initialTokens: e.initialTokens
38
59
  };
39
- super(i, t);
60
+ super(n, t);
40
61
  }
41
62
  // ============================================================================
42
63
  // Authentication (chrome.identity OAuth)
@@ -48,163 +69,72 @@ class ue extends M {
48
69
  e?.flowType === "redirect" && this.logger.warn("Extension mode does not support redirect flow type; using popup instead");
49
70
  const r = e?.userRole ?? "scope_user_user";
50
71
  e?.onProgress?.("requesting");
51
- const i = new P(this.authClientId).requestedRole(r).flowType("popup");
52
- e?.requested && i.requested(e.requested);
53
- const o = i.build(), s = await this.requestAccess(o), { id: n, review_url: h } = X(s);
72
+ const n = new v(this.authClientId).requestedRole(r).flowType("popup");
73
+ e?.requested && n.requested(e.requested);
74
+ const o = n.build(), s = await this.requestAccess(o), { id: i, review_url: h } = L(s);
54
75
  e?.onProgress?.("reviewing"), await chrome.tabs.create({ url: h });
55
- const a = await this.pollAccessRequestStatus(n, {
56
- intervalMs: e?.pollIntervalMs ?? O,
57
- timeoutMs: e?.pollTimeoutMs ?? b
76
+ const a = await this.pollAccessRequestStatus(i, {
77
+ intervalMs: e?.pollIntervalMs ?? b,
78
+ timeoutMs: e?.pollTimeoutMs ?? P
58
79
  });
59
80
  if (a.status !== "approved")
60
81
  throw l("auth_error", `Access request ${a.status}`);
61
- const u = a.access_request_scope;
62
- return e?.onProgress?.("authenticating"), this.performOAuthPkce(`openid profile email roles ${u ?? ""}`.trim());
82
+ const E = a.access_request_scope;
83
+ return e?.onProgress?.("authenticating"), this.performOAuthPkce(`openid profile email roles ${E ?? ""}`.trim());
63
84
  }
64
85
  async performOAuthPkce(e) {
65
- const t = C(), r = await U(t), i = C();
66
- await chrome.storage.session.set({
86
+ const t = A(), r = await B(t), n = A();
87
+ await this._storageSet({
67
88
  [this.storageKeys.CODE_VERIFIER]: t,
68
- [this.storageKeys.STATE]: i
89
+ [this.storageKeys.STATE]: n
69
90
  });
70
91
  const o = chrome.identity.getRedirectURL("callback"), s = new URL(this.authEndpoints.authorize);
71
- return s.searchParams.set("client_id", this.authClientId), s.searchParams.set("response_type", "code"), s.searchParams.set("redirect_uri", o), s.searchParams.set("scope", e), s.searchParams.set("code_challenge", r), s.searchParams.set("code_challenge_method", "S256"), s.searchParams.set("state", i), new Promise((n, h) => {
92
+ return s.searchParams.set("client_id", this.authClientId), s.searchParams.set("response_type", "code"), s.searchParams.set("redirect_uri", o), s.searchParams.set("scope", e), s.searchParams.set("code_challenge", r), s.searchParams.set("code_challenge_method", "S256"), s.searchParams.set("state", n), new Promise((i, h) => {
72
93
  chrome.identity.launchWebAuthFlow(
73
94
  { url: s.toString(), interactive: !0 },
74
95
  async (a) => {
75
96
  if (chrome.runtime.lastError) {
76
- await chrome.storage.session.remove([
77
- this.storageKeys.CODE_VERIFIER,
78
- this.storageKeys.STATE
79
- ]), h(chrome.runtime.lastError);
97
+ await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), h(chrome.runtime.lastError);
80
98
  return;
81
99
  }
82
100
  if (!a) {
83
- await chrome.storage.session.remove([
84
- this.storageKeys.CODE_VERIFIER,
85
- this.storageKeys.STATE
86
- ]), h(l("oauth_error", "No redirect URL received"));
101
+ await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), h(l("oauth_error", "No redirect URL received"));
87
102
  return;
88
103
  }
89
104
  try {
90
- const u = new URL(a), d = u.searchParams.get("code"), g = u.searchParams.get("state"), S = await chrome.storage.session.get(this.storageKeys.STATE);
91
- if (g !== S[this.storageKeys.STATE]) {
92
- await chrome.storage.session.remove([
93
- this.storageKeys.CODE_VERIFIER,
94
- this.storageKeys.STATE
95
- ]), h(l("oauth_error", "State mismatch"));
105
+ const E = new URL(a), d = E.searchParams.get("code"), u = E.searchParams.get("state"), g = await this._storageGet(this.storageKeys.STATE);
106
+ if (u !== g) {
107
+ await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), h(l("oauth_error", "State mismatch"));
96
108
  return;
97
109
  }
98
110
  if (!d) {
99
- await chrome.storage.session.remove([
100
- this.storageKeys.CODE_VERIFIER,
101
- this.storageKeys.STATE
102
- ]), h(l("oauth_error", "No authorization code"));
111
+ await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), h(l("oauth_error", "No authorization code"));
103
112
  return;
104
113
  }
105
114
  await this.exchangeCodeForTokens(d);
106
- const E = await this.getAuthState();
107
- if (E.status !== "authenticated")
115
+ const m = await this.getAuthState();
116
+ if (m.status !== "authenticated")
108
117
  throw l("oauth_error", "Login failed");
109
- this.setAuthState(E), await chrome.storage.session.remove([
110
- this.storageKeys.CODE_VERIFIER,
111
- this.storageKeys.STATE
112
- ]), n(E);
113
- } catch (u) {
114
- await chrome.storage.session.remove([
115
- this.storageKeys.CODE_VERIFIER,
116
- this.storageKeys.STATE
117
- ]), h(u);
118
+ this.setAuthState(m), await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), i(m);
119
+ } catch (E) {
120
+ await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), h(E);
118
121
  }
119
122
  }
120
123
  );
121
124
  });
122
125
  }
123
- async logout() {
124
- const t = (await chrome.storage.session.get(this.storageKeys.REFRESH_TOKEN))[this.storageKeys.REFRESH_TOKEN];
125
- if (t)
126
- try {
127
- const i = new URLSearchParams({
128
- token: t,
129
- client_id: this.authClientId,
130
- token_type_hint: "refresh_token"
131
- });
132
- await fetch(this.authEndpoints.revoke, {
133
- method: "POST",
134
- headers: {
135
- "Content-Type": "application/x-www-form-urlencoded"
136
- },
137
- body: i
138
- });
139
- } catch (i) {
140
- this.logger.warn("Token revocation failed:", i);
141
- }
142
- await chrome.storage.session.remove([
143
- this.storageKeys.ACCESS_TOKEN,
144
- this.storageKeys.REFRESH_TOKEN,
145
- this.storageKeys.EXPIRES_AT
146
- ]);
147
- const r = {
148
- status: "unauthenticated",
149
- user: null,
150
- accessToken: null,
151
- error: null
152
- };
153
- return this.setAuthState(r), r;
154
- }
155
- // ============================================================================
156
- // OAuth Helper Methods
157
- // ============================================================================
158
- async exchangeCodeForTokens(e) {
159
- const r = (await chrome.storage.session.get(this.storageKeys.CODE_VERIFIER))[this.storageKeys.CODE_VERIFIER], i = chrome.identity.getRedirectURL("callback"), o = await fetch(this.authEndpoints.token, {
160
- method: "POST",
161
- headers: {
162
- "Content-Type": "application/x-www-form-urlencoded"
163
- },
164
- body: new URLSearchParams({
165
- grant_type: "authorization_code",
166
- code: e,
167
- redirect_uri: i,
168
- client_id: this.authClientId,
169
- code_verifier: r
170
- })
171
- });
172
- if (!o.ok) {
173
- const h = await o.text();
174
- throw new Error(`Token exchange failed: ${o.status} ${h}`);
175
- }
176
- const s = await o.json(), n = Date.now() + (s.expires_in || 3600) * 1e3;
177
- await chrome.storage.session.set({
178
- [this.storageKeys.ACCESS_TOKEN]: s.access_token,
179
- [this.storageKeys.REFRESH_TOKEN]: s.refresh_token,
180
- [this.storageKeys.EXPIRES_AT]: n
181
- }), await chrome.storage.session.remove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]);
182
- }
183
- // ============================================================================
184
- // Storage Implementation (chrome.storage.session)
185
- // ============================================================================
186
- async _storageGet(e) {
187
- const r = (await chrome.storage.session.get(e))[e];
188
- return r !== void 0 ? String(r) : null;
189
- }
190
- async _storageSet(e) {
191
- await chrome.storage.session.set(e);
192
- }
193
- async _storageRemove(e) {
194
- await chrome.storage.session.remove(e);
195
- }
196
126
  _getRedirectUri() {
197
127
  return chrome.identity.getRedirectURL("callback");
198
128
  }
199
129
  }
200
- class de {
130
+ class _e {
201
131
  constructor(e = {}, t) {
202
132
  this.state = {
203
133
  type: "extension",
204
134
  extension: "not-initialized",
205
135
  extensionId: null,
206
136
  server: f
207
- }, this.extensionId = null, this.broadcastListenerActive = !1, this.config = e, this.logger = new w("ExtClient", e?.logLevel || "warn"), this.onStateChange = t ?? D, this.apiTimeoutMs = e.apiTimeoutMs ?? ce, this.authClientId = e.authClientId ?? "";
137
+ }, this.extensionId = null, this.broadcastListenerActive = !1, this.config = e, this.logger = new x("ExtClient", e?.logLevel || "warn"), this.onStateChange = t ?? V, this.apiTimeoutMs = e.apiTimeoutMs ?? de, this.authClientId = e.authClientId ?? "";
208
138
  }
209
139
  /**
210
140
  * Set client state and notify callback
@@ -272,17 +202,17 @@ class de {
272
202
  async init(e = {}) {
273
203
  if (!e.testConnection && !e.selectedConnection) {
274
204
  this.logger.info("No testConnection or selectedConnection, returning not-initialized state");
275
- const i = $();
276
- return this.setState(i), i;
205
+ const n = z();
206
+ return this.setState(n), n;
277
207
  }
278
208
  if (this.extensionId && !e.testConnection)
279
209
  return this.logger.debug("Already initialized with extensionId, skipping discovery"), this.state;
280
- const t = e.timeoutMs ?? this.config.initParams?.extension?.timeoutMs ?? oe, r = e.savedState?.extensionId;
210
+ const t = e.timeoutMs ?? this.config.initParams?.extension?.timeoutMs ?? ce, r = e.savedState?.extensionId;
281
211
  try {
282
212
  if (!this.extensionId) {
283
213
  if (r)
284
214
  this.logger.info("Restoring with known extensionId:", r), await this.sendExtMessageWithTimeout(
285
- m.SET_EXTENSION_ID,
215
+ p.SET_EXTENSION_ID,
286
216
  { extensionId: r },
287
217
  t
288
218
  ), this.extensionId = r;
@@ -292,16 +222,16 @@ class de {
292
222
  attempts: this.config.initParams?.extension?.attempts,
293
223
  attemptWaitMs: this.config.initParams?.extension?.attemptWaitMs,
294
224
  attemptTimeout: this.config.initParams?.extension?.attemptTimeout
295
- }, n = await this.sendExtMessageWithTimeout(
296
- m.DISCOVER_EXTENSION,
225
+ }, i = await this.sendExtMessageWithTimeout(
226
+ p.DISCOVER_EXTENSION,
297
227
  s,
298
228
  t
299
229
  );
300
- this.extensionId = n.extensionId, this.logger.info("Extension discovered:", this.extensionId);
230
+ this.extensionId = i.extensionId, this.logger.info("Extension discovered:", this.extensionId);
301
231
  }
302
232
  this.setupBroadcastListener();
303
233
  }
304
- const i = {
234
+ const n = {
305
235
  type: "extension",
306
236
  extension: "ready",
307
237
  extensionId: this.extensionId,
@@ -312,12 +242,12 @@ class de {
312
242
  try {
313
243
  o = await this.getServerState(), this.logger.info("Server connectivity tested, state:", o.status);
314
244
  } catch (s) {
315
- this.logger.error("Failed to get server state:", s), o = B;
245
+ this.logger.error("Failed to get server state:", s), o = K;
316
246
  }
317
- return this.setState({ ...i, server: o }), this.state;
318
- } catch (i) {
319
- this.logger.error("Failed to initialize extension:", i), this.extensionId = null;
320
- const o = K();
247
+ return this.setState({ ...n, server: o }), this.state;
248
+ } catch (n) {
249
+ this.logger.error("Failed to initialize extension:", n), this.extensionId = null;
250
+ const o = F();
321
251
  return this.setState(o), this.state;
322
252
  }
323
253
  }
@@ -325,10 +255,10 @@ class de {
325
255
  * Helper method to send ext message with timeout support
326
256
  */
327
257
  async sendExtMessageWithTimeout(e, t, r = 1e4) {
328
- const i = new Promise(
258
+ const n = new Promise(
329
259
  (o, s) => setTimeout(() => s(new Error("Timeout")), r)
330
260
  );
331
- return Promise.race([this.sendExtRequest(e, t), i]);
261
+ return Promise.race([this.sendExtRequest(e, t), n]);
332
262
  }
333
263
  /**
334
264
  * Send an EXT2EXT_CLIENT_REQUEST message and await EXT2EXT_CLIENT_RESPONSE
@@ -336,7 +266,7 @@ class de {
336
266
  */
337
267
  async sendExtRequest(e, t) {
338
268
  try {
339
- const r = this.generateRequestId(), i = await chrome.runtime.sendMessage({
269
+ const r = this.generateRequestId(), n = await chrome.runtime.sendMessage({
340
270
  type: c.EXT2EXT_CLIENT_REQUEST,
341
271
  requestId: r,
342
272
  request: {
@@ -344,15 +274,15 @@ class de {
344
274
  params: t
345
275
  }
346
276
  });
347
- if (!i)
277
+ if (!n)
348
278
  throw l("extension_error", "No response from background script");
349
- if (i.type !== c.EXT2EXT_CLIENT_RESPONSE)
279
+ if (n.type !== c.EXT2EXT_CLIENT_RESPONSE)
350
280
  throw l(
351
281
  "extension_error",
352
282
  "Invalid response type from background script"
353
283
  );
354
- const o = i.response;
355
- if (x(o)) {
284
+ const o = n.response;
285
+ if (I(o)) {
356
286
  const s = o.error.type || "extension_error";
357
287
  throw l(s, o.error.message);
358
288
  }
@@ -368,7 +298,7 @@ class de {
368
298
  * Send an API_REQUEST message and await API_RESPONSE (internal)
369
299
  * Returns ext2ext-specific ExtClientApiResponseMessage
370
300
  */
371
- async sendRawApiMessage(e, t, r, i, o) {
301
+ async sendRawApiMessage(e, t, r, n, o) {
372
302
  const s = this.generateRequestId();
373
303
  return await chrome.runtime.sendMessage({
374
304
  type: c.EXT2EXT_CLIENT_API_REQUEST,
@@ -377,7 +307,7 @@ class de {
377
307
  method: e,
378
308
  endpoint: t,
379
309
  body: r,
380
- headers: i,
310
+ headers: n,
381
311
  authenticated: o
382
312
  }
383
313
  });
@@ -386,7 +316,7 @@ class de {
386
316
  * Send an API message and return ApiResponse
387
317
  * @throws BodhiError on operational errors (network, timeout, extension-level)
388
318
  */
389
- async sendApiRequest(e, t, r, i, o) {
319
+ async sendApiRequest(e, t, r, n, o) {
390
320
  try {
391
321
  const s = new Promise(
392
322
  (h, a) => setTimeout(
@@ -397,20 +327,20 @@ class de {
397
327
  ),
398
328
  this.apiTimeoutMs
399
329
  )
400
- ), n = await Promise.race([
401
- this.sendRawApiMessage(e, t, r, i, o),
330
+ ), i = await Promise.race([
331
+ this.sendRawApiMessage(e, t, r, n, o),
402
332
  s
403
333
  ]);
404
- if (he(n)) {
405
- const h = n.error.type || "extension_error";
406
- throw new T(h, n.error.message);
334
+ if (le(i)) {
335
+ const h = i.error.type || "extension_error";
336
+ throw new T(h, i.error.message);
407
337
  }
408
- return n.response;
338
+ return i.response;
409
339
  } catch (s) {
410
340
  if (s instanceof T)
411
341
  throw s;
412
- const n = s instanceof Error ? s.message : String(s);
413
- throw new T("network_error", n);
342
+ const i = s instanceof Error ? s.message : String(s);
343
+ throw new T("network_error", i);
414
344
  }
415
345
  }
416
346
  /**
@@ -421,12 +351,12 @@ class de {
421
351
  */
422
352
  async login(e) {
423
353
  return new Promise((t, r) => {
424
- const i = async (o) => {
354
+ const n = async (o) => {
425
355
  if (o && typeof o == "object" && "type" in o && o.type === "EXT2EXT_CLIENT_BROADCAST" && "event" in o && o.event === "authStateChanged") {
426
- chrome.runtime.onMessage.removeListener(i);
356
+ chrome.runtime.onMessage.removeListener(n);
427
357
  try {
428
358
  const s = await this.getAuthState();
429
- if (W(s)) {
359
+ if (Z(s)) {
430
360
  r(
431
361
  l("auth_error", `Login failed: ${s.error?.message}`)
432
362
  );
@@ -442,8 +372,8 @@ class de {
442
372
  }
443
373
  }
444
374
  };
445
- chrome.runtime.onMessage.addListener(i), this.sendExtRequest(m.LOGIN, e).catch((o) => {
446
- chrome.runtime.onMessage.removeListener(i), r(o);
375
+ chrome.runtime.onMessage.addListener(n), this.sendExtRequest(p.LOGIN, e).catch((o) => {
376
+ chrome.runtime.onMessage.removeListener(n), r(o);
447
377
  });
448
378
  });
449
379
  }
@@ -453,12 +383,15 @@ class de {
453
383
  * @returns AuthLoggedOut with logged out state
454
384
  */
455
385
  async logout() {
456
- await this.sendExtRequest(m.LOGOUT);
386
+ await this.sendExtRequest(p.LOGOUT);
457
387
  const e = {
458
388
  status: "unauthenticated",
459
389
  user: null,
460
390
  accessToken: null,
461
- error: null
391
+ error: null,
392
+ refreshToken: null,
393
+ expiresAt: null,
394
+ isTokenRefresh: !1
462
395
  };
463
396
  return this.setAuthState(e), e;
464
397
  }
@@ -469,8 +402,8 @@ class de {
469
402
  */
470
403
  async getAuthState() {
471
404
  return this.isClientInitialized() ? (await this.sendExtRequest(
472
- m.GET_AUTH_STATE
473
- )).authState : V;
405
+ p.GET_AUTH_STATE
406
+ )).authState : G;
474
407
  }
475
408
  /**
476
409
  * Ping bodhi-browser-ext API via /ping endpoint
@@ -487,11 +420,11 @@ class de {
487
420
  try {
488
421
  e = await this.sendApiRequest("GET", "/bodhi/v1/info");
489
422
  } catch (o) {
490
- const s = o instanceof Error ? o.message : "Connection failed", n = o instanceof T ? o.code : "extension_error";
423
+ const s = o instanceof Error ? o.message : "Connection failed", i = o instanceof T ? o.code : "extension_error";
491
424
  return {
492
425
  status: "not-reachable",
493
426
  version: null,
494
- error: { message: s, type: n }
427
+ error: { message: s, type: i }
495
428
  };
496
429
  }
497
430
  if (e.status >= 400)
@@ -500,30 +433,30 @@ class de {
500
433
  version: null,
501
434
  error: { message: "API error from server", type: "extension_error" }
502
435
  };
503
- const t = e.body, r = t.version || "unknown", i = { deployment: t.deployment ?? null, client_id: t.client_id ?? null };
436
+ const t = e.body, r = t.version || "unknown", n = { deployment: t.deployment ?? null, client_id: t.client_id ?? null };
504
437
  switch (t.status) {
505
438
  case "ready":
506
- return { status: "ready", version: r, error: null, ...i };
439
+ return { status: "ready", version: r, error: null, ...n };
507
440
  case "setup":
508
441
  return {
509
442
  status: "setup",
510
443
  version: r,
511
444
  error: t.error ? { message: t.error.message, type: t.error.type } : { message: "Setup required", type: "extension_error" },
512
- ...i
445
+ ...n
513
446
  };
514
447
  case "resource_admin":
515
448
  return {
516
449
  status: "resource_admin",
517
450
  version: r,
518
451
  error: t.error ? { message: t.error.message, type: t.error.type } : { message: "Resource admin required", type: "extension_error" },
519
- ...i
452
+ ...n
520
453
  };
521
454
  case "error":
522
455
  return {
523
456
  status: "error",
524
457
  version: r,
525
458
  error: t.error ? { message: t.error.message, type: t.error.type } : { message: "Server error", type: "extension_error" },
526
- ...i
459
+ ...n
527
460
  };
528
461
  default:
529
462
  return {
@@ -539,69 +472,69 @@ class de {
539
472
  /**
540
473
  * Generic streaming method
541
474
  */
542
- async *stream(e, t, r, i, o = !0) {
475
+ async *stream(e, t, r, n, o = !0) {
543
476
  const s = this.generateRequestId();
544
477
  this.logger.debug("Starting stream", {
545
478
  method: e,
546
479
  endpoint: t,
547
480
  requestId: s
548
481
  });
549
- const n = chrome.runtime.connect({ name: k }), a = new ReadableStream({
550
- start: (u) => {
551
- n.onMessage.addListener((d) => {
482
+ const i = chrome.runtime.connect({ name: M }), a = new ReadableStream({
483
+ start: (E) => {
484
+ i.onMessage.addListener((d) => {
552
485
  if (d.requestId === s)
553
486
  switch (d.type) {
554
487
  case c.EXT2EXT_CLIENT_STREAM_DONE:
555
- this.logger.debug("Stream complete", { requestId: s }), u.close(), n.disconnect();
488
+ this.logger.debug("Stream complete", { requestId: s }), E.close(), i.disconnect();
556
489
  break;
557
490
  case c.EXT2EXT_CLIENT_STREAM_ERROR:
558
491
  this.logger.error("Stream error", {
559
492
  requestId: s,
560
493
  error: JSON.stringify(d.error)
561
- }), u.error(
494
+ }), E.error(
562
495
  new T(
563
496
  "extension_error",
564
497
  d.error.message
565
498
  )
566
- ), n.disconnect();
499
+ ), i.disconnect();
567
500
  break;
568
501
  case c.EXT2EXT_CLIENT_STREAM_API_ERROR: {
569
- const g = d;
502
+ const u = d;
570
503
  this.logger.error("Stream API error", {
571
504
  requestId: s,
572
- error: g.response.body?.error
573
- }), u.error(
574
- new z(
575
- g.response.status,
576
- g.response.body,
577
- g.response.body?.error?.message || "API error"
505
+ error: u.response.body?.error
506
+ }), E.error(
507
+ new Q(
508
+ u.response.status,
509
+ u.response.body,
510
+ u.response.body?.error?.message || "API error"
578
511
  )
579
- ), n.disconnect();
512
+ ), i.disconnect();
580
513
  break;
581
514
  }
582
515
  case c.EXT2EXT_CLIENT_STREAM_CHUNK: {
583
- const g = d;
584
- Z(g.response) && u.enqueue(g.response.body);
516
+ const u = d;
517
+ te(u.response) && E.enqueue(u.response.body);
585
518
  break;
586
519
  }
587
520
  }
588
- }), n.onDisconnect.addListener(() => {
521
+ }), i.onDisconnect.addListener(() => {
589
522
  this.logger.debug("Port disconnected", { requestId: s });
590
523
  try {
591
- u.error(new T("connection_closed", "Connection closed unexpectedly"));
524
+ E.error(new T("connection_closed", "Connection closed unexpectedly"));
592
525
  } catch {
593
526
  }
594
- }), n.postMessage({
527
+ }), i.postMessage({
595
528
  type: c.EXT2EXT_CLIENT_STREAM_REQUEST,
596
529
  requestId: s,
597
- request: { method: e, endpoint: t, body: r, headers: i, authenticated: o }
530
+ request: { method: e, endpoint: t, body: r, headers: n, authenticated: o }
598
531
  });
599
532
  }
600
533
  }).getReader();
601
534
  try {
602
535
  for (; ; ) {
603
- const { done: u, value: d } = await a.read();
604
- if (u) {
536
+ const { done: E, value: d } = await a.read();
537
+ if (E) {
605
538
  this.logger.debug("Stream iteration complete");
606
539
  break;
607
540
  }
@@ -611,20 +544,86 @@ class de {
611
544
  a.releaseLock();
612
545
  }
613
546
  }
547
+ /**
548
+ * Raw text streaming method - no SSE/JSON parsing
549
+ * Returns status, headers, and async generator of raw text chunks
550
+ */
551
+ async streamText(e, t, r, n, o = !0) {
552
+ const s = this.generateRequestId();
553
+ return new Promise((i, h) => {
554
+ let a, E = !1;
555
+ const d = new ReadableStream({
556
+ start: (g) => {
557
+ a = g;
558
+ }
559
+ }), u = chrome.runtime.connect({ name: O });
560
+ u.onMessage.addListener((g) => {
561
+ if (g.requestId === s)
562
+ switch (g.type) {
563
+ case c.EXT2EXT_CLIENT_STREAM_TEXT_START: {
564
+ E = !0;
565
+ async function* m(U) {
566
+ const C = U.getReader();
567
+ try {
568
+ for (; ; ) {
569
+ const { done: q, value: D } = await C.read();
570
+ if (q) break;
571
+ yield D;
572
+ }
573
+ } finally {
574
+ C.releaseLock();
575
+ }
576
+ }
577
+ i({
578
+ status: g.status,
579
+ headers: g.headers,
580
+ body: m(d)
581
+ });
582
+ break;
583
+ }
584
+ case c.EXT2EXT_CLIENT_STREAM_TEXT_CHUNK:
585
+ a.enqueue(g.chunk);
586
+ break;
587
+ case c.EXT2EXT_CLIENT_STREAM_TEXT_DONE:
588
+ a.close(), u.disconnect();
589
+ break;
590
+ case c.EXT2EXT_CLIENT_STREAM_TEXT_ERROR: {
591
+ const m = l("extension_error", g.error.message);
592
+ E ? a.error(m) : h(m), u.disconnect();
593
+ break;
594
+ }
595
+ }
596
+ }), u.onDisconnect.addListener(() => {
597
+ if (!E)
598
+ h(l("extension_error", "Connection closed unexpectedly"));
599
+ else
600
+ try {
601
+ a.error(
602
+ l("extension_error", "Connection closed unexpectedly")
603
+ );
604
+ } catch {
605
+ }
606
+ }), u.postMessage({
607
+ type: c.EXT2EXT_CLIENT_STREAM_TEXT_REQUEST,
608
+ requestId: s,
609
+ request: { method: e, endpoint: t, body: r, headers: n, authenticated: o }
610
+ });
611
+ });
612
+ }
614
613
  // ============================================================================
615
614
  // OpenAI-Compatible Namespaced API
616
615
  // ============================================================================
617
616
  get chat() {
618
- return this._chat ??= new F(this);
617
+ return this._chat ??= new H(this);
619
618
  }
620
619
  get models() {
621
- return this._models ??= new G(this);
620
+ return this._models ??= new W(this);
622
621
  }
623
622
  get embeddings() {
624
- return this._embeddings ??= new Q(this);
623
+ return this._embeddings ??= new J(this);
625
624
  }
626
625
  get mcps() {
627
- return this._mcps ??= new H(this);
626
+ return this._mcps ??= new Y(this);
628
627
  }
629
628
  // ============================================================================
630
629
  // Access Request Methods
@@ -648,7 +647,7 @@ class de {
648
647
  );
649
648
  }
650
649
  async pollAccessRequestStatus(e, t) {
651
- return L(
650
+ return k(
652
651
  (r) => this.getAccessRequestStatus(r),
653
652
  e,
654
653
  t
@@ -671,25 +670,27 @@ class de {
671
670
  };
672
671
  }
673
672
  }
674
- class me extends J {
673
+ class fe extends j {
675
674
  constructor(e, t, r) {
676
- const i = t || {}, o = {
677
- basePath: i.basePath || "/",
678
- authServerUrl: i.authServerUrl || "https://id.getbodhi.app/realms/bodhi",
679
- logLevel: i.logLevel || "warn",
680
- apiTimeoutMs: i.apiTimeoutMs,
681
- initParams: i.initParams
675
+ const n = t || {}, o = {
676
+ basePath: n.basePath || "/",
677
+ authServerUrl: n.authServerUrl || "https://id.getbodhi.app/realms/bodhi",
678
+ logLevel: n.logLevel || "warn",
679
+ apiTimeoutMs: n.apiTimeoutMs,
680
+ storage: n.storage,
681
+ initialTokens: n.initialTokens,
682
+ initParams: n.initParams
682
683
  };
683
684
  super(e, o, r);
684
685
  }
685
686
  createLogger(e) {
686
- return new w("ExtUIClient", e.logLevel);
687
+ return new x("ExtUIClient", e.logLevel);
687
688
  }
688
689
  createStoragePrefix(e) {
689
- return N(e.basePath, v.EXT);
690
+ return X(e.basePath, N.EXT);
690
691
  }
691
692
  createExtClient(e, t) {
692
- return new de(
693
+ return new _e(
693
694
  {
694
695
  authClientId: this.authClientId,
695
696
  logLevel: e.logLevel,
@@ -700,24 +701,26 @@ class me extends J {
700
701
  );
701
702
  }
702
703
  createDirectClient(e, t, r) {
703
- return new ue(
704
+ return new ge(
704
705
  {
705
706
  authClientId: e,
706
707
  authServerUrl: t.authServerUrl,
707
708
  logLevel: t.logLevel,
708
709
  basePath: t.basePath,
709
- apiTimeoutMs: t.apiTimeoutMs
710
+ apiTimeoutMs: t.apiTimeoutMs,
711
+ storage: t.storage,
712
+ initialTokens: t.initialTokens
710
713
  },
711
714
  r
712
715
  );
713
716
  }
714
717
  }
715
- const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckljjghmjbf"], R = "production", p = class p {
718
+ const pe = ["ggedphdcbekjlomjaidbajglgihbeaon"], me = ["bjdjhiombmfbcoeojijpfckljjghmjbf"], y = "production", S = class S {
716
719
  // ============================================================================
717
720
  // Constructor
718
721
  // ============================================================================
719
722
  constructor(e, t) {
720
- this.isAuthenticating = !1, this.state = "setup", this.listenersInitialized = !1, this.refreshPromise = null, this.activeStreamPorts = /* @__PURE__ */ new Map(), this.authClientId = e, this.authServerUrl = t?.authServerUrl || "https://id.getbodhi.app/realms/bodhi", this.extensionId = t?.extensionId, this.logger = new w("BodhiExtClient", t?.logLevel || "warn"), this.attempts = t?.attempts ?? ie, this.attemptWaitMs = t?.attemptWaitMs ?? ne, this.attemptTimeout = t?.attemptTimeout ?? ae, this.authEndpoints = {
723
+ this.isAuthenticating = !1, this.state = "setup", this.listenersInitialized = !1, this.refreshPromise = null, this.activeStreamPorts = /* @__PURE__ */ new Map(), this.authClientId = e, this.authServerUrl = t?.authServerUrl || "https://id.getbodhi.app/realms/bodhi", this.extensionId = t?.extensionId, this.logger = new x("BodhiExtClient", t?.logLevel || "warn"), this.attempts = t?.attempts ?? he, this.attemptWaitMs = t?.attemptWaitMs ?? Ee, this.attemptTimeout = t?.attemptTimeout ?? ue, this.authEndpoints = {
721
724
  authorize: `${this.authServerUrl}/protocol/openid-connect/auth`,
722
725
  token: `${this.authServerUrl}/protocol/openid-connect/token`,
723
726
  userinfo: `${this.authServerUrl}/protocol/openid-connect/userinfo`,
@@ -735,11 +738,11 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
735
738
  }
736
739
  static generateCodeVerifier() {
737
740
  const e = new Uint8Array(32);
738
- return crypto.getRandomValues(e), p.base64UrlEncode(e.buffer);
741
+ return crypto.getRandomValues(e), S.base64UrlEncode(e.buffer);
739
742
  }
740
743
  static async generateCodeChallenge(e) {
741
- const r = new TextEncoder().encode(e), i = await crypto.subtle.digest("SHA-256", r);
742
- return p.base64UrlEncode(i);
744
+ const r = new TextEncoder().encode(e), n = await crypto.subtle.digest("SHA-256", r);
745
+ return S.base64UrlEncode(n);
743
746
  }
744
747
  // ============================================================================
745
748
  // State Management
@@ -758,7 +761,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
758
761
  * Get extension IDs for current environment
759
762
  */
760
763
  getExtensionIdsForEnvironment() {
761
- const t = R !== "production" ? Ee : le;
764
+ const t = y !== "production" ? pe : me;
762
765
  return this.logger.info("[Ext2Ext/Registry] Environment: production"), this.logger.debug("[Ext2Ext/Registry] Using extension IDs:", t), t;
763
766
  }
764
767
  /**
@@ -768,7 +771,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
768
771
  return this.logger.debug(
769
772
  `[Ext2Ext/Discovery] Pinging extension: ${e} with timeout ${this.attemptTimeout}ms`
770
773
  ), new Promise((t, r) => {
771
- const i = setTimeout(() => {
774
+ const n = setTimeout(() => {
772
775
  this.logger.debug(`[Ext2Ext/Discovery] Timeout waiting for extension ${e}`), r(new Error("Timeout"));
773
776
  }, this.attemptTimeout);
774
777
  try {
@@ -780,7 +783,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
780
783
  }
781
784
  };
782
785
  this.logger.debug(`[Ext2Ext/Discovery] Sending message to ${e}:`, o), chrome.runtime.sendMessage(e, o, (s) => {
783
- if (clearTimeout(i), chrome.runtime.lastError) {
786
+ if (clearTimeout(n), chrome.runtime.lastError) {
784
787
  this.logger.error(
785
788
  `[Ext2Ext/Discovery] Error from extension ${e}:`,
786
789
  chrome.runtime.lastError.message
@@ -788,14 +791,14 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
788
791
  return;
789
792
  }
790
793
  this.logger.debug(`[Ext2Ext/Discovery] Response from ${e}:`, s);
791
- const n = s;
792
- n && n.type === _.EXT_RESPONSE ? (this.logger.debug(`[Ext2Ext/Discovery] ✓ Extension ${e} responded`), t(!0)) : (this.logger.error(
794
+ const i = s;
795
+ i && i.type === _.EXT_RESPONSE ? (this.logger.debug(`[Ext2Ext/Discovery] ✓ Extension ${e} responded`), t(!0)) : (this.logger.error(
793
796
  `[Ext2Ext/Discovery] Invalid response from ${e}:`,
794
797
  s
795
798
  ), r(new Error("Invalid response")));
796
799
  });
797
800
  } catch (o) {
798
- this.logger.error(`[Ext2Ext/Discovery] Exception pinging ${e}:`, o), clearTimeout(i), r(o);
801
+ this.logger.error(`[Ext2Ext/Discovery] Exception pinging ${e}:`, o), clearTimeout(n), r(o);
799
802
  }
800
803
  });
801
804
  }
@@ -810,9 +813,9 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
810
813
  * @param params Resolved discovery params
811
814
  */
812
815
  async discoverBodhiExtension(e) {
813
- const { attempts: t, attemptWaitMs: r, attemptTimeout: i } = e;
816
+ const { attempts: t, attemptWaitMs: r, attemptTimeout: n } = e;
814
817
  this.logger.info(
815
- `[Ext2Ext/Discovery] Starting discovery: ${t} attempts per ID, ${i}ms timeout, ${r}ms between attempts`
818
+ `[Ext2Ext/Discovery] Starting discovery: ${t} attempts per ID, ${n}ms timeout, ${r}ms between attempts`
816
819
  );
817
820
  const o = this.getExtensionIdsForEnvironment();
818
821
  this.logger.debug(
@@ -829,9 +832,9 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
829
832
  success: !0,
830
833
  extensionId: h
831
834
  };
832
- } catch (u) {
835
+ } catch (E) {
833
836
  this.logger.debug(
834
- `[Ext2Ext/Discovery] Attempt ${a} failed for ${h}: ${u instanceof Error ? u.message : "Unknown error"}`
837
+ `[Ext2Ext/Discovery] Attempt ${a} failed for ${h}: ${E instanceof Error ? E.message : "Unknown error"}`
835
838
  ), a < t && await this.sleep(r);
836
839
  }
837
840
  }
@@ -839,10 +842,10 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
839
842
  `[Ext2Ext/Discovery] ✗ Not found: ${h} after ${t} attempts`
840
843
  );
841
844
  }
842
- const s = o.join(", "), n = `Extension not found. Tried ${o.length} IDs with ${t} attempts each: ${s}`;
843
- return this.logger.error(`[Ext2Ext/Discovery] ${n}`), {
845
+ const s = o.join(", "), i = `Extension not found. Tried ${o.length} IDs with ${t} attempts each: ${s}`;
846
+ return this.logger.error(`[Ext2Ext/Discovery] ${i}`), {
844
847
  success: !1,
845
- error: n
848
+ error: i
846
849
  };
847
850
  }
848
851
  // ============================================================================
@@ -856,7 +859,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
856
859
  this.logger.debug("[BodhiExtClient] Listeners already initialized, skipping");
857
860
  return;
858
861
  }
859
- this.listenersInitialized = !0, chrome.runtime.onMessage.addListener((e, t, r) => e.type !== c.EXT2EXT_CLIENT_REQUEST && e.type !== c.EXT2EXT_CLIENT_API_REQUEST ? !1 : this.state !== "ready" && !(e.type === c.EXT2EXT_CLIENT_REQUEST && e.request.action === m.DISCOVER_EXTENSION) ? (e.type === c.EXT2EXT_CLIENT_REQUEST ? r({
862
+ this.listenersInitialized = !0, chrome.runtime.onMessage.addListener((e, t, r) => e.type !== c.EXT2EXT_CLIENT_REQUEST && e.type !== c.EXT2EXT_CLIENT_API_REQUEST ? !1 : this.state !== "ready" && !(e.type === c.EXT2EXT_CLIENT_REQUEST && e.request.action === p.DISCOVER_EXTENSION) ? (e.type === c.EXT2EXT_CLIENT_REQUEST ? r({
860
863
  type: c.EXT2EXT_CLIENT_RESPONSE,
861
864
  requestId: e.requestId,
862
865
  response: {
@@ -873,30 +876,19 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
873
876
  type: "NOT_INITIALIZED"
874
877
  }
875
878
  }), !0) : (this.logger.debug(`[BodhiExtClient] Processing message.type=${e.type}`), (async () => {
876
- const i = await this.handleAction(e);
877
- r(i);
878
- })(), !0)), chrome.runtime.onConnect.addListener((e) => {
879
- if (e.name !== k) {
880
- this.logger.debug("[BodhiExtClient] Ignoring port with name:", e.name);
881
- return;
882
- }
883
- this.logger.info("[BodhiExtClient] Streaming port connected"), e.onMessage.addListener(async (t) => {
884
- if (t.type !== c.EXT2EXT_CLIENT_STREAM_REQUEST) {
885
- this.logger.warn("[BodhiExtClient] Unknown stream message type:", t.type), e.postMessage({
886
- type: c.EXT2EXT_CLIENT_STREAM_ERROR,
887
- requestId: t.requestId,
888
- error: {
889
- message: "Unknown stream message type",
890
- type: "extension_error"
891
- }
892
- });
893
- return;
894
- }
895
- await this.handleStreamRequest(e, t);
896
- }), e.onDisconnect.addListener(() => {
897
- this.logger.info("[BodhiExtClient] Streaming port disconnected");
898
- });
899
- }), this.logger.info("[BodhiExtClient] Streaming listeners initialized");
879
+ const n = await this.handleAction(e);
880
+ r(n);
881
+ })(), !0)), this.registerStreamPortListener(
882
+ M,
883
+ c.EXT2EXT_CLIENT_STREAM_REQUEST,
884
+ c.EXT2EXT_CLIENT_STREAM_ERROR,
885
+ (e, t) => this.handleStreamRequest(e, t)
886
+ ), this.registerStreamPortListener(
887
+ O,
888
+ c.EXT2EXT_CLIENT_STREAM_TEXT_REQUEST,
889
+ c.EXT2EXT_CLIENT_STREAM_TEXT_ERROR,
890
+ (e, t) => this.handleStreamTextRequest(e, t)
891
+ ), this.logger.info("[BodhiExtClient] Streaming listeners initialized");
900
892
  }
901
893
  /**
902
894
  * Initialize client: setup listeners and discover bodhi-browser-ext
@@ -968,7 +960,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
968
960
  Authorization: `Bearer ${o}`
969
961
  }, this.logger.debug("[BodhiExtClient] Injected auth token for authenticated request");
970
962
  }
971
- const i = await this.sendApiRequest(
963
+ const n = await this.sendApiRequest(
972
964
  e.request.method,
973
965
  e.request.endpoint,
974
966
  e.request.body,
@@ -977,7 +969,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
977
969
  return {
978
970
  type: c.EXT2EXT_CLIENT_API_RESPONSE,
979
971
  requestId: t,
980
- response: i
972
+ response: n
981
973
  };
982
974
  } catch (r) {
983
975
  return this.logger.error("[BodhiExtClient] API request failed:", r), {
@@ -997,53 +989,53 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
997
989
  * @returns Action response message (success or error)
998
990
  */
999
991
  async handleExtClientRequest(e) {
1000
- const { requestId: t, request: r } = e, { action: i, params: o } = r;
1001
- this.logger.debug(`[BodhiExtClient] Handling action: ${i}`);
992
+ const { requestId: t, request: r } = e, { action: n, params: o } = r;
993
+ this.logger.debug(`[BodhiExtClient] Handling action: ${n}`);
1002
994
  try {
1003
995
  let s = {};
1004
- switch (i) {
1005
- case m.DISCOVER_EXTENSION: {
1006
- const n = o;
1007
- await this.init(n), this.logger.info("[BodhiExtClient] Discovery successful:", {
996
+ switch (n) {
997
+ case p.DISCOVER_EXTENSION: {
998
+ const i = o;
999
+ await this.init(i), this.logger.info("[BodhiExtClient] Discovery successful:", {
1008
1000
  extensionId: this.extensionId,
1009
- environment: R
1001
+ environment: y
1010
1002
  }), s = {
1011
1003
  extensionId: this.extensionId,
1012
- environment: R
1004
+ environment: y
1013
1005
  };
1014
1006
  break;
1015
1007
  }
1016
- case m.SET_EXTENSION_ID: {
1017
- const { extensionId: n } = o;
1018
- this.extensionId = n, this.state = "ready", this.logger.info("[BodhiExtClient] Extension ID set:", { extensionId: n }), s = { success: !0 };
1008
+ case p.SET_EXTENSION_ID: {
1009
+ const { extensionId: i } = o;
1010
+ this.extensionId = i, this.state = "ready", this.logger.info("[BodhiExtClient] Extension ID set:", { extensionId: i }), s = { success: !0 };
1019
1011
  break;
1020
1012
  }
1021
- case m.GET_EXTENSION_ID: {
1022
- const n = await this.sendExtRequestRaw(j.GET_EXTENSION_ID, o);
1023
- return x(n.response) ? {
1013
+ case p.GET_EXTENSION_ID: {
1014
+ const i = await this.sendExtRequestRaw(re.GET_EXTENSION_ID, o);
1015
+ return I(i.response) ? {
1024
1016
  type: c.EXT2EXT_CLIENT_RESPONSE,
1025
1017
  requestId: t,
1026
1018
  response: {
1027
1019
  error: {
1028
- message: n.response.error.message || `Extension request failed to get extension ID: ${JSON.stringify(n.response)}`,
1029
- type: n.response.error.type
1020
+ message: i.response.error.message || `Extension request failed to get extension ID: ${JSON.stringify(i.response)}`,
1021
+ type: i.response.error.type
1030
1022
  }
1031
1023
  }
1032
1024
  } : {
1033
1025
  type: c.EXT2EXT_CLIENT_RESPONSE,
1034
1026
  requestId: t,
1035
- response: n.response
1027
+ response: i.response
1036
1028
  };
1037
1029
  }
1038
- case m.LOGIN: {
1039
- const n = o;
1040
- await this.login(n), this.broadcastAuthStateChange();
1030
+ case p.LOGIN: {
1031
+ const i = o;
1032
+ await this.login(i), this.broadcastAuthStateChange();
1041
1033
  break;
1042
1034
  }
1043
- case m.LOGOUT:
1035
+ case p.LOGOUT:
1044
1036
  await this.logout(), this.broadcastAuthStateChange();
1045
1037
  break;
1046
- case m.GET_AUTH_STATE:
1038
+ case p.GET_AUTH_STATE:
1047
1039
  s = { authState: await this.getAuthState() };
1048
1040
  break;
1049
1041
  default:
@@ -1051,7 +1043,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1051
1043
  type: c.EXT2EXT_CLIENT_RESPONSE,
1052
1044
  requestId: t,
1053
1045
  response: {
1054
- error: { message: `Unknown action: ${i}`, type: "UNKNOWN_ACTION" }
1046
+ error: { message: `Unknown action: ${n}`, type: "UNKNOWN_ACTION" }
1055
1047
  }
1056
1048
  };
1057
1049
  }
@@ -1109,13 +1101,13 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1109
1101
  if (!this.extensionId)
1110
1102
  throw new Error("Extension not discovered. Please detect Bodhi extension before login.");
1111
1103
  e?.flowType === "redirect" && this.logger.warn("Extension mode does not support redirect flow type; using popup instead");
1112
- const r = e?.userRole ?? "scope_user_user", i = new P(this.authClientId).requestedRole(r).flowType("popup");
1113
- e?.requested && i.requested(e.requested);
1114
- const o = i.build(), s = await this.requestAccess(o), { id: n, review_url: h } = X(s);
1104
+ const r = e?.userRole ?? "scope_user_user", n = new v(this.authClientId).requestedRole(r).flowType("popup");
1105
+ e?.requested && n.requested(e.requested);
1106
+ const o = n.build(), s = await this.requestAccess(o), { id: i, review_url: h } = L(s);
1115
1107
  await chrome.tabs.create({ url: h });
1116
- const a = await this.pollAccessRequestStatus(n, {
1117
- intervalMs: e?.pollIntervalMs ?? O,
1118
- timeoutMs: e?.pollTimeoutMs ?? b
1108
+ const a = await this.pollAccessRequestStatus(i, {
1109
+ intervalMs: e?.pollIntervalMs ?? b,
1110
+ timeoutMs: e?.pollTimeoutMs ?? P
1119
1111
  });
1120
1112
  if (a.status !== "approved")
1121
1113
  throw l("auth_error", `Access request ${a.status}`);
@@ -1133,7 +1125,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1133
1125
  async exchangeCodeForTokens(e) {
1134
1126
  if ((await this.getAuthState()).status === "authenticated")
1135
1127
  return;
1136
- const { codeVerifier: r } = await chrome.storage.session.get("codeVerifier"), i = chrome.identity.getRedirectURL("callback"), o = await fetch(this.authEndpoints.token, {
1128
+ const { codeVerifier: r } = await chrome.storage.session.get("codeVerifier"), n = chrome.identity.getRedirectURL("callback"), o = await fetch(this.authEndpoints.token, {
1137
1129
  method: "POST",
1138
1130
  headers: {
1139
1131
  "Content-Type": "application/x-www-form-urlencoded"
@@ -1141,14 +1133,14 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1141
1133
  body: new URLSearchParams({
1142
1134
  grant_type: "authorization_code",
1143
1135
  code: e,
1144
- redirect_uri: i,
1136
+ redirect_uri: n,
1145
1137
  client_id: this.authClientId,
1146
1138
  code_verifier: r
1147
1139
  })
1148
1140
  });
1149
1141
  if (!o.ok) {
1150
- const n = await o.text();
1151
- throw new Error(`Token exchange failed: ${o.status} ${n}`);
1142
+ const i = await o.text();
1143
+ throw new Error(`Token exchange failed: ${o.status} ${i}`);
1152
1144
  }
1153
1145
  const s = await o.json();
1154
1146
  await this.storeTokens({
@@ -1165,7 +1157,15 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1165
1157
  async getAuthState() {
1166
1158
  const e = await this._getAccessTokenRaw();
1167
1159
  if (!e)
1168
- return { status: "unauthenticated", user: null, accessToken: null, error: null };
1160
+ return {
1161
+ status: "unauthenticated",
1162
+ user: null,
1163
+ accessToken: null,
1164
+ error: null,
1165
+ refreshToken: null,
1166
+ expiresAt: null,
1167
+ isTokenRefresh: !1
1168
+ };
1169
1169
  try {
1170
1170
  const t = this.parseJwt(e);
1171
1171
  return {
@@ -1179,10 +1179,21 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1179
1179
  preferred_username: t.preferred_username
1180
1180
  },
1181
1181
  accessToken: e,
1182
- error: null
1182
+ error: null,
1183
+ refreshToken: null,
1184
+ expiresAt: null,
1185
+ isTokenRefresh: !1
1183
1186
  };
1184
1187
  } catch (t) {
1185
- return this.logger.error("Failed to parse token:", t), { status: "unauthenticated", user: null, accessToken: null, error: null };
1188
+ return this.logger.error("Failed to parse token:", t), {
1189
+ status: "unauthenticated",
1190
+ user: null,
1191
+ accessToken: null,
1192
+ error: null,
1193
+ refreshToken: null,
1194
+ expiresAt: null,
1195
+ isTokenRefresh: !1
1196
+ };
1186
1197
  }
1187
1198
  }
1188
1199
  /**
@@ -1226,21 +1237,21 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1226
1237
  );
1227
1238
  }
1228
1239
  async pollAccessRequestStatus(e, t) {
1229
- return L(
1240
+ return k(
1230
1241
  (r) => this.getAccessRequestStatus(r),
1231
1242
  e,
1232
1243
  t
1233
1244
  );
1234
1245
  }
1235
1246
  async performOAuthPkce(e) {
1236
- const t = p.generateCodeVerifier(), r = await p.generateCodeChallenge(t), i = p.generateCodeVerifier();
1247
+ const t = S.generateCodeVerifier(), r = await S.generateCodeChallenge(t), n = S.generateCodeVerifier();
1237
1248
  await chrome.storage.session.set({
1238
1249
  codeVerifier: t,
1239
- state: i,
1250
+ state: n,
1240
1251
  authInProgress: !0
1241
1252
  });
1242
1253
  const o = chrome.identity.getRedirectURL("callback"), s = new URL(this.authEndpoints.authorize);
1243
- return s.searchParams.set("client_id", this.authClientId), s.searchParams.set("response_type", "code"), s.searchParams.set("redirect_uri", o), s.searchParams.set("scope", e), s.searchParams.set("code_challenge", r), s.searchParams.set("code_challenge_method", "S256"), s.searchParams.set("state", i), new Promise((n, h) => {
1254
+ return s.searchParams.set("client_id", this.authClientId), s.searchParams.set("response_type", "code"), s.searchParams.set("redirect_uri", o), s.searchParams.set("scope", e), s.searchParams.set("code_challenge", r), s.searchParams.set("code_challenge_method", "S256"), s.searchParams.set("state", n), new Promise((i, h) => {
1244
1255
  chrome.identity.launchWebAuthFlow(
1245
1256
  { url: s.toString(), interactive: !0 },
1246
1257
  async (a) => {
@@ -1253,8 +1264,8 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1253
1264
  return;
1254
1265
  }
1255
1266
  try {
1256
- const u = new URL(a), d = u.searchParams.get("code"), g = u.searchParams.get("state"), { state: S } = await chrome.storage.session.get("state");
1257
- if (g !== S) {
1267
+ const E = new URL(a), d = E.searchParams.get("code"), u = E.searchParams.get("state"), { state: g } = await chrome.storage.session.get("state");
1268
+ if (u !== g) {
1258
1269
  await chrome.storage.session.remove(["codeVerifier", "state"]), h(l("oauth_error", "State mismatch"));
1259
1270
  return;
1260
1271
  }
@@ -1263,12 +1274,12 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1263
1274
  return;
1264
1275
  }
1265
1276
  await this.exchangeCodeForTokens(d), await chrome.storage.session.remove(["codeVerifier", "state"]);
1266
- const E = await this.getAuthState();
1267
- if (E.status !== "authenticated")
1277
+ const m = await this.getAuthState();
1278
+ if (m.status !== "authenticated")
1268
1279
  throw l("oauth_error", "Login failed");
1269
- n(E);
1270
- } catch (u) {
1271
- await chrome.storage.session.remove(["codeVerifier", "state"]), h(u);
1280
+ i(m);
1281
+ } catch (E) {
1282
+ await chrome.storage.session.remove(["codeVerifier", "state"]), h(E);
1272
1283
  }
1273
1284
  }
1274
1285
  );
@@ -1284,7 +1295,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1284
1295
  */
1285
1296
  async sendExtRequest(e, t) {
1286
1297
  const r = await this.sendExtRequestRaw(e, t);
1287
- if (x(r.response))
1298
+ if (I(r.response))
1288
1299
  throw this.logger.error("[BodhiExtClient] Extension error:", r.response.error), new Error(
1289
1300
  r.response.error.message || `Extension request failed: ${JSON.stringify(r.response)}`
1290
1301
  );
@@ -1298,7 +1309,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1298
1309
  * @param headers Optional headers
1299
1310
  * @returns API response from LLM server via bodhi-browser-ext
1300
1311
  */
1301
- async sendApiRequest(e, t, r, i) {
1312
+ async sendApiRequest(e, t, r, n) {
1302
1313
  if (!this.extensionId)
1303
1314
  throw new T(
1304
1315
  "not_initialized",
@@ -1315,10 +1326,10 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1315
1326
  method: e,
1316
1327
  endpoint: t,
1317
1328
  body: r,
1318
- headers: i
1329
+ headers: n
1319
1330
  }
1320
1331
  };
1321
- return this.logger.debug(`[BodhiExtClient] Request ID: ${o}, Extension: ${this.extensionId}`), new Promise((n, h) => {
1332
+ return this.logger.debug(`[BodhiExtClient] Request ID: ${o}, Extension: ${this.extensionId}`), new Promise((i, h) => {
1322
1333
  try {
1323
1334
  chrome.runtime.sendMessage(this.extensionId, s, (a) => {
1324
1335
  if (chrome.runtime.lastError) {
@@ -1339,7 +1350,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1339
1350
  }
1340
1351
  a.type === _.API_RESPONSE && a.requestId === o ? "error" in a ? (this.logger.error(`[BodhiExtClient] API error for ${o}:`, a.error), h(
1341
1352
  new T(a.error.type || "extension_error", a.error.message)
1342
- )) : (this.logger.debug(`[BodhiExtClient] ✓ Valid API_RESPONSE for ${o}`), n(a.response)) : (this.logger.error(
1353
+ )) : (this.logger.debug(`[BodhiExtClient] ✓ Valid API_RESPONSE for ${o}`), i(a.response)) : (this.logger.error(
1343
1354
  `[BodhiExtClient] Invalid response format for ${o}:`,
1344
1355
  a
1345
1356
  ), h(new T("extension_error", "Invalid response format")));
@@ -1365,7 +1376,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1365
1376
  `[BodhiExtClient] Sending EXT_REQUEST (raw): action=${e}`,
1366
1377
  t ? { params: t } : ""
1367
1378
  );
1368
- const r = crypto.randomUUID(), i = {
1379
+ const r = crypto.randomUUID(), n = {
1369
1380
  type: _.EXT_REQUEST,
1370
1381
  requestId: r,
1371
1382
  request: {
@@ -1375,7 +1386,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1375
1386
  };
1376
1387
  return this.logger.debug(`[BodhiExtClient] Request ID: ${r}, Extension: ${this.extensionId}`), new Promise((o, s) => {
1377
1388
  try {
1378
- chrome.runtime.sendMessage(this.extensionId, i, (n) => {
1389
+ chrome.runtime.sendMessage(this.extensionId, n, (i) => {
1379
1390
  if (chrome.runtime.lastError) {
1380
1391
  this.logger.error(
1381
1392
  `[BodhiExtClient] Chrome runtime error for request ${r}:`,
@@ -1383,135 +1394,116 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1383
1394
  ), s(new Error(chrome.runtime.lastError.message));
1384
1395
  return;
1385
1396
  }
1386
- if (this.logger.debug(`[BodhiExtClient] Response for request ${r}:`, n), !n) {
1397
+ if (this.logger.debug(`[BodhiExtClient] Response for request ${r}:`, i), !i) {
1387
1398
  this.logger.error(`[BodhiExtClient] No response received for request ${r}`), s(new Error("No response from extension"));
1388
1399
  return;
1389
1400
  }
1390
- n.type === _.EXT_RESPONSE && n.requestId === r ? (this.logger.debug(`[BodhiExtClient] ✓ Valid EXT_RESPONSE for ${r}`), o(n)) : (this.logger.error(
1401
+ i.type === _.EXT_RESPONSE && i.requestId === r ? (this.logger.debug(`[BodhiExtClient] ✓ Valid EXT_RESPONSE for ${r}`), o(i)) : (this.logger.error(
1391
1402
  `[BodhiExtClient] Invalid response format for ${r}:`,
1392
- n
1403
+ i
1393
1404
  ), s(new T("extension_error", "Invalid response format")));
1394
1405
  });
1395
- } catch (n) {
1396
- this.logger.error(`[BodhiExtClient] Exception sending message for ${r}:`, n), s(n);
1406
+ } catch (i) {
1407
+ this.logger.error(`[BodhiExtClient] Exception sending message for ${r}:`, i), s(i);
1397
1408
  }
1398
1409
  });
1399
1410
  }
1400
1411
  /**
1401
- * Handle streaming request from UI port
1402
- * Connects to bodhi-browser-ext and forwards chunks directly to UI port
1403
- * @param uiPort Port connected from UI
1404
- * @param message Stream request message from UI
1412
+ * Register a chrome.runtime.onConnect listener for a streaming port.
1413
+ * Validates port name and message type, then delegates to handler.
1405
1414
  */
1406
- async handleStreamRequest(e, t) {
1407
- const { requestId: r, request: i } = t, { method: o, endpoint: s, body: n, headers: h, authenticated: a } = i;
1408
- this.logger.debug("[BodhiExtClient] Processing stream request:", {
1409
- requestId: r,
1410
- method: o,
1411
- endpoint: s,
1412
- authenticated: a
1413
- }), this.extensionId || e.postMessage({
1414
- type: c.EXT2EXT_CLIENT_STREAM_ERROR,
1415
- requestId: r,
1416
- error: {
1417
- message: this.createErrorClientNotInitialized(t),
1418
- type: "extension_error"
1419
- }
1415
+ registerStreamPortListener(e, t, r, n) {
1416
+ chrome.runtime.onConnect.addListener((o) => {
1417
+ o.name === e && (this.logger.info(`[BodhiExtClient] Port connected: ${e}`), o.onMessage.addListener(async (s) => {
1418
+ if (s.type !== t) {
1419
+ this.logger.warn(`[BodhiExtClient] Unknown message type on ${e}:`, s.type), o.postMessage({
1420
+ type: r,
1421
+ requestId: s.requestId,
1422
+ error: { message: "Unknown message type", type: "extension_error" }
1423
+ });
1424
+ return;
1425
+ }
1426
+ await n(o, s);
1427
+ }), o.onDisconnect.addListener(() => {
1428
+ this.logger.info(`[BodhiExtClient] Port disconnected: ${e}`);
1429
+ }));
1420
1430
  });
1431
+ }
1432
+ /**
1433
+ * Generic stream relay: validates auth, connects to bodhi-browser-ext,
1434
+ * sets up timeout/disconnect handling, and delegates message forwarding
1435
+ * to the onBodhiMessage callback.
1436
+ *
1437
+ * @param onBodhiMessage Called for each message from bodhi-browser-ext.
1438
+ * Returns true if the stream is complete (triggers cleanup).
1439
+ */
1440
+ async handleGenericStreamRelay(e, t, r, n, o, s, i) {
1441
+ if (this.logger.debug("[BodhiExtClient] Processing stream relay:", {
1442
+ requestId: t,
1443
+ method: r.method,
1444
+ endpoint: r.endpoint,
1445
+ bodhiPortName: n
1446
+ }), !this.extensionId) {
1447
+ e.postMessage({
1448
+ type: s,
1449
+ requestId: t,
1450
+ error: { message: "Client not initialized (no extensionId)", type: "extension_error" }
1451
+ });
1452
+ return;
1453
+ }
1421
1454
  try {
1422
- let u = { ...h };
1423
- if (a !== !1) {
1424
- const E = await this._getAccessTokenRaw();
1425
- if (!E) {
1455
+ let h = { ...r.headers };
1456
+ if (r.authenticated !== !1) {
1457
+ const u = await this._getAccessTokenRaw();
1458
+ if (!u) {
1426
1459
  e.postMessage({
1427
- type: c.EXT2EXT_CLIENT_STREAM_ERROR,
1428
- requestId: r,
1429
- error: {
1430
- message: "Not authenticated. Please log in first.",
1431
- type: "extension_error"
1432
- }
1460
+ type: s,
1461
+ requestId: t,
1462
+ error: { message: "Not authenticated. Please log in first.", type: "extension_error" }
1433
1463
  });
1434
1464
  return;
1435
1465
  }
1436
- u = {
1437
- ...u,
1438
- Authorization: `Bearer ${E}`
1439
- }, this.logger.debug("[BodhiExtClient] Injected auth token for authenticated request");
1466
+ h = { ...h, Authorization: `Bearer ${u}` }, this.logger.debug("[BodhiExtClient] Injected auth token for stream relay");
1440
1467
  }
1441
- const d = chrome.runtime.connect(this.extensionId, {
1442
- name: ee
1443
- });
1444
- this.activeStreamPorts.set(r, d);
1445
- const g = setTimeout(() => {
1446
- this.activeStreamPorts.has(r) && (this.logger.error(`[BodhiExtClient] Stream timeout for ${r}`), e.postMessage({
1447
- type: c.EXT2EXT_CLIENT_STREAM_ERROR,
1448
- requestId: r,
1449
- error: {
1450
- message: "Stream request timed out",
1451
- type: "timeout_error"
1452
- }
1453
- }), this.cleanupStreamPort(r));
1454
- }, p.STREAM_TIMEOUT);
1455
- d.onMessage.addListener((E) => {
1456
- if (te(E)) {
1457
- const I = E.response, q = I.body;
1458
- I.status >= 400 ? e.postMessage({
1459
- type: c.EXT2EXT_CLIENT_STREAM_API_ERROR,
1460
- requestId: r,
1461
- response: I
1462
- }) : q?.done ? (e.postMessage({
1463
- type: c.EXT2EXT_CLIENT_STREAM_DONE,
1464
- requestId: r
1465
- }), this.logger.info(`[BodhiExtClient] Stream complete for ${r}`), clearTimeout(g), this.cleanupStreamPort(r)) : e.postMessage({
1466
- type: c.EXT2EXT_CLIENT_STREAM_CHUNK,
1467
- requestId: r,
1468
- response: I
1469
- });
1470
- } else re(E) ? (this.logger.error(
1471
- `[BodhiExtClient] Stream API error for ${r}: ${E.response.status}`
1472
- ), e.postMessage({
1473
- type: c.EXT2EXT_CLIENT_STREAM_API_ERROR,
1474
- requestId: r,
1475
- response: E.response
1476
- })) : se(E) && (this.logger.error(
1477
- `[BodhiExtClient] Stream error for ${r}:`,
1478
- E.error.message
1479
- ), e.postMessage({
1480
- type: c.EXT2EXT_CLIENT_STREAM_ERROR,
1481
- requestId: r,
1482
- error: {
1483
- message: `stream error: ${JSON.stringify(E)}`,
1484
- type: "extension_error"
1485
- }
1486
- }), clearTimeout(g), this.cleanupStreamPort(r));
1487
- }), d.onDisconnect.addListener(() => {
1488
- clearTimeout(g), this.activeStreamPorts.has(r) && (this.logger.error(`[BodhiExtClient] Bodhi port disconnected for ${r}`), e.postMessage({
1489
- type: c.EXT2EXT_CLIENT_STREAM_ERROR,
1490
- requestId: r,
1468
+ const a = chrome.runtime.connect(this.extensionId, { name: n });
1469
+ this.activeStreamPorts.set(t, a);
1470
+ const E = setTimeout(() => {
1471
+ this.activeStreamPorts.has(t) && (this.logger.error(`[BodhiExtClient] Stream timeout for ${t}`), e.postMessage({
1472
+ type: s,
1473
+ requestId: t,
1474
+ error: { message: "Stream request timed out", type: "timeout_error" }
1475
+ }), this.cleanupStreamPort(t));
1476
+ }, S.STREAM_TIMEOUT);
1477
+ a.onMessage.addListener((u) => {
1478
+ i(u, e, t) && (clearTimeout(E), this.cleanupStreamPort(t));
1479
+ }), a.onDisconnect.addListener(() => {
1480
+ clearTimeout(E), this.activeStreamPorts.has(t) && (this.logger.error(`[BodhiExtClient] Bodhi port disconnected for ${t}`), e.postMessage({
1481
+ type: s,
1482
+ requestId: t,
1491
1483
  error: {
1492
1484
  message: "Connection to Bodhi extension closed unexpectedly",
1493
1485
  type: "network_error"
1494
1486
  }
1495
- }), this.activeStreamPorts.delete(r));
1487
+ }), this.activeStreamPorts.delete(t));
1496
1488
  });
1497
- const S = {
1498
- type: _.STREAM_REQUEST,
1499
- requestId: r,
1489
+ const d = {
1490
+ type: o,
1491
+ requestId: t,
1500
1492
  request: {
1501
- method: o,
1502
- endpoint: s,
1503
- body: n,
1504
- headers: u
1493
+ method: r.method,
1494
+ endpoint: r.endpoint,
1495
+ body: r.body,
1496
+ headers: h
1505
1497
  }
1506
1498
  };
1507
- this.logger.debug("[BodhiExtClient] Sending stream request to bodhi port:", S), d.postMessage(S);
1508
- } catch (u) {
1509
- const d = u;
1510
- this.logger.error("[BodhiExtClient] Stream error:", JSON.stringify(d.message)), e.postMessage({
1511
- type: c.EXT2EXT_CLIENT_STREAM_ERROR,
1512
- requestId: r,
1499
+ this.logger.debug("[BodhiExtClient] Sending stream request to bodhi port:", d), a.postMessage(d);
1500
+ } catch (h) {
1501
+ const a = h;
1502
+ this.logger.error("[BodhiExtClient] Stream relay error:", JSON.stringify(a.message)), e.postMessage({
1503
+ type: s,
1504
+ requestId: t,
1513
1505
  error: {
1514
- message: `uncaught error: ${JSON.stringify({ error: d, message: d.message })}`,
1506
+ message: `uncaught error: ${JSON.stringify({ error: a, message: a.message })}`,
1515
1507
  type: "extension_error"
1516
1508
  }
1517
1509
  });
@@ -1530,6 +1522,105 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1530
1522
  this.activeStreamPorts.delete(e);
1531
1523
  }
1532
1524
  }
1525
+ /**
1526
+ * Handle SSE-parsed streaming request — translates STREAM_* messages to EXT2EXT_CLIENT_STREAM_*
1527
+ */
1528
+ async handleStreamRequest(e, t) {
1529
+ const { requestId: r, request: n } = t;
1530
+ await this.handleGenericStreamRelay(
1531
+ e,
1532
+ r,
1533
+ n,
1534
+ se,
1535
+ _.STREAM_REQUEST,
1536
+ c.EXT2EXT_CLIENT_STREAM_ERROR,
1537
+ (o, s, i) => {
1538
+ if (oe(o)) {
1539
+ const h = o.response, a = h.body;
1540
+ return h.status >= 400 ? (s.postMessage({
1541
+ type: c.EXT2EXT_CLIENT_STREAM_API_ERROR,
1542
+ requestId: i,
1543
+ response: h
1544
+ }), !1) : a?.done ? (s.postMessage({
1545
+ type: c.EXT2EXT_CLIENT_STREAM_DONE,
1546
+ requestId: i
1547
+ }), this.logger.info(`[BodhiExtClient] Stream complete for ${i}`), !0) : (s.postMessage({
1548
+ type: c.EXT2EXT_CLIENT_STREAM_CHUNK,
1549
+ requestId: i,
1550
+ response: h
1551
+ }), !1);
1552
+ } else {
1553
+ if (ne(o))
1554
+ return this.logger.error(
1555
+ `[BodhiExtClient] Stream API error for ${i}: ${o.response.status}`
1556
+ ), s.postMessage({
1557
+ type: c.EXT2EXT_CLIENT_STREAM_API_ERROR,
1558
+ requestId: i,
1559
+ response: o.response
1560
+ }), !1;
1561
+ if (ie(o))
1562
+ return this.logger.error(
1563
+ `[BodhiExtClient] Stream error for ${i}:`,
1564
+ o.error.message
1565
+ ), s.postMessage({
1566
+ type: c.EXT2EXT_CLIENT_STREAM_ERROR,
1567
+ requestId: i,
1568
+ error: {
1569
+ message: `stream error: ${JSON.stringify(o)}`,
1570
+ type: "extension_error"
1571
+ }
1572
+ }), !0;
1573
+ }
1574
+ return !1;
1575
+ }
1576
+ );
1577
+ }
1578
+ /**
1579
+ * Handle raw text streaming request — translates STREAM_TEXT_* messages to EXT2EXT_CLIENT_STREAM_TEXT_*
1580
+ */
1581
+ async handleStreamTextRequest(e, t) {
1582
+ const { requestId: r, request: n } = t;
1583
+ await this.handleGenericStreamRelay(
1584
+ e,
1585
+ r,
1586
+ n,
1587
+ ae,
1588
+ _.STREAM_TEXT_REQUEST,
1589
+ c.EXT2EXT_CLIENT_STREAM_TEXT_ERROR,
1590
+ (o, s, i) => {
1591
+ switch (o.type) {
1592
+ case _.STREAM_TEXT_START:
1593
+ return s.postMessage({
1594
+ type: c.EXT2EXT_CLIENT_STREAM_TEXT_START,
1595
+ requestId: i,
1596
+ status: o.status,
1597
+ headers: o.headers
1598
+ }), !1;
1599
+ case _.STREAM_TEXT_CHUNK:
1600
+ return s.postMessage({
1601
+ type: c.EXT2EXT_CLIENT_STREAM_TEXT_CHUNK,
1602
+ requestId: i,
1603
+ chunk: o.chunk
1604
+ }), !1;
1605
+ case _.STREAM_TEXT_DONE:
1606
+ return this.logger.info(`[BodhiExtClient] Stream text complete for ${i}`), s.postMessage({
1607
+ type: c.EXT2EXT_CLIENT_STREAM_TEXT_DONE,
1608
+ requestId: i
1609
+ }), !0;
1610
+ case _.STREAM_TEXT_ERROR:
1611
+ return this.logger.error(
1612
+ `[BodhiExtClient] Stream text error for ${i}:`,
1613
+ o.error.message
1614
+ ), s.postMessage({
1615
+ type: c.EXT2EXT_CLIENT_STREAM_TEXT_ERROR,
1616
+ requestId: i,
1617
+ error: o.error
1618
+ }), !0;
1619
+ }
1620
+ return !1;
1621
+ }
1622
+ );
1623
+ }
1533
1624
  // ============================================================================
1534
1625
  // Token Management (Private Methods)
1535
1626
  // ============================================================================
@@ -1575,7 +1666,7 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1575
1666
  async _doRefreshToken(e) {
1576
1667
  this.logger.debug("Refreshing access token");
1577
1668
  try {
1578
- const t = await Y(
1669
+ const t = await ee(
1579
1670
  this.authEndpoints.token,
1580
1671
  e,
1581
1672
  this.authClientId
@@ -1615,29 +1706,32 @@ const Ee = ["ggedphdcbekjlomjaidbajglgihbeaon"], le = ["bjdjhiombmfbcoeojijpfckl
1615
1706
  ]);
1616
1707
  }
1617
1708
  parseJwt(e) {
1618
- const r = e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"), i = decodeURIComponent(
1709
+ const r = e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"), n = decodeURIComponent(
1619
1710
  atob(r).split("").map((o) => "%" + ("00" + o.charCodeAt(0).toString(16)).slice(-2)).join("")
1620
1711
  );
1621
- return JSON.parse(i);
1712
+ return JSON.parse(n);
1622
1713
  }
1623
1714
  createErrorClientNotInitialized(e) {
1624
1715
  return `Client not initialized. Extension discovery not triggered nor extensionId set, cannot handle request: ${JSON.stringify(e)}`;
1625
1716
  }
1626
1717
  };
1627
- p.STREAM_TIMEOUT = 6e4;
1628
- let A = p;
1629
- const pe = "production";
1718
+ S.STREAM_TIMEOUT = 6e4;
1719
+ let w = S;
1720
+ const ye = "production";
1630
1721
  export {
1631
- A as BodhiExtClient,
1632
- ce as DEFAULT_API_TIMEOUT_MS,
1633
- ie as DISCOVERY_ATTEMPTS,
1634
- ae as DISCOVERY_ATTEMPT_TIMEOUT,
1635
- ne as DISCOVERY_ATTEMPT_WAIT_MS,
1636
- oe as DISCOVERY_TIMEOUT_MS,
1637
- m as EXT2EXT_CLIENT_ACTIONS,
1722
+ w as BodhiExtClient,
1723
+ Te as ChromeSessionStorageAdapter,
1724
+ de as DEFAULT_API_TIMEOUT_MS,
1725
+ he as DISCOVERY_ATTEMPTS,
1726
+ ue as DISCOVERY_ATTEMPT_TIMEOUT,
1727
+ Ee as DISCOVERY_ATTEMPT_WAIT_MS,
1728
+ ce as DISCOVERY_TIMEOUT_MS,
1729
+ p as EXT2EXT_CLIENT_ACTIONS,
1638
1730
  c as EXT2EXT_CLIENT_MESSAGE_TYPES,
1639
- k as EXT2EXT_CLIENT_STREAM_PORT,
1640
- pe as EXT_BUILD_MODE,
1641
- me as ExtUIClient,
1642
- he as isExtClientApiError
1731
+ M as EXT2EXT_CLIENT_STREAM_PORT,
1732
+ O as EXT2EXT_CLIENT_STREAM_TEXT_PORT,
1733
+ ye as EXT_BUILD_MODE,
1734
+ fe as ExtUIClient,
1735
+ Ce as InMemoryStorage,
1736
+ le as isExtClientApiError
1643
1737
  };