@happyvertical/smrt-profiles 0.37.2 → 0.37.3

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 (61) hide show
  1. package/dist/chunks/ApiKey-3DlNEc91.js +145 -0
  2. package/dist/chunks/ApiKey-3DlNEc91.js.map +1 -0
  3. package/dist/chunks/ApiKeyCollection-PwVs0qDb.js +83 -0
  4. package/dist/chunks/ApiKeyCollection-PwVs0qDb.js.map +1 -0
  5. package/dist/chunks/AuditLogCollection-CnIYU0aK.js +191 -0
  6. package/dist/chunks/AuditLogCollection-CnIYU0aK.js.map +1 -0
  7. package/dist/chunks/NostrIdentityCollection-CG6HGf6c.js +3267 -0
  8. package/dist/chunks/NostrIdentityCollection-CG6HGf6c.js.map +1 -0
  9. package/dist/chunks/OidcIdentityCollection-DiLneB7J.js +158 -0
  10. package/dist/chunks/OidcIdentityCollection-DiLneB7J.js.map +1 -0
  11. package/dist/chunks/ProfileAssetCollection-BY2Wbem3.js +93 -0
  12. package/dist/chunks/ProfileAssetCollection-BY2Wbem3.js.map +1 -0
  13. package/dist/chunks/ProfileCollection-DlhdOnDr.js +641 -0
  14. package/dist/chunks/ProfileCollection-DlhdOnDr.js.map +1 -0
  15. package/dist/chunks/ProfileMetadataCollection-CGcO4Iw_.js +105 -0
  16. package/dist/chunks/ProfileMetadataCollection-CGcO4Iw_.js.map +1 -0
  17. package/dist/chunks/ProfileMetafieldCollection-C8TX9HvN.js +142 -0
  18. package/dist/chunks/ProfileMetafieldCollection-C8TX9HvN.js.map +1 -0
  19. package/dist/chunks/ProfileRelationshipCollection-JnskbZTd.js +159 -0
  20. package/dist/chunks/ProfileRelationshipCollection-JnskbZTd.js.map +1 -0
  21. package/dist/chunks/ProfileRelationshipTermCollection-UopP7sja.js +105 -0
  22. package/dist/chunks/ProfileRelationshipTermCollection-UopP7sja.js.map +1 -0
  23. package/dist/chunks/ProfileRelationshipType-OMBn5cWR.js +98 -0
  24. package/dist/chunks/ProfileRelationshipType-OMBn5cWR.js.map +1 -0
  25. package/dist/chunks/ProfileRelationshipTypeCollection-CQu08kxF.js +54 -0
  26. package/dist/chunks/ProfileRelationshipTypeCollection-CQu08kxF.js.map +1 -0
  27. package/dist/index.js +690 -69
  28. package/dist/index.js.map +1 -1
  29. package/dist/manifest.json +2 -2
  30. package/dist/smrt-knowledge.json +9 -9
  31. package/dist/types.js +0 -2
  32. package/dist/utils.js +18 -36
  33. package/dist/utils.js.map +1 -1
  34. package/package.json +16 -16
  35. package/dist/chunks/ApiKey-B2LKEaP8.js +0 -143
  36. package/dist/chunks/ApiKey-B2LKEaP8.js.map +0 -1
  37. package/dist/chunks/ApiKeyCollection-B6Op817e.js +0 -91
  38. package/dist/chunks/ApiKeyCollection-B6Op817e.js.map +0 -1
  39. package/dist/chunks/AuditLogCollection-BYqCj0uE.js +0 -195
  40. package/dist/chunks/AuditLogCollection-BYqCj0uE.js.map +0 -1
  41. package/dist/chunks/NostrIdentityCollection-DadQBHWy.js +0 -3065
  42. package/dist/chunks/NostrIdentityCollection-DadQBHWy.js.map +0 -1
  43. package/dist/chunks/ProfileAssetCollection-CUM5QfuJ.js +0 -122
  44. package/dist/chunks/ProfileAssetCollection-CUM5QfuJ.js.map +0 -1
  45. package/dist/chunks/ProfileCollection-M2PK8bp-.js +0 -800
  46. package/dist/chunks/ProfileCollection-M2PK8bp-.js.map +0 -1
  47. package/dist/chunks/ProfileMetadataCollection-DEhmljMY.js +0 -120
  48. package/dist/chunks/ProfileMetadataCollection-DEhmljMY.js.map +0 -1
  49. package/dist/chunks/ProfileMetafieldCollection-DMKhSHXX.js +0 -184
  50. package/dist/chunks/ProfileMetafieldCollection-DMKhSHXX.js.map +0 -1
  51. package/dist/chunks/ProfileRelationshipCollection-_TsY7MHL.js +0 -189
  52. package/dist/chunks/ProfileRelationshipCollection-_TsY7MHL.js.map +0 -1
  53. package/dist/chunks/ProfileRelationshipTermCollection-CXem_qT-.js +0 -117
  54. package/dist/chunks/ProfileRelationshipTermCollection-CXem_qT-.js.map +0 -1
  55. package/dist/chunks/ProfileRelationshipType-BXBLldea.js +0 -103
  56. package/dist/chunks/ProfileRelationshipType-BXBLldea.js.map +0 -1
  57. package/dist/chunks/ProfileRelationshipTypeCollection-CF8YvLTV.js +0 -48
  58. package/dist/chunks/ProfileRelationshipTypeCollection-CF8YvLTV.js.map +0 -1
  59. package/dist/chunks/index-B9lXQy7N.js +0 -1029
  60. package/dist/chunks/index-B9lXQy7N.js.map +0 -1
  61. package/dist/types.js.map +0 -1
@@ -0,0 +1,641 @@
1
+ import { x as __exportAll } from "./NostrIdentityCollection-CG6HGf6c.js";
2
+ import { SmrtCollection, SmrtObject, field, foreignKey, oneToMany, smrt } from "@happyvertical/smrt-core";
3
+ import { definePrompt, resolvePrompt } from "@happyvertical/smrt-prompts";
4
+ import { TenantScoped, queryGlobal, queryWithGlobals, tenantId } from "@happyvertical/smrt-tenancy";
5
+ import { addOwnedAssetFromCollection, assertValidOwnedAssetRelationship, assertValidOwnedAssetSortOrder, getOwnedAssetsFromCollection, removeOwnedAssetFromCollection, resolveOwnedAssetsById } from "@happyvertical/smrt-assets";
6
+ //#region src/prompts.ts
7
+ var smrtProfilesGenerateBioPrompt = definePrompt({
8
+ key: "smrtProfiles.profile.generateBio",
9
+ template: `Write a short, professional bio for this person.
10
+
11
+ Profile name: {profileName}
12
+ Profile description: {profileDescription}
13
+
14
+ Return only the bio text, with no commentary or surrounding quotation marks.`,
15
+ editable: {
16
+ template: true,
17
+ profile: true,
18
+ model: true,
19
+ params: true
20
+ }
21
+ });
22
+ function promptMessageOptions(ai) {
23
+ return {
24
+ ...ai.params || {},
25
+ ...ai.model ? { model: ai.model } : {},
26
+ ...typeof ai.temperature === "number" ? { temperature: ai.temperature } : {},
27
+ ...typeof ai.maxTokens === "number" ? { maxTokens: ai.maxTokens } : {}
28
+ };
29
+ }
30
+ //#endregion
31
+ //#region src/models/ProfileType.ts
32
+ var ProfileType_exports = /* @__PURE__ */ __exportAll({ ProfileType: () => ProfileType });
33
+ var __defProp$1 = Object.defineProperty;
34
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
35
+ var __decorateClass$1 = (decorators, target, key, kind) => {
36
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
37
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
38
+ if (kind && result) __defProp$1(target, key, result);
39
+ return result;
40
+ };
41
+ var ProfileType = class extends SmrtObject {
42
+ tenantId = null;
43
+ name = "";
44
+ description;
45
+ constructor(options = {}) {
46
+ super(options);
47
+ if (options.name) this.name = options.name;
48
+ if (options.description !== void 0) this.description = options.description;
49
+ }
50
+ /**
51
+ * Convenience method for slug-based lookup
52
+ *
53
+ * @param slug - The slug to search for
54
+ * @returns ProfileType instance or null if not found
55
+ */
56
+ static async getBySlug(_slug) {
57
+ return null;
58
+ }
59
+ };
60
+ __decorateClass$1([tenantId({ nullable: true })], ProfileType.prototype, "tenantId", 2);
61
+ __decorateClass$1([field({ required: true })], ProfileType.prototype, "name", 2);
62
+ ProfileType = __decorateClass$1([TenantScoped({ mode: "optional" }), smrt({
63
+ tableStrategy: "sti",
64
+ api: { include: [
65
+ "list",
66
+ "get",
67
+ "create",
68
+ "update"
69
+ ] },
70
+ mcp: { include: ["list", "get"] },
71
+ cli: true
72
+ })], ProfileType);
73
+ //#endregion
74
+ //#region src/models/Profile.ts
75
+ var __defProp = Object.defineProperty;
76
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
77
+ var __decorateClass = (decorators, target, key, kind) => {
78
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
79
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
80
+ if (kind && result) __defProp(target, key, result);
81
+ return result;
82
+ };
83
+ var Profile = class extends SmrtObject {
84
+ tenantId = null;
85
+ typeId;
86
+ email;
87
+ name = "";
88
+ description;
89
+ metadata = [];
90
+ relationshipsFrom = [];
91
+ relationshipsTo = [];
92
+ constructor(options = {}) {
93
+ super(options);
94
+ if (options.typeId !== void 0) this.typeId = options.typeId;
95
+ if (options.email !== void 0) this.email = options.email;
96
+ if (options.name) this.name = options.name;
97
+ if (options.description !== void 0) this.description = options.description;
98
+ }
99
+ /**
100
+ * Get the profile type slug for this profile
101
+ *
102
+ * @returns The slug of the profile type
103
+ */
104
+ async getTypeSlug() {
105
+ return (await this.loadRelated("typeId"))?.slug || "";
106
+ }
107
+ /**
108
+ * Set the profile type by slug
109
+ *
110
+ * @param slug - The slug of the profile type
111
+ * @throws Error if profile type not found
112
+ */
113
+ async setTypeBySlug(slug) {
114
+ const type = await ProfileType.getBySlug(slug);
115
+ if (!type) throw new Error(`Profile type '${slug}' not found`);
116
+ this.typeId = type.id;
117
+ }
118
+ /**
119
+ * Add metadata to this profile
120
+ *
121
+ * @param metafieldSlug - The slug of the metafield
122
+ * @param value - The value to set
123
+ */
124
+ async addMetadata(metafieldSlug, value) {
125
+ const { ProfileMetafieldCollection } = await import("./ProfileMetafieldCollection-C8TX9HvN.js").then((n) => n.n);
126
+ const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-CGcO4Iw_.js").then((n) => n.n);
127
+ const metafield = await (await ProfileMetafieldCollection.create(this.options)).getBySlug(metafieldSlug);
128
+ if (!metafield) throw new Error(`Metafield '${metafieldSlug}' not found`);
129
+ await metafield.validateValue(value);
130
+ const metadataCollection = await ProfileMetadataCollection.create(this.options);
131
+ const existing = await metadataCollection.list({
132
+ where: {
133
+ profileId: this.id,
134
+ metafieldId: metafield.id
135
+ },
136
+ limit: 1
137
+ });
138
+ if (existing.length > 0) {
139
+ const metadata = existing[0];
140
+ metadata.value = String(value);
141
+ await metadata.save();
142
+ } else {
143
+ if (!this.id || !metafield.id) throw new Error("Profile.addMetadata requires a persisted profile and metafield (missing id)");
144
+ await (await metadataCollection.create({
145
+ profileId: this.id,
146
+ metafieldId: metafield.id,
147
+ value: String(value)
148
+ })).save();
149
+ }
150
+ }
151
+ /**
152
+ * Get all metadata for this profile as key-value object
153
+ *
154
+ * @returns Object with metafield slugs as keys
155
+ */
156
+ async getMetadata() {
157
+ const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-CGcO4Iw_.js").then((n) => n.n);
158
+ return await (await ProfileMetadataCollection.create(this.options)).getMetadataObject(this.id);
159
+ }
160
+ /**
161
+ * Update multiple metadata values
162
+ *
163
+ * @param metadata - Object with metafield slugs as keys and values
164
+ */
165
+ async updateMetadata(metadata) {
166
+ for (const [metafieldSlug, value] of Object.entries(metadata)) await this.addMetadata(metafieldSlug, value);
167
+ }
168
+ /**
169
+ * Remove metadata by metafield slug
170
+ *
171
+ * @param metafieldSlug - The slug of the metafield to remove
172
+ */
173
+ async removeMetadata(metafieldSlug) {
174
+ const { ProfileMetafieldCollection } = await import("./ProfileMetafieldCollection-C8TX9HvN.js").then((n) => n.n);
175
+ const { ProfileMetadataCollection } = await import("./ProfileMetadataCollection-CGcO4Iw_.js").then((n) => n.n);
176
+ const metafield = await (await ProfileMetafieldCollection.create(this.options)).getBySlug(metafieldSlug);
177
+ if (!metafield) throw new Error(`Metafield '${metafieldSlug}' not found`);
178
+ const existing = await (await ProfileMetadataCollection.create(this.options)).list({
179
+ where: {
180
+ profileId: this.id,
181
+ metafieldId: metafield.id
182
+ },
183
+ limit: 1
184
+ });
185
+ if (existing.length > 0) await existing[0].delete();
186
+ }
187
+ async getProfileAssetCollection() {
188
+ const { ProfileAssetCollection } = await import("./ProfileAssetCollection-BY2Wbem3.js").then((n) => n.n);
189
+ return ProfileAssetCollection.create({ db: this.db });
190
+ }
191
+ async getAssets(relationship) {
192
+ if (!this.id) return [];
193
+ const linkedAssets = await (await this.getProfileAssetCollection()).byLeft(this.id, relationship ? { relationship } : {});
194
+ return resolveOwnedAssetsById(this.db, linkedAssets.map((link) => link.assetId), this.tenantId);
195
+ }
196
+ async addAsset(asset, relationship = "attachment", sortOrder = 0) {
197
+ if (!this.id || !asset.id) throw new Error("Cannot associate unsaved profile or asset");
198
+ assertValidOwnedAssetRelationship(relationship);
199
+ assertValidOwnedAssetSortOrder(sortOrder);
200
+ await (await this.getProfileAssetCollection()).attach(this.id, asset.id, {
201
+ relationship,
202
+ sortOrder,
203
+ tenantId: this.tenantId
204
+ });
205
+ }
206
+ async removeAsset(assetId, relationship) {
207
+ if (!this.id) return;
208
+ await (await this.getProfileAssetCollection()).detach(this.id, assetId, relationship ? { relationship } : {});
209
+ }
210
+ /**
211
+ * Add a relationship to another profile
212
+ *
213
+ * @param toProfile - The target profile
214
+ * @param relationshipSlug - The type of relationship
215
+ * @param contextProfile - Optional context profile for tertiary relationships
216
+ */
217
+ async addRelationship(toProfile, relationshipSlug, contextProfile) {
218
+ const { ProfileRelationshipTypeCollection } = await import("./ProfileRelationshipTypeCollection-CQu08kxF.js").then((n) => n.n);
219
+ const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-JnskbZTd.js").then((n) => n.n);
220
+ const { ProfileRelationshipType } = await import("./ProfileRelationshipType-OMBn5cWR.js").then((n) => n.n);
221
+ const relationshipType = await (await ProfileRelationshipTypeCollection.create(this.options)).getBySlug(relationshipSlug);
222
+ if (!relationshipType) throw new Error(`Relationship type '${relationshipSlug}' not found`);
223
+ const relationshipCollection = await ProfileRelationshipCollection.create(this.options);
224
+ if (!await relationshipCollection.exists(this.id, toProfile.id, relationshipType.id)) {
225
+ await (await relationshipCollection.create({
226
+ fromProfileId: this.id ?? void 0,
227
+ toProfileId: toProfile.id ?? void 0,
228
+ typeId: relationshipType.id ?? void 0,
229
+ contextProfileId: contextProfile?.id ?? void 0
230
+ })).save();
231
+ if (relationshipType.reciprocal) {
232
+ const handler = ProfileRelationshipType.getReciprocalHandler(relationshipSlug);
233
+ if (handler) await handler(this, toProfile, contextProfile);
234
+ }
235
+ }
236
+ }
237
+ /**
238
+ * Get all relationships for this profile
239
+ *
240
+ * @param options - Filter options (typeSlug, direction)
241
+ * @returns Array of ProfileRelationship instances
242
+ */
243
+ async getRelationships(options) {
244
+ const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-JnskbZTd.js").then((n) => n.n);
245
+ const { ProfileRelationshipTypeCollection } = await import("./ProfileRelationshipTypeCollection-CQu08kxF.js").then((n) => n.n);
246
+ const relationshipCollection = await ProfileRelationshipCollection.create(this.options);
247
+ const direction = options?.direction || "all";
248
+ let typeId;
249
+ if (options?.typeSlug) typeId = (await (await ProfileRelationshipTypeCollection.create(this.options)).getBySlug(options.typeSlug))?.id ?? void 0;
250
+ if (direction === "from") return await relationshipCollection.getFromProfile(this.id, typeId);
251
+ else if (direction === "to") return await relationshipCollection.getToProfile(this.id, typeId);
252
+ else return await relationshipCollection.getForProfile(this.id, typeId);
253
+ }
254
+ /**
255
+ * Get related profiles
256
+ *
257
+ * @param relationshipSlug - Optional filter by relationship type slug
258
+ * @returns Array of related Profile instances
259
+ */
260
+ async getRelatedProfiles(relationshipSlug) {
261
+ const { ProfileCollection } = await Promise.resolve().then(() => ProfileCollection_exports);
262
+ const relationships = await this.getRelationships({
263
+ typeSlug: relationshipSlug,
264
+ direction: "all"
265
+ });
266
+ const profileCollection = await ProfileCollection.create(this.options);
267
+ const relatedProfiles = [];
268
+ const seenIds = /* @__PURE__ */ new Set();
269
+ for (const relationship of relationships) {
270
+ const fromId = String(relationship.fromProfileId);
271
+ const toId = String(relationship.toProfileId);
272
+ const otherId = fromId === String(this.id) ? toId : fromId;
273
+ if (!seenIds.has(otherId)) {
274
+ seenIds.add(otherId);
275
+ const profile = await profileCollection.get({ id: otherId });
276
+ if (profile) relatedProfiles.push(profile);
277
+ }
278
+ }
279
+ return relatedProfiles;
280
+ }
281
+ /**
282
+ * Remove a relationship to another profile
283
+ *
284
+ * @param toProfile - The target profile
285
+ * @param relationshipSlug - The type of relationship to remove
286
+ */
287
+ async removeRelationship(toProfile, relationshipSlug) {
288
+ const { ProfileRelationshipTypeCollection } = await import("./ProfileRelationshipTypeCollection-CQu08kxF.js").then((n) => n.n);
289
+ const { ProfileRelationshipCollection } = await import("./ProfileRelationshipCollection-JnskbZTd.js").then((n) => n.n);
290
+ const relationshipType = await (await ProfileRelationshipTypeCollection.create(this.options)).getBySlug(relationshipSlug);
291
+ if (!relationshipType) throw new Error(`Relationship type '${relationshipSlug}' not found`);
292
+ const relationshipCollection = await ProfileRelationshipCollection.create(this.options);
293
+ const relationships = await relationshipCollection.list({ where: {
294
+ fromProfileId: this.id,
295
+ toProfileId: toProfile.id,
296
+ typeId: relationshipType.id
297
+ } });
298
+ for (const relationship of relationships) await relationship.delete();
299
+ if (relationshipType.reciprocal) {
300
+ const inverseRelationships = await relationshipCollection.list({ where: {
301
+ fromProfileId: toProfile.id,
302
+ toProfileId: this.id,
303
+ typeId: relationshipType.id
304
+ } });
305
+ for (const relationship of inverseRelationships) await relationship.delete();
306
+ }
307
+ }
308
+ /**
309
+ * AI-powered: Generate a professional bio for this profile
310
+ *
311
+ * Uses the `smrtProfiles.profile.generateBio` prompt registered via
312
+ * `@happyvertical/smrt-prompts`, allowing tenant- or instance-level
313
+ * overrides of the template, model, and parameters at runtime.
314
+ *
315
+ * @returns Generated bio text
316
+ */
317
+ async generateBio() {
318
+ const db = this.options.db ?? this.options.persistence;
319
+ const resolvedPrompt = await resolvePrompt(smrtProfilesGenerateBioPrompt.key, {
320
+ db,
321
+ tenantId: this.tenantId,
322
+ variables: {
323
+ profileName: this.name || "",
324
+ profileDescription: this.description || ""
325
+ }
326
+ });
327
+ return (await (await this.getAiClient()).message(resolvedPrompt.text, promptMessageOptions(resolvedPrompt.ai))).trim();
328
+ }
329
+ /**
330
+ * AI-powered: Check if profile matches criteria
331
+ *
332
+ * @param criteria - Criteria to match against
333
+ * @returns True if matches criteria
334
+ */
335
+ async matches(criteria) {
336
+ return await this.is(criteria);
337
+ }
338
+ /**
339
+ * Find profiles by metadata key-value pair
340
+ *
341
+ * @param metafieldSlug - The metafield slug to search
342
+ * @param value - The value to match
343
+ * @returns Array of matching profiles
344
+ */
345
+ static async findByMetadata(_metafieldSlug, _value) {
346
+ return [];
347
+ }
348
+ /**
349
+ * Find profiles by type slug
350
+ *
351
+ * @param typeSlug - The profile type slug
352
+ * @returns Array of matching profiles
353
+ */
354
+ static async findByType(_typeSlug) {
355
+ return [];
356
+ }
357
+ /**
358
+ * Find related profiles for a given profile
359
+ *
360
+ * @param profileId - The profile UUID
361
+ * @param relationshipSlug - Optional filter by relationship type
362
+ * @returns Array of related profiles
363
+ */
364
+ static async findRelated(_profileId, _relationshipSlug) {
365
+ return [];
366
+ }
367
+ /**
368
+ * Search profiles by email
369
+ *
370
+ * @param email - The email to search for
371
+ * @returns Profile or null if not found
372
+ */
373
+ static async searchByEmail(_email) {
374
+ return null;
375
+ }
376
+ /**
377
+ * Get all API keys for this profile
378
+ *
379
+ * @returns Array of API keys
380
+ */
381
+ async getApiKeys() {
382
+ const { ApiKeyCollection } = await import("./ApiKeyCollection-PwVs0qDb.js").then((n) => n.n);
383
+ return await (await ApiKeyCollection.create(this.options)).findByProfile(this.id);
384
+ }
385
+ /**
386
+ * Get active (non-revoked, non-expired) API keys for this profile
387
+ *
388
+ * @returns Array of active API keys
389
+ */
390
+ async getActiveApiKeys() {
391
+ const { ApiKeyCollection } = await import("./ApiKeyCollection-PwVs0qDb.js").then((n) => n.n);
392
+ return await (await ApiKeyCollection.create(this.options)).findActiveByProfile(this.id);
393
+ }
394
+ /**
395
+ * Generate a new API key for this profile
396
+ *
397
+ * @param options - Key options (name, scopes, expiration)
398
+ * @returns The generated key (plaintext) and ApiKey record
399
+ */
400
+ async generateApiKey(options) {
401
+ const { ApiKey } = await import("./ApiKey-3DlNEc91.js").then((n) => n.n);
402
+ return await ApiKey.generate(this, {
403
+ ...options,
404
+ db: this.options?.db
405
+ });
406
+ }
407
+ /**
408
+ * Get all OIDC identities linked to this profile
409
+ *
410
+ * @returns Array of OIDC identity records
411
+ */
412
+ async getOidcIdentities() {
413
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-DiLneB7J.js").then((n) => n.n);
414
+ return await (await OidcIdentityCollection.create(this.options)).findByProfile(this.id);
415
+ }
416
+ /**
417
+ * Link a new OIDC identity to this profile
418
+ *
419
+ * @param oidcData - OIDC provider data
420
+ * @returns The linked OIDC identity record
421
+ */
422
+ async linkOidcIdentity(oidcData) {
423
+ const { OidcIdentityCollection } = await import("./OidcIdentityCollection-DiLneB7J.js").then((n) => n.n);
424
+ return await (await OidcIdentityCollection.create(this.options)).linkToProfile(this, oidcData);
425
+ }
426
+ /**
427
+ * Get all Nostr identities linked to this profile
428
+ *
429
+ * @returns Array of Nostr identity records
430
+ */
431
+ async getNostrIdentities() {
432
+ const { NostrIdentityCollection } = await import("./NostrIdentityCollection-CG6HGf6c.js").then((n) => n.n);
433
+ return await (await NostrIdentityCollection.create(this.options)).findByProfile(this.id);
434
+ }
435
+ /**
436
+ * Link a new Nostr identity to this profile
437
+ *
438
+ * @param nostrData - Nostr identity data (encrypted keypair)
439
+ * @returns The linked Nostr identity record
440
+ */
441
+ async linkNostrIdentity(nostrData) {
442
+ const { NostrIdentityCollection } = await import("./NostrIdentityCollection-CG6HGf6c.js").then((n) => n.n);
443
+ return await (await NostrIdentityCollection.create(this.options)).linkToProfile(this, nostrData);
444
+ }
445
+ /**
446
+ * Get audit logs for actions performed by this profile
447
+ *
448
+ * @param limit - Maximum number of logs to return
449
+ * @returns Array of audit log entries
450
+ */
451
+ async getAuditLogs(limit = 50) {
452
+ const { AuditLogCollection } = await import("./AuditLogCollection-CnIYU0aK.js").then((n) => n.n);
453
+ return await (await AuditLogCollection.create(this.options)).getRecentActivity(this.id, limit);
454
+ }
455
+ /**
456
+ * Record an audit log entry for an action by this profile
457
+ *
458
+ * @param options - Audit log options
459
+ * @returns The created audit log entry
460
+ */
461
+ async recordAction(options) {
462
+ const { AuditLogCollection } = await import("./AuditLogCollection-CnIYU0aK.js").then((n) => n.n);
463
+ return await (await AuditLogCollection.create(this.options)).record({
464
+ profile: this,
465
+ ...options
466
+ });
467
+ }
468
+ };
469
+ __decorateClass([tenantId({ nullable: true })], Profile.prototype, "tenantId", 2);
470
+ __decorateClass([foreignKey("ProfileType", { required: true })], Profile.prototype, "typeId", 2);
471
+ __decorateClass([field({ unique: true })], Profile.prototype, "email", 2);
472
+ __decorateClass([field({ required: true })], Profile.prototype, "name", 2);
473
+ __decorateClass([oneToMany("ProfileMetadata")], Profile.prototype, "metadata", 2);
474
+ __decorateClass([oneToMany("ProfileRelationship", { foreignKey: "fromProfileId" })], Profile.prototype, "relationshipsFrom", 2);
475
+ __decorateClass([oneToMany("ProfileRelationship", { foreignKey: "toProfileId" })], Profile.prototype, "relationshipsTo", 2);
476
+ Profile = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
477
+ tableStrategy: "sti",
478
+ api: { include: [
479
+ "list",
480
+ "get",
481
+ "create",
482
+ "update",
483
+ "delete"
484
+ ] },
485
+ mcp: { include: [
486
+ "list",
487
+ "get",
488
+ "create",
489
+ "update"
490
+ ] },
491
+ cli: true
492
+ })], Profile);
493
+ //#endregion
494
+ //#region src/collections/ProfileCollection.ts
495
+ var ProfileCollection_exports = /* @__PURE__ */ __exportAll({ ProfileCollection: () => ProfileCollection });
496
+ var ProfileCollection = class extends SmrtCollection {
497
+ static _itemClass = Profile;
498
+ /**
499
+ * Find a profile by email address
500
+ *
501
+ * @param email - The email address to search for
502
+ * @returns The matching profile or null
503
+ */
504
+ async findByEmail(email) {
505
+ const normalizedEmail = email.toLowerCase();
506
+ const profiles = await this.list({
507
+ where: { email: normalizedEmail },
508
+ limit: 1
509
+ });
510
+ return profiles.length > 0 ? profiles[0] : null;
511
+ }
512
+ /**
513
+ * Find profiles by type slug
514
+ *
515
+ * @param typeSlug - The profile type slug to filter by
516
+ * @returns Array of matching profiles
517
+ */
518
+ async findByType(typeSlug) {
519
+ const allProfiles = await this.list({});
520
+ const filtered = [];
521
+ for (const profile of allProfiles) if (await profile.getTypeSlug() === typeSlug) filtered.push(profile);
522
+ return filtered;
523
+ }
524
+ /**
525
+ * Batch get metadata for multiple profiles
526
+ *
527
+ * @param profileIds - Array of profile UUIDs
528
+ * @returns Map of profile ID to metadata object
529
+ */
530
+ async batchGetMetadata(profileIds) {
531
+ const result = /* @__PURE__ */ new Map();
532
+ for (const profileId of profileIds) {
533
+ const profile = await this.get({ id: profileId });
534
+ if (profile) {
535
+ const metadata = await profile.getMetadata();
536
+ result.set(profileId, metadata);
537
+ }
538
+ }
539
+ return result;
540
+ }
541
+ /**
542
+ * Batch update metadata for multiple profiles
543
+ *
544
+ * @param updates - Array of { profileId, data } objects
545
+ */
546
+ async batchUpdateMetadata(updates) {
547
+ for (const update of updates) {
548
+ const profile = await this.get({ id: update.profileId });
549
+ if (profile) await profile.updateMetadata(update.data);
550
+ }
551
+ }
552
+ /**
553
+ * Find related profiles for a given profile
554
+ *
555
+ * @param profileId - The profile UUID
556
+ * @param relationshipSlug - Optional filter by relationship type
557
+ * @returns Array of related profiles
558
+ */
559
+ async findRelated(profileId, relationshipSlug) {
560
+ const profile = await this.get({ id: profileId });
561
+ if (!profile) return [];
562
+ return await profile.getRelatedProfiles(relationshipSlug);
563
+ }
564
+ async getAssets(profileId, relationship) {
565
+ return getOwnedAssetsFromCollection(this, profileId, relationship);
566
+ }
567
+ async addAsset(profileId, asset, relationship = "attachment", sortOrder = 0) {
568
+ await addOwnedAssetFromCollection(this, "Profile", profileId, asset, relationship, sortOrder);
569
+ }
570
+ async removeAsset(profileId, assetId, relationship) {
571
+ await removeOwnedAssetFromCollection(this, "Profile", profileId, assetId, relationship);
572
+ }
573
+ /**
574
+ * Get the relationship network for a profile up to a maximum depth
575
+ *
576
+ * @param profileId - The starting profile UUID
577
+ * @param options - Configuration options
578
+ * @returns Map of profile ID to depth level
579
+ */
580
+ async getRelationshipNetwork(profileId, options = {}) {
581
+ const maxDepth = options.maxDepth || 2;
582
+ const network = /* @__PURE__ */ new Map();
583
+ const visited = /* @__PURE__ */ new Set();
584
+ const queue = [{
585
+ id: profileId,
586
+ depth: 0
587
+ }];
588
+ while (queue.length > 0) {
589
+ const current = queue.shift();
590
+ if (!current) break;
591
+ if (visited.has(current.id) || current.depth > maxDepth) continue;
592
+ visited.add(current.id);
593
+ network.set(current.id, current.depth);
594
+ if (current.depth < maxDepth) {
595
+ const related = await this.findRelated(current.id);
596
+ for (const profile of related) if (profile.id && !visited.has(profile.id)) queue.push({
597
+ id: profile.id,
598
+ depth: current.depth + 1
599
+ });
600
+ }
601
+ }
602
+ return network;
603
+ }
604
+ /**
605
+ * Find all profiles belonging to a specific tenant
606
+ *
607
+ * @param tenantId - The tenant UUID to filter by
608
+ * @returns Array of profiles for this tenant
609
+ */
610
+ async findByTenant(tenantId) {
611
+ return this.list({ where: { tenantId } });
612
+ }
613
+ /**
614
+ * Find all global profiles (no tenant association).
615
+ *
616
+ * Routes through the shared tenant-global helper so it does not throw under
617
+ * an active tenant context (an explicit `tenant_id IS NULL` filter would be
618
+ * flagged as an isolation violation). (#1600)
619
+ *
620
+ * @returns Array of profiles with null tenantId
621
+ */
622
+ async findGlobal() {
623
+ return queryGlobal(this);
624
+ }
625
+ /**
626
+ * Find profiles belonging to a tenant plus all global profiles.
627
+ *
628
+ * Fails closed if an active tenant context requests a different tenant's
629
+ * rows; the admin/system path keeps the cross-tenant capability. (#1600)
630
+ *
631
+ * @param tenantId - The tenant UUID to include
632
+ * @returns Array of tenant-specific and global profiles
633
+ */
634
+ async findWithGlobals(tenantId) {
635
+ return queryWithGlobals(this, tenantId, "Profile.findWithGlobals");
636
+ }
637
+ };
638
+ //#endregion
639
+ export { ProfileType_exports as a, ProfileType as i, ProfileCollection_exports as n, promptMessageOptions as o, Profile as r, smrtProfilesGenerateBioPrompt as s, ProfileCollection as t };
640
+
641
+ //# sourceMappingURL=ProfileCollection-DlhdOnDr.js.map