@renown/sdk 6.2.0-dev.50 → 6.2.0-dev.52

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as VERIFIABLE_CREDENTIAL_EIP712_TYPE, a as BaseStorage, c as verifyCredentialSignature, d as CREDENTIAL_TYPES, f as DEFAULT_RENOWN_CHAIN_ID, g as ISSUER_TYPE, h as DOMAIN_TYPE, i as RenownMemoryStorage, l as CREDENTIAL_SCHEMA_EIP712_TYPE, m as DEFAULT_RENOWN_URL, n as fetchRenownProfile, o as buildAndSignCredential, p as DEFAULT_RENOWN_NETWORK_ID, r as Renown, s as recoverCredentialSigner, t as BaseRenownBuilder, u as CREDENTIAL_SUBJECT_TYPE } from "./renown-builder-CQIpzrA6.js";
1
+ import { _ as VERIFIABLE_CREDENTIAL_EIP712_TYPE, a as BaseStorage, c as verifyCredentialSignature, d as CREDENTIAL_TYPES, f as DEFAULT_RENOWN_CHAIN_ID, g as ISSUER_TYPE, h as DOMAIN_TYPE, i as RenownMemoryStorage, l as CREDENTIAL_SCHEMA_EIP712_TYPE, m as DEFAULT_RENOWN_URL, n as fetchRenownProfile, o as buildAndSignCredential, p as DEFAULT_RENOWN_NETWORK_ID, r as Renown, s as recoverCredentialSigner, t as BaseRenownBuilder, u as CREDENTIAL_SUBJECT_TYPE } from "./renown-builder-DP0iFzK1.js";
2
2
  import { a as signatureHasResultingHash, c as ConnectCrypto, d as createAuthBearerToken, f as getResolver, i as parseSignatureHashField, l as RenownCrypto, m as verifyAuthBearerToken, n as createSignatureVerifier, o as MemoryKeyStorage, p as parsePkhDid, r as extractResultingHashFromSignature, s as RenownCryptoBuilder, t as RenownCryptoSigner, u as assertIsAuthCredential } from "./signer-XkA-D7Qt.js";
3
3
  import { t as BrowserKeyStorage } from "./browser-key-storage-v4O-fjz0.js";
4
4
  //#region src/event/event.browser.ts
package/dist/node.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as VERIFIABLE_CREDENTIAL_EIP712_TYPE, a as BaseStorage, c as verifyCredentialSignature, d as CREDENTIAL_TYPES, f as DEFAULT_RENOWN_CHAIN_ID, g as ISSUER_TYPE, h as DOMAIN_TYPE, i as RenownMemoryStorage, l as CREDENTIAL_SCHEMA_EIP712_TYPE, m as DEFAULT_RENOWN_URL, n as fetchRenownProfile, o as buildAndSignCredential, p as DEFAULT_RENOWN_NETWORK_ID, r as Renown, s as recoverCredentialSigner, t as BaseRenownBuilder, u as CREDENTIAL_SUBJECT_TYPE } from "./renown-builder-CQIpzrA6.js";
1
+ import { _ as VERIFIABLE_CREDENTIAL_EIP712_TYPE, a as BaseStorage, c as verifyCredentialSignature, d as CREDENTIAL_TYPES, f as DEFAULT_RENOWN_CHAIN_ID, g as ISSUER_TYPE, h as DOMAIN_TYPE, i as RenownMemoryStorage, l as CREDENTIAL_SCHEMA_EIP712_TYPE, m as DEFAULT_RENOWN_URL, n as fetchRenownProfile, o as buildAndSignCredential, p as DEFAULT_RENOWN_NETWORK_ID, r as Renown, s as recoverCredentialSigner, t as BaseRenownBuilder, u as CREDENTIAL_SUBJECT_TYPE } from "./renown-builder-DP0iFzK1.js";
2
2
  import { a as signatureHasResultingHash, c as ConnectCrypto, d as createAuthBearerToken, f as getResolver, i as parseSignatureHashField, l as RenownCrypto, m as verifyAuthBearerToken, n as createSignatureVerifier, o as MemoryKeyStorage, p as parsePkhDid, r as extractResultingHashFromSignature, s as RenownCryptoBuilder, t as RenownCryptoSigner, u as assertIsAuthCredential } from "./signer-XkA-D7Qt.js";
3
3
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
@@ -149,7 +149,7 @@ var RenownBuilder = class extends BaseRenownBuilder {
149
149
  //#endregion
150
150
  //#region src/login.node.ts
151
151
  const DEFAULT_TIMEOUT_MS = 300 * 1e3;
152
- const POLL_INTERVAL_MS = 2e3;
152
+ const POLL_INTERVAL_MS = 500;
153
153
  const SECONDS_IN_DAY = 1440 * 60;
154
154
  function abortReason(signal) {
155
155
  if (signal.reason instanceof Error) return signal.reason;
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 = 2000; // 2 seconds\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"],"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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"}
@@ -311,7 +311,7 @@ var MemoryEventEmitter = class {
311
311
  //#region src/profile.ts
312
312
  const fetchRenownProfile = async (user, baseUrl) => {
313
313
  try {
314
- const response = await fetch(`${baseUrl}/api/profile`, {
314
+ const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/profile`, {
315
315
  method: "POST",
316
316
  headers: { "Content-Type": "application/json" },
317
317
  body: JSON.stringify({ ethAddress: user.address })
@@ -430,4 +430,4 @@ var BaseRenownBuilder = class BaseRenownBuilder {
430
430
  //#endregion
431
431
  export { VERIFIABLE_CREDENTIAL_EIP712_TYPE as _, BaseStorage as a, verifyCredentialSignature as c, CREDENTIAL_TYPES as d, DEFAULT_RENOWN_CHAIN_ID as f, ISSUER_TYPE as g, DOMAIN_TYPE as h, RenownMemoryStorage as i, CREDENTIAL_SCHEMA_EIP712_TYPE as l, DEFAULT_RENOWN_URL as m, fetchRenownProfile as n, buildAndSignCredential as o, DEFAULT_RENOWN_NETWORK_ID as p, Renown as r, recoverCredentialSigner as s, BaseRenownBuilder as t, CREDENTIAL_SUBJECT_TYPE as u };
432
432
 
433
- //# sourceMappingURL=renown-builder-CQIpzrA6.js.map
433
+ //# sourceMappingURL=renown-builder-DP0iFzK1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"renown-builder-CQIpzrA6.js","names":["#store","#eventEmitter","#baseUrl","#crypto","#appName","#profileFetcher","#signer","#status","#updateStatus","#getCredential","#updateUser","#listeners","#appName","#storage","#eventEmitter","#crypto","#keyPairStorage","#baseUrl","#profileFetcher"],"sources":["../src/constants.ts","../src/credential.ts","../src/storage/common.ts","../src/common.ts","../src/event/memory.ts","../src/profile.ts","../src/renown-builder.ts"],"sourcesContent":["export const DEFAULT_RENOWN_URL = \"https://www.renown.id\";\nexport const DEFAULT_RENOWN_NETWORK_ID = \"eip155\";\nexport const DEFAULT_RENOWN_CHAIN_ID = \"1\";\n\nexport const DOMAIN_TYPE = [\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n] as const;\n\nexport const VERIFIABLE_CREDENTIAL_EIP712_TYPE = [\n { name: \"@context\", type: \"string[]\" },\n { name: \"type\", type: \"string[]\" },\n { name: \"id\", type: \"string\" },\n { name: \"issuer\", type: \"Issuer\" },\n { name: \"credentialSubject\", type: \"CredentialSubject\" },\n { name: \"credentialSchema\", type: \"CredentialSchema\" },\n { name: \"issuanceDate\", type: \"string\" },\n { name: \"expirationDate\", type: \"string\" },\n] as const;\n\nexport const CREDENTIAL_SCHEMA_EIP712_TYPE = [\n { name: \"id\", type: \"string\" },\n { name: \"type\", type: \"string\" },\n] as const;\n\nexport const CREDENTIAL_SUBJECT_TYPE = [\n { name: \"app\", type: \"string\" },\n { name: \"id\", type: \"string\" },\n] as const;\n\nexport const ISSUER_TYPE = [\n { name: \"id\", type: \"string\" },\n { name: \"ethereumAddress\", type: \"string\" },\n] as const;\n\nexport const CREDENTIAL_TYPES = {\n EIP712Domain: DOMAIN_TYPE,\n VerifiableCredential: VERIFIABLE_CREDENTIAL_EIP712_TYPE,\n CredentialSchema: CREDENTIAL_SCHEMA_EIP712_TYPE,\n CredentialSubject: CREDENTIAL_SUBJECT_TYPE,\n Issuer: ISSUER_TYPE,\n} as const;\n","import { recoverTypedDataAddress } from \"viem\";\nimport { CREDENTIAL_TYPES, DEFAULT_RENOWN_NETWORK_ID } from \"./constants.js\";\nimport type { PowerhouseVerifiableCredential } from \"./types.js\";\n\n/* Local structural aliases (EIP-712 standard shapes) so renown's public .d.ts\n * never names viem — a viem type in the surface drags viem's whole closure in. */\ntype Hex = `0x${string}`;\ntype TypedDataDomain = {\n name?: string;\n version?: string;\n chainId?: number;\n verifyingContract?: Hex;\n salt?: Hex;\n};\ntype TypedDataParameter = { name: string; type: string };\n\n/** EIP-712 domain as signed by the credential issuer. */\nexport type CredentialDomain = {\n version: string;\n chainId: number;\n};\n\n/** The credential body that is EIP-712 signed (everything except `proof`). */\nexport type CredentialMessage = {\n \"@context\": string[];\n type: string[];\n id: string;\n issuer: { id: string; ethereumAddress: Hex };\n credentialSubject: { id: string; app: string };\n credentialSchema: { id: string; type: string };\n issuanceDate: string;\n expirationDate: string;\n};\n\n/** Typed-data signer; matches the loose shape used by wallet adapters. */\nexport type SignCredentialTypedData = (args: {\n domain: TypedDataDomain;\n types: Record<string, readonly TypedDataParameter[]>;\n primaryType: string;\n message: Record<string, unknown>;\n}) => Promise<Hex>;\n\nexport interface BuildCredentialParams {\n signTypedData: SignCredentialTypedData;\n address: Hex;\n chainId: number;\n app: string;\n /** Credential subject id: the app/client DID the credential delegates to. */\n appId: string;\n expiresInDays?: number;\n}\n\n/** Assemble a Renown delegation VC and sign it with the provided signer. */\nexport async function buildAndSignCredential(\n params: BuildCredentialParams,\n): Promise<PowerhouseVerifiableCredential> {\n const {\n signTypedData,\n address,\n chainId,\n app,\n appId,\n expiresInDays = 7,\n } = params;\n\n const issuerId = `did:pkh:${DEFAULT_RENOWN_NETWORK_ID}:${chainId}:${address.toLowerCase()}`;\n const credentialId = `urn:uuid:${globalThis.crypto.randomUUID()}`;\n const now = new Date();\n const expirationDate = new Date(\n now.getTime() + expiresInDays * 24 * 60 * 60 * 1000,\n );\n\n const message: CredentialMessage = {\n \"@context\": [\"https://www.w3.org/2018/credentials/v1\"],\n type: [\"VerifiableCredential\", \"RenownCredential\"],\n id: credentialId,\n issuer: { id: issuerId, ethereumAddress: address },\n credentialSubject: { id: appId, app },\n credentialSchema: {\n id: \"https://renown.id/schemas/renown-credential/v1\",\n type: \"JsonSchemaValidator2018\",\n },\n issuanceDate: now.toISOString(),\n expirationDate: expirationDate.toISOString(),\n };\n\n const domain: CredentialDomain = { version: \"1\", chainId };\n\n // viem and most wallet adapters reserve EIP712Domain and derive it from\n // `domain` — passing it explicitly makes them throw.\n const { EIP712Domain, ...signTypes } = CREDENTIAL_TYPES;\n void EIP712Domain;\n const signature = await signTypedData({\n domain,\n types: signTypes,\n primaryType: \"VerifiableCredential\",\n message,\n });\n\n return {\n ...message,\n proof: {\n type: \"EthereumEip712Signature2021\",\n created: message.issuanceDate,\n verificationMethod: issuerId,\n proofPurpose: \"assertionMethod\",\n proofValue: signature,\n ethereumAddress: address,\n eip712: {\n domain,\n types: CREDENTIAL_TYPES,\n primaryType: \"VerifiableCredential\",\n },\n },\n };\n}\n\n/** Recover the address that signed a credential's EIP-712 proof. */\nexport async function recoverCredentialSigner(\n credential: PowerhouseVerifiableCredential,\n): Promise<Hex> {\n const { proof, ...message } = credential;\n // Drop EIP712Domain so viem derives it from `domain`; viem ignores\n // message keys not present in the types, so the proof is excluded too.\n const { EIP712Domain, ...types } = CREDENTIAL_TYPES;\n void EIP712Domain;\n return recoverTypedDataAddress({\n domain: proof.eip712.domain,\n types,\n primaryType: \"VerifiableCredential\",\n message,\n signature: proof.proofValue as Hex,\n } as Parameters<typeof recoverTypedDataAddress>[0]);\n}\n\n/** True when the proof was signed by the credential's declared issuer address. */\nexport async function verifyCredentialSignature(\n credential: PowerhouseVerifiableCredential,\n): Promise<boolean> {\n try {\n const recovered = await recoverCredentialSigner(credential);\n return (\n recovered.toLowerCase() ===\n credential.issuer.ethereumAddress.toLowerCase()\n );\n } catch {\n // Malformed proof (bad hex, missing fields) is an invalid signature.\n return false;\n }\n}\n","export interface IStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n Key extends keyof T = keyof T,\n> {\n get(key: Key): T[Key] | undefined;\n set(key: Key, value?: T[Key]): void;\n delete(key: Key): void;\n}\n\nexport abstract class BaseStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n Key extends keyof T = keyof T,\n> implements IStorage<T> {\n abstract get(key: Key): T[Key] | undefined;\n abstract set(key: Key, value?: T[Key]): void;\n abstract delete(key: Key): void;\n}\n\nexport class MemoryStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n Key extends keyof T = keyof T,\n> extends BaseStorage<T> {\n private readonly data = new Map<Key, T[Key]>();\n\n get(key: Key) {\n return this.data.get(key);\n }\n\n set(key: Key, value?: T[Key]): void {\n if (value === undefined) {\n this.data.delete(key);\n } else {\n this.data.set(key, value);\n }\n }\n\n delete(key: Key): void {\n this.data.delete(key);\n }\n}\n","import { CREDENTIAL_TYPES, DEFAULT_RENOWN_URL } from \"./constants.js\";\nimport { verifyCredentialSignature } from \"./credential.js\";\nimport { RenownCryptoSigner, type IRenownCrypto } from \"./crypto/index.js\";\nimport { MemoryStorage } from \"./storage/common.js\";\nimport type {\n CreateBearerTokenOptions,\n IProof,\n IRenown,\n ISigner,\n LoginStatus,\n PowerhouseVerifiableCredential,\n ProfileFetcher,\n RenownEventEmitter,\n RenownEvents,\n RenownStorage,\n RenownStorageMap,\n User,\n} from \"./types.js\";\nimport { parsePkhDid, verifyAuthBearerToken } from \"./utils.js\";\nexport * from \"./constants.js\";\n\nexport class RenownMemoryStorage extends MemoryStorage<RenownStorageMap> {}\n\nexport class Renown implements IRenown {\n #baseUrl: string;\n #store: RenownStorage;\n #eventEmitter: RenownEventEmitter;\n #appName: string;\n #crypto: IRenownCrypto;\n #signer: ISigner;\n #profileFetcher?: ProfileFetcher;\n #status: LoginStatus = \"initial\";\n\n constructor(\n store: RenownStorage,\n eventEmitter: RenownEventEmitter,\n crypto: IRenownCrypto,\n appName: string,\n baseUrl = DEFAULT_RENOWN_URL,\n profileFetcher?: ProfileFetcher,\n ) {\n this.#store = store;\n this.#eventEmitter = eventEmitter;\n this.#baseUrl = baseUrl;\n this.#crypto = crypto;\n this.#appName = appName;\n this.#profileFetcher = profileFetcher;\n this.#signer = new RenownCryptoSigner(crypto, this.#appName, this.user);\n\n this.on(\"user\", (user) => {\n this.#signer.user = user;\n });\n }\n\n get baseUrl() {\n return this.#baseUrl;\n }\n\n get user() {\n return this.#store.get(\"user\");\n }\n\n get status() {\n return this.#status;\n }\n\n get signer() {\n return this.#signer;\n }\n\n get crypto() {\n return this.#crypto;\n }\n\n get did() {\n return this.#crypto.did;\n }\n\n get profileFetcher() {\n return this.#profileFetcher;\n }\n\n #updateStatus(status: LoginStatus) {\n this.#status = status;\n this.#eventEmitter.emit(\"status\", status);\n }\n\n #updateUser(user: User | undefined) {\n if (user) {\n this.#store.set(\"user\", user);\n } else {\n this.#store.delete(\"user\");\n }\n this.#eventEmitter.emit(\"user\", user);\n }\n\n async login(userDid: string): Promise<User> {\n this.#updateStatus(\"checking\");\n try {\n const result = parsePkhDid(userDid);\n const credential = await this.#getCredential(\n result.address,\n result.chainId,\n this.#crypto.did,\n );\n\n if (!credential) {\n this.#updateUser(undefined);\n throw new Error(\"Credential not found\");\n }\n\n if (\n !(\n credential.issuer.id === userDid &&\n credential.credentialSubject.id === this.did\n )\n ) {\n throw new Error(\"Invalid credential\");\n }\n\n // The deployed Renown credential API may return proof.eip712 without\n // domain/types, despite the declared type. The domain is canonical\n // (version \"1\", the DID's chainId), so reconstruct it — the signature\n // verification below still fails if the credential wasn't signed for\n // that domain.\n const eip712 = credential.proof.eip712 as\n | Partial<IProof[\"eip712\"]>\n | undefined;\n const verifiableCredential: PowerhouseVerifiableCredential =\n eip712?.domain\n ? credential\n : {\n ...credential,\n proof: {\n ...credential.proof,\n eip712: {\n domain: { version: \"1\", chainId: result.chainId },\n types: CREDENTIAL_TYPES,\n primaryType: \"VerifiableCredential\",\n },\n },\n };\n\n // Verify the EIP-712 proof was signed by the DID's address on its chain.\n if (\n credential.issuer.ethereumAddress.toLowerCase() !==\n result.address.toLowerCase() ||\n verifiableCredential.proof.eip712.domain.chainId !== result.chainId ||\n !(await verifyCredentialSignature(verifiableCredential))\n ) {\n throw new Error(\"Invalid credential signature\");\n }\n\n const user: User = {\n ...result,\n address: credential.issuer.ethereumAddress,\n did: userDid,\n credential: verifiableCredential,\n };\n\n this.#updateUser(user);\n this.#updateStatus(\"authorized\");\n\n // Fetch profile data in the background if a fetcher is configured\n if (this.#profileFetcher) {\n this.#profileFetcher(user, this.#baseUrl)\n .then((profile) => {\n if (\n profile &&\n this.user?.address === user.address &&\n this.user.chainId === user.chainId\n ) {\n this.#updateUser({\n ...this.user,\n profile,\n ens: {\n name: profile.username ?? undefined,\n avatarUrl: profile.userImage ?? undefined,\n },\n });\n }\n })\n .catch(console.error);\n }\n\n return user;\n } catch (error) {\n this.#updateUser(undefined);\n this.#updateStatus(\"not-authorized\");\n throw error;\n }\n }\n\n logout() {\n this.#updateUser(undefined);\n this.#updateStatus(\"initial\");\n return Promise.resolve();\n }\n\n on<K extends keyof RenownEvents>(\n event: K,\n listener: (data: RenownEvents[K]) => void,\n ): () => void {\n return this.#eventEmitter.on(event, listener);\n }\n\n async #getCredential(\n address: string,\n chainId: number,\n appDid: string,\n ): Promise<PowerhouseVerifiableCredential | undefined> {\n if (!this.#baseUrl) {\n throw new Error(\"RENOWN_URL is not set\");\n }\n const url = new URL(\n `/api/auth/credential?address=${encodeURIComponent(address)}&chainId=${encodeURIComponent(chainId)}&connectId=${encodeURIComponent(appDid)}&appId=${encodeURIComponent(appDid)}`,\n this.#baseUrl,\n );\n const response = await fetch(url, {\n method: \"GET\",\n });\n if (response.ok) {\n const result = (await response.json()) as {\n credential: PowerhouseVerifiableCredential;\n };\n return result.credential;\n } else {\n throw new Error(`Failed to get credential: ${response.status}`);\n }\n }\n\n async verifyBearerToken(token: string) {\n return verifyAuthBearerToken(token);\n }\n\n async getBearerToken(options: CreateBearerTokenOptions) {\n if (!this.user) {\n throw new Error(\"User not found\");\n }\n return this.#crypto.getBearerToken(this.user.address, options);\n }\n}\n","import type { RenownEvents } from \"../types.js\";\nimport type { IEventEmitter } from \"./types.js\";\n\nexport class MemoryEventEmitter implements IEventEmitter<RenownEvents> {\n #listeners = new Map<keyof RenownEvents, Set<(data: unknown) => void>>();\n\n on<K extends keyof RenownEvents>(\n event: K,\n listener: (data: RenownEvents[K]) => void,\n ): () => void {\n if (!this.#listeners.has(event)) {\n this.#listeners.set(event, new Set());\n }\n this.#listeners.get(event)!.add(listener as (data: unknown) => void);\n return () => {\n this.#listeners.get(event)?.delete(listener as (data: unknown) => void);\n };\n }\n\n emit<K extends keyof RenownEvents>(event: K, data: RenownEvents[K]): void {\n this.#listeners.get(event)?.forEach((listener) => listener(data));\n }\n}\n","import type { ProfileFetcher, RenownProfile } from \"./types.js\";\n\nexport const fetchRenownProfile: ProfileFetcher = async (user, baseUrl) => {\n try {\n const response = await fetch(`${baseUrl}/api/profile`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n ethAddress: user.address,\n }),\n });\n\n if (!response.ok) {\n return undefined;\n }\n\n const result = (await response.json()) as {\n profile?: RenownProfile;\n };\n\n return result.profile ?? undefined;\n } catch {\n return undefined;\n }\n};\n","import { Renown, RenownMemoryStorage } from \"./common.js\";\nimport { DEFAULT_RENOWN_URL } from \"./constants.js\";\nimport { RenownCryptoBuilder } from \"./crypto/renown-crypto-builder.js\";\nimport type { IRenownCrypto, JsonWebKeyPairStorage } from \"./crypto/types.js\";\nimport { MemoryEventEmitter } from \"./event/memory.js\";\nimport { fetchRenownProfile } from \"./profile.js\";\nimport type {\n ProfileFetcher,\n RenownEventEmitter,\n RenownStorage,\n} from \"./types.js\";\n\nexport interface RenownBuilderOptions {\n appName: string;\n storage?: RenownStorage;\n eventEmitter?: RenownEventEmitter;\n crypto?: IRenownCrypto;\n keyPairStorage?: JsonWebKeyPairStorage;\n baseUrl?: string;\n profileFetcher?: ProfileFetcher;\n}\n\n/**\n * Base builder for creating Renown instances.\n * Use platform-specific builders (RenownBuilder from init.browser.js or init.node.js)\n * for pre-configured defaults.\n */\nexport class BaseRenownBuilder {\n #appName: string;\n #storage?: RenownStorage;\n #eventEmitter?: RenownEventEmitter;\n #crypto?: IRenownCrypto;\n #keyPairStorage?: JsonWebKeyPairStorage;\n #baseUrl?: string;\n #profileFetcher?: ProfileFetcher;\n\n /**\n * @param appName - Application name used for signing context\n */\n constructor(appName: string) {\n this.#appName = appName;\n }\n\n /**\n * Set custom storage for user data persistence.\n * Defaults to in-memory storage if not set.\n */\n withStorage(storage: RenownStorage): this {\n this.#storage = storage;\n return this;\n }\n\n /**\n * Set custom event emitter for user state changes.\n * Defaults to in-memory event emitter if not set.\n */\n withEventEmitter(eventEmitter: RenownEventEmitter): this {\n this.#eventEmitter = eventEmitter;\n return this;\n }\n\n /**\n * Set a pre-built crypto instance.\n * Either crypto or keyPairStorage must be provided.\n */\n withCrypto(crypto: IRenownCrypto): this {\n this.#crypto = crypto;\n return this;\n }\n\n /**\n * Set key pair storage for cryptographic keys.\n * A crypto instance will be built from this storage.\n * Either crypto or keyPairStorage must be provided.\n */\n withKeyPairStorage(keyPairStorage: JsonWebKeyPairStorage): this {\n this.#keyPairStorage = keyPairStorage;\n return this;\n }\n\n /**\n * Set the Renown server URL for credential verification.\n * Defaults to https://www.renown.id\n */\n withBaseUrl(baseUrl: string): this {\n this.#baseUrl = baseUrl;\n return this;\n }\n\n /**\n * Set a profile fetcher strategy for enriching user data after login.\n * The fetcher receives the authenticated user and the base URL,\n * and returns a RenownProfile. Called in the background after each login.\n * Defaults to fetchRenownProfile which calls the Renown API.\n */\n withProfileFetcher(profileFetcher: ProfileFetcher): this {\n this.#profileFetcher = profileFetcher;\n return this;\n }\n\n /**\n * Build and initialize the Renown instance.\n * If a user is stored, attempts to re-authenticate them.\n * @throws Error if neither crypto nor keyPairStorage is provided\n */\n async build(): Promise<Renown> {\n if (!this.#crypto && !this.#keyPairStorage) {\n throw new Error(\n \"Either crypto or keyPairStorage is required. Use withCrypto() or withKeyPairStorage() to set one.\",\n );\n }\n\n const crypto =\n this.#crypto ??\n (await new RenownCryptoBuilder()\n .withKeyPairStorage(this.#keyPairStorage!)\n .build());\n\n const storage = this.#storage ?? new RenownMemoryStorage();\n const eventEmitter = this.#eventEmitter ?? new MemoryEventEmitter();\n const baseUrl = this.#baseUrl ?? DEFAULT_RENOWN_URL;\n\n const renown = new Renown(\n storage,\n eventEmitter,\n crypto,\n this.#appName,\n baseUrl,\n this.#profileFetcher ?? fetchRenownProfile,\n );\n\n // Re-authenticate stored user if present\n if (renown.user) {\n try {\n await renown.login(renown.user.did);\n } catch (error) {\n console.error(\"Failed to re-authenticate user:\", error);\n }\n }\n\n return renown;\n }\n\n /**\n * Create a BaseRenownBuilder from options object for a more concise API\n */\n static from(options: RenownBuilderOptions): BaseRenownBuilder {\n const builder = new BaseRenownBuilder(options.appName);\n\n if (options.storage) {\n builder.withStorage(options.storage);\n }\n if (options.eventEmitter) {\n builder.withEventEmitter(options.eventEmitter);\n }\n if (options.crypto) {\n builder.withCrypto(options.crypto);\n }\n if (options.keyPairStorage) {\n builder.withKeyPairStorage(options.keyPairStorage);\n }\n if (options.baseUrl) {\n builder.withBaseUrl(options.baseUrl);\n }\n if (options.profileFetcher) {\n builder.withProfileFetcher(options.profileFetcher);\n }\n\n return builder;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"renown-builder-DP0iFzK1.js","names":["#store","#eventEmitter","#baseUrl","#crypto","#appName","#profileFetcher","#signer","#status","#updateStatus","#getCredential","#updateUser","#listeners","#appName","#storage","#eventEmitter","#crypto","#keyPairStorage","#baseUrl","#profileFetcher"],"sources":["../src/constants.ts","../src/credential.ts","../src/storage/common.ts","../src/common.ts","../src/event/memory.ts","../src/profile.ts","../src/renown-builder.ts"],"sourcesContent":["export const DEFAULT_RENOWN_URL = \"https://www.renown.id\";\nexport const DEFAULT_RENOWN_NETWORK_ID = \"eip155\";\nexport const DEFAULT_RENOWN_CHAIN_ID = \"1\";\n\nexport const DOMAIN_TYPE = [\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n] as const;\n\nexport const VERIFIABLE_CREDENTIAL_EIP712_TYPE = [\n { name: \"@context\", type: \"string[]\" },\n { name: \"type\", type: \"string[]\" },\n { name: \"id\", type: \"string\" },\n { name: \"issuer\", type: \"Issuer\" },\n { name: \"credentialSubject\", type: \"CredentialSubject\" },\n { name: \"credentialSchema\", type: \"CredentialSchema\" },\n { name: \"issuanceDate\", type: \"string\" },\n { name: \"expirationDate\", type: \"string\" },\n] as const;\n\nexport const CREDENTIAL_SCHEMA_EIP712_TYPE = [\n { name: \"id\", type: \"string\" },\n { name: \"type\", type: \"string\" },\n] as const;\n\nexport const CREDENTIAL_SUBJECT_TYPE = [\n { name: \"app\", type: \"string\" },\n { name: \"id\", type: \"string\" },\n] as const;\n\nexport const ISSUER_TYPE = [\n { name: \"id\", type: \"string\" },\n { name: \"ethereumAddress\", type: \"string\" },\n] as const;\n\nexport const CREDENTIAL_TYPES = {\n EIP712Domain: DOMAIN_TYPE,\n VerifiableCredential: VERIFIABLE_CREDENTIAL_EIP712_TYPE,\n CredentialSchema: CREDENTIAL_SCHEMA_EIP712_TYPE,\n CredentialSubject: CREDENTIAL_SUBJECT_TYPE,\n Issuer: ISSUER_TYPE,\n} as const;\n","import { recoverTypedDataAddress } from \"viem\";\nimport { CREDENTIAL_TYPES, DEFAULT_RENOWN_NETWORK_ID } from \"./constants.js\";\nimport type { PowerhouseVerifiableCredential } from \"./types.js\";\n\n/* Local structural aliases (EIP-712 standard shapes) so renown's public .d.ts\n * never names viem — a viem type in the surface drags viem's whole closure in. */\ntype Hex = `0x${string}`;\ntype TypedDataDomain = {\n name?: string;\n version?: string;\n chainId?: number;\n verifyingContract?: Hex;\n salt?: Hex;\n};\ntype TypedDataParameter = { name: string; type: string };\n\n/** EIP-712 domain as signed by the credential issuer. */\nexport type CredentialDomain = {\n version: string;\n chainId: number;\n};\n\n/** The credential body that is EIP-712 signed (everything except `proof`). */\nexport type CredentialMessage = {\n \"@context\": string[];\n type: string[];\n id: string;\n issuer: { id: string; ethereumAddress: Hex };\n credentialSubject: { id: string; app: string };\n credentialSchema: { id: string; type: string };\n issuanceDate: string;\n expirationDate: string;\n};\n\n/** Typed-data signer; matches the loose shape used by wallet adapters. */\nexport type SignCredentialTypedData = (args: {\n domain: TypedDataDomain;\n types: Record<string, readonly TypedDataParameter[]>;\n primaryType: string;\n message: Record<string, unknown>;\n}) => Promise<Hex>;\n\nexport interface BuildCredentialParams {\n signTypedData: SignCredentialTypedData;\n address: Hex;\n chainId: number;\n app: string;\n /** Credential subject id: the app/client DID the credential delegates to. */\n appId: string;\n expiresInDays?: number;\n}\n\n/** Assemble a Renown delegation VC and sign it with the provided signer. */\nexport async function buildAndSignCredential(\n params: BuildCredentialParams,\n): Promise<PowerhouseVerifiableCredential> {\n const {\n signTypedData,\n address,\n chainId,\n app,\n appId,\n expiresInDays = 7,\n } = params;\n\n const issuerId = `did:pkh:${DEFAULT_RENOWN_NETWORK_ID}:${chainId}:${address.toLowerCase()}`;\n const credentialId = `urn:uuid:${globalThis.crypto.randomUUID()}`;\n const now = new Date();\n const expirationDate = new Date(\n now.getTime() + expiresInDays * 24 * 60 * 60 * 1000,\n );\n\n const message: CredentialMessage = {\n \"@context\": [\"https://www.w3.org/2018/credentials/v1\"],\n type: [\"VerifiableCredential\", \"RenownCredential\"],\n id: credentialId,\n issuer: { id: issuerId, ethereumAddress: address },\n credentialSubject: { id: appId, app },\n credentialSchema: {\n id: \"https://renown.id/schemas/renown-credential/v1\",\n type: \"JsonSchemaValidator2018\",\n },\n issuanceDate: now.toISOString(),\n expirationDate: expirationDate.toISOString(),\n };\n\n const domain: CredentialDomain = { version: \"1\", chainId };\n\n // viem and most wallet adapters reserve EIP712Domain and derive it from\n // `domain` — passing it explicitly makes them throw.\n const { EIP712Domain, ...signTypes } = CREDENTIAL_TYPES;\n void EIP712Domain;\n const signature = await signTypedData({\n domain,\n types: signTypes,\n primaryType: \"VerifiableCredential\",\n message,\n });\n\n return {\n ...message,\n proof: {\n type: \"EthereumEip712Signature2021\",\n created: message.issuanceDate,\n verificationMethod: issuerId,\n proofPurpose: \"assertionMethod\",\n proofValue: signature,\n ethereumAddress: address,\n eip712: {\n domain,\n types: CREDENTIAL_TYPES,\n primaryType: \"VerifiableCredential\",\n },\n },\n };\n}\n\n/** Recover the address that signed a credential's EIP-712 proof. */\nexport async function recoverCredentialSigner(\n credential: PowerhouseVerifiableCredential,\n): Promise<Hex> {\n const { proof, ...message } = credential;\n // Drop EIP712Domain so viem derives it from `domain`; viem ignores\n // message keys not present in the types, so the proof is excluded too.\n const { EIP712Domain, ...types } = CREDENTIAL_TYPES;\n void EIP712Domain;\n return recoverTypedDataAddress({\n domain: proof.eip712.domain,\n types,\n primaryType: \"VerifiableCredential\",\n message,\n signature: proof.proofValue as Hex,\n } as Parameters<typeof recoverTypedDataAddress>[0]);\n}\n\n/** True when the proof was signed by the credential's declared issuer address. */\nexport async function verifyCredentialSignature(\n credential: PowerhouseVerifiableCredential,\n): Promise<boolean> {\n try {\n const recovered = await recoverCredentialSigner(credential);\n return (\n recovered.toLowerCase() ===\n credential.issuer.ethereumAddress.toLowerCase()\n );\n } catch {\n // Malformed proof (bad hex, missing fields) is an invalid signature.\n return false;\n }\n}\n","export interface IStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n Key extends keyof T = keyof T,\n> {\n get(key: Key): T[Key] | undefined;\n set(key: Key, value?: T[Key]): void;\n delete(key: Key): void;\n}\n\nexport abstract class BaseStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n Key extends keyof T = keyof T,\n> implements IStorage<T> {\n abstract get(key: Key): T[Key] | undefined;\n abstract set(key: Key, value?: T[Key]): void;\n abstract delete(key: Key): void;\n}\n\nexport class MemoryStorage<\n T extends Record<string, unknown> = Record<string, unknown>,\n Key extends keyof T = keyof T,\n> extends BaseStorage<T> {\n private readonly data = new Map<Key, T[Key]>();\n\n get(key: Key) {\n return this.data.get(key);\n }\n\n set(key: Key, value?: T[Key]): void {\n if (value === undefined) {\n this.data.delete(key);\n } else {\n this.data.set(key, value);\n }\n }\n\n delete(key: Key): void {\n this.data.delete(key);\n }\n}\n","import { CREDENTIAL_TYPES, DEFAULT_RENOWN_URL } from \"./constants.js\";\nimport { verifyCredentialSignature } from \"./credential.js\";\nimport { RenownCryptoSigner, type IRenownCrypto } from \"./crypto/index.js\";\nimport { MemoryStorage } from \"./storage/common.js\";\nimport type {\n CreateBearerTokenOptions,\n IProof,\n IRenown,\n ISigner,\n LoginStatus,\n PowerhouseVerifiableCredential,\n ProfileFetcher,\n RenownEventEmitter,\n RenownEvents,\n RenownStorage,\n RenownStorageMap,\n User,\n} from \"./types.js\";\nimport { parsePkhDid, verifyAuthBearerToken } from \"./utils.js\";\nexport * from \"./constants.js\";\n\nexport class RenownMemoryStorage extends MemoryStorage<RenownStorageMap> {}\n\nexport class Renown implements IRenown {\n #baseUrl: string;\n #store: RenownStorage;\n #eventEmitter: RenownEventEmitter;\n #appName: string;\n #crypto: IRenownCrypto;\n #signer: ISigner;\n #profileFetcher?: ProfileFetcher;\n #status: LoginStatus = \"initial\";\n\n constructor(\n store: RenownStorage,\n eventEmitter: RenownEventEmitter,\n crypto: IRenownCrypto,\n appName: string,\n baseUrl = DEFAULT_RENOWN_URL,\n profileFetcher?: ProfileFetcher,\n ) {\n this.#store = store;\n this.#eventEmitter = eventEmitter;\n this.#baseUrl = baseUrl;\n this.#crypto = crypto;\n this.#appName = appName;\n this.#profileFetcher = profileFetcher;\n this.#signer = new RenownCryptoSigner(crypto, this.#appName, this.user);\n\n this.on(\"user\", (user) => {\n this.#signer.user = user;\n });\n }\n\n get baseUrl() {\n return this.#baseUrl;\n }\n\n get user() {\n return this.#store.get(\"user\");\n }\n\n get status() {\n return this.#status;\n }\n\n get signer() {\n return this.#signer;\n }\n\n get crypto() {\n return this.#crypto;\n }\n\n get did() {\n return this.#crypto.did;\n }\n\n get profileFetcher() {\n return this.#profileFetcher;\n }\n\n #updateStatus(status: LoginStatus) {\n this.#status = status;\n this.#eventEmitter.emit(\"status\", status);\n }\n\n #updateUser(user: User | undefined) {\n if (user) {\n this.#store.set(\"user\", user);\n } else {\n this.#store.delete(\"user\");\n }\n this.#eventEmitter.emit(\"user\", user);\n }\n\n async login(userDid: string): Promise<User> {\n this.#updateStatus(\"checking\");\n try {\n const result = parsePkhDid(userDid);\n const credential = await this.#getCredential(\n result.address,\n result.chainId,\n this.#crypto.did,\n );\n\n if (!credential) {\n this.#updateUser(undefined);\n throw new Error(\"Credential not found\");\n }\n\n if (\n !(\n credential.issuer.id === userDid &&\n credential.credentialSubject.id === this.did\n )\n ) {\n throw new Error(\"Invalid credential\");\n }\n\n // The deployed Renown credential API may return proof.eip712 without\n // domain/types, despite the declared type. The domain is canonical\n // (version \"1\", the DID's chainId), so reconstruct it — the signature\n // verification below still fails if the credential wasn't signed for\n // that domain.\n const eip712 = credential.proof.eip712 as\n | Partial<IProof[\"eip712\"]>\n | undefined;\n const verifiableCredential: PowerhouseVerifiableCredential =\n eip712?.domain\n ? credential\n : {\n ...credential,\n proof: {\n ...credential.proof,\n eip712: {\n domain: { version: \"1\", chainId: result.chainId },\n types: CREDENTIAL_TYPES,\n primaryType: \"VerifiableCredential\",\n },\n },\n };\n\n // Verify the EIP-712 proof was signed by the DID's address on its chain.\n if (\n credential.issuer.ethereumAddress.toLowerCase() !==\n result.address.toLowerCase() ||\n verifiableCredential.proof.eip712.domain.chainId !== result.chainId ||\n !(await verifyCredentialSignature(verifiableCredential))\n ) {\n throw new Error(\"Invalid credential signature\");\n }\n\n const user: User = {\n ...result,\n address: credential.issuer.ethereumAddress,\n did: userDid,\n credential: verifiableCredential,\n };\n\n this.#updateUser(user);\n this.#updateStatus(\"authorized\");\n\n // Fetch profile data in the background if a fetcher is configured\n if (this.#profileFetcher) {\n this.#profileFetcher(user, this.#baseUrl)\n .then((profile) => {\n if (\n profile &&\n this.user?.address === user.address &&\n this.user.chainId === user.chainId\n ) {\n this.#updateUser({\n ...this.user,\n profile,\n ens: {\n name: profile.username ?? undefined,\n avatarUrl: profile.userImage ?? undefined,\n },\n });\n }\n })\n .catch(console.error);\n }\n\n return user;\n } catch (error) {\n this.#updateUser(undefined);\n this.#updateStatus(\"not-authorized\");\n throw error;\n }\n }\n\n logout() {\n this.#updateUser(undefined);\n this.#updateStatus(\"initial\");\n return Promise.resolve();\n }\n\n on<K extends keyof RenownEvents>(\n event: K,\n listener: (data: RenownEvents[K]) => void,\n ): () => void {\n return this.#eventEmitter.on(event, listener);\n }\n\n async #getCredential(\n address: string,\n chainId: number,\n appDid: string,\n ): Promise<PowerhouseVerifiableCredential | undefined> {\n if (!this.#baseUrl) {\n throw new Error(\"RENOWN_URL is not set\");\n }\n const url = new URL(\n `/api/auth/credential?address=${encodeURIComponent(address)}&chainId=${encodeURIComponent(chainId)}&connectId=${encodeURIComponent(appDid)}&appId=${encodeURIComponent(appDid)}`,\n this.#baseUrl,\n );\n const response = await fetch(url, {\n method: \"GET\",\n });\n if (response.ok) {\n const result = (await response.json()) as {\n credential: PowerhouseVerifiableCredential;\n };\n return result.credential;\n } else {\n throw new Error(`Failed to get credential: ${response.status}`);\n }\n }\n\n async verifyBearerToken(token: string) {\n return verifyAuthBearerToken(token);\n }\n\n async getBearerToken(options: CreateBearerTokenOptions) {\n if (!this.user) {\n throw new Error(\"User not found\");\n }\n return this.#crypto.getBearerToken(this.user.address, options);\n }\n}\n","import type { RenownEvents } from \"../types.js\";\nimport type { IEventEmitter } from \"./types.js\";\n\nexport class MemoryEventEmitter implements IEventEmitter<RenownEvents> {\n #listeners = new Map<keyof RenownEvents, Set<(data: unknown) => void>>();\n\n on<K extends keyof RenownEvents>(\n event: K,\n listener: (data: RenownEvents[K]) => void,\n ): () => void {\n if (!this.#listeners.has(event)) {\n this.#listeners.set(event, new Set());\n }\n this.#listeners.get(event)!.add(listener as (data: unknown) => void);\n return () => {\n this.#listeners.get(event)?.delete(listener as (data: unknown) => void);\n };\n }\n\n emit<K extends keyof RenownEvents>(event: K, data: RenownEvents[K]): void {\n this.#listeners.get(event)?.forEach((listener) => listener(data));\n }\n}\n","import type { ProfileFetcher, RenownProfile } from \"./types.js\";\n\nexport const fetchRenownProfile: ProfileFetcher = async (user, baseUrl) => {\n try {\n const response = await fetch(`${baseUrl.replace(/\\/+$/, \"\")}/api/profile`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n ethAddress: user.address,\n }),\n });\n\n if (!response.ok) {\n return undefined;\n }\n\n const result = (await response.json()) as {\n profile?: RenownProfile;\n };\n\n return result.profile ?? undefined;\n } catch {\n return undefined;\n }\n};\n","import { Renown, RenownMemoryStorage } from \"./common.js\";\nimport { DEFAULT_RENOWN_URL } from \"./constants.js\";\nimport { RenownCryptoBuilder } from \"./crypto/renown-crypto-builder.js\";\nimport type { IRenownCrypto, JsonWebKeyPairStorage } from \"./crypto/types.js\";\nimport { MemoryEventEmitter } from \"./event/memory.js\";\nimport { fetchRenownProfile } from \"./profile.js\";\nimport type {\n ProfileFetcher,\n RenownEventEmitter,\n RenownStorage,\n} from \"./types.js\";\n\nexport interface RenownBuilderOptions {\n appName: string;\n storage?: RenownStorage;\n eventEmitter?: RenownEventEmitter;\n crypto?: IRenownCrypto;\n keyPairStorage?: JsonWebKeyPairStorage;\n baseUrl?: string;\n profileFetcher?: ProfileFetcher;\n}\n\n/**\n * Base builder for creating Renown instances.\n * Use platform-specific builders (RenownBuilder from init.browser.js or init.node.js)\n * for pre-configured defaults.\n */\nexport class BaseRenownBuilder {\n #appName: string;\n #storage?: RenownStorage;\n #eventEmitter?: RenownEventEmitter;\n #crypto?: IRenownCrypto;\n #keyPairStorage?: JsonWebKeyPairStorage;\n #baseUrl?: string;\n #profileFetcher?: ProfileFetcher;\n\n /**\n * @param appName - Application name used for signing context\n */\n constructor(appName: string) {\n this.#appName = appName;\n }\n\n /**\n * Set custom storage for user data persistence.\n * Defaults to in-memory storage if not set.\n */\n withStorage(storage: RenownStorage): this {\n this.#storage = storage;\n return this;\n }\n\n /**\n * Set custom event emitter for user state changes.\n * Defaults to in-memory event emitter if not set.\n */\n withEventEmitter(eventEmitter: RenownEventEmitter): this {\n this.#eventEmitter = eventEmitter;\n return this;\n }\n\n /**\n * Set a pre-built crypto instance.\n * Either crypto or keyPairStorage must be provided.\n */\n withCrypto(crypto: IRenownCrypto): this {\n this.#crypto = crypto;\n return this;\n }\n\n /**\n * Set key pair storage for cryptographic keys.\n * A crypto instance will be built from this storage.\n * Either crypto or keyPairStorage must be provided.\n */\n withKeyPairStorage(keyPairStorage: JsonWebKeyPairStorage): this {\n this.#keyPairStorage = keyPairStorage;\n return this;\n }\n\n /**\n * Set the Renown server URL for credential verification.\n * Defaults to https://www.renown.id\n */\n withBaseUrl(baseUrl: string): this {\n this.#baseUrl = baseUrl;\n return this;\n }\n\n /**\n * Set a profile fetcher strategy for enriching user data after login.\n * The fetcher receives the authenticated user and the base URL,\n * and returns a RenownProfile. Called in the background after each login.\n * Defaults to fetchRenownProfile which calls the Renown API.\n */\n withProfileFetcher(profileFetcher: ProfileFetcher): this {\n this.#profileFetcher = profileFetcher;\n return this;\n }\n\n /**\n * Build and initialize the Renown instance.\n * If a user is stored, attempts to re-authenticate them.\n * @throws Error if neither crypto nor keyPairStorage is provided\n */\n async build(): Promise<Renown> {\n if (!this.#crypto && !this.#keyPairStorage) {\n throw new Error(\n \"Either crypto or keyPairStorage is required. Use withCrypto() or withKeyPairStorage() to set one.\",\n );\n }\n\n const crypto =\n this.#crypto ??\n (await new RenownCryptoBuilder()\n .withKeyPairStorage(this.#keyPairStorage!)\n .build());\n\n const storage = this.#storage ?? new RenownMemoryStorage();\n const eventEmitter = this.#eventEmitter ?? new MemoryEventEmitter();\n const baseUrl = this.#baseUrl ?? DEFAULT_RENOWN_URL;\n\n const renown = new Renown(\n storage,\n eventEmitter,\n crypto,\n this.#appName,\n baseUrl,\n this.#profileFetcher ?? fetchRenownProfile,\n );\n\n // Re-authenticate stored user if present\n if (renown.user) {\n try {\n await renown.login(renown.user.did);\n } catch (error) {\n console.error(\"Failed to re-authenticate user:\", error);\n }\n }\n\n return renown;\n }\n\n /**\n * Create a BaseRenownBuilder from options object for a more concise API\n */\n static from(options: RenownBuilderOptions): BaseRenownBuilder {\n const builder = new BaseRenownBuilder(options.appName);\n\n if (options.storage) {\n builder.withStorage(options.storage);\n }\n if (options.eventEmitter) {\n builder.withEventEmitter(options.eventEmitter);\n }\n if (options.crypto) {\n builder.withCrypto(options.crypto);\n }\n if (options.keyPairStorage) {\n builder.withKeyPairStorage(options.keyPairStorage);\n }\n if (options.baseUrl) {\n builder.withBaseUrl(options.baseUrl);\n }\n if (options.profileFetcher) {\n builder.withProfileFetcher(options.profileFetcher);\n }\n\n return builder;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@renown/sdk",
3
- "version": "6.2.0-dev.50",
3
+ "version": "6.2.0-dev.52",
4
4
  "description": "Renown SDK — wallet-based authentication and user identity management for Powerhouse React applications.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "private": false,
@@ -56,7 +56,7 @@
56
56
  "key-did-resolver": "^4.0.0",
57
57
  "uint8arrays": "^5.1.0",
58
58
  "viem": "~2.50.4",
59
- "@powerhousedao/shared": "6.2.0-dev.50"
59
+ "@powerhousedao/shared": "6.2.0-dev.52"
60
60
  },
61
61
  "keywords": [
62
62
  "powerhouse",