accounts 0.6.0 → 0.6.2

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 (69) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/core/Adapter.d.ts +2 -2
  3. package/dist/core/Adapter.d.ts.map +1 -1
  4. package/dist/core/Client.d.ts +2 -2
  5. package/dist/core/Client.d.ts.map +1 -1
  6. package/dist/core/Client.js +13 -4
  7. package/dist/core/Client.js.map +1 -1
  8. package/dist/core/Provider.d.ts.map +1 -1
  9. package/dist/core/Provider.js +9 -2
  10. package/dist/core/Provider.js.map +1 -1
  11. package/dist/core/Schema.d.ts +22 -12
  12. package/dist/core/Schema.d.ts.map +1 -1
  13. package/dist/core/adapters/dialog.d.ts.map +1 -1
  14. package/dist/core/adapters/dialog.js +24 -4
  15. package/dist/core/adapters/dialog.js.map +1 -1
  16. package/dist/core/adapters/local.d.ts.map +1 -1
  17. package/dist/core/adapters/local.js +21 -3
  18. package/dist/core/adapters/local.js.map +1 -1
  19. package/dist/core/zod/rpc.d.ts +14 -9
  20. package/dist/core/zod/rpc.d.ts.map +1 -1
  21. package/dist/core/zod/rpc.js +8 -2
  22. package/dist/core/zod/rpc.js.map +1 -1
  23. package/dist/server/CliAuth.d.ts +11 -11
  24. package/dist/server/CliAuth.js +1 -1
  25. package/dist/server/CliAuth.js.map +1 -1
  26. package/dist/server/Handler.d.ts +4 -252
  27. package/dist/server/Handler.d.ts.map +1 -1
  28. package/dist/server/Handler.js +4 -573
  29. package/dist/server/Handler.js.map +1 -1
  30. package/dist/server/internal/handlers/codeAuth.d.ts +41 -0
  31. package/dist/server/internal/handlers/codeAuth.d.ts.map +1 -0
  32. package/dist/server/internal/handlers/codeAuth.js +104 -0
  33. package/dist/server/internal/handlers/codeAuth.js.map +1 -0
  34. package/dist/server/internal/handlers/feePayer.d.ts +73 -0
  35. package/dist/server/internal/handlers/feePayer.d.ts.map +1 -0
  36. package/dist/server/internal/handlers/feePayer.js +184 -0
  37. package/dist/server/internal/handlers/feePayer.js.map +1 -0
  38. package/dist/server/internal/handlers/relay.d.ts +148 -0
  39. package/dist/server/internal/handlers/relay.d.ts.map +1 -0
  40. package/dist/server/internal/handlers/relay.js +600 -0
  41. package/dist/server/internal/handlers/relay.js.map +1 -0
  42. package/dist/server/internal/handlers/utils.d.ts +12 -0
  43. package/dist/server/internal/handlers/utils.d.ts.map +1 -0
  44. package/dist/server/internal/handlers/utils.js +80 -0
  45. package/dist/server/internal/handlers/utils.js.map +1 -0
  46. package/dist/server/internal/handlers/webAuthn.d.ts +57 -0
  47. package/dist/server/internal/handlers/webAuthn.d.ts.map +1 -0
  48. package/dist/server/internal/handlers/webAuthn.js +143 -0
  49. package/dist/server/internal/handlers/webAuthn.js.map +1 -0
  50. package/package.json +2 -2
  51. package/src/core/Adapter.ts +2 -2
  52. package/src/core/Client.ts +13 -6
  53. package/src/core/Provider.connect.browser.test.ts +23 -2
  54. package/src/core/Provider.test.ts +292 -0
  55. package/src/core/Provider.ts +11 -3
  56. package/src/core/adapters/dialog.ts +21 -4
  57. package/src/core/adapters/local.ts +15 -3
  58. package/src/core/zod/rpc.ts +12 -2
  59. package/src/server/CliAuth.ts +1 -1
  60. package/src/server/Handler.test.ts +3 -418
  61. package/src/server/Handler.ts +5 -766
  62. package/src/server/internal/handlers/codeAuth.ts +148 -0
  63. package/src/server/internal/handlers/feePayer.test.ts +335 -0
  64. package/src/server/internal/handlers/feePayer.ts +271 -0
  65. package/src/server/internal/handlers/relay.test.ts +767 -0
  66. package/src/server/internal/handlers/relay.ts +817 -0
  67. package/src/server/internal/handlers/utils.ts +96 -0
  68. package/src/server/internal/handlers/webAuthn.test.ts +170 -0
  69. package/src/server/internal/handlers/webAuthn.ts +213 -0
@@ -0,0 +1,80 @@
1
+ import { Hex, RpcRequest, RpcResponse } from 'ox';
2
+ import { Transaction as core_Transaction } from 'ox/tempo';
3
+ import * as z from 'zod/mini';
4
+ export function resolveChainId(value) {
5
+ if (typeof value === 'number')
6
+ return value;
7
+ if (typeof value === 'bigint')
8
+ return Number(value);
9
+ if (typeof value === 'string' && Hex.validate(value))
10
+ return Hex.toNumber(value);
11
+ return undefined;
12
+ }
13
+ export function formatFillTransactionRequest(client, value) {
14
+ const format = client.chain?.formatters?.transactionRequest?.format;
15
+ if (!format)
16
+ return value;
17
+ return format({ ...value }, 'fillTransaction');
18
+ }
19
+ export function normalizeFillTransactionRequest(value) {
20
+ if (typeof value.to !== 'undefined' || typeof value.data !== 'undefined')
21
+ return value;
22
+ if (!Array.isArray(value.calls) || value.calls.length !== 1)
23
+ return value;
24
+ const [call] = value.calls;
25
+ const { calls: _, ...rest } = value;
26
+ return {
27
+ ...rest,
28
+ ...(typeof call?.data !== 'undefined' ? { data: call.data } : {}),
29
+ ...(typeof call?.to !== 'undefined' ? { to: call.to } : {}),
30
+ ...(typeof call?.value !== 'undefined' ? { value: normalizeFillValue(call.value) } : {}),
31
+ };
32
+ }
33
+ function normalizeFillValue(value) {
34
+ if (typeof value !== 'string' || !value.startsWith('0x'))
35
+ return value;
36
+ return BigInt(value === '0x' ? '0x0' : value);
37
+ }
38
+ export function normalizeTempoTransaction(value) {
39
+ if (!value)
40
+ throw new Error('Expected `tx` in eth_fillTransaction response.');
41
+ return core_Transaction.fromRpc({ type: '0x76', ...value });
42
+ }
43
+ export function rpcError(request, error) {
44
+ if (error instanceof RpcResponse.InvalidParamsError)
45
+ return Response.json(RpcResponse.from({ error }, { request }));
46
+ if (error instanceof RpcResponse.MethodNotSupportedError)
47
+ return Response.json(RpcResponse.from({ error }, { request }));
48
+ if (error.name === 'ZodError')
49
+ return Response.json(RpcResponse.from({
50
+ error: new RpcResponse.InvalidParamsError({
51
+ message: error.message,
52
+ }),
53
+ }, { request }));
54
+ const inner = resolveError(error);
55
+ const message = inner.message ?? error.message;
56
+ const code = inner.code ?? -32603;
57
+ const data = inner.data;
58
+ return Response.json(RpcResponse.from({
59
+ error: { code, message, ...(data ? { data } : {}) },
60
+ }, { request }));
61
+ }
62
+ export function rpcResult(request, result) {
63
+ return Response.json(RpcResponse.from({ result }, { request }));
64
+ }
65
+ export const parseParams = z.readonly(z.tuple([z.record(z.string(), z.unknown())]));
66
+ function resolveError(error) {
67
+ if (!error || typeof error !== 'object')
68
+ return {};
69
+ const e = error;
70
+ // Walk to the innermost cause with a numeric code (raw RPC error).
71
+ if (e.cause && typeof e.cause === 'object') {
72
+ const inner = resolveError(e.cause);
73
+ if (inner.message)
74
+ return inner;
75
+ }
76
+ if (typeof e.code === 'number' && typeof e.message === 'string')
77
+ return { message: e.message, code: e.code, data: e.data };
78
+ return {};
79
+ }
80
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/server/internal/handlers/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { type Handler, from } from '../../Handler.js';
2
+ import * as Kv from '../../Kv.js';
3
+ /**
4
+ * Instantiates a WebAuthn ceremony handler that manages registration and
5
+ * authentication flows server-side.
6
+ *
7
+ * Exposes 4 POST endpoints following the webauthx convention:
8
+ * - `POST /register/options` — generate credential creation options
9
+ * - `POST /register` — verify registration and store credential
10
+ * - `POST /login/options` — generate credential request options
11
+ * - `POST /login` — verify authentication
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { Handler, Kv } from 'accounts/server'
16
+ *
17
+ * const handler = Handler.webAuthn({
18
+ * kv: Kv.memory(),
19
+ * origin: 'https://example.com',
20
+ * rpId: 'example.com',
21
+ * })
22
+ *
23
+ * export default handler
24
+ * ```
25
+ *
26
+ * @param options - Options.
27
+ * @returns Request handler.
28
+ */
29
+ export declare function webAuthn(options: webAuthn.Options): Handler;
30
+ export declare namespace webAuthn {
31
+ type Options = from.Options & {
32
+ /** Maximum age of a challenge in seconds before it expires. @default 300 */
33
+ challengeTtl?: number | undefined;
34
+ /** Key-value store for challenges and credentials. */
35
+ kv: Kv.Kv;
36
+ /** Called after a successful registration. The returned response is merged onto the default JSON response. */
37
+ onRegister?: (parameters: {
38
+ credentialId: string;
39
+ publicKey: string;
40
+ request: Request;
41
+ }) => Response | Promise<Response> | void | Promise<void>;
42
+ /** Called after a successful authentication. The returned response is merged onto the default JSON response. */
43
+ onAuthenticate?: (parameters: {
44
+ credentialId: string;
45
+ publicKey: string;
46
+ userId?: string | undefined;
47
+ request: Request;
48
+ }) => Response | Promise<Response> | void | Promise<void>;
49
+ /** Expected origin(s) (e.g. `"https://example.com"` or `["https://a.com", "https://b.com"]`). */
50
+ origin: string | readonly string[];
51
+ /** Path prefix for the WebAuthn endpoints (e.g. `"/webauthn"`). @default "" */
52
+ path?: string | undefined;
53
+ /** Relying Party ID (e.g. `"example.com"`). */
54
+ rpId: string;
55
+ };
56
+ }
57
+ //# sourceMappingURL=webAuthn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webAuthn.d.ts","sourceRoot":"","sources":["../../../../src/server/internal/handlers/webAuthn.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,aAAa,CAAA;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAqI3D;AAED,MAAM,CAAC,OAAO,WAAW,QAAQ,CAAC;IAChC,KAAK,OAAO,GAAG,IAAI,CAAC,OAAO,GAAG;QAC5B,4EAA4E;QAC5E,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QACjC,sDAAsD;QACtD,EAAE,EAAE,EAAE,CAAC,EAAE,CAAA;QACT,8GAA8G;QAC9G,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE;YACxB,YAAY,EAAE,MAAM,CAAA;YACpB,SAAS,EAAE,MAAM,CAAA;YACjB,OAAO,EAAE,OAAO,CAAA;SACjB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACzD,gHAAgH;QAChH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE;YAC5B,YAAY,EAAE,MAAM,CAAA;YACpB,SAAS,EAAE,MAAM,CAAA;YACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YAC3B,OAAO,EAAE,OAAO,CAAA;SACjB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACzD,iGAAiG;QACjG,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;QAClC,+EAA+E;QAC/E,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QACzB,+CAA+C;QAC/C,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;CACF"}
@@ -0,0 +1,143 @@
1
+ import { Base64, Bytes, Hex } from 'ox';
2
+ import { Credential } from 'ox/webauthn';
3
+ import { Authentication, Registration, } from 'webauthx/server';
4
+ import { from } from '../../Handler.js';
5
+ import * as Kv from '../../Kv.js';
6
+ /**
7
+ * Instantiates a WebAuthn ceremony handler that manages registration and
8
+ * authentication flows server-side.
9
+ *
10
+ * Exposes 4 POST endpoints following the webauthx convention:
11
+ * - `POST /register/options` — generate credential creation options
12
+ * - `POST /register` — verify registration and store credential
13
+ * - `POST /login/options` — generate credential request options
14
+ * - `POST /login` — verify authentication
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { Handler, Kv } from 'accounts/server'
19
+ *
20
+ * const handler = Handler.webAuthn({
21
+ * kv: Kv.memory(),
22
+ * origin: 'https://example.com',
23
+ * rpId: 'example.com',
24
+ * })
25
+ *
26
+ * export default handler
27
+ * ```
28
+ *
29
+ * @param options - Options.
30
+ * @returns Request handler.
31
+ */
32
+ export function webAuthn(options) {
33
+ const { challengeTtl = 300, kv, onAuthenticate, onRegister, path = '', rpId, ...rest } = options;
34
+ const origin = options.origin;
35
+ const router = from(rest);
36
+ router.post(`${path}/register/options`, async (c) => {
37
+ try {
38
+ const body = await c.req.raw.json();
39
+ const { excludeCredentialIds, name, userId } = body;
40
+ const { challenge, options } = Registration.getOptions({
41
+ excludeCredentialIds,
42
+ name,
43
+ rp: { id: rpId, name: rpId },
44
+ ...(userId ? { user: { id: new TextEncoder().encode(userId), name } } : undefined),
45
+ });
46
+ await kv.set(`challenge:${challenge}`, Date.now());
47
+ return Response.json({ options });
48
+ }
49
+ catch (error) {
50
+ return Response.json({ error: error.message }, { status: 400 });
51
+ }
52
+ });
53
+ router.post(`${path}/register`, async (c) => {
54
+ try {
55
+ const credential = (await c.req.raw.json());
56
+ const deserialized = Credential.deserialize(credential);
57
+ const clientData = JSON.parse(Bytes.toString(new Uint8Array(deserialized.clientDataJSON)));
58
+ const challenge = Hex.fromBytes(Base64.toBytes(clientData.challenge));
59
+ const stored = await kv.get(`challenge:${challenge}`);
60
+ if (!stored || Date.now() - stored > challengeTtl * 1_000)
61
+ throw new Error('Missing or expired challenge');
62
+ await kv.delete(`challenge:${challenge}`);
63
+ const result = Registration.verify(credential, {
64
+ challenge,
65
+ origin,
66
+ rpId,
67
+ });
68
+ const { publicKey } = result.credential;
69
+ const credentialId = credential.id;
70
+ await kv.set(`credential:${credentialId}`, { publicKey });
71
+ const json = { credentialId, publicKey };
72
+ const hook = await onRegister?.({ credentialId, publicKey, request: c.req.raw });
73
+ return mergeResponse(json, hook);
74
+ }
75
+ catch (error) {
76
+ return Response.json({ error: error.message }, { status: 400 });
77
+ }
78
+ });
79
+ router.post(`${path}/login/options`, async (c) => {
80
+ try {
81
+ const body = await c.req.raw.json();
82
+ const { allowCredentialIds, challenge: requestChallenge, credentialId, mediation, } = body;
83
+ const { challenge, options: authOptions } = Authentication.getOptions({
84
+ challenge: requestChallenge,
85
+ credentialId: allowCredentialIds ?? credentialId,
86
+ rpId,
87
+ });
88
+ const options = mediation ? { ...authOptions, mediation } : authOptions;
89
+ await kv.set(`challenge:${challenge}`, Date.now());
90
+ return Response.json({ options });
91
+ }
92
+ catch (error) {
93
+ return Response.json({ error: error.message }, { status: 400 });
94
+ }
95
+ });
96
+ router.post(`${path}/login`, async (c) => {
97
+ try {
98
+ const response = (await c.req.raw.json());
99
+ const clientData = JSON.parse(response.metadata.clientDataJSON);
100
+ const challenge = Hex.fromBytes(Base64.toBytes(clientData.challenge));
101
+ const stored = await kv.get(`challenge:${challenge}`);
102
+ if (!stored || Date.now() - stored > challengeTtl * 1_000)
103
+ throw new Error('Missing or expired challenge');
104
+ await kv.delete(`challenge:${challenge}`);
105
+ const credentialData = await kv.get(`credential:${response.id}`);
106
+ if (!credentialData)
107
+ throw new Error('Unknown credential');
108
+ const valid = Authentication.verify(response, {
109
+ challenge,
110
+ origin,
111
+ publicKey: credentialData.publicKey,
112
+ rpId,
113
+ });
114
+ if (!valid)
115
+ throw new Error('Authentication failed');
116
+ const rawResponse = response.raw?.response;
117
+ const userHandle = rawResponse?.userHandle;
118
+ const json = {
119
+ credentialId: response.id,
120
+ publicKey: credentialData.publicKey,
121
+ ...(userHandle && userHandle.length > 0 ? { userId: userHandle } : undefined),
122
+ };
123
+ const hook = await onAuthenticate?.({ ...json, request: c.req.raw });
124
+ return mergeResponse(json, hook);
125
+ }
126
+ catch (error) {
127
+ return Response.json({ error: error.message }, { status: 400 });
128
+ }
129
+ });
130
+ return router;
131
+ }
132
+ async function mergeResponse(json, hook) {
133
+ if (!hook)
134
+ return Response.json(json);
135
+ const extra = (await hook.json().catch(() => ({})));
136
+ const headers = new Headers(hook.headers);
137
+ headers.set('content-type', 'application/json');
138
+ return new Response(JSON.stringify({ ...json, ...extra }), {
139
+ headers,
140
+ status: hook.status,
141
+ });
142
+ }
143
+ //# sourceMappingURL=webAuthn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webAuthn.js","sourceRoot":"","sources":["../../../../src/server/internal/handlers/webAuthn.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,13 +2,13 @@
2
2
  "name": "accounts",
3
3
  "description": "Tempo Accounts SDK",
4
4
  "type": "module",
5
- "version": "0.6.0",
5
+ "version": "0.6.2",
6
6
  "dependencies": {
7
7
  "hono": "^4.12.12",
8
8
  "idb-keyval": "^6.2.2",
9
9
  "mipd": "^0.0.7",
10
10
  "mppx": "^0.5.10",
11
- "ox": "~0.14.7",
11
+ "ox": "~0.14.15",
12
12
  "webauthx": "~0.1.0",
13
13
  "zod": "^4.3.6",
14
14
  "zustand": "^5.0.11"
@@ -133,8 +133,8 @@ export declare namespace getClient {
133
133
  type Options = {
134
134
  /** Chain ID. Defaults to the active chain. */
135
135
  chainId?: number | undefined
136
- /** Fee payer service URL. */
137
- feePayer?: string | undefined
136
+ /** Fee payer service URL, or `false` to opt out of fee payers for this transaction if set globally. */
137
+ feePayer?: string | false | undefined
138
138
  }
139
139
  }
140
140
 
@@ -20,12 +20,18 @@ export function fromChainId(
20
20
  options: fromChainId.Options,
21
21
  ): Client<Transport, typeof tempo> {
22
22
  const { chains, feePayer: feePayerOption, provider, store } = options
23
- const feePayerUrl = typeof feePayerOption === 'string' ? feePayerOption : feePayerOption?.url
24
- const precedence =
25
- (typeof feePayerOption === 'object' ? feePayerOption?.precedence : undefined) ??
26
- 'fee-payer-first'
23
+ const feePayerUrl = (() => {
24
+ if (feePayerOption === false) return undefined
25
+ if (typeof feePayerOption === 'string') return feePayerOption
26
+ return feePayerOption?.url
27
+ })()
28
+ const precedence = (() => {
29
+ if (typeof feePayerOption === 'object' && feePayerOption !== null)
30
+ return feePayerOption.precedence ?? 'fee-payer-first'
31
+ return 'fee-payer-first'
32
+ })()
27
33
  const id = chainId ?? store.getState().chainId
28
- const key = `${id}:${provider ? 'p' : ''}:${feePayerUrl ?? ''}:${precedence}`
34
+ const key = `${id}:${provider ? 'p' : ''}:${feePayerOption === false ? 'no-fp' : (feePayerUrl ?? '')}:${precedence}`
29
35
  let client = clients.get(key)
30
36
  if (!client) {
31
37
  const chain = chains.find((c) => c.id === id) ?? chains[0]!
@@ -44,9 +50,10 @@ export declare namespace fromChainId {
44
50
  type Options = {
45
51
  /** Supported chains. */
46
52
  chains: readonly [Chain, ...Chain[]]
47
- /** Fee payer configuration. A URL string or config object with `url` and `precedence`. */
53
+ /** Fee payer configuration. A URL string, config object, or `false` to opt out. */
48
54
  feePayer?:
49
55
  | string
56
+ | false
50
57
  | {
51
58
  /** Fee payer service URL. */
52
59
  url: string
@@ -1,7 +1,7 @@
1
- import { Hex } from 'ox'
1
+ import { Hex, WebCryptoP256 } from 'ox'
2
2
  import { type Address, createClient, defineChain, parseUnits } from 'viem'
3
3
  import { tempoLocalnet, tempoModerato } from 'viem/chains'
4
- import { Actions, Addresses } from 'viem/tempo'
4
+ import { Account as TempoAccount, Actions, Addresses } from 'viem/tempo'
5
5
  import { afterEach, beforeAll, describe, expect, test } from 'vp/test'
6
6
 
7
7
  import { accounts, http } from '../../test/config.js'
@@ -311,6 +311,27 @@ describe('wallet_authorizeAccessKey', () => {
311
311
  )
312
312
  expect(result.keyAuthorization.address).toMatch(/^0x[0-9a-fA-F]{40}$/)
313
313
  })
314
+
315
+ test('behavior: authorizes an external p256 access key via iframe confirm', async () => {
316
+ provider = getProvider()
317
+ await connectViaIframe(provider)
318
+
319
+ const keyPair = await WebCryptoP256.createKeyPair()
320
+ const accessKeyAccount = TempoAccount.fromWebCryptoP256(keyPair)
321
+
322
+ const result = await interact(
323
+ provider.request({
324
+ method: 'wallet_authorizeAccessKey',
325
+ params: [{ ...accessKeyAccount, expiry: Expiry.days(1) }],
326
+ }),
327
+ async (iframe) => {
328
+ await iframe.getByTestId('confirm').click()
329
+ },
330
+ )
331
+
332
+ expect(result.keyAuthorization.keyId).toBe(accessKeyAccount.address)
333
+ expect(result.keyAuthorization.keyType).toMatchInlineSnapshot(`"p256"`)
334
+ })
314
335
  })
315
336
 
316
337
  describe('wallet_revokeAccessKey', () => {