@bodhiapp/bodhi-js 0.0.2 → 0.0.4

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