@happyvertical/smrt-profiles 0.39.13 → 0.39.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +69 -5
- package/README.md +101 -50
- package/dist/chunks/{ApiKey-BrNyaaZN.js → ApiKey-Br9NGBnr.js} +3 -3
- package/dist/chunks/{ApiKey-BrNyaaZN.js.map → ApiKey-Br9NGBnr.js.map} +1 -1
- package/dist/chunks/{ApiKeyCollection-DNhDkS7O.js → ApiKeyCollection-CrTjdMz8.js} +3 -3
- package/dist/chunks/{ApiKeyCollection-DNhDkS7O.js.map → ApiKeyCollection-CrTjdMz8.js.map} +1 -1
- package/dist/chunks/{AuditLogCollection-CnIYU0aK.js → AuditLogCollection-BBIEI6BD.js} +2 -2
- package/dist/chunks/{AuditLogCollection-CnIYU0aK.js.map → AuditLogCollection-BBIEI6BD.js.map} +1 -1
- package/dist/chunks/{NostrIdentityCollection-CG6HGf6c.js → NostrIdentity-DF_a_WZk.js} +6 -125
- package/dist/chunks/NostrIdentity-DF_a_WZk.js.map +1 -0
- package/dist/chunks/NostrIdentityCollection-BRYUgt47.js +124 -0
- package/dist/chunks/NostrIdentityCollection-BRYUgt47.js.map +1 -0
- package/dist/chunks/OidcIdentity-ChkiT6hg.js +111 -0
- package/dist/chunks/OidcIdentity-ChkiT6hg.js.map +1 -0
- package/dist/chunks/OidcIdentityCollection-Ce4yv8p0.js +76 -0
- package/dist/chunks/OidcIdentityCollection-Ce4yv8p0.js.map +1 -0
- package/dist/chunks/{ProfileAssetCollection-DzUwbtTq.js → ProfileAssetCollection-CtlvXbGy.js} +3 -3
- package/dist/chunks/{ProfileAssetCollection-DzUwbtTq.js.map → ProfileAssetCollection-CtlvXbGy.js.map} +1 -1
- package/dist/chunks/ProfileCollection-Bix9yAiy.js +1161 -0
- package/dist/chunks/ProfileCollection-Bix9yAiy.js.map +1 -0
- package/dist/chunks/{ProfileMetadataCollection-CGcO4Iw_.js → ProfileMetadataCollection-loKVv_pj.js} +2 -2
- package/dist/chunks/{ProfileMetadataCollection-CGcO4Iw_.js.map → ProfileMetadataCollection-loKVv_pj.js.map} +1 -1
- package/dist/chunks/{ProfileMetafieldCollection-C8TX9HvN.js → ProfileMetafieldCollection-CACMY1hl.js} +2 -2
- package/dist/chunks/{ProfileMetafieldCollection-C8TX9HvN.js.map → ProfileMetafieldCollection-CACMY1hl.js.map} +1 -1
- package/dist/chunks/{ProfileRelationshipCollection-JnskbZTd.js → ProfileRelationshipCollection-CzQKfvMy.js} +5 -5
- package/dist/chunks/{ProfileRelationshipCollection-JnskbZTd.js.map → ProfileRelationshipCollection-CzQKfvMy.js.map} +1 -1
- package/dist/chunks/{ProfileRelationshipTermCollection-UopP7sja.js → ProfileRelationshipTermCollection-DzmU48P6.js} +2 -2
- package/dist/chunks/{ProfileRelationshipTermCollection-UopP7sja.js.map → ProfileRelationshipTermCollection-DzmU48P6.js.map} +1 -1
- package/dist/chunks/{ProfileRelationshipType-OMBn5cWR.js → ProfileRelationshipType-BjoaCt-u.js} +2 -2
- package/dist/chunks/{ProfileRelationshipType-OMBn5cWR.js.map → ProfileRelationshipType-BjoaCt-u.js.map} +1 -1
- package/dist/chunks/{ProfileRelationshipTypeCollection-CQu08kxF.js → ProfileRelationshipTypeCollection-Bh4xJ4-I.js} +3 -3
- package/dist/chunks/{ProfileRelationshipTypeCollection-CQu08kxF.js.map → ProfileRelationshipTypeCollection-Bh4xJ4-I.js.map} +1 -1
- package/dist/chunks/oidcProvisioningPrimitives-ZuVcDPt-.js +138 -0
- package/dist/chunks/oidcProvisioningPrimitives-ZuVcDPt-.js.map +1 -0
- package/dist/chunks/resolveIdentity-_h_2sGqJ.js +260 -0
- package/dist/chunks/resolveIdentity-_h_2sGqJ.js.map +1 -0
- package/dist/index.d.ts +127 -15
- package/dist/index.js +30 -273
- package/dist/index.js.map +1 -1
- package/dist/internal/oidc-provisioning.d.ts +17 -0
- package/dist/internal/oidc-provisioning.js +13 -0
- package/dist/internal/oidc-provisioning.js.map +1 -0
- package/dist/manifest.json +431 -46
- package/dist/oidc-provisioning.d.ts +83 -0
- package/dist/smrt-knowledge.json +105 -43
- package/dist/types.d.ts +26 -2
- package/dist/utils.d.ts +26 -2
- package/dist/utils.js +4 -4
- package/package.json +10 -6
- package/dist/chunks/NostrIdentityCollection-CG6HGf6c.js.map +0 -1
- package/dist/chunks/OidcIdentityCollection-DiLneB7J.js +0 -158
- package/dist/chunks/OidcIdentityCollection-DiLneB7J.js.map +0 -1
- package/dist/chunks/ProfileCollection-BOMOloTL.js +0 -641
- package/dist/chunks/ProfileCollection-BOMOloTL.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Asset } from '@happyvertical/smrt-assets';
|
|
2
|
+
import { getDatabase } from '@happyvertical/sql';
|
|
2
3
|
import { PromptDefinition } from '@happyvertical/smrt-prompts';
|
|
3
4
|
import { ResolvedPromptAI } from '@happyvertical/smrt-prompts';
|
|
4
5
|
import { SmrtCollection } from '@happyvertical/smrt-core';
|
|
@@ -6,6 +7,13 @@ import { SmrtJunction } from '@happyvertical/smrt-core';
|
|
|
6
7
|
import { SmrtObject } from '@happyvertical/smrt-core';
|
|
7
8
|
import { SmrtObjectOptions } from '@happyvertical/smrt-core';
|
|
8
9
|
|
|
10
|
+
/** More than one legacy row maps the same opaque OIDC issuer and subject. */
|
|
11
|
+
export declare class AmbiguousOidcIdentityError extends Error {
|
|
12
|
+
readonly issuer: string;
|
|
13
|
+
readonly subject: string;
|
|
14
|
+
constructor(issuer: string, subject: string);
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
export declare class ApiKey extends SmrtObject {
|
|
10
18
|
/**
|
|
11
19
|
* Link to the Profile (Person, Organization, Bot)
|
|
@@ -272,6 +280,19 @@ export declare interface AuthContext {
|
|
|
272
280
|
db?: SmrtObjectOptions['db'];
|
|
273
281
|
}
|
|
274
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Populate adapter-independent Profile email keys after the schema migration.
|
|
285
|
+
*
|
|
286
|
+
* Run this from one deploy process after legacy writers are stopped or
|
|
287
|
+
* upgraded. Every read and update runs in one transaction, and repeats are a
|
|
288
|
+
* no-op.
|
|
289
|
+
*/
|
|
290
|
+
export declare function backfillProfileEmailKeys(db: DatabaseInterface): Promise<BackfillProfileEmailKeysResult>;
|
|
291
|
+
|
|
292
|
+
export declare interface BackfillProfileEmailKeysResult {
|
|
293
|
+
updated: number;
|
|
294
|
+
}
|
|
295
|
+
|
|
275
296
|
/**
|
|
276
297
|
* Bot profile type
|
|
277
298
|
*
|
|
@@ -281,6 +302,14 @@ export declare class Bot extends Profile {
|
|
|
281
302
|
constructor(options?: ProfileOptions);
|
|
282
303
|
}
|
|
283
304
|
|
|
305
|
+
/** A Profile cannot safely represent one global human identity. */
|
|
306
|
+
export declare class CanonicalPersonProfileError extends Error {
|
|
307
|
+
readonly code: CanonicalPersonProfileErrorCode;
|
|
308
|
+
constructor(code: CanonicalPersonProfileErrorCode, message: string);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export declare type CanonicalPersonProfileErrorCode = 'ambiguous_email' | 'email_key_backfill_required' | 'email_mismatch' | 'missing_profile' | 'non_person' | 'reservation_conflict' | 'tenant_scoped';
|
|
312
|
+
|
|
284
313
|
/**
|
|
285
314
|
* Compute the event ID (SHA-256 hash of serialized event)
|
|
286
315
|
*/
|
|
@@ -355,23 +384,21 @@ export declare function createProfileFromNostr(email: string, nostrData: {
|
|
|
355
384
|
/**
|
|
356
385
|
* Create a profile from OIDC claims if it doesn't exist
|
|
357
386
|
*
|
|
358
|
-
* Supports email-based account linking: if a user signs in with Google
|
|
359
|
-
* and later with GitHub using the same email, they get the same profile.
|
|
360
|
-
*
|
|
361
387
|
* Resolution order:
|
|
362
388
|
* 1. If OIDC identity (iss + sub) already exists → return linked profile
|
|
363
|
-
* 2. If
|
|
389
|
+
* 2. If the email matches an existing Profile, fail closed because this
|
|
390
|
+
* package cannot prove whether a User owns it
|
|
364
391
|
* 3. Otherwise, create new profile + identity
|
|
365
392
|
*
|
|
366
393
|
* Security considerations:
|
|
367
|
-
* -
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
394
|
+
* - Existing issuer/subject links always keep their already-linked Profile,
|
|
395
|
+
* including legacy tenant-scoped or non-Person Profiles, and refresh the
|
|
396
|
+
* cached identity email. This exact-link compatibility does not perform
|
|
397
|
+
* email-based canonical reuse.
|
|
398
|
+
* - New identities never attach to an existing email match through this
|
|
399
|
+
* Profile-only helper because Profile ownership belongs to the users package.
|
|
400
|
+
* Use `UserCollection.getOrCreateFromOidc()` for owner-aware verified-email
|
|
401
|
+
* reuse and its supported pre-provision resolver hook.
|
|
375
402
|
* - This function trusts the OIDC provider to assert correct email_verified status.
|
|
376
403
|
* Only use with trusted providers.
|
|
377
404
|
*
|
|
@@ -393,6 +420,8 @@ export declare function createProfileFromOidc(claims: {
|
|
|
393
420
|
created: boolean;
|
|
394
421
|
}>;
|
|
395
422
|
|
|
423
|
+
declare type DatabaseInterface = Awaited<ReturnType<typeof getDatabase>>;
|
|
424
|
+
|
|
396
425
|
/**
|
|
397
426
|
* Decrypt a private key using AES-256-GCM
|
|
398
427
|
* @param encrypted - Encrypted key data
|
|
@@ -676,6 +705,14 @@ export declare interface Nip05Response {
|
|
|
676
705
|
relays?: Record<string, string[]>;
|
|
677
706
|
}
|
|
678
707
|
|
|
708
|
+
/**
|
|
709
|
+
* Canonicalize an email used as an external identity key.
|
|
710
|
+
*
|
|
711
|
+
* Keep this in application code: SQL `trim()` and `lower()` have
|
|
712
|
+
* adapter-specific whitespace and Unicode behavior.
|
|
713
|
+
*/
|
|
714
|
+
export declare function normalizeIdentityEmail(email: string): string;
|
|
715
|
+
|
|
679
716
|
export declare interface NostrEvent {
|
|
680
717
|
id?: string;
|
|
681
718
|
pubkey: string;
|
|
@@ -883,6 +920,14 @@ export declare class OidcIdentity extends SmrtObject {
|
|
|
883
920
|
* OIDC subject claim - unique identifier from the provider
|
|
884
921
|
*/
|
|
885
922
|
subject: string;
|
|
923
|
+
/**
|
|
924
|
+
* Stable issuer+subject key used as the database race arbiter.
|
|
925
|
+
*
|
|
926
|
+
* Nullable for legacy rows; every newly linked or reused identity backfills
|
|
927
|
+
* it. A separate unique constraint makes concurrent first login fail with a
|
|
928
|
+
* retryable conflict instead of creating two identities.
|
|
929
|
+
*/
|
|
930
|
+
identityKey: string | null;
|
|
886
931
|
/**
|
|
887
932
|
* Cached email from the IdP (for display/lookup)
|
|
888
933
|
*/
|
|
@@ -900,8 +945,17 @@ export declare class OidcIdentity extends SmrtObject {
|
|
|
900
945
|
* Find identity by issuer and subject
|
|
901
946
|
*/
|
|
902
947
|
static findBySubject(issuer: string, subject: string, options?: SmrtObjectOptions): Promise<OidcIdentity | null>;
|
|
948
|
+
/** Build the collision-free natural key for one OIDC issuer subject. */
|
|
949
|
+
static buildIdentityKey(issuer: string, subject: string): string;
|
|
950
|
+
/** Keep the durable key derived from its natural-key source fields. */
|
|
951
|
+
save(): Promise<this>;
|
|
903
952
|
/**
|
|
904
|
-
*
|
|
953
|
+
* Reuse an existing exact identity for its unchanged Profile.
|
|
954
|
+
*
|
|
955
|
+
* @deprecated Authentication links must be created through transactional
|
|
956
|
+
* provisioning. This compatibility method only refreshes a unique mapping
|
|
957
|
+
* that already belongs to the supplied Profile, including legacy Profile
|
|
958
|
+
* types, and deliberately refuses to create or rebind authority.
|
|
905
959
|
*/
|
|
906
960
|
static findOrCreate(profile: Profile, oidcData: {
|
|
907
961
|
provider: string;
|
|
@@ -930,7 +984,11 @@ export declare class OidcIdentityCollection extends SmrtCollection<OidcIdentity>
|
|
|
930
984
|
*/
|
|
931
985
|
findByProvider(provider: string): Promise<OidcIdentity[]>;
|
|
932
986
|
/**
|
|
933
|
-
*
|
|
987
|
+
* Reuse an existing exact OIDC identity for its unchanged Profile.
|
|
988
|
+
*
|
|
989
|
+
* @deprecated New authentication links require the owner-aware,
|
|
990
|
+
* transactional provisioning APIs. This compatibility helper may refresh a
|
|
991
|
+
* legacy Profile type, but refuses to create or rebind authority.
|
|
934
992
|
*/
|
|
935
993
|
linkToProfile(profile: Profile, oidcData: {
|
|
936
994
|
provider: string;
|
|
@@ -989,12 +1047,16 @@ export declare class Profile extends SmrtObject {
|
|
|
989
1047
|
tenantId: string | null;
|
|
990
1048
|
typeId?: string;
|
|
991
1049
|
email?: string;
|
|
1050
|
+
/** Adapter-independent identity lookup key derived from email on save. */
|
|
1051
|
+
emailKey: string | null;
|
|
992
1052
|
name: string;
|
|
993
1053
|
description?: string;
|
|
994
1054
|
metadata: ProfileMetadata[];
|
|
995
1055
|
relationshipsFrom: ProfileRelationship[];
|
|
996
1056
|
relationshipsTo: ProfileRelationship[];
|
|
997
1057
|
constructor(options?: ProfileOptions);
|
|
1058
|
+
/** Keep the durable identity key derived from the public email field. */
|
|
1059
|
+
save(): Promise<this>;
|
|
998
1060
|
/**
|
|
999
1061
|
* Get the profile type slug for this profile
|
|
1000
1062
|
*
|
|
@@ -1146,10 +1208,13 @@ export declare class Profile extends SmrtObject {
|
|
|
1146
1208
|
*/
|
|
1147
1209
|
getOidcIdentities(): Promise<OidcIdentity[]>;
|
|
1148
1210
|
/**
|
|
1149
|
-
*
|
|
1211
|
+
* Reuse an existing exact OIDC identity for this unchanged Profile.
|
|
1150
1212
|
*
|
|
1151
1213
|
* @param oidcData - OIDC provider data
|
|
1152
1214
|
* @returns The linked OIDC identity record
|
|
1215
|
+
* @deprecated New authentication links require owner-aware transactional
|
|
1216
|
+
* provisioning. This compatibility helper may refresh a legacy Profile
|
|
1217
|
+
* type, but refuses to create or rebind authority.
|
|
1153
1218
|
*/
|
|
1154
1219
|
linkOidcIdentity(oidcData: {
|
|
1155
1220
|
provider: string;
|
|
@@ -1200,6 +1265,8 @@ export declare class Profile extends SmrtObject {
|
|
|
1200
1265
|
}): Promise<AuditLog>;
|
|
1201
1266
|
}
|
|
1202
1267
|
|
|
1268
|
+
export declare const PROFILE_EMAIL_KEY_BACKFILL_NAME = "@happyvertical/smrt-profiles:profile-email-keys:v1";
|
|
1269
|
+
|
|
1203
1270
|
export declare class ProfileAsset extends SmrtObject {
|
|
1204
1271
|
tenantId: string | null;
|
|
1205
1272
|
profileId: string;
|
|
@@ -1230,6 +1297,7 @@ export declare interface ProfileAssetOptions extends SmrtObjectOptions {
|
|
|
1230
1297
|
|
|
1231
1298
|
export declare class ProfileCollection extends SmrtCollection<Profile> {
|
|
1232
1299
|
static readonly _itemClass: typeof Profile;
|
|
1300
|
+
private emailKeysReadyPromise;
|
|
1233
1301
|
/**
|
|
1234
1302
|
* Find a profile by email address
|
|
1235
1303
|
*
|
|
@@ -1237,6 +1305,30 @@ export declare class ProfileCollection extends SmrtCollection<Profile> {
|
|
|
1237
1305
|
* @returns The matching profile or null
|
|
1238
1306
|
*/
|
|
1239
1307
|
findByEmail(email: string): Promise<Profile | null>;
|
|
1308
|
+
/**
|
|
1309
|
+
* Resolve one unambiguous global Person by normalized email.
|
|
1310
|
+
*
|
|
1311
|
+
* Unlike `findByEmail()`, this identity-boundary helper deliberately reads
|
|
1312
|
+
* across tenant scopes and fails closed when any matching row is
|
|
1313
|
+
* tenant-scoped, is not a Person STI row, or when more than one row matches
|
|
1314
|
+
* case-insensitively. It is intended for verified external identities.
|
|
1315
|
+
*/
|
|
1316
|
+
findUniqueGlobalPersonByEmail(email: string): Promise<Profile | null>;
|
|
1317
|
+
/**
|
|
1318
|
+
* Validate and hydrate a supplied canonical Profile.
|
|
1319
|
+
*
|
|
1320
|
+
* The Profile must be the sole case-insensitive match for its stored email.
|
|
1321
|
+
* When `email` is provided, that address must also match the stored email.
|
|
1322
|
+
*/
|
|
1323
|
+
requireCanonicalGlobalPerson(profileId: string, email?: string): Promise<Profile>;
|
|
1324
|
+
/**
|
|
1325
|
+
* Reserve the normalized email for a previously validated canonical Person.
|
|
1326
|
+
*
|
|
1327
|
+
* The unique stored key turns a concurrent OIDC first-login race into a
|
|
1328
|
+
* retryable database conflict. Legacy Profiles remain unaffected until an
|
|
1329
|
+
* identity boundary safely claims them.
|
|
1330
|
+
*/
|
|
1331
|
+
reserveCanonicalIdentityEmail(profileId: string, email?: string): Promise<Profile>;
|
|
1240
1332
|
/**
|
|
1241
1333
|
* Find profiles by type slug
|
|
1242
1334
|
*
|
|
@@ -1244,6 +1336,15 @@ export declare class ProfileCollection extends SmrtCollection<Profile> {
|
|
|
1244
1336
|
* @returns Array of matching profiles
|
|
1245
1337
|
*/
|
|
1246
1338
|
findByType(typeSlug: string): Promise<Profile[]>;
|
|
1339
|
+
private requireDatabase;
|
|
1340
|
+
private loadCanonicalEmailRows;
|
|
1341
|
+
/** Require the deploy-time backfill marker before indexed identity reads. */
|
|
1342
|
+
private ensureEmailKeysReady;
|
|
1343
|
+
private checkEmailKeysReady;
|
|
1344
|
+
private isStaleEmailReservation;
|
|
1345
|
+
private assertRowEmailKeyCurrent;
|
|
1346
|
+
private assertCanonicalRows;
|
|
1347
|
+
private requireHydratedProfile;
|
|
1247
1348
|
/**
|
|
1248
1349
|
* Batch get metadata for multiple profiles
|
|
1249
1350
|
*
|
|
@@ -1688,6 +1789,17 @@ export declare class ProfileTypeCollection extends SmrtCollection<ProfileType> {
|
|
|
1688
1789
|
name: string;
|
|
1689
1790
|
description?: string;
|
|
1690
1791
|
}): Promise<ProfileType>;
|
|
1792
|
+
/**
|
|
1793
|
+
* Atomically create or load a global ProfileType from trusted system code.
|
|
1794
|
+
*
|
|
1795
|
+
* This intentionally bypasses tenant auto-population and therefore refuses
|
|
1796
|
+
* to run outside an explicit `withSystemContext()` boundary.
|
|
1797
|
+
*/
|
|
1798
|
+
getOrCreateGlobalBySlug(slug: string, defaults: {
|
|
1799
|
+
name: string;
|
|
1800
|
+
description?: string;
|
|
1801
|
+
}): Promise<ProfileType>;
|
|
1802
|
+
private loadGlobalBySlug;
|
|
1691
1803
|
}
|
|
1692
1804
|
|
|
1693
1805
|
export declare interface ProfileTypeOptions extends SmrtObjectOptions {
|