@happyvertical/smrt-profiles 0.40.69 → 0.40.70

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 (21) hide show
  1. package/AGENTS.md +9 -4
  2. package/dist/chunks/{OidcIdentity-CFbUlB_Z.js → OidcIdentity-Bd68oFpZ.js} +3 -3
  3. package/dist/chunks/{OidcIdentity-CFbUlB_Z.js.map → OidcIdentity-Bd68oFpZ.js.map} +1 -1
  4. package/dist/chunks/{OidcIdentityCollection-BLxSaqJT.js → OidcIdentityCollection-DmllRnCw.js} +2 -2
  5. package/dist/chunks/{OidcIdentityCollection-BLxSaqJT.js.map → OidcIdentityCollection-DmllRnCw.js.map} +1 -1
  6. package/dist/chunks/{ProfileAssetCollection-FhW8q7_1.js → ProfileAssetCollection-DS2Nh2IQ.js} +2 -2
  7. package/dist/chunks/{ProfileAssetCollection-FhW8q7_1.js.map → ProfileAssetCollection-DS2Nh2IQ.js.map} +1 -1
  8. package/dist/chunks/{ProfileCollection-DdJ3W4GG.js → ProfileCollection-BOwbNCgG.js} +7 -14
  9. package/dist/chunks/ProfileCollection-BOwbNCgG.js.map +1 -0
  10. package/dist/chunks/{oidcProvisioningPrimitives-C9XSQNZj.js → oidcProvisioningPrimitives-BWHPpJde.js} +3 -3
  11. package/dist/chunks/{oidcProvisioningPrimitives-C9XSQNZj.js.map → oidcProvisioningPrimitives-BWHPpJde.js.map} +1 -1
  12. package/dist/chunks/{resolveIdentity-BpkxPkz7.js → resolveIdentity-F6aErDyh.js} +15 -15
  13. package/dist/chunks/{resolveIdentity-BpkxPkz7.js.map → resolveIdentity-F6aErDyh.js.map} +1 -1
  14. package/dist/index.js +10 -10
  15. package/dist/internal/oidc-provisioning.js +2 -2
  16. package/dist/manifest.json +61 -1
  17. package/dist/oidc-provisioning.d.ts +13 -1
  18. package/dist/smrt-knowledge.json +5 -5
  19. package/dist/utils.js +1 -1
  20. package/package.json +6 -6
  21. package/dist/chunks/ProfileCollection-DdJ3W4GG.js.map +0 -1
package/AGENTS.md CHANGED
@@ -90,10 +90,15 @@ import { smrtProfilesGenerateBioPrompt } from '@happyvertical/smrt-profiles';
90
90
  `@happyvertical/smrt-profiles/internal/oidc-provisioning` subpath instead of
91
91
  duplicating adapter probing, locking, or retry policy, and supply both exact
92
92
  issuer/subject and normalized-email lock keys in deterministic order. The
93
- coordinator additionally serializes all SQLite/DuckDB provisioning
94
- transactions per database URL because those adapters cannot overlap
95
- unrelated root transactions safely and retries bounded PostgreSQL
96
- deadlock/serialization failures. New OIDC Profiles use per-profile,
93
+ coordinator additionally serializes every root-handle statement it owns per
94
+ database URL on SQLite/DuckDB shared `_smrt_backfills` initialization, the
95
+ provisioning transaction, and the post-commit rebind because those adapters
96
+ multiplex one native connection and cannot overlap unrelated root
97
+ transactions safely. **Never overlap two statements on one such handle,
98
+ transaction-bound or not** — no `Promise.all` over reads, not even
99
+ primary-key rebinds — because DuckDB fails the losing prepared statement or
100
+ aborts the process outright. It retries
101
+ bounded PostgreSQL deadlock/serialization failures. New OIDC Profiles use per-profile,
97
102
  non-semantic slugs so duplicate display names never invoke natural-key upsert.
98
103
  Caller-owned transactions never execute `_smrt_backfills` DDL; paths that
99
104
  perform canonical email lookup or reservation require the table to already
@@ -35,7 +35,7 @@ var OidcIdentity = class extends SmrtObject {
35
35
  * Find identity by issuer and subject
36
36
  */
37
37
  static async findBySubject(issuer, subject, options = {}) {
38
- const { OidcIdentityCollection } = await import("./OidcIdentityCollection-BLxSaqJT.js").then((n) => n.r);
38
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-DmllRnCw.js").then((n) => n.r);
39
39
  return await (await OidcIdentityCollection.create(options)).findBySubject(issuer, subject);
40
40
  }
41
41
  /** Build the collision-free natural key for one OIDC issuer subject. */
@@ -58,7 +58,7 @@ var OidcIdentity = class extends SmrtObject {
58
58
  static async findOrCreate(profile, oidcData, options = {}) {
59
59
  const profileId = profile.id;
60
60
  if (typeof profileId !== "string" || !profileId) throw new Error("OidcIdentity.findOrCreate() requires a saved Profile.");
61
- const { reuseExistingOidcIdentityForProfile } = await import("./resolveIdentity-BpkxPkz7.js").then((n) => n.i);
61
+ const { reuseExistingOidcIdentityForProfile } = await import("./resolveIdentity-F6aErDyh.js").then((n) => n.i);
62
62
  const profileOptions = profile.options ?? {};
63
63
  return (await reuseExistingOidcIdentityForProfile(profileId, {
64
64
  email: oidcData.email,
@@ -108,4 +108,4 @@ OidcIdentity = __decorateClass([smrt({
108
108
  //#endregion
109
109
  export { OidcIdentity as t };
110
110
 
111
- //# sourceMappingURL=OidcIdentity-CFbUlB_Z.js.map
111
+ //# sourceMappingURL=OidcIdentity-Bd68oFpZ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OidcIdentity-CFbUlB_Z.js","names":[],"sources":["../../src/models/OidcIdentity.ts"],"sourcesContent":["/**\n * OidcIdentity - Links OIDC provider identities to Profile\n *\n * Stores the mapping between external OIDC providers (Keycloak, Google, GitHub)\n * and internal Profile records. Multiple identities can link to a single profile.\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport type { Profile } from './Profile';\n\nexport interface OidcIdentityOptions extends SmrtObjectOptions {\n profileId?: string;\n provider?: string;\n issuer?: string;\n subject?: string;\n email?: string;\n lastUsedAt?: Date | null;\n}\n\n@smrt({\n tableName: 'oidc_identities',\n // Identity linking is an authentication authority change. Generated routes\n // authenticate callers but do not authorize Profile ownership, so mutations\n // must stay behind the trusted provisioning APIs below.\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class OidcIdentity extends SmrtObject {\n /**\n * Link to the Profile (Person, Organization, Bot)\n */\n @foreignKey('Profile', { required: true })\n profileId?: string;\n\n /**\n * Provider name (e.g., 'keycloak', 'google', 'github')\n */\n @field({ type: 'text' })\n provider: string = '';\n\n /**\n * OIDC issuer URL (e.g., https://keycloak.example.com/realms/bmp)\n */\n @field({ type: 'text', indexed: true })\n issuer: string = '';\n\n /**\n * OIDC subject claim - unique identifier from the provider\n */\n @field({ type: 'text', indexed: true })\n subject: string = '';\n\n /**\n * Stable issuer+subject key used as the database race arbiter.\n *\n * Nullable for legacy rows; every newly linked or reused identity backfills\n * it. A separate unique constraint makes concurrent first login fail with a\n * retryable conflict instead of creating two identities.\n */\n @field({ type: 'text', nullable: true, unique: true, readonly: true })\n identityKey: string | null = null;\n\n /**\n * Cached email from the IdP (for display/lookup)\n */\n @field({ type: 'text' })\n email: string = '';\n\n /**\n * Last time this identity was used for authentication\n */\n @field({ type: 'datetime', nullable: true })\n lastUsedAt: Date | null = null;\n\n constructor(options: OidcIdentityOptions = {}) {\n super(options);\n if (options.profileId) this.profileId = options.profileId;\n if (options.provider) this.provider = options.provider;\n if (options.issuer) this.issuer = options.issuer;\n if (options.subject) this.subject = options.subject;\n if (options.email) this.email = options.email;\n if (options.lastUsedAt !== undefined) this.lastUsedAt = options.lastUsedAt;\n }\n\n /**\n * Get the linked Profile\n */\n async getProfile(): Promise<Profile | null> {\n return (await this.getRelated('profileId')) as Profile | null;\n }\n\n /**\n * Find identity by issuer and subject\n */\n static async findBySubject(\n issuer: string,\n subject: string,\n options: SmrtObjectOptions = {},\n ): Promise<OidcIdentity | null> {\n const { OidcIdentityCollection } = await import(\n '../collections/OidcIdentityCollection'\n );\n const collection = await OidcIdentityCollection.create(options);\n return await collection.findBySubject(issuer, subject);\n }\n\n /** Build the collision-free natural key for one OIDC issuer subject. */\n static buildIdentityKey(issuer: string, subject: string): string {\n return JSON.stringify([issuer, subject]);\n }\n\n /** Keep the durable key derived from its natural-key source fields. */\n override async save(): Promise<this> {\n this.identityKey =\n this.issuer.trim() && this.subject.trim()\n ? OidcIdentity.buildIdentityKey(this.issuer, this.subject)\n : null;\n return super.save();\n }\n\n /**\n * Reuse an existing exact identity for its unchanged Profile.\n *\n * @deprecated Authentication links must be created through transactional\n * provisioning. This compatibility method only refreshes a unique mapping\n * that already belongs to the supplied Profile, including legacy Profile\n * types, and deliberately refuses to create or rebind authority.\n */\n static async findOrCreate(\n profile: Profile,\n oidcData: {\n provider: string;\n issuer: string;\n subject: string;\n email?: string;\n },\n options: SmrtObjectOptions = {},\n ): Promise<OidcIdentity> {\n const profileId = profile.id;\n if (typeof profileId !== 'string' || !profileId) {\n throw new Error('OidcIdentity.findOrCreate() requires a saved Profile.');\n }\n const { reuseExistingOidcIdentityForProfile } = await import(\n '../auth/resolveIdentity'\n );\n const profileOptions = profile.options ?? {};\n const result = await reuseExistingOidcIdentityForProfile(\n profileId,\n {\n email: oidcData.email,\n iss: oidcData.issuer,\n sub: oidcData.subject,\n },\n oidcData.provider,\n {\n ...profileOptions,\n ...options,\n db: options.db ?? profileOptions.db,\n },\n );\n return result.oidcIdentity;\n }\n\n /**\n * Record usage of this identity\n */\n async recordUsage(): Promise<void> {\n this.lastUsedAt = new Date();\n await this.save();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OidcIdentity-Bd68oFpZ.js","names":[],"sources":["../../src/models/OidcIdentity.ts"],"sourcesContent":["/**\n * OidcIdentity - Links OIDC provider identities to Profile\n *\n * Stores the mapping between external OIDC providers (Keycloak, Google, GitHub)\n * and internal Profile records. Multiple identities can link to a single profile.\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport type { Profile } from './Profile';\n\nexport interface OidcIdentityOptions extends SmrtObjectOptions {\n profileId?: string;\n provider?: string;\n issuer?: string;\n subject?: string;\n email?: string;\n lastUsedAt?: Date | null;\n}\n\n@smrt({\n tableName: 'oidc_identities',\n // Identity linking is an authentication authority change. Generated routes\n // authenticate callers but do not authorize Profile ownership, so mutations\n // must stay behind the trusted provisioning APIs below.\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class OidcIdentity extends SmrtObject {\n /**\n * Link to the Profile (Person, Organization, Bot)\n */\n @foreignKey('Profile', { required: true })\n profileId?: string;\n\n /**\n * Provider name (e.g., 'keycloak', 'google', 'github')\n */\n @field({ type: 'text' })\n provider: string = '';\n\n /**\n * OIDC issuer URL (e.g., https://keycloak.example.com/realms/bmp)\n */\n @field({ type: 'text', indexed: true })\n issuer: string = '';\n\n /**\n * OIDC subject claim - unique identifier from the provider\n */\n @field({ type: 'text', indexed: true })\n subject: string = '';\n\n /**\n * Stable issuer+subject key used as the database race arbiter.\n *\n * Nullable for legacy rows; every newly linked or reused identity backfills\n * it. A separate unique constraint makes concurrent first login fail with a\n * retryable conflict instead of creating two identities.\n */\n @field({ type: 'text', nullable: true, unique: true, readonly: true })\n identityKey: string | null = null;\n\n /**\n * Cached email from the IdP (for display/lookup)\n */\n @field({ type: 'text' })\n email: string = '';\n\n /**\n * Last time this identity was used for authentication\n */\n @field({ type: 'datetime', nullable: true })\n lastUsedAt: Date | null = null;\n\n constructor(options: OidcIdentityOptions = {}) {\n super(options);\n if (options.profileId) this.profileId = options.profileId;\n if (options.provider) this.provider = options.provider;\n if (options.issuer) this.issuer = options.issuer;\n if (options.subject) this.subject = options.subject;\n if (options.email) this.email = options.email;\n if (options.lastUsedAt !== undefined) this.lastUsedAt = options.lastUsedAt;\n }\n\n /**\n * Get the linked Profile\n */\n async getProfile(): Promise<Profile | null> {\n return (await this.getRelated('profileId')) as Profile | null;\n }\n\n /**\n * Find identity by issuer and subject\n */\n static async findBySubject(\n issuer: string,\n subject: string,\n options: SmrtObjectOptions = {},\n ): Promise<OidcIdentity | null> {\n const { OidcIdentityCollection } = await import(\n '../collections/OidcIdentityCollection'\n );\n const collection = await OidcIdentityCollection.create(options);\n return await collection.findBySubject(issuer, subject);\n }\n\n /** Build the collision-free natural key for one OIDC issuer subject. */\n static buildIdentityKey(issuer: string, subject: string): string {\n return JSON.stringify([issuer, subject]);\n }\n\n /** Keep the durable key derived from its natural-key source fields. */\n override async save(): Promise<this> {\n this.identityKey =\n this.issuer.trim() && this.subject.trim()\n ? OidcIdentity.buildIdentityKey(this.issuer, this.subject)\n : null;\n return super.save();\n }\n\n /**\n * Reuse an existing exact identity for its unchanged Profile.\n *\n * @deprecated Authentication links must be created through transactional\n * provisioning. This compatibility method only refreshes a unique mapping\n * that already belongs to the supplied Profile, including legacy Profile\n * types, and deliberately refuses to create or rebind authority.\n */\n static async findOrCreate(\n profile: Profile,\n oidcData: {\n provider: string;\n issuer: string;\n subject: string;\n email?: string;\n },\n options: SmrtObjectOptions = {},\n ): Promise<OidcIdentity> {\n const profileId = profile.id;\n if (typeof profileId !== 'string' || !profileId) {\n throw new Error('OidcIdentity.findOrCreate() requires a saved Profile.');\n }\n const { reuseExistingOidcIdentityForProfile } = await import(\n '../auth/resolveIdentity'\n );\n const profileOptions = profile.options ?? {};\n const result = await reuseExistingOidcIdentityForProfile(\n profileId,\n {\n email: oidcData.email,\n iss: oidcData.issuer,\n sub: oidcData.subject,\n },\n oidcData.provider,\n {\n ...profileOptions,\n ...options,\n db: options.db ?? profileOptions.db,\n },\n );\n return result.oidcIdentity;\n }\n\n /**\n * Record usage of this identity\n */\n async recordUsage(): Promise<void> {\n this.lastUsedAt = new Date();\n await this.save();\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { y as __exportAll } from "./NostrIdentity-DF_a_WZk.js";
2
- import { t as OidcIdentity } from "./OidcIdentity-CFbUlB_Z.js";
2
+ import { t as OidcIdentity } from "./OidcIdentity-Bd68oFpZ.js";
3
3
  import { SmrtCollection } from "@happyvertical/smrt-core";
4
4
  //#region src/collections/OidcIdentityCollection.ts
5
5
  var OidcIdentityCollection_exports = /* @__PURE__ */ __exportAll({
@@ -73,4 +73,4 @@ var OidcIdentityCollection = class extends SmrtCollection {
73
73
  //#endregion
74
74
  export { OidcIdentityCollection as n, OidcIdentityCollection_exports as r, AmbiguousOidcIdentityError as t };
75
75
 
76
- //# sourceMappingURL=OidcIdentityCollection-BLxSaqJT.js.map
76
+ //# sourceMappingURL=OidcIdentityCollection-DmllRnCw.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OidcIdentityCollection-BLxSaqJT.js","names":[],"sources":["../../src/collections/OidcIdentityCollection.ts"],"sourcesContent":["/**\n * OidcIdentityCollection - Collection for managing OIDC identity records\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { OidcIdentity } from '../models/OidcIdentity';\nimport type { Profile } from '../models/Profile';\n\n/** More than one legacy row maps the same opaque OIDC issuer and subject. */\nexport class AmbiguousOidcIdentityError extends Error {\n constructor(\n readonly issuer: string,\n readonly subject: string,\n ) {\n super('Multiple OIDC identities match the same issuer and subject.');\n this.name = 'AmbiguousOidcIdentityError';\n }\n}\n\nexport class OidcIdentityCollection extends SmrtCollection<OidcIdentity> {\n static readonly _itemClass = OidcIdentity;\n\n /**\n * Find identities for a profile\n */\n async findByProfile(profileId: string): Promise<OidcIdentity[]> {\n return await this.list({\n where: { profileId },\n });\n }\n\n /**\n * Find identity by issuer and subject\n */\n async findBySubject(\n issuer: string,\n subject: string,\n ): Promise<OidcIdentity | null> {\n const matches = await this.list({\n where: { issuer, subject },\n limit: 2,\n });\n if (matches.length > 1) {\n throw new AmbiguousOidcIdentityError(issuer, subject);\n }\n return matches[0] ?? null;\n }\n\n /**\n * Find identities by provider\n */\n async findByProvider(provider: string): Promise<OidcIdentity[]> {\n return await this.list({\n where: { provider },\n });\n }\n\n /**\n * Reuse an existing exact OIDC identity for its unchanged Profile.\n *\n * @deprecated New authentication links require the owner-aware,\n * transactional provisioning APIs. This compatibility helper may refresh a\n * legacy Profile type, but refuses to create or rebind authority.\n */\n async linkToProfile(\n profile: Profile,\n oidcData: {\n provider: string;\n issuer: string;\n subject: string;\n email?: string;\n },\n ): Promise<OidcIdentity> {\n return OidcIdentity.findOrCreate(profile, oidcData, this.options);\n }\n\n /**\n * Unlink an OIDC identity from a profile\n */\n async unlinkFromProfile(\n profileId: string,\n issuer: string,\n subject: string,\n ): Promise<boolean> {\n const identity = await this.findOne({\n where: { profileId, issuer, subject },\n });\n\n if (identity) {\n await identity.delete();\n return true;\n }\n return false;\n }\n}\n"],"mappings":";;;;;;;;AASO,IAAM,6BAAN,cAAyC,MAAM;CACpD,YACW,QACA,SACT;EACA,MAAM,6DAA6D;EAH1D,KAAA,SAAA;EACA,KAAA,UAAA;EAGT,KAAK,OAAO;CACd;CALW;CACA;AAKb;AAEO,IAAM,yBAAN,cAAqC,eAA6B;CACvE,OAAgB,aAAa;;;;CAK7B,MAAM,cAAc,WAA4C;EAC9D,OAAO,MAAM,KAAK,KAAK,EACrB,OAAO,EAAE,UAAU,EACrB,CAAC;CACH;;;;CAKA,MAAM,cACJ,QACA,SAC8B;EAC9B,MAAM,UAAU,MAAM,KAAK,KAAK;GAC9B,OAAO;IAAE;IAAQ;GAAQ;GACzB,OAAO;EACT,CAAC;EACD,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,2BAA2B,QAAQ,OAAO;EAEtD,OAAO,QAAQ,MAAM;CACvB;;;;CAKA,MAAM,eAAe,UAA2C;EAC9D,OAAO,MAAM,KAAK,KAAK,EACrB,OAAO,EAAE,SAAS,EACpB,CAAC;CACH;;;;;;;;CASA,MAAM,cACJ,SACA,UAMuB;EACvB,OAAO,aAAa,aAAa,SAAS,UAAU,KAAK,OAAO;CAClE;;;;CAKA,MAAM,kBACJ,WACA,QACA,SACkB;EAClB,MAAM,WAAW,MAAM,KAAK,QAAQ,EAClC,OAAO;GAAE;GAAW;GAAQ;EAAQ,EACtC,CAAC;EAED,IAAI,UAAU;GACZ,MAAM,SAAS,OAAO;GACtB,OAAO;EACT;EACA,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"OidcIdentityCollection-DmllRnCw.js","names":[],"sources":["../../src/collections/OidcIdentityCollection.ts"],"sourcesContent":["/**\n * OidcIdentityCollection - Collection for managing OIDC identity records\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { OidcIdentity } from '../models/OidcIdentity';\nimport type { Profile } from '../models/Profile';\n\n/** More than one legacy row maps the same opaque OIDC issuer and subject. */\nexport class AmbiguousOidcIdentityError extends Error {\n constructor(\n readonly issuer: string,\n readonly subject: string,\n ) {\n super('Multiple OIDC identities match the same issuer and subject.');\n this.name = 'AmbiguousOidcIdentityError';\n }\n}\n\nexport class OidcIdentityCollection extends SmrtCollection<OidcIdentity> {\n static readonly _itemClass = OidcIdentity;\n\n /**\n * Find identities for a profile\n */\n async findByProfile(profileId: string): Promise<OidcIdentity[]> {\n return await this.list({\n where: { profileId },\n });\n }\n\n /**\n * Find identity by issuer and subject\n */\n async findBySubject(\n issuer: string,\n subject: string,\n ): Promise<OidcIdentity | null> {\n const matches = await this.list({\n where: { issuer, subject },\n limit: 2,\n });\n if (matches.length > 1) {\n throw new AmbiguousOidcIdentityError(issuer, subject);\n }\n return matches[0] ?? null;\n }\n\n /**\n * Find identities by provider\n */\n async findByProvider(provider: string): Promise<OidcIdentity[]> {\n return await this.list({\n where: { provider },\n });\n }\n\n /**\n * Reuse an existing exact OIDC identity for its unchanged Profile.\n *\n * @deprecated New authentication links require the owner-aware,\n * transactional provisioning APIs. This compatibility helper may refresh a\n * legacy Profile type, but refuses to create or rebind authority.\n */\n async linkToProfile(\n profile: Profile,\n oidcData: {\n provider: string;\n issuer: string;\n subject: string;\n email?: string;\n },\n ): Promise<OidcIdentity> {\n return OidcIdentity.findOrCreate(profile, oidcData, this.options);\n }\n\n /**\n * Unlink an OIDC identity from a profile\n */\n async unlinkFromProfile(\n profileId: string,\n issuer: string,\n subject: string,\n ): Promise<boolean> {\n const identity = await this.findOne({\n where: { profileId, issuer, subject },\n });\n\n if (identity) {\n await identity.delete();\n return true;\n }\n return false;\n }\n}\n"],"mappings":";;;;;;;;AASO,IAAM,6BAAN,cAAyC,MAAM;CACpD,YACW,QACA,SACT;EACA,MAAM,6DAA6D;EAH1D,KAAA,SAAA;EACA,KAAA,UAAA;EAGT,KAAK,OAAO;CACd;CALW;CACA;AAKb;AAEO,IAAM,yBAAN,cAAqC,eAA6B;CACvE,OAAgB,aAAa;;;;CAK7B,MAAM,cAAc,WAA4C;EAC9D,OAAO,MAAM,KAAK,KAAK,EACrB,OAAO,EAAE,UAAU,EACrB,CAAC;CACH;;;;CAKA,MAAM,cACJ,QACA,SAC8B;EAC9B,MAAM,UAAU,MAAM,KAAK,KAAK;GAC9B,OAAO;IAAE;IAAQ;GAAQ;GACzB,OAAO;EACT,CAAC;EACD,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,2BAA2B,QAAQ,OAAO;EAEtD,OAAO,QAAQ,MAAM;CACvB;;;;CAKA,MAAM,eAAe,UAA2C;EAC9D,OAAO,MAAM,KAAK,KAAK,EACrB,OAAO,EAAE,SAAS,EACpB,CAAC;CACH;;;;;;;;CASA,MAAM,cACJ,SACA,UAMuB;EACvB,OAAO,aAAa,aAAa,SAAS,UAAU,KAAK,OAAO;CAClE;;;;CAKA,MAAM,kBACJ,WACA,QACA,SACkB;EAClB,MAAM,WAAW,MAAM,KAAK,QAAQ,EAClC,OAAO;GAAE;GAAW;GAAQ;EAAQ,EACtC,CAAC;EAED,IAAI,UAAU;GACZ,MAAM,SAAS,OAAO;GACtB,OAAO;EACT;EACA,OAAO;CACT;AACF"}
@@ -66,7 +66,7 @@ var ProfileAssetCollection = class extends SmrtJunction {
66
66
  profileCollectionPromise = null;
67
67
  async getProfileCollection() {
68
68
  if (!this.profileCollectionPromise) {
69
- const { ProfileCollection } = await import("./ProfileCollection-DdJ3W4GG.js").then((n) => n.r);
69
+ const { ProfileCollection } = await import("./ProfileCollection-BOwbNCgG.js").then((n) => n.r);
70
70
  this.profileCollectionPromise = ProfileCollection.create({ db: this.db });
71
71
  }
72
72
  return this.profileCollectionPromise;
@@ -90,4 +90,4 @@ ProfileAssetCollection = __decorateClass([smrt({
90
90
  //#endregion
91
91
  export { ProfileAssetCollection_exports as n, ProfileAsset as r, ProfileAssetCollection as t };
92
92
 
93
- //# sourceMappingURL=ProfileAssetCollection-FhW8q7_1.js.map
93
+ //# sourceMappingURL=ProfileAssetCollection-DS2Nh2IQ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileAssetCollection-FhW8q7_1.js","names":[],"sources":["../../src/models/ProfileAsset.ts","../../src/collections/ProfileAssetCollection.ts"],"sourcesContent":["import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface ProfileAssetOptions extends SmrtObjectOptions {\n profileId?: string;\n assetId?: string;\n relationship?: string;\n sortOrder?: number;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'profile_assets',\n conflictColumns: ['profile_id', 'asset_id', 'relationship'],\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ProfileAsset extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Profile', { required: true })\n profileId = '';\n\n @crossPackageRef('@happyvertical/smrt-assets:Asset', { required: true })\n assetId = '';\n\n @field({ required: true })\n relationship = 'attachment';\n\n @field()\n sortOrder = 0;\n\n constructor(options: ProfileAssetOptions = {}) {\n super(options);\n if (options.profileId) this.profileId = options.profileId;\n if (options.assetId) this.assetId = options.assetId;\n if (options.relationship) this.relationship = options.relationship;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n}\n","import type { Asset } from '@happyvertical/smrt-assets';\nimport {\n addOwnedAssetFromCollection,\n getOwnedAssetsFromCollection,\n removeOwnedAssetFromCollection,\n} from '@happyvertical/smrt-assets';\nimport type { SmrtCollectionOptions } from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { ProfileAsset } from '../models/ProfileAsset';\nimport type { ProfileCollection } from './ProfileCollection';\n\nexport interface ProfileAssetCollectionOptions extends SmrtCollectionOptions {}\n\n@smrt({\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ProfileAssetCollection extends SmrtJunction<ProfileAsset> {\n static readonly _itemClass = ProfileAsset;\n protected leftField = 'profileId';\n protected rightField = 'assetId';\n\n private profileCollectionPromise: Promise<ProfileCollection> | null = null;\n\n private async getProfileCollection(): Promise<ProfileCollection> {\n if (!this.profileCollectionPromise) {\n const { ProfileCollection } = await import('./ProfileCollection');\n this.profileCollectionPromise = ProfileCollection.create({ db: this.db });\n }\n\n return this.profileCollectionPromise;\n }\n\n async getAssets(profileId: string, relationship?: string): Promise<Asset[]> {\n return getOwnedAssetsFromCollection(\n await this.getProfileCollection(),\n profileId,\n relationship,\n );\n }\n\n async addAsset(\n profileId: string,\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n await addOwnedAssetFromCollection(\n await this.getProfileCollection(),\n 'Profile',\n profileId,\n asset,\n relationship,\n sortOrder,\n );\n }\n\n async removeAsset(\n profileId: string,\n assetId: string,\n relationship?: string,\n ): Promise<void> {\n await removeOwnedAssetFromCollection(\n await this.getProfileCollection(),\n 'Profile',\n profileId,\n assetId,\n relationship,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;AA0BO,IAAM,eAAN,cAA2B,WAAW;CAE3C,WAA0B;CAG1B,YAAY;CAGZ,UAAU;CAGV,eAAe;CAGf,YAAY;CAEZ,YAAY,UAA+B,CAAC,GAAG;EAC7C,MAAM,OAAO;EACb,IAAI,QAAQ,WAAW,KAAK,YAAY,QAAQ;EAChD,IAAI,QAAQ,SAAS,KAAK,UAAU,QAAQ;EAC5C,IAAI,QAAQ,cAAc,KAAK,eAAe,QAAQ;EACtD,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;CAC9D;AACF;AAtBE,kBAAA,CADC,SAAS,EAAE,UAAU,KAAK,CAAC,CAAA,GADjB,aAEX,WAAA,YAAA,CAAA;AAGA,kBAAA,CADC,WAAW,WAAW,EAAE,UAAU,KAAK,CAAC,CAAA,GAJ9B,aAKX,WAAA,aAAA,CAAA;AAGA,kBAAA,CADC,gBAAgB,oCAAoC,EAAE,UAAU,KAAK,CAAC,CAAA,GAP5D,aAQX,WAAA,WAAA,CAAA;AAGA,kBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAVd,aAWX,WAAA,gBAAA,CAAA;AAGA,kBAAA,CADC,MAAM,CAAA,GAbI,aAcX,WAAA,aAAA,CAAA;AAdW,eAAN,kBAAA,CARN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,iBAAiB;EAAC;EAAc;EAAY;CAAc;CAC1D,KAAK;CACL,KAAK;CACL,KAAK;AACP,CAAC,CAAA,GACY,YAAA;;;;;;;;;;;;;;;;;;;ACRN,IAAM,yBAAN,cAAqC,aAA2B;CAE3D,YAAY;CACZ,aAAa;CAEf,2BAA8D;CAEtE,MAAc,uBAAmD;EAC/D,IAAI,CAAC,KAAK,0BAA0B;GAClC,MAAM,EAAE,sBAAsB,MAAM,OAAO,kCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;GAC3C,KAAK,2BAA2B,kBAAkB,OAAO,EAAE,IAAI,KAAK,GAAG,CAAC;EAC1E;EAEA,OAAO,KAAK;CACd;CAEA,MAAM,UAAU,WAAmB,cAAyC;EAC1E,OAAO,6BACL,MAAM,KAAK,qBAAqB,GAChC,WACA,YACF;CACF;CAEA,MAAM,SACJ,WACA,OACA,eAAe,cACf,YAAY,GACG;EACf,MAAM,4BACJ,MAAM,KAAK,qBAAqB,GAChC,WACA,WACA,OACA,cACA,SACF;CACF;CAEA,MAAM,YACJ,WACA,SACA,cACe;EACf,MAAM,+BACJ,MAAM,KAAK,qBAAqB,GAChC,WACA,WACA,SACA,YACF;CACF;AACF;AApDE,cADW,wBACK,cAAa,YAAA;AADlB,yBAAN,gBAAA,CALN,KAAK;CACJ,KAAK;CACL,KAAK;CACL,KAAK;AACP,CAAC,CAAA,GACY,sBAAA"}
1
+ {"version":3,"file":"ProfileAssetCollection-DS2Nh2IQ.js","names":[],"sources":["../../src/models/ProfileAsset.ts","../../src/collections/ProfileAssetCollection.ts"],"sourcesContent":["import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface ProfileAssetOptions extends SmrtObjectOptions {\n profileId?: string;\n assetId?: string;\n relationship?: string;\n sortOrder?: number;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'profile_assets',\n conflictColumns: ['profile_id', 'asset_id', 'relationship'],\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ProfileAsset extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Profile', { required: true })\n profileId = '';\n\n @crossPackageRef('@happyvertical/smrt-assets:Asset', { required: true })\n assetId = '';\n\n @field({ required: true })\n relationship = 'attachment';\n\n @field()\n sortOrder = 0;\n\n constructor(options: ProfileAssetOptions = {}) {\n super(options);\n if (options.profileId) this.profileId = options.profileId;\n if (options.assetId) this.assetId = options.assetId;\n if (options.relationship) this.relationship = options.relationship;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n}\n","import type { Asset } from '@happyvertical/smrt-assets';\nimport {\n addOwnedAssetFromCollection,\n getOwnedAssetsFromCollection,\n removeOwnedAssetFromCollection,\n} from '@happyvertical/smrt-assets';\nimport type { SmrtCollectionOptions } from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { ProfileAsset } from '../models/ProfileAsset';\nimport type { ProfileCollection } from './ProfileCollection';\n\nexport interface ProfileAssetCollectionOptions extends SmrtCollectionOptions {}\n\n@smrt({\n api: false,\n mcp: false,\n cli: false,\n})\nexport class ProfileAssetCollection extends SmrtJunction<ProfileAsset> {\n static readonly _itemClass = ProfileAsset;\n protected leftField = 'profileId';\n protected rightField = 'assetId';\n\n private profileCollectionPromise: Promise<ProfileCollection> | null = null;\n\n private async getProfileCollection(): Promise<ProfileCollection> {\n if (!this.profileCollectionPromise) {\n const { ProfileCollection } = await import('./ProfileCollection');\n this.profileCollectionPromise = ProfileCollection.create({ db: this.db });\n }\n\n return this.profileCollectionPromise;\n }\n\n async getAssets(profileId: string, relationship?: string): Promise<Asset[]> {\n return getOwnedAssetsFromCollection(\n await this.getProfileCollection(),\n profileId,\n relationship,\n );\n }\n\n async addAsset(\n profileId: string,\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n await addOwnedAssetFromCollection(\n await this.getProfileCollection(),\n 'Profile',\n profileId,\n asset,\n relationship,\n sortOrder,\n );\n }\n\n async removeAsset(\n profileId: string,\n assetId: string,\n relationship?: string,\n ): Promise<void> {\n await removeOwnedAssetFromCollection(\n await this.getProfileCollection(),\n 'Profile',\n profileId,\n assetId,\n relationship,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;AA0BO,IAAM,eAAN,cAA2B,WAAW;CAE3C,WAA0B;CAG1B,YAAY;CAGZ,UAAU;CAGV,eAAe;CAGf,YAAY;CAEZ,YAAY,UAA+B,CAAC,GAAG;EAC7C,MAAM,OAAO;EACb,IAAI,QAAQ,WAAW,KAAK,YAAY,QAAQ;EAChD,IAAI,QAAQ,SAAS,KAAK,UAAU,QAAQ;EAC5C,IAAI,QAAQ,cAAc,KAAK,eAAe,QAAQ;EACtD,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;CAC9D;AACF;AAtBE,kBAAA,CADC,SAAS,EAAE,UAAU,KAAK,CAAC,CAAA,GADjB,aAEX,WAAA,YAAA,CAAA;AAGA,kBAAA,CADC,WAAW,WAAW,EAAE,UAAU,KAAK,CAAC,CAAA,GAJ9B,aAKX,WAAA,aAAA,CAAA;AAGA,kBAAA,CADC,gBAAgB,oCAAoC,EAAE,UAAU,KAAK,CAAC,CAAA,GAP5D,aAQX,WAAA,WAAA,CAAA;AAGA,kBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAVd,aAWX,WAAA,gBAAA,CAAA;AAGA,kBAAA,CADC,MAAM,CAAA,GAbI,aAcX,WAAA,aAAA,CAAA;AAdW,eAAN,kBAAA,CARN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,iBAAiB;EAAC;EAAc;EAAY;CAAc;CAC1D,KAAK;CACL,KAAK;CACL,KAAK;AACP,CAAC,CAAA,GACY,YAAA;;;;;;;;;;;;;;;;;;;ACRN,IAAM,yBAAN,cAAqC,aAA2B;CAE3D,YAAY;CACZ,aAAa;CAEf,2BAA8D;CAEtE,MAAc,uBAAmD;EAC/D,IAAI,CAAC,KAAK,0BAA0B;GAClC,MAAM,EAAE,sBAAsB,MAAM,OAAO,kCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;GAC3C,KAAK,2BAA2B,kBAAkB,OAAO,EAAE,IAAI,KAAK,GAAG,CAAC;EAC1E;EAEA,OAAO,KAAK;CACd;CAEA,MAAM,UAAU,WAAmB,cAAyC;EAC1E,OAAO,6BACL,MAAM,KAAK,qBAAqB,GAChC,WACA,YACF;CACF;CAEA,MAAM,SACJ,WACA,OACA,eAAe,cACf,YAAY,GACG;EACf,MAAM,4BACJ,MAAM,KAAK,qBAAqB,GAChC,WACA,WACA,OACA,cACA,SACF;CACF;CAEA,MAAM,YACJ,WACA,SACA,cACe;EACf,MAAM,+BACJ,MAAM,KAAK,qBAAqB,GAChC,WACA,WACA,SACA,YACF;CACF;AACF;AApDE,cADW,wBACK,cAAa,YAAA;AADlB,yBAAN,gBAAA,CALN,KAAK;CACJ,KAAK;CACL,KAAK;CACL,KAAK;AACP,CAAC,CAAA,GACY,sBAAA"}
@@ -1,5 +1,5 @@
1
1
  import { y as __exportAll } from "./NostrIdentity-DF_a_WZk.js";
2
- import { SmrtCollection, SmrtObject, ValidationError, field, foreignKey, oneToMany, smrt } from "@happyvertical/smrt-core";
2
+ import { SmrtCollection, SmrtObject, ValidationError, field, foreignKey, isAbortedTransactionError, oneToMany, smrt } from "@happyvertical/smrt-core";
3
3
  import { definePrompt, resolvePrompt } from "@happyvertical/smrt-prompts";
4
4
  import { TenantScoped, queryGlobal, queryWithGlobals, tenantId, withSystemContext } from "@happyvertical/smrt-tenancy";
5
5
  import { BackfillTableUnavailableError, BackfillTracker } from "@happyvertical/smrt-core/migrations";
@@ -68,8 +68,8 @@ var SavepointUnavailableError = class extends Error {
68
68
  };
69
69
  async function coordinateOidcProvisioning(options) {
70
70
  const rootBackfillTableReady = typeof options.db.beginTransaction === "function";
71
- if (rootBackfillTableReady) await new BackfillTracker({ db: options.db }).initialize();
72
71
  return withProvisioningLocks(options.db, options.lockKeys, async () => {
72
+ if (rootBackfillTableReady) await new BackfillTracker({ db: options.db }).initialize();
73
73
  const result = await retryProvisioning(options, () => withProvisioningTransaction(options.db, (tx) => {
74
74
  if (rootBackfillTableReady) BackfillTracker.inheritInitialization(tx, options.db);
75
75
  else BackfillTracker.requireExistingTable(tx);
@@ -84,14 +84,7 @@ async function withProvisioningLocks(db, lockKeys, callback) {
84
84
  return acquire(0);
85
85
  }
86
86
  function isOidcAbortedTransactionError(error) {
87
- const seen = /* @__PURE__ */ new Set();
88
- let current = error;
89
- while (current instanceof Error && !seen.has(current)) {
90
- seen.add(current);
91
- if (/current transaction is aborted|transaction.*aborted/iu.test(current.message)) return true;
92
- current = current.cause;
93
- }
94
- return false;
87
+ return isAbortedTransactionError(error);
95
88
  }
96
89
  function testRaceMessagePattern(pattern, message) {
97
90
  pattern.lastIndex = 0;
@@ -518,7 +511,7 @@ var Profile = class extends SmrtObject {
518
511
  if (existing.length > 0) await existing[0].delete();
519
512
  }
520
513
  async getProfileAssetCollection() {
521
- const { ProfileAssetCollection } = await import("./ProfileAssetCollection-FhW8q7_1.js").then((n) => n.n);
514
+ const { ProfileAssetCollection } = await import("./ProfileAssetCollection-DS2Nh2IQ.js").then((n) => n.n);
522
515
  return ProfileAssetCollection.create({ db: this.db });
523
516
  }
524
517
  async getAssets(relationship) {
@@ -743,7 +736,7 @@ var Profile = class extends SmrtObject {
743
736
  * @returns Array of OIDC identity records
744
737
  */
745
738
  async getOidcIdentities() {
746
- const { OidcIdentityCollection } = await import("./OidcIdentityCollection-BLxSaqJT.js").then((n) => n.r);
739
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-DmllRnCw.js").then((n) => n.r);
747
740
  return await (await OidcIdentityCollection.create(this.options)).findByProfile(this.id);
748
741
  }
749
742
  /**
@@ -756,7 +749,7 @@ var Profile = class extends SmrtObject {
756
749
  * type, but refuses to create or rebind authority.
757
750
  */
758
751
  async linkOidcIdentity(oidcData) {
759
- const { OidcIdentityCollection } = await import("./OidcIdentityCollection-BLxSaqJT.js").then((n) => n.r);
752
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-DmllRnCw.js").then((n) => n.r);
760
753
  return await (await OidcIdentityCollection.create(this.options)).linkToProfile(this, oidcData);
761
754
  }
762
755
  /**
@@ -1158,4 +1151,4 @@ function readRequiredString(row, key) {
1158
1151
  //#endregion
1159
1152
  export { smrtProfilesGenerateBioPrompt as _, Profile as a, OidcProfileEmailReservation as c, coordinateOidcProvisioning as d, isOidcAbortedTransactionError as f, promptMessageOptions as g, normalizeIdentityEmail as h, OidcProfileEmailReservationCollection as i, PROFILE_EMAIL_KEY_BACKFILL_NAME as l, saveOidcRaceArbiter as m, ProfileCollection as n, ProfileType as o, isOidcProvisioningRaceConflict as p, ProfileCollection_exports as r, ProfileType_exports as s, CanonicalPersonProfileError as t, backfillProfileEmailKeys as u };
1160
1153
 
1161
- //# sourceMappingURL=ProfileCollection-DdJ3W4GG.js.map
1154
+ //# sourceMappingURL=ProfileCollection-BOwbNCgG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileCollection-BOwbNCgG.js","names":["tx"],"sources":["../../src/prompts.ts","../../src/auth/normalizeIdentityEmail.ts","../../src/auth/oidcProvisioningCoordinator.ts","../../src/migrations/backfillProfileEmailKeys.ts","../../src/models/OidcProfileEmailReservation.ts","../../src/models/ProfileType.ts","../../src/models/Profile.ts","../../src/collections/OidcProfileEmailReservationCollection.ts","../../src/collections/ProfileCollection.ts"],"sourcesContent":["/**\n * Prompt registrations for the @happyvertical/smrt-profiles package.\n *\n * Prompts are registered at module-load time via `definePrompt()` so that\n * tenant-aware overrides can be applied at call time via `resolvePrompt()`.\n *\n * Mirrors the pattern used by `@happyvertical/smrt-content` (see\n * `content-prompts.ts`) and `@happyvertical/smrt-facts` (see `prompts.ts`).\n */\n\nimport {\n definePrompt,\n type ResolvedPromptAI,\n} from '@happyvertical/smrt-prompts';\n\n// Bio generation only uses non-PII profile fields (name + description).\n// Email is intentionally NOT passed to the AI provider — see review on PR\n// #1209 — to minimize PII exposure. If a downstream tenant needs email in\n// the bio, they can override the template via PromptOverride.\nexport const smrtProfilesGenerateBioPrompt = definePrompt({\n key: 'smrtProfiles.profile.generateBio',\n template: `Write a short, professional bio for this person.\n\nProfile name: {profileName}\nProfile description: {profileDescription}\n\nReturn only the bio text, with no commentary or surrounding quotation marks.`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport function promptMessageOptions(ai: ResolvedPromptAI) {\n return {\n ...(ai.params || {}),\n ...(ai.model ? { model: ai.model } : {}),\n ...(typeof ai.temperature === 'number'\n ? { temperature: ai.temperature }\n : {}),\n ...(typeof ai.maxTokens === 'number' ? { maxTokens: ai.maxTokens } : {}),\n };\n}\n","/**\n * Canonicalize an email used as an external identity key.\n *\n * Keep this in application code: SQL `trim()` and `lower()` have\n * adapter-specific whitespace and Unicode behavior.\n */\nexport function normalizeIdentityEmail(email: string): string {\n const normalized = email.trim().toLowerCase();\n if (!normalized) {\n throw new Error('Identity email normalization requires a non-blank email.');\n }\n return normalized;\n}\n","import {\n isAbortedTransactionError,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport {\n BackfillTableUnavailableError,\n BackfillTracker,\n} from '@happyvertical/smrt-core/migrations';\nimport type { getDatabase } from '@happyvertical/sql';\n\ntype DatabaseInterface = Awaited<ReturnType<typeof getDatabase>>;\n\nconst provisioningLocks = new Map<\n string | object,\n Map<string, Promise<void>>\n>();\nconst sqliteRetryLocks = new Map<string | object, Promise<void>>();\nlet savepointSequence = 0;\n\nconst OIDC_RACE_FIELD_NAMES = new Set([\n 'email_key',\n 'emailKey',\n 'identity_key',\n 'identityKey',\n 'profile_id',\n 'profileId',\n]);\nconst OIDC_RACE_MESSAGE_PATTERNS = [\n /oidc_identities[._].*identity_key/iu,\n /oidc_identities_identity_key/iu,\n /oidc_profile_email_reservations[._].*(?:email_key|profile_id)/iu,\n /profile_types_slug_context_meta_type/iu,\n];\n\nclass OidcRaceArbiterConflict extends Error {\n constructor(cause: unknown) {\n super('An OIDC provisioning race arbiter reported a unique conflict.', {\n cause,\n });\n this.name = 'OidcRaceArbiterConflict';\n }\n}\n\nclass SavepointUnavailableError extends Error {\n constructor(cause: unknown) {\n super('OIDC provisioning could not start a transaction savepoint.', {\n cause,\n });\n this.name = 'SavepointUnavailableError';\n }\n}\n\n/** Shared transaction and concurrency policy for OIDC provisioning. */\nexport interface OidcProvisioningCoordinatorOptions<T> {\n /** Root or transaction-bound database used for every provisioning write. */\n db: DatabaseInterface;\n /**\n * Stable keys used for local serialization. Supply both the exact\n * issuer/subject key and normalized email when available.\n */\n lockKeys: readonly string[];\n /** Package-specific durable race-arbiter classifier. */\n isRaceConflict: (error: unknown) => boolean;\n /** Package-specific transaction failure mapping. */\n createTransactionError: (message: string, cause?: unknown) => Error;\n /** Package-specific terminal concurrency failure mapping. */\n createConcurrencyError: (cause?: unknown) => Error;\n /** Provision atomically using the supplied transaction-bound handle. */\n provision: (tx: DatabaseInterface) => Promise<T>;\n /**\n * Rehydrate root-owned results after commit so models do not retain a\n * released transaction client. Omit for non-model results.\n */\n rebindRootResult?: (result: T, rootDb: DatabaseInterface) => Promise<T>;\n}\n\n/**\n * Coordinate one OIDC provisioning operation across adapters.\n *\n * Root adapters must expose `beginTransaction`. Already-bound adapters must\n * support savepoints. An adapter that exposes only `transaction()` is\n * intentionally ambiguous and fails closed instead of risking a nested\n * transaction that could roll back its caller's work.\n */\nexport async function coordinateOidcProvisioning<T>(\n options: OidcProvisioningCoordinatorOptions<T>,\n): Promise<T> {\n const rootBackfillTableReady =\n typeof options.db.beginTransaction === 'function';\n return withProvisioningLocks(options.db, options.lockKeys, async () => {\n // Establish the shared backfill table outside the provisioning\n // transaction but inside the coordinator locks. Transaction-bound callers\n // are handled below via savepoints and must not leak DDL into their\n // caller's transaction, and SQLite and DuckDB root handles multiplex one\n // native connection: a statement issued here while a concurrent flow\n // holds that connection's transaction races it, and DuckDB then fails the\n // in-flight prepared statement outright (#2352).\n if (rootBackfillTableReady) {\n await new BackfillTracker({ db: options.db }).initialize();\n }\n const result = await retryProvisioning(options, () =>\n withProvisioningTransaction(\n options.db,\n (tx) => {\n // Marker reads inside provisioning transactions must never run DDL.\n // Root callers inherit a verified durable initialization; already-\n // bound callers may read an existing table but fail closed if it is\n // absent because no root handle is available for safe recovery.\n if (rootBackfillTableReady) {\n BackfillTracker.inheritInitialization(tx, options.db);\n } else {\n BackfillTracker.requireExistingTable(tx);\n }\n return options.provision(tx);\n },\n options.createTransactionError,\n ),\n );\n return rootBackfillTableReady && options.rebindRootResult\n ? options.rebindRootResult(result, options.db)\n : result;\n });\n}\n\nasync function withProvisioningLocks<T>(\n db: DatabaseInterface,\n lockKeys: readonly string[],\n callback: () => Promise<T>,\n): Promise<T> {\n // SQLite and DuckDB root handles cannot safely overlap transactions, even\n // when the identities are unrelated. Their database-scoped adapter lock is\n // acquired before the narrower identity/email locks shared across handles.\n const keys = [\n ...new Set([\n ...(!isPostgresDatabase(db) || typeof db.beginTransaction !== 'function'\n ? ['adapter-transaction']\n : []),\n ...lockKeys,\n ]),\n ].sort();\n const acquire = (index: number): Promise<T> =>\n index >= keys.length\n ? callback()\n : withProvisioningLock(db, keys[index], () => acquire(index + 1));\n return acquire(0);\n}\n\n/**\n * Detect an adapter error caused by an aborted transaction.\n *\n * Reduced to the framework contract in #2366. The heuristic this replaced\n * matched a bare `/transaction.*aborted/` against every message in the chain,\n * which would misclassify a genuine foreign-key or check violation whose text\n * happened to mention a transaction. Core now recognizes PostgreSQL's\n * `25P02 in_failed_sql_transaction` from the driver's own SQLSTATE, whichever\n * layer wrapped it.\n *\n * Kept as a named export because it is part of this package's provisioning\n * API surface; the body is now a single delegation.\n */\nexport function isOidcAbortedTransactionError(error: unknown): boolean {\n return isAbortedTransactionError(error);\n}\n\nexport interface OidcProvisioningRaceClassifierOptions {\n /** Package-specific database constraint messages. */\n messagePatterns?: readonly RegExp[];\n}\n\nfunction testRaceMessagePattern(pattern: RegExp, message: string): boolean {\n // Callers may supply stateful global/sticky expressions. Do not let a prior\n // classification change the result of the next provisioning attempt.\n pattern.lastIndex = 0;\n try {\n return pattern.test(message);\n } finally {\n pattern.lastIndex = 0;\n }\n}\n\n/** Classify only the durable constraints used to converge OIDC retries. */\nexport function isOidcProvisioningRaceConflict(\n error: unknown,\n options: OidcProvisioningRaceClassifierOptions = {},\n): boolean {\n if (isOidcAbortedTransactionError(error)) return true;\n const pending: unknown[] = [error];\n const seen = new Set<unknown>();\n const messagePatterns = [\n ...OIDC_RACE_MESSAGE_PATTERNS,\n ...(options.messagePatterns ?? []),\n ];\n while (pending.length > 0) {\n const current = pending.pop();\n if (!current || typeof current !== 'object' || seen.has(current)) continue;\n seen.add(current);\n if (current instanceof OidcRaceArbiterConflict) return true;\n if (\n current instanceof Error &&\n current.name === 'CanonicalPersonProfileError' &&\n (current as Error & { code?: unknown }).code === 'reservation_conflict'\n ) {\n return true;\n }\n if (\n current instanceof ValidationError &&\n current.code === 'VALIDATION_UNIQUE_CONSTRAINT' &&\n OIDC_RACE_FIELD_NAMES.has(String(current.details?.fieldName ?? ''))\n ) {\n return true;\n }\n if (\n current instanceof Error &&\n messagePatterns.some((pattern) =>\n testRaceMessagePattern(pattern, current.message),\n )\n ) {\n return true;\n }\n const details = current as {\n cause?: unknown;\n context?: unknown;\n details?: unknown;\n originalError?: unknown;\n };\n pending.push(\n details.cause,\n details.context,\n details.details,\n details.originalError,\n );\n if (current instanceof AggregateError) pending.push(...current.errors);\n }\n return false;\n}\n\n/** Wrap a known OIDC arbiter write so only its unique failure is retryable. */\nexport async function saveOidcRaceArbiter<T>(\n operation: () => Promise<T>,\n): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n if (\n (error instanceof ValidationError &&\n error.code === 'VALIDATION_UNIQUE_CONSTRAINT') ||\n isOidcAbortedTransactionError(error)\n ) {\n throw new OidcRaceArbiterConflict(error);\n }\n throw error;\n }\n}\n\nasync function withProvisioningLock<T>(\n db: DatabaseInterface,\n lockKey: string,\n callback: () => Promise<T>,\n): Promise<T> {\n // Non-Postgres handles for the same URL share a local lock. Durable unique\n // keys remain the cross-process and PostgreSQL race arbiters.\n const databaseKey = getDatabaseLockKey(db);\n const locks = provisioningLocks.get(databaseKey) ?? new Map();\n provisioningLocks.set(databaseKey, locks);\n const previous = locks.get(lockKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const queued = previous.then(() => current);\n locks.set(lockKey, queued);\n await previous;\n try {\n return await callback();\n } finally {\n release();\n if (locks.get(lockKey) === queued) locks.delete(lockKey);\n if (locks.size === 0) provisioningLocks.delete(databaseKey);\n }\n}\n\nfunction getDatabaseLockKey(db: DatabaseInterface): string | object {\n const url = db.url;\n if (\n isPostgresDatabase(db) &&\n typeof db.beginTransaction !== 'function' &&\n db.client !== null &&\n (typeof db.client === 'object' || typeof db.client === 'function')\n ) {\n return db.client;\n }\n return url && !isPostgresDatabase(db) ? url : (db as object);\n}\n\nfunction isPostgresDatabase(db: DatabaseInterface): boolean {\n return /^postgres(?:ql)?:/iu.test(db.url ?? '');\n}\n\nasync function retryProvisioning<T>(\n options: OidcProvisioningCoordinatorOptions<T>,\n callback: () => Promise<T>,\n): Promise<T> {\n let serializeSqliteRetry = false;\n for (let attempt = 0; attempt < 8; attempt += 1) {\n try {\n return await (serializeSqliteRetry\n ? withSqliteRetryLock(options.db, callback)\n : callback());\n } catch (error) {\n if (error instanceof BackfillTableUnavailableError) {\n if (typeof options.db.beginTransaction === 'function' && attempt < 7) {\n BackfillTracker.invalidateInitialization(options.db);\n await new BackfillTracker({ db: options.db }).initialize();\n continue;\n }\n throw options.createTransactionError(\n 'Transaction-bound OIDC provisioning requires an existing _smrt_backfills table; pass the root database so SMRT can initialize it safely.',\n error,\n );\n }\n const sqliteBusy = isSqliteBusyError(error);\n const postgresTransactionRetry = isPostgresTransactionRetryError(error);\n const raceConflict = options.isRaceConflict(error);\n if (!sqliteBusy && !postgresTransactionRetry && !raceConflict)\n throw error;\n if (sqliteBusy && attempt < 7) {\n serializeSqliteRetry = true;\n await waitForRetry(Math.min(100 * 2 ** attempt, 1_000));\n continue;\n }\n if (postgresTransactionRetry && attempt < 7) {\n await waitForRetry(Math.min(25 * 2 ** attempt, 500));\n continue;\n }\n if (raceConflict && attempt === 0) continue;\n throw options.createConcurrencyError(error);\n }\n }\n throw options.createConcurrencyError();\n}\n\nfunction isPostgresTransactionRetryError(error: unknown): boolean {\n const pending: unknown[] = [error];\n const seen = new Set<unknown>();\n const messagePattern =\n /deadlock detected|could not serialize access|serialization failure/iu;\n while (pending.length > 0) {\n const current = pending.pop();\n if (!current || typeof current !== 'object' || seen.has(current)) continue;\n seen.add(current);\n const details = current as {\n cause?: unknown;\n code?: unknown;\n context?: unknown;\n originalError?: unknown;\n };\n if (details.code === '40P01' || details.code === '40001') return true;\n if (current instanceof Error && messagePattern.test(current.message)) {\n return true;\n }\n pending.push(details.cause, details.context, details.originalError);\n if (current instanceof AggregateError) pending.push(...current.errors);\n }\n return false;\n}\n\nasync function withSqliteRetryLock<T>(\n db: DatabaseInterface,\n callback: () => Promise<T>,\n): Promise<T> {\n const key = db.url || (db as object);\n const previous = sqliteRetryLocks.get(key) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const queued = previous.then(() => current);\n sqliteRetryLocks.set(key, queued);\n await previous;\n try {\n return await callback();\n } finally {\n release();\n if (sqliteRetryLocks.get(key) === queued) sqliteRetryLocks.delete(key);\n }\n}\n\nfunction isSqliteBusyError(error: unknown): boolean {\n const pending: unknown[] = [error];\n const seen = new Set<unknown>();\n const busyPattern =\n /SQLITE_(?:BUSY|LOCKED)|database(?: table)? is locked|cannot (?:commit transaction|release savepoint) - SQL statements in progress/iu;\n while (pending.length > 0) {\n const current = pending.pop();\n if (typeof current === 'string') {\n if (busyPattern.test(current)) return true;\n continue;\n }\n if (!current || typeof current !== 'object' || seen.has(current)) continue;\n seen.add(current);\n if (current instanceof Error) {\n if (busyPattern.test(current.message)) return true;\n pending.push((current as { cause?: unknown }).cause);\n if (current instanceof AggregateError) pending.push(...current.errors);\n }\n const details = current as {\n context?: unknown;\n details?: unknown;\n originalError?: unknown;\n };\n pending.push(details.context, details.details, details.originalError);\n }\n return false;\n}\n\nasync function waitForRetry(milliseconds: number): Promise<void> {\n await new Promise<void>((resolve) => setTimeout(resolve, milliseconds));\n}\n\nasync function withProvisioningTransaction<T>(\n db: DatabaseInterface,\n callback: (tx: DatabaseInterface) => Promise<T>,\n createTransactionError: (message: string, cause?: unknown) => Error,\n): Promise<T> {\n if (typeof db.beginTransaction === 'function') {\n if (db.transaction) return db.transaction((tx) => callback(tx));\n const tx = await db.beginTransaction();\n try {\n const result = await callback(tx);\n await tx.commit();\n return result;\n } catch (error) {\n try {\n if (tx.isActive()) await tx.rollback();\n } catch (rollbackError) {\n throw createTransactionError(\n 'OIDC provisioning could not roll back its root transaction.',\n new AggregateError([error, rollbackError]),\n );\n }\n throw error;\n }\n }\n\n try {\n return await withSavepoint(db, () => callback(db), createTransactionError);\n } catch (error) {\n if (!(error instanceof SavepointUnavailableError)) throw error;\n throw createTransactionError(\n 'OIDC provisioning requires a root database or a transaction handle that supports savepoints.',\n error.cause,\n );\n }\n}\n\nasync function withSavepoint<T>(\n db: DatabaseInterface,\n callback: () => Promise<T>,\n createTransactionError: (message: string, cause?: unknown) => Error,\n): Promise<T> {\n savepointSequence = (savepointSequence + 1) % Number.MAX_SAFE_INTEGER;\n const savepoint = `smrt_oidc_${savepointSequence.toString(36)}`;\n try {\n await db.query(`SAVEPOINT ${savepoint}`);\n } catch (error) {\n throw new SavepointUnavailableError(error);\n }\n\n try {\n const result = await callback();\n await db.query(`RELEASE SAVEPOINT ${savepoint}`);\n return result;\n } catch (error) {\n try {\n await db.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);\n await db.query(`RELEASE SAVEPOINT ${savepoint}`);\n } catch (rollbackError) {\n throw createTransactionError(\n 'OIDC provisioning could not roll back its transaction savepoint.',\n new AggregateError([error, rollbackError]),\n );\n }\n throw error;\n }\n}\n","import { BackfillTracker } from '@happyvertical/smrt-core/migrations';\nimport type { getDatabase } from '@happyvertical/sql';\nimport { normalizeIdentityEmail } from '../auth/normalizeIdentityEmail.js';\n\ntype DatabaseInterface = Awaited<ReturnType<typeof getDatabase>>;\n\nexport const PROFILE_EMAIL_KEY_BACKFILL_NAME =\n '@happyvertical/smrt-profiles:profile-email-keys:v1';\n\nexport interface BackfillProfileEmailKeysResult {\n updated: number;\n}\n\n/**\n * Populate adapter-independent Profile email keys after the schema migration.\n *\n * Run this from one deploy process after legacy writers are stopped or\n * upgraded. Every read and update runs in one transaction, and repeats are a\n * no-op.\n */\nexport async function backfillProfileEmailKeys(\n db: DatabaseInterface,\n): Promise<BackfillProfileEmailKeysResult> {\n if (!db.transaction) {\n throw new Error(\n 'Profile email-key backfill requires a root database with transaction().',\n );\n }\n\n const tracker = new BackfillTracker({ db });\n await tracker.initialize();\n\n return db.transaction(async (tx) => {\n BackfillTracker.inheritInitialization(tx, db);\n const result = await tx.query(\n 'SELECT id, email, email_key FROM profiles ORDER BY id',\n );\n const updates: Array<{ emailKey: string | null; id: string }> = [];\n\n for (const row of result.rows) {\n const id = typeof row.id === 'string' ? row.id : '';\n if (!id) {\n throw new Error(\n 'Profile email-key backfill found a row without an id.',\n );\n }\n const email = typeof row.email === 'string' ? row.email : '';\n const emailKey = email.trim() ? normalizeIdentityEmail(email) : null;\n const storedKey =\n typeof row.email_key === 'string' ? row.email_key : null;\n if (storedKey !== emailKey) updates.push({ emailKey, id });\n }\n\n for (const update of updates) {\n await tx.query(\n 'UPDATE profiles SET email_key = ? WHERE id = ?',\n update.emailKey,\n update.id,\n );\n }\n\n await new BackfillTracker({ db: tx }).recordApplied(\n PROFILE_EMAIL_KEY_BACKFILL_NAME,\n {\n description: 'Canonical Profile identity email keys are current.',\n packageName: '@happyvertical/smrt-profiles',\n },\n );\n\n return { updated: updates.length };\n });\n}\n","import {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\n\nexport interface OidcProfileEmailReservationOptions extends SmrtObjectOptions {\n emailKey?: string;\n profileId?: string;\n}\n\n/** Private database arbiter for canonical OIDC email provisioning races. */\n@smrt({\n tableName: 'oidc_profile_email_reservations',\n api: false,\n mcp: false,\n cli: false,\n})\nexport class OidcProfileEmailReservation extends SmrtObject {\n @foreignKey('Profile', { required: true, unique: true })\n profileId?: string;\n\n @field({ type: 'text', required: true, unique: true, readonly: true })\n emailKey: string = '';\n\n constructor(options: OidcProfileEmailReservationOptions = {}) {\n super(options);\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.emailKey !== undefined) this.emailKey = options.emailKey;\n }\n}\n","/**\n * ProfileType model - Lookup table defining profile types\n *\n * Represents the nature of a profile (e.g., 'human', 'org', 'robot').\n * Uses UUID primary key with unique slug for human-readable lookups.\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface ProfileTypeOptions extends SmrtObjectOptions {\n slug?: string;\n name?: string;\n description?: string;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class ProfileType extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n // id: UUID (auto-generated by SmrtObject)\n // slug is inherited from SmrtObject (auto-generated from name)\n @field({ required: true })\n name: string = '';\n\n description?: string;\n\n constructor(options: ProfileTypeOptions = {}) {\n super(options);\n if (options.name) this.name = options.name;\n if (options.description !== undefined)\n this.description = options.description;\n }\n\n /**\n * Convenience method for slug-based lookup\n *\n * @param slug - The slug to search for\n * @returns ProfileType instance or null if not found\n */\n static async getBySlug(_slug: string): Promise<ProfileType | null> {\n // Will be auto-implemented by SMRT\n return null;\n }\n}\n","/**\n * Profile model - Core entity representing any profile type\n *\n * Central table holding all primary entities with type, email, name, and description.\n * Uses UUID primary key with relationships to ProfileType for classification.\n */\n\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport {\n assertValidOwnedAssetRelationship,\n assertValidOwnedAssetSortOrder,\n resolveOwnedAssetsById,\n} from '@happyvertical/smrt-assets';\n\nimport {\n field,\n foreignKey,\n oneToMany,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { resolvePrompt } from '@happyvertical/smrt-prompts';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { normalizeIdentityEmail } from '../auth/normalizeIdentityEmail';\nimport {\n promptMessageOptions,\n smrtProfilesGenerateBioPrompt,\n} from '../prompts';\nimport type { ApiKey, GenerateKeyResult } from './ApiKey';\nimport type { AuditLog } from './AuditLog';\nimport type { NostrIdentity } from './NostrIdentity';\nimport type { OidcIdentity } from './OidcIdentity';\nimport type { ProfileMetadata } from './ProfileMetadata';\nimport type { ProfileRelationship } from './ProfileRelationship';\nimport { ProfileType } from './ProfileType';\n\nexport interface ProfileOptions extends SmrtObjectOptions {\n typeId?: string;\n email?: string;\n name?: string;\n description?: string;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: true,\n})\nexport class Profile extends SmrtObject {\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n // id: UUID (auto-generated by SmrtObject)\n @foreignKey('ProfileType', { required: true })\n typeId?: string; // References ProfileType.id\n\n @field({ unique: true })\n email?: string; // Optional email address\n\n /** Adapter-independent identity lookup key derived from email on save. */\n @field({ type: 'text', nullable: true, indexed: true, readonly: true })\n emailKey: string | null = null;\n\n @field({ required: true })\n name: string = ''; // Display name\n\n description?: string; // Short bio or description\n\n // Relationships (not stored as columns)\n @oneToMany('ProfileMetadata')\n metadata: ProfileMetadata[] = [];\n\n // ProfileRelationship declares multiple foreign keys back to Profile\n // (fromProfileId / toProfileId / contextProfileId), so each oneToMany names\n // its inverse side explicitly. This both disambiguates `loadRelatedMany`\n // and gives the R10-generated `getRelationshipsFrom()` / `getRelationshipsTo()`\n // accessors the correct inverse foreign key.\n @oneToMany('ProfileRelationship', { foreignKey: 'fromProfileId' })\n relationshipsFrom: ProfileRelationship[] = [];\n\n @oneToMany('ProfileRelationship', { foreignKey: 'toProfileId' })\n relationshipsTo: ProfileRelationship[] = [];\n\n constructor(options: ProfileOptions = {}) {\n super(options);\n if (options.typeId !== undefined) this.typeId = options.typeId;\n if (options.email !== undefined) this.email = options.email;\n if (options.name) this.name = options.name;\n if (options.description !== undefined)\n this.description = options.description;\n }\n\n /** Keep the durable identity key derived from the public email field. */\n override async save(): Promise<this> {\n this.emailKey = this.email?.trim()\n ? normalizeIdentityEmail(this.email)\n : null;\n return super.save();\n }\n\n /**\n * Get the profile type slug for this profile\n *\n * @returns The slug of the profile type\n */\n async getTypeSlug(): Promise<string> {\n const type = await this.loadRelated('typeId');\n return type?.slug || '';\n }\n\n /**\n * Set the profile type by slug\n *\n * @param slug - The slug of the profile type\n * @throws Error if profile type not found\n */\n async setTypeBySlug(slug: string): Promise<void> {\n const type = await ProfileType.getBySlug(slug);\n if (!type) throw new Error(`Profile type '${slug}' not found`);\n this.typeId = type.id as string;\n }\n\n /**\n * Add metadata to this profile\n *\n * @param metafieldSlug - The slug of the metafield\n * @param value - The value to set\n */\n async addMetadata(metafieldSlug: string, value: unknown): Promise<void> {\n const { ProfileMetafieldCollection } = await import(\n '../collections/ProfileMetafieldCollection'\n );\n const { ProfileMetadataCollection } = await import(\n '../collections/ProfileMetadataCollection'\n );\n\n // Get or create metafield collection\n const metafieldCollection = await ProfileMetafieldCollection.create(\n this.options,\n );\n\n // Find the metafield by slug\n const metafield = await metafieldCollection.getBySlug(metafieldSlug);\n if (!metafield) {\n throw new Error(`Metafield '${metafieldSlug}' not found`);\n }\n\n // Validate the value\n await metafield.validateValue(value);\n\n // Get or create metadata collection\n const metadataCollection = await ProfileMetadataCollection.create(\n this.options,\n );\n\n // Check if metadata already exists\n const existing = await metadataCollection.list({\n where: { profileId: this.id, metafieldId: metafield.id },\n limit: 1,\n });\n\n if (existing.length > 0) {\n // Update existing\n const metadata = existing[0];\n metadata.value = String(value);\n await metadata.save();\n } else {\n // Create new\n if (!this.id || !metafield.id) {\n throw new Error(\n 'Profile.addMetadata requires a persisted profile and metafield (missing id)',\n );\n }\n const metadata = await metadataCollection.create({\n profileId: this.id,\n metafieldId: metafield.id,\n value: String(value),\n });\n await metadata.save();\n }\n }\n\n /**\n * Get all metadata for this profile as key-value object\n *\n * @returns Object with metafield slugs as keys\n */\n async getMetadata(): Promise<Record<string, string>> {\n const { ProfileMetadataCollection } = await import(\n '../collections/ProfileMetadataCollection'\n );\n\n const metadataCollection = await ProfileMetadataCollection.create(\n this.options,\n );\n\n return await metadataCollection.getMetadataObject(this.id as string);\n }\n\n /**\n * Update multiple metadata values\n *\n * @param metadata - Object with metafield slugs as keys and values\n */\n async updateMetadata(metadata: Record<string, unknown>): Promise<void> {\n for (const [metafieldSlug, value] of Object.entries(metadata)) {\n await this.addMetadata(metafieldSlug, value);\n }\n }\n\n /**\n * Remove metadata by metafield slug\n *\n * @param metafieldSlug - The slug of the metafield to remove\n */\n async removeMetadata(metafieldSlug: string): Promise<void> {\n const { ProfileMetafieldCollection } = await import(\n '../collections/ProfileMetafieldCollection'\n );\n const { ProfileMetadataCollection } = await import(\n '../collections/ProfileMetadataCollection'\n );\n\n const metafieldCollection = await ProfileMetafieldCollection.create(\n this.options,\n );\n\n const metafield = await metafieldCollection.getBySlug(metafieldSlug);\n if (!metafield) {\n throw new Error(`Metafield '${metafieldSlug}' not found`);\n }\n\n const metadataCollection = await ProfileMetadataCollection.create(\n this.options,\n );\n\n const existing = await metadataCollection.list({\n where: { profileId: this.id, metafieldId: metafield.id },\n limit: 1,\n });\n\n if (existing.length > 0) {\n await existing[0].delete();\n }\n }\n\n private async getProfileAssetCollection() {\n const { ProfileAssetCollection } = await import(\n '../collections/ProfileAssetCollection'\n );\n return ProfileAssetCollection.create({ db: this.db });\n }\n async getAssets(relationship?: string): Promise<Asset[]> {\n if (!this.id) {\n return [];\n }\n\n const profileAssets = await this.getProfileAssetCollection();\n const linkedAssets = await profileAssets.byLeft(\n this.id,\n relationship ? { relationship } : {},\n );\n\n return resolveOwnedAssetsById(\n this.db,\n linkedAssets.map((link) => link.assetId),\n this.tenantId,\n );\n }\n\n async addAsset(\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n if (!this.id || !asset.id) {\n throw new Error('Cannot associate unsaved profile or asset');\n }\n\n assertValidOwnedAssetRelationship(relationship);\n assertValidOwnedAssetSortOrder(sortOrder);\n\n const profileAssets = await this.getProfileAssetCollection();\n await profileAssets.attach(this.id, asset.id, {\n relationship,\n sortOrder,\n tenantId: this.tenantId,\n });\n }\n\n async removeAsset(assetId: string, relationship?: string): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const profileAssets = await this.getProfileAssetCollection();\n await profileAssets.detach(\n this.id,\n assetId,\n relationship ? { relationship } : {},\n );\n }\n\n /**\n * Add a relationship to another profile\n *\n * @param toProfile - The target profile\n * @param relationshipSlug - The type of relationship\n * @param contextProfile - Optional context profile for tertiary relationships\n */\n async addRelationship(\n toProfile: Profile,\n relationshipSlug: string,\n contextProfile?: Profile,\n ): Promise<void> {\n const { ProfileRelationshipTypeCollection } = await import(\n '../collections/ProfileRelationshipTypeCollection'\n );\n const { ProfileRelationshipCollection } = await import(\n '../collections/ProfileRelationshipCollection'\n );\n const { ProfileRelationshipType } = await import(\n './ProfileRelationshipType'\n );\n\n // Get relationship type\n const relationshipTypeCollection =\n await ProfileRelationshipTypeCollection.create(this.options);\n\n const relationshipType =\n await relationshipTypeCollection.getBySlug(relationshipSlug);\n if (!relationshipType) {\n throw new Error(`Relationship type '${relationshipSlug}' not found`);\n }\n\n // Check if relationship already exists\n const relationshipCollection = await ProfileRelationshipCollection.create(\n this.options,\n );\n\n const exists = await relationshipCollection.exists(\n this.id as string,\n toProfile.id as string,\n relationshipType.id as string,\n );\n\n if (!exists) {\n // Create the relationship\n const relationship = await relationshipCollection.create({\n fromProfileId: this.id ?? undefined,\n toProfileId: toProfile.id ?? undefined,\n typeId: relationshipType.id ?? undefined,\n contextProfileId: contextProfile?.id ?? undefined,\n });\n await relationship.save();\n\n // Handle reciprocal relationships. A reciprocal handler creates the\n // inverse edge by calling addRelationship() back on `toProfile`. Gating\n // this on `!exists` is what terminates the recursion: the inverse call\n // creates its own edge and re-enters, but by then the original edge\n // already exists, so the handler is skipped and the cycle stops. Firing\n // it unconditionally instead recurses forever (the bundled friend /\n // spouse / partner / colleague / sibling handlers all call back here).\n if (relationshipType.reciprocal) {\n const handler =\n ProfileRelationshipType.getReciprocalHandler(relationshipSlug);\n if (handler) {\n await handler(this, toProfile, contextProfile);\n }\n }\n }\n }\n\n /**\n * Get all relationships for this profile\n *\n * @param options - Filter options (typeSlug, direction)\n * @returns Array of ProfileRelationship instances\n */\n async getRelationships(options?: {\n typeSlug?: string;\n direction?: 'from' | 'to' | 'all';\n }): Promise<ProfileRelationship[]> {\n const { ProfileRelationshipCollection } = await import(\n '../collections/ProfileRelationshipCollection'\n );\n const { ProfileRelationshipTypeCollection } = await import(\n '../collections/ProfileRelationshipTypeCollection'\n );\n\n const relationshipCollection = await ProfileRelationshipCollection.create(\n this.options,\n );\n\n const direction = options?.direction || 'all';\n\n // Get type ID if typeSlug is provided\n let typeId: string | undefined;\n if (options?.typeSlug) {\n const relationshipTypeCollection =\n await ProfileRelationshipTypeCollection.create(this.options);\n\n const relationshipType = await relationshipTypeCollection.getBySlug(\n options.typeSlug,\n );\n typeId = relationshipType?.id ?? undefined;\n }\n\n // Fetch relationships based on direction\n if (direction === 'from') {\n return await relationshipCollection.getFromProfile(\n this.id as string,\n typeId,\n );\n } else if (direction === 'to') {\n return await relationshipCollection.getToProfile(\n this.id as string,\n typeId,\n );\n } else {\n return await relationshipCollection.getForProfile(\n this.id as string,\n typeId,\n );\n }\n }\n\n /**\n * Get related profiles\n *\n * @param relationshipSlug - Optional filter by relationship type slug\n * @returns Array of related Profile instances\n */\n async getRelatedProfiles(relationshipSlug?: string): Promise<Profile[]> {\n const { ProfileCollection } = await import(\n '../collections/ProfileCollection'\n );\n\n const relationships = await this.getRelationships({\n typeSlug: relationshipSlug,\n direction: 'all',\n });\n\n const profileCollection = await ProfileCollection.create(this.options);\n\n const relatedProfiles: Profile[] = [];\n const seenIds = new Set<string>();\n\n for (const relationship of relationships) {\n // Get the other profile (not this one)\n // Convert Field instances to strings for comparison\n const fromId = String(relationship.fromProfileId);\n const toId = String(relationship.toProfileId);\n const thisId = String(this.id);\n const otherId = fromId === thisId ? toId : fromId;\n\n if (!seenIds.has(otherId)) {\n seenIds.add(otherId);\n const profile = await profileCollection.get({ id: otherId });\n if (profile) {\n relatedProfiles.push(profile);\n }\n }\n }\n\n return relatedProfiles;\n }\n\n /**\n * Remove a relationship to another profile\n *\n * @param toProfile - The target profile\n * @param relationshipSlug - The type of relationship to remove\n */\n async removeRelationship(\n toProfile: Profile,\n relationshipSlug: string,\n ): Promise<void> {\n const { ProfileRelationshipTypeCollection } = await import(\n '../collections/ProfileRelationshipTypeCollection'\n );\n const { ProfileRelationshipCollection } = await import(\n '../collections/ProfileRelationshipCollection'\n );\n\n // Get relationship type\n const relationshipTypeCollection =\n await ProfileRelationshipTypeCollection.create(this.options);\n\n const relationshipType =\n await relationshipTypeCollection.getBySlug(relationshipSlug);\n if (!relationshipType) {\n throw new Error(`Relationship type '${relationshipSlug}' not found`);\n }\n\n // Find and delete the relationship\n const relationshipCollection = await ProfileRelationshipCollection.create(\n this.options,\n );\n\n const relationships = await relationshipCollection.list({\n where: {\n fromProfileId: this.id,\n toProfileId: toProfile.id,\n typeId: relationshipType.id,\n },\n });\n\n for (const relationship of relationships) {\n await relationship.delete();\n }\n\n // Handle reciprocal relationships - delete the inverse\n if (relationshipType.reciprocal) {\n const inverseRelationships = await relationshipCollection.list({\n where: {\n fromProfileId: toProfile.id,\n toProfileId: this.id,\n typeId: relationshipType.id,\n },\n });\n\n for (const relationship of inverseRelationships) {\n await relationship.delete();\n }\n }\n }\n\n /**\n * AI-powered: Generate a professional bio for this profile\n *\n * Uses the `smrtProfiles.profile.generateBio` prompt registered via\n * `@happyvertical/smrt-prompts`, allowing tenant- or instance-level\n * overrides of the template, model, and parameters at runtime.\n *\n * @returns Generated bio text\n */\n async generateBio(): Promise<string> {\n // Resolve `db` from either the canonical `db` option or its `persistence`\n // alias. SmrtClass maps `persistence → db` lazily during `initialize()`,\n // so on a freshly-constructed Profile that has not yet been initialized,\n // `this.options.db` may be undefined while `this.options.persistence` is\n // set. Falling back here ensures stored app- and tenant-level prompt\n // overrides in `_smrt_prompt_overrides` are honored on the first call —\n // before `getAiClient()` triggers full initialization further below.\n const db = this.options.db ?? this.options.persistence;\n\n const resolvedPrompt = await resolvePrompt(\n smrtProfilesGenerateBioPrompt.key,\n {\n db,\n tenantId: this.tenantId,\n variables: {\n profileName: this.name || '',\n profileDescription: this.description || '',\n },\n },\n );\n\n const ai = await this.getAiClient();\n const response = await ai.message(\n resolvedPrompt.text,\n promptMessageOptions(resolvedPrompt.ai),\n );\n\n return response.trim();\n }\n\n /**\n * AI-powered: Check if profile matches criteria\n *\n * @param criteria - Criteria to match against\n * @returns True if matches criteria\n */\n async matches(criteria: string): Promise<boolean> {\n return await this.is(criteria);\n }\n\n /**\n * Find profiles by metadata key-value pair\n *\n * @param metafieldSlug - The metafield slug to search\n * @param value - The value to match\n * @returns Array of matching profiles\n */\n static async findByMetadata(\n _metafieldSlug: string,\n _value: unknown,\n ): Promise<Profile[]> {\n // Will be auto-implemented by SMRT\n return [];\n }\n\n /**\n * Find profiles by type slug\n *\n * @param typeSlug - The profile type slug\n * @returns Array of matching profiles\n */\n static async findByType(_typeSlug: string): Promise<Profile[]> {\n // Will be auto-implemented by SMRT\n return [];\n }\n\n /**\n * Find related profiles for a given profile\n *\n * @param profileId - The profile UUID\n * @param relationshipSlug - Optional filter by relationship type\n * @returns Array of related profiles\n */\n static async findRelated(\n _profileId: string,\n _relationshipSlug?: string,\n ): Promise<Profile[]> {\n // Will be auto-implemented by SMRT\n return [];\n }\n\n /**\n * Search profiles by email\n *\n * @param email - The email to search for\n * @returns Profile or null if not found\n */\n static async searchByEmail(_email: string): Promise<Profile | null> {\n // Will be auto-implemented by SMRT\n return null;\n }\n\n // ========================\n // Auth-related methods\n // ========================\n\n /**\n * Get all API keys for this profile\n *\n * @returns Array of API keys\n */\n async getApiKeys(): Promise<ApiKey[]> {\n const { ApiKeyCollection } = await import(\n '../collections/ApiKeyCollection'\n );\n const collection = await ApiKeyCollection.create(this.options);\n return await collection.findByProfile(this.id as string);\n }\n\n /**\n * Get active (non-revoked, non-expired) API keys for this profile\n *\n * @returns Array of active API keys\n */\n async getActiveApiKeys(): Promise<ApiKey[]> {\n const { ApiKeyCollection } = await import(\n '../collections/ApiKeyCollection'\n );\n const collection = await ApiKeyCollection.create(this.options);\n return await collection.findActiveByProfile(this.id as string);\n }\n\n /**\n * Generate a new API key for this profile\n *\n * @param options - Key options (name, scopes, expiration)\n * @returns The generated key (plaintext) and ApiKey record\n */\n async generateApiKey(options: {\n name: string;\n scopes?: string[];\n expiresAt?: Date | null;\n }): Promise<GenerateKeyResult> {\n const { ApiKey } = await import('./ApiKey');\n return await ApiKey.generate(this, {\n ...options,\n db: this.options?.db,\n });\n }\n\n /**\n * Get all OIDC identities linked to this profile\n *\n * @returns Array of OIDC identity records\n */\n async getOidcIdentities(): Promise<OidcIdentity[]> {\n const { OidcIdentityCollection } = await import(\n '../collections/OidcIdentityCollection'\n );\n const collection = await OidcIdentityCollection.create(this.options);\n return await collection.findByProfile(this.id as string);\n }\n\n /**\n * Reuse an existing exact OIDC identity for this unchanged Profile.\n *\n * @param oidcData - OIDC provider data\n * @returns The linked OIDC identity record\n * @deprecated New authentication links require owner-aware transactional\n * provisioning. This compatibility helper may refresh a legacy Profile\n * type, but refuses to create or rebind authority.\n */\n async linkOidcIdentity(oidcData: {\n provider: string;\n issuer: string;\n subject: string;\n email?: string;\n }): Promise<OidcIdentity> {\n const { OidcIdentityCollection } = await import(\n '../collections/OidcIdentityCollection'\n );\n const collection = await OidcIdentityCollection.create(this.options);\n return await collection.linkToProfile(this, oidcData);\n }\n\n /**\n * Get all Nostr identities linked to this profile\n *\n * @returns Array of Nostr identity records\n */\n async getNostrIdentities(): Promise<NostrIdentity[]> {\n const { NostrIdentityCollection } = await import(\n '../collections/NostrIdentityCollection'\n );\n const collection = await NostrIdentityCollection.create(this.options);\n return await collection.findByProfile(this.id as string);\n }\n\n /**\n * Link a new Nostr identity to this profile\n *\n * @param nostrData - Nostr identity data (encrypted keypair)\n * @returns The linked Nostr identity record\n */\n async linkNostrIdentity(nostrData: {\n pubkey: string;\n encryptedPrivkey: string;\n encryptionIv: string;\n encryptionTag: string;\n email: string;\n nip05Username?: string;\n }): Promise<NostrIdentity> {\n const { NostrIdentityCollection } = await import(\n '../collections/NostrIdentityCollection'\n );\n const collection = await NostrIdentityCollection.create(this.options);\n return await collection.linkToProfile(this, nostrData);\n }\n\n /**\n * Get audit logs for actions performed by this profile\n *\n * @param limit - Maximum number of logs to return\n * @returns Array of audit log entries\n */\n async getAuditLogs(limit: number = 50): Promise<AuditLog[]> {\n const { AuditLogCollection } = await import(\n '../collections/AuditLogCollection'\n );\n const collection = await AuditLogCollection.create(this.options);\n return await collection.getRecentActivity(this.id as string, limit);\n }\n\n /**\n * Record an audit log entry for an action by this profile\n *\n * @param options - Audit log options\n * @returns The created audit log entry\n */\n async recordAction(options: {\n action: string;\n resourceType: string;\n resourceId: string;\n source?: 'web' | 'cli' | 'ci' | 'webhook' | 'mcp';\n metadata?: Record<string, unknown>;\n onBehalfOf?: Profile | null;\n }): Promise<AuditLog> {\n const { AuditLogCollection } = await import(\n '../collections/AuditLogCollection'\n );\n const collection = await AuditLogCollection.create(this.options);\n return await collection.record({\n profile: this,\n ...options,\n });\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { OidcProfileEmailReservation } from '../models/OidcProfileEmailReservation';\n\n/** Internal collection for canonical OIDC email reservations. */\nexport class OidcProfileEmailReservationCollection extends SmrtCollection<OidcProfileEmailReservation> {\n static readonly _itemClass = OidcProfileEmailReservation;\n}\n","/**\n * ProfileCollection - Collection manager for Profile objects\n *\n * Provides advanced querying and batch operations for Profile entities.\n */\n\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport {\n addOwnedAssetFromCollection,\n getOwnedAssetsFromCollection,\n removeOwnedAssetFromCollection,\n} from '@happyvertical/smrt-assets';\nimport { SmrtCollection, ValidationError } from '@happyvertical/smrt-core';\nimport { BackfillTracker } from '@happyvertical/smrt-core/migrations';\nimport {\n queryGlobal,\n queryWithGlobals,\n withSystemContext,\n} from '@happyvertical/smrt-tenancy';\nimport type { getDatabase } from '@happyvertical/sql';\nimport { normalizeIdentityEmail } from '../auth/normalizeIdentityEmail';\nimport { isOidcAbortedTransactionError } from '../auth/oidcProvisioningCoordinator';\nimport { PROFILE_EMAIL_KEY_BACKFILL_NAME } from '../migrations/backfillProfileEmailKeys.js';\nimport { OidcProfileEmailReservation } from '../models/OidcProfileEmailReservation';\nimport { Profile } from '../models/Profile';\nimport { OidcProfileEmailReservationCollection } from './OidcProfileEmailReservationCollection';\n\nconst PERSON_META_TYPES = new Set([\n '@happyvertical/smrt-profiles:Person',\n 'Person',\n]);\n\ntype DatabaseInterface = Awaited<ReturnType<typeof getDatabase>>;\n\nexport type CanonicalPersonProfileErrorCode =\n | 'ambiguous_email'\n | 'email_key_backfill_required'\n | 'email_mismatch'\n | 'missing_profile'\n | 'non_person'\n | 'reservation_conflict'\n | 'tenant_scoped';\n\n/** A Profile cannot safely represent one global human identity. */\nexport class CanonicalPersonProfileError extends Error {\n constructor(\n readonly code: CanonicalPersonProfileErrorCode,\n message: string,\n ) {\n super(message);\n this.name = 'CanonicalPersonProfileError';\n }\n}\n\ninterface CanonicalProfileRow extends Record<string, unknown> {\n _meta_type?: unknown;\n email?: unknown;\n email_key?: unknown;\n id?: unknown;\n tenant_id?: unknown;\n}\n\nexport class ProfileCollection extends SmrtCollection<Profile> {\n static readonly _itemClass = Profile;\n private emailKeysReadyPromise: Promise<void> | null = null;\n\n /**\n * Find a profile by email address\n *\n * @param email - The email address to search for\n * @returns The matching profile or null\n */\n async findByEmail(email: string): Promise<Profile | null> {\n const normalizedEmail = normalizeIdentityEmail(email);\n const profiles = await this.list({\n where: { email: normalizedEmail },\n limit: 1,\n });\n return profiles[0] ?? null;\n }\n\n /**\n * Resolve one unambiguous global Person by normalized email.\n *\n * Unlike `findByEmail()`, this identity-boundary helper deliberately reads\n * across tenant scopes and fails closed when any matching row is\n * tenant-scoped, is not a Person STI row, or when more than one row matches\n * case-insensitively. It is intended for verified external identities.\n */\n async findUniqueGlobalPersonByEmail(email: string): Promise<Profile | null> {\n const normalizedEmail = normalizeIdentityEmail(email);\n const rows = await this.loadCanonicalEmailRows(normalizedEmail);\n\n if (rows.length === 0) return null;\n this.assertCanonicalRows(rows, normalizedEmail);\n return this.requireHydratedProfile(readRequiredString(rows[0], 'id'));\n }\n\n /**\n * Validate and hydrate a supplied canonical Profile.\n *\n * The Profile must be the sole case-insensitive match for its stored email.\n * When `email` is provided, that address must also match the stored email.\n */\n async requireCanonicalGlobalPerson(\n profileId: string,\n email?: string,\n ): Promise<Profile> {\n const db = this.requireDatabase();\n await this.ensureEmailKeysReady();\n const result = await withSystemContext(() =>\n db.query(\n `SELECT id, tenant_id, _meta_type, email, email_key\n FROM profiles\n WHERE id = ?\n LIMIT 1`,\n profileId,\n ),\n );\n const row = result.rows[0] as CanonicalProfileRow | undefined;\n\n if (!row) {\n throw new CanonicalPersonProfileError(\n 'missing_profile',\n `Profile ${profileId} does not exist.`,\n );\n }\n\n this.assertRowEmailKeyCurrent(row);\n this.assertCanonicalRows([row]);\n\n const storedEmail = readString(row, 'email');\n const normalizedEmail =\n email !== undefined\n ? normalizeIdentityEmail(email)\n : storedEmail\n ? normalizeIdentityEmail(storedEmail)\n : undefined;\n if (normalizedEmail !== undefined) {\n const matches = await this.loadCanonicalEmailRows(normalizedEmail);\n this.assertCanonicalRows(matches, normalizedEmail);\n if (\n matches.length !== 1 ||\n readRequiredString(matches[0], 'id') !== profileId\n ) {\n throw new CanonicalPersonProfileError(\n 'email_mismatch',\n `Profile ${profileId} is not the unique global Person for ${normalizedEmail}.`,\n );\n }\n }\n\n return this.requireHydratedProfile(profileId);\n }\n\n /**\n * Reserve the normalized email for a previously validated canonical Person.\n *\n * The unique stored key turns a concurrent OIDC first-login race into a\n * retryable database conflict. Legacy Profiles remain unaffected until an\n * identity boundary safely claims them.\n */\n async reserveCanonicalIdentityEmail(\n profileId: string,\n email?: string,\n ): Promise<Profile> {\n const profile = await this.requireCanonicalGlobalPerson(profileId, email);\n const normalizedEmail =\n email !== undefined\n ? normalizeIdentityEmail(email)\n : profile.email?.trim()\n ? normalizeIdentityEmail(profile.email)\n : null;\n const db = this.requireDatabase();\n const reservations = await OidcProfileEmailReservationCollection.create({\n db,\n });\n const byProfile = await reservations.list({\n where: { profileId },\n limit: 2,\n });\n if (byProfile.length > 1) {\n throw new CanonicalPersonProfileError(\n 'ambiguous_email',\n `Multiple canonical identity reservations exist for Profile ${profileId}.`,\n );\n }\n if (normalizedEmail === null) {\n await byProfile[0]?.delete();\n return profile;\n }\n\n const byEmail = await reservations.list({\n where: { emailKey: normalizedEmail },\n limit: 2,\n });\n const activeEmailReservations: typeof byEmail = [];\n for (const reservation of byEmail) {\n if (\n reservation.profileId !== profileId &&\n (await this.isStaleEmailReservation(reservation, normalizedEmail))\n ) {\n await reservation.delete();\n } else {\n activeEmailReservations.push(reservation);\n }\n }\n const conflictingEmail = activeEmailReservations.find(\n (reservation) => reservation.profileId !== profileId,\n );\n if (conflictingEmail) {\n throw new CanonicalPersonProfileError(\n 'reservation_conflict',\n `${normalizedEmail} is already reserved for a different canonical Person.`,\n );\n }\n if (activeEmailReservations.length > 1) {\n throw new CanonicalPersonProfileError(\n 'ambiguous_email',\n `Multiple canonical identity reservations exist for ${normalizedEmail}.`,\n );\n }\n\n const existing = byProfile[0];\n if (existing) {\n if (existing.emailKey !== normalizedEmail) {\n existing.emailKey = normalizedEmail;\n await saveIdentityEmailReservation(existing, normalizedEmail);\n }\n return profile;\n }\n if (!activeEmailReservations[0]) {\n const reservation = new OidcProfileEmailReservation({\n db,\n emailKey: normalizedEmail,\n profileId,\n });\n await reservation.initialize();\n await saveIdentityEmailReservation(reservation, normalizedEmail);\n }\n return profile;\n }\n\n /**\n * Find profiles by type slug\n *\n * @param typeSlug - The profile type slug to filter by\n * @returns Array of matching profiles\n */\n async findByType(typeSlug: string): Promise<Profile[]> {\n // Will use eager loading when available\n const allProfiles = await this.list({});\n\n const filtered: Profile[] = [];\n for (const profile of allProfiles) {\n const slug = await profile.getTypeSlug();\n if (slug === typeSlug) {\n filtered.push(profile);\n }\n }\n\n return filtered;\n }\n\n private requireDatabase(): DatabaseInterface {\n const db = this.options.db;\n if (!db || typeof db !== 'object' || !('query' in db)) {\n throw new Error(\n 'Canonical Profile identity resolution requires an initialized database.',\n );\n }\n return db as DatabaseInterface;\n }\n\n private async loadCanonicalEmailRows(\n normalizedEmail: string,\n ): Promise<CanonicalProfileRow[]> {\n const db = this.requireDatabase();\n await this.ensureEmailKeysReady();\n const result = await withSystemContext(async () => {\n return db.query(\n `SELECT id, tenant_id, _meta_type, email, email_key\n FROM profiles\n WHERE email_key = ?\n ORDER BY created_at ASC, id ASC\n LIMIT 2`,\n normalizedEmail,\n );\n });\n const rows = result.rows as CanonicalProfileRow[];\n for (const row of rows) this.assertRowEmailKeyCurrent(row, normalizedEmail);\n return rows;\n }\n\n /** Require the deploy-time backfill marker before indexed identity reads. */\n private async ensureEmailKeysReady(): Promise<void> {\n if (!this.emailKeysReadyPromise) {\n this.emailKeysReadyPromise = this.checkEmailKeysReady().catch((error) => {\n this.emailKeysReadyPromise = null;\n throw error;\n });\n }\n return this.emailKeysReadyPromise;\n }\n\n private async checkEmailKeysReady(): Promise<void> {\n const db = this.requireDatabase();\n if (\n await new BackfillTracker({ db }).isApplied(\n PROFILE_EMAIL_KEY_BACKFILL_NAME,\n )\n )\n return;\n throw new CanonicalPersonProfileError(\n 'email_key_backfill_required',\n 'Profile identity email keys are not marked ready; run backfillProfileEmailKeys() before identity lookup.',\n );\n }\n\n private async isStaleEmailReservation(\n reservation: OidcProfileEmailReservation,\n reservedEmail: string,\n ): Promise<boolean> {\n const profileId = reservation.profileId;\n if (!profileId) return true;\n const result = await this.requireDatabase().query(\n 'SELECT email FROM profiles WHERE id = ? LIMIT 1',\n profileId,\n );\n const row = result.rows[0] as CanonicalProfileRow | undefined;\n if (!row) return true;\n const email = readString(row, 'email');\n return !email?.trim() || normalizeIdentityEmail(email) !== reservedEmail;\n }\n\n private assertRowEmailKeyCurrent(\n row: CanonicalProfileRow,\n normalizedEmail?: string,\n ): void {\n const email = readString(row, 'email') ?? '';\n const expectedKey = email.trim() ? normalizeIdentityEmail(email) : null;\n const storedKey = readString(row, 'email_key') ?? null;\n if (\n storedKey !== expectedKey ||\n (normalizedEmail !== undefined && expectedKey !== normalizedEmail)\n ) {\n throw new CanonicalPersonProfileError(\n 'email_key_backfill_required',\n `Profile ${String(row.id ?? '<unknown>')} has a missing or stale identity email key; run backfillProfileEmailKeys() before identity lookup.`,\n );\n }\n }\n\n private assertCanonicalRows(\n rows: CanonicalProfileRow[],\n normalizedEmail?: string,\n ): void {\n const tenantScoped = rows.find((row) => readString(row, 'tenant_id'));\n if (tenantScoped) {\n throw new CanonicalPersonProfileError(\n 'tenant_scoped',\n `Profile ${readRequiredString(tenantScoped, 'id')} for ${normalizedEmail ?? 'the supplied identity'} is tenant-scoped.`,\n );\n }\n\n const nonPerson = rows.find(\n (row) => !PERSON_META_TYPES.has(readString(row, '_meta_type') ?? ''),\n );\n if (nonPerson) {\n throw new CanonicalPersonProfileError(\n 'non_person',\n `Profile ${readRequiredString(nonPerson, 'id')} for ${normalizedEmail ?? 'the supplied identity'} is not a Person.`,\n );\n }\n\n if (rows.length > 1) {\n throw new CanonicalPersonProfileError(\n 'ambiguous_email',\n `Multiple Profiles use ${normalizedEmail ?? 'the supplied identity email'}.`,\n );\n }\n }\n\n private async requireHydratedProfile(profileId: string): Promise<Profile> {\n const profile = await withSystemContext(() => this.get({ id: profileId }));\n if (!profile) {\n throw new CanonicalPersonProfileError(\n 'missing_profile',\n `Profile ${profileId} could not be hydrated.`,\n );\n }\n return profile;\n }\n\n /**\n * Batch get metadata for multiple profiles\n *\n * @param profileIds - Array of profile UUIDs\n * @returns Map of profile ID to metadata object\n */\n async batchGetMetadata(\n profileIds: string[],\n ): Promise<Map<string, Record<string, string>>> {\n const result = new Map<string, Record<string, string>>();\n\n for (const profileId of profileIds) {\n const profile = await this.get({ id: profileId });\n if (profile) {\n const metadata = await profile.getMetadata();\n result.set(profileId, metadata);\n }\n }\n\n return result;\n }\n\n /**\n * Batch update metadata for multiple profiles\n *\n * @param updates - Array of { profileId, data } objects\n */\n async batchUpdateMetadata(\n updates: Array<{ profileId: string; data: Record<string, unknown> }>,\n ): Promise<void> {\n for (const update of updates) {\n const profile = await this.get({ id: update.profileId });\n if (profile) {\n await profile.updateMetadata(update.data);\n }\n }\n }\n\n /**\n * Find related profiles for a given profile\n *\n * @param profileId - The profile UUID\n * @param relationshipSlug - Optional filter by relationship type\n * @returns Array of related profiles\n */\n async findRelated(\n profileId: string,\n relationshipSlug?: string,\n ): Promise<Profile[]> {\n const profile = await this.get({ id: profileId });\n if (!profile) return [];\n\n return await profile.getRelatedProfiles(relationshipSlug);\n }\n\n async getAssets(profileId: string, relationship?: string): Promise<Asset[]> {\n return getOwnedAssetsFromCollection(this, profileId, relationship);\n }\n\n async addAsset(\n profileId: string,\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n await addOwnedAssetFromCollection(\n this,\n 'Profile',\n profileId,\n asset,\n relationship,\n sortOrder,\n );\n }\n\n async removeAsset(\n profileId: string,\n assetId: string,\n relationship?: string,\n ): Promise<void> {\n await removeOwnedAssetFromCollection(\n this,\n 'Profile',\n profileId,\n assetId,\n relationship,\n );\n }\n\n /**\n * Get the relationship network for a profile up to a maximum depth\n *\n * @param profileId - The starting profile UUID\n * @param options - Configuration options\n * @returns Map of profile ID to depth level\n */\n async getRelationshipNetwork(\n profileId: string,\n options: { maxDepth?: number } = {},\n ): Promise<Map<string, number>> {\n const maxDepth = options.maxDepth || 2;\n const network = new Map<string, number>();\n const visited = new Set<string>();\n const queue: Array<{ id: string; depth: number }> = [\n { id: profileId, depth: 0 },\n ];\n\n while (queue.length > 0) {\n const current = queue.shift();\n if (!current) {\n break;\n }\n\n if (visited.has(current.id) || current.depth > maxDepth) {\n continue;\n }\n\n visited.add(current.id);\n network.set(current.id, current.depth);\n\n if (current.depth < maxDepth) {\n const related = await this.findRelated(current.id);\n for (const profile of related) {\n if (profile.id && !visited.has(profile.id)) {\n queue.push({ id: profile.id, depth: current.depth + 1 });\n }\n }\n }\n }\n\n return network;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant-scoped helper methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all profiles belonging to a specific tenant\n *\n * @param tenantId - The tenant UUID to filter by\n * @returns Array of profiles for this tenant\n */\n async findByTenant(tenantId: string): Promise<Profile[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global profiles (no tenant association).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n *\n * @returns Array of profiles with null tenantId\n */\n async findGlobal(): Promise<Profile[]> {\n return queryGlobal<Profile>(this);\n }\n\n /**\n * Find profiles belonging to a tenant plus all global profiles.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - The tenant UUID to include\n * @returns Array of tenant-specific and global profiles\n */\n async findWithGlobals(tenantId: string): Promise<Profile[]> {\n return queryWithGlobals<Profile>(this, tenantId, 'Profile.findWithGlobals');\n }\n}\n\nasync function saveIdentityEmailReservation(\n reservation: OidcProfileEmailReservation,\n normalizedEmail: string,\n): Promise<void> {\n try {\n await reservation.save();\n } catch (error) {\n if (\n (error instanceof ValidationError &&\n error.code === 'VALIDATION_UNIQUE_CONSTRAINT') ||\n isOidcAbortedTransactionError(error)\n ) {\n throw new CanonicalPersonProfileError(\n 'reservation_conflict',\n `${normalizedEmail} was concurrently reserved for another canonical Person.`,\n );\n }\n throw error;\n }\n}\n\nfunction readString(row: Record<string, unknown>, key: string): string | null {\n const value = row[key];\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nfunction readRequiredString(row: Record<string, unknown>, key: string): string {\n const value = readString(row, key);\n if (!value) {\n throw new Error(`Canonical Profile identity row is missing ${key}.`);\n }\n return value;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { y as __exportAll } from "./NostrIdentity-DF_a_WZk.js";
2
- import { a as Profile, m as saveOidcRaceArbiter, n as ProfileCollection, o as ProfileType } from "./ProfileCollection-DdJ3W4GG.js";
3
- import { t as OidcIdentity } from "./OidcIdentity-CFbUlB_Z.js";
2
+ import { a as Profile, m as saveOidcRaceArbiter, n as ProfileCollection, o as ProfileType } from "./ProfileCollection-BOwbNCgG.js";
3
+ import { t as OidcIdentity } from "./OidcIdentity-Bd68oFpZ.js";
4
4
  import { SmrtCollection, smrt } from "@happyvertical/smrt-core";
5
5
  import { isSystemContext } from "@happyvertical/smrt-tenancy";
6
6
  //#region src/collections/ProfileTypeCollection.ts
@@ -135,4 +135,4 @@ function requireProvisioningId(value, label) {
135
135
  //#endregion
136
136
  export { Person as a, ProfileTypeCollection_exports as c, Organization as i, insertOidcProvisioningIdentity as n, ProfileTypes_exports as o, Bot as r, ProfileTypeCollection as s, createOidcProvisioningPerson as t };
137
137
 
138
- //# sourceMappingURL=oidcProvisioningPrimitives-C9XSQNZj.js.map
138
+ //# sourceMappingURL=oidcProvisioningPrimitives-BWHPpJde.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"oidcProvisioningPrimitives-C9XSQNZj.js","names":[],"sources":["../../src/collections/ProfileTypeCollection.ts","../../src/models/ProfileTypes.ts","../../src/auth/oidcProvisioningPrimitives.ts"],"sourcesContent":["/**\n * ProfileTypeCollection - Collection manager for ProfileType objects\n *\n * Provides querying for profile type lookup table.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { isSystemContext } from '@happyvertical/smrt-tenancy';\nimport { ProfileType } from '../models/ProfileType';\n\nexport class ProfileTypeCollection extends SmrtCollection<ProfileType> {\n static readonly _itemClass = ProfileType;\n\n /**\n * Get profile type by slug\n *\n * @param slug - The slug to search for\n * @returns ProfileType instance or null\n */\n async getBySlug(slug: string): Promise<ProfileType | null> {\n return await this.get({ slug });\n }\n\n /**\n * Get or create a profile type by slug\n *\n * @param slug - The slug to search for\n * @param defaults - Default values if creating\n * @returns ProfileType instance\n */\n async getOrCreateBySlug(\n slug: string,\n defaults: { name: string; description?: string },\n ): Promise<ProfileType> {\n const existing = await this.getBySlug(slug);\n if (existing) return existing;\n\n const profileType = await this.create({ slug, ...defaults });\n await profileType.save();\n return profileType;\n }\n\n /**\n * Atomically create or load a global ProfileType from trusted system code.\n *\n * This intentionally bypasses tenant auto-population and therefore refuses\n * to run outside an explicit `withSystemContext()` boundary.\n */\n async getOrCreateGlobalBySlug(\n slug: string,\n defaults: { name: string; description?: string },\n ): Promise<ProfileType> {\n if (!isSystemContext()) {\n throw new Error(\n 'Global ProfileType creation requires an explicit system context.',\n );\n }\n\n const existing = await this.loadGlobalBySlug(slug);\n if (existing) return existing;\n\n // A plain SMRT create is an upsert and may replace the winning row's id\n // when two first-login transactions race. Keep the canonical id stable by\n // using a cross-adapter insert-if-absent and then hydrating the winner.\n await this.db.query(\n `INSERT INTO profile_types\n (id, slug, context, _meta_type, tenant_id, name, description)\n VALUES (?, ?, '', '@happyvertical/smrt-profiles:ProfileType', NULL, ?, ?)\n ON CONFLICT (slug, context, _meta_type) DO NOTHING`,\n crypto.randomUUID(),\n slug,\n defaults.name,\n defaults.description ?? null,\n );\n const profileType = await this.loadGlobalBySlug(slug);\n if (!profileType) {\n throw new Error(\n `Global ProfileType '${slug}' could not be created or loaded.`,\n );\n }\n return profileType;\n }\n\n private async loadGlobalBySlug(slug: string): Promise<ProfileType | null> {\n const result = await this.db.query(\n `SELECT id\n FROM profile_types\n WHERE slug = ?\n AND context = ''\n AND _meta_type = '@happyvertical/smrt-profiles:ProfileType'\n AND tenant_id IS NULL\n LIMIT 1`,\n slug,\n );\n const id = result.rows[0]?.id;\n return typeof id === 'string' ? this.get({ id }) : null;\n }\n}\n","/**\n * Profile subclasses for STI (Single Table Inheritance)\n *\n * These classes inherit from Profile and automatically use the shared\n * profiles table with _meta_type discriminator.\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport { Profile, type ProfileOptions } from './Profile';\n\n/**\n * Person profile type\n *\n * Represents individual people/users.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Person extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Person-specific initialization can go here\n }\n}\n\n/**\n * Organization profile type\n *\n * Represents companies, groups, institutions, and other organizational entities.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Organization extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Organization-specific initialization can go here\n }\n}\n\n/**\n * Bot profile type\n *\n * Represents automated agents, bots, and AI entities.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Bot extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Bot-specific initialization can go here\n }\n}\n","import type { getDatabase } from '@happyvertical/sql';\nimport { ProfileCollection } from '../collections/ProfileCollection';\nimport { ProfileTypeCollection } from '../collections/ProfileTypeCollection';\nimport { OidcIdentity } from '../models/OidcIdentity';\nimport type { Profile } from '../models/Profile';\nimport { Person } from '../models/ProfileTypes';\nimport { saveOidcRaceArbiter } from './oidcProvisioningCoordinator';\n\ntype DatabaseInterface = Awaited<ReturnType<typeof getDatabase>>;\n\nexport interface OidcProvisioningPersonInput {\n email?: string;\n name?: string;\n preferredUsername?: string;\n subject: string;\n}\n\nexport interface OidcProvisioningIdentityInput {\n email?: string;\n issuer: string;\n profileId: string;\n provider: string;\n subject: string;\n}\n\n/** Create and reserve a fresh global Person inside the caller's transaction. */\nexport async function createOidcProvisioningPerson(\n db: DatabaseInterface,\n input: OidcProvisioningPersonInput,\n): Promise<Profile> {\n const typeCollection = await ProfileTypeCollection.create({ db });\n const personType = await typeCollection.getOrCreateGlobalBySlug('person', {\n name: 'Person',\n description: 'Individual person profile',\n });\n const typeId = requireProvisioningId(personType.id, 'Person ProfileType');\n let profile: Profile = new Person({\n db,\n // OIDC display names are not identity keys. A per-profile slug keeps\n // SMRT's natural-key upsert from replacing an unrelated Person.\n slug: `oidc-${crypto.randomUUID()}`,\n tenantId: null,\n typeId,\n email: input.email ?? '',\n name: input.name || input.preferredUsername || input.subject,\n });\n await profile.initialize();\n await saveOidcRaceArbiter(() => profile.save());\n\n if (input.email) {\n const profiles = await ProfileCollection.create({ db });\n profile = await profiles.reserveCanonicalIdentityEmail(\n requireProvisioningId(profile.id, 'Created Profile'),\n input.email,\n );\n }\n return profile;\n}\n\n/** Insert the identity after the caller proves Profile ownership. */\nexport async function insertOidcProvisioningIdentity(\n db: DatabaseInterface,\n input: OidcProvisioningIdentityInput,\n): Promise<OidcIdentity> {\n const identity = new OidcIdentity({\n db,\n email: input.email ?? '',\n issuer: input.issuer,\n profileId: input.profileId,\n provider: input.provider,\n subject: input.subject,\n });\n await identity.initialize();\n await saveOidcRaceArbiter(() => identity.save());\n return identity;\n}\n\nfunction requireProvisioningId(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value) {\n throw new Error(`${label} did not produce an id.`);\n }\n return value;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"oidcProvisioningPrimitives-BWHPpJde.js","names":[],"sources":["../../src/collections/ProfileTypeCollection.ts","../../src/models/ProfileTypes.ts","../../src/auth/oidcProvisioningPrimitives.ts"],"sourcesContent":["/**\n * ProfileTypeCollection - Collection manager for ProfileType objects\n *\n * Provides querying for profile type lookup table.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { isSystemContext } from '@happyvertical/smrt-tenancy';\nimport { ProfileType } from '../models/ProfileType';\n\nexport class ProfileTypeCollection extends SmrtCollection<ProfileType> {\n static readonly _itemClass = ProfileType;\n\n /**\n * Get profile type by slug\n *\n * @param slug - The slug to search for\n * @returns ProfileType instance or null\n */\n async getBySlug(slug: string): Promise<ProfileType | null> {\n return await this.get({ slug });\n }\n\n /**\n * Get or create a profile type by slug\n *\n * @param slug - The slug to search for\n * @param defaults - Default values if creating\n * @returns ProfileType instance\n */\n async getOrCreateBySlug(\n slug: string,\n defaults: { name: string; description?: string },\n ): Promise<ProfileType> {\n const existing = await this.getBySlug(slug);\n if (existing) return existing;\n\n const profileType = await this.create({ slug, ...defaults });\n await profileType.save();\n return profileType;\n }\n\n /**\n * Atomically create or load a global ProfileType from trusted system code.\n *\n * This intentionally bypasses tenant auto-population and therefore refuses\n * to run outside an explicit `withSystemContext()` boundary.\n */\n async getOrCreateGlobalBySlug(\n slug: string,\n defaults: { name: string; description?: string },\n ): Promise<ProfileType> {\n if (!isSystemContext()) {\n throw new Error(\n 'Global ProfileType creation requires an explicit system context.',\n );\n }\n\n const existing = await this.loadGlobalBySlug(slug);\n if (existing) return existing;\n\n // A plain SMRT create is an upsert and may replace the winning row's id\n // when two first-login transactions race. Keep the canonical id stable by\n // using a cross-adapter insert-if-absent and then hydrating the winner.\n await this.db.query(\n `INSERT INTO profile_types\n (id, slug, context, _meta_type, tenant_id, name, description)\n VALUES (?, ?, '', '@happyvertical/smrt-profiles:ProfileType', NULL, ?, ?)\n ON CONFLICT (slug, context, _meta_type) DO NOTHING`,\n crypto.randomUUID(),\n slug,\n defaults.name,\n defaults.description ?? null,\n );\n const profileType = await this.loadGlobalBySlug(slug);\n if (!profileType) {\n throw new Error(\n `Global ProfileType '${slug}' could not be created or loaded.`,\n );\n }\n return profileType;\n }\n\n private async loadGlobalBySlug(slug: string): Promise<ProfileType | null> {\n const result = await this.db.query(\n `SELECT id\n FROM profile_types\n WHERE slug = ?\n AND context = ''\n AND _meta_type = '@happyvertical/smrt-profiles:ProfileType'\n AND tenant_id IS NULL\n LIMIT 1`,\n slug,\n );\n const id = result.rows[0]?.id;\n return typeof id === 'string' ? this.get({ id }) : null;\n }\n}\n","/**\n * Profile subclasses for STI (Single Table Inheritance)\n *\n * These classes inherit from Profile and automatically use the shared\n * profiles table with _meta_type discriminator.\n */\n\nimport { smrt } from '@happyvertical/smrt-core';\nimport { Profile, type ProfileOptions } from './Profile';\n\n/**\n * Person profile type\n *\n * Represents individual people/users.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Person extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Person-specific initialization can go here\n }\n}\n\n/**\n * Organization profile type\n *\n * Represents companies, groups, institutions, and other organizational entities.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Organization extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Organization-specific initialization can go here\n }\n}\n\n/**\n * Bot profile type\n *\n * Represents automated agents, bots, and AI entities.\n */\n@smrt({\n tableStrategy: 'sti',\n})\nexport class Bot extends Profile {\n constructor(options: ProfileOptions = {}) {\n super(options);\n // Bot-specific initialization can go here\n }\n}\n","import type { getDatabase } from '@happyvertical/sql';\nimport { ProfileCollection } from '../collections/ProfileCollection';\nimport { ProfileTypeCollection } from '../collections/ProfileTypeCollection';\nimport { OidcIdentity } from '../models/OidcIdentity';\nimport type { Profile } from '../models/Profile';\nimport { Person } from '../models/ProfileTypes';\nimport { saveOidcRaceArbiter } from './oidcProvisioningCoordinator';\n\ntype DatabaseInterface = Awaited<ReturnType<typeof getDatabase>>;\n\nexport interface OidcProvisioningPersonInput {\n email?: string;\n name?: string;\n preferredUsername?: string;\n subject: string;\n}\n\nexport interface OidcProvisioningIdentityInput {\n email?: string;\n issuer: string;\n profileId: string;\n provider: string;\n subject: string;\n}\n\n/** Create and reserve a fresh global Person inside the caller's transaction. */\nexport async function createOidcProvisioningPerson(\n db: DatabaseInterface,\n input: OidcProvisioningPersonInput,\n): Promise<Profile> {\n const typeCollection = await ProfileTypeCollection.create({ db });\n const personType = await typeCollection.getOrCreateGlobalBySlug('person', {\n name: 'Person',\n description: 'Individual person profile',\n });\n const typeId = requireProvisioningId(personType.id, 'Person ProfileType');\n let profile: Profile = new Person({\n db,\n // OIDC display names are not identity keys. A per-profile slug keeps\n // SMRT's natural-key upsert from replacing an unrelated Person.\n slug: `oidc-${crypto.randomUUID()}`,\n tenantId: null,\n typeId,\n email: input.email ?? '',\n name: input.name || input.preferredUsername || input.subject,\n });\n await profile.initialize();\n await saveOidcRaceArbiter(() => profile.save());\n\n if (input.email) {\n const profiles = await ProfileCollection.create({ db });\n profile = await profiles.reserveCanonicalIdentityEmail(\n requireProvisioningId(profile.id, 'Created Profile'),\n input.email,\n );\n }\n return profile;\n}\n\n/** Insert the identity after the caller proves Profile ownership. */\nexport async function insertOidcProvisioningIdentity(\n db: DatabaseInterface,\n input: OidcProvisioningIdentityInput,\n): Promise<OidcIdentity> {\n const identity = new OidcIdentity({\n db,\n email: input.email ?? '',\n issuer: input.issuer,\n profileId: input.profileId,\n provider: input.provider,\n subject: input.subject,\n });\n await identity.initialize();\n await saveOidcRaceArbiter(() => identity.save());\n return identity;\n}\n\nfunction requireProvisioningId(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value) {\n throw new Error(`${label} did not produce an id.`);\n }\n return value;\n}\n"],"mappings":";;;;;;;AAUO,IAAM,wBAAN,cAAoC,eAA4B;CACrE,OAAgB,aAAa;;;;;;;CAQ7B,MAAM,UAAU,MAA2C;EACzD,OAAO,MAAM,KAAK,IAAI,EAAE,KAAK,CAAC;CAChC;;;;;;;;CASA,MAAM,kBACJ,MACA,UACsB;EACtB,MAAM,WAAW,MAAM,KAAK,UAAU,IAAI;EAC1C,IAAI,UAAU,OAAO;EAErB,MAAM,cAAc,MAAM,KAAK,OAAO;GAAE;GAAM,GAAG;EAAS,CAAC;EAC3D,MAAM,YAAY,KAAK;EACvB,OAAO;CACT;;;;;;;CAQA,MAAM,wBACJ,MACA,UACsB;EACtB,IAAI,CAAC,gBAAgB,GACnB,MAAM,IAAI,MACR,kEACF;EAGF,MAAM,WAAW,MAAM,KAAK,iBAAiB,IAAI;EACjD,IAAI,UAAU,OAAO;EAKrB,MAAM,KAAK,GAAG,MACZ;;;4DAIA,OAAO,WAAW,GAClB,MACA,SAAS,MACT,SAAS,eAAe,IAC1B;EACA,MAAM,cAAc,MAAM,KAAK,iBAAiB,IAAI;EACpD,IAAI,CAAC,aACH,MAAM,IAAI,MACR,uBAAuB,KAAI,kCAC7B;EAEF,OAAO;CACT;CAEA,MAAc,iBAAiB,MAA2C;EAWxE,MAAM,MAAK,MAVU,KAAK,GAAG,MAC3B;;;;;;iBAOA,IACF,EAAA,CACkB,KAAK,EAAC,EAAG;EAC3B,OAAO,OAAO,OAAO,WAAW,KAAK,IAAI,EAAE,GAAG,CAAC,IAAI;CACrD;AACF;;;;;;;;;;;;;;;;AC/EO,IAAM,SAAN,cAAqB,QAAQ;CAClC,YAAY,UAA0B,CAAC,GAAG;EACxC,MAAM,OAAO;CAEf;AACF;AALa,SAAN,gBAAA,CAHN,KAAK,EACJ,eAAe,MACjB,CAAC,CAAA,GACY,MAAA;AAeN,IAAM,eAAN,cAA2B,QAAQ;CACxC,YAAY,UAA0B,CAAC,GAAG;EACxC,MAAM,OAAO;CAEf;AACF;AALa,eAAN,gBAAA,CAHN,KAAK,EACJ,eAAe,MACjB,CAAC,CAAA,GACY,YAAA;AAeN,IAAM,MAAN,cAAkB,QAAQ;CAC/B,YAAY,UAA0B,CAAC,GAAG;EACxC,MAAM,OAAO;CAEf;AACF;AALa,MAAN,gBAAA,CAHN,KAAK,EACJ,eAAe,MACjB,CAAC,CAAA,GACY,GAAA;;;ACtBb,eAAsB,6BACpB,IACA,OACkB;CAMlB,MAAM,SAAS,uBAAsB,OAJZ,MADI,sBAAsB,OAAO,EAAE,GAAG,CAAC,EAAA,CACxB,wBAAwB,UAAU;EACxE,MAAM;EACN,aAAa;CACf,CAAC,EAAA,CAC+C,IAAI,oBAAoB;CACxE,IAAI,UAAmB,IAAI,OAAO;EAChC;EAGA,MAAM,QAAQ,OAAO,WAAW;EAChC,UAAU;EACV;EACA,OAAO,MAAM,SAAS;EACtB,MAAM,MAAM,QAAQ,MAAM,qBAAqB,MAAM;CACvD,CAAC;CACD,MAAM,QAAQ,WAAW;CACzB,MAAM,0BAA0B,QAAQ,KAAK,CAAC;CAE9C,IAAI,MAAM,OAER,UAAU,OAAM,MADO,kBAAkB,OAAO,EAAE,GAAG,CAAC,EAAA,CAC7B,8BACvB,sBAAsB,QAAQ,IAAI,iBAAiB,GACnD,MAAM,KACR;CAEF,OAAO;AACT;AAGA,eAAsB,+BACpB,IACA,OACuB;CACvB,MAAM,WAAW,IAAI,aAAa;EAChC;EACA,OAAO,MAAM,SAAS;EACtB,QAAQ,MAAM;EACd,WAAW,MAAM;EACjB,UAAU,MAAM;EAChB,SAAS,MAAM;CACjB,CAAC;CACD,MAAM,SAAS,WAAW;CAC1B,MAAM,0BAA0B,SAAS,KAAK,CAAC;CAC/C,OAAO;AACT;AAEA,SAAS,sBAAsB,OAAgB,OAAuB;CACpE,IAAI,OAAO,UAAU,YAAY,CAAC,OAChC,MAAM,IAAI,MAAM,GAAG,MAAK,wBAAyB;CAEnD,OAAO;AACT"}