@multiplatform.one/web3 8.2.2 → 8.3.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 (42) hide show
  1. package/dist/cjs/connectkit/siwe/SIWEContext.native.js.map +1 -1
  2. package/dist/cjs/connectkit/siwe/SIWEProvider.cjs +19 -16
  3. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js +26 -16
  4. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  5. package/dist/cjs/keycloak/KeycloakWalletLogin.cjs +34 -3
  6. package/dist/cjs/keycloak/useWalletLogin.cjs +3 -2
  7. package/dist/esm/connectkit/siwe/SIWEContext.mjs.map +1 -1
  8. package/dist/esm/connectkit/siwe/SIWEContext.native.js.map +1 -1
  9. package/dist/esm/connectkit/siwe/SIWEProvider.mjs +19 -16
  10. package/dist/esm/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  11. package/dist/esm/connectkit/siwe/SIWEProvider.native.js +26 -16
  12. package/dist/esm/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  13. package/dist/esm/keycloak/KeycloakWalletLogin.mjs +33 -3
  14. package/dist/esm/keycloak/KeycloakWalletLogin.mjs.map +1 -1
  15. package/dist/esm/keycloak/useWalletLogin.mjs +3 -2
  16. package/dist/esm/keycloak/useWalletLogin.mjs.map +1 -1
  17. package/dist/jsx/connectkit/siwe/SIWEContext.mjs.map +1 -1
  18. package/dist/jsx/connectkit/siwe/SIWEContext.native.js.map +1 -1
  19. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs +19 -16
  20. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  21. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js +26 -16
  22. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  23. package/dist/jsx/keycloak/KeycloakWalletLogin.mjs +33 -3
  24. package/dist/jsx/keycloak/KeycloakWalletLogin.mjs.map +1 -1
  25. package/dist/jsx/keycloak/useWalletLogin.mjs +3 -2
  26. package/dist/jsx/keycloak/useWalletLogin.mjs.map +1 -1
  27. package/dist/keycloak/login.iife.js +335 -335
  28. package/package.json +7 -7
  29. package/src/connectkit/siwe/SIWEContext.tsx +2 -0
  30. package/src/connectkit/siwe/SIWEProvider.tsx +23 -10
  31. package/src/keycloak/KeycloakWalletLogin.spec.tsx +110 -0
  32. package/src/keycloak/KeycloakWalletLogin.stories.tsx +93 -0
  33. package/src/keycloak/KeycloakWalletLogin.tsx +39 -2
  34. package/src/keycloak/useWalletLogin.ts +5 -1
  35. package/types/connectkit/siwe/SIWEContext.d.ts +2 -0
  36. package/types/connectkit/siwe/SIWEContext.d.ts.map +1 -1
  37. package/types/connectkit/siwe/SIWEProvider.d.ts +0 -6
  38. package/types/connectkit/siwe/SIWEProvider.d.ts.map +1 -1
  39. package/types/keycloak/KeycloakWalletLogin.d.ts +6 -1
  40. package/types/keycloak/KeycloakWalletLogin.d.ts.map +1 -1
  41. package/types/keycloak/useWalletLogin.d.ts +2 -0
  42. package/types/keycloak/useWalletLogin.d.ts.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/web3",
3
- "version": "8.2.2",
3
+ "version": "8.3.0",
4
4
  "description": "Web3 wallet integration for multiplatform.one ecosystem with ConnectKit and wagmi",
5
5
  "keywords": [
6
6
  "connectkit",
@@ -120,10 +120,10 @@
120
120
  "@aave/account": "^0.2.1",
121
121
  "@coinbase/wallet-sdk": "^4.4.0",
122
122
  "@metamask/connect-evm": "^2.1.1",
123
- "@multiplatform.one/connectkit": "^8.2.2",
124
- "@multiplatform.one/gpg": "^8.2.2",
125
- "@multiplatform.one/platform": "^8.2.2",
126
- "@multiplatform.one/theme": "^8.2.2",
123
+ "@multiplatform.one/connectkit": "^8.3.0",
124
+ "@multiplatform.one/gpg": "^8.3.0",
125
+ "@multiplatform.one/platform": "^8.3.0",
126
+ "@multiplatform.one/theme": "^8.3.0",
127
127
  "@noble/ciphers": "^1.3.0",
128
128
  "@noble/curves": "^1.9.7",
129
129
  "@phosphor-icons/react": "^2.1.10",
@@ -147,8 +147,8 @@
147
147
  "wagmi": "^3.7.1"
148
148
  },
149
149
  "devDependencies": {
150
- "@multiplatform.one/config": "8.2.2",
151
- "@multiplatform.one/test-utils": "8.2.2",
150
+ "@multiplatform.one/config": "8.3.0",
151
+ "@multiplatform.one/test-utils": "8.3.0",
152
152
  "@tamagui/build": "2.7.6",
153
153
  "@tanstack/react-query": "^5.104.3",
154
154
  "@testing-library/jest-dom": "^7.0.1",
@@ -61,6 +61,8 @@ export type SIWEContextValue = Required<Omit<SIWEConfig, "onSign" | "subscribeNo
61
61
  nonce: ReturnType<typeof useQuery<string | null>>;
62
62
  session: ReturnType<typeof useQuery<SIWESession | null>>;
63
63
  status: StatusState;
64
+ /** What ended the last sign-in, while status is ERROR or REJECTED. */
65
+ error: Error | null;
64
66
  signIn: () => Promise<SIWESession | false>;
65
67
  resetStatus: () => void;
66
68
  };
@@ -26,6 +26,20 @@ const b64 = (s: string) => window.btoa(unescape(encodeURIComponent(s)));
26
26
  * connection store holds: `<SignInProvider {...kc.signInConfig(onSign)}>`,
27
27
  * or Web3Provider's `signIn` prop.
28
28
  */
29
+ // A transport wraps the wallet's own refusal (viem's HttpRequestError around a
30
+ // 4001), so the code can sit anywhere down the cause chain.
31
+ function isUserRejection(error: unknown): boolean {
32
+ for (
33
+ let cause = error as { code?: unknown; cause?: unknown } | undefined, depth = 0;
34
+ cause && depth < 8;
35
+ cause = cause.cause as typeof cause, depth++
36
+ ) {
37
+ if (cause.code === -32000 || cause.code === 4001 || cause.code === "ACTION_REJECTED")
38
+ return true;
39
+ }
40
+ return false;
41
+ }
42
+
29
43
  export const SIWEProvider = ({
30
44
  children,
31
45
  enabled = true,
@@ -39,7 +53,11 @@ export const SIWEProvider = ({
39
53
  ...siweConfig
40
54
  }: Props) => {
41
55
  const [status, setStatus] = useState<StatusState>(StatusState.READY);
42
- const resetStatus = () => setStatus(StatusState.READY);
56
+ const [error, setError] = useState<Error | null>(null);
57
+ const resetStatus = () => {
58
+ setStatus(StatusState.READY);
59
+ setError(null);
60
+ };
43
61
 
44
62
  // Only allow for mounting SIWEProvider once, so we avoid weird global state
45
63
  // collisions.
@@ -111,15 +129,8 @@ export const SIWEProvider = ({
111
129
 
112
130
  const onError = (error: any) => {
113
131
  console.error("signIn error", error, error.message);
114
- switch (error.code) {
115
- case -32000: // user rejected, as some wallets report it
116
- case 4001: // MetaMask: user rejected
117
- case "ACTION_REJECTED": // MetaMask: user rejected
118
- setStatus(StatusState.REJECTED);
119
- break;
120
- default:
121
- setStatus(StatusState.ERROR);
122
- }
132
+ setError(error instanceof Error ? error : new Error(String(error)));
133
+ setStatus(isUserRejection(error) ? StatusState.REJECTED : StatusState.ERROR);
123
134
  };
124
135
 
125
136
  const signIn = async () => {
@@ -135,6 +146,7 @@ export const SIWEProvider = ({
135
146
  if (!chainId) throw new Error("No chainId found");
136
147
 
137
148
  setStatus(StatusState.LOADING);
149
+ setError(null);
138
150
 
139
151
  // Fetch this sign-in's own nonce. A server that consumes its nonce on
140
152
  // verify refuses the one cached at mount the second time, so a cached
@@ -249,6 +261,7 @@ export const SIWEProvider = ({
249
261
  signIn,
250
262
  signOut: signOutAndRefetch,
251
263
  status,
264
+ error,
252
265
  resetStatus,
253
266
  }}
254
267
  >
@@ -423,3 +423,113 @@ describe("KeycloakWalletLogin after the page reloads during the wallet trip", ()
423
423
  expect(screen.queryByText("Mock Connector")).toBeNull();
424
424
  });
425
425
  });
426
+
427
+ describe("KeycloakWalletLogin when a sign-in fails (FZ-1825)", () => {
428
+ function failingFetch(answer: { nonce?: () => Response; sign?: Error }) {
429
+ vi.stubGlobal(
430
+ "fetch",
431
+ vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
432
+ if (String(input).endsWith("/nonce"))
433
+ return answer.nonce?.() ?? new Response("nonce123abc");
434
+ const body = String(
435
+ init?.body ?? (input instanceof Request ? await input.clone().text() : ""),
436
+ );
437
+ if (answer.sign && /"method":"(eth_sign|personal_sign)"/.test(body)) throw answer.sign;
438
+ return new Response("not found", { status: 404 });
439
+ }),
440
+ );
441
+ }
442
+
443
+ async function connectedLogin() {
444
+ const rendered = renderLogin({ wagmiConfig: makeConfig(memoryStorage(), true) });
445
+ await waitFor(() => expect(rendered.config.state.status).toBe("connected"));
446
+ return rendered;
447
+ }
448
+
449
+ it("keeps an empty live region under the wallet button before anything fails", async () => {
450
+ await connectedLogin();
451
+ const region = document.getElementById("mpo-wallet-login-error");
452
+ expect(region?.getAttribute("aria-live")).toBe("polite");
453
+ expect(region?.textContent).toBe("");
454
+ });
455
+
456
+ it("a rejected signature says so under the button, which stays usable", async () => {
457
+ failingFetch({
458
+ sign: Object.assign(new Error("User rejected the request."), { code: 4001 }),
459
+ });
460
+ const { walletButton } = await connectedLogin();
461
+ const region = document.getElementById("mpo-wallet-login-error")!;
462
+
463
+ fireEvent.click(walletButton);
464
+ await waitFor(() => expect(region.textContent).toBe("You declined the signature. Try again."));
465
+ expect(document.getElementById("mpo-wallet-login-error")).toBe(region);
466
+ expect(walletButton.disabled).toBe(false);
467
+ expect(walletButton.textContent).toBe("Sign in with Wallet");
468
+
469
+ failingFetch({});
470
+ fireEvent.click(walletButton);
471
+ await waitFor(() => expect(region.textContent).toBe(""));
472
+ });
473
+
474
+ // The sign-in joins the page's mount-time nonce fetch, which react-query
475
+ // retries three times with backoff before it fails (about seven seconds).
476
+ it.each([
477
+ ["a 503 nonce", () => new Response("down", { status: 503 })],
478
+ ["an empty siww nonce", () => new Response("")],
479
+ [
480
+ "an unreachable server",
481
+ () => {
482
+ throw new TypeError("Failed to fetch");
483
+ },
484
+ ],
485
+ ] as const)(
486
+ "%s says the sign-in server couldn't be reached, in plain words",
487
+ { timeout: 20_000 },
488
+ async (_case, nonce) => {
489
+ const logged = vi.spyOn(console, "error").mockImplementation(() => {});
490
+ failingFetch({ nonce });
491
+ const { walletButton } = await connectedLogin();
492
+
493
+ fireEvent.click(walletButton);
494
+ const region = document.getElementById("mpo-wallet-login-error")!;
495
+ await waitFor(
496
+ () => expect(region.textContent).toBe("Couldn't reach the sign-in server. Try again."),
497
+ { timeout: 15_000 },
498
+ );
499
+ expect(region.textContent).not.toMatch(/keycloak|nonce|\d{3}/i);
500
+ expect(walletButton.disabled).toBe(false);
501
+ expect(logged.mock.calls.some(([label]) => label === "signIn error")).toBe(true);
502
+ },
503
+ );
504
+
505
+ it("any other failure says the sign-in failed, without the server's words", async () => {
506
+ failingFetch({
507
+ sign: Object.assign(new Error("Internal JSON-RPC error."), { code: -32603 }),
508
+ });
509
+ const { walletButton } = await connectedLogin();
510
+
511
+ fireEvent.click(walletButton);
512
+ const region = document.getElementById("mpo-wallet-login-error")!;
513
+ await waitFor(() => expect(region.textContent).toBe("Couldn't sign in. Try again."));
514
+ });
515
+
516
+ it("paints the failure line in the field error ink, or the page's own class", async () => {
517
+ failingFetch({
518
+ sign: Object.assign(new Error("User rejected the request."), { code: 4001 }),
519
+ });
520
+ const { walletButton } = await connectedLogin();
521
+ fireEvent.click(walletButton);
522
+ const region = document.getElementById("mpo-wallet-login-error")!;
523
+ await waitFor(() => expect(region.textContent).not.toBe(""));
524
+ // jsdom drops light-dark() colours; the Storybook shots on FZ-1825 measure the ink.
525
+ expect(region.style.colorScheme).toBe("light dark");
526
+ cleanup();
527
+
528
+ renderLogin({ wagmiConfig: makeConfig(memoryStorage(), true), errorClassName: "kc-error" });
529
+ const themed = document.getElementById("mpo-wallet-login-error")!;
530
+ expect(themed.className).toBe("");
531
+ fireEvent.click(document.getElementById("mpo-wallet-login") as HTMLButtonElement);
532
+ await waitFor(() => expect(themed.className).toBe("kc-error"));
533
+ expect(themed.getAttribute("style")).toBeNull();
534
+ });
535
+ });
@@ -0,0 +1,93 @@
1
+ import type { ReactElement } from "react";
2
+ import { userEvent, within } from "storybook/test";
3
+ import { createConfig, createStorage, http } from "wagmi";
4
+ import { mainnet } from "wagmi/chains";
5
+ import { mock } from "wagmi/connectors";
6
+ import { KeycloakWalletLogin } from "./KeycloakWalletLogin";
7
+
8
+ const KEYCLOAK = "https://keycloak-wallet-login.mock.test";
9
+ const ACCOUNT = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
10
+
11
+ function memoryStorage() {
12
+ const map = new Map<string, string>();
13
+ return {
14
+ getItem: (key: string) => map.get(key) ?? null,
15
+ setItem: (key: string, value: string) => void map.set(key, value),
16
+ removeItem: (key: string) => void map.delete(key),
17
+ };
18
+ }
19
+
20
+ function connectedWallet() {
21
+ return createConfig({
22
+ chains: [mainnet],
23
+ connectors: [
24
+ mock({ accounts: [ACCOUNT], features: { reconnect: true, defaultConnected: true } }),
25
+ ],
26
+ transports: { [mainnet.id]: http() },
27
+ storage: createStorage({ storage: memoryStorage() }),
28
+ });
29
+ }
30
+
31
+ function answerKeycloak(nonce: () => Response) {
32
+ return () => {
33
+ const realFetch = window.fetch;
34
+ window.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
35
+ const url =
36
+ typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
37
+ if (url.endsWith("/nonce")) return nonce();
38
+ const body = String(init?.body ?? "");
39
+ if (/"method":"(eth_sign|personal_sign)"/.test(body)) {
40
+ throw Object.assign(new Error("User rejected the request."), { code: 4001 });
41
+ }
42
+ if (!url.startsWith(KEYCLOAK)) return realFetch(input, init);
43
+ return new Response("not found", { status: 404 });
44
+ };
45
+ return () => {
46
+ window.fetch = realFetch;
47
+ };
48
+ };
49
+ }
50
+
51
+ async function pressWallet({ canvasElement }: { canvasElement: HTMLElement }) {
52
+ const canvas = within(canvasElement);
53
+ await userEvent.click(await canvas.findByRole("button", { name: /sign in with wallet/i }));
54
+ await canvas.findByText(/try again/i, {}, { timeout: 20_000 });
55
+ }
56
+
57
+ const meta = {
58
+ title: "Web3/KeycloakWalletLogin",
59
+ component: KeycloakWalletLogin,
60
+ tags: ["!test"],
61
+ parameters: { layout: "centered" },
62
+ decorators: [
63
+ (Story: () => ReactElement) => (
64
+ <div style={{ width: 320 }}>
65
+ <Story />
66
+ </div>
67
+ ),
68
+ ],
69
+ };
70
+ export default meta;
71
+
72
+ export const Idle = {
73
+ beforeEach: answerKeycloak(() => new Response("nonce123abc")),
74
+ render: () => (
75
+ <KeycloakWalletLogin baseUrl={KEYCLOAK} realm="main" wagmiConfig={connectedWallet()} />
76
+ ),
77
+ };
78
+
79
+ export const Declined = {
80
+ beforeEach: answerKeycloak(() => new Response("nonce123abc")),
81
+ render: () => (
82
+ <KeycloakWalletLogin baseUrl={KEYCLOAK} realm="main" wagmiConfig={connectedWallet()} />
83
+ ),
84
+ play: pressWallet,
85
+ };
86
+
87
+ export const ServerUnreachable = {
88
+ beforeEach: answerKeycloak(() => new Response("down", { status: 503 })),
89
+ render: () => (
90
+ <KeycloakWalletLogin baseUrl={KEYCLOAK} realm="main" wagmiConfig={connectedWallet()} />
91
+ ),
92
+ play: pressWallet,
93
+ };
@@ -14,7 +14,7 @@ import type { MobileConnectOptions } from "../connectkit/openConnector";
14
14
  import { ConnectKitProvider } from "../connectkit/web3Provider";
15
15
  import type { BrowserFlowOptions } from "./browserFlow";
16
16
  import { deriveKeycloakFromLocation, keycloakWallet } from "./keycloakWallet";
17
- import type { KeycloakWalletResource } from "./types";
17
+ import { KeycloakWalletError, type KeycloakWalletResource } from "./types";
18
18
  import { useWalletLogin } from "./useWalletLogin";
19
19
 
20
20
  export interface KeycloakWalletLoginProps {
@@ -44,6 +44,8 @@ export interface KeycloakWalletLoginProps {
44
44
  className?: string;
45
45
  /** Replaces the built-in button look, e.g. the theme's `kcButtonClass`. */
46
46
  buttonClassName?: string;
47
+ /** Replaces the built-in failure line look, e.g. the theme's `kcInputErrorMessageClass`. */
48
+ errorClassName?: string;
47
49
  /** The wagmi config to sign with; built from the app props and `chains` when absent. */
48
50
  wagmiConfig?: Config;
49
51
  }
@@ -97,6 +99,31 @@ const buttonStyle: CSSProperties = {
97
99
  const themeScopeStyle: CSSProperties = { display: "block" };
98
100
 
99
101
  const noticeStyle: CSSProperties = { margin: "8px 0 0", fontSize: 13 };
102
+ const hiddenNoticeStyle: CSSProperties = { margin: 0 };
103
+ // MPO's field error ink ($red10 light and dark, form-colors.md) for a page that brings no class of its own.
104
+ const errorStyle: CSSProperties = {
105
+ ...noticeStyle,
106
+ colorScheme: "light dark",
107
+ color: "light-dark(#dc3e42, #ec5d5e)",
108
+ };
109
+
110
+ const declinedMessage = "You declined the signature. Try again.";
111
+ const unreachableMessage = "Couldn't reach the sign-in server. Try again.";
112
+ const failedMessage = "Couldn't sign in. Try again.";
113
+
114
+ /** The words a failed wallet sign-in shows; the raw reason stays on the error and in the console. */
115
+ export function walletLoginFailureMessage(
116
+ status: StatusState,
117
+ error: Error | null,
118
+ ): string | undefined {
119
+ if (status === StatusState.REJECTED) return declinedMessage;
120
+ if (status !== StatusState.ERROR) return undefined;
121
+ if (error instanceof TypeError) return unreachableMessage;
122
+ if (error instanceof KeycloakWalletError && (error.status < 300 || error.status >= 500)) {
123
+ return unreachableMessage;
124
+ }
125
+ return failedMessage;
126
+ }
100
127
 
101
128
  const themedNoticeStyle: CSSProperties = { ...noticeStyle, color: "var(--ck-body-color)" };
102
129
 
@@ -180,11 +207,13 @@ function LoginButtons({
180
207
  gpgLabel = "Sign in with GPG",
181
208
  className,
182
209
  buttonClassName,
210
+ errorClassName,
183
211
  }: KeycloakWalletLoginProps) {
184
- const { login, status, dropped } = useWalletLogin();
212
+ const { login, status, dropped, error } = useWalletLogin();
185
213
  const { openGpg } = useWeb3Modal();
186
214
  const style = buttonClassName ? undefined : buttonStyle;
187
215
  const busy = status === StatusState.LOADING || status === StatusState.SUCCESS;
216
+ const failure = dropped || busy ? undefined : walletLoginFailureMessage(status, error);
188
217
  const buttons = (
189
218
  <div className={className ?? "mpo-keycloak-wallet-login"}>
190
219
  <button
@@ -201,6 +230,14 @@ function LoginButtons({
201
230
  <WalletIcon />
202
231
  <span>{busy ? "Signing…" : walletLabel}</span>
203
232
  </button>
233
+ <p
234
+ id="mpo-wallet-login-error"
235
+ aria-live="polite"
236
+ className={failure ? errorClassName : undefined}
237
+ style={!failure ? hiddenNoticeStyle : errorClassName ? undefined : errorStyle}
238
+ >
239
+ {failure}
240
+ </p>
204
241
  {dropped && !busy && (
205
242
  <p
206
243
  id="mpo-wallet-login-dropped"
@@ -29,6 +29,8 @@ export interface UseWalletLoginResult {
29
29
  * connects afresh and clears it.
30
30
  */
31
31
  dropped: boolean;
32
+ /** What ended the last signature, while status is ERROR or REJECTED. */
33
+ error: Error | null;
32
34
  }
33
35
 
34
36
  function readIntent(key: string, ttl: number): boolean {
@@ -98,7 +100,8 @@ export function useWalletLogin(opts: UseWalletLoginOptions = {}): UseWalletLogin
98
100
  setDropped(false);
99
101
  // A failed signature leaves SIWE on ERROR, which the sign-in step would
100
102
  // show the next attempt as "Unknown Error".
101
- if (!signIn && siwe?.status === StatusState.ERROR) siwe.resetStatus();
103
+ if (!signIn && (siwe?.status === StatusState.ERROR || siwe?.status === StatusState.REJECTED))
104
+ siwe.resetStatus();
102
105
  if (isConnected) {
103
106
  await sign();
104
107
  return;
@@ -129,5 +132,6 @@ export function useWalletLogin(opts: UseWalletLoginOptions = {}): UseWalletLogin
129
132
  isConnected,
130
133
  address,
131
134
  dropped,
135
+ error: signIn ? null : (siwe?.error ?? null),
132
136
  };
133
137
  }
@@ -42,6 +42,8 @@ export type SIWEContextValue = Required<Omit<SIWEConfig, "onSign" | "subscribeNo
42
42
  nonce: ReturnType<typeof useQuery<string | null>>;
43
43
  session: ReturnType<typeof useQuery<SIWESession | null>>;
44
44
  status: StatusState;
45
+ /** What ended the last sign-in, while status is ERROR or REJECTED. */
46
+ error: Error | null;
45
47
  signIn: () => Promise<SIWESession | false>;
46
48
  resetStatus: () => void;
47
49
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SIWEContext.d.ts","sourceRoot":"","sources":["../../../src/connectkit/siwe/SIWEContext.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,eAAO,MAAM,WAAW;;;;;;CAMd,CAAC;AACX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEzE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IAKvB,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,CAAC,IAAI,EAAE;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC/B,aAAa,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,UAAU,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAGhC,OAAO,CAAC,EAAE,OAAO,CAAC;IAIlB,oBAAoB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAKjC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;IAI/C,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,qBAAqB,CAAC,CAAC,GACzF,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,qBAAqB,CAAC,GAAG;IACnD,KAAK,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAClD,OAAO,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC;IAC3C,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEJ,eAAO,MAAM,WAAW,kDAA+C,CAAC"}
1
+ {"version":3,"file":"SIWEContext.d.ts","sourceRoot":"","sources":["../../../src/connectkit/siwe/SIWEContext.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,eAAO,MAAM,WAAW;;;;;;CAMd,CAAC;AACX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEzE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IAKvB,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,CAAC,IAAI,EAAE;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC/B,aAAa,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,UAAU,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAGhC,OAAO,CAAC,EAAE,OAAO,CAAC;IAIlB,oBAAoB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAKjC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;IAI/C,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,qBAAqB,CAAC,CAAC,GACzF,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,qBAAqB,CAAC,GAAG;IACnD,KAAK,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAClD,OAAO,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,EAAE,WAAW,CAAC;IACpB,sEAAsE;IACtE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC;IAC3C,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEJ,eAAO,MAAM,WAAW,kDAA+C,CAAC"}
@@ -7,12 +7,6 @@ type Props = SIWEConfig & {
7
7
  };
8
8
  export declare const SIWE_NONCE_QUERY_KEY = "ckSiweNonce";
9
9
  export declare const SIWE_SESSION_QUERY_KEY = "ckSiweSession";
10
- /**
11
- * Sign-in over wagmi's account, mounted outside ConnectKitProvider.
12
- * @deprecated Goes in a later major. `SignInProvider` signs with whichever family the
13
- * connection store holds: `<SignInProvider {...kc.signInConfig(onSign)}>`,
14
- * or Web3Provider's `signIn` prop.
15
- */
16
10
  export declare const SIWEProvider: ({ children, enabled, nonceRefetchInterval, sessionRefetchInterval, signOutOnDisconnect, signOutOnAccountChange, signOutOnNetworkChange, onSignIn, onSignOut, ...siweConfig }: Props) => import("react/jsx-runtime").JSX.Element;
17
11
  export {};
18
12
  //# sourceMappingURL=SIWEProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SIWEProvider.d.ts","sourceRoot":"","sources":["../../../src/connectkit/siwe/SIWEProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmC,MAAM,OAAO,CAAC;AAMnE,OAAO,EAAe,UAAU,EAAe,WAAW,EAAE,MAAM,eAAe,CAAC;AAIlF,KAAK,KAAK,GAAG,UAAU,GAAG;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAClD,eAAO,MAAM,sBAAsB,kBAAkB,CAAC;AAKtD;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,8KAW1B,KAAK,4CA0NP,CAAC"}
1
+ {"version":3,"file":"SIWEProvider.d.ts","sourceRoot":"","sources":["../../../src/connectkit/siwe/SIWEProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmC,MAAM,OAAO,CAAC;AAMnE,OAAO,EAAe,UAAU,EAAe,WAAW,EAAE,MAAM,eAAe,CAAC;AAIlF,KAAK,KAAK,GAAG,UAAU,GAAG;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAClD,eAAO,MAAM,sBAAsB,kBAAkB,CAAC;AAyBtD,eAAO,MAAM,YAAY,GAAI,8KAW1B,KAAK,4CAyNP,CAAC"}
@@ -1,8 +1,9 @@
1
1
  import type { Chain } from "viem";
2
2
  import { type Config } from "wagmi";
3
+ import { StatusState } from "../connectkit/siwe/SIWEContext";
3
4
  import type { MobileConnectOptions } from "../connectkit/openConnector";
4
5
  import type { BrowserFlowOptions } from "./browserFlow";
5
- import type { KeycloakWalletResource } from "./types";
6
+ import { type KeycloakWalletResource } from "./types";
6
7
  export interface KeycloakWalletLoginProps {
7
8
  /** Defaults to the Keycloak base of the page it runs on. */
8
9
  baseUrl?: string;
@@ -30,11 +31,15 @@ export interface KeycloakWalletLoginProps {
30
31
  className?: string;
31
32
  /** Replaces the built-in button look, e.g. the theme's `kcButtonClass`. */
32
33
  buttonClassName?: string;
34
+ /** Replaces the built-in failure line look, e.g. the theme's `kcInputErrorMessageClass`. */
35
+ errorClassName?: string;
33
36
  /** The wagmi config to sign with; built from the app props and `chains` when absent. */
34
37
  wagmiConfig?: Config;
35
38
  }
36
39
  /** The wagmi config `<KeycloakWalletLogin>` builds when it is given none. */
37
40
  export declare function createKeycloakWalletConfig({ appName, appDescription, appUrl, appIcon, chains, }?: Pick<KeycloakWalletLoginProps, "appName" | "appDescription" | "appUrl" | "appIcon" | "chains">): Config;
41
+ /** The words a failed wallet sign-in shows; the raw reason stays on the error and in the console. */
42
+ export declare function walletLoginFailureMessage(status: StatusState, error: Error | null): string | undefined;
38
43
  /**
39
44
  * Wallet and GPG sign-in for a Keycloak login page, on the browser flow: the
40
45
  * signed credential posts to the page's authenticator. Carries its own wagmi,
@@ -1 +1 @@
1
- {"version":3,"file":"KeycloakWalletLogin.d.ts","sourceRoot":"","sources":["../../src/keycloak/KeycloakWalletLogin.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,KAAK,MAAM,EAA+B,MAAM,OAAO,CAAC;AAOjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGtD,MAAM,WAAW,wBAAwB;IACvC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACtC,kFAAkF;IAClF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,6EAA6E;AAC7E,wBAAgB,0BAA0B,CAAC,EACzC,OAAmB,EACnB,cAA2C,EAC3C,MAAuE,EACvE,OAAO,EACP,MAAsB,GACvB,GAAE,IAAI,CACL,wBAAwB,EACxB,SAAS,GAAG,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAC1D,GAAG,MAAM,CAgBd;AAwBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAkElE"}
1
+ {"version":3,"file":"KeycloakWalletLogin.d.ts","sourceRoot":"","sources":["../../src/keycloak/KeycloakWalletLogin.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,KAAK,MAAM,EAA+B,MAAM,OAAO,CAAC;AAKjE,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAG3E,MAAM,WAAW,wBAAwB;IACvC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACtC,kFAAkF;IAClF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,6EAA6E;AAC7E,wBAAgB,0BAA0B,CAAC,EACzC,OAAmB,EACnB,cAA2C,EAC3C,MAAuE,EACvE,OAAO,EACP,MAAsB,GACvB,GAAE,IAAI,CACL,wBAAwB,EACxB,SAAS,GAAG,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAC1D,GAAG,MAAM,CAgBd;AAiCD,qGAAqG;AACrG,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,KAAK,GAAG,IAAI,GAClB,MAAM,GAAG,SAAS,CAQpB;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAkElE"}
@@ -20,6 +20,8 @@ export interface UseWalletLoginResult {
20
20
  * connects afresh and clears it.
21
21
  */
22
22
  dropped: boolean;
23
+ /** What ended the last signature, while status is ERROR or REJECTED. */
24
+ error: Error | null;
23
25
  }
24
26
  /**
25
27
  * A wallet login button's behaviour. Pressing it while disconnected opens the
@@ -1 +1 @@
1
- {"version":3,"file":"useWalletLogin.d.ts","sourceRoot":"","sources":["../../src/keycloak/useWalletLogin.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAK1E,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,qBAA0B,GAAG,oBAAoB,CAgErF"}
1
+ {"version":3,"file":"useWalletLogin.d.ts","sourceRoot":"","sources":["../../src/keycloak/useWalletLogin.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAK1E,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,qBAA0B,GAAG,oBAAoB,CAkErF"}