@thunderid/react 1.3.0 → 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.
@@ -40,7 +40,7 @@ const FlowMetaProvider = ({ children, enabled = true, fetchMeta, initialMeta = n
40
40
  const [isLoading, setIsLoading] = (0, react.useState)(!initialMeta);
41
41
  const [error, setError] = (0, react.useState)(null);
42
42
  const [pendingLanguage, setPendingLanguage] = (0, react.useState)(null);
43
- const lastFetchedRef = (0, react.useRef)(null);
43
+ const lastRequestKeyRef = (0, react.useRef)(null);
44
44
  const initialMetaConsumedRef = (0, react.useRef)(false);
45
45
  const fetchFlowMeta = (0, react.useCallback)(async () => {
46
46
  if (!enabled) {
@@ -80,6 +80,21 @@ const FlowMetaProvider = ({ children, enabled = true, fetchMeta, initialMeta = n
80
80
  fetchMeta,
81
81
  namespace
82
82
  ]);
83
+ const fetchMetaRef = (0, react.useRef)(fetchMeta);
84
+ const fetchMetaVersionRef = (0, react.useRef)(0);
85
+ if (fetchMetaRef.current !== fetchMeta) {
86
+ fetchMetaRef.current = fetchMeta;
87
+ fetchMetaVersionRef.current += 1;
88
+ }
89
+ const requestKey = enabled && !isInitialized && !applicationId ? null : JSON.stringify([
90
+ enabled,
91
+ enabled && !fetchMeta ? baseUrl : null,
92
+ enabled && !fetchMeta ? (0, __thunderid_browser.resolveResourceEndpoint)("flowMeta", { endpoints }) : null,
93
+ applicationId ?? null,
94
+ namespace ?? null,
95
+ i18nContext?.currentLanguage ?? null,
96
+ fetchMetaVersionRef.current
97
+ ]);
83
98
  const switchLanguage = (0, react.useCallback)(async (language) => {
84
99
  if (!enabled) return;
85
100
  setIsLoading(true);
@@ -131,17 +146,18 @@ const FlowMetaProvider = ({ children, enabled = true, fetchMeta, initialMeta = n
131
146
  }
132
147
  }, [pendingLanguage, i18nContext?.setLanguage]);
133
148
  (0, react.useEffect)(() => {
149
+ if (requestKey === null) return;
134
150
  if (!initialMetaConsumedRef.current) {
135
151
  initialMetaConsumedRef.current = true;
136
152
  if (initialMeta) {
137
- lastFetchedRef.current = fetchFlowMeta;
153
+ lastRequestKeyRef.current = requestKey;
138
154
  return;
139
155
  }
140
156
  }
141
- if (lastFetchedRef.current === fetchFlowMeta) return;
142
- lastFetchedRef.current = fetchFlowMeta;
157
+ if (lastRequestKeyRef.current === requestKey) return;
158
+ lastRequestKeyRef.current = requestKey;
143
159
  fetchFlowMeta();
144
- }, [fetchFlowMeta]);
160
+ }, [requestKey]);
145
161
  (0, react.useEffect)(() => {
146
162
  if (!meta?.i18n?.translations || !i18nContext?.injectBundles) return;
147
163
  const metaLanguage = meta.i18n.language || __thunderid_browser.TranslationBundleConstants.FALLBACK_LOCALE;
@@ -1 +1 @@
1
- {"version":3,"file":"FlowMetaProvider.cjs","names":["FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>>","useThunderID","i18nContext: I18nContextValue","useI18n","lastFetchedRef: RefObject<(() => Promise<void>) | null>","initialMetaConsumedRef: RefObject<boolean>","fetchFlowMeta: () => Promise<void>","FlowMetaType","err: unknown","switchLanguage: (language: string) => Promise<void>","result: FlowMetadataResponse","flatTranslations: Record<string, string>","namespace","value","bundle: I18nBundle","metaLanguage: string","TranslationBundleConstants","bundlesToInject: Record<string, I18nBundle>","value: any","FlowMetaContext"],"sources":["../../../../src/contexts/FlowMeta/FlowMetaProvider.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n FlowMetadataResponse,\n FlowMetaType,\n getFlowMeta,\n I18nBundle,\n resolveResourceEndpoint,\n TranslationBundleConstants,\n} from '@thunderid/browser';\nimport {FC, PropsWithChildren, ReactElement, RefObject, useCallback, useEffect, useRef, useState} from 'react';\nimport FlowMetaContext from './FlowMetaContext';\nimport {I18nContextValue} from '../I18n/I18nContext';\nimport useI18n from '../I18n/useI18n';\nimport useThunderID from '../ThunderID/useThunderID';\n\nexport interface FlowMetaProviderProps {\n /**\n * When false the provider skips fetching and provides null meta.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Overrides how flow metadata is fetched, routing the request through a caller-supplied\n * function (e.g. a Next.js Server Action) instead of the provider's default direct\n * browser-to-`baseUrl` `fetch()`. Use this when the ThunderID server's `baseUrl` is a\n * different origin than the app and CORS isn't (or can't be) configured for it — the\n * override runs server-side, so the browser never talks to `baseUrl` directly.\n *\n * Called for both the initial fetch and `switchLanguage()`.\n */\n fetchMeta?: (params: {applicationId?: string; language?: string}) => Promise<FlowMetadataResponse>;\n\n /**\n * Flow metadata resolved ahead of time (e.g. fetched server-side during SSR) and used to seed\n * the provider's state. When present, the provider skips its own initial client-side fetch —\n * avoiding a redundant request and the flash of untranslated i18n keys while that fetch is in\n * flight — but still fetches normally on subsequent changes (e.g. an explicit language switch).\n */\n initialMeta?: FlowMetadataResponse | null;\n\n /** Sent as the flow-meta request's `namespace`, e.g. to scope namespace-keyed i18n data. */\n namespace?: string;\n}\n\n/**\n * FlowMetaProvider fetches flow metadata from the `GET /flow/meta` endpoint\n * (v2 API) and makes it available to child components through `FlowMetaContext`.\n *\n * It is designed to be used in v2 embedded-flow scenarios and integrates with\n * `ThemeProvider` so that theme settings (colors, direction, typography, …)\n * from the server-side design configuration are applied automatically.\n *\n * @example\n * ```tsx\n * <FlowMetaProvider\n * config={{\n * baseUrl: 'https://localhost:8090',\n * type: FlowMetaType.App,\n * id: 'your-app-id',\n * }}\n * >\n * <ThemeProvider>\n * <App />\n * </ThemeProvider>\n * </FlowMetaProvider>\n * ```\n */\nconst FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>> = ({\n children,\n enabled = true,\n fetchMeta,\n initialMeta = null,\n namespace,\n}: PropsWithChildren<FlowMetaProviderProps>): ReactElement => {\n const {baseUrl, endpoints, applicationId, isInitialized} = useThunderID();\n const i18nContext: I18nContextValue = useI18n();\n\n const [meta, setMeta] = useState<FlowMetadataResponse | null>(initialMeta);\n const [isLoading, setIsLoading] = useState<boolean>(!initialMeta);\n const [error, setError] = useState<Error | null>(null);\n const [pendingLanguage, setPendingLanguage] = useState<string | null>(null);\n\n // Track the last fetchFlowMeta reference that was actually dispatched.\n // This prevents two classes of double-fetch:\n // 1. React StrictMode simulates unmount+remount — the re-mount fires the\n // effect again with the same fetchFlowMeta reference; without this guard\n // the else-branch would issue a redundant second network request.\n // 2. Rapid dependency changes (e.g. baseUrl stabilising) that produce two\n // effect firings before the first fetch completes.\n const lastFetchedRef: RefObject<(() => Promise<void>) | null> = useRef<(() => Promise<void>) | null>(null);\n const initialMetaConsumedRef: RefObject<boolean> = useRef(false);\n const fetchFlowMeta: () => Promise<void> = useCallback(async (): Promise<void> => {\n if (!enabled) {\n setMeta(null);\n setIsLoading(false);\n return;\n }\n\n // Defer until ThunderID finishes initializing (e.g. loading applicationId\n // from storage on refresh). Once initialized, proceed even if applicationId\n // is absent — some flows (e.g. AcceptInvite) have no applicationId by design.\n if (!isInitialized && !applicationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language: i18nContext?.currentLanguage})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language: i18nContext?.currentLanguage,\n });\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n }, [enabled, baseUrl, endpoints, applicationId, isInitialized, i18nContext?.currentLanguage, fetchMeta, namespace]);\n\n const switchLanguage: (language: string) => Promise<void> = useCallback(\n async (language: string): Promise<void> => {\n if (!enabled) return;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language,\n });\n\n // Inject translations for the new language before switching\n if (result.i18n?.translations && i18nContext?.injectBundles) {\n const flatTranslations: Record<string, string> = {};\n Object.entries(result.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n i18nContext.injectBundles({[language]: bundle});\n }\n\n // Defer setLanguage to the next effect cycle so injectBundles state\n // is committed before I18nProvider's setLanguage checks mergedBundles.\n setPendingLanguage(language);\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n },\n [enabled, baseUrl, endpoints, applicationId, i18nContext, fetchMeta, namespace],\n );\n\n // After injectBundles + setPendingLanguage are batched and committed, this\n // effect fires with the updated i18nContext (mergedBundles now includes the\n // new language), so setLanguage succeeds on the first switch.\n useEffect(() => {\n if (pendingLanguage && i18nContext?.setLanguage) {\n i18nContext.setLanguage(pendingLanguage);\n setPendingLanguage(null);\n }\n }, [pendingLanguage, i18nContext?.setLanguage]);\n\n useEffect(() => {\n if (!initialMetaConsumedRef.current) {\n initialMetaConsumedRef.current = true;\n\n if (initialMeta) {\n // Seeded from SSR (or another caller) — skip the redundant first client-side fetch.\n // Later dependency changes (e.g. an explicit language switch) still fetch normally.\n lastFetchedRef.current = fetchFlowMeta;\n return;\n }\n }\n\n if (lastFetchedRef.current === fetchFlowMeta) {\n // Same reference as the last dispatch — this is a StrictMode re-mount\n // or an effect re-fire with unchanged deps. Skip to avoid a duplicate fetch.\n return;\n }\n\n lastFetchedRef.current = fetchFlowMeta;\n fetchFlowMeta();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fetchFlowMeta]);\n\n // When meta loads with i18n translations, inject them into the i18n system.\n // Meta translations act as the base layer — prop-provided bundles still take precedence.\n useEffect(() => {\n if (!meta?.i18n?.translations || !i18nContext?.injectBundles) {\n return;\n }\n\n const metaLanguage: string = meta.i18n.language || TranslationBundleConstants.FALLBACK_LOCALE;\n\n // Flatten namespace-keyed translations to dot-path keys:\n // { \"signin\": { \"heading\": \"Sign In\" } } → { \"signin.heading\": \"Sign In\" }\n const flatTranslations: Record<string, string> = {};\n Object.entries(meta.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n\n // Inject under the meta language code and the i18n current language so\n // lookups succeed regardless of whether the system uses \"en\" or \"en-US\".\n const bundlesToInject: Record<string, I18nBundle> = {[metaLanguage]: bundle};\n if (i18nContext.currentLanguage && i18nContext.currentLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.currentLanguage] = bundle;\n }\n if (i18nContext.fallbackLanguage && i18nContext.fallbackLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.fallbackLanguage] = bundle;\n }\n\n i18nContext.injectBundles(bundlesToInject);\n }, [meta?.i18n?.translations, i18nContext?.injectBundles]);\n\n const value: any = {\n error,\n fetchFlowMeta,\n isLoading,\n meta,\n switchLanguage,\n };\n\n return <FlowMetaContext.Provider value={value}>{children}</FlowMetaContext.Provider>;\n};\n\nexport default FlowMetaProvider;\n"],"mappings":"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"}
1
+ {"version":3,"file":"FlowMetaProvider.cjs","names":["FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>>","useThunderID","i18nContext: I18nContextValue","useI18n","lastRequestKeyRef: RefObject<string | null>","initialMetaConsumedRef: RefObject<boolean>","fetchFlowMeta: () => Promise<void>","FlowMetaType","err: unknown","fetchMetaRef: RefObject<FlowMetaProviderProps['fetchMeta'] | null>","fetchMetaVersionRef: RefObject<number>","requestKey: string | null","switchLanguage: (language: string) => Promise<void>","result: FlowMetadataResponse","flatTranslations: Record<string, string>","namespace","value","bundle: I18nBundle","metaLanguage: string","TranslationBundleConstants","bundlesToInject: Record<string, I18nBundle>","value: any","FlowMetaContext"],"sources":["../../../../src/contexts/FlowMeta/FlowMetaProvider.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n FlowMetadataResponse,\n FlowMetaType,\n getFlowMeta,\n I18nBundle,\n resolveResourceEndpoint,\n TranslationBundleConstants,\n} from '@thunderid/browser';\nimport {FC, PropsWithChildren, ReactElement, RefObject, useCallback, useEffect, useRef, useState} from 'react';\nimport FlowMetaContext from './FlowMetaContext';\nimport {I18nContextValue} from '../I18n/I18nContext';\nimport useI18n from '../I18n/useI18n';\nimport useThunderID from '../ThunderID/useThunderID';\n\nexport interface FlowMetaProviderProps {\n /**\n * When false the provider skips fetching and provides null meta.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Overrides how flow metadata is fetched, routing the request through a caller-supplied\n * function (e.g. a Next.js Server Action) instead of the provider's default direct\n * browser-to-`baseUrl` `fetch()`. Use this when the ThunderID server's `baseUrl` is a\n * different origin than the app and CORS isn't (or can't be) configured for it — the\n * override runs server-side, so the browser never talks to `baseUrl` directly.\n *\n * Called for both the initial fetch and `switchLanguage()`.\n */\n fetchMeta?: (params: {applicationId?: string; language?: string}) => Promise<FlowMetadataResponse>;\n\n /**\n * Flow metadata resolved ahead of time (e.g. fetched server-side during SSR) and used to seed\n * the provider's state. When present, the provider skips its own initial client-side fetch —\n * avoiding a redundant request and the flash of untranslated i18n keys while that fetch is in\n * flight — but still fetches normally on subsequent changes (e.g. an explicit language switch).\n */\n initialMeta?: FlowMetadataResponse | null;\n\n /** Sent as the flow-meta request's `namespace`, e.g. to scope namespace-keyed i18n data. */\n namespace?: string;\n}\n\n/**\n * FlowMetaProvider fetches flow metadata from the `GET /flow/meta` endpoint\n * (v2 API) and makes it available to child components through `FlowMetaContext`.\n *\n * It is designed to be used in v2 embedded-flow scenarios and integrates with\n * `ThemeProvider` so that theme settings (colors, direction, typography, …)\n * from the server-side design configuration are applied automatically.\n *\n * @example\n * ```tsx\n * <FlowMetaProvider\n * config={{\n * baseUrl: 'https://localhost:8090',\n * type: FlowMetaType.App,\n * id: 'your-app-id',\n * }}\n * >\n * <ThemeProvider>\n * <App />\n * </ThemeProvider>\n * </FlowMetaProvider>\n * ```\n */\nconst FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>> = ({\n children,\n enabled = true,\n fetchMeta,\n initialMeta = null,\n namespace,\n}: PropsWithChildren<FlowMetaProviderProps>): ReactElement => {\n const {baseUrl, endpoints, applicationId, isInitialized} = useThunderID();\n const i18nContext: I18nContextValue = useI18n();\n\n const [meta, setMeta] = useState<FlowMetadataResponse | null>(initialMeta);\n const [isLoading, setIsLoading] = useState<boolean>(!initialMeta);\n const [error, setError] = useState<Error | null>(null);\n const [pendingLanguage, setPendingLanguage] = useState<string | null>(null);\n\n // The last request the initial-fetch effect dispatched, as a key of everything that shapes it.\n // `fetchFlowMeta` is recreated whenever a dependency changes identity, and several do while\n // ThunderID initializes (`isInitialized` flips, `endpoints` is replaced with the resolved\n // configuration) without changing the request. Keying on the request skips those repeats, and\n // the StrictMode re-mount, so only a real change (e.g. a language switch) fetches again.\n const lastRequestKeyRef: RefObject<string | null> = useRef<string | null>(null);\n const initialMetaConsumedRef: RefObject<boolean> = useRef(false);\n const fetchFlowMeta: () => Promise<void> = useCallback(async (): Promise<void> => {\n if (!enabled) {\n setMeta(null);\n setIsLoading(false);\n return;\n }\n\n // Defer until ThunderID finishes initializing (e.g. loading applicationId\n // from storage on refresh). Once initialized, proceed even if applicationId\n // is absent — some flows (e.g. AcceptInvite) have no applicationId by design.\n if (!isInitialized && !applicationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language: i18nContext?.currentLanguage})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language: i18nContext?.currentLanguage,\n });\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n }, [enabled, baseUrl, endpoints, applicationId, isInitialized, i18nContext?.currentLanguage, fetchMeta, namespace]);\n\n const fetchMetaRef: RefObject<FlowMetaProviderProps['fetchMeta'] | null> = useRef(fetchMeta);\n const fetchMetaVersionRef: RefObject<number> = useRef(0);\n if (fetchMetaRef.current !== fetchMeta) {\n fetchMetaRef.current = fetchMeta;\n fetchMetaVersionRef.current += 1;\n }\n\n // Null while the fetch would be skipped, so the request that follows initialization still runs.\n const requestKey: string | null =\n enabled && !isInitialized && !applicationId\n ? null\n : JSON.stringify([\n enabled,\n enabled && !fetchMeta ? baseUrl : null,\n enabled && !fetchMeta ? resolveResourceEndpoint('flowMeta', {endpoints}) : null,\n applicationId ?? null,\n namespace ?? null,\n i18nContext?.currentLanguage ?? null,\n fetchMetaVersionRef.current,\n ]);\n\n const switchLanguage: (language: string) => Promise<void> = useCallback(\n async (language: string): Promise<void> => {\n if (!enabled) return;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language,\n });\n\n // Inject translations for the new language before switching\n if (result.i18n?.translations && i18nContext?.injectBundles) {\n const flatTranslations: Record<string, string> = {};\n Object.entries(result.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n i18nContext.injectBundles({[language]: bundle});\n }\n\n // Defer setLanguage to the next effect cycle so injectBundles state\n // is committed before I18nProvider's setLanguage checks mergedBundles.\n setPendingLanguage(language);\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n },\n [enabled, baseUrl, endpoints, applicationId, i18nContext, fetchMeta, namespace],\n );\n\n // After injectBundles + setPendingLanguage are batched and committed, this\n // effect fires with the updated i18nContext (mergedBundles now includes the\n // new language), so setLanguage succeeds on the first switch.\n useEffect(() => {\n if (pendingLanguage && i18nContext?.setLanguage) {\n i18nContext.setLanguage(pendingLanguage);\n setPendingLanguage(null);\n }\n }, [pendingLanguage, i18nContext?.setLanguage]);\n\n useEffect(() => {\n if (requestKey === null) {\n return;\n }\n\n if (!initialMetaConsumedRef.current) {\n initialMetaConsumedRef.current = true;\n\n if (initialMeta) {\n // Seeded from SSR (or another caller) — skip the redundant first client-side fetch.\n // Later changes to the request (e.g. an explicit language switch) still fetch normally.\n lastRequestKeyRef.current = requestKey;\n return;\n }\n }\n\n if (lastRequestKeyRef.current === requestKey) {\n return;\n }\n\n lastRequestKeyRef.current = requestKey;\n fetchFlowMeta();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [requestKey]);\n\n // When meta loads with i18n translations, inject them into the i18n system.\n // Meta translations act as the base layer — prop-provided bundles still take precedence.\n useEffect(() => {\n if (!meta?.i18n?.translations || !i18nContext?.injectBundles) {\n return;\n }\n\n const metaLanguage: string = meta.i18n.language || TranslationBundleConstants.FALLBACK_LOCALE;\n\n // Flatten namespace-keyed translations to dot-path keys:\n // { \"signin\": { \"heading\": \"Sign In\" } } → { \"signin.heading\": \"Sign In\" }\n const flatTranslations: Record<string, string> = {};\n Object.entries(meta.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n\n // Inject under the meta language code and the i18n current language so\n // lookups succeed regardless of whether the system uses \"en\" or \"en-US\".\n const bundlesToInject: Record<string, I18nBundle> = {[metaLanguage]: bundle};\n if (i18nContext.currentLanguage && i18nContext.currentLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.currentLanguage] = bundle;\n }\n if (i18nContext.fallbackLanguage && i18nContext.fallbackLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.fallbackLanguage] = bundle;\n }\n\n i18nContext.injectBundles(bundlesToInject);\n }, [meta?.i18n?.translations, i18nContext?.injectBundles]);\n\n const value: any = {\n error,\n fetchFlowMeta,\n isLoading,\n meta,\n switchLanguage,\n };\n\n return <FlowMetaContext.Provider value={value}>{children}</FlowMetaContext.Provider>;\n};\n\nexport default FlowMetaProvider;\n"],"mappings":"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"}
@@ -173,7 +173,7 @@ const ThunderIDProvider = ({ afterSignInUrl, afterSignOutUrl, baseUrl: initialBa
173
173
  const code = urlParams.get("code");
174
174
  const executionIdFromUrl = urlParams.get("executionId");
175
175
  const storedExecutionId = sessionStorage.getItem(`${(0, __thunderid_browser.getVendorPrefix)(config.vendor)}_execution_id`);
176
- if (code && !executionIdFromUrl && !storedExecutionId) await signIn();
176
+ if ((code || __thunderid_browser.SPAUtils.isSilentStatePresentInURL()) && !executionIdFromUrl && !storedExecutionId) await signIn();
177
177
  } catch (error) {
178
178
  throw new __thunderid_browser.ThunderIDRuntimeError(`Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`, "thunderid-signIn-Error", "react", "An error occurred while trying to sign in.");
179
179
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDProvider.cjs","names":["logger: ReturnType<typeof createPackageComponentLogger>","ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>>","reRenderCheckRef: RefObject<boolean>","client: ThunderIDReactClient","ThunderIDReactClient","invalidator: ResourceInvalidator","createResourceInvalidator","storageManagerRef: any","useBrowserUrl","pendingSessionUpdateRef: RefObject<Promise<void> | null>","resolvedBaseUrl: string","decodedToken: IdToken","shouldFetchProfile: boolean","claims: User","currentSignInStatus: boolean","getUsersMe","getUsersMeMeta","arg1: any","isV2FlowRequest: boolean","ThunderIDRuntimeError","currentUrl: URL","urlParams: URLSearchParams","code: string | null","executionIdFromUrl: string | null","storedExecutionId: string | null","interval: NodeJS.Timeout","status: boolean","getDecodedIdToken: () => Promise<IdToken>","getIdToken: () => Promise<string>","getAccessToken: () => Promise<string>","getStorageManager: () => Promise<any>","storageManager: any","request: (...args: any[]) => Promise<any>","requestAll: (...args: any[]) => Promise<any>","exchangeToken: (exchangeConfig: any) => Promise<any>","signOut: (...args: any[]) => Promise<any>","recover: (payload: any) => Promise<any>","signUp: (...args: any[]) => Promise<any>","clearSession: (...args: any[]) => Promise<any>","reInitialize: (reInitConfig: any) => Promise<any>","result: any","reinitializedConfig: ThunderIDReactConfig","value: any","ThunderIDContext","I18nProvider","FlowMetaProvider","ThemeProvider","FlowProvider","UserProvider","ComponentRendererProvider"],"sources":["../../../../src/contexts/ThunderID/ThunderIDProvider.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n ThunderIDRuntimeError,\n generateFlattenedUserProfile,\n OIDCDiscoveryApiResponse,\n SignInOptions,\n User,\n UserProfile,\n IdToken,\n extractUserClaimsFromIdToken,\n EmbeddedSignInFlowResponse,\n createPackageComponentLogger,\n getVendorPrefix,\n resolveResourceEndpoint,\n AttributeSchema,\n} from '@thunderid/browser';\nimport {FC, RefObject, PropsWithChildren, ReactElement, useEffect, useMemo, useRef, useState, useCallback} from 'react';\nimport ThunderIDContext from './ThunderIDContext';\nimport useBrowserUrl from '../../hooks/useBrowserUrl';\nimport {ThunderIDReactConfig} from '../../models/config';\nimport {configureEmotionNonce} from '../../styles/emotion';\nimport ThunderIDReactClient from '../../ThunderIDReactClient';\nimport createResourceInvalidator, {ResourceInvalidator} from '../../utils/createResourceInvalidator';\nimport ComponentRendererProvider from '../ComponentRenderer/ComponentRendererProvider';\nimport FlowProvider from '../Flow/FlowProvider';\nimport FlowMetaProvider from '../FlowMeta/FlowMetaProvider';\nimport I18nProvider from '../I18n/I18nProvider';\nimport ThemeProvider from '../Theme/ThemeProvider';\nimport UserProvider from '../User/UserProvider';\nimport getUsersMe from '../../api/getUsersMe';\nimport getUsersMeMeta from '../../api/getUsersMeMeta';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'ThunderIDProvider',\n);\n\n/**\n * Props interface of {@link ThunderIDProvider}\n */\nexport type ThunderIDProviderProps = ThunderIDReactConfig;\n\nconst ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>> = ({\n afterSignInUrl,\n afterSignOutUrl,\n baseUrl: initialBaseUrl,\n clientId,\n children,\n extensions,\n scopes,\n preferences,\n signInUrl,\n signUpUrl,\n organizationHandle,\n applicationId,\n signInOptions,\n tokenRequest,\n instanceId = 0,\n organizationChain,\n cspNonce,\n vendor,\n namespace,\n http: httpOptions,\n ...rest\n}: PropsWithChildren<ThunderIDProviderProps>): ReactElement => {\n // Must run synchronously here, in the render body, before any descendant's css()/cx()/\n // keyframes() calls execute during this same render pass - see the doc comment on\n // `configureEmotionNonce` for why a `useEffect` would be too late.\n configureEmotionNonce(cspNonce, vendor);\n\n const reRenderCheckRef: RefObject<boolean> = useRef(false);\n const client: ThunderIDReactClient = useMemo(() => new ThunderIDReactClient(instanceId), [instanceId]);\n const invalidator: ResourceInvalidator = useMemo(() => createResourceInvalidator(), []);\n const storageManagerRef: any = useRef<any>(null);\n const {hasAuthParams, hasCalledForThisInstance} = useBrowserUrl();\n const [user, setUser] = useState<any | null>(null);\n const [isSignedInSync, setIsSignedInSync] = useState<boolean>(false);\n const [isInitializedSync, setIsInitializedSync] = useState<boolean>(false);\n const [isLoadingSync, setIsLoadingSync] = useState<boolean>(true);\n\n const [userProfile, setUserProfile] = useState<UserProfile | null>(null);\n const [userSchema, setUserSchema] = useState<Record<string, AttributeSchema> | null>(null);\n const [baseUrl, setBaseUrl] = useState<string>(initialBaseUrl ?? '');\n const [config, setConfig] = useState<ThunderIDReactConfig>({\n afterSignInUrl: afterSignInUrl ?? window.location.origin,\n afterSignOutUrl: afterSignOutUrl ?? window.location.origin,\n applicationId,\n baseUrl,\n clientId,\n organizationChain,\n organizationHandle,\n scopes,\n signInOptions,\n tokenRequest,\n signInUrl,\n signUpUrl,\n vendor,\n ...rest,\n });\n\n const [isUpdatingSession, setIsUpdatingSession] = useState<boolean>(false);\n const [wellKnown, setWellKnown] = useState<OIDCDiscoveryApiResponse | null>(null);\n\n // Holds the in-flight `updateSession()` promise so concurrent callers coalesce onto a single\n // `/users/me` request instead of issuing one each.\n const pendingSessionUpdateRef: RefObject<Promise<void> | null> = useRef<Promise<void> | null>(null);\n\n useEffect(() => {\n setBaseUrl(initialBaseUrl ?? '');\n }, [initialBaseUrl]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n await client.initialize(config);\n const initializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(initializedConfig);\n setWellKnown(await client.getDiscoveryResponse());\n })();\n }, []);\n\n async function performSessionUpdate(): Promise<void> {\n try {\n // Set flag to prevent loading state tracking from interfering\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n let resolvedBaseUrl: string = baseUrl;\n\n const decodedToken: IdToken = await client.getDecodedIdToken();\n\n // If there's a `user_org` claim in the ID token,\n // Treat this login as a organization login.\n if (decodedToken?.['user_org']) {\n resolvedBaseUrl = `${(await client.getConfiguration()).baseUrl}/o`;\n setBaseUrl(resolvedBaseUrl);\n }\n\n const shouldFetchProfile: boolean = preferences?.user?.fetchUserProfile !== false;\n const claims: User = extractUserClaimsFromIdToken(decodedToken) as User;\n let profileData = claims;\n const currentSignInStatus: boolean = await client.isSignedIn();\n\n if (currentSignInStatus && shouldFetchProfile) {\n try {\n const fetchedProfile = await getUsersMe({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMe', config),\n instanceId,\n });\n profileData = {...claims, ...fetchedProfile};\n } catch (err) {\n logger.warn('Failed to fetch user profile from /users/me:', err);\n }\n\n try {\n const metaRes = await getUsersMeMeta({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMeMeta', config),\n instanceId,\n });\n if (metaRes?.schema) {\n setUserSchema(metaRes.schema);\n } else {\n setUserSchema(null);\n }\n } catch (err) {\n setUserSchema(null);\n logger.warn('Failed to fetch user schema metadata from /users/me/meta:', err);\n }\n } else {\n setUserSchema(null);\n }\n\n setUser(profileData);\n setUserProfile({\n flattenedProfile: generateFlattenedUserProfile(profileData, []),\n profile: profileData,\n });\n\n // CRITICAL: Update sign-in status BEFORE setting loading to false\n // This prevents the race condition where ProtectedRoute sees isLoading=false but isSignedIn=false\n setIsSignedInSync(currentSignInStatus);\n } catch (error) {\n // TODO: Add an error log.\n } finally {\n // Clear the flag and set final loading state\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n\n /**\n * Single-flight wrapper around {@link performSessionUpdate}.\n *\n * Concurrent callers share the in-flight request instead of each issuing their own `/users/me`.\n * This is not a cache: once the request settles the ref is cleared, so a later caller (e.g.\n * revalidation after a profile update) fetches again.\n */\n async function updateSession(): Promise<void> {\n if (pendingSessionUpdateRef.current) {\n return pendingSessionUpdateRef.current;\n }\n\n pendingSessionUpdateRef.current = performSessionUpdate().finally(() => {\n pendingSessionUpdateRef.current = null;\n });\n\n return pendingSessionUpdateRef.current;\n }\n\n async function signIn(...args: any): Promise<User | EmbeddedSignInFlowResponse> {\n // Check if this is a V2 embedded flow request BEFORE calling signIn\n // This allows us to skip session checks entirely for V2 flows\n const arg1: any = args[0];\n const isV2FlowRequest: boolean =\n typeof arg1 === 'object' && arg1 !== null && ('executionId' in arg1 || 'applicationId' in arg1);\n\n try {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n }\n\n return await client.signIn(...args);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n } finally {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n }\n\n /**\n * Try signing in when the component is mounted.\n */\n useEffect(() => {\n // React 18.x Strict.Mode has a new check for `Ensuring reusable state` to facilitate an upcoming react feature.\n // https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state\n // This will remount all the useEffects to ensure that there are no unexpected side effects.\n // When react remounts the signIn hook of the AuthProvider, it will cause a race condition. Hence, we have to\n // prevent the re-render of this hook as suggested in the following discussion.\n // https://github.com/reactwg/react-18/discussions/18#discussioncomment-795623\n if (reRenderCheckRef.current) {\n return;\n }\n\n reRenderCheckRef.current = true;\n\n (async (): Promise<void> => {\n // Sync session state whenever sign-in completes (both redirect and embedded V2 flows).\n // Pass the user returned by the SDK's sign-in flow so users/me result is not discarded.\n await client.on('sign-in', async () => {\n await updateSession();\n });\n\n // Start auto-refresh with a soft failure. This also covers the case where the access token\n // expired while the refresh token is still valid — startAutoRefreshToken() calls\n // refreshAccessToken() immediately when timeUntilRefresh <= 0 — so the sign-in check below\n // sees the refreshed state.\n try {\n await client.startAutoRefreshToken();\n } catch (error) {\n logger.warn('Failed to schedule automatic token refresh.', error);\n }\n\n // User is already authenticated. Restore the session and skip the sign-in path.\n if (await client.isSignedIn()) {\n await updateSession();\n\n return;\n }\n\n const currentUrl: URL = new URL(window.location.href);\n const hasAuthParamsResult: boolean =\n hasAuthParams(currentUrl, config.afterSignInUrl!) && hasCalledForThisInstance(currentUrl, instanceId ?? 0);\n\n if (hasAuthParamsResult) {\n try {\n const urlParams: URLSearchParams = currentUrl.searchParams;\n const code: string | null = urlParams.get('code');\n const executionIdFromUrl: string | null = urlParams.get('executionId');\n const storedExecutionId: string | null = sessionStorage.getItem(\n `${getVendorPrefix(config.vendor)}_execution_id`,\n );\n\n if (code && !executionIdFromUrl && !storedExecutionId) {\n await signIn();\n }\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n }\n }\n })();\n }, []);\n\n /**\n * Check if the user is signed in and update the state accordingly.\n * This will also set an interval to check for the sign-in status every second\n * until the user is signed in.\n */\n useEffect(() => {\n let interval: NodeJS.Timeout;\n\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isSignedIn();\n\n setIsSignedInSync(status);\n\n if (!status) {\n interval = setInterval(async () => {\n const newStatus: boolean = await client.isSignedIn();\n\n if (newStatus) {\n setIsSignedInSync(true);\n clearInterval(interval);\n }\n }, 1000);\n } else {\n // TODO: Add a debug log to indicate that the user is already signed in.\n }\n } catch (error) {\n setIsSignedInSync(false);\n }\n })();\n\n return (): void => {\n if (interval) {\n clearInterval(interval);\n }\n };\n }, [client]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isInitialized();\n\n setIsInitializedSync(status);\n } catch (error) {\n setIsInitializedSync(false);\n }\n })();\n }, [client]);\n\n /**\n * Track loading state changes from the ThunderID client\n */\n useEffect(() => {\n const checkLoadingState = (): void => {\n // Don't override loading state during critical session updates\n if (isUpdatingSession) {\n return;\n }\n\n // Don't set loading=false while auth params are in the URL and user isn't signed in yet.\n // This prevents ProtectedRoute from redirecting before the sign-in effect processes the auth code.\n const currentUrl: URL = new URL(window.location.href);\n if (!isSignedInSync && hasAuthParams(currentUrl, config.afterSignInUrl!)) {\n return;\n }\n\n setIsLoadingSync(client.isLoading());\n };\n\n // Initial check\n checkLoadingState();\n\n // Set up an interval to check for loading state changes\n const interval: NodeJS.Timeout = setInterval(checkLoadingState, 100);\n\n return (): void => {\n clearInterval(interval);\n };\n }, [client, isLoadingSync, isSignedInSync, isUpdatingSession]);\n\n const signInSilently = async (options?: SignInOptions): Promise<User | boolean> => {\n try {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n return await client.signInSilently(options);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Error while signing in silently: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signInSilently-Error',\n 'react',\n 'An error occurred while trying to sign in silently.',\n );\n } finally {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n };\n\n const handleProfileUpdate = (payload: User): void => {\n setUser(payload);\n setUserProfile((prev: UserProfile | null) => ({\n flattenedProfile: generateFlattenedUserProfile(payload),\n profile: payload,\n }));\n };\n\n const getDecodedIdToken: () => Promise<IdToken> = useCallback(\n async (): Promise<IdToken> => client.getDecodedIdToken(),\n [client],\n );\n\n const getIdToken: () => Promise<string> = useCallback(async (): Promise<string> => client.getIdToken(), [client]);\n\n const getAccessToken: () => Promise<string> = useCallback(\n async (): Promise<string> => client.getAccessToken(),\n [client],\n );\n\n const getStorageManager: () => Promise<any> = useCallback(async (): Promise<any> => {\n const storageManager: any = storageManagerRef.current ?? (await client.getStorageManager());\n if (storageManager) {\n storageManagerRef.current = storageManager;\n }\n return storageManager;\n }, [client]);\n\n const request: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.request(...args),\n [client],\n );\n\n const requestAll: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.requestAll(...args),\n [client],\n );\n\n const exchangeToken: (exchangeConfig: any) => Promise<any> = useCallback(\n async (exchangeConfig: any): Promise<any> => client.exchangeToken(exchangeConfig),\n [client],\n );\n\n const signOut: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signOut(...args),\n [client],\n );\n\n const recover: (payload: any) => Promise<any> = useCallback(\n async (payload: any): Promise<any> => client.recover(payload),\n [client],\n );\n\n const signUp: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signUp(...args),\n [client],\n );\n\n const clearSession: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.clearSession(...args),\n [client],\n );\n\n const reInitialize: (reInitConfig: any) => Promise<any> = useCallback(\n async (reInitConfig: any): Promise<any> => {\n const result: any = await client.reInitialize(reInitConfig);\n\n // Refresh React state from the reinitialized client so the context (config.endpoints,\n // baseUrl, discovery) reflects the new configuration instead of the pre-reinitialization state.\n const reinitializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(reinitializedConfig);\n setBaseUrl(reinitializedConfig.baseUrl ?? '');\n setWellKnown(await client.getDiscoveryResponse());\n\n return result;\n },\n [client],\n );\n\n const value: any = useMemo(\n () => ({\n afterSignInUrl: config.afterSignInUrl,\n applicationId: config.applicationId,\n baseUrl,\n endpoints: config.endpoints,\n scopes: config.scopes,\n clearSession,\n clientId,\n discovery: {\n wellKnown,\n },\n exchangeToken,\n getAccessToken,\n getDecodedIdToken,\n getIdToken,\n getStorageManager,\n http: {\n fetcher: httpOptions?.fetcher,\n request,\n requestAll,\n },\n instanceId,\n invalidator,\n isInitialized: isInitializedSync,\n isLoading: isLoadingSync,\n isSignedIn: isSignedInSync,\n organizationChain,\n organizationHandle: config?.organizationHandle,\n preferences,\n reInitialize,\n recover,\n signIn,\n signInOptions,\n tokenRequest,\n signInSilently,\n signInUrl,\n signOut,\n signUp,\n signUpUrl,\n user,\n userSchema,\n vendor: getVendorPrefix(config.vendor),\n }),\n [\n applicationId,\n config?.organizationHandle,\n config.vendor,\n config.afterSignInUrl,\n config.endpoints,\n config.scopes,\n signInUrl,\n signUpUrl,\n baseUrl,\n clientId,\n wellKnown,\n isInitializedSync,\n isLoadingSync,\n isSignedInSync,\n signIn,\n signInSilently,\n user,\n userSchema,\n client,\n signInOptions,\n tokenRequest,\n getDecodedIdToken,\n clearSession,\n exchangeToken,\n httpOptions?.fetcher,\n getAccessToken,\n getStorageManager,\n instanceId,\n invalidator,\n organizationChain,\n preferences,\n recover,\n reInitialize,\n request,\n requestAll,\n signOut,\n signUp,\n ],\n );\n\n return (\n <ThunderIDContext.Provider value={value}>\n <I18nProvider preferences={preferences?.i18n} vendor={getVendorPrefix(config.vendor)}>\n <FlowMetaProvider enabled={preferences?.resolveFromMeta !== false} namespace={namespace}>\n <ThemeProvider\n theme={{\n ...preferences?.theme?.overrides,\n direction: preferences?.theme?.direction,\n }}\n >\n <FlowProvider>\n <UserProvider\n profile={userProfile as UserProfile}\n userSchema={userSchema}\n onUpdateProfile={handleProfileUpdate}\n >\n <ComponentRendererProvider renderers={(extensions?.components?.renderers ?? {}) as any}>\n {children}\n </ComponentRendererProvider>\n </UserProvider>\n </FlowProvider>\n </ThemeProvider>\n </FlowMetaProvider>\n </I18nProvider>\n </ThunderIDContext.Provider>\n );\n};\n\nexport default ThunderIDProvider;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ThunderIDProvider.cjs","names":["logger: ReturnType<typeof createPackageComponentLogger>","ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>>","reRenderCheckRef: RefObject<boolean>","client: ThunderIDReactClient","ThunderIDReactClient","invalidator: ResourceInvalidator","createResourceInvalidator","storageManagerRef: any","useBrowserUrl","pendingSessionUpdateRef: RefObject<Promise<void> | null>","resolvedBaseUrl: string","decodedToken: IdToken","shouldFetchProfile: boolean","claims: User","currentSignInStatus: boolean","getUsersMe","getUsersMeMeta","arg1: any","isV2FlowRequest: boolean","ThunderIDRuntimeError","currentUrl: URL","urlParams: URLSearchParams","code: string | null","executionIdFromUrl: string | null","storedExecutionId: string | null","SPAUtils","interval: NodeJS.Timeout","status: boolean","getDecodedIdToken: () => Promise<IdToken>","getIdToken: () => Promise<string>","getAccessToken: () => Promise<string>","getStorageManager: () => Promise<any>","storageManager: any","request: (...args: any[]) => Promise<any>","requestAll: (...args: any[]) => Promise<any>","exchangeToken: (exchangeConfig: any) => Promise<any>","signOut: (...args: any[]) => Promise<any>","recover: (payload: any) => Promise<any>","signUp: (...args: any[]) => Promise<any>","clearSession: (...args: any[]) => Promise<any>","reInitialize: (reInitConfig: any) => Promise<any>","result: any","reinitializedConfig: ThunderIDReactConfig","value: any","ThunderIDContext","I18nProvider","FlowMetaProvider","ThemeProvider","FlowProvider","UserProvider","ComponentRendererProvider"],"sources":["../../../../src/contexts/ThunderID/ThunderIDProvider.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n ThunderIDRuntimeError,\n generateFlattenedUserProfile,\n OIDCDiscoveryApiResponse,\n SignInOptions,\n User,\n UserProfile,\n IdToken,\n extractUserClaimsFromIdToken,\n EmbeddedSignInFlowResponse,\n createPackageComponentLogger,\n getVendorPrefix,\n resolveResourceEndpoint,\n AttributeSchema,\n SPAUtils,\n} from '@thunderid/browser';\nimport {FC, RefObject, PropsWithChildren, ReactElement, useEffect, useMemo, useRef, useState, useCallback} from 'react';\nimport ThunderIDContext from './ThunderIDContext';\nimport useBrowserUrl from '../../hooks/useBrowserUrl';\nimport {ThunderIDReactConfig} from '../../models/config';\nimport {configureEmotionNonce} from '../../styles/emotion';\nimport ThunderIDReactClient from '../../ThunderIDReactClient';\nimport createResourceInvalidator, {ResourceInvalidator} from '../../utils/createResourceInvalidator';\nimport ComponentRendererProvider from '../ComponentRenderer/ComponentRendererProvider';\nimport FlowProvider from '../Flow/FlowProvider';\nimport FlowMetaProvider from '../FlowMeta/FlowMetaProvider';\nimport I18nProvider from '../I18n/I18nProvider';\nimport ThemeProvider from '../Theme/ThemeProvider';\nimport UserProvider from '../User/UserProvider';\nimport getUsersMe from '../../api/getUsersMe';\nimport getUsersMeMeta from '../../api/getUsersMeMeta';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'ThunderIDProvider',\n);\n\n/**\n * Props interface of {@link ThunderIDProvider}\n */\nexport type ThunderIDProviderProps = ThunderIDReactConfig;\n\nconst ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>> = ({\n afterSignInUrl,\n afterSignOutUrl,\n baseUrl: initialBaseUrl,\n clientId,\n children,\n extensions,\n scopes,\n preferences,\n signInUrl,\n signUpUrl,\n organizationHandle,\n applicationId,\n signInOptions,\n tokenRequest,\n instanceId = 0,\n organizationChain,\n cspNonce,\n vendor,\n namespace,\n http: httpOptions,\n ...rest\n}: PropsWithChildren<ThunderIDProviderProps>): ReactElement => {\n // Must run synchronously here, in the render body, before any descendant's css()/cx()/\n // keyframes() calls execute during this same render pass - see the doc comment on\n // `configureEmotionNonce` for why a `useEffect` would be too late.\n configureEmotionNonce(cspNonce, vendor);\n\n const reRenderCheckRef: RefObject<boolean> = useRef(false);\n const client: ThunderIDReactClient = useMemo(() => new ThunderIDReactClient(instanceId), [instanceId]);\n const invalidator: ResourceInvalidator = useMemo(() => createResourceInvalidator(), []);\n const storageManagerRef: any = useRef<any>(null);\n const {hasAuthParams, hasCalledForThisInstance} = useBrowserUrl();\n const [user, setUser] = useState<any | null>(null);\n const [isSignedInSync, setIsSignedInSync] = useState<boolean>(false);\n const [isInitializedSync, setIsInitializedSync] = useState<boolean>(false);\n const [isLoadingSync, setIsLoadingSync] = useState<boolean>(true);\n\n const [userProfile, setUserProfile] = useState<UserProfile | null>(null);\n const [userSchema, setUserSchema] = useState<Record<string, AttributeSchema> | null>(null);\n const [baseUrl, setBaseUrl] = useState<string>(initialBaseUrl ?? '');\n const [config, setConfig] = useState<ThunderIDReactConfig>({\n afterSignInUrl: afterSignInUrl ?? window.location.origin,\n afterSignOutUrl: afterSignOutUrl ?? window.location.origin,\n applicationId,\n baseUrl,\n clientId,\n organizationChain,\n organizationHandle,\n scopes,\n signInOptions,\n tokenRequest,\n signInUrl,\n signUpUrl,\n vendor,\n ...rest,\n });\n\n const [isUpdatingSession, setIsUpdatingSession] = useState<boolean>(false);\n const [wellKnown, setWellKnown] = useState<OIDCDiscoveryApiResponse | null>(null);\n\n // Holds the in-flight `updateSession()` promise so concurrent callers coalesce onto a single\n // `/users/me` request instead of issuing one each.\n const pendingSessionUpdateRef: RefObject<Promise<void> | null> = useRef<Promise<void> | null>(null);\n\n useEffect(() => {\n setBaseUrl(initialBaseUrl ?? '');\n }, [initialBaseUrl]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n await client.initialize(config);\n const initializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(initializedConfig);\n setWellKnown(await client.getDiscoveryResponse());\n })();\n }, []);\n\n async function performSessionUpdate(): Promise<void> {\n try {\n // Set flag to prevent loading state tracking from interfering\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n let resolvedBaseUrl: string = baseUrl;\n\n const decodedToken: IdToken = await client.getDecodedIdToken();\n\n // If there's a `user_org` claim in the ID token,\n // Treat this login as a organization login.\n if (decodedToken?.['user_org']) {\n resolvedBaseUrl = `${(await client.getConfiguration()).baseUrl}/o`;\n setBaseUrl(resolvedBaseUrl);\n }\n\n const shouldFetchProfile: boolean = preferences?.user?.fetchUserProfile !== false;\n const claims: User = extractUserClaimsFromIdToken(decodedToken) as User;\n let profileData = claims;\n const currentSignInStatus: boolean = await client.isSignedIn();\n\n if (currentSignInStatus && shouldFetchProfile) {\n try {\n const fetchedProfile = await getUsersMe({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMe', config),\n instanceId,\n });\n profileData = {...claims, ...fetchedProfile};\n } catch (err) {\n logger.warn('Failed to fetch user profile from /users/me:', err);\n }\n\n try {\n const metaRes = await getUsersMeMeta({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMeMeta', config),\n instanceId,\n });\n if (metaRes?.schema) {\n setUserSchema(metaRes.schema);\n } else {\n setUserSchema(null);\n }\n } catch (err) {\n setUserSchema(null);\n logger.warn('Failed to fetch user schema metadata from /users/me/meta:', err);\n }\n } else {\n setUserSchema(null);\n }\n\n setUser(profileData);\n setUserProfile({\n flattenedProfile: generateFlattenedUserProfile(profileData, []),\n profile: profileData,\n });\n\n // CRITICAL: Update sign-in status BEFORE setting loading to false\n // This prevents the race condition where ProtectedRoute sees isLoading=false but isSignedIn=false\n setIsSignedInSync(currentSignInStatus);\n } catch (error) {\n // TODO: Add an error log.\n } finally {\n // Clear the flag and set final loading state\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n\n /**\n * Single-flight wrapper around {@link performSessionUpdate}.\n *\n * Concurrent callers share the in-flight request instead of each issuing their own `/users/me`.\n * This is not a cache: once the request settles the ref is cleared, so a later caller (e.g.\n * revalidation after a profile update) fetches again.\n */\n async function updateSession(): Promise<void> {\n if (pendingSessionUpdateRef.current) {\n return pendingSessionUpdateRef.current;\n }\n\n pendingSessionUpdateRef.current = performSessionUpdate().finally(() => {\n pendingSessionUpdateRef.current = null;\n });\n\n return pendingSessionUpdateRef.current;\n }\n\n async function signIn(...args: any): Promise<User | EmbeddedSignInFlowResponse> {\n // Check if this is a V2 embedded flow request BEFORE calling signIn\n // This allows us to skip session checks entirely for V2 flows\n const arg1: any = args[0];\n const isV2FlowRequest: boolean =\n typeof arg1 === 'object' && arg1 !== null && ('executionId' in arg1 || 'applicationId' in arg1);\n\n try {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n }\n\n return await client.signIn(...args);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n } finally {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n }\n\n /**\n * Try signing in when the component is mounted.\n */\n useEffect(() => {\n // React 18.x Strict.Mode has a new check for `Ensuring reusable state` to facilitate an upcoming react feature.\n // https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state\n // This will remount all the useEffects to ensure that there are no unexpected side effects.\n // When react remounts the signIn hook of the AuthProvider, it will cause a race condition. Hence, we have to\n // prevent the re-render of this hook as suggested in the following discussion.\n // https://github.com/reactwg/react-18/discussions/18#discussioncomment-795623\n if (reRenderCheckRef.current) {\n return;\n }\n\n reRenderCheckRef.current = true;\n\n (async (): Promise<void> => {\n // Sync session state whenever sign-in completes (both redirect and embedded V2 flows).\n // Pass the user returned by the SDK's sign-in flow so users/me result is not discarded.\n await client.on('sign-in', async () => {\n await updateSession();\n });\n\n // Start auto-refresh with a soft failure. This also covers the case where the access token\n // expired while the refresh token is still valid — startAutoRefreshToken() calls\n // refreshAccessToken() immediately when timeUntilRefresh <= 0 — so the sign-in check below\n // sees the refreshed state.\n try {\n await client.startAutoRefreshToken();\n } catch (error) {\n logger.warn('Failed to schedule automatic token refresh.', error);\n }\n\n // User is already authenticated. Restore the session and skip the sign-in path.\n if (await client.isSignedIn()) {\n await updateSession();\n\n return;\n }\n\n const currentUrl: URL = new URL(window.location.href);\n const hasAuthParamsResult: boolean =\n hasAuthParams(currentUrl, config.afterSignInUrl!) && hasCalledForThisInstance(currentUrl, instanceId ?? 0);\n\n if (hasAuthParamsResult) {\n try {\n const urlParams: URLSearchParams = currentUrl.searchParams;\n const code: string | null = urlParams.get('code');\n const executionIdFromUrl: string | null = urlParams.get('executionId');\n const storedExecutionId: string | null = sessionStorage.getItem(\n `${getVendorPrefix(config.vendor)}_execution_id`,\n );\n\n // A silent sign-in response is handled even without a code: an error such as\n // login_required must still be relayed from the iframe to the waiting parent.\n if ((code || SPAUtils.isSilentStatePresentInURL()) && !executionIdFromUrl && !storedExecutionId) {\n await signIn();\n }\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n }\n }\n })();\n }, []);\n\n /**\n * Check if the user is signed in and update the state accordingly.\n * This will also set an interval to check for the sign-in status every second\n * until the user is signed in.\n */\n useEffect(() => {\n let interval: NodeJS.Timeout;\n\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isSignedIn();\n\n setIsSignedInSync(status);\n\n if (!status) {\n interval = setInterval(async () => {\n const newStatus: boolean = await client.isSignedIn();\n\n if (newStatus) {\n setIsSignedInSync(true);\n clearInterval(interval);\n }\n }, 1000);\n } else {\n // TODO: Add a debug log to indicate that the user is already signed in.\n }\n } catch (error) {\n setIsSignedInSync(false);\n }\n })();\n\n return (): void => {\n if (interval) {\n clearInterval(interval);\n }\n };\n }, [client]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isInitialized();\n\n setIsInitializedSync(status);\n } catch (error) {\n setIsInitializedSync(false);\n }\n })();\n }, [client]);\n\n /**\n * Track loading state changes from the ThunderID client\n */\n useEffect(() => {\n const checkLoadingState = (): void => {\n // Don't override loading state during critical session updates\n if (isUpdatingSession) {\n return;\n }\n\n // Don't set loading=false while auth params are in the URL and user isn't signed in yet.\n // This prevents ProtectedRoute from redirecting before the sign-in effect processes the auth code.\n const currentUrl: URL = new URL(window.location.href);\n if (!isSignedInSync && hasAuthParams(currentUrl, config.afterSignInUrl!)) {\n return;\n }\n\n setIsLoadingSync(client.isLoading());\n };\n\n // Initial check\n checkLoadingState();\n\n // Set up an interval to check for loading state changes\n const interval: NodeJS.Timeout = setInterval(checkLoadingState, 100);\n\n return (): void => {\n clearInterval(interval);\n };\n }, [client, isLoadingSync, isSignedInSync, isUpdatingSession]);\n\n const signInSilently = async (options?: SignInOptions): Promise<User | boolean> => {\n try {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n return await client.signInSilently(options);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Error while signing in silently: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signInSilently-Error',\n 'react',\n 'An error occurred while trying to sign in silently.',\n );\n } finally {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n };\n\n const handleProfileUpdate = (payload: User): void => {\n setUser(payload);\n setUserProfile((prev: UserProfile | null) => ({\n flattenedProfile: generateFlattenedUserProfile(payload),\n profile: payload,\n }));\n };\n\n const getDecodedIdToken: () => Promise<IdToken> = useCallback(\n async (): Promise<IdToken> => client.getDecodedIdToken(),\n [client],\n );\n\n const getIdToken: () => Promise<string> = useCallback(async (): Promise<string> => client.getIdToken(), [client]);\n\n const getAccessToken: () => Promise<string> = useCallback(\n async (): Promise<string> => client.getAccessToken(),\n [client],\n );\n\n const getStorageManager: () => Promise<any> = useCallback(async (): Promise<any> => {\n const storageManager: any = storageManagerRef.current ?? (await client.getStorageManager());\n if (storageManager) {\n storageManagerRef.current = storageManager;\n }\n return storageManager;\n }, [client]);\n\n const request: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.request(...args),\n [client],\n );\n\n const requestAll: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.requestAll(...args),\n [client],\n );\n\n const exchangeToken: (exchangeConfig: any) => Promise<any> = useCallback(\n async (exchangeConfig: any): Promise<any> => client.exchangeToken(exchangeConfig),\n [client],\n );\n\n const signOut: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signOut(...args),\n [client],\n );\n\n const recover: (payload: any) => Promise<any> = useCallback(\n async (payload: any): Promise<any> => client.recover(payload),\n [client],\n );\n\n const signUp: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signUp(...args),\n [client],\n );\n\n const clearSession: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.clearSession(...args),\n [client],\n );\n\n const reInitialize: (reInitConfig: any) => Promise<any> = useCallback(\n async (reInitConfig: any): Promise<any> => {\n const result: any = await client.reInitialize(reInitConfig);\n\n // Refresh React state from the reinitialized client so the context (config.endpoints,\n // baseUrl, discovery) reflects the new configuration instead of the pre-reinitialization state.\n const reinitializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(reinitializedConfig);\n setBaseUrl(reinitializedConfig.baseUrl ?? '');\n setWellKnown(await client.getDiscoveryResponse());\n\n return result;\n },\n [client],\n );\n\n const value: any = useMemo(\n () => ({\n afterSignInUrl: config.afterSignInUrl,\n applicationId: config.applicationId,\n baseUrl,\n endpoints: config.endpoints,\n scopes: config.scopes,\n clearSession,\n clientId,\n discovery: {\n wellKnown,\n },\n exchangeToken,\n getAccessToken,\n getDecodedIdToken,\n getIdToken,\n getStorageManager,\n http: {\n fetcher: httpOptions?.fetcher,\n request,\n requestAll,\n },\n instanceId,\n invalidator,\n isInitialized: isInitializedSync,\n isLoading: isLoadingSync,\n isSignedIn: isSignedInSync,\n organizationChain,\n organizationHandle: config?.organizationHandle,\n preferences,\n reInitialize,\n recover,\n signIn,\n signInOptions,\n tokenRequest,\n signInSilently,\n signInUrl,\n signOut,\n signUp,\n signUpUrl,\n user,\n userSchema,\n vendor: getVendorPrefix(config.vendor),\n }),\n [\n applicationId,\n config?.organizationHandle,\n config.vendor,\n config.afterSignInUrl,\n config.endpoints,\n config.scopes,\n signInUrl,\n signUpUrl,\n baseUrl,\n clientId,\n wellKnown,\n isInitializedSync,\n isLoadingSync,\n isSignedInSync,\n signIn,\n signInSilently,\n user,\n userSchema,\n client,\n signInOptions,\n tokenRequest,\n getDecodedIdToken,\n clearSession,\n exchangeToken,\n httpOptions?.fetcher,\n getAccessToken,\n getStorageManager,\n instanceId,\n invalidator,\n organizationChain,\n preferences,\n recover,\n reInitialize,\n request,\n requestAll,\n signOut,\n signUp,\n ],\n );\n\n return (\n <ThunderIDContext.Provider value={value}>\n <I18nProvider preferences={preferences?.i18n} vendor={getVendorPrefix(config.vendor)}>\n <FlowMetaProvider enabled={preferences?.resolveFromMeta !== false} namespace={namespace}>\n <ThemeProvider\n theme={{\n ...preferences?.theme?.overrides,\n direction: preferences?.theme?.direction,\n }}\n >\n <FlowProvider>\n <UserProvider\n profile={userProfile as UserProfile}\n userSchema={userSchema}\n onUpdateProfile={handleProfileUpdate}\n >\n <ComponentRendererProvider renderers={(extensions?.components?.renderers ?? {}) as any}>\n {children}\n </ComponentRendererProvider>\n </UserProvider>\n </FlowProvider>\n </ThemeProvider>\n </FlowMetaProvider>\n </I18nProvider>\n </ThunderIDContext.Provider>\n );\n};\n\nexport default ThunderIDProvider;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FlowMetaProvider.d.ts","sourceRoot":"","sources":["../../../src/contexts/FlowMeta/FlowMetaProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,oBAAoB,EAMrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAAoE,MAAM,OAAO,CAAC;AAM/G,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEnG;;;;;OAKG;IACH,WAAW,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAE1C,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,gBAAgB,EAAE,EAAE,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAiLlE,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"FlowMetaProvider.d.ts","sourceRoot":"","sources":["../../../src/contexts/FlowMeta/FlowMetaProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,oBAAoB,EAMrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAAoE,MAAM,OAAO,CAAC;AAM/G,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEnG;;;;;OAKG;IACH,WAAW,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAE1C,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,gBAAgB,EAAE,EAAE,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAsMlE,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -36,7 +36,7 @@ const FlowMetaProvider = ({ children, enabled = true, fetchMeta, initialMeta = n
36
36
  const [isLoading, setIsLoading] = useState(!initialMeta);
37
37
  const [error, setError] = useState(null);
38
38
  const [pendingLanguage, setPendingLanguage] = useState(null);
39
- const lastFetchedRef = useRef(null);
39
+ const lastRequestKeyRef = useRef(null);
40
40
  const initialMetaConsumedRef = useRef(false);
41
41
  const fetchFlowMeta = useCallback(async () => {
42
42
  if (!enabled) {
@@ -76,6 +76,21 @@ const FlowMetaProvider = ({ children, enabled = true, fetchMeta, initialMeta = n
76
76
  fetchMeta,
77
77
  namespace
78
78
  ]);
79
+ const fetchMetaRef = useRef(fetchMeta);
80
+ const fetchMetaVersionRef = useRef(0);
81
+ if (fetchMetaRef.current !== fetchMeta) {
82
+ fetchMetaRef.current = fetchMeta;
83
+ fetchMetaVersionRef.current += 1;
84
+ }
85
+ const requestKey = enabled && !isInitialized && !applicationId ? null : JSON.stringify([
86
+ enabled,
87
+ enabled && !fetchMeta ? baseUrl : null,
88
+ enabled && !fetchMeta ? resolveResourceEndpoint("flowMeta", { endpoints }) : null,
89
+ applicationId ?? null,
90
+ namespace ?? null,
91
+ i18nContext?.currentLanguage ?? null,
92
+ fetchMetaVersionRef.current
93
+ ]);
79
94
  const switchLanguage = useCallback(async (language) => {
80
95
  if (!enabled) return;
81
96
  setIsLoading(true);
@@ -127,17 +142,18 @@ const FlowMetaProvider = ({ children, enabled = true, fetchMeta, initialMeta = n
127
142
  }
128
143
  }, [pendingLanguage, i18nContext?.setLanguage]);
129
144
  useEffect(() => {
145
+ if (requestKey === null) return;
130
146
  if (!initialMetaConsumedRef.current) {
131
147
  initialMetaConsumedRef.current = true;
132
148
  if (initialMeta) {
133
- lastFetchedRef.current = fetchFlowMeta;
149
+ lastRequestKeyRef.current = requestKey;
134
150
  return;
135
151
  }
136
152
  }
137
- if (lastFetchedRef.current === fetchFlowMeta) return;
138
- lastFetchedRef.current = fetchFlowMeta;
153
+ if (lastRequestKeyRef.current === requestKey) return;
154
+ lastRequestKeyRef.current = requestKey;
139
155
  fetchFlowMeta();
140
- }, [fetchFlowMeta]);
156
+ }, [requestKey]);
141
157
  useEffect(() => {
142
158
  if (!meta?.i18n?.translations || !i18nContext?.injectBundles) return;
143
159
  const metaLanguage = meta.i18n.language || TranslationBundleConstants.FALLBACK_LOCALE;
@@ -1 +1 @@
1
- {"version":3,"file":"FlowMetaProvider.js","names":["FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>>","useThunderID","i18nContext: I18nContextValue","useI18n","lastFetchedRef: RefObject<(() => Promise<void>) | null>","initialMetaConsumedRef: RefObject<boolean>","fetchFlowMeta: () => Promise<void>","err: unknown","switchLanguage: (language: string) => Promise<void>","result: FlowMetadataResponse","flatTranslations: Record<string, string>","namespace","value","bundle: I18nBundle","metaLanguage: string","bundlesToInject: Record<string, I18nBundle>","value: any","FlowMetaContext"],"sources":["../../../src/contexts/FlowMeta/FlowMetaProvider.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n FlowMetadataResponse,\n FlowMetaType,\n getFlowMeta,\n I18nBundle,\n resolveResourceEndpoint,\n TranslationBundleConstants,\n} from '@thunderid/browser';\nimport {FC, PropsWithChildren, ReactElement, RefObject, useCallback, useEffect, useRef, useState} from 'react';\nimport FlowMetaContext from './FlowMetaContext';\nimport {I18nContextValue} from '../I18n/I18nContext';\nimport useI18n from '../I18n/useI18n';\nimport useThunderID from '../ThunderID/useThunderID';\n\nexport interface FlowMetaProviderProps {\n /**\n * When false the provider skips fetching and provides null meta.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Overrides how flow metadata is fetched, routing the request through a caller-supplied\n * function (e.g. a Next.js Server Action) instead of the provider's default direct\n * browser-to-`baseUrl` `fetch()`. Use this when the ThunderID server's `baseUrl` is a\n * different origin than the app and CORS isn't (or can't be) configured for it — the\n * override runs server-side, so the browser never talks to `baseUrl` directly.\n *\n * Called for both the initial fetch and `switchLanguage()`.\n */\n fetchMeta?: (params: {applicationId?: string; language?: string}) => Promise<FlowMetadataResponse>;\n\n /**\n * Flow metadata resolved ahead of time (e.g. fetched server-side during SSR) and used to seed\n * the provider's state. When present, the provider skips its own initial client-side fetch —\n * avoiding a redundant request and the flash of untranslated i18n keys while that fetch is in\n * flight — but still fetches normally on subsequent changes (e.g. an explicit language switch).\n */\n initialMeta?: FlowMetadataResponse | null;\n\n /** Sent as the flow-meta request's `namespace`, e.g. to scope namespace-keyed i18n data. */\n namespace?: string;\n}\n\n/**\n * FlowMetaProvider fetches flow metadata from the `GET /flow/meta` endpoint\n * (v2 API) and makes it available to child components through `FlowMetaContext`.\n *\n * It is designed to be used in v2 embedded-flow scenarios and integrates with\n * `ThemeProvider` so that theme settings (colors, direction, typography, …)\n * from the server-side design configuration are applied automatically.\n *\n * @example\n * ```tsx\n * <FlowMetaProvider\n * config={{\n * baseUrl: 'https://localhost:8090',\n * type: FlowMetaType.App,\n * id: 'your-app-id',\n * }}\n * >\n * <ThemeProvider>\n * <App />\n * </ThemeProvider>\n * </FlowMetaProvider>\n * ```\n */\nconst FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>> = ({\n children,\n enabled = true,\n fetchMeta,\n initialMeta = null,\n namespace,\n}: PropsWithChildren<FlowMetaProviderProps>): ReactElement => {\n const {baseUrl, endpoints, applicationId, isInitialized} = useThunderID();\n const i18nContext: I18nContextValue = useI18n();\n\n const [meta, setMeta] = useState<FlowMetadataResponse | null>(initialMeta);\n const [isLoading, setIsLoading] = useState<boolean>(!initialMeta);\n const [error, setError] = useState<Error | null>(null);\n const [pendingLanguage, setPendingLanguage] = useState<string | null>(null);\n\n // Track the last fetchFlowMeta reference that was actually dispatched.\n // This prevents two classes of double-fetch:\n // 1. React StrictMode simulates unmount+remount — the re-mount fires the\n // effect again with the same fetchFlowMeta reference; without this guard\n // the else-branch would issue a redundant second network request.\n // 2. Rapid dependency changes (e.g. baseUrl stabilising) that produce two\n // effect firings before the first fetch completes.\n const lastFetchedRef: RefObject<(() => Promise<void>) | null> = useRef<(() => Promise<void>) | null>(null);\n const initialMetaConsumedRef: RefObject<boolean> = useRef(false);\n const fetchFlowMeta: () => Promise<void> = useCallback(async (): Promise<void> => {\n if (!enabled) {\n setMeta(null);\n setIsLoading(false);\n return;\n }\n\n // Defer until ThunderID finishes initializing (e.g. loading applicationId\n // from storage on refresh). Once initialized, proceed even if applicationId\n // is absent — some flows (e.g. AcceptInvite) have no applicationId by design.\n if (!isInitialized && !applicationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language: i18nContext?.currentLanguage})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language: i18nContext?.currentLanguage,\n });\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n }, [enabled, baseUrl, endpoints, applicationId, isInitialized, i18nContext?.currentLanguage, fetchMeta, namespace]);\n\n const switchLanguage: (language: string) => Promise<void> = useCallback(\n async (language: string): Promise<void> => {\n if (!enabled) return;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language,\n });\n\n // Inject translations for the new language before switching\n if (result.i18n?.translations && i18nContext?.injectBundles) {\n const flatTranslations: Record<string, string> = {};\n Object.entries(result.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n i18nContext.injectBundles({[language]: bundle});\n }\n\n // Defer setLanguage to the next effect cycle so injectBundles state\n // is committed before I18nProvider's setLanguage checks mergedBundles.\n setPendingLanguage(language);\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n },\n [enabled, baseUrl, endpoints, applicationId, i18nContext, fetchMeta, namespace],\n );\n\n // After injectBundles + setPendingLanguage are batched and committed, this\n // effect fires with the updated i18nContext (mergedBundles now includes the\n // new language), so setLanguage succeeds on the first switch.\n useEffect(() => {\n if (pendingLanguage && i18nContext?.setLanguage) {\n i18nContext.setLanguage(pendingLanguage);\n setPendingLanguage(null);\n }\n }, [pendingLanguage, i18nContext?.setLanguage]);\n\n useEffect(() => {\n if (!initialMetaConsumedRef.current) {\n initialMetaConsumedRef.current = true;\n\n if (initialMeta) {\n // Seeded from SSR (or another caller) — skip the redundant first client-side fetch.\n // Later dependency changes (e.g. an explicit language switch) still fetch normally.\n lastFetchedRef.current = fetchFlowMeta;\n return;\n }\n }\n\n if (lastFetchedRef.current === fetchFlowMeta) {\n // Same reference as the last dispatch — this is a StrictMode re-mount\n // or an effect re-fire with unchanged deps. Skip to avoid a duplicate fetch.\n return;\n }\n\n lastFetchedRef.current = fetchFlowMeta;\n fetchFlowMeta();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fetchFlowMeta]);\n\n // When meta loads with i18n translations, inject them into the i18n system.\n // Meta translations act as the base layer — prop-provided bundles still take precedence.\n useEffect(() => {\n if (!meta?.i18n?.translations || !i18nContext?.injectBundles) {\n return;\n }\n\n const metaLanguage: string = meta.i18n.language || TranslationBundleConstants.FALLBACK_LOCALE;\n\n // Flatten namespace-keyed translations to dot-path keys:\n // { \"signin\": { \"heading\": \"Sign In\" } } → { \"signin.heading\": \"Sign In\" }\n const flatTranslations: Record<string, string> = {};\n Object.entries(meta.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n\n // Inject under the meta language code and the i18n current language so\n // lookups succeed regardless of whether the system uses \"en\" or \"en-US\".\n const bundlesToInject: Record<string, I18nBundle> = {[metaLanguage]: bundle};\n if (i18nContext.currentLanguage && i18nContext.currentLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.currentLanguage] = bundle;\n }\n if (i18nContext.fallbackLanguage && i18nContext.fallbackLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.fallbackLanguage] = bundle;\n }\n\n i18nContext.injectBundles(bundlesToInject);\n }, [meta?.i18n?.translations, i18nContext?.injectBundles]);\n\n const value: any = {\n error,\n fetchFlowMeta,\n isLoading,\n meta,\n switchLanguage,\n };\n\n return <FlowMetaContext.Provider value={value}>{children}</FlowMetaContext.Provider>;\n};\n\nexport default FlowMetaProvider;\n"],"mappings":"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"}
1
+ {"version":3,"file":"FlowMetaProvider.js","names":["FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>>","useThunderID","i18nContext: I18nContextValue","useI18n","lastRequestKeyRef: RefObject<string | null>","initialMetaConsumedRef: RefObject<boolean>","fetchFlowMeta: () => Promise<void>","err: unknown","fetchMetaRef: RefObject<FlowMetaProviderProps['fetchMeta'] | null>","fetchMetaVersionRef: RefObject<number>","requestKey: string | null","switchLanguage: (language: string) => Promise<void>","result: FlowMetadataResponse","flatTranslations: Record<string, string>","namespace","value","bundle: I18nBundle","metaLanguage: string","bundlesToInject: Record<string, I18nBundle>","value: any","FlowMetaContext"],"sources":["../../../src/contexts/FlowMeta/FlowMetaProvider.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n FlowMetadataResponse,\n FlowMetaType,\n getFlowMeta,\n I18nBundle,\n resolveResourceEndpoint,\n TranslationBundleConstants,\n} from '@thunderid/browser';\nimport {FC, PropsWithChildren, ReactElement, RefObject, useCallback, useEffect, useRef, useState} from 'react';\nimport FlowMetaContext from './FlowMetaContext';\nimport {I18nContextValue} from '../I18n/I18nContext';\nimport useI18n from '../I18n/useI18n';\nimport useThunderID from '../ThunderID/useThunderID';\n\nexport interface FlowMetaProviderProps {\n /**\n * When false the provider skips fetching and provides null meta.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * Overrides how flow metadata is fetched, routing the request through a caller-supplied\n * function (e.g. a Next.js Server Action) instead of the provider's default direct\n * browser-to-`baseUrl` `fetch()`. Use this when the ThunderID server's `baseUrl` is a\n * different origin than the app and CORS isn't (or can't be) configured for it — the\n * override runs server-side, so the browser never talks to `baseUrl` directly.\n *\n * Called for both the initial fetch and `switchLanguage()`.\n */\n fetchMeta?: (params: {applicationId?: string; language?: string}) => Promise<FlowMetadataResponse>;\n\n /**\n * Flow metadata resolved ahead of time (e.g. fetched server-side during SSR) and used to seed\n * the provider's state. When present, the provider skips its own initial client-side fetch —\n * avoiding a redundant request and the flash of untranslated i18n keys while that fetch is in\n * flight — but still fetches normally on subsequent changes (e.g. an explicit language switch).\n */\n initialMeta?: FlowMetadataResponse | null;\n\n /** Sent as the flow-meta request's `namespace`, e.g. to scope namespace-keyed i18n data. */\n namespace?: string;\n}\n\n/**\n * FlowMetaProvider fetches flow metadata from the `GET /flow/meta` endpoint\n * (v2 API) and makes it available to child components through `FlowMetaContext`.\n *\n * It is designed to be used in v2 embedded-flow scenarios and integrates with\n * `ThemeProvider` so that theme settings (colors, direction, typography, …)\n * from the server-side design configuration are applied automatically.\n *\n * @example\n * ```tsx\n * <FlowMetaProvider\n * config={{\n * baseUrl: 'https://localhost:8090',\n * type: FlowMetaType.App,\n * id: 'your-app-id',\n * }}\n * >\n * <ThemeProvider>\n * <App />\n * </ThemeProvider>\n * </FlowMetaProvider>\n * ```\n */\nconst FlowMetaProvider: FC<PropsWithChildren<FlowMetaProviderProps>> = ({\n children,\n enabled = true,\n fetchMeta,\n initialMeta = null,\n namespace,\n}: PropsWithChildren<FlowMetaProviderProps>): ReactElement => {\n const {baseUrl, endpoints, applicationId, isInitialized} = useThunderID();\n const i18nContext: I18nContextValue = useI18n();\n\n const [meta, setMeta] = useState<FlowMetadataResponse | null>(initialMeta);\n const [isLoading, setIsLoading] = useState<boolean>(!initialMeta);\n const [error, setError] = useState<Error | null>(null);\n const [pendingLanguage, setPendingLanguage] = useState<string | null>(null);\n\n // The last request the initial-fetch effect dispatched, as a key of everything that shapes it.\n // `fetchFlowMeta` is recreated whenever a dependency changes identity, and several do while\n // ThunderID initializes (`isInitialized` flips, `endpoints` is replaced with the resolved\n // configuration) without changing the request. Keying on the request skips those repeats, and\n // the StrictMode re-mount, so only a real change (e.g. a language switch) fetches again.\n const lastRequestKeyRef: RefObject<string | null> = useRef<string | null>(null);\n const initialMetaConsumedRef: RefObject<boolean> = useRef(false);\n const fetchFlowMeta: () => Promise<void> = useCallback(async (): Promise<void> => {\n if (!enabled) {\n setMeta(null);\n setIsLoading(false);\n return;\n }\n\n // Defer until ThunderID finishes initializing (e.g. loading applicationId\n // from storage on refresh). Once initialized, proceed even if applicationId\n // is absent — some flows (e.g. AcceptInvite) have no applicationId by design.\n if (!isInitialized && !applicationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language: i18nContext?.currentLanguage})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language: i18nContext?.currentLanguage,\n });\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n }, [enabled, baseUrl, endpoints, applicationId, isInitialized, i18nContext?.currentLanguage, fetchMeta, namespace]);\n\n const fetchMetaRef: RefObject<FlowMetaProviderProps['fetchMeta'] | null> = useRef(fetchMeta);\n const fetchMetaVersionRef: RefObject<number> = useRef(0);\n if (fetchMetaRef.current !== fetchMeta) {\n fetchMetaRef.current = fetchMeta;\n fetchMetaVersionRef.current += 1;\n }\n\n // Null while the fetch would be skipped, so the request that follows initialization still runs.\n const requestKey: string | null =\n enabled && !isInitialized && !applicationId\n ? null\n : JSON.stringify([\n enabled,\n enabled && !fetchMeta ? baseUrl : null,\n enabled && !fetchMeta ? resolveResourceEndpoint('flowMeta', {endpoints}) : null,\n applicationId ?? null,\n namespace ?? null,\n i18nContext?.currentLanguage ?? null,\n fetchMetaVersionRef.current,\n ]);\n\n const switchLanguage: (language: string) => Promise<void> = useCallback(\n async (language: string): Promise<void> => {\n if (!enabled) return;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result: FlowMetadataResponse = fetchMeta\n ? await fetchMeta({applicationId, language})\n : await getFlowMeta({\n baseUrl,\n url: resolveResourceEndpoint('flowMeta', {endpoints}),\n ...(applicationId ? {id: applicationId, type: FlowMetaType.App} : {}),\n ...(namespace ? {namespace} : {}),\n language,\n });\n\n // Inject translations for the new language before switching\n if (result.i18n?.translations && i18nContext?.injectBundles) {\n const flatTranslations: Record<string, string> = {};\n Object.entries(result.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n i18nContext.injectBundles({[language]: bundle});\n }\n\n // Defer setLanguage to the next effect cycle so injectBundles state\n // is committed before I18nProvider's setLanguage checks mergedBundles.\n setPendingLanguage(language);\n setMeta(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n },\n [enabled, baseUrl, endpoints, applicationId, i18nContext, fetchMeta, namespace],\n );\n\n // After injectBundles + setPendingLanguage are batched and committed, this\n // effect fires with the updated i18nContext (mergedBundles now includes the\n // new language), so setLanguage succeeds on the first switch.\n useEffect(() => {\n if (pendingLanguage && i18nContext?.setLanguage) {\n i18nContext.setLanguage(pendingLanguage);\n setPendingLanguage(null);\n }\n }, [pendingLanguage, i18nContext?.setLanguage]);\n\n useEffect(() => {\n if (requestKey === null) {\n return;\n }\n\n if (!initialMetaConsumedRef.current) {\n initialMetaConsumedRef.current = true;\n\n if (initialMeta) {\n // Seeded from SSR (or another caller) — skip the redundant first client-side fetch.\n // Later changes to the request (e.g. an explicit language switch) still fetch normally.\n lastRequestKeyRef.current = requestKey;\n return;\n }\n }\n\n if (lastRequestKeyRef.current === requestKey) {\n return;\n }\n\n lastRequestKeyRef.current = requestKey;\n fetchFlowMeta();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [requestKey]);\n\n // When meta loads with i18n translations, inject them into the i18n system.\n // Meta translations act as the base layer — prop-provided bundles still take precedence.\n useEffect(() => {\n if (!meta?.i18n?.translations || !i18nContext?.injectBundles) {\n return;\n }\n\n const metaLanguage: string = meta.i18n.language || TranslationBundleConstants.FALLBACK_LOCALE;\n\n // Flatten namespace-keyed translations to dot-path keys:\n // { \"signin\": { \"heading\": \"Sign In\" } } → { \"signin.heading\": \"Sign In\" }\n const flatTranslations: Record<string, string> = {};\n Object.entries(meta.i18n.translations).forEach(([namespace, keys]: [string, Record<string, string>]) => {\n Object.entries(keys).forEach(([key, value]: [string, string]) => {\n flatTranslations[`${namespace}.${key}`] = value;\n });\n });\n\n const bundle: I18nBundle = {translations: flatTranslations} as unknown as I18nBundle;\n\n // Inject under the meta language code and the i18n current language so\n // lookups succeed regardless of whether the system uses \"en\" or \"en-US\".\n const bundlesToInject: Record<string, I18nBundle> = {[metaLanguage]: bundle};\n if (i18nContext.currentLanguage && i18nContext.currentLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.currentLanguage] = bundle;\n }\n if (i18nContext.fallbackLanguage && i18nContext.fallbackLanguage !== metaLanguage) {\n bundlesToInject[i18nContext.fallbackLanguage] = bundle;\n }\n\n i18nContext.injectBundles(bundlesToInject);\n }, [meta?.i18n?.translations, i18nContext?.injectBundles]);\n\n const value: any = {\n error,\n fetchFlowMeta,\n isLoading,\n meta,\n switchLanguage,\n };\n\n return <FlowMetaContext.Provider value={value}>{children}</FlowMetaContext.Provider>;\n};\n\nexport default FlowMetaProvider;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDProvider.d.ts","sourceRoot":"","sources":["../../../src/contexts/ThunderID/ThunderIDProvider.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAC,EAAE,EAAa,iBAAiB,EAAkE,MAAM,OAAO,CAAC;AAGxH,OAAO,EAAC,oBAAoB,EAAC,MAAM,qBAAqB,CAAC;AAkBzD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE1D,QAAA,MAAM,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CAAC,sBAAsB,CAAC,CAyiBpE,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"ThunderIDProvider.d.ts","sourceRoot":"","sources":["../../../src/contexts/ThunderID/ThunderIDProvider.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,EAAE,EAAa,iBAAiB,EAAkE,MAAM,OAAO,CAAC;AAGxH,OAAO,EAAC,oBAAoB,EAAC,MAAM,qBAAqB,CAAC;AAkBzD;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE1D,QAAA,MAAM,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CAAC,sBAAsB,CAAC,CA2iBpE,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -11,7 +11,7 @@ import ThemeProvider_default from "../Theme/ThemeProvider.js";
11
11
  import UserProvider_default from "../User/UserProvider.js";
12
12
  import getUsersMe_default from "../../api/getUsersMe.js";
13
13
  import getUsersMeMeta_default from "../../api/getUsersMeMeta.js";
14
- import { ThunderIDRuntimeError, createPackageComponentLogger, extractUserClaimsFromIdToken, generateFlattenedUserProfile, getVendorPrefix, resolveResourceEndpoint } from "@thunderid/browser";
14
+ import { SPAUtils, ThunderIDRuntimeError, createPackageComponentLogger, extractUserClaimsFromIdToken, generateFlattenedUserProfile, getVendorPrefix, resolveResourceEndpoint } from "@thunderid/browser";
15
15
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
16
16
  import { jsx } from "react/jsx-runtime";
17
17
 
@@ -169,7 +169,7 @@ const ThunderIDProvider = ({ afterSignInUrl, afterSignOutUrl, baseUrl: initialBa
169
169
  const code = urlParams.get("code");
170
170
  const executionIdFromUrl = urlParams.get("executionId");
171
171
  const storedExecutionId = sessionStorage.getItem(`${getVendorPrefix(config.vendor)}_execution_id`);
172
- if (code && !executionIdFromUrl && !storedExecutionId) await signIn();
172
+ if ((code || SPAUtils.isSilentStatePresentInURL()) && !executionIdFromUrl && !storedExecutionId) await signIn();
173
173
  } catch (error) {
174
174
  throw new ThunderIDRuntimeError(`Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`, "thunderid-signIn-Error", "react", "An error occurred while trying to sign in.");
175
175
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDProvider.js","names":["logger: ReturnType<typeof createPackageComponentLogger>","ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>>","reRenderCheckRef: RefObject<boolean>","client: ThunderIDReactClient","ThunderIDReactClient","invalidator: ResourceInvalidator","createResourceInvalidator","storageManagerRef: any","useBrowserUrl","pendingSessionUpdateRef: RefObject<Promise<void> | null>","resolvedBaseUrl: string","decodedToken: IdToken","shouldFetchProfile: boolean","claims: User","currentSignInStatus: boolean","getUsersMe","getUsersMeMeta","arg1: any","isV2FlowRequest: boolean","currentUrl: URL","urlParams: URLSearchParams","code: string | null","executionIdFromUrl: string | null","storedExecutionId: string | null","interval: NodeJS.Timeout","status: boolean","getDecodedIdToken: () => Promise<IdToken>","getIdToken: () => Promise<string>","getAccessToken: () => Promise<string>","getStorageManager: () => Promise<any>","storageManager: any","request: (...args: any[]) => Promise<any>","requestAll: (...args: any[]) => Promise<any>","exchangeToken: (exchangeConfig: any) => Promise<any>","signOut: (...args: any[]) => Promise<any>","recover: (payload: any) => Promise<any>","signUp: (...args: any[]) => Promise<any>","clearSession: (...args: any[]) => Promise<any>","reInitialize: (reInitConfig: any) => Promise<any>","result: any","reinitializedConfig: ThunderIDReactConfig","value: any","ThunderIDContext","I18nProvider","FlowMetaProvider","ThemeProvider","FlowProvider","UserProvider","ComponentRendererProvider"],"sources":["../../../src/contexts/ThunderID/ThunderIDProvider.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n ThunderIDRuntimeError,\n generateFlattenedUserProfile,\n OIDCDiscoveryApiResponse,\n SignInOptions,\n User,\n UserProfile,\n IdToken,\n extractUserClaimsFromIdToken,\n EmbeddedSignInFlowResponse,\n createPackageComponentLogger,\n getVendorPrefix,\n resolveResourceEndpoint,\n AttributeSchema,\n} from '@thunderid/browser';\nimport {FC, RefObject, PropsWithChildren, ReactElement, useEffect, useMemo, useRef, useState, useCallback} from 'react';\nimport ThunderIDContext from './ThunderIDContext';\nimport useBrowserUrl from '../../hooks/useBrowserUrl';\nimport {ThunderIDReactConfig} from '../../models/config';\nimport {configureEmotionNonce} from '../../styles/emotion';\nimport ThunderIDReactClient from '../../ThunderIDReactClient';\nimport createResourceInvalidator, {ResourceInvalidator} from '../../utils/createResourceInvalidator';\nimport ComponentRendererProvider from '../ComponentRenderer/ComponentRendererProvider';\nimport FlowProvider from '../Flow/FlowProvider';\nimport FlowMetaProvider from '../FlowMeta/FlowMetaProvider';\nimport I18nProvider from '../I18n/I18nProvider';\nimport ThemeProvider from '../Theme/ThemeProvider';\nimport UserProvider from '../User/UserProvider';\nimport getUsersMe from '../../api/getUsersMe';\nimport getUsersMeMeta from '../../api/getUsersMeMeta';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'ThunderIDProvider',\n);\n\n/**\n * Props interface of {@link ThunderIDProvider}\n */\nexport type ThunderIDProviderProps = ThunderIDReactConfig;\n\nconst ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>> = ({\n afterSignInUrl,\n afterSignOutUrl,\n baseUrl: initialBaseUrl,\n clientId,\n children,\n extensions,\n scopes,\n preferences,\n signInUrl,\n signUpUrl,\n organizationHandle,\n applicationId,\n signInOptions,\n tokenRequest,\n instanceId = 0,\n organizationChain,\n cspNonce,\n vendor,\n namespace,\n http: httpOptions,\n ...rest\n}: PropsWithChildren<ThunderIDProviderProps>): ReactElement => {\n // Must run synchronously here, in the render body, before any descendant's css()/cx()/\n // keyframes() calls execute during this same render pass - see the doc comment on\n // `configureEmotionNonce` for why a `useEffect` would be too late.\n configureEmotionNonce(cspNonce, vendor);\n\n const reRenderCheckRef: RefObject<boolean> = useRef(false);\n const client: ThunderIDReactClient = useMemo(() => new ThunderIDReactClient(instanceId), [instanceId]);\n const invalidator: ResourceInvalidator = useMemo(() => createResourceInvalidator(), []);\n const storageManagerRef: any = useRef<any>(null);\n const {hasAuthParams, hasCalledForThisInstance} = useBrowserUrl();\n const [user, setUser] = useState<any | null>(null);\n const [isSignedInSync, setIsSignedInSync] = useState<boolean>(false);\n const [isInitializedSync, setIsInitializedSync] = useState<boolean>(false);\n const [isLoadingSync, setIsLoadingSync] = useState<boolean>(true);\n\n const [userProfile, setUserProfile] = useState<UserProfile | null>(null);\n const [userSchema, setUserSchema] = useState<Record<string, AttributeSchema> | null>(null);\n const [baseUrl, setBaseUrl] = useState<string>(initialBaseUrl ?? '');\n const [config, setConfig] = useState<ThunderIDReactConfig>({\n afterSignInUrl: afterSignInUrl ?? window.location.origin,\n afterSignOutUrl: afterSignOutUrl ?? window.location.origin,\n applicationId,\n baseUrl,\n clientId,\n organizationChain,\n organizationHandle,\n scopes,\n signInOptions,\n tokenRequest,\n signInUrl,\n signUpUrl,\n vendor,\n ...rest,\n });\n\n const [isUpdatingSession, setIsUpdatingSession] = useState<boolean>(false);\n const [wellKnown, setWellKnown] = useState<OIDCDiscoveryApiResponse | null>(null);\n\n // Holds the in-flight `updateSession()` promise so concurrent callers coalesce onto a single\n // `/users/me` request instead of issuing one each.\n const pendingSessionUpdateRef: RefObject<Promise<void> | null> = useRef<Promise<void> | null>(null);\n\n useEffect(() => {\n setBaseUrl(initialBaseUrl ?? '');\n }, [initialBaseUrl]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n await client.initialize(config);\n const initializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(initializedConfig);\n setWellKnown(await client.getDiscoveryResponse());\n })();\n }, []);\n\n async function performSessionUpdate(): Promise<void> {\n try {\n // Set flag to prevent loading state tracking from interfering\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n let resolvedBaseUrl: string = baseUrl;\n\n const decodedToken: IdToken = await client.getDecodedIdToken();\n\n // If there's a `user_org` claim in the ID token,\n // Treat this login as a organization login.\n if (decodedToken?.['user_org']) {\n resolvedBaseUrl = `${(await client.getConfiguration()).baseUrl}/o`;\n setBaseUrl(resolvedBaseUrl);\n }\n\n const shouldFetchProfile: boolean = preferences?.user?.fetchUserProfile !== false;\n const claims: User = extractUserClaimsFromIdToken(decodedToken) as User;\n let profileData = claims;\n const currentSignInStatus: boolean = await client.isSignedIn();\n\n if (currentSignInStatus && shouldFetchProfile) {\n try {\n const fetchedProfile = await getUsersMe({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMe', config),\n instanceId,\n });\n profileData = {...claims, ...fetchedProfile};\n } catch (err) {\n logger.warn('Failed to fetch user profile from /users/me:', err);\n }\n\n try {\n const metaRes = await getUsersMeMeta({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMeMeta', config),\n instanceId,\n });\n if (metaRes?.schema) {\n setUserSchema(metaRes.schema);\n } else {\n setUserSchema(null);\n }\n } catch (err) {\n setUserSchema(null);\n logger.warn('Failed to fetch user schema metadata from /users/me/meta:', err);\n }\n } else {\n setUserSchema(null);\n }\n\n setUser(profileData);\n setUserProfile({\n flattenedProfile: generateFlattenedUserProfile(profileData, []),\n profile: profileData,\n });\n\n // CRITICAL: Update sign-in status BEFORE setting loading to false\n // This prevents the race condition where ProtectedRoute sees isLoading=false but isSignedIn=false\n setIsSignedInSync(currentSignInStatus);\n } catch (error) {\n // TODO: Add an error log.\n } finally {\n // Clear the flag and set final loading state\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n\n /**\n * Single-flight wrapper around {@link performSessionUpdate}.\n *\n * Concurrent callers share the in-flight request instead of each issuing their own `/users/me`.\n * This is not a cache: once the request settles the ref is cleared, so a later caller (e.g.\n * revalidation after a profile update) fetches again.\n */\n async function updateSession(): Promise<void> {\n if (pendingSessionUpdateRef.current) {\n return pendingSessionUpdateRef.current;\n }\n\n pendingSessionUpdateRef.current = performSessionUpdate().finally(() => {\n pendingSessionUpdateRef.current = null;\n });\n\n return pendingSessionUpdateRef.current;\n }\n\n async function signIn(...args: any): Promise<User | EmbeddedSignInFlowResponse> {\n // Check if this is a V2 embedded flow request BEFORE calling signIn\n // This allows us to skip session checks entirely for V2 flows\n const arg1: any = args[0];\n const isV2FlowRequest: boolean =\n typeof arg1 === 'object' && arg1 !== null && ('executionId' in arg1 || 'applicationId' in arg1);\n\n try {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n }\n\n return await client.signIn(...args);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n } finally {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n }\n\n /**\n * Try signing in when the component is mounted.\n */\n useEffect(() => {\n // React 18.x Strict.Mode has a new check for `Ensuring reusable state` to facilitate an upcoming react feature.\n // https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state\n // This will remount all the useEffects to ensure that there are no unexpected side effects.\n // When react remounts the signIn hook of the AuthProvider, it will cause a race condition. Hence, we have to\n // prevent the re-render of this hook as suggested in the following discussion.\n // https://github.com/reactwg/react-18/discussions/18#discussioncomment-795623\n if (reRenderCheckRef.current) {\n return;\n }\n\n reRenderCheckRef.current = true;\n\n (async (): Promise<void> => {\n // Sync session state whenever sign-in completes (both redirect and embedded V2 flows).\n // Pass the user returned by the SDK's sign-in flow so users/me result is not discarded.\n await client.on('sign-in', async () => {\n await updateSession();\n });\n\n // Start auto-refresh with a soft failure. This also covers the case where the access token\n // expired while the refresh token is still valid — startAutoRefreshToken() calls\n // refreshAccessToken() immediately when timeUntilRefresh <= 0 — so the sign-in check below\n // sees the refreshed state.\n try {\n await client.startAutoRefreshToken();\n } catch (error) {\n logger.warn('Failed to schedule automatic token refresh.', error);\n }\n\n // User is already authenticated. Restore the session and skip the sign-in path.\n if (await client.isSignedIn()) {\n await updateSession();\n\n return;\n }\n\n const currentUrl: URL = new URL(window.location.href);\n const hasAuthParamsResult: boolean =\n hasAuthParams(currentUrl, config.afterSignInUrl!) && hasCalledForThisInstance(currentUrl, instanceId ?? 0);\n\n if (hasAuthParamsResult) {\n try {\n const urlParams: URLSearchParams = currentUrl.searchParams;\n const code: string | null = urlParams.get('code');\n const executionIdFromUrl: string | null = urlParams.get('executionId');\n const storedExecutionId: string | null = sessionStorage.getItem(\n `${getVendorPrefix(config.vendor)}_execution_id`,\n );\n\n if (code && !executionIdFromUrl && !storedExecutionId) {\n await signIn();\n }\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n }\n }\n })();\n }, []);\n\n /**\n * Check if the user is signed in and update the state accordingly.\n * This will also set an interval to check for the sign-in status every second\n * until the user is signed in.\n */\n useEffect(() => {\n let interval: NodeJS.Timeout;\n\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isSignedIn();\n\n setIsSignedInSync(status);\n\n if (!status) {\n interval = setInterval(async () => {\n const newStatus: boolean = await client.isSignedIn();\n\n if (newStatus) {\n setIsSignedInSync(true);\n clearInterval(interval);\n }\n }, 1000);\n } else {\n // TODO: Add a debug log to indicate that the user is already signed in.\n }\n } catch (error) {\n setIsSignedInSync(false);\n }\n })();\n\n return (): void => {\n if (interval) {\n clearInterval(interval);\n }\n };\n }, [client]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isInitialized();\n\n setIsInitializedSync(status);\n } catch (error) {\n setIsInitializedSync(false);\n }\n })();\n }, [client]);\n\n /**\n * Track loading state changes from the ThunderID client\n */\n useEffect(() => {\n const checkLoadingState = (): void => {\n // Don't override loading state during critical session updates\n if (isUpdatingSession) {\n return;\n }\n\n // Don't set loading=false while auth params are in the URL and user isn't signed in yet.\n // This prevents ProtectedRoute from redirecting before the sign-in effect processes the auth code.\n const currentUrl: URL = new URL(window.location.href);\n if (!isSignedInSync && hasAuthParams(currentUrl, config.afterSignInUrl!)) {\n return;\n }\n\n setIsLoadingSync(client.isLoading());\n };\n\n // Initial check\n checkLoadingState();\n\n // Set up an interval to check for loading state changes\n const interval: NodeJS.Timeout = setInterval(checkLoadingState, 100);\n\n return (): void => {\n clearInterval(interval);\n };\n }, [client, isLoadingSync, isSignedInSync, isUpdatingSession]);\n\n const signInSilently = async (options?: SignInOptions): Promise<User | boolean> => {\n try {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n return await client.signInSilently(options);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Error while signing in silently: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signInSilently-Error',\n 'react',\n 'An error occurred while trying to sign in silently.',\n );\n } finally {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n };\n\n const handleProfileUpdate = (payload: User): void => {\n setUser(payload);\n setUserProfile((prev: UserProfile | null) => ({\n flattenedProfile: generateFlattenedUserProfile(payload),\n profile: payload,\n }));\n };\n\n const getDecodedIdToken: () => Promise<IdToken> = useCallback(\n async (): Promise<IdToken> => client.getDecodedIdToken(),\n [client],\n );\n\n const getIdToken: () => Promise<string> = useCallback(async (): Promise<string> => client.getIdToken(), [client]);\n\n const getAccessToken: () => Promise<string> = useCallback(\n async (): Promise<string> => client.getAccessToken(),\n [client],\n );\n\n const getStorageManager: () => Promise<any> = useCallback(async (): Promise<any> => {\n const storageManager: any = storageManagerRef.current ?? (await client.getStorageManager());\n if (storageManager) {\n storageManagerRef.current = storageManager;\n }\n return storageManager;\n }, [client]);\n\n const request: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.request(...args),\n [client],\n );\n\n const requestAll: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.requestAll(...args),\n [client],\n );\n\n const exchangeToken: (exchangeConfig: any) => Promise<any> = useCallback(\n async (exchangeConfig: any): Promise<any> => client.exchangeToken(exchangeConfig),\n [client],\n );\n\n const signOut: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signOut(...args),\n [client],\n );\n\n const recover: (payload: any) => Promise<any> = useCallback(\n async (payload: any): Promise<any> => client.recover(payload),\n [client],\n );\n\n const signUp: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signUp(...args),\n [client],\n );\n\n const clearSession: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.clearSession(...args),\n [client],\n );\n\n const reInitialize: (reInitConfig: any) => Promise<any> = useCallback(\n async (reInitConfig: any): Promise<any> => {\n const result: any = await client.reInitialize(reInitConfig);\n\n // Refresh React state from the reinitialized client so the context (config.endpoints,\n // baseUrl, discovery) reflects the new configuration instead of the pre-reinitialization state.\n const reinitializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(reinitializedConfig);\n setBaseUrl(reinitializedConfig.baseUrl ?? '');\n setWellKnown(await client.getDiscoveryResponse());\n\n return result;\n },\n [client],\n );\n\n const value: any = useMemo(\n () => ({\n afterSignInUrl: config.afterSignInUrl,\n applicationId: config.applicationId,\n baseUrl,\n endpoints: config.endpoints,\n scopes: config.scopes,\n clearSession,\n clientId,\n discovery: {\n wellKnown,\n },\n exchangeToken,\n getAccessToken,\n getDecodedIdToken,\n getIdToken,\n getStorageManager,\n http: {\n fetcher: httpOptions?.fetcher,\n request,\n requestAll,\n },\n instanceId,\n invalidator,\n isInitialized: isInitializedSync,\n isLoading: isLoadingSync,\n isSignedIn: isSignedInSync,\n organizationChain,\n organizationHandle: config?.organizationHandle,\n preferences,\n reInitialize,\n recover,\n signIn,\n signInOptions,\n tokenRequest,\n signInSilently,\n signInUrl,\n signOut,\n signUp,\n signUpUrl,\n user,\n userSchema,\n vendor: getVendorPrefix(config.vendor),\n }),\n [\n applicationId,\n config?.organizationHandle,\n config.vendor,\n config.afterSignInUrl,\n config.endpoints,\n config.scopes,\n signInUrl,\n signUpUrl,\n baseUrl,\n clientId,\n wellKnown,\n isInitializedSync,\n isLoadingSync,\n isSignedInSync,\n signIn,\n signInSilently,\n user,\n userSchema,\n client,\n signInOptions,\n tokenRequest,\n getDecodedIdToken,\n clearSession,\n exchangeToken,\n httpOptions?.fetcher,\n getAccessToken,\n getStorageManager,\n instanceId,\n invalidator,\n organizationChain,\n preferences,\n recover,\n reInitialize,\n request,\n requestAll,\n signOut,\n signUp,\n ],\n );\n\n return (\n <ThunderIDContext.Provider value={value}>\n <I18nProvider preferences={preferences?.i18n} vendor={getVendorPrefix(config.vendor)}>\n <FlowMetaProvider enabled={preferences?.resolveFromMeta !== false} namespace={namespace}>\n <ThemeProvider\n theme={{\n ...preferences?.theme?.overrides,\n direction: preferences?.theme?.direction,\n }}\n >\n <FlowProvider>\n <UserProvider\n profile={userProfile as UserProfile}\n userSchema={userSchema}\n onUpdateProfile={handleProfileUpdate}\n >\n <ComponentRendererProvider renderers={(extensions?.components?.renderers ?? {}) as any}>\n {children}\n </ComponentRendererProvider>\n </UserProvider>\n </FlowProvider>\n </ThemeProvider>\n </FlowMetaProvider>\n </I18nProvider>\n </ThunderIDContext.Provider>\n );\n};\n\nexport default ThunderIDProvider;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ThunderIDProvider.js","names":["logger: ReturnType<typeof createPackageComponentLogger>","ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>>","reRenderCheckRef: RefObject<boolean>","client: ThunderIDReactClient","ThunderIDReactClient","invalidator: ResourceInvalidator","createResourceInvalidator","storageManagerRef: any","useBrowserUrl","pendingSessionUpdateRef: RefObject<Promise<void> | null>","resolvedBaseUrl: string","decodedToken: IdToken","shouldFetchProfile: boolean","claims: User","currentSignInStatus: boolean","getUsersMe","getUsersMeMeta","arg1: any","isV2FlowRequest: boolean","currentUrl: URL","urlParams: URLSearchParams","code: string | null","executionIdFromUrl: string | null","storedExecutionId: string | null","interval: NodeJS.Timeout","status: boolean","getDecodedIdToken: () => Promise<IdToken>","getIdToken: () => Promise<string>","getAccessToken: () => Promise<string>","getStorageManager: () => Promise<any>","storageManager: any","request: (...args: any[]) => Promise<any>","requestAll: (...args: any[]) => Promise<any>","exchangeToken: (exchangeConfig: any) => Promise<any>","signOut: (...args: any[]) => Promise<any>","recover: (payload: any) => Promise<any>","signUp: (...args: any[]) => Promise<any>","clearSession: (...args: any[]) => Promise<any>","reInitialize: (reInitConfig: any) => Promise<any>","result: any","reinitializedConfig: ThunderIDReactConfig","value: any","ThunderIDContext","I18nProvider","FlowMetaProvider","ThemeProvider","FlowProvider","UserProvider","ComponentRendererProvider"],"sources":["../../../src/contexts/ThunderID/ThunderIDProvider.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n ThunderIDRuntimeError,\n generateFlattenedUserProfile,\n OIDCDiscoveryApiResponse,\n SignInOptions,\n User,\n UserProfile,\n IdToken,\n extractUserClaimsFromIdToken,\n EmbeddedSignInFlowResponse,\n createPackageComponentLogger,\n getVendorPrefix,\n resolveResourceEndpoint,\n AttributeSchema,\n SPAUtils,\n} from '@thunderid/browser';\nimport {FC, RefObject, PropsWithChildren, ReactElement, useEffect, useMemo, useRef, useState, useCallback} from 'react';\nimport ThunderIDContext from './ThunderIDContext';\nimport useBrowserUrl from '../../hooks/useBrowserUrl';\nimport {ThunderIDReactConfig} from '../../models/config';\nimport {configureEmotionNonce} from '../../styles/emotion';\nimport ThunderIDReactClient from '../../ThunderIDReactClient';\nimport createResourceInvalidator, {ResourceInvalidator} from '../../utils/createResourceInvalidator';\nimport ComponentRendererProvider from '../ComponentRenderer/ComponentRendererProvider';\nimport FlowProvider from '../Flow/FlowProvider';\nimport FlowMetaProvider from '../FlowMeta/FlowMetaProvider';\nimport I18nProvider from '../I18n/I18nProvider';\nimport ThemeProvider from '../Theme/ThemeProvider';\nimport UserProvider from '../User/UserProvider';\nimport getUsersMe from '../../api/getUsersMe';\nimport getUsersMeMeta from '../../api/getUsersMeMeta';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'ThunderIDProvider',\n);\n\n/**\n * Props interface of {@link ThunderIDProvider}\n */\nexport type ThunderIDProviderProps = ThunderIDReactConfig;\n\nconst ThunderIDProvider: FC<PropsWithChildren<ThunderIDProviderProps>> = ({\n afterSignInUrl,\n afterSignOutUrl,\n baseUrl: initialBaseUrl,\n clientId,\n children,\n extensions,\n scopes,\n preferences,\n signInUrl,\n signUpUrl,\n organizationHandle,\n applicationId,\n signInOptions,\n tokenRequest,\n instanceId = 0,\n organizationChain,\n cspNonce,\n vendor,\n namespace,\n http: httpOptions,\n ...rest\n}: PropsWithChildren<ThunderIDProviderProps>): ReactElement => {\n // Must run synchronously here, in the render body, before any descendant's css()/cx()/\n // keyframes() calls execute during this same render pass - see the doc comment on\n // `configureEmotionNonce` for why a `useEffect` would be too late.\n configureEmotionNonce(cspNonce, vendor);\n\n const reRenderCheckRef: RefObject<boolean> = useRef(false);\n const client: ThunderIDReactClient = useMemo(() => new ThunderIDReactClient(instanceId), [instanceId]);\n const invalidator: ResourceInvalidator = useMemo(() => createResourceInvalidator(), []);\n const storageManagerRef: any = useRef<any>(null);\n const {hasAuthParams, hasCalledForThisInstance} = useBrowserUrl();\n const [user, setUser] = useState<any | null>(null);\n const [isSignedInSync, setIsSignedInSync] = useState<boolean>(false);\n const [isInitializedSync, setIsInitializedSync] = useState<boolean>(false);\n const [isLoadingSync, setIsLoadingSync] = useState<boolean>(true);\n\n const [userProfile, setUserProfile] = useState<UserProfile | null>(null);\n const [userSchema, setUserSchema] = useState<Record<string, AttributeSchema> | null>(null);\n const [baseUrl, setBaseUrl] = useState<string>(initialBaseUrl ?? '');\n const [config, setConfig] = useState<ThunderIDReactConfig>({\n afterSignInUrl: afterSignInUrl ?? window.location.origin,\n afterSignOutUrl: afterSignOutUrl ?? window.location.origin,\n applicationId,\n baseUrl,\n clientId,\n organizationChain,\n organizationHandle,\n scopes,\n signInOptions,\n tokenRequest,\n signInUrl,\n signUpUrl,\n vendor,\n ...rest,\n });\n\n const [isUpdatingSession, setIsUpdatingSession] = useState<boolean>(false);\n const [wellKnown, setWellKnown] = useState<OIDCDiscoveryApiResponse | null>(null);\n\n // Holds the in-flight `updateSession()` promise so concurrent callers coalesce onto a single\n // `/users/me` request instead of issuing one each.\n const pendingSessionUpdateRef: RefObject<Promise<void> | null> = useRef<Promise<void> | null>(null);\n\n useEffect(() => {\n setBaseUrl(initialBaseUrl ?? '');\n }, [initialBaseUrl]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n await client.initialize(config);\n const initializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(initializedConfig);\n setWellKnown(await client.getDiscoveryResponse());\n })();\n }, []);\n\n async function performSessionUpdate(): Promise<void> {\n try {\n // Set flag to prevent loading state tracking from interfering\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n let resolvedBaseUrl: string = baseUrl;\n\n const decodedToken: IdToken = await client.getDecodedIdToken();\n\n // If there's a `user_org` claim in the ID token,\n // Treat this login as a organization login.\n if (decodedToken?.['user_org']) {\n resolvedBaseUrl = `${(await client.getConfiguration()).baseUrl}/o`;\n setBaseUrl(resolvedBaseUrl);\n }\n\n const shouldFetchProfile: boolean = preferences?.user?.fetchUserProfile !== false;\n const claims: User = extractUserClaimsFromIdToken(decodedToken) as User;\n let profileData = claims;\n const currentSignInStatus: boolean = await client.isSignedIn();\n\n if (currentSignInStatus && shouldFetchProfile) {\n try {\n const fetchedProfile = await getUsersMe({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMe', config),\n instanceId,\n });\n profileData = {...claims, ...fetchedProfile};\n } catch (err) {\n logger.warn('Failed to fetch user profile from /users/me:', err);\n }\n\n try {\n const metaRes = await getUsersMeMeta({\n baseUrl: resolvedBaseUrl,\n url: resolveResourceEndpoint('usersMeMeta', config),\n instanceId,\n });\n if (metaRes?.schema) {\n setUserSchema(metaRes.schema);\n } else {\n setUserSchema(null);\n }\n } catch (err) {\n setUserSchema(null);\n logger.warn('Failed to fetch user schema metadata from /users/me/meta:', err);\n }\n } else {\n setUserSchema(null);\n }\n\n setUser(profileData);\n setUserProfile({\n flattenedProfile: generateFlattenedUserProfile(profileData, []),\n profile: profileData,\n });\n\n // CRITICAL: Update sign-in status BEFORE setting loading to false\n // This prevents the race condition where ProtectedRoute sees isLoading=false but isSignedIn=false\n setIsSignedInSync(currentSignInStatus);\n } catch (error) {\n // TODO: Add an error log.\n } finally {\n // Clear the flag and set final loading state\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n\n /**\n * Single-flight wrapper around {@link performSessionUpdate}.\n *\n * Concurrent callers share the in-flight request instead of each issuing their own `/users/me`.\n * This is not a cache: once the request settles the ref is cleared, so a later caller (e.g.\n * revalidation after a profile update) fetches again.\n */\n async function updateSession(): Promise<void> {\n if (pendingSessionUpdateRef.current) {\n return pendingSessionUpdateRef.current;\n }\n\n pendingSessionUpdateRef.current = performSessionUpdate().finally(() => {\n pendingSessionUpdateRef.current = null;\n });\n\n return pendingSessionUpdateRef.current;\n }\n\n async function signIn(...args: any): Promise<User | EmbeddedSignInFlowResponse> {\n // Check if this is a V2 embedded flow request BEFORE calling signIn\n // This allows us to skip session checks entirely for V2 flows\n const arg1: any = args[0];\n const isV2FlowRequest: boolean =\n typeof arg1 === 'object' && arg1 !== null && ('executionId' in arg1 || 'applicationId' in arg1);\n\n try {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n }\n\n return await client.signIn(...args);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n } finally {\n if (!isV2FlowRequest) {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n }\n }\n\n /**\n * Try signing in when the component is mounted.\n */\n useEffect(() => {\n // React 18.x Strict.Mode has a new check for `Ensuring reusable state` to facilitate an upcoming react feature.\n // https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state\n // This will remount all the useEffects to ensure that there are no unexpected side effects.\n // When react remounts the signIn hook of the AuthProvider, it will cause a race condition. Hence, we have to\n // prevent the re-render of this hook as suggested in the following discussion.\n // https://github.com/reactwg/react-18/discussions/18#discussioncomment-795623\n if (reRenderCheckRef.current) {\n return;\n }\n\n reRenderCheckRef.current = true;\n\n (async (): Promise<void> => {\n // Sync session state whenever sign-in completes (both redirect and embedded V2 flows).\n // Pass the user returned by the SDK's sign-in flow so users/me result is not discarded.\n await client.on('sign-in', async () => {\n await updateSession();\n });\n\n // Start auto-refresh with a soft failure. This also covers the case where the access token\n // expired while the refresh token is still valid — startAutoRefreshToken() calls\n // refreshAccessToken() immediately when timeUntilRefresh <= 0 — so the sign-in check below\n // sees the refreshed state.\n try {\n await client.startAutoRefreshToken();\n } catch (error) {\n logger.warn('Failed to schedule automatic token refresh.', error);\n }\n\n // User is already authenticated. Restore the session and skip the sign-in path.\n if (await client.isSignedIn()) {\n await updateSession();\n\n return;\n }\n\n const currentUrl: URL = new URL(window.location.href);\n const hasAuthParamsResult: boolean =\n hasAuthParams(currentUrl, config.afterSignInUrl!) && hasCalledForThisInstance(currentUrl, instanceId ?? 0);\n\n if (hasAuthParamsResult) {\n try {\n const urlParams: URLSearchParams = currentUrl.searchParams;\n const code: string | null = urlParams.get('code');\n const executionIdFromUrl: string | null = urlParams.get('executionId');\n const storedExecutionId: string | null = sessionStorage.getItem(\n `${getVendorPrefix(config.vendor)}_execution_id`,\n );\n\n // A silent sign-in response is handled even without a code: an error such as\n // login_required must still be relayed from the iframe to the waiting parent.\n if ((code || SPAUtils.isSilentStatePresentInURL()) && !executionIdFromUrl && !storedExecutionId) {\n await signIn();\n }\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Sign in failed: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signIn-Error',\n 'react',\n 'An error occurred while trying to sign in.',\n );\n }\n }\n })();\n }, []);\n\n /**\n * Check if the user is signed in and update the state accordingly.\n * This will also set an interval to check for the sign-in status every second\n * until the user is signed in.\n */\n useEffect(() => {\n let interval: NodeJS.Timeout;\n\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isSignedIn();\n\n setIsSignedInSync(status);\n\n if (!status) {\n interval = setInterval(async () => {\n const newStatus: boolean = await client.isSignedIn();\n\n if (newStatus) {\n setIsSignedInSync(true);\n clearInterval(interval);\n }\n }, 1000);\n } else {\n // TODO: Add a debug log to indicate that the user is already signed in.\n }\n } catch (error) {\n setIsSignedInSync(false);\n }\n })();\n\n return (): void => {\n if (interval) {\n clearInterval(interval);\n }\n };\n }, [client]);\n\n useEffect(() => {\n (async (): Promise<void> => {\n try {\n const status: boolean = await client.isInitialized();\n\n setIsInitializedSync(status);\n } catch (error) {\n setIsInitializedSync(false);\n }\n })();\n }, [client]);\n\n /**\n * Track loading state changes from the ThunderID client\n */\n useEffect(() => {\n const checkLoadingState = (): void => {\n // Don't override loading state during critical session updates\n if (isUpdatingSession) {\n return;\n }\n\n // Don't set loading=false while auth params are in the URL and user isn't signed in yet.\n // This prevents ProtectedRoute from redirecting before the sign-in effect processes the auth code.\n const currentUrl: URL = new URL(window.location.href);\n if (!isSignedInSync && hasAuthParams(currentUrl, config.afterSignInUrl!)) {\n return;\n }\n\n setIsLoadingSync(client.isLoading());\n };\n\n // Initial check\n checkLoadingState();\n\n // Set up an interval to check for loading state changes\n const interval: NodeJS.Timeout = setInterval(checkLoadingState, 100);\n\n return (): void => {\n clearInterval(interval);\n };\n }, [client, isLoadingSync, isSignedInSync, isUpdatingSession]);\n\n const signInSilently = async (options?: SignInOptions): Promise<User | boolean> => {\n try {\n setIsUpdatingSession(true);\n setIsLoadingSync(true);\n return await client.signInSilently(options);\n } catch (error) {\n throw new ThunderIDRuntimeError(\n `Error while signing in silently: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`,\n 'thunderid-signInSilently-Error',\n 'react',\n 'An error occurred while trying to sign in silently.',\n );\n } finally {\n setIsUpdatingSession(false);\n setIsLoadingSync(client.isLoading());\n }\n };\n\n const handleProfileUpdate = (payload: User): void => {\n setUser(payload);\n setUserProfile((prev: UserProfile | null) => ({\n flattenedProfile: generateFlattenedUserProfile(payload),\n profile: payload,\n }));\n };\n\n const getDecodedIdToken: () => Promise<IdToken> = useCallback(\n async (): Promise<IdToken> => client.getDecodedIdToken(),\n [client],\n );\n\n const getIdToken: () => Promise<string> = useCallback(async (): Promise<string> => client.getIdToken(), [client]);\n\n const getAccessToken: () => Promise<string> = useCallback(\n async (): Promise<string> => client.getAccessToken(),\n [client],\n );\n\n const getStorageManager: () => Promise<any> = useCallback(async (): Promise<any> => {\n const storageManager: any = storageManagerRef.current ?? (await client.getStorageManager());\n if (storageManager) {\n storageManagerRef.current = storageManager;\n }\n return storageManager;\n }, [client]);\n\n const request: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.request(...args),\n [client],\n );\n\n const requestAll: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.requestAll(...args),\n [client],\n );\n\n const exchangeToken: (exchangeConfig: any) => Promise<any> = useCallback(\n async (exchangeConfig: any): Promise<any> => client.exchangeToken(exchangeConfig),\n [client],\n );\n\n const signOut: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signOut(...args),\n [client],\n );\n\n const recover: (payload: any) => Promise<any> = useCallback(\n async (payload: any): Promise<any> => client.recover(payload),\n [client],\n );\n\n const signUp: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.signUp(...args),\n [client],\n );\n\n const clearSession: (...args: any[]) => Promise<any> = useCallback(\n async (...args: any[]): Promise<any> => client.clearSession(...args),\n [client],\n );\n\n const reInitialize: (reInitConfig: any) => Promise<any> = useCallback(\n async (reInitConfig: any): Promise<any> => {\n const result: any = await client.reInitialize(reInitConfig);\n\n // Refresh React state from the reinitialized client so the context (config.endpoints,\n // baseUrl, discovery) reflects the new configuration instead of the pre-reinitialization state.\n const reinitializedConfig: ThunderIDReactConfig = await client.getConfiguration();\n setConfig(reinitializedConfig);\n setBaseUrl(reinitializedConfig.baseUrl ?? '');\n setWellKnown(await client.getDiscoveryResponse());\n\n return result;\n },\n [client],\n );\n\n const value: any = useMemo(\n () => ({\n afterSignInUrl: config.afterSignInUrl,\n applicationId: config.applicationId,\n baseUrl,\n endpoints: config.endpoints,\n scopes: config.scopes,\n clearSession,\n clientId,\n discovery: {\n wellKnown,\n },\n exchangeToken,\n getAccessToken,\n getDecodedIdToken,\n getIdToken,\n getStorageManager,\n http: {\n fetcher: httpOptions?.fetcher,\n request,\n requestAll,\n },\n instanceId,\n invalidator,\n isInitialized: isInitializedSync,\n isLoading: isLoadingSync,\n isSignedIn: isSignedInSync,\n organizationChain,\n organizationHandle: config?.organizationHandle,\n preferences,\n reInitialize,\n recover,\n signIn,\n signInOptions,\n tokenRequest,\n signInSilently,\n signInUrl,\n signOut,\n signUp,\n signUpUrl,\n user,\n userSchema,\n vendor: getVendorPrefix(config.vendor),\n }),\n [\n applicationId,\n config?.organizationHandle,\n config.vendor,\n config.afterSignInUrl,\n config.endpoints,\n config.scopes,\n signInUrl,\n signUpUrl,\n baseUrl,\n clientId,\n wellKnown,\n isInitializedSync,\n isLoadingSync,\n isSignedInSync,\n signIn,\n signInSilently,\n user,\n userSchema,\n client,\n signInOptions,\n tokenRequest,\n getDecodedIdToken,\n clearSession,\n exchangeToken,\n httpOptions?.fetcher,\n getAccessToken,\n getStorageManager,\n instanceId,\n invalidator,\n organizationChain,\n preferences,\n recover,\n reInitialize,\n request,\n requestAll,\n signOut,\n signUp,\n ],\n );\n\n return (\n <ThunderIDContext.Provider value={value}>\n <I18nProvider preferences={preferences?.i18n} vendor={getVendorPrefix(config.vendor)}>\n <FlowMetaProvider enabled={preferences?.resolveFromMeta !== false} namespace={namespace}>\n <ThemeProvider\n theme={{\n ...preferences?.theme?.overrides,\n direction: preferences?.theme?.direction,\n }}\n >\n <FlowProvider>\n <UserProvider\n profile={userProfile as UserProfile}\n userSchema={userSchema}\n onUpdateProfile={handleProfileUpdate}\n >\n <ComponentRendererProvider renderers={(extensions?.components?.renderers ?? {}) as any}>\n {children}\n </ComponentRendererProvider>\n </UserProvider>\n </FlowProvider>\n </ThemeProvider>\n </FlowMetaProvider>\n </I18nProvider>\n </ThunderIDContext.Provider>\n );\n};\n\nexport default ThunderIDProvider;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thunderid/react",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "React SDK for ThunderID",
5
5
  "keywords": [
6
6
  "thunderid",
@@ -60,7 +60,7 @@
60
60
  "dependencies": {
61
61
  "@emotion/css": "11.13.5",
62
62
  "@floating-ui/react": "0.27.12",
63
- "@thunderid/browser": "^1.2.0",
63
+ "@thunderid/browser": "^1.2.1",
64
64
  "dompurify": "3.4.13",
65
65
  "tslib": "2.8.1"
66
66
  },