@renown/sdk 6.2.2-dev.6 → 6.2.2-dev.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +162 -1
  2. package/dist/{browser-key-storage-v4O-fjz0.js → browser-key-storage-e3RQsnLS.js} +1 -1
  3. package/dist/{browser-key-storage-v4O-fjz0.js.map → browser-key-storage-e3RQsnLS.js.map} +1 -1
  4. package/dist/constants-BexAR53F.js +82 -0
  5. package/dist/constants-BexAR53F.js.map +1 -0
  6. package/dist/crypto.d.ts +2 -2
  7. package/dist/crypto.js +2 -2
  8. package/dist/index-DNl6udpK.d.ts +131 -0
  9. package/dist/index-DNl6udpK.d.ts.map +1 -0
  10. package/dist/index.d.ts +11 -8
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +21 -9
  13. package/dist/index.js.map +1 -1
  14. package/dist/local-credential-verifier-C_XsxGgz.js +880 -0
  15. package/dist/local-credential-verifier-C_XsxGgz.js.map +1 -0
  16. package/dist/meta-BubXYEe3.d.ts +16 -0
  17. package/dist/meta-BubXYEe3.d.ts.map +1 -0
  18. package/dist/meta-CHgd9Qd0.js +31 -0
  19. package/dist/meta-CHgd9Qd0.js.map +1 -0
  20. package/dist/meta-CuSSO6OA.d.ts +19 -0
  21. package/dist/meta-CuSSO6OA.d.ts.map +1 -0
  22. package/dist/meta-D-5kvwx8.js +27 -0
  23. package/dist/meta-D-5kvwx8.js.map +1 -0
  24. package/dist/meta-HoXT6MS0.d.ts +19 -0
  25. package/dist/meta-HoXT6MS0.d.ts.map +1 -0
  26. package/dist/node.d.ts +11 -11
  27. package/dist/node.d.ts.map +1 -1
  28. package/dist/node.js +104 -12
  29. package/dist/node.js.map +1 -1
  30. package/dist/{signer-CgYhXTV7.js → signer-DrjINLqt.js} +13 -6
  31. package/dist/signer-DrjINLqt.js.map +1 -0
  32. package/dist/types-C_qc_62W.js +20 -0
  33. package/dist/types-C_qc_62W.js.map +1 -0
  34. package/dist/{signer-DYKGoYHB.d.ts → types-DVcz43Fb.d.ts} +170 -118
  35. package/dist/types-DVcz43Fb.d.ts.map +1 -0
  36. package/dist/types-b2fgIxlx.d.ts +59 -0
  37. package/dist/types-b2fgIxlx.d.ts.map +1 -0
  38. package/dist/{utils-C9ZgMs_C.d.ts → utils-CrNR-mv8.d.ts} +81 -94
  39. package/dist/utils-CrNR-mv8.d.ts.map +1 -0
  40. package/dist/wallet/index.d.ts +8 -0
  41. package/dist/wallet/index.d.ts.map +1 -0
  42. package/dist/wallet/index.js +30 -0
  43. package/dist/wallet/index.js.map +1 -0
  44. package/dist/wallet/mock/factory.d.ts +9 -0
  45. package/dist/wallet/mock/factory.d.ts.map +1 -0
  46. package/dist/wallet/mock/factory.js +35 -0
  47. package/dist/wallet/mock/factory.js.map +1 -0
  48. package/dist/wallet/mock/index.d.ts +9 -0
  49. package/dist/wallet/mock/index.d.ts.map +1 -0
  50. package/dist/wallet/mock/index.js +16 -0
  51. package/dist/wallet/mock/index.js.map +1 -0
  52. package/dist/wallet/privy/factory.d.ts +58 -0
  53. package/dist/wallet/privy/factory.d.ts.map +1 -0
  54. package/dist/wallet/privy/factory.js +258 -0
  55. package/dist/wallet/privy/factory.js.map +1 -0
  56. package/dist/wallet/privy/index.d.ts +9 -0
  57. package/dist/wallet/privy/index.d.ts.map +1 -0
  58. package/dist/wallet/privy/index.js +16 -0
  59. package/dist/wallet/privy/index.js.map +1 -0
  60. package/dist/wallet/rainbow/factory.d.ts +7 -0
  61. package/dist/wallet/rainbow/factory.d.ts.map +1 -0
  62. package/dist/wallet/rainbow/factory.js +219 -0
  63. package/dist/wallet/rainbow/factory.js.map +1 -0
  64. package/dist/wallet/rainbow/index.d.ts +9 -0
  65. package/dist/wallet/rainbow/index.d.ts.map +1 -0
  66. package/dist/wallet/rainbow/index.js +21 -0
  67. package/dist/wallet/rainbow/index.js.map +1 -0
  68. package/package.json +77 -4
  69. package/dist/browser-key-storage-DSkDBAhU.d.ts +0 -14
  70. package/dist/browser-key-storage-DSkDBAhU.d.ts.map +0 -1
  71. package/dist/renown-builder-Sn_Y2Cb2.js +0 -496
  72. package/dist/renown-builder-Sn_Y2Cb2.js.map +0 -1
  73. package/dist/signer-CgYhXTV7.js.map +0 -1
  74. package/dist/signer-DYKGoYHB.d.ts.map +0 -1
  75. package/dist/utils-C9ZgMs_C.d.ts.map +0 -1
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","names":["#filePath","#envKeyName","#logger","#parseKeyPair","#loadFromFile","#saveToFile","#emitter"],"sources":["../src/crypto/node-key-storage.ts","../src/event/event.node.ts","../src/storage/storage.node.ts","../src/init.node.ts","../src/login.node.ts"],"sourcesContent":["import {\n existsSync,\n mkdirSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ILogger } from \"../utils.js\";\nimport type { JsonWebKeyPairStorage, JwkKeyPair } from \"./types.js\";\n\nexport const RENOWN_PRIVATE_KEY_ENV = \"PH_RENOWN_PRIVATE_KEY\";\nexport const DEFAULT_KEYPAIR_PATH = \".ph/.keypair.json\";\n\n/**\n * Key storage that supports:\n * 1. PH_RENOWN_PRIVATE_KEY environment variable (JSON-encoded JwkKeyPair)\n * 2. Custom file path passed via options\n * 3. Falls back to file storage at .ph/.keypair.json in current working directory\n */\nexport class NodeKeyStorage implements JsonWebKeyPairStorage {\n #filePath: string;\n #envKeyName: string;\n #logger?: ILogger;\n\n static readonly DEFAULT_KEYPAIR_PATH = DEFAULT_KEYPAIR_PATH;\n static readonly RENOWN_PRIVATE_KEY_ENV = RENOWN_PRIVATE_KEY_ENV;\n\n constructor(\n filePath?: string,\n options: { envKeyName?: string; logger?: ILogger } = {},\n ) {\n this.#filePath = filePath || join(process.cwd(), DEFAULT_KEYPAIR_PATH);\n this.#envKeyName = options.envKeyName || RENOWN_PRIVATE_KEY_ENV;\n this.#logger = options.logger;\n\n // Ensure directory exists\n const dir = dirname(this.#filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n }\n\n loadKeyPair(): Promise<JwkKeyPair | undefined> {\n // First check environment variable\n const envKey = process.env[this.#envKeyName];\n if (envKey) {\n try {\n const keyPairJson = JSON.parse(envKey) as unknown;\n const keyPair: JwkKeyPair = this.#parseKeyPair(keyPairJson);\n\n // Validate it has the required structure\n this.#logger?.debug(\"Loaded keypair from environment variable\");\n return Promise.resolve(keyPair);\n } catch (e) {\n throw new Error(\n `Failed to parse ${this.#envKeyName}: ${e instanceof Error ? e.message : String(e)}`,\n {\n cause: e,\n },\n );\n }\n }\n\n // Fall back to file storage\n return Promise.resolve(this.#loadFromFile());\n }\n\n async saveKeyPair(keyPair: JwkKeyPair): Promise<void> {\n // Don't save if using env var\n if (process.env[this.#envKeyName]) {\n return;\n }\n\n // Save to file\n this.#saveToFile(keyPair);\n return Promise.resolve();\n }\n\n removeKeyPair(): Promise<void> {\n if (process.env[this.#envKeyName]) {\n delete process.env[this.#envKeyName];\n }\n if (existsSync(this.#filePath)) {\n unlinkSync(this.#filePath);\n }\n return Promise.resolve();\n }\n\n #loadFromFile(): JwkKeyPair | undefined {\n try {\n if (!existsSync(this.#filePath)) {\n return undefined;\n }\n const data = readFileSync(this.#filePath, \"utf-8\");\n const parsed = JSON.parse(data) as unknown;\n const keyPair: JwkKeyPair = this.#parseKeyPair(parsed);\n this.#logger?.debug(`Loaded keypair from ${this.#filePath}`);\n return keyPair;\n } catch (e) {\n throw new Error(\n `Failed to parse ${this.#filePath}: ${e instanceof Error ? e.message : String(e)}`,\n {\n cause: e,\n },\n );\n }\n }\n\n #saveToFile(keyPair: JwkKeyPair): void {\n const data = { keyPair };\n writeFileSync(this.#filePath, JSON.stringify(data, null, 2), \"utf-8\");\n this.#logger?.debug(`Saved keypair to ${this.#filePath}`);\n }\n\n #parseKeyPair(json: unknown): JwkKeyPair {\n if (typeof json !== \"object\") {\n throw new Error(\"Invalid keyPair format:\" + JSON.stringify(json));\n }\n\n const object = json as JwkKeyPair | { keyPair: JwkKeyPair };\n let keyPair: JwkKeyPair;\n if (\"keyPair\" in object) {\n keyPair = object.keyPair;\n } else {\n keyPair = object;\n }\n\n if (\"publicKey\" in keyPair && \"privateKey\" in keyPair) {\n return keyPair;\n } else {\n throw new Error(\"Invalid keyPair format:\" + JSON.stringify(json));\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport type { IEventEmitter } from \"./types.js\";\n\nexport class NodeEventEmitter<\n Events extends Record<string, unknown>,\n> implements IEventEmitter<Events> {\n #emitter = new EventEmitter();\n\n constructor() {\n this.#emitter.setMaxListeners(0);\n }\n\n on<K extends keyof Events>(\n event: K,\n listener: (data: Events[K]) => void,\n ): () => void {\n this.#emitter.on(event as string, listener);\n return () => {\n this.#emitter.removeListener(event.toString(), listener);\n };\n }\n\n emit<K extends keyof Events>(event: K, data: Events[K]): void {\n this.#emitter.emit(event.toString(), data);\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { BaseStorage } from \"./common.js\";\n\nexport class NodeStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n> extends BaseStorage<T> {\n private readonly filePath: string;\n\n constructor(filePath: string) {\n super();\n this.filePath = filePath;\n\n const parentFolder = dirname(this.filePath);\n mkdirSync(parentFolder, { recursive: true });\n\n if (!existsSync(this.filePath)) {\n writeFileSync(this.filePath, JSON.stringify({}));\n }\n }\n\n private readData(): T {\n const data = readFileSync(this.filePath, \"utf-8\");\n return JSON.parse(data) as T;\n }\n\n private writeData(data: T): void {\n writeFileSync(this.filePath, JSON.stringify(data, null, 2));\n }\n\n get<Key extends keyof T>(key: Key): T[Key] | undefined {\n const data = this.readData();\n return data[key];\n }\n\n set<Key extends keyof T>(key: Key, value?: T[Key]): void {\n const data = this.readData();\n if (value === undefined) {\n delete data[key];\n } else {\n data[key] = value;\n }\n this.writeData(data);\n }\n\n delete(key: keyof T): void {\n const data = this.readData();\n delete data[key];\n this.writeData(data);\n }\n}\n","import { NodeKeyStorage } from \"./crypto/node-key-storage.js\";\nimport { NodeEventEmitter } from \"./event/event.node.js\";\nimport { BaseRenownBuilder } from \"./renown-builder.js\";\nimport { NodeStorage } from \"./storage/storage.node.js\";\nimport type { RenownEvents, RenownStorageMap } from \"./types.js\";\n\nexport class NodeRenownEventEmitter extends NodeEventEmitter<RenownEvents> {}\nexport class NodeRenownStorage extends NodeStorage<RenownStorageMap> {}\n\nexport const DEFAULT_RENOWN_STORAGE_PATH = \"./.ph/.renown.json\";\n\nexport interface NodeRenownBuilderOptions {\n /** File path for user storage. Defaults to \".ph/.renown.json\" in cwd */\n storagePath?: string;\n /** File path for keypair storage. Defaults to \".ph/.keypair.json\" in cwd */\n keyPath?: string;\n /** Renown server URL. Defaults to https://www.renown.id */\n baseUrl?: string;\n}\n\n/**\n * Node.js-specific Renown builder with pre-configured defaults.\n * Uses file-based storage for both user data and key storage.\n */\nexport class RenownBuilder extends BaseRenownBuilder {\n /**\n * @param appName - Application name used for signing context\n * @param options - Node.js-specific configuration options\n */\n constructor(appName: string, options: NodeRenownBuilderOptions = {}) {\n super(appName);\n\n const {\n storagePath = DEFAULT_RENOWN_STORAGE_PATH,\n keyPath,\n baseUrl,\n } = options;\n\n this.withKeyPairStorage(new NodeKeyStorage(keyPath));\n this.withStorage(new NodeRenownStorage(storagePath));\n this.withEventEmitter(new NodeRenownEventEmitter());\n if (baseUrl) {\n this.withBaseUrl(baseUrl);\n }\n }\n}\n","import type { CreateBearerTokenOptions, IRenown, User } from \"./types.js\";\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\nconst POLL_INTERVAL_MS = 500; // 0.5s: session store is in-memory, cheap to poll\nconst SECONDS_IN_DAY = 24 * 60 * 60;\n\nexport interface BrowserLoginOptions {\n /** Renown server URL */\n renownUrl: string;\n /** Timeout in milliseconds. Defaults to 5 minutes. */\n timeoutMs?: number;\n /** Called with the login URL and session ID before the browser is opened */\n onLoginUrl?: (url: string, sessionId: string) => void;\n /** Called on each poll tick while waiting for authentication */\n onPollTick?: () => void;\n /** Called when the browser failed to open automatically */\n onBrowserOpenFailed?: (url: string) => void;\n /** AbortSignal to cancel the login flow */\n signal?: AbortSignal;\n}\n\nexport interface BrowserLoginResult {\n user: User;\n cliDid: string;\n}\n\nexport interface AuthStatusResult {\n authenticated: boolean;\n address?: string;\n userDid?: string;\n chainId?: number;\n cliDid: string;\n authenticatedAt?: Date;\n baseUrl: string;\n}\n\ninterface PendingSessionResponse {\n sessionId: string;\n status: \"pending\";\n}\n\ninterface ReadySessionResponse {\n sessionId: string;\n status: \"ready\";\n address: string;\n chainId: number;\n did: string;\n credentialId: string;\n userDocumentId: string;\n}\n\ntype SessionResponse = PendingSessionResponse | ReadySessionResponse;\n\nfunction abortReason(signal: AbortSignal): Error {\n if (signal.reason instanceof Error) return signal.reason;\n if (signal.reason) return new Error(String(signal.reason));\n return new DOMException(\"Aborted\", \"AbortError\");\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n return;\n }\n const onAbort = () => {\n clearTimeout(timer);\n reject(abortReason(signal!));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * Open a URL in the default browser (cross-platform).\n */\nexport async function openBrowser(url: string): Promise<void> {\n const { execFile } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const execFileAsync = promisify(execFile);\n const platform = process.platform;\n\n if (platform === \"darwin\") {\n await execFileAsync(\"open\", [url]);\n } else if (platform === \"win32\") {\n await execFileAsync(\"cmd\", [\"/c\", \"start\", \"\", url]);\n } else {\n await execFileAsync(\"xdg-open\", [url]);\n }\n}\n\nasync function pollSession(\n renownUrl: string,\n sessionId: string,\n timeoutMs: number,\n onPollTick?: () => void,\n signal?: AbortSignal,\n): Promise<ReadySessionResponse | null> {\n const startTime = Date.now();\n const sessionUrl = new URL(\n `/api/console/session/${sessionId}`,\n renownUrl,\n ).toString();\n\n while (Date.now() - startTime < timeoutMs) {\n signal?.throwIfAborted();\n try {\n const response = await fetch(sessionUrl, { signal });\n if (response.ok) {\n const data = (await response.json()) as SessionResponse;\n if (data.status === \"ready\") {\n return data;\n }\n }\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\")\n throw error;\n // Network error, will retry\n }\n onPollTick?.();\n await sleep(POLL_INTERVAL_MS, signal);\n }\n\n return null;\n}\n\n/**\n * Perform a browser-based login flow with Renown.\n * Opens the user's browser to authenticate, then polls for completion.\n * Throws if already authenticated or if the flow times out.\n * If the browser fails to open, the flow continues polling — callers\n * can use onBrowserOpenFailed to show the URL as a fallback.\n */\nexport async function browserLogin(\n renown: IRenown,\n options: BrowserLoginOptions,\n): Promise<BrowserLoginResult> {\n if (renown.user?.credential) {\n throw new Error(\n `Already authenticated as ${renown.user.address}. Logout first.`,\n );\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const sessionId = crypto.randomUUID();\n\n const loginUrl = new URL(\"/console\", options.renownUrl);\n loginUrl.searchParams.set(\"session\", sessionId);\n loginUrl.searchParams.set(\"connect\", renown.did);\n loginUrl.searchParams.set(\"app\", renown.did);\n\n const url = loginUrl.toString();\n options.onLoginUrl?.(url, sessionId);\n\n try {\n await openBrowser(url);\n } catch {\n options.onBrowserOpenFailed?.(url);\n }\n\n const result = await pollSession(\n options.renownUrl,\n sessionId,\n timeoutMs,\n options.onPollTick,\n options.signal,\n );\n\n if (!result) {\n throw new Error(\"Authentication timed out.\");\n }\n\n const user = await renown.login(result.did);\n return { user, cliDid: renown.did };\n}\n\n/**\n * Get the current authentication status from a Renown instance.\n */\nexport function getAuthStatus(renown: IRenown): AuthStatusResult {\n const user = renown.user;\n const credential = user?.credential;\n\n return {\n authenticated: !!credential,\n address: user?.address,\n userDid: user?.did,\n chainId: user?.chainId,\n cliDid: renown.did,\n authenticatedAt: credential ? new Date(credential.issuanceDate) : undefined,\n baseUrl: renown.baseUrl,\n };\n}\n\nexport interface AccessTokenResult {\n token: string;\n did: string;\n address: string;\n expiresIn: number;\n}\n\n/**\n * Generate a bearer token for API authentication.\n * Requires the user to be authenticated (via browserLogin or equivalent).\n * Throws if not authenticated.\n */\nexport async function generateAccessToken(\n renown: IRenown,\n options?: CreateBearerTokenOptions,\n): Promise<AccessTokenResult> {\n const user = renown.user;\n if (!user?.credential) {\n throw new Error(\n \"Not authenticated. Login first to generate access tokens.\",\n );\n }\n\n const token = await renown.getBearerToken(options ?? {});\n\n return {\n token,\n did: renown.did,\n address: user.address,\n expiresIn: options?.expiresIn ?? 0,\n };\n}\n\n/**\n * Parse a human-readable expiry string to seconds.\n * Supports formats: \"7d\" (days), \"24h\" (hours), \"3600\" (seconds), \"3600s\" (seconds).\n * Only accepts positive integers — decimals like \"1.5h\" are rejected.\n */\nexport function parseExpiry(expiry: string): number {\n const trimmed = expiry.trim().toLowerCase();\n const match = trimmed.match(/^(\\d+)(d|h|s)?$/);\n\n if (!match) {\n throw new Error(\n `Invalid expiry format: ${expiry}. Expected a positive integer with optional suffix: \"7d\", \"24h\", \"3600s\", or \"3600\".`,\n );\n }\n\n const value = Number(match[1]);\n const unit = match[2];\n\n if (value <= 0) {\n throw new Error(\n `Invalid expiry format: ${expiry}. Value must be a positive integer.`,\n );\n }\n\n switch (unit) {\n case \"d\":\n return value * SECONDS_IN_DAY;\n case \"h\":\n return value * 60 * 60;\n default:\n return value;\n }\n}\n\n/**\n * Format an expiry duration in seconds to a human-readable string.\n */\nexport function formatExpiry(expiresIn: number): string {\n const days = Math.floor(expiresIn / SECONDS_IN_DAY);\n const hours = Math.floor((expiresIn % SECONDS_IN_DAY) / 3600);\n\n if (days > 0) {\n const dayStr = `${days} day${days !== 1 ? \"s\" : \"\"}`;\n if (hours > 0) {\n return `${dayStr} and ${hours} hour${hours !== 1 ? \"s\" : \"\"}`;\n }\n return dayStr;\n }\n\n if (hours > 0) {\n return `${hours} hour${hours !== 1 ? \"s\" : \"\"}`;\n }\n\n return `${expiresIn} second${expiresIn !== 1 ? \"s\" : \"\"}`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"node.js","names":["#filePath","#envKeyName","#logger","#parseKeyPair","#loadFromFile","#saveToFile","#emitter","#revalidate"],"sources":["../src/crypto/node-key-storage.ts","../src/event/event.node.ts","../src/storage/storage.node.ts","../src/init.node.ts","../src/login.node.ts","../src/session.ts"],"sourcesContent":["import {\n existsSync,\n mkdirSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ILogger } from \"../utils.js\";\nimport type { JsonWebKeyPairStorage, JwkKeyPair } from \"./types.js\";\n\nexport const RENOWN_PRIVATE_KEY_ENV = \"PH_RENOWN_PRIVATE_KEY\";\nexport const DEFAULT_KEYPAIR_PATH = \".ph/.keypair.json\";\n\n/**\n * Key storage that supports:\n * 1. PH_RENOWN_PRIVATE_KEY environment variable (JSON-encoded JwkKeyPair)\n * 2. Custom file path passed via options\n * 3. Falls back to file storage at .ph/.keypair.json in current working directory\n */\nexport class NodeKeyStorage implements JsonWebKeyPairStorage {\n #filePath: string;\n #envKeyName: string;\n #logger?: ILogger;\n\n static readonly DEFAULT_KEYPAIR_PATH = DEFAULT_KEYPAIR_PATH;\n static readonly RENOWN_PRIVATE_KEY_ENV = RENOWN_PRIVATE_KEY_ENV;\n\n constructor(\n filePath?: string,\n options: { envKeyName?: string; logger?: ILogger } = {},\n ) {\n this.#filePath = filePath || join(process.cwd(), DEFAULT_KEYPAIR_PATH);\n this.#envKeyName = options.envKeyName || RENOWN_PRIVATE_KEY_ENV;\n this.#logger = options.logger;\n\n // Ensure directory exists\n const dir = dirname(this.#filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n }\n\n loadKeyPair(): Promise<JwkKeyPair | undefined> {\n // First check environment variable\n const envKey = process.env[this.#envKeyName];\n if (envKey) {\n try {\n const keyPairJson = JSON.parse(envKey) as unknown;\n const keyPair: JwkKeyPair = this.#parseKeyPair(keyPairJson);\n\n // Validate it has the required structure\n this.#logger?.debug(\"Loaded keypair from environment variable\");\n return Promise.resolve(keyPair);\n } catch (e) {\n throw new Error(\n `Failed to parse ${this.#envKeyName}: ${e instanceof Error ? e.message : String(e)}`,\n {\n cause: e,\n },\n );\n }\n }\n\n // Fall back to file storage\n return Promise.resolve(this.#loadFromFile());\n }\n\n async saveKeyPair(keyPair: JwkKeyPair): Promise<void> {\n // Don't save if using env var\n if (process.env[this.#envKeyName]) {\n return;\n }\n\n // Save to file\n this.#saveToFile(keyPair);\n return Promise.resolve();\n }\n\n removeKeyPair(): Promise<void> {\n if (process.env[this.#envKeyName]) {\n delete process.env[this.#envKeyName];\n }\n if (existsSync(this.#filePath)) {\n unlinkSync(this.#filePath);\n }\n return Promise.resolve();\n }\n\n #loadFromFile(): JwkKeyPair | undefined {\n try {\n if (!existsSync(this.#filePath)) {\n return undefined;\n }\n const data = readFileSync(this.#filePath, \"utf-8\");\n const parsed = JSON.parse(data) as unknown;\n const keyPair: JwkKeyPair = this.#parseKeyPair(parsed);\n this.#logger?.debug(`Loaded keypair from ${this.#filePath}`);\n return keyPair;\n } catch (e) {\n throw new Error(\n `Failed to parse ${this.#filePath}: ${e instanceof Error ? e.message : String(e)}`,\n {\n cause: e,\n },\n );\n }\n }\n\n #saveToFile(keyPair: JwkKeyPair): void {\n const data = { keyPair };\n writeFileSync(this.#filePath, JSON.stringify(data, null, 2), \"utf-8\");\n this.#logger?.debug(`Saved keypair to ${this.#filePath}`);\n }\n\n #parseKeyPair(json: unknown): JwkKeyPair {\n if (typeof json !== \"object\") {\n throw new Error(\"Invalid keyPair format:\" + JSON.stringify(json));\n }\n\n const object = json as JwkKeyPair | { keyPair: JwkKeyPair };\n let keyPair: JwkKeyPair;\n if (\"keyPair\" in object) {\n keyPair = object.keyPair;\n } else {\n keyPair = object;\n }\n\n if (\"publicKey\" in keyPair && \"privateKey\" in keyPair) {\n return keyPair;\n } else {\n throw new Error(\"Invalid keyPair format:\" + JSON.stringify(json));\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport type { IEventEmitter } from \"./types.js\";\n\nexport class NodeEventEmitter<\n Events extends Record<string, unknown>,\n> implements IEventEmitter<Events> {\n #emitter = new EventEmitter();\n\n constructor() {\n this.#emitter.setMaxListeners(0);\n }\n\n on<K extends keyof Events>(\n event: K,\n listener: (data: Events[K]) => void,\n ): () => void {\n this.#emitter.on(event as string, listener);\n return () => {\n this.#emitter.removeListener(event.toString(), listener);\n };\n }\n\n emit<K extends keyof Events>(event: K, data: Events[K]): void {\n this.#emitter.emit(event.toString(), data);\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { BaseStorage } from \"./common.js\";\n\nexport class NodeStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n> extends BaseStorage<T> {\n private readonly filePath: string;\n\n constructor(filePath: string) {\n super();\n this.filePath = filePath;\n\n const parentFolder = dirname(this.filePath);\n mkdirSync(parentFolder, { recursive: true });\n\n if (!existsSync(this.filePath)) {\n writeFileSync(this.filePath, JSON.stringify({}));\n }\n }\n\n private readData(): T {\n const data = readFileSync(this.filePath, \"utf-8\");\n return JSON.parse(data) as T;\n }\n\n private writeData(data: T): void {\n writeFileSync(this.filePath, JSON.stringify(data, null, 2));\n }\n\n get<Key extends keyof T>(key: Key): T[Key] | undefined {\n const data = this.readData();\n return data[key];\n }\n\n set<Key extends keyof T>(key: Key, value?: T[Key]): void {\n const data = this.readData();\n if (value === undefined) {\n delete data[key];\n } else {\n data[key] = value;\n }\n this.writeData(data);\n }\n\n delete(key: keyof T): void {\n const data = this.readData();\n delete data[key];\n this.writeData(data);\n }\n}\n","import type { Renown } from \"./common.js\";\nimport { NodeKeyStorage } from \"./crypto/node-key-storage.js\";\nimport { NodeEventEmitter } from \"./event/event.node.js\";\nimport { BaseRenownBuilder } from \"./renown-builder.js\";\nimport { NodeStorage } from \"./storage/storage.node.js\";\nimport type { RenownEvents, RenownStorageMap } from \"./types.js\";\n\nexport class NodeRenownEventEmitter extends NodeEventEmitter<RenownEvents> {}\nexport class NodeRenownStorage extends NodeStorage<RenownStorageMap> {}\n\nexport const DEFAULT_RENOWN_STORAGE_PATH = \"./.ph/.renown.json\";\n\nexport interface NodeRenownBuilderOptions {\n /** File path for user storage. Defaults to \".ph/.renown.json\" in cwd */\n storagePath?: string;\n /** File path for keypair storage. Defaults to \".ph/.keypair.json\" in cwd */\n keyPath?: string;\n /** Renown server URL. Defaults to https://www.renown.id */\n baseUrl?: string;\n /** Switchboard GraphQL endpoint for the direct-to-reactor flow. */\n switchboardUrl?: string;\n /** Re-check a stored credential on build (default \"always\"). */\n revalidate?: \"always\" | \"never\";\n}\n\n/** Node.js Renown builder: file-based user + key storage. */\nexport class RenownBuilder extends BaseRenownBuilder {\n #revalidate: \"always\" | \"never\";\n\n constructor(appName: string, options: NodeRenownBuilderOptions = {}) {\n super(appName);\n\n const {\n storagePath = DEFAULT_RENOWN_STORAGE_PATH,\n keyPath,\n baseUrl,\n switchboardUrl,\n revalidate = \"always\",\n } = options;\n\n this.#revalidate = revalidate;\n this.withKeyPairStorage(new NodeKeyStorage(keyPath));\n this.withStorage(new NodeRenownStorage(storagePath));\n this.withEventEmitter(new NodeRenownEventEmitter());\n if (baseUrl) {\n this.withBaseUrl(baseUrl);\n }\n if (switchboardUrl) {\n this.withSwitchboardUrl(switchboardUrl);\n }\n }\n\n // Node scripts/CLI act on auth state once and exit, so revalidation must\n // finish before build() resolves — block on it (unlike the browser builder).\n async build(): Promise<Renown> {\n const renown = await super.build();\n if (this.#revalidate === \"always\" && renown.user) {\n await renown.revalidate();\n }\n return renown;\n }\n}\n","import type { CreateBearerTokenOptions, IRenown, User } from \"./types.js\";\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\nconst POLL_INTERVAL_MS = 500; // 0.5s: session store is in-memory, cheap to poll\nconst SECONDS_IN_DAY = 24 * 60 * 60;\n\nexport interface BrowserLoginOptions {\n /** Renown server URL */\n renownUrl: string;\n /** Timeout in milliseconds. Defaults to 5 minutes. */\n timeoutMs?: number;\n /** Called with the login URL and session ID before the browser is opened */\n onLoginUrl?: (url: string, sessionId: string) => void;\n /** Called on each poll tick while waiting for authentication */\n onPollTick?: () => void;\n /** Called when the browser failed to open automatically */\n onBrowserOpenFailed?: (url: string) => void;\n /** AbortSignal to cancel the login flow */\n signal?: AbortSignal;\n}\n\nexport interface BrowserLoginResult {\n user: User;\n cliDid: string;\n}\n\nexport interface AuthStatusResult {\n authenticated: boolean;\n address?: string;\n userDid?: string;\n chainId?: number;\n cliDid: string;\n authenticatedAt?: Date;\n baseUrl: string;\n}\n\ninterface PendingSessionResponse {\n sessionId: string;\n status: \"pending\";\n}\n\ninterface ReadySessionResponse {\n sessionId: string;\n status: \"ready\";\n address: string;\n chainId: number;\n did: string;\n credentialId: string;\n userDocumentId: string;\n}\n\ntype SessionResponse = PendingSessionResponse | ReadySessionResponse;\n\nfunction abortReason(signal: AbortSignal): Error {\n if (signal.reason instanceof Error) return signal.reason;\n if (signal.reason) return new Error(String(signal.reason));\n return new DOMException(\"Aborted\", \"AbortError\");\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n return;\n }\n const onAbort = () => {\n clearTimeout(timer);\n reject(abortReason(signal!));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * Open a URL in the default browser (cross-platform).\n */\nexport async function openBrowser(url: string): Promise<void> {\n const { execFile } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const execFileAsync = promisify(execFile);\n const platform = process.platform;\n\n if (platform === \"darwin\") {\n await execFileAsync(\"open\", [url]);\n } else if (platform === \"win32\") {\n await execFileAsync(\"cmd\", [\"/c\", \"start\", \"\", url]);\n } else {\n await execFileAsync(\"xdg-open\", [url]);\n }\n}\n\nasync function pollSession(\n renownUrl: string,\n sessionId: string,\n timeoutMs: number,\n onPollTick?: () => void,\n signal?: AbortSignal,\n): Promise<ReadySessionResponse | null> {\n const startTime = Date.now();\n const sessionUrl = new URL(\n `/api/console/session/${sessionId}`,\n renownUrl,\n ).toString();\n\n while (Date.now() - startTime < timeoutMs) {\n signal?.throwIfAborted();\n try {\n const response = await fetch(sessionUrl, { signal });\n if (response.ok) {\n const data = (await response.json()) as SessionResponse;\n if (data.status === \"ready\") {\n return data;\n }\n }\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\")\n throw error;\n // Network error, will retry\n }\n onPollTick?.();\n await sleep(POLL_INTERVAL_MS, signal);\n }\n\n return null;\n}\n\n/**\n * Perform a browser-based login flow with Renown.\n * Opens the user's browser to authenticate, then polls for completion.\n * Throws if already authenticated or if the flow times out.\n * If the browser fails to open, the flow continues polling — callers\n * can use onBrowserOpenFailed to show the URL as a fallback.\n */\nexport async function browserLogin(\n renown: IRenown,\n options: BrowserLoginOptions,\n): Promise<BrowserLoginResult> {\n if (renown.user?.credential) {\n throw new Error(\n `Already authenticated as ${renown.user.address}. Logout first.`,\n );\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const sessionId = crypto.randomUUID();\n\n const loginUrl = new URL(\"/console\", options.renownUrl);\n loginUrl.searchParams.set(\"session\", sessionId);\n loginUrl.searchParams.set(\"connect\", renown.did);\n loginUrl.searchParams.set(\"app\", renown.did);\n\n const url = loginUrl.toString();\n options.onLoginUrl?.(url, sessionId);\n\n try {\n await openBrowser(url);\n } catch {\n options.onBrowserOpenFailed?.(url);\n }\n\n const result = await pollSession(\n options.renownUrl,\n sessionId,\n timeoutMs,\n options.onPollTick,\n options.signal,\n );\n\n if (!result) {\n throw new Error(\"Authentication timed out.\");\n }\n\n const user = await renown.login(result.did);\n return { user, cliDid: renown.did };\n}\n\n/**\n * Get the current authentication status from a Renown instance.\n */\nexport function getAuthStatus(renown: IRenown): AuthStatusResult {\n const user = renown.user;\n const credential = user?.credential;\n\n return {\n authenticated: !!credential,\n address: user?.address,\n userDid: user?.did,\n chainId: user?.chainId,\n cliDid: renown.did,\n authenticatedAt: credential ? new Date(credential.issuanceDate) : undefined,\n baseUrl: renown.baseUrl,\n };\n}\n\nexport interface AccessTokenResult {\n token: string;\n did: string;\n address: string;\n expiresIn: number;\n}\n\n/**\n * Generate a bearer token for API authentication.\n * Requires the user to be authenticated (via browserLogin or equivalent).\n * Throws if not authenticated.\n */\nexport async function generateAccessToken(\n renown: IRenown,\n options?: CreateBearerTokenOptions,\n): Promise<AccessTokenResult> {\n const user = renown.user;\n if (!user?.credential) {\n throw new Error(\n \"Not authenticated. Login first to generate access tokens.\",\n );\n }\n\n const token = await renown.getBearerToken(options ?? {});\n\n return {\n token,\n did: renown.did,\n address: user.address,\n expiresIn: options?.expiresIn ?? 0,\n };\n}\n\n/**\n * Parse a human-readable expiry string to seconds.\n * Supports formats: \"7d\" (days), \"24h\" (hours), \"3600\" (seconds), \"3600s\" (seconds).\n * Only accepts positive integers — decimals like \"1.5h\" are rejected.\n */\nexport function parseExpiry(expiry: string): number {\n const trimmed = expiry.trim().toLowerCase();\n const match = trimmed.match(/^(\\d+)(d|h|s)?$/);\n\n if (!match) {\n throw new Error(\n `Invalid expiry format: ${expiry}. Expected a positive integer with optional suffix: \"7d\", \"24h\", \"3600s\", or \"3600\".`,\n );\n }\n\n const value = Number(match[1]);\n const unit = match[2];\n\n if (value <= 0) {\n throw new Error(\n `Invalid expiry format: ${expiry}. Value must be a positive integer.`,\n );\n }\n\n switch (unit) {\n case \"d\":\n return value * SECONDS_IN_DAY;\n case \"h\":\n return value * 60 * 60;\n default:\n return value;\n }\n}\n\n/**\n * Format an expiry duration in seconds to a human-readable string.\n */\nexport function formatExpiry(expiresIn: number): string {\n const days = Math.floor(expiresIn / SECONDS_IN_DAY);\n const hours = Math.floor((expiresIn % SECONDS_IN_DAY) / 3600);\n\n if (days > 0) {\n const dayStr = `${days} day${days !== 1 ? \"s\" : \"\"}`;\n if (hours > 0) {\n return `${dayStr} and ${hours} hour${hours !== 1 ? \"s\" : \"\"}`;\n }\n return dayStr;\n }\n\n if (hours > 0) {\n return `${hours} hour${hours !== 1 ? \"s\" : \"\"}`;\n }\n\n return `${expiresIn} second${expiresIn !== 1 ? \"s\" : \"\"}`;\n}\n","import { verifyAuthCredential } from \"./credential.js\";\nimport type { User } from \"./types.js\";\nimport { verifyAuthBearerToken } from \"./utils.js\";\n\n/** Server-side view of an authenticated Renown session. */\nexport interface RenownSession {\n /** Authenticated user identity derived from the session token. */\n user: User;\n /** App/client DID the token was issued by. */\n appDid: string;\n /** Token expiry (epoch seconds), when present. */\n expiresAt?: number;\n}\n\n/** Display hint carried alongside the token (unverified; not for auth). */\nexport interface RenownSessionProfile {\n name?: string | null;\n avatar?: string | null;\n /** Renown profile document id, so SSR can resolve profile links. */\n documentId?: string | null;\n username?: string | null;\n userImage?: string | null;\n}\n\n/** The `renown_session` cookie payload: the bearer token + a display hint. */\nexport interface RenownSessionCookie {\n token: string;\n profile?: RenownSessionProfile | null;\n}\n\nexport interface VerifyRenownSessionOptions {\n /** Expected `aud` claim on the token. */\n audience?: string;\n /** Switchboard GraphQL endpoint used when re-verifying the credential. */\n switchboardUrl?: string;\n /** Renown service base URL used when re-verifying the credential. */\n renownUrl?: string;\n /** Also re-verify the credential against Switchboard (default false = token-only, no network). */\n verifyCredential?: boolean;\n}\n\n/** Claims read from a session token without verifying its signature. */\nexport interface RenownSessionClaims {\n address?: string;\n chainId?: number;\n networkId?: string;\n /** Expiry in epoch seconds. */\n expiresAt?: number;\n}\n\n/** Serialize a session cookie value (token + optional display hint). */\nexport function serializeRenownSessionCookie(\n value: RenownSessionCookie,\n): string {\n return JSON.stringify(value);\n}\n\n// Parse the JSON cookie envelope { token, profile }; undefined if malformed.\nfunction parseSessionCookie(value: string): RenownSessionCookie | undefined {\n try {\n const parsed = JSON.parse(value) as unknown;\n if (\n parsed &&\n typeof parsed === \"object\" &&\n typeof (parsed as RenownSessionCookie).token === \"string\"\n ) {\n return parsed as RenownSessionCookie;\n }\n } catch {\n // Malformed cookie.\n }\n return undefined;\n}\n\n// Decode a session cookie's claims WITHOUT verifying the signature — cheap\n// optimistic checks only (e.g. proxy redirect); never trust for access control.\nexport function readSessionClaims(\n value: string,\n): RenownSessionClaims | undefined {\n const parsed = parseSessionCookie(value);\n if (!parsed) return undefined;\n const parts = parsed.token.split(\".\");\n if (parts.length < 2) return undefined;\n try {\n const json = Buffer.from(parts[1], \"base64url\").toString(\"utf8\");\n const payload = JSON.parse(json) as {\n exp?: number;\n vc?: {\n credentialSubject?: {\n address?: string;\n chainId?: number;\n networkId?: string;\n };\n };\n };\n const subject = payload.vc?.credentialSubject;\n return {\n address: subject?.address,\n chainId: subject?.chainId,\n networkId: subject?.networkId,\n expiresAt: payload.exp,\n };\n } catch {\n return undefined;\n }\n}\n\n// Verify a session cookie (envelope or bare token) → user, or undefined. Pass\n// verifyCredential:true to also check vs Switchboard; envelope hint is merged.\nexport async function verifyRenownSession(\n value: string,\n options: VerifyRenownSessionOptions = {},\n): Promise<RenownSession | undefined> {\n const { verifyCredential = false } = options;\n const parsed = parseSessionCookie(value);\n if (!parsed) return undefined;\n const { token, profile } = parsed;\n\n let session: RenownSession | undefined;\n if (verifyCredential) {\n const verified = await verifyAuthCredential(token, {\n audience: options.audience,\n renownUrl: options.renownUrl,\n switchboardUrl: options.switchboardUrl,\n });\n if (verified) {\n session = {\n user: {\n address: verified.address as `0x${string}`,\n chainId: verified.chainId,\n networkId: verified.networkId,\n did: verified.did,\n credential: verified.credential,\n },\n appDid: verified.appDid,\n };\n }\n } else {\n const verified = await verifyAuthBearerToken(token, {\n audience: options.audience,\n });\n if (verified) {\n const subject = verified.verifiableCredential.credentialSubject;\n const did = `did:pkh:${subject.networkId}:${subject.chainId}:${subject.address.toLowerCase()}`;\n session = {\n user: {\n address: subject.address as `0x${string}`,\n chainId: subject.chainId,\n networkId: subject.networkId,\n did,\n credential: undefined,\n },\n appDid: verified.issuer,\n expiresAt: verified.payload.exp,\n };\n }\n }\n\n if (!session) return undefined;\n\n // Merge the (unverified) display hint from the envelope — display only. The\n // richer fields make this seed shape-identical to the client's restored user.\n if (profile) {\n const name = profile.name ?? profile.username ?? undefined;\n const avatarUrl = profile.avatar ?? profile.userImage ?? undefined;\n const user = { ...session.user };\n if (name || avatarUrl) {\n user.ens = { name, avatarUrl };\n }\n // Only `documentId` makes a seeded profile useful (profile links); display\n // already flows through `ens`, so there is nothing to seed without it.\n if (profile.documentId) {\n user.profile = {\n documentId: profile.documentId,\n username: profile.username ?? null,\n userImage: profile.userImage ?? null,\n ethAddress: session.user.address,\n };\n }\n session.user = user;\n }\n return session;\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { a as DEFAULT_RENOWN_NETWORK_ID } from "./constants-BexAR53F.js";
1
2
  import { createVerifiableCredentialJwt, verifyCredential } from "did-jwt-vc";
2
3
  import { Resolver } from "did-resolver";
3
4
  import { getResolver } from "key-did-resolver";
@@ -101,26 +102,27 @@ async function generateKeyPair(subtleCrypto, algorithm = ECDSA_ALGORITHM) {
101
102
  }
102
103
  //#endregion
103
104
  //#region src/crypto/renown-crypto.ts
104
- const RENOWN_NETWORK_ID = "eip155";
105
- const RENOWN_CHAIN_ID = 1;
106
105
  var RenownCrypto = class RenownCrypto {
107
106
  #subtleCrypto;
108
107
  #keyPair;
109
108
  #keyPairStorage;
110
109
  did;
110
+ /** Chain id the bearer token is scoped to; keep it equal to the issuing Renown instance's. */
111
+ chainId;
111
112
  static algorithm = ECDSA_ALGORITHM;
112
113
  static signAlgorithm = ECDSA_SIGN_ALGORITHM;
113
- constructor(keyPairStorage, crypto, keyPair, did) {
114
+ constructor(keyPairStorage, crypto, keyPair, did, chainId = 1) {
114
115
  this.#keyPairStorage = keyPairStorage;
115
116
  this.#subtleCrypto = crypto;
116
117
  this.#keyPair = keyPair;
117
118
  this.did = did;
119
+ this.chainId = chainId;
118
120
  }
119
121
  get publicKey() {
120
122
  return this.#keyPair.publicKey;
121
123
  }
122
124
  async getBearerToken(address, options) {
123
- return await createAuthBearerToken(Number(RENOWN_CHAIN_ID), RENOWN_NETWORK_ID, address || this.did, this.issuer, options);
125
+ return await createAuthBearerToken(this.chainId, DEFAULT_RENOWN_NETWORK_ID, address || this.did, this.issuer, options);
124
126
  }
125
127
  async removeDid() {
126
128
  await this.#keyPairStorage.removeKeyPair();
@@ -158,6 +160,7 @@ var ConnectCrypto = class extends RenownCrypto {};
158
160
  var RenownCryptoBuilder = class {
159
161
  keyPairStorage;
160
162
  subtleCrypto;
163
+ chainId;
161
164
  withKeyPairStorage(storage) {
162
165
  this.keyPairStorage = storage;
163
166
  return this;
@@ -166,12 +169,16 @@ var RenownCryptoBuilder = class {
166
169
  this.subtleCrypto = crypto;
167
170
  return this;
168
171
  }
172
+ withChainId(chainId) {
173
+ this.chainId = chainId;
174
+ return this;
175
+ }
169
176
  async build() {
170
177
  if (!this.keyPairStorage) throw new Error("KeyPairStorage is required. Use withKeyPairStorage() to set it.");
171
178
  const subtleCrypto = this.subtleCrypto ?? globalThis.crypto.subtle;
172
179
  const keyPair = await this.#initializeKeyPair(subtleCrypto, this.keyPairStorage);
173
180
  const did = await parseDid(keyPair);
174
- return new RenownCrypto(this.keyPairStorage, subtleCrypto, keyPair, did);
181
+ return new RenownCrypto(this.keyPairStorage, subtleCrypto, keyPair, did, this.chainId);
175
182
  }
176
183
  async #initializeKeyPair(subtleCrypto, keyPairStorage) {
177
184
  const loadedKeyPair = await keyPairStorage.loadKeyPair();
@@ -457,4 +464,4 @@ function signatureHasResultingHash(signature) {
457
464
  //#endregion
458
465
  export { signatureHasResultingHash as a, ConnectCrypto as c, createAuthBearerToken as d, getResolver$1 as f, parseSignatureHashField as i, RenownCrypto as l, verifyAuthBearerToken as m, createSignatureVerifier as n, MemoryKeyStorage as o, parsePkhDid as p, extractResultingHashFromSignature as r, RenownCryptoBuilder as s, RenownCryptoSigner as t, assertIsAuthCredential as u };
459
466
 
460
- //# sourceMappingURL=signer-CgYhXTV7.js.map
467
+ //# sourceMappingURL=signer-DrjINLqt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer-DrjINLqt.js","names":["getResolver","keyDidResolver","#keyPairStorage","#subtleCrypto","#keyPair","#stringToBytes","#initializeKeyPair"],"sources":["../src/utils.ts","../src/crypto/utils.ts","../src/crypto/renown-crypto.ts","../src/crypto/renown-crypto-builder.ts","../src/crypto/memory-key-storage.ts","../src/crypto/signer.ts"],"sourcesContent":["import type { JwtCredentialPayload } from \"did-jwt-vc\";\nimport { createVerifiableCredentialJwt, verifyCredential } from \"did-jwt-vc\";\nimport { Resolver } from \"did-resolver\";\nimport { getResolver as keyDidResolver } from \"key-did-resolver\";\nimport type {\n AuthVerifiedCredential,\n CreateBearerTokenOptions,\n IAuthCredentialSubject,\n Issuer,\n PKHDid,\n VerifiedCredential,\n} from \"./types.js\";\n\nexport type ILogger = {\n level: \"verbose\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\n verbose: (message: string, ...replacements: any[]) => void;\n debug: (message: string, ...replacements: any[]) => void;\n info: (message: string, ...replacements: any[]) => void;\n warn: (message: string, ...replacements: any[]) => void;\n error: (message: string, ...replacements: any[]) => void;\n};\n\n/**\n * Parse a DID:pkh string to extract network, chain ID, and address information\n * @param did - The DID string in format \"did:pkh:networkId:chainId:address\"\n * @returns Parsed DID information\n * @throws Error if the DID format is invalid\n */\nexport function parsePkhDid(did: string): PKHDid {\n const parts = did.split(\":\");\n if (!did.startsWith(\"did:pkh:\") || parts.length !== 5) {\n throw new Error(\"Invalid pkh did\");\n }\n const [, , networkId, chainIdStr, address] = parts;\n\n if (!address.startsWith(\"0x\")) {\n throw new Error(`Invalid address: ${address}`);\n }\n\n const chainId = Number(chainIdStr);\n if (isNaN(chainId)) {\n throw new Error(`Invalid chain id: ${chainIdStr}`);\n }\n\n return {\n chainId,\n networkId,\n address: address as PKHDid[\"address\"],\n };\n}\n\nexport interface VerifyAuthBearerTokenOptions {\n /** Expected `aud` claim. Required when verifying tokens that include an\n * audience claim — did-jwt rejects them otherwise with\n * `invalid_config: JWT audience is required but your app address has not\n * been configured`. Tokens minted without `aud` are unaffected. */\n audience?: string;\n}\n\nexport async function verifyAuthBearerToken(\n jwt: string,\n options?: VerifyAuthBearerTokenOptions,\n): Promise<false | AuthVerifiedCredential> {\n try {\n const now = parseInt(String(Date.now() / 1000));\n const verified: VerifiedCredential = await verifyCredential(\n jwt,\n getResolver(),\n {\n ...(options?.audience !== undefined && { audience: options.audience }),\n policies: {\n now: parseInt(String(Date.now() / 1000)),\n expirationDate: true,\n issuanceDate: true,\n },\n },\n );\n\n if (verified.payload.exp && verified.payload.exp < now) {\n return false;\n }\n assertIsAuthCredential(verified);\n return verified;\n } catch (e) {\n console.error(e);\n return false;\n }\n}\n\nexport function assertIsAuthCredential(\n credential: VerifiedCredential,\n): asserts credential is AuthVerifiedCredential {\n const subjectKeys = Object.keys(\n credential.verifiableCredential.credentialSubject,\n );\n if (\n ![\"address\", \"chainId\", \"networkId\"].every((key) =>\n subjectKeys.includes(key),\n )\n ) {\n throw new Error(\n \"Invalid Auth Credential Subject:\" +\n JSON.stringify(\n credential.verifiableCredential.credentialSubject,\n null,\n 2,\n ),\n );\n }\n}\n\nexport async function createAuthBearerToken(\n chainId: number,\n networkId: string,\n address: string,\n issuer: Issuer,\n options?: CreateBearerTokenOptions,\n) {\n const vcPayload: JwtCredentialPayload = {\n sub: issuer.did,\n vc: {\n \"@context\": [\"https://www.w3.org/2018/credentials/v1\"],\n type: [\"VerifiableCredential\"],\n credentialSubject: {\n chainId,\n networkId,\n address,\n } satisfies IAuthCredentialSubject,\n },\n aud: options?.aud,\n };\n\n const jwt = await createVerifiableCredentialJwt(vcPayload, issuer, {\n expiresIn: options?.expiresIn,\n });\n return jwt;\n}\n\nexport const getResolver = () => {\n const keyResolver = keyDidResolver();\n if (!keyResolver) {\n throw new Error(\"Failed to get key resolver\");\n }\n\n return new Resolver(keyResolver);\n};\n","import { encodeDIDFromPub, getPublicKey } from \"@didtools/key-webcrypto\";\nimport type { DID, JwkKeyPair } from \"./types.js\";\n\nexport const ECDSA_ALGORITHM: EcKeyAlgorithm = {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n};\n\nexport const ECDSA_SIGN_ALGORITHM = {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n hash: \"SHA-256\",\n};\n\nexport async function parseDid(keyPair: CryptoKeyPair): Promise<DID> {\n return encodeDIDFromPub(await getPublicKey(keyPair)) as DID;\n}\n\nexport async function exportKeyPair(\n keyPair: CryptoKeyPair,\n subtleCrypto: SubtleCrypto,\n): Promise<JwkKeyPair> {\n return {\n publicKey: await subtleCrypto.exportKey(\"jwk\", keyPair.publicKey),\n privateKey: await subtleCrypto.exportKey(\"jwk\", keyPair.privateKey),\n };\n}\n\nexport async function importKeyPair(\n jwkKeyPair: JwkKeyPair,\n subtleCrypto: SubtleCrypto,\n algorithm: EcKeyAlgorithm = ECDSA_ALGORITHM,\n): Promise<CryptoKeyPair> {\n return {\n publicKey: await subtleCrypto.importKey(\n \"jwk\",\n jwkKeyPair.publicKey,\n algorithm,\n true,\n [\"verify\"],\n ),\n privateKey: await subtleCrypto.importKey(\n \"jwk\",\n jwkKeyPair.privateKey,\n algorithm,\n true,\n [\"sign\"],\n ),\n };\n}\n\nexport async function generateKeyPair(\n subtleCrypto: SubtleCrypto,\n algorithm: EcKeyAlgorithm = ECDSA_ALGORITHM,\n): Promise<CryptoKeyPair> {\n return subtleCrypto.generateKey(algorithm, true, [\"sign\", \"verify\"]);\n}\n","import { fromString, toString } from \"uint8arrays\";\nimport {\n DEFAULT_RENOWN_CHAIN_ID,\n DEFAULT_RENOWN_NETWORK_ID,\n} from \"../constants.js\";\nimport type { CreateBearerTokenOptions, Issuer } from \"../types.js\";\nimport { createAuthBearerToken } from \"../utils.js\";\nimport type { DID, IRenownCrypto, JsonWebKeyPairStorage } from \"./types.js\";\nimport { ECDSA_ALGORITHM, ECDSA_SIGN_ALGORITHM } from \"./utils.js\";\n\nexport class RenownCrypto implements IRenownCrypto {\n #subtleCrypto: SubtleCrypto;\n #keyPair: CryptoKeyPair;\n #keyPairStorage: JsonWebKeyPairStorage;\n\n readonly did: DID;\n /** Chain id the bearer token is scoped to; keep it equal to the issuing Renown instance's. */\n readonly chainId: number;\n\n static algorithm = ECDSA_ALGORITHM;\n static signAlgorithm = ECDSA_SIGN_ALGORITHM;\n\n constructor(\n keyPairStorage: JsonWebKeyPairStorage,\n crypto: SubtleCrypto,\n keyPair: CryptoKeyPair,\n did: DID,\n chainId = Number(DEFAULT_RENOWN_CHAIN_ID),\n ) {\n this.#keyPairStorage = keyPairStorage;\n this.#subtleCrypto = crypto;\n this.#keyPair = keyPair;\n this.did = did;\n this.chainId = chainId;\n }\n\n get publicKey() {\n return this.#keyPair.publicKey;\n }\n\n async getBearerToken(\n address: string | undefined,\n options?: CreateBearerTokenOptions,\n ): Promise<string> {\n return await createAuthBearerToken(\n this.chainId,\n DEFAULT_RENOWN_NETWORK_ID,\n address || this.did,\n this.issuer,\n options,\n );\n }\n\n async removeDid(): Promise<void> {\n await this.#keyPairStorage.removeKeyPair();\n }\n\n #stringToBytes(s: string): Uint8Array {\n return fromString(s, \"utf-8\");\n }\n\n async sign(data: Uint8Array | string): Promise<Uint8Array> {\n const dataBytes: Uint8Array =\n typeof data === \"string\" ? this.#stringToBytes(data) : data;\n\n const arrayBuffer = await this.#subtleCrypto.sign(\n RenownCrypto.signAlgorithm,\n this.#keyPair.privateKey,\n dataBytes.buffer as ArrayBuffer,\n );\n\n return new Uint8Array(arrayBuffer);\n }\n\n async verify(data: Uint8Array, signature: Uint8Array): Promise<boolean> {\n return this.#subtleCrypto.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n this.#keyPair.publicKey,\n signature.buffer as ArrayBuffer,\n data.buffer as ArrayBuffer,\n );\n }\n\n get issuer(): Issuer {\n return {\n did: this.did,\n signer: async (data: string | Uint8Array) => {\n const signature = await this.sign(\n typeof data === \"string\" ? new TextEncoder().encode(data) : data,\n );\n return toString(signature, \"base64url\");\n },\n alg: \"ES256\",\n };\n }\n}\n\n/**\n * @deprecated Use RenownCrypto instead\n */\nexport class ConnectCrypto extends RenownCrypto {}\n","import { RenownCrypto } from \"./renown-crypto.js\";\nimport type { JsonWebKeyPairStorage } from \"./types.js\";\nimport {\n exportKeyPair,\n generateKeyPair,\n importKeyPair,\n parseDid,\n} from \"./utils.js\";\n\nexport class RenownCryptoBuilder {\n private keyPairStorage?: JsonWebKeyPairStorage;\n private subtleCrypto?: SubtleCrypto;\n private chainId?: number;\n\n withKeyPairStorage(storage: JsonWebKeyPairStorage): this {\n this.keyPairStorage = storage;\n return this;\n }\n\n withSubtleCrypto(crypto: SubtleCrypto): this {\n this.subtleCrypto = crypto;\n return this;\n }\n\n // Scopes the bearer token to a chain (default 1). Match the Renown instance\n // issuing credentials, or the token and the credential disagree.\n withChainId(chainId: number): this {\n this.chainId = chainId;\n return this;\n }\n\n async build(): Promise<RenownCrypto> {\n if (!this.keyPairStorage) {\n throw new Error(\n \"KeyPairStorage is required. Use withKeyPairStorage() to set it.\",\n );\n }\n\n const subtleCrypto = this.subtleCrypto ?? globalThis.crypto.subtle;\n const keyPair = await this.#initializeKeyPair(\n subtleCrypto,\n this.keyPairStorage,\n );\n const did = await parseDid(keyPair);\n\n return new RenownCrypto(\n this.keyPairStorage,\n subtleCrypto,\n keyPair,\n did,\n this.chainId,\n );\n }\n\n async #initializeKeyPair(\n subtleCrypto: SubtleCrypto,\n keyPairStorage: JsonWebKeyPairStorage,\n ): Promise<CryptoKeyPair> {\n const loadedKeyPair = await keyPairStorage.loadKeyPair();\n if (loadedKeyPair) {\n return importKeyPair(loadedKeyPair, subtleCrypto);\n }\n\n const keyPair = await generateKeyPair(subtleCrypto);\n const exported = await exportKeyPair(keyPair, subtleCrypto);\n await keyPairStorage.saveKeyPair(exported);\n return keyPair;\n }\n}\n","import type { JsonWebKeyPairStorage, JwkKeyPair } from \"./types.js\";\n\nexport class MemoryKeyStorage implements JsonWebKeyPairStorage {\n private keyPair: JwkKeyPair | undefined;\n\n constructor(keyPair?: JwkKeyPair) {\n this.keyPair = keyPair;\n }\n\n loadKeyPair() {\n return Promise.resolve(this.keyPair);\n }\n\n saveKeyPair(keyPair: JwkKeyPair) {\n this.keyPair = keyPair;\n return Promise.resolve();\n }\n\n removeKeyPair() {\n this.keyPair = undefined;\n return Promise.resolve();\n }\n}\n","import type {\n Action,\n AppActionSigner,\n ISigner,\n Operation,\n Signature,\n SignatureVerificationHandler,\n UserActionSigner,\n} from \"@powerhousedao/shared/document-model\";\nimport type { IRenownCrypto } from \"./index.js\";\n\nexport class InvalidSignatureError extends Error {\n constructor() {\n super(\"Invalid signature\");\n }\n}\n\nexport class RenownCryptoSigner implements ISigner {\n readonly app: AppActionSigner;\n\n constructor(\n private readonly crypto: IRenownCrypto,\n private readonly appName: string,\n public user?: UserActionSigner,\n ) {\n this.app = {\n key: this.crypto.did,\n name: this.appName,\n };\n }\n\n get publicKey() {\n return this.crypto.publicKey;\n }\n\n async sign(data: Uint8Array): Promise<Uint8Array> {\n return this.crypto.sign(data);\n }\n\n async verify(data: Uint8Array, signature: Uint8Array): Promise<void> {\n const isValid = await this.crypto.verify(data, signature);\n if (!isValid) {\n throw new InvalidSignatureError();\n }\n }\n\n async signAction(\n action: Action,\n abortSignal?: AbortSignal,\n ): Promise<Signature> {\n const hashField = action.context?.prevOpHash ?? \"\";\n return this._signAction(action, hashField, abortSignal);\n }\n\n /**\n * Signs an action including a predicted resulting state hash.\n *\n * The resulting hash is packed into the signature tuple's 4th element (index 3)\n * using the format: `${prevStateHash}:${resultingStateHash}`\n *\n * This allows offline verification of documents without reducer logic:\n * - Verifier can check that the signature is valid for the claimed resulting state\n * - Verifier can compare claimed resulting state to actual operation.hash\n *\n * @param action - The action to sign\n * @param resultingStateHash - The predicted hash of document state AFTER this action runs\n * @param abortSignal - Optional abort signal\n * @returns A Signature tuple with the resulting hash encoded in element [3]\n */\n async signActionWithResultingState(\n action: Action,\n resultingStateHash: string,\n abortSignal?: AbortSignal,\n ): Promise<Signature> {\n const prevStateHash = action.context?.prevOpHash ?? \"\";\n const hashField = `${prevStateHash}:${resultingStateHash}`;\n return this._signAction(action, hashField, abortSignal);\n }\n\n /**\n * Internal signing implementation shared by signAction and signActionWithResultingState.\n */\n private async _signAction(\n action: Action,\n hashField: string,\n abortSignal?: AbortSignal,\n ): Promise<Signature> {\n if (abortSignal?.aborted) {\n throw new Error(\"Signing aborted\");\n }\n\n const timestamp = (new Date().getTime() / 1000).toFixed(0);\n const hash = await this.hashAction(action);\n\n if (abortSignal?.aborted) {\n throw new Error(\"Signing aborted\");\n }\n\n const params: [string, string, string, string] = [\n timestamp,\n this.crypto.did,\n hash,\n hashField,\n ];\n const message = this.buildSignatureMessage(params);\n const signatureBytes = await this.crypto.sign(message);\n const signatureHex = `0x${this.arrayBufferToHex(signatureBytes)}`;\n\n if (abortSignal?.aborted) {\n throw new Error(\"Signing aborted\");\n }\n\n return [...params, signatureHex];\n }\n\n private async hashAction(action: Action): Promise<string> {\n const payload = [\n action.scope,\n action.type,\n JSON.stringify(action.input),\n ].join(\"\");\n const encoder = new TextEncoder();\n const data = encoder.encode(payload);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n return this.arrayBufferToBase64(hashBuffer);\n }\n\n private buildSignatureMessage(\n params: [string, string, string, string],\n ): Uint8Array {\n const message = params.join(\"\");\n const prefix = \"\\x19Signed Operation:\\n\" + message.length.toString();\n const encoder = new TextEncoder();\n return encoder.encode(prefix + message);\n }\n\n private arrayBufferToHex(buffer: Uint8Array | ArrayBuffer): string {\n const bytes =\n buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n return Array.from(bytes)\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n}\n\n/**\n * Creates a signature verification handler that verifies signatures using the Web Crypto API.\n * The verification uses ECDSA with P-256 curve and SHA-256 hash, matching the RenownCrypto signing algorithm.\n */\nexport function createSignatureVerifier(\n requireSignature = false,\n): SignatureVerificationHandler {\n return async (operation: Operation, publicKey: string): Promise<boolean> => {\n const signer = operation.action.context?.signer;\n if (!signer || !publicKey) {\n return !requireSignature;\n }\n\n const signatures = signer.signatures;\n if (signatures.length === 0) {\n return false;\n }\n\n const signature = signatures[signatures.length - 1];\n const [timestamp, signerKey, hash, prevStateHash, signatureHex] = signature;\n\n if (signerKey !== publicKey) {\n return false;\n }\n\n const params: [string, string, string, string] = [\n timestamp,\n signerKey,\n hash,\n prevStateHash,\n ];\n const message = buildSignatureMessage(params);\n const signatureBytes = hexToUint8Array(signatureHex);\n\n const cryptoKey = await importPublicKey(publicKey);\n\n const isValid = await crypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n cryptoKey,\n signatureBytes.buffer as ArrayBuffer,\n message.buffer as ArrayBuffer,\n );\n\n return isValid;\n };\n}\n\nfunction buildSignatureMessage(\n params: [string, string, string, string],\n): Uint8Array {\n const message = params.join(\"\");\n const prefix = \"\\x19Signed Operation:\\n\" + message.length.toString();\n const encoder = new TextEncoder();\n return encoder.encode(prefix + message);\n}\n\nfunction hexToUint8Array(hex: string): Uint8Array {\n const cleanHex = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n\nasync function importPublicKey(did: string): Promise<CryptoKey> {\n const keyData = extractKeyFromDid(did);\n return crypto.subtle.importKey(\n \"raw\",\n keyData.buffer as ArrayBuffer,\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"verify\"],\n );\n}\n\nfunction extractKeyFromDid(did: string): Uint8Array {\n const parts = did.split(\":\");\n if (parts.length < 3 || parts[0] !== \"did\" || parts[1] !== \"key\") {\n throw new Error(`Invalid DID format: ${did}`);\n }\n\n const multibaseKey = parts[2];\n if (!multibaseKey.startsWith(\"z\")) {\n throw new Error(`Unsupported multibase encoding: ${multibaseKey[0]}`);\n }\n\n const decoded = base58Decode(multibaseKey.slice(1));\n\n if (decoded[0] !== 0x80 || decoded[1] !== 0x24) {\n throw new Error(\"Not a P-256 public key multicodec\");\n }\n\n const compressedKey = decoded.slice(2);\n return decompressP256PublicKey(compressedKey);\n}\n\nfunction base58Decode(input: string): Uint8Array {\n const ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n const ALPHABET_MAP = new Map<string, number>();\n for (let i = 0; i < ALPHABET.length; i++) {\n ALPHABET_MAP.set(ALPHABET[i], i);\n }\n\n if (input.length === 0) {\n return new Uint8Array(0);\n }\n\n const bytes: number[] = [0];\n for (const char of input) {\n const value = ALPHABET_MAP.get(char);\n if (value === undefined) {\n throw new Error(`Invalid base58 character: ${char}`);\n }\n\n let carry = value;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n for (const char of input) {\n if (char !== \"1\") break;\n bytes.push(0);\n }\n\n return new Uint8Array(bytes.reverse());\n}\n\nfunction decompressP256PublicKey(compressed: Uint8Array): Uint8Array {\n if (compressed.length !== 33) {\n throw new Error(`Invalid compressed key length: ${compressed.length}`);\n }\n\n const prefix = compressed[0];\n if (prefix !== 0x02 && prefix !== 0x03) {\n throw new Error(`Invalid compression prefix: ${prefix}`);\n }\n\n const p = BigInt(\n \"0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff\",\n );\n const a = BigInt(\n \"0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc\",\n );\n const b = BigInt(\n \"0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b\",\n );\n\n let x = BigInt(0);\n for (let i = 1; i < compressed.length; i++) {\n x = (x << BigInt(8)) | BigInt(compressed[i]);\n }\n\n const ySquared = (modPow(x, BigInt(3), p) + a * x + b) % p;\n let y = modPow(ySquared, (p + BigInt(1)) / BigInt(4), p);\n\n const isYEven = y % BigInt(2) === BigInt(0);\n const shouldBeEven = prefix === 0x02;\n if (isYEven !== shouldBeEven) {\n y = p - y;\n }\n\n const uncompressed = new Uint8Array(65);\n uncompressed[0] = 0x04;\n\n const xBytes = bigIntToBytes(x, 32);\n const yBytes = bigIntToBytes(y, 32);\n\n uncompressed.set(xBytes, 1);\n uncompressed.set(yBytes, 33);\n\n return uncompressed;\n}\n\nfunction modPow(base: bigint, exp: bigint, mod: bigint): bigint {\n let result = BigInt(1);\n base = base % mod;\n while (exp > BigInt(0)) {\n if (exp % BigInt(2) === BigInt(1)) {\n result = (result * base) % mod;\n }\n exp = exp >> BigInt(1);\n base = (base * base) % mod;\n }\n return result;\n}\n\nfunction bigIntToBytes(n: bigint, length: number): Uint8Array {\n const bytes = new Uint8Array(length);\n for (let i = length - 1; i >= 0; i--) {\n bytes[i] = Number(n & BigInt(0xff));\n n = n >> BigInt(8);\n }\n return bytes;\n}\n\n/**\n * Parses the hash field (element [3]) from a signature tuple.\n *\n * Supports two formats:\n * - Old format: just `prevStateHash` (no colon)\n * - New format: `prevStateHash:resultingStateHash` (colon-separated)\n *\n * @param hashField - The 4th element of a Signature tuple\n * @returns Object with prevStateHash and optional resultingStateHash\n */\nexport function parseSignatureHashField(hashField: string): {\n prevStateHash: string;\n resultingStateHash: string | undefined;\n} {\n const colonIndex = hashField.indexOf(\":\");\n\n if (colonIndex === -1) {\n return {\n prevStateHash: hashField,\n resultingStateHash: undefined,\n };\n }\n\n return {\n prevStateHash: hashField.substring(0, colonIndex),\n resultingStateHash: hashField.substring(colonIndex + 1),\n };\n}\n\n/**\n * Extracts the resulting state hash from a signature, if present.\n *\n * @param signature - A Signature tuple\n * @returns The resulting state hash, or undefined if not present\n */\nexport function extractResultingHashFromSignature(\n signature: Signature,\n): string | undefined {\n const hashField = signature[3];\n const { resultingStateHash } = parseSignatureHashField(hashField);\n return resultingStateHash;\n}\n\n/**\n * Checks if a signature includes a resulting state hash.\n *\n * @param signature - A Signature tuple\n * @returns true if the signature includes a resulting state hash\n */\nexport function signatureHasResultingHash(signature: Signature): boolean {\n return extractResultingHashFromSignature(signature) !== undefined;\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ //#region src/wallet/types.ts
2
+ const LoginMethod = {
3
+ WALLET: "wallet",
4
+ GOOGLE: "google",
5
+ EMAIL: "email",
6
+ APPLE: "apple"
7
+ };
8
+ function normalizeWalletTheme(theme) {
9
+ if (theme === void 0) return { mode: "light" };
10
+ if (typeof theme === "string") return { mode: theme };
11
+ return {
12
+ mode: theme.mode,
13
+ accentColor: theme.accentColor,
14
+ accentColorForeground: theme.accentColorForeground
15
+ };
16
+ }
17
+ //#endregion
18
+ export { normalizeWalletTheme as n, LoginMethod as t };
19
+
20
+ //# sourceMappingURL=types-C_qc_62W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-C_qc_62W.js","names":[],"sources":["../src/wallet/types.ts"],"sourcesContent":["import type { ComponentType, ReactNode } from \"react\";\nimport type { SignCredentialTypedData } from \"../credential.js\";\n\n// Const object rather than an enum so config can be authored with plain string\n// literals (`methods: [\"google\"]`) while `LoginMethod.GOOGLE` still works.\nexport const LoginMethod = {\n WALLET: \"wallet\",\n GOOGLE: \"google\",\n EMAIL: \"email\",\n APPLE: \"apple\",\n} as const;\n\nexport type LoginMethod = (typeof LoginMethod)[keyof typeof LoginMethod];\n\n// Colors the host passes into an adapter Provider so its wallet UI matches.\n// The adapter stays agnostic to how the host derives them (CSS tokens, etc.).\nexport interface WalletThemeColors {\n accentColor?: string;\n accentColorForeground?: string;\n}\n\n// The theme the host passes at runtime: a bare mode, or a mode plus colors.\nexport type WalletTheme =\n | \"light\"\n | \"dark\"\n | ({ mode: \"light\" | \"dark\" } & WalletThemeColors);\n\n// Normalize a WalletTheme (or undefined) to a mode + colors the adapters use.\nexport function normalizeWalletTheme(theme: WalletTheme | undefined): {\n mode: \"light\" | \"dark\";\n accentColor?: string;\n accentColorForeground?: string;\n} {\n if (theme === undefined) return { mode: \"light\" };\n if (typeof theme === \"string\") return { mode: theme };\n return {\n mode: theme.mode,\n accentColor: theme.accentColor,\n accentColorForeground: theme.accentColorForeground,\n };\n}\n\n// The signer surface signIn needs, produced by an adapter after the user connects.\nexport interface WalletSession {\n address: `0x${string}`;\n chainId: number;\n signTypedData: SignCredentialTypedData;\n // Capability, not policy: the session can sign without a user prompt (e.g. a\n // Privy embedded wallet). Whether/when to sign silently is the host's call.\n canSignSilently?: boolean;\n}\n\n// Imperative controls returned by an adapter's React hook (used inside its Provider).\nexport interface WalletController {\n connect(method?: LoginMethod): Promise<WalletSession>;\n disconnect(): Promise<void>;\n getSession(): WalletSession | undefined;\n // Optional push stream of session changes (fires immediately with the current\n // one), so a host can complete sign-in on an OAuth return with no live connect().\n subscribe?(\n listener: (session: WalletSession | undefined) => void,\n ): () => void;\n}\n\n// Identity + capabilities, declared once per adapter in a dependency-free module\n// so a host can list methods and detect a redirect return with no wallet library.\nexport interface WalletAdapterMeta {\n id: string;\n // URL params the adapter leaves when a full-page OAuth login returns; empty for\n // adapters with no redirect flow.\n redirectReturnParams: string[];\n // Must be known before load(): the login UI renders buttons before any wallet\n // library is fetched.\n supportedMethods: LoginMethod[];\n}\n\n// Behaviour only — what an adapter factory returns. Identity lives in the meta.\nexport interface WalletAdapterImpl {\n // React provider that must wrap the app subtree for this adapter to work; the\n // host passes its current theme so the adapter's UI can match.\n Provider: ComponentType<{ children: ReactNode; theme?: WalletTheme }>;\n // Hook returning imperative controls; MUST be called inside <Provider>.\n useController: () => WalletController;\n}\n\n// What the host consumes: resolveAdapters pairs an impl with its meta.\nexport interface WalletAdapter extends WalletAdapterImpl {\n meta: WalletAdapterMeta;\n}\n\n// An adapter's light entry: eager meta plus a lazy loader that pulls the factory\n// and its wallet library only once login is activated.\nexport interface WalletAdapterDescriptor {\n meta: WalletAdapterMeta;\n load: () => Promise<WalletAdapterImpl>;\n}\n\nexport type WalletAdapterFactory<Config = unknown> = (\n config: Config,\n) => WalletAdapterImpl;\n\nexport type WalletAdapterProvider<Config = unknown> = (\n config: Config,\n) => WalletAdapterDescriptor;\n"],"mappings":";AAKA,MAAa,cAAc;CACzB,QAAQ;CACR,QAAQ;CACR,OAAO;CACP,OAAO;CACR;AAkBD,SAAgB,qBAAqB,OAInC;AACA,KAAI,UAAU,KAAA,EAAW,QAAO,EAAE,MAAM,SAAS;AACjD,KAAI,OAAO,UAAU,SAAU,QAAO,EAAE,MAAM,OAAO;AACrD,QAAO;EACL,MAAM,MAAM;EACZ,aAAa,MAAM;EACnB,uBAAuB,MAAM;EAC9B"}