@thunderid/nextjs 1.0.8 → 1.1.0

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/ThunderIDNextClient.d.ts +16 -0
  2. package/dist/ThunderIDNextClient.d.ts.map +1 -1
  3. package/dist/ThunderIDNextClient.js +27 -1
  4. package/dist/ThunderIDNextClient.js.map +1 -1
  5. package/dist/cjs/ThunderIDNextClient.cjs +26 -0
  6. package/dist/cjs/ThunderIDNextClient.cjs.map +1 -1
  7. package/dist/cjs/client/components/presentation/ChangeCredential/ChangeCredential.cjs +104 -0
  8. package/dist/cjs/client/components/presentation/ChangeCredential/ChangeCredential.cjs.map +1 -0
  9. package/dist/cjs/client/components/presentation/UserDropdown/UserDropdown.cjs +8 -4
  10. package/dist/cjs/client/components/presentation/UserDropdown/UserDropdown.cjs.map +1 -1
  11. package/dist/cjs/client/contexts/ThunderID/ThunderIDProvider.cjs +1 -1
  12. package/dist/cjs/client/contexts/ThunderID/ThunderIDProvider.cjs.map +1 -1
  13. package/dist/cjs/client/index.cjs +1 -0
  14. package/dist/cjs/index.cjs +2 -0
  15. package/dist/cjs/server/actions/updateUserCredentialsAction.cjs +41 -0
  16. package/dist/cjs/server/actions/updateUserCredentialsAction.cjs.map +1 -0
  17. package/dist/client/components/presentation/ChangeCredential/ChangeCredential.d.ts +45 -0
  18. package/dist/client/components/presentation/ChangeCredential/ChangeCredential.d.ts.map +1 -0
  19. package/dist/client/components/presentation/ChangeCredential/ChangeCredential.js +99 -0
  20. package/dist/client/components/presentation/ChangeCredential/ChangeCredential.js.map +1 -0
  21. package/dist/client/components/presentation/UserDropdown/UserDropdown.d.ts +12 -0
  22. package/dist/client/components/presentation/UserDropdown/UserDropdown.d.ts.map +1 -1
  23. package/dist/client/components/presentation/UserDropdown/UserDropdown.js +8 -4
  24. package/dist/client/components/presentation/UserDropdown/UserDropdown.js.map +1 -1
  25. package/dist/client/contexts/ThunderID/ThunderIDProvider.d.ts.map +1 -1
  26. package/dist/client/contexts/ThunderID/ThunderIDProvider.js +2 -2
  27. package/dist/client/contexts/ThunderID/ThunderIDProvider.js.map +1 -1
  28. package/dist/client/index.d.ts +2 -0
  29. package/dist/client/index.d.ts.map +1 -1
  30. package/dist/client/index.js +1 -0
  31. package/dist/index.js +2 -1
  32. package/dist/server/actions/updateUserCredentialsAction.d.ts +16 -0
  33. package/dist/server/actions/updateUserCredentialsAction.d.ts.map +1 -0
  34. package/dist/server/actions/updateUserCredentialsAction.js +39 -0
  35. package/dist/server/actions/updateUserCredentialsAction.js.map +1 -0
  36. package/package.json +3 -3
@@ -16,8 +16,10 @@ const require_SignUp = require('./client/components/presentation/SignUp/SignUp.c
16
16
  const require_UserProfile = require('./client/components/presentation/UserProfile/UserProfile.cjs');
17
17
  const require_UserDropdown = require('./client/components/presentation/UserDropdown/UserDropdown.cjs');
18
18
  const require_UserAvatar = require('./client/components/presentation/UserAvatar/UserAvatar.cjs');
19
+ const require_ChangeCredential = require('./client/components/presentation/ChangeCredential/ChangeCredential.cjs');
19
20
  require('./client/index.cjs');
20
21
 
22
+ exports.ChangeCredential = require_ChangeCredential.default;
21
23
  exports.SignIn = require_SignIn.default;
22
24
  exports.SignInButton = require_SignInButton.default;
23
25
  exports.SignOutButton = require_SignOutButton.default;
@@ -0,0 +1,41 @@
1
+ 'use server';
2
+
3
+
4
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
5
+ const require_getClient = require('../getClient.cjs');
6
+ let __thunderid_node = require("@thunderid/node");
7
+ __thunderid_node = require_rolldown_runtime.__toESM(__thunderid_node);
8
+
9
+ //#region src/server/actions/updateUserCredentialsAction.ts
10
+ /**
11
+ * Server action to update one of the signed-in user's own credentials (e.g. `password`).
12
+ *
13
+ * Never throws across the server action boundary — a thrown class instance loses its
14
+ * prototype chain crossing it, so `error instanceof ThunderIDAPIError` would no longer hold on
15
+ * the client. Instead, the real error is mapped to a field/message here, server-side, while it
16
+ * is still the genuine `ThunderIDAPIError` the core `updateMeCredentials` call threw, and only
17
+ * the plain, serializable result crosses back.
18
+ */
19
+ const updateUserCredentialsAction = async (payload, sessionId) => {
20
+ try {
21
+ await require_getClient.default().updateUserCredentials(payload, sessionId);
22
+ return {
23
+ field: null,
24
+ messageKey: "",
25
+ success: true
26
+ };
27
+ } catch (error) {
28
+ const { field, message, messageKey } = (0, __thunderid_node.mapCredentialUpdateError)(error);
29
+ return {
30
+ field,
31
+ message,
32
+ messageKey,
33
+ success: false
34
+ };
35
+ }
36
+ };
37
+ var updateUserCredentialsAction_default = updateUserCredentialsAction;
38
+
39
+ //#endregion
40
+ exports.default = updateUserCredentialsAction_default;
41
+ //# sourceMappingURL=updateUserCredentialsAction.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateUserCredentialsAction.cjs","names":["getClient"],"sources":["../../../../src/server/actions/updateUserCredentialsAction.ts"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {CredentialUpdateErrorResult, mapCredentialUpdateError} from '@thunderid/node';\nimport getClient from '../getClient';\n\nexport interface UpdateUserCredentialsActionResult extends CredentialUpdateErrorResult {\n success: boolean;\n}\n\n/**\n * Server action to update one of the signed-in user's own credentials (e.g. `password`).\n *\n * Never throws across the server action boundary — a thrown class instance loses its\n * prototype chain crossing it, so `error instanceof ThunderIDAPIError` would no longer hold on\n * the client. Instead, the real error is mapped to a field/message here, server-side, while it\n * is still the genuine `ThunderIDAPIError` the core `updateMeCredentials` call threw, and only\n * the plain, serializable result crosses back.\n */\nconst updateUserCredentialsAction = async (\n payload: Record<string, string>,\n sessionId?: string,\n): Promise<UpdateUserCredentialsActionResult> => {\n try {\n const client = getClient();\n await client.updateUserCredentials(payload, sessionId);\n return {field: null, messageKey: '', success: true};\n } catch (error) {\n const {field, message, messageKey}: CredentialUpdateErrorResult = mapCredentialUpdateError(error);\n return {field, message, messageKey, success: false};\n }\n};\n\nexport default updateUserCredentialsAction;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAM,8BAA8B,OAClC,SACA,cAC+C;AAC/C,KAAI;AAEF,QADeA,2BAAW,CACb,sBAAsB,SAAS,UAAU;AACtD,SAAO;GAAC,OAAO;GAAM,YAAY;GAAI,SAAS;GAAK;UAC5C,OAAO;EACd,MAAM,EAAC,OAAO,SAAS,8DAAoE,MAAM;AACjG,SAAO;GAAC;GAAO;GAAS;GAAY,SAAS;GAAM;;;AAIvD,0CAAe"}
@@ -0,0 +1,45 @@
1
+ import { BaseChangeCredentialProps } from '@thunderid/react';
2
+ import { FC } from 'react';
3
+ /**
4
+ * Props for the ChangeCredential component.
5
+ * Mirrors `@thunderid/react`'s `ChangeCredentialProps` exactly, so a consumer moving between
6
+ * the React and Next.js SDKs doesn't need to change how they call it.
7
+ */
8
+ export type ChangeCredentialProps = Omit<BaseChangeCredentialProps, 'credentialDisplayName' | 'error' | 'fieldErrors' | 'loading' | 'onSubmit' | 'success'> & {
9
+ /**
10
+ * The credential attribute this instance manages, any attribute the user's entity type
11
+ * schema declares `credential: true` (for example `password` or `pin`). Defaults to
12
+ * `password`. Render the component once per credential to let a user manage more than one,
13
+ * for example `<ChangeCredential />` for the password and
14
+ * `<ChangeCredential attribute="pin" />` for a PIN.
15
+ */
16
+ attribute?: string;
17
+ /**
18
+ * Called after the credential has been changed successfully.
19
+ */
20
+ onSuccess?: () => void;
21
+ };
22
+ /**
23
+ * ChangeCredential lets the signed-in user set a new value for one of their own credentials.
24
+ *
25
+ * This is the Next.js-specific implementation: it uses `BaseChangeCredential` from
26
+ * `@thunderid/react` for rendering, but routes the write through
27
+ * `updateUserCredentialsAction` (a server action) instead of calling the ThunderID server
28
+ * directly from the browser, matching how `UserProfile` reaches `updateUserProfileAction`.
29
+ *
30
+ * Defaults to managing the `password` credential. To manage a different one (for example a
31
+ * PIN declared on the user type schema), set `attribute`; render the component once per
32
+ * credential to let a user manage several.
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * // Basic usage, manages the password
37
+ * <ChangeCredential onSuccess={() => toast('Password updated')} />
38
+ *
39
+ * // Managing a different credential declared on the schema
40
+ * <ChangeCredential attribute="pin" />
41
+ * ```
42
+ */
43
+ declare const ChangeCredential: FC<ChangeCredentialProps>;
44
+ export default ChangeCredential;
45
+ //# sourceMappingURL=ChangeCredential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChangeCredential.d.ts","sourceRoot":"","sources":["../../../../../src/client/components/presentation/ChangeCredential/ChangeCredential.tsx"],"names":[],"mappings":"AAMA,OAAO,EAEL,yBAAyB,EAI1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,EAAE,EAAkC,MAAM,OAAO,CAAC;AAa1D;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,yBAAyB,EACzB,uBAAuB,GAAG,OAAO,GAAG,aAAa,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CACvF,GAAG;IACF;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,QAAA,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CA4E/C,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,99 @@
1
+ 'use client';
2
+
3
+
4
+ import getSessionId_default from "../../../../server/actions/getSessionId.js";
5
+ import useThunderID_default from "../../../contexts/ThunderID/useThunderID.js";
6
+ import updateUserCredentialsAction_default from "../../../../server/actions/updateUserCredentialsAction.js";
7
+ import { CredentialConstants, resolveChangeCredentialPolicy, supportsCredential } from "@thunderid/node";
8
+ import { BaseChangeCredential, useTranslation, useUser } from "@thunderid/react";
9
+ import { useMemo, useState } from "react";
10
+ import { jsx } from "react/jsx-runtime";
11
+
12
+ //#region src/client/components/presentation/ChangeCredential/ChangeCredential.tsx
13
+ /**
14
+ * Title-cases a credential attribute name for use as a display-name fallback when the schema
15
+ * declares no `displayName` for it, e.g. `pin` -> `Pin`.
16
+ */
17
+ const defaultDisplayName = (attribute) => attribute.charAt(0).toUpperCase() + attribute.slice(1);
18
+ /**
19
+ * ChangeCredential lets the signed-in user set a new value for one of their own credentials.
20
+ *
21
+ * This is the Next.js-specific implementation: it uses `BaseChangeCredential` from
22
+ * `@thunderid/react` for rendering, but routes the write through
23
+ * `updateUserCredentialsAction` (a server action) instead of calling the ThunderID server
24
+ * directly from the browser, matching how `UserProfile` reaches `updateUserProfileAction`.
25
+ *
26
+ * Defaults to managing the `password` credential. To manage a different one (for example a
27
+ * PIN declared on the user type schema), set `attribute`; render the component once per
28
+ * credential to let a user manage several.
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * // Basic usage, manages the password
33
+ * <ChangeCredential onSuccess={() => toast('Password updated')} />
34
+ *
35
+ * // Managing a different credential declared on the schema
36
+ * <ChangeCredential attribute="pin" />
37
+ * ```
38
+ */
39
+ const ChangeCredential = ({ attribute = CredentialConstants.PASSWORD, onSuccess, policy, preferences,...rest }) => {
40
+ const { preferences: contextPreferences } = useThunderID_default();
41
+ const { userSchema } = useUser();
42
+ const resolvedDisplayName = userSchema?.[attribute]?.displayName ?? defaultDisplayName(attribute);
43
+ const resolvedPreferences = useMemo(() => ({
44
+ ...contextPreferences,
45
+ ...preferences,
46
+ user: {
47
+ ...contextPreferences?.user,
48
+ ...preferences?.user
49
+ }
50
+ }), [contextPreferences, preferences]);
51
+ const { t } = useTranslation(resolvedPreferences?.i18n);
52
+ const [error, setError] = useState(null);
53
+ const [fieldErrors, setFieldErrors] = useState({});
54
+ const [loading, setLoading] = useState(false);
55
+ const [success, setSuccess] = useState(false);
56
+ const resolvedPolicy = useMemo(() => resolveChangeCredentialPolicy(userSchema, attribute, policy), [
57
+ userSchema,
58
+ attribute,
59
+ policy
60
+ ]);
61
+ const handleSubmit = async ({ newPassword }) => {
62
+ setError(null);
63
+ setFieldErrors({});
64
+ setSuccess(false);
65
+ setLoading(true);
66
+ const result = await updateUserCredentialsAction_default({ [attribute]: newPassword }, await getSessionId_default());
67
+ if (result.success) {
68
+ setSuccess(true);
69
+ onSuccess?.();
70
+ } else {
71
+ const text = result.message ?? t(result.messageKey, {
72
+ credential: resolvedDisplayName,
73
+ credentialLower: resolvedDisplayName.toLowerCase()
74
+ });
75
+ if (result.field) setFieldErrors({ [result.field]: text });
76
+ else setError(text);
77
+ }
78
+ setLoading(false);
79
+ };
80
+ return /* @__PURE__ */ jsx(BaseChangeCredential, {
81
+ ...rest,
82
+ credentialDisplayName: resolvedDisplayName,
83
+ error,
84
+ fieldErrors,
85
+ loading,
86
+ policy: resolvedPolicy,
87
+ preferences: resolvedPreferences,
88
+ success,
89
+ unavailable: !supportsCredential(userSchema, attribute),
90
+ onSubmit: (values) => {
91
+ handleSubmit(values);
92
+ }
93
+ });
94
+ };
95
+ var ChangeCredential_default = ChangeCredential;
96
+
97
+ //#endregion
98
+ export { ChangeCredential_default as default };
99
+ //# sourceMappingURL=ChangeCredential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChangeCredential.js","names":["ChangeCredential: FC<ChangeCredentialProps>","useThunderID","resolvedDisplayName: string","resolvedPolicy: PasswordPolicy","result: UpdateUserCredentialsActionResult","updateUserCredentialsAction","getSessionId","text: string"],"sources":["../../../../../src/client/components/presentation/ChangeCredential/ChangeCredential.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use client';\n\nimport {CredentialConstants, PasswordPolicy, resolveChangeCredentialPolicy, supportsCredential} from '@thunderid/node';\nimport {\n BaseChangeCredential,\n BaseChangeCredentialProps,\n ChangePasswordValues,\n useTranslation,\n useUser,\n} from '@thunderid/react';\nimport {FC, ReactElement, useMemo, useState} from 'react';\nimport getSessionId from '../../../../server/actions/getSessionId';\nimport updateUserCredentialsAction, {\n UpdateUserCredentialsActionResult,\n} from '../../../../server/actions/updateUserCredentialsAction';\nimport useThunderID from '../../../contexts/ThunderID/useThunderID';\n\n/**\n * Title-cases a credential attribute name for use as a display-name fallback when the schema\n * declares no `displayName` for it, e.g. `pin` -> `Pin`.\n */\nconst defaultDisplayName = (attribute: string): string => attribute.charAt(0).toUpperCase() + attribute.slice(1);\n\n/**\n * Props for the ChangeCredential component.\n * Mirrors `@thunderid/react`'s `ChangeCredentialProps` exactly, so a consumer moving between\n * the React and Next.js SDKs doesn't need to change how they call it.\n */\nexport type ChangeCredentialProps = Omit<\n BaseChangeCredentialProps,\n 'credentialDisplayName' | 'error' | 'fieldErrors' | 'loading' | 'onSubmit' | 'success'\n> & {\n /**\n * The credential attribute this instance manages, any attribute the user's entity type\n * schema declares `credential: true` (for example `password` or `pin`). Defaults to\n * `password`. Render the component once per credential to let a user manage more than one,\n * for example `<ChangeCredential />` for the password and\n * `<ChangeCredential attribute=\"pin\" />` for a PIN.\n */\n attribute?: string;\n /**\n * Called after the credential has been changed successfully.\n */\n onSuccess?: () => void;\n};\n\n/**\n * ChangeCredential lets the signed-in user set a new value for one of their own credentials.\n *\n * This is the Next.js-specific implementation: it uses `BaseChangeCredential` from\n * `@thunderid/react` for rendering, but routes the write through\n * `updateUserCredentialsAction` (a server action) instead of calling the ThunderID server\n * directly from the browser, matching how `UserProfile` reaches `updateUserProfileAction`.\n *\n * Defaults to managing the `password` credential. To manage a different one (for example a\n * PIN declared on the user type schema), set `attribute`; render the component once per\n * credential to let a user manage several.\n *\n * @example\n * ```tsx\n * // Basic usage, manages the password\n * <ChangeCredential onSuccess={() => toast('Password updated')} />\n *\n * // Managing a different credential declared on the schema\n * <ChangeCredential attribute=\"pin\" />\n * ```\n */\nconst ChangeCredential: FC<ChangeCredentialProps> = ({\n attribute = CredentialConstants.PASSWORD,\n onSuccess,\n policy,\n preferences,\n ...rest\n}: ChangeCredentialProps): ReactElement => {\n const {preferences: contextPreferences} = useThunderID();\n const {userSchema} = useUser();\n const resolvedDisplayName: string = userSchema?.[attribute]?.displayName ?? defaultDisplayName(attribute);\n\n const resolvedPreferences = useMemo(\n () => ({\n ...contextPreferences,\n ...preferences,\n user: {...contextPreferences?.user, ...preferences?.user},\n }),\n [contextPreferences, preferences],\n );\n const {t} = useTranslation(resolvedPreferences?.i18n);\n\n const [error, setError] = useState<string | null>(null);\n const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});\n const [loading, setLoading] = useState<boolean>(false);\n const [success, setSuccess] = useState<boolean>(false);\n\n const resolvedPolicy: PasswordPolicy = useMemo(\n () => resolveChangeCredentialPolicy(userSchema, attribute, policy),\n [userSchema, attribute, policy],\n );\n\n const handleSubmit = async ({newPassword}: ChangePasswordValues): Promise<void> => {\n setError(null);\n setFieldErrors({});\n setSuccess(false);\n setLoading(true);\n\n const result: UpdateUserCredentialsActionResult = await updateUserCredentialsAction(\n {[attribute]: newPassword},\n await getSessionId(),\n );\n\n if (result.success) {\n setSuccess(true);\n onSuccess?.();\n } else {\n const text: string =\n result.message ??\n t(result.messageKey, {credential: resolvedDisplayName, credentialLower: resolvedDisplayName.toLowerCase()});\n\n if (result.field) {\n setFieldErrors({[result.field]: text});\n } else {\n setError(text);\n }\n }\n\n setLoading(false);\n };\n\n return (\n <BaseChangeCredential\n {...rest}\n credentialDisplayName={resolvedDisplayName}\n error={error}\n fieldErrors={fieldErrors}\n loading={loading}\n policy={resolvedPolicy}\n preferences={resolvedPreferences}\n success={success}\n unavailable={!supportsCredential(userSchema, attribute)}\n onSubmit={(values: ChangePasswordValues): void => {\n void handleSubmit(values);\n }}\n />\n );\n};\n\nexport default ChangeCredential;\n"],"mappings":";;;;;;;;;;;;;;;;AAwBA,MAAM,sBAAsB,cAA8B,UAAU,OAAO,EAAE,CAAC,aAAa,GAAG,UAAU,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;AA8ChH,MAAMA,oBAA+C,EACnD,YAAY,oBAAoB,UAChC,WACA,QACA,YACA,GAAG,WACsC;CACzC,MAAM,EAAC,aAAa,uBAAsBC,sBAAc;CACxD,MAAM,EAAC,eAAc,SAAS;CAC9B,MAAMC,sBAA8B,aAAa,YAAY,eAAe,mBAAmB,UAAU;CAEzG,MAAM,sBAAsB,eACnB;EACL,GAAG;EACH,GAAG;EACH,MAAM;GAAC,GAAG,oBAAoB;GAAM,GAAG,aAAa;GAAK;EAC1D,GACD,CAAC,oBAAoB,YAAY,CAClC;CACD,MAAM,EAAC,MAAK,eAAe,qBAAqB,KAAK;CAErD,MAAM,CAAC,OAAO,YAAY,SAAwB,KAAK;CACvD,MAAM,CAAC,aAAa,kBAAkB,SAAiC,EAAE,CAAC;CAC1E,MAAM,CAAC,SAAS,cAAc,SAAkB,MAAM;CACtD,MAAM,CAAC,SAAS,cAAc,SAAkB,MAAM;CAEtD,MAAMC,iBAAiC,cAC/B,8BAA8B,YAAY,WAAW,OAAO,EAClE;EAAC;EAAY;EAAW;EAAO,CAChC;CAED,MAAM,eAAe,OAAO,EAAC,kBAAsD;AACjF,WAAS,KAAK;AACd,iBAAe,EAAE,CAAC;AAClB,aAAW,MAAM;AACjB,aAAW,KAAK;EAEhB,MAAMC,SAA4C,MAAMC,oCACtD,GAAE,YAAY,aAAY,EAC1B,MAAMC,sBAAc,CACrB;AAED,MAAI,OAAO,SAAS;AAClB,cAAW,KAAK;AAChB,gBAAa;SACR;GACL,MAAMC,OACJ,OAAO,WACP,EAAE,OAAO,YAAY;IAAC,YAAY;IAAqB,iBAAiB,oBAAoB,aAAa;IAAC,CAAC;AAE7G,OAAI,OAAO,MACT,gBAAe,GAAE,OAAO,QAAQ,MAAK,CAAC;OAEtC,UAAS,KAAK;;AAIlB,aAAW,MAAM;;AAGnB,QACE,oBAAC;EACC,GAAI;EACJ,uBAAuB;EAChB;EACM;EACJ;EACT,QAAQ;EACR,aAAa;EACJ;EACT,aAAa,CAAC,mBAAmB,YAAY,UAAU;EACvD,WAAW,WAAuC;AAChD,GAAK,aAAa,OAAO;;GAE3B;;AAIN,+BAAe"}
@@ -27,6 +27,18 @@ export type UserDropdownProps = Omit<BaseUserDropdownProps, 'user' | 'onManagePr
27
27
  * When provided, this completely replaces the default dropdown rendering.
28
28
  */
29
29
  children?: (props: UserDropdownRenderProps) => ReactNode;
30
+ /**
31
+ * Called instead of opening the built-in "Manage Profile" popup when the "Manage Profile"
32
+ * menu item (see `manageProfileLabel`) is clicked. Use this when the app has its own
33
+ * profile/account page it wants to navigate to instead, for example with the router's
34
+ * `push()`.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <UserDropdown manageProfileLabel="Manage Account" onManageProfile={() => router.push('/account')} />
39
+ * ```
40
+ */
41
+ onManageProfile?: () => void;
30
42
  /**
31
43
  * Custom render function for the dropdown content.
32
44
  * When provided, this replaces just the dropdown content while keeping the trigger.
@@ -1 +1 @@
1
- {"version":3,"file":"UserDropdown.d.ts","sourceRoot":"","sources":["../../../../../src/client/components/presentation/UserDropdown/UserDropdown.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAmB,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAC,EAAE,EAAgB,SAAS,EAAW,MAAM,OAAO,CAAC;AAI5D;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,2CAA2C;IAC3C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,mDAAmD;IACnD,aAAa,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,oCAAoC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oCAAoC;IACpC,IAAI,EAAE,GAAG,CAAC;CACX;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,GAAG,iBAAiB,CAAC,GAAG;IACxF;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAC;IACzD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAC;IAC/D;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAC;CAC/D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,QAAA,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAiFvC,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"UserDropdown.d.ts","sourceRoot":"","sources":["../../../../../src/client/components/presentation/UserDropdown/UserDropdown.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAmB,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAC,EAAE,EAAgB,SAAS,EAAW,MAAM,OAAO,CAAC;AAI5D;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,2CAA2C;IAC3C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,mDAAmD;IACnD,aAAa,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,oCAAoC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oCAAoC;IACpC,IAAI,EAAE,GAAG,CAAC;CACX;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,GAAG,iBAAiB,CAAC,GAAG;IACxF;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAC;IACzD;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAC;IAC/D;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAC;CAC/D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,QAAA,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAwFvC,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -54,10 +54,14 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
54
54
  * />
55
55
  * ```
56
56
  */
57
- const UserDropdown = ({ children, renderTrigger, renderDropdown, onSignOut,...rest }) => {
57
+ const UserDropdown = ({ children, renderTrigger, renderDropdown, onManageProfile: onManageProfileOverride, onSignOut,...rest }) => {
58
58
  const { user, isLoading, signOut } = useThunderID_default();
59
59
  const [isProfileOpen, setIsProfileOpen] = useState(false);
60
60
  const handleManageProfile = () => {
61
+ if (onManageProfileOverride) {
62
+ onManageProfileOverride();
63
+ return;
64
+ }
61
65
  setIsProfileOpen(true);
62
66
  };
63
67
  const handleSignOut = () => {
@@ -75,7 +79,7 @@ const UserDropdown = ({ children, renderTrigger, renderDropdown, onSignOut,...re
75
79
  signOut: handleSignOut,
76
80
  user
77
81
  };
78
- if (children) return /* @__PURE__ */ jsxs(Fragment, { children: [children(renderProps), /* @__PURE__ */ jsx(UserProfile_default, {
82
+ if (children) return /* @__PURE__ */ jsxs(Fragment, { children: [children(renderProps), !onManageProfileOverride && /* @__PURE__ */ jsx(UserProfile_default, {
79
83
  mode: "popup",
80
84
  open: isProfileOpen,
81
85
  onOpenChange: setIsProfileOpen
@@ -86,7 +90,7 @@ const UserDropdown = ({ children, renderTrigger, renderDropdown, onSignOut,...re
86
90
  onManageProfile: handleManageProfile,
87
91
  onSignOut: handleSignOut,
88
92
  ...rest
89
- }), /* @__PURE__ */ jsx(UserProfile_default, {
93
+ }), !onManageProfileOverride && /* @__PURE__ */ jsx(UserProfile_default, {
90
94
  mode: "popup",
91
95
  open: isProfileOpen,
92
96
  onOpenChange: setIsProfileOpen
@@ -97,7 +101,7 @@ const UserDropdown = ({ children, renderTrigger, renderDropdown, onSignOut,...re
97
101
  onManageProfile: handleManageProfile,
98
102
  onSignOut: handleSignOut,
99
103
  ...rest
100
- }), isProfileOpen && /* @__PURE__ */ jsx(UserProfile_default, {
104
+ }), !onManageProfileOverride && isProfileOpen && /* @__PURE__ */ jsx(UserProfile_default, {
101
105
  mode: "popup",
102
106
  open: isProfileOpen,
103
107
  onOpenChange: setIsProfileOpen
@@ -1 +1 @@
1
- {"version":3,"file":"UserDropdown.js","names":["UserDropdown: FC<UserDropdownProps>","useThunderID","renderProps: UserDropdownRenderProps","UserProfile"],"sources":["../../../../../src/client/components/presentation/UserDropdown/UserDropdown.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use client';\n\nimport {BaseUserDropdown, BaseUserDropdownProps} from '@thunderid/react';\nimport {FC, ReactElement, ReactNode, useState} from 'react';\nimport useThunderID from '../../../contexts/ThunderID/useThunderID';\nimport UserProfile from '../UserProfile/UserProfile.js';\n\n/**\n * Render props data passed to the children function\n */\nexport interface UserDropdownRenderProps {\n /** Function to close the profile dialog */\n closeProfile: () => void;\n /** Whether user data is currently loading */\n isLoading: boolean;\n /** Whether the profile dialog is currently open */\n isProfileOpen: boolean;\n /** Function to open the user profile dialog */\n openProfile: () => void;\n /** Function to sign out the user */\n signOut: () => void;\n /** The authenticated user object */\n user: any;\n}\n\n/**\n * Props for the UserDropdown component.\n * Extends BaseUserDropdownProps but excludes user, onManageProfile, and onSignOut since they're handled internally\n */\nexport type UserDropdownProps = Omit<BaseUserDropdownProps, 'user' | 'onManageProfile'> & {\n /**\n * Render prop function that receives user state and actions.\n * When provided, this completely replaces the default dropdown rendering.\n */\n children?: (props: UserDropdownRenderProps) => ReactNode;\n /**\n * Custom render function for the dropdown content.\n * When provided, this replaces just the dropdown content while keeping the trigger.\n */\n renderDropdown?: (props: UserDropdownRenderProps) => ReactNode;\n /**\n * Custom render function for the trigger button.\n * When provided, this replaces just the trigger button while keeping the dropdown.\n */\n renderTrigger?: (props: UserDropdownRenderProps) => ReactNode;\n};\n\n/**\n * UserDropdown component displays a user avatar with a dropdown menu.\n * When clicked, it shows a popover with customizable menu items.\n * This component is the React-specific implementation that uses the BaseUserDropdown\n * and automatically retrieves the user data from ThunderID context.\n *\n * Supports render props for complete customization of the dropdown appearance and behavior.\n *\n * @example\n * ```tsx\n * // Basic usage - will use user from ThunderID context\n * <UserDropdown menuItems={[\n * { label: 'Profile', onClick: () => {} },\n * { label: 'Settings', href: '/settings' },\n * { label: 'Sign Out', onClick: () => {} }\n * ]} />\n *\n * // With custom configuration\n * <UserDropdown\n * showTriggerLabel={true}\n * avatarSize={40}\n * fallback={<div>Please sign in</div>}\n * />\n *\n * // Using render props for complete customization\n * <UserDropdown>\n * {({ user, isLoading, openProfile, signOut }) => (\n * <div>\n * <button onClick={openProfile}>\n * {user?.name || 'Loading...'}\n * </button>\n * <button onClick={signOut}>Logout</button>\n * </div>\n * )}\n * </UserDropdown>\n *\n * // Using partial render props\n * <UserDropdown\n * renderTrigger={({ user, openProfile }) => (\n * <button onClick={openProfile} className=\"custom-trigger\">\n * Welcome, {user?.name}!\n * </button>\n * )}\n * />\n * ```\n */\nconst UserDropdown: FC<UserDropdownProps> = ({\n children,\n renderTrigger,\n renderDropdown,\n onSignOut,\n ...rest\n}: UserDropdownProps): ReactElement => {\n const {user, isLoading, signOut} = useThunderID();\n const [isProfileOpen, setIsProfileOpen] = useState(false);\n\n const handleManageProfile = (): void => {\n setIsProfileOpen(true);\n };\n\n const handleSignOut = (): void => {\n signOut();\n if (onSignOut) {\n onSignOut();\n }\n };\n\n const closeProfile = (): void => {\n setIsProfileOpen(false);\n };\n\n // Prepare render props data\n const renderProps: UserDropdownRenderProps = {\n closeProfile,\n isLoading: isLoading!,\n isProfileOpen,\n openProfile: handleManageProfile,\n signOut: handleSignOut,\n user,\n };\n\n // If children render prop is provided, use it for complete customization\n if (children) {\n return (\n <>\n {children(renderProps)}\n <UserProfile mode=\"popup\" open={isProfileOpen} onOpenChange={setIsProfileOpen} />\n </>\n );\n }\n\n // If partial render props are provided, customize specific parts\n if (renderTrigger || renderDropdown) {\n // This would require significant changes to BaseUserDropdown to support partial customization\n // For now, we'll provide a simple implementation that shows how it could work\n return (\n <>\n {renderTrigger ? (\n renderTrigger(renderProps)\n ) : (\n <BaseUserDropdown\n user={user}\n isLoading={isLoading}\n onManageProfile={handleManageProfile}\n onSignOut={handleSignOut}\n {...rest}\n />\n )}\n {/* Note: renderDropdown would need BaseUserDropdown modifications to implement properly */}\n <UserProfile mode=\"popup\" open={isProfileOpen} onOpenChange={setIsProfileOpen} />\n </>\n );\n }\n\n // Default behavior - use BaseUserDropdown as before\n return (\n <>\n <BaseUserDropdown\n user={user}\n isLoading={isLoading}\n onManageProfile={handleManageProfile}\n onSignOut={handleSignOut}\n {...rest}\n />\n {isProfileOpen && <UserProfile mode=\"popup\" open={isProfileOpen} onOpenChange={setIsProfileOpen} />}\n </>\n );\n};\n\nexport default UserDropdown;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgGA,MAAMA,gBAAuC,EAC3C,UACA,eACA,gBACA,UACA,GAAG,WACkC;CACrC,MAAM,EAAC,MAAM,WAAW,YAAWC,sBAAc;CACjD,MAAM,CAAC,eAAe,oBAAoB,SAAS,MAAM;CAEzD,MAAM,4BAAkC;AACtC,mBAAiB,KAAK;;CAGxB,MAAM,sBAA4B;AAChC,WAAS;AACT,MAAI,UACF,YAAW;;CAIf,MAAM,qBAA2B;AAC/B,mBAAiB,MAAM;;CAIzB,MAAMC,cAAuC;EAC3C;EACW;EACX;EACA,aAAa;EACb,SAAS;EACT;EACD;AAGD,KAAI,SACF,QACE,4CACG,SAAS,YAAY,EACtB,oBAACC;EAAY,MAAK;EAAQ,MAAM;EAAe,cAAc;GAAoB,IAChF;AAKP,KAAI,iBAAiB,eAGnB,QACE,4CACG,gBACC,cAAc,YAAY,GAE1B,oBAAC;EACO;EACK;EACX,iBAAiB;EACjB,WAAW;EACX,GAAI;GACJ,EAGJ,oBAACA;EAAY,MAAK;EAAQ,MAAM;EAAe,cAAc;GAAoB,IAChF;AAKP,QACE,4CACE,oBAAC;EACO;EACK;EACX,iBAAiB;EACjB,WAAW;EACX,GAAI;GACJ,EACD,iBAAiB,oBAACA;EAAY,MAAK;EAAQ,MAAM;EAAe,cAAc;GAAoB,IAClG;;AAIP,2BAAe"}
1
+ {"version":3,"file":"UserDropdown.js","names":["UserDropdown: FC<UserDropdownProps>","useThunderID","renderProps: UserDropdownRenderProps","UserProfile"],"sources":["../../../../../src/client/components/presentation/UserDropdown/UserDropdown.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use client';\n\nimport {BaseUserDropdown, BaseUserDropdownProps} from '@thunderid/react';\nimport {FC, ReactElement, ReactNode, useState} from 'react';\nimport useThunderID from '../../../contexts/ThunderID/useThunderID';\nimport UserProfile from '../UserProfile/UserProfile.js';\n\n/**\n * Render props data passed to the children function\n */\nexport interface UserDropdownRenderProps {\n /** Function to close the profile dialog */\n closeProfile: () => void;\n /** Whether user data is currently loading */\n isLoading: boolean;\n /** Whether the profile dialog is currently open */\n isProfileOpen: boolean;\n /** Function to open the user profile dialog */\n openProfile: () => void;\n /** Function to sign out the user */\n signOut: () => void;\n /** The authenticated user object */\n user: any;\n}\n\n/**\n * Props for the UserDropdown component.\n * Extends BaseUserDropdownProps but excludes user, onManageProfile, and onSignOut since they're handled internally\n */\nexport type UserDropdownProps = Omit<BaseUserDropdownProps, 'user' | 'onManageProfile'> & {\n /**\n * Render prop function that receives user state and actions.\n * When provided, this completely replaces the default dropdown rendering.\n */\n children?: (props: UserDropdownRenderProps) => ReactNode;\n /**\n * Called instead of opening the built-in \"Manage Profile\" popup when the \"Manage Profile\"\n * menu item (see `manageProfileLabel`) is clicked. Use this when the app has its own\n * profile/account page it wants to navigate to instead, for example with the router's\n * `push()`.\n *\n * @example\n * ```tsx\n * <UserDropdown manageProfileLabel=\"Manage Account\" onManageProfile={() => router.push('/account')} />\n * ```\n */\n onManageProfile?: () => void;\n /**\n * Custom render function for the dropdown content.\n * When provided, this replaces just the dropdown content while keeping the trigger.\n */\n renderDropdown?: (props: UserDropdownRenderProps) => ReactNode;\n /**\n * Custom render function for the trigger button.\n * When provided, this replaces just the trigger button while keeping the dropdown.\n */\n renderTrigger?: (props: UserDropdownRenderProps) => ReactNode;\n};\n\n/**\n * UserDropdown component displays a user avatar with a dropdown menu.\n * When clicked, it shows a popover with customizable menu items.\n * This component is the React-specific implementation that uses the BaseUserDropdown\n * and automatically retrieves the user data from ThunderID context.\n *\n * Supports render props for complete customization of the dropdown appearance and behavior.\n *\n * @example\n * ```tsx\n * // Basic usage - will use user from ThunderID context\n * <UserDropdown menuItems={[\n * { label: 'Profile', onClick: () => {} },\n * { label: 'Settings', href: '/settings' },\n * { label: 'Sign Out', onClick: () => {} }\n * ]} />\n *\n * // With custom configuration\n * <UserDropdown\n * showTriggerLabel={true}\n * avatarSize={40}\n * fallback={<div>Please sign in</div>}\n * />\n *\n * // Using render props for complete customization\n * <UserDropdown>\n * {({ user, isLoading, openProfile, signOut }) => (\n * <div>\n * <button onClick={openProfile}>\n * {user?.name || 'Loading...'}\n * </button>\n * <button onClick={signOut}>Logout</button>\n * </div>\n * )}\n * </UserDropdown>\n *\n * // Using partial render props\n * <UserDropdown\n * renderTrigger={({ user, openProfile }) => (\n * <button onClick={openProfile} className=\"custom-trigger\">\n * Welcome, {user?.name}!\n * </button>\n * )}\n * />\n * ```\n */\nconst UserDropdown: FC<UserDropdownProps> = ({\n children,\n renderTrigger,\n renderDropdown,\n onManageProfile: onManageProfileOverride,\n onSignOut,\n ...rest\n}: UserDropdownProps): ReactElement => {\n const {user, isLoading, signOut} = useThunderID();\n const [isProfileOpen, setIsProfileOpen] = useState(false);\n\n const handleManageProfile = (): void => {\n if (onManageProfileOverride) {\n onManageProfileOverride();\n return;\n }\n setIsProfileOpen(true);\n };\n\n const handleSignOut = (): void => {\n signOut();\n if (onSignOut) {\n onSignOut();\n }\n };\n\n const closeProfile = (): void => {\n setIsProfileOpen(false);\n };\n\n // Prepare render props data\n const renderProps: UserDropdownRenderProps = {\n closeProfile,\n isLoading: isLoading!,\n isProfileOpen,\n openProfile: handleManageProfile,\n signOut: handleSignOut,\n user,\n };\n\n // If children render prop is provided, use it for complete customization\n if (children) {\n return (\n <>\n {children(renderProps)}\n {!onManageProfileOverride && <UserProfile mode=\"popup\" open={isProfileOpen} onOpenChange={setIsProfileOpen} />}\n </>\n );\n }\n\n // If partial render props are provided, customize specific parts\n if (renderTrigger || renderDropdown) {\n // This would require significant changes to BaseUserDropdown to support partial customization\n // For now, we'll provide a simple implementation that shows how it could work\n return (\n <>\n {renderTrigger ? (\n renderTrigger(renderProps)\n ) : (\n <BaseUserDropdown\n user={user}\n isLoading={isLoading}\n onManageProfile={handleManageProfile}\n onSignOut={handleSignOut}\n {...rest}\n />\n )}\n {/* Note: renderDropdown would need BaseUserDropdown modifications to implement properly */}\n {!onManageProfileOverride && <UserProfile mode=\"popup\" open={isProfileOpen} onOpenChange={setIsProfileOpen} />}\n </>\n );\n }\n\n // Default behavior - use BaseUserDropdown as before\n return (\n <>\n <BaseUserDropdown\n user={user}\n isLoading={isLoading}\n onManageProfile={handleManageProfile}\n onSignOut={handleSignOut}\n {...rest}\n />\n {!onManageProfileOverride && isProfileOpen && (\n <UserProfile mode=\"popup\" open={isProfileOpen} onOpenChange={setIsProfileOpen} />\n )}\n </>\n );\n};\n\nexport default UserDropdown;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4GA,MAAMA,gBAAuC,EAC3C,UACA,eACA,gBACA,iBAAiB,yBACjB,UACA,GAAG,WACkC;CACrC,MAAM,EAAC,MAAM,WAAW,YAAWC,sBAAc;CACjD,MAAM,CAAC,eAAe,oBAAoB,SAAS,MAAM;CAEzD,MAAM,4BAAkC;AACtC,MAAI,yBAAyB;AAC3B,4BAAyB;AACzB;;AAEF,mBAAiB,KAAK;;CAGxB,MAAM,sBAA4B;AAChC,WAAS;AACT,MAAI,UACF,YAAW;;CAIf,MAAM,qBAA2B;AAC/B,mBAAiB,MAAM;;CAIzB,MAAMC,cAAuC;EAC3C;EACW;EACX;EACA,aAAa;EACb,SAAS;EACT;EACD;AAGD,KAAI,SACF,QACE,4CACG,SAAS,YAAY,EACrB,CAAC,2BAA2B,oBAACC;EAAY,MAAK;EAAQ,MAAM;EAAe,cAAc;GAAoB,IAC7G;AAKP,KAAI,iBAAiB,eAGnB,QACE,4CACG,gBACC,cAAc,YAAY,GAE1B,oBAAC;EACO;EACK;EACX,iBAAiB;EACjB,WAAW;EACX,GAAI;GACJ,EAGH,CAAC,2BAA2B,oBAACA;EAAY,MAAK;EAAQ,MAAM;EAAe,cAAc;GAAoB,IAC7G;AAKP,QACE,4CACE,oBAAC;EACO;EACK;EACX,iBAAiB;EACjB,WAAW;EACX,GAAI;GACJ,EACD,CAAC,2BAA2B,iBAC3B,oBAACA;EAAY,MAAK;EAAQ,MAAM;EAAe,cAAc;GAAoB,IAElF;;AAIP,2BAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDProvider.d.ts","sourceRoot":"","sources":["../../../../src/client/contexts/ThunderID/ThunderIDProvider.tsx"],"names":[],"mappings":"AAKA,OAAO,EACL,eAAe,EAEf,oBAAoB,EAEpB,qBAAqB,EACrB,IAAI,EACJ,WAAW,EAGZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAQL,sBAAsB,EAEvB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAAkD,MAAM,OAAO,CAAC;AAC7F,OAAyB,EAAC,qBAAqB,EAAC,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAC,aAAa,EAAC,MAAM,sCAAsC,CAAC;AAGnE;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,SAAS,GAAG,UAAU,CAAC,CAAC,GACtG,IAAI,CAAC,sBAAsB,EAAE,SAAS,GAAG,UAAU,CAAC,GAAG;IACrD,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC;IACtD,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnG,mBAAmB,EAAE,CACnB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,KAClB,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAC,CAAC,CAAC;IACvE;;;OAGG;IACH,WAAW,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,qBAAqB,CAAC,oBAAoB,CAAC,CAAC;IAChE,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACxC,aAAa,EAAE,CACb,aAAa,EAAE,qBAAqB,EACpC,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC;QAAC,IAAI,EAAE;YAAC,IAAI,EAAE,IAAI,CAAA;SAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAC,CAAC,CAAC;IACpE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI,CAAC;CACrD,CAAC;AAEJ,QAAA,MAAM,uBAAuB,EAAE,EAAE,CAAC,iBAAiB,CAAC,4BAA4B,CAAC,CA6VhF,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ThunderIDProvider.d.ts","sourceRoot":"","sources":["../../../../src/client/contexts/ThunderID/ThunderIDProvider.tsx"],"names":[],"mappings":"AAKA,OAAO,EACL,eAAe,EAEf,oBAAoB,EAEpB,qBAAqB,EACrB,IAAI,EACJ,WAAW,EAGZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAQL,sBAAsB,EACvB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAAkD,MAAM,OAAO,CAAC;AAC7F,OAAyB,EAAC,qBAAqB,EAAC,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAC,aAAa,EAAC,MAAM,sCAAsC,CAAC;AAGnE;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,SAAS,GAAG,UAAU,CAAC,CAAC,GACtG,IAAI,CAAC,sBAAsB,EAAE,SAAS,GAAG,UAAU,CAAC,GAAG;IACrD,aAAa,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC;IACtD,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnG,mBAAmB,EAAE,CACnB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,KAClB,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAC,CAAC,CAAC;IACvE;;;OAGG;IACH,WAAW,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,qBAAqB,CAAC,oBAAoB,CAAC,CAAC;IAChE,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACxC,aAAa,EAAE,CACb,aAAa,EAAE,qBAAqB,EACpC,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC;QAAC,IAAI,EAAE;YAAC,IAAI,EAAE,IAAI,CAAA;SAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAC,CAAC,CAAC;IACpE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI,CAAC;CACrD,CAAC;AAEJ,QAAA,MAAM,uBAAuB,EAAE,EAAE,CAAC,iBAAiB,CAAC,4BAA4B,CAAC,CA6VhF,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -4,7 +4,7 @@
4
4
  import logger_default from "../../../utils/logger.js";
5
5
  import ThunderIDContext_default from "./ThunderIDContext.js";
6
6
  import { ThunderIDRuntimeError, generateFlattenedUserProfile, getVendorPrefix } from "@thunderid/node";
7
- import { FlowMetaProvider, FlowProvider, I18nProvider, ThemeProvider, ThunderIDContext, UserProvider, getActiveTheme } from "@thunderid/react";
7
+ import { FlowMetaProvider, FlowProvider, I18nProvider, ThemeProvider, ThunderIDContext, UserProvider } from "@thunderid/react";
8
8
  import { useRouter, useSearchParams } from "next/navigation";
9
9
  import { useEffect, useMemo, useRef, useState } from "react";
10
10
  import { jsx } from "react/jsx-runtime";
@@ -204,7 +204,7 @@ const ThunderIDClientProvider = ({ baseUrl, children, signIn, clearSession, refr
204
204
  fetchMeta,
205
205
  children: /* @__PURE__ */ jsx(ThemeProvider, {
206
206
  theme: preferences?.theme?.overrides,
207
- mode: getActiveTheme(preferences?.theme?.mode),
207
+ mode: preferences?.theme?.mode,
208
208
  children: /* @__PURE__ */ jsx(FlowProvider, { children: /* @__PURE__ */ jsx(UserProvider, {
209
209
  profile: userProfile,
210
210
  userSchema,
@@ -1 +1 @@
1
- {"version":3,"file":"ThunderIDProvider.js","names":["ThunderIDClientProvider: FC<PropsWithChildren<ThunderIDClientProviderProps>>","reRenderCheckRef: RefObject<boolean>","router: AppRouterInstance","searchParams: ReadonlyURLSearchParams","code: string | null","state: string | null","sessionState: string | null","result: {error?: string; redirectUrl?: string; success: boolean}","result: any","contextValue: ThunderIDContextProps","reactContextValue: ReactThunderIDContextProps","ThunderIDContext","ReactThunderIDContext"],"sources":["../../../../src/client/contexts/ThunderID/ThunderIDProvider.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use client';\n\nimport {\n AttributeSchema,\n EmbeddedFlowExecuteRequestConfig,\n FlowMetadataResponse,\n generateFlattenedUserProfile,\n UpdateMeProfileConfig,\n User,\n UserProfile,\n ThunderIDRuntimeError,\n getVendorPrefix,\n} from '@thunderid/node';\nimport {\n I18nProvider,\n FlowMetaProvider,\n FlowProvider,\n UserProvider,\n ThemeProvider,\n ThunderIDContext as ReactThunderIDContext,\n ThunderIDContextProps as ReactThunderIDContextProps,\n ThunderIDProviderProps,\n getActiveTheme,\n} from '@thunderid/react';\nimport {ReadonlyURLSearchParams} from 'next/dist/client/components/navigation.react-server';\nimport {AppRouterInstance} from 'next/dist/shared/lib/app-router-context.shared-runtime';\nimport {useRouter, useSearchParams} from 'next/navigation';\nimport {FC, PropsWithChildren, RefObject, useEffect, useMemo, useRef, useState} from 'react';\nimport ThunderIDContext, {ThunderIDContextProps} from './ThunderIDContext';\nimport {RefreshResult} from '../../../server/actions/refreshToken';\nimport logger from '../../../utils/logger';\n\n/**\n * Props interface of {@link ThunderIDClientProvider}\n */\nexport type ThunderIDClientProviderProps = Partial<Omit<ThunderIDProviderProps, 'baseUrl' | 'clientId'>> &\n Pick<ThunderIDProviderProps, 'baseUrl' | 'clientId'> & {\n applicationId: ThunderIDContextProps['applicationId'];\n clearSession: () => Promise<void>;\n /**\n * Server Action that fetches `GET /flow/meta` server-side, passed down to `FlowMetaProvider` so\n * it never calls `baseUrl` directly from the browser — avoiding the CORS requirement that a\n * direct client-side fetch to the ThunderID server would otherwise impose. Used for both the\n * initial fetch (when `initialMeta` isn't seeded, e.g. it failed server-side) and subsequent\n * `switchLanguage()` calls.\n */\n fetchMeta?: (params: {applicationId?: string; language?: string}) => Promise<FlowMetadataResponse>;\n handleOAuthCallback: (\n code: string,\n state: string,\n sessionState?: string,\n ) => Promise<{error?: string; redirectUrl?: string; success: boolean}>;\n /**\n * Flow metadata fetched server-side ahead of time, seeding `FlowMetaProvider` so it can skip\n * its own initial client-side fetch (avoiding a flash of untranslated i18n keys).\n */\n initialMeta?: FlowMetadataResponse | null;\n isSignedIn: boolean;\n organizationHandle: ThunderIDContextProps['organizationHandle'];\n refreshToken: () => Promise<RefreshResult>;\n signIn: ThunderIDContextProps['signIn'];\n signOut: ThunderIDContextProps['signOut'];\n signUp: ThunderIDContextProps['signUp'];\n updateProfile: (\n requestConfig: UpdateMeProfileConfig,\n sessionId?: string,\n ) => Promise<{data: {user: User}; error: string; success: boolean}>;\n user: User | null;\n userProfile: UserProfile;\n userSchema?: Record<string, AttributeSchema> | null;\n };\n\nconst ThunderIDClientProvider: FC<PropsWithChildren<ThunderIDClientProviderProps>> = ({\n baseUrl,\n children,\n signIn,\n clearSession,\n refreshToken,\n signOut,\n signUp,\n handleOAuthCallback,\n preferences,\n isSignedIn,\n signInUrl,\n signUpUrl,\n user: _user,\n userProfile: _userProfile,\n userSchema: _userSchema = null,\n updateProfile,\n applicationId,\n organizationHandle,\n scopes,\n vendor,\n initialMeta = null,\n fetchMeta,\n}: PropsWithChildren<ThunderIDClientProviderProps>) => {\n const reRenderCheckRef: RefObject<boolean> = useRef(false);\n const router: AppRouterInstance = useRouter();\n const searchParams: ReadonlyURLSearchParams = useSearchParams();\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [user, setUser] = useState<User | null>(_user);\n const [userProfile, setUserProfile] = useState<UserProfile>(_userProfile);\n const [userSchema, setUserSchema] = useState<Record<string, AttributeSchema> | null>(_userSchema);\n\n useEffect(() => {\n setUserProfile(_userProfile);\n }, [_userProfile]);\n\n useEffect(() => {\n setUserSchema(_userSchema);\n }, [_userSchema]);\n\n useEffect(() => {\n setUser(_user);\n }, [_user]);\n\n // Handle OAuth callback automatically\n useEffect(() => {\n // React 18.x Strict.Mode has a new check for `Ensuring reusable state` to facilitate an upcoming react feature.\n // https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state\n // This will remount all the useEffects to ensure that there are no unexpected side effects.\n // When react remounts the signIn hook of the AuthProvider, it will cause a race condition. Hence, we have to\n // prevent the re-render of this hook as suggested in the following discussion.\n // https://github.com/reactwg/react-18/discussions/18#discussioncomment-795623\n if (reRenderCheckRef.current) {\n return;\n }\n\n reRenderCheckRef.current = true;\n\n // Don't handle callback if already signed in\n if (isSignedIn) return;\n\n (async (): Promise<void> => {\n try {\n const code: string | null = searchParams.get('code');\n const state: string | null = searchParams.get('state');\n const sessionState: string | null = searchParams.get('session_state');\n const error: string | null = searchParams.get('error');\n\n // Check for OAuth errors first\n if (error) {\n logger.error('[ThunderIDClientProvider] An error was received for the initiated sign-in request.');\n\n return;\n }\n\n // Handle OAuth callback if code and state are present\n if (code && state) {\n setIsLoading(true);\n\n const result: {error?: string; redirectUrl?: string; success: boolean} = await handleOAuthCallback(\n code,\n state,\n sessionState || undefined,\n );\n\n if (result.success) {\n // Redirect to the success URL\n if (result.redirectUrl) {\n router.push(result.redirectUrl);\n } else {\n // Refresh the page to update authentication state\n window.location.reload();\n }\n } else {\n logger.error(\n `[ThunderIDClientProvider] An error occurred while signing in: ${result.error || 'Authentication failed'}`,\n );\n }\n }\n } catch (error) {\n logger.error('[ThunderIDClientProvider] Failed to handle OAuth callback:', error);\n }\n })();\n }, []);\n\n useEffect(() => {\n // Set loading to false when server has resolved authentication state\n setIsLoading(false);\n }, [isSignedIn, user]);\n\n const handleSignIn = async (payload: any, request: EmbeddedFlowExecuteRequestConfig): Promise<any> => {\n if (!signIn) {\n throw new ThunderIDRuntimeError(\n '`signIn` function is not available.',\n 'ThunderIDClientProvider-handleSignIn-RuntimeError-001',\n 'nextjs',\n );\n }\n\n const result: any = await signIn(payload, request);\n\n // Redirect based flow URL is sent as `signInUrl` in the response.\n // Use window.location.href instead of router.push() — the OAuth authorization\n // endpoint is on an external server, and router.push() would send RSC fetch\n // headers that the identity provider doesn't understand, causing a CORS error.\n if (result?.data?.signInUrl) {\n window.location.href = result.data.signInUrl;\n\n return undefined;\n }\n\n // After the Embedded flow is successful, the URL to navigate next is sent as `afterSignInUrl` in the response.\n if (result?.data?.afterSignInUrl) {\n router.push(result.data.afterSignInUrl);\n\n return undefined;\n }\n\n if (result?.error) {\n throw new Error(result.error);\n }\n\n return result?.data ?? result;\n };\n\n const handleSignUp = async (payload: any, request: EmbeddedFlowExecuteRequestConfig): Promise<any> => {\n if (!signUp) {\n throw new ThunderIDRuntimeError(\n '`signUp` function is not available.',\n 'ThunderIDClientProvider-handleSignUp-RuntimeError-001',\n 'nextjs',\n );\n }\n\n const result: any = await signUp(payload, request);\n\n // Redirect based flow URL is sent as `signUpUrl` in the response.\n if (result?.data?.signUpUrl) {\n router.push(result.data.signUpUrl);\n\n return undefined;\n }\n\n // After the Embedded flow is successful, the URL to navigate next is sent as `afterSignUpUrl` in the response.\n if (result?.data?.afterSignUpUrl) {\n router.push(result.data.afterSignUpUrl);\n\n return undefined;\n }\n\n if (result?.error) {\n throw new Error(result.error);\n }\n\n return result?.data ?? result;\n };\n\n const handleSignOut = async (): Promise<any> => {\n logger.debug('[ThunderIDClientProvider][handleSignOut] `handleSignOut` called.');\n\n try {\n const result: any = await signOut();\n\n logger.debug('[ThunderIDClientProvider][handleSignOut] Sign out result:', result);\n\n if (result?.data?.afterSignOutUrl) {\n router.push(result.data.afterSignOutUrl);\n\n return {location: result.data.afterSignOutUrl, redirected: true};\n }\n\n if (result?.error) {\n logger.error(\n '[ThunderIDClientProvider][handleSignOut] Error result was returned during signing the user out with a button click:',\n result.error,\n );\n }\n\n return result?.data ?? result;\n } catch (error) {\n logger.error(\n '[ThunderIDClientProvider][handleSignOut] Error occurred during signing the user out with a button click:',\n error,\n );\n\n return undefined;\n }\n };\n\n const contextValue: ThunderIDContextProps = useMemo(\n () => ({\n applicationId,\n baseUrl,\n clearSession,\n isLoading,\n isSignedIn,\n organizationHandle,\n preferences,\n refreshToken,\n scopes,\n signIn: handleSignIn,\n signInUrl,\n signOut: handleSignOut,\n signUp: handleSignUp,\n signUpUrl,\n user,\n }),\n [\n baseUrl,\n user,\n isSignedIn,\n isLoading,\n signInUrl,\n signUpUrl,\n applicationId,\n organizationHandle,\n scopes,\n preferences,\n ],\n );\n\n const handleProfileUpdate = (payload: User): void => {\n setUser(payload);\n setUserProfile((prev: UserProfile) => ({\n ...prev,\n flattenedProfile: generateFlattenedUserProfile(payload),\n profile: payload,\n }));\n };\n\n // Bridge into @thunderid/react's own ThunderIDContext. Internal react components rendered by\n // BaseSignIn/BaseSignUp — most notably FlowMetaProvider, which fetches `/flow/meta` and injects\n // its i18n bundle — call react's `useThunderID()` directly. Without this bridge they'd only see\n // react's context default (applicationId/baseUrl undefined, isInitialized false), so the meta\n // fetch would never fire and flow labels would render as untranslated i18n keys. Fields with no\n // nextjs equivalent (token/http helpers meant for direct browser API calls) are stubbed out,\n // since nextjs routes those operations through server actions instead.\n const unsupported = (name: string): (() => Promise<never>) => {\n return () =>\n Promise.reject(\n new ThunderIDRuntimeError(\n `\\`${name}\\` is not supported in @thunderid/nextjs.`,\n `ThunderIDClientProvider-${name}-NotSupportedError-001`,\n 'nextjs',\n ),\n );\n };\n\n const reactContextValue: ReactThunderIDContextProps = useMemo(\n () => ({\n afterSignInUrl: undefined,\n applicationId,\n baseUrl,\n clearSession,\n clientId: undefined,\n discovery: {wellKnown: null},\n exchangeToken: unsupported('exchangeToken'),\n getAccessToken: unsupported('getAccessToken'),\n getDecodedIdToken: unsupported('getDecodedIdToken'),\n getIdToken: unsupported('getIdToken'),\n getStorageManager: () => Promise.resolve(null),\n http: {\n request: unsupported('http.request'),\n requestAll: unsupported('http.requestAll'),\n },\n instanceId: 0,\n isInitialized: !isLoading,\n isLoading,\n isMetaLoading: false,\n isSignedIn,\n meta: initialMeta ?? null,\n organizationHandle,\n reInitialize: unsupported('reInitialize'),\n recover: unsupported('recover'),\n resolveFlowTemplateLiterals: (text: string | undefined): string => text ?? '',\n scopes,\n signIn: handleSignIn,\n signInSilently: unsupported('signInSilently'),\n signInUrl,\n signOut: handleSignOut,\n signUp: handleSignUp,\n signUpUrl,\n user,\n userSchema,\n vendor: getVendorPrefix(vendor),\n }),\n [\n applicationId,\n baseUrl,\n clearSession,\n isLoading,\n isSignedIn,\n organizationHandle,\n scopes,\n signInUrl,\n signUpUrl,\n user,\n userSchema,\n initialMeta,\n vendor,\n ],\n );\n\n return (\n <ThunderIDContext.Provider value={contextValue}>\n <ReactThunderIDContext.Provider value={reactContextValue}>\n <I18nProvider preferences={preferences?.i18n}>\n <FlowMetaProvider\n enabled={preferences?.resolveFromMeta !== false}\n initialMeta={initialMeta}\n fetchMeta={fetchMeta}\n >\n <ThemeProvider theme={preferences?.theme?.overrides} mode={getActiveTheme(preferences?.theme?.mode as any)}>\n <FlowProvider>\n <UserProvider\n profile={userProfile}\n userSchema={userSchema}\n onUpdateProfile={handleProfileUpdate}\n updateProfile={updateProfile}\n >\n {children}\n </UserProvider>\n </FlowProvider>\n </ThemeProvider>\n </FlowMetaProvider>\n </I18nProvider>\n </ReactThunderIDContext.Provider>\n </ThunderIDContext.Provider>\n );\n};\n\nexport default ThunderIDClientProvider;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ThunderIDProvider.js","names":["ThunderIDClientProvider: FC<PropsWithChildren<ThunderIDClientProviderProps>>","reRenderCheckRef: RefObject<boolean>","router: AppRouterInstance","searchParams: ReadonlyURLSearchParams","code: string | null","state: string | null","sessionState: string | null","result: {error?: string; redirectUrl?: string; success: boolean}","result: any","contextValue: ThunderIDContextProps","reactContextValue: ReactThunderIDContextProps","ThunderIDContext","ReactThunderIDContext"],"sources":["../../../../src/client/contexts/ThunderID/ThunderIDProvider.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use client';\n\nimport {\n AttributeSchema,\n EmbeddedFlowExecuteRequestConfig,\n FlowMetadataResponse,\n generateFlattenedUserProfile,\n UpdateMeProfileConfig,\n User,\n UserProfile,\n ThunderIDRuntimeError,\n getVendorPrefix,\n} from '@thunderid/node';\nimport {\n I18nProvider,\n FlowMetaProvider,\n FlowProvider,\n UserProvider,\n ThemeProvider,\n ThunderIDContext as ReactThunderIDContext,\n ThunderIDContextProps as ReactThunderIDContextProps,\n ThunderIDProviderProps,\n} from '@thunderid/react';\nimport {ReadonlyURLSearchParams} from 'next/dist/client/components/navigation.react-server';\nimport {AppRouterInstance} from 'next/dist/shared/lib/app-router-context.shared-runtime';\nimport {useRouter, useSearchParams} from 'next/navigation';\nimport {FC, PropsWithChildren, RefObject, useEffect, useMemo, useRef, useState} from 'react';\nimport ThunderIDContext, {ThunderIDContextProps} from './ThunderIDContext';\nimport {RefreshResult} from '../../../server/actions/refreshToken';\nimport logger from '../../../utils/logger';\n\n/**\n * Props interface of {@link ThunderIDClientProvider}\n */\nexport type ThunderIDClientProviderProps = Partial<Omit<ThunderIDProviderProps, 'baseUrl' | 'clientId'>> &\n Pick<ThunderIDProviderProps, 'baseUrl' | 'clientId'> & {\n applicationId: ThunderIDContextProps['applicationId'];\n clearSession: () => Promise<void>;\n /**\n * Server Action that fetches `GET /flow/meta` server-side, passed down to `FlowMetaProvider` so\n * it never calls `baseUrl` directly from the browser — avoiding the CORS requirement that a\n * direct client-side fetch to the ThunderID server would otherwise impose. Used for both the\n * initial fetch (when `initialMeta` isn't seeded, e.g. it failed server-side) and subsequent\n * `switchLanguage()` calls.\n */\n fetchMeta?: (params: {applicationId?: string; language?: string}) => Promise<FlowMetadataResponse>;\n handleOAuthCallback: (\n code: string,\n state: string,\n sessionState?: string,\n ) => Promise<{error?: string; redirectUrl?: string; success: boolean}>;\n /**\n * Flow metadata fetched server-side ahead of time, seeding `FlowMetaProvider` so it can skip\n * its own initial client-side fetch (avoiding a flash of untranslated i18n keys).\n */\n initialMeta?: FlowMetadataResponse | null;\n isSignedIn: boolean;\n organizationHandle: ThunderIDContextProps['organizationHandle'];\n refreshToken: () => Promise<RefreshResult>;\n signIn: ThunderIDContextProps['signIn'];\n signOut: ThunderIDContextProps['signOut'];\n signUp: ThunderIDContextProps['signUp'];\n updateProfile: (\n requestConfig: UpdateMeProfileConfig,\n sessionId?: string,\n ) => Promise<{data: {user: User}; error: string; success: boolean}>;\n user: User | null;\n userProfile: UserProfile;\n userSchema?: Record<string, AttributeSchema> | null;\n };\n\nconst ThunderIDClientProvider: FC<PropsWithChildren<ThunderIDClientProviderProps>> = ({\n baseUrl,\n children,\n signIn,\n clearSession,\n refreshToken,\n signOut,\n signUp,\n handleOAuthCallback,\n preferences,\n isSignedIn,\n signInUrl,\n signUpUrl,\n user: _user,\n userProfile: _userProfile,\n userSchema: _userSchema = null,\n updateProfile,\n applicationId,\n organizationHandle,\n scopes,\n vendor,\n initialMeta = null,\n fetchMeta,\n}: PropsWithChildren<ThunderIDClientProviderProps>) => {\n const reRenderCheckRef: RefObject<boolean> = useRef(false);\n const router: AppRouterInstance = useRouter();\n const searchParams: ReadonlyURLSearchParams = useSearchParams();\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [user, setUser] = useState<User | null>(_user);\n const [userProfile, setUserProfile] = useState<UserProfile>(_userProfile);\n const [userSchema, setUserSchema] = useState<Record<string, AttributeSchema> | null>(_userSchema);\n\n useEffect(() => {\n setUserProfile(_userProfile);\n }, [_userProfile]);\n\n useEffect(() => {\n setUserSchema(_userSchema);\n }, [_userSchema]);\n\n useEffect(() => {\n setUser(_user);\n }, [_user]);\n\n // Handle OAuth callback automatically\n useEffect(() => {\n // React 18.x Strict.Mode has a new check for `Ensuring reusable state` to facilitate an upcoming react feature.\n // https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state\n // This will remount all the useEffects to ensure that there are no unexpected side effects.\n // When react remounts the signIn hook of the AuthProvider, it will cause a race condition. Hence, we have to\n // prevent the re-render of this hook as suggested in the following discussion.\n // https://github.com/reactwg/react-18/discussions/18#discussioncomment-795623\n if (reRenderCheckRef.current) {\n return;\n }\n\n reRenderCheckRef.current = true;\n\n // Don't handle callback if already signed in\n if (isSignedIn) return;\n\n (async (): Promise<void> => {\n try {\n const code: string | null = searchParams.get('code');\n const state: string | null = searchParams.get('state');\n const sessionState: string | null = searchParams.get('session_state');\n const error: string | null = searchParams.get('error');\n\n // Check for OAuth errors first\n if (error) {\n logger.error('[ThunderIDClientProvider] An error was received for the initiated sign-in request.');\n\n return;\n }\n\n // Handle OAuth callback if code and state are present\n if (code && state) {\n setIsLoading(true);\n\n const result: {error?: string; redirectUrl?: string; success: boolean} = await handleOAuthCallback(\n code,\n state,\n sessionState || undefined,\n );\n\n if (result.success) {\n // Redirect to the success URL\n if (result.redirectUrl) {\n router.push(result.redirectUrl);\n } else {\n // Refresh the page to update authentication state\n window.location.reload();\n }\n } else {\n logger.error(\n `[ThunderIDClientProvider] An error occurred while signing in: ${result.error || 'Authentication failed'}`,\n );\n }\n }\n } catch (error) {\n logger.error('[ThunderIDClientProvider] Failed to handle OAuth callback:', error);\n }\n })();\n }, []);\n\n useEffect(() => {\n // Set loading to false when server has resolved authentication state\n setIsLoading(false);\n }, [isSignedIn, user]);\n\n const handleSignIn = async (payload: any, request: EmbeddedFlowExecuteRequestConfig): Promise<any> => {\n if (!signIn) {\n throw new ThunderIDRuntimeError(\n '`signIn` function is not available.',\n 'ThunderIDClientProvider-handleSignIn-RuntimeError-001',\n 'nextjs',\n );\n }\n\n const result: any = await signIn(payload, request);\n\n // Redirect based flow URL is sent as `signInUrl` in the response.\n // Use window.location.href instead of router.push() — the OAuth authorization\n // endpoint is on an external server, and router.push() would send RSC fetch\n // headers that the identity provider doesn't understand, causing a CORS error.\n if (result?.data?.signInUrl) {\n window.location.href = result.data.signInUrl;\n\n return undefined;\n }\n\n // After the Embedded flow is successful, the URL to navigate next is sent as `afterSignInUrl` in the response.\n if (result?.data?.afterSignInUrl) {\n router.push(result.data.afterSignInUrl);\n\n return undefined;\n }\n\n if (result?.error) {\n throw new Error(result.error);\n }\n\n return result?.data ?? result;\n };\n\n const handleSignUp = async (payload: any, request: EmbeddedFlowExecuteRequestConfig): Promise<any> => {\n if (!signUp) {\n throw new ThunderIDRuntimeError(\n '`signUp` function is not available.',\n 'ThunderIDClientProvider-handleSignUp-RuntimeError-001',\n 'nextjs',\n );\n }\n\n const result: any = await signUp(payload, request);\n\n // Redirect based flow URL is sent as `signUpUrl` in the response.\n if (result?.data?.signUpUrl) {\n router.push(result.data.signUpUrl);\n\n return undefined;\n }\n\n // After the Embedded flow is successful, the URL to navigate next is sent as `afterSignUpUrl` in the response.\n if (result?.data?.afterSignUpUrl) {\n router.push(result.data.afterSignUpUrl);\n\n return undefined;\n }\n\n if (result?.error) {\n throw new Error(result.error);\n }\n\n return result?.data ?? result;\n };\n\n const handleSignOut = async (): Promise<any> => {\n logger.debug('[ThunderIDClientProvider][handleSignOut] `handleSignOut` called.');\n\n try {\n const result: any = await signOut();\n\n logger.debug('[ThunderIDClientProvider][handleSignOut] Sign out result:', result);\n\n if (result?.data?.afterSignOutUrl) {\n router.push(result.data.afterSignOutUrl);\n\n return {location: result.data.afterSignOutUrl, redirected: true};\n }\n\n if (result?.error) {\n logger.error(\n '[ThunderIDClientProvider][handleSignOut] Error result was returned during signing the user out with a button click:',\n result.error,\n );\n }\n\n return result?.data ?? result;\n } catch (error) {\n logger.error(\n '[ThunderIDClientProvider][handleSignOut] Error occurred during signing the user out with a button click:',\n error,\n );\n\n return undefined;\n }\n };\n\n const contextValue: ThunderIDContextProps = useMemo(\n () => ({\n applicationId,\n baseUrl,\n clearSession,\n isLoading,\n isSignedIn,\n organizationHandle,\n preferences,\n refreshToken,\n scopes,\n signIn: handleSignIn,\n signInUrl,\n signOut: handleSignOut,\n signUp: handleSignUp,\n signUpUrl,\n user,\n }),\n [\n baseUrl,\n user,\n isSignedIn,\n isLoading,\n signInUrl,\n signUpUrl,\n applicationId,\n organizationHandle,\n scopes,\n preferences,\n ],\n );\n\n const handleProfileUpdate = (payload: User): void => {\n setUser(payload);\n setUserProfile((prev: UserProfile) => ({\n ...prev,\n flattenedProfile: generateFlattenedUserProfile(payload),\n profile: payload,\n }));\n };\n\n // Bridge into @thunderid/react's own ThunderIDContext. Internal react components rendered by\n // BaseSignIn/BaseSignUp — most notably FlowMetaProvider, which fetches `/flow/meta` and injects\n // its i18n bundle — call react's `useThunderID()` directly. Without this bridge they'd only see\n // react's context default (applicationId/baseUrl undefined, isInitialized false), so the meta\n // fetch would never fire and flow labels would render as untranslated i18n keys. Fields with no\n // nextjs equivalent (token/http helpers meant for direct browser API calls) are stubbed out,\n // since nextjs routes those operations through server actions instead.\n const unsupported = (name: string): (() => Promise<never>) => {\n return () =>\n Promise.reject(\n new ThunderIDRuntimeError(\n `\\`${name}\\` is not supported in @thunderid/nextjs.`,\n `ThunderIDClientProvider-${name}-NotSupportedError-001`,\n 'nextjs',\n ),\n );\n };\n\n const reactContextValue: ReactThunderIDContextProps = useMemo(\n () => ({\n afterSignInUrl: undefined,\n applicationId,\n baseUrl,\n clearSession,\n clientId: undefined,\n discovery: {wellKnown: null},\n exchangeToken: unsupported('exchangeToken'),\n getAccessToken: unsupported('getAccessToken'),\n getDecodedIdToken: unsupported('getDecodedIdToken'),\n getIdToken: unsupported('getIdToken'),\n getStorageManager: () => Promise.resolve(null),\n http: {\n request: unsupported('http.request'),\n requestAll: unsupported('http.requestAll'),\n },\n instanceId: 0,\n isInitialized: !isLoading,\n isLoading,\n isMetaLoading: false,\n isSignedIn,\n meta: initialMeta ?? null,\n organizationHandle,\n reInitialize: unsupported('reInitialize'),\n recover: unsupported('recover'),\n resolveFlowTemplateLiterals: (text: string | undefined): string => text ?? '',\n scopes,\n signIn: handleSignIn,\n signInSilently: unsupported('signInSilently'),\n signInUrl,\n signOut: handleSignOut,\n signUp: handleSignUp,\n signUpUrl,\n user,\n userSchema,\n vendor: getVendorPrefix(vendor),\n }),\n [\n applicationId,\n baseUrl,\n clearSession,\n isLoading,\n isSignedIn,\n organizationHandle,\n scopes,\n signInUrl,\n signUpUrl,\n user,\n userSchema,\n initialMeta,\n vendor,\n ],\n );\n\n return (\n <ThunderIDContext.Provider value={contextValue}>\n <ReactThunderIDContext.Provider value={reactContextValue}>\n <I18nProvider preferences={preferences?.i18n}>\n <FlowMetaProvider\n enabled={preferences?.resolveFromMeta !== false}\n initialMeta={initialMeta}\n fetchMeta={fetchMeta}\n >\n <ThemeProvider theme={preferences?.theme?.overrides} mode={preferences?.theme?.mode}>\n <FlowProvider>\n <UserProvider\n profile={userProfile}\n userSchema={userSchema}\n onUpdateProfile={handleProfileUpdate}\n updateProfile={updateProfile}\n >\n {children}\n </UserProvider>\n </FlowProvider>\n </ThemeProvider>\n </FlowMetaProvider>\n </I18nProvider>\n </ReactThunderIDContext.Provider>\n </ThunderIDContext.Provider>\n );\n};\n\nexport default ThunderIDClientProvider;\n"],"mappings":"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"}
@@ -21,4 +21,6 @@ export { default as UserAvatar } from './components/presentation/UserAvatar/User
21
21
  export type { UserAvatarProps } from './components/presentation/UserAvatar/UserAvatar';
22
22
  export { default as UserProfile } from './components/presentation/UserProfile/UserProfile';
23
23
  export type { UserProfileProps } from './components/presentation/UserProfile/UserProfile';
24
+ export { default as ChangeCredential } from './components/presentation/ChangeCredential/ChangeCredential';
25
+ export type { ChangeCredentialProps } from './components/presentation/ChangeCredential/ChangeCredential';
24
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,wCAAwC,CAAC;AAC3E,YAAY,EAAC,aAAa,EAAC,MAAM,wCAAwC,CAAC;AAE1E,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,0CAA0C,CAAC;AAC9E,YAAY,EAAC,cAAc,EAAC,MAAM,0CAA0C,CAAC;AAE7E,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,gDAAgD,CAAC;AACvF,YAAY,EAAC,iBAAiB,EAAC,MAAM,gDAAgD,CAAC;AAEtF,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,gDAAgD,CAAC;AACvF,YAAY,EAAC,iBAAiB,EAAC,MAAM,gDAAgD,CAAC;AAEtF,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,yCAAyC,CAAC;AAC1E,YAAY,EAAC,WAAW,EAAC,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAC,OAAO,IAAI,aAAa,EAAC,MAAM,kDAAkD,CAAC;AAC1F,YAAY,EAAC,kBAAkB,EAAC,MAAM,kDAAkD,CAAC;AAEzF,OAAO,EAAC,OAAO,IAAI,IAAI,EAAC,MAAM,qCAAqC,CAAC;AACpE,YAAY,EAAC,SAAS,EAAC,MAAM,qCAAqC,CAAC;AAEnE,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,yCAAyC,CAAC;AAC1E,YAAY,EAAC,WAAW,EAAC,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,qDAAqD,CAAC;AAC5F,YAAY,EAAC,iBAAiB,EAAC,MAAM,qDAAqD,CAAC;AAE3F,OAAO,EAAC,OAAO,IAAI,UAAU,EAAC,MAAM,iDAAiD,CAAC;AACtF,YAAY,EAAC,eAAe,EAAC,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAC,OAAO,IAAI,WAAW,EAAC,MAAM,mDAAmD,CAAC;AACzF,YAAY,EAAC,gBAAgB,EAAC,MAAM,mDAAmD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,wCAAwC,CAAC;AAC3E,YAAY,EAAC,aAAa,EAAC,MAAM,wCAAwC,CAAC;AAE1E,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,0CAA0C,CAAC;AAC9E,YAAY,EAAC,cAAc,EAAC,MAAM,0CAA0C,CAAC;AAE7E,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,gDAAgD,CAAC;AACvF,YAAY,EAAC,iBAAiB,EAAC,MAAM,gDAAgD,CAAC;AAEtF,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,gDAAgD,CAAC;AACvF,YAAY,EAAC,iBAAiB,EAAC,MAAM,gDAAgD,CAAC;AAEtF,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,yCAAyC,CAAC;AAC1E,YAAY,EAAC,WAAW,EAAC,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAC,OAAO,IAAI,aAAa,EAAC,MAAM,kDAAkD,CAAC;AAC1F,YAAY,EAAC,kBAAkB,EAAC,MAAM,kDAAkD,CAAC;AAEzF,OAAO,EAAC,OAAO,IAAI,IAAI,EAAC,MAAM,qCAAqC,CAAC;AACpE,YAAY,EAAC,SAAS,EAAC,MAAM,qCAAqC,CAAC;AAEnE,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,yCAAyC,CAAC;AAC1E,YAAY,EAAC,WAAW,EAAC,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAC,OAAO,IAAI,YAAY,EAAC,MAAM,qDAAqD,CAAC;AAC5F,YAAY,EAAC,iBAAiB,EAAC,MAAM,qDAAqD,CAAC;AAE3F,OAAO,EAAC,OAAO,IAAI,UAAU,EAAC,MAAM,iDAAiD,CAAC;AACtF,YAAY,EAAC,eAAe,EAAC,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAC,OAAO,IAAI,WAAW,EAAC,MAAM,mDAAmD,CAAC;AACzF,YAAY,EAAC,gBAAgB,EAAC,MAAM,mDAAmD,CAAC;AAExF,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,MAAM,6DAA6D,CAAC;AACxG,YAAY,EAAC,qBAAqB,EAAC,MAAM,6DAA6D,CAAC"}
@@ -10,5 +10,6 @@ import SignUp_default from "./components/presentation/SignUp/SignUp.js";
10
10
  import UserProfile_default from "./components/presentation/UserProfile/UserProfile.js";
11
11
  import UserDropdown_default from "./components/presentation/UserDropdown/UserDropdown.js";
12
12
  import UserAvatar_default from "./components/presentation/UserAvatar/UserAvatar.js";
13
+ import ChangeCredential_default from "./components/presentation/ChangeCredential/ChangeCredential.js";
13
14
 
14
15
  export { };
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ import SignUp_default from "./client/components/presentation/SignUp/SignUp.js";
16
16
  import UserProfile_default from "./client/components/presentation/UserProfile/UserProfile.js";
17
17
  import UserDropdown_default from "./client/components/presentation/UserDropdown/UserDropdown.js";
18
18
  import UserAvatar_default from "./client/components/presentation/UserAvatar/UserAvatar.js";
19
+ import ChangeCredential_default from "./client/components/presentation/ChangeCredential/ChangeCredential.js";
19
20
  import "./client/index.js";
20
21
 
21
- export { SignIn_default as SignIn, SignInButton_default as SignInButton, SignOutButton_default as SignOutButton, SignUp_default as SignUp, SignUpButton_default as SignUpButton, SignedIn_default as SignedIn, SignedOut_default as SignedOut, ThunderIDNextClient_default as ThunderIDNext, ThunderIDProvider_default as ThunderIDProvider, User_default as User, UserAvatar_default as UserAvatar, UserDropdown_default as UserDropdown, UserProfile_default as UserProfile, createRouteMatcher_default as createRouteMatcher, removeChunkedCookieFromHeader, replaceChunkedCookieInHeader, thunderIDProxy_default as thunderIDProxy, thunderid_default as thunderid, useThunderID_default as useThunderID };
22
+ export { ChangeCredential_default as ChangeCredential, SignIn_default as SignIn, SignInButton_default as SignInButton, SignOutButton_default as SignOutButton, SignUp_default as SignUp, SignUpButton_default as SignUpButton, SignedIn_default as SignedIn, SignedOut_default as SignedOut, ThunderIDNextClient_default as ThunderIDNext, ThunderIDProvider_default as ThunderIDProvider, User_default as User, UserAvatar_default as UserAvatar, UserDropdown_default as UserDropdown, UserProfile_default as UserProfile, createRouteMatcher_default as createRouteMatcher, removeChunkedCookieFromHeader, replaceChunkedCookieInHeader, thunderIDProxy_default as thunderIDProxy, thunderid_default as thunderid, useThunderID_default as useThunderID };
@@ -0,0 +1,16 @@
1
+ import { CredentialUpdateErrorResult } from '@thunderid/node';
2
+ export interface UpdateUserCredentialsActionResult extends CredentialUpdateErrorResult {
3
+ success: boolean;
4
+ }
5
+ /**
6
+ * Server action to update one of the signed-in user's own credentials (e.g. `password`).
7
+ *
8
+ * Never throws across the server action boundary — a thrown class instance loses its
9
+ * prototype chain crossing it, so `error instanceof ThunderIDAPIError` would no longer hold on
10
+ * the client. Instead, the real error is mapped to a field/message here, server-side, while it
11
+ * is still the genuine `ThunderIDAPIError` the core `updateMeCredentials` call threw, and only
12
+ * the plain, serializable result crosses back.
13
+ */
14
+ declare const updateUserCredentialsAction: (payload: Record<string, string>, sessionId?: string) => Promise<UpdateUserCredentialsActionResult>;
15
+ export default updateUserCredentialsAction;
16
+ //# sourceMappingURL=updateUserCredentialsAction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateUserCredentialsAction.d.ts","sourceRoot":"","sources":["../../../src/server/actions/updateUserCredentialsAction.ts"],"names":[],"mappings":"AAKA,OAAO,EAAC,2BAA2B,EAA2B,MAAM,iBAAiB,CAAC;AAGtF,MAAM,WAAW,iCAAkC,SAAQ,2BAA2B;IACpF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,QAAA,MAAM,2BAA2B,GAC/B,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,YAAY,MAAM,KACjB,OAAO,CAAC,iCAAiC,CAS3C,CAAC;AAEF,eAAe,2BAA2B,CAAC"}
@@ -0,0 +1,39 @@
1
+ 'use server';
2
+
3
+
4
+ import getClient_default from "../getClient.js";
5
+ import { mapCredentialUpdateError } from "@thunderid/node";
6
+
7
+ //#region src/server/actions/updateUserCredentialsAction.ts
8
+ /**
9
+ * Server action to update one of the signed-in user's own credentials (e.g. `password`).
10
+ *
11
+ * Never throws across the server action boundary — a thrown class instance loses its
12
+ * prototype chain crossing it, so `error instanceof ThunderIDAPIError` would no longer hold on
13
+ * the client. Instead, the real error is mapped to a field/message here, server-side, while it
14
+ * is still the genuine `ThunderIDAPIError` the core `updateMeCredentials` call threw, and only
15
+ * the plain, serializable result crosses back.
16
+ */
17
+ const updateUserCredentialsAction = async (payload, sessionId) => {
18
+ try {
19
+ await getClient_default().updateUserCredentials(payload, sessionId);
20
+ return {
21
+ field: null,
22
+ messageKey: "",
23
+ success: true
24
+ };
25
+ } catch (error) {
26
+ const { field, message, messageKey } = mapCredentialUpdateError(error);
27
+ return {
28
+ field,
29
+ message,
30
+ messageKey,
31
+ success: false
32
+ };
33
+ }
34
+ };
35
+ var updateUserCredentialsAction_default = updateUserCredentialsAction;
36
+
37
+ //#endregion
38
+ export { updateUserCredentialsAction_default as default };
39
+ //# sourceMappingURL=updateUserCredentialsAction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateUserCredentialsAction.js","names":["getClient"],"sources":["../../../src/server/actions/updateUserCredentialsAction.ts"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\n'use server';\n\nimport {CredentialUpdateErrorResult, mapCredentialUpdateError} from '@thunderid/node';\nimport getClient from '../getClient';\n\nexport interface UpdateUserCredentialsActionResult extends CredentialUpdateErrorResult {\n success: boolean;\n}\n\n/**\n * Server action to update one of the signed-in user's own credentials (e.g. `password`).\n *\n * Never throws across the server action boundary — a thrown class instance loses its\n * prototype chain crossing it, so `error instanceof ThunderIDAPIError` would no longer hold on\n * the client. Instead, the real error is mapped to a field/message here, server-side, while it\n * is still the genuine `ThunderIDAPIError` the core `updateMeCredentials` call threw, and only\n * the plain, serializable result crosses back.\n */\nconst updateUserCredentialsAction = async (\n payload: Record<string, string>,\n sessionId?: string,\n): Promise<UpdateUserCredentialsActionResult> => {\n try {\n const client = getClient();\n await client.updateUserCredentials(payload, sessionId);\n return {field: null, messageKey: '', success: true};\n } catch (error) {\n const {field, message, messageKey}: CredentialUpdateErrorResult = mapCredentialUpdateError(error);\n return {field, message, messageKey, success: false};\n }\n};\n\nexport default updateUserCredentialsAction;\n"],"mappings":";;;;;;;;;;;;;;;;AAqBA,MAAM,8BAA8B,OAClC,SACA,cAC+C;AAC/C,KAAI;AAEF,QADeA,mBAAW,CACb,sBAAsB,SAAS,UAAU;AACtD,SAAO;GAAC,OAAO;GAAM,YAAY;GAAI,SAAS;GAAK;UAC5C,OAAO;EACd,MAAM,EAAC,OAAO,SAAS,eAA2C,yBAAyB,MAAM;AACjG,SAAO;GAAC;GAAO;GAAS;GAAY,SAAS;GAAM;;;AAIvD,0CAAe"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thunderid/nextjs",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "Next.js SDK for ThunderID",
5
5
  "keywords": [
6
6
  "thunderid",
@@ -37,8 +37,8 @@
37
37
  "directory": "packages/nextjs"
38
38
  },
39
39
  "dependencies": {
40
- "@thunderid/node": "^1.0.7",
41
- "@thunderid/react": "^1.0.8",
40
+ "@thunderid/node": "^1.1.0",
41
+ "@thunderid/react": "^1.1.0",
42
42
  "@types/react": "19.2.14",
43
43
  "jose": "6.2.3",
44
44
  "tslib": "2.8.1"