@bodhiapp/bodhi-js 0.0.5 → 0.0.6

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,38 +1,48 @@
1
- import { DirectClientBase as R, createStoragePrefixWithBasePath as y, STORAGE_PREFIXES as S, generateCodeVerifier as u, generateCodeChallenge as _, isApiResultOperationError as w, isApiResultSuccess as f, createStorageKeys as I, EXTENSION_STATE_NOT_INITIALIZED as p, Logger as T, createOAuthEndpoints as C, NOOP_STATE_CALLBACK as x, createOperationError as h, EXTENSION_STATE_NOT_FOUND as A, PENDING_EXTENSION_READY as k, BACKEND_SERVER_NOT_REACHABLE as g, extractUserInfo as m, refreshAccessToken as v, backendServerNotReady as E, SERVER_ERROR_CODES as b, createApiError as O, BaseFacadeClient as P } from "@bodhiapp/bodhi-js-core";
2
- class K extends R {
3
- constructor(e, t) {
4
- const r = e.basePath || "/", s = y(r, S.DIRECT);
5
- super({ ...e, storagePrefix: s }, "DirectWebClient", t), this.redirectUri = e.redirectUri;
1
+ import { DirectClientBase as C, createStoragePrefixWithBasePath as p, STORAGE_PREFIXES as S, isApiResultOperationError as f, createOperationError as h, isApiResultError as w, isApiResultSuccess as m, generateCodeVerifier as g, generateCodeChallenge as T, createStorageKeys as I, EXTENSION_STATE_NOT_INITIALIZED as y, Logger as R, createOAuthEndpoints as x, NOOP_STATE_CALLBACK as k, EXTENSION_STATE_NOT_FOUND as A, PENDING_EXTENSION_READY as v, BACKEND_SERVER_NOT_REACHABLE as d, extractUserInfo as _, refreshAccessToken as b, backendServerNotReady as E, SERVER_ERROR_CODES as O, createApiError as P, BaseFacadeClient as K } from "@bodhiapp/bodhi-js-core";
2
+ class U extends C {
3
+ constructor(t, e) {
4
+ const r = t.basePath || "/", s = p(r, S.DIRECT);
5
+ super({ ...t, storagePrefix: s }, "DirectWebClient", e), this.redirectUri = t.redirectUri;
6
6
  }
7
7
  // ============================================================================
8
8
  // Authentication (Browser Redirect OAuth)
9
9
  // ============================================================================
10
10
  async login() {
11
- const e = await this.getAuthState();
12
- if (e.isLoggedIn)
13
- return e;
14
- const t = await this.requestResourceAccess(), r = `openid profile email roles ${this.userScope} ${t}`, s = u(), i = await _(s), o = u();
15
- localStorage.setItem(this.storageKeys.CODE_VERIFIER, s), localStorage.setItem(this.storageKeys.STATE, o);
11
+ const t = await this.getAuthState();
12
+ if (t.status === "authenticated")
13
+ return t;
14
+ const e = await this.requestResourceAccess();
15
+ if (f(e))
16
+ throw h(e.error.message, e.error.type);
17
+ if (w(e)) {
18
+ const { message: i } = e.body.error;
19
+ throw h(i, "auth_error");
20
+ }
21
+ if (!m(e))
22
+ throw h(`Unexpected HTTP ${e.status}`, "auth_error");
23
+ const r = e.body.scope;
24
+ localStorage.setItem(this.storageKeys.RESOURCE_SCOPE, r);
25
+ const s = `openid profile email roles ${this.userScope} ${r}`, a = g(), o = await T(a), c = g();
26
+ localStorage.setItem(this.storageKeys.CODE_VERIFIER, a), localStorage.setItem(this.storageKeys.STATE, c);
16
27
  const n = new URL(this.authEndpoints.authorize);
17
- throw n.searchParams.set("client_id", this.authClientId), n.searchParams.set("response_type", "code"), n.searchParams.set("redirect_uri", this.redirectUri), n.searchParams.set("scope", r), n.searchParams.set("code_challenge", i), n.searchParams.set("code_challenge_method", "S256"), n.searchParams.set("state", o), window.location.href = n.toString(), new Error("Redirect initiated");
28
+ throw n.searchParams.set("client_id", this.authClientId), n.searchParams.set("response_type", "code"), n.searchParams.set("redirect_uri", this.redirectUri), n.searchParams.set("scope", s), n.searchParams.set("code_challenge", o), n.searchParams.set("code_challenge_method", "S256"), n.searchParams.set("state", c), window.location.href = n.toString(), new Error("Redirect initiated");
18
29
  }
19
- async handleOAuthCallback(e, t) {
30
+ async handleOAuthCallback(t, e) {
20
31
  const r = localStorage.getItem(this.storageKeys.STATE);
21
- if (!r || r !== t)
32
+ if (!r || r !== e)
22
33
  throw new Error("Invalid state parameter - possible CSRF attack");
23
- await this.exchangeCodeForTokens(e), localStorage.removeItem(this.storageKeys.CODE_VERIFIER), localStorage.removeItem(this.storageKeys.STATE);
34
+ await this.exchangeCodeForTokens(t), localStorage.removeItem(this.storageKeys.CODE_VERIFIER), localStorage.removeItem(this.storageKeys.STATE);
24
35
  const s = await this.getAuthState();
25
- if (!s.isLoggedIn)
36
+ if (s.status !== "authenticated")
26
37
  throw new Error("Login failed");
27
- const i = s;
28
- return this.setAuthState(i), i;
38
+ return this.setAuthState(s), s;
29
39
  }
30
40
  async logout() {
31
- const e = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
32
- if (e)
41
+ const t = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
42
+ if (t)
33
43
  try {
34
44
  const r = new URLSearchParams({
35
- token: e,
45
+ token: t,
36
46
  client_id: this.authClientId,
37
47
  token_type_hint: "refresh_token"
38
48
  });
@@ -47,32 +57,20 @@ class K extends R {
47
57
  this.logger.warn("Token revocation failed:", r);
48
58
  }
49
59
  localStorage.removeItem(this.storageKeys.ACCESS_TOKEN), localStorage.removeItem(this.storageKeys.REFRESH_TOKEN), localStorage.removeItem(this.storageKeys.EXPIRES_AT), localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);
50
- const t = {
51
- isLoggedIn: !1
60
+ const e = {
61
+ status: "unauthenticated",
62
+ user: null,
63
+ accessToken: null,
64
+ error: null
52
65
  };
53
- return this.setAuthState(t), t;
66
+ return this.setAuthState(e), e;
54
67
  }
55
68
  // ============================================================================
56
69
  // OAuth Helper Methods
57
70
  // ============================================================================
58
- async requestResourceAccess() {
59
- const e = await this.sendApiRequest(
60
- "POST",
61
- "/bodhi/v1/apps/request-access",
62
- { app_client_id: this.authClientId },
63
- {},
64
- !1
65
- );
66
- if (w(e))
67
- throw new Error("Failed to get resource access scope from server");
68
- if (!f(e))
69
- throw new Error("Failed to get resource access scope from server: API error");
70
- const t = e.body.scope;
71
- return localStorage.setItem(this.storageKeys.RESOURCE_SCOPE, t), t;
72
- }
73
- async exchangeCodeForTokens(e) {
74
- const t = localStorage.getItem(this.storageKeys.CODE_VERIFIER);
75
- if (!t)
71
+ async exchangeCodeForTokens(t) {
72
+ const e = localStorage.getItem(this.storageKeys.CODE_VERIFIER);
73
+ if (!e)
76
74
  throw new Error("Code verifier not found");
77
75
  const r = await fetch(this.authEndpoints.token, {
78
76
  method: "POST",
@@ -81,67 +79,67 @@ class K extends R {
81
79
  },
82
80
  body: new URLSearchParams({
83
81
  grant_type: "authorization_code",
84
- code: e,
82
+ code: t,
85
83
  redirect_uri: this.redirectUri,
86
84
  client_id: this.authClientId,
87
- code_verifier: t
85
+ code_verifier: e
88
86
  })
89
87
  });
90
88
  if (!r.ok) {
91
- const i = await r.text();
92
- throw new Error(`Token exchange failed: ${r.status} ${i}`);
89
+ const a = await r.text();
90
+ throw new Error(`Token exchange failed: ${r.status} ${a}`);
93
91
  }
94
92
  const s = await r.json();
95
93
  if (localStorage.setItem(this.storageKeys.ACCESS_TOKEN, s.access_token), s.refresh_token && localStorage.setItem(this.storageKeys.REFRESH_TOKEN, s.refresh_token), s.expires_in) {
96
- const i = Date.now() + s.expires_in * 1e3;
97
- localStorage.setItem(this.storageKeys.EXPIRES_AT, i.toString());
94
+ const a = Date.now() + s.expires_in * 1e3;
95
+ localStorage.setItem(this.storageKeys.EXPIRES_AT, a.toString());
98
96
  }
99
97
  }
100
98
  // ============================================================================
101
99
  // Storage Implementation (localStorage)
102
100
  // ============================================================================
103
- async _storageGet(e) {
104
- return localStorage.getItem(e);
101
+ async _storageGet(t) {
102
+ return localStorage.getItem(t);
105
103
  }
106
- async _storageSet(e) {
107
- Object.entries(e).forEach(([t, r]) => {
108
- localStorage.setItem(t, String(r));
104
+ async _storageSet(t) {
105
+ Object.entries(t).forEach(([e, r]) => {
106
+ localStorage.setItem(e, String(r));
109
107
  });
110
108
  }
111
- async _storageRemove(e) {
112
- e.forEach((t) => localStorage.removeItem(t));
109
+ async _storageRemove(t) {
110
+ t.forEach((e) => localStorage.removeItem(e));
113
111
  }
114
112
  _getRedirectUri() {
115
113
  return this.redirectUri;
116
114
  }
117
115
  }
118
- const U = 500, L = 5e3;
116
+ const N = 500, D = 5e3;
119
117
  I(S.WEB);
120
- function N(l = "/") {
121
- const e = y(l, S.WEB);
122
- return I(e);
118
+ function L(u = "/") {
119
+ const t = p(u, S.WEB);
120
+ return I(t);
123
121
  }
124
- class D {
125
- constructor(e, t, r, s) {
126
- this.state = p, this.bodhiext = null, this.refreshPromise = null, this.logger = new T("WindowBodhiextClient", t.logLevel), this.authClientId = e, this.config = t, this.authEndpoints = C(this.config.authServerUrl), this.onStateChange = r ?? x, this.storageKeys = N(s || "/");
122
+ class F {
123
+ constructor(t, e, r, s) {
124
+ this.state = y, this.bodhiext = null, this.refreshPromise = null, this.logger = new R("WindowBodhiextClient", e.logLevel), this.authClientId = t, this.config = e, this.authEndpoints = x(this.config.authServerUrl), this.onStateChange = r ?? k, this.storageKeys = L(s || "/");
127
125
  }
128
126
  /**
129
127
  * Set client state and notify callback
130
128
  */
131
- setState(e) {
132
- this.state = e, this.logger.info(`{state: ${JSON.stringify(e)}} - Setting client state`), this.onStateChange({ type: "client-state", state: e });
129
+ setState(t) {
130
+ this.state = t, this.logger.info(`{state: ${JSON.stringify(t)}} - Setting client state`), this.onStateChange({ type: "client-state", state: t });
133
131
  }
134
132
  /**
135
133
  * Set auth state and notify callback
136
134
  */
137
- setAuthState(e) {
138
- this.onStateChange({ type: "auth-state", state: e });
135
+ setAuthState(t) {
136
+ this.onStateChange({ type: "auth-state", state: t });
139
137
  }
140
138
  /**
141
139
  * Set or update the state change callback
142
140
  */
143
- setStateCallback(e) {
144
- this.onStateChange = e;
141
+ setStateCallback(t) {
142
+ this.onStateChange = t;
145
143
  }
146
144
  // ============================================================================
147
145
  // Extension Communication
@@ -157,14 +155,14 @@ class D {
157
155
  /**
158
156
  * Send extension request via window.bodhiext.sendExtRequest
159
157
  */
160
- async sendExtRequest(e, t) {
161
- return this.ensureBodhiext(), this.bodhiext.sendExtRequest(e, t);
158
+ async sendExtRequest(t, e) {
159
+ return this.ensureBodhiext(), this.bodhiext.sendExtRequest(t, e);
162
160
  }
163
161
  /**
164
162
  * Send API message via window.bodhiext.sendApiRequest
165
163
  * Converts ApiResponse to ApiResponseResult
166
164
  */
167
- async sendApiRequest(e, t, r, s, i) {
165
+ async sendApiRequest(t, e, r, s, a) {
168
166
  try {
169
167
  this.ensureBodhiext();
170
168
  } catch (o) {
@@ -177,9 +175,9 @@ class D {
177
175
  }
178
176
  try {
179
177
  let o = s || {};
180
- if (i) {
181
- const c = await this._getAccessTokenRaw();
182
- if (!c)
178
+ if (a) {
179
+ const n = await this._getAccessTokenRaw();
180
+ if (!n)
183
181
  return {
184
182
  error: {
185
183
  message: "Not authenticated. Please log in first.",
@@ -188,21 +186,21 @@ class D {
188
186
  };
189
187
  o = {
190
188
  ...o,
191
- Authorization: `Bearer ${c}`
189
+ Authorization: `Bearer ${n}`
192
190
  };
193
191
  }
194
192
  return await this.bodhiext.sendApiRequest(
195
- e,
196
193
  t,
194
+ e,
197
195
  r,
198
196
  o
199
197
  );
200
198
  } catch (o) {
201
- const n = o?.error, c = n?.message ?? (o instanceof Error ? o.message : String(o)), a = n?.type || "extension_error";
199
+ const c = o?.error, n = c?.message ?? (o instanceof Error ? o.message : String(o)), i = c?.type || "extension_error";
202
200
  return {
203
201
  error: {
204
- message: c,
205
- type: a
202
+ message: n,
203
+ type: i
206
204
  }
207
205
  };
208
206
  }
@@ -226,43 +224,43 @@ class D {
226
224
  * Note: Web mode uses stateless discovery (always polls for window.bodhiext)
227
225
  * No extensionId storage/restoration needed - window.bodhiext handle is ephemeral
228
226
  */
229
- async init(e = {}) {
230
- if (!e.testConnection && !e.selectedConnection)
231
- return this.logger.info("No testConnection or selectedConnection, returning not-initialized state"), p;
232
- if (this.bodhiext && !e.testConnection)
227
+ async init(t = {}) {
228
+ if (!t.testConnection && !t.selectedConnection)
229
+ return this.logger.info("No testConnection or selectedConnection, returning not-initialized state"), y;
230
+ if (this.bodhiext && !t.testConnection)
233
231
  return this.logger.debug("Already have bodhiext handle, skipping polling"), this.state;
234
232
  if (!this.bodhiext) {
235
- const s = e.timeoutMs ?? this.config.initParams?.extension?.timeoutMs ?? L, i = e.intervalMs ?? this.config.initParams?.extension?.intervalMs ?? U, o = Date.now();
236
- if (!await new Promise((c) => {
237
- const a = () => {
233
+ const s = t.timeoutMs ?? this.config.initParams?.extension?.timeoutMs ?? D, a = t.intervalMs ?? this.config.initParams?.extension?.intervalMs ?? N, o = Date.now();
234
+ if (!await new Promise((n) => {
235
+ const i = () => {
238
236
  if (window.bodhiext) {
239
- this.bodhiext = window.bodhiext, c(!0);
237
+ this.bodhiext = window.bodhiext, n(!0);
240
238
  return;
241
239
  }
242
240
  if (Date.now() - o >= s) {
243
- c(!1);
241
+ n(!1);
244
242
  return;
245
243
  }
246
- setTimeout(a, i);
244
+ setTimeout(i, a);
247
245
  };
248
- a();
246
+ i();
249
247
  }))
250
248
  return this.logger.warn("Extension discovery timed out"), this.setState(A), this.state;
251
249
  }
252
- const t = await this.bodhiext.getExtensionId();
253
- this.logger.info(`Extension discovered: ${t}`);
250
+ const e = await this.bodhiext.getExtensionId();
251
+ this.logger.info(`Extension discovered: ${e}`);
254
252
  const r = {
255
253
  type: "extension",
256
254
  extension: "ready",
257
- extensionId: t,
258
- server: k
255
+ extensionId: e,
256
+ server: v
259
257
  };
260
- if (e.testConnection)
258
+ if (t.testConnection)
261
259
  try {
262
260
  const s = await this.getServerState();
263
261
  this.setState({ ...r, server: s }), this.logger.info(`Server connectivity tested: ${s.status}`);
264
262
  } catch (s) {
265
- this.logger.error("Failed to get server state:", s), this.setState({ ...r, server: g });
263
+ this.logger.error("Failed to get server state:", s), this.setState({ ...r, server: d });
266
264
  }
267
265
  else
268
266
  this.setState(r);
@@ -276,66 +274,74 @@ class D {
276
274
  * Required for authenticated API access
277
275
  */
278
276
  async requestResourceAccess() {
279
- this.ensureBodhiext();
280
- const e = await this.bodhiext.sendApiRequest("POST", "/bodhi/v1/apps/request-access", {
281
- app_client_id: this.authClientId
282
- });
283
- if (!f(e))
284
- throw new Error("Failed to get resource access scope: API error");
285
- const t = e.body.scope;
286
- return localStorage.setItem(this.storageKeys.RESOURCE_SCOPE, t), t;
277
+ return this.ensureBodhiext(), this.bodhiext.sendApiRequest(
278
+ "POST",
279
+ "/bodhi/v1/apps/request-access",
280
+ { app_client_id: this.authClientId }
281
+ );
287
282
  }
288
283
  /**
289
284
  * Login via browser redirect OAuth2 + PKCE flow
290
- * @returns AuthLoggedIn (though in practice, this redirects and never returns)
285
+ * @returns AuthState (though in practice, this redirects and never returns)
291
286
  */
292
287
  async login() {
293
- const e = await this.getAuthState();
294
- if (e.isLoggedIn)
295
- return e;
288
+ const t = await this.getAuthState();
289
+ if (t.status === "authenticated")
290
+ return t;
296
291
  this.ensureBodhiext();
297
- const t = await this.requestResourceAccess(), r = u(), s = await _(r), i = u();
298
- localStorage.setItem(this.storageKeys.CODE_VERIFIER, r), localStorage.setItem(this.storageKeys.STATE, i);
299
- const o = ["openid", "profile", "email", "roles", this.config.userScope, t], n = new URLSearchParams({
292
+ const e = await this.requestResourceAccess();
293
+ if (f(e))
294
+ throw h(e.error.message, e.error.type);
295
+ if (w(e)) {
296
+ const { message: l } = e.body.error;
297
+ throw h(l, "auth_error");
298
+ }
299
+ if (!m(e))
300
+ throw h(`Unexpected HTTP ${e.status}`, "auth_error");
301
+ const r = e.body.scope;
302
+ localStorage.setItem(this.storageKeys.RESOURCE_SCOPE, r);
303
+ const s = g(), a = await T(s), o = g();
304
+ localStorage.setItem(this.storageKeys.CODE_VERIFIER, s), localStorage.setItem(this.storageKeys.STATE, o);
305
+ const c = ["openid", "profile", "email", "roles", this.config.userScope, r], n = new URLSearchParams({
300
306
  response_type: "code",
301
307
  client_id: this.authClientId,
302
308
  redirect_uri: this.config.redirectUri,
303
- scope: o.join(" "),
304
- state: i,
305
- code_challenge: s,
309
+ scope: c.join(" "),
310
+ state: o,
311
+ code_challenge: a,
306
312
  code_challenge_method: "S256"
307
- }), c = `${this.authEndpoints.authorize}?${n}`;
308
- return window.location.href = c, new Promise(() => {
313
+ }), i = `${this.authEndpoints.authorize}?${n}`;
314
+ return window.location.href = i, new Promise(() => {
309
315
  });
310
316
  }
311
317
  /**
312
318
  * Handle OAuth callback with authorization code
313
319
  * Should be called from callback page with extracted URL params
314
- * @returns AuthLoggedIn with login state and user info
320
+ * @returns AuthState with login state and user info
315
321
  */
316
- async handleOAuthCallback(e, t) {
322
+ async handleOAuthCallback(t, e) {
317
323
  const r = localStorage.getItem(this.storageKeys.STATE);
318
- if (!r || r !== t)
324
+ if (!r || r !== e)
319
325
  throw new Error("Invalid state parameter - possible CSRF attack");
320
- await this.exchangeCodeForTokens(e), localStorage.removeItem(this.storageKeys.CODE_VERIFIER), localStorage.removeItem(this.storageKeys.STATE);
326
+ await this.exchangeCodeForTokens(t), localStorage.removeItem(this.storageKeys.CODE_VERIFIER), localStorage.removeItem(this.storageKeys.STATE);
321
327
  const s = await this.getAuthState();
322
- if (!s.isLoggedIn)
328
+ if (s.status !== "authenticated")
323
329
  throw new Error("Login failed");
324
330
  return this.setAuthState(s), s;
325
331
  }
326
332
  /**
327
333
  * Exchange authorization code for tokens
328
334
  */
329
- async exchangeCodeForTokens(e) {
330
- const t = localStorage.getItem(this.storageKeys.CODE_VERIFIER);
331
- if (!t)
335
+ async exchangeCodeForTokens(t) {
336
+ const e = localStorage.getItem(this.storageKeys.CODE_VERIFIER);
337
+ if (!e)
332
338
  throw new Error("Code verifier not found");
333
339
  const r = new URLSearchParams({
334
340
  grant_type: "authorization_code",
335
341
  client_id: this.authClientId,
336
- code: e,
342
+ code: t,
337
343
  redirect_uri: this.config.redirectUri,
338
- code_verifier: t
344
+ code_verifier: e
339
345
  }), s = await fetch(this.authEndpoints.token, {
340
346
  method: "POST",
341
347
  headers: {
@@ -347,11 +353,11 @@ class D {
347
353
  const o = await s.text();
348
354
  throw new Error(`Token exchange failed: ${s.status} ${o}`);
349
355
  }
350
- const i = await s.json();
351
- if (!i.access_token)
356
+ const a = await s.json();
357
+ if (!a.access_token)
352
358
  throw new Error("No access token received");
353
- if (localStorage.setItem(this.storageKeys.ACCESS_TOKEN, i.access_token), i.refresh_token && localStorage.setItem(this.storageKeys.REFRESH_TOKEN, i.refresh_token), i.expires_in) {
354
- const o = Date.now() + i.expires_in * 1e3;
359
+ if (localStorage.setItem(this.storageKeys.ACCESS_TOKEN, a.access_token), a.refresh_token && localStorage.setItem(this.storageKeys.REFRESH_TOKEN, a.refresh_token), a.expires_in) {
360
+ const o = Date.now() + a.expires_in * 1e3;
355
361
  localStorage.setItem(this.storageKeys.EXPIRES_AT, o.toString());
356
362
  }
357
363
  }
@@ -360,11 +366,11 @@ class D {
360
366
  * @returns AuthLoggedOut with logged out state
361
367
  */
362
368
  async logout() {
363
- const e = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
364
- if (e)
369
+ const t = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
370
+ if (t)
365
371
  try {
366
372
  const r = new URLSearchParams({
367
- token: e,
373
+ token: t,
368
374
  client_id: this.authClientId,
369
375
  token_type_hint: "refresh_token"
370
376
  });
@@ -379,22 +385,25 @@ class D {
379
385
  this.logger.warn("Token revocation failed:", r);
380
386
  }
381
387
  localStorage.removeItem(this.storageKeys.ACCESS_TOKEN), localStorage.removeItem(this.storageKeys.REFRESH_TOKEN), localStorage.removeItem(this.storageKeys.EXPIRES_AT), localStorage.removeItem(this.storageKeys.CODE_VERIFIER), localStorage.removeItem(this.storageKeys.STATE), localStorage.removeItem(this.storageKeys.RESOURCE_SCOPE);
382
- const t = {
383
- isLoggedIn: !1
388
+ const e = {
389
+ status: "unauthenticated",
390
+ user: null,
391
+ accessToken: null,
392
+ error: null
384
393
  };
385
- return this.setAuthState(t), t;
394
+ return this.setAuthState(e), e;
386
395
  }
387
396
  /**
388
397
  * Get current authentication state
389
398
  */
390
399
  async getAuthState() {
391
- const e = await this._getAccessTokenRaw();
392
- if (!e)
393
- return { isLoggedIn: !1 };
400
+ const t = await this._getAccessTokenRaw();
401
+ if (!t)
402
+ return { status: "unauthenticated", user: null, accessToken: null, error: null };
394
403
  try {
395
- return { isLoggedIn: !0, userInfo: m(e), accessToken: e };
396
- } catch (t) {
397
- return this.logger.error("Failed to parse token:", t), { isLoggedIn: !1 };
404
+ return { status: "authenticated", user: _(t), accessToken: t, error: null };
405
+ } catch (e) {
406
+ return this.logger.error("Failed to parse token:", e), { status: "unauthenticated", user: null, accessToken: null, error: null };
398
407
  }
399
408
  }
400
409
  /**
@@ -402,26 +411,26 @@ class D {
402
411
  * Returns null if not logged in or token expired
403
412
  */
404
413
  async _getAccessTokenRaw() {
405
- const e = localStorage.getItem(this.storageKeys.ACCESS_TOKEN), t = localStorage.getItem(this.storageKeys.EXPIRES_AT);
406
- if (!e)
414
+ const t = localStorage.getItem(this.storageKeys.ACCESS_TOKEN), e = localStorage.getItem(this.storageKeys.EXPIRES_AT);
415
+ if (!t)
407
416
  return null;
408
- if (t) {
409
- const r = parseInt(t, 10);
417
+ if (e) {
418
+ const r = parseInt(e, 10);
410
419
  if (Date.now() >= r - 5 * 1e3) {
411
420
  const s = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
412
421
  return s ? this._tryRefreshToken(s) : null;
413
422
  }
414
423
  }
415
- return e;
424
+ return t;
416
425
  }
417
426
  /**
418
427
  * Try to refresh access token using refresh token
419
428
  * Race condition prevention: Returns existing promise if refresh already in progress
420
429
  */
421
- async _tryRefreshToken(e) {
430
+ async _tryRefreshToken(t) {
422
431
  if (this.refreshPromise)
423
432
  return this.logger.debug("Refresh already in progress, returning existing promise"), this.refreshPromise;
424
- this.refreshPromise = this._doRefreshToken(e);
433
+ this.refreshPromise = this._doRefreshToken(t);
425
434
  try {
426
435
  return await this.refreshPromise;
427
436
  } finally {
@@ -431,25 +440,26 @@ class D {
431
440
  /**
432
441
  * Perform the actual token refresh
433
442
  */
434
- async _doRefreshToken(e) {
443
+ async _doRefreshToken(t) {
435
444
  this.logger.debug("Refreshing access token");
436
445
  try {
437
- const t = await v(
446
+ const e = await b(
438
447
  this.authEndpoints.token,
439
- e,
448
+ t,
440
449
  this.authClientId
441
450
  );
442
- if (t) {
443
- this._storeRefreshedTokens(t);
444
- const r = m(t.access_token);
451
+ if (e) {
452
+ this._storeRefreshedTokens(e);
453
+ const r = _(e.access_token);
445
454
  return this.setAuthState({
446
- isLoggedIn: !0,
447
- userInfo: r,
448
- accessToken: t.access_token
449
- }), this.logger.info("Token refreshed successfully"), t.access_token;
455
+ status: "authenticated",
456
+ user: r,
457
+ accessToken: e.access_token,
458
+ error: null
459
+ }), this.logger.info("Token refreshed successfully"), e.access_token;
450
460
  }
451
- } catch (t) {
452
- this.logger.warn("Token refresh failed:", t);
461
+ } catch (e) {
462
+ this.logger.warn("Token refresh failed:", e);
453
463
  }
454
464
  throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"), h(
455
465
  "Access token expired and unable to refresh. Try logging out and logging in again.",
@@ -459,9 +469,9 @@ class D {
459
469
  /**
460
470
  * Store refreshed tokens
461
471
  */
462
- _storeRefreshedTokens(e) {
463
- const t = Date.now() + e.expires_in * 1e3;
464
- localStorage.setItem(this.storageKeys.ACCESS_TOKEN, e.access_token), localStorage.setItem(this.storageKeys.EXPIRES_AT, String(t)), e.refresh_token && localStorage.setItem(this.storageKeys.REFRESH_TOKEN, e.refresh_token);
472
+ _storeRefreshedTokens(t) {
473
+ const e = Date.now() + t.expires_in * 1e3;
474
+ localStorage.setItem(this.storageKeys.ACCESS_TOKEN, t.access_token), localStorage.setItem(this.storageKeys.EXPIRES_AT, String(e)), t.refresh_token && localStorage.setItem(this.storageKeys.REFRESH_TOKEN, t.refresh_token);
465
475
  }
466
476
  /**
467
477
  * Ping API
@@ -486,76 +496,76 @@ class D {
486
496
  * Calls /bodhi/v1/info and returns structured server state
487
497
  */
488
498
  async getServerState() {
489
- const e = await this.sendApiRequest("GET", "/bodhi/v1/info");
490
- if (w(e))
491
- return g;
492
- if (!f(e))
493
- return g;
494
- const t = e.body;
495
- switch (t.status) {
499
+ const t = await this.sendApiRequest("GET", "/bodhi/v1/info");
500
+ if (f(t))
501
+ return d;
502
+ if (!m(t))
503
+ return d;
504
+ const e = t.body;
505
+ switch (e.status) {
496
506
  case "ready":
497
- return { status: "ready", version: t.version || "unknown" };
507
+ return { status: "ready", version: e.version || "unknown", error: null };
498
508
  case "setup":
499
- return E("setup", t.version || "unknown");
509
+ return E("setup", e.version || "unknown");
500
510
  case "resource-admin":
501
- return E("resource-admin", t.version || "unknown");
511
+ return E("resource-admin", e.version || "unknown");
502
512
  case "error":
503
513
  return E(
504
514
  "error",
505
- t.version || "unknown",
506
- t.error ? { message: t.error.message, type: t.error.type } : b.SERVER_NOT_READY
515
+ e.version || "unknown",
516
+ e.error ? { message: e.error.message, type: e.error.type } : O.SERVER_NOT_READY
507
517
  );
508
518
  default:
509
- return g;
519
+ return d;
510
520
  }
511
521
  }
512
522
  /**
513
523
  * Generic streaming via window.bodhiext.sendStreamRequest
514
524
  * Wraps ReadableStream as AsyncGenerator
515
525
  */
516
- async *stream(e, t, r, s, i = !0) {
526
+ async *stream(t, e, r, s, a = !0) {
517
527
  this.ensureBodhiext();
518
528
  let o = s || {};
519
- if (i) {
520
- const a = await this._getAccessTokenRaw();
521
- if (!a)
529
+ if (a) {
530
+ const i = await this._getAccessTokenRaw();
531
+ if (!i)
522
532
  throw h("Not authenticated. Please log in first.", "auth_error");
523
533
  o = {
524
534
  ...o,
525
- Authorization: `Bearer ${a}`
535
+ Authorization: `Bearer ${i}`
526
536
  };
527
537
  }
528
- const c = this.bodhiext.sendStreamRequest(e, t, r, o).getReader();
538
+ const n = this.bodhiext.sendStreamRequest(t, e, r, o).getReader();
529
539
  try {
530
540
  for (; ; ) {
531
- const { value: a, done: d } = await c.read();
532
- if (d || a?.done)
541
+ const { value: i, done: l } = await n.read();
542
+ if (l || i?.done)
533
543
  break;
534
- yield a.body;
544
+ yield i.body;
535
545
  }
536
- } catch (a) {
537
- if (a instanceof Error) {
538
- if ("response" in a) {
539
- const d = a;
540
- throw O(a.message, d.response.status, d.response.body);
546
+ } catch (i) {
547
+ if (i instanceof Error) {
548
+ if ("response" in i) {
549
+ const l = i;
550
+ throw P(i.message, l.response.status, l.response.body);
541
551
  }
542
- throw "error" in a ? h(a.message, "extension_error") : h(a.message, "extension_error");
552
+ throw "error" in i ? h(i.message, "extension_error") : h(i.message, "extension_error");
543
553
  }
544
- throw a;
554
+ throw i;
545
555
  } finally {
546
- c.releaseLock();
556
+ n.releaseLock();
547
557
  }
548
558
  }
549
559
  /**
550
560
  * Chat streaming
551
561
  */
552
- async *streamChat(e, t, r = !0) {
562
+ async *streamChat(t, e, r = !0) {
553
563
  yield* this.stream(
554
564
  "POST",
555
565
  "/v1/chat/completions",
556
566
  {
557
- model: e,
558
- messages: [{ role: "user", content: t }],
567
+ model: t,
568
+ messages: [{ role: "user", content: e }],
559
569
  stream: !0
560
570
  },
561
571
  void 0,
@@ -586,34 +596,34 @@ class D {
586
596
  };
587
597
  }
588
598
  }
589
- class B extends P {
590
- constructor(e, t, r, s) {
591
- const i = {
592
- redirectUri: t.redirectUri,
593
- authServerUrl: t.authServerUrl || "https://id.getbodhi.app/realms/bodhi",
594
- userScope: t.userScope || "scope_user_user",
595
- basePath: t.basePath || "/",
596
- logLevel: t.logLevel || "warn",
597
- initParams: t.initParams
599
+ class q extends K {
600
+ constructor(t, e, r, s) {
601
+ const a = {
602
+ redirectUri: e.redirectUri,
603
+ authServerUrl: e.authServerUrl || "https://id.getbodhi.app/realms/bodhi",
604
+ userScope: e.userScope || "scope_user_user",
605
+ basePath: e.basePath || "/",
606
+ logLevel: e.logLevel || "warn",
607
+ initParams: e.initParams
598
608
  };
599
- super(e, i, r, s, t.basePath);
609
+ super(t, a, r, s, e.basePath);
600
610
  }
601
- createLogger(e) {
602
- return new T("WebUIClient", e.logLevel);
611
+ createLogger(t) {
612
+ return new R("WebUIClient", t.logLevel);
603
613
  }
604
- createExtClient(e, t) {
605
- return new D(this.authClientId, e, t, e.basePath);
614
+ createExtClient(t, e) {
615
+ return new F(this.authClientId, t, e, t.basePath);
606
616
  }
607
- createDirectClient(e, t, r) {
608
- return new K(
617
+ createDirectClient(t, e, r) {
618
+ return new U(
609
619
  {
610
- authClientId: e,
611
- authServerUrl: t.authServerUrl,
612
- redirectUri: t.redirectUri,
613
- userScope: t.userScope,
614
- logLevel: t.logLevel,
620
+ authClientId: t,
621
+ authServerUrl: e.authServerUrl,
622
+ redirectUri: e.redirectUri,
623
+ userScope: e.userScope,
624
+ logLevel: e.logLevel,
615
625
  storagePrefix: S.WEB,
616
- basePath: t.basePath
626
+ basePath: e.basePath
617
627
  },
618
628
  r
619
629
  );
@@ -621,12 +631,12 @@ class B extends P {
621
631
  // ============================================================================
622
632
  // Web-specific OAuth Callback
623
633
  // ============================================================================
624
- async handleOAuthCallback(e, t) {
625
- return this.connectionMode === "direct" ? this.directClient.handleOAuthCallback(e, t) : this.extClient.handleOAuthCallback(e, t);
634
+ async handleOAuthCallback(t, e) {
635
+ return this.connectionMode === "direct" ? this.directClient.handleOAuthCallback(t, e) : this.extClient.handleOAuthCallback(t, e);
626
636
  }
627
637
  }
628
- const q = "production";
638
+ const V = "production";
629
639
  export {
630
- q as WEB_BUILD_MODE,
631
- B as WebUIClient
640
+ V as WEB_BUILD_MODE,
641
+ q as WebUIClient
632
642
  };