@happyvertical/smrt-profiles 0.42.6 → 0.43.0

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.
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-profiles",
6
- "packageVersion": "0.42.6",
6
+ "packageVersion": "0.43.0",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "6e3f314a28c19c8c4e6051a9e075659a96c9dc2c791702b97a07e2dba273c0c9",
11
- "packageJson": "3163ba9f642cb74f5249609fe904077b47bed89e66c683f10b78a40afcf68b53",
10
+ "manifest": "ff717199b8e9a5c8f7ae8f1ab10df69e13906299f677a783b27a3a37d95de507",
11
+ "packageJson": "1256ba80e200694a690ed4262ab4546117c605435714e21ecccaf5445032dd29",
12
12
  "agents": "475e041f9b6a04721dda5d475337a22f72c80c8fdc8be95acca5011535744b15"
13
13
  },
14
14
  "exports": [
@@ -2291,7 +2291,8 @@
2291
2291
  "toJSON",
2292
2292
  "toPlainObject",
2293
2293
  "toPublicJSON",
2294
- "updateMetadata"
2294
+ "updateMetadata",
2295
+ "withDatabase"
2295
2296
  ],
2296
2297
  "methodSignatures": [
2297
2298
  {
@@ -2773,6 +2774,15 @@
2773
2774
  "metadata: Record<string>"
2774
2775
  ],
2775
2776
  "returns": "Promise<void>"
2777
+ },
2778
+ {
2779
+ "name": "withDatabase",
2780
+ "async": true,
2781
+ "params": [
2782
+ "db: DatabaseInterface",
2783
+ "operation: Function"
2784
+ ],
2785
+ "returns": "Promise<T>"
2776
2786
  }
2777
2787
  ],
2778
2788
  "tenant": {
@@ -3076,7 +3086,8 @@
3076
3086
  "toJSON",
3077
3087
  "toPlainObject",
3078
3088
  "toPublicJSON",
3079
- "validate"
3089
+ "validate",
3090
+ "withDatabase"
3080
3091
  ],
3081
3092
  "methodSignatures": [
3082
3093
  {
@@ -3352,6 +3363,15 @@
3352
3363
  "name": "validate",
3353
3364
  "async": true,
3354
3365
  "returns": "Promise<boolean>"
3366
+ },
3367
+ {
3368
+ "name": "withDatabase",
3369
+ "async": true,
3370
+ "params": [
3371
+ "db: DatabaseInterface",
3372
+ "operation: Function"
3373
+ ],
3374
+ "returns": "Promise<T>"
3355
3375
  }
3356
3376
  ],
3357
3377
  "tenant": {
@@ -3549,7 +3569,8 @@
3549
3569
  "toJSON",
3550
3570
  "toPlainObject",
3551
3571
  "toPublicJSON",
3552
- "validateValue"
3572
+ "validateValue",
3573
+ "withDatabase"
3553
3574
  ],
3554
3575
  "methodSignatures": [
3555
3576
  {
@@ -3849,6 +3870,15 @@
3849
3870
  "value: any"
3850
3871
  ],
3851
3872
  "returns": "Promise<boolean>"
3873
+ },
3874
+ {
3875
+ "name": "withDatabase",
3876
+ "async": true,
3877
+ "params": [
3878
+ "db: DatabaseInterface",
3879
+ "operation: Function"
3880
+ ],
3881
+ "returns": "Promise<T>"
3852
3882
  }
3853
3883
  ],
3854
3884
  "tenant": {
@@ -4088,7 +4118,8 @@
4088
4118
  "summarizeAiUsage",
4089
4119
  "toJSON",
4090
4120
  "toPlainObject",
4091
- "toPublicJSON"
4121
+ "toPublicJSON",
4122
+ "withDatabase"
4092
4123
  ],
4093
4124
  "methodSignatures": [
4094
4125
  {
@@ -4386,6 +4417,15 @@
4386
4417
  "options?: PublicJsonOptions"
4387
4418
  ],
4388
4419
  "returns": "Record<string>"
4420
+ },
4421
+ {
4422
+ "name": "withDatabase",
4423
+ "async": true,
4424
+ "params": [
4425
+ "db: DatabaseInterface",
4426
+ "operation: Function"
4427
+ ],
4428
+ "returns": "Promise<T>"
4389
4429
  }
4390
4430
  ],
4391
4431
  "tenant": {
@@ -4577,7 +4617,8 @@
4577
4617
  "summarizeAiUsage",
4578
4618
  "toJSON",
4579
4619
  "toPlainObject",
4580
- "toPublicJSON"
4620
+ "toPublicJSON",
4621
+ "withDatabase"
4581
4622
  ],
4582
4623
  "methodSignatures": [
4583
4624
  {
@@ -4859,6 +4900,15 @@
4859
4900
  "options?: PublicJsonOptions"
4860
4901
  ],
4861
4902
  "returns": "Record<string>"
4903
+ },
4904
+ {
4905
+ "name": "withDatabase",
4906
+ "async": true,
4907
+ "params": [
4908
+ "db: DatabaseInterface",
4909
+ "operation: Function"
4910
+ ],
4911
+ "returns": "Promise<T>"
4862
4912
  }
4863
4913
  ],
4864
4914
  "tableStrategy": "sti",
@@ -5034,7 +5084,8 @@
5034
5084
  "summarizeAiUsage",
5035
5085
  "toJSON",
5036
5086
  "toPlainObject",
5037
- "toPublicJSON"
5087
+ "toPublicJSON",
5088
+ "withDatabase"
5038
5089
  ],
5039
5090
  "methodSignatures": [
5040
5091
  {
@@ -5335,6 +5386,15 @@
5335
5386
  "options?: PublicJsonOptions"
5336
5387
  ],
5337
5388
  "returns": "Record<string>"
5389
+ },
5390
+ {
5391
+ "name": "withDatabase",
5392
+ "async": true,
5393
+ "params": [
5394
+ "db: DatabaseInterface",
5395
+ "operation: Function"
5396
+ ],
5397
+ "returns": "Promise<T>"
5338
5398
  }
5339
5399
  ],
5340
5400
  "tableStrategy": "sti",
@@ -5503,7 +5563,8 @@
5503
5563
  "summarizeAiUsage",
5504
5564
  "toJSON",
5505
5565
  "toPlainObject",
5506
- "toPublicJSON"
5566
+ "toPublicJSON",
5567
+ "withDatabase"
5507
5568
  ],
5508
5569
  "methodSignatures": [
5509
5570
  {
@@ -5778,6 +5839,15 @@
5778
5839
  "options?: PublicJsonOptions"
5779
5840
  ],
5780
5841
  "returns": "Record<string>"
5842
+ },
5843
+ {
5844
+ "name": "withDatabase",
5845
+ "async": true,
5846
+ "params": [
5847
+ "db: DatabaseInterface",
5848
+ "operation: Function"
5849
+ ],
5850
+ "returns": "Promise<T>"
5781
5851
  }
5782
5852
  ],
5783
5853
  "tenant": {
@@ -6048,7 +6118,8 @@
6048
6118
  "toJSON",
6049
6119
  "toPlainObject",
6050
6120
  "toPublicJSON",
6051
- "updateMetadata"
6121
+ "updateMetadata",
6122
+ "withDatabase"
6052
6123
  ],
6053
6124
  "methodSignatures": [
6054
6125
  {
@@ -6530,6 +6601,15 @@
6530
6601
  "metadata: Record<string>"
6531
6602
  ],
6532
6603
  "returns": "Promise<void>"
6604
+ },
6605
+ {
6606
+ "name": "withDatabase",
6607
+ "async": true,
6608
+ "params": [
6609
+ "db: DatabaseInterface",
6610
+ "operation: Function"
6611
+ ],
6612
+ "returns": "Promise<T>"
6533
6613
  }
6534
6614
  ],
6535
6615
  "tableStrategy": "sti",
@@ -6716,7 +6796,8 @@
6716
6796
  "toJSON",
6717
6797
  "toPlainObject",
6718
6798
  "toPublicJSON",
6719
- "updateMetadata"
6799
+ "updateMetadata",
6800
+ "withDatabase"
6720
6801
  ],
6721
6802
  "methodSignatures": [
6722
6803
  {
@@ -7198,6 +7279,15 @@
7198
7279
  "metadata: Record<string>"
7199
7280
  ],
7200
7281
  "returns": "Promise<void>"
7282
+ },
7283
+ {
7284
+ "name": "withDatabase",
7285
+ "async": true,
7286
+ "params": [
7287
+ "db: DatabaseInterface",
7288
+ "operation: Function"
7289
+ ],
7290
+ "returns": "Promise<T>"
7201
7291
  }
7202
7292
  ],
7203
7293
  "tableStrategy": "sti",
@@ -7384,7 +7474,8 @@
7384
7474
  "toJSON",
7385
7475
  "toPlainObject",
7386
7476
  "toPublicJSON",
7387
- "updateMetadata"
7477
+ "updateMetadata",
7478
+ "withDatabase"
7388
7479
  ],
7389
7480
  "methodSignatures": [
7390
7481
  {
@@ -7866,6 +7957,15 @@
7866
7957
  "metadata: Record<string>"
7867
7958
  ],
7868
7959
  "returns": "Promise<void>"
7960
+ },
7961
+ {
7962
+ "name": "withDatabase",
7963
+ "async": true,
7964
+ "params": [
7965
+ "db: DatabaseInterface",
7966
+ "operation: Function"
7967
+ ],
7968
+ "returns": "Promise<T>"
7869
7969
  }
7870
7970
  ],
7871
7971
  "tableStrategy": "sti",
package/dist/utils.js CHANGED
@@ -4,7 +4,7 @@ async function getProfileMetadata(profileId, options = {}) {
4
4
  return await (await ProfileMetadataCollection.create(options)).getMetadataObject(profileId);
5
5
  }
6
6
  async function setProfileMetadata(profileId, metafieldSlug, value, options = {}) {
7
- const { ProfileCollection } = await import("./chunks/ProfileCollection-BsKhR5Dp.js").then((n) => n.r);
7
+ const { ProfileCollection } = await import("./chunks/ProfileCollection-WlRQ7bj3.js").then((n) => n.r);
8
8
  const profile = await (await ProfileCollection.create(options)).get({ id: profileId });
9
9
  if (!profile) throw new Error(`Profile '${profileId}' not found`);
10
10
  await profile.addMetadata(metafieldSlug, value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-profiles",
3
- "version": "0.42.6",
3
+ "version": "0.43.0",
4
4
  "description": "Profile management system with relationships, metadata, and reciprocal associations for SMRT framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -34,10 +34,10 @@
34
34
  "@happyvertical/utils": "^0.88.0",
35
35
  "@noble/curves": "^1.9.7",
36
36
  "bech32": "^2.0.0",
37
- "@happyvertical/smrt-assets": "0.42.6",
38
- "@happyvertical/smrt-core": "0.42.6",
39
- "@happyvertical/smrt-prompts": "0.42.6",
40
- "@happyvertical/smrt-tenancy": "0.42.6"
37
+ "@happyvertical/smrt-assets": "0.43.0",
38
+ "@happyvertical/smrt-core": "0.43.0",
39
+ "@happyvertical/smrt-prompts": "0.43.0",
40
+ "@happyvertical/smrt-tenancy": "0.43.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@faker-js/faker": "^10.5.0",
@@ -46,7 +46,7 @@
46
46
  "typescript": "5.9.3",
47
47
  "vite": "8.1.4",
48
48
  "vitest": "4.1.10",
49
- "@happyvertical/smrt-vitest": "0.42.6"
49
+ "@happyvertical/smrt-vitest": "0.43.0"
50
50
  },
51
51
  "keywords": [
52
52
  "ai",
@@ -1 +0,0 @@
1
- {"version":3,"file":"OidcIdentityCollection-eSM4gzHL.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 +0,0 @@
1
- {"version":3,"file":"oidcProvisioningPrimitives-Bzv4VTcn.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\nfunction isPostgresUrl(url: string | undefined): boolean {\n return /^postgres(?:ql)?:/iu.test(url ?? '');\n}\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 //\n // The table's unique key is `(tenant_id, slug, context, _meta_type)` since\n // smrt#2360, and a global row's NULL tenant never conflicts at the\n // database level (NULLs are distinct in a unique index), so a raw\n // `ON CONFLICT (…) DO NOTHING` can no longer arbitrate this race. Serialize\n // the global create per slug instead: PostgreSQL through a\n // transaction-scoped advisory lock (the arbiter the SDK's null-aware\n // upsert uses too); the embedded engines through the provisioning\n // coordinator's in-process lock plus their single-writer transactions.\n const insertIfAbsent = async (db: typeof this.db): Promise<void> => {\n if (isPostgresUrl(db.url)) {\n await db.query(\n 'SELECT pg_advisory_xact_lock(hashtext(?), hashtext(?))',\n '@happyvertical/smrt-profiles:profile_types:global',\n slug,\n );\n }\n await db.query(\n `INSERT INTO profile_types\n (id, slug, context, _meta_type, tenant_id, name, description)\n SELECT ?, ?, '', '@happyvertical/smrt-profiles:ProfileType', NULL, ?, ?\n WHERE NOT EXISTS (\n SELECT 1 FROM profile_types\n WHERE slug = ?\n AND context = ''\n AND _meta_type = '@happyvertical/smrt-profiles:ProfileType'\n AND tenant_id IS NULL\n )`,\n crypto.randomUUID(),\n slug,\n defaults.name,\n defaults.description ?? null,\n slug,\n );\n };\n\n // A transaction-scoped advisory lock only spans both statements when they\n // run on one transaction. On PostgreSQL, any handle that is NOT already\n // transaction-bound may route each query to a different pooled connection\n // — a root adapter (`beginTransaction` present) and equally a view\n // wrapper (only `transaction()` present) — so open a transaction for the\n // pair on every such handle. A transaction-bound handle (fingerprint: it\n // carries `commit`) already keeps both statements on one client and must\n // not nest. Embedded engines run directly: a nested root transaction\n // would deadlock their single-writer adapters, and the provisioning\n // coordinator's in-process lock already serializes them.\n const isTransactionBound =\n typeof (this.db as { commit?: unknown }).commit === 'function';\n if (\n isPostgresUrl(this.db.url) &&\n !isTransactionBound &&\n typeof this.db.transaction === 'function'\n ) {\n await this.db.transaction((tx) => insertIfAbsent(tx));\n } else {\n await insertIfAbsent(this.db);\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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"}