@happyvertical/smrt-profiles 0.51.32 → 0.51.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/__smrt-register__.d.ts +2 -0
  2. package/dist/__smrt-register__.d.ts.map +1 -0
  3. package/dist/agent-profile.d.ts +71 -0
  4. package/dist/agent-profile.d.ts.map +1 -0
  5. package/dist/auth/index.d.ts +12 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/magicLinkService.d.ts +79 -0
  8. package/dist/auth/magicLinkService.d.ts.map +1 -0
  9. package/dist/auth/nip05Handler.d.ts +73 -0
  10. package/dist/auth/nip05Handler.d.ts.map +1 -0
  11. package/dist/auth/normalizeIdentityEmail.d.ts +8 -0
  12. package/dist/auth/normalizeIdentityEmail.d.ts.map +1 -0
  13. package/dist/auth/nostrCrypto.d.ts +111 -0
  14. package/dist/auth/nostrCrypto.d.ts.map +1 -0
  15. package/dist/auth/oidcProvisioningCoordinator.d.ts +58 -0
  16. package/dist/auth/oidcProvisioningCoordinator.d.ts.map +1 -0
  17. package/dist/auth/oidcProvisioningPrimitives.d.ts +23 -0
  18. package/dist/auth/oidcProvisioningPrimitives.d.ts.map +1 -0
  19. package/dist/auth/resolveIdentity.d.ts +188 -0
  20. package/dist/auth/resolveIdentity.d.ts.map +1 -0
  21. package/dist/collections/ApiKeyCollection.d.ts +46 -0
  22. package/dist/collections/ApiKeyCollection.d.ts.map +1 -0
  23. package/dist/collections/AuditLogCollection.d.ts +50 -0
  24. package/dist/collections/AuditLogCollection.d.ts.map +1 -0
  25. package/dist/collections/MagicLinkTokenCollection.d.ts +58 -0
  26. package/dist/collections/MagicLinkTokenCollection.d.ts.map +1 -0
  27. package/dist/collections/NostrIdentityCollection.d.ts +66 -0
  28. package/dist/collections/NostrIdentityCollection.d.ts.map +1 -0
  29. package/dist/collections/OidcIdentityCollection.d.ts +45 -0
  30. package/dist/collections/OidcIdentityCollection.d.ts.map +1 -0
  31. package/dist/collections/OidcProfileEmailReservationCollection.d.ts +7 -0
  32. package/dist/collections/OidcProfileEmailReservationCollection.d.ts.map +1 -0
  33. package/dist/collections/ProfileAssetCollection.d.ts +17 -0
  34. package/dist/collections/ProfileAssetCollection.d.ts.map +1 -0
  35. package/dist/collections/ProfileCollection.d.ts +130 -0
  36. package/dist/collections/ProfileCollection.d.ts.map +1 -0
  37. package/dist/collections/ProfileMetadataCollection.d.ts +33 -0
  38. package/dist/collections/ProfileMetadataCollection.d.ts.map +1 -0
  39. package/dist/collections/ProfileMetafieldCollection.d.ts +31 -0
  40. package/dist/collections/ProfileMetafieldCollection.d.ts.map +1 -0
  41. package/dist/collections/ProfileRelationshipCollection.d.ts +44 -0
  42. package/dist/collections/ProfileRelationshipCollection.d.ts.map +1 -0
  43. package/dist/collections/ProfileRelationshipTermCollection.d.ts +32 -0
  44. package/dist/collections/ProfileRelationshipTermCollection.d.ts.map +1 -0
  45. package/dist/collections/ProfileRelationshipTypeCollection.d.ts +41 -0
  46. package/dist/collections/ProfileRelationshipTypeCollection.d.ts.map +1 -0
  47. package/dist/collections/ProfileTypeCollection.d.ts +40 -0
  48. package/dist/collections/ProfileTypeCollection.d.ts.map +1 -0
  49. package/dist/collections/index.d.ts +18 -0
  50. package/dist/collections/index.d.ts.map +1 -0
  51. package/dist/index.d.ts +55 -2059
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +1 -1
  54. package/dist/internal/oidc-provisioning.d.ts +14 -119
  55. package/dist/internal/oidc-provisioning.d.ts.map +1 -0
  56. package/dist/manifest.json +1 -1
  57. package/dist/migrations/backfillProfileEmailKeys.d.ts +16 -0
  58. package/dist/migrations/backfillProfileEmailKeys.d.ts.map +1 -0
  59. package/dist/models/ApiKey.d.ts +94 -0
  60. package/dist/models/ApiKey.d.ts.map +1 -0
  61. package/dist/models/AuditLog.d.ts +71 -0
  62. package/dist/models/AuditLog.d.ts.map +1 -0
  63. package/dist/models/MagicLinkToken.d.ts +104 -0
  64. package/dist/models/MagicLinkToken.d.ts.map +1 -0
  65. package/dist/models/NostrIdentity.d.ts +112 -0
  66. package/dist/models/NostrIdentity.d.ts.map +1 -0
  67. package/dist/models/OidcIdentity.d.ts +82 -0
  68. package/dist/models/OidcIdentity.d.ts.map +1 -0
  69. package/dist/models/OidcProfileEmailReservation.d.ts +12 -0
  70. package/dist/models/OidcProfileEmailReservation.d.ts.map +1 -0
  71. package/dist/models/Profile.d.ts +243 -0
  72. package/dist/models/Profile.d.ts.map +1 -0
  73. package/dist/models/ProfileAsset.d.ts +18 -0
  74. package/dist/models/ProfileAsset.d.ts.map +1 -0
  75. package/dist/models/ProfileMetadata.d.ts +33 -0
  76. package/dist/models/ProfileMetadata.d.ts.map +1 -0
  77. package/dist/models/ProfileMetafield.d.ts +62 -0
  78. package/dist/models/ProfileMetafield.d.ts.map +1 -0
  79. package/dist/models/ProfileRelationship.d.ts +56 -0
  80. package/dist/models/ProfileRelationship.d.ts.map +1 -0
  81. package/dist/models/ProfileRelationshipTerm.d.ts +37 -0
  82. package/dist/models/ProfileRelationshipTerm.d.ts.map +1 -0
  83. package/dist/models/ProfileRelationshipType.d.ts +59 -0
  84. package/dist/models/ProfileRelationshipType.d.ts.map +1 -0
  85. package/dist/models/ProfileType.d.ts +27 -0
  86. package/dist/models/ProfileType.d.ts.map +1 -0
  87. package/dist/models/ProfileTypes.d.ts +32 -0
  88. package/dist/models/ProfileTypes.d.ts.map +1 -0
  89. package/dist/models/index.d.ts +18 -0
  90. package/dist/models/index.d.ts.map +1 -0
  91. package/dist/prompts.d.ts +17 -0
  92. package/dist/prompts.d.ts.map +1 -0
  93. package/dist/smrt-knowledge.json +4 -4
  94. package/dist/testing/oidcProvisioningDecisionMatrix.d.ts +1168 -0
  95. package/dist/testing/oidcProvisioningDecisionMatrix.d.ts.map +1 -0
  96. package/dist/types.d.ts +33 -732
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/utils.d.ts +52 -817
  99. package/dist/utils.d.ts.map +1 -0
  100. package/package.json +7 -7
package/dist/index.d.ts CHANGED
@@ -1,2063 +1,59 @@
1
- import { Asset } from '@happyvertical/smrt-assets';
2
- import { getDatabase } from '@happyvertical/sql';
3
- import { PromptDefinition } from '@happyvertical/smrt-prompts';
4
- import { ResolvedPromptAI } from '@happyvertical/smrt-prompts';
5
- import { SmrtCollection } from '@happyvertical/smrt-core';
6
- import { SmrtJunction } from '@happyvertical/smrt-core';
7
- import { SmrtObject } from '@happyvertical/smrt-core';
8
- import { SmrtObjectOptions } from '@happyvertical/smrt-core';
9
-
10
- /**
11
- * Reserved slug context for agent-owned profiles.
12
- *
13
- * Agent identifiers come from application configuration, not from the profile
14
- * namespace, so they are scoped into their own slug context rather than
15
- * competing with person/organization slugs.
16
- */
17
- export declare const AGENT_PROFILE_CONTEXT = "smrt:agent";
18
-
19
- /** Slug of the {@link ProfileType} agent profiles are classified under. */
20
- export declare const AGENT_PROFILE_TYPE_SLUG = "bot";
21
-
22
- /** More than one legacy row maps the same opaque OIDC issuer and subject. */
23
- export declare class AmbiguousOidcIdentityError extends Error {
24
- readonly issuer: string;
25
- readonly subject: string;
26
- constructor(issuer: string, subject: string);
27
- }
28
-
29
- export declare class ApiKey extends SmrtObject {
30
- /**
31
- * Link to the Profile (Person, Organization, Bot)
32
- */
33
- profileId?: string;
34
- /**
35
- * SHA-256 hash of the API key.
36
- *
37
- * Indexed: `verify()` looks keys up by this hash on every authenticated
38
- * request (#2364, epic #2382 finding A3).
39
- */
40
- keyHash: string;
41
- /**
42
- * First 8 characters of the key for identification (e.g., "sk_live_a1b2...")
43
- */
44
- keyPrefix: string;
45
- /**
46
- * Human-readable name for the key (e.g., "CI Bot", "Local CLI")
47
- */
48
- name: string;
49
- /**
50
- * Scopes/permissions for this key
51
- */
52
- scopes: string[];
53
- /**
54
- * Last time this key was used
55
- */
56
- lastUsedAt: Date | null;
57
- /**
58
- * When this key expires (null = never)
59
- */
60
- expiresAt: Date | null;
61
- /**
62
- * When this key was revoked (null = active)
63
- */
64
- revokedAt: Date | null;
65
- constructor(options?: ApiKeyOptions);
66
- /**
67
- * Get the linked Profile
68
- */
69
- getProfile(): Promise<Profile | null>;
70
- /**
71
- * Check if this key is valid (not expired, not revoked)
72
- */
73
- isValid(): boolean;
74
- /**
75
- * Check if this key has a specific scope
76
- */
77
- hasScope(scope: string): boolean;
78
- /**
79
- * Revoke this key
80
- */
81
- revoke(): Promise<void>;
82
- /**
83
- * Record usage of this key
84
- */
85
- recordUsage(): Promise<void>;
86
- /**
87
- * Hash an API key
88
- */
89
- static hashKey(key: string): string;
90
- /**
91
- * Generate a new API key for a profile
92
- */
93
- static generate(profile: Profile, options: {
94
- name: string;
95
- scopes?: string[];
96
- expiresAt?: Date | null;
97
- db?: SmrtObjectOptions['db'];
98
- }): Promise<GenerateKeyResult>;
99
- /**
100
- * Verify an API key and return the ApiKey record if valid
101
- */
102
- static verify(key: string, options?: SmrtObjectOptions): Promise<ApiKey | null>;
103
- }
104
-
105
- export declare class ApiKeyCollection extends SmrtCollection<ApiKey> {
106
- static readonly _itemClass: typeof ApiKey;
107
- /**
108
- * Find all keys for a profile
109
- */
110
- findByProfile(profileId: string): Promise<ApiKey[]>;
111
- /**
112
- * Find active (non-revoked, non-expired) keys for a profile
113
- */
114
- findActiveByProfile(profileId: string): Promise<ApiKey[]>;
115
- /**
116
- * Find key by hash
117
- */
118
- findByHash(keyHash: string): Promise<ApiKey | null>;
119
- /**
120
- * Verify an API key string and return the record if valid
121
- */
122
- verify(key: string): Promise<ApiKey | null>;
123
- /**
124
- * Generate a new key for a profile
125
- */
126
- generateForProfile(profile: Profile, options: {
127
- name: string;
128
- scopes?: string[];
129
- expiresAt?: Date | null;
130
- }): Promise<GenerateKeyResult>;
131
- /**
132
- * Revoke all keys for a profile
133
- */
134
- revokeAllForProfile(profileId: string): Promise<number>;
135
- /**
136
- * Revoke a specific key by prefix
137
- */
138
- revokeByPrefix(keyPrefix: string): Promise<boolean>;
139
- /**
140
- * Clean up expired keys (soft delete by setting revokedAt)
141
- */
142
- cleanupExpired(): Promise<number>;
143
- }
144
-
145
- export declare interface ApiKeyOptions extends SmrtObjectOptions {
146
- profileId?: string;
147
- name?: string;
148
- scopes?: string[];
149
- expiresAt?: Date | null;
150
- }
151
-
152
- export declare class AuditLog extends SmrtObject {
153
- tenantId: string | null;
154
- /**
155
- * The profile who performed the action
156
- */
157
- profileId?: string;
158
- /**
159
- * Action performed (e.g., 'issue.update', 'feedback.incorporate')
160
- */
161
- action: string;
162
- /**
163
- * Type of resource affected (e.g., 'Issue', 'Repository')
164
- */
165
- resourceType: string;
166
- /**
167
- * ID of the affected resource
168
- */
169
- resourceId: string;
170
- /**
171
- * Source of the action
172
- */
173
- source: AuditSource;
174
- /**
175
- * Additional context (CI run ID, request ID, etc.)
176
- */
177
- metadata: Record<string, unknown>;
178
- /**
179
- * For pass-through identity in CI - the actual person who triggered
180
- */
181
- onBehalfOfId?: string | null;
182
- constructor(options?: AuditLogOptions);
183
- /**
184
- * Get the profile who performed the action
185
- */
186
- getProfile(): Promise<Profile | null>;
187
- /**
188
- * Get the profile on whose behalf the action was performed (if any)
189
- */
190
- getOnBehalfOf(): Promise<Profile | null>;
191
- /**
192
- * Get the effective actor (onBehalfOf if set, otherwise profile)
193
- */
194
- getEffectiveActor(): Promise<Profile | null>;
195
- /**
196
- * Create an audit log entry
197
- */
198
- static record(options: AuditLogOptions & {
199
- profile: Profile;
200
- onBehalfOf?: Profile | null;
201
- }): Promise<AuditLog>;
202
- }
203
-
204
- export declare class AuditLogCollection extends SmrtCollection<AuditLog> {
205
- static readonly _itemClass: typeof AuditLog;
206
- /**
207
- * Find logs for a profile (actions they performed)
208
- */
209
- findByProfile(profileId: string): Promise<AuditLog[]>;
210
- /**
211
- * Find logs for a resource
212
- */
213
- findByResource(resourceType: string, resourceId: string): Promise<AuditLog[]>;
214
- /**
215
- * Find logs by action type
216
- */
217
- findByAction(action: string): Promise<AuditLog[]>;
218
- /**
219
- * Find logs by source
220
- */
221
- findBySource(source: AuditSource): Promise<AuditLog[]>;
222
- /**
223
- * Find logs where actions were performed on behalf of someone
224
- */
225
- findOnBehalfOf(profileId: string): Promise<AuditLog[]>;
226
- /**
227
- * Record a new audit log entry
228
- */
229
- record(options: {
230
- profile: Profile;
231
- action: string;
232
- resourceType: string;
233
- resourceId: string;
234
- source?: AuditSource;
235
- metadata?: Record<string, unknown>;
236
- onBehalfOf?: Profile | null;
237
- }): Promise<AuditLog>;
238
- /**
239
- * Get recent activity for a profile
240
- */
241
- getRecentActivity(profileId: string, limit?: number): Promise<AuditLog[]>;
242
- /**
243
- * Get activity timeline for a resource
244
- */
245
- getResourceTimeline(resourceType: string, resourceId: string): Promise<AuditLog[]>;
246
- }
247
-
248
- export declare interface AuditLogOptions extends SmrtObjectOptions {
249
- profileId?: string;
250
- action?: string;
251
- resourceType?: string;
252
- resourceId?: string;
253
- source?: AuditSource;
254
- metadata?: Record<string, unknown>;
255
- onBehalfOfId?: string | null;
256
- tenantId?: string | null;
257
- }
258
-
259
- export declare type AuditSource = 'web' | 'cli' | 'ci' | 'webhook' | 'mcp';
260
-
261
- /**
262
- * Context provided to resolveIdentity
263
- */
264
- export declare interface AuthContext {
265
- /**
266
- * API key from X-API-Key header or similar
267
- */
268
- apiKey?: string | null;
269
- /**
270
- * OIDC session data (from @auth/sveltekit or similar)
271
- */
272
- oidcSession?: {
273
- sub?: string;
274
- iss?: string;
275
- email?: string;
276
- name?: string;
277
- } | null;
278
- /**
279
- * Actor identifier for CI pass-through identity
280
- * Usually the GitHub actor (username) who triggered the workflow
281
- */
282
- actor?: string | null;
283
- /**
284
- * Nostr authentication data (NIP-42 style)
285
- */
286
- nostrAuth?: {
287
- /** Signed Nostr event for authentication */
288
- event: NostrEvent;
289
- /** Expected challenge (to prevent replay attacks) */
290
- challenge: string;
291
- } | null;
292
- /**
293
- * Database/persistence options
294
- */
295
- db?: SmrtObjectOptions['db'];
296
- }
297
-
298
- /**
299
- * Populate adapter-independent Profile email keys after the schema migration.
300
- *
301
- * Run this from one deploy process after legacy writers are stopped or
302
- * upgraded. Every read and update runs in one transaction, and repeats are a
303
- * no-op.
304
- */
305
- export declare function backfillProfileEmailKeys(db: DatabaseInterface): Promise<BackfillProfileEmailKeysResult>;
306
-
307
- export declare interface BackfillProfileEmailKeysResult {
308
- updated: number;
309
- }
310
-
311
- /**
312
- * Bot profile type
313
- *
314
- * Represents automated agents, bots, and AI entities.
315
- */
316
- export declare class Bot extends Profile {
317
- constructor(options?: ProfileOptions);
318
- }
319
-
320
- /** A Profile cannot safely represent one global human identity. */
321
- export declare class CanonicalPersonProfileError extends Error {
322
- readonly code: CanonicalPersonProfileErrorCode;
323
- constructor(code: CanonicalPersonProfileErrorCode, message: string);
324
- }
325
-
326
- export declare type CanonicalPersonProfileErrorCode = 'ambiguous_email' | 'email_key_backfill_required' | 'email_mismatch' | 'missing_profile' | 'non_person' | 'reservation_conflict' | 'tenant_scoped';
327
-
328
- /**
329
- * Compute the event ID (SHA-256 hash of serialized event)
330
- */
331
- export declare function computeEventId(event: NostrEvent): string;
332
-
333
- /**
334
- * Create a Nostr event for authentication (NIP-42 style)
335
- * @param privkey - Private key to sign with
336
- * @param challenge - Server challenge string
337
- * @param relay - Relay URL (optional)
338
- */
339
- export declare function createAuthEvent(privkey: string, challenge: string, relay?: string): NostrEvent;
340
-
341
- /**
342
- * Create a magic link service instance
343
- */
344
- export declare function createMagicLinkService(config: MagicLinkConfig): MagicLinkService;
345
-
346
- /**
347
- * Create a NIP-05 handler
348
- *
349
- * @example
350
- * // SvelteKit
351
- * import { createNip05Handler } from '@happyvertical/smrt-profiles';
352
- *
353
- * const handler = createNip05Handler({ db: { type: 'postgres', url: DATABASE_URL } });
354
- *
355
- * export async function GET({ url }) {
356
- * const result = await handler({ name: url.searchParams.get('name') });
357
- * return new Response(JSON.stringify(result.body), {
358
- * status: result.status,
359
- * headers: result.headers,
360
- * });
361
- * }
362
- *
363
- * @example
364
- * // Express
365
- * import { createNip05Handler } from '@happyvertical/smrt-profiles';
366
- *
367
- * const handler = createNip05Handler({ db: { type: 'postgres', url: DATABASE_URL } });
368
- *
369
- * app.get('/.well-known/nostr.json', async (req, res) => {
370
- * const result = await handler({ name: req.query.name });
371
- * res.status(result.status).set(result.headers).json(result.body);
372
- * });
373
- */
374
- export declare function createNip05Handler(config: Nip05HandlerConfig): (request: Nip05Request) => Promise<Nip05HandlerResult>;
375
-
376
- /**
377
- * Create a profile from Nostr identity (used by magic link service)
378
- *
379
- * This is typically called internally by the magic link service,
380
- * but can be used directly if needed.
381
- *
382
- * @param email - Email address for the profile
383
- * @param nostrData - Encrypted Nostr keypair data
384
- * @param options - Database options
385
- * @returns The created profile with linked Nostr identity
386
- */
387
- export declare function createProfileFromNostr(email: string, nostrData: {
388
- pubkey: string;
389
- encryptedPrivkey: string;
390
- encryptionIv: string;
391
- encryptionTag: string;
392
- nip05Username?: string;
393
- }, options: SmrtObjectOptions): Promise<{
394
- profile: Profile;
395
- nostrIdentity: NostrIdentity;
396
- created: boolean;
397
- }>;
398
-
399
- /**
400
- * Create a profile from OIDC claims if it doesn't exist
401
- *
402
- * Resolution order:
403
- * 1. If OIDC identity (iss + sub) already exists → return linked profile
404
- * 2. If the email matches an existing Profile, fail closed because this
405
- * package cannot prove whether a User owns it
406
- * 3. Otherwise, create new profile + identity
407
- *
408
- * Security considerations:
409
- * - Existing issuer/subject links always keep their already-linked Profile,
410
- * including legacy tenant-scoped or non-Person Profiles, and refresh the
411
- * cached identity email. This exact-link compatibility does not perform
412
- * email-based canonical reuse.
413
- * - New identities never attach to an existing email match through this
414
- * Profile-only helper because Profile ownership belongs to the users package.
415
- * Use `UserCollection.getOrCreateFromOidc()` for owner-aware verified-email
416
- * reuse and its supported pre-provision resolver hook.
417
- * - This function trusts the OIDC provider to assert correct email_verified status.
418
- * Only use with trusted providers.
419
- *
420
- * @param claims - OIDC token claims
421
- * @param provider - Provider name (e.g., 'keycloak', 'google', 'github')
422
- * @param options - Database options
423
- * @returns The created or existing profile with linked OIDC identity
424
- */
425
- export declare function createProfileFromOidc(claims: {
426
- sub: string;
427
- iss: string;
428
- email?: string;
429
- email_verified?: boolean;
430
- name?: string;
431
- preferred_username?: string;
432
- }, provider: string, options: SmrtObjectOptions): Promise<{
433
- profile: Profile;
434
- oidcIdentity: OidcIdentity;
435
- created: boolean;
436
- }>;
437
-
438
- declare type DatabaseInterface = Awaited<ReturnType<typeof getDatabase>>;
439
-
440
- /**
441
- * Decrypt a private key using AES-256-GCM
442
- * @param encrypted - Encrypted key data
443
- * @param masterSecret - Server master secret (from env)
444
- */
445
- export declare function decryptPrivkey(encrypted: EncryptedKey, masterSecret: string): string;
446
-
447
- /**
448
- * Derive an encryption key from the master secret using HKDF
449
- * @param masterSecret - Server master secret
450
- */
451
- export declare function deriveEncryptionKey(masterSecret: string): Buffer;
452
-
453
- export declare interface EncryptedKey {
454
- /** Base64-encoded ciphertext */
455
- ciphertext: string;
456
- /** Base64-encoded initialization vector */
457
- iv: string;
458
- /** Base64-encoded authentication tag */
459
- tag: string;
460
- }
461
-
462
- /**
463
- * Encrypt a private key using AES-256-GCM
464
- * @param privkey - Hex-encoded private key
465
- * @param masterSecret - Server master secret (from env)
466
- */
467
- export declare function encryptPrivkey(privkey: string, masterSecret: string): EncryptedKey;
468
-
469
- export declare interface GenerateKeyResult {
470
- key: string;
471
- apiKey: ApiKey;
472
- }
473
-
474
- /**
475
- * Generate a new Nostr keypair (secp256k1)
476
- */
477
- export declare function generateNostrKeypair(): NostrKeypair;
478
-
479
- export declare interface GenerateTokenResult {
480
- /** The plaintext token (only available at creation time) */
481
- token: string;
482
- /** The MagicLinkToken record */
483
- magicLinkToken: MagicLinkToken;
484
- }
485
-
486
- /**
487
- * Get public key from private key
488
- */
489
- export declare function getPublicKey(privkey: string): string;
490
-
491
- export declare interface InitiateResult {
492
- success: boolean;
493
- /** The Nostr identity (existing or new) */
494
- nostrIdentity?: NostrIdentity;
495
- /** The profile (existing or new) */
496
- profile?: Profile;
497
- /** True if a new profile was created */
498
- created: boolean;
499
- /** Error message if success is false */
500
- error?: string;
501
- /** Error code for programmatic handling */
502
- errorCode?: 'RATE_LIMITED_EMAIL' | 'RATE_LIMITED_IP' | 'EMAIL_SEND_FAILED';
503
- }
504
-
505
- /**
506
- * Validate a NIP-05 identifier format
507
- * @param identifier - The identifier to validate (e.g., "alice@example.com")
508
- */
509
- export declare function isValidNip05Identifier(identifier: string): boolean;
510
-
511
- /**
512
- * Validate a hex-encoded private key
513
- */
514
- export declare function isValidPrivkey(privkey: string): boolean;
515
-
516
- /**
517
- * Validate a hex-encoded public key
518
- */
519
- export declare function isValidPubkey(pubkey: string): boolean;
520
-
521
- export declare interface MagicLinkConfig {
522
- /** Base URL for magic links (e.g., "https://example.com") */
523
- baseUrl: string;
524
- /** Path for verification endpoint (default: "/auth/verify") */
525
- verifyPath?: string;
526
- /** Token expiration in minutes (default: 15) */
527
- expiresInMinutes?: number;
528
- /** Maximum tokens per email per hour (default: 5) */
529
- maxTokensPerEmailPerHour?: number;
530
- /** Maximum tokens per IP per hour (default: 10) */
531
- maxTokensPerIpPerHour?: number;
532
- /** Server master secret for encryption */
533
- masterSecret: string;
534
- /** Callback to send the email */
535
- sendEmail: (to: string, magicLink: string) => Promise<void>;
536
- /** Database options */
537
- db: SmrtObjectOptions['db'];
538
- }
539
-
540
- export declare interface MagicLinkService {
541
- /**
542
- * Initiate magic link flow - generates token and sends email
543
- */
544
- initiate(email: string, options?: {
545
- requestedFromIp?: string;
546
- nip05Username?: string;
547
- }): Promise<InitiateResult>;
548
- /**
549
- * Verify a magic link token and return decrypted keypair
550
- */
551
- verify(token: string): Promise<VerifyResult>;
552
- }
553
-
554
- export declare class MagicLinkToken extends SmrtObject {
555
- /**
556
- * Link to the NostrIdentity this token is for
557
- */
558
- nostrIdentityId?: string;
559
- /**
560
- * SHA-256 hash of the token (never store plaintext).
561
- *
562
- * Indexed: `verify()` looks tokens up by this hash on every magic-link
563
- * click (#2364, epic #2382 finding A3).
564
- */
565
- tokenHash: string;
566
- /**
567
- * Email this token was sent to
568
- */
569
- email: string;
570
- /**
571
- * When this token expires
572
- */
573
- expiresAt: Date;
574
- /**
575
- * When this token was used (null = unused)
576
- */
577
- usedAt: Date | null;
578
- /**
579
- * IP address that requested the token (for rate limiting)
580
- */
581
- requestedFromIp: string;
582
- /**
583
- * When this token was created (for rate limiting)
584
- */
585
- createdAt: Date;
586
- constructor(options?: MagicLinkTokenOptions);
587
- /**
588
- * Hash a token using SHA-256
589
- */
590
- static hashToken(token: string): string;
591
- /**
592
- * Generate a new magic link token
593
- * @param nostrIdentity - The identity this token is for
594
- * @param email - The email address to send to
595
- * @param options - Additional options
596
- */
597
- static generate(nostrIdentity: NostrIdentity, email: string, options?: {
598
- expiresInMinutes?: number;
599
- requestedFromIp?: string;
600
- db?: SmrtObjectOptions['db'];
601
- }): Promise<GenerateTokenResult>;
602
- /**
603
- * Verify a token and return the MagicLinkToken if valid
604
- * @param token - The plaintext token to verify
605
- * @param options - Database options
606
- * @returns The MagicLinkToken if valid, null otherwise
607
- */
608
- static verify(token: string, options?: SmrtObjectOptions): Promise<MagicLinkToken | null>;
609
- /**
610
- * Check if this token is valid (not expired and not used)
611
- */
612
- isValid(): boolean;
613
- /**
614
- * Check if this token has expired
615
- */
616
- isExpired(): boolean;
617
- /**
618
- * Check if this token has been used
619
- */
620
- isUsed(): boolean;
621
- /**
622
- * Mark this token as used
623
- */
624
- markUsed(): Promise<void>;
625
- /**
626
- * Get the NostrIdentity this token is for
627
- */
628
- getNostrIdentity(): Promise<NostrIdentity | null>;
629
- /**
630
- * Get time remaining until expiration in seconds
631
- */
632
- getTimeRemainingSeconds(): number;
633
- }
634
-
635
- export declare class MagicLinkTokenCollection extends SmrtCollection<MagicLinkToken> {
636
- static readonly _itemClass: typeof MagicLinkToken;
637
- /**
638
- * Find token by hash
639
- */
640
- findByTokenHash(tokenHash: string): Promise<MagicLinkToken | null>;
641
- /**
642
- * Find active (non-expired, non-used) tokens for an email
643
- */
644
- findActiveForEmail(email: string): Promise<MagicLinkToken[]>;
645
- /**
646
- * Find tokens for a NostrIdentity
647
- */
648
- findByIdentity(nostrIdentityId: string): Promise<MagicLinkToken[]>;
649
- /**
650
- * Count tokens created for an email within a time window (for rate limiting)
651
- * @param email - Email address
652
- * @param withinMinutes - Time window in minutes
653
- */
654
- countRecentByEmail(email: string, withinMinutes: number): Promise<number>;
655
- /**
656
- * Count tokens created from an IP within a time window (for rate limiting)
657
- * @param ip - IP address
658
- * @param withinMinutes - Time window in minutes
659
- */
660
- countRecentByIp(ip: string, withinMinutes: number): Promise<number>;
661
- /**
662
- * Verify a token and return it if valid
663
- */
664
- verify(token: string): Promise<MagicLinkToken | null>;
665
- /**
666
- * Clean up expired tokens by deleting them
667
- * @returns Number of tokens deleted
668
- */
669
- cleanupExpired(): Promise<number>;
670
- /**
671
- * Revoke all tokens for a NostrIdentity (e.g., when identity is deleted)
672
- */
673
- revokeForIdentity(nostrIdentityId: string): Promise<number>;
674
- /**
675
- * Check if rate limit is exceeded for email
676
- * @param email - Email address
677
- * @param maxPerHour - Maximum tokens allowed per hour (default: 5)
678
- */
679
- isRateLimitedByEmail(email: string, maxPerHour?: number): Promise<boolean>;
680
- /**
681
- * Check if rate limit is exceeded for IP
682
- * @param ip - IP address
683
- * @param maxPerHour - Maximum tokens allowed per hour (default: 10)
684
- */
685
- isRateLimitedByIp(ip: string, maxPerHour?: number): Promise<boolean>;
686
- }
687
-
688
- export declare interface MagicLinkTokenOptions extends SmrtObjectOptions {
689
- nostrIdentityId?: string;
690
- tokenHash?: string;
691
- email?: string;
692
- expiresAt?: Date;
693
- usedAt?: Date | null;
694
- requestedFromIp?: string;
695
- createdAt?: Date;
696
- }
697
-
698
- export declare interface Nip05HandlerConfig {
699
- /** Database options */
700
- db: SmrtObjectOptions['db'];
701
- /** Optional: Additional relays to include for all users */
702
- defaultRelays?: string[];
703
- /** Optional: Cache TTL in seconds (default: 300 = 5 minutes) */
704
- cacheTtlSeconds?: number;
705
- }
706
-
707
- export declare interface Nip05HandlerResult {
708
- /** The NIP-05 response body */
709
- body: Nip05Response;
710
- /** Suggested headers for the response */
711
- headers: Record<string, string>;
712
- /** HTTP status code */
713
- status: number;
714
- }
715
-
716
- export declare interface Nip05Request {
717
- /** The 'name' query parameter from the request */
718
- name?: string | null;
719
- }
720
-
721
- export declare interface Nip05Response {
722
- names: Record<string, string>;
723
- relays?: Record<string, string[]>;
724
- }
725
-
726
- /**
727
- * Canonicalize an email used as an external identity key.
728
- *
729
- * Keep this in application code: SQL `trim()` and `lower()` have
730
- * adapter-specific whitespace and Unicode behavior.
731
- */
732
- export declare function normalizeIdentityEmail(email: string): string;
733
-
734
- export declare interface NostrEvent {
735
- id?: string;
736
- pubkey: string;
737
- created_at: number;
738
- kind: number;
739
- tags: string[][];
740
- content: string;
741
- sig?: string;
742
- }
743
-
744
- export declare class NostrIdentity extends SmrtObject {
745
- /**
746
- * Link to the Profile (Person, Organization, Bot)
747
- */
748
- profileId?: string;
749
- /**
750
- * Hex-encoded secp256k1 public key (64 characters).
751
- *
752
- * Indexed: `findByPubkey()` looks identities up by this column (#2364,
753
- * epic #2382 finding A3).
754
- */
755
- pubkey: string;
756
- /**
757
- * AES-256-GCM encrypted private key (base64-encoded ciphertext)
758
- */
759
- encryptedPrivkey: string;
760
- /**
761
- * Initialization vector for AES-GCM decryption (base64)
762
- */
763
- encryptionIv: string;
764
- /**
765
- * Authentication tag from AES-GCM (base64)
766
- */
767
- encryptionTag: string;
768
- /**
769
- * Email address associated with this identity
770
- */
771
- email: string;
772
- /**
773
- * Username for NIP-05 verification (e.g., "alice" for alice@domain.com)
774
- */
775
- nip05Username: string;
776
- /**
777
- * Last time this identity was used for authentication
778
- */
779
- lastUsedAt: Date | null;
780
- /**
781
- * When this identity was verified via magic link
782
- */
783
- verifiedAt: Date | null;
784
- constructor(options?: NostrIdentityOptions);
785
- /**
786
- * Get the linked Profile
787
- */
788
- getProfile(): Promise<Profile | null>;
789
- /**
790
- * Find identity by public key
791
- */
792
- static findByPubkey(pubkey: string, options?: SmrtObjectOptions): Promise<NostrIdentity | null>;
793
- /**
794
- * Find identity by email
795
- */
796
- static findByEmail(email: string, options?: SmrtObjectOptions): Promise<NostrIdentity | null>;
797
- /**
798
- * Find identity by NIP-05 username
799
- */
800
- static findByNip05(username: string, options?: SmrtObjectOptions): Promise<NostrIdentity | null>;
801
- /**
802
- * Decrypt the private key using the server master secret
803
- * @param masterSecret - SERVER_MASTER_SECRET from environment
804
- * @returns Hex-encoded private key
805
- */
806
- decryptPrivkey(masterSecret: string): string;
807
- /**
808
- * Get the full keypair (requires master secret)
809
- * @param masterSecret - SERVER_MASTER_SECRET from environment
810
- */
811
- getKeypair(masterSecret: string): {
812
- pubkey: string;
813
- privkey: string;
814
- npub: string;
815
- nsec: string;
816
- };
817
- /**
818
- * Record usage of this identity
819
- */
820
- recordUsage(): Promise<void>;
821
- /**
822
- * Mark this identity as verified
823
- */
824
- markVerified(): Promise<void>;
825
- /**
826
- * Check if this identity is verified
827
- */
828
- isVerified(): boolean;
829
- /**
830
- * Get the NIP-05 identifier (username@domain)
831
- * Note: Domain must be provided by the application
832
- */
833
- getNip05Identifier(domain: string): string;
834
- }
835
-
836
- export declare class NostrIdentityCollection extends SmrtCollection<NostrIdentity> {
837
- static readonly _itemClass: typeof NostrIdentity;
838
- /**
839
- * Find identities for a profile
840
- */
841
- findByProfile(profileId: string): Promise<NostrIdentity[]>;
842
- /**
843
- * Find identity by public key
844
- */
845
- findByPubkey(pubkey: string): Promise<NostrIdentity | null>;
846
- /**
847
- * Find identity by email
848
- */
849
- findByEmail(email: string): Promise<NostrIdentity | null>;
850
- /**
851
- * Find identity by NIP-05 username
852
- */
853
- findByNip05(username: string): Promise<NostrIdentity | null>;
854
- /**
855
- * Link a new Nostr identity to a profile with a new keypair
856
- * @param profile - The profile to link to
857
- * @param email - Email address for this identity
858
- * @param masterSecret - Server master secret for encryption
859
- * @param nip05Username - Optional NIP-05 username (defaults to email local part)
860
- */
861
- createForProfile(profile: Profile, email: string, masterSecret: string, nip05Username?: string): Promise<NostrIdentity>;
862
- /**
863
- * Link an existing Nostr identity (with encrypted keypair) to a profile
864
- */
865
- linkToProfile(profile: Profile, nostrData: {
866
- pubkey: string;
867
- encryptedPrivkey: string;
868
- encryptionIv: string;
869
- encryptionTag: string;
870
- email: string;
871
- nip05Username?: string;
872
- }): Promise<NostrIdentity>;
873
- /**
874
- * Unlink a Nostr identity from a profile
875
- */
876
- unlinkFromProfile(profileId: string, pubkey: string): Promise<boolean>;
877
- /**
878
- * Get NIP-05 response data for the /.well-known/nostr.json endpoint
879
- * @param username - Optional username filter, returns all if not provided
880
- */
881
- getNip05Response(username?: string): Promise<Nip05Response>;
882
- /**
883
- * Check if a NIP-05 username is available
884
- */
885
- isNip05Available(username: string): Promise<boolean>;
886
- /**
887
- * Update NIP-05 username for an identity
888
- */
889
- updateNip05Username(identity: NostrIdentity, newUsername: string): Promise<NostrIdentity>;
890
- }
891
-
892
- export declare interface NostrIdentityOptions extends SmrtObjectOptions {
893
- profileId?: string;
894
- pubkey?: string;
895
- encryptedPrivkey?: string;
896
- encryptionIv?: string;
897
- encryptionTag?: string;
898
- email?: string;
899
- nip05Username?: string;
900
- lastUsedAt?: Date | null;
901
- verifiedAt?: Date | null;
902
- }
903
-
904
- /**
905
- * Nostr cryptographic utilities
906
- *
907
- * Handles keypair generation, encryption/decryption of private keys,
908
- * signature verification, and bech32 encoding for Nostr authentication.
909
- */
910
- export declare interface NostrKeypair {
911
- /** Hex-encoded public key (64 characters) */
912
- pubkey: string;
913
- /** Hex-encoded private key (64 characters) */
914
- privkey: string;
915
- }
916
-
917
- /**
918
- * Convert npub (bech32) to hex public key
919
- */
920
- export declare function npubToPubkey(npub: string): string;
921
-
922
- /**
923
- * Convert nsec (bech32) to hex private key
924
- */
925
- export declare function nsecToPrivkey(nsec: string): string;
926
-
927
- export declare class OidcIdentity extends SmrtObject {
928
- /**
929
- * Link to the Profile (Person, Organization, Bot)
930
- */
931
- profileId?: string;
932
- /**
933
- * Provider name (e.g., 'keycloak', 'google', 'github')
934
- */
935
- provider: string;
936
- /**
937
- * OIDC issuer URL (e.g., https://keycloak.example.com/realms/bmp)
938
- */
939
- issuer: string;
940
- /**
941
- * OIDC subject claim - unique identifier from the provider
942
- */
943
- subject: string;
944
- /**
945
- * Stable issuer+subject key used as the database race arbiter.
946
- *
947
- * Nullable for legacy rows; every newly linked or reused identity backfills
948
- * it. A separate unique constraint makes concurrent first login fail with a
949
- * retryable conflict instead of creating two identities.
950
- */
951
- identityKey: string | null;
952
- /**
953
- * Cached email from the IdP (for display/lookup)
954
- */
955
- email: string;
956
- /**
957
- * Last time this identity was used for authentication
958
- */
959
- lastUsedAt: Date | null;
960
- constructor(options?: OidcIdentityOptions);
961
- /**
962
- * Get the linked Profile
963
- */
964
- getProfile(): Promise<Profile | null>;
965
- /**
966
- * Find identity by issuer and subject
967
- */
968
- static findBySubject(issuer: string, subject: string, options?: SmrtObjectOptions): Promise<OidcIdentity | null>;
969
- /** Build the collision-free natural key for one OIDC issuer subject. */
970
- static buildIdentityKey(issuer: string, subject: string): string;
971
- /** Keep the durable key derived from its natural-key source fields. */
972
- save(): Promise<this>;
973
- /**
974
- * Reuse an existing exact identity for its unchanged Profile.
975
- *
976
- * @deprecated Authentication links must be created through transactional
977
- * provisioning. This compatibility method only refreshes a unique mapping
978
- * that already belongs to the supplied Profile, including legacy Profile
979
- * types, and deliberately refuses to create or rebind authority.
980
- */
981
- static findOrCreate(profile: Profile, oidcData: {
982
- provider: string;
983
- issuer: string;
984
- subject: string;
985
- email?: string;
986
- }, options?: SmrtObjectOptions): Promise<OidcIdentity>;
987
- /**
988
- * Record usage of this identity
989
- */
990
- recordUsage(): Promise<void>;
991
- }
992
-
993
- export declare class OidcIdentityCollection extends SmrtCollection<OidcIdentity> {
994
- static readonly _itemClass: typeof OidcIdentity;
995
- /**
996
- * Find identities for a profile
997
- */
998
- findByProfile(profileId: string): Promise<OidcIdentity[]>;
999
- /**
1000
- * Find identity by issuer and subject
1001
- */
1002
- findBySubject(issuer: string, subject: string): Promise<OidcIdentity | null>;
1003
- /**
1004
- * Find identities by provider
1005
- */
1006
- findByProvider(provider: string): Promise<OidcIdentity[]>;
1007
- /**
1008
- * Reuse an existing exact OIDC identity for its unchanged Profile.
1009
- *
1010
- * @deprecated New authentication links require the owner-aware,
1011
- * transactional provisioning APIs. This compatibility helper may refresh a
1012
- * legacy Profile type, but refuses to create or rebind authority.
1013
- */
1014
- linkToProfile(profile: Profile, oidcData: {
1015
- provider: string;
1016
- issuer: string;
1017
- subject: string;
1018
- email?: string;
1019
- }): Promise<OidcIdentity>;
1020
- /**
1021
- * Unlink an OIDC identity from a profile
1022
- */
1023
- unlinkFromProfile(profileId: string, issuer: string, subject: string): Promise<boolean>;
1024
- }
1025
-
1026
- export declare interface OidcIdentityOptions extends SmrtObjectOptions {
1027
- profileId?: string;
1028
- provider?: string;
1029
- issuer?: string;
1030
- subject?: string;
1031
- email?: string;
1032
- lastUsedAt?: Date | null;
1033
- }
1034
-
1035
- /** Private database arbiter for canonical OIDC email provisioning races. */
1036
- export declare class OidcProfileEmailReservation extends SmrtObject {
1037
- profileId?: string;
1038
- emailKey: string;
1039
- constructor(options?: OidcProfileEmailReservationOptions);
1040
- }
1041
-
1042
- /** Internal collection for canonical OIDC email reservations. */
1043
- export declare class OidcProfileEmailReservationCollection extends SmrtCollection<OidcProfileEmailReservation> {
1044
- static readonly _itemClass: typeof OidcProfileEmailReservation;
1045
- }
1046
-
1047
- export declare interface OidcProfileEmailReservationOptions extends SmrtObjectOptions {
1048
- emailKey?: string;
1049
- profileId?: string;
1050
- }
1051
-
1052
- /**
1053
- * Organization profile type
1054
- *
1055
- * Represents companies, groups, institutions, and other organizational entities.
1056
- */
1057
- export declare class Organization extends Profile {
1058
- constructor(options?: ProfileOptions);
1059
- }
1060
-
1061
- /**
1062
- * Parse a NIP-05 identifier into its parts
1063
- * @param identifier - The identifier to parse (e.g., "alice@example.com")
1064
- */
1065
- export declare function parseNip05Identifier(identifier: string): {
1066
- localPart: string;
1067
- domain: string;
1068
- } | null;
1069
-
1070
- /**
1071
- * Person profile type
1072
- *
1073
- * Represents individual people/users.
1074
- */
1075
- export declare class Person extends Profile {
1076
- constructor(options?: ProfileOptions);
1077
- }
1078
-
1079
- /**
1080
- * Convert hex private key to nsec (bech32)
1081
- */
1082
- export declare function privkeyToNsec(privkey: string): string;
1083
-
1084
- export declare class Profile extends SmrtObject {
1085
- tenantId: string | null;
1086
- typeId?: string;
1087
- email?: string;
1088
- /** Adapter-independent identity lookup key derived from email on save. */
1089
- emailKey: string | null;
1090
- name: string;
1091
- description?: string;
1092
- metadata: ProfileMetadata[];
1093
- relationshipsFrom: ProfileRelationship[];
1094
- relationshipsTo: ProfileRelationship[];
1095
- constructor(options?: ProfileOptions);
1096
- /** Keep the durable identity key derived from the public email field. */
1097
- save(): Promise<this>;
1098
- /**
1099
- * Get the profile type slug for this profile
1100
- *
1101
- * @returns The slug of the profile type
1102
- */
1103
- getTypeSlug(): Promise<string>;
1104
- /**
1105
- * Set the profile type by slug
1106
- *
1107
- * @param slug - The slug of the profile type
1108
- * @throws Error if profile type not found
1109
- */
1110
- setTypeBySlug(slug: string): Promise<void>;
1111
- /**
1112
- * Add metadata to this profile
1113
- *
1114
- * @param metafieldSlug - The slug of the metafield
1115
- * @param value - The value to set
1116
- */
1117
- addMetadata(metafieldSlug: string, value: unknown): Promise<void>;
1118
- /**
1119
- * Get all metadata for this profile as key-value object
1120
- *
1121
- * @returns Object with metafield slugs as keys
1122
- */
1123
- getMetadata(): Promise<Record<string, string>>;
1124
- /**
1125
- * Update multiple metadata values
1126
- *
1127
- * @param metadata - Object with metafield slugs as keys and values
1128
- */
1129
- updateMetadata(metadata: Record<string, unknown>): Promise<void>;
1130
- /**
1131
- * Remove metadata by metafield slug
1132
- *
1133
- * @param metafieldSlug - The slug of the metafield to remove
1134
- */
1135
- removeMetadata(metafieldSlug: string): Promise<void>;
1136
- private getProfileAssetCollection;
1137
- getAssets(relationship?: string): Promise<Asset[]>;
1138
- addAsset(asset: Asset, relationship?: string, sortOrder?: number): Promise<void>;
1139
- removeAsset(assetId: string, relationship?: string): Promise<void>;
1140
- /**
1141
- * Add a relationship to another profile
1142
- *
1143
- * @param toProfile - The target profile
1144
- * @param relationshipSlug - The type of relationship
1145
- * @param contextProfile - Optional context profile for tertiary relationships
1146
- */
1147
- addRelationship(toProfile: Profile, relationshipSlug: string, contextProfile?: Profile): Promise<void>;
1148
- /**
1149
- * Get all relationships for this profile
1150
- *
1151
- * @param options - Filter options (typeSlug, direction)
1152
- * @returns Array of ProfileRelationship instances
1153
- */
1154
- getRelationships(options?: {
1155
- typeSlug?: string;
1156
- direction?: 'from' | 'to' | 'all';
1157
- }): Promise<ProfileRelationship[]>;
1158
- /**
1159
- * Get related profiles
1160
- *
1161
- * @param relationshipSlug - Optional filter by relationship type slug
1162
- * @returns Array of related Profile instances
1163
- */
1164
- getRelatedProfiles(relationshipSlug?: string): Promise<Profile[]>;
1165
- /**
1166
- * Remove a relationship to another profile
1167
- *
1168
- * @param toProfile - The target profile
1169
- * @param relationshipSlug - The type of relationship to remove
1170
- */
1171
- removeRelationship(toProfile: Profile, relationshipSlug: string): Promise<void>;
1172
- /**
1173
- * AI-powered: Generate a professional bio for this profile
1174
- *
1175
- * Uses the `smrtProfiles.profile.generateBio` prompt registered via
1176
- * `@happyvertical/smrt-prompts`, allowing tenant- or instance-level
1177
- * overrides of the template, model, and parameters at runtime.
1178
- *
1179
- * @returns Generated bio text
1180
- */
1181
- generateBio(): Promise<string>;
1182
- /**
1183
- * AI-powered: Check if profile matches criteria
1184
- *
1185
- * @param criteria - Criteria to match against
1186
- * @returns True if matches criteria
1187
- */
1188
- matches(criteria: string): Promise<boolean>;
1189
- /**
1190
- * Find profiles by metadata key-value pair
1191
- *
1192
- * @param metafieldSlug - The metafield slug to search
1193
- * @param value - The value to match
1194
- * @returns Array of matching profiles
1195
- */
1196
- static findByMetadata(_metafieldSlug: string, _value: unknown): Promise<Profile[]>;
1197
- /**
1198
- * Find profiles by type slug
1199
- *
1200
- * @param typeSlug - The profile type slug
1201
- * @returns Array of matching profiles
1202
- */
1203
- static findByType(_typeSlug: string): Promise<Profile[]>;
1204
- /**
1205
- * Find related profiles for a given profile
1206
- *
1207
- * @param profileId - The profile UUID
1208
- * @param relationshipSlug - Optional filter by relationship type
1209
- * @returns Array of related profiles
1210
- */
1211
- static findRelated(_profileId: string, _relationshipSlug?: string): Promise<Profile[]>;
1212
- /**
1213
- * Search profiles by email
1214
- *
1215
- * @param email - The email to search for
1216
- * @returns Profile or null if not found
1217
- */
1218
- static searchByEmail(_email: string): Promise<Profile | null>;
1219
- /**
1220
- * Get all API keys for this profile
1221
- *
1222
- * @returns Array of API keys
1223
- */
1224
- getApiKeys(): Promise<ApiKey[]>;
1225
- /**
1226
- * Get active (non-revoked, non-expired) API keys for this profile
1227
- *
1228
- * @returns Array of active API keys
1229
- */
1230
- getActiveApiKeys(): Promise<ApiKey[]>;
1231
- /**
1232
- * Generate a new API key for this profile
1233
- *
1234
- * @param options - Key options (name, scopes, expiration)
1235
- * @returns The generated key (plaintext) and ApiKey record
1236
- */
1237
- generateApiKey(options: {
1238
- name: string;
1239
- scopes?: string[];
1240
- expiresAt?: Date | null;
1241
- }): Promise<GenerateKeyResult>;
1242
- /**
1243
- * Get all OIDC identities linked to this profile
1244
- *
1245
- * @returns Array of OIDC identity records
1246
- */
1247
- getOidcIdentities(): Promise<OidcIdentity[]>;
1248
- /**
1249
- * Reuse an existing exact OIDC identity for this unchanged Profile.
1250
- *
1251
- * @param oidcData - OIDC provider data
1252
- * @returns The linked OIDC identity record
1253
- * @deprecated New authentication links require owner-aware transactional
1254
- * provisioning. This compatibility helper may refresh a legacy Profile
1255
- * type, but refuses to create or rebind authority.
1256
- */
1257
- linkOidcIdentity(oidcData: {
1258
- provider: string;
1259
- issuer: string;
1260
- subject: string;
1261
- email?: string;
1262
- }): Promise<OidcIdentity>;
1263
- /**
1264
- * Get all Nostr identities linked to this profile
1265
- *
1266
- * @returns Array of Nostr identity records
1267
- */
1268
- getNostrIdentities(): Promise<NostrIdentity[]>;
1269
- /**
1270
- * Link a new Nostr identity to this profile
1271
- *
1272
- * @param nostrData - Nostr identity data (encrypted keypair)
1273
- * @returns The linked Nostr identity record
1274
- */
1275
- linkNostrIdentity(nostrData: {
1276
- pubkey: string;
1277
- encryptedPrivkey: string;
1278
- encryptionIv: string;
1279
- encryptionTag: string;
1280
- email: string;
1281
- nip05Username?: string;
1282
- }): Promise<NostrIdentity>;
1283
- /**
1284
- * Get audit logs for actions performed by this profile
1285
- *
1286
- * @param limit - Maximum number of logs to return
1287
- * @returns Array of audit log entries
1288
- */
1289
- getAuditLogs(limit?: number): Promise<AuditLog[]>;
1290
- /**
1291
- * Record an audit log entry for an action by this profile
1292
- *
1293
- * @param options - Audit log options
1294
- * @returns The created audit log entry
1295
- */
1296
- recordAction(options: {
1297
- action: string;
1298
- resourceType: string;
1299
- resourceId: string;
1300
- source?: 'web' | 'cli' | 'ci' | 'webhook' | 'mcp';
1301
- metadata?: Record<string, unknown>;
1302
- onBehalfOf?: Profile | null;
1303
- }): Promise<AuditLog>;
1304
- }
1305
-
1306
- export declare const PROFILE_EMAIL_KEY_BACKFILL_NAME = "@happyvertical/smrt-profiles:profile-email-keys:v1";
1307
-
1308
- export declare class ProfileAsset extends SmrtObject {
1309
- tenantId: string | null;
1310
- profileId: string;
1311
- assetId: string;
1312
- relationship: string;
1313
- sortOrder: number;
1314
- constructor(options?: ProfileAssetOptions);
1315
- }
1316
-
1317
- export declare class ProfileAssetCollection extends SmrtJunction<ProfileAsset> {
1318
- static readonly _itemClass: typeof ProfileAsset;
1319
- protected leftField: string;
1320
- protected rightField: string;
1321
- private profileCollectionPromise;
1322
- private getProfileCollection;
1323
- getAssets(profileId: string, relationship?: string): Promise<Asset[]>;
1324
- addAsset(profileId: string, asset: Asset, relationship?: string, sortOrder?: number): Promise<void>;
1325
- removeAsset(profileId: string, assetId: string, relationship?: string): Promise<void>;
1326
- }
1327
-
1328
- export declare interface ProfileAssetOptions extends SmrtObjectOptions {
1329
- profileId?: string;
1330
- assetId?: string;
1331
- relationship?: string;
1332
- sortOrder?: number;
1333
- tenantId?: string | null;
1334
- }
1335
-
1336
- export declare class ProfileCollection extends SmrtCollection<Profile> {
1337
- static readonly _itemClass: typeof Profile;
1338
- private emailKeysReadyPromise;
1339
- /**
1340
- * Find a profile by email address
1341
- *
1342
- * @param email - The email address to search for
1343
- * @returns The matching profile or null
1344
- */
1345
- findByEmail(email: string): Promise<Profile | null>;
1346
- /**
1347
- * Resolve one unambiguous global Person by normalized email.
1348
- *
1349
- * Unlike `findByEmail()`, this identity-boundary helper deliberately reads
1350
- * across tenant scopes and fails closed when any matching row is
1351
- * tenant-scoped, is not a Person STI row, or when more than one row matches
1352
- * case-insensitively. It is intended for verified external identities.
1353
- */
1354
- findUniqueGlobalPersonByEmail(email: string): Promise<Profile | null>;
1355
- /**
1356
- * Validate and hydrate a supplied canonical Profile.
1357
- *
1358
- * The Profile must be the sole case-insensitive match for its stored email.
1359
- * When `email` is provided, that address must also match the stored email.
1360
- */
1361
- requireCanonicalGlobalPerson(profileId: string, email?: string): Promise<Profile>;
1362
- /**
1363
- * Reserve the normalized email for a previously validated canonical Person.
1364
- *
1365
- * The unique stored key turns a concurrent OIDC first-login race into a
1366
- * retryable database conflict. Legacy Profiles remain unaffected until an
1367
- * identity boundary safely claims them.
1368
- */
1369
- reserveCanonicalIdentityEmail(profileId: string, email?: string): Promise<Profile>;
1370
- /**
1371
- * Find profiles by type slug
1372
- *
1373
- * @param typeSlug - The profile type slug to filter by
1374
- * @returns Array of matching profiles
1375
- */
1376
- findByType(typeSlug: string): Promise<Profile[]>;
1377
- private requireDatabase;
1378
- private loadCanonicalEmailRows;
1379
- /** Require the deploy-time backfill marker before indexed identity reads. */
1380
- private ensureEmailKeysReady;
1381
- private checkEmailKeysReady;
1382
- private isStaleEmailReservation;
1383
- private assertRowEmailKeyCurrent;
1384
- private assertCanonicalRows;
1385
- private requireHydratedProfile;
1386
- /**
1387
- * Batch get metadata for multiple profiles
1388
- *
1389
- * @param profileIds - Array of profile UUIDs
1390
- * @returns Map of profile ID to metadata object
1391
- */
1392
- batchGetMetadata(profileIds: string[]): Promise<Map<string, Record<string, string>>>;
1393
- /**
1394
- * Batch update metadata for multiple profiles
1395
- *
1396
- * @param updates - Array of { profileId, data } objects
1397
- */
1398
- batchUpdateMetadata(updates: Array<{
1399
- profileId: string;
1400
- data: Record<string, unknown>;
1401
- }>): Promise<void>;
1402
- /**
1403
- * Find related profiles for a given profile
1404
- *
1405
- * @param profileId - The profile UUID
1406
- * @param relationshipSlug - Optional filter by relationship type
1407
- * @returns Array of related profiles
1408
- */
1409
- findRelated(profileId: string, relationshipSlug?: string): Promise<Profile[]>;
1410
- getAssets(profileId: string, relationship?: string): Promise<Asset[]>;
1411
- addAsset(profileId: string, asset: Asset, relationship?: string, sortOrder?: number): Promise<void>;
1412
- removeAsset(profileId: string, assetId: string, relationship?: string): Promise<void>;
1413
- /**
1414
- * Get the relationship network for a profile up to a maximum depth
1415
- *
1416
- * @param profileId - The starting profile UUID
1417
- * @param options - Configuration options
1418
- * @returns Map of profile ID to depth level
1419
- */
1420
- getRelationshipNetwork(profileId: string, options?: {
1421
- maxDepth?: number;
1422
- }): Promise<Map<string, number>>;
1423
- /**
1424
- * Find all profiles belonging to a specific tenant
1425
- *
1426
- * @param tenantId - The tenant UUID to filter by
1427
- * @returns Array of profiles for this tenant
1428
- */
1429
- findByTenant(tenantId: string): Promise<Profile[]>;
1430
- /**
1431
- * Find all global profiles (no tenant association).
1432
- *
1433
- * Routes through the shared tenant-global helper so it does not throw under
1434
- * an active tenant context (an explicit `tenant_id IS NULL` filter would be
1435
- * flagged as an isolation violation). (#1600)
1436
- *
1437
- * @returns Array of profiles with null tenantId
1438
- */
1439
- findGlobal(): Promise<Profile[]>;
1440
- /**
1441
- * Find profiles belonging to a tenant plus all global profiles.
1442
- *
1443
- * Fails closed if an active tenant context requests a different tenant's
1444
- * rows; the admin/system path keeps the cross-tenant capability. (#1600)
1445
- *
1446
- * @param tenantId - The tenant UUID to include
1447
- * @returns Array of tenant-specific and global profiles
1448
- */
1449
- findWithGlobals(tenantId: string): Promise<Profile[]>;
1450
- }
1451
-
1452
- export declare class ProfileMetadata extends SmrtObject {
1453
- tenantId: string | null;
1454
- profileId?: string;
1455
- metafieldId?: string;
1456
- value: string;
1457
- constructor(options?: ProfileMetadataOptions);
1458
- /**
1459
- * Validate this metadata value against the metafield's validation schema
1460
- *
1461
- * @returns True if valid, throws error if invalid
1462
- */
1463
- validate(): Promise<boolean>;
1464
- /**
1465
- * Get the metafield slug for this metadata
1466
- *
1467
- * @returns The slug of the metafield
1468
- */
1469
- getMetafieldSlug(): Promise<string>;
1470
- }
1471
-
1472
- export declare class ProfileMetadataCollection extends SmrtCollection<ProfileMetadata> {
1473
- static readonly _itemClass: typeof ProfileMetadata;
1474
- /**
1475
- * Get all metadata for a profile
1476
- *
1477
- * @param profileId - The profile UUID
1478
- * @returns Array of ProfileMetadata instances
1479
- */
1480
- getByProfile(profileId: string): Promise<ProfileMetadata[]>;
1481
- /**
1482
- * Get metadata as key-value object for a profile
1483
- *
1484
- * @param profileId - The profile UUID
1485
- * @returns Object with metafield slugs as keys
1486
- */
1487
- getMetadataObject(profileId: string): Promise<Record<string, string>>;
1488
- /**
1489
- * Find all profiles with a specific metadata key-value pair
1490
- *
1491
- * @param metafieldId - The metafield UUID
1492
- * @param value - The value to match
1493
- * @returns Array of profile UUIDs
1494
- */
1495
- findProfilesByMetadata(metafieldId: string, value: unknown): Promise<string[]>;
1496
- }
1497
-
1498
- export declare interface ProfileMetadataOptions extends SmrtObjectOptions {
1499
- profileId?: string;
1500
- metafieldId?: string;
1501
- value?: string;
1502
- tenantId?: string | null;
1503
- }
1504
-
1505
- export declare class ProfileMetafield extends SmrtObject {
1506
- tenantId: string | null;
1507
- name: string;
1508
- description?: string;
1509
- validation?: ValidationSchema;
1510
- constructor(options?: ProfileMetafieldOptions);
1511
- /**
1512
- * Convenience method for slug-based lookup
1513
- *
1514
- * @param slug - The slug to search for
1515
- * @returns ProfileMetafield instance or null if not found
1516
- */
1517
- static getBySlug(_slug: string): Promise<ProfileMetafield | null>;
1518
- /**
1519
- * Register a custom validator function
1520
- *
1521
- * @param name - Name of the validator (used in validation.custom field)
1522
- * @param validator - The validator function
1523
- */
1524
- static registerValidator(name: string, validator: ValidatorFunction): void;
1525
- /**
1526
- * Get a registered custom validator
1527
- *
1528
- * @param name - Name of the validator
1529
- * @returns The validator function or undefined
1530
- */
1531
- static getValidator(name: string): ValidatorFunction | undefined;
1532
- /**
1533
- * Validate a value against this metafield's validation schema
1534
- *
1535
- * @param value - The value to validate
1536
- * @returns True if valid, throws ValidationError if invalid
1537
- */
1538
- validateValue(value: unknown): Promise<boolean>;
1539
- }
1540
-
1541
- export declare class ProfileMetafieldCollection extends SmrtCollection<ProfileMetafield> {
1542
- static readonly _itemClass: typeof ProfileMetafield;
1543
- /**
1544
- * Get metafield by slug
1545
- *
1546
- * @param slug - The slug to search for
1547
- * @returns ProfileMetafield instance or null
1548
- */
1549
- getBySlug(slug: string): Promise<ProfileMetafield | null>;
1550
- /**
1551
- * Get or create a metafield by slug
1552
- *
1553
- * @param slug - The slug to search for
1554
- * @param defaults - Default values if creating
1555
- * @returns ProfileMetafield instance
1556
- */
1557
- getOrCreateBySlug(slug: string, defaults: {
1558
- name: string;
1559
- description?: string;
1560
- validation?: ValidationSchema;
1561
- }): Promise<ProfileMetafield>;
1562
- }
1563
-
1564
- export declare interface ProfileMetafieldOptions extends SmrtObjectOptions {
1565
- slug?: string;
1566
- name?: string;
1567
- description?: string;
1568
- validation?: ValidationSchema;
1569
- tenantId?: string | null;
1570
- }
1571
-
1572
- export declare interface ProfileOptions extends SmrtObjectOptions {
1573
- typeId?: string;
1574
- email?: string;
1575
- name?: string;
1576
- description?: string;
1577
- tenantId?: string | null;
1578
- }
1579
-
1580
- export declare class ProfileRelationship extends SmrtObject {
1581
- tenantId: string | null;
1582
- fromProfileId?: string;
1583
- toProfileId?: string;
1584
- typeId?: string;
1585
- contextProfileId?: string;
1586
- terms: ProfileRelationshipTerm[];
1587
- constructor(options?: ProfileRelationshipOptions);
1588
- /**
1589
- * Get the relationship type slug
1590
- *
1591
- * @returns The slug of the relationship type
1592
- */
1593
- getTypeSlug(): Promise<string>;
1594
- /**
1595
- * Add a term (time period) to this relationship
1596
- *
1597
- * @param startedAt - Start date of the term
1598
- * @param endedAt - Optional end date of the term
1599
- */
1600
- addTerm(startedAt: Date, endedAt?: Date): Promise<void>;
1601
- /**
1602
- * End the current active term
1603
- *
1604
- * @param endedAt - End date for the term
1605
- */
1606
- endCurrentTerm(endedAt: Date): Promise<void>;
1607
- /**
1608
- * Get all terms for this relationship
1609
- *
1610
- * @returns Array of ProfileRelationshipTerm instances
1611
- */
1612
- getTerms(): Promise<ProfileRelationshipTerm[]>;
1613
- /**
1614
- * Get the active term (no end date)
1615
- *
1616
- * @returns Current term or null if none active
1617
- */
1618
- getActiveTerm(): Promise<ProfileRelationshipTerm | null>;
1619
- }
1620
-
1621
- export declare class ProfileRelationshipCollection extends SmrtCollection<ProfileRelationship> {
1622
- static readonly _itemClass: typeof ProfileRelationship;
1623
- /**
1624
- * Get all relationships from a profile
1625
- *
1626
- * @param fromProfileId - The origin profile UUID
1627
- * @param typeId - Optional filter by relationship type UUID
1628
- * @returns Array of ProfileRelationship instances
1629
- */
1630
- getFromProfile(fromProfileId: string, typeId?: string): Promise<ProfileRelationship[]>;
1631
- /**
1632
- * Get all relationships to a profile
1633
- *
1634
- * @param toProfileId - The target profile UUID
1635
- * @param typeId - Optional filter by relationship type UUID
1636
- * @returns Array of ProfileRelationship instances
1637
- */
1638
- getToProfile(toProfileId: string, typeId?: string): Promise<ProfileRelationship[]>;
1639
- /**
1640
- * Get all relationships for a profile (both directions)
1641
- *
1642
- * @param profileId - The profile UUID
1643
- * @param typeId - Optional filter by relationship type UUID
1644
- * @returns Array of ProfileRelationship instances
1645
- */
1646
- getForProfile(profileId: string, typeId?: string): Promise<ProfileRelationship[]>;
1647
- /**
1648
- * Check if a relationship exists between two profiles
1649
- *
1650
- * @param fromProfileId - The origin profile UUID
1651
- * @param toProfileId - The target profile UUID
1652
- * @param typeId - The relationship type UUID
1653
- * @returns True if relationship exists
1654
- */
1655
- exists(fromProfileId: string, toProfileId: string, typeId: string): Promise<boolean>;
1656
- }
1657
-
1658
- export declare interface ProfileRelationshipOptions extends SmrtObjectOptions {
1659
- fromProfileId?: string;
1660
- toProfileId?: string;
1661
- typeId?: string;
1662
- contextProfileId?: string;
1663
- tenantId?: string | null;
1664
- }
1665
-
1666
- export declare class ProfileRelationshipTerm extends SmrtObject {
1667
- relationshipId?: string;
1668
- startedAt: Date;
1669
- endedAt?: Date;
1670
- constructor(options?: ProfileRelationshipTermOptions);
1671
- /**
1672
- * Check if this term is currently active
1673
- *
1674
- * @returns True if active (no end date or end date in future)
1675
- */
1676
- isActive(): boolean;
1677
- /**
1678
- * End this term
1679
- *
1680
- * @param endedAt - End date for the term (defaults to now)
1681
- */
1682
- end(endedAt?: Date): Promise<void>;
1683
- /**
1684
- * Get the duration of this term in days
1685
- *
1686
- * @returns Duration in days
1687
- */
1688
- getDurationDays(): number;
1689
- }
1690
-
1691
- export declare class ProfileRelationshipTermCollection extends SmrtCollection<ProfileRelationshipTerm> {
1692
- static readonly _itemClass: typeof ProfileRelationshipTerm;
1693
- /**
1694
- * Get all terms for a relationship
1695
- *
1696
- * @param relationshipId - The relationship UUID
1697
- * @returns Array of ProfileRelationshipTerm instances
1698
- */
1699
- getByRelationship(relationshipId: string): Promise<ProfileRelationshipTerm[]>;
1700
- /**
1701
- * Get the active term for a relationship (no end date or future end date)
1702
- *
1703
- * @param relationshipId - The relationship UUID
1704
- * @returns Active term or null
1705
- */
1706
- getActiveTerm(relationshipId: string): Promise<ProfileRelationshipTerm | null>;
1707
- /**
1708
- * Get all historical (ended) terms for a relationship
1709
- *
1710
- * @param relationshipId - The relationship UUID
1711
- * @returns Array of ended ProfileRelationshipTerm instances
1712
- */
1713
- getHistoricalTerms(relationshipId: string): Promise<ProfileRelationshipTerm[]>;
1714
- }
1715
-
1716
- export declare interface ProfileRelationshipTermOptions extends SmrtObjectOptions {
1717
- relationshipId?: string;
1718
- startedAt?: Date;
1719
- endedAt?: Date;
1720
- }
1721
-
1722
- export declare class ProfileRelationshipType extends SmrtObject {
1723
- name: string;
1724
- reciprocal: boolean;
1725
- constructor(options?: ProfileRelationshipTypeOptions);
1726
- /**
1727
- * Convenience method for slug-based lookup
1728
- *
1729
- * @param slug - The slug to search for
1730
- * @returns ProfileRelationshipType instance or null if not found
1731
- */
1732
- static getBySlug(_slug: string): Promise<ProfileRelationshipType | null>;
1733
- /**
1734
- * Register a custom reciprocal handler for a relationship type
1735
- *
1736
- * @param slug - The relationship type slug
1737
- * @param handler - The handler function to execute when creating reciprocal relationship
1738
- */
1739
- static registerReciprocalHandler(slug: string, handler: ReciprocalHandler): void;
1740
- /**
1741
- * Get the reciprocal handler for a relationship type
1742
- *
1743
- * @param slug - The relationship type slug
1744
- * @returns The handler function or undefined
1745
- */
1746
- static getReciprocalHandler(slug: string): ReciprocalHandler | undefined;
1747
- /**
1748
- * Check if a relationship type is reciprocal
1749
- *
1750
- * @param slug - The relationship type slug
1751
- * @returns True if reciprocal, false otherwise
1752
- */
1753
- static isReciprocal(slug: string): Promise<boolean>;
1754
- }
1755
-
1756
- export declare class ProfileRelationshipTypeCollection extends SmrtCollection<ProfileRelationshipType> {
1757
- static readonly _itemClass: typeof ProfileRelationshipType;
1758
- /**
1759
- * Get relationship type by slug
1760
- *
1761
- * @param slug - The slug to search for
1762
- * @returns ProfileRelationshipType instance or null
1763
- */
1764
- getBySlug(slug: string): Promise<ProfileRelationshipType | null>;
1765
- /**
1766
- * Get or create a relationship type by slug
1767
- *
1768
- * @param slug - The slug to search for
1769
- * @param defaults - Default values if creating
1770
- * @returns ProfileRelationshipType instance
1771
- */
1772
- getOrCreateBySlug(slug: string, defaults: {
1773
- name: string;
1774
- reciprocal?: boolean;
1775
- }): Promise<ProfileRelationshipType>;
1776
- /**
1777
- * Get all reciprocal relationship types
1778
- *
1779
- * @returns Array of reciprocal ProfileRelationshipType instances
1780
- */
1781
- getReciprocal(): Promise<ProfileRelationshipType[]>;
1782
- /**
1783
- * Get all directional (non-reciprocal) relationship types
1784
- *
1785
- * @returns Array of directional ProfileRelationshipType instances
1786
- */
1787
- getDirectional(): Promise<ProfileRelationshipType[]>;
1788
- }
1789
-
1790
- export declare interface ProfileRelationshipTypeOptions extends SmrtObjectOptions {
1791
- slug?: string;
1792
- name?: string;
1793
- reciprocal?: boolean;
1794
- }
1795
-
1796
- export declare class ProfileType extends SmrtObject {
1797
- tenantId: string | null;
1798
- name: string;
1799
- description?: string;
1800
- constructor(options?: ProfileTypeOptions);
1801
- /**
1802
- * Convenience method for slug-based lookup
1803
- *
1804
- * @param slug - The slug to search for
1805
- * @returns ProfileType instance or null if not found
1806
- */
1807
- static getBySlug(_slug: string): Promise<ProfileType | null>;
1808
- }
1809
-
1810
- export declare class ProfileTypeCollection extends SmrtCollection<ProfileType> {
1811
- static readonly _itemClass: typeof ProfileType;
1812
- /**
1813
- * Get profile type by slug
1814
- *
1815
- * @param slug - The slug to search for
1816
- * @returns ProfileType instance or null
1817
- */
1818
- getBySlug(slug: string): Promise<ProfileType | null>;
1819
- /**
1820
- * Get or create a profile type by slug
1821
- *
1822
- * @param slug - The slug to search for
1823
- * @param defaults - Default values if creating
1824
- * @returns ProfileType instance
1825
- */
1826
- getOrCreateBySlug(slug: string, defaults: {
1827
- name: string;
1828
- description?: string;
1829
- }): Promise<ProfileType>;
1830
- /**
1831
- * Atomically create or load a global ProfileType from trusted system code.
1832
- *
1833
- * This intentionally bypasses tenant auto-population and therefore refuses
1834
- * to run outside an explicit `withSystemContext()` boundary.
1835
- */
1836
- getOrCreateGlobalBySlug(slug: string, defaults: {
1837
- name: string;
1838
- description?: string;
1839
- }): Promise<ProfileType>;
1840
- private loadGlobalBySlug;
1841
- }
1842
-
1843
- export declare interface ProfileTypeOptions extends SmrtObjectOptions {
1844
- slug?: string;
1845
- name?: string;
1846
- description?: string;
1847
- tenantId?: string | null;
1848
- }
1849
-
1850
- export declare function promptMessageOptions(ai: ResolvedPromptAI): {
1851
- maxTokens?: number | undefined;
1852
- temperature?: number | undefined;
1853
- model?: string | undefined;
1854
- };
1855
-
1856
- /**
1857
- * Convert hex public key to npub (bech32)
1858
- */
1859
- export declare function pubkeyToNpub(pubkey: string): string;
1860
-
1861
- /**
1862
- * Handler function interface for reciprocal relationships
1863
- *
1864
- * @param from - The profile initiating the relationship
1865
- * @param to - The target profile
1866
- * @param context - Optional context profile for tertiary relationships
1867
- * @param options - Additional options for the handler
1868
- */
1869
- export declare type ReciprocalHandler = (from: Profile, to: Profile, context?: Profile, options?: Record<string, unknown>) => Promise<void>;
1870
-
1871
- /**
1872
- * Resolve — creating on first use — the {@link Profile} an agent authors as.
1873
- *
1874
- * The lookup is tenant-bound: an agent identifier resolves to a distinct
1875
- * profile per tenant, so one tenant's assistant can never author into another
1876
- * tenant's conversation. Resolution is idempotent; repeated calls for the same
1877
- * `(tenantId, agentId)` return the same profile.
1878
- *
1879
- * @param profiles - Profile collection bound to the caller's database options.
1880
- * @param params - Agent identity to resolve.
1881
- * @returns The agent's profile, whose `id` is a real uuid.
1882
- * @throws Error when `agentId` is empty.
1883
- */
1884
- export declare function resolveAgentProfile(profiles: ProfileCollection, params: ResolveAgentProfileParams): Promise<Profile>;
1885
-
1886
- /**
1887
- * Resolve an agent profile and return its uuid.
1888
- *
1889
- * Convenience wrapper for the common case — an authoring seam that needs the
1890
- * id, not the row.
1891
- *
1892
- * @param profiles - Profile collection bound to the caller's database options.
1893
- * @param params - Agent identity to resolve.
1894
- * @returns The agent profile's uuid.
1895
- */
1896
- export declare function resolveAgentProfileId(profiles: ProfileCollection, params: ResolveAgentProfileParams): Promise<string>;
1897
-
1898
- /** Inputs for {@link resolveAgentProfile}. */
1899
- export declare interface ResolveAgentProfileParams {
1900
- /** Stable agent identifier (e.g. `anytown_site_assistant`). */
1901
- agentId: string;
1902
- /** Owning tenant, or `null` for an untenanted agent. */
1903
- tenantId?: string | null;
1904
- /** Display name for a newly created profile. Defaults to `agentId`. */
1905
- name?: string;
1906
- }
1907
-
1908
- /**
1909
- * Resolve authentication context to a Profile
1910
- *
1911
- * @param context - The authentication context from the request
1912
- * @returns The resolved profile and metadata
1913
- *
1914
- * @example
1915
- * ```typescript
1916
- * // In SvelteKit hooks.server.ts
1917
- * import { resolveIdentity } from '@happyvertical/smrt-profiles';
1918
- *
1919
- * const identityMiddleware: Handle = async ({ event, resolve }) => {
1920
- * const session = await event.locals.auth();
1921
- *
1922
- * const { profile, source } = await resolveIdentity({
1923
- * oidcSession: session,
1924
- * apiKey: event.request.headers.get('X-API-Key'),
1925
- * actor: event.request.headers.get('X-Actor'),
1926
- * db: { type: 'postgres', url: DATABASE_URL },
1927
- * });
1928
- *
1929
- * event.locals.profile = profile;
1930
- * event.locals.authSource = source;
1931
- *
1932
- * return resolve(event);
1933
- * };
1934
- * ```
1935
- */
1936
- export declare function resolveIdentity(context: AuthContext): Promise<ResolveIdentityResult>;
1937
-
1938
- /**
1939
- * Result of identity resolution
1940
- */
1941
- export declare interface ResolveIdentityResult {
1942
- /**
1943
- * The resolved profile, or null if not authenticated
1944
- */
1945
- profile: Profile | null;
1946
- /**
1947
- * How the identity was resolved
1948
- */
1949
- source: 'api_key' | 'oidc' | 'nostr' | 'actor' | 'none';
1950
- /**
1951
- * The API key record if authenticated via API key
1952
- */
1953
- apiKey?: ApiKey;
1954
- /**
1955
- * The OIDC identity record if authenticated via OIDC
1956
- */
1957
- oidcIdentity?: OidcIdentity;
1958
- /**
1959
- * The Nostr identity record if authenticated via Nostr
1960
- */
1961
- nostrIdentity?: NostrIdentity;
1962
- }
1963
-
1964
- /**
1965
- * Sign a Nostr event using Schnorr signatures (BIP-340)
1966
- * @param event - Event to sign (without id and sig)
1967
- * @param privkey - Hex-encoded private key
1968
- */
1969
- export declare function signEvent(event: Omit<NostrEvent, 'id' | 'sig'>, privkey: string): NostrEvent;
1970
-
1971
- export declare const smrtProfilesGenerateBioPrompt: PromptDefinition;
1972
-
1973
- /**
1974
- * Validation schema structure for profile metadata fields
1975
- */
1976
- export declare interface ValidationSchema {
1977
- /** Type constraint */
1978
- type?: 'string' | 'number' | 'boolean' | 'date' | 'json';
1979
- /** Regex pattern for string validation */
1980
- pattern?: string;
1981
- /** Minimum string length */
1982
- minLength?: number;
1983
- /** Maximum string length */
1984
- maxLength?: number;
1985
- /** Minimum numeric value */
1986
- min?: number;
1987
- /** Maximum numeric value */
1988
- max?: number;
1989
- /** Custom validator function name */
1990
- custom?: string;
1991
- /** Custom validation error message */
1992
- message?: string;
1993
- }
1994
-
1995
- /**
1996
- * Custom validator function type
1997
- */
1998
- export declare type ValidatorFunction = (value: unknown) => boolean | Promise<boolean>;
1999
-
2000
- /**
2001
- * Verify an authentication event
2002
- * @param event - Auth event to verify
2003
- * @param expectedChallenge - Expected challenge string
2004
- * @param maxAgeSeconds - Maximum age of the event in seconds (default: 300 = 5 minutes)
2005
- */
2006
- export declare function verifyAuthEvent(event: NostrEvent, expectedChallenge: string, maxAgeSeconds?: number): {
2007
- valid: boolean;
2008
- error?: string;
2009
- };
2010
-
2011
- /**
2012
- * Verify a Nostr event Schnorr signature (BIP-340)
2013
- * @param event - Nostr event object with sig field
2014
- */
2015
- export declare function verifyNostrSignature(event: NostrEvent): boolean;
2016
-
2017
- export declare interface VerifyResult {
2018
- success: boolean;
2019
- /** The profile */
2020
- profile?: Profile;
2021
- /** The Nostr identity */
2022
- nostrIdentity?: NostrIdentity;
2023
- /** The decrypted keypair (only on success) */
2024
- keypair?: {
2025
- pubkey: string;
2026
- privkey: string;
2027
- npub: string;
2028
- nsec: string;
2029
- };
2030
- /** Error message if success is false */
2031
- error?: string;
2032
- /** Error code for programmatic handling */
2033
- errorCode?: 'INVALID_TOKEN' | 'EXPIRED_TOKEN' | 'USED_TOKEN' | 'NOT_FOUND';
2034
- }
2035
-
2036
- export { }
2037
-
2038
-
2039
1
  /**
2040
- * Extend globalThis to include reciprocal handlers registry.
2041
- * Using globalThis ensures all module instances share the same handlers,
2042
- * which is critical in monorepos where the same package can be loaded
2043
- * from different paths (e.g., pnpm store vs workspace symlink).
2
+ * @happyvertical/smrt-profiles
2044
3
  *
2045
- * @see https://github.com/happyvertical/smrt/issues/543
2046
- */
2047
- declare global {
2048
- var __smrtProfileRelationshipHandlers: Map<string, ReciprocalHandler> | undefined;
2049
- var __smrtProfileRelationshipHandlersInitialized: boolean | undefined;
2050
- }
2051
-
2052
-
2053
- /**
2054
- * Extend globalThis to include custom validators registry.
2055
- * Using globalThis ensures all module instances share the same validators,
2056
- * which is critical in monorepos where the same package can be loaded
2057
- * from different paths (e.g., pnpm store vs workspace symlink).
4
+ * Profile management system with relationships, metadata, reciprocal associations,
5
+ * and authentication primitives (OIDC, Nostr, API keys, audit logging).
2058
6
  *
2059
- * @see https://github.com/happyvertical/smrt/issues/543
7
+ * @packageDocumentation
2060
8
  */
2061
- declare global {
2062
- var __smrtProfileMetafieldValidators: Map<string, ValidatorFunction> | undefined;
2063
- }
9
+ import './__smrt-register__.js';
10
+ import './prompts.js';
11
+ export { AGENT_PROFILE_CONTEXT, AGENT_PROFILE_TYPE_SLUG, type ResolveAgentProfileParams, resolveAgentProfile, resolveAgentProfileId, } from './agent-profile';
12
+ export { type AuthContext, computeEventId, createAuthEvent, createMagicLinkService, createNip05Handler, createProfileFromNostr, createProfileFromOidc, decryptPrivkey, deriveEncryptionKey, type EncryptedKey, encryptPrivkey, generateNostrKeypair, getPublicKey, type InitiateResult, isValidNip05Identifier, isValidPrivkey, isValidPubkey, type MagicLinkConfig, type MagicLinkService, type Nip05HandlerConfig, type Nip05HandlerResult, type Nip05Request, type NostrEvent, type NostrKeypair, normalizeIdentityEmail, npubToPubkey, nsecToPrivkey, parseNip05Identifier, privkeyToNsec, pubkeyToNpub, type ResolveIdentityResult, resolveIdentity, signEvent, type VerifyResult, verifyAuthEvent, verifyNostrSignature, } from './auth';
13
+ export { ApiKeyCollection } from './collections/ApiKeyCollection';
14
+ export { AuditLogCollection } from './collections/AuditLogCollection';
15
+ export { MagicLinkTokenCollection } from './collections/MagicLinkTokenCollection';
16
+ export { type Nip05Response, NostrIdentityCollection, } from './collections/NostrIdentityCollection';
17
+ export { AmbiguousOidcIdentityError, OidcIdentityCollection, } from './collections/OidcIdentityCollection';
18
+ export { OidcProfileEmailReservationCollection } from './collections/OidcProfileEmailReservationCollection';
19
+ export { ProfileAssetCollection } from './collections/ProfileAssetCollection';
20
+ export { CanonicalPersonProfileError, type CanonicalPersonProfileErrorCode, ProfileCollection, } from './collections/ProfileCollection';
21
+ export { ProfileMetadataCollection } from './collections/ProfileMetadataCollection';
22
+ export { ProfileMetafieldCollection } from './collections/ProfileMetafieldCollection';
23
+ export { ProfileRelationshipCollection } from './collections/ProfileRelationshipCollection';
24
+ export { ProfileRelationshipTermCollection } from './collections/ProfileRelationshipTermCollection';
25
+ export { ProfileRelationshipTypeCollection } from './collections/ProfileRelationshipTypeCollection';
26
+ export { ProfileTypeCollection } from './collections/ProfileTypeCollection';
27
+ export { type BackfillProfileEmailKeysResult, backfillProfileEmailKeys, PROFILE_EMAIL_KEY_BACKFILL_NAME, } from './migrations/backfillProfileEmailKeys.js';
28
+ export type { ApiKeyOptions, GenerateKeyResult } from './models/ApiKey';
29
+ export { ApiKey } from './models/ApiKey';
30
+ export type { AuditLogOptions, AuditSource } from './models/AuditLog';
31
+ export { AuditLog } from './models/AuditLog';
32
+ export type { GenerateTokenResult, MagicLinkTokenOptions, } from './models/MagicLinkToken';
33
+ export { MagicLinkToken } from './models/MagicLinkToken';
34
+ export type { NostrIdentityOptions } from './models/NostrIdentity';
35
+ export { NostrIdentity } from './models/NostrIdentity';
36
+ export type { OidcIdentityOptions } from './models/OidcIdentity';
37
+ export { OidcIdentity } from './models/OidcIdentity';
38
+ export type { OidcProfileEmailReservationOptions } from './models/OidcProfileEmailReservation';
39
+ export { OidcProfileEmailReservation } from './models/OidcProfileEmailReservation';
40
+ export type { ProfileOptions } from './models/Profile';
41
+ export { Profile } from './models/Profile';
42
+ export type { ProfileAssetOptions } from './models/ProfileAsset';
43
+ export { ProfileAsset } from './models/ProfileAsset';
44
+ export type { ProfileMetadataOptions } from './models/ProfileMetadata';
45
+ export { ProfileMetadata } from './models/ProfileMetadata';
46
+ export type { ProfileMetafieldOptions } from './models/ProfileMetafield';
47
+ export { ProfileMetafield } from './models/ProfileMetafield';
48
+ export type { ProfileRelationshipOptions } from './models/ProfileRelationship';
49
+ export { ProfileRelationship } from './models/ProfileRelationship';
50
+ export type { ProfileRelationshipTermOptions } from './models/ProfileRelationshipTerm';
51
+ export { ProfileRelationshipTerm } from './models/ProfileRelationshipTerm';
52
+ export type { ProfileRelationshipTypeOptions } from './models/ProfileRelationshipType';
53
+ export { ProfileRelationshipType } from './models/ProfileRelationshipType';
54
+ export type { ProfileTypeOptions } from './models/ProfileType';
55
+ export { ProfileType } from './models/ProfileType';
56
+ export { Bot, Organization, Person } from './models/ProfileTypes';
57
+ export { promptMessageOptions, smrtProfilesGenerateBioPrompt, } from './prompts';
58
+ export type { ReciprocalHandler, ValidationSchema, ValidatorFunction, } from './types';
59
+ //# sourceMappingURL=index.d.ts.map