@bodhiapp/bodhi-js 0.0.2 → 0.0.3

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