@bodhiapp/bodhi-js 0.0.4 → 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.
Files changed (34) hide show
  1. package/dist/bodhi-browser-ext/src/types/bodhiext.d.ts +0 -1
  2. package/dist/bodhi-browser-ext/src/types/common.d.ts +1 -0
  3. package/dist/bodhi-browser-ext/src/types/protocol.d.ts +0 -1
  4. package/dist/bodhi-js-sdk/core/src/direct-client-base.d.ts +5 -5
  5. package/dist/bodhi-js-sdk/core/src/errors.d.ts +0 -1
  6. package/dist/bodhi-js-sdk/core/src/facade-client-base.d.ts +5 -6
  7. package/dist/bodhi-js-sdk/core/src/interface.d.ts +14 -7
  8. package/dist/bodhi-js-sdk/core/src/logger.d.ts +0 -1
  9. package/dist/bodhi-js-sdk/core/src/oauth.d.ts +0 -1
  10. package/dist/bodhi-js-sdk/core/src/onboarding/config.d.ts +0 -1
  11. package/dist/bodhi-js-sdk/core/src/onboarding/modal.d.ts +1 -2
  12. package/dist/bodhi-js-sdk/core/src/onboarding/protocol-utils.d.ts +0 -1
  13. package/dist/bodhi-js-sdk/core/src/platform.d.ts +0 -1
  14. package/dist/bodhi-js-sdk/core/src/types/api.d.ts +0 -1
  15. package/dist/bodhi-js-sdk/core/src/types/auth.d.ts +37 -0
  16. package/dist/bodhi-js-sdk/core/src/types/callback.d.ts +1 -2
  17. package/dist/bodhi-js-sdk/core/src/types/client-state.d.ts +43 -94
  18. package/dist/bodhi-js-sdk/core/src/types/config.d.ts +0 -1
  19. package/dist/bodhi-js-sdk/core/src/types/index.d.ts +4 -3
  20. package/dist/bodhi-js-sdk/core/src/types/platform.d.ts +0 -1
  21. package/dist/bodhi-js-sdk/core/src/types/user-info.d.ts +0 -32
  22. package/dist/bodhi-js-sdk/web/src/constants.d.ts +0 -1
  23. package/dist/bodhi-js-sdk/web/src/direct-client.d.ts +4 -6
  24. package/dist/bodhi-js-sdk/web/src/ext-client.d.ts +7 -8
  25. package/dist/bodhi-js-sdk/web/src/facade-client.d.ts +2 -3
  26. package/dist/bodhi-js-sdk/web/src/index.d.ts +0 -1
  27. package/dist/bodhi-web.cjs.js +1 -1
  28. package/dist/bodhi-web.esm.d.ts +1 -0
  29. package/dist/bodhi-web.esm.js +274 -265
  30. package/dist/setup-modal/src/types/message-types.d.ts +0 -1
  31. package/dist/setup-modal/src/types/protocol.d.ts +0 -1
  32. package/dist/setup-modal/src/types/state.d.ts +0 -1
  33. package/dist/setup-modal/src/types/type-guards.d.ts +0 -1
  34. package/package.json +10 -6
@@ -1,38 +1,48 @@
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;
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(), 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)
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);
27
+ const n = new URL(this.authEndpoints.authorize);
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");
29
+ }
30
+ async handleOAuthCallback(t, e) {
31
+ const r = localStorage.getItem(this.storageKeys.STATE);
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);
24
- const r = await this.getAuthState();
25
- if (!r.isLoggedIn)
34
+ await this.exchangeCodeForTokens(t), localStorage.removeItem(this.storageKeys.CODE_VERIFIER), localStorage.removeItem(this.storageKeys.STATE);
35
+ const s = await this.getAuthState();
36
+ if (s.status !== "authenticated")
26
37
  throw new Error("Login failed");
27
- const i = r;
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
- const s = new URLSearchParams({
35
- token: e,
44
+ const r = new URLSearchParams({
45
+ token: t,
36
46
  client_id: this.authClientId,
37
47
  token_type_hint: "refresh_token"
38
48
  });
@@ -41,130 +51,118 @@ class L extends x {
41
51
  headers: {
42
52
  "Content-Type": "application/x-www-form-urlencoded"
43
53
  },
44
- body: s
54
+ body: r
45
55
  });
46
- } catch (s) {
47
- this.logger.warn("Token revocation failed:", s);
56
+ } catch (r) {
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 (T(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
- const s = await fetch(this.authEndpoints.token, {
75
+ const r = await fetch(this.authEndpoints.token, {
78
76
  method: "POST",
79
77
  headers: {
80
78
  "Content-Type": "application/x-www-form-urlencoded"
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
- if (!s.ok) {
91
- const i = await s.text();
92
- throw new Error(`Token exchange failed: ${s.status} ${i}`);
88
+ if (!r.ok) {
89
+ const a = await r.text();
90
+ throw new Error(`Token exchange failed: ${r.status} ${a}`);
93
91
  }
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());
92
+ const s = await r.json();
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) {
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, s]) => {
108
- localStorage.setItem(t, String(s));
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
116
  const N = 500, D = 5e3;
119
- R(u.WEB);
120
- function F(l = "/") {
121
- const e = w(l, u.WEB);
122
- return R(e);
117
+ I(S.WEB);
118
+ function L(u = "/") {
119
+ const t = p(u, S.WEB);
120
+ return I(t);
123
121
  }
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 || "/");
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
148
146
  // ============================================================================
149
147
  /**
150
148
  * Ensure bodhiext is available, attempting to acquire it if not already set
151
- * @throws Error if client not initialized
149
+ * @throws OperationError if client not initialized
152
150
  */
153
151
  ensureBodhiext() {
154
152
  if (!this.bodhiext && window.bodhiext && (this.logger.info("Acquiring window.bodhiext reference"), this.bodhiext = window.bodhiext), !this.bodhiext)
155
- throw new Error("Client not initialized");
153
+ throw h("Client not initialized", "extension_error");
156
154
  }
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, s, r, i) {
165
+ async sendApiRequest(t, e, r, s, a) {
168
166
  try {
169
167
  this.ensureBodhiext();
170
168
  } catch (o) {
@@ -176,10 +174,10 @@ class B {
176
174
  };
177
175
  }
178
176
  try {
179
- let o = r || {};
180
- if (i) {
181
- const c = await this._getAccessTokenRaw();
182
- if (!c)
177
+ let o = s || {};
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 B {
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,
197
- s,
194
+ e,
195
+ r,
198
196
  o
199
197
  );
200
198
  } 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";
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: n
202
+ message: n,
203
+ type: i
206
204
  }
207
205
  };
208
206
  }
@@ -226,47 +224,46 @@ class B {
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
- var r, i, o, a;
231
- if (!e.testConnection && !e.selectedConnection)
227
+ async init(t = {}) {
228
+ if (!t.testConnection && !t.selectedConnection)
232
229
  return this.logger.info("No testConnection or selectedConnection, returning not-initialized state"), y;
233
- if (this.bodhiext && !e.testConnection)
230
+ if (this.bodhiext && !t.testConnection)
234
231
  return this.logger.debug("Already have bodhiext handle, skipping polling"), this.state;
235
232
  if (!this.bodhiext) {
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 = () => {
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 = () => {
239
236
  if (window.bodhiext) {
240
- this.bodhiext = window.bodhiext, p(!0);
237
+ this.bodhiext = window.bodhiext, n(!0);
241
238
  return;
242
239
  }
243
- if (Date.now() - h >= c) {
244
- p(!1);
240
+ if (Date.now() - o >= s) {
241
+ n(!1);
245
242
  return;
246
243
  }
247
- setTimeout(m, n);
244
+ setTimeout(i, a);
248
245
  };
249
- m();
246
+ i();
250
247
  }))
251
- return this.logger.warn("Extension discovery timed out"), this.setState(v), this.state;
248
+ return this.logger.warn("Extension discovery timed out"), this.setState(A), this.state;
252
249
  }
253
- const t = await this.bodhiext.getExtensionId();
254
- this.logger.info(`Extension discovered: ${t}`);
255
- const s = {
250
+ const e = await this.bodhiext.getExtensionId();
251
+ this.logger.info(`Extension discovered: ${e}`);
252
+ const r = {
256
253
  type: "extension",
257
254
  extension: "ready",
258
- extensionId: t,
259
- server: b
255
+ extensionId: e,
256
+ server: v
260
257
  };
261
- if (e.testConnection)
258
+ if (t.testConnection)
262
259
  try {
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 });
260
+ const s = await this.getServerState();
261
+ this.setState({ ...r, server: s }), this.logger.info(`Server connectivity tested: ${s.status}`);
262
+ } catch (s) {
263
+ this.logger.error("Failed to get server state:", s), this.setState({ ...r, server: d });
267
264
  }
268
265
  else
269
- this.setState(s);
266
+ this.setState(r);
270
267
  return this.state;
271
268
  }
272
269
  // ============================================================================
@@ -277,82 +274,90 @@ class B {
277
274
  * Required for authenticated API access
278
275
  */
279
276
  async requestResourceAccess() {
280
- this.ensureBodhiext();
281
- const e = await this.bodhiext.sendApiRequest("POST", "/bodhi/v1/apps/request-access", {
282
- app_client_id: this.authClientId
283
- });
284
- if (!f(e))
285
- throw new Error("Failed to get resource access scope: API error");
286
- const t = e.body.scope;
287
- 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
+ );
288
282
  }
289
283
  /**
290
284
  * Login via browser redirect OAuth2 + PKCE flow
291
- * @returns AuthLoggedIn (though in practice, this redirects and never returns)
285
+ * @returns AuthState (though in practice, this redirects and never returns)
292
286
  */
293
287
  async login() {
294
- const e = await this.getAuthState();
295
- if (e.isLoggedIn)
296
- return e;
288
+ const t = await this.getAuthState();
289
+ if (t.status === "authenticated")
290
+ return t;
297
291
  this.ensureBodhiext();
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({
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({
301
306
  response_type: "code",
302
307
  client_id: this.authClientId,
303
308
  redirect_uri: this.config.redirectUri,
304
- scope: o.join(" "),
305
- state: i,
306
- code_challenge: r,
309
+ scope: c.join(" "),
310
+ state: o,
311
+ code_challenge: a,
307
312
  code_challenge_method: "S256"
308
- }), c = `${this.authEndpoints.authorize}?${a}`;
309
- return window.location.href = c, new Promise(() => {
313
+ }), i = `${this.authEndpoints.authorize}?${n}`;
314
+ return window.location.href = i, new Promise(() => {
310
315
  });
311
316
  }
312
317
  /**
313
318
  * Handle OAuth callback with authorization code
314
319
  * Should be called from callback page with extracted URL params
315
- * @returns AuthLoggedIn with login state and user info
320
+ * @returns AuthState with login state and user info
316
321
  */
317
- async handleOAuthCallback(e, t) {
318
- const s = localStorage.getItem(this.storageKeys.STATE);
319
- if (!s || s !== t)
322
+ async handleOAuthCallback(t, e) {
323
+ const r = localStorage.getItem(this.storageKeys.STATE);
324
+ if (!r || r !== e)
320
325
  throw new Error("Invalid state parameter - possible CSRF attack");
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)
326
+ await this.exchangeCodeForTokens(t), localStorage.removeItem(this.storageKeys.CODE_VERIFIER), localStorage.removeItem(this.storageKeys.STATE);
327
+ const s = await this.getAuthState();
328
+ if (s.status !== "authenticated")
324
329
  throw new Error("Login failed");
325
- return this.setAuthState(r), r;
330
+ return this.setAuthState(s), s;
326
331
  }
327
332
  /**
328
333
  * Exchange authorization code for tokens
329
334
  */
330
- async exchangeCodeForTokens(e) {
331
- const t = localStorage.getItem(this.storageKeys.CODE_VERIFIER);
332
- if (!t)
335
+ async exchangeCodeForTokens(t) {
336
+ const e = localStorage.getItem(this.storageKeys.CODE_VERIFIER);
337
+ if (!e)
333
338
  throw new Error("Code verifier not found");
334
- const s = new URLSearchParams({
339
+ const r = new URLSearchParams({
335
340
  grant_type: "authorization_code",
336
341
  client_id: this.authClientId,
337
- code: e,
342
+ code: t,
338
343
  redirect_uri: this.config.redirectUri,
339
- code_verifier: t
340
- }), r = await fetch(this.authEndpoints.token, {
344
+ code_verifier: e
345
+ }), s = await fetch(this.authEndpoints.token, {
341
346
  method: "POST",
342
347
  headers: {
343
348
  "Content-Type": "application/x-www-form-urlencoded"
344
349
  },
345
- body: s
350
+ body: r
346
351
  });
347
- if (!r.ok) {
348
- const o = await r.text();
349
- throw new Error(`Token exchange failed: ${r.status} ${o}`);
352
+ if (!s.ok) {
353
+ const o = await s.text();
354
+ throw new Error(`Token exchange failed: ${s.status} ${o}`);
350
355
  }
351
- const i = await r.json();
352
- if (!i.access_token)
356
+ const a = await s.json();
357
+ if (!a.access_token)
353
358
  throw new Error("No access token received");
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;
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;
356
361
  localStorage.setItem(this.storageKeys.EXPIRES_AT, o.toString());
357
362
  }
358
363
  }
@@ -361,11 +366,11 @@ class B {
361
366
  * @returns AuthLoggedOut with logged out state
362
367
  */
363
368
  async logout() {
364
- const e = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
365
- if (e)
369
+ const t = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
370
+ if (t)
366
371
  try {
367
- const s = new URLSearchParams({
368
- token: e,
372
+ const r = new URLSearchParams({
373
+ token: t,
369
374
  client_id: this.authClientId,
370
375
  token_type_hint: "refresh_token"
371
376
  });
@@ -374,28 +379,31 @@ class B {
374
379
  headers: {
375
380
  "Content-Type": "application/x-www-form-urlencoded"
376
381
  },
377
- body: s
382
+ body: r
378
383
  });
379
- } catch (s) {
380
- this.logger.warn("Token revocation failed:", s);
384
+ } catch (r) {
385
+ this.logger.warn("Token revocation failed:", r);
381
386
  }
382
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);
383
- const t = {
384
- isLoggedIn: !1
388
+ const e = {
389
+ status: "unauthenticated",
390
+ user: null,
391
+ accessToken: null,
392
+ error: null
385
393
  };
386
- return this.setAuthState(t), t;
394
+ return this.setAuthState(e), e;
387
395
  }
388
396
  /**
389
397
  * Get current authentication state
390
398
  */
391
399
  async getAuthState() {
392
- const e = await this._getAccessTokenRaw();
393
- if (!e)
394
- return { isLoggedIn: !1 };
400
+ const t = await this._getAccessTokenRaw();
401
+ if (!t)
402
+ return { status: "unauthenticated", user: null, accessToken: null, error: null };
395
403
  try {
396
- return { isLoggedIn: !0, userInfo: _(e), accessToken: e };
397
- } catch (t) {
398
- 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 };
399
407
  }
400
408
  }
401
409
  /**
@@ -403,26 +411,26 @@ class B {
403
411
  * Returns null if not logged in or token expired
404
412
  */
405
413
  async _getAccessTokenRaw() {
406
- const e = localStorage.getItem(this.storageKeys.ACCESS_TOKEN), t = localStorage.getItem(this.storageKeys.EXPIRES_AT);
407
- if (!e)
414
+ const t = localStorage.getItem(this.storageKeys.ACCESS_TOKEN), e = localStorage.getItem(this.storageKeys.EXPIRES_AT);
415
+ if (!t)
408
416
  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;
417
+ if (e) {
418
+ const r = parseInt(e, 10);
419
+ if (Date.now() >= r - 5 * 1e3) {
420
+ const s = localStorage.getItem(this.storageKeys.REFRESH_TOKEN);
421
+ return s ? this._tryRefreshToken(s) : null;
414
422
  }
415
423
  }
416
- return e;
424
+ return t;
417
425
  }
418
426
  /**
419
427
  * Try to refresh access token using refresh token
420
428
  * Race condition prevention: Returns existing promise if refresh already in progress
421
429
  */
422
- async _tryRefreshToken(e) {
430
+ async _tryRefreshToken(t) {
423
431
  if (this.refreshPromise)
424
432
  return this.logger.debug("Refresh already in progress, returning existing promise"), this.refreshPromise;
425
- this.refreshPromise = this._doRefreshToken(e);
433
+ this.refreshPromise = this._doRefreshToken(t);
426
434
  try {
427
435
  return await this.refreshPromise;
428
436
  } finally {
@@ -432,27 +440,28 @@ class B {
432
440
  /**
433
441
  * Perform the actual token refresh
434
442
  */
435
- async _doRefreshToken(e) {
443
+ async _doRefreshToken(t) {
436
444
  this.logger.debug("Refreshing access token");
437
445
  try {
438
- const t = await P(
446
+ const e = await b(
439
447
  this.authEndpoints.token,
440
- e,
448
+ t,
441
449
  this.authClientId
442
450
  );
443
- if (t) {
444
- this._storeRefreshedTokens(t);
445
- const s = _(t.access_token);
451
+ if (e) {
452
+ this._storeRefreshedTokens(e);
453
+ const r = _(e.access_token);
446
454
  return this.setAuthState({
447
- isLoggedIn: !0,
448
- userInfo: s,
449
- accessToken: t.access_token
450
- }), 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;
451
460
  }
452
- } catch (t) {
453
- this.logger.warn("Token refresh failed:", t);
461
+ } catch (e) {
462
+ this.logger.warn("Token refresh failed:", e);
454
463
  }
455
- throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"), S(
464
+ throw this.logger.warn("Token refresh failed, keeping tokens for manual retry"), h(
456
465
  "Access token expired and unable to refresh. Try logging out and logging in again.",
457
466
  "token_refresh_failed"
458
467
  );
@@ -460,9 +469,9 @@ class B {
460
469
  /**
461
470
  * Store refreshed tokens
462
471
  */
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);
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);
466
475
  }
467
476
  /**
468
477
  * Ping API
@@ -487,24 +496,24 @@ class B {
487
496
  * Calls /bodhi/v1/info and returns structured server state
488
497
  */
489
498
  async getServerState() {
490
- const e = await this.sendApiRequest("GET", "/bodhi/v1/info");
491
- if (T(e))
499
+ const t = await this.sendApiRequest("GET", "/bodhi/v1/info");
500
+ if (f(t))
492
501
  return d;
493
- if (!f(e))
502
+ if (!m(t))
494
503
  return d;
495
- const t = e.body;
496
- switch (t.status) {
504
+ const e = t.body;
505
+ switch (e.status) {
497
506
  case "ready":
498
- return { status: "ready", version: t.version || "unknown" };
507
+ return { status: "ready", version: e.version || "unknown", error: null };
499
508
  case "setup":
500
- return E("setup", t.version || "unknown");
509
+ return E("setup", e.version || "unknown");
501
510
  case "resource-admin":
502
- return E("resource-admin", t.version || "unknown");
511
+ return E("resource-admin", e.version || "unknown");
503
512
  case "error":
504
513
  return E(
505
514
  "error",
506
- t.version || "unknown",
507
- t.error ? { message: t.error.message, type: t.error.type } : O.SERVER_NOT_READY
515
+ e.version || "unknown",
516
+ e.error ? { message: e.error.message, type: e.error.type } : O.SERVER_NOT_READY
508
517
  );
509
518
  default:
510
519
  return d;
@@ -514,53 +523,53 @@ class B {
514
523
  * Generic streaming via window.bodhiext.sendStreamRequest
515
524
  * Wraps ReadableStream as AsyncGenerator
516
525
  */
517
- async *stream(e, t, s, r, i = !0) {
526
+ async *stream(t, e, r, s, a = !0) {
518
527
  this.ensureBodhiext();
519
- let o = r || {};
520
- if (i) {
521
- const n = await this._getAccessTokenRaw();
522
- if (!n)
523
- throw new Error("Not authenticated. Please log in first.");
528
+ let o = s || {};
529
+ if (a) {
530
+ const i = await this._getAccessTokenRaw();
531
+ if (!i)
532
+ throw h("Not authenticated. Please log in first.", "auth_error");
524
533
  o = {
525
534
  ...o,
526
- Authorization: `Bearer ${n}`
535
+ Authorization: `Bearer ${i}`
527
536
  };
528
537
  }
529
- const c = this.bodhiext.sendStreamRequest(e, t, s, o).getReader();
538
+ const n = this.bodhiext.sendStreamRequest(t, e, r, o).getReader();
530
539
  try {
531
540
  for (; ; ) {
532
- const { value: n, done: h } = await c.read();
533
- if (h || n != null && n.done)
541
+ const { value: i, done: l } = await n.read();
542
+ if (l || i?.done)
534
543
  break;
535
- yield n.body;
544
+ yield i.body;
536
545
  }
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);
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);
542
551
  }
543
- throw "error" in n ? S(n.message, "extension_error") : S(n.message, "extension_error");
552
+ throw "error" in i ? h(i.message, "extension_error") : h(i.message, "extension_error");
544
553
  }
545
- throw n;
554
+ throw i;
546
555
  } finally {
547
- c.releaseLock();
556
+ n.releaseLock();
548
557
  }
549
558
  }
550
559
  /**
551
560
  * Chat streaming
552
561
  */
553
- async *streamChat(e, t, s = !0) {
562
+ async *streamChat(t, e, r = !0) {
554
563
  yield* this.stream(
555
564
  "POST",
556
565
  "/v1/chat/completions",
557
566
  {
558
- model: e,
559
- messages: [{ role: "user", content: t }],
567
+ model: t,
568
+ messages: [{ role: "user", content: e }],
560
569
  stream: !0
561
570
  },
562
571
  void 0,
563
- s
572
+ r
564
573
  );
565
574
  }
566
575
  /**
@@ -587,47 +596,47 @@ class B {
587
596
  };
588
597
  }
589
598
  }
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
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
599
608
  };
600
- super(e, i, s, r, t.basePath);
609
+ super(t, a, r, s, e.basePath);
601
610
  }
602
- createLogger(e) {
603
- return new C("WebUIClient", e.logLevel);
611
+ createLogger(t) {
612
+ return new R("WebUIClient", t.logLevel);
604
613
  }
605
- createExtClient(e, t) {
606
- return new B(this.authClientId, e, t, e.basePath);
614
+ createExtClient(t, e) {
615
+ return new F(this.authClientId, t, e, t.basePath);
607
616
  }
608
- createDirectClient(e, t, s) {
609
- return new L(
617
+ createDirectClient(t, e, r) {
618
+ return new U(
610
619
  {
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
620
+ authClientId: t,
621
+ authServerUrl: e.authServerUrl,
622
+ redirectUri: e.redirectUri,
623
+ userScope: e.userScope,
624
+ logLevel: e.logLevel,
625
+ storagePrefix: S.WEB,
626
+ basePath: e.basePath
618
627
  },
619
- s
628
+ r
620
629
  );
621
630
  }
622
631
  // ============================================================================
623
632
  // Web-specific OAuth Callback
624
633
  // ============================================================================
625
- async handleOAuthCallback(e, t) {
626
- 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);
627
636
  }
628
637
  }
629
- const $ = "production";
638
+ const V = "production";
630
639
  export {
631
- $ as WEB_BUILD_MODE,
632
- W as WebUIClient
640
+ V as WEB_BUILD_MODE,
641
+ q as WebUIClient
633
642
  };