@happyvertical/smrt-profiles 0.35.1 → 0.35.3

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-B9lXQy7N.js","sources":["../../src/__smrt-register__.ts","../../src/models/MagicLinkToken.ts","../../src/collections/MagicLinkTokenCollection.ts","../../src/auth/magicLinkService.ts","../../src/auth/nip05Handler.ts","../../src/models/OidcIdentity.ts","../../src/auth/resolveIdentity.ts","../../src/collections/OidcIdentityCollection.ts","../../src/collections/ProfileTypeCollection.ts","../../src/models/ProfileTypes.ts"],"sourcesContent":["/**\n * Self-registers this package's build-time manifest before any @smrt() decorator\n * in the package fires. Fixes issue #1132: in consumer runtimes (tsx, SvelteKit\n * SSR, plain `vite dev`) the decorator's synchronous manifest lookup previously\n * missed because no step populated the global manifest cache — classes got\n * registered with zero fields and `save()` / `toJSON()` silently dropped every\n * declared property.\n *\n * Import this module as the first statement in `src/index.ts` so its top-level\n * side effect runs ahead of any class module's @smrt() decorator.\n *\n * Silent no-op in dev/test, where the vitest plugin already populates manifests\n * via a different path. Only needs to succeed in the published dist output.\n *\n * @see https://github.com/happyvertical/smrt/issues/1132\n */\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n// `new URL('./manifest.json', import.meta.url)` resolves at runtime to the\n// manifest sitting next to this module's compiled output. Vite warns at build\n// time that it cannot pre-resolve the URL; that is the intended behavior —\n// the URL must resolve to dist/manifest.json at runtime, not be inlined.\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","/**\n * MagicLinkToken - Temporary tokens for email verification\n *\n * Stores hashed magic link tokens with expiration. Tokens are single-use\n * and automatically invalidated after verification or expiration.\n */\n\nimport { createHash, randomBytes } from 'node:crypto';\nimport {\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport type { NostrIdentity } from './NostrIdentity';\n\nexport interface MagicLinkTokenOptions extends SmrtObjectOptions {\n nostrIdentityId?: string;\n tokenHash?: string;\n email?: string;\n expiresAt?: Date;\n usedAt?: Date | null;\n requestedFromIp?: string;\n createdAt?: Date;\n}\n\nexport interface GenerateTokenResult {\n /** The plaintext token (only available at creation time) */\n token: string;\n /** The MagicLinkToken record */\n magicLinkToken: MagicLinkToken;\n}\n\n/** Default token expiration: 15 minutes */\nconst DEFAULT_EXPIRATION_MINUTES = 15;\n\n@smrt({\n tableName: 'magic_link_tokens',\n api: { exclude: ['*'] }, // No API access - internal only\n mcp: { exclude: ['*'] },\n cli: { include: ['list'] }, // Admin visibility only\n})\nexport class MagicLinkToken extends SmrtObject {\n /**\n * Link to the NostrIdentity this token is for\n */\n @foreignKey('NostrIdentity', { required: true })\n nostrIdentityId?: string;\n\n /**\n * SHA-256 hash of the token (never store plaintext)\n */\n tokenHash: string = '';\n\n /**\n * Email this token was sent to\n */\n email: string = '';\n\n /**\n * When this token expires\n */\n expiresAt: Date = new Date(\n Date.now() + DEFAULT_EXPIRATION_MINUTES * 60 * 1000,\n );\n\n /**\n * When this token was used (null = unused)\n */\n usedAt: Date | null = null;\n\n /**\n * IP address that requested the token (for rate limiting)\n */\n requestedFromIp: string = '';\n\n /**\n * When this token was created (for rate limiting)\n */\n createdAt: Date = new Date();\n\n constructor(options: MagicLinkTokenOptions = {}) {\n super(options);\n if (options.nostrIdentityId) this.nostrIdentityId = options.nostrIdentityId;\n if (options.tokenHash) this.tokenHash = options.tokenHash;\n if (options.email) this.email = options.email;\n if (options.expiresAt) this.expiresAt = options.expiresAt;\n if (options.usedAt !== undefined) this.usedAt = options.usedAt;\n if (options.requestedFromIp) this.requestedFromIp = options.requestedFromIp;\n if (options.createdAt) this.createdAt = options.createdAt;\n }\n\n /**\n * Hash a token using SHA-256\n */\n static hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n }\n\n /**\n * Generate a new magic link token\n * @param nostrIdentity - The identity this token is for\n * @param email - The email address to send to\n * @param options - Additional options\n */\n static async generate(\n nostrIdentity: NostrIdentity,\n email: string,\n options: {\n expiresInMinutes?: number;\n requestedFromIp?: string;\n db?: SmrtObjectOptions['db'];\n } = {},\n ): Promise<GenerateTokenResult> {\n // Generate 32 bytes of random data (256 bits of entropy)\n const tokenBytes = randomBytes(32);\n const token = tokenBytes.toString('base64url');\n const tokenHash = MagicLinkToken.hashToken(token);\n\n const expiresInMinutes =\n options.expiresInMinutes ?? DEFAULT_EXPIRATION_MINUTES;\n const expiresAt = new Date(Date.now() + expiresInMinutes * 60 * 1000);\n\n const magicLinkToken = new MagicLinkToken({\n db: options.db ?? nostrIdentity.options?.db,\n nostrIdentityId: nostrIdentity.id as string,\n tokenHash,\n email: email.toLowerCase(),\n expiresAt,\n requestedFromIp: options.requestedFromIp || '',\n });\n\n await magicLinkToken.initialize();\n await magicLinkToken.save();\n\n return { token, magicLinkToken };\n }\n\n /**\n * Verify a token and return the MagicLinkToken if valid\n * @param token - The plaintext token to verify\n * @param options - Database options\n * @returns The MagicLinkToken if valid, null otherwise\n */\n static async verify(\n token: string,\n options: SmrtObjectOptions = {},\n ): Promise<MagicLinkToken | null> {\n const tokenHash = MagicLinkToken.hashToken(token);\n\n const { MagicLinkTokenCollection } = await import(\n '../collections/MagicLinkTokenCollection'\n );\n const collection = await MagicLinkTokenCollection.create(options);\n\n const magicLinkToken = await collection.findOne({\n where: { tokenHash },\n });\n\n if (!magicLinkToken) {\n return null;\n }\n\n // Check if valid\n if (!magicLinkToken.isValid()) {\n return null;\n }\n\n return magicLinkToken;\n }\n\n /**\n * Check if this token is valid (not expired and not used)\n */\n isValid(): boolean {\n if (this.usedAt !== null) {\n return false;\n }\n if (new Date() > this.expiresAt) {\n return false;\n }\n return true;\n }\n\n /**\n * Check if this token has expired\n */\n isExpired(): boolean {\n return new Date() > this.expiresAt;\n }\n\n /**\n * Check if this token has been used\n */\n isUsed(): boolean {\n return this.usedAt !== null;\n }\n\n /**\n * Mark this token as used\n */\n async markUsed(): Promise<void> {\n this.usedAt = new Date();\n await this.save();\n }\n\n /**\n * Get the NostrIdentity this token is for\n */\n async getNostrIdentity(): Promise<NostrIdentity | null> {\n return (await this.getRelated('nostrIdentityId')) as NostrIdentity | null;\n }\n\n /**\n * Get time remaining until expiration in seconds\n */\n getTimeRemainingSeconds(): number {\n const now = new Date();\n const diff = this.expiresAt.getTime() - now.getTime();\n return Math.max(0, Math.floor(diff / 1000));\n }\n}\n","/**\n * MagicLinkTokenCollection - Collection for managing magic link tokens\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { MagicLinkToken } from '../models/MagicLinkToken';\n\nexport class MagicLinkTokenCollection extends SmrtCollection<MagicLinkToken> {\n static readonly _itemClass = MagicLinkToken;\n\n /**\n * Find token by hash\n */\n async findByTokenHash(tokenHash: string): Promise<MagicLinkToken | null> {\n return await this.findOne({\n where: { tokenHash },\n });\n }\n\n /**\n * Find active (non-expired, non-used) tokens for an email\n */\n async findActiveForEmail(email: string): Promise<MagicLinkToken[]> {\n const tokens = await this.list({\n where: { email: email.toLowerCase() },\n });\n return tokens.filter((token) => token.isValid());\n }\n\n /**\n * Find tokens for a NostrIdentity\n */\n async findByIdentity(nostrIdentityId: string): Promise<MagicLinkToken[]> {\n return await this.list({\n where: { nostrIdentityId },\n });\n }\n\n /**\n * Count tokens created for an email within a time window (for rate limiting)\n * @param email - Email address\n * @param withinMinutes - Time window in minutes\n */\n async countRecentByEmail(\n email: string,\n withinMinutes: number,\n ): Promise<number> {\n const cutoff = new Date(Date.now() - withinMinutes * 60 * 1000);\n const tokens = await this.list({\n where: { email: email.toLowerCase() },\n });\n\n // Filter tokens created after cutoff\n // Note: We use createdAt from SmrtObject base\n return tokens.filter((token) => {\n const createdAt = token.createdAt;\n return createdAt && new Date(createdAt) > cutoff;\n }).length;\n }\n\n /**\n * Count tokens created from an IP within a time window (for rate limiting)\n * @param ip - IP address\n * @param withinMinutes - Time window in minutes\n */\n async countRecentByIp(ip: string, withinMinutes: number): Promise<number> {\n const cutoff = new Date(Date.now() - withinMinutes * 60 * 1000);\n const tokens = await this.list({\n where: { requestedFromIp: ip },\n });\n\n // Filter tokens created after cutoff\n return tokens.filter((token) => {\n const createdAt = token.createdAt;\n return createdAt && new Date(createdAt) > cutoff;\n }).length;\n }\n\n /**\n * Verify a token and return it if valid\n */\n async verify(token: string): Promise<MagicLinkToken | null> {\n const tokenHash = MagicLinkToken.hashToken(token);\n const magicLinkToken = await this.findByTokenHash(tokenHash);\n\n if (!magicLinkToken) {\n return null;\n }\n\n if (!magicLinkToken.isValid()) {\n return null;\n }\n\n return magicLinkToken;\n }\n\n /**\n * Clean up expired tokens by deleting them\n * @returns Number of tokens deleted\n */\n async cleanupExpired(): Promise<number> {\n const now = new Date();\n const allTokens = await this.list({});\n let deleted = 0;\n\n for (const token of allTokens) {\n if (token.isExpired() || token.isUsed()) {\n await token.delete();\n deleted++;\n }\n }\n\n return deleted;\n }\n\n /**\n * Revoke all tokens for a NostrIdentity (e.g., when identity is deleted)\n */\n async revokeForIdentity(nostrIdentityId: string): Promise<number> {\n const tokens = await this.findByIdentity(nostrIdentityId);\n let revoked = 0;\n\n for (const token of tokens) {\n if (!token.isUsed()) {\n await token.markUsed(); // Mark as used to invalidate\n revoked++;\n }\n }\n\n return revoked;\n }\n\n /**\n * Check if rate limit is exceeded for email\n * @param email - Email address\n * @param maxPerHour - Maximum tokens allowed per hour (default: 5)\n */\n async isRateLimitedByEmail(\n email: string,\n maxPerHour: number = 5,\n ): Promise<boolean> {\n const count = await this.countRecentByEmail(email, 60);\n return count >= maxPerHour;\n }\n\n /**\n * Check if rate limit is exceeded for IP\n * @param ip - IP address\n * @param maxPerHour - Maximum tokens allowed per hour (default: 10)\n */\n async isRateLimitedByIp(\n ip: string,\n maxPerHour: number = 10,\n ): Promise<boolean> {\n const count = await this.countRecentByIp(ip, 60);\n return count >= maxPerHour;\n }\n}\n","/**\n * Magic Link Service\n *\n * Handles the magic link authentication flow including:\n * - Token generation and storage\n * - Email sending (via callback)\n * - Token verification\n * - Rate limiting checks\n */\n\nimport type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport { MagicLinkTokenCollection } from '../collections/MagicLinkTokenCollection';\nimport { NostrIdentityCollection } from '../collections/NostrIdentityCollection';\nimport { MagicLinkToken } from '../models/MagicLinkToken';\nimport type { NostrIdentity } from '../models/NostrIdentity';\nimport type { Profile } from '../models/Profile';\nimport { encryptPrivkey, generateNostrKeypair } from './nostrCrypto';\n\nexport interface MagicLinkConfig {\n /** Base URL for magic links (e.g., \"https://example.com\") */\n baseUrl: string;\n /** Path for verification endpoint (default: \"/auth/verify\") */\n verifyPath?: string;\n /** Token expiration in minutes (default: 15) */\n expiresInMinutes?: number;\n /** Maximum tokens per email per hour (default: 5) */\n maxTokensPerEmailPerHour?: number;\n /** Maximum tokens per IP per hour (default: 10) */\n maxTokensPerIpPerHour?: number;\n /** Server master secret for encryption */\n masterSecret: string;\n /** Callback to send the email */\n sendEmail: (to: string, magicLink: string) => Promise<void>;\n /** Database options */\n db: SmrtObjectOptions['db'];\n}\n\nexport interface InitiateResult {\n success: boolean;\n /** The Nostr identity (existing or new) */\n nostrIdentity?: NostrIdentity;\n /** The profile (existing or new) */\n profile?: Profile;\n /** True if a new profile was created */\n created: boolean;\n /** Error message if success is false */\n error?: string;\n /** Error code for programmatic handling */\n errorCode?: 'RATE_LIMITED_EMAIL' | 'RATE_LIMITED_IP' | 'EMAIL_SEND_FAILED';\n}\n\nexport interface VerifyResult {\n success: boolean;\n /** The profile */\n profile?: Profile;\n /** The Nostr identity */\n nostrIdentity?: NostrIdentity;\n /** The decrypted keypair (only on success) */\n keypair?: {\n pubkey: string;\n privkey: string;\n npub: string;\n nsec: string;\n };\n /** Error message if success is false */\n error?: string;\n /** Error code for programmatic handling */\n errorCode?: 'INVALID_TOKEN' | 'EXPIRED_TOKEN' | 'USED_TOKEN' | 'NOT_FOUND';\n}\n\nexport interface MagicLinkService {\n /**\n * Initiate magic link flow - generates token and sends email\n */\n initiate(\n email: string,\n options?: {\n requestedFromIp?: string;\n nip05Username?: string;\n },\n ): Promise<InitiateResult>;\n\n /**\n * Verify a magic link token and return decrypted keypair\n */\n verify(token: string): Promise<VerifyResult>;\n}\n\n/**\n * Create a magic link service instance\n */\nexport function createMagicLinkService(\n config: MagicLinkConfig,\n): MagicLinkService {\n const {\n baseUrl,\n verifyPath = '/auth/verify',\n expiresInMinutes = 15,\n maxTokensPerEmailPerHour = 5,\n maxTokensPerIpPerHour = 10,\n masterSecret,\n sendEmail,\n db,\n } = config;\n\n return {\n async initiate(\n email: string,\n options: {\n requestedFromIp?: string;\n nip05Username?: string;\n } = {},\n ): Promise<InitiateResult> {\n const normalizedEmail = email.toLowerCase().trim();\n const { requestedFromIp, nip05Username } = options;\n\n // Create collections\n const identityCollection = await NostrIdentityCollection.create({ db });\n const tokenCollection = await MagicLinkTokenCollection.create({ db });\n\n // Rate limiting checks\n if (\n await tokenCollection.isRateLimitedByEmail(\n normalizedEmail,\n maxTokensPerEmailPerHour,\n )\n ) {\n return {\n success: false,\n created: false,\n error: 'Too many requests for this email. Please try again later.',\n errorCode: 'RATE_LIMITED_EMAIL',\n };\n }\n\n if (\n requestedFromIp &&\n (await tokenCollection.isRateLimitedByIp(\n requestedFromIp,\n maxTokensPerIpPerHour,\n ))\n ) {\n return {\n success: false,\n created: false,\n error: 'Too many requests from this IP. Please try again later.',\n errorCode: 'RATE_LIMITED_IP',\n };\n }\n\n // Check if identity exists\n let nostrIdentity = await identityCollection.findByEmail(normalizedEmail);\n let profile: Profile | null = null;\n let created = false;\n\n if (!nostrIdentity) {\n // Create new identity and profile\n const { Person } = await import('../models/ProfileTypes');\n const { ProfileTypeCollection } = await import(\n '../collections/ProfileTypeCollection'\n );\n\n // Profile.typeId is a required FK, so resolve (or seed) the canonical\n // 'person' type before creating the profile — otherwise `.save()`\n // fails required-field validation. Mirrors createProfileFromNostr /\n // createProfileFromOidc in resolveIdentity.ts.\n const typeCollection = await ProfileTypeCollection.create({ db });\n let personType = await typeCollection.getBySlug('person');\n if (!personType) {\n const { ProfileType } = await import('../models/ProfileType');\n personType = new ProfileType({\n db,\n slug: 'person',\n name: 'Person',\n description: 'Individual person profile',\n });\n await personType.initialize();\n await personType.save();\n }\n\n // Create a new profile for this user (Person is an STI subclass of Profile)\n profile = new Person({\n db,\n typeId: personType.id as string,\n email: normalizedEmail,\n name: normalizedEmail.split('@')[0], // Default name from email\n });\n await profile.initialize();\n await profile.save();\n\n // Generate keypair and encrypt\n const keypair = generateNostrKeypair();\n const encrypted = encryptPrivkey(keypair.privkey, masterSecret);\n\n // Create Nostr identity\n const { NostrIdentity: NostrIdentityClass } = await import(\n '../models/NostrIdentity'\n );\n nostrIdentity = new NostrIdentityClass({\n db,\n profileId: profile.id!,\n pubkey: keypair.pubkey,\n encryptedPrivkey: encrypted.ciphertext,\n encryptionIv: encrypted.iv,\n encryptionTag: encrypted.tag,\n email: normalizedEmail,\n nip05Username:\n nip05Username?.toLowerCase() || normalizedEmail.split('@')[0],\n });\n await nostrIdentity.initialize();\n await nostrIdentity.save();\n\n created = true;\n } else {\n profile = await nostrIdentity.getProfile();\n }\n\n // Generate magic link token\n const { token } = await MagicLinkToken.generate(\n nostrIdentity,\n normalizedEmail,\n {\n expiresInMinutes,\n requestedFromIp,\n db,\n },\n );\n\n // Build magic link URL\n const magicLink = `${baseUrl}${verifyPath}?token=${encodeURIComponent(token)}`;\n\n // Send email\n try {\n await sendEmail(normalizedEmail, magicLink);\n } catch (emailError) {\n return {\n success: false,\n created,\n nostrIdentity,\n profile: profile || undefined,\n error: 'Failed to send email. Please try again.',\n errorCode: 'EMAIL_SEND_FAILED',\n };\n }\n\n return {\n success: true,\n created,\n nostrIdentity,\n profile: profile || undefined,\n };\n },\n\n async verify(token: string): Promise<VerifyResult> {\n // Verify token\n const magicLinkToken = await MagicLinkToken.verify(token, { db });\n\n if (!magicLinkToken) {\n // Try to get more specific error\n const tokenHash = MagicLinkToken.hashToken(token);\n const tokenCollection = await MagicLinkTokenCollection.create({ db });\n const existingToken = await tokenCollection.findByTokenHash(tokenHash);\n\n if (!existingToken) {\n return {\n success: false,\n error: 'Invalid or expired token.',\n errorCode: 'NOT_FOUND',\n };\n }\n\n if (existingToken.isUsed()) {\n return {\n success: false,\n error: 'This link has already been used.',\n errorCode: 'USED_TOKEN',\n };\n }\n\n if (existingToken.isExpired()) {\n return {\n success: false,\n error: 'This link has expired. Please request a new one.',\n errorCode: 'EXPIRED_TOKEN',\n };\n }\n\n return {\n success: false,\n error: 'Invalid token.',\n errorCode: 'INVALID_TOKEN',\n };\n }\n\n // Mark token as used\n await magicLinkToken.markUsed();\n\n // Get the Nostr identity\n const nostrIdentity = await magicLinkToken.getNostrIdentity();\n if (!nostrIdentity) {\n return {\n success: false,\n error: 'Identity not found.',\n errorCode: 'NOT_FOUND',\n };\n }\n\n // Mark identity as verified\n await nostrIdentity.markVerified();\n\n // Get profile\n const profile = await nostrIdentity.getProfile();\n\n // Decrypt keypair\n const keypair = nostrIdentity.getKeypair(masterSecret);\n\n return {\n success: true,\n profile: profile || undefined,\n nostrIdentity,\n keypair,\n };\n },\n };\n}\n","/**\n * NIP-05 Handler\n *\n * Provides a helper for serving the /.well-known/nostr.json endpoint\n * for NIP-05 identity verification.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/05.md\n */\n\nimport type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n type Nip05Response,\n NostrIdentityCollection,\n} from '../collections/NostrIdentityCollection';\n\nexport interface Nip05HandlerConfig {\n /** Database options */\n db: SmrtObjectOptions['db'];\n /** Optional: Additional relays to include for all users */\n defaultRelays?: string[];\n /** Optional: Cache TTL in seconds (default: 300 = 5 minutes) */\n cacheTtlSeconds?: number;\n}\n\nexport interface Nip05Request {\n /** The 'name' query parameter from the request */\n name?: string | null;\n}\n\nexport interface Nip05HandlerResult {\n /** The NIP-05 response body */\n body: Nip05Response;\n /** Suggested headers for the response */\n headers: Record<string, string>;\n /** HTTP status code */\n status: number;\n}\n\n/**\n * Create a NIP-05 handler\n *\n * @example\n * // SvelteKit\n * import { createNip05Handler } from '@happyvertical/smrt-profiles';\n *\n * const handler = createNip05Handler({ db: { type: 'postgres', url: DATABASE_URL } });\n *\n * export async function GET({ url }) {\n * const result = await handler({ name: url.searchParams.get('name') });\n * return new Response(JSON.stringify(result.body), {\n * status: result.status,\n * headers: result.headers,\n * });\n * }\n *\n * @example\n * // Express\n * import { createNip05Handler } from '@happyvertical/smrt-profiles';\n *\n * const handler = createNip05Handler({ db: { type: 'postgres', url: DATABASE_URL } });\n *\n * app.get('/.well-known/nostr.json', async (req, res) => {\n * const result = await handler({ name: req.query.name });\n * res.status(result.status).set(result.headers).json(result.body);\n * });\n */\nexport function createNip05Handler(config: Nip05HandlerConfig) {\n const { db, defaultRelays = [], cacheTtlSeconds = 300 } = config;\n\n return async function handleNip05Request(\n request: Nip05Request,\n ): Promise<Nip05HandlerResult> {\n const { name } = request;\n\n const collection = await NostrIdentityCollection.create({ db });\n const response = await collection.getNip05Response(name || undefined);\n\n // Add default relays if configured\n if (defaultRelays.length > 0 && Object.keys(response.names).length > 0) {\n response.relays = {};\n for (const pubkey of Object.values(response.names)) {\n response.relays[pubkey] = defaultRelays;\n }\n }\n\n // If specific name requested but not found, return empty names\n if (name && Object.keys(response.names).length === 0) {\n return {\n body: { names: {} },\n headers: {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n 'Cache-Control': `public, max-age=${cacheTtlSeconds}`,\n },\n status: 200, // NIP-05 spec says return 200 with empty names, not 404\n };\n }\n\n return {\n body: response,\n headers: {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n 'Cache-Control': `public, max-age=${cacheTtlSeconds}`,\n },\n status: 200,\n };\n };\n}\n\n/**\n * Validate a NIP-05 identifier format\n * @param identifier - The identifier to validate (e.g., \"alice@example.com\")\n */\nexport function isValidNip05Identifier(identifier: string): boolean {\n // NIP-05 format: <local-part>@<domain>\n const parts = identifier.split('@');\n if (parts.length !== 2) {\n return false;\n }\n\n const [localPart, domain] = parts;\n\n // Local part: alphanumeric, _, -\n if (!/^[a-z0-9_-]+$/i.test(localPart)) {\n return false;\n }\n\n // Domain: basic domain validation\n if (!/^[a-z0-9.-]+\\.[a-z]{2,}$/i.test(domain)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Parse a NIP-05 identifier into its parts\n * @param identifier - The identifier to parse (e.g., \"alice@example.com\")\n */\nexport function parseNip05Identifier(identifier: string): {\n localPart: string;\n domain: string;\n} | null {\n if (!isValidNip05Identifier(identifier)) {\n return null;\n }\n\n const [localPart, domain] = identifier.split('@');\n return { localPart, domain };\n}\n","/**\n * OidcIdentity - Links OIDC provider identities to Profile\n *\n * Stores the mapping between external OIDC providers (Keycloak, Google, GitHub)\n * and internal Profile records. Multiple identities can link to a single profile.\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport type { Profile } from './Profile';\n\nexport interface OidcIdentityOptions extends SmrtObjectOptions {\n profileId?: string;\n provider?: string;\n issuer?: string;\n subject?: string;\n email?: string;\n lastUsedAt?: Date | null;\n}\n\n@smrt({\n tableName: 'oidc_identities',\n api: { exclude: ['delete'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class OidcIdentity extends SmrtObject {\n /**\n * Link to the Profile (Person, Organization, Bot)\n */\n @foreignKey('Profile', { required: true })\n profileId?: string;\n\n /**\n * Provider name (e.g., 'keycloak', 'google', 'github')\n */\n @field({ type: 'text' })\n provider: string = '';\n\n /**\n * OIDC issuer URL (e.g., https://keycloak.example.com/realms/bmp)\n */\n @field({ type: 'text' })\n issuer: string = '';\n\n /**\n * OIDC subject claim - unique identifier from the provider\n */\n @field({ type: 'text' })\n subject: string = '';\n\n /**\n * Cached email from the IdP (for display/lookup)\n */\n @field({ type: 'text' })\n email: string = '';\n\n /**\n * Last time this identity was used for authentication\n */\n @field({ type: 'datetime', nullable: true })\n lastUsedAt: Date | null = null;\n\n constructor(options: OidcIdentityOptions = {}) {\n super(options);\n if (options.profileId) this.profileId = options.profileId;\n if (options.provider) this.provider = options.provider;\n if (options.issuer) this.issuer = options.issuer;\n if (options.subject) this.subject = options.subject;\n if (options.email) this.email = options.email;\n if (options.lastUsedAt !== undefined) this.lastUsedAt = options.lastUsedAt;\n }\n\n /**\n * Get the linked Profile\n */\n async getProfile(): Promise<Profile | null> {\n return (await this.getRelated('profileId')) as Profile | null;\n }\n\n /**\n * Find identity by issuer and subject\n */\n static async findBySubject(\n issuer: string,\n subject: string,\n options: SmrtObjectOptions = {},\n ): Promise<OidcIdentity | null> {\n const { OidcIdentityCollection } = await import(\n '../collections/OidcIdentityCollection'\n );\n const collection = await OidcIdentityCollection.create(options);\n return await collection.findOne({\n where: { issuer, subject },\n });\n }\n\n /**\n * Find or create identity for a profile\n */\n static async findOrCreate(\n profile: Profile,\n oidcData: {\n provider: string;\n issuer: string;\n subject: string;\n email?: string;\n },\n options: SmrtObjectOptions = {},\n ): Promise<OidcIdentity> {\n const existing = await OidcIdentity.findBySubject(\n oidcData.issuer,\n oidcData.subject,\n options,\n );\n\n if (existing) {\n // Update last used\n existing.lastUsedAt = new Date();\n if (oidcData.email) existing.email = oidcData.email;\n await existing.save();\n return existing;\n }\n\n // Create new\n const identity = new OidcIdentity({\n ...options,\n profileId: profile.id as string,\n provider: oidcData.provider,\n issuer: oidcData.issuer,\n subject: oidcData.subject,\n email: oidcData.email || '',\n });\n await identity.initialize();\n await identity.save();\n return identity;\n }\n\n /**\n * Record usage of this identity\n */\n async recordUsage(): Promise<void> {\n this.lastUsedAt = new Date();\n await this.save();\n }\n}\n","/**\n * resolveIdentity - Resolves authentication context to a Profile\n *\n * Used by apps (blindmanpress.com) to resolve incoming auth to a Profile.\n * Modules (aedile, praeco) should receive the resolved profile from the app.\n *\n * Resolution order:\n * 1. API key header → ApiKey → Profile\n * 2. OIDC session → OidcIdentity → Profile\n * 3. Nostr auth → NostrIdentity → Profile\n * 4. Actor header (CI pass-through) → Profile lookup\n */\n\nimport type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport { ApiKey } from '../models/ApiKey';\nimport { NostrIdentity } from '../models/NostrIdentity';\nimport { OidcIdentity } from '../models/OidcIdentity';\nimport type { Profile } from '../models/Profile';\nimport { type NostrEvent, verifyAuthEvent } from './nostrCrypto';\n\n/**\n * Context provided to resolveIdentity\n */\nexport interface AuthContext {\n /**\n * API key from X-API-Key header or similar\n */\n apiKey?: string | null;\n\n /**\n * OIDC session data (from @auth/sveltekit or similar)\n */\n oidcSession?: {\n sub?: string;\n iss?: string;\n email?: string;\n name?: string;\n } | null;\n\n /**\n * Actor identifier for CI pass-through identity\n * Usually the GitHub actor (username) who triggered the workflow\n */\n actor?: string | null;\n\n /**\n * Nostr authentication data (NIP-42 style)\n */\n nostrAuth?: {\n /** Signed Nostr event for authentication */\n event: NostrEvent;\n /** Expected challenge (to prevent replay attacks) */\n challenge: string;\n } | null;\n\n /**\n * Database/persistence options\n */\n db?: SmrtObjectOptions['db'];\n}\n\n/**\n * Result of identity resolution\n */\nexport interface ResolveIdentityResult {\n /**\n * The resolved profile, or null if not authenticated\n */\n profile: Profile | null;\n\n /**\n * How the identity was resolved\n */\n source: 'api_key' | 'oidc' | 'nostr' | 'actor' | 'none';\n\n /**\n * The API key record if authenticated via API key\n */\n apiKey?: ApiKey;\n\n /**\n * The OIDC identity record if authenticated via OIDC\n */\n oidcIdentity?: OidcIdentity;\n\n /**\n * The Nostr identity record if authenticated via Nostr\n */\n nostrIdentity?: NostrIdentity;\n}\n\n/**\n * Resolve authentication context to a Profile\n *\n * @param context - The authentication context from the request\n * @returns The resolved profile and metadata\n *\n * @example\n * ```typescript\n * // In SvelteKit hooks.server.ts\n * import { resolveIdentity } from '@happyvertical/smrt-profiles';\n *\n * const identityMiddleware: Handle = async ({ event, resolve }) => {\n * const session = await event.locals.auth();\n *\n * const { profile, source } = await resolveIdentity({\n * oidcSession: session,\n * apiKey: event.request.headers.get('X-API-Key'),\n * actor: event.request.headers.get('X-Actor'),\n * db: { type: 'postgres', url: DATABASE_URL },\n * });\n *\n * event.locals.profile = profile;\n * event.locals.authSource = source;\n *\n * return resolve(event);\n * };\n * ```\n */\nexport async function resolveIdentity(\n context: AuthContext,\n): Promise<ResolveIdentityResult> {\n const options: SmrtObjectOptions = { db: context.db };\n\n // 1. Check API key header first (highest priority for programmatic access)\n if (context.apiKey) {\n const apiKey = await ApiKey.verify(context.apiKey, options);\n if (apiKey) {\n const profile = await apiKey.getProfile();\n if (profile) {\n return {\n profile,\n source: 'api_key',\n apiKey,\n };\n }\n }\n }\n\n // 2. Check OIDC session (web users)\n if (context.oidcSession?.sub && context.oidcSession?.iss) {\n const oidcIdentity = await OidcIdentity.findBySubject(\n context.oidcSession.iss,\n context.oidcSession.sub,\n options,\n );\n\n if (oidcIdentity) {\n // Record usage\n await oidcIdentity.recordUsage();\n\n const profile = await oidcIdentity.getProfile();\n if (profile) {\n return {\n profile,\n source: 'oidc',\n oidcIdentity,\n };\n }\n }\n }\n\n // 3. Check Nostr auth (NIP-42 style signed event)\n if (context.nostrAuth?.event && context.nostrAuth?.challenge) {\n const { event, challenge } = context.nostrAuth;\n\n // Verify the auth event\n const verifyResult = verifyAuthEvent(event, challenge);\n if (verifyResult.valid) {\n // Look up identity by public key\n const nostrIdentity = await NostrIdentity.findByPubkey(\n event.pubkey,\n options,\n );\n\n if (nostrIdentity) {\n // Record usage\n await nostrIdentity.recordUsage();\n\n const profile = await nostrIdentity.getProfile();\n if (profile) {\n return {\n profile,\n source: 'nostr',\n nostrIdentity,\n };\n }\n }\n }\n }\n\n // 4. Check actor for CI pass-through (look up by metadata)\n if (context.actor) {\n const profile = await findProfileByExternalId(\n 'github',\n context.actor,\n options,\n );\n if (profile) {\n return {\n profile,\n source: 'actor',\n };\n }\n }\n\n // No authentication found\n return {\n profile: null,\n source: 'none',\n };\n}\n\n/**\n * Find a profile by external ID (e.g., GitHub username)\n *\n * This looks up profiles by their linked external identities or metadata.\n *\n * @param provider - The external provider (e.g., 'github')\n * @param externalId - The external identifier (e.g., GitHub username)\n * @param options - Database options\n * @returns The profile or null\n */\nasync function findProfileByExternalId(\n provider: string,\n externalId: string,\n options: SmrtObjectOptions,\n): Promise<Profile | null> {\n // First check OIDC identities (if they use the provider)\n const { OidcIdentityCollection } = await import(\n '../collections/OidcIdentityCollection'\n );\n\n const oidcCollection = await OidcIdentityCollection.create(options);\n const identities = await oidcCollection.findByProvider(provider);\n\n for (const identity of identities) {\n // Check if the subject matches the external ID\n if (\n identity.subject === externalId ||\n identity.email?.includes(externalId)\n ) {\n const profile = await identity.getProfile();\n if (profile) return profile;\n }\n }\n\n // Could also check profile metadata for external IDs\n // This would require a standardized metadata field like 'github_username'\n const { ProfileCollection } = await import(\n '../collections/ProfileCollection'\n );\n const profileCollection = await ProfileCollection.create(options);\n\n // Try to find by email that looks like a GitHub noreply\n const profiles = await profileCollection.list({\n where: {\n email: `${externalId}@users.noreply.github.com`,\n },\n limit: 1,\n });\n\n if (profiles.length > 0) {\n return profiles[0];\n }\n\n return null;\n}\n\n/**\n * Create a profile from OIDC claims if it doesn't exist\n *\n * Supports email-based account linking: if a user signs in with Google\n * and later with GitHub using the same email, they get the same profile.\n *\n * Resolution order:\n * 1. If OIDC identity (iss + sub) already exists → return linked profile\n * 2. If verified email provided, check if profile with same email exists → link new identity\n * 3. Otherwise, create new profile + identity\n *\n * Security considerations:\n * - Email-based linking only occurs when `email_verified` is true. This prevents\n * attackers from claiming unverified emails to hijack accounts.\n * - Linking is automatic and irreversible through this API. Multiple OIDC\n * identities from different providers sharing the same verified email will\n * be associated to the same Profile.\n * - If an OIDC provider does not supply an email, or the email changes later,\n * existing links are not automatically updated. New sign-ins without an email\n * or with a different email may result in a new Profile being created.\n * - This function trusts the OIDC provider to assert correct email_verified status.\n * Only use with trusted providers.\n *\n * @param claims - OIDC token claims\n * @param provider - Provider name (e.g., 'keycloak', 'google', 'github')\n * @param options - Database options\n * @returns The created or existing profile with linked OIDC identity\n */\nexport async function createProfileFromOidc(\n claims: {\n sub: string;\n iss: string;\n email?: string;\n email_verified?: boolean;\n name?: string;\n preferred_username?: string;\n },\n provider: string,\n options: SmrtObjectOptions,\n): Promise<{ profile: Profile; oidcIdentity: OidcIdentity; created: boolean }> {\n // 1. If OIDC identity already exists for this issuer+subject, return linked profile\n const existingIdentity = await OidcIdentity.findBySubject(\n claims.iss,\n claims.sub,\n options,\n );\n\n if (existingIdentity) {\n const profile = await existingIdentity.getProfile();\n if (profile) {\n // Update identity with latest claims\n if (claims.email) existingIdentity.email = claims.email;\n existingIdentity.lastUsedAt = new Date();\n await existingIdentity.save();\n\n return {\n profile,\n oidcIdentity: existingIdentity,\n created: false,\n };\n }\n }\n\n // 2. Email-based account linking: only link if email is verified (security)\n if (claims.email && claims.email_verified) {\n const { ProfileCollection } = await import(\n '../collections/ProfileCollection'\n );\n\n const profileCollection = await ProfileCollection.create(options);\n const existingProfile = await profileCollection.findByEmail(claims.email);\n\n if (existingProfile) {\n // Link new OIDC identity to existing profile (email-based linking)\n const oidcIdentity = await OidcIdentity.findOrCreate(\n existingProfile,\n {\n provider,\n issuer: claims.iss,\n subject: claims.sub,\n email: claims.email,\n },\n options,\n );\n\n return {\n profile: existingProfile,\n oidcIdentity,\n created: false,\n };\n }\n }\n\n // 3. Create new profile\n const { Person } = await import('../models/ProfileTypes');\n const { ProfileTypeCollection } = await import(\n '../collections/ProfileTypeCollection'\n );\n\n // Get or create the 'person' type\n const typeCollection = await ProfileTypeCollection.create(options);\n let personType = await typeCollection.getBySlug('person');\n\n if (!personType) {\n // Create the person type if it doesn't exist\n const { ProfileType } = await import('../models/ProfileType');\n personType = new ProfileType({\n ...options,\n slug: 'person',\n name: 'Person',\n description: 'Individual person profile',\n });\n await personType.initialize();\n await personType.save();\n }\n\n const profile = new Person({\n ...options,\n typeId: personType.id as string,\n email: claims.email || '',\n name: claims.name || claims.preferred_username || claims.sub,\n });\n await profile.initialize();\n await profile.save();\n\n // Link OIDC identity\n const oidcIdentity = await OidcIdentity.findOrCreate(\n profile,\n {\n provider,\n issuer: claims.iss,\n subject: claims.sub,\n email: claims.email,\n },\n options,\n );\n\n return {\n profile,\n oidcIdentity,\n created: true,\n };\n}\n\n/**\n * Create a profile from Nostr identity (used by magic link service)\n *\n * This is typically called internally by the magic link service,\n * but can be used directly if needed.\n *\n * @param email - Email address for the profile\n * @param nostrData - Encrypted Nostr keypair data\n * @param options - Database options\n * @returns The created profile with linked Nostr identity\n */\nexport async function createProfileFromNostr(\n email: string,\n nostrData: {\n pubkey: string;\n encryptedPrivkey: string;\n encryptionIv: string;\n encryptionTag: string;\n nip05Username?: string;\n },\n options: SmrtObjectOptions,\n): Promise<{\n profile: Profile;\n nostrIdentity: NostrIdentity;\n created: boolean;\n}> {\n const normalizedEmail = email.toLowerCase();\n\n // Check if Nostr identity already exists\n const existingIdentity = await NostrIdentity.findByEmail(\n normalizedEmail,\n options,\n );\n\n if (existingIdentity) {\n const profile = await existingIdentity.getProfile();\n if (profile) {\n return {\n profile,\n nostrIdentity: existingIdentity,\n created: false,\n };\n }\n }\n\n // Create new profile\n const { Person } = await import('../models/ProfileTypes');\n const { ProfileTypeCollection } = await import(\n '../collections/ProfileTypeCollection'\n );\n\n // Get or create the 'person' type\n const typeCollection = await ProfileTypeCollection.create(options);\n let personType = await typeCollection.getBySlug('person');\n\n if (!personType) {\n const { ProfileType } = await import('../models/ProfileType');\n personType = new ProfileType({\n ...options,\n slug: 'person',\n name: 'Person',\n description: 'Individual person profile',\n });\n await personType.initialize();\n await personType.save();\n }\n\n const profile = new Person({\n ...options,\n typeId: personType.id as string,\n email: normalizedEmail,\n name: normalizedEmail.split('@')[0], // Default name from email\n });\n await profile.initialize();\n await profile.save();\n\n // Create Nostr identity\n const nostrIdentity = new NostrIdentity({\n ...options,\n profileId: profile.id as string,\n pubkey: nostrData.pubkey,\n encryptedPrivkey: nostrData.encryptedPrivkey,\n encryptionIv: nostrData.encryptionIv,\n encryptionTag: nostrData.encryptionTag,\n email: normalizedEmail,\n nip05Username:\n nostrData.nip05Username?.toLowerCase() || normalizedEmail.split('@')[0],\n });\n await nostrIdentity.initialize();\n await nostrIdentity.save();\n\n return {\n profile,\n nostrIdentity,\n created: true,\n };\n}\n","/**\n * OidcIdentityCollection - Collection for managing OIDC identity records\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { OidcIdentity } from '../models/OidcIdentity';\nimport type { Profile } from '../models/Profile';\n\nexport class OidcIdentityCollection extends SmrtCollection<OidcIdentity> {\n static readonly _itemClass = OidcIdentity;\n\n /**\n * Find identities for a profile\n */\n async findByProfile(profileId: string): Promise<OidcIdentity[]> {\n return await this.list({\n where: { profileId },\n });\n }\n\n /**\n * Find identity by issuer and subject\n */\n async findBySubject(\n issuer: string,\n subject: string,\n ): Promise<OidcIdentity | null> {\n return await this.findOne({\n where: { issuer, subject },\n });\n }\n\n /**\n * Find identities by provider\n */\n async findByProvider(provider: string): Promise<OidcIdentity[]> {\n return await this.list({\n where: { provider },\n });\n }\n\n /**\n * Link a new OIDC identity to a profile\n */\n async linkToProfile(\n profile: Profile,\n oidcData: {\n provider: string;\n issuer: string;\n subject: string;\n email?: string;\n },\n ): Promise<OidcIdentity> {\n // Check if already exists\n const existing = await this.findBySubject(\n oidcData.issuer,\n oidcData.subject,\n );\n if (existing) {\n // Update and return existing\n existing.lastUsedAt = new Date();\n if (oidcData.email) existing.email = oidcData.email;\n await existing.save();\n return existing;\n }\n\n // Create new\n const identity = new OidcIdentity({\n ...this.options,\n profileId: profile.id as string,\n provider: oidcData.provider,\n issuer: oidcData.issuer,\n subject: oidcData.subject,\n email: oidcData.email || '',\n });\n await identity.initialize();\n await identity.save();\n return identity;\n }\n\n /**\n * Unlink an OIDC identity from a profile\n */\n async unlinkFromProfile(\n profileId: string,\n issuer: string,\n subject: string,\n ): Promise<boolean> {\n const identity = await this.findOne({\n where: { profileId, issuer, subject },\n });\n\n if (identity) {\n await identity.delete();\n return true;\n }\n return false;\n }\n}\n","/**\n * ProfileTypeCollection - Collection manager for ProfileType objects\n *\n * Provides querying for profile type lookup table.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { ProfileType } from '../models/ProfileType';\n\nexport class ProfileTypeCollection extends SmrtCollection<ProfileType> {\n static readonly _itemClass = ProfileType;\n\n /**\n * Get profile type by slug\n *\n * @param slug - The slug to search for\n * @returns ProfileType instance or null\n */\n async getBySlug(slug: string): Promise<ProfileType | null> {\n return await this.get({ slug });\n }\n\n /**\n * Get or create a profile type by slug\n *\n * @param slug - The slug to search for\n * @param defaults - Default values if creating\n * @returns ProfileType instance\n */\n async getOrCreateBySlug(\n slug: string,\n defaults: { name: string; description?: string },\n ): Promise<ProfileType> {\n const existing = await this.getBySlug(slug);\n if (existing) return existing;\n\n const profileType = await this.create({ slug, ...defaults });\n await profileType.save();\n return profileType;\n }\n}\n","/**\n * Profile subclasses for STI (Single Table Inheritance)\n *\n * These classes inherit from Profile and automatically use the shared\n * profiles table with _meta_type discriminator.\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport { Profile, type ProfileOptions } from './Profile';\n\n/**\n * Person profile type\n *\n * Represents individual people/users.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Person extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Person-specific initialization can go here\n }\n}\n\n/**\n * Organization profile type\n *\n * Represents companies, groups, institutions, and other organizational entities.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Organization extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Organization-specific initialization can go here\n }\n}\n\n/**\n * Bot profile type\n *\n * Represents automated agents, bots, and AI entities.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Bot extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Bot-specific initialization can go here\n }\n}\n"],"names":["MagicLinkTokenCollection","__decorateClass","Person","ProfileTypeCollection","ProfileType","OidcIdentityCollection","profile","oidcIdentity"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -151,7 +151,7 @@ export declare class AuditLog extends SmrtObject {
151
151
  /**
152
152
  * Additional context (CI run ID, request ID, etc.)
153
153
  */
154
- metadata: Record<string, any>;
154
+ metadata: Record<string, unknown>;
155
155
  /**
156
156
  * For pass-through identity in CI - the actual person who triggered
157
157
  */
@@ -209,7 +209,7 @@ export declare class AuditLogCollection extends SmrtCollection<AuditLog> {
209
209
  resourceType: string;
210
210
  resourceId: string;
211
211
  source?: AuditSource;
212
- metadata?: Record<string, any>;
212
+ metadata?: Record<string, unknown>;
213
213
  onBehalfOf?: Profile | null;
214
214
  }): Promise<AuditLog>;
215
215
  /**
@@ -228,7 +228,7 @@ export declare interface AuditLogOptions extends SmrtObjectOptions {
228
228
  resourceType?: string;
229
229
  resourceId?: string;
230
230
  source?: AuditSource;
231
- metadata?: Record<string, any>;
231
+ metadata?: Record<string, unknown>;
232
232
  onBehalfOfId?: string | null;
233
233
  tenantId?: string | null;
234
234
  }
@@ -991,9 +991,9 @@ export declare class Profile extends SmrtObject {
991
991
  email?: string;
992
992
  name: string;
993
993
  description?: string;
994
- metadata: any[];
995
- relationshipsFrom: any[];
996
- relationshipsTo: any[];
994
+ metadata: ProfileMetadata[];
995
+ relationshipsFrom: ProfileRelationship[];
996
+ relationshipsTo: ProfileRelationship[];
997
997
  constructor(options?: ProfileOptions);
998
998
  /**
999
999
  * Get the profile type slug for this profile
@@ -1014,19 +1014,19 @@ export declare class Profile extends SmrtObject {
1014
1014
  * @param metafieldSlug - The slug of the metafield
1015
1015
  * @param value - The value to set
1016
1016
  */
1017
- addMetadata(metafieldSlug: string, value: any): Promise<void>;
1017
+ addMetadata(metafieldSlug: string, value: unknown): Promise<void>;
1018
1018
  /**
1019
1019
  * Get all metadata for this profile as key-value object
1020
1020
  *
1021
1021
  * @returns Object with metafield slugs as keys
1022
1022
  */
1023
- getMetadata(): Promise<Record<string, any>>;
1023
+ getMetadata(): Promise<Record<string, string>>;
1024
1024
  /**
1025
1025
  * Update multiple metadata values
1026
1026
  *
1027
1027
  * @param metadata - Object with metafield slugs as keys and values
1028
1028
  */
1029
- updateMetadata(metadata: Record<string, any>): Promise<void>;
1029
+ updateMetadata(metadata: Record<string, unknown>): Promise<void>;
1030
1030
  /**
1031
1031
  * Remove metadata by metafield slug
1032
1032
  *
@@ -1093,7 +1093,7 @@ export declare class Profile extends SmrtObject {
1093
1093
  * @param value - The value to match
1094
1094
  * @returns Array of matching profiles
1095
1095
  */
1096
- static findByMetadata(_metafieldSlug: string, _value: any): Promise<Profile[]>;
1096
+ static findByMetadata(_metafieldSlug: string, _value: unknown): Promise<Profile[]>;
1097
1097
  /**
1098
1098
  * Find profiles by type slug
1099
1099
  *
@@ -1121,13 +1121,13 @@ export declare class Profile extends SmrtObject {
1121
1121
  *
1122
1122
  * @returns Array of API keys
1123
1123
  */
1124
- getApiKeys(): Promise<any[]>;
1124
+ getApiKeys(): Promise<ApiKey[]>;
1125
1125
  /**
1126
1126
  * Get active (non-revoked, non-expired) API keys for this profile
1127
1127
  *
1128
1128
  * @returns Array of active API keys
1129
1129
  */
1130
- getActiveApiKeys(): Promise<any[]>;
1130
+ getActiveApiKeys(): Promise<ApiKey[]>;
1131
1131
  /**
1132
1132
  * Generate a new API key for this profile
1133
1133
  *
@@ -1138,16 +1138,13 @@ export declare class Profile extends SmrtObject {
1138
1138
  name: string;
1139
1139
  scopes?: string[];
1140
1140
  expiresAt?: Date | null;
1141
- }): Promise<{
1142
- key: string;
1143
- apiKey: any;
1144
- }>;
1141
+ }): Promise<GenerateKeyResult>;
1145
1142
  /**
1146
1143
  * Get all OIDC identities linked to this profile
1147
1144
  *
1148
1145
  * @returns Array of OIDC identity records
1149
1146
  */
1150
- getOidcIdentities(): Promise<any[]>;
1147
+ getOidcIdentities(): Promise<OidcIdentity[]>;
1151
1148
  /**
1152
1149
  * Link a new OIDC identity to this profile
1153
1150
  *
@@ -1159,13 +1156,13 @@ export declare class Profile extends SmrtObject {
1159
1156
  issuer: string;
1160
1157
  subject: string;
1161
1158
  email?: string;
1162
- }): Promise<any>;
1159
+ }): Promise<OidcIdentity>;
1163
1160
  /**
1164
1161
  * Get all Nostr identities linked to this profile
1165
1162
  *
1166
1163
  * @returns Array of Nostr identity records
1167
1164
  */
1168
- getNostrIdentities(): Promise<any[]>;
1165
+ getNostrIdentities(): Promise<NostrIdentity[]>;
1169
1166
  /**
1170
1167
  * Link a new Nostr identity to this profile
1171
1168
  *
@@ -1179,14 +1176,14 @@ export declare class Profile extends SmrtObject {
1179
1176
  encryptionTag: string;
1180
1177
  email: string;
1181
1178
  nip05Username?: string;
1182
- }): Promise<any>;
1179
+ }): Promise<NostrIdentity>;
1183
1180
  /**
1184
1181
  * Get audit logs for actions performed by this profile
1185
1182
  *
1186
1183
  * @param limit - Maximum number of logs to return
1187
1184
  * @returns Array of audit log entries
1188
1185
  */
1189
- getAuditLogs(limit?: number): Promise<any[]>;
1186
+ getAuditLogs(limit?: number): Promise<AuditLog[]>;
1190
1187
  /**
1191
1188
  * Record an audit log entry for an action by this profile
1192
1189
  *
@@ -1198,9 +1195,9 @@ export declare class Profile extends SmrtObject {
1198
1195
  resourceType: string;
1199
1196
  resourceId: string;
1200
1197
  source?: 'web' | 'cli' | 'ci' | 'webhook' | 'mcp';
1201
- metadata?: Record<string, any>;
1198
+ metadata?: Record<string, unknown>;
1202
1199
  onBehalfOf?: Profile | null;
1203
- }): Promise<any>;
1200
+ }): Promise<AuditLog>;
1204
1201
  }
1205
1202
 
1206
1203
  export declare class ProfileAsset extends SmrtObject {
@@ -1253,7 +1250,7 @@ export declare class ProfileCollection extends SmrtCollection<Profile> {
1253
1250
  * @param profileIds - Array of profile UUIDs
1254
1251
  * @returns Map of profile ID to metadata object
1255
1252
  */
1256
- batchGetMetadata(profileIds: string[]): Promise<Map<string, Record<string, any>>>;
1253
+ batchGetMetadata(profileIds: string[]): Promise<Map<string, Record<string, string>>>;
1257
1254
  /**
1258
1255
  * Batch update metadata for multiple profiles
1259
1256
  *
@@ -1261,7 +1258,7 @@ export declare class ProfileCollection extends SmrtCollection<Profile> {
1261
1258
  */
1262
1259
  batchUpdateMetadata(updates: Array<{
1263
1260
  profileId: string;
1264
- data: Record<string, any>;
1261
+ data: Record<string, unknown>;
1265
1262
  }>): Promise<void>;
1266
1263
  /**
1267
1264
  * Find related profiles for a given profile
@@ -1348,7 +1345,7 @@ export declare class ProfileMetadataCollection extends SmrtCollection<ProfileMet
1348
1345
  * @param profileId - The profile UUID
1349
1346
  * @returns Object with metafield slugs as keys
1350
1347
  */
1351
- getMetadataObject(profileId: string): Promise<Record<string, any>>;
1348
+ getMetadataObject(profileId: string): Promise<Record<string, string>>;
1352
1349
  /**
1353
1350
  * Find all profiles with a specific metadata key-value pair
1354
1351
  *
@@ -1356,7 +1353,7 @@ export declare class ProfileMetadataCollection extends SmrtCollection<ProfileMet
1356
1353
  * @param value - The value to match
1357
1354
  * @returns Array of profile UUIDs
1358
1355
  */
1359
- findProfilesByMetadata(metafieldId: string, value: any): Promise<string[]>;
1356
+ findProfilesByMetadata(metafieldId: string, value: unknown): Promise<string[]>;
1360
1357
  }
1361
1358
 
1362
1359
  export declare interface ProfileMetadataOptions extends SmrtObjectOptions {
@@ -1370,7 +1367,7 @@ export declare class ProfileMetafield extends SmrtObject {
1370
1367
  tenantId: string | null;
1371
1368
  name: string;
1372
1369
  description?: string;
1373
- validation?: Record<string, any>;
1370
+ validation?: ValidationSchema;
1374
1371
  constructor(options?: ProfileMetafieldOptions);
1375
1372
  /**
1376
1373
  * Convenience method for slug-based lookup
@@ -1399,7 +1396,7 @@ export declare class ProfileMetafield extends SmrtObject {
1399
1396
  * @param value - The value to validate
1400
1397
  * @returns True if valid, throws ValidationError if invalid
1401
1398
  */
1402
- validateValue(value: any): Promise<boolean>;
1399
+ validateValue(value: unknown): Promise<boolean>;
1403
1400
  }
1404
1401
 
1405
1402
  export declare class ProfileMetafieldCollection extends SmrtCollection<ProfileMetafield> {
@@ -1447,7 +1444,7 @@ export declare class ProfileRelationship extends SmrtObject {
1447
1444
  toProfileId?: string;
1448
1445
  typeId?: string;
1449
1446
  contextProfileId?: string;
1450
- terms: any[];
1447
+ terms: ProfileRelationshipTerm[];
1451
1448
  constructor(options?: ProfileRelationshipOptions);
1452
1449
  /**
1453
1450
  * Get the relationship type slug
@@ -1711,9 +1708,6 @@ export declare function promptMessageOptions(ai: ResolvedPromptAI): {
1711
1708
  */
1712
1709
  export declare function pubkeyToNpub(pubkey: string): string;
1713
1710
 
1714
- /**
1715
- * TypeScript type definitions for @have/profiles package
1716
- */
1717
1711
  /**
1718
1712
  * Handler function interface for reciprocal relationships
1719
1713
  *
@@ -1722,7 +1716,7 @@ export declare function pubkeyToNpub(pubkey: string): string;
1722
1716
  * @param context - Optional context profile for tertiary relationships
1723
1717
  * @param options - Additional options for the handler
1724
1718
  */
1725
- export declare type ReciprocalHandler = (from: any, to: any, context?: any, options?: any) => Promise<void>;
1719
+ export declare type ReciprocalHandler = (from: Profile, to: Profile, context?: Profile, options?: Record<string, unknown>) => Promise<void>;
1726
1720
 
1727
1721
  /**
1728
1722
  * Resolve authentication context to a Profile
@@ -1814,7 +1808,7 @@ export declare interface ValidationSchema {
1814
1808
  /**
1815
1809
  * Custom validator function type
1816
1810
  */
1817
- export declare type ValidatorFunction = (value: any) => boolean | Promise<boolean>;
1811
+ export declare type ValidatorFunction = (value: unknown) => boolean | Promise<boolean>;
1818
1812
 
1819
1813
  /**
1820
1814
  * Verify an authentication event
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import { B, M, a, O, b, c, P, d, e, f, g, h, i, p, r } from "./chunks/index-DHLYp075.js";
2
- import { a as a2, b as b2, P as P2, p as p2, s } from "./chunks/ProfileCollection-DQD1uJEc.js";
1
+ import { B, M, a, O, b, c, P, d, e, f, g, h, i, p, r } from "./chunks/index-B9lXQy7N.js";
2
+ import { a as a2, b as b2, P as P2, p as p2, s } from "./chunks/ProfileCollection-M2PK8bp-.js";
3
3
  import { a as a3, N, c as c2, b as b3, d as d2, f as f2, e as e2, g as g2, h as h2, i as i2, j, n, k, p as p3, l, s as s2, v, m } from "./chunks/NostrIdentityCollection-DadQBHWy.js";
4
4
  import { ApiKeyCollection } from "./chunks/ApiKeyCollection-B6Op817e.js";
5
5
  import { A, a as a4 } from "./chunks/AuditLogCollection-BYqCj0uE.js";
6
- import { P as P3, a as a5 } from "./chunks/ProfileAssetCollection-ChX4kLjN.js";
6
+ import { P as P3, a as a5 } from "./chunks/ProfileAssetCollection-CUM5QfuJ.js";
7
7
  import { P as P4, a as a6 } from "./chunks/ProfileMetadataCollection-DEhmljMY.js";
8
8
  import { P as P5, a as a7 } from "./chunks/ProfileMetafieldCollection-DMKhSHXX.js";
9
- import { P as P6, a as a8 } from "./chunks/ProfileRelationshipCollection-C0IM8UQR.js";
9
+ import { P as P6, a as a8 } from "./chunks/ProfileRelationshipCollection-_TsY7MHL.js";
10
10
  import { P as P7, a as a9 } from "./chunks/ProfileRelationshipTermCollection-CXem_qT-.js";
11
11
  import { ProfileRelationshipTypeCollection } from "./chunks/ProfileRelationshipTypeCollection-CF8YvLTV.js";
12
12
  import { ApiKey } from "./chunks/ApiKey-B2LKEaP8.js";