@bodhiapp/bodhi-js-ext 0.0.42 → 0.0.44

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,6 +1,6 @@
1
- import { DirectClientBase as V, createStoragePrefixWithNamespace as X, STORAGE_PREFIXES as N, generateCodeVerifier as w, generateCodeChallenge as z, buildAuthorizeUrl as v, BASE_OAUTH_SCOPE as L, buildErrorUrl as b, AccessRequestBuilder as P, unwrapResponse as k, buildReviewUrl as O, createOperationError as d, throwAccessRequestDenialError as M, PENDING_EXTENSION_READY as f, Logger as x, NOOP_STATE_CALLBACK as Q, createExtensionStateNotInitialized as G, BACKEND_SERVER_NOT_REACHABLE as K, createExtensionStateNotFound as F, BodhiError as T, INITIAL_AUTH_STATE as H, BodhiApiError as W, Chat as J, Models as Y, Embeddings as j, Mcps as Z, isAuthError as ee, BaseFacadeClient as te, refreshAccessToken as re } from "@bodhiapp/bodhi-js-core";
1
+ import { DirectClientBase as V, createStoragePrefixWithNamespace as X, STORAGE_PREFIXES as N, generateCodeVerifier as w, generateCodeChallenge as z, buildAuthorizeUrl as v, BASE_OAUTH_SCOPE as L, buildErrorUrl as b, AccessRequestBuilder as k, unwrapResponse as P, buildReviewUrl as O, createOperationError as l, throwAccessRequestDenialError as M, PENDING_EXTENSION_READY as f, Logger as y, NOOP_STATE_CALLBACK as Q, createExtensionStateNotInitialized as G, BACKEND_SERVER_NOT_REACHABLE as K, createExtensionStateNotFound as F, BodhiError as T, INITIAL_AUTH_STATE as H, BodhiApiError as W, Chat as J, Models as Y, Embeddings as j, Mcps as Z, isAuthError as ee, BaseFacadeClient as te, refreshAccessToken as re } from "@bodhiapp/bodhi-js-core";
2
2
  import { InMemoryStorage as Ae } from "@bodhiapp/bodhi-js-core";
3
- import { isExtError as y, isApiSuccessResponse as se, MESSAGE_TYPES as _, EXT_ACTIONS as oe, BODHI_STREAM_PORT as ie, isStreamChunk as ne, isStreamApiError as ae, isStreamError as ce, BODHI_STREAM_TEXT_PORT as he } from "@bodhiapp/bodhi-browser-types";
3
+ import { isExtError as x, isApiSuccessResponse as se, MESSAGE_TYPES as _, EXT_ACTIONS as ie, BODHI_STREAM_PORT as ne, isStreamChunk as oe, isStreamApiError as ae, isStreamError as ce, BODHI_STREAM_TEXT_PORT as he } from "@bodhiapp/bodhi-browser-types";
4
4
  const a = {
5
5
  EXT2EXT_CLIENT_REQUEST: "EXT2EXT_CLIENT_REQUEST",
6
6
  EXT2EXT_CLIENT_RESPONSE: "EXT2EXT_CLIENT_RESPONSE",
@@ -47,7 +47,7 @@ class me extends V {
47
47
  const r = X(
48
48
  e.basePath,
49
49
  N.EXT_DIRECT
50
- ), i = {
50
+ ), o = {
51
51
  authClientId: e.authClientId,
52
52
  authServerUrl: e.authServerUrl,
53
53
  storagePrefix: r,
@@ -57,63 +57,63 @@ class me extends V {
57
57
  storage: e.storage ?? new _e(),
58
58
  initialTokens: e.initialTokens
59
59
  };
60
- super(i, t);
60
+ super(o, t);
61
61
  }
62
62
  // ============================================================================
63
63
  // Authentication (chrome.identity OAuth)
64
64
  // ============================================================================
65
65
  async login(e) {
66
66
  const t = await this.getAuthState();
67
- if (t.status === "authenticated")
67
+ if (t.status === "authenticated" && !e?.exchange)
68
68
  return t;
69
- const r = e?.userRole ?? "scope_user_user", i = this._getRedirectUri();
69
+ const r = e?.userRole ?? "scope_user_user", o = this._getRedirectUri();
70
70
  e?.onProgress?.("requesting");
71
- const s = w(), o = await z(s), n = w();
71
+ const s = w(), i = await z(s), n = w();
72
72
  await this._storageSet({
73
73
  [this.storageKeys.CODE_VERIFIER]: s,
74
74
  [this.storageKeys.STATE]: n
75
75
  });
76
- const h = v(this.authEndpoints, {
76
+ const u = v(this.authEndpoints, {
77
77
  clientId: this.authClientId,
78
- redirectUri: i,
78
+ redirectUri: o,
79
79
  scope: L,
80
80
  state: n,
81
- codeChallenge: o
82
- }), c = b(i), E = new P(this.authClientId).requestedRole(r);
83
- e?.requested && E.requested(e.requested);
84
- const l = await this.requestAccess(E.build()), { review_url: u } = k(l), g = O(u, h, c);
81
+ codeChallenge: i
82
+ }), c = b(o), h = new k(this.authClientId).requestedRole(r);
83
+ e?.requested && h.requested(e.requested), e?.exchange && h.exchange(!0);
84
+ const E = await this.requestAccess(h.build()), { review_url: d } = P(E), g = O(d, u, c);
85
85
  e?.onProgress?.("reviewing");
86
86
  const S = await this.launchReview(g);
87
87
  return e?.onProgress?.("authenticating"), this.completeOAuthRedirect(S);
88
88
  }
89
89
  launchReview(e) {
90
90
  return new Promise((t, r) => {
91
- chrome.identity.launchWebAuthFlow({ url: e, interactive: !0 }, (i) => {
91
+ chrome.identity.launchWebAuthFlow({ url: e, interactive: !0 }, (o) => {
92
92
  if (chrome.runtime.lastError) {
93
93
  r(chrome.runtime.lastError);
94
94
  return;
95
95
  }
96
- if (!i) {
97
- r(d("oauth_error", "No redirect URL received"));
96
+ if (!o) {
97
+ r(l("oauth_error", "No redirect URL received"));
98
98
  return;
99
99
  }
100
- t(i);
100
+ t(o);
101
101
  });
102
102
  });
103
103
  }
104
104
  async completeOAuthRedirect(e) {
105
105
  const t = new URL(e), r = t.searchParams.get("error");
106
106
  if (r)
107
- throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), t.searchParams.get("error_source") === "bodhi" && M(r === "access_denied" ? "denied" : r), d("oauth_error", t.searchParams.get("error_description") ?? r);
108
- const i = t.searchParams.get("code"), s = t.searchParams.get("state"), o = await this._storageGet(this.storageKeys.STATE);
109
- if (!s || s !== o)
110
- throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), d("oauth_error", "State mismatch");
111
- if (!i)
112
- throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), d("oauth_error", "No authorization code");
113
- await this.exchangeCodeForTokens(i);
107
+ throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), t.searchParams.get("error_source") === "bodhi" && M(r === "access_denied" ? "denied" : r), l("oauth_error", t.searchParams.get("error_description") ?? r);
108
+ const o = t.searchParams.get("code"), s = t.searchParams.get("state"), i = await this._storageGet(this.storageKeys.STATE);
109
+ if (!s || s !== i)
110
+ throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), l("oauth_error", "State mismatch");
111
+ if (!o)
112
+ throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), l("oauth_error", "No authorization code");
113
+ await this.exchangeCodeForTokens(o);
114
114
  const n = await this.getAuthState();
115
115
  if (n.status !== "authenticated")
116
- throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), d("oauth_error", "Login failed");
116
+ throw await this._storageRemove([this.storageKeys.CODE_VERIFIER, this.storageKeys.STATE]), l("oauth_error", "Login failed");
117
117
  return this.setAuthState(n), n;
118
118
  }
119
119
  _getRedirectUri() {
@@ -127,7 +127,7 @@ class pe {
127
127
  extension: "not-initialized",
128
128
  extensionId: null,
129
129
  server: f
130
- }, this.extensionId = null, this.broadcastListenerActive = !1, this.config = e, this.logger = new x("ExtClient", e?.logLevel || "warn"), this.onStateChange = t ?? Q, this.apiTimeoutMs = e.apiTimeoutMs ?? Te, this.authClientId = e.authClientId ?? "";
130
+ }, this.extensionId = null, this.broadcastListenerActive = !1, this.config = e, this.logger = new y("ExtClient", e?.logLevel || "warn"), this.onStateChange = t ?? Q, this.apiTimeoutMs = e.apiTimeoutMs ?? Te, this.authClientId = e.authClientId ?? "";
131
131
  }
132
132
  /**
133
133
  * Set client state and notify callback
@@ -195,8 +195,8 @@ class pe {
195
195
  async init(e = {}) {
196
196
  if (!e.testConnection && !e.selectedConnection) {
197
197
  this.logger.info("No testConnection or selectedConnection, returning not-initialized state");
198
- const i = G();
199
- return this.setState(i), i;
198
+ const o = G();
199
+ return this.setState(o), o;
200
200
  }
201
201
  if (this.extensionId && !e.testConnection)
202
202
  return this.logger.debug("Already initialized with extensionId, skipping discovery"), this.state;
@@ -211,20 +211,20 @@ class pe {
211
211
  ), this.extensionId = r;
212
212
  else {
213
213
  this.logger.info("Discovering bodhi-browser extension...");
214
- const o = {
214
+ const i = {
215
215
  attempts: this.config.initParams?.extension?.attempts,
216
216
  attemptWaitMs: this.config.initParams?.extension?.attemptWaitMs,
217
217
  attemptTimeout: this.config.initParams?.extension?.attemptTimeout
218
218
  }, n = await this.sendExtMessageWithTimeout(
219
219
  m.DISCOVER_EXTENSION,
220
- o,
220
+ i,
221
221
  t
222
222
  );
223
223
  this.extensionId = n.extensionId, this.logger.info("Extension discovered:", this.extensionId);
224
224
  }
225
225
  this.setupBroadcastListener();
226
226
  }
227
- const i = {
227
+ const o = {
228
228
  type: "extension",
229
229
  extension: "ready",
230
230
  extensionId: this.extensionId,
@@ -234,12 +234,12 @@ class pe {
234
234
  if (e.testConnection)
235
235
  try {
236
236
  s = await this.getServerState(), this.logger.info("Server connectivity tested, state:", s.status);
237
- } catch (o) {
238
- this.logger.error("Failed to get server state:", o), s = K;
237
+ } catch (i) {
238
+ this.logger.error("Failed to get server state:", i), s = K;
239
239
  }
240
- return this.setState({ ...i, server: s }), this.state;
241
- } catch (i) {
242
- this.logger.error("Failed to initialize extension:", i), this.extensionId = null;
240
+ return this.setState({ ...o, server: s }), this.state;
241
+ } catch (o) {
242
+ this.logger.error("Failed to initialize extension:", o), this.extensionId = null;
243
243
  const s = F();
244
244
  return this.setState(s), this.state;
245
245
  }
@@ -248,10 +248,10 @@ class pe {
248
248
  * Helper method to send ext message with timeout support
249
249
  */
250
250
  async sendExtMessageWithTimeout(e, t, r = 1e4) {
251
- const i = new Promise(
252
- (s, o) => setTimeout(() => o(new Error("Timeout")), r)
251
+ const o = new Promise(
252
+ (s, i) => setTimeout(() => i(new Error("Timeout")), r)
253
253
  );
254
- return Promise.race([this.sendExtRequest(e, t), i]);
254
+ return Promise.race([this.sendExtRequest(e, t), o]);
255
255
  }
256
256
  /**
257
257
  * Send an EXT2EXT_CLIENT_REQUEST message and await EXT2EXT_CLIENT_RESPONSE
@@ -259,7 +259,7 @@ class pe {
259
259
  */
260
260
  async sendExtRequest(e, t) {
261
261
  try {
262
- const r = this.generateRequestId(), i = await chrome.runtime.sendMessage({
262
+ const r = this.generateRequestId(), o = await chrome.runtime.sendMessage({
263
263
  type: a.EXT2EXT_CLIENT_REQUEST,
264
264
  requestId: r,
265
265
  request: {
@@ -267,21 +267,21 @@ class pe {
267
267
  params: t
268
268
  }
269
269
  });
270
- if (!i)
271
- throw d("extension_error", "No response from background script");
272
- if (i.type !== a.EXT2EXT_CLIENT_RESPONSE)
273
- throw d(
270
+ if (!o)
271
+ throw l("extension_error", "No response from background script");
272
+ if (o.type !== a.EXT2EXT_CLIENT_RESPONSE)
273
+ throw l(
274
274
  "extension_error",
275
275
  "Invalid response type from background script"
276
276
  );
277
- const s = i.response;
278
- if (y(s)) {
279
- const o = s.error.type || "extension_error";
280
- throw d(o, s.error.message);
277
+ const s = o.response;
278
+ if (x(s)) {
279
+ const i = s.error.type || "extension_error";
280
+ throw l(i, s.error.message);
281
281
  }
282
282
  return s;
283
283
  } catch (r) {
284
- throw r instanceof T ? r : d(
284
+ throw r instanceof T ? r : l(
285
285
  "extension_error",
286
286
  r instanceof Error ? r.message : "Unknown error occurred"
287
287
  );
@@ -291,16 +291,16 @@ class pe {
291
291
  * Send an API_REQUEST message and await API_RESPONSE (internal)
292
292
  * Returns ext2ext-specific ExtClientApiResponseMessage
293
293
  */
294
- async sendRawApiMessage(e, t, r, i, s) {
295
- const o = this.generateRequestId();
294
+ async sendRawApiMessage(e, t, r, o, s) {
295
+ const i = this.generateRequestId();
296
296
  return await chrome.runtime.sendMessage({
297
297
  type: a.EXT2EXT_CLIENT_API_REQUEST,
298
- requestId: o,
298
+ requestId: i,
299
299
  request: {
300
300
  method: e,
301
301
  endpoint: t,
302
302
  body: r,
303
- headers: i,
303
+ headers: o,
304
304
  authenticated: s
305
305
  }
306
306
  });
@@ -309,10 +309,10 @@ class pe {
309
309
  * Send an API message and return ApiResponse
310
310
  * @throws BodhiError on operational errors (network, timeout, extension-level)
311
311
  */
312
- async sendApiRequest(e, t, r, i, s) {
312
+ async sendApiRequest(e, t, r, o, s) {
313
313
  try {
314
- const o = new Promise(
315
- (h, c) => setTimeout(
314
+ const i = new Promise(
315
+ (u, c) => setTimeout(
316
316
  () => c(
317
317
  new Error(
318
318
  `[bodhi-js-sdk/ext] network timeout: api request not completed within configured/default timeout of ${this.apiTimeoutMs}ms`
@@ -321,18 +321,18 @@ class pe {
321
321
  this.apiTimeoutMs
322
322
  )
323
323
  ), n = await Promise.race([
324
- this.sendRawApiMessage(e, t, r, i, s),
325
- o
324
+ this.sendRawApiMessage(e, t, r, o, s),
325
+ i
326
326
  ]);
327
327
  if (ge(n)) {
328
- const h = n.error.type || "extension_error";
329
- throw new T(h, n.error.message);
328
+ const u = n.error.type || "extension_error";
329
+ throw new T(u, n.error.message);
330
330
  }
331
331
  return n.response;
332
- } catch (o) {
333
- if (o instanceof T)
334
- throw o;
335
- const n = o instanceof Error ? o.message : String(o);
332
+ } catch (i) {
333
+ if (i instanceof T)
334
+ throw i;
335
+ const n = i instanceof Error ? i.message : String(i);
336
336
  throw new T("network_error", n);
337
337
  }
338
338
  }
@@ -344,29 +344,29 @@ class pe {
344
344
  */
345
345
  async login(e) {
346
346
  return new Promise((t, r) => {
347
- const i = async (s) => {
347
+ const o = async (s) => {
348
348
  if (s && typeof s == "object" && "type" in s && s.type === "EXT2EXT_CLIENT_BROADCAST" && "event" in s && s.event === "authStateChanged") {
349
- chrome.runtime.onMessage.removeListener(i);
349
+ chrome.runtime.onMessage.removeListener(o);
350
350
  try {
351
- const o = await this.getAuthState();
352
- if (ee(o)) {
351
+ const i = await this.getAuthState();
352
+ if (ee(i)) {
353
353
  r(
354
- d("auth_error", `Login failed: ${o.error?.message}`)
354
+ l("auth_error", `Login failed: ${i.error?.message}`)
355
355
  );
356
356
  return;
357
357
  }
358
- if (o.status !== "authenticated") {
359
- r(d("auth_error", "Login failed: User is not logged in"));
358
+ if (i.status !== "authenticated") {
359
+ r(l("auth_error", "Login failed: User is not logged in"));
360
360
  return;
361
361
  }
362
- this.setAuthState(o), t(o);
363
- } catch (o) {
364
- r(o);
362
+ this.setAuthState(i), t(i);
363
+ } catch (i) {
364
+ r(i);
365
365
  }
366
366
  }
367
367
  };
368
- chrome.runtime.onMessage.addListener(i), this.sendExtRequest(m.LOGIN, e).catch((s) => {
369
- chrome.runtime.onMessage.removeListener(i), r(s);
368
+ chrome.runtime.onMessage.addListener(o), this.sendExtRequest(m.LOGIN, e).catch((s) => {
369
+ chrome.runtime.onMessage.removeListener(o), r(s);
370
370
  });
371
371
  });
372
372
  }
@@ -413,11 +413,11 @@ class pe {
413
413
  try {
414
414
  e = await this.sendApiRequest("GET", "/bodhi/v1/info");
415
415
  } catch (s) {
416
- const o = s instanceof Error ? s.message : "Connection failed", n = s instanceof T ? s.code : "extension_error";
416
+ const i = s instanceof Error ? s.message : "Connection failed", n = s instanceof T ? s.code : "extension_error";
417
417
  return {
418
418
  status: "not-reachable",
419
419
  version: null,
420
- error: { message: o, type: n }
420
+ error: { message: i, type: n }
421
421
  };
422
422
  }
423
423
  if (e.status >= 400)
@@ -426,30 +426,30 @@ class pe {
426
426
  version: null,
427
427
  error: { message: "API error from server", type: "extension_error" }
428
428
  };
429
- const t = e.body, r = t.version || "unknown", i = { deployment: t.deployment ?? null, client_id: t.client_id ?? null };
429
+ const t = e.body, r = t.version || "unknown", o = { deployment: t.deployment ?? null, client_id: t.client_id ?? null };
430
430
  switch (t.status) {
431
431
  case "ready":
432
- return { status: "ready", version: r, error: null, ...i };
432
+ return { status: "ready", version: r, error: null, ...o };
433
433
  case "setup":
434
434
  return {
435
435
  status: "setup",
436
436
  version: r,
437
437
  error: t.error ? { message: t.error.message, type: t.error.type } : { message: "Setup required", type: "extension_error" },
438
- ...i
438
+ ...o
439
439
  };
440
440
  case "resource_admin":
441
441
  return {
442
442
  status: "resource_admin",
443
443
  version: r,
444
444
  error: t.error ? { message: t.error.message, type: t.error.type } : { message: "Resource admin required", type: "extension_error" },
445
- ...i
445
+ ...o
446
446
  };
447
447
  case "error":
448
448
  return {
449
449
  status: "error",
450
450
  version: r,
451
451
  error: t.error ? { message: t.error.message, type: t.error.type } : { message: "Server error", type: "extension_error" },
452
- ...i
452
+ ...o
453
453
  };
454
454
  default:
455
455
  return {
@@ -465,73 +465,73 @@ class pe {
465
465
  /**
466
466
  * Generic streaming method
467
467
  */
468
- async *stream(e, t, r, i, s = !0) {
469
- const o = this.generateRequestId();
468
+ async *stream(e, t, r, o, s = !0) {
469
+ const i = this.generateRequestId();
470
470
  this.logger.debug("Starting stream", {
471
471
  method: e,
472
472
  endpoint: t,
473
- requestId: o
473
+ requestId: i
474
474
  });
475
475
  const n = chrome.runtime.connect({ name: U }), c = new ReadableStream({
476
- start: (E) => {
477
- n.onMessage.addListener((l) => {
478
- if (l.requestId === o)
479
- switch (l.type) {
476
+ start: (h) => {
477
+ n.onMessage.addListener((E) => {
478
+ if (E.requestId === i)
479
+ switch (E.type) {
480
480
  case a.EXT2EXT_CLIENT_STREAM_DONE:
481
- this.logger.debug("Stream complete", { requestId: o }), E.close(), n.disconnect();
481
+ this.logger.debug("Stream complete", { requestId: i }), h.close(), n.disconnect();
482
482
  break;
483
483
  case a.EXT2EXT_CLIENT_STREAM_ERROR:
484
484
  this.logger.error("Stream error", {
485
- requestId: o,
486
- error: JSON.stringify(l.error)
487
- }), E.error(
485
+ requestId: i,
486
+ error: JSON.stringify(E.error)
487
+ }), h.error(
488
488
  new T(
489
489
  "extension_error",
490
- l.error.message
490
+ E.error.message
491
491
  )
492
492
  ), n.disconnect();
493
493
  break;
494
494
  case a.EXT2EXT_CLIENT_STREAM_API_ERROR: {
495
- const u = l;
495
+ const d = E;
496
496
  this.logger.error("Stream API error", {
497
- requestId: o,
498
- error: u.response.body?.error
499
- }), E.error(
497
+ requestId: i,
498
+ error: d.response.body?.error
499
+ }), h.error(
500
500
  new W(
501
- u.response.status,
502
- u.response.body,
503
- u.response.body?.error?.message || "API error"
501
+ d.response.status,
502
+ d.response.body,
503
+ d.response.body?.error?.message || "API error"
504
504
  )
505
505
  ), n.disconnect();
506
506
  break;
507
507
  }
508
508
  case a.EXT2EXT_CLIENT_STREAM_CHUNK: {
509
- const u = l;
510
- se(u.response) && E.enqueue(u.response.body);
509
+ const d = E;
510
+ se(d.response) && h.enqueue(d.response.body);
511
511
  break;
512
512
  }
513
513
  }
514
514
  }), n.onDisconnect.addListener(() => {
515
- this.logger.debug("Port disconnected", { requestId: o });
515
+ this.logger.debug("Port disconnected", { requestId: i });
516
516
  try {
517
- E.error(new T("connection_closed", "Connection closed unexpectedly"));
517
+ h.error(new T("connection_closed", "Connection closed unexpectedly"));
518
518
  } catch {
519
519
  }
520
520
  }), n.postMessage({
521
521
  type: a.EXT2EXT_CLIENT_STREAM_REQUEST,
522
- requestId: o,
523
- request: { method: e, endpoint: t, body: r, headers: i, authenticated: s }
522
+ requestId: i,
523
+ request: { method: e, endpoint: t, body: r, headers: o, authenticated: s }
524
524
  });
525
525
  }
526
526
  }).getReader();
527
527
  try {
528
528
  for (; ; ) {
529
- const { done: E, value: l } = await c.read();
530
- if (E) {
529
+ const { done: h, value: E } = await c.read();
530
+ if (h) {
531
531
  this.logger.debug("Stream iteration complete");
532
532
  break;
533
533
  }
534
- yield l;
534
+ yield E;
535
535
  }
536
536
  } finally {
537
537
  c.releaseLock();
@@ -541,20 +541,20 @@ class pe {
541
541
  * Raw text streaming method - no SSE/JSON parsing
542
542
  * Returns status, headers, and async generator of raw text chunks
543
543
  */
544
- async streamText(e, t, r, i, s = !0) {
545
- const o = this.generateRequestId();
546
- return new Promise((n, h) => {
547
- let c, E = !1;
548
- const l = new ReadableStream({
544
+ async streamText(e, t, r, o, s = !0) {
545
+ const i = this.generateRequestId();
546
+ return new Promise((n, u) => {
547
+ let c, h = !1;
548
+ const E = new ReadableStream({
549
549
  start: (g) => {
550
550
  c = g;
551
551
  }
552
- }), u = chrome.runtime.connect({ name: D });
553
- u.onMessage.addListener((g) => {
554
- if (g.requestId === o)
552
+ }), d = chrome.runtime.connect({ name: D });
553
+ d.onMessage.addListener((g) => {
554
+ if (g.requestId === i)
555
555
  switch (g.type) {
556
556
  case a.EXT2EXT_CLIENT_STREAM_TEXT_START: {
557
- E = !0;
557
+ h = !0;
558
558
  async function* S(q) {
559
559
  const C = q.getReader();
560
560
  try {
@@ -570,7 +570,7 @@ class pe {
570
570
  n({
571
571
  status: g.status,
572
572
  headers: g.headers,
573
- body: S(l)
573
+ body: S(E)
574
574
  });
575
575
  break;
576
576
  }
@@ -578,28 +578,28 @@ class pe {
578
578
  c.enqueue(g.chunk);
579
579
  break;
580
580
  case a.EXT2EXT_CLIENT_STREAM_TEXT_DONE:
581
- c.close(), u.disconnect();
581
+ c.close(), d.disconnect();
582
582
  break;
583
583
  case a.EXT2EXT_CLIENT_STREAM_TEXT_ERROR: {
584
- const S = d("extension_error", g.error.message);
585
- E ? c.error(S) : h(S), u.disconnect();
584
+ const S = l("extension_error", g.error.message);
585
+ h ? c.error(S) : u(S), d.disconnect();
586
586
  break;
587
587
  }
588
588
  }
589
- }), u.onDisconnect.addListener(() => {
590
- if (!E)
591
- h(d("extension_error", "Connection closed unexpectedly"));
589
+ }), d.onDisconnect.addListener(() => {
590
+ if (!h)
591
+ u(l("extension_error", "Connection closed unexpectedly"));
592
592
  else
593
593
  try {
594
594
  c.error(
595
- d("extension_error", "Connection closed unexpectedly")
595
+ l("extension_error", "Connection closed unexpectedly")
596
596
  );
597
597
  } catch {
598
598
  }
599
- }), u.postMessage({
599
+ }), d.postMessage({
600
600
  type: a.EXT2EXT_CLIENT_STREAM_TEXT_REQUEST,
601
- requestId: o,
602
- request: { method: e, endpoint: t, body: r, headers: i, authenticated: s }
601
+ requestId: i,
602
+ request: { method: e, endpoint: t, body: r, headers: o, authenticated: s }
603
603
  });
604
604
  });
605
605
  }
@@ -647,21 +647,21 @@ class pe {
647
647
  };
648
648
  }
649
649
  }
650
- class ye extends te {
650
+ class xe extends te {
651
651
  constructor(e, t, r) {
652
- const i = t || {}, s = {
653
- basePath: i.basePath || "/",
654
- authServerUrl: i.authServerUrl || "https://id.getbodhi.app/realms/bodhi",
655
- logLevel: i.logLevel || "warn",
656
- apiTimeoutMs: i.apiTimeoutMs,
657
- storage: i.storage,
658
- initialTokens: i.initialTokens,
659
- initParams: i.initParams
652
+ const o = t || {}, s = {
653
+ basePath: o.basePath || "/",
654
+ authServerUrl: o.authServerUrl || "https://id.getbodhi.app/realms/bodhi",
655
+ logLevel: o.logLevel || "warn",
656
+ apiTimeoutMs: o.apiTimeoutMs,
657
+ storage: o.storage,
658
+ initialTokens: o.initialTokens,
659
+ initParams: o.initParams
660
660
  };
661
661
  super(e, s, r);
662
662
  }
663
663
  createLogger(e) {
664
- return new x("ExtUIClient", e.logLevel);
664
+ return new y("ExtUIClient", e.logLevel);
665
665
  }
666
666
  createStoragePrefix(e) {
667
667
  return X(e.basePath, N.EXT);
@@ -697,7 +697,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
697
697
  // Constructor
698
698
  // ============================================================================
699
699
  constructor(e, t) {
700
- 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 ?? ue, this.attemptWaitMs = t?.attemptWaitMs ?? de, this.attemptTimeout = t?.attemptTimeout ?? le, this.authEndpoints = {
700
+ this.isAuthenticating = !1, this.isExchanging = !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 y("BodhiExtClient", t?.logLevel || "warn"), this.attempts = t?.attempts ?? ue, this.attemptWaitMs = t?.attemptWaitMs ?? de, this.attemptTimeout = t?.attemptTimeout ?? le, this.authEndpoints = {
701
701
  authorize: `${this.authServerUrl}/protocol/openid-connect/auth`,
702
702
  token: `${this.authServerUrl}/protocol/openid-connect/token`,
703
703
  userinfo: `${this.authServerUrl}/protocol/openid-connect/userinfo`,
@@ -718,8 +718,8 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
718
718
  return crypto.getRandomValues(e), p.base64UrlEncode(e.buffer);
719
719
  }
720
720
  static async generateCodeChallenge(e) {
721
- const r = new TextEncoder().encode(e), i = await crypto.subtle.digest("SHA-256", r);
722
- return p.base64UrlEncode(i);
721
+ const r = new TextEncoder().encode(e), o = await crypto.subtle.digest("SHA-256", r);
722
+ return p.base64UrlEncode(o);
723
723
  }
724
724
  // ============================================================================
725
725
  // State Management
@@ -748,7 +748,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
748
748
  return this.logger.debug(
749
749
  `[Ext2Ext/Discovery] Pinging extension: ${e} with timeout ${this.attemptTimeout}ms`
750
750
  ), new Promise((t, r) => {
751
- const i = setTimeout(() => {
751
+ const o = setTimeout(() => {
752
752
  this.logger.debug(`[Ext2Ext/Discovery] Timeout waiting for extension ${e}`), r(new Error("Timeout"));
753
753
  }, this.attemptTimeout);
754
754
  try {
@@ -759,23 +759,23 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
759
759
  action: "get_extension_id"
760
760
  }
761
761
  };
762
- this.logger.debug(`[Ext2Ext/Discovery] Sending message to ${e}:`, s), chrome.runtime.sendMessage(e, s, (o) => {
763
- if (clearTimeout(i), chrome.runtime.lastError) {
762
+ this.logger.debug(`[Ext2Ext/Discovery] Sending message to ${e}:`, s), chrome.runtime.sendMessage(e, s, (i) => {
763
+ if (clearTimeout(o), chrome.runtime.lastError) {
764
764
  this.logger.error(
765
765
  `[Ext2Ext/Discovery] Error from extension ${e}:`,
766
766
  chrome.runtime.lastError.message
767
767
  ), r(new Error(chrome.runtime.lastError.message));
768
768
  return;
769
769
  }
770
- this.logger.debug(`[Ext2Ext/Discovery] Response from ${e}:`, o);
771
- const n = o;
770
+ this.logger.debug(`[Ext2Ext/Discovery] Response from ${e}:`, i);
771
+ const n = i;
772
772
  n && n.type === _.EXT_RESPONSE ? (this.logger.debug(`[Ext2Ext/Discovery] ✓ Extension ${e} responded`), t(!0)) : (this.logger.error(
773
773
  `[Ext2Ext/Discovery] Invalid response from ${e}:`,
774
- o
774
+ i
775
775
  ), r(new Error("Invalid response")));
776
776
  });
777
777
  } catch (s) {
778
- this.logger.error(`[Ext2Ext/Discovery] Exception pinging ${e}:`, s), clearTimeout(i), r(s);
778
+ this.logger.error(`[Ext2Ext/Discovery] Exception pinging ${e}:`, s), clearTimeout(o), r(s);
779
779
  }
780
780
  });
781
781
  }
@@ -790,36 +790,36 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
790
790
  * @param params Resolved discovery params
791
791
  */
792
792
  async discoverBodhiExtension(e) {
793
- const { attempts: t, attemptWaitMs: r, attemptTimeout: i } = e;
793
+ const { attempts: t, attemptWaitMs: r, attemptTimeout: o } = e;
794
794
  this.logger.info(
795
- `[Ext2Ext/Discovery] Starting discovery: ${t} attempts per ID, ${i}ms timeout, ${r}ms between attempts`
795
+ `[Ext2Ext/Discovery] Starting discovery: ${t} attempts per ID, ${o}ms timeout, ${r}ms between attempts`
796
796
  );
797
797
  const s = this.getExtensionIdsForEnvironment();
798
798
  this.logger.debug(
799
799
  `[Ext2Ext/Discovery] Will try ${s.length} extension(s):`,
800
800
  s
801
801
  );
802
- for (const h of s) {
802
+ for (const u of s) {
803
803
  for (let c = 1; c <= t; c++) {
804
804
  this.logger.debug(
805
- `[Ext2Ext/Discovery] Trying ${h} - attempt ${c}/${t}`
805
+ `[Ext2Ext/Discovery] Trying ${u} - attempt ${c}/${t}`
806
806
  );
807
807
  try {
808
- return await this.pingExtension(h), this.logger.info(`[Ext2Ext/Discovery] ✓ Found: ${h} on attempt ${c}`), {
808
+ return await this.pingExtension(u), this.logger.info(`[Ext2Ext/Discovery] ✓ Found: ${u} on attempt ${c}`), {
809
809
  success: !0,
810
- extensionId: h
810
+ extensionId: u
811
811
  };
812
- } catch (E) {
812
+ } catch (h) {
813
813
  this.logger.debug(
814
- `[Ext2Ext/Discovery] Attempt ${c} failed for ${h}: ${E instanceof Error ? E.message : "Unknown error"}`
814
+ `[Ext2Ext/Discovery] Attempt ${c} failed for ${u}: ${h instanceof Error ? h.message : "Unknown error"}`
815
815
  ), c < t && await this.sleep(r);
816
816
  }
817
817
  }
818
818
  this.logger.warn(
819
- `[Ext2Ext/Discovery] ✗ Not found: ${h} after ${t} attempts`
819
+ `[Ext2Ext/Discovery] ✗ Not found: ${u} after ${t} attempts`
820
820
  );
821
821
  }
822
- const o = s.join(", "), n = `Extension not found. Tried ${s.length} IDs with ${t} attempts each: ${o}`;
822
+ const i = s.join(", "), n = `Extension not found. Tried ${s.length} IDs with ${t} attempts each: ${i}`;
823
823
  return this.logger.error(`[Ext2Ext/Discovery] ${n}`), {
824
824
  success: !1,
825
825
  error: n
@@ -853,8 +853,8 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
853
853
  type: "NOT_INITIALIZED"
854
854
  }
855
855
  }), !0) : (this.logger.debug(`[BodhiExtClient] Processing message.type=${e.type}`), (async () => {
856
- const i = await this.handleAction(e);
857
- r(i);
856
+ const o = await this.handleAction(e);
857
+ r(o);
858
858
  })(), !0)), this.registerStreamPortListener(
859
859
  U,
860
860
  a.EXT2EXT_CLIENT_STREAM_REQUEST,
@@ -937,7 +937,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
937
937
  Authorization: `Bearer ${s}`
938
938
  }, this.logger.debug("[BodhiExtClient] Injected auth token for authenticated request");
939
939
  }
940
- const i = await this.sendApiRequest(
940
+ const o = await this.sendApiRequest(
941
941
  e.request.method,
942
942
  e.request.endpoint,
943
943
  e.request.body,
@@ -946,7 +946,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
946
946
  return {
947
947
  type: a.EXT2EXT_CLIENT_API_RESPONSE,
948
948
  requestId: t,
949
- response: i
949
+ response: o
950
950
  };
951
951
  } catch (r) {
952
952
  return this.logger.error("[BodhiExtClient] API request failed:", r), {
@@ -966,17 +966,17 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
966
966
  * @returns Action response message (success or error)
967
967
  */
968
968
  async handleExtClientRequest(e) {
969
- const { requestId: t, request: r } = e, { action: i, params: s } = r;
970
- this.logger.debug(`[BodhiExtClient] Handling action: ${i}`);
969
+ const { requestId: t, request: r } = e, { action: o, params: s } = r;
970
+ this.logger.debug(`[BodhiExtClient] Handling action: ${o}`);
971
971
  try {
972
- let o = {};
973
- switch (i) {
972
+ let i = {};
973
+ switch (o) {
974
974
  case m.DISCOVER_EXTENSION: {
975
975
  const n = s;
976
976
  await this.init(n), this.logger.info("[BodhiExtClient] Discovery successful:", {
977
977
  extensionId: this.extensionId,
978
978
  environment: I
979
- }), o = {
979
+ }), i = {
980
980
  extensionId: this.extensionId,
981
981
  environment: I
982
982
  };
@@ -984,12 +984,12 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
984
984
  }
985
985
  case m.SET_EXTENSION_ID: {
986
986
  const { extensionId: n } = s;
987
- this.extensionId = n, this.state = "ready", this.logger.info("[BodhiExtClient] Extension ID set:", { extensionId: n }), o = { success: !0 };
987
+ this.extensionId = n, this.state = "ready", this.logger.info("[BodhiExtClient] Extension ID set:", { extensionId: n }), i = { success: !0 };
988
988
  break;
989
989
  }
990
990
  case m.GET_EXTENSION_ID: {
991
- const n = await this.sendExtRequestRaw(oe.GET_EXTENSION_ID, s);
992
- return y(n.response) ? {
991
+ const n = await this.sendExtRequestRaw(ie.GET_EXTENSION_ID, s);
992
+ return x(n.response) ? {
993
993
  type: a.EXT2EXT_CLIENT_RESPONSE,
994
994
  requestId: t,
995
995
  response: {
@@ -1013,29 +1013,29 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1013
1013
  await this.logout(), this.broadcastAuthStateChange();
1014
1014
  break;
1015
1015
  case m.GET_AUTH_STATE:
1016
- o = { authState: await this.getAuthState() };
1016
+ i = { authState: await this.getAuthState() };
1017
1017
  break;
1018
1018
  default:
1019
1019
  return {
1020
1020
  type: a.EXT2EXT_CLIENT_RESPONSE,
1021
1021
  requestId: t,
1022
1022
  response: {
1023
- error: { message: `Unknown action: ${i}`, type: "UNKNOWN_ACTION" }
1023
+ error: { message: `Unknown action: ${o}`, type: "UNKNOWN_ACTION" }
1024
1024
  }
1025
1025
  };
1026
1026
  }
1027
1027
  return {
1028
1028
  type: a.EXT2EXT_CLIENT_RESPONSE,
1029
1029
  requestId: t,
1030
- response: o
1030
+ response: i
1031
1031
  };
1032
- } catch (o) {
1033
- return this.logger.error("[BodhiExtClient] Unexpected error:", o), {
1032
+ } catch (i) {
1033
+ return this.logger.error("[BodhiExtClient] Unexpected error:", i), {
1034
1034
  type: a.EXT2EXT_CLIENT_RESPONSE,
1035
1035
  requestId: t,
1036
1036
  response: {
1037
1037
  error: {
1038
- message: o instanceof Error ? o.message : `Unexpected error: ${JSON.stringify(o)}`
1038
+ message: i instanceof Error ? i.message : `Unexpected error: ${JSON.stringify(i)}`
1039
1039
  }
1040
1040
  }
1041
1041
  };
@@ -1072,25 +1072,25 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1072
1072
  * @throws Error if login fails
1073
1073
  */
1074
1074
  async login(e) {
1075
- if (!(this.isAuthenticating || (await this.getAuthState()).status === "authenticated")) {
1076
- this.isAuthenticating = !0;
1075
+ if (!(this.isAuthenticating || (await this.getAuthState()).status === "authenticated" && !e?.exchange)) {
1076
+ this.isAuthenticating = !0, this.isExchanging = e?.exchange ?? !1;
1077
1077
  try {
1078
1078
  if (!this.extensionId)
1079
1079
  throw new Error("Extension not discovered. Please detect Bodhi extension before login.");
1080
- const r = e?.userRole ?? "scope_user_user", i = chrome.identity.getRedirectURL("callback"), s = p.generateCodeVerifier(), o = await p.generateCodeChallenge(s), n = p.generateCodeVerifier();
1080
+ const r = e?.userRole ?? "scope_user_user", o = chrome.identity.getRedirectURL("callback"), s = p.generateCodeVerifier(), i = await p.generateCodeChallenge(s), n = p.generateCodeVerifier();
1081
1081
  await chrome.storage.session.set({ codeVerifier: s, state: n, authInProgress: !0 });
1082
- const h = v(this.authEndpoints, {
1082
+ const u = v(this.authEndpoints, {
1083
1083
  clientId: this.authClientId,
1084
- redirectUri: i,
1084
+ redirectUri: o,
1085
1085
  scope: L,
1086
1086
  state: n,
1087
- codeChallenge: o
1088
- }), c = b(i), E = new P(this.authClientId).requestedRole(r);
1089
- e?.requested && E.requested(e.requested);
1090
- const l = await this.requestAccess(E.build()), { review_url: u } = k(l), g = O(u, h, c), S = await this.launchReview(g);
1087
+ codeChallenge: i
1088
+ }), c = b(o), h = new k(this.authClientId).requestedRole(r);
1089
+ e?.requested && h.requested(e.requested), e?.exchange && h.exchange(!0);
1090
+ const E = await this.requestAccess(h.build()), { review_url: d } = P(E), g = O(d, u, c), S = await this.launchReview(g);
1091
1091
  await this.completeOAuthRedirect(S);
1092
1092
  } finally {
1093
- this.isAuthenticating = !1;
1093
+ this.isAuthenticating = !1, this.isExchanging = !1;
1094
1094
  }
1095
1095
  }
1096
1096
  }
@@ -1099,9 +1099,9 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1099
1099
  * @param code Authorization code from OAuth callback
1100
1100
  */
1101
1101
  async exchangeCodeForTokens(e) {
1102
- if ((await this.getAuthState()).status === "authenticated")
1102
+ if ((await this.getAuthState()).status === "authenticated" && !this.isExchanging)
1103
1103
  return;
1104
- const { codeVerifier: r } = await chrome.storage.session.get("codeVerifier"), i = chrome.identity.getRedirectURL("callback"), s = await fetch(this.authEndpoints.token, {
1104
+ const { codeVerifier: r } = await chrome.storage.session.get("codeVerifier"), o = chrome.identity.getRedirectURL("callback"), s = await fetch(this.authEndpoints.token, {
1105
1105
  method: "POST",
1106
1106
  headers: {
1107
1107
  "Content-Type": "application/x-www-form-urlencoded"
@@ -1109,7 +1109,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1109
1109
  body: new URLSearchParams({
1110
1110
  grant_type: "authorization_code",
1111
1111
  code: e,
1112
- redirect_uri: i,
1112
+ redirect_uri: o,
1113
1113
  client_id: this.authClientId,
1114
1114
  code_verifier: r
1115
1115
  })
@@ -1118,12 +1118,12 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1118
1118
  const n = await s.text();
1119
1119
  throw new Error(`Token exchange failed: ${s.status} ${n}`);
1120
1120
  }
1121
- const o = await s.json();
1121
+ const i = await s.json();
1122
1122
  await this.storeTokens({
1123
- accessToken: o.access_token,
1124
- refreshToken: o.refresh_token,
1125
- idToken: o.id_token,
1126
- expiresIn: o.expires_in
1123
+ accessToken: i.access_token,
1124
+ refreshToken: i.refresh_token,
1125
+ idToken: i.id_token,
1126
+ expiresIn: i.expires_in
1127
1127
  });
1128
1128
  }
1129
1129
  /**
@@ -1203,35 +1203,37 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1203
1203
  return this.sendApiRequest(
1204
1204
  "POST",
1205
1205
  "/bodhi/v1/apps/request-access",
1206
- e
1206
+ e,
1207
+ void 0,
1208
+ !0
1207
1209
  );
1208
1210
  }
1209
1211
  launchReview(e) {
1210
1212
  return new Promise((t, r) => {
1211
- chrome.identity.launchWebAuthFlow({ url: e, interactive: !0 }, async (i) => {
1213
+ chrome.identity.launchWebAuthFlow({ url: e, interactive: !0 }, async (o) => {
1212
1214
  if (await chrome.storage.session.set({ authInProgress: !1 }), chrome.runtime.lastError) {
1213
1215
  await chrome.storage.session.remove(["codeVerifier", "state"]), r(chrome.runtime.lastError);
1214
1216
  return;
1215
1217
  }
1216
- if (!i) {
1217
- await chrome.storage.session.remove(["codeVerifier", "state"]), r(d("oauth_error", "No redirect URL received"));
1218
+ if (!o) {
1219
+ await chrome.storage.session.remove(["codeVerifier", "state"]), r(l("oauth_error", "No redirect URL received"));
1218
1220
  return;
1219
1221
  }
1220
- t(i);
1222
+ t(o);
1221
1223
  });
1222
1224
  });
1223
1225
  }
1224
1226
  async completeOAuthRedirect(e) {
1225
1227
  const t = new URL(e), r = t.searchParams.get("error");
1226
1228
  if (r)
1227
- throw await chrome.storage.session.remove(["codeVerifier", "state"]), t.searchParams.get("error_source") === "bodhi" && M(r === "access_denied" ? "denied" : r), d("oauth_error", t.searchParams.get("error_description") ?? r);
1228
- const i = t.searchParams.get("code"), s = t.searchParams.get("state"), { state: o } = await chrome.storage.session.get("state");
1229
- if (!s || s !== o)
1230
- throw await chrome.storage.session.remove(["codeVerifier", "state"]), d("oauth_error", "State mismatch");
1231
- if (!i)
1232
- throw await chrome.storage.session.remove(["codeVerifier", "state"]), d("oauth_error", "No authorization code");
1233
- if (await this.exchangeCodeForTokens(i), await chrome.storage.session.remove(["codeVerifier", "state"]), (await this.getAuthState()).status !== "authenticated")
1234
- throw d("oauth_error", "Login failed");
1229
+ throw await chrome.storage.session.remove(["codeVerifier", "state"]), t.searchParams.get("error_source") === "bodhi" && M(r === "access_denied" ? "denied" : r), l("oauth_error", t.searchParams.get("error_description") ?? r);
1230
+ const o = t.searchParams.get("code"), s = t.searchParams.get("state"), { state: i } = await chrome.storage.session.get("state");
1231
+ if (!s || s !== i)
1232
+ throw await chrome.storage.session.remove(["codeVerifier", "state"]), l("oauth_error", "State mismatch");
1233
+ if (!o)
1234
+ throw await chrome.storage.session.remove(["codeVerifier", "state"]), l("oauth_error", "No authorization code");
1235
+ if (await this.exchangeCodeForTokens(o), await chrome.storage.session.remove(["codeVerifier", "state"]), (await this.getAuthState()).status !== "authenticated")
1236
+ throw l("oauth_error", "Login failed");
1235
1237
  }
1236
1238
  // Ext2Ext Communication (Private Methods)
1237
1239
  // ============================================================================
@@ -1243,7 +1245,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1243
1245
  */
1244
1246
  async sendExtRequest(e, t) {
1245
1247
  const r = await this.sendExtRequestRaw(e, t);
1246
- if (y(r.response))
1248
+ if (x(r.response))
1247
1249
  throw this.logger.error("[BodhiExtClient] Extension error:", r.response.error), new Error(
1248
1250
  r.response.error.message || `Extension request failed: ${JSON.stringify(r.response)}`
1249
1251
  );
@@ -1255,9 +1257,10 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1255
1257
  * @param endpoint API endpoint path
1256
1258
  * @param body Optional request body
1257
1259
  * @param headers Optional headers
1260
+ * @param authenticated Attach the current token when one exists (safe: skipped if none)
1258
1261
  * @returns API response from LLM server via bodhi-browser-ext
1259
1262
  */
1260
- async sendApiRequest(e, t, r, i) {
1263
+ async sendApiRequest(e, t, r, o, s = !1) {
1261
1264
  if (!this.extensionId)
1262
1265
  throw new T(
1263
1266
  "not_initialized",
@@ -1267,9 +1270,14 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1267
1270
  `[BodhiExtClient] Sending API_REQUEST: method=${e}, endpoint=${t}`,
1268
1271
  r ? { body: r } : ""
1269
1272
  );
1270
- const s = crypto.randomUUID(), o = {
1273
+ let i = o;
1274
+ if (s) {
1275
+ const c = await this._getAccessTokenRaw();
1276
+ c && (i = { ...o, Authorization: `Bearer ${c}` });
1277
+ }
1278
+ const n = crypto.randomUUID(), u = {
1271
1279
  type: _.API_REQUEST,
1272
- requestId: s,
1280
+ requestId: n,
1273
1281
  request: {
1274
1282
  method: e,
1275
1283
  endpoint: t,
@@ -1277,12 +1285,12 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1277
1285
  headers: i
1278
1286
  }
1279
1287
  };
1280
- return this.logger.debug(`[BodhiExtClient] Request ID: ${s}, Extension: ${this.extensionId}`), new Promise((n, h) => {
1288
+ return this.logger.debug(`[BodhiExtClient] Request ID: ${n}, Extension: ${this.extensionId}`), new Promise((c, h) => {
1281
1289
  try {
1282
- chrome.runtime.sendMessage(this.extensionId, o, (c) => {
1290
+ chrome.runtime.sendMessage(this.extensionId, u, (E) => {
1283
1291
  if (chrome.runtime.lastError) {
1284
1292
  this.logger.error(
1285
- `[BodhiExtClient] Chrome runtime error for request ${s}:`,
1293
+ `[BodhiExtClient] Chrome runtime error for request ${n}:`,
1286
1294
  chrome.runtime.lastError
1287
1295
  ), h(
1288
1296
  new T(
@@ -1292,19 +1300,19 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1292
1300
  );
1293
1301
  return;
1294
1302
  }
1295
- if (this.logger.debug(`[BodhiExtClient] Response for request ${s}:`, c), !c) {
1296
- this.logger.error(`[BodhiExtClient] No response received for request ${s}`), h(new T("extension_error", "No response from extension"));
1303
+ if (this.logger.debug(`[BodhiExtClient] Response for request ${n}:`, E), !E) {
1304
+ this.logger.error(`[BodhiExtClient] No response received for request ${n}`), h(new T("extension_error", "No response from extension"));
1297
1305
  return;
1298
1306
  }
1299
- c.type === _.API_RESPONSE && c.requestId === s ? "error" in c ? (this.logger.error(`[BodhiExtClient] API error for ${s}:`, c.error), h(
1300
- new T(c.error.type || "extension_error", c.error.message)
1301
- )) : (this.logger.debug(`[BodhiExtClient] ✓ Valid API_RESPONSE for ${s}`), n(c.response)) : (this.logger.error(
1302
- `[BodhiExtClient] Invalid response format for ${s}:`,
1303
- c
1307
+ E.type === _.API_RESPONSE && E.requestId === n ? "error" in E ? (this.logger.error(`[BodhiExtClient] API error for ${n}:`, E.error), h(
1308
+ new T(E.error.type || "extension_error", E.error.message)
1309
+ )) : (this.logger.debug(`[BodhiExtClient] ✓ Valid API_RESPONSE for ${n}`), c(E.response)) : (this.logger.error(
1310
+ `[BodhiExtClient] Invalid response format for ${n}:`,
1311
+ E
1304
1312
  ), h(new T("extension_error", "Invalid response format")));
1305
1313
  });
1306
- } catch (c) {
1307
- this.logger.error(`[BodhiExtClient] Exception sending message for ${s}:`, c), h(c);
1314
+ } catch (E) {
1315
+ this.logger.error(`[BodhiExtClient] Exception sending message for ${n}:`, E), h(E);
1308
1316
  }
1309
1317
  });
1310
1318
  }
@@ -1324,7 +1332,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1324
1332
  `[BodhiExtClient] Sending EXT_REQUEST (raw): action=${e}`,
1325
1333
  t ? { params: t } : ""
1326
1334
  );
1327
- const r = crypto.randomUUID(), i = {
1335
+ const r = crypto.randomUUID(), o = {
1328
1336
  type: _.EXT_REQUEST,
1329
1337
  requestId: r,
1330
1338
  request: {
@@ -1332,27 +1340,27 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1332
1340
  params: t
1333
1341
  }
1334
1342
  };
1335
- return this.logger.debug(`[BodhiExtClient] Request ID: ${r}, Extension: ${this.extensionId}`), new Promise((s, o) => {
1343
+ return this.logger.debug(`[BodhiExtClient] Request ID: ${r}, Extension: ${this.extensionId}`), new Promise((s, i) => {
1336
1344
  try {
1337
- chrome.runtime.sendMessage(this.extensionId, i, (n) => {
1345
+ chrome.runtime.sendMessage(this.extensionId, o, (n) => {
1338
1346
  if (chrome.runtime.lastError) {
1339
1347
  this.logger.error(
1340
1348
  `[BodhiExtClient] Chrome runtime error for request ${r}:`,
1341
1349
  chrome.runtime.lastError
1342
- ), o(new Error(chrome.runtime.lastError.message));
1350
+ ), i(new Error(chrome.runtime.lastError.message));
1343
1351
  return;
1344
1352
  }
1345
1353
  if (this.logger.debug(`[BodhiExtClient] Response for request ${r}:`, n), !n) {
1346
- this.logger.error(`[BodhiExtClient] No response received for request ${r}`), o(new Error("No response from extension"));
1354
+ this.logger.error(`[BodhiExtClient] No response received for request ${r}`), i(new Error("No response from extension"));
1347
1355
  return;
1348
1356
  }
1349
1357
  n.type === _.EXT_RESPONSE && n.requestId === r ? (this.logger.debug(`[BodhiExtClient] ✓ Valid EXT_RESPONSE for ${r}`), s(n)) : (this.logger.error(
1350
1358
  `[BodhiExtClient] Invalid response format for ${r}:`,
1351
1359
  n
1352
- ), o(new T("extension_error", "Invalid response format")));
1360
+ ), i(new T("extension_error", "Invalid response format")));
1353
1361
  });
1354
1362
  } catch (n) {
1355
- this.logger.error(`[BodhiExtClient] Exception sending message for ${r}:`, n), o(n);
1363
+ this.logger.error(`[BodhiExtClient] Exception sending message for ${r}:`, n), i(n);
1356
1364
  }
1357
1365
  });
1358
1366
  }
@@ -1360,18 +1368,18 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1360
1368
  * Register a chrome.runtime.onConnect listener for a streaming port.
1361
1369
  * Validates port name and message type, then delegates to handler.
1362
1370
  */
1363
- registerStreamPortListener(e, t, r, i) {
1371
+ registerStreamPortListener(e, t, r, o) {
1364
1372
  chrome.runtime.onConnect.addListener((s) => {
1365
- s.name === e && (this.logger.info(`[BodhiExtClient] Port connected: ${e}`), s.onMessage.addListener(async (o) => {
1366
- if (o.type !== t) {
1367
- this.logger.warn(`[BodhiExtClient] Unknown message type on ${e}:`, o.type), s.postMessage({
1373
+ s.name === e && (this.logger.info(`[BodhiExtClient] Port connected: ${e}`), s.onMessage.addListener(async (i) => {
1374
+ if (i.type !== t) {
1375
+ this.logger.warn(`[BodhiExtClient] Unknown message type on ${e}:`, i.type), s.postMessage({
1368
1376
  type: r,
1369
- requestId: o.requestId,
1377
+ requestId: i.requestId,
1370
1378
  error: { message: "Unknown message type", type: "extension_error" }
1371
1379
  });
1372
1380
  return;
1373
1381
  }
1374
- await i(s, o);
1382
+ await o(s, i);
1375
1383
  }), s.onDisconnect.addListener(() => {
1376
1384
  this.logger.info(`[BodhiExtClient] Port disconnected: ${e}`);
1377
1385
  }));
@@ -1385,48 +1393,48 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1385
1393
  * @param onBodhiMessage Called for each message from bodhi-browser-ext.
1386
1394
  * Returns true if the stream is complete (triggers cleanup).
1387
1395
  */
1388
- async handleGenericStreamRelay(e, t, r, i, s, o, n) {
1396
+ async handleGenericStreamRelay(e, t, r, o, s, i, n) {
1389
1397
  if (this.logger.debug("[BodhiExtClient] Processing stream relay:", {
1390
1398
  requestId: t,
1391
1399
  method: r.method,
1392
1400
  endpoint: r.endpoint,
1393
- bodhiPortName: i
1401
+ bodhiPortName: o
1394
1402
  }), !this.extensionId) {
1395
1403
  e.postMessage({
1396
- type: o,
1404
+ type: i,
1397
1405
  requestId: t,
1398
1406
  error: { message: "Client not initialized (no extensionId)", type: "extension_error" }
1399
1407
  });
1400
1408
  return;
1401
1409
  }
1402
1410
  try {
1403
- let h = { ...r.headers };
1411
+ let u = { ...r.headers };
1404
1412
  if (r.authenticated !== !1) {
1405
- const u = await this._getAccessTokenRaw();
1406
- if (!u) {
1413
+ const d = await this._getAccessTokenRaw();
1414
+ if (!d) {
1407
1415
  e.postMessage({
1408
- type: o,
1416
+ type: i,
1409
1417
  requestId: t,
1410
1418
  error: { message: "Not authenticated. Please log in first.", type: "extension_error" }
1411
1419
  });
1412
1420
  return;
1413
1421
  }
1414
- h = { ...h, Authorization: `Bearer ${u}` }, this.logger.debug("[BodhiExtClient] Injected auth token for stream relay");
1422
+ u = { ...u, Authorization: `Bearer ${d}` }, this.logger.debug("[BodhiExtClient] Injected auth token for stream relay");
1415
1423
  }
1416
- const c = chrome.runtime.connect(this.extensionId, { name: i });
1424
+ const c = chrome.runtime.connect(this.extensionId, { name: o });
1417
1425
  this.activeStreamPorts.set(t, c);
1418
- const E = setTimeout(() => {
1426
+ const h = setTimeout(() => {
1419
1427
  this.activeStreamPorts.has(t) && (this.logger.error(`[BodhiExtClient] Stream timeout for ${t}`), e.postMessage({
1420
- type: o,
1428
+ type: i,
1421
1429
  requestId: t,
1422
1430
  error: { message: "Stream request timed out", type: "timeout_error" }
1423
1431
  }), this.cleanupStreamPort(t));
1424
1432
  }, p.STREAM_TIMEOUT);
1425
- c.onMessage.addListener((u) => {
1426
- n(u, e, t) && (clearTimeout(E), this.cleanupStreamPort(t));
1433
+ c.onMessage.addListener((d) => {
1434
+ n(d, e, t) && (clearTimeout(h), this.cleanupStreamPort(t));
1427
1435
  }), c.onDisconnect.addListener(() => {
1428
- clearTimeout(E), this.activeStreamPorts.has(t) && (this.logger.error(`[BodhiExtClient] Bodhi port disconnected for ${t}`), e.postMessage({
1429
- type: o,
1436
+ clearTimeout(h), this.activeStreamPorts.has(t) && (this.logger.error(`[BodhiExtClient] Bodhi port disconnected for ${t}`), e.postMessage({
1437
+ type: i,
1430
1438
  requestId: t,
1431
1439
  error: {
1432
1440
  message: "Connection to Bodhi extension closed unexpectedly",
@@ -1434,21 +1442,21 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1434
1442
  }
1435
1443
  }), this.activeStreamPorts.delete(t));
1436
1444
  });
1437
- const l = {
1445
+ const E = {
1438
1446
  type: s,
1439
1447
  requestId: t,
1440
1448
  request: {
1441
1449
  method: r.method,
1442
1450
  endpoint: r.endpoint,
1443
1451
  body: r.body,
1444
- headers: h
1452
+ headers: u
1445
1453
  }
1446
1454
  };
1447
- this.logger.debug("[BodhiExtClient] Sending stream request to bodhi port:", l), c.postMessage(l);
1448
- } catch (h) {
1449
- const c = h;
1455
+ this.logger.debug("[BodhiExtClient] Sending stream request to bodhi port:", E), c.postMessage(E);
1456
+ } catch (u) {
1457
+ const c = u;
1450
1458
  this.logger.error("[BodhiExtClient] Stream relay error:", JSON.stringify(c.message)), e.postMessage({
1451
- type: o,
1459
+ type: i,
1452
1460
  requestId: t,
1453
1461
  error: {
1454
1462
  message: `uncaught error: ${JSON.stringify({ error: c, message: c.message })}`,
@@ -1474,34 +1482,34 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1474
1482
  * Handle SSE-parsed streaming request — translates STREAM_* messages to EXT2EXT_CLIENT_STREAM_*
1475
1483
  */
1476
1484
  async handleStreamRequest(e, t) {
1477
- const { requestId: r, request: i } = t;
1485
+ const { requestId: r, request: o } = t;
1478
1486
  await this.handleGenericStreamRelay(
1479
1487
  e,
1480
1488
  r,
1481
- i,
1482
- ie,
1489
+ o,
1490
+ ne,
1483
1491
  _.STREAM_REQUEST,
1484
1492
  a.EXT2EXT_CLIENT_STREAM_ERROR,
1485
- (s, o, n) => {
1486
- if (ne(s)) {
1487
- const h = s.response, c = h.body;
1488
- return h.status >= 400 ? (o.postMessage({
1493
+ (s, i, n) => {
1494
+ if (oe(s)) {
1495
+ const u = s.response, c = u.body;
1496
+ return u.status >= 400 ? (i.postMessage({
1489
1497
  type: a.EXT2EXT_CLIENT_STREAM_API_ERROR,
1490
1498
  requestId: n,
1491
- response: h
1492
- }), !1) : c?.done ? (o.postMessage({
1499
+ response: u
1500
+ }), !1) : c?.done ? (i.postMessage({
1493
1501
  type: a.EXT2EXT_CLIENT_STREAM_DONE,
1494
1502
  requestId: n
1495
- }), this.logger.info(`[BodhiExtClient] Stream complete for ${n}`), !0) : (o.postMessage({
1503
+ }), this.logger.info(`[BodhiExtClient] Stream complete for ${n}`), !0) : (i.postMessage({
1496
1504
  type: a.EXT2EXT_CLIENT_STREAM_CHUNK,
1497
1505
  requestId: n,
1498
- response: h
1506
+ response: u
1499
1507
  }), !1);
1500
1508
  } else {
1501
1509
  if (ae(s))
1502
1510
  return this.logger.error(
1503
1511
  `[BodhiExtClient] Stream API error for ${n}: ${s.response.status}`
1504
- ), o.postMessage({
1512
+ ), i.postMessage({
1505
1513
  type: a.EXT2EXT_CLIENT_STREAM_API_ERROR,
1506
1514
  requestId: n,
1507
1515
  response: s.response
@@ -1510,7 +1518,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1510
1518
  return this.logger.error(
1511
1519
  `[BodhiExtClient] Stream error for ${n}:`,
1512
1520
  s.error.message
1513
- ), o.postMessage({
1521
+ ), i.postMessage({
1514
1522
  type: a.EXT2EXT_CLIENT_STREAM_ERROR,
1515
1523
  requestId: n,
1516
1524
  error: {
@@ -1527,31 +1535,31 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1527
1535
  * Handle raw text streaming request — translates STREAM_TEXT_* messages to EXT2EXT_CLIENT_STREAM_TEXT_*
1528
1536
  */
1529
1537
  async handleStreamTextRequest(e, t) {
1530
- const { requestId: r, request: i } = t;
1538
+ const { requestId: r, request: o } = t;
1531
1539
  await this.handleGenericStreamRelay(
1532
1540
  e,
1533
1541
  r,
1534
- i,
1542
+ o,
1535
1543
  he,
1536
1544
  _.STREAM_TEXT_REQUEST,
1537
1545
  a.EXT2EXT_CLIENT_STREAM_TEXT_ERROR,
1538
- (s, o, n) => {
1546
+ (s, i, n) => {
1539
1547
  switch (s.type) {
1540
1548
  case _.STREAM_TEXT_START:
1541
- return o.postMessage({
1549
+ return i.postMessage({
1542
1550
  type: a.EXT2EXT_CLIENT_STREAM_TEXT_START,
1543
1551
  requestId: n,
1544
1552
  status: s.status,
1545
1553
  headers: s.headers
1546
1554
  }), !1;
1547
1555
  case _.STREAM_TEXT_CHUNK:
1548
- return o.postMessage({
1556
+ return i.postMessage({
1549
1557
  type: a.EXT2EXT_CLIENT_STREAM_TEXT_CHUNK,
1550
1558
  requestId: n,
1551
1559
  chunk: s.chunk
1552
1560
  }), !1;
1553
1561
  case _.STREAM_TEXT_DONE:
1554
- return this.logger.info(`[BodhiExtClient] Stream text complete for ${n}`), o.postMessage({
1562
+ return this.logger.info(`[BodhiExtClient] Stream text complete for ${n}`), i.postMessage({
1555
1563
  type: a.EXT2EXT_CLIENT_STREAM_TEXT_DONE,
1556
1564
  requestId: n
1557
1565
  }), !0;
@@ -1559,7 +1567,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1559
1567
  return this.logger.error(
1560
1568
  `[BodhiExtClient] Stream text error for ${n}:`,
1561
1569
  s.error.message
1562
- ), o.postMessage({
1570
+ ), i.postMessage({
1563
1571
  type: a.EXT2EXT_CLIENT_STREAM_TEXT_ERROR,
1564
1572
  requestId: n,
1565
1573
  error: s.error
@@ -1626,7 +1634,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1626
1634
  } catch (t) {
1627
1635
  this.logger.warn("Token refresh failed:", t);
1628
1636
  }
1629
- throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"), d(
1637
+ throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"), l(
1630
1638
  "auth_error",
1631
1639
  "Access token expired and unable to refresh. Try logging out and logging in again."
1632
1640
  );
@@ -1654,10 +1662,10 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1654
1662
  ]);
1655
1663
  }
1656
1664
  parseJwt(e) {
1657
- const r = e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"), i = decodeURIComponent(
1665
+ const r = e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"), o = decodeURIComponent(
1658
1666
  atob(r).split("").map((s) => "%" + ("00" + s.charCodeAt(0).toString(16)).slice(-2)).join("")
1659
1667
  );
1660
- return JSON.parse(i);
1668
+ return JSON.parse(o);
1661
1669
  }
1662
1670
  createErrorClientNotInitialized(e) {
1663
1671
  return `Client not initialized. Extension discovery not triggered nor extensionId set, cannot handle request: ${JSON.stringify(e)}`;
@@ -1665,7 +1673,7 @@ const Se = ["ggedphdcbekjlomjaidbajglgihbeaon"], Re = ["bjdjhiombmfbcoeojijpfckl
1665
1673
  };
1666
1674
  p.STREAM_TIMEOUT = 6e4;
1667
1675
  let A = p;
1668
- const xe = "production";
1676
+ const ye = "production";
1669
1677
  export {
1670
1678
  A as BodhiExtClient,
1671
1679
  _e as ChromeSessionStorageAdapter,
@@ -1678,8 +1686,8 @@ export {
1678
1686
  a as EXT2EXT_CLIENT_MESSAGE_TYPES,
1679
1687
  U as EXT2EXT_CLIENT_STREAM_PORT,
1680
1688
  D as EXT2EXT_CLIENT_STREAM_TEXT_PORT,
1681
- xe as EXT_BUILD_MODE,
1682
- ye as ExtUIClient,
1689
+ ye as EXT_BUILD_MODE,
1690
+ xe as ExtUIClient,
1683
1691
  Ae as InMemoryStorage,
1684
1692
  ge as isExtClientApiError
1685
1693
  };