@happyvertical/smrt-profiles 0.51.32 → 0.51.33

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
@@ -0,0 +1,188 @@
1
+ /**
2
+ * resolveIdentity - Resolves authentication context to a Profile
3
+ *
4
+ * Used by apps (blindmanpress.com) to resolve incoming auth to a Profile.
5
+ * Modules (aedile, praeco) should receive the resolved profile from the app.
6
+ *
7
+ * Resolution order:
8
+ * 1. API key header → ApiKey → Profile
9
+ * 2. OIDC session → OidcIdentity → Profile
10
+ * 3. Nostr auth → NostrIdentity → Profile
11
+ * 4. Actor header (CI pass-through) → Profile lookup
12
+ */
13
+ import { type SmrtObjectOptions } from '@happyvertical/smrt-core';
14
+ import { ApiKey } from '../models/ApiKey';
15
+ import { NostrIdentity } from '../models/NostrIdentity';
16
+ import { OidcIdentity } from '../models/OidcIdentity';
17
+ import type { Profile } from '../models/Profile';
18
+ import { type NostrEvent } from './nostrCrypto';
19
+ /**
20
+ * Context provided to resolveIdentity
21
+ */
22
+ export interface AuthContext {
23
+ /**
24
+ * API key from X-API-Key header or similar
25
+ */
26
+ apiKey?: string | null;
27
+ /**
28
+ * OIDC session data (from @auth/sveltekit or similar)
29
+ */
30
+ oidcSession?: {
31
+ sub?: string;
32
+ iss?: string;
33
+ email?: string;
34
+ name?: string;
35
+ } | null;
36
+ /**
37
+ * Actor identifier for CI pass-through identity
38
+ * Usually the GitHub actor (username) who triggered the workflow
39
+ */
40
+ actor?: string | null;
41
+ /**
42
+ * Nostr authentication data (NIP-42 style)
43
+ */
44
+ nostrAuth?: {
45
+ /** Signed Nostr event for authentication */
46
+ event: NostrEvent;
47
+ /** Expected challenge (to prevent replay attacks) */
48
+ challenge: string;
49
+ } | null;
50
+ /**
51
+ * Database/persistence options
52
+ */
53
+ db?: SmrtObjectOptions['db'];
54
+ }
55
+ /**
56
+ * Result of identity resolution
57
+ */
58
+ export interface ResolveIdentityResult {
59
+ /**
60
+ * The resolved profile, or null if not authenticated
61
+ */
62
+ profile: Profile | null;
63
+ /**
64
+ * How the identity was resolved
65
+ */
66
+ source: 'api_key' | 'oidc' | 'nostr' | 'actor' | 'none';
67
+ /**
68
+ * The API key record if authenticated via API key
69
+ */
70
+ apiKey?: ApiKey;
71
+ /**
72
+ * The OIDC identity record if authenticated via OIDC
73
+ */
74
+ oidcIdentity?: OidcIdentity;
75
+ /**
76
+ * The Nostr identity record if authenticated via Nostr
77
+ */
78
+ nostrIdentity?: NostrIdentity;
79
+ }
80
+ /**
81
+ * Resolve authentication context to a Profile
82
+ *
83
+ * @param context - The authentication context from the request
84
+ * @returns The resolved profile and metadata
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * // In SvelteKit hooks.server.ts
89
+ * import { resolveIdentity } from '@happyvertical/smrt-profiles';
90
+ *
91
+ * const identityMiddleware: Handle = async ({ event, resolve }) => {
92
+ * const session = await event.locals.auth();
93
+ *
94
+ * const { profile, source } = await resolveIdentity({
95
+ * oidcSession: session,
96
+ * apiKey: event.request.headers.get('X-API-Key'),
97
+ * actor: event.request.headers.get('X-Actor'),
98
+ * db: { type: 'postgres', url: DATABASE_URL },
99
+ * });
100
+ *
101
+ * event.locals.profile = profile;
102
+ * event.locals.authSource = source;
103
+ *
104
+ * return resolve(event);
105
+ * };
106
+ * ```
107
+ */
108
+ export declare function resolveIdentity(context: AuthContext): Promise<ResolveIdentityResult>;
109
+ /**
110
+ * Create a profile from OIDC claims if it doesn't exist
111
+ *
112
+ * Resolution order:
113
+ * 1. If OIDC identity (iss + sub) already exists → return linked profile
114
+ * 2. If the email matches an existing Profile, fail closed because this
115
+ * package cannot prove whether a User owns it
116
+ * 3. Otherwise, create new profile + identity
117
+ *
118
+ * Security considerations:
119
+ * - Existing issuer/subject links always keep their already-linked Profile,
120
+ * including legacy tenant-scoped or non-Person Profiles, and refresh the
121
+ * cached identity email. This exact-link compatibility does not perform
122
+ * email-based canonical reuse.
123
+ * - New identities never attach to an existing email match through this
124
+ * Profile-only helper because Profile ownership belongs to the users package.
125
+ * Use `UserCollection.getOrCreateFromOidc()` for owner-aware verified-email
126
+ * reuse and its supported pre-provision resolver hook.
127
+ * - This function trusts the OIDC provider to assert correct email_verified status.
128
+ * Only use with trusted providers.
129
+ *
130
+ * @param claims - OIDC token claims
131
+ * @param provider - Provider name (e.g., 'keycloak', 'google', 'github')
132
+ * @param options - Database options
133
+ * @returns The created or existing profile with linked OIDC identity
134
+ */
135
+ export declare function createProfileFromOidc(claims: {
136
+ sub: string;
137
+ iss: string;
138
+ email?: string;
139
+ email_verified?: boolean;
140
+ name?: string;
141
+ preferred_username?: string;
142
+ }, provider: string, options: SmrtObjectOptions): Promise<{
143
+ profile: Profile;
144
+ oidcIdentity: OidcIdentity;
145
+ created: boolean;
146
+ }>;
147
+ /**
148
+ * @internal Transactionally reuse one exact legacy issuer/subject link.
149
+ *
150
+ * This path cannot create or rebind authority. It intentionally preserves
151
+ * existing tenant-scoped and non-Person Profile links; canonical global Person
152
+ * validation remains mandatory for every path that creates a User/session.
153
+ */
154
+ export declare function reuseExistingOidcIdentityForProfile(profileId: string, claims: {
155
+ sub: string;
156
+ iss: string;
157
+ email?: string;
158
+ email_verified?: boolean;
159
+ name?: string;
160
+ preferred_username?: string;
161
+ }, provider: string, options: SmrtObjectOptions): Promise<{
162
+ profile: Profile;
163
+ oidcIdentity: OidcIdentity;
164
+ created: false;
165
+ }>;
166
+ /**
167
+ * Create a profile from Nostr identity (used by magic link service)
168
+ *
169
+ * This is typically called internally by the magic link service,
170
+ * but can be used directly if needed.
171
+ *
172
+ * @param email - Email address for the profile
173
+ * @param nostrData - Encrypted Nostr keypair data
174
+ * @param options - Database options
175
+ * @returns The created profile with linked Nostr identity
176
+ */
177
+ export declare function createProfileFromNostr(email: string, nostrData: {
178
+ pubkey: string;
179
+ encryptedPrivkey: string;
180
+ encryptionIv: string;
181
+ encryptionTag: string;
182
+ nip05Username?: string;
183
+ }, options: SmrtObjectOptions): Promise<{
184
+ profile: Profile;
185
+ nostrIdentity: NostrIdentity;
186
+ created: boolean;
187
+ }>;
188
+ //# sourceMappingURL=resolveIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveIdentity.d.ts","sourceRoot":"","sources":["../../src/auth/resolveIdentity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * ApiKeyCollection - Collection for managing API keys
3
+ */
4
+ import { SmrtCollection } from '@happyvertical/smrt-core';
5
+ import { ApiKey, type GenerateKeyResult } from '../models/ApiKey';
6
+ import type { Profile } from '../models/Profile';
7
+ export declare class ApiKeyCollection extends SmrtCollection<ApiKey> {
8
+ static readonly _itemClass: typeof ApiKey;
9
+ /**
10
+ * Find all keys for a profile
11
+ */
12
+ findByProfile(profileId: string): Promise<ApiKey[]>;
13
+ /**
14
+ * Find active (non-revoked, non-expired) keys for a profile
15
+ */
16
+ findActiveByProfile(profileId: string): Promise<ApiKey[]>;
17
+ /**
18
+ * Find key by hash
19
+ */
20
+ findByHash(keyHash: string): Promise<ApiKey | null>;
21
+ /**
22
+ * Verify an API key string and return the record if valid
23
+ */
24
+ verify(key: string): Promise<ApiKey | null>;
25
+ /**
26
+ * Generate a new key for a profile
27
+ */
28
+ generateForProfile(profile: Profile, options: {
29
+ name: string;
30
+ scopes?: string[];
31
+ expiresAt?: Date | null;
32
+ }): Promise<GenerateKeyResult>;
33
+ /**
34
+ * Revoke all keys for a profile
35
+ */
36
+ revokeAllForProfile(profileId: string): Promise<number>;
37
+ /**
38
+ * Revoke a specific key by prefix
39
+ */
40
+ revokeByPrefix(keyPrefix: string): Promise<boolean>;
41
+ /**
42
+ * Clean up expired keys (soft delete by setting revokedAt)
43
+ */
44
+ cleanupExpired(): Promise<number>;
45
+ }
46
+ //# sourceMappingURL=ApiKeyCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiKeyCollection.d.ts","sourceRoot":"","sources":["../../src/collections/ApiKeyCollection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,qBAAa,gBAAiB,SAAQ,cAAc,CAAC,MAAM,CAAC;IAC1D,MAAM,CAAC,QAAQ,CAAC,UAAU,gBAAU;IAEpC;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMzD;;OAEG;IACG,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAK/D;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAMzD;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAiBjD;;OAEG;IACG,kBAAkB,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;KACzB,GACA,OAAO,CAAC,iBAAiB,CAAC;IAO7B;;OAEG;IACG,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ7D;;OAEG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYzD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;CAexC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * AuditLogCollection - Collection for querying audit logs
3
+ */
4
+ import { SmrtCollection } from '@happyvertical/smrt-core';
5
+ import { AuditLog, type AuditSource } from '../models/AuditLog';
6
+ import type { Profile } from '../models/Profile';
7
+ export declare class AuditLogCollection extends SmrtCollection<AuditLog> {
8
+ static readonly _itemClass: typeof AuditLog;
9
+ /**
10
+ * Find logs for a profile (actions they performed)
11
+ */
12
+ findByProfile(profileId: string): Promise<AuditLog[]>;
13
+ /**
14
+ * Find logs for a resource
15
+ */
16
+ findByResource(resourceType: string, resourceId: string): Promise<AuditLog[]>;
17
+ /**
18
+ * Find logs by action type
19
+ */
20
+ findByAction(action: string): Promise<AuditLog[]>;
21
+ /**
22
+ * Find logs by source
23
+ */
24
+ findBySource(source: AuditSource): Promise<AuditLog[]>;
25
+ /**
26
+ * Find logs where actions were performed on behalf of someone
27
+ */
28
+ findOnBehalfOf(profileId: string): Promise<AuditLog[]>;
29
+ /**
30
+ * Record a new audit log entry
31
+ */
32
+ record(options: {
33
+ profile: Profile;
34
+ action: string;
35
+ resourceType: string;
36
+ resourceId: string;
37
+ source?: AuditSource;
38
+ metadata?: Record<string, unknown>;
39
+ onBehalfOf?: Profile | null;
40
+ }): Promise<AuditLog>;
41
+ /**
42
+ * Get recent activity for a profile
43
+ */
44
+ getRecentActivity(profileId: string, limit?: number): Promise<AuditLog[]>;
45
+ /**
46
+ * Get activity timeline for a resource
47
+ */
48
+ getResourceTimeline(resourceType: string, resourceId: string): Promise<AuditLog[]>;
49
+ }
50
+ //# sourceMappingURL=AuditLogCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuditLogCollection.d.ts","sourceRoot":"","sources":["../../src/collections/AuditLogCollection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,qBAAa,kBAAmB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAC9D,MAAM,CAAC,QAAQ,CAAC,UAAU,kBAAY;IAEtC;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAO3D;;OAEG;IACG,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAOtB;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAOvD;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAO5D;;OAEG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAO5D;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE;QACpB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAC7B,GAAG,OAAO,CAAC,QAAQ,CAAC;IAgBrB;;OAEG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAQtB;;OAEG;IACG,mBAAmB,CACvB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC;CAMvB"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * MagicLinkTokenCollection - Collection for managing magic link tokens
3
+ */
4
+ import { SmrtCollection } from '@happyvertical/smrt-core';
5
+ import { MagicLinkToken } from '../models/MagicLinkToken';
6
+ export declare class MagicLinkTokenCollection extends SmrtCollection<MagicLinkToken> {
7
+ static readonly _itemClass: typeof MagicLinkToken;
8
+ /**
9
+ * Find token by hash
10
+ */
11
+ findByTokenHash(tokenHash: string): Promise<MagicLinkToken | null>;
12
+ /**
13
+ * Find active (non-expired, non-used) tokens for an email
14
+ */
15
+ findActiveForEmail(email: string): Promise<MagicLinkToken[]>;
16
+ /**
17
+ * Find tokens for a NostrIdentity
18
+ */
19
+ findByIdentity(nostrIdentityId: string): Promise<MagicLinkToken[]>;
20
+ /**
21
+ * Count tokens created for an email within a time window (for rate limiting)
22
+ * @param email - Email address
23
+ * @param withinMinutes - Time window in minutes
24
+ */
25
+ countRecentByEmail(email: string, withinMinutes: number): Promise<number>;
26
+ /**
27
+ * Count tokens created from an IP within a time window (for rate limiting)
28
+ * @param ip - IP address
29
+ * @param withinMinutes - Time window in minutes
30
+ */
31
+ countRecentByIp(ip: string, withinMinutes: number): Promise<number>;
32
+ /**
33
+ * Verify a token and return it if valid
34
+ */
35
+ verify(token: string): Promise<MagicLinkToken | null>;
36
+ /**
37
+ * Clean up expired tokens by deleting them
38
+ * @returns Number of tokens deleted
39
+ */
40
+ cleanupExpired(): Promise<number>;
41
+ /**
42
+ * Revoke all tokens for a NostrIdentity (e.g., when identity is deleted)
43
+ */
44
+ revokeForIdentity(nostrIdentityId: string): Promise<number>;
45
+ /**
46
+ * Check if rate limit is exceeded for email
47
+ * @param email - Email address
48
+ * @param maxPerHour - Maximum tokens allowed per hour (default: 5)
49
+ */
50
+ isRateLimitedByEmail(email: string, maxPerHour?: number): Promise<boolean>;
51
+ /**
52
+ * Check if rate limit is exceeded for IP
53
+ * @param ip - IP address
54
+ * @param maxPerHour - Maximum tokens allowed per hour (default: 10)
55
+ */
56
+ isRateLimitedByIp(ip: string, maxPerHour?: number): Promise<boolean>;
57
+ }
58
+ //# sourceMappingURL=MagicLinkTokenCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MagicLinkTokenCollection.d.ts","sourceRoot":"","sources":["../../src/collections/MagicLinkTokenCollection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,qBAAa,wBAAyB,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC1E,MAAM,CAAC,QAAQ,CAAC,UAAU,wBAAkB;IAE5C;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAMxE;;OAEG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAOlE;;OAEG;IACG,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAMxE;;;;OAIG;IACG,kBAAkB,CACtB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC;IAclB;;;;OAIG;IACG,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAazE;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAe3D;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAevC;;OAEG;IACG,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcjE;;;;OAIG;IACG,oBAAoB,CACxB,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAU,GACrB,OAAO,CAAC,OAAO,CAAC;IAKnB;;;;OAIG;IACG,iBAAiB,CACrB,EAAE,EAAE,MAAM,EACV,UAAU,GAAE,MAAW,GACtB,OAAO,CAAC,OAAO,CAAC;CAIpB"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * NostrIdentityCollection - Collection for managing Nostr identity records
3
+ */
4
+ import { SmrtCollection } from '@happyvertical/smrt-core';
5
+ import { NostrIdentity } from '../models/NostrIdentity';
6
+ import type { Profile } from '../models/Profile';
7
+ export interface Nip05Response {
8
+ names: Record<string, string>;
9
+ relays?: Record<string, string[]>;
10
+ }
11
+ export declare class NostrIdentityCollection extends SmrtCollection<NostrIdentity> {
12
+ static readonly _itemClass: typeof NostrIdentity;
13
+ /**
14
+ * Find identities for a profile
15
+ */
16
+ findByProfile(profileId: string): Promise<NostrIdentity[]>;
17
+ /**
18
+ * Find identity by public key
19
+ */
20
+ findByPubkey(pubkey: string): Promise<NostrIdentity | null>;
21
+ /**
22
+ * Find identity by email
23
+ */
24
+ findByEmail(email: string): Promise<NostrIdentity | null>;
25
+ /**
26
+ * Find identity by NIP-05 username
27
+ */
28
+ findByNip05(username: string): Promise<NostrIdentity | null>;
29
+ /**
30
+ * Link a new Nostr identity to a profile with a new keypair
31
+ * @param profile - The profile to link to
32
+ * @param email - Email address for this identity
33
+ * @param masterSecret - Server master secret for encryption
34
+ * @param nip05Username - Optional NIP-05 username (defaults to email local part)
35
+ */
36
+ createForProfile(profile: Profile, email: string, masterSecret: string, nip05Username?: string): Promise<NostrIdentity>;
37
+ /**
38
+ * Link an existing Nostr identity (with encrypted keypair) to a profile
39
+ */
40
+ linkToProfile(profile: Profile, nostrData: {
41
+ pubkey: string;
42
+ encryptedPrivkey: string;
43
+ encryptionIv: string;
44
+ encryptionTag: string;
45
+ email: string;
46
+ nip05Username?: string;
47
+ }): Promise<NostrIdentity>;
48
+ /**
49
+ * Unlink a Nostr identity from a profile
50
+ */
51
+ unlinkFromProfile(profileId: string, pubkey: string): Promise<boolean>;
52
+ /**
53
+ * Get NIP-05 response data for the /.well-known/nostr.json endpoint
54
+ * @param username - Optional username filter, returns all if not provided
55
+ */
56
+ getNip05Response(username?: string): Promise<Nip05Response>;
57
+ /**
58
+ * Check if a NIP-05 username is available
59
+ */
60
+ isNip05Available(username: string): Promise<boolean>;
61
+ /**
62
+ * Update NIP-05 username for an identity
63
+ */
64
+ updateNip05Username(identity: NostrIdentity, newUsername: string): Promise<NostrIdentity>;
65
+ }
66
+ //# sourceMappingURL=NostrIdentityCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NostrIdentityCollection.d.ts","sourceRoot":"","sources":["../../src/collections/NostrIdentityCollection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACnC;AAED,qBAAa,uBAAwB,SAAQ,cAAc,CAAC,aAAa,CAAC;IACxE,MAAM,CAAC,QAAQ,CAAC,UAAU,uBAAiB;IAE3C;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAMhE;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAMjE;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAM/D;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAMlE;;;;;;OAMG;IACG,gBAAgB,CACpB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;IAqCzB;;OAEG;IACG,aAAa,CACjB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GACA,OAAO,CAAC,aAAa,CAAC;IAgCzB;;OAEG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAY5E;;;OAGG;IACG,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAoBjE;;OAEG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1D;;OAEG;IACG,mBAAmB,CACvB,QAAQ,EAAE,aAAa,EACvB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC;CAc1B"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * OidcIdentityCollection - Collection for managing OIDC identity records
3
+ */
4
+ import { SmrtCollection } from '@happyvertical/smrt-core';
5
+ import { OidcIdentity } from '../models/OidcIdentity';
6
+ import type { Profile } from '../models/Profile';
7
+ /** More than one legacy row maps the same opaque OIDC issuer and subject. */
8
+ export declare class AmbiguousOidcIdentityError extends Error {
9
+ readonly issuer: string;
10
+ readonly subject: string;
11
+ constructor(issuer: string, subject: string);
12
+ }
13
+ export declare class OidcIdentityCollection extends SmrtCollection<OidcIdentity> {
14
+ static readonly _itemClass: typeof OidcIdentity;
15
+ /**
16
+ * Find identities for a profile
17
+ */
18
+ findByProfile(profileId: string): Promise<OidcIdentity[]>;
19
+ /**
20
+ * Find identity by issuer and subject
21
+ */
22
+ findBySubject(issuer: string, subject: string): Promise<OidcIdentity | null>;
23
+ /**
24
+ * Find identities by provider
25
+ */
26
+ findByProvider(provider: string): Promise<OidcIdentity[]>;
27
+ /**
28
+ * Reuse an existing exact OIDC identity for its unchanged Profile.
29
+ *
30
+ * @deprecated New authentication links require the owner-aware,
31
+ * transactional provisioning APIs. This compatibility helper may refresh a
32
+ * legacy Profile type, but refuses to create or rebind authority.
33
+ */
34
+ linkToProfile(profile: Profile, oidcData: {
35
+ provider: string;
36
+ issuer: string;
37
+ subject: string;
38
+ email?: string;
39
+ }): Promise<OidcIdentity>;
40
+ /**
41
+ * Unlink an OIDC identity from a profile
42
+ */
43
+ unlinkFromProfile(profileId: string, issuer: string, subject: string): Promise<boolean>;
44
+ }
45
+ //# sourceMappingURL=OidcIdentityCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OidcIdentityCollection.d.ts","sourceRoot":"","sources":["../../src/collections/OidcIdentityCollection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,6EAA6E;AAC7E,qBAAa,0BAA2B,SAAQ,KAAK;IAEjD,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM;gBADf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;CAK3B;AAED,qBAAa,sBAAuB,SAAQ,cAAc,CAAC,YAAY,CAAC;IACtE,MAAM,CAAC,QAAQ,CAAC,UAAU,sBAAgB;IAE1C;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM/D;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA0B/B;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM/D;;;;;;OAMG;IACG,aAAa,CACjB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GACA,OAAO,CAAC,YAAY,CAAC;IAIxB;;OAEG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC;CAWpB"}
@@ -0,0 +1,7 @@
1
+ import { SmrtCollection } from '@happyvertical/smrt-core';
2
+ import { OidcProfileEmailReservation } from '../models/OidcProfileEmailReservation';
3
+ /** Internal collection for canonical OIDC email reservations. */
4
+ export declare class OidcProfileEmailReservationCollection extends SmrtCollection<OidcProfileEmailReservation> {
5
+ static readonly _itemClass: typeof OidcProfileEmailReservation;
6
+ }
7
+ //# sourceMappingURL=OidcProfileEmailReservationCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OidcProfileEmailReservationCollection.d.ts","sourceRoot":"","sources":["../../src/collections/OidcProfileEmailReservationCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AAEpF,iEAAiE;AACjE,qBAAa,qCAAsC,SAAQ,cAAc,CAAC,2BAA2B,CAAC;IACpG,MAAM,CAAC,QAAQ,CAAC,UAAU,qCAA+B;CAC1D"}
@@ -0,0 +1,17 @@
1
+ import type { Asset } from '@happyvertical/smrt-assets';
2
+ import type { SmrtCollectionOptions } from '@happyvertical/smrt-core';
3
+ import { SmrtJunction } from '@happyvertical/smrt-core';
4
+ import { ProfileAsset } from '../models/ProfileAsset';
5
+ export interface ProfileAssetCollectionOptions extends SmrtCollectionOptions {
6
+ }
7
+ export declare class ProfileAssetCollection extends SmrtJunction<ProfileAsset> {
8
+ static readonly _itemClass: typeof ProfileAsset;
9
+ protected leftField: string;
10
+ protected rightField: string;
11
+ private profileCollectionPromise;
12
+ private getProfileCollection;
13
+ getAssets(profileId: string, relationship?: string): Promise<Asset[]>;
14
+ addAsset(profileId: string, asset: Asset, relationship?: string, sortOrder?: number): Promise<void>;
15
+ removeAsset(profileId: string, assetId: string, relationship?: string): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=ProfileAssetCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileAssetCollection.d.ts","sourceRoot":"","sources":["../../src/collections/ProfileAssetCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAMxD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,YAAY,EAAQ,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGtD,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;CAAG;AAE/E,qBAKa,sBAAuB,SAAQ,YAAY,CAAC,YAAY,CAAC;IACpE,MAAM,CAAC,QAAQ,CAAC,UAAU,sBAAgB;IAC1C,SAAS,CAAC,SAAS,SAAe;IAClC,SAAS,CAAC,UAAU,SAAa;IAEjC,OAAO,CAAC,wBAAwB,CAA2C;YAE7D,oBAAoB;IAS5B,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAQrE,QAAQ,CACZ,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,KAAK,EACZ,YAAY,SAAe,EAC3B,SAAS,SAAI,GACZ,OAAO,CAAC,IAAI,CAAC;IAWV,WAAW,CACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC;CASjB"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * ProfileCollection - Collection manager for Profile objects
3
+ *
4
+ * Provides advanced querying and batch operations for Profile entities.
5
+ */
6
+ import type { Asset } from '@happyvertical/smrt-assets';
7
+ import { SmrtCollection } from '@happyvertical/smrt-core';
8
+ import { Profile } from '../models/Profile';
9
+ export type CanonicalPersonProfileErrorCode = 'ambiguous_email' | 'email_key_backfill_required' | 'email_mismatch' | 'missing_profile' | 'non_person' | 'reservation_conflict' | 'tenant_scoped';
10
+ /** A Profile cannot safely represent one global human identity. */
11
+ export declare class CanonicalPersonProfileError extends Error {
12
+ readonly code: CanonicalPersonProfileErrorCode;
13
+ constructor(code: CanonicalPersonProfileErrorCode, message: string);
14
+ }
15
+ export declare class ProfileCollection extends SmrtCollection<Profile> {
16
+ static readonly _itemClass: typeof Profile;
17
+ private emailKeysReadyPromise;
18
+ /**
19
+ * Find a profile by email address
20
+ *
21
+ * @param email - The email address to search for
22
+ * @returns The matching profile or null
23
+ */
24
+ findByEmail(email: string): Promise<Profile | null>;
25
+ /**
26
+ * Resolve one unambiguous global Person by normalized email.
27
+ *
28
+ * Unlike `findByEmail()`, this identity-boundary helper deliberately reads
29
+ * across tenant scopes and fails closed when any matching row is
30
+ * tenant-scoped, is not a Person STI row, or when more than one row matches
31
+ * case-insensitively. It is intended for verified external identities.
32
+ */
33
+ findUniqueGlobalPersonByEmail(email: string): Promise<Profile | null>;
34
+ /**
35
+ * Validate and hydrate a supplied canonical Profile.
36
+ *
37
+ * The Profile must be the sole case-insensitive match for its stored email.
38
+ * When `email` is provided, that address must also match the stored email.
39
+ */
40
+ requireCanonicalGlobalPerson(profileId: string, email?: string): Promise<Profile>;
41
+ /**
42
+ * Reserve the normalized email for a previously validated canonical Person.
43
+ *
44
+ * The unique stored key turns a concurrent OIDC first-login race into a
45
+ * retryable database conflict. Legacy Profiles remain unaffected until an
46
+ * identity boundary safely claims them.
47
+ */
48
+ reserveCanonicalIdentityEmail(profileId: string, email?: string): Promise<Profile>;
49
+ /**
50
+ * Find profiles by type slug
51
+ *
52
+ * @param typeSlug - The profile type slug to filter by
53
+ * @returns Array of matching profiles
54
+ */
55
+ findByType(typeSlug: string): Promise<Profile[]>;
56
+ private requireDatabase;
57
+ private loadCanonicalEmailRows;
58
+ /** Require the deploy-time backfill marker before indexed identity reads. */
59
+ private ensureEmailKeysReady;
60
+ private checkEmailKeysReady;
61
+ private isStaleEmailReservation;
62
+ private assertRowEmailKeyCurrent;
63
+ private assertCanonicalRows;
64
+ private requireHydratedProfile;
65
+ /**
66
+ * Batch get metadata for multiple profiles
67
+ *
68
+ * @param profileIds - Array of profile UUIDs
69
+ * @returns Map of profile ID to metadata object
70
+ */
71
+ batchGetMetadata(profileIds: string[]): Promise<Map<string, Record<string, string>>>;
72
+ /**
73
+ * Batch update metadata for multiple profiles
74
+ *
75
+ * @param updates - Array of { profileId, data } objects
76
+ */
77
+ batchUpdateMetadata(updates: Array<{
78
+ profileId: string;
79
+ data: Record<string, unknown>;
80
+ }>): Promise<void>;
81
+ /**
82
+ * Find related profiles for a given profile
83
+ *
84
+ * @param profileId - The profile UUID
85
+ * @param relationshipSlug - Optional filter by relationship type
86
+ * @returns Array of related profiles
87
+ */
88
+ findRelated(profileId: string, relationshipSlug?: string): Promise<Profile[]>;
89
+ getAssets(profileId: string, relationship?: string): Promise<Asset[]>;
90
+ addAsset(profileId: string, asset: Asset, relationship?: string, sortOrder?: number): Promise<void>;
91
+ removeAsset(profileId: string, assetId: string, relationship?: string): Promise<void>;
92
+ /**
93
+ * Get the relationship network for a profile up to a maximum depth
94
+ *
95
+ * @param profileId - The starting profile UUID
96
+ * @param options - Configuration options
97
+ * @returns Map of profile ID to depth level
98
+ */
99
+ getRelationshipNetwork(profileId: string, options?: {
100
+ maxDepth?: number;
101
+ }): Promise<Map<string, number>>;
102
+ /**
103
+ * Find all profiles belonging to a specific tenant
104
+ *
105
+ * @param tenantId - The tenant UUID to filter by
106
+ * @returns Array of profiles for this tenant
107
+ */
108
+ findByTenant(tenantId: string): Promise<Profile[]>;
109
+ /**
110
+ * Find all global profiles (no tenant association).
111
+ *
112
+ * Routes through the shared tenant-global helper so it does not throw under
113
+ * an active tenant context (an explicit `tenant_id IS NULL` filter would be
114
+ * flagged as an isolation violation). (#1600)
115
+ *
116
+ * @returns Array of profiles with null tenantId
117
+ */
118
+ findGlobal(): Promise<Profile[]>;
119
+ /**
120
+ * Find profiles belonging to a tenant plus all global profiles.
121
+ *
122
+ * Fails closed if an active tenant context requests a different tenant's
123
+ * rows; the admin/system path keeps the cross-tenant capability. (#1600)
124
+ *
125
+ * @param tenantId - The tenant UUID to include
126
+ * @returns Array of tenant-specific and global profiles
127
+ */
128
+ findWithGlobals(tenantId: string): Promise<Profile[]>;
129
+ }
130
+ //# sourceMappingURL=ProfileCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileCollection.d.ts","sourceRoot":"","sources":["../../src/collections/ProfileCollection.ts"],"names":[],"mappings":"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"}