ns-auth-sdk 1.12.6 → 1.12.7
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.cjs +4 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -363,12 +363,9 @@ function getPublicKeyFromPassword(password, salt = DEFAULT_SALT) {
|
|
|
363
363
|
* Nosskey class for Passkey-Derived Nostr Identity
|
|
364
364
|
* @packageDocumentation
|
|
365
365
|
*/
|
|
366
|
-
|
|
366
|
+
function deriveSaltFromUsername(username) {
|
|
367
367
|
if (!username) return "";
|
|
368
|
-
const
|
|
369
|
-
const subtle = globalThis.crypto?.subtle;
|
|
370
|
-
if (!subtle) throw new Error("Web Crypto API not available");
|
|
371
|
-
const hashBuffer = await subtle.digest("SHA-256", msgBuffer);
|
|
368
|
+
const hashBuffer = (0, _noble_hashes_sha256.sha256)(new TextEncoder().encode(username.toLowerCase().trim()));
|
|
372
369
|
return bytesToHex(new Uint8Array(hashBuffer));
|
|
373
370
|
}
|
|
374
371
|
function parseRecoveryTag(tags) {
|
|
@@ -409,12 +406,8 @@ async function verifyRecoverySignature(kind0) {
|
|
|
409
406
|
return false;
|
|
410
407
|
}
|
|
411
408
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const subtle = globalThis.crypto?.subtle;
|
|
415
|
-
if (!subtle) throw new Error("Web Crypto API not available");
|
|
416
|
-
const hashBuffer = await subtle.digest("SHA-256", msgBuffer);
|
|
417
|
-
return new Uint8Array(hashBuffer);
|
|
409
|
+
function sha256(message) {
|
|
410
|
+
return (0, _noble_hashes_sha256.sha256)(new TextEncoder().encode(message));
|
|
418
411
|
}
|
|
419
412
|
/**
|
|
420
413
|
* Nosskey - Passkey-Derived Nostr Keys
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["#cacheOptions","#cachedEntry","#clearCachedEntry","#scheduleExpiry","#getCachedKeyIfValid","#clearKey","#expiryTimer","secp256k1","gcm","bin","bytes","sha256","secp256k1","#keyCache","#storageOptions","#prfOptions","#loadKeyInfoFromStorage","#currentKeyInfo","#saveKeyInfoToStorage","#clearKey","#signWithKey"],"sources":["../src/utils/utils.ts","../src/utils/key-cache.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/nosskey.ts","../src/utils/crypto-utils.ts","../src/utils/test-utils.ts","../src/services/auth.service.ts","../src/utils/validation.ts","../src/services/relay.service.ts"],"sourcesContent":["/**\n * @packageDocumentation\n */\n\n/**\n * @param bytes\n * @returns\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n const key = '0123456789abcdef';\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n const firstNibble = bytes[i] >> 4;\n const secondNibble = bytes[i] & 15;\n hex += key[firstNibble] + key[secondNibble];\n }\n return hex;\n}\n\n/**\n * @param hex\n * @returns\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const key = '0123456789abcdef';\n const bytes = [];\n let currentByte = 0;\n let highNibble = true;\n\n for (let i = 0; i < hex.length; i++) {\n const charValue = key.indexOf(hex[i].toLowerCase());\n if (charValue === -1) continue;\n\n if (highNibble) {\n currentByte = charValue << 4;\n highNibble = false;\n } else {\n currentByte += charValue;\n bytes.push(currentByte);\n highNibble = true;\n }\n }\n\n return new Uint8Array(bytes);\n}\n","/**\n * Key cache management for Nosskey\n * @packageDocumentation\n */\n\nimport type { KeyCacheOptions } from './types.js';\nimport { bytesToHex } from './utils.js';\n\n/**\n * Key cache entry with expiration time\n */\ninterface CacheEntry {\n id: string;\n sk: Uint8Array;\n expireAt: number;\n}\n\n/**\n * Key cache manager for managing temporary secret keys\n */\nexport class KeyCache {\n #cachedEntry: CacheEntry | null = null;\n\n #expiryTimer: NodeJS.Timeout | null = null;\n\n #cacheOptions: KeyCacheOptions = {\n enabled: false,\n timeoutMs: 5 * 60 * 1000,\n };\n\n /**\n * KeyCache\n * @param options\n */\n constructor(options?: Partial<KeyCacheOptions>) {\n if (options) {\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n if (Object.keys(options).length > 0 && this.#cachedEntry !== null) {\n this.clearAllCachedKeys();\n }\n\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n\n getCacheOptions(): KeyCacheOptions {\n return { ...this.#cacheOptions };\n }\n\n isEnabled(): boolean {\n return this.#cacheOptions.enabled;\n }\n\n /**\n * @param credentialId\n * @param sk\n */\n setKey(credentialId: Uint8Array | string, sk: Uint8Array): void {\n if (!this.#cacheOptions.enabled) return;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n const timeout =\n this.#cacheOptions.timeoutMs !== undefined ? this.#cacheOptions.timeoutMs : 5 * 60 * 1000;\n const expireAt = Date.now() + timeout;\n\n this.#clearCachedEntry();\n\n this.#cachedEntry = {\n id,\n sk: new Uint8Array(sk),\n expireAt,\n };\n\n try {\n this.#scheduleExpiry();\n } catch (error) {\n this.#clearCachedEntry();\n throw error;\n }\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n getKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n if (!this.#cacheOptions.enabled) return undefined;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n return this.#getCachedKeyIfValid(id);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n\n if (this.#cachedEntry && this.#cachedEntry.id === id) {\n this.#clearCachedEntry();\n }\n }\n\n clearAllCachedKeys(): void {\n this.#clearCachedEntry();\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n #getCachedKeyIfValid(credentialId: string): Uint8Array | undefined {\n if (!this.#cachedEntry || this.#cachedEntry.id !== credentialId) {\n return undefined;\n }\n\n if (Date.now() < this.#cachedEntry.expireAt) {\n return this.#cachedEntry.sk;\n }\n\n this.#clearCachedEntry();\n return undefined;\n }\n\n #clearCachedEntry(): void {\n if (this.#cachedEntry) {\n this.#clearKey(this.#cachedEntry.sk);\n this.#cachedEntry = null;\n }\n\n if (this.#expiryTimer) {\n clearTimeout(this.#expiryTimer);\n this.#expiryTimer = null;\n }\n }\n\n #scheduleExpiry(): void {\n if (!this.#cachedEntry) return;\n\n const now = Date.now();\n const timeToExpiry = this.#cachedEntry.expireAt - now;\n\n if (timeToExpiry <= 0) {\n this.#clearCachedEntry();\n return;\n }\n\n this.#expiryTimer = setTimeout(() => {\n this.#clearCachedEntry();\n }, timeToExpiry + 1);\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * PRF (Pseudo-Random Function) handler for WebAuthn\n * @packageDocumentation\n */\n\nimport type { GetPrfSecretOptions, PasskeyCreationOptions } from './types.js';\n\nconst PRF_EVAL_INPUT = new TextEncoder().encode('nostr-pwk');\n\n/**\n * @returns PRF\n */\nexport async function isPrfSupported(): Promise<boolean> {\n try {\n const response = await navigator.credentials.get({\n publicKey: {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials: [],\n userVerification: 'required',\n extensions: { prf: { eval: { first: PRF_EVAL_INPUT } } },\n } as PublicKeyCredentialRequestOptions,\n });\n\n if (!response) return false;\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const res = assertion.getClientExtensionResults()?.prf?.results?.first;\n return !!res;\n } catch {\n return false;\n }\n}\n\n/**\n * @param options\n * @returns Credential\n */\nexport async function createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n // Node\n const rpName = options.rp?.name || (typeof location !== 'undefined' ? location.host : 'Nosskey');\n const rpId = options.rp?.id;\n const userName = options.user?.name || 'user@example.com';\n const userDisplayName = options.user?.displayName || 'Nosskey user';\n\n const credentialCreationOptions: CredentialCreationOptions = {\n publicKey: {\n rp: {\n name: rpName,\n id: rpId,\n },\n user: {\n id: crypto.getRandomValues(new Uint8Array(16)),\n name: userName,\n displayName: userDisplayName,\n },\n pubKeyCredParams: options.pubKeyCredParams || [{ type: 'public-key', alg: -7 }], // ES256\n authenticatorSelection: options.authenticatorSelection || {\n residentKey: 'required',\n userVerification: 'required',\n },\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n extensions: options.extensions || { prf: {} }, // PRF拡張を要求\n } as PublicKeyCredentialCreationOptions,\n };\n const cred = (await navigator.credentials.create(\n credentialCreationOptions\n )) as PublicKeyCredential;\n\n return new Uint8Array(cred.rawId);\n}\n\n/**\n * ID\n * @param credentialId \n * @param options PRF(rpId、timeout、userVerification)\n * @returns PRF credentialID\n */\nexport async function getPrfSecret(\n credentialId?: Uint8Array,\n options?: GetPrfSecretOptions\n): Promise<{ secret: Uint8Array; id: Uint8Array }> {\n const allowCredentials = credentialId ? [{ type: 'public-key' as const, id: credentialId }] : [];\n\n const requestOptions: PublicKeyCredentialRequestOptions = {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials,\n userVerification: options?.userVerification || 'required',\n extensions: {\n prf: { eval: { first: PRF_EVAL_INPUT } },\n } as AuthenticationExtensionsClientInputs,\n };\n\n if (options?.rpId) {\n requestOptions.rpId = options.rpId;\n }\n if (options?.timeout) {\n requestOptions.timeout = options.timeout;\n }\n\n const response = await navigator.credentials.get({\n publicKey: requestOptions,\n });\n\n if (!response) {\n throw new Error('Authentication failed');\n }\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const secret = assertion.getClientExtensionResults()?.prf?.results?.first;\n if (!secret) {\n throw new Error('PRF secret not available');\n }\n\n // response credentialId\n const responseId = new Uint8Array((response as PublicKeyCredential).rawId);\n\n return {\n secret: new Uint8Array(secret),\n id: responseId,\n };\n}\n","/**\n * PRF support check with a password-protected-key fallback.\n * If the PRF WebAuthn extension is unavailable, callers can fall back to a\n * password-protected private key. The private key is wrapped with a password-\n * derived AES-GCM key and stored alongside the public key (SPKI).\n *\n * This implementation uses @noble libraries for cryptographic operations,\n * ensuring functionality even when Web Crypto API is unavailable.\n */\n\nimport { getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { pbkdf2 } from '@noble/hashes/pbkdf2';\nimport { gcm } from '@noble/ciphers/aes';\n\nconst { randomBytes } = secp256k1.etc;\nconst aesGcm = gcm;\n\nexport type PasswordProtectedBundle = {\n publicKeySpkiBase64: string;\n wrappedPrivateKeyBase64: string;\n saltBase64: string;\n ivBase64: string;\n};\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);\n if (typeof window !== 'undefined' && (window as any).btoa) {\n return (window as any).btoa(binary);\n }\n return btoa(binary);\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n if (typeof window !== 'undefined' && (window as any).atob) {\n const bin = (window as any).atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n }\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport async function checkPRFSupport(): Promise<boolean> {\n try {\n const caps = typeof PublicKeyCredential !== 'undefined' ? await PublicKeyCredential.getClientCapabilities() : null;\n const supported = caps?.['extension:prf'] === true;\n if (supported) {\n console.log('PRF extension is supported.');\n } else {\n console.log('PRF extension is not supported.');\n }\n return !!supported;\n } catch (e) {\n console.log('Could not determine PRF support:', e);\n return false;\n }\n}\n\nexport async function generatePasswordProtectedKey(password: string): Promise<PasswordProtectedBundle> {\n const privateKey = secp256k1.utils.randomPrivateKey();\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n\n const publicKeySpkiBase64 = toBase64(publicKey);\n\n const salt = randomBytes(16);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = randomBytes(12);\n const ct = aesGcm(derivedKey, iv).encrypt(privateKey);\n\n return {\n publicKeySpkiBase64,\n wrappedPrivateKeyBase64: toBase64(ct),\n saltBase64: toBase64(salt),\n ivBase64: toBase64(iv),\n };\n}\n\nexport async function unwrapPasswordProtectedPrivateKey(bundle: PasswordProtectedBundle, password: string): Promise<Uint8Array> {\n const salt = fromBase64(bundle.saltBase64);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = fromBase64(bundle.ivBase64);\n const ct = fromBase64(bundle.wrappedPrivateKeyBase64);\n const privateKey = aesGcm(derivedKey, iv).decrypt(ct);\n return privateKey;\n}\n\nfunction base64UrlToBytes(base64url: string): Uint8Array {\n let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');\n const pad = base64.length % 4;\n if (pad) base64 += '='.repeat(4 - pad);\n if (typeof window !== 'undefined' && (window as any).atob) {\n const binary = (window as any).atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n }\n const bin = atob(base64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport function importPublicKeyFromBundle(bundle: PasswordProtectedBundle): Uint8Array {\n const spki = fromBase64(bundle.publicKeySpkiBase64);\n return spki;\n}\n\nconst DEFAULT_SALT = 'nostr-key-derivation';\n\nexport function deriveNostrPrivateKey(password: string, salt: string = DEFAULT_SALT): Uint8Array {\n const derivedBits = pbkdf2(sha256, new TextEncoder().encode(password), new TextEncoder().encode(salt), { c: 100000, dkLen: 32 });\n return derivedBits;\n}\n\nexport function getPublicKeyFromPassword(password: string, salt: string = DEFAULT_SALT): string {\n const sk = deriveNostrPrivateKey(password, salt);\n return getPublicKey(sk);\n}\n","import { finalizeEvent, getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { KeyCache } from './key-cache.js';\nimport { createPasskey, getPrfSecret, isPrfSupported } from './prf-handler.js';\nimport { checkPRFSupport, deriveNostrPrivateKey, getPublicKeyFromPassword, unwrapPasswordProtectedPrivateKey } from './prf-password-fallback.js';\nimport type {\n GetPrfSecretOptions,\n KeyCacheOptions,\n KeyOptions,\n NosskeyManagerLike,\n KeyManagerOptions,\n Event,\n KeyInfo,\n NostrKeyStorageOptions,\n PasskeyCreationOptions,\n SignOptions,\n} from './types.js';\n/**\n * Nosskey class for Passkey-Derived Nostr Identity\n * @packageDocumentation\n */\nimport { bytesToHex, hexToBytes } from './utils.js';\nimport type { KeyRecovery } from './types.js';\n\nexport async function deriveSaltFromUsername(username?: string): Promise<string> {\n if (!username) {\n return '';\n }\n \n const msgBuffer = new TextEncoder().encode(username.toLowerCase().trim());\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n const hashBuffer = await subtle.digest('SHA-256', msgBuffer);\n return bytesToHex(new Uint8Array(hashBuffer));\n}\n\nexport function parseRecoveryTag(tags: string[][]): KeyRecovery | null {\n const recoveryTag = tags.find(tag => tag[0] === 'r');\n if (!recoveryTag || recoveryTag.length < 3) return null;\n\n // Format: ['r', recoveryPubkey, recoverySalt, createdAt, signature]\n const createdAt = recoveryTag[3] ? parseInt(recoveryTag[3], 10) : undefined;\n return {\n recoveryPubkey: recoveryTag[1],\n recoverySalt: recoveryTag[2],\n createdAt: createdAt || undefined,\n signature: recoveryTag[4] || undefined,\n };\n}\n\nexport function createRecoveryTag(recovery: KeyRecovery): string[] {\n return [\n 'r',\n recovery.recoveryPubkey,\n recovery.recoverySalt,\n recovery.createdAt?.toString() || '',\n recovery.signature || '',\n ];\n}\n\nexport function getRecoverySignature(kind0: Event): string | null {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return null;\n \n const tag = kind0.tags?.find(t => t[0] === 'r');\n return tag && tag.length > 4 ? tag[4] || null : null;\n}\n\nexport async function verifyRecoverySignature(kind0: Event): Promise<boolean> {\n try {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return false;\n \n const signature = getRecoverySignature(kind0);\n if (!signature || !kind0.pubkey) return false;\n \n // Verify Schnorr signature: signature over current pubkey (as message)\n // using the recovery pubkey\n // Note: verify expects the message hash, not the message itself\n const messageHash = await sha256(kind0.pubkey);\n const signatureBytes = hexToBytes(signature);\n const pubkeyBytes = hexToBytes(kind0.pubkey);\n \n return secp256k1.verify(signatureBytes, messageHash, pubkeyBytes);\n } catch (e) {\n return false;\n }\n}\n\nasync function sha256(message: string): Promise<Uint8Array> {\n const msgBuffer = new TextEncoder().encode(message);\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n const hashBuffer = await subtle.digest('SHA-256', msgBuffer);\n return new Uint8Array(hashBuffer);\n}\n\n/**\n * Nosskey - Passkey-Derived Nostr Keys\n */\nexport class NosskeyManager implements NosskeyManagerLike {\n #keyCache: KeyCache;\n\n // KeyInfo\n #currentKeyInfo: KeyInfo | null = null;\n\n // KeyInfo\n #storageOptions: NostrKeyStorageOptions = {\n enabled: true,\n storageKey: 'nosskey_keyinfo',\n };\n\n // PRF\n #prfOptions: GetPrfSecretOptions = {};\n\n /**\n * NosskeyManager\n * @param options\n */\n constructor(options?: KeyManagerOptions) {\n // KeyCache\n this.#keyCache = new KeyCache(options?.cacheOptions);\n\n if (options?.storageOptions) {\n this.#storageOptions = { ...this.#storageOptions, ...options.storageOptions };\n }\n\n // option\n const userVerification = options?.prfOptions?.userVerification ?? 'required';\n if (options?.prfOptions) {\n this.#prfOptions = { ...options.prfOptions, userVerification };\n } else {\n this.#prfOptions = { userVerification };\n }\n\n // KeyInfo\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n }\n }\n }\n\n /**\n * KeyInfo\n * @param options\n */\n setStorageOptions(options: Partial<NostrKeyStorageOptions>): void {\n this.#storageOptions = { ...this.#storageOptions, ...options };\n\n if (options.enabled === false) {\n this.clearStoredKeyInfo();\n }\n }\n\n /**\n * KeyInfo\n */\n getStorageOptions(): NostrKeyStorageOptions {\n return { ...this.#storageOptions };\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n this.#currentKeyInfo = keyInfo;\n\n if (this.#storageOptions.enabled) {\n void this.#saveKeyInfoToStorage(keyInfo);\n }\n }\n\n /**\n * KeyInfo\n */\n getCurrentKeyInfo(): KeyInfo | null {\n // KeyInfo\n if (!this.#currentKeyInfo && this.#storageOptions.enabled) {\n this.#currentKeyInfo = this.#loadKeyInfoFromStorage();\n }\n return this.#currentKeyInfo;\n }\n\n /**\n * KeyInfo\n * @returns KeyInfo\n */\n hasKeyInfo(): boolean {\n if (this.#currentKeyInfo) {\n return true;\n }\n\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n async #saveKeyInfoToStorage(keyInfo: KeyInfo): Promise<void> {\n if (!this.#storageOptions.enabled) return;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.setItem(key, JSON.stringify(keyInfo));\n }\n\n /**\n * KeyInfo\n */\n #loadKeyInfoFromStorage(): KeyInfo | null {\n if (!this.#storageOptions.enabled) return null;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return null;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n const data = storage.getItem(key);\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as KeyInfo;\n } catch (e) {\n console.error('Failed to parse stored KeyInfo', e);\n return null;\n }\n }\n\n /**\n * KeyInfo\n */\n clearStoredKeyInfo(): void {\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.removeItem(key);\n\n // KeyInfo\n this.#currentKeyInfo = null;\n }\n\n /**\n * NIP-07\n * KeyInfo\n */\n async getPublicKey(): Promise<string> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return keyInfo.pubkey;\n }\n\n /**\n * NIP-07\n * KeyInfo\n * @param event Nostr\n */\n async signEvent(event: Event): Promise<Event> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return this.signEventWithKeyInfo(event, keyInfo);\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n this.#keyCache.setCacheOptions(options);\n }\n\n getCacheOptions(): KeyCacheOptions {\n return this.#keyCache.getCacheOptions();\n }\n\n getCachedSecretKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n return this.#keyCache.getKey(credentialId);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n this.#keyCache.clearCachedKey(credentialId);\n }\n\n clearAllCachedKeys(): void {\n this.#keyCache.clearAllCachedKeys();\n }\n\n /**\n * @param options\n * @returns Credential\n */\n async createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n return createPasskey({\n rp: {\n id: this.#prfOptions.rpId,\n name: this.#prfOptions.rpId,\n },\n authenticatorSelection: {\n userVerification: this.#prfOptions.userVerification,\n },\n ...options,\n });\n }\n\n/**\n * Check if PRF is supported\n */\n async checkPRFSupport(): Promise<boolean> {\n return checkPRFSupport();\n }\n\n /**\n * Create Nostr key - automatically uses password fallback if PRF unavailable\n * @param credentialId Passkey credential ID\n * @param password Password for encryption (required if PRF not supported)\n * @param options \n */\n async createKey(credentialId?: Uint8Array, password?: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const prfSupported = await this.checkPRFSupport();\n \n let keyInfo: KeyInfo;\n \n if (prfSupported) {\n keyInfo = await this.createPrfNostrKey(credentialId, options);\n \n // Auto-add password recovery if requested and PRF is supported\n if (options.recoveryPassword) {\n keyInfo = await this.addPasswordRecovery(options.recoveryPassword, credentialId);\n }\n } else {\n if (!password) {\n throw new Error('Password is required when PRF is not supported');\n }\n if (!options.username) {\n throw new Error('Username is required when PRF is not supported');\n }\n keyInfo = await this.createPasswordProtectedNostrKey(password, options);\n }\n \n return keyInfo;\n }\n\n /**\n * Create Nostr key using PRF (standard passkey flow)\n */\n async createPrfNostrKey(credentialId?: Uint8Array, options: KeyOptions = {}): Promise<KeyInfo> {\n const { secret: sk, id: responseId } = await getPrfSecret(credentialId, this.#prfOptions);\n\n if (sk.every((byte) => byte === 0)) {\n throw new Error('Invalid PRF output: all zeros');\n }\n\n const skHex = bytesToHex(sk);\n const publicKey = getPublicKey(sk);\n \n const salt = await deriveSaltFromUsername(options.username);\n\n const keyInfo: KeyInfo = {\n credentialId: bytesToHex(credentialId || responseId),\n pubkey: publicKey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n if (this.#keyCache.isEnabled() && this.#keyCache.getCacheOptions().cacheOnCreation) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n\n return keyInfo;\n }\n\n /**\n * Create Nostr key using password-derived key (fallback when PRF unavailable)\n * @param password Password to derive the private key\n * @param options \n */\n async createPasswordProtectedNostrKey(password: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const salt = await deriveSaltFromUsername(options.username);\n const pubkey = getPublicKeyFromPassword(password, salt);\n\n const credentialId = bytesToHex((typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto).getRandomValues(new Uint8Array(16)));\n\n const keyInfo: KeyInfo = {\n credentialId,\n pubkey: pubkey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n return keyInfo;\n }\n\n/**\n * @param event Nostr\n * @param keyInfo KeyInfo\n * @param options\n */\n async signEventWithKeyInfo(\n event: Event,\n keyInfo: KeyInfo,\n options: SignOptions = {}\n ): Promise<Event> {\n const { clearMemory = true, tags, password } = options;\n\n const shouldUseCache = this.#keyCache.isEnabled();\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n\n let sk: Uint8Array | undefined;\n\n if (isPasswordDerived) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = deriveNostrPrivateKey(password, keyInfo.salt);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password to sign.');\n }\n } else if (keyInfo.passwordProtectedBundle) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle!, password);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password or use createNostrKey to initialize.');\n }\n } else {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n\n if (!sk) {\n const { secret: prfSecret } = await getPrfSecret(\n hexToBytes(keyInfo.credentialId),\n this.#prfOptions\n );\n sk = prfSecret;\n\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n }\n\n const eventToSign = {\n kind: event.kind,\n content: event.content,\n created_at: event.created_at || Math.floor(Date.now() / 1000),\n tags: tags ? [...(event.tags || []), ...tags] : event.tags || [],\n };\n\n const signedEvent = finalizeEvent(eventToSign, sk);\n\n if (!shouldUseCache && clearMemory) {\n this.#clearKey(sk);\n }\n\n return signedEvent;\n }\n\n/**\n * @param keyInfo KeyInfo\n * @param credentialId KeyInfoのcredentialId\n * @param options\n * @returns \n */\n async exportNostrKey(keyInfo: KeyInfo, credentialId?: Uint8Array, options: KeyOptions = {}): Promise<string> {\n if (keyInfo.passwordProtectedBundle) {\n if (!options.password) {\n throw new Error('Password is required for password-protected keys');\n }\n const sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle, options.password);\n return bytesToHex(sk);\n }\n\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n if (isPasswordDerived) {\n if (!options.password) {\n throw new Error('Password is required for password-derived keys');\n }\n const sk = deriveNostrPrivateKey(options.password, keyInfo.salt);\n return bytesToHex(sk);\n }\n\n let usedCredentialId = credentialId;\n\n if (!usedCredentialId && keyInfo.credentialId) {\n usedCredentialId = hexToBytes(keyInfo.credentialId);\n }\n\n const { secret: sk } = await getPrfSecret(usedCredentialId, this.#prfOptions);\n const skHex = bytesToHex(sk);\n\n return skHex;\n }\n\n /**\n * PRF\n */\n async isPrfSupported(): Promise<boolean> {\n return isPrfSupported();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n * @param currentCredentialId Current passkey credential ID\n */\n async addPasswordRecovery(password: string, currentCredentialId?: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (keyInfo.passwordProtectedBundle) {\n throw new Error('Password recovery already exists for password-derived key');\n }\n\n if (keyInfo.recovery) {\n throw new Error('Recovery already configured');\n }\n\n const usedCredentialId = currentCredentialId || (keyInfo.credentialId ? hexToBytes(keyInfo.credentialId) : undefined);\n if (!usedCredentialId) {\n throw new Error('Credential ID required');\n }\n\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n\n // Generate recovery salt\n const recoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n\n // Derive recovery pubkey from password\n const recoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n\n // Sign current pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, keyInfo.pubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n ...keyInfo,\n recovery: {\n recoveryPubkey,\n recoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n #signWithKey(sk: Uint8Array, message: string): string {\n const event = finalizeEvent({\n kind: 0,\n content: '',\n tags: [],\n created_at: Math.floor(Date.now() / 1000),\n }, sk);\n return event.sig;\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (!keyInfo.recovery) {\n throw new Error('No recovery key configured');\n }\n\n if (!newCredentialId) {\n throw new Error('New credential ID is required for recovery');\n }\n\n const { recoveryPubkey, recoverySalt } = keyInfo.recovery;\n\n // Verify password\n const derivedRecoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n if (derivedRecoveryPubkey !== recoveryPubkey) {\n throw new Error('Invalid recovery password');\n }\n\n // Derive new key from new credential\n const { secret: newSk } = await getPrfSecret(newCredentialId, this.#prfOptions);\n const newPubkey = getPublicKey(newSk);\n this.#clearKey(newSk);\n\n // Generate new recovery for the new key\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n const newRecoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n const newRecoveryPubkey = getPublicKeyFromPassword(password, newRecoverySalt);\n\n // Sign new pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, newPubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n credentialId: bytesToHex(newCredentialId),\n pubkey: newPubkey,\n salt: keyInfo.salt,\n recovery: {\n recoveryPubkey: newRecoveryPubkey,\n recoverySalt: newRecoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n /**\n * Get the recovery data for publishing to kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number; signature?: string } | null {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo || !keyInfo.recovery) return null;\n\n return {\n recoveryPubkey: keyInfo.recovery.recoveryPubkey,\n recoverySalt: keyInfo.recovery.recoverySalt,\n createdAt: keyInfo.recovery.createdAt,\n signature: keyInfo.recovery.signature,\n };\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * Cryptographic utilities for Nosskey\n * @packageDocumentation\n */\n\nconst INFO_BYTES = new TextEncoder().encode('nostr-pwk');\nconst AES_LENGTH = 256; // bits\n\nfunction getSubtle(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n return subtle;\n}\n\n/**\n * PRF AES-GCM\n * @param secret PRF\n * @param salt\n * @returns AES-GCM\n */\nexport async function deriveAesGcmKey(secret: Uint8Array, salt: Uint8Array): Promise<CryptoKey> {\n const subtle = getSubtle();\n const keyMaterial = await subtle.importKey('raw', secret, 'HKDF', false, ['deriveKey']);\n\n return subtle.deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt, info: INFO_BYTES },\n keyMaterial,\n { name: 'AES-GCM', length: AES_LENGTH },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param plaintext\n * @returns\n */\nexport async function aesGcmEncrypt(key: CryptoKey, iv: Uint8Array, plaintext: Uint8Array) {\n const subtle = getSubtle();\n const buf = await subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);\n\n const bytes = new Uint8Array(buf);\n return {\n ciphertext: bytes.slice(0, -16),\n tag: bytes.slice(-16),\n };\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param ct\n * @param tag\n * @returns\n */\nexport async function aesGcmDecrypt(\n key: CryptoKey,\n iv: Uint8Array,\n ct: Uint8Array,\n tag: Uint8Array\n): Promise<Uint8Array> {\n const subtle = getSubtle();\n const buf = await subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n new Uint8Array([...ct, ...tag])\n );\n return new Uint8Array(buf);\n}\n","/**\n * Test utilities for sdk\n * @packageDocumentation\n */\n\n/**\n * Helper for testing/debugging\n * @param userId - User identifier\n * @returns Promise resolving to the dummy credential\n */\nexport async function registerDummyPasskey(userId: string): Promise<PublicKeyCredential> {\n // Create a dummy credential for testing\n const dummySignature = new Uint8Array(64);\n // Fill with some non-zero values for testing\n for (let i = 0; i < dummySignature.length; i++) {\n dummySignature[i] = (i + 1) % 256;\n }\n\n const dummyId = new Uint8Array(32);\n for (let i = 0; i < dummyId.length; i++) {\n dummyId[i] = (i + 1) % 256;\n }\n\n const credential = {\n id: 'dummy-credential-id',\n rawId: dummyId,\n type: 'public-key',\n response: {\n clientDataJSON: new Uint8Array(0),\n attestationObject: new Uint8Array(0),\n signature: dummySignature,\n authenticatorData: new Uint8Array(0),\n getAuthenticatorData: () => new Uint8Array(0),\n getPublicKey: () => new Uint8Array(0),\n getPublicKeyAlgorithm: () => -7,\n getTransports: () => ['internal'],\n },\n } as unknown as PublicKeyCredential;\n\n return credential;\n}\n","import { NosskeyManager, type KeyInfo, type Event, type PasskeyCreationOptions, type SignOptions, type KeyOptions } from '../utils';\nimport type { AuthServiceConfig } from '../types/auth';\n\n/**\n * Service wrapper around NosskeyManager\n * Handles WebAuthn/Passkey integration with Nostr\n */\nexport class AuthService {\n private manager: NosskeyManager | null = null;\n private config: AuthServiceConfig;\n\n constructor(config: AuthServiceConfig = {}) {\n this.config = {\n rpId: config.rpId || (typeof window !== 'undefined' ? window.location.hostname.replace(/^www\\./, '') : 'localhost'),\n rpName: config.rpName || this.getDefaultRpName(),\n storageKey: config.storageKey || 'nsauth_keyinfo',\n cacheTimeoutMs: config.cacheTimeoutMs || 30 * 60 * 1000,\n cacheOnCreation: config.cacheOnCreation !== undefined ? config.cacheOnCreation : true,\n };\n }\n\n private getDefaultRpName(): string {\n if (typeof window === 'undefined') return 'localhost';\n const hostname = window.location.hostname;\n if (hostname.includes('nosskey.app')) return 'nosskey.app';\n return hostname.replace(/^www\\./, '');\n }\n\n /**\n * Initialize the NosskeyManager instance\n */\n private getManager(): NosskeyManager {\n if (!this.manager) {\n this.manager = new NosskeyManager({\n cacheOptions: {\n enabled: true,\n timeoutMs: this.config.cacheTimeoutMs,\n cacheOnCreation: this.config.cacheOnCreation,\n },\n storageOptions: {\n enabled: true,\n storageKey: this.config.storageKey,\n },\n });\n }\n return this.manager;\n }\n\n /**\n * Create a new passkey\n * Uses platform authenticator only (Touch ID, Face ID, Windows Hello)\n */\n async createPasskey(username?: string): Promise<Uint8Array> {\n const manager = this.getManager();\n \n const rpId = this.config.rpId === 'localhost' ? 'localhost' : this.config.rpId;\n const rpName = this.config.rpName;\n \n const trimmedUsername = username?.trim();\n const uniqueUsername = trimmedUsername \n ? trimmedUsername \n : `user-${Date.now()}@example.com`;\n \n const options: PasskeyCreationOptions = {\n rp: {\n id: rpId,\n name: rpName,\n },\n user: {\n name: uniqueUsername,\n displayName: trimmedUsername || 'User',\n },\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n residentKey: 'preferred',\n userVerification: 'preferred',\n },\n extensions: {\n prf: {},\n },\n };\n \n return await manager.createPasskey(options);\n }\n\n/**\n * Create a new Nostr key from a credential ID\n * Automatically uses password fallback if PRF is not supported\n * @param credentialId Passkey credential ID\n * @param password Password (required if PRF not supported)\n * @param options.username Username for the key\n * @param options.recoveryPassword Password for recovery (enables recovery on new device)\n */\n async createKey(credentialId?: Uint8Array, password?: string, options?: KeyOptions): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.createKey(credentialId, password, options);\n }\n\n /**\n * Check if PRF is supported, otherwise password fallback is needed\n */\n async checkPRFSupport(): Promise<boolean> {\n const manager = this.getManager();\n return await manager.checkPRFSupport();\n }\n\n /**\n * Get the current public key\n */\n async getPublicKey(): Promise<string> {\n const manager = this.getManager();\n return await manager.getPublicKey();\n }\n\n /**\n * Sign a Nostr event\n */\n async signEvent(event: Event, options?: SignOptions): Promise<Event> {\n const manager = this.getManager();\n return await manager.signEvent(event, options);\n }\n\n /**\n * Get current key info\n */\n getCurrentKeyInfo(): KeyInfo | null {\n const manager = this.getManager();\n return manager.getCurrentKeyInfo();\n }\n\n /**\n * Set current key info\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n const manager = this.getManager();\n manager.setCurrentKeyInfo(keyInfo);\n }\n\n /**\n * Check if key info exists\n */\n hasKeyInfo(): boolean {\n const manager = this.getManager();\n return manager.hasKeyInfo();\n }\n\n /**\n * Clear stored key info\n */\n clearStoredKeyInfo(): void {\n const manager = this.getManager();\n manager.clearStoredKeyInfo();\n }\n\n/**\n * Check if PRF is supported (legacy alias)\n */\n async isPrfSupported(): Promise<boolean> {\n return this.checkPRFSupport();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n */\n async addPasswordRecovery(password: string): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.addPasswordRecovery(password);\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.activateWithPassword(password, newCredentialId);\n }\n\n /**\n * Get recovery data for kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number } | null {\n const manager = this.getManager();\n return manager.getRecoveryForKind0();\n }\n}\n\n","export const MAX_ROLE_LENGTH = 100;\nconst ROLE_PATTERN = /^[a-zA-Z0-9\\s\\-_]+$/;\n\nexport const isValidRoleTag = (role: string): boolean => {\n const trimmed = role.trim();\n return (\n trimmed.length > 0 &&\n trimmed.length <= MAX_ROLE_LENGTH &&\n ROLE_PATTERN.test(trimmed)\n );\n};\n\nexport const isValidPubkey = (pubkey: string): boolean =>\n pubkey.length === 64 && /^[0-9a-fA-F]+$/.test(pubkey);\n\nexport const isValidHttpUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['http:', 'https:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n};\n\nexport const isValidRelayUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['ws:', 'wss:'].includes(parsed.protocol) && parsed.hostname.length > 0;\n } catch {\n return false;\n }\n};\n","import type { EventStore } from 'applesauce-core';\nimport type { Event } from '../types/nostr';\nimport type { ProfileMetadata, FollowEntry } from '../types/nostr';\nimport type { RelayServiceConfig } from '../types/auth';\nimport { isValidPubkey, isValidRelayUrl, isValidRoleTag } from '../utils/validation';\n\n/**\n * Service for communicating with Nostr relays using applesauce-core\n */\nexport class RelayService {\n private eventStore: EventStore | null = null;\n private relayUrls: string[];\n private defaultRelays = ['wss://relay.damus.io'];\n private readonly maxProfileContentSize = 10000;\n private readonly minProfileQueryIntervalMs = 300;\n private readonly minPublishIntervalMs = 750;\n private readonly lastActionAt = new Map<string, number>();\n\n constructor(config: RelayServiceConfig = {}) {\n this.relayUrls = this.validateRelayUrls(config.relayUrls ?? this.defaultRelays);\n }\n\n /**\n * Initialize with applesauce EventStore\n */\n initialize(eventStore: EventStore): void {\n this.eventStore = eventStore;\n // Set default relays if EventStore has a method for it\n if (eventStore && 'setRelays' in eventStore && typeof eventStore.setRelays === 'function') {\n (eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Set relay URLs\n */\n setRelays(urls: string[]): void {\n this.relayUrls = this.validateRelayUrls(urls);\n if (this.eventStore && 'setRelays' in this.eventStore && typeof this.eventStore.setRelays === 'function') {\n (this.eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Get current relay URLs\n */\n getRelays(): string[] {\n return [...this.relayUrls];\n }\n\n /**\n * Publish an event to relays\n */\n async publishEvent(event: Event, timeoutMs = 1000): Promise<boolean> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('publish', this.minPublishIntervalMs);\n return new Promise((resolve, reject) => {\n if (this.relayUrls.length === 0) {\n reject(new Error('No relays configured'));\n return;\n }\n\n // Use EventStore's publish method\n // Note: This is a simplified implementation - actual applesauce API may differ\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.publish !== 'function') {\n reject(new Error('EventStore does not support publish method'));\n return;\n }\n const subscription = eventStore.publish(event).subscribe({\n next: (response: any) => {\n if (response?.type === 'OK') {\n subscription.unsubscribe();\n resolve(true);\n }\n },\n error: (error: Error) => {\n subscription.unsubscribe();\n reject(error);\n },\n });\n\n // Timeout fallback\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(false);\n }, timeoutMs);\n });\n }\n\n /**\n * Fetch a profile (Kind 0 event)\n */\n async fetchProfile(pubkey: string): Promise<ProfileMetadata | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-profile', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n subscription.unsubscribe();\n resolve(metadata);\n return;\n }\n console.error('Failed to parse profile metadata');\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n // Timeout\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch role tag from profile event (Kind 0)\n */\n async fetchProfileRoleTag(pubkey: string): Promise<string | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-role-tag', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const tags = packet.event.tags || [];\n for (const tag of tags) {\n if (tag[0] === 'role' && tag[1]) {\n const candidate = tag[1].trim();\n if (isValidRoleTag(candidate)) {\n subscription.unsubscribe();\n resolve(candidate);\n return;\n }\n }\n }\n subscription.unsubscribe();\n resolve(null);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile role tag:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch a follow list (Kind 3 event)\n */\n async fetchFollowList(pubkey: string): Promise<FollowEntry[]> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-follow-list', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [3],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve([]);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 3) {\n const followList: FollowEntry[] = [];\n const tags = packet.event.tags || [];\n\n for (const tag of tags) {\n if (tag[0] === 'p' && tag[1]) {\n followList.push({\n pubkey: tag[1],\n relay: tag[2] || undefined,\n petname: tag[3] || undefined,\n });\n }\n }\n\n subscription.unsubscribe();\n resolve(followList);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve([]);\n },\n error: (error: Error) => {\n console.error('Error fetching follow list:', error);\n subscription.unsubscribe();\n resolve([]);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve([]);\n }, 10000);\n });\n }\n\n /**\n * Fetch multiple profiles in batch\n */\n async fetchMultipleProfiles(pubkeys: string[]): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n if (pubkeys.length === 0) {\n return new Map();\n }\n\n await this.enforceRateLimit('fetch-multiple-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, ProfileMetadata>();\n const filter = {\n kinds: [0],\n authors: pubkeys,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n profiles.set(packet.event.pubkey, metadata);\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(profiles);\n },\n error: (error: Error) => {\n console.error('Error fetching profiles:', error);\n subscription.unsubscribe();\n resolve(profiles);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(profiles);\n }, 1000);\n });\n }\n\n /**\n * Query kind 0 events (profiles) by pubkey\n * If pubkeys array is empty, fetches recent kind 0 events\n */\n async queryProfiles(pubkeys: string[] = [], limit = 100): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('query-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, { metadata: ProfileMetadata; timestamp: number }>();\n const filter: any = {\n kinds: [0],\n limit,\n };\n\n if (pubkeys.length > 0) {\n filter.authors = pubkeys;\n }\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n const timestamp = packet.event.created_at || 0;\n const existing = profiles.get(packet.event.pubkey);\n if (!existing || timestamp > existing.timestamp) {\n profiles.set(packet.event.pubkey, { metadata, timestamp });\n }\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n error: (error: Error) => {\n console.error('Error querying profiles:', error);\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n }, 10000);\n });\n }\n\n /**\n * Publish or update a kind 3 event (follow list/contacts)\n */\n async publishFollowList(\n pubkey: string,\n followList: FollowEntry[],\n signEvent: (event: Event) => Promise<Event>\n ): Promise<boolean> {\n const tags: string[][] = followList.map((entry) => {\n if (!isValidPubkey(entry.pubkey)) {\n throw new Error('Invalid pubkey format for follow list entry.');\n }\n if (entry.relay && !isValidRelayUrl(entry.relay)) {\n throw new Error('Invalid relay URL format for follow list entry.');\n }\n const tag: string[] = ['p', entry.pubkey];\n if (entry.relay) {\n tag.push(entry.relay);\n }\n if (entry.petname) {\n tag.push(entry.petname);\n }\n return tag;\n });\n\n const event: Event = {\n kind: 3,\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n tags,\n };\n\n const signedEvent = await signEvent(event);\n return await this.publishEvent(signedEvent);\n }\n\n private validateRelayUrls(urls: string[]): string[] {\n if (urls.length === 0) {\n return [];\n }\n const validUrls = urls.filter((url) => isValidRelayUrl(url));\n if (validUrls.length !== urls.length) {\n throw new Error('Invalid relay URL format');\n }\n return validUrls;\n }\n\n private parseProfileMetadata(content: string): ProfileMetadata | null {\n if (content.length > this.maxProfileContentSize) {\n return null;\n }\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n const metadata: ProfileMetadata = {};\n if (typeof (parsed as ProfileMetadata).name === 'string') {\n metadata.name = (parsed as ProfileMetadata).name;\n }\n if (typeof (parsed as ProfileMetadata).display_name === 'string') {\n metadata.display_name = (parsed as ProfileMetadata).display_name;\n }\n if (typeof (parsed as ProfileMetadata).about === 'string') {\n metadata.about = (parsed as ProfileMetadata).about;\n }\n if (typeof (parsed as ProfileMetadata).picture === 'string') {\n metadata.picture = (parsed as ProfileMetadata).picture;\n }\n if (typeof (parsed as ProfileMetadata).website === 'string') {\n metadata.website = (parsed as ProfileMetadata).website;\n }\n return metadata;\n } catch (error) {\n console.error('Failed to parse profile metadata:', error);\n return null;\n }\n }\n\n private async enforceRateLimit(action: string, minIntervalMs: number): Promise<void> {\n const lastAt = this.lastActionAt.get(action) ?? 0;\n const now = Date.now();\n const waitMs = minIntervalMs - (now - lastAt);\n if (waitMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n this.lastActionAt.set(action, Date.now());\n }\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["#cacheOptions","#cachedEntry","#clearCachedEntry","#scheduleExpiry","#getCachedKeyIfValid","#clearKey","#expiryTimer","secp256k1","gcm","bin","bytes","sha256","secp256k1","#keyCache","#storageOptions","#prfOptions","#loadKeyInfoFromStorage","#currentKeyInfo","#saveKeyInfoToStorage","#clearKey","#signWithKey"],"sources":["../src/utils/utils.ts","../src/utils/key-cache.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/nosskey.ts","../src/utils/crypto-utils.ts","../src/utils/test-utils.ts","../src/services/auth.service.ts","../src/utils/validation.ts","../src/services/relay.service.ts"],"sourcesContent":["/**\n * @packageDocumentation\n */\n\n/**\n * @param bytes\n * @returns\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n const key = '0123456789abcdef';\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n const firstNibble = bytes[i] >> 4;\n const secondNibble = bytes[i] & 15;\n hex += key[firstNibble] + key[secondNibble];\n }\n return hex;\n}\n\n/**\n * @param hex\n * @returns\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const key = '0123456789abcdef';\n const bytes = [];\n let currentByte = 0;\n let highNibble = true;\n\n for (let i = 0; i < hex.length; i++) {\n const charValue = key.indexOf(hex[i].toLowerCase());\n if (charValue === -1) continue;\n\n if (highNibble) {\n currentByte = charValue << 4;\n highNibble = false;\n } else {\n currentByte += charValue;\n bytes.push(currentByte);\n highNibble = true;\n }\n }\n\n return new Uint8Array(bytes);\n}\n","/**\n * Key cache management for Nosskey\n * @packageDocumentation\n */\n\nimport type { KeyCacheOptions } from './types.js';\nimport { bytesToHex } from './utils.js';\n\n/**\n * Key cache entry with expiration time\n */\ninterface CacheEntry {\n id: string;\n sk: Uint8Array;\n expireAt: number;\n}\n\n/**\n * Key cache manager for managing temporary secret keys\n */\nexport class KeyCache {\n #cachedEntry: CacheEntry | null = null;\n\n #expiryTimer: NodeJS.Timeout | null = null;\n\n #cacheOptions: KeyCacheOptions = {\n enabled: false,\n timeoutMs: 5 * 60 * 1000,\n };\n\n /**\n * KeyCache\n * @param options\n */\n constructor(options?: Partial<KeyCacheOptions>) {\n if (options) {\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n if (Object.keys(options).length > 0 && this.#cachedEntry !== null) {\n this.clearAllCachedKeys();\n }\n\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n\n getCacheOptions(): KeyCacheOptions {\n return { ...this.#cacheOptions };\n }\n\n isEnabled(): boolean {\n return this.#cacheOptions.enabled;\n }\n\n /**\n * @param credentialId\n * @param sk\n */\n setKey(credentialId: Uint8Array | string, sk: Uint8Array): void {\n if (!this.#cacheOptions.enabled) return;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n const timeout =\n this.#cacheOptions.timeoutMs !== undefined ? this.#cacheOptions.timeoutMs : 5 * 60 * 1000;\n const expireAt = Date.now() + timeout;\n\n this.#clearCachedEntry();\n\n this.#cachedEntry = {\n id,\n sk: new Uint8Array(sk),\n expireAt,\n };\n\n try {\n this.#scheduleExpiry();\n } catch (error) {\n this.#clearCachedEntry();\n throw error;\n }\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n getKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n if (!this.#cacheOptions.enabled) return undefined;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n return this.#getCachedKeyIfValid(id);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n\n if (this.#cachedEntry && this.#cachedEntry.id === id) {\n this.#clearCachedEntry();\n }\n }\n\n clearAllCachedKeys(): void {\n this.#clearCachedEntry();\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n #getCachedKeyIfValid(credentialId: string): Uint8Array | undefined {\n if (!this.#cachedEntry || this.#cachedEntry.id !== credentialId) {\n return undefined;\n }\n\n if (Date.now() < this.#cachedEntry.expireAt) {\n return this.#cachedEntry.sk;\n }\n\n this.#clearCachedEntry();\n return undefined;\n }\n\n #clearCachedEntry(): void {\n if (this.#cachedEntry) {\n this.#clearKey(this.#cachedEntry.sk);\n this.#cachedEntry = null;\n }\n\n if (this.#expiryTimer) {\n clearTimeout(this.#expiryTimer);\n this.#expiryTimer = null;\n }\n }\n\n #scheduleExpiry(): void {\n if (!this.#cachedEntry) return;\n\n const now = Date.now();\n const timeToExpiry = this.#cachedEntry.expireAt - now;\n\n if (timeToExpiry <= 0) {\n this.#clearCachedEntry();\n return;\n }\n\n this.#expiryTimer = setTimeout(() => {\n this.#clearCachedEntry();\n }, timeToExpiry + 1);\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * PRF (Pseudo-Random Function) handler for WebAuthn\n * @packageDocumentation\n */\n\nimport type { GetPrfSecretOptions, PasskeyCreationOptions } from './types.js';\n\nconst PRF_EVAL_INPUT = new TextEncoder().encode('nostr-pwk');\n\n/**\n * @returns PRF\n */\nexport async function isPrfSupported(): Promise<boolean> {\n try {\n const response = await navigator.credentials.get({\n publicKey: {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials: [],\n userVerification: 'required',\n extensions: { prf: { eval: { first: PRF_EVAL_INPUT } } },\n } as PublicKeyCredentialRequestOptions,\n });\n\n if (!response) return false;\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const res = assertion.getClientExtensionResults()?.prf?.results?.first;\n return !!res;\n } catch {\n return false;\n }\n}\n\n/**\n * @param options\n * @returns Credential\n */\nexport async function createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n // Node\n const rpName = options.rp?.name || (typeof location !== 'undefined' ? location.host : 'Nosskey');\n const rpId = options.rp?.id;\n const userName = options.user?.name || 'user@example.com';\n const userDisplayName = options.user?.displayName || 'Nosskey user';\n\n const credentialCreationOptions: CredentialCreationOptions = {\n publicKey: {\n rp: {\n name: rpName,\n id: rpId,\n },\n user: {\n id: crypto.getRandomValues(new Uint8Array(16)),\n name: userName,\n displayName: userDisplayName,\n },\n pubKeyCredParams: options.pubKeyCredParams || [{ type: 'public-key', alg: -7 }], // ES256\n authenticatorSelection: options.authenticatorSelection || {\n residentKey: 'required',\n userVerification: 'required',\n },\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n extensions: options.extensions || { prf: {} }, // PRF拡張を要求\n } as PublicKeyCredentialCreationOptions,\n };\n const cred = (await navigator.credentials.create(\n credentialCreationOptions\n )) as PublicKeyCredential;\n\n return new Uint8Array(cred.rawId);\n}\n\n/**\n * ID\n * @param credentialId \n * @param options PRF(rpId、timeout、userVerification)\n * @returns PRF credentialID\n */\nexport async function getPrfSecret(\n credentialId?: Uint8Array,\n options?: GetPrfSecretOptions\n): Promise<{ secret: Uint8Array; id: Uint8Array }> {\n const allowCredentials = credentialId ? [{ type: 'public-key' as const, id: credentialId }] : [];\n\n const requestOptions: PublicKeyCredentialRequestOptions = {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials,\n userVerification: options?.userVerification || 'required',\n extensions: {\n prf: { eval: { first: PRF_EVAL_INPUT } },\n } as AuthenticationExtensionsClientInputs,\n };\n\n if (options?.rpId) {\n requestOptions.rpId = options.rpId;\n }\n if (options?.timeout) {\n requestOptions.timeout = options.timeout;\n }\n\n const response = await navigator.credentials.get({\n publicKey: requestOptions,\n });\n\n if (!response) {\n throw new Error('Authentication failed');\n }\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const secret = assertion.getClientExtensionResults()?.prf?.results?.first;\n if (!secret) {\n throw new Error('PRF secret not available');\n }\n\n // response credentialId\n const responseId = new Uint8Array((response as PublicKeyCredential).rawId);\n\n return {\n secret: new Uint8Array(secret),\n id: responseId,\n };\n}\n","/**\n * PRF support check with a password-protected-key fallback.\n * If the PRF WebAuthn extension is unavailable, callers can fall back to a\n * password-protected private key. The private key is wrapped with a password-\n * derived AES-GCM key and stored alongside the public key (SPKI).\n *\n * This implementation uses @noble libraries for cryptographic operations,\n * ensuring functionality even when Web Crypto API is unavailable.\n */\n\nimport { getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { pbkdf2 } from '@noble/hashes/pbkdf2';\nimport { gcm } from '@noble/ciphers/aes';\n\nconst { randomBytes } = secp256k1.etc;\nconst aesGcm = gcm;\n\nexport type PasswordProtectedBundle = {\n publicKeySpkiBase64: string;\n wrappedPrivateKeyBase64: string;\n saltBase64: string;\n ivBase64: string;\n};\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);\n if (typeof window !== 'undefined' && (window as any).btoa) {\n return (window as any).btoa(binary);\n }\n return btoa(binary);\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n if (typeof window !== 'undefined' && (window as any).atob) {\n const bin = (window as any).atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n }\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport async function checkPRFSupport(): Promise<boolean> {\n try {\n const caps = typeof PublicKeyCredential !== 'undefined' ? await PublicKeyCredential.getClientCapabilities() : null;\n const supported = caps?.['extension:prf'] === true;\n if (supported) {\n console.log('PRF extension is supported.');\n } else {\n console.log('PRF extension is not supported.');\n }\n return !!supported;\n } catch (e) {\n console.log('Could not determine PRF support:', e);\n return false;\n }\n}\n\nexport async function generatePasswordProtectedKey(password: string): Promise<PasswordProtectedBundle> {\n const privateKey = secp256k1.utils.randomPrivateKey();\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n\n const publicKeySpkiBase64 = toBase64(publicKey);\n\n const salt = randomBytes(16);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = randomBytes(12);\n const ct = aesGcm(derivedKey, iv).encrypt(privateKey);\n\n return {\n publicKeySpkiBase64,\n wrappedPrivateKeyBase64: toBase64(ct),\n saltBase64: toBase64(salt),\n ivBase64: toBase64(iv),\n };\n}\n\nexport async function unwrapPasswordProtectedPrivateKey(bundle: PasswordProtectedBundle, password: string): Promise<Uint8Array> {\n const salt = fromBase64(bundle.saltBase64);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = fromBase64(bundle.ivBase64);\n const ct = fromBase64(bundle.wrappedPrivateKeyBase64);\n const privateKey = aesGcm(derivedKey, iv).decrypt(ct);\n return privateKey;\n}\n\nfunction base64UrlToBytes(base64url: string): Uint8Array {\n let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');\n const pad = base64.length % 4;\n if (pad) base64 += '='.repeat(4 - pad);\n if (typeof window !== 'undefined' && (window as any).atob) {\n const binary = (window as any).atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n }\n const bin = atob(base64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport function importPublicKeyFromBundle(bundle: PasswordProtectedBundle): Uint8Array {\n const spki = fromBase64(bundle.publicKeySpkiBase64);\n return spki;\n}\n\nconst DEFAULT_SALT = 'nostr-key-derivation';\n\nexport function deriveNostrPrivateKey(password: string, salt: string = DEFAULT_SALT): Uint8Array {\n const derivedBits = pbkdf2(sha256, new TextEncoder().encode(password), new TextEncoder().encode(salt), { c: 100000, dkLen: 32 });\n return derivedBits;\n}\n\nexport function getPublicKeyFromPassword(password: string, salt: string = DEFAULT_SALT): string {\n const sk = deriveNostrPrivateKey(password, salt);\n return getPublicKey(sk);\n}\n","import { finalizeEvent, getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { sha256 as nobleSha256 } from '@noble/hashes/sha256';\nimport { KeyCache } from './key-cache.js';\nimport { createPasskey, getPrfSecret, isPrfSupported } from './prf-handler.js';\nimport { checkPRFSupport, deriveNostrPrivateKey, getPublicKeyFromPassword, unwrapPasswordProtectedPrivateKey } from './prf-password-fallback.js';\nimport type {\n GetPrfSecretOptions,\n KeyCacheOptions,\n KeyOptions,\n NosskeyManagerLike,\n KeyManagerOptions,\n Event,\n KeyInfo,\n NostrKeyStorageOptions,\n PasskeyCreationOptions,\n SignOptions,\n} from './types.js';\n/**\n * Nosskey class for Passkey-Derived Nostr Identity\n * @packageDocumentation\n */\nimport { bytesToHex, hexToBytes } from './utils.js';\nimport type { KeyRecovery } from './types.js';\n\nexport function deriveSaltFromUsername(username?: string): string {\n if (!username) {\n return '';\n }\n \n const msgBuffer = new TextEncoder().encode(username.toLowerCase().trim());\n const hashBuffer = nobleSha256(msgBuffer);\n return bytesToHex(new Uint8Array(hashBuffer));\n}\n\nexport function parseRecoveryTag(tags: string[][]): KeyRecovery | null {\n const recoveryTag = tags.find(tag => tag[0] === 'r');\n if (!recoveryTag || recoveryTag.length < 3) return null;\n\n // Format: ['r', recoveryPubkey, recoverySalt, createdAt, signature]\n const createdAt = recoveryTag[3] ? parseInt(recoveryTag[3], 10) : undefined;\n return {\n recoveryPubkey: recoveryTag[1],\n recoverySalt: recoveryTag[2],\n createdAt: createdAt || undefined,\n signature: recoveryTag[4] || undefined,\n };\n}\n\nexport function createRecoveryTag(recovery: KeyRecovery): string[] {\n return [\n 'r',\n recovery.recoveryPubkey,\n recovery.recoverySalt,\n recovery.createdAt?.toString() || '',\n recovery.signature || '',\n ];\n}\n\nexport function getRecoverySignature(kind0: Event): string | null {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return null;\n \n const tag = kind0.tags?.find(t => t[0] === 'r');\n return tag && tag.length > 4 ? tag[4] || null : null;\n}\n\nexport async function verifyRecoverySignature(kind0: Event): Promise<boolean> {\n try {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return false;\n \n const signature = getRecoverySignature(kind0);\n if (!signature || !kind0.pubkey) return false;\n \n // Verify Schnorr signature: signature over current pubkey (as message)\n // using the recovery pubkey\n // Note: verify expects the message hash, not the message itself\n const messageHash = await sha256(kind0.pubkey);\n const signatureBytes = hexToBytes(signature);\n const pubkeyBytes = hexToBytes(kind0.pubkey);\n \n return secp256k1.verify(signatureBytes, messageHash, pubkeyBytes);\n } catch (e) {\n return false;\n }\n}\n\nfunction sha256(message: string): Uint8Array {\n return nobleSha256(new TextEncoder().encode(message));\n}\n\n/**\n * Nosskey - Passkey-Derived Nostr Keys\n */\nexport class NosskeyManager implements NosskeyManagerLike {\n #keyCache: KeyCache;\n\n // KeyInfo\n #currentKeyInfo: KeyInfo | null = null;\n\n // KeyInfo\n #storageOptions: NostrKeyStorageOptions = {\n enabled: true,\n storageKey: 'nosskey_keyinfo',\n };\n\n // PRF\n #prfOptions: GetPrfSecretOptions = {};\n\n /**\n * NosskeyManager\n * @param options\n */\n constructor(options?: KeyManagerOptions) {\n // KeyCache\n this.#keyCache = new KeyCache(options?.cacheOptions);\n\n if (options?.storageOptions) {\n this.#storageOptions = { ...this.#storageOptions, ...options.storageOptions };\n }\n\n // option\n const userVerification = options?.prfOptions?.userVerification ?? 'required';\n if (options?.prfOptions) {\n this.#prfOptions = { ...options.prfOptions, userVerification };\n } else {\n this.#prfOptions = { userVerification };\n }\n\n // KeyInfo\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n }\n }\n }\n\n /**\n * KeyInfo\n * @param options\n */\n setStorageOptions(options: Partial<NostrKeyStorageOptions>): void {\n this.#storageOptions = { ...this.#storageOptions, ...options };\n\n if (options.enabled === false) {\n this.clearStoredKeyInfo();\n }\n }\n\n /**\n * KeyInfo\n */\n getStorageOptions(): NostrKeyStorageOptions {\n return { ...this.#storageOptions };\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n this.#currentKeyInfo = keyInfo;\n\n if (this.#storageOptions.enabled) {\n void this.#saveKeyInfoToStorage(keyInfo);\n }\n }\n\n /**\n * KeyInfo\n */\n getCurrentKeyInfo(): KeyInfo | null {\n // KeyInfo\n if (!this.#currentKeyInfo && this.#storageOptions.enabled) {\n this.#currentKeyInfo = this.#loadKeyInfoFromStorage();\n }\n return this.#currentKeyInfo;\n }\n\n /**\n * KeyInfo\n * @returns KeyInfo\n */\n hasKeyInfo(): boolean {\n if (this.#currentKeyInfo) {\n return true;\n }\n\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n async #saveKeyInfoToStorage(keyInfo: KeyInfo): Promise<void> {\n if (!this.#storageOptions.enabled) return;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.setItem(key, JSON.stringify(keyInfo));\n }\n\n /**\n * KeyInfo\n */\n #loadKeyInfoFromStorage(): KeyInfo | null {\n if (!this.#storageOptions.enabled) return null;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return null;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n const data = storage.getItem(key);\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as KeyInfo;\n } catch (e) {\n console.error('Failed to parse stored KeyInfo', e);\n return null;\n }\n }\n\n /**\n * KeyInfo\n */\n clearStoredKeyInfo(): void {\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.removeItem(key);\n\n // KeyInfo\n this.#currentKeyInfo = null;\n }\n\n /**\n * NIP-07\n * KeyInfo\n */\n async getPublicKey(): Promise<string> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return keyInfo.pubkey;\n }\n\n /**\n * NIP-07\n * KeyInfo\n * @param event Nostr\n */\n async signEvent(event: Event): Promise<Event> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return this.signEventWithKeyInfo(event, keyInfo);\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n this.#keyCache.setCacheOptions(options);\n }\n\n getCacheOptions(): KeyCacheOptions {\n return this.#keyCache.getCacheOptions();\n }\n\n getCachedSecretKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n return this.#keyCache.getKey(credentialId);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n this.#keyCache.clearCachedKey(credentialId);\n }\n\n clearAllCachedKeys(): void {\n this.#keyCache.clearAllCachedKeys();\n }\n\n /**\n * @param options\n * @returns Credential\n */\n async createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n return createPasskey({\n rp: {\n id: this.#prfOptions.rpId,\n name: this.#prfOptions.rpId,\n },\n authenticatorSelection: {\n userVerification: this.#prfOptions.userVerification,\n },\n ...options,\n });\n }\n\n/**\n * Check if PRF is supported\n */\n async checkPRFSupport(): Promise<boolean> {\n return checkPRFSupport();\n }\n\n /**\n * Create Nostr key - automatically uses password fallback if PRF unavailable\n * @param credentialId Passkey credential ID\n * @param password Password for encryption (required if PRF not supported)\n * @param options \n */\n async createKey(credentialId?: Uint8Array, password?: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const prfSupported = await this.checkPRFSupport();\n \n let keyInfo: KeyInfo;\n \n if (prfSupported) {\n keyInfo = await this.createPrfNostrKey(credentialId, options);\n \n // Auto-add password recovery if requested and PRF is supported\n if (options.recoveryPassword) {\n keyInfo = await this.addPasswordRecovery(options.recoveryPassword, credentialId);\n }\n } else {\n if (!password) {\n throw new Error('Password is required when PRF is not supported');\n }\n if (!options.username) {\n throw new Error('Username is required when PRF is not supported');\n }\n keyInfo = await this.createPasswordProtectedNostrKey(password, options);\n }\n \n return keyInfo;\n }\n\n /**\n * Create Nostr key using PRF (standard passkey flow)\n */\n async createPrfNostrKey(credentialId?: Uint8Array, options: KeyOptions = {}): Promise<KeyInfo> {\n const { secret: sk, id: responseId } = await getPrfSecret(credentialId, this.#prfOptions);\n\n if (sk.every((byte) => byte === 0)) {\n throw new Error('Invalid PRF output: all zeros');\n }\n\n const skHex = bytesToHex(sk);\n const publicKey = getPublicKey(sk);\n \n const salt = await deriveSaltFromUsername(options.username);\n\n const keyInfo: KeyInfo = {\n credentialId: bytesToHex(credentialId || responseId),\n pubkey: publicKey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n if (this.#keyCache.isEnabled() && this.#keyCache.getCacheOptions().cacheOnCreation) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n\n return keyInfo;\n }\n\n /**\n * Create Nostr key using password-derived key (fallback when PRF unavailable)\n * @param password Password to derive the private key\n * @param options \n */\n async createPasswordProtectedNostrKey(password: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const salt = await deriveSaltFromUsername(options.username);\n const pubkey = getPublicKeyFromPassword(password, salt);\n\n const credentialId = bytesToHex((typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto).getRandomValues(new Uint8Array(16)));\n\n const keyInfo: KeyInfo = {\n credentialId,\n pubkey: pubkey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n return keyInfo;\n }\n\n/**\n * @param event Nostr\n * @param keyInfo KeyInfo\n * @param options\n */\n async signEventWithKeyInfo(\n event: Event,\n keyInfo: KeyInfo,\n options: SignOptions = {}\n ): Promise<Event> {\n const { clearMemory = true, tags, password } = options;\n\n const shouldUseCache = this.#keyCache.isEnabled();\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n\n let sk: Uint8Array | undefined;\n\n if (isPasswordDerived) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = deriveNostrPrivateKey(password, keyInfo.salt);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password to sign.');\n }\n } else if (keyInfo.passwordProtectedBundle) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle!, password);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password or use createNostrKey to initialize.');\n }\n } else {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n\n if (!sk) {\n const { secret: prfSecret } = await getPrfSecret(\n hexToBytes(keyInfo.credentialId),\n this.#prfOptions\n );\n sk = prfSecret;\n\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n }\n\n const eventToSign = {\n kind: event.kind,\n content: event.content,\n created_at: event.created_at || Math.floor(Date.now() / 1000),\n tags: tags ? [...(event.tags || []), ...tags] : event.tags || [],\n };\n\n const signedEvent = finalizeEvent(eventToSign, sk);\n\n if (!shouldUseCache && clearMemory) {\n this.#clearKey(sk);\n }\n\n return signedEvent;\n }\n\n/**\n * @param keyInfo KeyInfo\n * @param credentialId KeyInfoのcredentialId\n * @param options\n * @returns \n */\n async exportNostrKey(keyInfo: KeyInfo, credentialId?: Uint8Array, options: KeyOptions = {}): Promise<string> {\n if (keyInfo.passwordProtectedBundle) {\n if (!options.password) {\n throw new Error('Password is required for password-protected keys');\n }\n const sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle, options.password);\n return bytesToHex(sk);\n }\n\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n if (isPasswordDerived) {\n if (!options.password) {\n throw new Error('Password is required for password-derived keys');\n }\n const sk = deriveNostrPrivateKey(options.password, keyInfo.salt);\n return bytesToHex(sk);\n }\n\n let usedCredentialId = credentialId;\n\n if (!usedCredentialId && keyInfo.credentialId) {\n usedCredentialId = hexToBytes(keyInfo.credentialId);\n }\n\n const { secret: sk } = await getPrfSecret(usedCredentialId, this.#prfOptions);\n const skHex = bytesToHex(sk);\n\n return skHex;\n }\n\n /**\n * PRF\n */\n async isPrfSupported(): Promise<boolean> {\n return isPrfSupported();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n * @param currentCredentialId Current passkey credential ID\n */\n async addPasswordRecovery(password: string, currentCredentialId?: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (keyInfo.passwordProtectedBundle) {\n throw new Error('Password recovery already exists for password-derived key');\n }\n\n if (keyInfo.recovery) {\n throw new Error('Recovery already configured');\n }\n\n const usedCredentialId = currentCredentialId || (keyInfo.credentialId ? hexToBytes(keyInfo.credentialId) : undefined);\n if (!usedCredentialId) {\n throw new Error('Credential ID required');\n }\n\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n\n // Generate recovery salt\n const recoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n\n // Derive recovery pubkey from password\n const recoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n\n // Sign current pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, keyInfo.pubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n ...keyInfo,\n recovery: {\n recoveryPubkey,\n recoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n #signWithKey(sk: Uint8Array, message: string): string {\n const event = finalizeEvent({\n kind: 0,\n content: '',\n tags: [],\n created_at: Math.floor(Date.now() / 1000),\n }, sk);\n return event.sig;\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (!keyInfo.recovery) {\n throw new Error('No recovery key configured');\n }\n\n if (!newCredentialId) {\n throw new Error('New credential ID is required for recovery');\n }\n\n const { recoveryPubkey, recoverySalt } = keyInfo.recovery;\n\n // Verify password\n const derivedRecoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n if (derivedRecoveryPubkey !== recoveryPubkey) {\n throw new Error('Invalid recovery password');\n }\n\n // Derive new key from new credential\n const { secret: newSk } = await getPrfSecret(newCredentialId, this.#prfOptions);\n const newPubkey = getPublicKey(newSk);\n this.#clearKey(newSk);\n\n // Generate new recovery for the new key\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n const newRecoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n const newRecoveryPubkey = getPublicKeyFromPassword(password, newRecoverySalt);\n\n // Sign new pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, newPubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n credentialId: bytesToHex(newCredentialId),\n pubkey: newPubkey,\n salt: keyInfo.salt,\n recovery: {\n recoveryPubkey: newRecoveryPubkey,\n recoverySalt: newRecoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n /**\n * Get the recovery data for publishing to kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number; signature?: string } | null {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo || !keyInfo.recovery) return null;\n\n return {\n recoveryPubkey: keyInfo.recovery.recoveryPubkey,\n recoverySalt: keyInfo.recovery.recoverySalt,\n createdAt: keyInfo.recovery.createdAt,\n signature: keyInfo.recovery.signature,\n };\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * Cryptographic utilities for Nosskey\n * @packageDocumentation\n */\n\nconst INFO_BYTES = new TextEncoder().encode('nostr-pwk');\nconst AES_LENGTH = 256; // bits\n\nfunction getSubtle(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n return subtle;\n}\n\n/**\n * PRF AES-GCM\n * @param secret PRF\n * @param salt\n * @returns AES-GCM\n */\nexport async function deriveAesGcmKey(secret: Uint8Array, salt: Uint8Array): Promise<CryptoKey> {\n const subtle = getSubtle();\n const keyMaterial = await subtle.importKey('raw', secret, 'HKDF', false, ['deriveKey']);\n\n return subtle.deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt, info: INFO_BYTES },\n keyMaterial,\n { name: 'AES-GCM', length: AES_LENGTH },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param plaintext\n * @returns\n */\nexport async function aesGcmEncrypt(key: CryptoKey, iv: Uint8Array, plaintext: Uint8Array) {\n const subtle = getSubtle();\n const buf = await subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);\n\n const bytes = new Uint8Array(buf);\n return {\n ciphertext: bytes.slice(0, -16),\n tag: bytes.slice(-16),\n };\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param ct\n * @param tag\n * @returns\n */\nexport async function aesGcmDecrypt(\n key: CryptoKey,\n iv: Uint8Array,\n ct: Uint8Array,\n tag: Uint8Array\n): Promise<Uint8Array> {\n const subtle = getSubtle();\n const buf = await subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n new Uint8Array([...ct, ...tag])\n );\n return new Uint8Array(buf);\n}\n","/**\n * Test utilities for sdk\n * @packageDocumentation\n */\n\n/**\n * Helper for testing/debugging\n * @param userId - User identifier\n * @returns Promise resolving to the dummy credential\n */\nexport async function registerDummyPasskey(userId: string): Promise<PublicKeyCredential> {\n // Create a dummy credential for testing\n const dummySignature = new Uint8Array(64);\n // Fill with some non-zero values for testing\n for (let i = 0; i < dummySignature.length; i++) {\n dummySignature[i] = (i + 1) % 256;\n }\n\n const dummyId = new Uint8Array(32);\n for (let i = 0; i < dummyId.length; i++) {\n dummyId[i] = (i + 1) % 256;\n }\n\n const credential = {\n id: 'dummy-credential-id',\n rawId: dummyId,\n type: 'public-key',\n response: {\n clientDataJSON: new Uint8Array(0),\n attestationObject: new Uint8Array(0),\n signature: dummySignature,\n authenticatorData: new Uint8Array(0),\n getAuthenticatorData: () => new Uint8Array(0),\n getPublicKey: () => new Uint8Array(0),\n getPublicKeyAlgorithm: () => -7,\n getTransports: () => ['internal'],\n },\n } as unknown as PublicKeyCredential;\n\n return credential;\n}\n","import { NosskeyManager, type KeyInfo, type Event, type PasskeyCreationOptions, type SignOptions, type KeyOptions } from '../utils';\nimport type { AuthServiceConfig } from '../types/auth';\n\n/**\n * Service wrapper around NosskeyManager\n * Handles WebAuthn/Passkey integration with Nostr\n */\nexport class AuthService {\n private manager: NosskeyManager | null = null;\n private config: AuthServiceConfig;\n\n constructor(config: AuthServiceConfig = {}) {\n this.config = {\n rpId: config.rpId || (typeof window !== 'undefined' ? window.location.hostname.replace(/^www\\./, '') : 'localhost'),\n rpName: config.rpName || this.getDefaultRpName(),\n storageKey: config.storageKey || 'nsauth_keyinfo',\n cacheTimeoutMs: config.cacheTimeoutMs || 30 * 60 * 1000,\n cacheOnCreation: config.cacheOnCreation !== undefined ? config.cacheOnCreation : true,\n };\n }\n\n private getDefaultRpName(): string {\n if (typeof window === 'undefined') return 'localhost';\n const hostname = window.location.hostname;\n if (hostname.includes('nosskey.app')) return 'nosskey.app';\n return hostname.replace(/^www\\./, '');\n }\n\n /**\n * Initialize the NosskeyManager instance\n */\n private getManager(): NosskeyManager {\n if (!this.manager) {\n this.manager = new NosskeyManager({\n cacheOptions: {\n enabled: true,\n timeoutMs: this.config.cacheTimeoutMs,\n cacheOnCreation: this.config.cacheOnCreation,\n },\n storageOptions: {\n enabled: true,\n storageKey: this.config.storageKey,\n },\n });\n }\n return this.manager;\n }\n\n /**\n * Create a new passkey\n * Uses platform authenticator only (Touch ID, Face ID, Windows Hello)\n */\n async createPasskey(username?: string): Promise<Uint8Array> {\n const manager = this.getManager();\n \n const rpId = this.config.rpId === 'localhost' ? 'localhost' : this.config.rpId;\n const rpName = this.config.rpName;\n \n const trimmedUsername = username?.trim();\n const uniqueUsername = trimmedUsername \n ? trimmedUsername \n : `user-${Date.now()}@example.com`;\n \n const options: PasskeyCreationOptions = {\n rp: {\n id: rpId,\n name: rpName,\n },\n user: {\n name: uniqueUsername,\n displayName: trimmedUsername || 'User',\n },\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n residentKey: 'preferred',\n userVerification: 'preferred',\n },\n extensions: {\n prf: {},\n },\n };\n \n return await manager.createPasskey(options);\n }\n\n/**\n * Create a new Nostr key from a credential ID\n * Automatically uses password fallback if PRF is not supported\n * @param credentialId Passkey credential ID\n * @param password Password (required if PRF not supported)\n * @param options.username Username for the key\n * @param options.recoveryPassword Password for recovery (enables recovery on new device)\n */\n async createKey(credentialId?: Uint8Array, password?: string, options?: KeyOptions): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.createKey(credentialId, password, options);\n }\n\n /**\n * Check if PRF is supported, otherwise password fallback is needed\n */\n async checkPRFSupport(): Promise<boolean> {\n const manager = this.getManager();\n return await manager.checkPRFSupport();\n }\n\n /**\n * Get the current public key\n */\n async getPublicKey(): Promise<string> {\n const manager = this.getManager();\n return await manager.getPublicKey();\n }\n\n /**\n * Sign a Nostr event\n */\n async signEvent(event: Event, options?: SignOptions): Promise<Event> {\n const manager = this.getManager();\n return await manager.signEvent(event, options);\n }\n\n /**\n * Get current key info\n */\n getCurrentKeyInfo(): KeyInfo | null {\n const manager = this.getManager();\n return manager.getCurrentKeyInfo();\n }\n\n /**\n * Set current key info\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n const manager = this.getManager();\n manager.setCurrentKeyInfo(keyInfo);\n }\n\n /**\n * Check if key info exists\n */\n hasKeyInfo(): boolean {\n const manager = this.getManager();\n return manager.hasKeyInfo();\n }\n\n /**\n * Clear stored key info\n */\n clearStoredKeyInfo(): void {\n const manager = this.getManager();\n manager.clearStoredKeyInfo();\n }\n\n/**\n * Check if PRF is supported (legacy alias)\n */\n async isPrfSupported(): Promise<boolean> {\n return this.checkPRFSupport();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n */\n async addPasswordRecovery(password: string): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.addPasswordRecovery(password);\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.activateWithPassword(password, newCredentialId);\n }\n\n /**\n * Get recovery data for kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number } | null {\n const manager = this.getManager();\n return manager.getRecoveryForKind0();\n }\n}\n\n","export const MAX_ROLE_LENGTH = 100;\nconst ROLE_PATTERN = /^[a-zA-Z0-9\\s\\-_]+$/;\n\nexport const isValidRoleTag = (role: string): boolean => {\n const trimmed = role.trim();\n return (\n trimmed.length > 0 &&\n trimmed.length <= MAX_ROLE_LENGTH &&\n ROLE_PATTERN.test(trimmed)\n );\n};\n\nexport const isValidPubkey = (pubkey: string): boolean =>\n pubkey.length === 64 && /^[0-9a-fA-F]+$/.test(pubkey);\n\nexport const isValidHttpUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['http:', 'https:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n};\n\nexport const isValidRelayUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['ws:', 'wss:'].includes(parsed.protocol) && parsed.hostname.length > 0;\n } catch {\n return false;\n }\n};\n","import type { EventStore } from 'applesauce-core';\nimport type { Event } from '../types/nostr';\nimport type { ProfileMetadata, FollowEntry } from '../types/nostr';\nimport type { RelayServiceConfig } from '../types/auth';\nimport { isValidPubkey, isValidRelayUrl, isValidRoleTag } from '../utils/validation';\n\n/**\n * Service for communicating with Nostr relays using applesauce-core\n */\nexport class RelayService {\n private eventStore: EventStore | null = null;\n private relayUrls: string[];\n private defaultRelays = ['wss://relay.damus.io'];\n private readonly maxProfileContentSize = 10000;\n private readonly minProfileQueryIntervalMs = 300;\n private readonly minPublishIntervalMs = 750;\n private readonly lastActionAt = new Map<string, number>();\n\n constructor(config: RelayServiceConfig = {}) {\n this.relayUrls = this.validateRelayUrls(config.relayUrls ?? this.defaultRelays);\n }\n\n /**\n * Initialize with applesauce EventStore\n */\n initialize(eventStore: EventStore): void {\n this.eventStore = eventStore;\n // Set default relays if EventStore has a method for it\n if (eventStore && 'setRelays' in eventStore && typeof eventStore.setRelays === 'function') {\n (eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Set relay URLs\n */\n setRelays(urls: string[]): void {\n this.relayUrls = this.validateRelayUrls(urls);\n if (this.eventStore && 'setRelays' in this.eventStore && typeof this.eventStore.setRelays === 'function') {\n (this.eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Get current relay URLs\n */\n getRelays(): string[] {\n return [...this.relayUrls];\n }\n\n /**\n * Publish an event to relays\n */\n async publishEvent(event: Event, timeoutMs = 1000): Promise<boolean> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('publish', this.minPublishIntervalMs);\n return new Promise((resolve, reject) => {\n if (this.relayUrls.length === 0) {\n reject(new Error('No relays configured'));\n return;\n }\n\n // Use EventStore's publish method\n // Note: This is a simplified implementation - actual applesauce API may differ\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.publish !== 'function') {\n reject(new Error('EventStore does not support publish method'));\n return;\n }\n const subscription = eventStore.publish(event).subscribe({\n next: (response: any) => {\n if (response?.type === 'OK') {\n subscription.unsubscribe();\n resolve(true);\n }\n },\n error: (error: Error) => {\n subscription.unsubscribe();\n reject(error);\n },\n });\n\n // Timeout fallback\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(false);\n }, timeoutMs);\n });\n }\n\n /**\n * Fetch a profile (Kind 0 event)\n */\n async fetchProfile(pubkey: string): Promise<ProfileMetadata | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-profile', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n subscription.unsubscribe();\n resolve(metadata);\n return;\n }\n console.error('Failed to parse profile metadata');\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n // Timeout\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch role tag from profile event (Kind 0)\n */\n async fetchProfileRoleTag(pubkey: string): Promise<string | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-role-tag', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const tags = packet.event.tags || [];\n for (const tag of tags) {\n if (tag[0] === 'role' && tag[1]) {\n const candidate = tag[1].trim();\n if (isValidRoleTag(candidate)) {\n subscription.unsubscribe();\n resolve(candidate);\n return;\n }\n }\n }\n subscription.unsubscribe();\n resolve(null);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile role tag:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch a follow list (Kind 3 event)\n */\n async fetchFollowList(pubkey: string): Promise<FollowEntry[]> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-follow-list', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [3],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve([]);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 3) {\n const followList: FollowEntry[] = [];\n const tags = packet.event.tags || [];\n\n for (const tag of tags) {\n if (tag[0] === 'p' && tag[1]) {\n followList.push({\n pubkey: tag[1],\n relay: tag[2] || undefined,\n petname: tag[3] || undefined,\n });\n }\n }\n\n subscription.unsubscribe();\n resolve(followList);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve([]);\n },\n error: (error: Error) => {\n console.error('Error fetching follow list:', error);\n subscription.unsubscribe();\n resolve([]);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve([]);\n }, 10000);\n });\n }\n\n /**\n * Fetch multiple profiles in batch\n */\n async fetchMultipleProfiles(pubkeys: string[]): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n if (pubkeys.length === 0) {\n return new Map();\n }\n\n await this.enforceRateLimit('fetch-multiple-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, ProfileMetadata>();\n const filter = {\n kinds: [0],\n authors: pubkeys,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n profiles.set(packet.event.pubkey, metadata);\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(profiles);\n },\n error: (error: Error) => {\n console.error('Error fetching profiles:', error);\n subscription.unsubscribe();\n resolve(profiles);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(profiles);\n }, 1000);\n });\n }\n\n /**\n * Query kind 0 events (profiles) by pubkey\n * If pubkeys array is empty, fetches recent kind 0 events\n */\n async queryProfiles(pubkeys: string[] = [], limit = 100): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('query-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, { metadata: ProfileMetadata; timestamp: number }>();\n const filter: any = {\n kinds: [0],\n limit,\n };\n\n if (pubkeys.length > 0) {\n filter.authors = pubkeys;\n }\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n const timestamp = packet.event.created_at || 0;\n const existing = profiles.get(packet.event.pubkey);\n if (!existing || timestamp > existing.timestamp) {\n profiles.set(packet.event.pubkey, { metadata, timestamp });\n }\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n error: (error: Error) => {\n console.error('Error querying profiles:', error);\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n }, 10000);\n });\n }\n\n /**\n * Publish or update a kind 3 event (follow list/contacts)\n */\n async publishFollowList(\n pubkey: string,\n followList: FollowEntry[],\n signEvent: (event: Event) => Promise<Event>\n ): Promise<boolean> {\n const tags: string[][] = followList.map((entry) => {\n if (!isValidPubkey(entry.pubkey)) {\n throw new Error('Invalid pubkey format for follow list entry.');\n }\n if (entry.relay && !isValidRelayUrl(entry.relay)) {\n throw new Error('Invalid relay URL format for follow list entry.');\n }\n const tag: string[] = ['p', entry.pubkey];\n if (entry.relay) {\n tag.push(entry.relay);\n }\n if (entry.petname) {\n tag.push(entry.petname);\n }\n return tag;\n });\n\n const event: Event = {\n kind: 3,\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n tags,\n };\n\n const signedEvent = await signEvent(event);\n return await this.publishEvent(signedEvent);\n }\n\n private validateRelayUrls(urls: string[]): string[] {\n if (urls.length === 0) {\n return [];\n }\n const validUrls = urls.filter((url) => isValidRelayUrl(url));\n if (validUrls.length !== urls.length) {\n throw new Error('Invalid relay URL format');\n }\n return validUrls;\n }\n\n private parseProfileMetadata(content: string): ProfileMetadata | null {\n if (content.length > this.maxProfileContentSize) {\n return null;\n }\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n const metadata: ProfileMetadata = {};\n if (typeof (parsed as ProfileMetadata).name === 'string') {\n metadata.name = (parsed as ProfileMetadata).name;\n }\n if (typeof (parsed as ProfileMetadata).display_name === 'string') {\n metadata.display_name = (parsed as ProfileMetadata).display_name;\n }\n if (typeof (parsed as ProfileMetadata).about === 'string') {\n metadata.about = (parsed as ProfileMetadata).about;\n }\n if (typeof (parsed as ProfileMetadata).picture === 'string') {\n metadata.picture = (parsed as ProfileMetadata).picture;\n }\n if (typeof (parsed as ProfileMetadata).website === 'string') {\n metadata.website = (parsed as ProfileMetadata).website;\n }\n return metadata;\n } catch (error) {\n console.error('Failed to parse profile metadata:', error);\n return null;\n }\n }\n\n private async enforceRateLimit(action: string, minIntervalMs: number): Promise<void> {\n const lastAt = this.lastActionAt.get(action) ?? 0;\n const now = Date.now();\n const waitMs = minIntervalMs - (now - lastAt);\n if (waitMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n this.lastActionAt.set(action, Date.now());\n }\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,SAAgB,WAAW,OAA2B;CACpD,MAAM,MAAM;CACZ,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,cAAc,MAAM,MAAM;EAChC,MAAM,eAAe,MAAM,KAAK;AAChC,SAAO,IAAI,eAAe,IAAI;;AAEhC,QAAO;;;;;;AAOT,SAAgB,WAAW,KAAyB;CAClD,MAAM,MAAM;CACZ,MAAM,QAAQ,EAAE;CAChB,IAAI,cAAc;CAClB,IAAI,aAAa;AAEjB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,YAAY,IAAI,QAAQ,IAAI,GAAG,aAAa,CAAC;AACnD,MAAI,cAAc,GAAI;AAEtB,MAAI,YAAY;AACd,iBAAc,aAAa;AAC3B,gBAAa;SACR;AACL,kBAAe;AACf,SAAM,KAAK,YAAY;AACvB,gBAAa;;;AAIjB,QAAO,IAAI,WAAW,MAAM;;;;;;;;ACvB9B,IAAa,WAAb,MAAsB;CACpB,eAAkC;CAElC,eAAsC;CAEtC,gBAAiC;EAC/B,SAAS;EACT,WAAW,MAAS;EACrB;;;;;CAMD,YAAY,SAAoC;AAC9C,MAAI,QACF,OAAKA,eAAgB;GAAE,GAAG,MAAKA;GAAe,GAAG;GAAS;;;;;CAO9D,gBAAgB,SAAyC;AACvD,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,KAAK,MAAKC,gBAAiB,KAC3D,MAAK,oBAAoB;AAG3B,QAAKD,eAAgB;GAAE,GAAG,MAAKA;GAAe,GAAG;GAAS;;CAG5D,kBAAmC;AACjC,SAAO,EAAE,GAAG,MAAKA,cAAe;;CAGlC,YAAqB;AACnB,SAAO,MAAKA,aAAc;;;;;;CAO5B,OAAO,cAAmC,IAAsB;AAC9D,MAAI,CAAC,MAAKA,aAAc,QAAS;EAEjC,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;EACrF,MAAM,UACJ,MAAKA,aAAc,cAAc,SAAY,MAAKA,aAAc,YAAY,MAAS;EACvF,MAAM,WAAW,KAAK,KAAK,GAAG;AAE9B,QAAKE,kBAAmB;AAExB,QAAKD,cAAe;GAClB;GACA,IAAI,IAAI,WAAW,GAAG;GACtB;GACD;AAED,MAAI;AACF,SAAKE,gBAAiB;WACf,OAAO;AACd,SAAKD,kBAAmB;AACxB,SAAM;;;;;;;CAQV,OAAO,cAA2D;AAChE,MAAI,CAAC,MAAKF,aAAc,QAAS,QAAO;EAExC,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;AACrF,SAAO,MAAKI,oBAAqB,GAAG;;;;;CAMtC,eAAe,cAAyC;EACtD,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;AAErF,MAAI,MAAKH,eAAgB,MAAKA,YAAa,OAAO,GAChD,OAAKC,kBAAmB;;CAI5B,qBAA2B;AACzB,QAAKA,kBAAmB;;;;;;CAO1B,qBAAqB,cAA8C;AACjE,MAAI,CAAC,MAAKD,eAAgB,MAAKA,YAAa,OAAO,aACjD;AAGF,MAAI,KAAK,KAAK,GAAG,MAAKA,YAAa,SACjC,QAAO,MAAKA,YAAa;AAG3B,QAAKC,kBAAmB;;CAI1B,oBAA0B;AACxB,MAAI,MAAKD,aAAc;AACrB,SAAKI,SAAU,MAAKJ,YAAa,GAAG;AACpC,SAAKA,cAAe;;AAGtB,MAAI,MAAKK,aAAc;AACrB,gBAAa,MAAKA,YAAa;AAC/B,SAAKA,cAAe;;;CAIxB,kBAAwB;AACtB,MAAI,CAAC,MAAKL,YAAc;EAExB,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,eAAe,MAAKA,YAAa,WAAW;AAElD,MAAI,gBAAgB,GAAG;AACrB,SAAKC,kBAAmB;AACxB;;AAGF,QAAKI,cAAe,iBAAiB;AACnC,SAAKJ,kBAAmB;KACvB,eAAe,EAAE;;;;;CAMtB,UAAU,KAAuB;AAC/B,OAAK,OAAO,EAAE;;;;;;AC3JlB,MAAM,iBAAiB,IAAI,aAAa,CAAC,OAAO,YAAY;;;;AAK5D,eAAsB,iBAAmC;AACvD,KAAI;EACF,MAAM,WAAW,MAAM,UAAU,YAAY,IAAI,EAC/C,WAAW;GACT,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;GACrD,kBAAkB,EAAE;GACpB,kBAAkB;GAClB,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,gBAAgB,EAAE,EAAE;GACzD,EACF,CAAC;AAEF,MAAI,CAAC,SAAU,QAAO;AAatB,SAAO,CAAC,CAXU,SAUI,2BAA2B,EAAE,KAAK,SAAS;SAE3D;AACN,SAAO;;;;;;;AAQX,eAAsB,cAAc,UAAkC,EAAE,EAAuB;CAE7F,MAAM,SAAS,QAAQ,IAAI,SAAS,OAAO,aAAa,cAAc,SAAS,OAAO;CACtF,MAAM,OAAO,QAAQ,IAAI;CACzB,MAAM,WAAW,QAAQ,MAAM,QAAQ;CACvC,MAAM,kBAAkB,QAAQ,MAAM,eAAe;CAErD,MAAM,4BAAuD,EAC3D,WAAW;EACT,IAAI;GACF,MAAM;GACN,IAAI;GACL;EACD,MAAM;GACJ,IAAI,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;GAC9C,MAAM;GACN,aAAa;GACd;EACD,kBAAkB,QAAQ,oBAAoB,CAAC;GAAE,MAAM;GAAc,KAAK;GAAI,CAAC;EAC/E,wBAAwB,QAAQ,0BAA0B;GACxD,aAAa;GACb,kBAAkB;GACnB;EACD,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;EACrD,YAAY,QAAQ,cAAc,EAAE,KAAK,EAAE,EAAE;EAC9C,EACF;CACD,MAAM,OAAQ,MAAM,UAAU,YAAY,OACxC,0BACD;AAED,QAAO,IAAI,WAAW,KAAK,MAAM;;;;;;;;AASnC,eAAsB,aACpB,cACA,SACiD;CACjD,MAAM,mBAAmB,eAAe,CAAC;EAAE,MAAM;EAAuB,IAAI;EAAc,CAAC,GAAG,EAAE;CAEhG,MAAM,iBAAoD;EACxD,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;EACrD;EACA,kBAAkB,SAAS,oBAAoB;EAC/C,YAAY,EACV,KAAK,EAAE,MAAM,EAAE,OAAO,gBAAgB,EAAE,EACzC;EACF;AAED,KAAI,SAAS,KACX,gBAAe,OAAO,QAAQ;AAEhC,KAAI,SAAS,QACX,gBAAe,UAAU,QAAQ;CAGnC,MAAM,WAAW,MAAM,UAAU,YAAY,IAAI,EAC/C,WAAW,gBACZ,CAAC;AAEF,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,wBAAwB;CAa1C,MAAM,SAVY,SAUO,2BAA2B,EAAE,KAAK,SAAS;AACpE,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,2BAA2B;CAI7C,MAAM,aAAa,IAAI,WAAY,SAAiC,MAAM;AAE1E,QAAO;EACL,QAAQ,IAAI,WAAW,OAAO;EAC9B,IAAI;EACL;;;;;;;;;;;;;;ACzHH,MAAM,EAAE,gBAAgBK,iBAAU;AAClC,MAAM,SAASC;AASf,SAAS,SAAS,OAA2B;CAC3C,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,YAAY,IAAK,WAAU,OAAO,aAAa,MAAM,GAAG;AAClF,KAAI,OAAO,WAAW,eAAgB,OAAe,KACnD,QAAQ,OAAe,KAAK,OAAO;AAErC,QAAO,KAAK,OAAO;;AAGrB,SAAS,WAAW,KAAyB;AAC3C,KAAI,OAAO,WAAW,eAAgB,OAAe,MAAM;EACzD,MAAMC,QAAO,OAAe,KAAK,IAAI;EACrC,MAAMC,UAAQ,IAAI,WAAWD,MAAI,OAAO;AACxC,OAAK,IAAI,IAAI,GAAG,IAAIA,MAAI,QAAQ,IAAK,SAAM,KAAKA,MAAI,WAAW,EAAE;AACjE,SAAOC;;CAET,MAAM,MAAM,KAAK,IAAI;CACrB,MAAM,QAAQ,IAAI,WAAW,IAAI,OAAO;AACxC,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,OAAM,KAAK,IAAI,WAAW,EAAE;AACjE,QAAO;;AAGT,eAAsB,kBAAoC;AACxD,KAAI;EAEF,MAAM,aADO,OAAO,wBAAwB,cAAc,MAAM,oBAAoB,uBAAuB,GAAG,QACrF,qBAAqB;AAC9C,MAAI,UACF,SAAQ,IAAI,8BAA8B;MAE1C,SAAQ,IAAI,kCAAkC;AAEhD,SAAO,CAAC,CAAC;UACF,GAAG;AACV,UAAQ,IAAI,oCAAoC,EAAE;AAClD,SAAO;;;AAIX,eAAsB,6BAA6B,UAAoD;CACrG,MAAM,aAAaH,iBAAU,MAAM,kBAAkB;CAGrD,MAAM,sBAAsB,SAFVA,iBAAU,aAAa,YAAY,KAAK,CAEX;CAE/C,MAAM,OAAO,YAAY,GAAG;CAC5B,MAAM,8CAAoBI,6BAAQ,IAAI,aAAa,CAAC,OAAO,SAAS,EAAE,MAAM;EAAE,GAAG;EAAQ,OAAO;EAAI,CAAC;CACrG,MAAM,KAAK,YAAY,GAAG;AAG1B,QAAO;EACL;EACA,yBAAyB,SAJhB,OAAO,YAAY,GAAG,CAAC,QAAQ,WAAW,CAId;EACrC,YAAY,SAAS,KAAK;EAC1B,UAAU,SAAS,GAAG;EACvB;;AAGH,eAAsB,kCAAkC,QAAiC,UAAuC;CAC9H,MAAM,OAAO,WAAW,OAAO,WAAW;CAC1C,MAAM,8CAAoBA,6BAAQ,IAAI,aAAa,CAAC,OAAO,SAAS,EAAE,MAAM;EAAE,GAAG;EAAQ,OAAO;EAAI,CAAC;CACrG,MAAM,KAAK,WAAW,OAAO,SAAS;CACtC,MAAM,KAAK,WAAW,OAAO,wBAAwB;AAErD,QADmB,OAAO,YAAY,GAAG,CAAC,QAAQ,GAAG;;AAoBvD,SAAgB,0BAA0B,QAA6C;AAErF,QADa,WAAW,OAAO,oBAAoB;;AAIrD,MAAM,eAAe;AAErB,SAAgB,sBAAsB,UAAkB,OAAe,cAA0B;AAE/F,yCAD2BA,6BAAQ,IAAI,aAAa,CAAC,OAAO,SAAS,EAAE,IAAI,aAAa,CAAC,OAAO,KAAK,EAAE;EAAE,GAAG;EAAQ,OAAO;EAAI,CAAC;;AAIlI,SAAgB,yBAAyB,UAAkB,OAAe,cAAsB;AAE9F,kDADW,sBAAsB,UAAU,KAAK,CACzB;;;;;;;;;ACjGzB,SAAgB,uBAAuB,UAA2B;AAChE,KAAI,CAAC,SACH,QAAO;CAIT,MAAM,8CADY,IAAI,aAAa,CAAC,OAAO,SAAS,aAAa,CAAC,MAAM,CAAC,CAChC;AACzC,QAAO,WAAW,IAAI,WAAW,WAAW,CAAC;;AAG/C,SAAgB,iBAAiB,MAAsC;CACrE,MAAM,cAAc,KAAK,MAAK,QAAO,IAAI,OAAO,IAAI;AACpD,KAAI,CAAC,eAAe,YAAY,SAAS,EAAG,QAAO;CAGnD,MAAM,YAAY,YAAY,KAAK,SAAS,YAAY,IAAI,GAAG,GAAG;AAClE,QAAO;EACL,gBAAgB,YAAY;EAC5B,cAAc,YAAY;EAC1B,WAAW,aAAa;EACxB,WAAW,YAAY,MAAM;EAC9B;;AAGH,SAAgB,kBAAkB,UAAiC;AACjE,QAAO;EACL;EACA,SAAS;EACT,SAAS;EACT,SAAS,WAAW,UAAU,IAAI;EAClC,SAAS,aAAa;EACvB;;AAGH,SAAgB,qBAAqB,OAA6B;AAEhE,KAAI,CADa,iBAAiB,MAAM,QAAQ,EAAE,CAAC,CACpC,QAAO;CAEtB,MAAM,MAAM,MAAM,MAAM,MAAK,MAAK,EAAE,OAAO,IAAI;AAC/C,QAAO,OAAO,IAAI,SAAS,IAAI,IAAI,MAAM,OAAO;;AAGlD,eAAsB,wBAAwB,OAAgC;AAC5E,KAAI;AAEF,MAAI,CADa,iBAAiB,MAAM,QAAQ,EAAE,CAAC,CACpC,QAAO;EAEtB,MAAM,YAAY,qBAAqB,MAAM;AAC7C,MAAI,CAAC,aAAa,CAAC,MAAM,OAAQ,QAAO;EAKxC,MAAM,cAAc,MAAM,OAAO,MAAM,OAAO;EAC9C,MAAM,iBAAiB,WAAW,UAAU;EAC5C,MAAM,cAAc,WAAW,MAAM,OAAO;AAE5C,SAAOC,iBAAU,OAAO,gBAAgB,aAAa,YAAY;UAC1D,GAAG;AACV,SAAO;;;AAIX,SAAS,OAAO,SAA6B;AAC3C,yCAAmB,IAAI,aAAa,CAAC,OAAO,QAAQ,CAAC;;;;;AAMvD,IAAa,iBAAb,MAA0D;CACxD;CAGA,kBAAkC;CAGlC,kBAA0C;EACxC,SAAS;EACT,YAAY;EACb;CAGD,cAAmC,EAAE;;;;;CAMrC,YAAY,SAA6B;AAEvC,QAAKC,WAAY,IAAI,SAAS,SAAS,aAAa;AAEpD,MAAI,SAAS,eACX,OAAKC,iBAAkB;GAAE,GAAG,MAAKA;GAAiB,GAAG,QAAQ;GAAgB;EAI/E,MAAM,mBAAmB,SAAS,YAAY,oBAAoB;AAClE,MAAI,SAAS,WACX,OAAKC,aAAc;GAAE,GAAG,QAAQ;GAAY;GAAkB;MAE9D,OAAKA,aAAc,EAAE,kBAAkB;AAIzC,MAAI,MAAKD,eAAgB,SAAS;GAChC,MAAM,gBAAgB,MAAKE,wBAAyB;AACpD,OAAI,cACF,OAAKC,iBAAkB;;;;;;;CAS7B,kBAAkB,SAAgD;AAChE,QAAKH,iBAAkB;GAAE,GAAG,MAAKA;GAAiB,GAAG;GAAS;AAE9D,MAAI,QAAQ,YAAY,MACtB,MAAK,oBAAoB;;;;;CAO7B,oBAA4C;AAC1C,SAAO,EAAE,GAAG,MAAKA,gBAAiB;;;;;;CAOpC,kBAAkB,SAAwB;AACxC,QAAKG,iBAAkB;AAEvB,MAAI,MAAKH,eAAgB,QACvB,CAAK,MAAKI,qBAAsB,QAAQ;;;;;CAO5C,oBAAoC;AAElC,MAAI,CAAC,MAAKD,kBAAmB,MAAKH,eAAgB,QAChD,OAAKG,iBAAkB,MAAKD,wBAAyB;AAEvD,SAAO,MAAKC;;;;;;CAOd,aAAsB;AACpB,MAAI,MAAKA,eACP,QAAO;AAGT,MAAI,MAAKH,eAAgB,SAAS;GAChC,MAAM,gBAAgB,MAAKE,wBAAyB;AACpD,OAAI,eAAe;AACjB,UAAKC,iBAAkB;AACvB,WAAO;;;AAIX,SAAO;;;;;;CAOT,OAAMC,qBAAsB,SAAiC;AAC3D,MAAI,CAAC,MAAKJ,eAAgB,QAAS;EAEnC,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS;EAEd,MAAM,MAAM,MAAKA,eAAgB,cAAc;AAC/C,UAAQ,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAC;;;;;CAM/C,0BAA0C;AACxC,MAAI,CAAC,MAAKA,eAAgB,QAAS,QAAO;EAE1C,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,MAAM,MAAKA,eAAgB,cAAc;EAC/C,MAAM,OAAO,QAAQ,QAAQ,IAAI;AAEjC,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACF,UAAO,KAAK,MAAM,KAAK;WAChB,GAAG;AACV,WAAQ,MAAM,kCAAkC,EAAE;AAClD,UAAO;;;;;;CAOX,qBAA2B;EACzB,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS;EAEd,MAAM,MAAM,MAAKA,eAAgB,cAAc;AAC/C,UAAQ,WAAW,IAAI;AAGvB,QAAKG,iBAAkB;;;;;;CAOzB,MAAM,eAAgC;EACpC,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAE3C,SAAO,QAAQ;;;;;;;CAQjB,MAAM,UAAU,OAA8B;EAC5C,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAE3C,SAAO,KAAK,qBAAqB,OAAO,QAAQ;;;;;CAMlD,gBAAgB,SAAyC;AACvD,QAAKJ,SAAU,gBAAgB,QAAQ;;CAGzC,kBAAmC;AACjC,SAAO,MAAKA,SAAU,iBAAiB;;CAGzC,mBAAmB,cAA2D;AAC5E,SAAO,MAAKA,SAAU,OAAO,aAAa;;;;;CAM5C,eAAe,cAAyC;AACtD,QAAKA,SAAU,eAAe,aAAa;;CAG7C,qBAA2B;AACzB,QAAKA,SAAU,oBAAoB;;;;;;CAOrC,MAAM,cAAc,UAAkC,EAAE,EAAuB;AAC7E,SAAO,cAAc;GACnB,IAAI;IACF,IAAI,MAAKE,WAAY;IACrB,MAAM,MAAKA,WAAY;IACxB;GACD,wBAAwB,EACtB,kBAAkB,MAAKA,WAAY,kBACpC;GACD,GAAG;GACJ,CAAC;;;;;CAMJ,MAAM,kBAAoC;AACxC,SAAO,iBAAiB;;;;;;;;CAS1B,MAAM,UAAU,cAA2B,UAAmB,UAAsB,EAAE,EAAoB;EACxG,MAAM,eAAe,MAAM,KAAK,iBAAiB;EAEjD,IAAI;AAEJ,MAAI,cAAc;AAChB,aAAU,MAAM,KAAK,kBAAkB,cAAc,QAAQ;AAG7D,OAAI,QAAQ,iBACV,WAAU,MAAM,KAAK,oBAAoB,QAAQ,kBAAkB,aAAa;SAE7E;AACL,OAAI,CAAC,SACH,OAAM,IAAI,MAAM,iDAAiD;AAEnE,OAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,iDAAiD;AAEnE,aAAU,MAAM,KAAK,gCAAgC,UAAU,QAAQ;;AAGzE,SAAO;;;;;CAMT,MAAM,kBAAkB,cAA2B,UAAsB,EAAE,EAAoB;EAC7F,MAAM,EAAE,QAAQ,IAAI,IAAI,eAAe,MAAM,aAAa,cAAc,MAAKA,WAAY;AAEzF,MAAI,GAAG,OAAO,SAAS,SAAS,EAAE,CAChC,OAAM,IAAI,MAAM,gCAAgC;AAGpC,aAAW,GAAG;EAC5B,MAAM,sDAAyB,GAAG;EAElC,MAAM,OAAO,MAAM,uBAAuB,QAAQ,SAAS;EAE3D,MAAM,UAAmB;GACvB,cAAc,WAAW,gBAAgB,WAAW;GACpD,QAAQ;GACF;GACN,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,UAAU;GACvD;AAED,MAAI,MAAKF,SAAU,WAAW,IAAI,MAAKA,SAAU,iBAAiB,CAAC,gBACjE,OAAKA,SAAU,OAAO,QAAQ,cAAc,GAAG;AAGjD,SAAO;;;;;;;CAQT,MAAM,gCAAgC,UAAkB,UAAsB,EAAE,EAAoB;EAClG,MAAM,OAAO,MAAM,uBAAuB,QAAQ,SAAS;EAC3D,MAAM,SAAS,yBAAyB,UAAU,KAAK;AAWvD,SAPyB;GACvB,cAHmB,YAAY,OAAO,WAAW,cAAc,OAAO,SAAU,WAAmB,QAAQ,gBAAgB,IAAI,WAAW,GAAG,CAAC,CAAC;GAIvI;GACF;GACN,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,UAAU;GACvD;;;;;;;CAUH,MAAM,qBACJ,OACA,SACA,UAAuB,EAAE,EACT;EAChB,MAAM,EAAE,cAAc,MAAM,MAAM,aAAa;EAE/C,MAAM,iBAAiB,MAAKA,SAAU,WAAW;EACjD,MAAM,oBAAoB,CAAC,QAAQ,2BAA2B,QAAQ;EAEtE,IAAI;AAEJ,MAAI,mBAAmB;AACrB,OAAI,eACF,MAAK,MAAKA,SAAU,OAAO,QAAQ,aAAa;AAElD,OAAI,CAAC,MAAM,UAAU;AACnB,SAAK,sBAAsB,UAAU,QAAQ,KAAK;AAClD,QAAI,eACF,OAAKA,SAAU,OAAO,QAAQ,cAAc,GAAG;;AAGnD,OAAI,CAAC,GACH,OAAM,IAAI,MAAM,kEAAkE;aAE3E,QAAQ,yBAAyB;AAC1C,OAAI,eACF,MAAK,MAAKA,SAAU,OAAO,QAAQ,aAAa;AAElD,OAAI,CAAC,MAAM,UAAU;AACnB,SAAK,MAAM,kCAAkC,QAAQ,yBAA0B,SAAS;AACxF,QAAI,eACF,OAAKA,SAAU,OAAO,QAAQ,cAAc,GAAG;;AAGnD,OAAI,CAAC,GACH,OAAM,IAAI,MAAM,8FAA8F;SAE3G;AACL,OAAI,eACF,MAAK,MAAKA,SAAU,OAAO,QAAQ,aAAa;AAGlD,OAAI,CAAC,IAAI;IACP,MAAM,EAAE,QAAQ,cAAc,MAAM,aAClC,WAAW,QAAQ,aAAa,EAChC,MAAKE,WACN;AACD,SAAK;AAEL,QAAI,eACF,OAAKF,SAAU,OAAO,QAAQ,cAAc,GAAG;;;EAYrD,MAAM,yDAPc;GAClB,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,YAAY,MAAM,cAAc,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GAC7D,MAAM,OAAO,CAAC,GAAI,MAAM,QAAQ,EAAE,EAAG,GAAG,KAAK,GAAG,MAAM,QAAQ,EAAE;GACjE,EAE8C,GAAG;AAElD,MAAI,CAAC,kBAAkB,YACrB,OAAKM,SAAU,GAAG;AAGpB,SAAO;;;;;;;;CAST,MAAM,eAAe,SAAkB,cAA2B,UAAsB,EAAE,EAAmB;AAC3G,MAAI,QAAQ,yBAAyB;AACnC,OAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,mDAAmD;AAGrE,UAAO,WADI,MAAM,kCAAkC,QAAQ,yBAAyB,QAAQ,SAAS,CAChF;;AAIvB,MAD0B,CAAC,QAAQ,2BAA2B,QAAQ,MAC/C;AACrB,OAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,iDAAiD;AAGnE,UAAO,WADI,sBAAsB,QAAQ,UAAU,QAAQ,KAAK,CAC3C;;EAGvB,IAAI,mBAAmB;AAEvB,MAAI,CAAC,oBAAoB,QAAQ,aAC/B,oBAAmB,WAAW,QAAQ,aAAa;EAGrD,MAAM,EAAE,QAAQ,OAAO,MAAM,aAAa,kBAAkB,MAAKJ,WAAY;AAG7E,SAFc,WAAW,GAAG;;;;;CAQ9B,MAAM,iBAAmC;AACvC,SAAO,gBAAgB;;;;;;;CAQzB,MAAM,oBAAoB,UAAkB,qBAAoD;EAC9F,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAG3C,MAAI,QAAQ,wBACV,OAAM,IAAI,MAAM,4DAA4D;AAG9E,MAAI,QAAQ,SACV,OAAM,IAAI,MAAM,8BAA8B;AAIhD,MAAI,EADqB,wBAAwB,QAAQ,eAAe,WAAW,QAAQ,aAAa,GAAG,SAEzG,OAAM,IAAI,MAAM,yBAAyB;EAM3C,MAAM,eAAe,YAHH,OAAO,WAAW,cAAc,OAAO,SAAU,WAAmB,QAG5C,gBAAgB,IAAI,WAAW,GAAG,CAAC,CAAC;EAG9E,MAAM,iBAAiB,yBAAyB,UAAU,aAAa;EAGvE,MAAM,aAAa,sBAAsB,UAAU,aAAa;EAChE,MAAM,YAAY,MAAKK,YAAa,YAAY,QAAQ,OAAO;AAC/D,QAAKD,SAAU,WAAW;EAE1B,MAAM,iBAA0B;GAC9B,GAAG;GACH,UAAU;IACR;IACA;IACA,WAAW,KAAK,KAAK;IACrB;IACD;GACF;AAED,OAAK,kBAAkB,eAAe;AACtC,SAAO;;CAGT,aAAa,IAAgB,SAAyB;AAOpD,oDAN4B;GAC1B,MAAM;GACN,SAAS;GACT,MAAM,EAAE;GACR,YAAY,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GAC1C,EAAE,GAAG,CACO;;;;;;;;CASf,MAAM,qBAAqB,UAAkB,iBAA+C;EAC1F,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAG3C,MAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,6BAA6B;AAG/C,MAAI,CAAC,gBACH,OAAM,IAAI,MAAM,6CAA6C;EAG/D,MAAM,EAAE,gBAAgB,iBAAiB,QAAQ;AAIjD,MAD8B,yBAAyB,UAAU,aAAa,KAChD,eAC5B,OAAM,IAAI,MAAM,4BAA4B;EAI9C,MAAM,EAAE,QAAQ,UAAU,MAAM,aAAa,iBAAiB,MAAKJ,WAAY;EAC/E,MAAM,sDAAyB,MAAM;AACrC,QAAKI,SAAU,MAAM;EAIrB,MAAM,kBAAkB,YADN,OAAO,WAAW,cAAc,OAAO,SAAU,WAAmB,QACzC,gBAAgB,IAAI,WAAW,GAAG,CAAC,CAAC;EACjF,MAAM,oBAAoB,yBAAyB,UAAU,gBAAgB;EAG7E,MAAM,aAAa,sBAAsB,UAAU,aAAa;EAChE,MAAM,YAAY,MAAKC,YAAa,YAAY,UAAU;AAC1D,QAAKD,SAAU,WAAW;EAE1B,MAAM,iBAA0B;GAC9B,cAAc,WAAW,gBAAgB;GACzC,QAAQ;GACR,MAAM,QAAQ;GACd,UAAU;IACR,gBAAgB;IAChB,cAAc;IACd,WAAW,KAAK,KAAK;IACrB;IACD;GACF;AAED,OAAK,kBAAkB,eAAe;AACtC,SAAO;;;;;CAMT,sBAAuH;EACrH,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,WAAW,CAAC,QAAQ,SAAU,QAAO;AAE1C,SAAO;GACL,gBAAgB,QAAQ,SAAS;GACjC,cAAc,QAAQ,SAAS;GAC/B,WAAW,QAAQ,SAAS;GAC5B,WAAW,QAAQ,SAAS;GAC7B;;;;;CAMH,UAAU,KAAuB;AAC/B,OAAK,OAAO,EAAE;;;;;;;;;;AC3pBlB,MAAM,aAAa,IAAI,aAAa,CAAC,OAAO,YAAY;AACxD,MAAM,aAAa;AAEnB,SAAS,YAA0B;CACjC,MAAM,SAAS,WAAW,QAAQ;AAClC,KAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,+BAA+B;AAC5D,QAAO;;;;;;;;AAST,eAAsB,gBAAgB,QAAoB,MAAsC;CAC9F,MAAM,SAAS,WAAW;CAC1B,MAAM,cAAc,MAAM,OAAO,UAAU,OAAO,QAAQ,QAAQ,OAAO,CAAC,YAAY,CAAC;AAEvF,QAAO,OAAO,UACZ;EAAE,MAAM;EAAQ,MAAM;EAAW;EAAM,MAAM;EAAY,EACzD,aACA;EAAE,MAAM;EAAW,QAAQ;EAAY,EACvC,OACA,CAAC,WAAW,UAAU,CACvB;;;;;;;;;AAUH,eAAsB,cAAc,KAAgB,IAAgB,WAAuB;CAEzF,MAAM,MAAM,MADG,WAAW,CACD,QAAQ;EAAE,MAAM;EAAW;EAAI,EAAE,KAAK,UAAU;CAEzE,MAAM,QAAQ,IAAI,WAAW,IAAI;AACjC,QAAO;EACL,YAAY,MAAM,MAAM,GAAG,IAAI;EAC/B,KAAK,MAAM,MAAM,IAAI;EACtB;;;;;;;;;;AAWH,eAAsB,cACpB,KACA,IACA,IACA,KACqB;CAErB,MAAM,MAAM,MADG,WAAW,CACD,QACvB;EAAE,MAAM;EAAW;EAAI,EACvB,KACA,IAAI,WAAW,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAChC;AACD,QAAO,IAAI,WAAW,IAAI;;;;;;;;;;;;;;AC7D5B,eAAsB,qBAAqB,QAA8C;CAEvF,MAAM,iBAAiB,IAAI,WAAW,GAAG;AAEzC,MAAK,IAAI,IAAI,GAAG,IAAI,eAAe,QAAQ,IACzC,gBAAe,MAAM,IAAI,KAAK;CAGhC,MAAM,UAAU,IAAI,WAAW,GAAG;AAClC,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,SAAQ,MAAM,IAAI,KAAK;AAmBzB,QAhBmB;EACjB,IAAI;EACJ,OAAO;EACP,MAAM;EACN,UAAU;GACR,gBAAgB,IAAI,WAAW,EAAE;GACjC,mBAAmB,IAAI,WAAW,EAAE;GACpC,WAAW;GACX,mBAAmB,IAAI,WAAW,EAAE;GACpC,4BAA4B,IAAI,WAAW,EAAE;GAC7C,oBAAoB,IAAI,WAAW,EAAE;GACrC,6BAA6B;GAC7B,qBAAqB,CAAC,WAAW;GAClC;EACF;;;;;;;;;AC9BH,IAAa,cAAb,MAAyB;CAIvB,YAAY,SAA4B,EAAE,EAAE;iBAHH;AAIvC,OAAK,SAAS;GACZ,MAAM,OAAO,SAAS,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS,QAAQ,UAAU,GAAG,GAAG;GACvG,QAAQ,OAAO,UAAU,KAAK,kBAAkB;GAChD,YAAY,OAAO,cAAc;GACjC,gBAAgB,OAAO,kBAAkB,OAAU;GACnD,iBAAiB,OAAO,oBAAoB,SAAY,OAAO,kBAAkB;GAClF;;CAGH,AAAQ,mBAA2B;AACjC,MAAI,OAAO,WAAW,YAAa,QAAO;EAC1C,MAAM,WAAW,OAAO,SAAS;AACjC,MAAI,SAAS,SAAS,cAAc,CAAE,QAAO;AAC7C,SAAO,SAAS,QAAQ,UAAU,GAAG;;;;;CAMvC,AAAQ,aAA6B;AACnC,MAAI,CAAC,KAAK,QACR,MAAK,UAAU,IAAI,eAAe;GAChC,cAAc;IACZ,SAAS;IACT,WAAW,KAAK,OAAO;IACvB,iBAAiB,KAAK,OAAO;IAC9B;GACD,gBAAgB;IACd,SAAS;IACT,YAAY,KAAK,OAAO;IACzB;GACF,CAAC;AAEJ,SAAO,KAAK;;;;;;CAOd,MAAM,cAAc,UAAwC;EAC1D,MAAM,UAAU,KAAK,YAAY;EAEjC,MAAM,OAAO,KAAK,OAAO,SAAS,cAAc,cAAc,KAAK,OAAO;EAC1E,MAAM,SAAS,KAAK,OAAO;EAE3B,MAAM,kBAAkB,UAAU,MAAM;EACxC,MAAM,iBAAiB,kBACnB,kBACA,QAAQ,KAAK,KAAK,CAAC;EAEvB,MAAM,UAAkC;GACtC,IAAI;IACF,IAAI;IACJ,MAAM;IACP;GACD,MAAM;IACJ,MAAM;IACN,aAAa,mBAAmB;IACjC;GACD,wBAAwB;IACtB,yBAAyB;IACzB,aAAa;IACb,kBAAkB;IACnB;GACD,YAAY,EACV,KAAK,EAAE,EACR;GACF;AAED,SAAO,MAAM,QAAQ,cAAc,QAAQ;;;;;;;;;;CAW7C,MAAM,UAAU,cAA2B,UAAmB,SAAwC;AAEpG,SAAO,MADS,KAAK,YAAY,CACZ,UAAU,cAAc,UAAU,QAAQ;;;;;CAMjE,MAAM,kBAAoC;AAExC,SAAO,MADS,KAAK,YAAY,CACZ,iBAAiB;;;;;CAMxC,MAAM,eAAgC;AAEpC,SAAO,MADS,KAAK,YAAY,CACZ,cAAc;;;;;CAMrC,MAAM,UAAU,OAAc,SAAuC;AAEnE,SAAO,MADS,KAAK,YAAY,CACZ,UAAU,OAAO,QAAQ;;;;;CAMhD,oBAAoC;AAElC,SADgB,KAAK,YAAY,CAClB,mBAAmB;;;;;CAMpC,kBAAkB,SAAwB;AAExC,EADgB,KAAK,YAAY,CACzB,kBAAkB,QAAQ;;;;;CAMpC,aAAsB;AAEpB,SADgB,KAAK,YAAY,CAClB,YAAY;;;;;CAM7B,qBAA2B;AAEzB,EADgB,KAAK,YAAY,CACzB,oBAAoB;;;;;CAM9B,MAAM,iBAAmC;AACvC,SAAO,KAAK,iBAAiB;;;;;;CAO/B,MAAM,oBAAoB,UAAoC;AAE5D,SAAO,MADS,KAAK,YAAY,CACZ,oBAAoB,SAAS;;;;;;;;CASpD,MAAM,qBAAqB,UAAkB,iBAA+C;AAE1F,SAAO,MADS,KAAK,YAAY,CACZ,qBAAqB,UAAU,gBAAgB;;;;;CAMtE,sBAAmG;AAEjG,SADgB,KAAK,YAAY,CAClB,qBAAqB;;;;;;AC1LxC,MAAa,kBAAkB;AAC/B,MAAM,eAAe;AAErB,MAAa,kBAAkB,SAA0B;CACvD,MAAM,UAAU,KAAK,MAAM;AAC3B,QACE,QAAQ,SAAS,KACjB,QAAQ,UAAU,mBAClB,aAAa,KAAK,QAAQ;;AAI9B,MAAa,iBAAiB,WAC5B,OAAO,WAAW,MAAM,iBAAiB,KAAK,OAAO;AAWvD,MAAa,mBAAmB,QAAyB;AACvD,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,SAAO,CAAC,OAAO,OAAO,CAAC,SAAS,OAAO,SAAS,IAAI,OAAO,SAAS,SAAS;SACvE;AACN,SAAO;;;;;;;;;ACpBX,IAAa,eAAb,MAA0B;CASxB,YAAY,SAA6B,EAAE,EAAE;oBARL;uBAEhB,CAAC,uBAAuB;+BACP;mCACI;8BACL;sCACR,IAAI,KAAqB;AAGvD,OAAK,YAAY,KAAK,kBAAkB,OAAO,aAAa,KAAK,cAAc;;;;;CAMjF,WAAW,YAA8B;AACvC,OAAK,aAAa;AAElB,MAAI,cAAc,eAAe,cAAc,OAAO,WAAW,cAAc,WAC7E,CAAC,WAAmB,UAAU,KAAK,UAAU;;;;;CAOjD,UAAU,MAAsB;AAC9B,OAAK,YAAY,KAAK,kBAAkB,KAAK;AAC7C,MAAI,KAAK,cAAc,eAAe,KAAK,cAAc,OAAO,KAAK,WAAW,cAAc,WAC5F,CAAC,KAAK,WAAmB,UAAU,KAAK,UAAU;;;;;CAOtD,YAAsB;AACpB,SAAO,CAAC,GAAG,KAAK,UAAU;;;;;CAM5B,MAAM,aAAa,OAAc,YAAY,KAAwB;AACnE,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,WAAW,KAAK,qBAAqB;AACjE,SAAO,IAAI,SAAS,SAAS,WAAW;AACtC,OAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,2BAAO,IAAI,MAAM,uBAAuB,CAAC;AACzC;;GAKF,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,YAAY,YAAY;AAC3D,2BAAO,IAAI,MAAM,6CAA6C,CAAC;AAC/D;;GAEF,MAAM,eAAe,WAAW,QAAQ,MAAM,CAAC,UAAU;IACvD,OAAO,aAAkB;AACvB,SAAI,UAAU,SAAS,MAAM;AAC3B,mBAAa,aAAa;AAC1B,cAAQ,KAAK;;;IAGjB,QAAQ,UAAiB;AACvB,kBAAa,aAAa;AAC1B,YAAO,MAAM;;IAEhB,CAAC;AAGF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,MAAM;MACb,UAAU;IACb;;;;;CAMJ,MAAM,aAAa,QAAiD;AAClE,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,iBAAiB,KAAK,0BAA0B;AAC5E,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS,CAAC,OAAO;IACjB,OAAO;IACR;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,YAAQ,KAAK;AACb;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,GAAG;MAC5C,MAAM,WAAW,KAAK,qBAAqB,OAAO,MAAM,QAAQ;AAChE,UAAI,UAAU;AACZ,oBAAa,aAAa;AAC1B,eAAQ,SAAS;AACjB;;AAEF,cAAQ,MAAM,mCAAmC;;;IAGrD,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEf,QAAQ,UAAiB;AACvB,aAAQ,MAAM,2BAA2B,MAAM;AAC/C,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEhB,CAAC;AAGF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,KAAK;MACZ,IAAK;IACR;;;;;CAMJ,MAAM,oBAAoB,QAAwC;AAChE,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,kBAAkB,KAAK,0BAA0B;AAC7E,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS,CAAC,OAAO;IACjB,OAAO;IACR;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,YAAQ,KAAK;AACb;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,GAAG;MAC5C,MAAM,OAAO,OAAO,MAAM,QAAQ,EAAE;AACpC,WAAK,MAAM,OAAO,KAChB,KAAI,IAAI,OAAO,UAAU,IAAI,IAAI;OAC/B,MAAM,YAAY,IAAI,GAAG,MAAM;AAC/B,WAAI,eAAe,UAAU,EAAE;AAC7B,qBAAa,aAAa;AAC1B,gBAAQ,UAAU;AAClB;;;AAIN,mBAAa,aAAa;AAC1B,cAAQ,KAAK;;;IAGjB,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEf,QAAQ,UAAiB;AACvB,aAAQ,MAAM,oCAAoC,MAAM;AACxD,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEhB,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,KAAK;MACZ,IAAK;IACR;;;;;CAMJ,MAAM,gBAAgB,QAAwC;AAC5D,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,qBAAqB,KAAK,0BAA0B;AAChF,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS,CAAC,OAAO;IACjB,OAAO;IACR;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,YAAQ,EAAE,CAAC;AACX;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,GAAG;MAC5C,MAAM,aAA4B,EAAE;MACpC,MAAM,OAAO,OAAO,MAAM,QAAQ,EAAE;AAEpC,WAAK,MAAM,OAAO,KAChB,KAAI,IAAI,OAAO,OAAO,IAAI,GACxB,YAAW,KAAK;OACd,QAAQ,IAAI;OACZ,OAAO,IAAI,MAAM;OACjB,SAAS,IAAI,MAAM;OACpB,CAAC;AAIN,mBAAa,aAAa;AAC1B,cAAQ,WAAW;;;IAGvB,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,EAAE,CAAC;;IAEb,QAAQ,UAAiB;AACvB,aAAQ,MAAM,+BAA+B,MAAM;AACnD,kBAAa,aAAa;AAC1B,aAAQ,EAAE,CAAC;;IAEd,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,EAAE,CAAC;MACV,IAAM;IACT;;;;;CAMJ,MAAM,sBAAsB,SAA0D;AACpF,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,MAAI,QAAQ,WAAW,EACrB,wBAAO,IAAI,KAAK;AAGlB,QAAM,KAAK,iBAAiB,2BAA2B,KAAK,0BAA0B;AACtF,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,2BAAW,IAAI,KAA8B;GACnD,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS;IACV;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,4BAAQ,IAAI,KAAK,CAAC;AAClB;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,KAAK,OAAO,MAAM,QAAQ;MACnE,MAAM,WAAW,KAAK,qBAAqB,OAAO,MAAM,QAAQ;AAChE,UAAI,SACF,UAAS,IAAI,OAAO,MAAM,QAAQ,SAAS;UAE3C,SAAQ,MAAM,mCAAmC;;;IAIvD,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,SAAS;;IAEnB,QAAQ,UAAiB;AACvB,aAAQ,MAAM,4BAA4B,MAAM;AAChD,kBAAa,aAAa;AAC1B,aAAQ,SAAS;;IAEpB,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,SAAS;MAChB,IAAK;IACR;;;;;;CAOJ,MAAM,cAAc,UAAoB,EAAE,EAAE,QAAQ,KAA4C;AAC9F,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,kBAAkB,KAAK,0BAA0B;AAC7E,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,2BAAW,IAAI,KAA+D;GACpF,MAAM,SAAc;IAClB,OAAO,CAAC,EAAE;IACV;IACD;AAED,OAAI,QAAQ,SAAS,EACnB,QAAO,UAAU;GAGnB,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,4BAAQ,IAAI,KAAK,CAAC;AAClB;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,KAAK,OAAO,MAAM,QAAQ;MACnE,MAAM,WAAW,KAAK,qBAAqB,OAAO,MAAM,QAAQ;AAChE,UAAI,UAAU;OACZ,MAAM,YAAY,OAAO,MAAM,cAAc;OAC7C,MAAM,WAAW,SAAS,IAAI,OAAO,MAAM,OAAO;AAClD,WAAI,CAAC,YAAY,YAAY,SAAS,UACpC,UAAS,IAAI,OAAO,MAAM,QAAQ;QAAE;QAAU;QAAW,CAAC;YAG5D,SAAQ,MAAM,mCAAmC;;;IAIvD,gBAAgB;AACd,kBAAa,aAAa;KAC1B,MAAM,yBAAS,IAAI,KAA8B;AACjD,cAAS,SAAS,OAAO,WAAW;AAClC,aAAO,IAAI,QAAQ,MAAM,SAAS;OAClC;AACF,aAAQ,OAAO;;IAEjB,QAAQ,UAAiB;AACvB,aAAQ,MAAM,4BAA4B,MAAM;AAChD,kBAAa,aAAa;KAC1B,MAAM,yBAAS,IAAI,KAA8B;AACjD,cAAS,SAAS,OAAO,WAAW;AAClC,aAAO,IAAI,QAAQ,MAAM,SAAS;OAClC;AACF,aAAQ,OAAO;;IAElB,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;IAC1B,MAAM,yBAAS,IAAI,KAA8B;AACjD,aAAS,SAAS,OAAO,WAAW;AAClC,YAAO,IAAI,QAAQ,MAAM,SAAS;MAClC;AACF,YAAQ,OAAO;MACd,IAAM;IACT;;;;;CAMJ,MAAM,kBACJ,QACA,YACA,WACkB;EAClB,MAAM,OAAmB,WAAW,KAAK,UAAU;AACjD,OAAI,CAAC,cAAc,MAAM,OAAO,CAC9B,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAI,MAAM,SAAS,CAAC,gBAAgB,MAAM,MAAM,CAC9C,OAAM,IAAI,MAAM,kDAAkD;GAEpE,MAAM,MAAgB,CAAC,KAAK,MAAM,OAAO;AACzC,OAAI,MAAM,MACR,KAAI,KAAK,MAAM,MAAM;AAEvB,OAAI,MAAM,QACR,KAAI,KAAK,MAAM,QAAQ;AAEzB,UAAO;IACP;EASF,MAAM,cAAc,MAAM,UAPL;GACnB,MAAM;GACN,SAAS;GACT,YAAY,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GACzC;GACD,CAEyC;AAC1C,SAAO,MAAM,KAAK,aAAa,YAAY;;CAG7C,AAAQ,kBAAkB,MAA0B;AAClD,MAAI,KAAK,WAAW,EAClB,QAAO,EAAE;EAEX,MAAM,YAAY,KAAK,QAAQ,QAAQ,gBAAgB,IAAI,CAAC;AAC5D,MAAI,UAAU,WAAW,KAAK,OAC5B,OAAM,IAAI,MAAM,2BAA2B;AAE7C,SAAO;;CAGT,AAAQ,qBAAqB,SAAyC;AACpE,MAAI,QAAQ,SAAS,KAAK,sBACxB,QAAO;AAET,MAAI;GACF,MAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,OAAI,CAAC,UAAU,OAAO,WAAW,SAC/B,QAAO;GAET,MAAM,WAA4B,EAAE;AACpC,OAAI,OAAQ,OAA2B,SAAS,SAC9C,UAAS,OAAQ,OAA2B;AAE9C,OAAI,OAAQ,OAA2B,iBAAiB,SACtD,UAAS,eAAgB,OAA2B;AAEtD,OAAI,OAAQ,OAA2B,UAAU,SAC/C,UAAS,QAAS,OAA2B;AAE/C,OAAI,OAAQ,OAA2B,YAAY,SACjD,UAAS,UAAW,OAA2B;AAEjD,OAAI,OAAQ,OAA2B,YAAY,SACjD,UAAS,UAAW,OAA2B;AAEjD,UAAO;WACA,OAAO;AACd,WAAQ,MAAM,qCAAqC,MAAM;AACzD,UAAO;;;CAIX,MAAc,iBAAiB,QAAgB,eAAsC;EACnF,MAAM,SAAS,KAAK,aAAa,IAAI,OAAO,IAAI;EAEhD,MAAM,SAAS,iBADH,KAAK,KAAK,GACgB;AACtC,MAAI,SAAS,EACX,OAAM,IAAI,SAAS,YAAY,WAAW,SAAS,OAAO,CAAC;AAE7D,OAAK,aAAa,IAAI,QAAQ,KAAK,KAAK,CAAC"}
|
package/dist/index.d.cts
CHANGED
|
@@ -190,7 +190,7 @@ interface NosskeyManagerLike {
|
|
|
190
190
|
}
|
|
191
191
|
//#endregion
|
|
192
192
|
//#region src/utils/nosskey.d.ts
|
|
193
|
-
declare function deriveSaltFromUsername(username?: string):
|
|
193
|
+
declare function deriveSaltFromUsername(username?: string): string;
|
|
194
194
|
declare function parseRecoveryTag(tags: string[][]): KeyRecovery | null;
|
|
195
195
|
declare function createRecoveryTag(recovery: KeyRecovery): string[];
|
|
196
196
|
declare function getRecoverySignature(kind0: Event$1): string | null;
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/utils/types.ts","../src/utils/nosskey.ts","../src/utils/utils.ts","../src/utils/crypto-utils.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/test-utils.ts","../src/types/auth.ts","../src/services/auth.service.ts","../src/types/nostr.ts","../src/services/relay.service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAQA;AAaA;AAUiB,UAvBA,OAAA,CAuBO;EASP,EAAA,CAAA,EAAA,MAAA;EAOA,MAAA,CAAA,EAAA,MAAA;EASU,UAAA,CAAA,EAAA,MAAA;EACN,IAAA,EAAA,MAAA;EACN,IAAA,CAAA,EAAA,MAAA,EAAA,EAAA;EAAM,OAAA,EAAA,MAAA;EAMJ,GAAA,CAAA,EAAA,MAAA;AASjB;AAOA;AASA;AAYA;AASiB,UAzFA,yBAAA,CAyFiB;EACT,mBAAA,EAAA,MAAA;EAAR,uBAAA,EAAA,MAAA;EACU,UAAA,EAAA,MAAA;EAAR,QAAA,EAAA,MAAA;;;AAOnB;;AAWmB,UAnGF,OAAA,CAmGE;EAAgB,YAAA,EAAA,MAAA;EAAR,MAAA,EAAA,MAAA;EAME,IAAA,EAAA,MAAA;EAKN,QAAA,CAAA,EAAA,MAAA;EAYc,uBAAA,CAAA,EArHT,yBAqHS;EAAR,QAAA,CAAA,EApHhB,WAoHgB;;AAeR,UAhIJ,WAAA,CAgII;EAMK,cAAA,EAAA,MAAA;EAAiC,YAAA,EAAA,MAAA;EAAR,SAAA,CAAA,EAAA,MAAA;EAQxB,SAAA,CAAA,EAAA,MAAA;;AAA8D,UAvIxE,sBAAA,CAuIwE;EAAR,EAAA,CAAA,EAAA;IAQtE,IAAA,CAAA,EAAA,MAAA;IACE,EAAA,CAAA,EAAA,MAAA;EACC,CAAA;EACD,IAAA,CAAA,EAAA;IAAR,IAAA,CAAA,EAAA,MAAA;IAK8B,WAAA,CAAA,EAAA,MAAA;EAAR,CAAA;EAEN,sBAAA,CAAA,EAhJM,8BAgJN;EAKU,gBAAA,CAAA,EApJV,6BAoJU,EAAA;EAWlB,UAAA,CAAA,EA9JE,MA8JF,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;UAxJI,UAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/utils/types.ts","../src/utils/nosskey.ts","../src/utils/utils.ts","../src/utils/crypto-utils.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/test-utils.ts","../src/types/auth.ts","../src/services/auth.service.ts","../src/types/nostr.ts","../src/services/relay.service.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -190,7 +190,7 @@ interface NosskeyManagerLike {
|
|
|
190
190
|
}
|
|
191
191
|
//#endregion
|
|
192
192
|
//#region src/utils/nosskey.d.ts
|
|
193
|
-
declare function deriveSaltFromUsername(username?: string):
|
|
193
|
+
declare function deriveSaltFromUsername(username?: string): string;
|
|
194
194
|
declare function parseRecoveryTag(tags: string[][]): KeyRecovery | null;
|
|
195
195
|
declare function createRecoveryTag(recovery: KeyRecovery): string[];
|
|
196
196
|
declare function getRecoverySignature(kind0: Event$1): string | null;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/utils/types.ts","../src/utils/nosskey.ts","../src/utils/utils.ts","../src/utils/crypto-utils.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/test-utils.ts","../src/types/auth.ts","../src/services/auth.service.ts","../src/types/nostr.ts","../src/services/relay.service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAQA;AAaA;AAUiB,UAvBA,OAAA,CAuBO;EASP,EAAA,CAAA,EAAA,MAAA;EAOA,MAAA,CAAA,EAAA,MAAA;EASU,UAAA,CAAA,EAAA,MAAA;EACN,IAAA,EAAA,MAAA;EACN,IAAA,CAAA,EAAA,MAAA,EAAA,EAAA;EAAM,OAAA,EAAA,MAAA;EAMJ,GAAA,CAAA,EAAA,MAAA;AASjB;AAOA;AASA;AAYA;AASiB,UAzFA,yBAAA,CAyFiB;EACT,mBAAA,EAAA,MAAA;EAAR,uBAAA,EAAA,MAAA;EACU,UAAA,EAAA,MAAA;EAAR,QAAA,EAAA,MAAA;;;AAOnB;;AAWmB,UAnGF,OAAA,CAmGE;EAAgB,YAAA,EAAA,MAAA;EAAR,MAAA,EAAA,MAAA;EAME,IAAA,EAAA,MAAA;EAKN,QAAA,CAAA,EAAA,MAAA;EAYc,uBAAA,CAAA,EArHT,yBAqHS;EAAR,QAAA,CAAA,EApHhB,WAoHgB;;AAeR,UAhIJ,WAAA,CAgII;EAMK,cAAA,EAAA,MAAA;EAAiC,YAAA,EAAA,MAAA;EAAR,SAAA,CAAA,EAAA,MAAA;EAQxB,SAAA,CAAA,EAAA,MAAA;;AAA8D,UAvIxE,sBAAA,CAuIwE;EAAR,EAAA,CAAA,EAAA;IAQtE,IAAA,CAAA,EAAA,MAAA;IACE,EAAA,CAAA,EAAA,MAAA;EACC,CAAA;EACD,IAAA,CAAA,EAAA;IAAR,IAAA,CAAA,EAAA,MAAA;IAK8B,WAAA,CAAA,EAAA,MAAA;EAAR,CAAA;EAEN,sBAAA,CAAA,EAhJM,8BAgJN;EAKU,gBAAA,CAAA,EApJV,6BAoJU,EAAA;EAWlB,UAAA,CAAA,EA9JE,MA8JF,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;UAxJI,UAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/utils/types.ts","../src/utils/nosskey.ts","../src/utils/utils.ts","../src/utils/crypto-utils.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/test-utils.ts","../src/types/auth.ts","../src/services/auth.service.ts","../src/types/nostr.ts","../src/services/relay.service.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -337,12 +337,9 @@ function getPublicKeyFromPassword(password, salt = DEFAULT_SALT) {
|
|
|
337
337
|
* Nosskey class for Passkey-Derived Nostr Identity
|
|
338
338
|
* @packageDocumentation
|
|
339
339
|
*/
|
|
340
|
-
|
|
340
|
+
function deriveSaltFromUsername(username) {
|
|
341
341
|
if (!username) return "";
|
|
342
|
-
const
|
|
343
|
-
const subtle = globalThis.crypto?.subtle;
|
|
344
|
-
if (!subtle) throw new Error("Web Crypto API not available");
|
|
345
|
-
const hashBuffer = await subtle.digest("SHA-256", msgBuffer);
|
|
342
|
+
const hashBuffer = sha256(new TextEncoder().encode(username.toLowerCase().trim()));
|
|
346
343
|
return bytesToHex(new Uint8Array(hashBuffer));
|
|
347
344
|
}
|
|
348
345
|
function parseRecoveryTag(tags) {
|
|
@@ -383,12 +380,8 @@ async function verifyRecoverySignature(kind0) {
|
|
|
383
380
|
return false;
|
|
384
381
|
}
|
|
385
382
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const subtle = globalThis.crypto?.subtle;
|
|
389
|
-
if (!subtle) throw new Error("Web Crypto API not available");
|
|
390
|
-
const hashBuffer = await subtle.digest("SHA-256", msgBuffer);
|
|
391
|
-
return new Uint8Array(hashBuffer);
|
|
383
|
+
function sha256$1(message) {
|
|
384
|
+
return sha256(new TextEncoder().encode(message));
|
|
392
385
|
}
|
|
393
386
|
/**
|
|
394
387
|
* Nosskey - Passkey-Derived Nostr Keys
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["#cacheOptions","#cachedEntry","#clearCachedEntry","#scheduleExpiry","#getCachedKeyIfValid","#clearKey","#expiryTimer","bin","bytes","sha256","#keyCache","#storageOptions","#prfOptions","#loadKeyInfoFromStorage","#currentKeyInfo","#saveKeyInfoToStorage","#clearKey","#signWithKey"],"sources":["../src/utils/utils.ts","../src/utils/key-cache.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/nosskey.ts","../src/utils/crypto-utils.ts","../src/utils/test-utils.ts","../src/services/auth.service.ts","../src/utils/validation.ts","../src/services/relay.service.ts"],"sourcesContent":["/**\n * @packageDocumentation\n */\n\n/**\n * @param bytes\n * @returns\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n const key = '0123456789abcdef';\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n const firstNibble = bytes[i] >> 4;\n const secondNibble = bytes[i] & 15;\n hex += key[firstNibble] + key[secondNibble];\n }\n return hex;\n}\n\n/**\n * @param hex\n * @returns\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const key = '0123456789abcdef';\n const bytes = [];\n let currentByte = 0;\n let highNibble = true;\n\n for (let i = 0; i < hex.length; i++) {\n const charValue = key.indexOf(hex[i].toLowerCase());\n if (charValue === -1) continue;\n\n if (highNibble) {\n currentByte = charValue << 4;\n highNibble = false;\n } else {\n currentByte += charValue;\n bytes.push(currentByte);\n highNibble = true;\n }\n }\n\n return new Uint8Array(bytes);\n}\n","/**\n * Key cache management for Nosskey\n * @packageDocumentation\n */\n\nimport type { KeyCacheOptions } from './types.js';\nimport { bytesToHex } from './utils.js';\n\n/**\n * Key cache entry with expiration time\n */\ninterface CacheEntry {\n id: string;\n sk: Uint8Array;\n expireAt: number;\n}\n\n/**\n * Key cache manager for managing temporary secret keys\n */\nexport class KeyCache {\n #cachedEntry: CacheEntry | null = null;\n\n #expiryTimer: NodeJS.Timeout | null = null;\n\n #cacheOptions: KeyCacheOptions = {\n enabled: false,\n timeoutMs: 5 * 60 * 1000,\n };\n\n /**\n * KeyCache\n * @param options\n */\n constructor(options?: Partial<KeyCacheOptions>) {\n if (options) {\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n if (Object.keys(options).length > 0 && this.#cachedEntry !== null) {\n this.clearAllCachedKeys();\n }\n\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n\n getCacheOptions(): KeyCacheOptions {\n return { ...this.#cacheOptions };\n }\n\n isEnabled(): boolean {\n return this.#cacheOptions.enabled;\n }\n\n /**\n * @param credentialId\n * @param sk\n */\n setKey(credentialId: Uint8Array | string, sk: Uint8Array): void {\n if (!this.#cacheOptions.enabled) return;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n const timeout =\n this.#cacheOptions.timeoutMs !== undefined ? this.#cacheOptions.timeoutMs : 5 * 60 * 1000;\n const expireAt = Date.now() + timeout;\n\n this.#clearCachedEntry();\n\n this.#cachedEntry = {\n id,\n sk: new Uint8Array(sk),\n expireAt,\n };\n\n try {\n this.#scheduleExpiry();\n } catch (error) {\n this.#clearCachedEntry();\n throw error;\n }\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n getKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n if (!this.#cacheOptions.enabled) return undefined;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n return this.#getCachedKeyIfValid(id);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n\n if (this.#cachedEntry && this.#cachedEntry.id === id) {\n this.#clearCachedEntry();\n }\n }\n\n clearAllCachedKeys(): void {\n this.#clearCachedEntry();\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n #getCachedKeyIfValid(credentialId: string): Uint8Array | undefined {\n if (!this.#cachedEntry || this.#cachedEntry.id !== credentialId) {\n return undefined;\n }\n\n if (Date.now() < this.#cachedEntry.expireAt) {\n return this.#cachedEntry.sk;\n }\n\n this.#clearCachedEntry();\n return undefined;\n }\n\n #clearCachedEntry(): void {\n if (this.#cachedEntry) {\n this.#clearKey(this.#cachedEntry.sk);\n this.#cachedEntry = null;\n }\n\n if (this.#expiryTimer) {\n clearTimeout(this.#expiryTimer);\n this.#expiryTimer = null;\n }\n }\n\n #scheduleExpiry(): void {\n if (!this.#cachedEntry) return;\n\n const now = Date.now();\n const timeToExpiry = this.#cachedEntry.expireAt - now;\n\n if (timeToExpiry <= 0) {\n this.#clearCachedEntry();\n return;\n }\n\n this.#expiryTimer = setTimeout(() => {\n this.#clearCachedEntry();\n }, timeToExpiry + 1);\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * PRF (Pseudo-Random Function) handler for WebAuthn\n * @packageDocumentation\n */\n\nimport type { GetPrfSecretOptions, PasskeyCreationOptions } from './types.js';\n\nconst PRF_EVAL_INPUT = new TextEncoder().encode('nostr-pwk');\n\n/**\n * @returns PRF\n */\nexport async function isPrfSupported(): Promise<boolean> {\n try {\n const response = await navigator.credentials.get({\n publicKey: {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials: [],\n userVerification: 'required',\n extensions: { prf: { eval: { first: PRF_EVAL_INPUT } } },\n } as PublicKeyCredentialRequestOptions,\n });\n\n if (!response) return false;\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const res = assertion.getClientExtensionResults()?.prf?.results?.first;\n return !!res;\n } catch {\n return false;\n }\n}\n\n/**\n * @param options\n * @returns Credential\n */\nexport async function createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n // Node\n const rpName = options.rp?.name || (typeof location !== 'undefined' ? location.host : 'Nosskey');\n const rpId = options.rp?.id;\n const userName = options.user?.name || 'user@example.com';\n const userDisplayName = options.user?.displayName || 'Nosskey user';\n\n const credentialCreationOptions: CredentialCreationOptions = {\n publicKey: {\n rp: {\n name: rpName,\n id: rpId,\n },\n user: {\n id: crypto.getRandomValues(new Uint8Array(16)),\n name: userName,\n displayName: userDisplayName,\n },\n pubKeyCredParams: options.pubKeyCredParams || [{ type: 'public-key', alg: -7 }], // ES256\n authenticatorSelection: options.authenticatorSelection || {\n residentKey: 'required',\n userVerification: 'required',\n },\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n extensions: options.extensions || { prf: {} }, // PRF拡張を要求\n } as PublicKeyCredentialCreationOptions,\n };\n const cred = (await navigator.credentials.create(\n credentialCreationOptions\n )) as PublicKeyCredential;\n\n return new Uint8Array(cred.rawId);\n}\n\n/**\n * ID\n * @param credentialId \n * @param options PRF(rpId、timeout、userVerification)\n * @returns PRF credentialID\n */\nexport async function getPrfSecret(\n credentialId?: Uint8Array,\n options?: GetPrfSecretOptions\n): Promise<{ secret: Uint8Array; id: Uint8Array }> {\n const allowCredentials = credentialId ? [{ type: 'public-key' as const, id: credentialId }] : [];\n\n const requestOptions: PublicKeyCredentialRequestOptions = {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials,\n userVerification: options?.userVerification || 'required',\n extensions: {\n prf: { eval: { first: PRF_EVAL_INPUT } },\n } as AuthenticationExtensionsClientInputs,\n };\n\n if (options?.rpId) {\n requestOptions.rpId = options.rpId;\n }\n if (options?.timeout) {\n requestOptions.timeout = options.timeout;\n }\n\n const response = await navigator.credentials.get({\n publicKey: requestOptions,\n });\n\n if (!response) {\n throw new Error('Authentication failed');\n }\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const secret = assertion.getClientExtensionResults()?.prf?.results?.first;\n if (!secret) {\n throw new Error('PRF secret not available');\n }\n\n // response credentialId\n const responseId = new Uint8Array((response as PublicKeyCredential).rawId);\n\n return {\n secret: new Uint8Array(secret),\n id: responseId,\n };\n}\n","/**\n * PRF support check with a password-protected-key fallback.\n * If the PRF WebAuthn extension is unavailable, callers can fall back to a\n * password-protected private key. The private key is wrapped with a password-\n * derived AES-GCM key and stored alongside the public key (SPKI).\n *\n * This implementation uses @noble libraries for cryptographic operations,\n * ensuring functionality even when Web Crypto API is unavailable.\n */\n\nimport { getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { pbkdf2 } from '@noble/hashes/pbkdf2';\nimport { gcm } from '@noble/ciphers/aes';\n\nconst { randomBytes } = secp256k1.etc;\nconst aesGcm = gcm;\n\nexport type PasswordProtectedBundle = {\n publicKeySpkiBase64: string;\n wrappedPrivateKeyBase64: string;\n saltBase64: string;\n ivBase64: string;\n};\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);\n if (typeof window !== 'undefined' && (window as any).btoa) {\n return (window as any).btoa(binary);\n }\n return btoa(binary);\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n if (typeof window !== 'undefined' && (window as any).atob) {\n const bin = (window as any).atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n }\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport async function checkPRFSupport(): Promise<boolean> {\n try {\n const caps = typeof PublicKeyCredential !== 'undefined' ? await PublicKeyCredential.getClientCapabilities() : null;\n const supported = caps?.['extension:prf'] === true;\n if (supported) {\n console.log('PRF extension is supported.');\n } else {\n console.log('PRF extension is not supported.');\n }\n return !!supported;\n } catch (e) {\n console.log('Could not determine PRF support:', e);\n return false;\n }\n}\n\nexport async function generatePasswordProtectedKey(password: string): Promise<PasswordProtectedBundle> {\n const privateKey = secp256k1.utils.randomPrivateKey();\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n\n const publicKeySpkiBase64 = toBase64(publicKey);\n\n const salt = randomBytes(16);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = randomBytes(12);\n const ct = aesGcm(derivedKey, iv).encrypt(privateKey);\n\n return {\n publicKeySpkiBase64,\n wrappedPrivateKeyBase64: toBase64(ct),\n saltBase64: toBase64(salt),\n ivBase64: toBase64(iv),\n };\n}\n\nexport async function unwrapPasswordProtectedPrivateKey(bundle: PasswordProtectedBundle, password: string): Promise<Uint8Array> {\n const salt = fromBase64(bundle.saltBase64);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = fromBase64(bundle.ivBase64);\n const ct = fromBase64(bundle.wrappedPrivateKeyBase64);\n const privateKey = aesGcm(derivedKey, iv).decrypt(ct);\n return privateKey;\n}\n\nfunction base64UrlToBytes(base64url: string): Uint8Array {\n let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');\n const pad = base64.length % 4;\n if (pad) base64 += '='.repeat(4 - pad);\n if (typeof window !== 'undefined' && (window as any).atob) {\n const binary = (window as any).atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n }\n const bin = atob(base64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport function importPublicKeyFromBundle(bundle: PasswordProtectedBundle): Uint8Array {\n const spki = fromBase64(bundle.publicKeySpkiBase64);\n return spki;\n}\n\nconst DEFAULT_SALT = 'nostr-key-derivation';\n\nexport function deriveNostrPrivateKey(password: string, salt: string = DEFAULT_SALT): Uint8Array {\n const derivedBits = pbkdf2(sha256, new TextEncoder().encode(password), new TextEncoder().encode(salt), { c: 100000, dkLen: 32 });\n return derivedBits;\n}\n\nexport function getPublicKeyFromPassword(password: string, salt: string = DEFAULT_SALT): string {\n const sk = deriveNostrPrivateKey(password, salt);\n return getPublicKey(sk);\n}\n","import { finalizeEvent, getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { KeyCache } from './key-cache.js';\nimport { createPasskey, getPrfSecret, isPrfSupported } from './prf-handler.js';\nimport { checkPRFSupport, deriveNostrPrivateKey, getPublicKeyFromPassword, unwrapPasswordProtectedPrivateKey } from './prf-password-fallback.js';\nimport type {\n GetPrfSecretOptions,\n KeyCacheOptions,\n KeyOptions,\n NosskeyManagerLike,\n KeyManagerOptions,\n Event,\n KeyInfo,\n NostrKeyStorageOptions,\n PasskeyCreationOptions,\n SignOptions,\n} from './types.js';\n/**\n * Nosskey class for Passkey-Derived Nostr Identity\n * @packageDocumentation\n */\nimport { bytesToHex, hexToBytes } from './utils.js';\nimport type { KeyRecovery } from './types.js';\n\nexport async function deriveSaltFromUsername(username?: string): Promise<string> {\n if (!username) {\n return '';\n }\n \n const msgBuffer = new TextEncoder().encode(username.toLowerCase().trim());\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n const hashBuffer = await subtle.digest('SHA-256', msgBuffer);\n return bytesToHex(new Uint8Array(hashBuffer));\n}\n\nexport function parseRecoveryTag(tags: string[][]): KeyRecovery | null {\n const recoveryTag = tags.find(tag => tag[0] === 'r');\n if (!recoveryTag || recoveryTag.length < 3) return null;\n\n // Format: ['r', recoveryPubkey, recoverySalt, createdAt, signature]\n const createdAt = recoveryTag[3] ? parseInt(recoveryTag[3], 10) : undefined;\n return {\n recoveryPubkey: recoveryTag[1],\n recoverySalt: recoveryTag[2],\n createdAt: createdAt || undefined,\n signature: recoveryTag[4] || undefined,\n };\n}\n\nexport function createRecoveryTag(recovery: KeyRecovery): string[] {\n return [\n 'r',\n recovery.recoveryPubkey,\n recovery.recoverySalt,\n recovery.createdAt?.toString() || '',\n recovery.signature || '',\n ];\n}\n\nexport function getRecoverySignature(kind0: Event): string | null {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return null;\n \n const tag = kind0.tags?.find(t => t[0] === 'r');\n return tag && tag.length > 4 ? tag[4] || null : null;\n}\n\nexport async function verifyRecoverySignature(kind0: Event): Promise<boolean> {\n try {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return false;\n \n const signature = getRecoverySignature(kind0);\n if (!signature || !kind0.pubkey) return false;\n \n // Verify Schnorr signature: signature over current pubkey (as message)\n // using the recovery pubkey\n // Note: verify expects the message hash, not the message itself\n const messageHash = await sha256(kind0.pubkey);\n const signatureBytes = hexToBytes(signature);\n const pubkeyBytes = hexToBytes(kind0.pubkey);\n \n return secp256k1.verify(signatureBytes, messageHash, pubkeyBytes);\n } catch (e) {\n return false;\n }\n}\n\nasync function sha256(message: string): Promise<Uint8Array> {\n const msgBuffer = new TextEncoder().encode(message);\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n const hashBuffer = await subtle.digest('SHA-256', msgBuffer);\n return new Uint8Array(hashBuffer);\n}\n\n/**\n * Nosskey - Passkey-Derived Nostr Keys\n */\nexport class NosskeyManager implements NosskeyManagerLike {\n #keyCache: KeyCache;\n\n // KeyInfo\n #currentKeyInfo: KeyInfo | null = null;\n\n // KeyInfo\n #storageOptions: NostrKeyStorageOptions = {\n enabled: true,\n storageKey: 'nosskey_keyinfo',\n };\n\n // PRF\n #prfOptions: GetPrfSecretOptions = {};\n\n /**\n * NosskeyManager\n * @param options\n */\n constructor(options?: KeyManagerOptions) {\n // KeyCache\n this.#keyCache = new KeyCache(options?.cacheOptions);\n\n if (options?.storageOptions) {\n this.#storageOptions = { ...this.#storageOptions, ...options.storageOptions };\n }\n\n // option\n const userVerification = options?.prfOptions?.userVerification ?? 'required';\n if (options?.prfOptions) {\n this.#prfOptions = { ...options.prfOptions, userVerification };\n } else {\n this.#prfOptions = { userVerification };\n }\n\n // KeyInfo\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n }\n }\n }\n\n /**\n * KeyInfo\n * @param options\n */\n setStorageOptions(options: Partial<NostrKeyStorageOptions>): void {\n this.#storageOptions = { ...this.#storageOptions, ...options };\n\n if (options.enabled === false) {\n this.clearStoredKeyInfo();\n }\n }\n\n /**\n * KeyInfo\n */\n getStorageOptions(): NostrKeyStorageOptions {\n return { ...this.#storageOptions };\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n this.#currentKeyInfo = keyInfo;\n\n if (this.#storageOptions.enabled) {\n void this.#saveKeyInfoToStorage(keyInfo);\n }\n }\n\n /**\n * KeyInfo\n */\n getCurrentKeyInfo(): KeyInfo | null {\n // KeyInfo\n if (!this.#currentKeyInfo && this.#storageOptions.enabled) {\n this.#currentKeyInfo = this.#loadKeyInfoFromStorage();\n }\n return this.#currentKeyInfo;\n }\n\n /**\n * KeyInfo\n * @returns KeyInfo\n */\n hasKeyInfo(): boolean {\n if (this.#currentKeyInfo) {\n return true;\n }\n\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n async #saveKeyInfoToStorage(keyInfo: KeyInfo): Promise<void> {\n if (!this.#storageOptions.enabled) return;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.setItem(key, JSON.stringify(keyInfo));\n }\n\n /**\n * KeyInfo\n */\n #loadKeyInfoFromStorage(): KeyInfo | null {\n if (!this.#storageOptions.enabled) return null;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return null;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n const data = storage.getItem(key);\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as KeyInfo;\n } catch (e) {\n console.error('Failed to parse stored KeyInfo', e);\n return null;\n }\n }\n\n /**\n * KeyInfo\n */\n clearStoredKeyInfo(): void {\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.removeItem(key);\n\n // KeyInfo\n this.#currentKeyInfo = null;\n }\n\n /**\n * NIP-07\n * KeyInfo\n */\n async getPublicKey(): Promise<string> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return keyInfo.pubkey;\n }\n\n /**\n * NIP-07\n * KeyInfo\n * @param event Nostr\n */\n async signEvent(event: Event): Promise<Event> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return this.signEventWithKeyInfo(event, keyInfo);\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n this.#keyCache.setCacheOptions(options);\n }\n\n getCacheOptions(): KeyCacheOptions {\n return this.#keyCache.getCacheOptions();\n }\n\n getCachedSecretKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n return this.#keyCache.getKey(credentialId);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n this.#keyCache.clearCachedKey(credentialId);\n }\n\n clearAllCachedKeys(): void {\n this.#keyCache.clearAllCachedKeys();\n }\n\n /**\n * @param options\n * @returns Credential\n */\n async createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n return createPasskey({\n rp: {\n id: this.#prfOptions.rpId,\n name: this.#prfOptions.rpId,\n },\n authenticatorSelection: {\n userVerification: this.#prfOptions.userVerification,\n },\n ...options,\n });\n }\n\n/**\n * Check if PRF is supported\n */\n async checkPRFSupport(): Promise<boolean> {\n return checkPRFSupport();\n }\n\n /**\n * Create Nostr key - automatically uses password fallback if PRF unavailable\n * @param credentialId Passkey credential ID\n * @param password Password for encryption (required if PRF not supported)\n * @param options \n */\n async createKey(credentialId?: Uint8Array, password?: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const prfSupported = await this.checkPRFSupport();\n \n let keyInfo: KeyInfo;\n \n if (prfSupported) {\n keyInfo = await this.createPrfNostrKey(credentialId, options);\n \n // Auto-add password recovery if requested and PRF is supported\n if (options.recoveryPassword) {\n keyInfo = await this.addPasswordRecovery(options.recoveryPassword, credentialId);\n }\n } else {\n if (!password) {\n throw new Error('Password is required when PRF is not supported');\n }\n if (!options.username) {\n throw new Error('Username is required when PRF is not supported');\n }\n keyInfo = await this.createPasswordProtectedNostrKey(password, options);\n }\n \n return keyInfo;\n }\n\n /**\n * Create Nostr key using PRF (standard passkey flow)\n */\n async createPrfNostrKey(credentialId?: Uint8Array, options: KeyOptions = {}): Promise<KeyInfo> {\n const { secret: sk, id: responseId } = await getPrfSecret(credentialId, this.#prfOptions);\n\n if (sk.every((byte) => byte === 0)) {\n throw new Error('Invalid PRF output: all zeros');\n }\n\n const skHex = bytesToHex(sk);\n const publicKey = getPublicKey(sk);\n \n const salt = await deriveSaltFromUsername(options.username);\n\n const keyInfo: KeyInfo = {\n credentialId: bytesToHex(credentialId || responseId),\n pubkey: publicKey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n if (this.#keyCache.isEnabled() && this.#keyCache.getCacheOptions().cacheOnCreation) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n\n return keyInfo;\n }\n\n /**\n * Create Nostr key using password-derived key (fallback when PRF unavailable)\n * @param password Password to derive the private key\n * @param options \n */\n async createPasswordProtectedNostrKey(password: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const salt = await deriveSaltFromUsername(options.username);\n const pubkey = getPublicKeyFromPassword(password, salt);\n\n const credentialId = bytesToHex((typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto).getRandomValues(new Uint8Array(16)));\n\n const keyInfo: KeyInfo = {\n credentialId,\n pubkey: pubkey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n return keyInfo;\n }\n\n/**\n * @param event Nostr\n * @param keyInfo KeyInfo\n * @param options\n */\n async signEventWithKeyInfo(\n event: Event,\n keyInfo: KeyInfo,\n options: SignOptions = {}\n ): Promise<Event> {\n const { clearMemory = true, tags, password } = options;\n\n const shouldUseCache = this.#keyCache.isEnabled();\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n\n let sk: Uint8Array | undefined;\n\n if (isPasswordDerived) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = deriveNostrPrivateKey(password, keyInfo.salt);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password to sign.');\n }\n } else if (keyInfo.passwordProtectedBundle) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle!, password);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password or use createNostrKey to initialize.');\n }\n } else {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n\n if (!sk) {\n const { secret: prfSecret } = await getPrfSecret(\n hexToBytes(keyInfo.credentialId),\n this.#prfOptions\n );\n sk = prfSecret;\n\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n }\n\n const eventToSign = {\n kind: event.kind,\n content: event.content,\n created_at: event.created_at || Math.floor(Date.now() / 1000),\n tags: tags ? [...(event.tags || []), ...tags] : event.tags || [],\n };\n\n const signedEvent = finalizeEvent(eventToSign, sk);\n\n if (!shouldUseCache && clearMemory) {\n this.#clearKey(sk);\n }\n\n return signedEvent;\n }\n\n/**\n * @param keyInfo KeyInfo\n * @param credentialId KeyInfoのcredentialId\n * @param options\n * @returns \n */\n async exportNostrKey(keyInfo: KeyInfo, credentialId?: Uint8Array, options: KeyOptions = {}): Promise<string> {\n if (keyInfo.passwordProtectedBundle) {\n if (!options.password) {\n throw new Error('Password is required for password-protected keys');\n }\n const sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle, options.password);\n return bytesToHex(sk);\n }\n\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n if (isPasswordDerived) {\n if (!options.password) {\n throw new Error('Password is required for password-derived keys');\n }\n const sk = deriveNostrPrivateKey(options.password, keyInfo.salt);\n return bytesToHex(sk);\n }\n\n let usedCredentialId = credentialId;\n\n if (!usedCredentialId && keyInfo.credentialId) {\n usedCredentialId = hexToBytes(keyInfo.credentialId);\n }\n\n const { secret: sk } = await getPrfSecret(usedCredentialId, this.#prfOptions);\n const skHex = bytesToHex(sk);\n\n return skHex;\n }\n\n /**\n * PRF\n */\n async isPrfSupported(): Promise<boolean> {\n return isPrfSupported();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n * @param currentCredentialId Current passkey credential ID\n */\n async addPasswordRecovery(password: string, currentCredentialId?: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (keyInfo.passwordProtectedBundle) {\n throw new Error('Password recovery already exists for password-derived key');\n }\n\n if (keyInfo.recovery) {\n throw new Error('Recovery already configured');\n }\n\n const usedCredentialId = currentCredentialId || (keyInfo.credentialId ? hexToBytes(keyInfo.credentialId) : undefined);\n if (!usedCredentialId) {\n throw new Error('Credential ID required');\n }\n\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n\n // Generate recovery salt\n const recoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n\n // Derive recovery pubkey from password\n const recoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n\n // Sign current pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, keyInfo.pubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n ...keyInfo,\n recovery: {\n recoveryPubkey,\n recoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n #signWithKey(sk: Uint8Array, message: string): string {\n const event = finalizeEvent({\n kind: 0,\n content: '',\n tags: [],\n created_at: Math.floor(Date.now() / 1000),\n }, sk);\n return event.sig;\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (!keyInfo.recovery) {\n throw new Error('No recovery key configured');\n }\n\n if (!newCredentialId) {\n throw new Error('New credential ID is required for recovery');\n }\n\n const { recoveryPubkey, recoverySalt } = keyInfo.recovery;\n\n // Verify password\n const derivedRecoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n if (derivedRecoveryPubkey !== recoveryPubkey) {\n throw new Error('Invalid recovery password');\n }\n\n // Derive new key from new credential\n const { secret: newSk } = await getPrfSecret(newCredentialId, this.#prfOptions);\n const newPubkey = getPublicKey(newSk);\n this.#clearKey(newSk);\n\n // Generate new recovery for the new key\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n const newRecoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n const newRecoveryPubkey = getPublicKeyFromPassword(password, newRecoverySalt);\n\n // Sign new pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, newPubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n credentialId: bytesToHex(newCredentialId),\n pubkey: newPubkey,\n salt: keyInfo.salt,\n recovery: {\n recoveryPubkey: newRecoveryPubkey,\n recoverySalt: newRecoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n /**\n * Get the recovery data for publishing to kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number; signature?: string } | null {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo || !keyInfo.recovery) return null;\n\n return {\n recoveryPubkey: keyInfo.recovery.recoveryPubkey,\n recoverySalt: keyInfo.recovery.recoverySalt,\n createdAt: keyInfo.recovery.createdAt,\n signature: keyInfo.recovery.signature,\n };\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * Cryptographic utilities for Nosskey\n * @packageDocumentation\n */\n\nconst INFO_BYTES = new TextEncoder().encode('nostr-pwk');\nconst AES_LENGTH = 256; // bits\n\nfunction getSubtle(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n return subtle;\n}\n\n/**\n * PRF AES-GCM\n * @param secret PRF\n * @param salt\n * @returns AES-GCM\n */\nexport async function deriveAesGcmKey(secret: Uint8Array, salt: Uint8Array): Promise<CryptoKey> {\n const subtle = getSubtle();\n const keyMaterial = await subtle.importKey('raw', secret, 'HKDF', false, ['deriveKey']);\n\n return subtle.deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt, info: INFO_BYTES },\n keyMaterial,\n { name: 'AES-GCM', length: AES_LENGTH },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param plaintext\n * @returns\n */\nexport async function aesGcmEncrypt(key: CryptoKey, iv: Uint8Array, plaintext: Uint8Array) {\n const subtle = getSubtle();\n const buf = await subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);\n\n const bytes = new Uint8Array(buf);\n return {\n ciphertext: bytes.slice(0, -16),\n tag: bytes.slice(-16),\n };\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param ct\n * @param tag\n * @returns\n */\nexport async function aesGcmDecrypt(\n key: CryptoKey,\n iv: Uint8Array,\n ct: Uint8Array,\n tag: Uint8Array\n): Promise<Uint8Array> {\n const subtle = getSubtle();\n const buf = await subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n new Uint8Array([...ct, ...tag])\n );\n return new Uint8Array(buf);\n}\n","/**\n * Test utilities for sdk\n * @packageDocumentation\n */\n\n/**\n * Helper for testing/debugging\n * @param userId - User identifier\n * @returns Promise resolving to the dummy credential\n */\nexport async function registerDummyPasskey(userId: string): Promise<PublicKeyCredential> {\n // Create a dummy credential for testing\n const dummySignature = new Uint8Array(64);\n // Fill with some non-zero values for testing\n for (let i = 0; i < dummySignature.length; i++) {\n dummySignature[i] = (i + 1) % 256;\n }\n\n const dummyId = new Uint8Array(32);\n for (let i = 0; i < dummyId.length; i++) {\n dummyId[i] = (i + 1) % 256;\n }\n\n const credential = {\n id: 'dummy-credential-id',\n rawId: dummyId,\n type: 'public-key',\n response: {\n clientDataJSON: new Uint8Array(0),\n attestationObject: new Uint8Array(0),\n signature: dummySignature,\n authenticatorData: new Uint8Array(0),\n getAuthenticatorData: () => new Uint8Array(0),\n getPublicKey: () => new Uint8Array(0),\n getPublicKeyAlgorithm: () => -7,\n getTransports: () => ['internal'],\n },\n } as unknown as PublicKeyCredential;\n\n return credential;\n}\n","import { NosskeyManager, type KeyInfo, type Event, type PasskeyCreationOptions, type SignOptions, type KeyOptions } from '../utils';\nimport type { AuthServiceConfig } from '../types/auth';\n\n/**\n * Service wrapper around NosskeyManager\n * Handles WebAuthn/Passkey integration with Nostr\n */\nexport class AuthService {\n private manager: NosskeyManager | null = null;\n private config: AuthServiceConfig;\n\n constructor(config: AuthServiceConfig = {}) {\n this.config = {\n rpId: config.rpId || (typeof window !== 'undefined' ? window.location.hostname.replace(/^www\\./, '') : 'localhost'),\n rpName: config.rpName || this.getDefaultRpName(),\n storageKey: config.storageKey || 'nsauth_keyinfo',\n cacheTimeoutMs: config.cacheTimeoutMs || 30 * 60 * 1000,\n cacheOnCreation: config.cacheOnCreation !== undefined ? config.cacheOnCreation : true,\n };\n }\n\n private getDefaultRpName(): string {\n if (typeof window === 'undefined') return 'localhost';\n const hostname = window.location.hostname;\n if (hostname.includes('nosskey.app')) return 'nosskey.app';\n return hostname.replace(/^www\\./, '');\n }\n\n /**\n * Initialize the NosskeyManager instance\n */\n private getManager(): NosskeyManager {\n if (!this.manager) {\n this.manager = new NosskeyManager({\n cacheOptions: {\n enabled: true,\n timeoutMs: this.config.cacheTimeoutMs,\n cacheOnCreation: this.config.cacheOnCreation,\n },\n storageOptions: {\n enabled: true,\n storageKey: this.config.storageKey,\n },\n });\n }\n return this.manager;\n }\n\n /**\n * Create a new passkey\n * Uses platform authenticator only (Touch ID, Face ID, Windows Hello)\n */\n async createPasskey(username?: string): Promise<Uint8Array> {\n const manager = this.getManager();\n \n const rpId = this.config.rpId === 'localhost' ? 'localhost' : this.config.rpId;\n const rpName = this.config.rpName;\n \n const trimmedUsername = username?.trim();\n const uniqueUsername = trimmedUsername \n ? trimmedUsername \n : `user-${Date.now()}@example.com`;\n \n const options: PasskeyCreationOptions = {\n rp: {\n id: rpId,\n name: rpName,\n },\n user: {\n name: uniqueUsername,\n displayName: trimmedUsername || 'User',\n },\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n residentKey: 'preferred',\n userVerification: 'preferred',\n },\n extensions: {\n prf: {},\n },\n };\n \n return await manager.createPasskey(options);\n }\n\n/**\n * Create a new Nostr key from a credential ID\n * Automatically uses password fallback if PRF is not supported\n * @param credentialId Passkey credential ID\n * @param password Password (required if PRF not supported)\n * @param options.username Username for the key\n * @param options.recoveryPassword Password for recovery (enables recovery on new device)\n */\n async createKey(credentialId?: Uint8Array, password?: string, options?: KeyOptions): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.createKey(credentialId, password, options);\n }\n\n /**\n * Check if PRF is supported, otherwise password fallback is needed\n */\n async checkPRFSupport(): Promise<boolean> {\n const manager = this.getManager();\n return await manager.checkPRFSupport();\n }\n\n /**\n * Get the current public key\n */\n async getPublicKey(): Promise<string> {\n const manager = this.getManager();\n return await manager.getPublicKey();\n }\n\n /**\n * Sign a Nostr event\n */\n async signEvent(event: Event, options?: SignOptions): Promise<Event> {\n const manager = this.getManager();\n return await manager.signEvent(event, options);\n }\n\n /**\n * Get current key info\n */\n getCurrentKeyInfo(): KeyInfo | null {\n const manager = this.getManager();\n return manager.getCurrentKeyInfo();\n }\n\n /**\n * Set current key info\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n const manager = this.getManager();\n manager.setCurrentKeyInfo(keyInfo);\n }\n\n /**\n * Check if key info exists\n */\n hasKeyInfo(): boolean {\n const manager = this.getManager();\n return manager.hasKeyInfo();\n }\n\n /**\n * Clear stored key info\n */\n clearStoredKeyInfo(): void {\n const manager = this.getManager();\n manager.clearStoredKeyInfo();\n }\n\n/**\n * Check if PRF is supported (legacy alias)\n */\n async isPrfSupported(): Promise<boolean> {\n return this.checkPRFSupport();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n */\n async addPasswordRecovery(password: string): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.addPasswordRecovery(password);\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.activateWithPassword(password, newCredentialId);\n }\n\n /**\n * Get recovery data for kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number } | null {\n const manager = this.getManager();\n return manager.getRecoveryForKind0();\n }\n}\n\n","export const MAX_ROLE_LENGTH = 100;\nconst ROLE_PATTERN = /^[a-zA-Z0-9\\s\\-_]+$/;\n\nexport const isValidRoleTag = (role: string): boolean => {\n const trimmed = role.trim();\n return (\n trimmed.length > 0 &&\n trimmed.length <= MAX_ROLE_LENGTH &&\n ROLE_PATTERN.test(trimmed)\n );\n};\n\nexport const isValidPubkey = (pubkey: string): boolean =>\n pubkey.length === 64 && /^[0-9a-fA-F]+$/.test(pubkey);\n\nexport const isValidHttpUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['http:', 'https:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n};\n\nexport const isValidRelayUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['ws:', 'wss:'].includes(parsed.protocol) && parsed.hostname.length > 0;\n } catch {\n return false;\n }\n};\n","import type { EventStore } from 'applesauce-core';\nimport type { Event } from '../types/nostr';\nimport type { ProfileMetadata, FollowEntry } from '../types/nostr';\nimport type { RelayServiceConfig } from '../types/auth';\nimport { isValidPubkey, isValidRelayUrl, isValidRoleTag } from '../utils/validation';\n\n/**\n * Service for communicating with Nostr relays using applesauce-core\n */\nexport class RelayService {\n private eventStore: EventStore | null = null;\n private relayUrls: string[];\n private defaultRelays = ['wss://relay.damus.io'];\n private readonly maxProfileContentSize = 10000;\n private readonly minProfileQueryIntervalMs = 300;\n private readonly minPublishIntervalMs = 750;\n private readonly lastActionAt = new Map<string, number>();\n\n constructor(config: RelayServiceConfig = {}) {\n this.relayUrls = this.validateRelayUrls(config.relayUrls ?? this.defaultRelays);\n }\n\n /**\n * Initialize with applesauce EventStore\n */\n initialize(eventStore: EventStore): void {\n this.eventStore = eventStore;\n // Set default relays if EventStore has a method for it\n if (eventStore && 'setRelays' in eventStore && typeof eventStore.setRelays === 'function') {\n (eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Set relay URLs\n */\n setRelays(urls: string[]): void {\n this.relayUrls = this.validateRelayUrls(urls);\n if (this.eventStore && 'setRelays' in this.eventStore && typeof this.eventStore.setRelays === 'function') {\n (this.eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Get current relay URLs\n */\n getRelays(): string[] {\n return [...this.relayUrls];\n }\n\n /**\n * Publish an event to relays\n */\n async publishEvent(event: Event, timeoutMs = 1000): Promise<boolean> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('publish', this.minPublishIntervalMs);\n return new Promise((resolve, reject) => {\n if (this.relayUrls.length === 0) {\n reject(new Error('No relays configured'));\n return;\n }\n\n // Use EventStore's publish method\n // Note: This is a simplified implementation - actual applesauce API may differ\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.publish !== 'function') {\n reject(new Error('EventStore does not support publish method'));\n return;\n }\n const subscription = eventStore.publish(event).subscribe({\n next: (response: any) => {\n if (response?.type === 'OK') {\n subscription.unsubscribe();\n resolve(true);\n }\n },\n error: (error: Error) => {\n subscription.unsubscribe();\n reject(error);\n },\n });\n\n // Timeout fallback\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(false);\n }, timeoutMs);\n });\n }\n\n /**\n * Fetch a profile (Kind 0 event)\n */\n async fetchProfile(pubkey: string): Promise<ProfileMetadata | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-profile', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n subscription.unsubscribe();\n resolve(metadata);\n return;\n }\n console.error('Failed to parse profile metadata');\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n // Timeout\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch role tag from profile event (Kind 0)\n */\n async fetchProfileRoleTag(pubkey: string): Promise<string | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-role-tag', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const tags = packet.event.tags || [];\n for (const tag of tags) {\n if (tag[0] === 'role' && tag[1]) {\n const candidate = tag[1].trim();\n if (isValidRoleTag(candidate)) {\n subscription.unsubscribe();\n resolve(candidate);\n return;\n }\n }\n }\n subscription.unsubscribe();\n resolve(null);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile role tag:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch a follow list (Kind 3 event)\n */\n async fetchFollowList(pubkey: string): Promise<FollowEntry[]> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-follow-list', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [3],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve([]);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 3) {\n const followList: FollowEntry[] = [];\n const tags = packet.event.tags || [];\n\n for (const tag of tags) {\n if (tag[0] === 'p' && tag[1]) {\n followList.push({\n pubkey: tag[1],\n relay: tag[2] || undefined,\n petname: tag[3] || undefined,\n });\n }\n }\n\n subscription.unsubscribe();\n resolve(followList);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve([]);\n },\n error: (error: Error) => {\n console.error('Error fetching follow list:', error);\n subscription.unsubscribe();\n resolve([]);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve([]);\n }, 10000);\n });\n }\n\n /**\n * Fetch multiple profiles in batch\n */\n async fetchMultipleProfiles(pubkeys: string[]): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n if (pubkeys.length === 0) {\n return new Map();\n }\n\n await this.enforceRateLimit('fetch-multiple-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, ProfileMetadata>();\n const filter = {\n kinds: [0],\n authors: pubkeys,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n profiles.set(packet.event.pubkey, metadata);\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(profiles);\n },\n error: (error: Error) => {\n console.error('Error fetching profiles:', error);\n subscription.unsubscribe();\n resolve(profiles);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(profiles);\n }, 1000);\n });\n }\n\n /**\n * Query kind 0 events (profiles) by pubkey\n * If pubkeys array is empty, fetches recent kind 0 events\n */\n async queryProfiles(pubkeys: string[] = [], limit = 100): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('query-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, { metadata: ProfileMetadata; timestamp: number }>();\n const filter: any = {\n kinds: [0],\n limit,\n };\n\n if (pubkeys.length > 0) {\n filter.authors = pubkeys;\n }\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n const timestamp = packet.event.created_at || 0;\n const existing = profiles.get(packet.event.pubkey);\n if (!existing || timestamp > existing.timestamp) {\n profiles.set(packet.event.pubkey, { metadata, timestamp });\n }\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n error: (error: Error) => {\n console.error('Error querying profiles:', error);\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n }, 10000);\n });\n }\n\n /**\n * Publish or update a kind 3 event (follow list/contacts)\n */\n async publishFollowList(\n pubkey: string,\n followList: FollowEntry[],\n signEvent: (event: Event) => Promise<Event>\n ): Promise<boolean> {\n const tags: string[][] = followList.map((entry) => {\n if (!isValidPubkey(entry.pubkey)) {\n throw new Error('Invalid pubkey format for follow list entry.');\n }\n if (entry.relay && !isValidRelayUrl(entry.relay)) {\n throw new Error('Invalid relay URL format for follow list entry.');\n }\n const tag: string[] = ['p', entry.pubkey];\n if (entry.relay) {\n tag.push(entry.relay);\n }\n if (entry.petname) {\n tag.push(entry.petname);\n }\n return tag;\n });\n\n const event: Event = {\n kind: 3,\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n tags,\n };\n\n const signedEvent = await signEvent(event);\n return await this.publishEvent(signedEvent);\n }\n\n private validateRelayUrls(urls: string[]): string[] {\n if (urls.length === 0) {\n return [];\n }\n const validUrls = urls.filter((url) => isValidRelayUrl(url));\n if (validUrls.length !== urls.length) {\n throw new Error('Invalid relay URL format');\n }\n return validUrls;\n }\n\n private parseProfileMetadata(content: string): ProfileMetadata | null {\n if (content.length > this.maxProfileContentSize) {\n return null;\n }\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n const metadata: ProfileMetadata = {};\n if (typeof (parsed as ProfileMetadata).name === 'string') {\n metadata.name = (parsed as ProfileMetadata).name;\n }\n if (typeof (parsed as ProfileMetadata).display_name === 'string') {\n metadata.display_name = (parsed as ProfileMetadata).display_name;\n }\n if (typeof (parsed as ProfileMetadata).about === 'string') {\n metadata.about = (parsed as ProfileMetadata).about;\n }\n if (typeof (parsed as ProfileMetadata).picture === 'string') {\n metadata.picture = (parsed as ProfileMetadata).picture;\n }\n if (typeof (parsed as ProfileMetadata).website === 'string') {\n metadata.website = (parsed as ProfileMetadata).website;\n }\n return metadata;\n } catch (error) {\n console.error('Failed to parse profile metadata:', error);\n return null;\n }\n }\n\n private async enforceRateLimit(action: string, minIntervalMs: number): Promise<void> {\n const lastAt = this.lastActionAt.get(action) ?? 0;\n const now = Date.now();\n const waitMs = minIntervalMs - (now - lastAt);\n if (waitMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n this.lastActionAt.set(action, Date.now());\n }\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["#cacheOptions","#cachedEntry","#clearCachedEntry","#scheduleExpiry","#getCachedKeyIfValid","#clearKey","#expiryTimer","bin","bytes","nobleSha256","sha256","#keyCache","#storageOptions","#prfOptions","#loadKeyInfoFromStorage","#currentKeyInfo","#saveKeyInfoToStorage","#clearKey","#signWithKey"],"sources":["../src/utils/utils.ts","../src/utils/key-cache.ts","../src/utils/prf-handler.ts","../src/utils/prf-password-fallback.ts","../src/utils/nosskey.ts","../src/utils/crypto-utils.ts","../src/utils/test-utils.ts","../src/services/auth.service.ts","../src/utils/validation.ts","../src/services/relay.service.ts"],"sourcesContent":["/**\n * @packageDocumentation\n */\n\n/**\n * @param bytes\n * @returns\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n const key = '0123456789abcdef';\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n const firstNibble = bytes[i] >> 4;\n const secondNibble = bytes[i] & 15;\n hex += key[firstNibble] + key[secondNibble];\n }\n return hex;\n}\n\n/**\n * @param hex\n * @returns\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const key = '0123456789abcdef';\n const bytes = [];\n let currentByte = 0;\n let highNibble = true;\n\n for (let i = 0; i < hex.length; i++) {\n const charValue = key.indexOf(hex[i].toLowerCase());\n if (charValue === -1) continue;\n\n if (highNibble) {\n currentByte = charValue << 4;\n highNibble = false;\n } else {\n currentByte += charValue;\n bytes.push(currentByte);\n highNibble = true;\n }\n }\n\n return new Uint8Array(bytes);\n}\n","/**\n * Key cache management for Nosskey\n * @packageDocumentation\n */\n\nimport type { KeyCacheOptions } from './types.js';\nimport { bytesToHex } from './utils.js';\n\n/**\n * Key cache entry with expiration time\n */\ninterface CacheEntry {\n id: string;\n sk: Uint8Array;\n expireAt: number;\n}\n\n/**\n * Key cache manager for managing temporary secret keys\n */\nexport class KeyCache {\n #cachedEntry: CacheEntry | null = null;\n\n #expiryTimer: NodeJS.Timeout | null = null;\n\n #cacheOptions: KeyCacheOptions = {\n enabled: false,\n timeoutMs: 5 * 60 * 1000,\n };\n\n /**\n * KeyCache\n * @param options\n */\n constructor(options?: Partial<KeyCacheOptions>) {\n if (options) {\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n if (Object.keys(options).length > 0 && this.#cachedEntry !== null) {\n this.clearAllCachedKeys();\n }\n\n this.#cacheOptions = { ...this.#cacheOptions, ...options };\n }\n\n getCacheOptions(): KeyCacheOptions {\n return { ...this.#cacheOptions };\n }\n\n isEnabled(): boolean {\n return this.#cacheOptions.enabled;\n }\n\n /**\n * @param credentialId\n * @param sk\n */\n setKey(credentialId: Uint8Array | string, sk: Uint8Array): void {\n if (!this.#cacheOptions.enabled) return;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n const timeout =\n this.#cacheOptions.timeoutMs !== undefined ? this.#cacheOptions.timeoutMs : 5 * 60 * 1000;\n const expireAt = Date.now() + timeout;\n\n this.#clearCachedEntry();\n\n this.#cachedEntry = {\n id,\n sk: new Uint8Array(sk),\n expireAt,\n };\n\n try {\n this.#scheduleExpiry();\n } catch (error) {\n this.#clearCachedEntry();\n throw error;\n }\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n getKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n if (!this.#cacheOptions.enabled) return undefined;\n\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n return this.#getCachedKeyIfValid(id);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n const id = typeof credentialId === 'string' ? credentialId : bytesToHex(credentialId);\n\n if (this.#cachedEntry && this.#cachedEntry.id === id) {\n this.#clearCachedEntry();\n }\n }\n\n clearAllCachedKeys(): void {\n this.#clearCachedEntry();\n }\n\n /**\n * @param credentialId\n * @returns undefined\n */\n #getCachedKeyIfValid(credentialId: string): Uint8Array | undefined {\n if (!this.#cachedEntry || this.#cachedEntry.id !== credentialId) {\n return undefined;\n }\n\n if (Date.now() < this.#cachedEntry.expireAt) {\n return this.#cachedEntry.sk;\n }\n\n this.#clearCachedEntry();\n return undefined;\n }\n\n #clearCachedEntry(): void {\n if (this.#cachedEntry) {\n this.#clearKey(this.#cachedEntry.sk);\n this.#cachedEntry = null;\n }\n\n if (this.#expiryTimer) {\n clearTimeout(this.#expiryTimer);\n this.#expiryTimer = null;\n }\n }\n\n #scheduleExpiry(): void {\n if (!this.#cachedEntry) return;\n\n const now = Date.now();\n const timeToExpiry = this.#cachedEntry.expireAt - now;\n\n if (timeToExpiry <= 0) {\n this.#clearCachedEntry();\n return;\n }\n\n this.#expiryTimer = setTimeout(() => {\n this.#clearCachedEntry();\n }, timeToExpiry + 1);\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * PRF (Pseudo-Random Function) handler for WebAuthn\n * @packageDocumentation\n */\n\nimport type { GetPrfSecretOptions, PasskeyCreationOptions } from './types.js';\n\nconst PRF_EVAL_INPUT = new TextEncoder().encode('nostr-pwk');\n\n/**\n * @returns PRF\n */\nexport async function isPrfSupported(): Promise<boolean> {\n try {\n const response = await navigator.credentials.get({\n publicKey: {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials: [],\n userVerification: 'required',\n extensions: { prf: { eval: { first: PRF_EVAL_INPUT } } },\n } as PublicKeyCredentialRequestOptions,\n });\n\n if (!response) return false;\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const res = assertion.getClientExtensionResults()?.prf?.results?.first;\n return !!res;\n } catch {\n return false;\n }\n}\n\n/**\n * @param options\n * @returns Credential\n */\nexport async function createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n // Node\n const rpName = options.rp?.name || (typeof location !== 'undefined' ? location.host : 'Nosskey');\n const rpId = options.rp?.id;\n const userName = options.user?.name || 'user@example.com';\n const userDisplayName = options.user?.displayName || 'Nosskey user';\n\n const credentialCreationOptions: CredentialCreationOptions = {\n publicKey: {\n rp: {\n name: rpName,\n id: rpId,\n },\n user: {\n id: crypto.getRandomValues(new Uint8Array(16)),\n name: userName,\n displayName: userDisplayName,\n },\n pubKeyCredParams: options.pubKeyCredParams || [{ type: 'public-key', alg: -7 }], // ES256\n authenticatorSelection: options.authenticatorSelection || {\n residentKey: 'required',\n userVerification: 'required',\n },\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n extensions: options.extensions || { prf: {} }, // PRF拡張を要求\n } as PublicKeyCredentialCreationOptions,\n };\n const cred = (await navigator.credentials.create(\n credentialCreationOptions\n )) as PublicKeyCredential;\n\n return new Uint8Array(cred.rawId);\n}\n\n/**\n * ID\n * @param credentialId \n * @param options PRF(rpId、timeout、userVerification)\n * @returns PRF credentialID\n */\nexport async function getPrfSecret(\n credentialId?: Uint8Array,\n options?: GetPrfSecretOptions\n): Promise<{ secret: Uint8Array; id: Uint8Array }> {\n const allowCredentials = credentialId ? [{ type: 'public-key' as const, id: credentialId }] : [];\n\n const requestOptions: PublicKeyCredentialRequestOptions = {\n challenge: crypto.getRandomValues(new Uint8Array(32)),\n allowCredentials,\n userVerification: options?.userVerification || 'required',\n extensions: {\n prf: { eval: { first: PRF_EVAL_INPUT } },\n } as AuthenticationExtensionsClientInputs,\n };\n\n if (options?.rpId) {\n requestOptions.rpId = options.rpId;\n }\n if (options?.timeout) {\n requestOptions.timeout = options.timeout;\n }\n\n const response = await navigator.credentials.get({\n publicKey: requestOptions,\n });\n\n if (!response) {\n throw new Error('Authentication failed');\n }\n\n const assertion = response as unknown as {\n getClientExtensionResults: () => {\n prf?: {\n results?: {\n first?: ArrayBuffer;\n };\n };\n };\n };\n\n const secret = assertion.getClientExtensionResults()?.prf?.results?.first;\n if (!secret) {\n throw new Error('PRF secret not available');\n }\n\n // response credentialId\n const responseId = new Uint8Array((response as PublicKeyCredential).rawId);\n\n return {\n secret: new Uint8Array(secret),\n id: responseId,\n };\n}\n","/**\n * PRF support check with a password-protected-key fallback.\n * If the PRF WebAuthn extension is unavailable, callers can fall back to a\n * password-protected private key. The private key is wrapped with a password-\n * derived AES-GCM key and stored alongside the public key (SPKI).\n *\n * This implementation uses @noble libraries for cryptographic operations,\n * ensuring functionality even when Web Crypto API is unavailable.\n */\n\nimport { getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { pbkdf2 } from '@noble/hashes/pbkdf2';\nimport { gcm } from '@noble/ciphers/aes';\n\nconst { randomBytes } = secp256k1.etc;\nconst aesGcm = gcm;\n\nexport type PasswordProtectedBundle = {\n publicKeySpkiBase64: string;\n wrappedPrivateKeyBase64: string;\n saltBase64: string;\n ivBase64: string;\n};\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);\n if (typeof window !== 'undefined' && (window as any).btoa) {\n return (window as any).btoa(binary);\n }\n return btoa(binary);\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n if (typeof window !== 'undefined' && (window as any).atob) {\n const bin = (window as any).atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n }\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport async function checkPRFSupport(): Promise<boolean> {\n try {\n const caps = typeof PublicKeyCredential !== 'undefined' ? await PublicKeyCredential.getClientCapabilities() : null;\n const supported = caps?.['extension:prf'] === true;\n if (supported) {\n console.log('PRF extension is supported.');\n } else {\n console.log('PRF extension is not supported.');\n }\n return !!supported;\n } catch (e) {\n console.log('Could not determine PRF support:', e);\n return false;\n }\n}\n\nexport async function generatePasswordProtectedKey(password: string): Promise<PasswordProtectedBundle> {\n const privateKey = secp256k1.utils.randomPrivateKey();\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n\n const publicKeySpkiBase64 = toBase64(publicKey);\n\n const salt = randomBytes(16);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = randomBytes(12);\n const ct = aesGcm(derivedKey, iv).encrypt(privateKey);\n\n return {\n publicKeySpkiBase64,\n wrappedPrivateKeyBase64: toBase64(ct),\n saltBase64: toBase64(salt),\n ivBase64: toBase64(iv),\n };\n}\n\nexport async function unwrapPasswordProtectedPrivateKey(bundle: PasswordProtectedBundle, password: string): Promise<Uint8Array> {\n const salt = fromBase64(bundle.saltBase64);\n const derivedKey = pbkdf2(sha256, new TextEncoder().encode(password), salt, { c: 100000, dkLen: 32 });\n const iv = fromBase64(bundle.ivBase64);\n const ct = fromBase64(bundle.wrappedPrivateKeyBase64);\n const privateKey = aesGcm(derivedKey, iv).decrypt(ct);\n return privateKey;\n}\n\nfunction base64UrlToBytes(base64url: string): Uint8Array {\n let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');\n const pad = base64.length % 4;\n if (pad) base64 += '='.repeat(4 - pad);\n if (typeof window !== 'undefined' && (window as any).atob) {\n const binary = (window as any).atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n }\n const bin = atob(base64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nexport function importPublicKeyFromBundle(bundle: PasswordProtectedBundle): Uint8Array {\n const spki = fromBase64(bundle.publicKeySpkiBase64);\n return spki;\n}\n\nconst DEFAULT_SALT = 'nostr-key-derivation';\n\nexport function deriveNostrPrivateKey(password: string, salt: string = DEFAULT_SALT): Uint8Array {\n const derivedBits = pbkdf2(sha256, new TextEncoder().encode(password), new TextEncoder().encode(salt), { c: 100000, dkLen: 32 });\n return derivedBits;\n}\n\nexport function getPublicKeyFromPassword(password: string, salt: string = DEFAULT_SALT): string {\n const sk = deriveNostrPrivateKey(password, salt);\n return getPublicKey(sk);\n}\n","import { finalizeEvent, getPublicKey } from 'applesauce-core/helpers';\nimport * as secp256k1 from '@noble/secp256k1';\nimport { sha256 as nobleSha256 } from '@noble/hashes/sha256';\nimport { KeyCache } from './key-cache.js';\nimport { createPasskey, getPrfSecret, isPrfSupported } from './prf-handler.js';\nimport { checkPRFSupport, deriveNostrPrivateKey, getPublicKeyFromPassword, unwrapPasswordProtectedPrivateKey } from './prf-password-fallback.js';\nimport type {\n GetPrfSecretOptions,\n KeyCacheOptions,\n KeyOptions,\n NosskeyManagerLike,\n KeyManagerOptions,\n Event,\n KeyInfo,\n NostrKeyStorageOptions,\n PasskeyCreationOptions,\n SignOptions,\n} from './types.js';\n/**\n * Nosskey class for Passkey-Derived Nostr Identity\n * @packageDocumentation\n */\nimport { bytesToHex, hexToBytes } from './utils.js';\nimport type { KeyRecovery } from './types.js';\n\nexport function deriveSaltFromUsername(username?: string): string {\n if (!username) {\n return '';\n }\n \n const msgBuffer = new TextEncoder().encode(username.toLowerCase().trim());\n const hashBuffer = nobleSha256(msgBuffer);\n return bytesToHex(new Uint8Array(hashBuffer));\n}\n\nexport function parseRecoveryTag(tags: string[][]): KeyRecovery | null {\n const recoveryTag = tags.find(tag => tag[0] === 'r');\n if (!recoveryTag || recoveryTag.length < 3) return null;\n\n // Format: ['r', recoveryPubkey, recoverySalt, createdAt, signature]\n const createdAt = recoveryTag[3] ? parseInt(recoveryTag[3], 10) : undefined;\n return {\n recoveryPubkey: recoveryTag[1],\n recoverySalt: recoveryTag[2],\n createdAt: createdAt || undefined,\n signature: recoveryTag[4] || undefined,\n };\n}\n\nexport function createRecoveryTag(recovery: KeyRecovery): string[] {\n return [\n 'r',\n recovery.recoveryPubkey,\n recovery.recoverySalt,\n recovery.createdAt?.toString() || '',\n recovery.signature || '',\n ];\n}\n\nexport function getRecoverySignature(kind0: Event): string | null {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return null;\n \n const tag = kind0.tags?.find(t => t[0] === 'r');\n return tag && tag.length > 4 ? tag[4] || null : null;\n}\n\nexport async function verifyRecoverySignature(kind0: Event): Promise<boolean> {\n try {\n const recovery = parseRecoveryTag(kind0.tags || []);\n if (!recovery) return false;\n \n const signature = getRecoverySignature(kind0);\n if (!signature || !kind0.pubkey) return false;\n \n // Verify Schnorr signature: signature over current pubkey (as message)\n // using the recovery pubkey\n // Note: verify expects the message hash, not the message itself\n const messageHash = await sha256(kind0.pubkey);\n const signatureBytes = hexToBytes(signature);\n const pubkeyBytes = hexToBytes(kind0.pubkey);\n \n return secp256k1.verify(signatureBytes, messageHash, pubkeyBytes);\n } catch (e) {\n return false;\n }\n}\n\nfunction sha256(message: string): Uint8Array {\n return nobleSha256(new TextEncoder().encode(message));\n}\n\n/**\n * Nosskey - Passkey-Derived Nostr Keys\n */\nexport class NosskeyManager implements NosskeyManagerLike {\n #keyCache: KeyCache;\n\n // KeyInfo\n #currentKeyInfo: KeyInfo | null = null;\n\n // KeyInfo\n #storageOptions: NostrKeyStorageOptions = {\n enabled: true,\n storageKey: 'nosskey_keyinfo',\n };\n\n // PRF\n #prfOptions: GetPrfSecretOptions = {};\n\n /**\n * NosskeyManager\n * @param options\n */\n constructor(options?: KeyManagerOptions) {\n // KeyCache\n this.#keyCache = new KeyCache(options?.cacheOptions);\n\n if (options?.storageOptions) {\n this.#storageOptions = { ...this.#storageOptions, ...options.storageOptions };\n }\n\n // option\n const userVerification = options?.prfOptions?.userVerification ?? 'required';\n if (options?.prfOptions) {\n this.#prfOptions = { ...options.prfOptions, userVerification };\n } else {\n this.#prfOptions = { userVerification };\n }\n\n // KeyInfo\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n }\n }\n }\n\n /**\n * KeyInfo\n * @param options\n */\n setStorageOptions(options: Partial<NostrKeyStorageOptions>): void {\n this.#storageOptions = { ...this.#storageOptions, ...options };\n\n if (options.enabled === false) {\n this.clearStoredKeyInfo();\n }\n }\n\n /**\n * KeyInfo\n */\n getStorageOptions(): NostrKeyStorageOptions {\n return { ...this.#storageOptions };\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n this.#currentKeyInfo = keyInfo;\n\n if (this.#storageOptions.enabled) {\n void this.#saveKeyInfoToStorage(keyInfo);\n }\n }\n\n /**\n * KeyInfo\n */\n getCurrentKeyInfo(): KeyInfo | null {\n // KeyInfo\n if (!this.#currentKeyInfo && this.#storageOptions.enabled) {\n this.#currentKeyInfo = this.#loadKeyInfoFromStorage();\n }\n return this.#currentKeyInfo;\n }\n\n /**\n * KeyInfo\n * @returns KeyInfo\n */\n hasKeyInfo(): boolean {\n if (this.#currentKeyInfo) {\n return true;\n }\n\n if (this.#storageOptions.enabled) {\n const loadedKeyInfo = this.#loadKeyInfoFromStorage();\n if (loadedKeyInfo) {\n this.#currentKeyInfo = loadedKeyInfo;\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * KeyInfo\n * @param keyInfo KeyInfo\n */\n async #saveKeyInfoToStorage(keyInfo: KeyInfo): Promise<void> {\n if (!this.#storageOptions.enabled) return;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.setItem(key, JSON.stringify(keyInfo));\n }\n\n /**\n * KeyInfo\n */\n #loadKeyInfoFromStorage(): KeyInfo | null {\n if (!this.#storageOptions.enabled) return null;\n\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return null;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n const data = storage.getItem(key);\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as KeyInfo;\n } catch (e) {\n console.error('Failed to parse stored KeyInfo', e);\n return null;\n }\n }\n\n /**\n * KeyInfo\n */\n clearStoredKeyInfo(): void {\n const storage =\n this.#storageOptions.storage || (typeof localStorage !== 'undefined' ? localStorage : null);\n\n if (!storage) return;\n\n const key = this.#storageOptions.storageKey || 'nosskey_keyinfo';\n storage.removeItem(key);\n\n // KeyInfo\n this.#currentKeyInfo = null;\n }\n\n /**\n * NIP-07\n * KeyInfo\n */\n async getPublicKey(): Promise<string> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return keyInfo.pubkey;\n }\n\n /**\n * NIP-07\n * KeyInfo\n * @param event Nostr\n */\n async signEvent(event: Event): Promise<Event> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n return this.signEventWithKeyInfo(event, keyInfo);\n }\n\n /**\n * @param options\n */\n setCacheOptions(options: Partial<KeyCacheOptions>): void {\n this.#keyCache.setCacheOptions(options);\n }\n\n getCacheOptions(): KeyCacheOptions {\n return this.#keyCache.getCacheOptions();\n }\n\n getCachedSecretKey(credentialId: Uint8Array | string): Uint8Array | undefined {\n return this.#keyCache.getKey(credentialId);\n }\n\n /**\n * @param credentialId\n */\n clearCachedKey(credentialId: Uint8Array | string): void {\n this.#keyCache.clearCachedKey(credentialId);\n }\n\n clearAllCachedKeys(): void {\n this.#keyCache.clearAllCachedKeys();\n }\n\n /**\n * @param options\n * @returns Credential\n */\n async createPasskey(options: PasskeyCreationOptions = {}): Promise<Uint8Array> {\n return createPasskey({\n rp: {\n id: this.#prfOptions.rpId,\n name: this.#prfOptions.rpId,\n },\n authenticatorSelection: {\n userVerification: this.#prfOptions.userVerification,\n },\n ...options,\n });\n }\n\n/**\n * Check if PRF is supported\n */\n async checkPRFSupport(): Promise<boolean> {\n return checkPRFSupport();\n }\n\n /**\n * Create Nostr key - automatically uses password fallback if PRF unavailable\n * @param credentialId Passkey credential ID\n * @param password Password for encryption (required if PRF not supported)\n * @param options \n */\n async createKey(credentialId?: Uint8Array, password?: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const prfSupported = await this.checkPRFSupport();\n \n let keyInfo: KeyInfo;\n \n if (prfSupported) {\n keyInfo = await this.createPrfNostrKey(credentialId, options);\n \n // Auto-add password recovery if requested and PRF is supported\n if (options.recoveryPassword) {\n keyInfo = await this.addPasswordRecovery(options.recoveryPassword, credentialId);\n }\n } else {\n if (!password) {\n throw new Error('Password is required when PRF is not supported');\n }\n if (!options.username) {\n throw new Error('Username is required when PRF is not supported');\n }\n keyInfo = await this.createPasswordProtectedNostrKey(password, options);\n }\n \n return keyInfo;\n }\n\n /**\n * Create Nostr key using PRF (standard passkey flow)\n */\n async createPrfNostrKey(credentialId?: Uint8Array, options: KeyOptions = {}): Promise<KeyInfo> {\n const { secret: sk, id: responseId } = await getPrfSecret(credentialId, this.#prfOptions);\n\n if (sk.every((byte) => byte === 0)) {\n throw new Error('Invalid PRF output: all zeros');\n }\n\n const skHex = bytesToHex(sk);\n const publicKey = getPublicKey(sk);\n \n const salt = await deriveSaltFromUsername(options.username);\n\n const keyInfo: KeyInfo = {\n credentialId: bytesToHex(credentialId || responseId),\n pubkey: publicKey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n if (this.#keyCache.isEnabled() && this.#keyCache.getCacheOptions().cacheOnCreation) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n\n return keyInfo;\n }\n\n /**\n * Create Nostr key using password-derived key (fallback when PRF unavailable)\n * @param password Password to derive the private key\n * @param options \n */\n async createPasswordProtectedNostrKey(password: string, options: KeyOptions = {}): Promise<KeyInfo> {\n const salt = await deriveSaltFromUsername(options.username);\n const pubkey = getPublicKeyFromPassword(password, salt);\n\n const credentialId = bytesToHex((typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto).getRandomValues(new Uint8Array(16)));\n\n const keyInfo: KeyInfo = {\n credentialId,\n pubkey: pubkey,\n salt: salt,\n ...(options.username && { username: options.username }),\n };\n\n return keyInfo;\n }\n\n/**\n * @param event Nostr\n * @param keyInfo KeyInfo\n * @param options\n */\n async signEventWithKeyInfo(\n event: Event,\n keyInfo: KeyInfo,\n options: SignOptions = {}\n ): Promise<Event> {\n const { clearMemory = true, tags, password } = options;\n\n const shouldUseCache = this.#keyCache.isEnabled();\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n\n let sk: Uint8Array | undefined;\n\n if (isPasswordDerived) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = deriveNostrPrivateKey(password, keyInfo.salt);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password to sign.');\n }\n } else if (keyInfo.passwordProtectedBundle) {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n if (!sk && password) {\n sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle!, password);\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n if (!sk) {\n throw new Error('Password required - key not in cache. Provide password or use createNostrKey to initialize.');\n }\n } else {\n if (shouldUseCache) {\n sk = this.#keyCache.getKey(keyInfo.credentialId);\n }\n\n if (!sk) {\n const { secret: prfSecret } = await getPrfSecret(\n hexToBytes(keyInfo.credentialId),\n this.#prfOptions\n );\n sk = prfSecret;\n\n if (shouldUseCache) {\n this.#keyCache.setKey(keyInfo.credentialId, sk);\n }\n }\n }\n\n const eventToSign = {\n kind: event.kind,\n content: event.content,\n created_at: event.created_at || Math.floor(Date.now() / 1000),\n tags: tags ? [...(event.tags || []), ...tags] : event.tags || [],\n };\n\n const signedEvent = finalizeEvent(eventToSign, sk);\n\n if (!shouldUseCache && clearMemory) {\n this.#clearKey(sk);\n }\n\n return signedEvent;\n }\n\n/**\n * @param keyInfo KeyInfo\n * @param credentialId KeyInfoのcredentialId\n * @param options\n * @returns \n */\n async exportNostrKey(keyInfo: KeyInfo, credentialId?: Uint8Array, options: KeyOptions = {}): Promise<string> {\n if (keyInfo.passwordProtectedBundle) {\n if (!options.password) {\n throw new Error('Password is required for password-protected keys');\n }\n const sk = await unwrapPasswordProtectedPrivateKey(keyInfo.passwordProtectedBundle, options.password);\n return bytesToHex(sk);\n }\n\n const isPasswordDerived = !keyInfo.passwordProtectedBundle && keyInfo.salt;\n if (isPasswordDerived) {\n if (!options.password) {\n throw new Error('Password is required for password-derived keys');\n }\n const sk = deriveNostrPrivateKey(options.password, keyInfo.salt);\n return bytesToHex(sk);\n }\n\n let usedCredentialId = credentialId;\n\n if (!usedCredentialId && keyInfo.credentialId) {\n usedCredentialId = hexToBytes(keyInfo.credentialId);\n }\n\n const { secret: sk } = await getPrfSecret(usedCredentialId, this.#prfOptions);\n const skHex = bytesToHex(sk);\n\n return skHex;\n }\n\n /**\n * PRF\n */\n async isPrfSupported(): Promise<boolean> {\n return isPrfSupported();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n * @param currentCredentialId Current passkey credential ID\n */\n async addPasswordRecovery(password: string, currentCredentialId?: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (keyInfo.passwordProtectedBundle) {\n throw new Error('Password recovery already exists for password-derived key');\n }\n\n if (keyInfo.recovery) {\n throw new Error('Recovery already configured');\n }\n\n const usedCredentialId = currentCredentialId || (keyInfo.credentialId ? hexToBytes(keyInfo.credentialId) : undefined);\n if (!usedCredentialId) {\n throw new Error('Credential ID required');\n }\n\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n\n // Generate recovery salt\n const recoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n\n // Derive recovery pubkey from password\n const recoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n\n // Sign current pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, keyInfo.pubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n ...keyInfo,\n recovery: {\n recoveryPubkey,\n recoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n #signWithKey(sk: Uint8Array, message: string): string {\n const event = finalizeEvent({\n kind: 0,\n content: '',\n tags: [],\n created_at: Math.floor(Date.now() / 1000),\n }, sk);\n return event.sig;\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo) {\n throw new Error('No current KeyInfo set');\n }\n\n if (!keyInfo.recovery) {\n throw new Error('No recovery key configured');\n }\n\n if (!newCredentialId) {\n throw new Error('New credential ID is required for recovery');\n }\n\n const { recoveryPubkey, recoverySalt } = keyInfo.recovery;\n\n // Verify password\n const derivedRecoveryPubkey = getPublicKeyFromPassword(password, recoverySalt);\n if (derivedRecoveryPubkey !== recoveryPubkey) {\n throw new Error('Invalid recovery password');\n }\n\n // Derive new key from new credential\n const { secret: newSk } = await getPrfSecret(newCredentialId, this.#prfOptions);\n const newPubkey = getPublicKey(newSk);\n this.#clearKey(newSk);\n\n // Generate new recovery for the new key\n const cryptoObj = typeof window !== 'undefined' ? window.crypto : (globalThis as any).crypto;\n const newRecoverySalt = bytesToHex(cryptoObj.getRandomValues(new Uint8Array(16)));\n const newRecoveryPubkey = getPublicKeyFromPassword(password, newRecoverySalt);\n\n // Sign new pubkey with recovery key\n const recoverySk = deriveNostrPrivateKey(password, recoverySalt);\n const signature = this.#signWithKey(recoverySk, newPubkey);\n this.#clearKey(recoverySk);\n\n const updatedKeyInfo: KeyInfo = {\n credentialId: bytesToHex(newCredentialId),\n pubkey: newPubkey,\n salt: keyInfo.salt,\n recovery: {\n recoveryPubkey: newRecoveryPubkey,\n recoverySalt: newRecoverySalt,\n createdAt: Date.now(),\n signature,\n },\n };\n\n this.setCurrentKeyInfo(updatedKeyInfo);\n return updatedKeyInfo;\n }\n\n /**\n * Get the recovery data for publishing to kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number; signature?: string } | null {\n const keyInfo = this.getCurrentKeyInfo();\n if (!keyInfo || !keyInfo.recovery) return null;\n\n return {\n recoveryPubkey: keyInfo.recovery.recoveryPubkey,\n recoverySalt: keyInfo.recovery.recoverySalt,\n createdAt: keyInfo.recovery.createdAt,\n signature: keyInfo.recovery.signature,\n };\n }\n\n /**\n * @param key\n */\n #clearKey(key: Uint8Array): void {\n key?.fill?.(0);\n }\n}\n","/**\n * Cryptographic utilities for Nosskey\n * @packageDocumentation\n */\n\nconst INFO_BYTES = new TextEncoder().encode('nostr-pwk');\nconst AES_LENGTH = 256; // bits\n\nfunction getSubtle(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('Web Crypto API not available');\n return subtle;\n}\n\n/**\n * PRF AES-GCM\n * @param secret PRF\n * @param salt\n * @returns AES-GCM\n */\nexport async function deriveAesGcmKey(secret: Uint8Array, salt: Uint8Array): Promise<CryptoKey> {\n const subtle = getSubtle();\n const keyMaterial = await subtle.importKey('raw', secret, 'HKDF', false, ['deriveKey']);\n\n return subtle.deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt, info: INFO_BYTES },\n keyMaterial,\n { name: 'AES-GCM', length: AES_LENGTH },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param plaintext\n * @returns\n */\nexport async function aesGcmEncrypt(key: CryptoKey, iv: Uint8Array, plaintext: Uint8Array) {\n const subtle = getSubtle();\n const buf = await subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);\n\n const bytes = new Uint8Array(buf);\n return {\n ciphertext: bytes.slice(0, -16),\n tag: bytes.slice(-16),\n };\n}\n\n/**\n * AES-GCM\n * @param key\n * @param iv\n * @param ct\n * @param tag\n * @returns\n */\nexport async function aesGcmDecrypt(\n key: CryptoKey,\n iv: Uint8Array,\n ct: Uint8Array,\n tag: Uint8Array\n): Promise<Uint8Array> {\n const subtle = getSubtle();\n const buf = await subtle.decrypt(\n { name: 'AES-GCM', iv },\n key,\n new Uint8Array([...ct, ...tag])\n );\n return new Uint8Array(buf);\n}\n","/**\n * Test utilities for sdk\n * @packageDocumentation\n */\n\n/**\n * Helper for testing/debugging\n * @param userId - User identifier\n * @returns Promise resolving to the dummy credential\n */\nexport async function registerDummyPasskey(userId: string): Promise<PublicKeyCredential> {\n // Create a dummy credential for testing\n const dummySignature = new Uint8Array(64);\n // Fill with some non-zero values for testing\n for (let i = 0; i < dummySignature.length; i++) {\n dummySignature[i] = (i + 1) % 256;\n }\n\n const dummyId = new Uint8Array(32);\n for (let i = 0; i < dummyId.length; i++) {\n dummyId[i] = (i + 1) % 256;\n }\n\n const credential = {\n id: 'dummy-credential-id',\n rawId: dummyId,\n type: 'public-key',\n response: {\n clientDataJSON: new Uint8Array(0),\n attestationObject: new Uint8Array(0),\n signature: dummySignature,\n authenticatorData: new Uint8Array(0),\n getAuthenticatorData: () => new Uint8Array(0),\n getPublicKey: () => new Uint8Array(0),\n getPublicKeyAlgorithm: () => -7,\n getTransports: () => ['internal'],\n },\n } as unknown as PublicKeyCredential;\n\n return credential;\n}\n","import { NosskeyManager, type KeyInfo, type Event, type PasskeyCreationOptions, type SignOptions, type KeyOptions } from '../utils';\nimport type { AuthServiceConfig } from '../types/auth';\n\n/**\n * Service wrapper around NosskeyManager\n * Handles WebAuthn/Passkey integration with Nostr\n */\nexport class AuthService {\n private manager: NosskeyManager | null = null;\n private config: AuthServiceConfig;\n\n constructor(config: AuthServiceConfig = {}) {\n this.config = {\n rpId: config.rpId || (typeof window !== 'undefined' ? window.location.hostname.replace(/^www\\./, '') : 'localhost'),\n rpName: config.rpName || this.getDefaultRpName(),\n storageKey: config.storageKey || 'nsauth_keyinfo',\n cacheTimeoutMs: config.cacheTimeoutMs || 30 * 60 * 1000,\n cacheOnCreation: config.cacheOnCreation !== undefined ? config.cacheOnCreation : true,\n };\n }\n\n private getDefaultRpName(): string {\n if (typeof window === 'undefined') return 'localhost';\n const hostname = window.location.hostname;\n if (hostname.includes('nosskey.app')) return 'nosskey.app';\n return hostname.replace(/^www\\./, '');\n }\n\n /**\n * Initialize the NosskeyManager instance\n */\n private getManager(): NosskeyManager {\n if (!this.manager) {\n this.manager = new NosskeyManager({\n cacheOptions: {\n enabled: true,\n timeoutMs: this.config.cacheTimeoutMs,\n cacheOnCreation: this.config.cacheOnCreation,\n },\n storageOptions: {\n enabled: true,\n storageKey: this.config.storageKey,\n },\n });\n }\n return this.manager;\n }\n\n /**\n * Create a new passkey\n * Uses platform authenticator only (Touch ID, Face ID, Windows Hello)\n */\n async createPasskey(username?: string): Promise<Uint8Array> {\n const manager = this.getManager();\n \n const rpId = this.config.rpId === 'localhost' ? 'localhost' : this.config.rpId;\n const rpName = this.config.rpName;\n \n const trimmedUsername = username?.trim();\n const uniqueUsername = trimmedUsername \n ? trimmedUsername \n : `user-${Date.now()}@example.com`;\n \n const options: PasskeyCreationOptions = {\n rp: {\n id: rpId,\n name: rpName,\n },\n user: {\n name: uniqueUsername,\n displayName: trimmedUsername || 'User',\n },\n authenticatorSelection: {\n authenticatorAttachment: 'platform',\n residentKey: 'preferred',\n userVerification: 'preferred',\n },\n extensions: {\n prf: {},\n },\n };\n \n return await manager.createPasskey(options);\n }\n\n/**\n * Create a new Nostr key from a credential ID\n * Automatically uses password fallback if PRF is not supported\n * @param credentialId Passkey credential ID\n * @param password Password (required if PRF not supported)\n * @param options.username Username for the key\n * @param options.recoveryPassword Password for recovery (enables recovery on new device)\n */\n async createKey(credentialId?: Uint8Array, password?: string, options?: KeyOptions): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.createKey(credentialId, password, options);\n }\n\n /**\n * Check if PRF is supported, otherwise password fallback is needed\n */\n async checkPRFSupport(): Promise<boolean> {\n const manager = this.getManager();\n return await manager.checkPRFSupport();\n }\n\n /**\n * Get the current public key\n */\n async getPublicKey(): Promise<string> {\n const manager = this.getManager();\n return await manager.getPublicKey();\n }\n\n /**\n * Sign a Nostr event\n */\n async signEvent(event: Event, options?: SignOptions): Promise<Event> {\n const manager = this.getManager();\n return await manager.signEvent(event, options);\n }\n\n /**\n * Get current key info\n */\n getCurrentKeyInfo(): KeyInfo | null {\n const manager = this.getManager();\n return manager.getCurrentKeyInfo();\n }\n\n /**\n * Set current key info\n */\n setCurrentKeyInfo(keyInfo: KeyInfo): void {\n const manager = this.getManager();\n manager.setCurrentKeyInfo(keyInfo);\n }\n\n /**\n * Check if key info exists\n */\n hasKeyInfo(): boolean {\n const manager = this.getManager();\n return manager.hasKeyInfo();\n }\n\n /**\n * Clear stored key info\n */\n clearStoredKeyInfo(): void {\n const manager = this.getManager();\n manager.clearStoredKeyInfo();\n }\n\n/**\n * Check if PRF is supported (legacy alias)\n */\n async isPrfSupported(): Promise<boolean> {\n return this.checkPRFSupport();\n }\n\n /**\n * Add password recovery to an existing PRF key\n * @param password Password for recovery key\n */\n async addPasswordRecovery(password: string): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.addPasswordRecovery(password);\n }\n\n /**\n * Activate recovery using password\n * Requires new credential ID from new device\n * @param password Password for recovery key\n * @param newCredentialId New passkey credential ID (required)\n */\n async activateWithPassword(password: string, newCredentialId: Uint8Array): Promise<KeyInfo> {\n const manager = this.getManager();\n return await manager.activateWithPassword(password, newCredentialId);\n }\n\n /**\n * Get recovery data for kind-0\n */\n getRecoveryForKind0(): { recoveryPubkey: string; recoverySalt: string; createdAt?: number } | null {\n const manager = this.getManager();\n return manager.getRecoveryForKind0();\n }\n}\n\n","export const MAX_ROLE_LENGTH = 100;\nconst ROLE_PATTERN = /^[a-zA-Z0-9\\s\\-_]+$/;\n\nexport const isValidRoleTag = (role: string): boolean => {\n const trimmed = role.trim();\n return (\n trimmed.length > 0 &&\n trimmed.length <= MAX_ROLE_LENGTH &&\n ROLE_PATTERN.test(trimmed)\n );\n};\n\nexport const isValidPubkey = (pubkey: string): boolean =>\n pubkey.length === 64 && /^[0-9a-fA-F]+$/.test(pubkey);\n\nexport const isValidHttpUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['http:', 'https:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n};\n\nexport const isValidRelayUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return ['ws:', 'wss:'].includes(parsed.protocol) && parsed.hostname.length > 0;\n } catch {\n return false;\n }\n};\n","import type { EventStore } from 'applesauce-core';\nimport type { Event } from '../types/nostr';\nimport type { ProfileMetadata, FollowEntry } from '../types/nostr';\nimport type { RelayServiceConfig } from '../types/auth';\nimport { isValidPubkey, isValidRelayUrl, isValidRoleTag } from '../utils/validation';\n\n/**\n * Service for communicating with Nostr relays using applesauce-core\n */\nexport class RelayService {\n private eventStore: EventStore | null = null;\n private relayUrls: string[];\n private defaultRelays = ['wss://relay.damus.io'];\n private readonly maxProfileContentSize = 10000;\n private readonly minProfileQueryIntervalMs = 300;\n private readonly minPublishIntervalMs = 750;\n private readonly lastActionAt = new Map<string, number>();\n\n constructor(config: RelayServiceConfig = {}) {\n this.relayUrls = this.validateRelayUrls(config.relayUrls ?? this.defaultRelays);\n }\n\n /**\n * Initialize with applesauce EventStore\n */\n initialize(eventStore: EventStore): void {\n this.eventStore = eventStore;\n // Set default relays if EventStore has a method for it\n if (eventStore && 'setRelays' in eventStore && typeof eventStore.setRelays === 'function') {\n (eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Set relay URLs\n */\n setRelays(urls: string[]): void {\n this.relayUrls = this.validateRelayUrls(urls);\n if (this.eventStore && 'setRelays' in this.eventStore && typeof this.eventStore.setRelays === 'function') {\n (this.eventStore as any).setRelays(this.relayUrls);\n }\n }\n\n /**\n * Get current relay URLs\n */\n getRelays(): string[] {\n return [...this.relayUrls];\n }\n\n /**\n * Publish an event to relays\n */\n async publishEvent(event: Event, timeoutMs = 1000): Promise<boolean> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('publish', this.minPublishIntervalMs);\n return new Promise((resolve, reject) => {\n if (this.relayUrls.length === 0) {\n reject(new Error('No relays configured'));\n return;\n }\n\n // Use EventStore's publish method\n // Note: This is a simplified implementation - actual applesauce API may differ\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.publish !== 'function') {\n reject(new Error('EventStore does not support publish method'));\n return;\n }\n const subscription = eventStore.publish(event).subscribe({\n next: (response: any) => {\n if (response?.type === 'OK') {\n subscription.unsubscribe();\n resolve(true);\n }\n },\n error: (error: Error) => {\n subscription.unsubscribe();\n reject(error);\n },\n });\n\n // Timeout fallback\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(false);\n }, timeoutMs);\n });\n }\n\n /**\n * Fetch a profile (Kind 0 event)\n */\n async fetchProfile(pubkey: string): Promise<ProfileMetadata | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-profile', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n subscription.unsubscribe();\n resolve(metadata);\n return;\n }\n console.error('Failed to parse profile metadata');\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n // Timeout\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch role tag from profile event (Kind 0)\n */\n async fetchProfileRoleTag(pubkey: string): Promise<string | null> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-role-tag', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [0],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(null);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0) {\n const tags = packet.event.tags || [];\n for (const tag of tags) {\n if (tag[0] === 'role' && tag[1]) {\n const candidate = tag[1].trim();\n if (isValidRoleTag(candidate)) {\n subscription.unsubscribe();\n resolve(candidate);\n return;\n }\n }\n }\n subscription.unsubscribe();\n resolve(null);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(null);\n },\n error: (error: Error) => {\n console.error('Error fetching profile role tag:', error);\n subscription.unsubscribe();\n resolve(null);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Fetch a follow list (Kind 3 event)\n */\n async fetchFollowList(pubkey: string): Promise<FollowEntry[]> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('fetch-follow-list', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const filter = {\n kinds: [3],\n authors: [pubkey],\n limit: 1,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve([]);\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 3) {\n const followList: FollowEntry[] = [];\n const tags = packet.event.tags || [];\n\n for (const tag of tags) {\n if (tag[0] === 'p' && tag[1]) {\n followList.push({\n pubkey: tag[1],\n relay: tag[2] || undefined,\n petname: tag[3] || undefined,\n });\n }\n }\n\n subscription.unsubscribe();\n resolve(followList);\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve([]);\n },\n error: (error: Error) => {\n console.error('Error fetching follow list:', error);\n subscription.unsubscribe();\n resolve([]);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve([]);\n }, 10000);\n });\n }\n\n /**\n * Fetch multiple profiles in batch\n */\n async fetchMultipleProfiles(pubkeys: string[]): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n if (pubkeys.length === 0) {\n return new Map();\n }\n\n await this.enforceRateLimit('fetch-multiple-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, ProfileMetadata>();\n const filter = {\n kinds: [0],\n authors: pubkeys,\n };\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n profiles.set(packet.event.pubkey, metadata);\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n resolve(profiles);\n },\n error: (error: Error) => {\n console.error('Error fetching profiles:', error);\n subscription.unsubscribe();\n resolve(profiles);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n resolve(profiles);\n }, 1000);\n });\n }\n\n /**\n * Query kind 0 events (profiles) by pubkey\n * If pubkeys array is empty, fetches recent kind 0 events\n */\n async queryProfiles(pubkeys: string[] = [], limit = 100): Promise<Map<string, ProfileMetadata>> {\n if (!this.eventStore) {\n throw new Error('RelayService not initialized. Call initialize() with an EventStore instance.');\n }\n\n await this.enforceRateLimit('query-profiles', this.minProfileQueryIntervalMs);\n return new Promise((resolve) => {\n const profiles = new Map<string, { metadata: ProfileMetadata; timestamp: number }>();\n const filter: any = {\n kinds: [0],\n limit,\n };\n\n if (pubkeys.length > 0) {\n filter.authors = pubkeys;\n }\n\n const eventStore = this.eventStore as any;\n if (!eventStore || typeof eventStore.query !== 'function') {\n resolve(new Map());\n return;\n }\n const subscription = eventStore.query(filter).subscribe({\n next: (packet: any) => {\n if (packet?.event && packet.event.kind === 0 && packet.event.pubkey) {\n const metadata = this.parseProfileMetadata(packet.event.content);\n if (metadata) {\n const timestamp = packet.event.created_at || 0;\n const existing = profiles.get(packet.event.pubkey);\n if (!existing || timestamp > existing.timestamp) {\n profiles.set(packet.event.pubkey, { metadata, timestamp });\n }\n } else {\n console.error('Failed to parse profile metadata');\n }\n }\n },\n complete: () => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n error: (error: Error) => {\n console.error('Error querying profiles:', error);\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n },\n });\n\n setTimeout(() => {\n subscription.unsubscribe();\n const result = new Map<string, ProfileMetadata>();\n profiles.forEach((value, pubkey) => {\n result.set(pubkey, value.metadata);\n });\n resolve(result);\n }, 10000);\n });\n }\n\n /**\n * Publish or update a kind 3 event (follow list/contacts)\n */\n async publishFollowList(\n pubkey: string,\n followList: FollowEntry[],\n signEvent: (event: Event) => Promise<Event>\n ): Promise<boolean> {\n const tags: string[][] = followList.map((entry) => {\n if (!isValidPubkey(entry.pubkey)) {\n throw new Error('Invalid pubkey format for follow list entry.');\n }\n if (entry.relay && !isValidRelayUrl(entry.relay)) {\n throw new Error('Invalid relay URL format for follow list entry.');\n }\n const tag: string[] = ['p', entry.pubkey];\n if (entry.relay) {\n tag.push(entry.relay);\n }\n if (entry.petname) {\n tag.push(entry.petname);\n }\n return tag;\n });\n\n const event: Event = {\n kind: 3,\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n tags,\n };\n\n const signedEvent = await signEvent(event);\n return await this.publishEvent(signedEvent);\n }\n\n private validateRelayUrls(urls: string[]): string[] {\n if (urls.length === 0) {\n return [];\n }\n const validUrls = urls.filter((url) => isValidRelayUrl(url));\n if (validUrls.length !== urls.length) {\n throw new Error('Invalid relay URL format');\n }\n return validUrls;\n }\n\n private parseProfileMetadata(content: string): ProfileMetadata | null {\n if (content.length > this.maxProfileContentSize) {\n return null;\n }\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n const metadata: ProfileMetadata = {};\n if (typeof (parsed as ProfileMetadata).name === 'string') {\n metadata.name = (parsed as ProfileMetadata).name;\n }\n if (typeof (parsed as ProfileMetadata).display_name === 'string') {\n metadata.display_name = (parsed as ProfileMetadata).display_name;\n }\n if (typeof (parsed as ProfileMetadata).about === 'string') {\n metadata.about = (parsed as ProfileMetadata).about;\n }\n if (typeof (parsed as ProfileMetadata).picture === 'string') {\n metadata.picture = (parsed as ProfileMetadata).picture;\n }\n if (typeof (parsed as ProfileMetadata).website === 'string') {\n metadata.website = (parsed as ProfileMetadata).website;\n }\n return metadata;\n } catch (error) {\n console.error('Failed to parse profile metadata:', error);\n return null;\n }\n }\n\n private async enforceRateLimit(action: string, minIntervalMs: number): Promise<void> {\n const lastAt = this.lastActionAt.get(action) ?? 0;\n const now = Date.now();\n const waitMs = minIntervalMs - (now - lastAt);\n if (waitMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n this.lastActionAt.set(action, Date.now());\n }\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;AAQA,SAAgB,WAAW,OAA2B;CACpD,MAAM,MAAM;CACZ,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,cAAc,MAAM,MAAM;EAChC,MAAM,eAAe,MAAM,KAAK;AAChC,SAAO,IAAI,eAAe,IAAI;;AAEhC,QAAO;;;;;;AAOT,SAAgB,WAAW,KAAyB;CAClD,MAAM,MAAM;CACZ,MAAM,QAAQ,EAAE;CAChB,IAAI,cAAc;CAClB,IAAI,aAAa;AAEjB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,YAAY,IAAI,QAAQ,IAAI,GAAG,aAAa,CAAC;AACnD,MAAI,cAAc,GAAI;AAEtB,MAAI,YAAY;AACd,iBAAc,aAAa;AAC3B,gBAAa;SACR;AACL,kBAAe;AACf,SAAM,KAAK,YAAY;AACvB,gBAAa;;;AAIjB,QAAO,IAAI,WAAW,MAAM;;;;;;;;ACvB9B,IAAa,WAAb,MAAsB;CACpB,eAAkC;CAElC,eAAsC;CAEtC,gBAAiC;EAC/B,SAAS;EACT,WAAW,MAAS;EACrB;;;;;CAMD,YAAY,SAAoC;AAC9C,MAAI,QACF,OAAKA,eAAgB;GAAE,GAAG,MAAKA;GAAe,GAAG;GAAS;;;;;CAO9D,gBAAgB,SAAyC;AACvD,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,KAAK,MAAKC,gBAAiB,KAC3D,MAAK,oBAAoB;AAG3B,QAAKD,eAAgB;GAAE,GAAG,MAAKA;GAAe,GAAG;GAAS;;CAG5D,kBAAmC;AACjC,SAAO,EAAE,GAAG,MAAKA,cAAe;;CAGlC,YAAqB;AACnB,SAAO,MAAKA,aAAc;;;;;;CAO5B,OAAO,cAAmC,IAAsB;AAC9D,MAAI,CAAC,MAAKA,aAAc,QAAS;EAEjC,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;EACrF,MAAM,UACJ,MAAKA,aAAc,cAAc,SAAY,MAAKA,aAAc,YAAY,MAAS;EACvF,MAAM,WAAW,KAAK,KAAK,GAAG;AAE9B,QAAKE,kBAAmB;AAExB,QAAKD,cAAe;GAClB;GACA,IAAI,IAAI,WAAW,GAAG;GACtB;GACD;AAED,MAAI;AACF,SAAKE,gBAAiB;WACf,OAAO;AACd,SAAKD,kBAAmB;AACxB,SAAM;;;;;;;CAQV,OAAO,cAA2D;AAChE,MAAI,CAAC,MAAKF,aAAc,QAAS,QAAO;EAExC,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;AACrF,SAAO,MAAKI,oBAAqB,GAAG;;;;;CAMtC,eAAe,cAAyC;EACtD,MAAM,KAAK,OAAO,iBAAiB,WAAW,eAAe,WAAW,aAAa;AAErF,MAAI,MAAKH,eAAgB,MAAKA,YAAa,OAAO,GAChD,OAAKC,kBAAmB;;CAI5B,qBAA2B;AACzB,QAAKA,kBAAmB;;;;;;CAO1B,qBAAqB,cAA8C;AACjE,MAAI,CAAC,MAAKD,eAAgB,MAAKA,YAAa,OAAO,aACjD;AAGF,MAAI,KAAK,KAAK,GAAG,MAAKA,YAAa,SACjC,QAAO,MAAKA,YAAa;AAG3B,QAAKC,kBAAmB;;CAI1B,oBAA0B;AACxB,MAAI,MAAKD,aAAc;AACrB,SAAKI,SAAU,MAAKJ,YAAa,GAAG;AACpC,SAAKA,cAAe;;AAGtB,MAAI,MAAKK,aAAc;AACrB,gBAAa,MAAKA,YAAa;AAC/B,SAAKA,cAAe;;;CAIxB,kBAAwB;AACtB,MAAI,CAAC,MAAKL,YAAc;EAExB,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,eAAe,MAAKA,YAAa,WAAW;AAElD,MAAI,gBAAgB,GAAG;AACrB,SAAKC,kBAAmB;AACxB;;AAGF,QAAKI,cAAe,iBAAiB;AACnC,SAAKJ,kBAAmB;KACvB,eAAe,EAAE;;;;;CAMtB,UAAU,KAAuB;AAC/B,OAAK,OAAO,EAAE;;;;;;AC3JlB,MAAM,iBAAiB,IAAI,aAAa,CAAC,OAAO,YAAY;;;;AAK5D,eAAsB,iBAAmC;AACvD,KAAI;EACF,MAAM,WAAW,MAAM,UAAU,YAAY,IAAI,EAC/C,WAAW;GACT,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;GACrD,kBAAkB,EAAE;GACpB,kBAAkB;GAClB,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,gBAAgB,EAAE,EAAE;GACzD,EACF,CAAC;AAEF,MAAI,CAAC,SAAU,QAAO;AAatB,SAAO,CAAC,CAXU,SAUI,2BAA2B,EAAE,KAAK,SAAS;SAE3D;AACN,SAAO;;;;;;;AAQX,eAAsB,cAAc,UAAkC,EAAE,EAAuB;CAE7F,MAAM,SAAS,QAAQ,IAAI,SAAS,OAAO,aAAa,cAAc,SAAS,OAAO;CACtF,MAAM,OAAO,QAAQ,IAAI;CACzB,MAAM,WAAW,QAAQ,MAAM,QAAQ;CACvC,MAAM,kBAAkB,QAAQ,MAAM,eAAe;CAErD,MAAM,4BAAuD,EAC3D,WAAW;EACT,IAAI;GACF,MAAM;GACN,IAAI;GACL;EACD,MAAM;GACJ,IAAI,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;GAC9C,MAAM;GACN,aAAa;GACd;EACD,kBAAkB,QAAQ,oBAAoB,CAAC;GAAE,MAAM;GAAc,KAAK;GAAI,CAAC;EAC/E,wBAAwB,QAAQ,0BAA0B;GACxD,aAAa;GACb,kBAAkB;GACnB;EACD,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;EACrD,YAAY,QAAQ,cAAc,EAAE,KAAK,EAAE,EAAE;EAC9C,EACF;CACD,MAAM,OAAQ,MAAM,UAAU,YAAY,OACxC,0BACD;AAED,QAAO,IAAI,WAAW,KAAK,MAAM;;;;;;;;AASnC,eAAsB,aACpB,cACA,SACiD;CACjD,MAAM,mBAAmB,eAAe,CAAC;EAAE,MAAM;EAAuB,IAAI;EAAc,CAAC,GAAG,EAAE;CAEhG,MAAM,iBAAoD;EACxD,WAAW,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;EACrD;EACA,kBAAkB,SAAS,oBAAoB;EAC/C,YAAY,EACV,KAAK,EAAE,MAAM,EAAE,OAAO,gBAAgB,EAAE,EACzC;EACF;AAED,KAAI,SAAS,KACX,gBAAe,OAAO,QAAQ;AAEhC,KAAI,SAAS,QACX,gBAAe,UAAU,QAAQ;CAGnC,MAAM,WAAW,MAAM,UAAU,YAAY,IAAI,EAC/C,WAAW,gBACZ,CAAC;AAEF,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,wBAAwB;CAa1C,MAAM,SAVY,SAUO,2BAA2B,EAAE,KAAK,SAAS;AACpE,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,2BAA2B;CAI7C,MAAM,aAAa,IAAI,WAAY,SAAiC,MAAM;AAE1E,QAAO;EACL,QAAQ,IAAI,WAAW,OAAO;EAC9B,IAAI;EACL;;;;;;;;;;;;;;ACzHH,MAAM,EAAE,gBAAgB,UAAU;AAClC,MAAM,SAAS;AASf,SAAS,SAAS,OAA2B;CAC3C,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,YAAY,IAAK,WAAU,OAAO,aAAa,MAAM,GAAG;AAClF,KAAI,OAAO,WAAW,eAAgB,OAAe,KACnD,QAAQ,OAAe,KAAK,OAAO;AAErC,QAAO,KAAK,OAAO;;AAGrB,SAAS,WAAW,KAAyB;AAC3C,KAAI,OAAO,WAAW,eAAgB,OAAe,MAAM;EACzD,MAAMK,QAAO,OAAe,KAAK,IAAI;EACrC,MAAMC,UAAQ,IAAI,WAAWD,MAAI,OAAO;AACxC,OAAK,IAAI,IAAI,GAAG,IAAIA,MAAI,QAAQ,IAAK,SAAM,KAAKA,MAAI,WAAW,EAAE;AACjE,SAAOC;;CAET,MAAM,MAAM,KAAK,IAAI;CACrB,MAAM,QAAQ,IAAI,WAAW,IAAI,OAAO;AACxC,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,OAAM,KAAK,IAAI,WAAW,EAAE;AACjE,QAAO;;AAGT,eAAsB,kBAAoC;AACxD,KAAI;EAEF,MAAM,aADO,OAAO,wBAAwB,cAAc,MAAM,oBAAoB,uBAAuB,GAAG,QACrF,qBAAqB;AAC9C,MAAI,UACF,SAAQ,IAAI,8BAA8B;MAE1C,SAAQ,IAAI,kCAAkC;AAEhD,SAAO,CAAC,CAAC;UACF,GAAG;AACV,UAAQ,IAAI,oCAAoC,EAAE;AAClD,SAAO;;;AAIX,eAAsB,6BAA6B,UAAoD;CACrG,MAAM,aAAa,UAAU,MAAM,kBAAkB;CAGrD,MAAM,sBAAsB,SAFV,UAAU,aAAa,YAAY,KAAK,CAEX;CAE/C,MAAM,OAAO,YAAY,GAAG;CAC5B,MAAM,aAAa,OAAO,QAAQ,IAAI,aAAa,CAAC,OAAO,SAAS,EAAE,MAAM;EAAE,GAAG;EAAQ,OAAO;EAAI,CAAC;CACrG,MAAM,KAAK,YAAY,GAAG;AAG1B,QAAO;EACL;EACA,yBAAyB,SAJhB,OAAO,YAAY,GAAG,CAAC,QAAQ,WAAW,CAId;EACrC,YAAY,SAAS,KAAK;EAC1B,UAAU,SAAS,GAAG;EACvB;;AAGH,eAAsB,kCAAkC,QAAiC,UAAuC;CAC9H,MAAM,OAAO,WAAW,OAAO,WAAW;CAC1C,MAAM,aAAa,OAAO,QAAQ,IAAI,aAAa,CAAC,OAAO,SAAS,EAAE,MAAM;EAAE,GAAG;EAAQ,OAAO;EAAI,CAAC;CACrG,MAAM,KAAK,WAAW,OAAO,SAAS;CACtC,MAAM,KAAK,WAAW,OAAO,wBAAwB;AAErD,QADmB,OAAO,YAAY,GAAG,CAAC,QAAQ,GAAG;;AAoBvD,SAAgB,0BAA0B,QAA6C;AAErF,QADa,WAAW,OAAO,oBAAoB;;AAIrD,MAAM,eAAe;AAErB,SAAgB,sBAAsB,UAAkB,OAAe,cAA0B;AAE/F,QADoB,OAAO,QAAQ,IAAI,aAAa,CAAC,OAAO,SAAS,EAAE,IAAI,aAAa,CAAC,OAAO,KAAK,EAAE;EAAE,GAAG;EAAQ,OAAO;EAAI,CAAC;;AAIlI,SAAgB,yBAAyB,UAAkB,OAAe,cAAsB;AAE9F,QAAO,aADI,sBAAsB,UAAU,KAAK,CACzB;;;;;;;;;ACjGzB,SAAgB,uBAAuB,UAA2B;AAChE,KAAI,CAAC,SACH,QAAO;CAIT,MAAM,aAAaC,OADD,IAAI,aAAa,CAAC,OAAO,SAAS,aAAa,CAAC,MAAM,CAAC,CAChC;AACzC,QAAO,WAAW,IAAI,WAAW,WAAW,CAAC;;AAG/C,SAAgB,iBAAiB,MAAsC;CACrE,MAAM,cAAc,KAAK,MAAK,QAAO,IAAI,OAAO,IAAI;AACpD,KAAI,CAAC,eAAe,YAAY,SAAS,EAAG,QAAO;CAGnD,MAAM,YAAY,YAAY,KAAK,SAAS,YAAY,IAAI,GAAG,GAAG;AAClE,QAAO;EACL,gBAAgB,YAAY;EAC5B,cAAc,YAAY;EAC1B,WAAW,aAAa;EACxB,WAAW,YAAY,MAAM;EAC9B;;AAGH,SAAgB,kBAAkB,UAAiC;AACjE,QAAO;EACL;EACA,SAAS;EACT,SAAS;EACT,SAAS,WAAW,UAAU,IAAI;EAClC,SAAS,aAAa;EACvB;;AAGH,SAAgB,qBAAqB,OAA6B;AAEhE,KAAI,CADa,iBAAiB,MAAM,QAAQ,EAAE,CAAC,CACpC,QAAO;CAEtB,MAAM,MAAM,MAAM,MAAM,MAAK,MAAK,EAAE,OAAO,IAAI;AAC/C,QAAO,OAAO,IAAI,SAAS,IAAI,IAAI,MAAM,OAAO;;AAGlD,eAAsB,wBAAwB,OAAgC;AAC5E,KAAI;AAEF,MAAI,CADa,iBAAiB,MAAM,QAAQ,EAAE,CAAC,CACpC,QAAO;EAEtB,MAAM,YAAY,qBAAqB,MAAM;AAC7C,MAAI,CAAC,aAAa,CAAC,MAAM,OAAQ,QAAO;EAKxC,MAAM,cAAc,MAAMC,SAAO,MAAM,OAAO;EAC9C,MAAM,iBAAiB,WAAW,UAAU;EAC5C,MAAM,cAAc,WAAW,MAAM,OAAO;AAE5C,SAAO,UAAU,OAAO,gBAAgB,aAAa,YAAY;UAC1D,GAAG;AACV,SAAO;;;AAIX,SAASA,SAAO,SAA6B;AAC3C,QAAOD,OAAY,IAAI,aAAa,CAAC,OAAO,QAAQ,CAAC;;;;;AAMvD,IAAa,iBAAb,MAA0D;CACxD;CAGA,kBAAkC;CAGlC,kBAA0C;EACxC,SAAS;EACT,YAAY;EACb;CAGD,cAAmC,EAAE;;;;;CAMrC,YAAY,SAA6B;AAEvC,QAAKE,WAAY,IAAI,SAAS,SAAS,aAAa;AAEpD,MAAI,SAAS,eACX,OAAKC,iBAAkB;GAAE,GAAG,MAAKA;GAAiB,GAAG,QAAQ;GAAgB;EAI/E,MAAM,mBAAmB,SAAS,YAAY,oBAAoB;AAClE,MAAI,SAAS,WACX,OAAKC,aAAc;GAAE,GAAG,QAAQ;GAAY;GAAkB;MAE9D,OAAKA,aAAc,EAAE,kBAAkB;AAIzC,MAAI,MAAKD,eAAgB,SAAS;GAChC,MAAM,gBAAgB,MAAKE,wBAAyB;AACpD,OAAI,cACF,OAAKC,iBAAkB;;;;;;;CAS7B,kBAAkB,SAAgD;AAChE,QAAKH,iBAAkB;GAAE,GAAG,MAAKA;GAAiB,GAAG;GAAS;AAE9D,MAAI,QAAQ,YAAY,MACtB,MAAK,oBAAoB;;;;;CAO7B,oBAA4C;AAC1C,SAAO,EAAE,GAAG,MAAKA,gBAAiB;;;;;;CAOpC,kBAAkB,SAAwB;AACxC,QAAKG,iBAAkB;AAEvB,MAAI,MAAKH,eAAgB,QACvB,CAAK,MAAKI,qBAAsB,QAAQ;;;;;CAO5C,oBAAoC;AAElC,MAAI,CAAC,MAAKD,kBAAmB,MAAKH,eAAgB,QAChD,OAAKG,iBAAkB,MAAKD,wBAAyB;AAEvD,SAAO,MAAKC;;;;;;CAOd,aAAsB;AACpB,MAAI,MAAKA,eACP,QAAO;AAGT,MAAI,MAAKH,eAAgB,SAAS;GAChC,MAAM,gBAAgB,MAAKE,wBAAyB;AACpD,OAAI,eAAe;AACjB,UAAKC,iBAAkB;AACvB,WAAO;;;AAIX,SAAO;;;;;;CAOT,OAAMC,qBAAsB,SAAiC;AAC3D,MAAI,CAAC,MAAKJ,eAAgB,QAAS;EAEnC,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS;EAEd,MAAM,MAAM,MAAKA,eAAgB,cAAc;AAC/C,UAAQ,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAC;;;;;CAM/C,0BAA0C;AACxC,MAAI,CAAC,MAAKA,eAAgB,QAAS,QAAO;EAE1C,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,MAAM,MAAKA,eAAgB,cAAc;EAC/C,MAAM,OAAO,QAAQ,QAAQ,IAAI;AAEjC,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACF,UAAO,KAAK,MAAM,KAAK;WAChB,GAAG;AACV,WAAQ,MAAM,kCAAkC,EAAE;AAClD,UAAO;;;;;;CAOX,qBAA2B;EACzB,MAAM,UACJ,MAAKA,eAAgB,YAAY,OAAO,iBAAiB,cAAc,eAAe;AAExF,MAAI,CAAC,QAAS;EAEd,MAAM,MAAM,MAAKA,eAAgB,cAAc;AAC/C,UAAQ,WAAW,IAAI;AAGvB,QAAKG,iBAAkB;;;;;;CAOzB,MAAM,eAAgC;EACpC,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAE3C,SAAO,QAAQ;;;;;;;CAQjB,MAAM,UAAU,OAA8B;EAC5C,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAE3C,SAAO,KAAK,qBAAqB,OAAO,QAAQ;;;;;CAMlD,gBAAgB,SAAyC;AACvD,QAAKJ,SAAU,gBAAgB,QAAQ;;CAGzC,kBAAmC;AACjC,SAAO,MAAKA,SAAU,iBAAiB;;CAGzC,mBAAmB,cAA2D;AAC5E,SAAO,MAAKA,SAAU,OAAO,aAAa;;;;;CAM5C,eAAe,cAAyC;AACtD,QAAKA,SAAU,eAAe,aAAa;;CAG7C,qBAA2B;AACzB,QAAKA,SAAU,oBAAoB;;;;;;CAOrC,MAAM,cAAc,UAAkC,EAAE,EAAuB;AAC7E,SAAO,cAAc;GACnB,IAAI;IACF,IAAI,MAAKE,WAAY;IACrB,MAAM,MAAKA,WAAY;IACxB;GACD,wBAAwB,EACtB,kBAAkB,MAAKA,WAAY,kBACpC;GACD,GAAG;GACJ,CAAC;;;;;CAMJ,MAAM,kBAAoC;AACxC,SAAO,iBAAiB;;;;;;;;CAS1B,MAAM,UAAU,cAA2B,UAAmB,UAAsB,EAAE,EAAoB;EACxG,MAAM,eAAe,MAAM,KAAK,iBAAiB;EAEjD,IAAI;AAEJ,MAAI,cAAc;AAChB,aAAU,MAAM,KAAK,kBAAkB,cAAc,QAAQ;AAG7D,OAAI,QAAQ,iBACV,WAAU,MAAM,KAAK,oBAAoB,QAAQ,kBAAkB,aAAa;SAE7E;AACL,OAAI,CAAC,SACH,OAAM,IAAI,MAAM,iDAAiD;AAEnE,OAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,iDAAiD;AAEnE,aAAU,MAAM,KAAK,gCAAgC,UAAU,QAAQ;;AAGzE,SAAO;;;;;CAMT,MAAM,kBAAkB,cAA2B,UAAsB,EAAE,EAAoB;EAC7F,MAAM,EAAE,QAAQ,IAAI,IAAI,eAAe,MAAM,aAAa,cAAc,MAAKA,WAAY;AAEzF,MAAI,GAAG,OAAO,SAAS,SAAS,EAAE,CAChC,OAAM,IAAI,MAAM,gCAAgC;AAGpC,aAAW,GAAG;EAC5B,MAAM,YAAY,aAAa,GAAG;EAElC,MAAM,OAAO,MAAM,uBAAuB,QAAQ,SAAS;EAE3D,MAAM,UAAmB;GACvB,cAAc,WAAW,gBAAgB,WAAW;GACpD,QAAQ;GACF;GACN,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,UAAU;GACvD;AAED,MAAI,MAAKF,SAAU,WAAW,IAAI,MAAKA,SAAU,iBAAiB,CAAC,gBACjE,OAAKA,SAAU,OAAO,QAAQ,cAAc,GAAG;AAGjD,SAAO;;;;;;;CAQT,MAAM,gCAAgC,UAAkB,UAAsB,EAAE,EAAoB;EAClG,MAAM,OAAO,MAAM,uBAAuB,QAAQ,SAAS;EAC3D,MAAM,SAAS,yBAAyB,UAAU,KAAK;AAWvD,SAPyB;GACvB,cAHmB,YAAY,OAAO,WAAW,cAAc,OAAO,SAAU,WAAmB,QAAQ,gBAAgB,IAAI,WAAW,GAAG,CAAC,CAAC;GAIvI;GACF;GACN,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,UAAU;GACvD;;;;;;;CAUH,MAAM,qBACJ,OACA,SACA,UAAuB,EAAE,EACT;EAChB,MAAM,EAAE,cAAc,MAAM,MAAM,aAAa;EAE/C,MAAM,iBAAiB,MAAKA,SAAU,WAAW;EACjD,MAAM,oBAAoB,CAAC,QAAQ,2BAA2B,QAAQ;EAEtE,IAAI;AAEJ,MAAI,mBAAmB;AACrB,OAAI,eACF,MAAK,MAAKA,SAAU,OAAO,QAAQ,aAAa;AAElD,OAAI,CAAC,MAAM,UAAU;AACnB,SAAK,sBAAsB,UAAU,QAAQ,KAAK;AAClD,QAAI,eACF,OAAKA,SAAU,OAAO,QAAQ,cAAc,GAAG;;AAGnD,OAAI,CAAC,GACH,OAAM,IAAI,MAAM,kEAAkE;aAE3E,QAAQ,yBAAyB;AAC1C,OAAI,eACF,MAAK,MAAKA,SAAU,OAAO,QAAQ,aAAa;AAElD,OAAI,CAAC,MAAM,UAAU;AACnB,SAAK,MAAM,kCAAkC,QAAQ,yBAA0B,SAAS;AACxF,QAAI,eACF,OAAKA,SAAU,OAAO,QAAQ,cAAc,GAAG;;AAGnD,OAAI,CAAC,GACH,OAAM,IAAI,MAAM,8FAA8F;SAE3G;AACL,OAAI,eACF,MAAK,MAAKA,SAAU,OAAO,QAAQ,aAAa;AAGlD,OAAI,CAAC,IAAI;IACP,MAAM,EAAE,QAAQ,cAAc,MAAM,aAClC,WAAW,QAAQ,aAAa,EAChC,MAAKE,WACN;AACD,SAAK;AAEL,QAAI,eACF,OAAKF,SAAU,OAAO,QAAQ,cAAc,GAAG;;;EAYrD,MAAM,cAAc,cAPA;GAClB,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,YAAY,MAAM,cAAc,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GAC7D,MAAM,OAAO,CAAC,GAAI,MAAM,QAAQ,EAAE,EAAG,GAAG,KAAK,GAAG,MAAM,QAAQ,EAAE;GACjE,EAE8C,GAAG;AAElD,MAAI,CAAC,kBAAkB,YACrB,OAAKM,SAAU,GAAG;AAGpB,SAAO;;;;;;;;CAST,MAAM,eAAe,SAAkB,cAA2B,UAAsB,EAAE,EAAmB;AAC3G,MAAI,QAAQ,yBAAyB;AACnC,OAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,mDAAmD;AAGrE,UAAO,WADI,MAAM,kCAAkC,QAAQ,yBAAyB,QAAQ,SAAS,CAChF;;AAIvB,MAD0B,CAAC,QAAQ,2BAA2B,QAAQ,MAC/C;AACrB,OAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,iDAAiD;AAGnE,UAAO,WADI,sBAAsB,QAAQ,UAAU,QAAQ,KAAK,CAC3C;;EAGvB,IAAI,mBAAmB;AAEvB,MAAI,CAAC,oBAAoB,QAAQ,aAC/B,oBAAmB,WAAW,QAAQ,aAAa;EAGrD,MAAM,EAAE,QAAQ,OAAO,MAAM,aAAa,kBAAkB,MAAKJ,WAAY;AAG7E,SAFc,WAAW,GAAG;;;;;CAQ9B,MAAM,iBAAmC;AACvC,SAAO,gBAAgB;;;;;;;CAQzB,MAAM,oBAAoB,UAAkB,qBAAoD;EAC9F,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAG3C,MAAI,QAAQ,wBACV,OAAM,IAAI,MAAM,4DAA4D;AAG9E,MAAI,QAAQ,SACV,OAAM,IAAI,MAAM,8BAA8B;AAIhD,MAAI,EADqB,wBAAwB,QAAQ,eAAe,WAAW,QAAQ,aAAa,GAAG,SAEzG,OAAM,IAAI,MAAM,yBAAyB;EAM3C,MAAM,eAAe,YAHH,OAAO,WAAW,cAAc,OAAO,SAAU,WAAmB,QAG5C,gBAAgB,IAAI,WAAW,GAAG,CAAC,CAAC;EAG9E,MAAM,iBAAiB,yBAAyB,UAAU,aAAa;EAGvE,MAAM,aAAa,sBAAsB,UAAU,aAAa;EAChE,MAAM,YAAY,MAAKK,YAAa,YAAY,QAAQ,OAAO;AAC/D,QAAKD,SAAU,WAAW;EAE1B,MAAM,iBAA0B;GAC9B,GAAG;GACH,UAAU;IACR;IACA;IACA,WAAW,KAAK,KAAK;IACrB;IACD;GACF;AAED,OAAK,kBAAkB,eAAe;AACtC,SAAO;;CAGT,aAAa,IAAgB,SAAyB;AAOpD,SANc,cAAc;GAC1B,MAAM;GACN,SAAS;GACT,MAAM,EAAE;GACR,YAAY,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GAC1C,EAAE,GAAG,CACO;;;;;;;;CASf,MAAM,qBAAqB,UAAkB,iBAA+C;EAC1F,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,yBAAyB;AAG3C,MAAI,CAAC,QAAQ,SACX,OAAM,IAAI,MAAM,6BAA6B;AAG/C,MAAI,CAAC,gBACH,OAAM,IAAI,MAAM,6CAA6C;EAG/D,MAAM,EAAE,gBAAgB,iBAAiB,QAAQ;AAIjD,MAD8B,yBAAyB,UAAU,aAAa,KAChD,eAC5B,OAAM,IAAI,MAAM,4BAA4B;EAI9C,MAAM,EAAE,QAAQ,UAAU,MAAM,aAAa,iBAAiB,MAAKJ,WAAY;EAC/E,MAAM,YAAY,aAAa,MAAM;AACrC,QAAKI,SAAU,MAAM;EAIrB,MAAM,kBAAkB,YADN,OAAO,WAAW,cAAc,OAAO,SAAU,WAAmB,QACzC,gBAAgB,IAAI,WAAW,GAAG,CAAC,CAAC;EACjF,MAAM,oBAAoB,yBAAyB,UAAU,gBAAgB;EAG7E,MAAM,aAAa,sBAAsB,UAAU,aAAa;EAChE,MAAM,YAAY,MAAKC,YAAa,YAAY,UAAU;AAC1D,QAAKD,SAAU,WAAW;EAE1B,MAAM,iBAA0B;GAC9B,cAAc,WAAW,gBAAgB;GACzC,QAAQ;GACR,MAAM,QAAQ;GACd,UAAU;IACR,gBAAgB;IAChB,cAAc;IACd,WAAW,KAAK,KAAK;IACrB;IACD;GACF;AAED,OAAK,kBAAkB,eAAe;AACtC,SAAO;;;;;CAMT,sBAAuH;EACrH,MAAM,UAAU,KAAK,mBAAmB;AACxC,MAAI,CAAC,WAAW,CAAC,QAAQ,SAAU,QAAO;AAE1C,SAAO;GACL,gBAAgB,QAAQ,SAAS;GACjC,cAAc,QAAQ,SAAS;GAC/B,WAAW,QAAQ,SAAS;GAC5B,WAAW,QAAQ,SAAS;GAC7B;;;;;CAMH,UAAU,KAAuB;AAC/B,OAAK,OAAO,EAAE;;;;;;;;;;AC3pBlB,MAAM,aAAa,IAAI,aAAa,CAAC,OAAO,YAAY;AACxD,MAAM,aAAa;AAEnB,SAAS,YAA0B;CACjC,MAAM,SAAS,WAAW,QAAQ;AAClC,KAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,+BAA+B;AAC5D,QAAO;;;;;;;;AAST,eAAsB,gBAAgB,QAAoB,MAAsC;CAC9F,MAAM,SAAS,WAAW;CAC1B,MAAM,cAAc,MAAM,OAAO,UAAU,OAAO,QAAQ,QAAQ,OAAO,CAAC,YAAY,CAAC;AAEvF,QAAO,OAAO,UACZ;EAAE,MAAM;EAAQ,MAAM;EAAW;EAAM,MAAM;EAAY,EACzD,aACA;EAAE,MAAM;EAAW,QAAQ;EAAY,EACvC,OACA,CAAC,WAAW,UAAU,CACvB;;;;;;;;;AAUH,eAAsB,cAAc,KAAgB,IAAgB,WAAuB;CAEzF,MAAM,MAAM,MADG,WAAW,CACD,QAAQ;EAAE,MAAM;EAAW;EAAI,EAAE,KAAK,UAAU;CAEzE,MAAM,QAAQ,IAAI,WAAW,IAAI;AACjC,QAAO;EACL,YAAY,MAAM,MAAM,GAAG,IAAI;EAC/B,KAAK,MAAM,MAAM,IAAI;EACtB;;;;;;;;;;AAWH,eAAsB,cACpB,KACA,IACA,IACA,KACqB;CAErB,MAAM,MAAM,MADG,WAAW,CACD,QACvB;EAAE,MAAM;EAAW;EAAI,EACvB,KACA,IAAI,WAAW,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAChC;AACD,QAAO,IAAI,WAAW,IAAI;;;;;;;;;;;;;;AC7D5B,eAAsB,qBAAqB,QAA8C;CAEvF,MAAM,iBAAiB,IAAI,WAAW,GAAG;AAEzC,MAAK,IAAI,IAAI,GAAG,IAAI,eAAe,QAAQ,IACzC,gBAAe,MAAM,IAAI,KAAK;CAGhC,MAAM,UAAU,IAAI,WAAW,GAAG;AAClC,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,SAAQ,MAAM,IAAI,KAAK;AAmBzB,QAhBmB;EACjB,IAAI;EACJ,OAAO;EACP,MAAM;EACN,UAAU;GACR,gBAAgB,IAAI,WAAW,EAAE;GACjC,mBAAmB,IAAI,WAAW,EAAE;GACpC,WAAW;GACX,mBAAmB,IAAI,WAAW,EAAE;GACpC,4BAA4B,IAAI,WAAW,EAAE;GAC7C,oBAAoB,IAAI,WAAW,EAAE;GACrC,6BAA6B;GAC7B,qBAAqB,CAAC,WAAW;GAClC;EACF;;;;;;;;;AC9BH,IAAa,cAAb,MAAyB;CAIvB,YAAY,SAA4B,EAAE,EAAE;iBAHH;AAIvC,OAAK,SAAS;GACZ,MAAM,OAAO,SAAS,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS,QAAQ,UAAU,GAAG,GAAG;GACvG,QAAQ,OAAO,UAAU,KAAK,kBAAkB;GAChD,YAAY,OAAO,cAAc;GACjC,gBAAgB,OAAO,kBAAkB,OAAU;GACnD,iBAAiB,OAAO,oBAAoB,SAAY,OAAO,kBAAkB;GAClF;;CAGH,AAAQ,mBAA2B;AACjC,MAAI,OAAO,WAAW,YAAa,QAAO;EAC1C,MAAM,WAAW,OAAO,SAAS;AACjC,MAAI,SAAS,SAAS,cAAc,CAAE,QAAO;AAC7C,SAAO,SAAS,QAAQ,UAAU,GAAG;;;;;CAMvC,AAAQ,aAA6B;AACnC,MAAI,CAAC,KAAK,QACR,MAAK,UAAU,IAAI,eAAe;GAChC,cAAc;IACZ,SAAS;IACT,WAAW,KAAK,OAAO;IACvB,iBAAiB,KAAK,OAAO;IAC9B;GACD,gBAAgB;IACd,SAAS;IACT,YAAY,KAAK,OAAO;IACzB;GACF,CAAC;AAEJ,SAAO,KAAK;;;;;;CAOd,MAAM,cAAc,UAAwC;EAC1D,MAAM,UAAU,KAAK,YAAY;EAEjC,MAAM,OAAO,KAAK,OAAO,SAAS,cAAc,cAAc,KAAK,OAAO;EAC1E,MAAM,SAAS,KAAK,OAAO;EAE3B,MAAM,kBAAkB,UAAU,MAAM;EACxC,MAAM,iBAAiB,kBACnB,kBACA,QAAQ,KAAK,KAAK,CAAC;EAEvB,MAAM,UAAkC;GACtC,IAAI;IACF,IAAI;IACJ,MAAM;IACP;GACD,MAAM;IACJ,MAAM;IACN,aAAa,mBAAmB;IACjC;GACD,wBAAwB;IACtB,yBAAyB;IACzB,aAAa;IACb,kBAAkB;IACnB;GACD,YAAY,EACV,KAAK,EAAE,EACR;GACF;AAED,SAAO,MAAM,QAAQ,cAAc,QAAQ;;;;;;;;;;CAW7C,MAAM,UAAU,cAA2B,UAAmB,SAAwC;AAEpG,SAAO,MADS,KAAK,YAAY,CACZ,UAAU,cAAc,UAAU,QAAQ;;;;;CAMjE,MAAM,kBAAoC;AAExC,SAAO,MADS,KAAK,YAAY,CACZ,iBAAiB;;;;;CAMxC,MAAM,eAAgC;AAEpC,SAAO,MADS,KAAK,YAAY,CACZ,cAAc;;;;;CAMrC,MAAM,UAAU,OAAc,SAAuC;AAEnE,SAAO,MADS,KAAK,YAAY,CACZ,UAAU,OAAO,QAAQ;;;;;CAMhD,oBAAoC;AAElC,SADgB,KAAK,YAAY,CAClB,mBAAmB;;;;;CAMpC,kBAAkB,SAAwB;AAExC,EADgB,KAAK,YAAY,CACzB,kBAAkB,QAAQ;;;;;CAMpC,aAAsB;AAEpB,SADgB,KAAK,YAAY,CAClB,YAAY;;;;;CAM7B,qBAA2B;AAEzB,EADgB,KAAK,YAAY,CACzB,oBAAoB;;;;;CAM9B,MAAM,iBAAmC;AACvC,SAAO,KAAK,iBAAiB;;;;;;CAO/B,MAAM,oBAAoB,UAAoC;AAE5D,SAAO,MADS,KAAK,YAAY,CACZ,oBAAoB,SAAS;;;;;;;;CASpD,MAAM,qBAAqB,UAAkB,iBAA+C;AAE1F,SAAO,MADS,KAAK,YAAY,CACZ,qBAAqB,UAAU,gBAAgB;;;;;CAMtE,sBAAmG;AAEjG,SADgB,KAAK,YAAY,CAClB,qBAAqB;;;;;;AC1LxC,MAAa,kBAAkB;AAC/B,MAAM,eAAe;AAErB,MAAa,kBAAkB,SAA0B;CACvD,MAAM,UAAU,KAAK,MAAM;AAC3B,QACE,QAAQ,SAAS,KACjB,QAAQ,UAAU,mBAClB,aAAa,KAAK,QAAQ;;AAI9B,MAAa,iBAAiB,WAC5B,OAAO,WAAW,MAAM,iBAAiB,KAAK,OAAO;AAWvD,MAAa,mBAAmB,QAAyB;AACvD,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,SAAO,CAAC,OAAO,OAAO,CAAC,SAAS,OAAO,SAAS,IAAI,OAAO,SAAS,SAAS;SACvE;AACN,SAAO;;;;;;;;;ACpBX,IAAa,eAAb,MAA0B;CASxB,YAAY,SAA6B,EAAE,EAAE;oBARL;uBAEhB,CAAC,uBAAuB;+BACP;mCACI;8BACL;sCACR,IAAI,KAAqB;AAGvD,OAAK,YAAY,KAAK,kBAAkB,OAAO,aAAa,KAAK,cAAc;;;;;CAMjF,WAAW,YAA8B;AACvC,OAAK,aAAa;AAElB,MAAI,cAAc,eAAe,cAAc,OAAO,WAAW,cAAc,WAC7E,CAAC,WAAmB,UAAU,KAAK,UAAU;;;;;CAOjD,UAAU,MAAsB;AAC9B,OAAK,YAAY,KAAK,kBAAkB,KAAK;AAC7C,MAAI,KAAK,cAAc,eAAe,KAAK,cAAc,OAAO,KAAK,WAAW,cAAc,WAC5F,CAAC,KAAK,WAAmB,UAAU,KAAK,UAAU;;;;;CAOtD,YAAsB;AACpB,SAAO,CAAC,GAAG,KAAK,UAAU;;;;;CAM5B,MAAM,aAAa,OAAc,YAAY,KAAwB;AACnE,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,WAAW,KAAK,qBAAqB;AACjE,SAAO,IAAI,SAAS,SAAS,WAAW;AACtC,OAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,2BAAO,IAAI,MAAM,uBAAuB,CAAC;AACzC;;GAKF,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,YAAY,YAAY;AAC3D,2BAAO,IAAI,MAAM,6CAA6C,CAAC;AAC/D;;GAEF,MAAM,eAAe,WAAW,QAAQ,MAAM,CAAC,UAAU;IACvD,OAAO,aAAkB;AACvB,SAAI,UAAU,SAAS,MAAM;AAC3B,mBAAa,aAAa;AAC1B,cAAQ,KAAK;;;IAGjB,QAAQ,UAAiB;AACvB,kBAAa,aAAa;AAC1B,YAAO,MAAM;;IAEhB,CAAC;AAGF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,MAAM;MACb,UAAU;IACb;;;;;CAMJ,MAAM,aAAa,QAAiD;AAClE,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,iBAAiB,KAAK,0BAA0B;AAC5E,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS,CAAC,OAAO;IACjB,OAAO;IACR;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,YAAQ,KAAK;AACb;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,GAAG;MAC5C,MAAM,WAAW,KAAK,qBAAqB,OAAO,MAAM,QAAQ;AAChE,UAAI,UAAU;AACZ,oBAAa,aAAa;AAC1B,eAAQ,SAAS;AACjB;;AAEF,cAAQ,MAAM,mCAAmC;;;IAGrD,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEf,QAAQ,UAAiB;AACvB,aAAQ,MAAM,2BAA2B,MAAM;AAC/C,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEhB,CAAC;AAGF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,KAAK;MACZ,IAAK;IACR;;;;;CAMJ,MAAM,oBAAoB,QAAwC;AAChE,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,kBAAkB,KAAK,0BAA0B;AAC7E,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS,CAAC,OAAO;IACjB,OAAO;IACR;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,YAAQ,KAAK;AACb;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,GAAG;MAC5C,MAAM,OAAO,OAAO,MAAM,QAAQ,EAAE;AACpC,WAAK,MAAM,OAAO,KAChB,KAAI,IAAI,OAAO,UAAU,IAAI,IAAI;OAC/B,MAAM,YAAY,IAAI,GAAG,MAAM;AAC/B,WAAI,eAAe,UAAU,EAAE;AAC7B,qBAAa,aAAa;AAC1B,gBAAQ,UAAU;AAClB;;;AAIN,mBAAa,aAAa;AAC1B,cAAQ,KAAK;;;IAGjB,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEf,QAAQ,UAAiB;AACvB,aAAQ,MAAM,oCAAoC,MAAM;AACxD,kBAAa,aAAa;AAC1B,aAAQ,KAAK;;IAEhB,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,KAAK;MACZ,IAAK;IACR;;;;;CAMJ,MAAM,gBAAgB,QAAwC;AAC5D,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,qBAAqB,KAAK,0BAA0B;AAChF,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS,CAAC,OAAO;IACjB,OAAO;IACR;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,YAAQ,EAAE,CAAC;AACX;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,GAAG;MAC5C,MAAM,aAA4B,EAAE;MACpC,MAAM,OAAO,OAAO,MAAM,QAAQ,EAAE;AAEpC,WAAK,MAAM,OAAO,KAChB,KAAI,IAAI,OAAO,OAAO,IAAI,GACxB,YAAW,KAAK;OACd,QAAQ,IAAI;OACZ,OAAO,IAAI,MAAM;OACjB,SAAS,IAAI,MAAM;OACpB,CAAC;AAIN,mBAAa,aAAa;AAC1B,cAAQ,WAAW;;;IAGvB,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,EAAE,CAAC;;IAEb,QAAQ,UAAiB;AACvB,aAAQ,MAAM,+BAA+B,MAAM;AACnD,kBAAa,aAAa;AAC1B,aAAQ,EAAE,CAAC;;IAEd,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,EAAE,CAAC;MACV,IAAM;IACT;;;;;CAMJ,MAAM,sBAAsB,SAA0D;AACpF,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,MAAI,QAAQ,WAAW,EACrB,wBAAO,IAAI,KAAK;AAGlB,QAAM,KAAK,iBAAiB,2BAA2B,KAAK,0BAA0B;AACtF,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,2BAAW,IAAI,KAA8B;GACnD,MAAM,SAAS;IACb,OAAO,CAAC,EAAE;IACV,SAAS;IACV;GAED,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,4BAAQ,IAAI,KAAK,CAAC;AAClB;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,KAAK,OAAO,MAAM,QAAQ;MACnE,MAAM,WAAW,KAAK,qBAAqB,OAAO,MAAM,QAAQ;AAChE,UAAI,SACF,UAAS,IAAI,OAAO,MAAM,QAAQ,SAAS;UAE3C,SAAQ,MAAM,mCAAmC;;;IAIvD,gBAAgB;AACd,kBAAa,aAAa;AAC1B,aAAQ,SAAS;;IAEnB,QAAQ,UAAiB;AACvB,aAAQ,MAAM,4BAA4B,MAAM;AAChD,kBAAa,aAAa;AAC1B,aAAQ,SAAS;;IAEpB,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;AAC1B,YAAQ,SAAS;MAChB,IAAK;IACR;;;;;;CAOJ,MAAM,cAAc,UAAoB,EAAE,EAAE,QAAQ,KAA4C;AAC9F,MAAI,CAAC,KAAK,WACR,OAAM,IAAI,MAAM,+EAA+E;AAGjG,QAAM,KAAK,iBAAiB,kBAAkB,KAAK,0BAA0B;AAC7E,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,2BAAW,IAAI,KAA+D;GACpF,MAAM,SAAc;IAClB,OAAO,CAAC,EAAE;IACV;IACD;AAED,OAAI,QAAQ,SAAS,EACnB,QAAO,UAAU;GAGnB,MAAM,aAAa,KAAK;AACxB,OAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AACzD,4BAAQ,IAAI,KAAK,CAAC;AAClB;;GAEF,MAAM,eAAe,WAAW,MAAM,OAAO,CAAC,UAAU;IACtD,OAAO,WAAgB;AACrB,SAAI,QAAQ,SAAS,OAAO,MAAM,SAAS,KAAK,OAAO,MAAM,QAAQ;MACnE,MAAM,WAAW,KAAK,qBAAqB,OAAO,MAAM,QAAQ;AAChE,UAAI,UAAU;OACZ,MAAM,YAAY,OAAO,MAAM,cAAc;OAC7C,MAAM,WAAW,SAAS,IAAI,OAAO,MAAM,OAAO;AAClD,WAAI,CAAC,YAAY,YAAY,SAAS,UACpC,UAAS,IAAI,OAAO,MAAM,QAAQ;QAAE;QAAU;QAAW,CAAC;YAG5D,SAAQ,MAAM,mCAAmC;;;IAIvD,gBAAgB;AACd,kBAAa,aAAa;KAC1B,MAAM,yBAAS,IAAI,KAA8B;AACjD,cAAS,SAAS,OAAO,WAAW;AAClC,aAAO,IAAI,QAAQ,MAAM,SAAS;OAClC;AACF,aAAQ,OAAO;;IAEjB,QAAQ,UAAiB;AACvB,aAAQ,MAAM,4BAA4B,MAAM;AAChD,kBAAa,aAAa;KAC1B,MAAM,yBAAS,IAAI,KAA8B;AACjD,cAAS,SAAS,OAAO,WAAW;AAClC,aAAO,IAAI,QAAQ,MAAM,SAAS;OAClC;AACF,aAAQ,OAAO;;IAElB,CAAC;AAEF,oBAAiB;AACf,iBAAa,aAAa;IAC1B,MAAM,yBAAS,IAAI,KAA8B;AACjD,aAAS,SAAS,OAAO,WAAW;AAClC,YAAO,IAAI,QAAQ,MAAM,SAAS;MAClC;AACF,YAAQ,OAAO;MACd,IAAM;IACT;;;;;CAMJ,MAAM,kBACJ,QACA,YACA,WACkB;EAClB,MAAM,OAAmB,WAAW,KAAK,UAAU;AACjD,OAAI,CAAC,cAAc,MAAM,OAAO,CAC9B,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAI,MAAM,SAAS,CAAC,gBAAgB,MAAM,MAAM,CAC9C,OAAM,IAAI,MAAM,kDAAkD;GAEpE,MAAM,MAAgB,CAAC,KAAK,MAAM,OAAO;AACzC,OAAI,MAAM,MACR,KAAI,KAAK,MAAM,MAAM;AAEvB,OAAI,MAAM,QACR,KAAI,KAAK,MAAM,QAAQ;AAEzB,UAAO;IACP;EASF,MAAM,cAAc,MAAM,UAPL;GACnB,MAAM;GACN,SAAS;GACT,YAAY,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GACzC;GACD,CAEyC;AAC1C,SAAO,MAAM,KAAK,aAAa,YAAY;;CAG7C,AAAQ,kBAAkB,MAA0B;AAClD,MAAI,KAAK,WAAW,EAClB,QAAO,EAAE;EAEX,MAAM,YAAY,KAAK,QAAQ,QAAQ,gBAAgB,IAAI,CAAC;AAC5D,MAAI,UAAU,WAAW,KAAK,OAC5B,OAAM,IAAI,MAAM,2BAA2B;AAE7C,SAAO;;CAGT,AAAQ,qBAAqB,SAAyC;AACpE,MAAI,QAAQ,SAAS,KAAK,sBACxB,QAAO;AAET,MAAI;GACF,MAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,OAAI,CAAC,UAAU,OAAO,WAAW,SAC/B,QAAO;GAET,MAAM,WAA4B,EAAE;AACpC,OAAI,OAAQ,OAA2B,SAAS,SAC9C,UAAS,OAAQ,OAA2B;AAE9C,OAAI,OAAQ,OAA2B,iBAAiB,SACtD,UAAS,eAAgB,OAA2B;AAEtD,OAAI,OAAQ,OAA2B,UAAU,SAC/C,UAAS,QAAS,OAA2B;AAE/C,OAAI,OAAQ,OAA2B,YAAY,SACjD,UAAS,UAAW,OAA2B;AAEjD,OAAI,OAAQ,OAA2B,YAAY,SACjD,UAAS,UAAW,OAA2B;AAEjD,UAAO;WACA,OAAO;AACd,WAAQ,MAAM,qCAAqC,MAAM;AACzD,UAAO;;;CAIX,MAAc,iBAAiB,QAAgB,eAAsC;EACnF,MAAM,SAAS,KAAK,aAAa,IAAI,OAAO,IAAI;EAEhD,MAAM,SAAS,iBADH,KAAK,KAAK,GACgB;AACtC,MAAI,SAAS,EACX,OAAM,IAAI,SAAS,YAAY,WAAW,SAAS,OAAO,CAAC;AAE7D,OAAK,aAAa,IAAI,QAAQ,KAAK,KAAK,CAAC"}
|