@thunderid/browser 1.2.2 → 1.3.1

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 +1 @@
1
- {"version":3,"file":"FetchHttpClient.d.ts","sourceRoot":"","sources":["../src/FetchHttpClient.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,UAAU,EAAa,iBAAiB,EAAE,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAE7F;;;;;;;GAOG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAO,CAAC,MAAM,CAAC,SAAS,CAAoE;IAE5F,MAAM,CAAC,WAAW,CAChB,UAAU,SAAI,EACd,gBAAgB,UAAO,EACvB,WAAW,GAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAA0C,GAClG,eAAe;IAOlB,MAAM,CAAC,eAAe,CAAC,UAAU,SAAI,GAAG,IAAI;cAI5B,SAAS,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;CAoFxF;AAED,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"FetchHttpClient.d.ts","sourceRoot":"","sources":["../src/FetchHttpClient.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,UAAU,EAAa,iBAAiB,EAAE,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAE7F;;;;;;;GAOG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAO,CAAC,MAAM,CAAC,SAAS,CAAoE;IAE5F,MAAM,CAAC,WAAW,CAChB,UAAU,SAAI,EACd,gBAAgB,UAAO,EACvB,WAAW,GAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAA0C,GAClG,eAAe;IAOlB,MAAM,CAAC,eAAe,CAAC,UAAU,SAAI,GAAG,IAAI;cAI5B,SAAS,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;CAuFxF;AAED,eAAe,eAAe,CAAC"}
@@ -1,4 +1,4 @@
1
- import { ThunderIDJavaScriptClient, User, IsomorphicCrypto, IdToken, OIDCEndpoints, Storage, TokenResponse, HttpRequestConfig, HttpResponse } from '@thunderid/javascript';
1
+ import { ThunderIDJavaScriptClient, User, IsomorphicCrypto, IdToken, OIDCEndpoints, Storage, TokenResponse, HttpRequestConfig, HttpResponse, UserProfile } from '@thunderid/javascript';
2
2
  import FetchHttpClient from './FetchHttpClient';
3
3
  import { BrowserAuthConfig } from './models/BrowserConfig';
4
4
  import SignInConfig from './models/SignInConfig';
@@ -11,14 +11,7 @@ declare class ThunderIDBrowserClient<T = BrowserAuthConfig> extends ThunderIDJav
11
11
  private _storage;
12
12
  private _getSignOutURLFromSessionStorage;
13
13
  private _isHttpHandlerEnabled;
14
- private _httpErrorCallback;
15
- private _httpFinishCallback;
16
- private _onSignInCallback;
17
- private _onSignOutCallback;
18
- private _onSignOutFailedCallback;
19
- private _onEndUserSession;
20
- private _onInitialize;
21
- private _onCustomGrant;
14
+ private _hookCallbacks;
22
15
  private _initialized;
23
16
  private _startedInitialize;
24
17
  constructor(instanceId?: number);
@@ -39,6 +32,17 @@ declare class ThunderIDBrowserClient<T = BrowserAuthConfig> extends ThunderIDJav
39
32
  httpRequest(requestConfig: HttpRequestConfig): Promise<HttpResponse | undefined>;
40
33
  httpRequestAll(configs: HttpRequestConfig[]): Promise<HttpResponse[] | undefined>;
41
34
  getUser(userId?: string): Promise<User>;
35
+ /**
36
+ * Fetches the signed-in user's profile from the `/users/me` endpoint (or `endpoints.usersMe` when
37
+ * configured), sending the request through the client's HTTP client so the access token is attached.
38
+ *
39
+ * @param options - Optional `baseUrl` or full `url` overrides for the profile endpoint.
40
+ * @returns The user's profile.
41
+ */
42
+ getUserProfile(options?: {
43
+ baseUrl?: string;
44
+ url?: string;
45
+ }): Promise<UserProfile>;
42
46
  getAccessToken(sessionId?: string): Promise<string>;
43
47
  getDecodedIdToken(userId?: string, idToken?: string): Promise<IdToken>;
44
48
  getIdToken(userId?: string): Promise<string>;
@@ -56,7 +60,20 @@ declare class ThunderIDBrowserClient<T = BrowserAuthConfig> extends ThunderIDJav
56
60
  enableHttpHandler(): Promise<boolean | undefined>;
57
61
  disableHttpHandler(): Promise<boolean | undefined>;
58
62
  decodeJwtToken<R = Record<string, unknown>>(token: string): Promise<R>;
63
+ /**
64
+ * Subscribes a callback to a lifecycle hook. Every callback registered for a hook is called when it
65
+ * fires; registering the same callback again for the same hook has no further effect. Hooks can be
66
+ * registered before or after `initialize()`.
67
+ *
68
+ * @param hook - The hook to subscribe to (see `Hooks`).
69
+ * @param callback - Called when the hook fires.
70
+ * @param id - The custom grant id. Required for `custom-grant`.
71
+ */
59
72
  on(hook: string, callback: (response?: any) => void | Promise<void>, id?: string): Promise<void>;
73
+ private _addHookCallback;
74
+ private _emitHook;
75
+ private _emitHttpError;
76
+ private _emitHttpFinish;
60
77
  private _enableRetrievingSignOutURLFromSession;
61
78
  private _constructSilentSignInUrl;
62
79
  getInstanceId(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDBrowserClient.d.ts","sourceRoot":"","sources":["../src/ThunderIDBrowserClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ThunderIDBrowserClient.d.ts","sourceRoot":"","sources":["../src/ThunderIDBrowserClient.ts"],"names":[],"mappings":"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"}
@@ -35,6 +35,26 @@ fast_sha256 = __toESM(fast_sha256);
35
35
  let jose = require("jose");
36
36
  jose = __toESM(jose);
37
37
 
38
+ //#region src/constants/Hooks.ts
39
+ /**
40
+ * Event hook names for attaching callbacks via `ThunderIDBrowserClient.on()`.
41
+ */
42
+ let Hooks = /* @__PURE__ */ function(Hooks$1) {
43
+ Hooks$1["SignIn"] = "sign-in";
44
+ Hooks$1["SignOut"] = "sign-out";
45
+ Hooks$1["Initialize"] = "initialize";
46
+ Hooks$1["HttpRequestStart"] = "http-request-start";
47
+ Hooks$1["HttpRequestFinish"] = "http-request-finish";
48
+ Hooks$1["HttpRequestError"] = "http-request-error";
49
+ Hooks$1["HttpRequestSuccess"] = "http-request-success";
50
+ Hooks$1["RevokeAccessToken"] = "revoke-access-token";
51
+ Hooks$1["CustomGrant"] = "custom-grant";
52
+ Hooks$1["SignOutFailed"] = "sign-out-failed";
53
+ return Hooks$1;
54
+ }({});
55
+ var Hooks_default = Hooks;
56
+
57
+ //#endregion
38
58
  //#region src/constants/SPAConstants.ts
39
59
  const ERROR = "error";
40
60
  const ERROR_DESCRIPTION = "error_description";
@@ -91,9 +111,11 @@ var FetchHttpClient = class FetchHttpClient extends __thunderid_javascript.HttpC
91
111
  method: (method ?? "GET").toUpperCase()
92
112
  });
93
113
  } catch (networkError) {
114
+ const isAbort = networkError?.name === "AbortError";
94
115
  throw Object.assign(new Error(networkError.message), {
95
- code: "NETWORK_ERROR",
96
- config
116
+ code: isAbort ? "ABORT_ERROR" : "NETWORK_ERROR",
117
+ config,
118
+ name: isAbort ? "AbortError" : "Error"
97
119
  });
98
120
  }
99
121
  const responseData = (fetchResponse.headers.get("content-type") ?? "").includes("application/json") ? await fetchResponse.json() : await fetchResponse.text();
@@ -780,6 +802,57 @@ var AuthenticationHelper = class {
780
802
  };
781
803
  var AuthenticationHelper_default = AuthenticationHelper;
782
804
 
805
+ //#endregion
806
+ //#region src/utils/createHttpClientFetcher.ts
807
+ /**
808
+ * Builds a `fetch`-shaped function backed by the shared `FetchHttpClient` singleton, for
809
+ * framework wrappers (`@thunderid/react`, `@thunderid/vue`) that need to hand a core
810
+ * `@thunderid/javascript` API function a `fetcher` carrying the access token automatically.
811
+ *
812
+ * Unlike a plain `fetch` call, `FetchHttpClient.request` throws on a non-2xx response instead
813
+ * of resolving it. This adapter catches that and reconstructs a `Response`-shaped object from
814
+ * the thrown error's `response`, so the core API function sees the real status and body instead
815
+ * of treating every non-2xx result as a network failure. A genuine network error (no response
816
+ * attached) still propagates.
817
+ *
818
+ * @param instanceId - Which `FetchHttpClient` instance to use, for multi-instance apps. Defaults to `0`.
819
+ * @returns A function matching the `(url, config) => Promise<Response>` shape core API functions expect.
820
+ * @example
821
+ * ```typescript
822
+ * await updateMeCredentials({
823
+ * ...config,
824
+ * fetcher: fetcher ?? createHttpClientFetcher(instanceId),
825
+ * });
826
+ * ```
827
+ */
828
+ const createHttpClientFetcher = (instanceId = 0) => {
829
+ return async (url, config) => {
830
+ const httpClient = FetchHttpClient_default.getInstance(instanceId);
831
+ const toResponse = (data, status, statusText) => ({
832
+ json: () => Promise.resolve(data),
833
+ ok: status >= 200 && status < 300,
834
+ status,
835
+ statusText,
836
+ text: () => Promise.resolve(typeof data === "string" ? data : JSON.stringify(data))
837
+ });
838
+ try {
839
+ const response = await httpClient.request({
840
+ data: config.body ? JSON.parse(config.body) : void 0,
841
+ headers: config.headers,
842
+ method: config.method || "POST",
843
+ signal: config.signal,
844
+ url
845
+ });
846
+ return toResponse(response.data, response.status, response.statusText || "");
847
+ } catch (error) {
848
+ const httpError = error;
849
+ if (httpError?.response) return toResponse(httpError.response.data, httpError.response.status, httpError.response.statusText ?? "");
850
+ throw error;
851
+ }
852
+ };
853
+ };
854
+ var createHttpClientFetcher_default = createHttpClientFetcher;
855
+
783
856
  //#endregion
784
857
  //#region src/utils/navigate.ts
785
858
  /**
@@ -2439,14 +2512,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2439
2512
  _storage = BrowserStorage_default.SessionStorage;
2440
2513
  _getSignOutURLFromSessionStorage = false;
2441
2514
  _isHttpHandlerEnabled = true;
2442
- _httpErrorCallback;
2443
- _httpFinishCallback;
2444
- _onSignInCallback = () => null;
2445
- _onSignOutCallback = () => null;
2446
- _onSignOutFailedCallback = () => null;
2447
- _onEndUserSession = () => null;
2448
- _onInitialize = () => null;
2449
- _onCustomGrant = /* @__PURE__ */ new Map();
2515
+ _hookCallbacks = /* @__PURE__ */ new Map();
2450
2516
  _initialized = false;
2451
2517
  _startedInitialize = false;
2452
2518
  constructor(instanceId = 0) {
@@ -2473,6 +2539,12 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2473
2539
  await this._authHelper?.attachTokenToRequestConfig(request);
2474
2540
  };
2475
2541
  this._httpClient = FetchHttpClient_default.getInstance(this._browserInstanceId, true, attachToken);
2542
+ this._httpClient.setHttpRequestStartCallback((request) => {
2543
+ this._emitHook(Hooks_default.HttpRequestStart, request);
2544
+ });
2545
+ this._httpClient.setHttpRequestSuccessCallback((response) => {
2546
+ this._emitHook(Hooks_default.HttpRequestSuccess, response);
2547
+ });
2476
2548
  this._authHelper = new AuthenticationHelper_default(sm, this._spaHelper, this._browserInstanceId, {
2477
2549
  exchangeToken: (cfg) => super.exchangeToken(cfg),
2478
2550
  getAccessToken: (sessionId) => this.getAccessToken(sessionId),
@@ -2487,7 +2559,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2487
2559
  setPKCECode: (pkceKey, state) => this.setPKCECode(pkceKey, state)
2488
2560
  });
2489
2561
  this._initialized = true;
2490
- if (this._onInitialize) this._onInitialize(true);
2562
+ this._emitHook(Hooks_default.Initialize, true);
2491
2563
  if (!merged.autoLogoutOnTokenRefreshError) return true;
2492
2564
  window.addEventListener("message", (event) => {
2493
2565
  if (event?.data?.type === REFRESH_ACCESS_TOKEN_ERR0R) this.signOut();
@@ -2518,7 +2590,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2518
2590
  if (!SPAUtils_default.canContinueSignIn(Boolean(config?.callOnlyOnRedirect), authorizationCode)) return;
2519
2591
  delete config?.callOnlyOnRedirect;
2520
2592
  const user = await this._signInInternal(config, authorizationCode, state, tokenRequestConfig);
2521
- if (user && this._onSignInCallback) this._onSignInCallback(user);
2593
+ if (user) this._emitHook(Hooks_default.SignIn, user);
2522
2594
  return user;
2523
2595
  }
2524
2596
  async _signInInternal(signInConfig, authorizationCode, state, tokenRequestConfig) {
@@ -2587,7 +2659,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2587
2659
  await this.isInitialized();
2588
2660
  if (SPAUtils_default.wasSignInCalled()) return;
2589
2661
  const response = await this._signInSilentlyInternal(additionalParams, tokenRequestConfig);
2590
- if (this._onSignInCallback && response) this._onSignInCallback(response);
2662
+ if (response) this._emitHook(Hooks_default.SignIn, response);
2591
2663
  return response;
2592
2664
  }
2593
2665
  async _signInSilentlyInternal(additionalParams, tokenRequestConfig) {
@@ -2633,16 +2705,40 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2633
2705
  }
2634
2706
  async httpRequest(requestConfig) {
2635
2707
  await this._validateMethod(false);
2636
- return this._authHelper.httpRequest(this._httpClient, requestConfig, this._isHttpHandlerEnabled, this._httpErrorCallback, this._httpFinishCallback);
2708
+ const response = await this._authHelper.httpRequest(this._httpClient, requestConfig, this._isHttpHandlerEnabled, this._emitHttpError, this._emitHttpFinish);
2709
+ if (this._isHttpHandlerEnabled) this._emitHttpFinish();
2710
+ return response;
2637
2711
  }
2638
2712
  async httpRequestAll(configs) {
2639
2713
  await this._validateMethod(false);
2640
- return this._authHelper.httpRequestAll(configs, this._httpClient, this._isHttpHandlerEnabled, this._httpErrorCallback, this._httpFinishCallback);
2714
+ const responses = await this._authHelper.httpRequestAll(configs, this._httpClient, this._isHttpHandlerEnabled, this._emitHttpError, this._emitHttpFinish);
2715
+ if (this._isHttpHandlerEnabled) this._emitHttpFinish();
2716
+ return responses;
2641
2717
  }
2642
2718
  async getUser(userId) {
2643
2719
  await this._validateMethod();
2644
2720
  return super.getUser(userId);
2645
2721
  }
2722
+ /**
2723
+ * Fetches the signed-in user's profile from the `/users/me` endpoint (or `endpoints.usersMe` when
2724
+ * configured), sending the request through the client's HTTP client so the access token is attached.
2725
+ *
2726
+ * @param options - Optional `baseUrl` or full `url` overrides for the profile endpoint.
2727
+ * @returns The user's profile.
2728
+ */
2729
+ async getUserProfile(options) {
2730
+ await this._validateMethod();
2731
+ const configData = await this.getStorageManager().getConfigData();
2732
+ const profile = await (0, __thunderid_javascript.getUsersMe)({
2733
+ baseUrl: options?.baseUrl ?? configData?.baseUrl,
2734
+ fetcher: createHttpClientFetcher_default(this._browserInstanceId),
2735
+ url: (0, __thunderid_javascript.resolveResourceEndpoint)("usersMe", configData, options?.url)
2736
+ });
2737
+ return {
2738
+ flattenedProfile: (0, __thunderid_javascript.generateFlattenedUserProfile)(profile),
2739
+ profile
2740
+ };
2741
+ }
2646
2742
  async getAccessToken(sessionId) {
2647
2743
  return super.getAccessToken(sessionId);
2648
2744
  }
@@ -2671,7 +2767,7 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2671
2767
  return super.isSignedIn(userId);
2672
2768
  }
2673
2769
  notifySignIn(user) {
2674
- this._onSignInCallback(user);
2770
+ this._emitHook(Hooks_default.SignIn, user);
2675
2771
  }
2676
2772
  async isSessionActive() {
2677
2773
  await this.isInitialized();
@@ -2690,14 +2786,14 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2690
2786
  const timer = await this._spaHelper.getRefreshTimeoutTimer();
2691
2787
  await super.revokeAccessToken(userId);
2692
2788
  await this._spaHelper.clearRefreshTokenTimeout(timer);
2693
- this._onEndUserSession && await this._onEndUserSession(true);
2789
+ await this._emitHook(Hooks_default.RevokeAccessToken, true);
2694
2790
  return true;
2695
2791
  }
2696
2792
  async exchangeToken(config) {
2697
2793
  if (config.signInRequired) await this._validateMethod();
2698
2794
  if (!config.id) return Promise.reject(new __thunderid_javascript.ThunderIDAuthException("SPA-AUTH_CLIENT-RCG-NF01", "The custom grant request id not found.", "Set the `id` attribute on the token exchange config."));
2699
2795
  const response = await this._authHelper.exchangeToken(config, (cfg) => this._enableRetrievingSignOutURLFromSession(cfg));
2700
- this._onCustomGrant.get(config.id)?.(response);
2796
+ this._emitHook(`${Hooks_default.CustomGrant}:${config.id}`, response);
2701
2797
  return response;
2702
2798
  }
2703
2799
  async reInitialize(config) {
@@ -2724,47 +2820,56 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2724
2820
  async decodeJwtToken(token) {
2725
2821
  return this.getCryptoHelper().decodeJwtToken(token);
2726
2822
  }
2823
+ /**
2824
+ * Subscribes a callback to a lifecycle hook. Every callback registered for a hook is called when it
2825
+ * fires; registering the same callback again for the same hook has no further effect. Hooks can be
2826
+ * registered before or after `initialize()`.
2827
+ *
2828
+ * @param hook - The hook to subscribe to (see `Hooks`).
2829
+ * @param callback - Called when the hook fires.
2830
+ * @param id - The custom grant id. Required for `custom-grant`.
2831
+ */
2727
2832
  async on(hook, callback, id) {
2728
2833
  await this.isInitialized();
2729
2834
  if (!callback || typeof callback !== "function") throw new __thunderid_javascript.ThunderIDAuthException("SPA-AUTH_CLIENT-ON-IV02", "Invalid callback function.", "The provided callback must be a function.");
2730
2835
  switch (hook) {
2731
- case "sign-in":
2732
- this._onSignInCallback = callback;
2733
- break;
2734
- case "sign-out":
2735
- this._onSignOutCallback = callback;
2736
- if (await SPAUtils_default.isSignOutSuccessful(ThunderIDBrowserClient.isSignOutSuccessful.bind(ThunderIDBrowserClient), () => ThunderIDBrowserClient.clearSession())) this._onSignOutCallback();
2737
- break;
2738
- case "revoke-access-token":
2739
- this._onEndUserSession = callback;
2740
- break;
2741
- case "initialize":
2742
- this._onInitialize = callback;
2743
- break;
2744
- case "http-request-error":
2745
- this._httpErrorCallback = callback;
2746
- break;
2747
- case "http-request-finish":
2748
- this._httpFinishCallback = callback;
2836
+ case Hooks_default.SignIn:
2837
+ case Hooks_default.RevokeAccessToken:
2838
+ case Hooks_default.Initialize:
2839
+ case Hooks_default.HttpRequestError:
2840
+ case Hooks_default.HttpRequestFinish:
2841
+ case Hooks_default.HttpRequestStart:
2842
+ case Hooks_default.HttpRequestSuccess:
2843
+ this._addHookCallback(hook, callback);
2749
2844
  break;
2750
- case "http-request-start":
2751
- this._httpClient?.setHttpRequestStartCallback?.(callback);
2845
+ case Hooks_default.SignOut:
2846
+ if (await SPAUtils_default.isSignOutSuccessful(ThunderIDBrowserClient.isSignOutSuccessful.bind(ThunderIDBrowserClient), () => ThunderIDBrowserClient.clearSession())) callback();
2752
2847
  break;
2753
- case "http-request-success":
2754
- this._httpClient?.setHttpRequestSuccessCallback?.(callback);
2848
+ case Hooks_default.CustomGrant:
2849
+ id && this._addHookCallback(`${Hooks_default.CustomGrant}:${id}`, callback);
2755
2850
  break;
2756
- case "custom-grant":
2757
- id && this._onCustomGrant.set(id, callback);
2758
- break;
2759
- case "sign-out-failed": {
2760
- this._onSignOutFailedCallback = callback;
2851
+ case Hooks_default.SignOutFailed: {
2761
2852
  const signOutFail = SPAUtils_default.didSignOutFail(ThunderIDBrowserClient.didSignOutFail.bind(ThunderIDBrowserClient));
2762
- if (signOutFail) this._onSignOutFailedCallback(signOutFail);
2853
+ if (signOutFail) callback(signOutFail);
2763
2854
  break;
2764
2855
  }
2765
2856
  default: throw new __thunderid_javascript.ThunderIDAuthException("SPA-AUTH_CLIENT-ON-IV01", "Invalid hook.", `Unknown hook: "${hook}"`);
2766
2857
  }
2767
2858
  }
2859
+ _addHookCallback(hook, callback) {
2860
+ const callbacks = this._hookCallbacks.get(hook) ?? /* @__PURE__ */ new Set();
2861
+ callbacks.add(callback);
2862
+ this._hookCallbacks.set(hook, callbacks);
2863
+ }
2864
+ _emitHook(hook, response) {
2865
+ return Promise.all([...this._hookCallbacks.get(hook) ?? []].map((callback) => Promise.resolve(callback(response))));
2866
+ }
2867
+ _emitHttpError = async (error) => {
2868
+ await this._emitHook(Hooks_default.HttpRequestError, error);
2869
+ };
2870
+ _emitHttpFinish = () => {
2871
+ this._emitHook(Hooks_default.HttpRequestFinish);
2872
+ };
2768
2873
  _enableRetrievingSignOutURLFromSession(config) {
2769
2874
  if (config.preventSignOutURLUpdate) this._getSignOutURLFromSessionStorage = true;
2770
2875
  }
@@ -2790,26 +2895,6 @@ var ThunderIDBrowserClient = class ThunderIDBrowserClient extends __thunderid_ja
2790
2895
  };
2791
2896
  var ThunderIDBrowserClient_default = ThunderIDBrowserClient;
2792
2897
 
2793
- //#endregion
2794
- //#region src/constants/Hooks.ts
2795
- /**
2796
- * Event hook names for attaching callbacks via `ThunderIDBrowserClient.on()`.
2797
- */
2798
- let Hooks = /* @__PURE__ */ function(Hooks$1) {
2799
- Hooks$1["SignIn"] = "sign-in";
2800
- Hooks$1["SignOut"] = "sign-out";
2801
- Hooks$1["Initialize"] = "initialize";
2802
- Hooks$1["HttpRequestStart"] = "http-request-start";
2803
- Hooks$1["HttpRequestFinish"] = "http-request-finish";
2804
- Hooks$1["HttpRequestError"] = "http-request-error";
2805
- Hooks$1["HttpRequestSuccess"] = "http-request-success";
2806
- Hooks$1["RevokeAccessToken"] = "revoke-access-token";
2807
- Hooks$1["CustomGrant"] = "custom-grant";
2808
- Hooks$1["SignOutFailed"] = "sign-out-failed";
2809
- return Hooks$1;
2810
- }({});
2811
- var Hooks_default = Hooks;
2812
-
2813
2898
  //#endregion
2814
2899
  //#region src/utils/hasAuthParamsInUrl.ts
2815
2900
  /**
@@ -2862,54 +2947,26 @@ const http = (client) => {
2862
2947
  var http_default = http;
2863
2948
 
2864
2949
  //#endregion
2865
- //#region src/utils/createHttpClientFetcher.ts
2950
+ //#region src/utils/copyTextToClipboard.ts
2866
2951
  /**
2867
- * Builds a `fetch`-shaped function backed by the shared `FetchHttpClient` singleton, for
2868
- * framework wrappers (`@thunderid/react`, `@thunderid/vue`) that need to hand a core
2869
- * `@thunderid/javascript` API function a `fetcher` carrying the access token automatically.
2870
- *
2871
- * Unlike a plain `fetch` call, `FetchHttpClient.request` throws on a non-2xx response instead
2872
- * of resolving it. This adapter catches that and reconstructs a `Response`-shaped object from
2873
- * the thrown error's `response`, so the core API function sees the real status and body instead
2874
- * of treating every non-2xx result as a network failure. A genuine network error (no response
2875
- * attached) still propagates.
2952
+ * Copies text to the clipboard. It uses the Clipboard API, and falls back to a hidden textarea and
2953
+ * `document.execCommand('copy')` where the API is missing or refuses, such as on a page without a secure context.
2876
2954
  *
2877
- * @param instanceId - Which `FetchHttpClient` instance to use, for multi-instance apps. Defaults to `0`.
2878
- * @returns A function matching the `(url, config) => Promise<Response>` shape core API functions expect.
2879
- * @example
2880
- * ```typescript
2881
- * await updateMeCredentials({
2882
- * ...config,
2883
- * fetcher: fetcher ?? createHttpClientFetcher(instanceId),
2884
- * });
2885
- * ```
2955
+ * @param text - The text to copy.
2886
2956
  */
2887
- const createHttpClientFetcher = (instanceId = 0) => {
2888
- return async (url, config) => {
2889
- const httpClient = FetchHttpClient_default.getInstance(instanceId);
2890
- const toResponse = (data, status, statusText) => ({
2891
- json: () => Promise.resolve(data),
2892
- ok: status >= 200 && status < 300,
2893
- status,
2894
- statusText,
2895
- text: () => Promise.resolve(typeof data === "string" ? data : JSON.stringify(data))
2896
- });
2897
- try {
2898
- const response = await httpClient.request({
2899
- data: config.body ? JSON.parse(config.body) : void 0,
2900
- headers: config.headers,
2901
- method: config.method || "POST",
2902
- url
2903
- });
2904
- return toResponse(response.data, response.status, response.statusText || "");
2905
- } catch (error) {
2906
- const httpError = error;
2907
- if (httpError?.response) return toResponse(httpError.response.data, httpError.response.status, httpError.response.statusText ?? "");
2908
- throw error;
2909
- }
2910
- };
2957
+ const copyTextToClipboard = async (text) => {
2958
+ try {
2959
+ await navigator.clipboard.writeText(text);
2960
+ } catch {
2961
+ const textArea = document.createElement("textarea");
2962
+ textArea.value = text;
2963
+ document.body.appendChild(textArea);
2964
+ textArea.select();
2965
+ document.execCommand("copy");
2966
+ document.body.removeChild(textArea);
2967
+ }
2911
2968
  };
2912
- var createHttpClientFetcher_default = createHttpClientFetcher;
2969
+ var copyTextToClipboard_default = copyTextToClipboard;
2913
2970
 
2914
2971
  //#endregion
2915
2972
  //#region src/utils/handleWebAuthnAuthentication.ts
@@ -3482,6 +3539,23 @@ const AVATAR_PALETTES = [
3482
3539
  * without needing the actual palette values.
3483
3540
  */
3484
3541
  const AVATAR_GRADIENT_COUNT = AVATAR_PALETTES.length;
3542
+ const XML_ESCAPES = {
3543
+ "\"": "&quot;",
3544
+ "&": "&amp;",
3545
+ "'": "&apos;",
3546
+ "<": "&lt;",
3547
+ ">": "&gt;"
3548
+ };
3549
+ /**
3550
+ * Escapes a caller-supplied value for interpolation into SVG text.
3551
+ */
3552
+ const escapeXml = (value) => value.replace(/["&'<>]/g, (ch) => XML_ESCAPES[ch]);
3553
+ /**
3554
+ * Encodes an SVG document as a data URI. Lone UTF-16 surrogates are replaced with U+FFFD
3555
+ * first, since `encodeURIComponent` throws a `URIError` on them. `Array.from` iterates by
3556
+ * code point, so a surrogate it yields on its own is unpaired.
3557
+ */
3558
+ const toSvgDataUri = (svg) => `data:image/svg+xml,${encodeURIComponent(Array.from(svg, (ch) => ch.length === 1 && ch >= "\ud800" && ch <= "\udfff" ? "�" : ch).join(""))}`;
3485
3559
  /**
3486
3560
  * Fills in `params.content` when the spec itself didn't carry one, deriving it from a raw
3487
3561
  * seed name (e.g. an app or user display name) — extracting initials for letter variants,
@@ -3532,11 +3606,10 @@ const generateGradientAvatar = ({ shape, variant, content, colors, bg }) => {
3532
3606
  let text = "";
3533
3607
  if (variant !== "blank") {
3534
3608
  const letterCount = variant === "one_letter" ? 1 : 2;
3535
- const initials = (content || "A").toUpperCase().slice(0, letterCount);
3609
+ const initials = escapeXml(Array.from((content || "A").toUpperCase()).slice(0, letterCount).join(""));
3536
3610
  text = `<text x="50" y="64" font-family="Helvetica,Arial,sans-serif" font-weight="700" font-size="${letterCount === 1 ? 46 : 34}" text-anchor="middle" fill="#fff">${initials}</text>`;
3537
3611
  }
3538
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${defs}${shapeMarkup(shape, background)}${text}</svg>`;
3539
- return `data:image/svg+xml,${encodeURIComponent(svg)}`;
3612
+ return toSvgDataUri(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${defs}${shapeMarkup(shape, background)}${text}</svg>`);
3540
3613
  };
3541
3614
  /**
3542
3615
  * Renders one of the curated anonymous-animal icons, applying the requested background
@@ -3548,8 +3621,7 @@ const generateAnonymousAnimalAvatar = ({ shape, content, bg }) => {
3548
3621
  const icon = ANONYMOUS_ANIMAL_ICONS[Object.prototype.hasOwnProperty.call(ANONYMOUS_ANIMAL_ICONS, content) ? content : pickAnonymousAvatarName_default()];
3549
3622
  const color = bg ?? icon.color;
3550
3623
  const markup = icon.markup.replaceAll("%COLOR%", color);
3551
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${shapeMarkup(shape, color)}${markup}</svg>`;
3552
- return `data:image/svg+xml,${encodeURIComponent(svg)}`;
3624
+ return toSvgDataUri(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${shapeMarkup(shape, color)}${markup}</svg>`);
3553
3625
  };
3554
3626
  /**
3555
3627
  * Renders one of the curated anonymous-entity icons (application/organization/resource-server
@@ -3561,8 +3633,7 @@ const generateAnonymousEntityAvatar = ({ shape, content, bg }) => {
3561
3633
  const icon = ANONYMOUS_ENTITY_ICONS[Object.prototype.hasOwnProperty.call(ANONYMOUS_ENTITY_ICONS, content) ? content : pickAnonymousEntityName_default()];
3562
3634
  const color = bg ?? icon.color;
3563
3635
  const markup = icon.markup.replaceAll("%COLOR%", color);
3564
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${shapeMarkup(shape, color)}${markup}</svg>`;
3565
- return `data:image/svg+xml,${encodeURIComponent(svg)}`;
3636
+ return toSvgDataUri(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${shapeMarkup(shape, color)}${markup}</svg>`);
3566
3637
  };
3567
3638
  /**
3568
3639
  * Generates an avatar image as an `svg+xml` data URI from a fully-resolved {@link AvatarParams}.
@@ -3679,7 +3750,8 @@ const createClassObserver = (targetElement, callback, config = {}) => {
3679
3750
  return observer;
3680
3751
  };
3681
3752
  /**
3682
- * Creates a media query listener for system theme changes
3753
+ * Creates a media query listener for system theme changes. Call `disconnect()` on the returned
3754
+ * object to remove the listener.
3683
3755
  */
3684
3756
  const createMediaQueryListener = (callback) => {
3685
3757
  if (typeof window === "undefined" || !window.matchMedia) return null;
@@ -3689,7 +3761,10 @@ const createMediaQueryListener = (callback) => {
3689
3761
  };
3690
3762
  if (mediaQuery.addEventListener) mediaQuery.addEventListener("change", handleChange);
3691
3763
  else mediaQuery.addListener(handleChange);
3692
- return mediaQuery;
3764
+ return Object.assign(mediaQuery, { disconnect: () => {
3765
+ if (mediaQuery.removeEventListener) mediaQuery.removeEventListener("change", handleChange);
3766
+ else mediaQuery.removeListener(handleChange);
3767
+ } });
3693
3768
  };
3694
3769
 
3695
3770
  //#endregion
@@ -3772,6 +3847,7 @@ exports.SessionStore = SessionStore_default;
3772
3847
  exports.TOKEN_REQUEST_CONFIG_KEY = TOKEN_REQUEST_CONFIG_KEY;
3773
3848
  exports.ThunderIDBrowserClient = ThunderIDBrowserClient_default;
3774
3849
  exports.buildAvatarSpec = buildAvatarSpec_default;
3850
+ exports.copyTextToClipboard = copyTextToClipboard_default;
3775
3851
  exports.createClassObserver = createClassObserver;
3776
3852
  exports.createHttpClientFetcher = createHttpClientFetcher_default;
3777
3853
  exports.createMediaQueryListener = createMediaQueryListener;