UNPKG

@ory/elements-react

Version:

Ory Elements React - a collection of React components for authentication UIs.

1,657 lines (1,649 loc) 3.89 MB
'use strict'; var clientFetch = require('@ory/client-fetch'); var react = require('react'); var jsxRuntime = require('react/jsx-runtime'); var reactIntl = require('react-intl'); var reactHookForm = require('react-hook-form'); var usehooksTs = require('usehooks-ts'); var sonner = require('sonner'); // src/context/component.tsx var defaultNodeOrder = [ "oidc", "saml", "identifier_first", "default", "profile", "password", "captcha", "passkey", "code", "webauthn" ]; var Slot = { Inputs: 0, Checkboxes: 1, Captcha: 2, Buttons: 3 }; function isUiNodeButton(node) { return clientFetch.isUiNodeInputAttributes(node.attributes) && (node.attributes.type === "submit" || node.attributes.type === "button"); } function makeUiNodeComparator({ groupOrder = defaultNodeOrder } = {}) { const groupRank = new Map(groupOrder.map((g, i) => [g, i])); const unknownGroupRank = groupOrder.length; const slotRank = (node) => { if (clientFetch.isUiNodeInputAttributes(node.attributes) === false) { return Slot.Inputs; } const { type } = node.attributes; if (node.group === "webauthn" && type !== "submit" && type !== "button") { return Slot.Buttons; } if (type === "checkbox") { return Slot.Checkboxes; } if (node.group === "captcha") { return Slot.Captcha; } if (type === "submit" || type === "button") { return Slot.Buttons; } return Slot.Inputs; }; return (a, b) => { var _a, _b; const sa = slotRank(a); const sb = slotRank(b); if (sa !== sb) { return sa - sb; } const ga = (_a = groupRank.get(a.group)) != null ? _a : unknownGroupRank; const gb = (_b = groupRank.get(b.group)) != null ? _b : unknownGroupRank; if (ga !== gb) { return ga - gb; } if (a.group === "webauthn" && b.group === "webauthn") { const aIsButton = isUiNodeButton(a); const bIsButton = isUiNodeButton(b); if (aIsButton !== bIsButton) { return aIsButton ? 1 : -1; } } return 0; }; } var defaultNodeSorter = makeUiNodeComparator({ groupOrder: defaultNodeOrder }); var ComponentContext = react.createContext({ components: null, // fine because we throw an error if it's not provided nodeSorter: () => 0, groupSorter: () => 0 }); function useComponents() { const ctx = react.useContext(ComponentContext); if (!ctx) { throw new Error("useComponents must be used within a ComponentProvider"); } return ctx.components; } function useNodeSorter() { const ctx = react.useContext(ComponentContext); if (!ctx) { throw new Error("useNodeSorter must be used within a ComponentProvider"); } return ctx.nodeSorter; } function useGroupSorter() { const ctx = react.useContext(ComponentContext); if (!ctx) { throw new Error("useGroupSorter must be used within a ComponentProvider"); } return ctx.groupSorter; } var defaultGroupOrder = [ clientFetch.UiNodeGroupEnum.Default, clientFetch.UiNodeGroupEnum.Profile, clientFetch.UiNodeGroupEnum.Password, clientFetch.UiNodeGroupEnum.Oidc, clientFetch.UiNodeGroupEnum.Code, clientFetch.UiNodeGroupEnum.LookupSecret, clientFetch.UiNodeGroupEnum.Passkey, clientFetch.UiNodeGroupEnum.Webauthn, clientFetch.UiNodeGroupEnum.Totp ]; function defaultGroupSorter(a, b) { var _a, _b; const aGroupWeight = (_a = defaultGroupOrder.indexOf(a)) != null ? _a : 999; const bGroupWeight = (_b = defaultGroupOrder.indexOf(b)) != null ? _b : 999; return aGroupWeight - bGroupWeight; } function OryComponentProvider({ children, components, nodeSorter = defaultNodeSorter, groupSorter = defaultGroupSorter }) { return /* @__PURE__ */ jsxRuntime.jsx( ComponentContext.Provider, { value: { components, nodeSorter, groupSorter }, children } ); } // src/theme/default/utils/form.ts function isGroupImmediateSubmit(group) { return group === "code"; } function triggerToWindowCall(trigger) { if (!trigger) { return; } const fn = triggerToFunction(trigger); if (fn) { fn(); return; } let i = 0; const ms = 100; const interval = setInterval(() => { i++; if (i > 100) { clearInterval(interval); throw new Error( "Unable to load Ory's WebAuthn script. Is it being blocked or otherwise failing to load? If you are running an old version of Ory Elements, please upgrade. For more information, please check your browser's developer console." ); } const fn2 = triggerToFunction(trigger); if (fn2) { clearInterval(interval); return fn2(); } }, ms); return; } function triggerToFunction(trigger) { if (typeof window === "undefined") { console.debug( "The Ory SDK is missing a required function: window is undefined." ); return void 0; } const typedWindow = window; if (!(trigger in typedWindow) || !typedWindow[trigger]) { console.debug(`The Ory SDK is missing a required function: ${trigger}.`); return void 0; } const triggerFn = typedWindow[trigger]; if (typeof triggerFn !== "function") { console.debug( `The Ory SDK is missing a required function: ${trigger}. It is not a function.` ); return void 0; } return triggerFn; } function nodesToAuthMethodGroups(nodes, excludeAuthMethods = []) { var _a; const groups = {}; for (const node of nodes) { if (node.type === "script") { continue; } const groupNodes = (_a = groups[node.group]) != null ? _a : []; groupNodes.push(node); groups[node.group] = groupNodes; } return Object.values(clientFetch.UiNodeGroupEnum).filter((group) => { var _a2; return (_a2 = groups[group]) == null ? void 0 : _a2.length; }).filter( (group) => ![ clientFetch.UiNodeGroupEnum.Default, clientFetch.UiNodeGroupEnum.IdentifierFirst, clientFetch.UiNodeGroupEnum.Profile, clientFetch.UiNodeGroupEnum.Captcha, ...excludeAuthMethods ].includes(group) ); } function useNodesGroups(nodes, { omit } = {}) { const groupSorter = useGroupSorter(); const groups = react.useMemo(() => { var _a, _b; const groups2 = {}; const groupRetained = {}; for (const node of nodes) { const groupNodes = (_a = groups2[node.group]) != null ? _a : []; groupNodes.push(node); groups2[node.group] = groupNodes; if ((omit == null ? void 0 : omit.includes("script")) && clientFetch.isUiNodeScriptAttributes(node.attributes)) { continue; } if ((omit == null ? void 0 : omit.includes("input_hidden")) && clientFetch.isUiNodeInputAttributes(node.attributes) && node.attributes.type === "hidden") { continue; } groupRetained[node.group] = ((_b = groupRetained[node.group]) != null ? _b : 0) + 1; } const finalGroups = {}; for (const [group, count] of Object.entries(groupRetained)) { if (count > 0) { finalGroups[group] = groups2[group]; } } return finalGroups; }, [nodes, omit]); const entries = react.useMemo( () => Object.entries(groups).sort(([a], [b]) => groupSorter(a, b)), [groups, groupSorter] ); return { groups, entries }; } var finder = (opt) => (n) => { return n.attributes.node_type === opt.node_type && (opt.group ? opt.group instanceof RegExp ? n.group.match(opt.group) : n.group === opt.group : !opt.group) && (opt.id && n.attributes.node_type !== "input" ? opt.id instanceof RegExp ? n.attributes.id.match(opt.id) : n.attributes.id === opt.id : !opt.id) && (opt.name && n.attributes.node_type === "input" ? opt.name instanceof RegExp ? n.attributes.name.match(opt.name) : n.attributes.name === opt.name : !opt.name) && (opt.type && n.attributes.node_type === "input" ? opt.type instanceof RegExp ? n.attributes.type.match(opt.type) : n.attributes.type === opt.type : !opt.type); }; var findNode = (nodes, opt) => nodes.find(finder(opt)); function useFunctionalNodes(nodes) { return nodes.filter( ({ group }) => [ clientFetch.UiNodeGroupEnum.Default, clientFetch.UiNodeGroupEnum.IdentifierFirst, clientFetch.UiNodeGroupEnum.Profile, clientFetch.UiNodeGroupEnum.Captcha ].includes(group) ); } function isUiNodeGroupEnum(method) { return Object.values(clientFetch.UiNodeGroupEnum).includes(method); } function isSingleSignOnNode(node) { return node.group === clientFetch.UiNodeGroupEnum.Oidc || node.group === clientFetch.UiNodeGroupEnum.Saml; } function hasSingleSignOnNodes(nodes) { return nodes.some(isSingleSignOnNode); } function withoutSingleSignOnNodes(nodes) { return nodes.filter((node) => !isSingleSignOnNode(node)); } function isNodeVisible(node) { if (clientFetch.isUiNodeScriptAttributes(node.attributes)) { return false; } else if (clientFetch.isUiNodeInputAttributes(node.attributes)) { if (node.attributes.type === "hidden") { return false; } } return true; } function useNodeGroupsWithVisibleNodes(nodes) { return react.useMemo(() => { var _a, _b; const groups = {}; const groupRetained = {}; for (const node of nodes) { const groupNodes = (_a = groups[node.group]) != null ? _a : []; const groupCount = (_b = groupRetained[node.group]) != null ? _b : 0; groupNodes.push(node); groups[node.group] = groupNodes; if (!isNodeVisible(node)) { continue; } groupRetained[node.group] = groupCount + 1; } const finalGroups = {}; for (const [group, count] of Object.entries(groupRetained)) { if (count > 0) { finalGroups[group] = groups[group]; } } return finalGroups; }, [nodes]); } function findCodeIdentifierNode(nodes) { var _a; return (_a = findNode(nodes, { group: "identifier_first", node_type: "input", name: "identifier" })) != null ? _a : findNode(nodes, { group: "code", node_type: "input", name: "address" }); } // src/components/card/two-step/utils.ts function isScreenSelectionNode(node) { if ("name" in node.attributes && node.attributes.name === "screen" && "value" in node.attributes && node.attributes.value === "previous") { return true; } if (node.group === clientFetch.UiNodeGroupEnum.IdentifierFirst && "name" in node.attributes && node.attributes.name === "identifier" && node.attributes.type === "hidden") { return true; } return false; } function isChoosingMethod(flow) { if (flow.flowType === clientFetch.FlowType.Login) { if (flow.flow.requested_aal === "aal2") { return true; } if (flow.flow.refresh && // TODO: Once https://github.com/ory/kratos/issues/4194 is fixed, this can be removed // Without this, we show the method chooser, and an email input, which looks weird !flow.flow.ui.nodes.some((n) => n.group === "code")) { return true; } } return flow.flow.ui.nodes.some(isScreenSelectionNode); } function getFinalNodes(uniqueGroups, selectedGroup) { var _a, _b, _c, _d; const selectedNodes = selectedGroup ? (_a = uniqueGroups[selectedGroup]) != null ? _a : [] : []; return [ ...(_b = uniqueGroups == null ? void 0 : uniqueGroups.identifier_first) != null ? _b : [], ...(_c = uniqueGroups == null ? void 0 : uniqueGroups.default) != null ? _c : [], ...(_d = uniqueGroups == null ? void 0 : uniqueGroups.captcha) != null ? _d : [] ].flat().filter( (node) => "type" in node.attributes && node.attributes.type === "hidden" ).concat(selectedNodes); } var handleAfterFormSubmit = (dispatchFormState) => (method) => { if (typeof method !== "string" || !isUiNodeGroupEnum(method)) { return; } if (isGroupImmediateSubmit(method)) { dispatchFormState({ type: "action_select_method", method }); } }; // src/context/form-state.ts function findMethodWithMessage(nodes) { var _a; return (_a = nodes == null ? void 0 : nodes.filter((n) => !["default", "identifier_first"].includes(n.group))) == null ? void 0 : _a.find((node) => { var _a2; return ((_a2 = node.messages) == null ? void 0 : _a2.length) > 0; }); } function parseStateFromFlow(flow) { var _a; switch (flow.flowType) { case clientFetch.FlowType.Registration: case clientFetch.FlowType.Login: { const methodWithMessage = findMethodWithMessage(flow.flow.ui.nodes); if (flow.flow.active == "link_recovery") { return { current: "method_active", method: "link" }; } else if (flow.flow.active == "code_recovery") { return { current: "method_active", method: "code" }; } else if (methodWithMessage) { return { current: "method_active", method: methodWithMessage.group }; } else if ((_a = flow.flow.ui.messages) == null ? void 0 : _a.some((m) => m.id === 1010016)) { return { current: "select_method" }; } else if (flow.flow.active && !["default", "identifier_first"].includes(flow.flow.active)) { return { current: "method_active", method: flow.flow.active }; } else if (isChoosingMethod(flow)) { const authMethods = nodesToAuthMethodGroups(flow.flow.ui.nodes); if (authMethods.length === 1 && !["code", "passkey"].includes(authMethods[0])) { return { current: "method_active", method: authMethods[0] }; } return { current: "select_method" }; } return { current: "provide_identifier" }; } case clientFetch.FlowType.Recovery: case clientFetch.FlowType.Verification: if (flow.flow.active === "code" || flow.flow.active === "link") { if (flow.flow.state === "choose_method") { return { current: "provide_identifier" }; } return { current: "method_active", method: flow.flow.active }; } break; case clientFetch.FlowType.Settings: return { current: "settings" }; case clientFetch.FlowType.OAuth2Consent: return { current: "method_active", method: "oauth2_consent" }; } console.warn( `[Ory/Elements React] Encountered an unknown form state on ${flow.flowType} flow with ID ${flow.flow.id}` ); throw new Error("Unknown form state"); } function useFormStateReducer(flow) { const action = parseStateFromFlow(flow); const [selectedMethod, setSelectedMethod] = react.useState(); const [isRedirecting, setRedirecting] = react.useState(false); const [loadingInputs, setLoadingInputs] = react.useState( /* @__PURE__ */ new Set() ); const formStateReducer = (state, action2) => { switch (action2.type) { case "action_flow_update": { if (selectedMethod) { setLoadingInputs(/* @__PURE__ */ new Set()); return { current: "method_active", method: selectedMethod, isReady: state.isReady, isSubmitting: state.isSubmitting }; } const flowFormState = parseStateFromFlow(action2.flow); return { ...flowFormState, isReady: state.isReady, isSubmitting: state.isSubmitting }; } case "action_select_method": { setSelectedMethod(action2.method); return { current: "method_active", method: action2.method, isReady: state.isReady, isSubmitting: state.isSubmitting }; } case "action_clear_active_method": { return { current: "select_method", isReady: state.isReady, isSubmitting: state.isSubmitting }; } case "form_input_loading": setLoadingInputs((prev) => new Set(prev).add(action2.group)); return { ...state, isReady: false, isSubmitting: state.isSubmitting }; case "form_input_ready": { const newLoadingInputs = new Set(loadingInputs); newLoadingInputs.delete(action2.input); setLoadingInputs(newLoadingInputs); return { ...state, isReady: newLoadingInputs.size === 0, isSubmitting: state.isSubmitting }; } case "form_submit_start": return { ...state, isSubmitting: true }; case "form_submit_end": return { ...state, // If we ever dispatched a page redirect, we want to keep the submitting state true // This is because the page will redirect/is redirecting to a potentially slow loading external page. isSubmitting: isRedirecting }; case "page_redirect": setRedirecting(true); return { ...state, isSubmitting: true }; } return state; }; return react.useReducer(formStateReducer, { ...action, isReady: true, isSubmitting: false }); } function useOryFlow() { const ctx = react.useContext(OryFlowContext); if (!ctx) { throw new Error("useOryFlow must be used within a OryFlowProvider"); } return ctx; } var OryFlowContext = react.createContext(null); function OryFlowProvider({ children, onSuccess, onValidationError, onError, transientPayload, ...container }) { const [flowContainer, setFlowContainer] = react.useState(container); const [formState, dispatchFormState] = useFormStateReducer(container); return /* @__PURE__ */ jsxRuntime.jsx( OryFlowContext.Provider, { value: { ...flowContainer, setFlowContainer: (flowContainer2) => { setFlowContainer(flowContainer2); dispatchFormState({ type: "action_flow_update", flow: flowContainer2 }); }, formState, dispatchFormState, onSuccess, onValidationError, onError, transientPayload }, children } ); } // src/client/config.ts function isProduction() { var _a, _b; return ["production", "prod"].indexOf( (_b = (_a = process.env.VERCEL_ENV) != null ? _a : process.env.NODE_ENV) != null ? _b : "" ) > -1; } function frontendClient(sdkUrl, opts = {}) { const config = new clientFetch.Configuration({ ...opts, basePath: sdkUrl, credentials: "include", headers: { Accept: "application/json", ...opts.headers } }); return new clientFetch.FrontendApi(config); } var defaultProject = { name: "Ory", registration_enabled: true, verification_enabled: true, recovery_enabled: true, recovery_ui_url: "/ui/recovery", registration_ui_url: "/ui/registration", verification_ui_url: "/ui/verification", login_ui_url: "/ui/login", settings_ui_url: "/ui/settings", default_redirect_url: "/ui/welcome", error_ui_url: "/ui/error", hide_ory_branding: false }; function useOryConfiguration() { const configCtx = react.useContext(OryConfigurationContext); return { sdk: { ...configCtx.sdk, frontend: frontendClient(configCtx.sdk.url, configCtx.sdk.options) }, project: { ...configCtx.project } }; } var OryConfigurationContext = react.createContext({ sdk: null, // This is fine, because we always supply a proper default value for the SDK configuration in the provider project: defaultProject }); function OryConfigurationProvider({ children, sdk: initialConfig, project }) { const configRef = react.useRef({ sdk: computeSdkConfig(initialConfig), project: { ...defaultProject, ...project } }); return /* @__PURE__ */ jsxRuntime.jsx(OryConfigurationContext.Provider, { value: configRef.current, children }); } function computeSdkConfig(config) { if ((config == null ? void 0 : config.url) && typeof config.url === "string") { return { url: config.url.replace(/\/$/, ""), options: config.options || {} }; } return { url: getSDKUrl(), options: (config == null ? void 0 : config.options) || {} }; } function getSDKUrl() { var _a; if (typeof process !== "undefined" && !!process.env) { if (isProduction()) { const sdkUrl = (_a = process.env["NEXT_PUBLIC_ORY_SDK_URL"]) != null ? _a : process.env["ORY_SDK_URL"]; if (!sdkUrl) { throw new Error( "Unable to determine SDK URL. Please set NEXT_PUBLIC_ORY_SDK_URL and/or ORY_SDK_URL in production environments." ); } return sdkUrl.replace(/\/$/, ""); } else { if (process.env["__NEXT_PRIVATE_ORIGIN"]) { return process.env["__NEXT_PRIVATE_ORIGIN"].replace(/\/$/, ""); } else if (process.env["VERCEL_URL"]) { return `https://${process.env["VERCEL_URL"]}`.replace(/\/$/, ""); } } } if (typeof window !== "undefined") { return window.location.origin; } throw new Error( "Unable to determine SDK URL. Please set NEXT_PUBLIC_ORY_SDK_URL and/or ORY_SDK_URL or supply the sdk.url parameter in the Ory configuration." ); } function mergeTranslations(locale, customTranslations) { return Object.keys(customTranslations).reduce((acc, key) => { var _a; return { ...acc, [key]: (_a = customTranslations[key]) != null ? _a : OryLocales[locale][key] }; }, OryLocales[locale]); } var IntlProvider = ({ children, locale, customTranslations }) => { var _a; const existingIntlContext = react.useContext(reactIntl.IntlContext); const messages = mergeTranslations(locale, (_a = customTranslations == null ? void 0 : customTranslations[locale]) != null ? _a : {}); if (existingIntlContext) { return children; } const cache = reactIntl.createIntlCache(); const intl = reactIntl.createIntl({ locale, messages }, cache); return /* @__PURE__ */ jsxRuntime.jsx(reactIntl.RawIntlProvider, { value: intl, children }); }; function OryProvider({ children, components: Components, config, onSuccess, onValidationError, onError, transientPayload, ...oryFlowProps }) { var _a, _b, _c; return /* @__PURE__ */ jsxRuntime.jsx(OryConfigurationProvider, { sdk: config.sdk, project: config.project, children: /* @__PURE__ */ jsxRuntime.jsx( IntlProvider, { locale: (_b = (_a = config.intl) == null ? void 0 : _a.locale) != null ? _b : "en", customTranslations: (_c = config.intl) == null ? void 0 : _c.customTranslations, children: /* @__PURE__ */ jsxRuntime.jsx( OryFlowProvider, { ...oryFlowProps, onSuccess, onValidationError, onError, transientPayload, children: /* @__PURE__ */ jsxRuntime.jsx(OryComponentProvider, { components: Components, children }) } ) } ) }); } function OryCardHeader() { const { Card } = useComponents(); return /* @__PURE__ */ jsxRuntime.jsx(Card.Header, {}); } function computeDefaultValues(flow) { const defaults = flow.ui.nodes.reduce((acc, node) => { var _a; const attrs = node.attributes; if (clientFetch.isUiNodeInputAttributes(attrs)) { if (attrs.type === "checkbox" && typeof attrs.value === "undefined") { attrs.value = false; } if (attrs.name === "method" || attrs.type === "submit") { return acc; } if (attrs.name.startsWith("grant_scope")) { const scope = attrs.value; if (Array.isArray(acc.grant_scope)) { return { ...acc, // We want to have all scopes accepted by default, so that the user has to actively uncheck them. grant_scope: [...acc.grant_scope, scope] }; } else if (!acc.grant_scope) { return { ...acc, grant_scope: [scope] }; } return acc; } return unrollTrait( { name: attrs.name, value: (_a = attrs.value) != null ? _a : "" }, acc ); } return acc; }, {}); if (flow.active) { defaults.method = flow.active; } return defaults; } function unrollTrait(input, output = {}) { const keys = input.name.split("."); let current = output; keys.forEach((key, index) => { if (!key) return; current = current[key] = index === keys.length - 1 ? input.value : current[key] || {}; }); return output; } function isCodeResendRequest(data) { var _a, _b; return (_b = (_a = data.email) != null ? _a : data.resend) != null ? _b : data.recovery_confirm_address; } function useOryFormResolver() { const flowContainer = useOryFlow(); return (data) => { if (flowContainer.formState.current === "method_active") { if ( // When we submit a code data.method === "code" && // And the code is not present !data.code && // And the flow is not a code resend request !isCodeResendRequest(data) && // And the flow has a code input node flowContainer.flow.ui.nodes.find(({ attributes, group }) => { if (!clientFetch.isUiNodeInputAttributes(attributes)) { return false; } return group === "code" && attributes.name === "code" && attributes.type !== "hidden"; }) ) { return { values: data, errors: { // We know the code node exists, so we can safely hardcode the ID. code: { id: 4000002, context: { property: "code" }, type: "error", text: "Property code is missing" } } }; } } return { values: data, errors: {} }; }; } // src/util/nodes.ts function isDynamicText(text) { return text.id === 1070002 && !!text.context && "name" in text.context && typeof text.context["name"] === "string"; } var KNOWN_KRATOS_MESSAGE_IDS = [ 1010001, 1010002, 1010003, 1010004, 1010005, 1010006, 1010007, 1010008, 1010009, 1010010, 1010011, 1010012, 1010013, 1010014, 1010015, 1010016, 1010017, 1010018, 1010019, 1010021, 1010022, 1010023, 1010024, 1010025, 1040001, 1040002, 1040003, 1040004, 1040005, 1040006, 1040007, 1040008, 1040009, 1050001, 1050002, 1050003, 1050004, 1050005, 1050006, 1050007, 1050008, 1050009, 1050010, 1050011, 1050012, 1050013, 1050014, 1050015, 1050016, 1050017, 1050018, 1050019, 1050020, 1060001, 1060002, 1060003, 1060004, 1060005, 1060006, 1060007, 1070001, 1070002, 1070003, 1070004, 1070005, 1070006, 1070007, 1070008, 1070009, 1070010, 1070011, 1070012, 1070013, 1070014, 1070015, 1070016, 1070017, 1070018, 1080001, 1080002, 1080003, 1080004, 1080005, 4000001, 4000002, 4000003, 4000004, 4000005, 4000006, 4000007, 4000008, 4000009, 4000010, 4000011, 4000012, 4000013, 4000014, 4000015, 4000016, 4000017, 4000018, 4000019, 4000020, 4000021, 4000022, 4000023, 4000024, 4000025, 4000026, 4000027, 4000028, 4000029, 4000030, 4000031, 4000032, 4000033, 4000034, 4000035, 4000036, 4000037, 4000038, 4000039, 4000040, 4000041, 4000042, 4000043, 4000044, 4010001, 4010002, 4010003, 4010004, 4010005, 4010006, 4010007, 4010008, 4010009, 4010010, 4010011, 4040001, 4040002, 4040003, 4050001, 4050002, 4060001, 4060002, 4060004, 4060005, 4060006, 4070001, 4070002, 4070003, 4070005, 4070006, 5000001, 5000002, 5000003 ]; function isKratosMessageId(id) { return typeof id === "number" && KNOWN_KRATOS_MESSAGE_IDS.includes(id); } var kratosMessages = reactIntl.defineMessages({ 1010001: { id: "identities.messages.1010001", defaultMessage: `Sign in` }, 1010002: { id: "identities.messages.1010002", defaultMessage: `Sign in with {provider}` }, 1010003: { id: "identities.messages.1010003", defaultMessage: `Please confirm this action by verifying that it is you.` }, 1010004: { id: "identities.messages.1010004", defaultMessage: `Please complete the second authentication challenge.` }, 1010005: { id: "identities.messages.1010005", defaultMessage: `Verify` }, 1010006: { id: "identities.messages.1010006", defaultMessage: `Authentication code` }, 1010007: { id: "identities.messages.1010007", defaultMessage: `Backup recovery code` }, 1010008: { id: "identities.messages.1010008", defaultMessage: `Continue with hardware key` }, 1010009: { id: "identities.messages.1010009", defaultMessage: `Continue` }, 1010010: { id: "identities.messages.1010010", defaultMessage: `Continue` }, 1010011: { id: "identities.messages.1010011", defaultMessage: `Sign in with a hardware key` }, 1010012: { id: "identities.messages.1010012", defaultMessage: `Prepare your WebAuthn device (e.g. security key, biometrics scanner, ...) and press continue.` }, 1010013: { id: "identities.messages.1010013", defaultMessage: `Continue` }, 1010014: { id: "identities.messages.1010014", defaultMessage: `A code was sent to the address you provided. If you didn't receive it, please check the spelling of the address and try again.` }, 1010015: { id: "identities.messages.1010015", defaultMessage: `Send sign in code` }, 1010016: { id: "identities.messages.1010016", defaultMessage: `You tried to sign in with "{duplicateIdentifier}", but that email is already used by another account. Sign in to your account with one of the options below to add your account "{duplicateIdentifier}" at "{provider}" as another way to sign in.` }, 1010017: { id: "identities.messages.1010017", defaultMessage: `Sign in and link` }, 1010018: { id: "identities.messages.1010018", defaultMessage: `Confirm with {provider}` }, 1010019: { id: "identities.messages.1010019", defaultMessage: `Request code to continue` }, 1010021: { id: "identities.messages.1010021", defaultMessage: `Sign in with passkey` }, 1010022: { id: "identities.messages.1010022", defaultMessage: `Sign in with password` }, 1010023: { id: "identities.messages.1010023", defaultMessage: `Send code to {address}` }, 1010024: { id: "identities.messages.1010024", defaultMessage: `Sign in with a hardware key` }, 1010025: { id: "identities.messages.1010025", defaultMessage: `A code was sent to your address. If you didn't receive it, please try again.` }, 1040001: { id: "identities.messages.1040001", defaultMessage: `Sign up` }, 1040002: { id: "identities.messages.1040002", defaultMessage: `Sign up with {provider}` }, 1040003: { id: "identities.messages.1040003", defaultMessage: `Continue` }, 1040004: { id: "identities.messages.1040004", defaultMessage: `Sign up with security key` }, 1040005: { id: "identities.messages.1040005", defaultMessage: `A code has been sent to the address(es) you provided. If you have not received a message, check the spelling of the address and retry the registration.` }, 1040006: { id: "identities.messages.1040006", defaultMessage: `Send sign up code` }, 1040007: { id: "identities.messages.1040007", defaultMessage: `Sign up with passkey` }, 1040008: { id: "identities.messages.1040008", defaultMessage: `Back` }, 1040009: { id: "identities.messages.1040009", defaultMessage: `Please choose a credential to authenticate yourself with.` }, 1050001: { id: "identities.messages.1050001", defaultMessage: `Your changes have been saved!` }, 1050002: { id: "identities.messages.1050002", defaultMessage: `Link {provider}` }, 1050003: { id: "identities.messages.1050003", defaultMessage: `Unlink {provider}` }, 1050004: { id: "identities.messages.1050004", defaultMessage: `Unlink TOTP Authenticator App` }, 1050005: { id: "identities.messages.1050005", defaultMessage: `Authenticator app QR code` }, 1050006: { id: "identities.messages.1050006", defaultMessage: `{secret}` }, 1050007: { id: "identities.messages.1050007", defaultMessage: `Reveal backup recovery codes` }, 1050008: { id: "identities.messages.1050008", defaultMessage: `Enable` }, 1050009: { id: "identities.messages.1050009", defaultMessage: `{secret}` }, 1050010: { id: "identities.messages.1050010", defaultMessage: `These are your back up recovery codes. Please keep them in a safe place!` }, 1050011: { id: "identities.messages.1050011", defaultMessage: `Confirm backup recovery codes` }, 1050012: { id: "identities.messages.1050012", defaultMessage: `Add security key` }, 1050013: { id: "identities.messages.1050013", defaultMessage: `Name of the security key` }, 1050014: { id: "identities.messages.1050014", defaultMessage: `Secret was used at {used_at, date, long}` }, 1050015: { id: "identities.messages.1050015", defaultMessage: `{secrets_list}` }, 1050016: { id: "identities.messages.1050016", defaultMessage: `Disable this method` }, 1050017: { id: "identities.messages.1050017", defaultMessage: `Authenticator Secret` }, 1050018: { id: "identities.messages.1050018", defaultMessage: `Remove security key "{display_name}"` }, 1050019: { id: "identities.messages.1050019", defaultMessage: `Add passkey` }, 1050020: { id: "identities.messages.1050020", defaultMessage: `Remove passkey "{display_name}"` }, 1060001: { id: "identities.messages.1060001", defaultMessage: `You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next {privileged_session_expires_at_unix_until_minutes} minutes.` }, 1060002: { id: "identities.messages.1060002", defaultMessage: `An email containing a recovery link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.` }, 1060003: { id: "identities.messages.1060003", defaultMessage: `An email containing a recovery code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.` }, 1060004: { id: "identities.messages.1060004", defaultMessage: `A recovery code has been sent to {masked_address}. If you have not received it, check the spelling of the address and make sure to use the address you registered with.` }, 1060005: { id: "identities.messages.1060005", defaultMessage: `Recover access to your account by providing your recovery address in full.` }, 1060006: { id: "identities.messages.1060006", defaultMessage: `How do you want to recover your account?` }, 1060007: { id: "identities.messages.1060007", defaultMessage: `Back` }, 1070001: { id: "identities.messages.1070001", defaultMessage: `Password` }, 1070002: { id: "identities.messages.1070002", defaultMessage: `{title}` }, 1070003: { id: "identities.messages.1070003", defaultMessage: `Save` }, 1070004: { id: "identities.messages.1070004", defaultMessage: `ID` }, 1070005: { id: "identities.messages.1070005", defaultMessage: `Submit` }, 1070006: { id: "identities.messages.1070006", defaultMessage: `Verify code` }, 1070007: { id: "identities.messages.1070007", defaultMessage: `Email` }, 1070008: { id: "identities.messages.1070008", defaultMessage: `Resend code` }, 1070009: { id: "identities.messages.1070009", defaultMessage: `Continue` }, 1070010: { id: "identities.messages.1070010", defaultMessage: `Recovery code` }, 1070011: { id: "identities.messages.1070011", defaultMessage: `Verification code` }, 1070012: { id: "identities.messages.1070012", defaultMessage: `Registration code` }, 1070013: { id: "identities.messages.1070013", defaultMessage: `Login code` }, 1070014: { id: "identities.messages.1070014", defaultMessage: `Login and link credential` }, 1070015: { id: "identities.messages.1070015", defaultMessage: `Please complete the captcha challenge to continue.` }, 1070016: { id: "identities.messages.1070016", defaultMessage: `Recovery address` }, 1070017: { id: "identities.messages.1070017", defaultMessage: `Phone number` }, 1070018: { id: "identities.messages.1070018", defaultMessage: `Email or phone number` }, 1080001: { id: "identities.messages.1080001", defaultMessage: `An email containing a verification link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.` }, 1080002: { id: "identities.messages.1080002", defaultMessage: `You successfully verified your email address.` }, 1080003: { id: "identities.messages.1080003", defaultMessage: `An email containing a verification code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.` }, 1080004: { id: "identities.messages.1080004", defaultMessage: `A text message containing a verification code has been sent to the phone number you provided. If you have not received a text message, check the spelling of the number and make sure to use the number you registered with.` }, 1080005: { id: "identities.messages.1080005", defaultMessage: `You successfully verified your phone number.` }, 4000001: { id: "identities.messages.4000001", defaultMessage: `{reason}` }, 4000002: { id: "identities.messages.4000002", defaultMessage: `Please enter the {property} and try again.` }, 4000003: { id: "identities.messages.4000003", defaultMessage: `length must be >= {min_length}, but got {actual_length}` }, 4000004: { id: "identities.messages.4000004", defaultMessage: `does not match pattern "{pattern}"` }, 4000005: { id: "identities.messages.4000005", defaultMessage: `The password can not be used because {reason}.` }, 4000006: { id: "identities.messages.4000006", defaultMessage: `The provided credentials are invalid, check for spelling mistakes in your password or username, email address, or phone number.` }, 4000007: { id: "identities.messages.4000007", defaultMessage: `An account with the same identifier (email, phone, username, ...) exists already.` }, 4000008: { id: "identities.messages.4000008", defaultMessage: `The provided authentication code is invalid, please try again.` }, 4000009: { id: "identities.messages.4000009", defaultMessage: `Could not find any login identifiers. Did you forget to set them? This could also be caused by a server misconfiguration.` }, 4000010: { id: "identities.messages.4000010", defaultMessage: `Account not active yet. Did you forget to verify your email address?` }, 4000011: { id: "identities.messages.4000011", defaultMessage: `You have no TOTP device set up.` }, 4000012: { id: "identities.messages.4000012", defaultMessage: `This backup recovery code has already been used.` }, 4000013: { id: "identities.messages.4000013", defaultMessage: `You have no WebAuthn device set up.` }, 4000014: { id: "identities.messages.4000014", defaultMessage: `You have no backup recovery codes set up.` }, 4000015: { id: "identities.messages.4000015", defaultMessage: `This account does not exist or has no security key set up.` }, 4000016: { id: "identities.messages.4000016", defaultMessage: `The backup recovery code is not valid.` }, 4000017: { id: "identities.messages.4000017", defaultMessage: `length must be <= {max_length}, but got {actual_length}` }, 4000018: { id: "identities.messages.4000018", defaultMessage: `must be >= {minimum} but found {actual}` }, 4000019: { id: "identities.messages.4000019", defaultMessage: `must be > {minimum} but found {actual}` }, 4000020: { id: "identities.messages.4000020", defaultMessage: `must be <= {maximum} but found {actual}` }, 4000021: { id: "identities.messages.4000021", defaultMessage: `must be < {maximum} but found {actual}` }, 4000022: { id: "identities.messages.4000022", defaultMessage: `{actual} not multipleOf {base}` }, 4000023: { id: "identities.messages.4000023", defaultMessage: `maximum {max_items} items allowed, but found {actual_items} items` }, 4000024: { id: "identities.messages.4000024", defaultMessage: `minimum {min_items} items allowed, but found {actual_items} items` }, 4000025: { id: "identities.messages.4000025", defaultMessage: `items at index {index_a} and {index_b} are equal` }, 4000026: { id: "identities.messages.4000026", defaultMessage: `expected {allowed_types_list}, but got {actual_type}` }, 4000027: { id: "identities.messages.4000027", defaultMessage: `An account with the same identifier (email, phone, username, ...) exists already. Please sign in to your existing account to link your social profile.` }, 4000028: { id: "identities.messages.4000028", defaultMessage: `You tried signing in with {credential_identifier_hint} which is already in use by another account. You can sign in using {available_credential_types_list}. You can sign in using one of the following social sign in providers: {available_oidc_providers_list}.` }, 4000029: { id: "identities.messages.4000029", defaultMessage: `must be equal to constant {expected}` }, 4000030: { id: "identities.messages.4000030", defaultMessage: `const failed` }, 4000031: { id: "identities.messages.4000031", defaultMessage: `The password can not be used because it is too similar to the identifier.` }, 4000032: { id: "identities.messages.4000032", defaultMessage: `The password must be at least {min_length} characters long, but got {actual_length}.` }, 4000033: { id: "identities.messages.4000033", defaultMessage: `The password must be at most {max_length} characters long, but got {actual_length}.` }, 4000034: { id: "identities.messages.4000034", defaultMessage: `The password has been found in data breaches and must no longer be used.` }, 4000035: { id: "identities.messages.4000035", defaultMessage: `This account does not exist or has not setup sign in with code.` }, 4000036: { id: "identities.messages.4000036", defaultMessage: `The provided traits do not match the traits previously associated with this flow.` }, 4000037: { id: "identities.messages.4000037", defaultMessage: `This account does not exist or has no login method configured.` }, 4000038: { id: "identities.messages.4000038", defaultMessage: `Captcha verification failed, please try again.` }, 4000039: { id: "identities.messages.4000039", defaultMessage: `The new password must be different from the old password.` }, 4000040: { id: "identities.messages.4000040", defaultMessage: `Enter a valid email address` }, 4000041: { id: "identities.messages.4000041", defaultMessage: `Enter a valid phone number` }, 4000042: { id: "identities.messages.4000042", defaultMessage: `You have no DeviceAuthn device set up.` }, 4000043: { id: "identities.messages.4000043", defaultMessage: `The provided web authn login is invalid, please try again.` }, 4000044: { id: "identities.messages.4000044", defaultMessage: `The provided DeviceAuthn signature is invalid.` }, 4010001: { id: "identities.messages.4010001", defaultMessage: `The interaction expired. Please try again.` }, 4010002: { id: "identities.messages.4010002", defaultMessage: `Could not find a strategy to log you in with. Did you fill out the form correctly?` }, 4010003: { id: "identities.messages.4010003", defaultMessage: `Could not find a strategy to sign you up with. Did you fill out the form correctly?` }, 4010004: { id: "identities.messages.4010004", defaultMessage: `Could not find a strategy to update your settings. Did you fill out the form correctly?` }, 4010005: { id: "identities.messages.4010005", defaultMessage: `Could not find a strategy to recover your account with. Did you fill out the form correctly?` }, 4010006: { id: "identities.messages.4010006", defaultMessage: `Could not find a strategy to verify your account with. Did you fill out the form correctly?` }, 4010007: { id: "identities.messages.4010007", defaultMessage: `The request was already completed successfully and can not be retried.` }, 4010008: { id: "identities.messages.4010008", defaultMessage: `The login code is invalid or has already been used. Please try again.` }, 4010009: { id: "identities.messages.4010009", defaultMessage: `Linked credentials do not match.` }, 4010010: { id: "identities.messages.4010010", defaultMessage: `The address you entered does not match any known addresses in the current account.` }, 4010011: { id: "identities.messages.4010011", defaultMessage: `This account has been disabled. Please contact support for assistance.` }, 4040001: { id: "identities.messages.4040001", defaultMessage: `The interaction expired. Please try again.` }, 4040002: { id: "identities.messages.4040002", defaultMessage: `The request was already completed successfully and can not be retried.` }, 4040003: { id: "identities.messages.4040003", defaultMessage: `The registration code is invalid or has already been used. Please try again.` }, 4050001: { id: "identities.messages.4050001", defaultMessage: `The interaction expired. Please try again.` }, 4050002: { id: "identities.messages.4050002", defaultMessage: `You can only change one address at a time. Please update each address separately.` }, 4060001: { id: "identities.messages.4060001", defaultMessage: `The request was already completed successfully and can not be retried.` }, 4060002: { id: "identities.messages.4060002", defaultMessage: `The recovery flow reached a failure state and must be retried.` }, 4060004: { id: "identities.messages.4060004", defaultMessage: `The recovery token is invalid or has already been used. Please retry the flow.` }, 4060005: { id: "identities.messages.4060005", defaultMessage: `The interaction expired. Please try again.` }, 4060006: { id: "identities.messages.4060006", defaultMessage: `The recovery code is invalid or has already been used. Please try again.` }, 4070001: { id: "identities.messages.4070001", defaultMessage: `The verification token is invalid or has already been used. Please retry the flow.` }, 4070002: { id: "identities.messages.4070002", defaultMessage: `The request was already completed successfully and can not be retried.` }, 4070003: { id: "identities.messages.4070003", defaultMessage: `The verification flow reached a failure state and must be retried.` }, 4070005: { id: "identities.messages.4070005", defaultMessage: `The interaction expired. Please try again.` }, 4070006: { id: "identities.messages.4070006", defaultMessage: `The verification code is invalid or has already been used. Please try again.` }, 5000001: { id: "identities.messages.5000001", defaultMessage: `{reason}` }, 5000002: { id: "identities.messages.5000002", defaultMessage: `No authentication methods are available. Please contact the system administrator.` }, 5000003: { id: "identities.messages.5000003", defaultMessage: `Your organization requires SSO authentication, but no SSO provider is configured. Please contact the system administrator.` } }); // src/util/i18n/index.ts var uiTextToFormattedMessage = ({ id, context = {}, text }, intl) => { const contextInjectedMessage = Object.entries(context).reduce( (accumulator, [key, value]) => { if (Array.isArray(value)) { return { ...accumulator, [key]: value, [key + "_list"]: intl.formatList(value) }; } else if (key.endsWith("_unix")) { if (typeof value === "number") { return { ...accumulator, [key]: intl.formatDate(new Date(value * 1e3)), [key + "_since"]: intl.formatDateTimeRange( new Date(value), /* @__PURE__ */ new Date() ), [key + "_since_minutes"]: Math.ceil( (value - (/* @__PURE__ */ new Date()).getTime() / 1e3) / 60 ).toFixed(0), [key + "_until"]: intl.formatDateTimeRange( /* @__PURE__ */ new Date(), new Date(value) ), [key + "_until_minutes"]: Math.ceil( (value - (/* @__PURE__ */ new Date()).getTime() / 1e3) / 60 ).toFixed(0) }; } } else if (key === "property") { if (isKnownPropertyKey(value)) { return { ...accumulator, [key]: intl.formatMessage(propertyMessages[value]) }; } else { return { ...accumulator, [key]: value }; } } return { ...accumulator, [key]: value }; }, {} ); if (isKratosMessageId(id)) { const hasEmptyArrayContext = Object.values(context).some( (v) => Array.isArray(v) && v.length === 0 ); if (hasEmptyArrayContext) { return text; } return intl.formatMessage(kratosMessages[id], contextInject