@intlayer/design-system 9.5.6 → 9.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/esm/api/hooks/auth.mjs +1 -0
  2. package/dist/esm/api/hooks/auth.mjs.map +1 -1
  3. package/dist/esm/api/useAuth/useOAuth2.mjs +1 -1
  4. package/dist/esm/components/Browser/extractUrlFromSitemap.mjs +29 -24
  5. package/dist/esm/components/Browser/extractUrlFromSitemap.mjs.map +1 -1
  6. package/dist/esm/components/Browser/index.mjs +2 -1
  7. package/dist/esm/components/IDE/shikiLanguages.mjs +1 -3
  8. package/dist/esm/components/IDE/shikiLanguages.mjs.map +1 -1
  9. package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs +23 -5
  10. package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs.map +1 -1
  11. package/dist/esm/components/index.mjs +2 -1
  12. package/dist/esm/libs/auth.mjs +7 -1
  13. package/dist/esm/libs/auth.mjs.map +1 -1
  14. package/dist/esm/providers/ThemeProvider.mjs +2 -2
  15. package/dist/esm/providers/ThemeProvider.mjs.map +1 -1
  16. package/dist/esm/routes.mjs +4 -5
  17. package/dist/esm/routes.mjs.map +1 -1
  18. package/dist/types/api/hooks/auth.d.ts.map +1 -1
  19. package/dist/types/components/Browser/extractUrlFromSitemap.d.ts +15 -1
  20. package/dist/types/components/Browser/extractUrlFromSitemap.d.ts.map +1 -1
  21. package/dist/types/components/Browser/index.d.ts +2 -1
  22. package/dist/types/components/IDE/shikiBundle.d.ts +0 -2
  23. package/dist/types/components/IDE/shikiBundle.d.ts.map +1 -1
  24. package/dist/types/components/IDE/shikiLanguages.d.ts +1 -3
  25. package/dist/types/components/IDE/shikiLanguages.d.ts.map +1 -1
  26. package/dist/types/components/LocaleSwitcherDropDown/LocaleSwitcher.d.ts +3 -0
  27. package/dist/types/components/LocaleSwitcherDropDown/LocaleSwitcher.d.ts.map +1 -1
  28. package/dist/types/components/LocaleSwitcherDropDown/index.d.ts +2 -2
  29. package/dist/types/components/index.d.ts +3 -2
  30. package/dist/types/libs/auth.d.ts +5 -0
  31. package/dist/types/libs/auth.d.ts.map +1 -1
  32. package/dist/types/providers/ThemeProvider.d.ts +7 -0
  33. package/dist/types/providers/ThemeProvider.d.ts.map +1 -1
  34. package/dist/types/routes.d.ts +3 -4
  35. package/dist/types/routes.d.ts.map +1 -1
  36. package/package.json +22 -24
@@ -11,6 +11,7 @@ const useLogin = () => {
11
11
  mutationKey: ["login"],
12
12
  mutationFn: (args) => intlayerAuth.signInEmail(args),
13
13
  onSuccess: (data) => {
14
+ if (!data.data?.user) return;
14
15
  const session = queryClient.getQueryData(["session"]);
15
16
  queryClient.setQueryData(["session"], {
16
17
  ...session,
@@ -1 +1 @@
1
- {"version":3,"file":"auth.mjs","names":[],"sources":["../../../../src/api/hooks/auth.ts"],"sourcesContent":["'use client';\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport type { AuthAPI } from '../../libs/auth';\nimport { useIntlayerAuth } from '../useIntlayerAPI';\n\nexport const useLogin = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationKey: ['login'],\n mutationFn: (args: Parameters<AuthAPI['signInEmail']>[0]) =>\n intlayerAuth.signInEmail(args),\n onSuccess: (data) => {\n const session = queryClient.getQueryData(['session']);\n\n queryClient.setQueryData(['session'], {\n ...session,\n user: data.data.user,\n });\n queryClient.invalidateQueries({ queryKey: ['session'] });\n queryClient.invalidateQueries({ queryKey: ['deviceSessions'] });\n },\n });\n};\n\nexport const useListAccounts = () => {\n const intlayerAuth = useIntlayerAuth();\n return useQuery({\n queryKey: ['listAccounts'],\n queryFn: () => intlayerAuth.listAccounts(),\n });\n};\n\nexport const useUnlinkAccount = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['unlinkAccount'],\n mutationFn: (args: Parameters<AuthAPI['unlinkAccount']>[0]) =>\n intlayerAuth.unlinkAccount(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['listAccounts'] });\n },\n });\n};\n\nexport const useLinkSocial = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['linkSocial'],\n mutationFn: (args: Parameters<AuthAPI['linkSocial']>[0]) =>\n intlayerAuth.linkSocial(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['listAccounts'] });\n },\n });\n};\n\nexport const useGetVerifyEmailStatus = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['getVerifyEmailStatus'],\n mutationFn: (args: Parameters<AuthAPI['verifyEmailSession']>) =>\n intlayerAuth.verifyEmailSession(...args),\n });\n};\n\nexport const useRegister = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['register'],\n mutationFn: (args: Parameters<AuthAPI['signUpEmail']>[0]) =>\n intlayerAuth.signUpEmail(args),\n });\n};\n\nconst LOGOUT_QUERY_KEYS: string[][] = [\n ['session'],\n ['users'],\n ['organizations'],\n ['projects'],\n ['dictionaries'],\n ['tags'],\n];\n\nexport const useLogout = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationKey: ['logout'],\n mutationFn: () => intlayerAuth.signOut(),\n // removeQueries instead of resetQueries: evicts cached data without\n // triggering a re-fetch. A re-fetch (resetQueries) can race with the\n // signOut response and resurrect a session from better-auth's\n // short-lived cookie cache, causing an infinite redirect loop between\n // the dashboard and the login page.\n onSettled: () => {\n LOGOUT_QUERY_KEYS.forEach((queryKey) => {\n queryClient.removeQueries({ queryKey });\n });\n },\n });\n};\n\nexport const useChangePassword = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['changePassword'],\n mutationFn: (args: Parameters<AuthAPI['changePasswordSession']>) =>\n intlayerAuth.changePasswordSession(...args),\n });\n};\n\nexport const useAskResetPassword = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['askResetPassword'],\n mutationFn: (args: Parameters<AuthAPI['requestPasswordResetSession']>[0]) =>\n intlayerAuth.requestPasswordResetSession(args),\n });\n};\n\nexport const useResetPassword = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['resetPassword'],\n mutationFn: (args: Parameters<AuthAPI['resetPassword']>[0]) =>\n intlayerAuth.resetPassword(args),\n });\n};\n\nexport const useVerifyEmail = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['verifyEmail'],\n mutationFn: (args: Parameters<AuthAPI['verifyEmailSession']>[0]) =>\n intlayerAuth.verifyEmailSession(args),\n });\n};\n\nexport const useGetUserByAccount = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['user'],\n mutationFn: (args: Parameters<AuthAPI['accountInfo']>[0]) =>\n intlayerAuth.accountInfo(args),\n });\n};\n\nexport const useEnableTwoFactor = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['enableTwoFactor'],\n mutationFn: (args: Parameters<AuthAPI['enableTwoFactor']>[0]) =>\n intlayerAuth.enableTwoFactor(args),\n });\n};\n\nexport const useDisableTwoFactor = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['disableTwoFactor'],\n mutationFn: (args: Parameters<AuthAPI['disableTwoFactor']>[0]) =>\n intlayerAuth.disableTwoFactor(args),\n });\n};\n\nexport const useVerifyTotp = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['verifyTotp'],\n mutationFn: (args: Parameters<AuthAPI['verifyTotp']>[0]) =>\n intlayerAuth.verifyTotp(args),\n });\n};\n\nexport const useVerifyBackupCode = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['verifyBackupCode'],\n mutationFn: (args: Parameters<AuthAPI['verifyBackupCode']>[0]) =>\n intlayerAuth.verifyBackupCode(args),\n });\n};\n\nexport const useAddPasskey = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['addPasskey'],\n mutationFn: (args: Parameters<AuthAPI['addPasskey']>[0]) =>\n intlayerAuth.addPasskey(args),\n });\n};\n\nexport const useSignInPasskey = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['signInPasskey'],\n mutationFn: (args?: Parameters<AuthAPI['signInPasskey']>[0]) =>\n intlayerAuth.signInPasskey(args),\n });\n};\n\nexport const useDeletePasskey = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['deletePasskey'],\n mutationFn: (args: Parameters<AuthAPI['deletePasskey']>[0]) =>\n intlayerAuth.deletePasskey(args),\n });\n};\n\nexport const useListPasskeys = () => {\n const intlayerAuth = useIntlayerAuth();\n return useQuery({\n queryKey: ['listPasskeys'],\n queryFn: () => intlayerAuth.listPasskeys(),\n });\n};\n\nexport const useSignInMagicLink = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['signInMagicLink'],\n mutationFn: (args?: any) => intlayerAuth.signInMagicLink(args),\n });\n};\n\nexport const useRegisterSSO = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['registerSSO'],\n mutationFn: (args: Parameters<AuthAPI['registerSSO']>[0]) =>\n intlayerAuth.registerSSO(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['ssoProviders'] });\n },\n });\n};\n\nexport const useSignInSSO = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['signInSSO'],\n mutationFn: (args: Parameters<AuthAPI['signInSSO']>[0]) =>\n intlayerAuth.signInSSO(args),\n });\n};\n\nexport const useListSSOProviders = () => {\n const intlayerAuth = useIntlayerAuth();\n return useQuery({\n queryKey: ['ssoProviders'],\n queryFn: () => intlayerAuth.listSSOProviders(),\n });\n};\n\nexport const useDeleteSSOProvider = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['deleteSSOProvider'],\n mutationFn: (args: Parameters<AuthAPI['deleteSSOProvider']>[0]) =>\n intlayerAuth.deleteSSOProvider(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['ssoProviders'] });\n },\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"auth.mjs","names":[],"sources":["../../../../src/api/hooks/auth.ts"],"sourcesContent":["'use client';\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport type { AuthAPI } from '../../libs/auth';\nimport { useIntlayerAuth } from '../useIntlayerAPI';\n\nexport const useLogin = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationKey: ['login'],\n mutationFn: (args: Parameters<AuthAPI['signInEmail']>[0]) =>\n intlayerAuth.signInEmail(args),\n onSuccess: (data) => {\n // better-auth resolves (never throws) on a failed sign-in, with\n // `data: null` and `error` set; the global mutation cache toasts it.\n if (!data.data?.user) return;\n\n const session = queryClient.getQueryData(['session']);\n\n queryClient.setQueryData(['session'], {\n ...session,\n user: data.data.user,\n });\n queryClient.invalidateQueries({ queryKey: ['session'] });\n queryClient.invalidateQueries({ queryKey: ['deviceSessions'] });\n },\n });\n};\n\nexport const useListAccounts = () => {\n const intlayerAuth = useIntlayerAuth();\n return useQuery({\n queryKey: ['listAccounts'],\n queryFn: () => intlayerAuth.listAccounts(),\n });\n};\n\nexport const useUnlinkAccount = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['unlinkAccount'],\n mutationFn: (args: Parameters<AuthAPI['unlinkAccount']>[0]) =>\n intlayerAuth.unlinkAccount(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['listAccounts'] });\n },\n });\n};\n\nexport const useLinkSocial = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['linkSocial'],\n mutationFn: (args: Parameters<AuthAPI['linkSocial']>[0]) =>\n intlayerAuth.linkSocial(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['listAccounts'] });\n },\n });\n};\n\nexport const useGetVerifyEmailStatus = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['getVerifyEmailStatus'],\n mutationFn: (args: Parameters<AuthAPI['verifyEmailSession']>) =>\n intlayerAuth.verifyEmailSession(...args),\n });\n};\n\nexport const useRegister = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['register'],\n mutationFn: (args: Parameters<AuthAPI['signUpEmail']>[0]) =>\n intlayerAuth.signUpEmail(args),\n });\n};\n\nconst LOGOUT_QUERY_KEYS: string[][] = [\n ['session'],\n ['users'],\n ['organizations'],\n ['projects'],\n ['dictionaries'],\n ['tags'],\n];\n\nexport const useLogout = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationKey: ['logout'],\n mutationFn: () => intlayerAuth.signOut(),\n // removeQueries instead of resetQueries: evicts cached data without\n // triggering a re-fetch. A re-fetch (resetQueries) can race with the\n // signOut response and resurrect a session from better-auth's\n // short-lived cookie cache, causing an infinite redirect loop between\n // the dashboard and the login page.\n onSettled: () => {\n LOGOUT_QUERY_KEYS.forEach((queryKey) => {\n queryClient.removeQueries({ queryKey });\n });\n },\n });\n};\n\nexport const useChangePassword = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['changePassword'],\n mutationFn: (args: Parameters<AuthAPI['changePasswordSession']>) =>\n intlayerAuth.changePasswordSession(...args),\n });\n};\n\nexport const useAskResetPassword = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['askResetPassword'],\n mutationFn: (args: Parameters<AuthAPI['requestPasswordResetSession']>[0]) =>\n intlayerAuth.requestPasswordResetSession(args),\n });\n};\n\nexport const useResetPassword = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['resetPassword'],\n mutationFn: (args: Parameters<AuthAPI['resetPassword']>[0]) =>\n intlayerAuth.resetPassword(args),\n });\n};\n\nexport const useVerifyEmail = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['verifyEmail'],\n mutationFn: (args: Parameters<AuthAPI['verifyEmailSession']>[0]) =>\n intlayerAuth.verifyEmailSession(args),\n });\n};\n\nexport const useGetUserByAccount = () => {\n const intlayerAuth = useIntlayerAuth();\n\n return useMutation({\n mutationKey: ['user'],\n mutationFn: (args: Parameters<AuthAPI['accountInfo']>[0]) =>\n intlayerAuth.accountInfo(args),\n });\n};\n\nexport const useEnableTwoFactor = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['enableTwoFactor'],\n mutationFn: (args: Parameters<AuthAPI['enableTwoFactor']>[0]) =>\n intlayerAuth.enableTwoFactor(args),\n });\n};\n\nexport const useDisableTwoFactor = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['disableTwoFactor'],\n mutationFn: (args: Parameters<AuthAPI['disableTwoFactor']>[0]) =>\n intlayerAuth.disableTwoFactor(args),\n });\n};\n\nexport const useVerifyTotp = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['verifyTotp'],\n mutationFn: (args: Parameters<AuthAPI['verifyTotp']>[0]) =>\n intlayerAuth.verifyTotp(args),\n });\n};\n\nexport const useVerifyBackupCode = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['verifyBackupCode'],\n mutationFn: (args: Parameters<AuthAPI['verifyBackupCode']>[0]) =>\n intlayerAuth.verifyBackupCode(args),\n });\n};\n\nexport const useAddPasskey = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['addPasskey'],\n mutationFn: (args: Parameters<AuthAPI['addPasskey']>[0]) =>\n intlayerAuth.addPasskey(args),\n });\n};\n\nexport const useSignInPasskey = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['signInPasskey'],\n mutationFn: (args?: Parameters<AuthAPI['signInPasskey']>[0]) =>\n intlayerAuth.signInPasskey(args),\n });\n};\n\nexport const useDeletePasskey = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['deletePasskey'],\n mutationFn: (args: Parameters<AuthAPI['deletePasskey']>[0]) =>\n intlayerAuth.deletePasskey(args),\n });\n};\n\nexport const useListPasskeys = () => {\n const intlayerAuth = useIntlayerAuth();\n return useQuery({\n queryKey: ['listPasskeys'],\n queryFn: () => intlayerAuth.listPasskeys(),\n });\n};\n\nexport const useSignInMagicLink = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['signInMagicLink'],\n mutationFn: (args?: any) => intlayerAuth.signInMagicLink(args),\n });\n};\n\nexport const useRegisterSSO = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['registerSSO'],\n mutationFn: (args: Parameters<AuthAPI['registerSSO']>[0]) =>\n intlayerAuth.registerSSO(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['ssoProviders'] });\n },\n });\n};\n\nexport const useSignInSSO = () => {\n const intlayerAuth = useIntlayerAuth();\n return useMutation({\n mutationKey: ['signInSSO'],\n mutationFn: (args: Parameters<AuthAPI['signInSSO']>[0]) =>\n intlayerAuth.signInSSO(args),\n });\n};\n\nexport const useListSSOProviders = () => {\n const intlayerAuth = useIntlayerAuth();\n return useQuery({\n queryKey: ['ssoProviders'],\n queryFn: () => intlayerAuth.listSSOProviders(),\n });\n};\n\nexport const useDeleteSSOProvider = () => {\n const intlayerAuth = useIntlayerAuth();\n const queryClient = useQueryClient();\n return useMutation({\n mutationKey: ['deleteSSOProvider'],\n mutationFn: (args: Parameters<AuthAPI['deleteSSOProvider']>[0]) =>\n intlayerAuth.deleteSSOProvider(args),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['ssoProviders'] });\n },\n });\n};\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
 
3
3
  import { useIsAuthFetchEnabled } from "../../providers/DeferredAuthProvider.mjs";
4
+ import { getOAuthAPI } from "@intlayer/api";
4
5
  import { editor } from "@intlayer/config/built";
5
6
  import { useQuery } from "@tanstack/react-query";
6
- import { getOAuthAPI } from "@intlayer/api";
7
7
  import { useConfiguration } from "@intlayer/editor-react";
8
8
  import { defu } from "defu";
9
9
 
@@ -1,41 +1,46 @@
1
1
  //#region src/components/Browser/extractUrlFromSitemap.ts
2
- const fetchWithTimeout = (url, timeout = 5e3) => {
2
+ const fetchTextWithTimeout = async (url, timeoutInMilliseconds) => {
3
3
  const controller = new AbortController();
4
- const id = setTimeout(() => controller.abort(), timeout);
5
- return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(id));
4
+ const timeoutId = setTimeout(() => controller.abort(), timeoutInMilliseconds);
5
+ try {
6
+ const response = await fetch(url, { signal: controller.signal });
7
+ if (!response.ok) return null;
8
+ return await response.text();
9
+ } catch {
10
+ return null;
11
+ } finally {
12
+ clearTimeout(timeoutId);
13
+ }
6
14
  };
7
15
  const parseLocs = (xml) => {
8
16
  return (xml.match(/<loc>([\s\S]*?)<\/loc>/g) ?? []).map((m) => m.replace(/<\/?loc>/g, "").trim()).filter(Boolean);
9
17
  };
10
- const fetchSitemapUrls = async (sitemapUrl, visited) => {
18
+ const fetchSitemapUrls = async (sitemapUrl, visited, fetchText) => {
11
19
  if (visited.has(sitemapUrl)) return [];
12
20
  visited.add(sitemapUrl);
13
- try {
14
- const res = await fetchWithTimeout(sitemapUrl);
15
- if (!res.ok) return [];
16
- const xml = await res.text();
17
- if (xml.includes("<sitemapindex")) {
18
- const childUrls = parseLocs(xml);
19
- return (await Promise.all(childUrls.map((url) => fetchSitemapUrls(url, visited)))).flat();
20
- }
21
- return parseLocs(xml);
22
- } catch {
23
- return [];
21
+ const xml = await fetchText(sitemapUrl, 5e3);
22
+ if (!xml) return [];
23
+ if (xml.includes("<sitemapindex")) {
24
+ const childUrls = parseLocs(xml);
25
+ return (await Promise.all(childUrls.map((url) => fetchSitemapUrls(url, visited, fetchText)))).flat();
24
26
  }
27
+ return parseLocs(xml);
25
28
  };
26
- const extractUrlFromSitemap = async (pageUrl) => {
29
+ /**
30
+ * Lists every page URL of the site hosting `pageUrl`, following the sitemaps
31
+ * declared in `robots.txt` (or `/sitemap.xml`) and nested sitemap indexes.
32
+ */
33
+ const extractUrlFromSitemap = async (pageUrl, { fetchText = fetchTextWithTimeout } = {}) => {
27
34
  const origin = new URL(pageUrl).origin;
28
35
  const candidateUrls = [];
29
- try {
30
- const res = await fetchWithTimeout(`${origin}/robots.txt`, 3e3);
31
- if (res.ok) ((await res.text()).match(/^Sitemap:\s*(.+)$/gim) ?? []).forEach((m) => {
32
- const url = m.replace(/^Sitemap:\s*/i, "").trim();
33
- if (url) candidateUrls.push(url);
34
- });
35
- } catch {}
36
+ const robotsText = await fetchText(`${origin}/robots.txt`, 3e3);
37
+ if (robotsText) (robotsText.match(/^Sitemap:\s*(.+)$/gim) ?? []).forEach((m) => {
38
+ const url = m.replace(/^Sitemap:\s*/i, "").trim();
39
+ if (url) candidateUrls.push(url);
40
+ });
36
41
  if (candidateUrls.length === 0) candidateUrls.push(`${origin}/sitemap.xml`);
37
42
  const visited = /* @__PURE__ */ new Set();
38
- const results = await Promise.all(candidateUrls.map((url) => fetchSitemapUrls(url, visited)));
43
+ const results = await Promise.all(candidateUrls.map((url) => fetchSitemapUrls(url, visited, fetchText)));
39
44
  return Array.from(new Set(results.flat())).sort();
40
45
  };
41
46
 
@@ -1 +1 @@
1
- {"version":3,"file":"extractUrlFromSitemap.mjs","names":[],"sources":["../../../../src/components/Browser/extractUrlFromSitemap.ts"],"sourcesContent":["const fetchWithTimeout = (url: string, timeout = 5000): Promise<Response> => {\n const controller = new AbortController();\n const id = setTimeout(() => controller.abort(), timeout);\n return fetch(url, { signal: controller.signal }).finally(() =>\n clearTimeout(id)\n );\n};\n\nconst parseLocs = (xml: string): string[] => {\n const matches = xml.match(/<loc>([\\s\\S]*?)<\\/loc>/g) ?? [];\n return matches.map((m) => m.replace(/<\\/?loc>/g, '').trim()).filter(Boolean);\n};\n\nconst fetchSitemapUrls = async (\n sitemapUrl: string,\n visited: Set<string>\n): Promise<string[]> => {\n if (visited.has(sitemapUrl)) return [];\n visited.add(sitemapUrl);\n\n try {\n const res = await fetchWithTimeout(sitemapUrl);\n if (!res.ok) return [];\n const xml = await res.text();\n\n if (xml.includes('<sitemapindex')) {\n const childUrls = parseLocs(xml);\n const results = await Promise.all(\n childUrls.map((url) => fetchSitemapUrls(url, visited))\n );\n return results.flat();\n }\n\n return parseLocs(xml);\n } catch {\n return [];\n }\n};\n\nexport const extractUrlFromSitemap = async (\n pageUrl: string\n): Promise<string[]> => {\n const origin = new URL(pageUrl).origin;\n const candidateUrls: string[] = [];\n\n try {\n const res = await fetchWithTimeout(`${origin}/robots.txt`, 3000);\n if (res.ok) {\n const text = await res.text();\n const matches = text.match(/^Sitemap:\\s*(.+)$/gim) ?? [];\n matches.forEach((m) => {\n const url = m.replace(/^Sitemap:\\s*/i, '').trim();\n if (url) candidateUrls.push(url);\n });\n }\n } catch {\n // Ignore network / CORS errors for robots.txt\n }\n\n if (candidateUrls.length === 0) {\n candidateUrls.push(`${origin}/sitemap.xml`);\n }\n\n const visited = new Set<string>();\n const results = await Promise.all(\n candidateUrls.map((url) => fetchSitemapUrls(url, visited))\n );\n\n return Array.from(new Set(results.flat())).sort();\n};\n"],"mappings":";AAAA,MAAM,oBAAoB,KAAa,UAAU,QAA4B;CAC3E,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,KAAK,iBAAiB,WAAW,MAAM,GAAG,OAAO;CACvD,OAAO,MAAM,KAAK,EAAE,QAAQ,WAAW,OAAO,CAAC,CAAC,CAAC,cAC/C,aAAa,EAAE,CACjB;AACF;AAEA,MAAM,aAAa,QAA0B;CAE3C,QADgB,IAAI,MAAM,yBAAyB,KAAK,CAAC,EAC3C,CAAC,KAAK,MAAM,EAAE,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO;AAC7E;AAEA,MAAM,mBAAmB,OACvB,YACA,YACsB;CACtB,IAAI,QAAQ,IAAI,UAAU,GAAG,OAAO,CAAC;CACrC,QAAQ,IAAI,UAAU;CAEtB,IAAI;EACF,MAAM,MAAM,MAAM,iBAAiB,UAAU;EAC7C,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;EACrB,MAAM,MAAM,MAAM,IAAI,KAAK;EAE3B,IAAI,IAAI,SAAS,eAAe,GAAG;GACjC,MAAM,YAAY,UAAU,GAAG;GAI/B,QAAO,MAHe,QAAQ,IAC5B,UAAU,KAAK,QAAQ,iBAAiB,KAAK,OAAO,CAAC,CACvD,EACc,CAAC,KAAK;EACtB;EAEA,OAAO,UAAU,GAAG;CACtB,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,MAAa,wBAAwB,OACnC,YACsB;CACtB,MAAM,SAAS,IAAI,IAAI,OAAO,CAAC,CAAC;CAChC,MAAM,gBAA0B,CAAC;CAEjC,IAAI;EACF,MAAM,MAAM,MAAM,iBAAiB,GAAG,OAAO,cAAc,GAAI;EAC/D,IAAI,IAAI,IAGN,EADgB,MADG,IAAI,KAAK,EACR,CAAC,MAAM,sBAAsB,KAAK,CAAC,EAChD,CAAC,SAAS,MAAM;GACrB,MAAM,MAAM,EAAE,QAAQ,iBAAiB,EAAE,CAAC,CAAC,KAAK;GAChD,IAAI,KAAK,cAAc,KAAK,GAAG;EACjC,CAAC;CAEL,QAAQ,CAER;CAEA,IAAI,cAAc,WAAW,GAC3B,cAAc,KAAK,GAAG,OAAO,aAAa;CAG5C,MAAM,0BAAU,IAAI,IAAY;CAChC,MAAM,UAAU,MAAM,QAAQ,IAC5B,cAAc,KAAK,QAAQ,iBAAiB,KAAK,OAAO,CAAC,CAC3D;CAEA,OAAO,MAAM,KAAK,IAAI,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;AAClD"}
1
+ {"version":3,"file":"extractUrlFromSitemap.mjs","names":[],"sources":["../../../../src/components/Browser/extractUrlFromSitemap.ts"],"sourcesContent":["/**\n * Fetches the body of a URL as text, or `null` when the request fails.\n * Injectable so callers that cannot `fetch` cross-origin directly (e.g. a\n * browser extension popup) can proxy the request through the inspected page.\n */\nexport type SitemapTextFetcher = (\n url: string,\n timeoutInMilliseconds: number\n) => Promise<string | null>;\n\nexport type ExtractUrlFromSitemapOptions = {\n /** Defaults to a plain `fetch` with an abort timeout. */\n fetchText?: SitemapTextFetcher;\n};\n\nconst fetchTextWithTimeout: SitemapTextFetcher = async (\n url,\n timeoutInMilliseconds\n) => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutInMilliseconds);\n\n try {\n const response = await fetch(url, { signal: controller.signal });\n if (!response.ok) return null;\n return await response.text();\n } catch {\n return null;\n } finally {\n clearTimeout(timeoutId);\n }\n};\n\nconst parseLocs = (xml: string): string[] => {\n const matches = xml.match(/<loc>([\\s\\S]*?)<\\/loc>/g) ?? [];\n return matches.map((m) => m.replace(/<\\/?loc>/g, '').trim()).filter(Boolean);\n};\n\nconst fetchSitemapUrls = async (\n sitemapUrl: string,\n visited: Set<string>,\n fetchText: SitemapTextFetcher\n): Promise<string[]> => {\n if (visited.has(sitemapUrl)) return [];\n visited.add(sitemapUrl);\n\n const xml = await fetchText(sitemapUrl, 5000);\n if (!xml) return [];\n\n if (xml.includes('<sitemapindex')) {\n const childUrls = parseLocs(xml);\n const results = await Promise.all(\n childUrls.map((url) => fetchSitemapUrls(url, visited, fetchText))\n );\n return results.flat();\n }\n\n return parseLocs(xml);\n};\n\n/**\n * Lists every page URL of the site hosting `pageUrl`, following the sitemaps\n * declared in `robots.txt` (or `/sitemap.xml`) and nested sitemap indexes.\n */\nexport const extractUrlFromSitemap = async (\n pageUrl: string,\n { fetchText = fetchTextWithTimeout }: ExtractUrlFromSitemapOptions = {}\n): Promise<string[]> => {\n const origin = new URL(pageUrl).origin;\n const candidateUrls: string[] = [];\n\n const robotsText = await fetchText(`${origin}/robots.txt`, 3000);\n if (robotsText) {\n const matches = robotsText.match(/^Sitemap:\\s*(.+)$/gim) ?? [];\n matches.forEach((m) => {\n const url = m.replace(/^Sitemap:\\s*/i, '').trim();\n if (url) candidateUrls.push(url);\n });\n }\n\n if (candidateUrls.length === 0) {\n candidateUrls.push(`${origin}/sitemap.xml`);\n }\n\n const visited = new Set<string>();\n const results = await Promise.all(\n candidateUrls.map((url) => fetchSitemapUrls(url, visited, fetchText))\n );\n\n return Array.from(new Set(results.flat())).sort();\n};\n"],"mappings":";AAeA,MAAM,uBAA2C,OAC/C,KACA,0BACG;CACH,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,YAAY,iBAAiB,WAAW,MAAM,GAAG,qBAAqB;CAE5E,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,WAAW,OAAO,CAAC;EAC/D,IAAI,CAAC,SAAS,IAAI,OAAO;EACzB,OAAO,MAAM,SAAS,KAAK;CAC7B,QAAQ;EACN,OAAO;CACT,UAAU;EACR,aAAa,SAAS;CACxB;AACF;AAEA,MAAM,aAAa,QAA0B;CAE3C,QADgB,IAAI,MAAM,yBAAyB,KAAK,CAAC,EAC3C,CAAC,KAAK,MAAM,EAAE,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO;AAC7E;AAEA,MAAM,mBAAmB,OACvB,YACA,SACA,cACsB;CACtB,IAAI,QAAQ,IAAI,UAAU,GAAG,OAAO,CAAC;CACrC,QAAQ,IAAI,UAAU;CAEtB,MAAM,MAAM,MAAM,UAAU,YAAY,GAAI;CAC5C,IAAI,CAAC,KAAK,OAAO,CAAC;CAElB,IAAI,IAAI,SAAS,eAAe,GAAG;EACjC,MAAM,YAAY,UAAU,GAAG;EAI/B,QAAO,MAHe,QAAQ,IAC5B,UAAU,KAAK,QAAQ,iBAAiB,KAAK,SAAS,SAAS,CAAC,CAClE,EACc,CAAC,KAAK;CACtB;CAEA,OAAO,UAAU,GAAG;AACtB;;;;;AAMA,MAAa,wBAAwB,OACnC,SACA,EAAE,YAAY,yBAAuD,CAAC,MAChD;CACtB,MAAM,SAAS,IAAI,IAAI,OAAO,CAAC,CAAC;CAChC,MAAM,gBAA0B,CAAC;CAEjC,MAAM,aAAa,MAAM,UAAU,GAAG,OAAO,cAAc,GAAI;CAC/D,IAAI,YAEF,CADgB,WAAW,MAAM,sBAAsB,KAAK,CAAC,EACtD,CAAC,SAAS,MAAM;EACrB,MAAM,MAAM,EAAE,QAAQ,iBAAiB,EAAE,CAAC,CAAC,KAAK;EAChD,IAAI,KAAK,cAAc,KAAK,GAAG;CACjC,CAAC;CAGH,IAAI,cAAc,WAAW,GAC3B,cAAc,KAAK,GAAG,OAAO,aAAa;CAG5C,MAAM,0BAAU,IAAI,IAAY;CAChC,MAAM,UAAU,MAAM,QAAQ,IAC5B,cAAc,KAAK,QAAQ,iBAAiB,KAAK,SAAS,SAAS,CAAC,CACtE;CAEA,OAAO,MAAM,KAAK,IAAI,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;AAClD"}
@@ -1,3 +1,4 @@
1
1
  import { Browser } from "./Browser.mjs";
2
+ import { extractUrlFromSitemap } from "./extractUrlFromSitemap.mjs";
2
3
 
3
- export { Browser };
4
+ export { Browser, extractUrlFromSitemap };
@@ -33,8 +33,6 @@ const grammarAliases = {
33
33
  cjs: "javascript",
34
34
  console: "bash",
35
35
  cts: "typescript",
36
- dockerfile: "docker",
37
- gql: "graphql",
38
36
  htm: "html",
39
37
  js: "javascript",
40
38
  jsonc: "json5",
@@ -63,7 +61,7 @@ const PLAIN_TEXT_LANGUAGE = "plaintext";
63
61
  *
64
62
  * @example
65
63
  * resolveCodeLanguage('ts'); // { id: 'typescript', loadGrammar: fn }
66
- * resolveCodeLanguage('toml'); // { id: 'toml', loadGrammar: fn }
64
+ * resolveCodeLanguage('yaml'); // { id: 'yaml', loadGrammar: fn }
67
65
  * resolveCodeLanguage('brainfuck'); // { id: 'plaintext', loadGrammar: null }
68
66
  */
69
67
  const resolveCodeLanguage = (language) => {
@@ -1 +1 @@
1
- {"version":3,"file":"shikiLanguages.mjs","names":[],"sources":["../../../../src/components/IDE/shikiLanguages.ts"],"sourcesContent":["/**\n * Grammar registrations, as default-exported by the `shiki/langs/*` modules.\n */\nexport type LanguageGrammar =\n typeof import('shiki/langs/typescript.mjs')['default'];\n\n/**\n * Loads a single Shiki grammar (and its embedded dependencies).\n */\nexport type GrammarLoader = () => Promise<{ default: LanguageGrammar }>;\n\n/**\n * Shiki grammar loaders, keyed by the canonical Shiki language id.\n *\n * Import specifiers are written as literals (never template strings) so that\n * bundlers can statically analyse them and emit one lazily fetched chunk per\n * grammar instead of bundling every language up front.\n */\nexport const grammarLoaders = {\n astro: () => import('shiki/langs/astro.mjs'),\n bash: () => import('shiki/langs/bash.mjs'),\n css: () => import('shiki/langs/css.mjs'),\n html: () => import('shiki/langs/html.mjs'),\n javascript: () => import('shiki/langs/javascript.mjs'),\n json: () => import('shiki/langs/json.mjs'),\n json5: () => import('shiki/langs/json5.mjs'),\n jsonc: () => import('shiki/langs/jsonc.mjs'),\n markdown: () => import('shiki/langs/markdown.mjs'),\n svelte: () => import('shiki/langs/svelte.mjs'),\n tsx: () => import('shiki/langs/tsx.mjs'),\n typescript: () => import('shiki/langs/typescript.mjs'),\n vue: () => import('shiki/langs/vue.mjs'),\n xml: () => import('shiki/langs/xml.mjs'),\n yaml: () => import('shiki/langs/yaml.mjs'),\n // 'angular-html': () => import('shiki/langs/angular-html.mjs'),\n // 'angular-ts': () => import('shiki/langs/angular-ts.mjs'),\n // c: () => import('shiki/langs/c.mjs'),\n // cpp: () => import('shiki/langs/cpp.mjs'),\n // csharp: () => import('shiki/langs/csharp.mjs'),\n // csv: () => import('shiki/langs/csv.mjs'),\n // dart: () => import('shiki/langs/dart.mjs'),\n // diff: () => import('shiki/langs/diff.mjs'),\n // docker: () => import('shiki/langs/docker.mjs'),\n // go: () => import('shiki/langs/go.mjs'),\n // graphql: () => import('shiki/langs/graphql.mjs'),\n // http: () => import('shiki/langs/http.mjs'),\n // ini: () => import('shiki/langs/ini.mjs'),\n // java: () => import('shiki/langs/java.mjs'),\n // kotlin: () => import('shiki/langs/kotlin.mjs'),\n // less: () => import('shiki/langs/less.mjs'),\n // lua: () => import('shiki/langs/lua.mjs'),\n // nginx: () => import('shiki/langs/nginx.mjs'),\n // php: () => import('shiki/langs/php.mjs'),\n // powershell: () => import('shiki/langs/powershell.mjs'),\n // prisma: () => import('shiki/langs/prisma.mjs'),\n // python: () => import('shiki/langs/python.mjs'),\n // ruby: () => import('shiki/langs/ruby.mjs'),\n // rust: () => import('shiki/langs/rust.mjs'),\n // scss: () => import('shiki/langs/scss.mjs'),\n // sql: () => import('shiki/langs/sql.mjs'), // swift: () => import('shiki/langs/swift.mjs'),\n // toml: () => import('shiki/langs/toml.mjs'),\n} satisfies Record<string, GrammarLoader>;\n\n/** Canonical Shiki language ids this package can highlight. */\nexport type ShikiLanguageId = keyof typeof grammarLoaders;\n\n/** Every canonical language id that ships with a grammar loader. */\nexport const shikiLanguageIds = Object.keys(\n grammarLoaders\n) as ShikiLanguageId[];\n\n/**\n * Code fence names that are rendered by another grammar, mapped to the\n * canonical id that actually owns the grammar.\n */\nexport const grammarAliases = {\n cjs: 'javascript',\n console: 'bash',\n cts: 'typescript',\n dockerfile: 'docker',\n gql: 'graphql',\n htm: 'html',\n js: 'javascript',\n jsonc: 'json5',\n jsx: 'tsx',\n md: 'markdown',\n mdx: 'markdown',\n mjs: 'javascript',\n mts: 'typescript',\n postcss: 'css',\n sh: 'bash',\n shell: 'bash',\n shellscript: 'bash',\n ts: 'typescript',\n yml: 'yaml',\n zsh: 'bash',\n} satisfies Record<string, ShikiLanguageId>;\n\n/** Code fence names accepted as aliases of a canonical language id. */\nexport type ShikiLanguageAlias = keyof typeof grammarAliases;\n\n/**\n * Languages Shiki renders without any grammar. They are also used as the\n * fallback for languages this package does not ship a grammar for.\n */\nexport type PlainTextLanguage = 'plaintext' | 'text' | 'txt';\n\nconst PLAIN_TEXT_LANGUAGE = 'plaintext' satisfies PlainTextLanguage;\n\n/** Every language name accepted by the code block components. */\nexport type CodeLanguage =\n | ShikiLanguageId\n | ShikiLanguageAlias\n | PlainTextLanguage;\n\n/**\n * A language name resolved to what Shiki actually needs to highlight it.\n */\nexport type ResolvedCodeLanguage = {\n /** Canonical language id to pass to `codeToHtml` / `codeToHast`. */\n id: ShikiLanguageId | PlainTextLanguage;\n /** Grammar loader, or `null` when the language needs no grammar. */\n loadGrammar: GrammarLoader | null;\n};\n\n/**\n * Resolve a code fence language name to a canonical Shiki id and its grammar\n * loader.\n *\n * Unknown names resolve to plain text rather than to an arbitrary grammar, so\n * that `codeToHtml` never receives a language it has not loaded.\n *\n * @param language - Language name coming from a code fence or a `lang` prop.\n *\n * @example\n * resolveCodeLanguage('ts'); // { id: 'typescript', loadGrammar: fn }\n * resolveCodeLanguage('toml'); // { id: 'toml', loadGrammar: fn }\n * resolveCodeLanguage('brainfuck'); // { id: 'plaintext', loadGrammar: null }\n */\nexport const resolveCodeLanguage = (\n language: CodeLanguage | string | undefined | null\n): ResolvedCodeLanguage => {\n const normalizedLanguage = (language ?? '').trim().toLowerCase();\n\n const canonicalId =\n grammarAliases[normalizedLanguage as ShikiLanguageAlias] ??\n (normalizedLanguage as ShikiLanguageId);\n\n const loadGrammar = grammarLoaders[canonicalId] as GrammarLoader | undefined;\n\n if (!loadGrammar) {\n return { id: PLAIN_TEXT_LANGUAGE, loadGrammar: null };\n }\n\n return { id: canonicalId, loadGrammar };\n};\n"],"mappings":";;;;;;;;AAkBA,MAAa,iBAAiB;CAC5B,aAAa,OAAO;CACpB,YAAY,OAAO;CACnB,WAAW,OAAO;CAClB,YAAY,OAAO;CACnB,kBAAkB,OAAO;CACzB,YAAY,OAAO;CACnB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,gBAAgB,OAAO;CACvB,cAAc,OAAO;CACrB,WAAW,OAAO;CAClB,kBAAkB,OAAO;CACzB,WAAW,OAAO;CAClB,WAAW,OAAO;CAClB,YAAY,OAAO;AA4BrB;;AAMA,MAAa,mBAAmB,OAAO,KACrC,cACF;;;;;AAMA,MAAa,iBAAiB;CAC5B,KAAK;CACL,SAAS;CACT,KAAK;CACL,YAAY;CACZ,KAAK;CACL,KAAK;CACL,IAAI;CACJ,OAAO;CACP,KAAK;CACL,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CACL,SAAS;CACT,IAAI;CACJ,OAAO;CACP,aAAa;CACb,IAAI;CACJ,KAAK;CACL,KAAK;AACP;AAWA,MAAM,sBAAsB;;;;;;;;;;;;;;;AAgC5B,MAAa,uBACX,aACyB;CACzB,MAAM,sBAAsB,YAAY,GAAE,CAAE,KAAK,CAAC,CAAC,YAAY;CAE/D,MAAM,cACJ,eAAe,uBACd;CAEH,MAAM,cAAc,eAAe;CAEnC,IAAI,CAAC,aACH,OAAO;EAAE,IAAI;EAAqB,aAAa;CAAK;CAGtD,OAAO;EAAE,IAAI;EAAa;CAAY;AACxC"}
1
+ {"version":3,"file":"shikiLanguages.mjs","names":[],"sources":["../../../../src/components/IDE/shikiLanguages.ts"],"sourcesContent":["/**\n * Grammar registrations, as default-exported by the `shiki/langs/*` modules.\n */\nexport type LanguageGrammar =\n typeof import('shiki/langs/typescript.mjs')['default'];\n\n/**\n * Loads a single Shiki grammar (and its embedded dependencies).\n */\nexport type GrammarLoader = () => Promise<{ default: LanguageGrammar }>;\n\n/**\n * Shiki grammar loaders, keyed by the canonical Shiki language id.\n *\n * Import specifiers are written as literals (never template strings) so that\n * bundlers can statically analyse them and emit one lazily fetched chunk per\n * grammar instead of bundling every language up front.\n */\nexport const grammarLoaders = {\n astro: () => import('shiki/langs/astro.mjs'),\n bash: () => import('shiki/langs/bash.mjs'),\n css: () => import('shiki/langs/css.mjs'),\n html: () => import('shiki/langs/html.mjs'),\n javascript: () => import('shiki/langs/javascript.mjs'),\n json: () => import('shiki/langs/json.mjs'),\n json5: () => import('shiki/langs/json5.mjs'),\n jsonc: () => import('shiki/langs/jsonc.mjs'),\n markdown: () => import('shiki/langs/markdown.mjs'),\n svelte: () => import('shiki/langs/svelte.mjs'),\n tsx: () => import('shiki/langs/tsx.mjs'),\n typescript: () => import('shiki/langs/typescript.mjs'),\n vue: () => import('shiki/langs/vue.mjs'),\n xml: () => import('shiki/langs/xml.mjs'),\n yaml: () => import('shiki/langs/yaml.mjs'),\n // 'angular-html': () => import('shiki/langs/angular-html.mjs'),\n // 'angular-ts': () => import('shiki/langs/angular-ts.mjs'),\n // c: () => import('shiki/langs/c.mjs'),\n // cpp: () => import('shiki/langs/cpp.mjs'),\n // csharp: () => import('shiki/langs/csharp.mjs'),\n // csv: () => import('shiki/langs/csv.mjs'),\n // dart: () => import('shiki/langs/dart.mjs'),\n // diff: () => import('shiki/langs/diff.mjs'),\n // docker: () => import('shiki/langs/docker.mjs'),\n // go: () => import('shiki/langs/go.mjs'),\n // graphql: () => import('shiki/langs/graphql.mjs'),\n // http: () => import('shiki/langs/http.mjs'),\n // ini: () => import('shiki/langs/ini.mjs'),\n // java: () => import('shiki/langs/java.mjs'),\n // kotlin: () => import('shiki/langs/kotlin.mjs'),\n // less: () => import('shiki/langs/less.mjs'),\n // lua: () => import('shiki/langs/lua.mjs'),\n // nginx: () => import('shiki/langs/nginx.mjs'),\n // php: () => import('shiki/langs/php.mjs'),\n // powershell: () => import('shiki/langs/powershell.mjs'),\n // prisma: () => import('shiki/langs/prisma.mjs'),\n // python: () => import('shiki/langs/python.mjs'),\n // ruby: () => import('shiki/langs/ruby.mjs'),\n // rust: () => import('shiki/langs/rust.mjs'),\n // scss: () => import('shiki/langs/scss.mjs'),\n // sql: () => import('shiki/langs/sql.mjs'), // swift: () => import('shiki/langs/swift.mjs'),\n // toml: () => import('shiki/langs/toml.mjs'),\n} satisfies Record<string, GrammarLoader>;\n\n/** Canonical Shiki language ids this package can highlight. */\nexport type ShikiLanguageId = keyof typeof grammarLoaders;\n\n/** Every canonical language id that ships with a grammar loader. */\nexport const shikiLanguageIds = Object.keys(\n grammarLoaders\n) as ShikiLanguageId[];\n\n/**\n * Code fence names that are rendered by another grammar, mapped to the\n * canonical id that actually owns the grammar.\n */\nexport const grammarAliases = {\n cjs: 'javascript',\n console: 'bash',\n cts: 'typescript',\n htm: 'html',\n js: 'javascript',\n jsonc: 'json5',\n jsx: 'tsx',\n md: 'markdown',\n mdx: 'markdown',\n mjs: 'javascript',\n mts: 'typescript',\n postcss: 'css',\n sh: 'bash',\n shell: 'bash',\n shellscript: 'bash',\n ts: 'typescript',\n yml: 'yaml',\n zsh: 'bash',\n} satisfies Record<string, ShikiLanguageId>;\n\n/** Code fence names accepted as aliases of a canonical language id. */\nexport type ShikiLanguageAlias = keyof typeof grammarAliases;\n\n/**\n * Languages Shiki renders without any grammar. They are also used as the\n * fallback for languages this package does not ship a grammar for.\n */\nexport type PlainTextLanguage = 'plaintext' | 'text' | 'txt';\n\nconst PLAIN_TEXT_LANGUAGE = 'plaintext' satisfies PlainTextLanguage;\n\n/** Every language name accepted by the code block components. */\nexport type CodeLanguage =\n | ShikiLanguageId\n | ShikiLanguageAlias\n | PlainTextLanguage;\n\n/**\n * A language name resolved to what Shiki actually needs to highlight it.\n */\nexport type ResolvedCodeLanguage = {\n /** Canonical language id to pass to `codeToHtml` / `codeToHast`. */\n id: ShikiLanguageId | PlainTextLanguage;\n /** Grammar loader, or `null` when the language needs no grammar. */\n loadGrammar: GrammarLoader | null;\n};\n\n/**\n * Resolve a code fence language name to a canonical Shiki id and its grammar\n * loader.\n *\n * Unknown names resolve to plain text rather than to an arbitrary grammar, so\n * that `codeToHtml` never receives a language it has not loaded.\n *\n * @param language - Language name coming from a code fence or a `lang` prop.\n *\n * @example\n * resolveCodeLanguage('ts'); // { id: 'typescript', loadGrammar: fn }\n * resolveCodeLanguage('yaml'); // { id: 'yaml', loadGrammar: fn }\n * resolveCodeLanguage('brainfuck'); // { id: 'plaintext', loadGrammar: null }\n */\nexport const resolveCodeLanguage = (\n language: CodeLanguage | string | undefined | null\n): ResolvedCodeLanguage => {\n const normalizedLanguage = (language ?? '').trim().toLowerCase();\n\n const canonicalId =\n grammarAliases[normalizedLanguage as ShikiLanguageAlias] ??\n (normalizedLanguage as ShikiLanguageId);\n\n const loadGrammar = grammarLoaders[canonicalId] as GrammarLoader | undefined;\n\n if (!loadGrammar) {\n return { id: PLAIN_TEXT_LANGUAGE, loadGrammar: null };\n }\n\n return { id: canonicalId, loadGrammar };\n};\n"],"mappings":";;;;;;;;AAkBA,MAAa,iBAAiB;CAC5B,aAAa,OAAO;CACpB,YAAY,OAAO;CACnB,WAAW,OAAO;CAClB,YAAY,OAAO;CACnB,kBAAkB,OAAO;CACzB,YAAY,OAAO;CACnB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,gBAAgB,OAAO;CACvB,cAAc,OAAO;CACrB,WAAW,OAAO;CAClB,kBAAkB,OAAO;CACzB,WAAW,OAAO;CAClB,WAAW,OAAO;CAClB,YAAY,OAAO;AA4BrB;;AAMA,MAAa,mBAAmB,OAAO,KACrC,cACF;;;;;AAMA,MAAa,iBAAiB;CAC5B,KAAK;CACL,SAAS;CACT,KAAK;CACL,KAAK;CACL,IAAI;CACJ,OAAO;CACP,KAAK;CACL,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CACL,SAAS;CACT,IAAI;CACJ,OAAO;CACP,aAAa;CACb,IAAI;CACJ,KAAK;CACL,KAAK;AACP;AAWA,MAAM,sBAAsB;;;;;;;;;;;;;;;AAgC5B,MAAa,uBACX,aACyB;CACzB,MAAM,sBAAsB,YAAY,GAAE,CAAE,KAAK,CAAC,CAAC,YAAY;CAE/D,MAAM,cACJ,eAAe,uBACd;CAEH,MAAM,cAAc,eAAe;CAEnC,IAAI,CAAC,aACH,OAAO;EAAE,IAAI;EAAqB,aAAa;CAAK;CAGtD,OAAO;EAAE,IAAI;EAAa;CAAY;AACxC"}
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { cn } from "../../utils/cn.mjs";
3
4
  import { Button } from "../Button/Button.mjs";
4
5
  import { Container } from "../Container/index.mjs";
5
6
  import { DropDown } from "../DropDown/index.mjs";
@@ -13,8 +14,22 @@ import { ENGLISH } from "@intlayer/types/locales";
13
14
  import Fuse from "fuse.js";
14
15
 
15
16
  //#region src/components/LocaleSwitcherDropDown/LocaleSwitcher.tsx
17
+ const sizeClassNames = {
18
+ sm: {
19
+ nav: "rounded-full border-[1.3px] border-text",
20
+ trigger: "min-h-0 px-1.5 py-0.5 text-xs",
21
+ label: "px-1",
22
+ icon: "size-3"
23
+ },
24
+ md: {
25
+ nav: "rounded-xl border border-text",
26
+ trigger: "",
27
+ label: "px-2",
28
+ icon: "w-5"
29
+ }
30
+ };
16
31
  const DROPDOWN_IDENTIFIER = "locale-switcher";
17
- const LocaleSwitcher = ({ locale, localeList, availableLocales, fullLocaleName = true, setLocale, panelProps }) => {
32
+ const LocaleSwitcher = ({ locale, localeList, availableLocales, fullLocaleName = true, setLocale, panelProps, size = "md" }) => {
18
33
  let localeName = "Select a locale";
19
34
  const { switchTo, searchInput, languageListLabel, localeSwitcherLabel } = useIntlayer("locale-switcher");
20
35
  const inputRef = useRef(null);
@@ -58,19 +73,22 @@ const LocaleSwitcher = ({ locale, localeList, availableLocales, fullLocaleName =
58
73
  }, [fuse, multilingualAvailableLocales]);
59
74
  if (locale) localeName = fullLocaleName ? getLocaleName(locale) : locale.toUpperCase();
60
75
  return /* @__PURE__ */ jsx("nav", {
61
- className: "rounded-xl border border-text",
76
+ className: sizeClassNames[size].nav,
62
77
  "aria-label": localeSwitcherLabel.value,
63
78
  children: /* @__PURE__ */ jsxs(DropDown, {
64
79
  identifier: DROPDOWN_IDENTIFIER,
65
80
  children: [/* @__PURE__ */ jsx(DropDown.Trigger, {
66
81
  identifier: DROPDOWN_IDENTIFIER,
67
- color: "text",
82
+ color: "custom",
83
+ size: size === "sm" ? "custom" : "md",
84
+ roundedSize: size === "sm" ? "full" : "md",
85
+ className: cn("text-text", sizeClassNames[size].trigger),
68
86
  children: /* @__PURE__ */ jsxs("div", {
69
87
  className: "flex w-full items-center justify-between",
70
88
  children: [/* @__PURE__ */ jsx("div", {
71
- className: "text-nowrap px-2",
89
+ className: cn("text-nowrap", sizeClassNames[size].label),
72
90
  children: localeName
73
- }), /* @__PURE__ */ jsx(MoveVertical, { className: "w-5 self-center" })]
91
+ }), /* @__PURE__ */ jsx(MoveVertical, { className: cn("self-center", sizeClassNames[size].icon) })]
74
92
  })
75
93
  }), /* @__PURE__ */ jsx(DropDown.Panel, {
76
94
  identifier: DROPDOWN_IDENTIFIER,
@@ -1 +1 @@
1
- {"version":3,"file":"LocaleSwitcher.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherDropDown/LocaleSwitcher.tsx"],"sourcesContent":["'use client';\n\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { MoveVertical } from 'lucide-react';\nimport { type FC, useCallback, useMemo, useRef, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\n\nexport type LocaleSwitcherProps = {\n locale?: Locale;\n localeList: Locale[];\n availableLocales?: Locale[];\n fullLocaleName?: boolean;\n setLocale: (locale: Locale) => void;\n panelProps?: Omit<PanelProps, 'identifier'>;\n};\n\nconst DROPDOWN_IDENTIFIER = 'locale-switcher';\n\ntype MultilingualAvailableLocales = {\n locale: Locale;\n englishName: string;\n currentLocaleName: string;\n ownLocaleName: string;\n};\n\nexport const LocaleSwitcher: FC<LocaleSwitcherProps> = ({\n locale,\n localeList,\n availableLocales,\n fullLocaleName = true,\n setLocale,\n panelProps,\n}) => {\n let localeName = 'Select a locale';\n const { switchTo, searchInput, languageListLabel, localeSwitcherLabel } =\n useIntlayer('locale-switcher');\n const inputRef = useRef<HTMLInputElement>(null);\n\n const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo(\n () =>\n localeList.map((localeEl) => {\n const englishName = getLocaleName(localeEl, ENGLISH);\n const currentLocaleName = getLocaleName(localeEl, locale);\n const ownLocaleName = getLocaleName(localeEl);\n return {\n locale: localeEl,\n englishName,\n currentLocaleName,\n ownLocaleName,\n };\n }),\n [localeList, locale]\n );\n\n const [results, setResults] = useState<MultilingualAvailableLocales[]>(\n multilingualAvailableLocales\n );\n\n // Create a new Fuse instance with the options and documentation data\n const fuse = useMemo(() => {\n const fuseOptions: IFuseOptions<MultilingualAvailableLocales> = {\n keys: [\n { name: 'ownLocaleName', weight: 0.4 },\n { name: 'englishName', weight: 0.2 },\n { name: 'currentLocaleName', weight: 0.2 },\n { name: 'locale', weight: 0.2 },\n ],\n threshold: 0.02, // Defines how fuzzy the matching should be (lower is more strict)\n };\n\n return new Fuse(multilingualAvailableLocales, fuseOptions);\n }, [multilingualAvailableLocales]);\n\n const handleSearch = useCallback(\n (searchQuery: string) => {\n if (searchQuery) {\n // Perform search on every input change\n const searchResults = fuse\n .search(searchQuery)\n .map((result) => result.item);\n setResults(searchResults);\n } else {\n setResults(multilingualAvailableLocales);\n }\n },\n [fuse, multilingualAvailableLocales]\n );\n\n if (locale) {\n localeName = fullLocaleName ? getLocaleName(locale) : locale.toUpperCase();\n }\n\n return (\n <nav\n className=\"rounded-xl border border-text\"\n aria-label={localeSwitcherLabel.value}\n >\n <DropDown identifier={DROPDOWN_IDENTIFIER}>\n <DropDown.Trigger identifier={DROPDOWN_IDENTIFIER} color=\"text\">\n <div className=\"flex w-full items-center justify-between\">\n <div className=\"text-nowrap px-2\">{localeName}</div>\n <MoveVertical className=\"w-5 self-center\" />\n </div>\n </DropDown.Trigger>\n\n <DropDown.Panel\n identifier={DROPDOWN_IDENTIFIER}\n isOverable\n isFocusable\n align=\"end\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[80vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"xs\"\n aria-label={languageListLabel.value}\n >\n <div className=\"p-3\">\n <Input\n type=\"search\"\n aria-label={searchInput.ariaLabel.value}\n placeholder={searchInput.placeholder.value}\n onChange={(e) => handleSearch(e.target.value)}\n ref={inputRef}\n />\n </div>\n <ol className=\"divide-y divide-dashed divide-text/20 overflow-y-auto p-1\">\n {results.map(\n ({ locale: localeItem, currentLocaleName, ownLocaleName }) => (\n <li className=\"px-1.5 py-1\" key={localeItem}>\n <Button\n onClick={() => setLocale(localeItem)}\n label={`${switchTo} ${currentLocaleName}`}\n disabled={\n !(availableLocales ?? localeList).includes(localeItem)\n }\n isActive={locale === localeItem}\n variant=\"hoverable\"\n color=\"text\"\n isFullWidth\n textAlign=\"left\"\n >\n <div className=\"flex flex-row items-center justify-between gap-3 px-2 py-1\">\n <div className=\"flex flex-col text-nowrap\">\n <span\n dir={getHTMLTextDir(localeItem)}\n lang={localeItem}\n suppressHydrationWarning\n >\n {ownLocaleName}\n </span>\n <span\n className=\"text-neutral text-xs\"\n suppressHydrationWarning\n >\n {currentLocaleName}\n </span>\n </div>\n <span className=\"text-neutral text-sm\">\n {localeItem.toUpperCase()}\n </span>\n </div>\n </Button>\n </li>\n )\n )}\n </ol>\n </Container>\n </DropDown.Panel>\n </DropDown>\n </nav>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAM,sBAAsB;AAS5B,MAAa,kBAA2C,EACtD,QACA,YACA,kBACA,iBAAiB,MACjB,WACA,iBACI;CACJ,IAAI,aAAa;CACjB,MAAM,EAAE,UAAU,aAAa,mBAAmB,wBAChD,YAAY,iBAAiB;CAC/B,MAAM,WAAW,OAAyB,IAAI;CAE9C,MAAM,+BAA+D,cAEjE,WAAW,KAAK,aAAa;EAI3B,OAAO;GACL,QAAQ;GACR,aALkB,cAAc,UAAU,OAKhC;GACV,mBALwB,cAAc,UAAU,MAKhC;GAChB,eALoB,cAAc,QAKtB;EACd;CACF,CAAC,GACH,CAAC,YAAY,MAAM,CACrB;CAEA,MAAM,CAAC,SAAS,cAAc,SAC5B,4BACF;CAGA,MAAM,OAAO,cAAc;EAWzB,OAAO,IAAI,KAAK,8BAA8B;GAT5C,MAAM;IACJ;KAAE,MAAM;KAAiB,QAAQ;IAAI;IACrC;KAAE,MAAM;KAAe,QAAQ;IAAI;IACnC;KAAE,MAAM;KAAqB,QAAQ;IAAI;IACzC;KAAE,MAAM;KAAU,QAAQ;IAAI;GAChC;GACA,WAAW;EAG2C,CAAC;CAC3D,GAAG,CAAC,4BAA4B,CAAC;CAEjC,MAAM,eAAe,aAClB,gBAAwB;EACvB,IAAI,aAAa;GAEf,MAAM,gBAAgB,KACnB,OAAO,WAAW,CAAC,CACnB,KAAK,WAAW,OAAO,IAAI;GAC9B,WAAW,aAAa;EAC1B,OACE,WAAW,4BAA4B;CAE3C,GACA,CAAC,MAAM,4BAA4B,CACrC;CAEA,IAAI,QACF,aAAa,iBAAiB,cAAc,MAAM,IAAI,OAAO,YAAY;CAG3E,OACE,oBAAC,OAAD;EACE,WAAU;EACV,cAAY,oBAAoB;YAEhC,qBAAC,UAAD;GAAU,YAAY;aAAtB,CACE,oBAAC,SAAS,SAAV;IAAkB,YAAY;IAAqB,OAAM;cACvD,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,OAAD;MAAK,WAAU;gBAAoB;KAAgB,IACnD,oBAAC,cAAD,EAAc,WAAU,kBAAmB,EACxC;;GACW,IAElB,oBAAC,SAAS,OAAV;IACE,YAAY;IACZ;IACA;IACA,OAAM;IACN,GAAI;cAEJ,qBAAC,WAAD;KACE,WAAU;KACV,WAAU;KACV,MAAK;KACL,cAAa;KACb,cAAY,kBAAkB;eALhC,CAOE,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,OAAD;OACE,MAAK;OACL,cAAY,YAAY,UAAU;OAClC,aAAa,YAAY,YAAY;OACrC,WAAW,MAAM,aAAa,EAAE,OAAO,KAAK;OAC5C,KAAK;MACN;KACE,IACL,oBAAC,MAAD;MAAI,WAAU;gBACX,QAAQ,KACN,EAAE,QAAQ,YAAY,mBAAmB,oBACxC,oBAAC,MAAD;OAAI,WAAU;iBACZ,oBAAC,QAAD;QACE,eAAe,UAAU,UAAU;QACnC,OAAO,GAAG,SAAS,GAAG;QACtB,UACE,EAAE,oBAAoB,WAAU,CAAE,SAAS,UAAU;QAEvD,UAAU,WAAW;QACrB,SAAQ;QACR,OAAM;QACN;QACA,WAAU;kBAEV,qBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,qBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,oBAAC,QAAD;WACE,KAAK,eAAe,UAAU;WAC9B,MAAM;WACN;qBAEC;UACG,IACN,oBAAC,QAAD;WACE,WAAU;WACV;qBAEC;UACG,EACH;aACL,oBAAC,QAAD;UAAM,WAAU;oBACb,WAAW,YAAY;SACpB,EACH;;OACC;MACN,GAlC6B,UAkC7B,CAER;KACE,EACK;;GACG,EACR;;CACP;AAET"}
1
+ {"version":3,"file":"LocaleSwitcher.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherDropDown/LocaleSwitcher.tsx"],"sourcesContent":["'use client';\n\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport { cn } from '@utils/cn';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { MoveVertical } from 'lucide-react';\nimport { type FC, useCallback, useMemo, useRef, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\n\nexport type LocaleSwitcherProps = {\n locale?: Locale;\n localeList: Locale[];\n availableLocales?: Locale[];\n fullLocaleName?: boolean;\n setLocale: (locale: Locale) => void;\n panelProps?: Omit<PanelProps, 'identifier'>;\n /** `sm` renders a compact pill, matching the `xs` `SwitchSelector`. */\n size?: LocaleSwitcherSize;\n};\n\nexport type LocaleSwitcherSize = 'sm' | 'md';\n\nconst sizeClassNames: Record<\n LocaleSwitcherSize,\n { nav: string; trigger: string; label: string; icon: string }\n> = {\n sm: {\n nav: 'rounded-full border-[1.3px] border-text',\n trigger: 'min-h-0 px-1.5 py-0.5 text-xs',\n label: 'px-1',\n icon: 'size-3',\n },\n md: {\n nav: 'rounded-xl border border-text',\n trigger: '',\n label: 'px-2',\n icon: 'w-5',\n },\n};\n\nconst DROPDOWN_IDENTIFIER = 'locale-switcher';\n\ntype MultilingualAvailableLocales = {\n locale: Locale;\n englishName: string;\n currentLocaleName: string;\n ownLocaleName: string;\n};\n\nexport const LocaleSwitcher: FC<LocaleSwitcherProps> = ({\n locale,\n localeList,\n availableLocales,\n fullLocaleName = true,\n setLocale,\n panelProps,\n size = 'md',\n}) => {\n let localeName = 'Select a locale';\n const { switchTo, searchInput, languageListLabel, localeSwitcherLabel } =\n useIntlayer('locale-switcher');\n const inputRef = useRef<HTMLInputElement>(null);\n\n const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo(\n () =>\n localeList.map((localeEl) => {\n const englishName = getLocaleName(localeEl, ENGLISH);\n const currentLocaleName = getLocaleName(localeEl, locale);\n const ownLocaleName = getLocaleName(localeEl);\n return {\n locale: localeEl,\n englishName,\n currentLocaleName,\n ownLocaleName,\n };\n }),\n [localeList, locale]\n );\n\n const [results, setResults] = useState<MultilingualAvailableLocales[]>(\n multilingualAvailableLocales\n );\n\n // Create a new Fuse instance with the options and documentation data\n const fuse = useMemo(() => {\n const fuseOptions: IFuseOptions<MultilingualAvailableLocales> = {\n keys: [\n { name: 'ownLocaleName', weight: 0.4 },\n { name: 'englishName', weight: 0.2 },\n { name: 'currentLocaleName', weight: 0.2 },\n { name: 'locale', weight: 0.2 },\n ],\n threshold: 0.02, // Defines how fuzzy the matching should be (lower is more strict)\n };\n\n return new Fuse(multilingualAvailableLocales, fuseOptions);\n }, [multilingualAvailableLocales]);\n\n const handleSearch = useCallback(\n (searchQuery: string) => {\n if (searchQuery) {\n // Perform search on every input change\n const searchResults = fuse\n .search(searchQuery)\n .map((result) => result.item);\n setResults(searchResults);\n } else {\n setResults(multilingualAvailableLocales);\n }\n },\n [fuse, multilingualAvailableLocales]\n );\n\n if (locale) {\n localeName = fullLocaleName ? getLocaleName(locale) : locale.toUpperCase();\n }\n\n return (\n <nav\n className={sizeClassNames[size].nav}\n aria-label={localeSwitcherLabel.value}\n >\n <DropDown identifier={DROPDOWN_IDENTIFIER}>\n <DropDown.Trigger\n identifier={DROPDOWN_IDENTIFIER}\n // `text` color paints children with `text-opposite`, unreadable on\n // the transparent `none` variant.\n color=\"custom\"\n size={size === 'sm' ? 'custom' : 'md'}\n roundedSize={size === 'sm' ? 'full' : 'md'}\n className={cn('text-text', sizeClassNames[size].trigger)}\n >\n <div className=\"flex w-full items-center justify-between\">\n <div className={cn('text-nowrap', sizeClassNames[size].label)}>\n {localeName}\n </div>\n <MoveVertical\n className={cn('self-center', sizeClassNames[size].icon)}\n />\n </div>\n </DropDown.Trigger>\n\n <DropDown.Panel\n identifier={DROPDOWN_IDENTIFIER}\n isOverable\n isFocusable\n align=\"end\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[80vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"xs\"\n aria-label={languageListLabel.value}\n >\n <div className=\"p-3\">\n <Input\n type=\"search\"\n aria-label={searchInput.ariaLabel.value}\n placeholder={searchInput.placeholder.value}\n onChange={(e) => handleSearch(e.target.value)}\n ref={inputRef}\n />\n </div>\n <ol className=\"divide-y divide-dashed divide-text/20 overflow-y-auto p-1\">\n {results.map(\n ({ locale: localeItem, currentLocaleName, ownLocaleName }) => (\n <li className=\"px-1.5 py-1\" key={localeItem}>\n <Button\n onClick={() => setLocale(localeItem)}\n label={`${switchTo} ${currentLocaleName}`}\n disabled={\n !(availableLocales ?? localeList).includes(localeItem)\n }\n isActive={locale === localeItem}\n variant=\"hoverable\"\n color=\"text\"\n isFullWidth\n textAlign=\"left\"\n >\n <div className=\"flex flex-row items-center justify-between gap-3 px-2 py-1\">\n <div className=\"flex flex-col text-nowrap\">\n <span\n dir={getHTMLTextDir(localeItem)}\n lang={localeItem}\n suppressHydrationWarning\n >\n {ownLocaleName}\n </span>\n <span\n className=\"text-neutral text-xs\"\n suppressHydrationWarning\n >\n {currentLocaleName}\n </span>\n </div>\n <span className=\"text-neutral text-sm\">\n {localeItem.toUpperCase()}\n </span>\n </div>\n </Button>\n </li>\n )\n )}\n </ol>\n </Container>\n </DropDown.Panel>\n </DropDown>\n </nav>\n );\n};\n"],"mappings":"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"}
@@ -19,6 +19,7 @@ import { InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlo
19
19
  import { Radio, radioVariants } from "./Input/Radio.mjs";
20
20
  import { SearchInput } from "./Input/SearchInput.mjs";
21
21
  import { Browser } from "./Browser/Browser.mjs";
22
+ import { extractUrlFromSitemap } from "./Browser/extractUrlFromSitemap.mjs";
22
23
  import { KeyboardShortcut } from "./KeyboardShortcut/KeyboardShortcut.mjs";
23
24
  import { Detail, PopoverStatic, usePopoverIds } from "./Popover/static.mjs";
24
25
  import { Popover } from "./Popover/dynamic.mjs";
@@ -143,4 +144,4 @@ import { Terminal } from "./Terminal/Terminal.mjs";
143
144
  import { DesktopThemeSwitcher } from "./ThemeSwitcherDropDown/DesktopThemeSwitcher.mjs";
144
145
  import { MobileThemeSwitcher } from "./ThemeSwitcherDropDown/MobileThemeSwitcher.mjs";
145
146
 
146
- export { Accordion, AutoCompleteTextarea, AutoSizedTextArea, Avatar, Badge, BitbucketLogo, Breadcrumb, Browser, Burger, Button, Carousel, Checkbox, ClickOutsideDiv, Code, CodeBlock, CodeDefault, CodeHighlighted, CollapsibleTable, Command, CommandRoot, Container, ContentEditableTextArea, ContentEditor, ContentEditorInput, ContentEditorTextArea, ContentSelector, CopyButton, CopyToClipboard, DesktopNavbar, DesktopThemeSwitcher, Detail, DictionaryCreationForm, DictionaryEditor, DictionaryFieldEditor, DiscordLogo, DotPattern, DropDown, EditableFieldInput, EditableFieldTextArea, ExpandCollapse, FacebookLogo, FileList, Flag, flags_exports as Flags, Footer, Form, AutoSizedTextAreaElement as FormAutoSizedTextArea, Button as FormButton, CheckboxElement as FormCheckbox, FormControl, FormDescription, EditableFieldInputElement as FormEditableFieldInput, EditableFieldTextAreaElement as FormEditableFieldTextArea, FormElement, FormField, InputElement as FormInput, InputPasswordElement as FormInputPassword, FormItem, FormLabelLayout as FormLabel, FormMessage, MultiSelectElement as FormMultiSelect, OTPElement as FormOTP, SearchInputElement as FormSearchInput, SelectElement as FormSelect, SwitchSelectorElement as FormSwitchSelector, TextAreaElement as FormTextArea, GitHubLogo, GitLabLogo, GoogleLogo, GridDistortionPattern, GridPattern, H1, H2, H3, H4, H5, H6, HTMLRenderer, HeightResizer, HideShow, Hr, IDE, InformationTag, Input, InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, InputPassword, InstagramLogo, KeyPathBreadcrumb, KeyboardScreenAdapter, KeyboardShortcut, Label, LanguageBackground, LanguageSection, Link, LinkedInLogo, Loader, LocalCardList, LocaleSwitcher, LocaleSwitcherContent, LocaleSwitcherContentProvider, Logo, LogoTextOnly, LogoWithText, LogoWithTextBelow, MarkDownIframe, MarkdownEditor, MarkdownRenderer, MaxHeightSmoother, MaxWidthSmoother, MobileNavbar, MobileThemeSwitcher, Modal, MultiSelect, Navbar, NodeEditor, NumberItemsSelector, OTPInput, OTPInputContext, Pagination, Popover, PopoverStatic, PressableSpan, ProductHuntLogo, Radio, RightDrawer, SaveForm, SearchInput, Select, SelectContent, SelectLabel, SelectSeparator, ShowingResultsNumberItems, SmartTable, SocialNetworks, Spotlight, Step, Steps, SwitchSelector, Tab, TabSelector, Table, Tag, Td, TechLogo, techLogos_exports as TechLogos, Terminal, TextArea, TextEditor, TextEditorContainer, Th, TiktokLogo, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Tr, VersionSwitcher, VersionSwitcherProvider, VerticalSwitchSelector, WithResizer, XLogo, YoutubeLogo, badgeVariants, baseMarkdownComponents, buttonVariants, checkIsExternalLink, checkboxVariants, choiceVariant, containerVariants, createEditorUploadFn, defaultChoices, drawerManager, getCapitals, getFormWebMCPAttributes, getIntlayerHTMLOptions, getIntlayerMarkdownOptions, getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl, indicatorVariant, inputSlotVariants, inputVariants, isTextChildren, linkVariants, paginationVariants, radioVariants, reducer, shikiWrapperClassName, switchSelectorVariant, toast, toastVariants, traceKeys, useContentEditable, useCopyToClipboard, useForm, useFormField, useIsRightDrawerOpen, useLocaleSwitcherContent, usePasswordManagerBadge, usePopoverIds, usePrevious, useRightDrawer, useRightDrawerActions, useToast, useVersionSwitcher };
147
+ export { Accordion, AutoCompleteTextarea, AutoSizedTextArea, Avatar, Badge, BitbucketLogo, Breadcrumb, Browser, Burger, Button, Carousel, Checkbox, ClickOutsideDiv, Code, CodeBlock, CodeDefault, CodeHighlighted, CollapsibleTable, Command, CommandRoot, Container, ContentEditableTextArea, ContentEditor, ContentEditorInput, ContentEditorTextArea, ContentSelector, CopyButton, CopyToClipboard, DesktopNavbar, DesktopThemeSwitcher, Detail, DictionaryCreationForm, DictionaryEditor, DictionaryFieldEditor, DiscordLogo, DotPattern, DropDown, EditableFieldInput, EditableFieldTextArea, ExpandCollapse, FacebookLogo, FileList, Flag, flags_exports as Flags, Footer, Form, AutoSizedTextAreaElement as FormAutoSizedTextArea, Button as FormButton, CheckboxElement as FormCheckbox, FormControl, FormDescription, EditableFieldInputElement as FormEditableFieldInput, EditableFieldTextAreaElement as FormEditableFieldTextArea, FormElement, FormField, InputElement as FormInput, InputPasswordElement as FormInputPassword, FormItem, FormLabelLayout as FormLabel, FormMessage, MultiSelectElement as FormMultiSelect, OTPElement as FormOTP, SearchInputElement as FormSearchInput, SelectElement as FormSelect, SwitchSelectorElement as FormSwitchSelector, TextAreaElement as FormTextArea, GitHubLogo, GitLabLogo, GoogleLogo, GridDistortionPattern, GridPattern, H1, H2, H3, H4, H5, H6, HTMLRenderer, HeightResizer, HideShow, Hr, IDE, InformationTag, Input, InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, InputPassword, InstagramLogo, KeyPathBreadcrumb, KeyboardScreenAdapter, KeyboardShortcut, Label, LanguageBackground, LanguageSection, Link, LinkedInLogo, Loader, LocalCardList, LocaleSwitcher, LocaleSwitcherContent, LocaleSwitcherContentProvider, Logo, LogoTextOnly, LogoWithText, LogoWithTextBelow, MarkDownIframe, MarkdownEditor, MarkdownRenderer, MaxHeightSmoother, MaxWidthSmoother, MobileNavbar, MobileThemeSwitcher, Modal, MultiSelect, Navbar, NodeEditor, NumberItemsSelector, OTPInput, OTPInputContext, Pagination, Popover, PopoverStatic, PressableSpan, ProductHuntLogo, Radio, RightDrawer, SaveForm, SearchInput, Select, SelectContent, SelectLabel, SelectSeparator, ShowingResultsNumberItems, SmartTable, SocialNetworks, Spotlight, Step, Steps, SwitchSelector, Tab, TabSelector, Table, Tag, Td, TechLogo, techLogos_exports as TechLogos, Terminal, TextArea, TextEditor, TextEditorContainer, Th, TiktokLogo, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Tr, VersionSwitcher, VersionSwitcherProvider, VerticalSwitchSelector, WithResizer, XLogo, YoutubeLogo, badgeVariants, baseMarkdownComponents, buttonVariants, checkIsExternalLink, checkboxVariants, choiceVariant, containerVariants, createEditorUploadFn, defaultChoices, drawerManager, extractUrlFromSitemap, getCapitals, getFormWebMCPAttributes, getIntlayerHTMLOptions, getIntlayerMarkdownOptions, getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl, indicatorVariant, inputSlotVariants, inputVariants, isTextChildren, linkVariants, paginationVariants, radioVariants, reducer, shikiWrapperClassName, switchSelectorVariant, toast, toastVariants, traceKeys, useContentEditable, useCopyToClipboard, useForm, useFormField, useIsRightDrawerOpen, useLocaleSwitcherContent, usePasswordManagerBadge, usePopoverIds, usePrevious, useRightDrawer, useRightDrawerActions, useToast, useVersionSwitcher };
@@ -1,13 +1,19 @@
1
1
  import { passkeyClient } from "@better-auth/passkey/client";
2
2
  import { ssoClient } from "@better-auth/sso/client";
3
+ import { resolveInternalBackendUrl } from "@intlayer/api";
3
4
  import { editor } from "@intlayer/config/built";
4
5
  import { BACKEND_URL } from "@intlayer/config/defaultValues";
5
6
  import { createAuthClient } from "better-auth/client";
6
7
  import { lastLoginMethodClient, magicLinkClient, multiSessionClient, twoFactorClient } from "better-auth/client/plugins";
7
8
 
8
9
  //#region src/libs/auth.ts
10
+ /**
11
+ * better-auth performs its own fetches, bypassing `@intlayer/api`'s fetcher,
12
+ * so the server-side `INTLAYER_BACKEND_INTERNAL_URL` override is applied here
13
+ * to the base URL. In the browser the URL passes through unchanged.
14
+ */
9
15
  const getAuthClient = (backendURL) => createAuthClient({
10
- baseURL: backendURL,
16
+ baseURL: resolveInternalBackendUrl(backendURL, backendURL),
11
17
  withCredentials: true,
12
18
  plugins: [
13
19
  twoFactorClient({ onTwoFactorRedirect: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"auth.mjs","names":[],"sources":["../../../src/libs/auth.ts"],"sourcesContent":["import { passkeyClient } from '@better-auth/passkey/client';\nimport { ssoClient } from '@better-auth/sso/client';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createAuthClient } from 'better-auth/client';\nimport {\n lastLoginMethodClient,\n magicLinkClient,\n multiSessionClient,\n twoFactorClient,\n} from 'better-auth/client/plugins';\n\nconst getAuthClient = (backendURL: string) =>\n createAuthClient({\n baseURL: backendURL,\n withCredentials: true, // makes fetch forward cookies\n plugins: [\n twoFactorClient({\n onTwoFactorRedirect: () => {\n // Preserve redirect_url when redirecting to 2FA\n const searchParams = new URLSearchParams(window.location.search);\n const redirectUrl = searchParams.get('redirect_url');\n const twoFaUrl = redirectUrl\n ? `/auth/2fa?redirect_url=${encodeURIComponent(redirectUrl)}`\n : '/auth/2fa';\n window.location.href = twoFaUrl;\n },\n }),\n passkeyClient(),\n magicLinkClient() as never,\n ssoClient(),\n multiSessionClient(),\n lastLoginMethodClient(),\n ],\n });\n\ntype AuthClient = ReturnType<typeof getAuthClient>;\n\nexport interface AuthAPI {\n getAuthClient: () => AuthClient;\n signInEmail: AuthClient['signIn']['email'];\n signUpEmail: AuthClient['signUp']['email'];\n signOut: AuthClient['signOut'];\n signInSocial: AuthClient['signIn']['social'];\n linkSocial: AuthClient['linkSocial'];\n changePasswordSession: AuthClient['changePassword'];\n requestPasswordResetSession: AuthClient['requestPasswordReset'];\n resetPassword: AuthClient['resetPassword'];\n verifyEmailSession: AuthClient['verifyEmail'];\n getSession: AuthClient['getSession'];\n forgetPassword: AuthClient['requestPasswordReset'];\n sendVerificationEmail: AuthClient['sendVerificationEmail'];\n changeEmail: AuthClient['changeEmail'];\n deleteUser: AuthClient['deleteUser'];\n revokeSession: AuthClient['revokeSession'];\n revokeSessions: AuthClient['revokeSessions'];\n revokeOtherSessions: AuthClient['revokeOtherSessions'];\n listAccounts: AuthClient['listAccounts'];\n unlinkAccount: AuthClient['unlinkAccount'];\n refreshToken: AuthClient['refreshToken'];\n getAccessToken: AuthClient['getAccessToken'];\n accountInfo: AuthClient['accountInfo'];\n updateUser: AuthClient['updateUser'];\n listSessions: AuthClient['listSessions'];\n enableTwoFactor: AuthClient['twoFactor']['enable'];\n disableTwoFactor: AuthClient['twoFactor']['disable'];\n verifyTotp: AuthClient['twoFactor']['verifyTotp'];\n verifyBackupCode: AuthClient['twoFactor']['verifyBackupCode'];\n addPasskey: AuthClient['passkey']['addPasskey'];\n signInPasskey: AuthClient['signIn']['passkey'];\n deletePasskey: AuthClient['passkey']['deletePasskey'];\n listPasskeys: () => Promise<any>;\n signInMagicLink: (\n // Redeclare it because of type inference issues\n input: { email: string; callbackURL: string }\n ) => any;\n registerSSO: AuthClient['sso']['register'];\n listSSOProviders: () => Promise<any>;\n deleteSSOProvider: (args: { providerId: string }) => Promise<any>;\n signInSSO: AuthClient['signIn']['sso'];\n listDeviceSessions: AuthClient['multiSession']['listDeviceSessions'];\n setActiveSession: AuthClient['multiSession']['setActive'];\n revokeDeviceSession: AuthClient['multiSession']['revoke'];\n}\n\nexport const getAuthAPI = (\n intlayerConfig?: Pick<IntlayerConfig, 'editor'>\n): AuthAPI => {\n let backendURL = intlayerConfig?.editor?.backendURL ?? editor?.backendURL;\n\n if (!backendURL) {\n backendURL = BACKEND_URL;\n console.error('Backend URL is not defined in the Intlayer configuration.');\n }\n\n const client = getAuthClient(backendURL);\n\n const signInEmail: AuthClient['signIn']['email'] = async (...args) => {\n return client.signIn.email(...args);\n };\n\n const signInSocial: AuthClient['signIn']['social'] = async (...args) => {\n return client.signIn.social(...args);\n };\n\n const signUpEmail: AuthClient['signUp']['email'] = async (...args) => {\n return client.signUp.email(...args);\n };\n\n const signOut: AuthClient['signOut'] = async (...args) => {\n return client.signOut(...args);\n };\n\n const changePasswordSession: AuthClient['changePassword'] = async (\n ...args\n ) => {\n return client.changePassword(...args);\n };\n\n const requestPasswordResetSession: AuthClient['requestPasswordReset'] =\n async (...args) => {\n return client.requestPasswordReset(...args);\n };\n\n // @ts-ignore - resetPassword is not typed\n const resetPassword: AuthClient['resetPassword'] = async (...args) => {\n return client.resetPassword(...args);\n };\n\n const verifyEmailSession: AuthClient['verifyEmail'] = async (...args) => {\n return client.verifyEmail(...args);\n };\n\n const getSession: AuthClient['getSession'] = async (...args) => {\n return client.getSession(...args);\n };\n\n const forgetPassword: AuthClient['requestPasswordReset'] = async (\n ...args\n ) => {\n return client.requestPasswordReset(...args);\n };\n\n const sendVerificationEmail: AuthClient['sendVerificationEmail'] = async (\n ...args\n ) => {\n return client.sendVerificationEmail(...args);\n };\n\n const changeEmail: AuthClient['changeEmail'] = async (...args) => {\n return client.changeEmail(...args);\n };\n\n // @ts-ignore - deleteUser is not typed\n const deleteUser: AuthClient['deleteUser'] = async (...args) => {\n return client.deleteUser(...args);\n };\n\n const revokeSession: AuthClient['revokeSession'] = async (...args) => {\n return client.revokeSession(...args);\n };\n\n const revokeSessions: AuthClient['revokeSessions'] = async (...args) => {\n return client.revokeSessions(...args);\n };\n\n const revokeOtherSessions: AuthClient['revokeOtherSessions'] = async (\n ...args\n ) => {\n return client.revokeOtherSessions(...args);\n };\n\n const linkSocial: AuthClient['linkSocial'] = async (...args) => {\n return client.linkSocial(...args);\n };\n\n const listAccounts: AuthClient['listAccounts'] = async (...args) => {\n return client.listAccounts(...args);\n };\n\n const unlinkAccount: AuthClient['unlinkAccount'] = async (...args) => {\n return client.unlinkAccount(...args);\n };\n\n const refreshToken: AuthClient['refreshToken'] = async (...args) => {\n return client.refreshToken(...args);\n };\n\n const getAccessToken: AuthClient['getAccessToken'] = async (...args) => {\n return client.getAccessToken(...args);\n };\n\n const accountInfo: AuthClient['accountInfo'] = async (...args) => {\n return client.accountInfo(...args);\n };\n\n const updateUser: AuthClient['updateUser'] = async (...args) => {\n return client.updateUser(...args);\n };\n\n const listSessions: AuthClient['listSessions'] = async (...args) => {\n return client.listSessions(...args);\n };\n\n const enableTwoFactor: AuthClient['twoFactor']['enable'] = async (\n ...args\n ) => {\n return client.twoFactor.enable(...args) as ReturnType<\n AuthClient['twoFactor']['enable']\n >;\n };\n\n const disableTwoFactor: AuthClient['twoFactor']['disable'] = async (\n ...args\n ) => {\n return client.twoFactor.disable(...args) as ReturnType<\n AuthClient['twoFactor']['disable']\n >;\n };\n\n const verifyTotp: AuthClient['twoFactor']['verifyTotp'] = async (...args) => {\n return client.twoFactor.verifyTotp(...args) as ReturnType<\n AuthClient['twoFactor']['verifyTotp']\n >;\n };\n\n const verifyBackupCode: AuthClient['twoFactor']['verifyBackupCode'] = async (\n ...args\n ) => {\n return client.twoFactor.verifyBackupCode(...args) as ReturnType<\n AuthClient['twoFactor']['verifyBackupCode']\n >;\n };\n\n const addPasskey: AuthClient['passkey']['addPasskey'] = async (...args) => {\n return client.passkey.addPasskey(...args);\n };\n\n const signInPasskey: AuthClient['signIn']['passkey'] = async (...args) => {\n return client.signIn.passkey(...args);\n };\n\n const deletePasskey: AuthClient['passkey']['deletePasskey'] = async (\n ...args\n ) => {\n return client.passkey.deletePasskey(...args);\n };\n\n const listPasskeys = async () => {\n // @ts-ignore - listPasskeys may not be typed yet\n return client.$fetch('/passkey/list-user-passkeys', {\n method: 'GET',\n });\n };\n\n const signInMagicLink: any = async (...args: any[]) => {\n return (client.signIn as any).magicLink(...args);\n };\n\n const signInSSO: AuthClient['signIn']['sso'] = async (...args) => {\n return client.signIn.sso(...args);\n };\n\n const registerSSO: AuthClient['sso']['register'] = async (...args) => {\n return client.sso.register(...args);\n };\n\n const listSSOProviders = async () => {\n const response = await (client.sso as any).providers();\n return { data: response?.data?.providers ?? [] };\n };\n\n const deleteSSOProvider = async (args: { providerId: string }) => {\n return (client.sso as any).deleteProvider({ providerId: args.providerId });\n };\n\n const listDeviceSessions: AuthClient['multiSession']['listDeviceSessions'] =\n async (...args) => {\n return client.multiSession.listDeviceSessions(...args);\n };\n\n const setActiveSession: AuthClient['multiSession']['setActive'] = async (\n ...args\n ) => {\n return client.multiSession.setActive(...args);\n };\n\n const revokeDeviceSession: AuthClient['multiSession']['revoke'] = async (\n ...args\n ) => {\n return client.multiSession.revoke(...args);\n };\n\n return {\n getAuthClient: () => client,\n signInEmail,\n signUpEmail,\n signOut,\n signInSocial,\n linkSocial,\n changePasswordSession,\n requestPasswordResetSession,\n resetPassword,\n verifyEmailSession,\n getSession,\n forgetPassword,\n sendVerificationEmail,\n changeEmail,\n deleteUser,\n revokeSession,\n revokeSessions,\n revokeOtherSessions,\n listAccounts,\n unlinkAccount,\n refreshToken,\n getAccessToken,\n accountInfo,\n updateUser,\n listSessions,\n enableTwoFactor,\n disableTwoFactor,\n verifyTotp,\n verifyBackupCode,\n addPasskey,\n signInPasskey,\n deletePasskey,\n listPasskeys,\n signInMagicLink,\n signInSSO,\n registerSSO,\n listSSOProviders,\n deleteSSOProvider,\n listDeviceSessions,\n revokeDeviceSession,\n setActiveSession,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"auth.mjs","names":[],"sources":["../../../src/libs/auth.ts"],"sourcesContent":["import { passkeyClient } from '@better-auth/passkey/client';\nimport { ssoClient } from '@better-auth/sso/client';\nimport { resolveInternalBackendUrl } from '@intlayer/api';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createAuthClient } from 'better-auth/client';\nimport {\n lastLoginMethodClient,\n magicLinkClient,\n multiSessionClient,\n twoFactorClient,\n} from 'better-auth/client/plugins';\n\n/**\n * better-auth performs its own fetches, bypassing `@intlayer/api`'s fetcher,\n * so the server-side `INTLAYER_BACKEND_INTERNAL_URL` override is applied here\n * to the base URL. In the browser the URL passes through unchanged.\n */\nconst getAuthClient = (backendURL: string) =>\n createAuthClient({\n baseURL: resolveInternalBackendUrl(backendURL, backendURL),\n withCredentials: true, // makes fetch forward cookies\n plugins: [\n twoFactorClient({\n onTwoFactorRedirect: () => {\n // Preserve redirect_url when redirecting to 2FA\n const searchParams = new URLSearchParams(window.location.search);\n const redirectUrl = searchParams.get('redirect_url');\n const twoFaUrl = redirectUrl\n ? `/auth/2fa?redirect_url=${encodeURIComponent(redirectUrl)}`\n : '/auth/2fa';\n window.location.href = twoFaUrl;\n },\n }),\n passkeyClient(),\n magicLinkClient() as never,\n ssoClient(),\n multiSessionClient(),\n lastLoginMethodClient(),\n ],\n });\n\ntype AuthClient = ReturnType<typeof getAuthClient>;\n\nexport interface AuthAPI {\n getAuthClient: () => AuthClient;\n signInEmail: AuthClient['signIn']['email'];\n signUpEmail: AuthClient['signUp']['email'];\n signOut: AuthClient['signOut'];\n signInSocial: AuthClient['signIn']['social'];\n linkSocial: AuthClient['linkSocial'];\n changePasswordSession: AuthClient['changePassword'];\n requestPasswordResetSession: AuthClient['requestPasswordReset'];\n resetPassword: AuthClient['resetPassword'];\n verifyEmailSession: AuthClient['verifyEmail'];\n getSession: AuthClient['getSession'];\n forgetPassword: AuthClient['requestPasswordReset'];\n sendVerificationEmail: AuthClient['sendVerificationEmail'];\n changeEmail: AuthClient['changeEmail'];\n deleteUser: AuthClient['deleteUser'];\n revokeSession: AuthClient['revokeSession'];\n revokeSessions: AuthClient['revokeSessions'];\n revokeOtherSessions: AuthClient['revokeOtherSessions'];\n listAccounts: AuthClient['listAccounts'];\n unlinkAccount: AuthClient['unlinkAccount'];\n refreshToken: AuthClient['refreshToken'];\n getAccessToken: AuthClient['getAccessToken'];\n accountInfo: AuthClient['accountInfo'];\n updateUser: AuthClient['updateUser'];\n listSessions: AuthClient['listSessions'];\n enableTwoFactor: AuthClient['twoFactor']['enable'];\n disableTwoFactor: AuthClient['twoFactor']['disable'];\n verifyTotp: AuthClient['twoFactor']['verifyTotp'];\n verifyBackupCode: AuthClient['twoFactor']['verifyBackupCode'];\n addPasskey: AuthClient['passkey']['addPasskey'];\n signInPasskey: AuthClient['signIn']['passkey'];\n deletePasskey: AuthClient['passkey']['deletePasskey'];\n listPasskeys: () => Promise<any>;\n signInMagicLink: (\n // Redeclare it because of type inference issues\n input: { email: string; callbackURL: string }\n ) => any;\n registerSSO: AuthClient['sso']['register'];\n listSSOProviders: () => Promise<any>;\n deleteSSOProvider: (args: { providerId: string }) => Promise<any>;\n signInSSO: AuthClient['signIn']['sso'];\n listDeviceSessions: AuthClient['multiSession']['listDeviceSessions'];\n setActiveSession: AuthClient['multiSession']['setActive'];\n revokeDeviceSession: AuthClient['multiSession']['revoke'];\n}\n\nexport const getAuthAPI = (\n intlayerConfig?: Pick<IntlayerConfig, 'editor'>\n): AuthAPI => {\n let backendURL = intlayerConfig?.editor?.backendURL ?? editor?.backendURL;\n\n if (!backendURL) {\n backendURL = BACKEND_URL;\n console.error('Backend URL is not defined in the Intlayer configuration.');\n }\n\n const client = getAuthClient(backendURL);\n\n const signInEmail: AuthClient['signIn']['email'] = async (...args) => {\n return client.signIn.email(...args);\n };\n\n const signInSocial: AuthClient['signIn']['social'] = async (...args) => {\n return client.signIn.social(...args);\n };\n\n const signUpEmail: AuthClient['signUp']['email'] = async (...args) => {\n return client.signUp.email(...args);\n };\n\n const signOut: AuthClient['signOut'] = async (...args) => {\n return client.signOut(...args);\n };\n\n const changePasswordSession: AuthClient['changePassword'] = async (\n ...args\n ) => {\n return client.changePassword(...args);\n };\n\n const requestPasswordResetSession: AuthClient['requestPasswordReset'] =\n async (...args) => {\n return client.requestPasswordReset(...args);\n };\n\n // @ts-ignore - resetPassword is not typed\n const resetPassword: AuthClient['resetPassword'] = async (...args) => {\n return client.resetPassword(...args);\n };\n\n const verifyEmailSession: AuthClient['verifyEmail'] = async (...args) => {\n return client.verifyEmail(...args);\n };\n\n const getSession: AuthClient['getSession'] = async (...args) => {\n return client.getSession(...args);\n };\n\n const forgetPassword: AuthClient['requestPasswordReset'] = async (\n ...args\n ) => {\n return client.requestPasswordReset(...args);\n };\n\n const sendVerificationEmail: AuthClient['sendVerificationEmail'] = async (\n ...args\n ) => {\n return client.sendVerificationEmail(...args);\n };\n\n const changeEmail: AuthClient['changeEmail'] = async (...args) => {\n return client.changeEmail(...args);\n };\n\n // @ts-ignore - deleteUser is not typed\n const deleteUser: AuthClient['deleteUser'] = async (...args) => {\n return client.deleteUser(...args);\n };\n\n const revokeSession: AuthClient['revokeSession'] = async (...args) => {\n return client.revokeSession(...args);\n };\n\n const revokeSessions: AuthClient['revokeSessions'] = async (...args) => {\n return client.revokeSessions(...args);\n };\n\n const revokeOtherSessions: AuthClient['revokeOtherSessions'] = async (\n ...args\n ) => {\n return client.revokeOtherSessions(...args);\n };\n\n const linkSocial: AuthClient['linkSocial'] = async (...args) => {\n return client.linkSocial(...args);\n };\n\n const listAccounts: AuthClient['listAccounts'] = async (...args) => {\n return client.listAccounts(...args);\n };\n\n const unlinkAccount: AuthClient['unlinkAccount'] = async (...args) => {\n return client.unlinkAccount(...args);\n };\n\n const refreshToken: AuthClient['refreshToken'] = async (...args) => {\n return client.refreshToken(...args);\n };\n\n const getAccessToken: AuthClient['getAccessToken'] = async (...args) => {\n return client.getAccessToken(...args);\n };\n\n const accountInfo: AuthClient['accountInfo'] = async (...args) => {\n return client.accountInfo(...args);\n };\n\n const updateUser: AuthClient['updateUser'] = async (...args) => {\n return client.updateUser(...args);\n };\n\n const listSessions: AuthClient['listSessions'] = async (...args) => {\n return client.listSessions(...args);\n };\n\n const enableTwoFactor: AuthClient['twoFactor']['enable'] = async (\n ...args\n ) => {\n return client.twoFactor.enable(...args) as ReturnType<\n AuthClient['twoFactor']['enable']\n >;\n };\n\n const disableTwoFactor: AuthClient['twoFactor']['disable'] = async (\n ...args\n ) => {\n return client.twoFactor.disable(...args) as ReturnType<\n AuthClient['twoFactor']['disable']\n >;\n };\n\n const verifyTotp: AuthClient['twoFactor']['verifyTotp'] = async (...args) => {\n return client.twoFactor.verifyTotp(...args) as ReturnType<\n AuthClient['twoFactor']['verifyTotp']\n >;\n };\n\n const verifyBackupCode: AuthClient['twoFactor']['verifyBackupCode'] = async (\n ...args\n ) => {\n return client.twoFactor.verifyBackupCode(...args) as ReturnType<\n AuthClient['twoFactor']['verifyBackupCode']\n >;\n };\n\n const addPasskey: AuthClient['passkey']['addPasskey'] = async (...args) => {\n return client.passkey.addPasskey(...args);\n };\n\n const signInPasskey: AuthClient['signIn']['passkey'] = async (...args) => {\n return client.signIn.passkey(...args);\n };\n\n const deletePasskey: AuthClient['passkey']['deletePasskey'] = async (\n ...args\n ) => {\n return client.passkey.deletePasskey(...args);\n };\n\n const listPasskeys = async () => {\n // @ts-ignore - listPasskeys may not be typed yet\n return client.$fetch('/passkey/list-user-passkeys', {\n method: 'GET',\n });\n };\n\n const signInMagicLink: any = async (...args: any[]) => {\n return (client.signIn as any).magicLink(...args);\n };\n\n const signInSSO: AuthClient['signIn']['sso'] = async (...args) => {\n return client.signIn.sso(...args);\n };\n\n const registerSSO: AuthClient['sso']['register'] = async (...args) => {\n return client.sso.register(...args);\n };\n\n const listSSOProviders = async () => {\n const response = await (client.sso as any).providers();\n return { data: response?.data?.providers ?? [] };\n };\n\n const deleteSSOProvider = async (args: { providerId: string }) => {\n return (client.sso as any).deleteProvider({ providerId: args.providerId });\n };\n\n const listDeviceSessions: AuthClient['multiSession']['listDeviceSessions'] =\n async (...args) => {\n return client.multiSession.listDeviceSessions(...args);\n };\n\n const setActiveSession: AuthClient['multiSession']['setActive'] = async (\n ...args\n ) => {\n return client.multiSession.setActive(...args);\n };\n\n const revokeDeviceSession: AuthClient['multiSession']['revoke'] = async (\n ...args\n ) => {\n return client.multiSession.revoke(...args);\n };\n\n return {\n getAuthClient: () => client,\n signInEmail,\n signUpEmail,\n signOut,\n signInSocial,\n linkSocial,\n changePasswordSession,\n requestPasswordResetSession,\n resetPassword,\n verifyEmailSession,\n getSession,\n forgetPassword,\n sendVerificationEmail,\n changeEmail,\n deleteUser,\n revokeSession,\n revokeSessions,\n revokeOtherSessions,\n listAccounts,\n unlinkAccount,\n refreshToken,\n getAccessToken,\n accountInfo,\n updateUser,\n listSessions,\n enableTwoFactor,\n disableTwoFactor,\n verifyTotp,\n verifyBackupCode,\n addPasskey,\n signInPasskey,\n deletePasskey,\n listPasskeys,\n signInMagicLink,\n signInSSO,\n registerSSO,\n listSSOProviders,\n deleteSSOProvider,\n listDeviceSessions,\n revokeDeviceSession,\n setActiveSession,\n };\n};\n"],"mappings":"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"}
@@ -81,7 +81,7 @@ const fallbackThemeContext = {
81
81
  * ```
82
82
  */
83
83
  const useTheme = () => useContext(ThemeContext) ?? fallbackThemeContext;
84
- const Theme = ({ storageKey = "theme", nonce, children }) => {
84
+ const Theme = ({ storageKey = "theme", nonce, hasBootstrapScript = true, children }) => {
85
85
  const [theme, setThemeState] = useState("system");
86
86
  const [systemTheme, setSystemTheme] = useState(void 0);
87
87
  const resolvedTheme = theme === "system" ? systemTheme : theme;
@@ -127,7 +127,7 @@ const Theme = ({ storageKey = "theme", nonce, children }) => {
127
127
  ]);
128
128
  return /* @__PURE__ */ jsxs(ThemeContext.Provider, {
129
129
  value,
130
- children: [/* @__PURE__ */ jsx("script", {
130
+ children: [hasBootstrapScript && /* @__PURE__ */ jsx("script", {
131
131
  suppressHydrationWarning: true,
132
132
  nonce: isServer ? nonce : "",
133
133
  dangerouslySetInnerHTML: { __html: buildBootstrap(storageKey) }
@@ -1 +1 @@
1
- {"version":3,"file":"ThemeProvider.mjs","names":[],"sources":["../../../src/providers/ThemeProvider.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n type FC,\n type PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from 'react';\n\n/** Theme actually painted — the OS preference once `system` is resolved. */\nexport type ResolvedTheme = 'light' | 'dark';\n\n/** Theme stored as the user preference. `system` follows the OS setting. */\nexport type Theme = ResolvedTheme | 'system';\n\n/** Attribute mirrored on `<html>`; the Tailwind dark variant keys on it. */\nconst THEME_ATTRIBUTE = 'data-theme';\n\n/** Media query resolving the OS colour scheme. */\nconst DARK_MEDIA_QUERY = '(prefers-color-scheme: dark)';\n\nconst isServer = typeof window === 'undefined';\n\n/**\n * Inline bootstrap applying the persisted theme before the first paint.\n *\n * Held as source text rather than serialized from a real function through\n * `Function.prototype.toString()`: that echoes whatever formatting the bundler\n * emitted, and the SSR and browser bundles do not agree on it (tabs versus\n * spaces), so the two renders produced different script bodies and hydration\n * failed. A string literal is copied verbatim by every bundler.\n *\n * It runs before hydration, so it must stay self-contained: no import, no\n * module-scope binding. Every value it needs is passed as an argument.\n */\nconst THEME_SCRIPT_SOURCE = `(function (storageKey, themeAttribute, darkMediaQuery) {\n var storedTheme = null;\n try {\n storedTheme = localStorage.getItem(storageKey);\n } catch (error) {\n /* Storage can throw (private mode, blocked cookies) — fall back to the OS. */\n }\n var theme =\n storedTheme === 'light' || storedTheme === 'dark'\n ? storedTheme\n : window.matchMedia(darkMediaQuery).matches\n ? 'dark'\n : 'light';\n var element = document.documentElement;\n element.setAttribute(themeAttribute, theme);\n element.style.colorScheme = theme;\n})`;\n\n/** Serializes the bootstrap and its arguments into inline script source. */\nconst buildBootstrap = (storageKey: string): string =>\n `${THEME_SCRIPT_SOURCE}(${JSON.stringify(storageKey)},${JSON.stringify(THEME_ATTRIBUTE)},${JSON.stringify(DARK_MEDIA_QUERY)})`;\n\n/** Reads the persisted preference, discarding unknown values. */\nconst getStoredTheme = (storageKey: string): Theme => {\n try {\n const storedTheme = localStorage.getItem(storageKey);\n\n if (\n storedTheme === 'light' ||\n storedTheme === 'dark' ||\n storedTheme === 'system'\n ) {\n return storedTheme;\n }\n } catch {\n // Storage can throw (private mode, blocked cookies).\n }\n\n return 'system';\n};\n\n/**\n * Suppresses CSS transitions while the theme attribute flips, so every themed\n * element repaints at once instead of animating between palettes.\n *\n * @returns Callback restoring transitions, to call once the theme is applied.\n */\nconst suppressTransitions = (nonce?: string): (() => void) => {\n const style = document.createElement('style');\n\n if (nonce) style.setAttribute('nonce', nonce);\n\n style.appendChild(\n document.createTextNode('*,*::before,*::after{transition:none!important}')\n );\n document.head.appendChild(style);\n\n return () => {\n // Reading a computed value forces a synchronous style recalculation, so\n // the new theme is committed while transitions are still suppressed.\n getComputedStyle(document.body).getPropertyValue('transition');\n style.remove();\n };\n};\n\nconst useIsomorphicLayoutEffect = isServer ? useEffect : useLayoutEffect;\n\ntype ThemeContextValue = {\n /** Persisted preference — `system` while following the OS. */\n theme: Theme;\n /** Theme applied to `<html>`. `undefined` until the client resolves it. */\n resolvedTheme: ResolvedTheme | undefined;\n /** Persists a preference and applies it. */\n setTheme: (theme: Theme) => void;\n};\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\n/** Served outside of a provider, so consumers render light instead of crashing. */\nconst fallbackThemeContext: ThemeContextValue = {\n theme: 'system',\n resolvedTheme: undefined,\n setTheme: () => undefined,\n};\n\n/**\n * Reads and updates the current theme.\n *\n * @example\n * ```tsx\n * const { resolvedTheme, setTheme } = useTheme();\n * ```\n */\nexport const useTheme = (): ThemeContextValue =>\n useContext(ThemeContext) ?? fallbackThemeContext;\n\nexport type ThemeProviderProps = {\n /** `localStorage` key holding the preference. Defaults to `theme`. */\n storageKey?: string;\n /** CSP nonce, required when the page forbids unsafe inline scripts. */\n nonce?: string;\n};\n\nconst Theme: FC<PropsWithChildren<ThemeProviderProps>> = ({\n storageKey = 'theme',\n nonce,\n children,\n}) => {\n // Both the server render and the first client one start from `system`, so\n // the hydrated markup matches; the browser state is read back before paint.\n const [theme, setThemeState] = useState<Theme>('system');\n const [systemTheme, setSystemTheme] = useState<ResolvedTheme | undefined>(\n undefined\n );\n\n const resolvedTheme = theme === 'system' ? systemTheme : theme;\n\n // Read the browser state back before the first paint, then keep following\n // the OS preference and the other tabs.\n useIsomorphicLayoutEffect(() => {\n const media = window.matchMedia(DARK_MEDIA_QUERY);\n\n setThemeState(getStoredTheme(storageKey));\n setSystemTheme(media.matches ? 'dark' : 'light');\n\n const handleSystemChange = (event: MediaQueryListEvent) =>\n setSystemTheme(event.matches ? 'dark' : 'light');\n\n const handleStorageChange = (event: StorageEvent) => {\n if (event.key !== storageKey) return;\n\n setThemeState(getStoredTheme(storageKey));\n };\n\n media.addEventListener('change', handleSystemChange);\n window.addEventListener('storage', handleStorageChange);\n\n return () => {\n media.removeEventListener('change', handleSystemChange);\n window.removeEventListener('storage', handleStorageChange);\n };\n }, [storageKey]);\n\n // Mirror the resolved theme onto `<html>`.\n useIsomorphicLayoutEffect(() => {\n if (!resolvedTheme) return;\n\n const element = document.documentElement;\n\n // The inline bootstrap already applied it on the initial load.\n if (element.getAttribute(THEME_ATTRIBUTE) === resolvedTheme) return;\n\n const restoreTransitions = suppressTransitions(nonce);\n\n element.setAttribute(THEME_ATTRIBUTE, resolvedTheme);\n element.style.colorScheme = resolvedTheme;\n\n restoreTransitions();\n }, [resolvedTheme, nonce]);\n\n const setTheme = useCallback(\n (nextTheme: Theme) => {\n setThemeState(nextTheme);\n\n try {\n localStorage.setItem(storageKey, nextTheme);\n } catch {\n // Storage can throw — the choice then only lasts for this page.\n }\n },\n [storageKey]\n );\n\n const value = useMemo<ThemeContextValue>(\n () => ({ theme, resolvedTheme, setTheme }),\n [theme, resolvedTheme, setTheme]\n );\n\n return (\n <ThemeContext.Provider value={value}>\n <script\n // Browsers hide the nonce value from the DOM API, so echoing it while\n // hydrating would mismatch the server markup — hence the suppression.\n // The script has already run by then; React never patches it.\n suppressHydrationWarning\n nonce={isServer ? nonce : ''}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: the bootstrap has to run before hydration, and its content is built from literals\n dangerouslySetInnerHTML={{ __html: buildBootstrap(storageKey) }}\n />\n {children}\n </ThemeContext.Provider>\n );\n};\n\n/**\n * Applies the persisted theme to `<html>` before the first paint, keeps it in\n * sync with the OS preference and with the other tabs, and exposes it through\n * {@link useTheme}.\n *\n * Nested providers pass through, so a layout can mount one without fighting an\n * outer provider over the `<html>` attribute.\n */\nexport const ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>> = ({\n children,\n ...props\n}) => {\n const parentTheme = useContext(ThemeContext);\n\n if (parentTheme) return <>{children}</>;\n\n return <Theme {...props}>{children}</Theme>;\n};\n"],"mappings":";;;;;;;AAqBA,MAAM,kBAAkB;;AAGxB,MAAM,mBAAmB;AAEzB,MAAM,WAAW,OAAO,WAAW;;;;;;;;;;;;;AAcnC,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;AAmB5B,MAAM,kBAAkB,eACtB,GAAG,oBAAoB,GAAG,KAAK,UAAU,UAAU,EAAE,GAAG,KAAK,UAAU,eAAe,EAAE,GAAG,KAAK,UAAU,gBAAgB,EAAE;;AAG9H,MAAM,kBAAkB,eAA8B;CACpD,IAAI;EACF,MAAM,cAAc,aAAa,QAAQ,UAAU;EAEnD,IACE,gBAAgB,WAChB,gBAAgB,UAChB,gBAAgB,UAEhB,OAAO;CAEX,QAAQ,CAER;CAEA,OAAO;AACT;;;;;;;AAQA,MAAM,uBAAuB,UAAiC;CAC5D,MAAM,QAAQ,SAAS,cAAc,OAAO;CAE5C,IAAI,OAAO,MAAM,aAAa,SAAS,KAAK;CAE5C,MAAM,YACJ,SAAS,eAAe,iDAAiD,CAC3E;CACA,SAAS,KAAK,YAAY,KAAK;CAE/B,aAAa;EAGX,iBAAiB,SAAS,IAAI,CAAC,CAAC,iBAAiB,YAAY;EAC7D,MAAM,OAAO;CACf;AACF;AAEA,MAAM,4BAA4B,WAAW,YAAY;AAWzD,MAAM,eAAe,cAA6C,MAAS;;AAG3E,MAAM,uBAA0C;CAC9C,OAAO;CACP,eAAe;CACf,gBAAgB;AAClB;;;;;;;;;AAUA,MAAa,iBACX,WAAW,YAAY,KAAK;AAS9B,MAAM,SAAoD,EACxD,aAAa,SACb,OACA,eACI;CAGJ,MAAM,CAAC,OAAO,iBAAiB,SAAgB,QAAQ;CACvD,MAAM,CAAC,aAAa,kBAAkB,SACpC,MACF;CAEA,MAAM,gBAAgB,UAAU,WAAW,cAAc;CAIzD,gCAAgC;EAC9B,MAAM,QAAQ,OAAO,WAAW,gBAAgB;EAEhD,cAAc,eAAe,UAAU,CAAC;EACxC,eAAe,MAAM,UAAU,SAAS,OAAO;EAE/C,MAAM,sBAAsB,UAC1B,eAAe,MAAM,UAAU,SAAS,OAAO;EAEjD,MAAM,uBAAuB,UAAwB;GACnD,IAAI,MAAM,QAAQ,YAAY;GAE9B,cAAc,eAAe,UAAU,CAAC;EAC1C;EAEA,MAAM,iBAAiB,UAAU,kBAAkB;EACnD,OAAO,iBAAiB,WAAW,mBAAmB;EAEtD,aAAa;GACX,MAAM,oBAAoB,UAAU,kBAAkB;GACtD,OAAO,oBAAoB,WAAW,mBAAmB;EAC3D;CACF,GAAG,CAAC,UAAU,CAAC;CAGf,gCAAgC;EAC9B,IAAI,CAAC,eAAe;EAEpB,MAAM,UAAU,SAAS;EAGzB,IAAI,QAAQ,aAAa,eAAe,MAAM,eAAe;EAE7D,MAAM,qBAAqB,oBAAoB,KAAK;EAEpD,QAAQ,aAAa,iBAAiB,aAAa;EACnD,QAAQ,MAAM,cAAc;EAE5B,mBAAmB;CACrB,GAAG,CAAC,eAAe,KAAK,CAAC;CAEzB,MAAM,WAAW,aACd,cAAqB;EACpB,cAAc,SAAS;EAEvB,IAAI;GACF,aAAa,QAAQ,YAAY,SAAS;EAC5C,QAAQ,CAER;CACF,GACA,CAAC,UAAU,CACb;CAEA,MAAM,QAAQ,eACL;EAAE;EAAO;EAAe;CAAS,IACxC;EAAC;EAAO;EAAe;CAAQ,CACjC;CAEA,OACE,qBAAC,aAAa,UAAd;EAA8B;YAA9B,CACE,oBAAC,UAAD;GAIE;GACA,OAAO,WAAW,QAAQ;GAE1B,yBAAyB,EAAE,QAAQ,eAAe,UAAU,EAAE;EAC/D,IACA,QACoB;;AAE3B;;;;;;;;;AAUA,MAAa,iBAA4D,EACvE,UACA,GAAG,YACC;CAGJ,IAFoB,WAAW,YAEjB,GAAG,OAAO,kCAAG,SAAW;CAEtC,OAAO,oBAAC,OAAD;EAAO,GAAI;EAAQ;CAAgB;AAC5C"}
1
+ {"version":3,"file":"ThemeProvider.mjs","names":[],"sources":["../../../src/providers/ThemeProvider.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n type FC,\n type PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from 'react';\n\n/** Theme actually painted — the OS preference once `system` is resolved. */\nexport type ResolvedTheme = 'light' | 'dark';\n\n/** Theme stored as the user preference. `system` follows the OS setting. */\nexport type Theme = ResolvedTheme | 'system';\n\n/** Attribute mirrored on `<html>`; the Tailwind dark variant keys on it. */\nconst THEME_ATTRIBUTE = 'data-theme';\n\n/** Media query resolving the OS colour scheme. */\nconst DARK_MEDIA_QUERY = '(prefers-color-scheme: dark)';\n\nconst isServer = typeof window === 'undefined';\n\n/**\n * Inline bootstrap applying the persisted theme before the first paint.\n *\n * Held as source text rather than serialized from a real function through\n * `Function.prototype.toString()`: that echoes whatever formatting the bundler\n * emitted, and the SSR and browser bundles do not agree on it (tabs versus\n * spaces), so the two renders produced different script bodies and hydration\n * failed. A string literal is copied verbatim by every bundler.\n *\n * It runs before hydration, so it must stay self-contained: no import, no\n * module-scope binding. Every value it needs is passed as an argument.\n */\nconst THEME_SCRIPT_SOURCE = `(function (storageKey, themeAttribute, darkMediaQuery) {\n var storedTheme = null;\n try {\n storedTheme = localStorage.getItem(storageKey);\n } catch (error) {\n /* Storage can throw (private mode, blocked cookies) — fall back to the OS. */\n }\n var theme =\n storedTheme === 'light' || storedTheme === 'dark'\n ? storedTheme\n : window.matchMedia(darkMediaQuery).matches\n ? 'dark'\n : 'light';\n var element = document.documentElement;\n element.setAttribute(themeAttribute, theme);\n element.style.colorScheme = theme;\n})`;\n\n/** Serializes the bootstrap and its arguments into inline script source. */\nconst buildBootstrap = (storageKey: string): string =>\n `${THEME_SCRIPT_SOURCE}(${JSON.stringify(storageKey)},${JSON.stringify(THEME_ATTRIBUTE)},${JSON.stringify(DARK_MEDIA_QUERY)})`;\n\n/** Reads the persisted preference, discarding unknown values. */\nconst getStoredTheme = (storageKey: string): Theme => {\n try {\n const storedTheme = localStorage.getItem(storageKey);\n\n if (\n storedTheme === 'light' ||\n storedTheme === 'dark' ||\n storedTheme === 'system'\n ) {\n return storedTheme;\n }\n } catch {\n // Storage can throw (private mode, blocked cookies).\n }\n\n return 'system';\n};\n\n/**\n * Suppresses CSS transitions while the theme attribute flips, so every themed\n * element repaints at once instead of animating between palettes.\n *\n * @returns Callback restoring transitions, to call once the theme is applied.\n */\nconst suppressTransitions = (nonce?: string): (() => void) => {\n const style = document.createElement('style');\n\n if (nonce) style.setAttribute('nonce', nonce);\n\n style.appendChild(\n document.createTextNode('*,*::before,*::after{transition:none!important}')\n );\n document.head.appendChild(style);\n\n return () => {\n // Reading a computed value forces a synchronous style recalculation, so\n // the new theme is committed while transitions are still suppressed.\n getComputedStyle(document.body).getPropertyValue('transition');\n style.remove();\n };\n};\n\nconst useIsomorphicLayoutEffect = isServer ? useEffect : useLayoutEffect;\n\ntype ThemeContextValue = {\n /** Persisted preference — `system` while following the OS. */\n theme: Theme;\n /** Theme applied to `<html>`. `undefined` until the client resolves it. */\n resolvedTheme: ResolvedTheme | undefined;\n /** Persists a preference and applies it. */\n setTheme: (theme: Theme) => void;\n};\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\n/** Served outside of a provider, so consumers render light instead of crashing. */\nconst fallbackThemeContext: ThemeContextValue = {\n theme: 'system',\n resolvedTheme: undefined,\n setTheme: () => undefined,\n};\n\n/**\n * Reads and updates the current theme.\n *\n * @example\n * ```tsx\n * const { resolvedTheme, setTheme } = useTheme();\n * ```\n */\nexport const useTheme = (): ThemeContextValue =>\n useContext(ThemeContext) ?? fallbackThemeContext;\n\nexport type ThemeProviderProps = {\n /** `localStorage` key holding the preference. Defaults to `theme`. */\n storageKey?: string;\n /** CSP nonce, required when the page forbids unsafe inline scripts. */\n nonce?: string;\n /**\n * Renders the inline bootstrap applying the theme before hydration.\n * Disable it on client-only pages whose CSP forbids inline scripts (browser\n * extensions): Preact executes client-created scripts, unlike React.\n * Defaults to `true`.\n */\n hasBootstrapScript?: boolean;\n};\n\nconst Theme: FC<PropsWithChildren<ThemeProviderProps>> = ({\n storageKey = 'theme',\n nonce,\n hasBootstrapScript = true,\n children,\n}) => {\n // Both the server render and the first client one start from `system`, so\n // the hydrated markup matches; the browser state is read back before paint.\n const [theme, setThemeState] = useState<Theme>('system');\n const [systemTheme, setSystemTheme] = useState<ResolvedTheme | undefined>(\n undefined\n );\n\n const resolvedTheme = theme === 'system' ? systemTheme : theme;\n\n // Read the browser state back before the first paint, then keep following\n // the OS preference and the other tabs.\n useIsomorphicLayoutEffect(() => {\n const media = window.matchMedia(DARK_MEDIA_QUERY);\n\n setThemeState(getStoredTheme(storageKey));\n setSystemTheme(media.matches ? 'dark' : 'light');\n\n const handleSystemChange = (event: MediaQueryListEvent) =>\n setSystemTheme(event.matches ? 'dark' : 'light');\n\n const handleStorageChange = (event: StorageEvent) => {\n if (event.key !== storageKey) return;\n\n setThemeState(getStoredTheme(storageKey));\n };\n\n media.addEventListener('change', handleSystemChange);\n window.addEventListener('storage', handleStorageChange);\n\n return () => {\n media.removeEventListener('change', handleSystemChange);\n window.removeEventListener('storage', handleStorageChange);\n };\n }, [storageKey]);\n\n // Mirror the resolved theme onto `<html>`.\n useIsomorphicLayoutEffect(() => {\n if (!resolvedTheme) return;\n\n const element = document.documentElement;\n\n // The inline bootstrap already applied it on the initial load.\n if (element.getAttribute(THEME_ATTRIBUTE) === resolvedTheme) return;\n\n const restoreTransitions = suppressTransitions(nonce);\n\n element.setAttribute(THEME_ATTRIBUTE, resolvedTheme);\n element.style.colorScheme = resolvedTheme;\n\n restoreTransitions();\n }, [resolvedTheme, nonce]);\n\n const setTheme = useCallback(\n (nextTheme: Theme) => {\n setThemeState(nextTheme);\n\n try {\n localStorage.setItem(storageKey, nextTheme);\n } catch {\n // Storage can throw — the choice then only lasts for this page.\n }\n },\n [storageKey]\n );\n\n const value = useMemo<ThemeContextValue>(\n () => ({ theme, resolvedTheme, setTheme }),\n [theme, resolvedTheme, setTheme]\n );\n\n return (\n <ThemeContext.Provider value={value}>\n {hasBootstrapScript && (\n <script\n // Browsers hide the nonce value from the DOM API, so echoing it while\n // hydrating would mismatch the server markup — hence the suppression.\n // The script has already run by then; React never patches it.\n suppressHydrationWarning\n nonce={isServer ? nonce : ''}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: the bootstrap has to run before hydration, and its content is built from literals\n dangerouslySetInnerHTML={{ __html: buildBootstrap(storageKey) }}\n />\n )}\n {children}\n </ThemeContext.Provider>\n );\n};\n\n/**\n * Applies the persisted theme to `<html>` before the first paint, keeps it in\n * sync with the OS preference and with the other tabs, and exposes it through\n * {@link useTheme}.\n *\n * Nested providers pass through, so a layout can mount one without fighting an\n * outer provider over the `<html>` attribute.\n */\nexport const ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>> = ({\n children,\n ...props\n}) => {\n const parentTheme = useContext(ThemeContext);\n\n if (parentTheme) return <>{children}</>;\n\n return <Theme {...props}>{children}</Theme>;\n};\n"],"mappings":"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"}