kentucky-signer-viem 0.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,714 @@
1
+ // src/account.ts
2
+ import {
3
+ hashMessage,
4
+ hashTypedData,
5
+ keccak256,
6
+ serializeTransaction
7
+ } from "viem";
8
+ import { toAccount } from "viem/accounts";
9
+
10
+ // src/client.ts
11
+ var KentuckySignerError = class extends Error {
12
+ constructor(message, code, details) {
13
+ super(message);
14
+ this.code = code;
15
+ this.details = details;
16
+ this.name = "KentuckySignerError";
17
+ }
18
+ };
19
+ var KentuckySignerClient = class {
20
+ constructor(options) {
21
+ this.baseUrl = options.baseUrl.replace(/\/$/, "");
22
+ this.fetchImpl = options.fetch ?? globalThis.fetch;
23
+ this.timeout = options.timeout ?? 3e4;
24
+ }
25
+ /**
26
+ * Make an authenticated request to the API
27
+ */
28
+ async request(path, options = {}) {
29
+ const { token, ...fetchOptions } = options;
30
+ const headers = {
31
+ "Content-Type": "application/json",
32
+ ...options.headers
33
+ };
34
+ if (token) {
35
+ ;
36
+ headers["Authorization"] = `Bearer ${token}`;
37
+ }
38
+ const controller = new AbortController();
39
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
40
+ try {
41
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
42
+ ...fetchOptions,
43
+ headers,
44
+ signal: controller.signal
45
+ });
46
+ const data = await response.json();
47
+ if (!response.ok || data.success === false) {
48
+ const error = data;
49
+ throw new KentuckySignerError(
50
+ error.error?.message ?? "Unknown error",
51
+ error.error?.code ?? "UNKNOWN_ERROR",
52
+ error.error?.details
53
+ );
54
+ }
55
+ return data;
56
+ } finally {
57
+ clearTimeout(timeoutId);
58
+ }
59
+ }
60
+ /**
61
+ * Get a challenge for passkey authentication
62
+ *
63
+ * @param accountId - Account ID to authenticate
64
+ * @returns Challenge response with 32-byte challenge
65
+ */
66
+ async getChallenge(accountId) {
67
+ return this.request("/api/auth/challenge", {
68
+ method: "POST",
69
+ body: JSON.stringify({ account_id: accountId })
70
+ });
71
+ }
72
+ /**
73
+ * Authenticate with a passkey credential
74
+ *
75
+ * @param accountId - Account ID to authenticate
76
+ * @param credential - WebAuthn credential from navigator.credentials.get()
77
+ * @returns Authentication response with JWT token
78
+ */
79
+ async authenticatePasskey(accountId, credential) {
80
+ return this.request("/api/auth/passkey", {
81
+ method: "POST",
82
+ body: JSON.stringify({
83
+ account_id: accountId,
84
+ credential_id: credential.credentialId,
85
+ client_data_json: credential.clientDataJSON,
86
+ authenticator_data: credential.authenticatorData,
87
+ signature: credential.signature,
88
+ user_handle: credential.userHandle
89
+ })
90
+ });
91
+ }
92
+ /**
93
+ * Refresh an authentication token
94
+ *
95
+ * @param token - Current JWT token
96
+ * @returns New authentication response with fresh token
97
+ */
98
+ async refreshToken(token) {
99
+ return this.request("/api/auth/refresh", {
100
+ method: "POST",
101
+ token
102
+ });
103
+ }
104
+ /**
105
+ * Logout and invalidate token
106
+ *
107
+ * @param token - JWT token to invalidate
108
+ */
109
+ async logout(token) {
110
+ await this.request("/api/auth/logout", {
111
+ method: "POST",
112
+ token
113
+ });
114
+ }
115
+ /**
116
+ * Get account information
117
+ *
118
+ * @param accountId - Account ID
119
+ * @param token - JWT token
120
+ * @returns Account info with addresses and passkeys
121
+ */
122
+ async getAccountInfo(accountId, token) {
123
+ return this.request(`/api/accounts/${accountId}`, {
124
+ method: "GET",
125
+ token
126
+ });
127
+ }
128
+ /**
129
+ * Check if an account exists
130
+ *
131
+ * @param accountId - Account ID
132
+ * @param token - JWT token
133
+ * @returns True if account exists
134
+ */
135
+ async accountExists(accountId, token) {
136
+ try {
137
+ await this.request(`/api/accounts/${accountId}`, {
138
+ method: "HEAD",
139
+ token
140
+ });
141
+ return true;
142
+ } catch {
143
+ return false;
144
+ }
145
+ }
146
+ /**
147
+ * Sign an EVM transaction hash
148
+ *
149
+ * @param request - Sign request with tx_hash and chain_id
150
+ * @param token - JWT token
151
+ * @returns Signature response with r, s, v components
152
+ */
153
+ async signEvmTransaction(request, token) {
154
+ return this.request("/api/sign/evm", {
155
+ method: "POST",
156
+ token,
157
+ body: JSON.stringify(request)
158
+ });
159
+ }
160
+ /**
161
+ * Sign a raw hash for EVM
162
+ *
163
+ * Convenience method that wraps signEvmTransaction.
164
+ *
165
+ * @param hash - 32-byte hash to sign (hex encoded with 0x prefix)
166
+ * @param chainId - Chain ID
167
+ * @param token - JWT token
168
+ * @returns Full signature (hex encoded with 0x prefix)
169
+ */
170
+ async signHash(hash, chainId, token) {
171
+ const response = await this.signEvmTransaction(
172
+ { tx_hash: hash, chain_id: chainId },
173
+ token
174
+ );
175
+ return response.signature.full;
176
+ }
177
+ /**
178
+ * Create a new account with passkey authentication
179
+ *
180
+ * @param credential - WebAuthn credential from navigator.credentials.create()
181
+ * @returns Account creation response with account ID and addresses
182
+ */
183
+ async createAccountWithPasskey(credential) {
184
+ return this.request("/api/accounts/create/passkey", {
185
+ method: "POST",
186
+ body: JSON.stringify({
187
+ credential_id: credential.credentialId,
188
+ public_key: credential.publicKey,
189
+ client_data_json: credential.clientDataJSON,
190
+ authenticator_data: credential.authenticatorData
191
+ })
192
+ });
193
+ }
194
+ /**
195
+ * Create a new account with password authentication
196
+ *
197
+ * @param request - Password and confirmation
198
+ * @returns Account creation response with account ID and addresses
199
+ */
200
+ async createAccountWithPassword(request) {
201
+ return this.request("/api/accounts/create/password", {
202
+ method: "POST",
203
+ body: JSON.stringify(request)
204
+ });
205
+ }
206
+ /**
207
+ * Authenticate with password
208
+ *
209
+ * @param request - Account ID and password
210
+ * @returns Authentication response with JWT token
211
+ */
212
+ async authenticatePassword(request) {
213
+ return this.request("/api/auth/password", {
214
+ method: "POST",
215
+ body: JSON.stringify(request)
216
+ });
217
+ }
218
+ /**
219
+ * Health check
220
+ *
221
+ * @returns True if the API is healthy
222
+ */
223
+ async healthCheck() {
224
+ try {
225
+ const response = await this.request("/api/health", {
226
+ method: "GET"
227
+ });
228
+ return response.status === "ok";
229
+ } catch {
230
+ return false;
231
+ }
232
+ }
233
+ /**
234
+ * Get API version
235
+ *
236
+ * @returns Version string
237
+ */
238
+ async getVersion() {
239
+ const response = await this.request("/api/version", {
240
+ method: "GET"
241
+ });
242
+ return response.version;
243
+ }
244
+ };
245
+ function createClient(options) {
246
+ return new KentuckySignerClient(options);
247
+ }
248
+
249
+ // src/account.ts
250
+ function createKentuckySignerAccount(options) {
251
+ const { config, defaultChainId = 1, onSessionExpired } = options;
252
+ let session = options.session;
253
+ const client = new KentuckySignerClient({ baseUrl: config.baseUrl });
254
+ async function getToken() {
255
+ if (Date.now() + 6e4 >= session.expiresAt) {
256
+ if (onSessionExpired) {
257
+ session = await onSessionExpired();
258
+ } else {
259
+ throw new KentuckySignerError(
260
+ "Session expired",
261
+ "SESSION_EXPIRED",
262
+ "Please re-authenticate with your passkey"
263
+ );
264
+ }
265
+ }
266
+ return session.token;
267
+ }
268
+ async function signHash(hash, chainId) {
269
+ const token = await getToken();
270
+ const response = await client.signEvmTransaction(
271
+ { tx_hash: hash, chain_id: chainId },
272
+ token
273
+ );
274
+ return response.signature.full;
275
+ }
276
+ function parseSignature(signature) {
277
+ const r = `0x${signature.slice(2, 66)}`;
278
+ const s = `0x${signature.slice(66, 130)}`;
279
+ const v = BigInt(`0x${signature.slice(130, 132)}`);
280
+ return { r, s, v };
281
+ }
282
+ const account = toAccount({
283
+ address: session.evmAddress,
284
+ /**
285
+ * Sign a message
286
+ *
287
+ * Supports string messages, hex messages, and raw bytes.
288
+ */
289
+ async signMessage({ message }) {
290
+ const messageHash = hashMessage(message);
291
+ return signHash(messageHash, defaultChainId);
292
+ },
293
+ /**
294
+ * Sign a transaction
295
+ *
296
+ * Serializes the transaction, hashes it, signs via Kentucky Signer,
297
+ * and returns the signed serialized transaction.
298
+ */
299
+ async signTransaction(transaction) {
300
+ const chainId = transaction.chainId ?? defaultChainId;
301
+ const serializedUnsigned = serializeTransaction(transaction);
302
+ const txHash = keccak256(serializedUnsigned);
303
+ const signature = await signHash(txHash, chainId);
304
+ const { r, s, v } = parseSignature(signature);
305
+ let yParity;
306
+ if (transaction.type === "eip1559" || transaction.type === "eip2930" || transaction.type === "eip4844" || transaction.type === "eip7702") {
307
+ yParity = Number(v) - 27;
308
+ } else {
309
+ yParity = Number(v);
310
+ }
311
+ const serializedSigned = serializeTransaction(transaction, {
312
+ r,
313
+ s,
314
+ v: BigInt(yParity),
315
+ yParity
316
+ });
317
+ return serializedSigned;
318
+ },
319
+ /**
320
+ * Sign typed data (EIP-712)
321
+ */
322
+ async signTypedData(typedData) {
323
+ const hash = hashTypedData(typedData);
324
+ return signHash(hash, defaultChainId);
325
+ }
326
+ });
327
+ account.source = "kentuckySigner";
328
+ account.accountId = config.accountId;
329
+ account.session = session;
330
+ account.updateSession = (newSession) => {
331
+ session = newSession;
332
+ if (newSession.evmAddress !== account.address) {
333
+ ;
334
+ account.address = newSession.evmAddress;
335
+ }
336
+ };
337
+ return account;
338
+ }
339
+ function createServerAccount(baseUrl, accountId, token, evmAddress, chainId = 1) {
340
+ const session = {
341
+ token,
342
+ accountId,
343
+ evmAddress,
344
+ expiresAt: Date.now() + 36e5
345
+ // 1 hour default
346
+ };
347
+ return createKentuckySignerAccount({
348
+ config: { baseUrl, accountId },
349
+ session,
350
+ defaultChainId: chainId
351
+ });
352
+ }
353
+
354
+ // src/utils.ts
355
+ function base64UrlEncode(data) {
356
+ let base64;
357
+ if (typeof Buffer !== "undefined") {
358
+ base64 = Buffer.from(data).toString("base64");
359
+ } else {
360
+ const binary = Array.from(data).map((byte) => String.fromCharCode(byte)).join("");
361
+ base64 = btoa(binary);
362
+ }
363
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
364
+ }
365
+ function base64UrlDecode(str) {
366
+ let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
367
+ const padding = (4 - base64.length % 4) % 4;
368
+ base64 += "=".repeat(padding);
369
+ if (typeof Buffer !== "undefined") {
370
+ return new Uint8Array(Buffer.from(base64, "base64"));
371
+ } else {
372
+ const binary = atob(base64);
373
+ const bytes = new Uint8Array(binary.length);
374
+ for (let i = 0; i < binary.length; i++) {
375
+ bytes[i] = binary.charCodeAt(i);
376
+ }
377
+ return bytes;
378
+ }
379
+ }
380
+ function hexToBytes(hex) {
381
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
382
+ const bytes = new Uint8Array(cleanHex.length / 2);
383
+ for (let i = 0; i < bytes.length; i++) {
384
+ bytes[i] = parseInt(cleanHex.slice(i * 2, i * 2 + 2), 16);
385
+ }
386
+ return bytes;
387
+ }
388
+ function bytesToHex(bytes, withPrefix = true) {
389
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
390
+ return withPrefix ? `0x${hex}` : hex;
391
+ }
392
+ function isValidAccountId(accountId) {
393
+ return /^[0-9a-fA-F]{64}$/.test(accountId);
394
+ }
395
+ function isValidEvmAddress(address) {
396
+ return /^0x[0-9a-fA-F]{40}$/.test(address);
397
+ }
398
+ function sleep(ms) {
399
+ return new Promise((resolve) => setTimeout(resolve, ms));
400
+ }
401
+ async function withRetry(fn, maxRetries = 3, baseDelay = 1e3) {
402
+ let lastError;
403
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
404
+ try {
405
+ return await fn();
406
+ } catch (error) {
407
+ lastError = error;
408
+ if (attempt < maxRetries) {
409
+ const delay = baseDelay * Math.pow(2, attempt);
410
+ await sleep(delay);
411
+ }
412
+ }
413
+ }
414
+ throw lastError;
415
+ }
416
+ function parseJwt(token) {
417
+ const parts = token.split(".");
418
+ if (parts.length !== 3) {
419
+ throw new Error("Invalid JWT format");
420
+ }
421
+ const payload = base64UrlDecode(parts[1]);
422
+ const text = new TextDecoder().decode(payload);
423
+ return JSON.parse(text);
424
+ }
425
+ function getJwtExpiration(token) {
426
+ try {
427
+ const payload = parseJwt(token);
428
+ if (typeof payload.exp === "number") {
429
+ return payload.exp * 1e3;
430
+ }
431
+ return null;
432
+ } catch {
433
+ return null;
434
+ }
435
+ }
436
+ function formatError(error) {
437
+ if (error instanceof Error) {
438
+ return error.message;
439
+ }
440
+ if (typeof error === "string") {
441
+ return error;
442
+ }
443
+ return "An unknown error occurred";
444
+ }
445
+
446
+ // src/auth.ts
447
+ function isWebAuthnAvailable() {
448
+ return typeof window !== "undefined" && typeof window.PublicKeyCredential !== "undefined" && typeof navigator.credentials !== "undefined";
449
+ }
450
+ var MemoryTokenStorage = class {
451
+ constructor() {
452
+ this.token = null;
453
+ this.expiresAt = 0;
454
+ }
455
+ async getToken() {
456
+ if (this.token && Date.now() < this.expiresAt) {
457
+ return this.token;
458
+ }
459
+ return null;
460
+ }
461
+ async setToken(token, expiresAt) {
462
+ this.token = token;
463
+ this.expiresAt = expiresAt;
464
+ }
465
+ async clearToken() {
466
+ this.token = null;
467
+ this.expiresAt = 0;
468
+ }
469
+ };
470
+ var LocalStorageTokenStorage = class {
471
+ constructor(keyPrefix = "kentucky_signer") {
472
+ this.keyPrefix = keyPrefix;
473
+ }
474
+ async getToken() {
475
+ if (typeof localStorage === "undefined") return null;
476
+ const token = localStorage.getItem(`${this.keyPrefix}_token`);
477
+ const expiresAt = localStorage.getItem(`${this.keyPrefix}_expires`);
478
+ if (token && expiresAt && Date.now() < parseInt(expiresAt, 10)) {
479
+ return token;
480
+ }
481
+ await this.clearToken();
482
+ return null;
483
+ }
484
+ async setToken(token, expiresAt) {
485
+ if (typeof localStorage === "undefined") return;
486
+ localStorage.setItem(`${this.keyPrefix}_token`, token);
487
+ localStorage.setItem(`${this.keyPrefix}_expires`, expiresAt.toString());
488
+ }
489
+ async clearToken() {
490
+ if (typeof localStorage === "undefined") return;
491
+ localStorage.removeItem(`${this.keyPrefix}_token`);
492
+ localStorage.removeItem(`${this.keyPrefix}_expires`);
493
+ }
494
+ };
495
+ function credentialToPasskey(credential) {
496
+ const response = credential.response;
497
+ return {
498
+ credentialId: base64UrlEncode(new Uint8Array(credential.rawId)),
499
+ clientDataJSON: base64UrlEncode(new Uint8Array(response.clientDataJSON)),
500
+ authenticatorData: base64UrlEncode(new Uint8Array(response.authenticatorData)),
501
+ signature: base64UrlEncode(new Uint8Array(response.signature)),
502
+ userHandle: response.userHandle ? base64UrlEncode(new Uint8Array(response.userHandle)) : void 0
503
+ };
504
+ }
505
+ async function authenticateWithPasskey(options) {
506
+ if (!isWebAuthnAvailable()) {
507
+ throw new KentuckySignerError(
508
+ "WebAuthn is not available in this environment",
509
+ "WEBAUTHN_NOT_AVAILABLE",
510
+ "Use authenticateWithToken() for server-side authentication"
511
+ );
512
+ }
513
+ const client = new KentuckySignerClient({ baseUrl: options.baseUrl });
514
+ const challengeResponse = await client.getChallenge(options.accountId);
515
+ const challengeBytes = base64UrlDecode(challengeResponse.challenge);
516
+ const credentialRequestOptions = {
517
+ publicKey: {
518
+ challenge: challengeBytes.buffer,
519
+ timeout: 6e4,
520
+ rpId: options.rpId ?? window.location.hostname,
521
+ userVerification: "preferred",
522
+ allowCredentials: options.allowCredentials?.map((id) => ({
523
+ type: "public-key",
524
+ id: base64UrlDecode(id).buffer
525
+ }))
526
+ }
527
+ };
528
+ const credential = await navigator.credentials.get(
529
+ credentialRequestOptions
530
+ );
531
+ if (!credential) {
532
+ throw new KentuckySignerError(
533
+ "User cancelled passkey authentication",
534
+ "USER_CANCELLED"
535
+ );
536
+ }
537
+ const passkeyCredential = credentialToPasskey(credential);
538
+ const authResponse = await client.authenticatePasskey(
539
+ options.accountId,
540
+ passkeyCredential
541
+ );
542
+ const accountInfo = await client.getAccountInfo(
543
+ options.accountId,
544
+ authResponse.token
545
+ );
546
+ const expiresAt = Date.now() + authResponse.expires_in * 1e3;
547
+ return {
548
+ token: authResponse.token,
549
+ accountId: options.accountId,
550
+ evmAddress: accountInfo.addresses.evm,
551
+ btcAddress: accountInfo.addresses.bitcoin,
552
+ solAddress: accountInfo.addresses.solana,
553
+ expiresAt
554
+ };
555
+ }
556
+ async function authenticateWithToken(baseUrl, accountId, token, expiresAt) {
557
+ const client = new KentuckySignerClient({ baseUrl });
558
+ const accountInfo = await client.getAccountInfo(accountId, token);
559
+ return {
560
+ token,
561
+ accountId,
562
+ evmAddress: accountInfo.addresses.evm,
563
+ btcAddress: accountInfo.addresses.bitcoin,
564
+ solAddress: accountInfo.addresses.solana,
565
+ expiresAt: expiresAt ?? Date.now() + 36e5
566
+ // Default 1 hour if not specified
567
+ };
568
+ }
569
+ async function registerPasskey(options) {
570
+ if (!isWebAuthnAvailable()) {
571
+ throw new KentuckySignerError(
572
+ "WebAuthn is not available in this environment",
573
+ "WEBAUTHN_NOT_AVAILABLE"
574
+ );
575
+ }
576
+ const userId = new Uint8Array(32);
577
+ crypto.getRandomValues(userId);
578
+ const challenge = new Uint8Array(32);
579
+ crypto.getRandomValues(challenge);
580
+ const createOptions = {
581
+ publicKey: {
582
+ challenge,
583
+ rp: {
584
+ name: options.rpName ?? "Kentucky Signer",
585
+ id: options.rpId ?? window.location.hostname
586
+ },
587
+ user: {
588
+ id: userId,
589
+ name: options.username ?? "user@example.com",
590
+ displayName: options.username ?? "User"
591
+ },
592
+ pubKeyCredParams: [
593
+ { type: "public-key", alg: -7 },
594
+ // ES256 (P-256)
595
+ { type: "public-key", alg: -257 }
596
+ // RS256
597
+ ],
598
+ authenticatorSelection: {
599
+ authenticatorAttachment: "platform",
600
+ userVerification: "preferred",
601
+ residentKey: "preferred"
602
+ },
603
+ timeout: 6e4,
604
+ attestation: "none"
605
+ }
606
+ };
607
+ const credential = await navigator.credentials.create(
608
+ createOptions
609
+ );
610
+ if (!credential) {
611
+ throw new KentuckySignerError(
612
+ "User cancelled passkey registration",
613
+ "USER_CANCELLED"
614
+ );
615
+ }
616
+ const response = credential.response;
617
+ const publicKeyBytes = response.getPublicKey?.();
618
+ if (!publicKeyBytes) {
619
+ throw new KentuckySignerError(
620
+ "Failed to get public key from credential",
621
+ "PUBLIC_KEY_ERROR"
622
+ );
623
+ }
624
+ return {
625
+ credentialId: base64UrlEncode(new Uint8Array(credential.rawId)),
626
+ clientDataJSON: base64UrlEncode(new Uint8Array(response.clientDataJSON)),
627
+ authenticatorData: base64UrlEncode(new Uint8Array(response.getAuthenticatorData())),
628
+ signature: "",
629
+ // Not applicable for registration
630
+ publicKey: base64UrlEncode(new Uint8Array(publicKeyBytes))
631
+ };
632
+ }
633
+ function isSessionValid(session, bufferMs = 6e4) {
634
+ return Date.now() + bufferMs < session.expiresAt;
635
+ }
636
+ async function refreshSessionIfNeeded(session, baseUrl, bufferMs = 6e4) {
637
+ if (isSessionValid(session, bufferMs)) {
638
+ return session;
639
+ }
640
+ const client = new KentuckySignerClient({ baseUrl });
641
+ const authResponse = await client.refreshToken(session.token);
642
+ return {
643
+ ...session,
644
+ token: authResponse.token,
645
+ expiresAt: Date.now() + authResponse.expires_in * 1e3
646
+ };
647
+ }
648
+ async function authenticateWithPassword(options) {
649
+ const client = new KentuckySignerClient({ baseUrl: options.baseUrl });
650
+ const authResponse = await client.authenticatePassword({
651
+ account_id: options.accountId,
652
+ password: options.password
653
+ });
654
+ const accountInfo = await client.getAccountInfo(
655
+ options.accountId,
656
+ authResponse.token
657
+ );
658
+ const expiresAt = Date.now() + authResponse.expires_in * 1e3;
659
+ return {
660
+ token: authResponse.token,
661
+ accountId: options.accountId,
662
+ evmAddress: accountInfo.addresses.evm,
663
+ btcAddress: accountInfo.addresses.bitcoin,
664
+ solAddress: accountInfo.addresses.solana,
665
+ expiresAt
666
+ };
667
+ }
668
+ async function createAccountWithPassword(options) {
669
+ if (options.password !== options.confirmation) {
670
+ throw new KentuckySignerError(
671
+ "Password and confirmation do not match",
672
+ "PASSWORD_MISMATCH"
673
+ );
674
+ }
675
+ if (options.password.length < 8 || options.password.length > 128) {
676
+ throw new KentuckySignerError(
677
+ "Password must be 8-128 characters",
678
+ "INVALID_PASSWORD"
679
+ );
680
+ }
681
+ const client = new KentuckySignerClient({ baseUrl: options.baseUrl });
682
+ return client.createAccountWithPassword({
683
+ password: options.password,
684
+ confirmation: options.confirmation
685
+ });
686
+ }
687
+ export {
688
+ KentuckySignerClient,
689
+ KentuckySignerError,
690
+ LocalStorageTokenStorage,
691
+ MemoryTokenStorage,
692
+ authenticateWithPasskey,
693
+ authenticateWithPassword,
694
+ authenticateWithToken,
695
+ base64UrlDecode,
696
+ base64UrlEncode,
697
+ bytesToHex,
698
+ createAccountWithPassword,
699
+ createClient,
700
+ createKentuckySignerAccount,
701
+ createServerAccount,
702
+ formatError,
703
+ getJwtExpiration,
704
+ hexToBytes,
705
+ isSessionValid,
706
+ isValidAccountId,
707
+ isValidEvmAddress,
708
+ isWebAuthnAvailable,
709
+ parseJwt,
710
+ refreshSessionIfNeeded,
711
+ registerPasskey,
712
+ withRetry
713
+ };
714
+ //# sourceMappingURL=index.mjs.map