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/README.md +428 -0
- package/dist/index.d.mts +603 -0
- package/dist/index.d.ts +603 -0
- package/dist/index.js +760 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +714 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +288 -0
- package/dist/react/index.d.ts +288 -0
- package/dist/react/index.js +815 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +791 -0
- package/dist/react/index.mjs.map +1 -0
- package/package.json +60 -0
- package/src/account.ts +255 -0
- package/src/auth.ts +427 -0
- package/src/client.ts +308 -0
- package/src/index.ts +73 -0
- package/src/react/context.tsx +317 -0
- package/src/react/hooks.ts +287 -0
- package/src/react/index.ts +31 -0
- package/src/types.ts +237 -0
- package/src/utils.ts +197 -0
package/src/utils.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Kentucky Signer Viem integration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base64URL encode a Uint8Array
|
|
7
|
+
*
|
|
8
|
+
* @param data - Data to encode
|
|
9
|
+
* @returns Base64URL encoded string (no padding)
|
|
10
|
+
*/
|
|
11
|
+
export function base64UrlEncode(data: Uint8Array): string {
|
|
12
|
+
// Convert to regular base64
|
|
13
|
+
let base64: string
|
|
14
|
+
if (typeof Buffer !== 'undefined') {
|
|
15
|
+
// Node.js
|
|
16
|
+
base64 = Buffer.from(data).toString('base64')
|
|
17
|
+
} else {
|
|
18
|
+
// Browser
|
|
19
|
+
const binary = Array.from(data)
|
|
20
|
+
.map((byte) => String.fromCharCode(byte))
|
|
21
|
+
.join('')
|
|
22
|
+
base64 = btoa(binary)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Convert to base64url (replace + with -, / with _, remove padding)
|
|
26
|
+
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Base64URL decode a string to Uint8Array
|
|
31
|
+
*
|
|
32
|
+
* @param str - Base64URL encoded string
|
|
33
|
+
* @returns Decoded bytes
|
|
34
|
+
*/
|
|
35
|
+
export function base64UrlDecode(str: string): Uint8Array {
|
|
36
|
+
// Convert base64url to regular base64
|
|
37
|
+
let base64 = str.replace(/-/g, '+').replace(/_/g, '/')
|
|
38
|
+
|
|
39
|
+
// Add padding if needed
|
|
40
|
+
const padding = (4 - (base64.length % 4)) % 4
|
|
41
|
+
base64 += '='.repeat(padding)
|
|
42
|
+
|
|
43
|
+
if (typeof Buffer !== 'undefined') {
|
|
44
|
+
// Node.js
|
|
45
|
+
return new Uint8Array(Buffer.from(base64, 'base64'))
|
|
46
|
+
} else {
|
|
47
|
+
// Browser
|
|
48
|
+
const binary = atob(base64)
|
|
49
|
+
const bytes = new Uint8Array(binary.length)
|
|
50
|
+
for (let i = 0; i < binary.length; i++) {
|
|
51
|
+
bytes[i] = binary.charCodeAt(i)
|
|
52
|
+
}
|
|
53
|
+
return bytes
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Convert a hex string to Uint8Array
|
|
59
|
+
*
|
|
60
|
+
* @param hex - Hex string (with or without 0x prefix)
|
|
61
|
+
* @returns Byte array
|
|
62
|
+
*/
|
|
63
|
+
export function hexToBytes(hex: string): Uint8Array {
|
|
64
|
+
const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex
|
|
65
|
+
const bytes = new Uint8Array(cleanHex.length / 2)
|
|
66
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
67
|
+
bytes[i] = parseInt(cleanHex.slice(i * 2, i * 2 + 2), 16)
|
|
68
|
+
}
|
|
69
|
+
return bytes
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Convert a Uint8Array to hex string
|
|
74
|
+
*
|
|
75
|
+
* @param bytes - Byte array
|
|
76
|
+
* @param withPrefix - Include 0x prefix (default: true)
|
|
77
|
+
* @returns Hex string
|
|
78
|
+
*/
|
|
79
|
+
export function bytesToHex(bytes: Uint8Array, withPrefix: boolean = true): string {
|
|
80
|
+
const hex = Array.from(bytes)
|
|
81
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
82
|
+
.join('')
|
|
83
|
+
return withPrefix ? `0x${hex}` : hex
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Validate an account ID format
|
|
88
|
+
*
|
|
89
|
+
* Account IDs are 64-character hex strings (32 bytes).
|
|
90
|
+
*
|
|
91
|
+
* @param accountId - Account ID to validate
|
|
92
|
+
* @returns True if valid
|
|
93
|
+
*/
|
|
94
|
+
export function isValidAccountId(accountId: string): boolean {
|
|
95
|
+
return /^[0-9a-fA-F]{64}$/.test(accountId)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Validate an EVM address format
|
|
100
|
+
*
|
|
101
|
+
* @param address - Address to validate
|
|
102
|
+
* @returns True if valid
|
|
103
|
+
*/
|
|
104
|
+
export function isValidEvmAddress(address: string): boolean {
|
|
105
|
+
return /^0x[0-9a-fA-F]{40}$/.test(address)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Sleep for a specified duration
|
|
110
|
+
*
|
|
111
|
+
* @param ms - Milliseconds to sleep
|
|
112
|
+
*/
|
|
113
|
+
export function sleep(ms: number): Promise<void> {
|
|
114
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Retry a function with exponential backoff
|
|
119
|
+
*
|
|
120
|
+
* @param fn - Function to retry
|
|
121
|
+
* @param maxRetries - Maximum number of retries (default: 3)
|
|
122
|
+
* @param baseDelay - Base delay in ms (default: 1000)
|
|
123
|
+
* @returns Result of the function
|
|
124
|
+
*/
|
|
125
|
+
export async function withRetry<T>(
|
|
126
|
+
fn: () => Promise<T>,
|
|
127
|
+
maxRetries: number = 3,
|
|
128
|
+
baseDelay: number = 1000
|
|
129
|
+
): Promise<T> {
|
|
130
|
+
let lastError: Error | undefined
|
|
131
|
+
|
|
132
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
133
|
+
try {
|
|
134
|
+
return await fn()
|
|
135
|
+
} catch (error) {
|
|
136
|
+
lastError = error as Error
|
|
137
|
+
|
|
138
|
+
if (attempt < maxRetries) {
|
|
139
|
+
const delay = baseDelay * Math.pow(2, attempt)
|
|
140
|
+
await sleep(delay)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
throw lastError
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Parse a JWT token (without validation)
|
|
150
|
+
*
|
|
151
|
+
* @param token - JWT token string
|
|
152
|
+
* @returns Decoded payload
|
|
153
|
+
*/
|
|
154
|
+
export function parseJwt(token: string): Record<string, unknown> {
|
|
155
|
+
const parts = token.split('.')
|
|
156
|
+
if (parts.length !== 3) {
|
|
157
|
+
throw new Error('Invalid JWT format')
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const payload = base64UrlDecode(parts[1])
|
|
161
|
+
const text = new TextDecoder().decode(payload)
|
|
162
|
+
return JSON.parse(text)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Get JWT expiration time
|
|
167
|
+
*
|
|
168
|
+
* @param token - JWT token string
|
|
169
|
+
* @returns Expiration timestamp in milliseconds, or null if no exp claim
|
|
170
|
+
*/
|
|
171
|
+
export function getJwtExpiration(token: string): number | null {
|
|
172
|
+
try {
|
|
173
|
+
const payload = parseJwt(token)
|
|
174
|
+
if (typeof payload.exp === 'number') {
|
|
175
|
+
return payload.exp * 1000 // Convert seconds to milliseconds
|
|
176
|
+
}
|
|
177
|
+
return null
|
|
178
|
+
} catch {
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Format an error for display
|
|
185
|
+
*
|
|
186
|
+
* @param error - Error to format
|
|
187
|
+
* @returns Formatted error message
|
|
188
|
+
*/
|
|
189
|
+
export function formatError(error: unknown): string {
|
|
190
|
+
if (error instanceof Error) {
|
|
191
|
+
return error.message
|
|
192
|
+
}
|
|
193
|
+
if (typeof error === 'string') {
|
|
194
|
+
return error
|
|
195
|
+
}
|
|
196
|
+
return 'An unknown error occurred'
|
|
197
|
+
}
|